How do you build a performance culture on a team: budgets, regression gates, ownership and release guardrails?
Predict first
A performance test fails one run in five on a shared CI runner, for no code reason. What is the best response?
// A: rerun until green
// B: move it to a dedicated device pool, add warm-up and iterations, compare to a baseline from the same pool
// C: delete the test
- A
- B
- C
Mental model. A performance culture is a household budget: set limits, see the spending every month, and stop the big purchase before it is made rather than discovering the overdraft.
Performance gets worse by a thousand small changes that each looked harmless, so the answer is process that catches them early, not heroics late. Start with budgets: a few numbers the product cares about, written as percentiles on named devices (“p90 cold launch under 1 s on the oldest supported iPhone”, “scroll hitch ratio under 5 ms per second on the feed”, “no more than X MB written per day”). Put them where people see them: a dashboard built from MetricKit and Organizer data per release, shown in the same place as crash-free rate. Add regression gates in CI: XCTest performance tests with baselines and XCTOSSignpostMetric for key flows, run on a dedicated, consistent device pool (noisy shared runners create false alarms that teach people to ignore the gate), plus cheap static guards such as binary-size and launch-time budgets in the build.
Then give it ownership. Someone owns each budget and is paused-on when it breaks; new features include a performance note (“what does this cost at launch, in memory, on a bad network”); and the code review checklist includes the usual traps (work on the main thread, unbounded caches, polling timers). Ship with guardrails: phased release with an automatic pause when hang rate, launch time or memory-kill rate regresses beyond a threshold, feature flags to turn off an expensive feature without a release, and an on-call path for a performance incident. Keep a short written history of the wins and regressions, because the lessons are what stop the next regression. A staff-level answer connects these: lab numbers to find, field numbers to decide, gates to prevent, rollout to limit blast radius.
A gate you cannot trust is worse than none; make the measurement stable so a red result means something.
Common traps
- A flaky performance gate on noisy shared runners. People learn to rerun until green, and the gate guards nothing.
- Budgets nobody owns. A number without an owner drifts upward quietly.
They might follow up with
- How do you keep CI measurements stable? Use dedicated devices, fixed OS versions, warm-up, several iterations and compare to a baseline from the same pool.
- What do you do when a release regresses launch? Pause the rollout, find the change with the signposts and the lab scenario, and fix forward or revert behind a flag.
Related questions
- 21.3.1 What does MetricKit give you in production, how do you subscribe, and what is the difference between metric…
- 21.2.2 How do signposts and Points of Interest work, and how do you turn a measurement into an XCTest performance…
- 21.1.2 How do you measure performance reliably: what makes numbers lie, and why do percentiles beat averages?
- 21.7.2 Where does binary size come from, how do you measure and shrink it, and what do optimisation level, stripping…
- 6.4.3 Your app launches slowly. How do you find out why and what do you cut?
← What does MetricKit give you in production, how do you subscribe, and…