Skip to main content

The Real Problem with Legacy Code

· 5 min read

"Legacy code is code without tests." — Michael Feathers, Working Effectively with Legacy Code

Feathers is right, but he's only describing a symptom. The real problem with legacy code isn't technical. It's a people problem.

What Makes Code "Legacy"?

Legacy code is code that is hard to modify and that few — if any — people understand. It lacks tests that codify and validate its behaviors. It lacks clear structure and design patterns that make data flow easy to reason about. It lacks documentation explaining why certain decisions were made instead of others.

Notice what's missing from that description: age.

Legacy code is not old code. Old things aren't lower quality because they are old. They're only lower quality if they're in a state of disrepair. A well-maintained cast iron skillet lasts decades and outperforms a brand new cheap pan from your local megastore. Old code that still does what it was built to do, without bugs, doesn't need to be updated.

Code becomes legacy when the people responsible for it stop maintaining it well.

The Rewrite Trap

The instinct when confronting a legacy system is to rewrite it. Start fresh. Do it right this time. But consider:

If the new system is built with the same poor practices as the old one, the best case is you end up with a new legacy system. Worst case, you have a new legacy system that isn't even as good as the old one, and the project gets abandoned.

If it took 15 years to get the old system to where it is — in terms of the business value it delivers — how reasonable is it to think the rewrite will take less? Ask yourself honestly:

  • Do you have a bigger team?
  • Do you have substantially better developers?
  • Do you have better development practices?
  • Do you have new tech that substantially reduces the time to define and implement behaviors?
  • Do you even know what the old system's behaviors are?

We foolishly underestimate and undervalue the work that went into the old system. Every weird edge case it handles, every subtle business rule baked into a conditional — that's years of accumulated knowledge. A rewrite doesn't inherit that knowledge automatically. You have to rediscover it, and you will miss things.

Sometimes a rewrite is the right call. If the answer to most of those questions is "yes" — better team, better practices, clear understanding of the existing behaviors — then go for it. But be honest about it. Most teams that push for a rewrite are really just tired of the old system. Fatigue is not a strategy.

Knowledge Is the Asset

Think of a codebase as a system with two inputs: knowledge added (features built, bugs fixed, edge cases handled) and knowledge lost (people leaving, missing documentation, unclear code). The system's state — how well-understood and maintainable the code is — depends on the balance between the two.

A healthy codebase has a positive knowledge balance. More understanding flows in than leaks out. Tests capture behavior. Documentation captures intent. Clear structure makes the code readable to newcomers. Each of these slows the rate of knowledge loss.

A legacy codebase is one where knowledge loss has outpaced knowledge gain for long enough that the balance has gone deeply negative. Nobody fully understands what the system does or why. At that point, even simple changes are risky, because you can't predict what will break.

A rewrite doesn't fix a negative knowledge balance. It resets the total knowledge to near zero and starts accumulating again. If the rate of loss hasn't changed — same practices, same turnover, same lack of documentation — you'll end up in the same place.

Good Systems Need Good Stewards

Say you beat the odds. You deliver a rewrite that really is better, that isn't already legacy code on arrival. What happens next?

Will the same people who built it well continue to maintain it? If they leave and the new maintainers don't follow the same practices, the code rots. You'll be right back in legacy system land within a few years.

Avoiding legacy code is not a one-time achievement. It's a continuous attitude toward software ownership and maintenance. It's how you keep the knowledge balance positive:

  • Codify behaviors in tests. Every test is a piece of knowledge that survives staff turnover.
  • Keep code structure clear and simple. Readable code transfers understanding to the next person who opens the file.
  • Write documentation that tells the stories the code can't. Capture the why, not just the what.

It's Always a People Problem

People own the system. People are responsible for the outcomes. If you want a good system, you need people who are good, who will own it, and who will keep it good. No technology choice, no framework, no rewrite fixes the problem if the people and practices aren't there.

Legacy code is what happens when nobody takes ownership.