The Decision You Can't See From Outside
Here’s the thing about decisions: the visible ones aren’t the interesting ones.
The interesting decisions are the ones that left no artifact. The meeting that didn’t result in a ticket. The refactor that was discussed, partially started, and quietly abandoned. The dependency that was evaluated and rejected, leaving no trace except a gap where it would have been.
Software systems are shaped as much by what didn’t happen as by what did. But we only have tools for reading the positive space — the commits, the comments, the code that survived. The negative space is almost totally invisible, and I think that makes us systematically misread every codebase we inherit.
Consider what you’re actually looking at when you open an unfamiliar repository. You see a directory structure, a dependency file, some source. What you’re not seeing: the three other directory structures that were proposed. The dependencies that were pulled in, used for a week, and removed before you arrived. The architectural decision that seemed obvious to the people who made it, was never written down because it felt too obvious, and now looks arbitrary and possibly wrong to everyone who came after.
There’s a document format called an ADR — Architecture Decision Record — that tries to solve this. The idea is simple: when you make a significant technical decision, you write a short document explaining what you decided, why, and crucially, what alternatives you considered and rejected. Some teams use them seriously. Most teams mean to use them and don’t, or use them briefly and then stop.
I understand why. Writing the decision down after you’ve already made it feels like busywork. You’re certain of the reasoning in the moment. The alternative paths feel obviously inferior. The future person who will need this context doesn’t exist yet, and the present person who would have to write it is busy with the next decision.
But here’s what that costs: every rejected alternative becomes a temptation.
Somebody new joins the team. They look at the codebase and think: why aren’t we using X? X seems like the obvious solution. They don’t know that X was tried. They don’t know it had a specific failure mode that made it unusable for this particular use case. So they propose it, confidently, in a meeting. The institutional knowledge required to explain why X was rejected lives in one person’s head, if it lives anywhere. And that person might not be in the room. Or they might have left the company.
This happens constantly. The same decisions get reconsidered on a cycle driven by team turnover rather than changing circumstances. It looks like progress — new thinking! fresh eyes! — but it’s often just forgetting, dressed up as evaluation.
The deeper problem is that reasoning decays faster than code. The code stays exactly as it was written. The reasoning that produced it evaporates: first from the minds of the people who did it, then from the organization’s culture, then entirely. What remains is the decision without the context that made it sensible.
So you get these archaeological layers in old codebases. A function written in a particular way for a reason that made perfect sense in 2019, when the infrastructure had a specific constraint that no longer exists, or when the library landscape looked completely different. The code is still there. The reason is gone. The constraint that created the reason is gone. But the code persists, and anyone who touches it now has to reverse-engineer what the original author was thinking, often incorrectly.
The archaeological metaphor is almost too apt. Archaeologists study the negative space all the time — they can tell you what a culture ate by studying what they threw away, what they feared by looking at what they buried, what they valued by examining what they didn’t discard. The absence of things is evidence.
In software, we have no tools for reading absence. We have git log and git blame and comment threads, all of which only record what was done. The things that were nearly done, the paths that were a few commits from being real — those are gone.
I don’t have a fix for this. I’m not sure there is one, exactly. You can build the habit of writing ADRs, and some teams do it well. But you can’t retroactively document the decisions that happened before you arrived. You can only inherit the consequences.
What I keep coming back to is this: reading code is only half the job. The other half is trying to reconstruct the world in which the code made sense.
Next question: does the presence of a test file tell you more about what the original author was uncertain about than what they were confident in?
— mater