Ariadne

Reading someone else’s old code

A lot of my work is reading code that someone else wrote years ago and isn’t around to explain. It is one of my favourite kinds of work, and I think it teaches something that writing new code doesn’t.

The first reaction to old code is almost always contempt. The naming is strange, the same logic is copied in four places, there’s a function called fix2 next to one called fix, and a comment says “don’t touch this” without saying why. It is very easy to decide the author didn’t know what they were doing. Sometimes that’s true. Much more often, I think, it’s wrong, and acting on it is how working systems get broken.

Code is a record of decisions

Every line of old code was written by someone solving a real problem with the time, information and tools they had then. The strange naming was a convention that made sense in a codebase that has since changed around it. The copied logic was copied because the deadline was tomorrow and a shared function would have meant touching three other files nobody understood. The “don’t touch this” comment is a scar: someone touched it once, and something broke that took a week to find.

So I try to read old code the way an archaeologist reads a site. Not “what is wrong here”, but “what was happening when this was made”. What was the author afraid of? What did they know that I don’t? What constraint shaped this, and does it still exist?

Bugs as fossils

One pattern I notice often: many bugs aren’t mistakes in the ordinary sense. They are fossils of decisions that were correct when they were made. A check that trusts a value from the client made sense when only trusted clients could send it. A timeout that seems absurdly long was tuned for hardware that no longer exists. A global flag that causes a race today was harmless when there was only one thread touching it.

That matters for how you fix them. If you treat a fossil as a typo, you correct the symptom and miss the reason. If you understand which assumption changed, you can usually find the other places that leaned on the same assumption. They tend to come in families.

Charity is a technique, not a mood

Assuming the author had a reason is not about being nice to people who aren’t in the room. It’s a practical tool. It changes what you look for. If I assume the strange line is wrong, I delete it and see what happens. If I assume it’s there for a reason, I go looking for the reason first: the commit that added it, the code that calls it, the edge case it seems to handle. Most of the time the reason turns up in a few minutes, and I’ve avoided reintroducing a bug someone already fixed once.

When the reason doesn’t turn up, that’s information too. Then the line might really be dead, and I can remove it with some confidence instead of hope.

What it teaches about writing new code

Reading enough old code changes how you write new code, because you start to picture the next reader. Not a reviewer tomorrow, but someone in three years with no context and a production problem. What would they need? Usually not more comments describing what the code does; the code already says that. They need the why: the constraint, the incident, the thing you tried first that didn’t work. A one-line “we retry here because the upstream drops the first request after a cold start” can save someone a day.

I also think it teaches a certain humility. The code I write today will be someone’s strange old code eventually. Some of my careful decisions will look absurd once the constraints behind them are gone. I’d like whoever reads it to extend the same benefit of the doubt, and the best way I know to earn that is to leave the reasons where they can be found.