The most expensive mistake in a shared codebase is solving a problem that’s already solved.

Not because the duplication itself is costly — two implementations of the same thing can coexist for a long time without incident. The cost is what happens when they drift. When one gets a bug fix the other doesn’t. When the behavior diverges and nobody notices until a user does. When a new engineer finds both and has to guess which one is authoritative.

The root cause, almost always, is someone who wrote before they read.

The Temptation

There’s a pull toward writing. Writing feels like progress. A new file, a new function, a cursor blinking on an empty line — it’s possible to measure the output in lines and feel productive.

Reading doesn’t feel the same. Reading feels like work before the work. It’s auditing, searching, building a mental model of a system someone else designed, for purposes you’re only beginning to understand. You can spend an hour reading and have nothing to show for it except knowledge.

Knowledge is the thing, though.

What You Find When You Read First

When you read a codebase before touching it, you find things. You find the utility that already does what you were about to build. You find the convention for how errors propagate, which saves you from introducing a new one. You find the comment that explains why the obvious approach was tried and abandoned. You find the test that will fail if you do the thing you were about to do.

You find context. And context changes what you write — or whether you write at all.

The best code I’ve encountered isn’t impressive because of what it adds. It’s impressive because of what it chose not to add. Because whoever wrote it understood the system well enough to see that the problem was already handled, or that the right move was a small edit rather than a new abstraction.

The Mechanical Habit

Reading first isn’t inspiration. It’s a habit enforced by routine.

Before creating a file, search for it. Before writing a function, search for the function name and the concept it implements. Before adding a dependency, check whether the capability already exists. Before solving a problem, read the tests — they describe the contract the system already enforces.

This takes time. Less time, almost always, than the alternative.

On Reading Code You Didn’t Write

There’s a particular skill in reading someone else’s code charitably. The instinct is to notice what’s wrong — the naming that doesn’t fit, the approach you’d have done differently, the missing comment. The better habit is to first understand why it is the way it is.

Most code that looks wrong was written by someone who understood something you don’t yet. The constraint that isn’t obvious. The edge case that was hit in production. The performance requirement that ruled out the elegant solution.

Read to understand before you read to critique. The critique is more useful after.

The Practical Test

A useful test before committing anything: can you explain, in plain language, how your change fits into the system? Not just what your code does — how it relates to what’s already there. What it reuses. What it replaces. What it leaves alone.

If you can’t answer that, you haven’t read enough yet.

Write less. Read more. The code will be better for it.