Skip to content

step 20 / 32 · 5 min

Making something faster, on purpose

Performance work done by intuition mostly optimises code that was not slow. Done with measurement it is usually a small change with a large effect.

Measure first

code
1. is it actually slow, and by whose standard
2. where does the time go
3. change one thing
4. measure again
5. stop when it is fast enough

Step 5 matters. Performance work has diminishing returns and a real cost in complexity, and "fast enough" is a decision, not a failure.

Percentiles, not averages

code
average       120ms     looks fine
p50            80ms
p95           400ms
p99         3,200ms     one in a hundred requests takes 3 seconds

The average hides the tail. On a page making 20 requests, a p99 of 3 seconds means most page loads contain one, so the experience most users get is the p99, not the median.

Report p50, p95 and p99. An average alone is close to useless.

Where the time usually is

CauseTypical
N plus one queriesone page, hundreds of queries
A missing indexone query, seconds
Waiting on a third partythe whole request
Doing work nobody asked foreager loading everything
Serialising a large responseCPU, at the end
Too many round tripslatency times count

Almost none of these are fixed by faster code. They are fixed by doing less.

Amdahl's law, informally

If a step is 20 percent of the total, making it instant improves the total by 20 percent and no more. Optimising the wrong step is bounded by how much of the time it was.

Which is why profiling before optimising is not pedantry: it tells you the ceiling on the change you are about to make.

The order to try

Do less. Fewer queries, less data, fewer round trips, no work nobody needs. Almost always the biggest win.

Do it earlier. Cache, precompute, materialise.

Do it later. Queue what the user does not wait for.

Do it in parallel. Independent calls at the same time rather than in sequence.

Do it faster. Better algorithms, then better code. Last, because it is the most effort for the least reward in most systems.

Watch it in production

Local benchmarks use small data, warm caches and no network. Production has real data volumes, cold caches, contention and latency. Improvements that hold locally and vanish in production are common enough to expect.