Developer Culture

Stop optimizing code nobody has read yet

45 minutes ago · 6 mins read
Summarize and analyze this article with:
Share this

There is a version of you that has spent three hours making a function 12% faster. The feature it lives in has not shipped yet. Nobody knows if users will even use it. And you feel good about those three hours.

That feeling is the problem.

Premature optimization is one of those phrases developers hear early and then promptly ignore for the rest of their careers. Donald Knuth said it was the root of all evil back in 1974. We have been nodding along and doing it anyway ever since. The reason is not that developers are careless. It is that optimizing feels productive. It feels like the right kind of work. Clean, measurable, satisfying. You run a benchmark, you see a number go down, you feel like you have accomplished something real.

But if nobody has read the code, if the feature has not shipped, if you do not know yet whether the system will actually be under that kind of load, you have not accomplished something real. You have spent time solving a problem that may not exist.

The readability problem nobody talks about

Here is what actually happens when you optimize too early. You write code that works. Then you optimize it. The optimized version is harder to read. Not always dramatically, but usually a little. You trade a for loop that any junior dev can follow for a chain of bitwise operations that requires a comment explaining what it does, and then six months later someone edits the comment but not the code, and now you have a lie in your codebase.

Readable code is not a nice-to-have. It is the thing that lets your team move fast without breaking things constantly. When you optimize prematurely, you are trading future maintainability for a performance win you may never need. That is a bad trade in most cases, and it is an especially bad trade when nobody has confirmed the trade is necessary yet.

Code is read far more often than it is written. The first person who benefits from readable code is usually you, three weeks from now, when you have completely forgotten why you wrote it.

This is not abstract. Think about the last time you opened a file and saw something like this:

// Fast path for sorted input
 const result = arr.reduce((a, x, i) => i && arr[i-1] <= x ? a : [...a, x], []) .sort((a,b) => (a|0)-(b|0)) .filter((v,i,s) => s[i+1] !== v);

Now think about how long it took you to understand what that was doing. Now ask whether the person who wrote it checked whether the array would ever have more than fifty items in practice. That check probably never happened.

The "what if it gets popular" trap

A lot of premature optimization hides behind a reasonable-sounding question. What if this thing actually takes off? What if we get ten thousand concurrent users? Should we not be prepared?

The answer is: not yet. And the reason is that you do not know what the bottleneck will actually be until users show up and start hammering the system in ways you did not predict. The part you spent three days optimizing may turn out to be irrelevant. The thing that kills you under load is usually something you did not expect. A missing database index. A third-party API that rate limits you. An N+1 query hiding inside a loop you thought was fine.

You cannot optimize your way out of unknown unknowns in advance. What you can do is write code that is clear enough to diagnose quickly when something does go wrong. That is where the real value is.

The system that ships and then gets optimized based on real data beats the system that never ships because someone was still tuning it.

What "unread code" actually costs

When a new developer joins your team and opens a file, the first thing they try to do is build a mental model of what the code is doing. Every optimization that sacrifices clarity adds tax to that process. Multiply that across a whole codebase and you have a system where onboarding takes months instead of weeks, where nobody wants to touch anything because they are not sure what will break, and where bugs hide in complexity because the code is too dense to reason about quickly.

This is a real, measurable cost. It shows up in slower feature delivery, more bugs in production, and experienced developers spending their time deciphering code instead of building things. But it does not show up in the benchmark you ran when you first wrote the function. So it is easy to ignore.

The rule that actually works

There is a version of this principle that is practical and easy to follow: do not optimize until you have a reason to. A reason means a real performance problem in a shipped, running system, confirmed by a profiler, not a hunch. Until that reason exists, write the clearest, most obvious version of the code you can.

This does not mean write slow code on purpose. It does not mean ignore obvious inefficiencies. If you are writing a loop that will run ten million times and you know it, think about that. But if you are writing a function that transforms a list of twenty items before rendering a settings page, stop asking whether you should memoize it and just write the straightforward version.

Ship the thing. Get users on it. Use a profiler. Find the actual bottleneck. Then, and only then, make it fast. At that point you will have real numbers, real usage patterns, and a real justification for the complexity you are about to introduce.

A word on the instinct itself

The urge to optimize early is not irrational. It comes from caring about quality, from wanting the system to be good. That instinct is worth keeping. But it needs to be pointed at the right target.

In most projects, especially early-stage ones, the constraint is not CPU cycles or memory. It is clarity. It is the ability for a team to understand the system well enough to change it quickly. That is what slows projects down, not the fact that you used a forEach instead of a reduce.

The best thing you can do for performance, in the early stages of most projects, is write code so clear that the performance problem is obvious when it eventually shows up. Because it will show up. And when it does, you want a codebase you can actually work in.

Make it work. Make it readable. Make it fast when it needs to be.

In that order, every time.