Read
☕ 2 min
Topics
Process & SDLC · Performance testing
Rev
25 Oct 2026

Make it work, make it right, make it fast

This line has stuck in a corner of my mind for years. I used to read a lot of Medium posts and books like that, and I’ve shared this order with plenty of people since. When I asked myself where I’d picked it up and when it became a habit, I dug a little deeper and found it credited to Kent Beck. It’s actually older. Stephen Johnson and Brian Kernighan wrote it in Byte in 1983, about C: “the strategy is definitely: first make it work, then make it right, and, finally, make it fast.”

People quote it as three things to do. I read it as an order, where each step has its own definition of done and makes the next one safe.

✗ premature optimization measure → change → measure WORKRIGHTFAST tests passclean, tests still passmeasured, hits a target
Fig. 1 · Three gates, each with its own 'done'. Fast is a loop of measuring. The shortcut from working code straight to fast code is the one to avoid.

Make it work

Done means the tests for the behaviour you need are passing. It doesn’t have to be pretty, and it certainly doesn’t have to be fast. It has to be correct, and provably so, because the next step depends on those tests.

Make it right

Now you clean up, and the tests stay green while you do. That is refactoring in the strict sense from principle 01: new structure, same behaviour.

Ward Cunningham’s C2 wiki, the first wiki, opened in 1995, is one of the places where extreme programming and design patterns were first argued out. It has a long argument about what “right” means. Some say clean design, others say the edge cases handled properly. I think it’s both: the special cases covered, and code you’d be happy to change next month.

Make it fast

Two people who earned the right to say it have already warned us about this step.

Donald Knuth, in 1974: “We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%.” The second sentence usually gets left out. Knuth wasn’t against optimizing. He was against guessing where to optimize.

Rob Pike, in 1989: “You can’t tell where a program is going to spend its time. Bottlenecks occur in surprising places, so don’t try to second guess and put in a speed hack until you’ve proven that’s where the bottleneck is.” His next rule is a single word: “Measure.”

Try it yourself:

This handler is slow. Where does the time go? Make a guess.

What the profile says

  • Parse the request JSON 9%
  • Query the database 27%
  • Calculate the price 6%
  • Write the log line 58%
Fig. 2 · An illustrative profile, not a real measurement. The shape is the point: one part overwhelms the rest, and it's rarely the one people bet on.

Once you have a measurement, “fast” becomes a loop: change the hot part, measure again, stop when you hit the target. That last bit matters. Without a target, you never know when you’re done.

Why the order matters

Fast before right is one of the most obvious mistakes. Clever tricks stuck onto messy code get tangled up with it, and the next change has to fight both. Right before work has its own cost: you end up polishing code that doesn’t do the job yet.

I went looking for who first said these three steps and ended up with two people writing about C in 1983. More than forty years on, the languages have changed and agents write a lot of the code, but the order hasn’t. When did you last make something fast, and had you taken a measurement beforehand?