We talk about software "rotting" as if code degrades on its own, like fruit. It doesn't. The bytes you wrote five years ago are identical today. What changed is that the people who knew why they were written that way are gone — and a system whose reasons have left is a system nobody can safely touch.
Every codebase is a pile of decisions. Use this database, not that one. Build for this scale, not that one. Special-case this customer because the contract demanded it. Skip the abstraction here because the deadline was Friday. Thousands of them, made by dozens of people, over years. The running system is the residue of all those choices.
And here is the problem at the center of every aging codebase: the code records what was decided. It never records why.
What walks out the door isn't talent. It's context.
When a senior engineer resigns, everyone worries about losing their throughput — the tickets they would have closed. That's the wrong thing to mourn. Throughput is replaceable; you can hire more hands. What you can't easily replace is the map in their head: which parts of the system are load-bearing, which are held together with tape, which look wrong but are wrong on purpose, and which are genuinely safe to change.
That map was never written down. It lived in one person's memory, and it left with them. The new hire inherits the same code — but not the same understanding of it. To the person who built it, a strange-looking module was an old friend with a known history. To the person who inherited it, it's an artifact of unknown origin and unknown blast radius. Same code. Completely different risk.
"A system you understand is an asset. The exact same system, understood by no one, is a liability. The code didn't change. The knowledge did."
How the why actually disappears
Knowledge doesn't vanish in a single dramatic event. It drains, slowly, through ordinary channels nobody flags as risky.
- Turnover. The obvious one. Someone leaves, and the reasoning behind everything they touched leaves with them. The average tenure on an engineering team is a few years; the codebase is older than that. Do the math and most of the decisions in your system were made by people who no longer work there.
- Reorgs. A team gets reshuffled, a domain changes hands, and the new owners inherit the code without the conversations that produced it. The handover is an hour and a wiki page. The context was a thousand hours and a hundred conversations.
- The hero. One person becomes the de facto owner of a critical system because they understand it and nobody else wants to learn. The team comes to rely on asking them. Which means the knowledge never gets distributed — it gets concentrated, into exactly the single point of failure you least want.
- Time itself. Even the person who made a decision forgets why. "I'm sure there was a reason we did it this way" is something engineers say about their own code from two years ago. Memory is not a storage medium.
None of these show up on a dashboard. There's no alert for "the last person who understood the billing engine just accepted another offer." The loss is invisible until the day you need the knowledge and discover it's gone.
Why this is what makes a codebase unmaintainable
A codebase doesn't become unmaintainable because it's large or old or written in an unfashionable language. It becomes unmaintainable when the people working in it no longer understand why it is the way it is — because understanding is the prerequisite for safe change.
Watch what happens to a team in that state. They stop refactoring, because you don't refactor what you don't understand — you might be removing the one line holding production together. They build around problems instead of through them, layering new code on top of code they're afraid to touch. They pad every estimate, because any change might detonate something they can't see. Velocity drops, not because the engineers got worse, but because the system got opaque. This is technical debt in its truest form: not messy code, but lost understanding.
The fear is rational. That's what makes it so corrosive. A team that's afraid of its own codebase is making the correct decision given what it knows — which is not enough.
The documentation that was supposed to save us
"This is why we write documentation," someone always says. And documentation is good. But it doesn't solve this problem, for two reasons.
First, documentation records the what, not the why. It tells you the system uses an event queue; it rarely tells you that the team chose the queue over a direct call because a specific outage in 2022 made synchronous coupling unacceptable. The decision and its trigger — the actual reasoning — are exactly what gets left out, because at the time they were obvious to everyone in the room.
Second, documentation describes a moment, and the system keeps moving. The doc is accurate the day it's written and decays from there. Within a year, the dangerous documentation isn't the missing page — it's the confident one that's quietly wrong. Teams learn to distrust the wiki, which means they stop reading it, which means they stop writing it. The cycle completes.
The thing nobody admits
Most organizations have no idea how much of their system is understood by exactly one person, or by no one at all. They find out the hard way — during an acquisition, a key departure, a new CTO's first ninety days, or an outage in a subsystem everyone had quietly stopped touching. By then, recovering the context is a forensic exercise under pressure, not a planned one.
The question isn't whether your codebase has decisions nobody remembers. Every codebase that's older than its team does. The question is whether you find out which ones on your schedule, or on the day it costs you.
The good news: the system kept a record the people didn't
Here's the part that changes the picture. The reasons feel lost because they left people's heads — but they were never only in people's heads. Every decision left a trace in the one place that can't forget: the system's own history.
The commit that introduced the workaround has a timestamp, an author, and a diff. The pull request has the discussion that justified it. The ticket links the change to the requirement that demanded it. The bug that prompted the special case is in the tracker. The deployment that followed the outage is in the logs. None of it was written as documentation — but together, correlated over time, it is the record of why the system became what it is.
Reading that record to reconstruct the lost reasoning is a discipline. We call it decision archaeology: treating the codebase and its history as a site to be excavated, not interviewed. You don't ask the team what they remember — memory is the thing that failed. You let the system testify. The commit can't forget the date. The diff can't spin the change. The ticket can't claim a fix that never shipped. Where the team's account and the evidence disagree, the evidence wins.
Done well, this turns the unmaintainable back into the maintainable. Not by rewriting the code, but by restoring the thing whose absence made it dangerous: an accurate understanding of why it is the way it is, mapped to the parts of the business that depend on it. A team that understands its system again can refactor it, modernize it, defend it to a board, or hand it to an acquirer. A team that doesn't can only tiptoe around it and hope.
The asset you didn't know you were losing
Every quarter, context drains out of your organization through resignations, reorgs, and ordinary forgetting, and almost no one accounts for it. It doesn't appear on a balance sheet. It doesn't trigger an alert. It shows up later, disguised as slowing velocity, ballooning estimates, a failed integration, or a due-diligence surprise.
Software doesn't rot. The reasons leave. And the reasons, unlike the people, can be brought back — because the system was keeping a record the whole time. The only question is whether you read it before you need it, or after.