Make It Work → Right → Fast — Profile Before You Optimize
Make it work, make it right, make it fast — in that order
Kent Beck's sequence is a discipline, not a slogan. Correctness first; speed last and only where measured. The opposite — optimizing while building, by intuition — is what Knuth meant by "premature optimization is the root of all evil": you add complexity and bugs to speed up code that wasn't the bottleneck.
The performance method: measure, don't guess
- Establish a baseline & a target — "no number = no goal" (from the approach lesson).
- Profile to find the hotspot. Almost always the time is concentrated (Pareto: ~80% in ~20% of the code, often a single function or query). Flame graphs (Brendan Gregg) show it at a glance.
- Fix the biggest contributor — and re-measure. The win must show up in the number, not your belief.
- Repeat until you hit the target, then stop.
Why fixing the non-bottleneck is wasted — Amdahl's Law: if a part is 6% of runtime, making it infinitely fast saves at most 6%. The diagram's 78% DB query is the only thing worth touching first; add the index, not a faster renderer.
One worked pass of the loop, with Amdahl ranking the fixes. Baseline p99 = 1000 ms, target 300 ms. Profile: DB query 78%, serialization 11%, render 6%. Candidate A — index the query (a quick spike measures 10× on that step): predicted overall speedup = 1/((1−0.78)+0.78/10) = 1/(0.22+0.078) ≈ 3.36× → ~298 ms — hits the target. Candidate B — rewrite the renderer 10× faster: 1/((1−0.06)+0.06/10) = 1/(0.94+0.006) ≈ 1.06× → ~946 ms — invisible. Same engineering effort, a ~60:1 difference in payoff. Do A, re-measure, observe ~300 ms, stop.
The general form: overall speedup = 1/((1−p) + p/s), where p is the fraction of runtime in the part you improve and s is how much faster that part gets. The rule: estimate p from the profile and s from a spike before committing to any optimization — the formula ranks candidate fixes while they are still cheap to abandon.
When the sequence is not absolute
Beck's order is the default, not a law. You may choose the data structure or concurrency model up front when the latency/throughput budget is a hard requirement. Examples: a real-time pricing feed that must stay under 10 µs, a kernel scheduler, or a bounded queue that must never OOM under overload. In those cases the algorithmic choice is part of "make it work" because a mutexed prototype can never meet the SLO. The anti-pattern is not up-front performance thinking — it is micro-optimizing before measuring.
Rule of thumb: algorithm and data structure first when the budget is load-bearing; micro-optimization only after profiling.
Example: high-frequency matching engine
A matching engine with a 10 µs p99 latency SLO cannot be built with a mutex-protected order book and then "optimized later." The lock-free queue, lock-free skip list, and cache-aware layout are chosen during the "make it work" phase because a synchronized design has no path to the budget. That is not premature optimization; it is a constraint driving the architecture.
Reading resource health: the USE method
For any resource (CPU, memory, disk, network), check Utilization, Saturation (queueing), and Errors. A saturated, queueing resource is your bottleneck — this is how you find which resource to profile before diving into code.
Pitfalls
- Optimizing by intuition — engineers are famously wrong about where time goes; profile.
- No baseline — you can't tell if a change helped.
- Micro-optimizing the 6% — Amdahl caps the payoff; find the 78% first.
- Optimizing before it's correct — fast wrong code is still wrong.
- The "I rewrote it and nothing moved" tell — if a change lands and the same resource is still the bottleneck, or a correctness test regresses, you optimized a spot the profile never pointed at. Revert and re-read the flame graph before touching anything else.
Takeaways
- Work → right → fast, in order; speed only where measured.
- Profile to the hotspot (Pareto); fix the biggest, re-measure; Amdahl caps non-bottleneck wins.
- USE (Utilization/Saturation/Errors) finds the bottlenecked resource first.
Re-authored for this guide; profile/loop diagram hand-authored as SVG. Follows Beck, Knuth, and Brendan Gregg's performance methodology (USE method, flame graphs). See also: How to Approach a Problem, Tail Latency, (Concurrency) Amdahl's Law, How a Query Executes.
🤖 Don't fully get this? Learn it with Claude
Stuck on Make It Work → Right → Fast — Profile Before You Optimize? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.
Build the mental picture, not memorization.
I just read a lesson on **Make It Work → Right → Fast — Profile Before You Optimize** (System Design) and want to truly understand it. Explain Make It Work → Right → Fast — Profile Before You Optimize from first principles using ONE vivid real-world analogy and a visual mental model — draw it as ASCII art or a clear step-by-step diagram — with a concrete example using real numbers. Then ask me one question to check I got the mental picture, and wait for my reply. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Socratic — adapts to where you're stuck.
Teach me **Make It Work → Right → Fast — Profile Before You Optimize** interactively. Ask me ONE guiding question at a time, wait for my answer, and adapt to my confusion — build the idea with me step by step instead of explaining it all at once. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Active recall exposes what you missed.
Quiz me on **Make It Work → Right → Fast — Profile Before You Optimize** with 5 questions, easy to tricky, ONE at a time. Tell me if each answer is right; at the end, explain clearly what I got wrong and why. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Intuition + hook + flashcards for long-term memory.
Help me remember **Make It Work → Right → Fast — Profile Before You Optimize** for the long term: give the one-sentence intuition, a memorable hook/mnemonic, a tiny worked example, and 3 active-recall flashcards (Q -> A). If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.