Chesterton’s Fence: Why Understanding Legacy Code Saves Software Projects

G.K. Chesterton wrote in 1929 about a reformer who finds a fence crossing a road and wants to remove it because he can’t see the point of it. Chesterton’s response: if you can’t see the point of it, you don’t get to remove it. First understand why it was built. The person who built it had a reason. That reason may still apply.

In software engineering, this is one of the most practically useful principles on any list. Legacy code is full of fences.

What Legacy Code Actually Is

Legacy code has a reputation as code written by people who didn’t know what they were doing. This is sometimes true. More often, legacy code is code written by capable people under constraints that no longer exist, solving problems that are no longer visible, with knowledge that was never documented.

The convoluted validation function that checks twelve conditions before allowing a transaction to proceed. The three-second sleep in the deployment script before the health check runs. The conditional that routes certain enterprise customers through a completely different code path. The configuration flag that’s never been false in production.

Each of these was written by someone who had a reason. The validation was written after a production incident. The sleep was added after a race condition during a late-night deployment. The enterprise routing was added for a specific customer’s compliance requirements. The flag was added for a migration that finished two years ago.

The Cost of Moving Without Understanding

When developers remove code they don’t understand, they sometimes get away with it. Sometimes they don’t. The incident that follows is usually instructive. The validation function they deleted was the one preventing double charges on certain payment methods. The sleep they removed caused the deployment to fail intermittently in a way that took three weeks to reproduce.

These incidents are expensive and completely avoidable. The fix is simple in principle: before changing or deleting something you don’t understand, find out why it exists.

In Agile terms, this is the investigative work that belongs in the sprint. Not all investigation is a spike. Sometimes the right definition of “done” for a refactoring story includes understanding why the existing code is the way it is.

ADRs: Making Reasons Visible

Architecture Decision Records are one of the most practical LEAN tools for preventing Chesterton’s Fence problems in the future. An ADR is a short document that records an architectural decision, the context in which it was made, the options that were considered, and the reasoning behind the choice.

ADRs are kept in version control alongside the code. When a developer three years from now wonders why the system uses a particular caching strategy, the ADR tells them. When someone wants to change the database schema in a way that conflicts with an old decision, the ADR explains the tradeoff that made the original decision reasonable.

Writing ADRs is Chesterton’s Fence turned into a practice. You’re building the explanation into the codebase so that future developers don’t have to reverse-engineer it from incomplete evidence.

The Strangler Fig Pattern for Safe Refactoring

When a team needs to replace a legacy system or a large section of legacy code, the strangler fig pattern is the Agile and Continuous Delivery approach that applies Chesterton’s Fence most directly.

The strangler fig doesn’t replace the old system all at once. It builds the new system alongside the old one, routing specific behaviors to the new system incrementally while the old one remains in production. As confidence in the new system grows, more behaviors move over. Eventually the old system handles nothing and can be removed.

This approach requires understanding the old system well enough to replicate its behavior correctly. That understanding is exactly what Chesterton’s Fence demands. The pattern forces the investigation that protects teams from the incident that would follow a less careful replacement.

Characterization Tests

Michael Feathers introduced the concept of characterization tests in his book “Working Effectively with Legacy Code.” A characterization test documents the current behavior of a system, whatever that behavior is, without judgment about whether it’s correct.

Before refactoring a piece of legacy code, you write tests that capture everything the code currently does. Then you refactor. If any test fails, you understand exactly what behavior changed. You can then decide whether that change was intentional or whether you accidentally removed something that mattered.

This is the git blame equivalent in automated test form. Before you remove the fence, you document it in enough detail that you can rebuild it if it turns out you were wrong to remove it.

Git Blame: The First Tool

The simplest application of Chesterton’s Fence is reading git blame before changing code you don’t understand.

Git blame shows who wrote each line, when, and in what commit. The commit message tells you why. The linked issue or pull request tells you more. In most cases, five minutes of reading git blame explains a confusing piece of code. The explanation might be “this was written under deadline pressure and should be cleaned up.” It might be “this was written to handle a case that will crash production if you remove it.” You can’t know which until you look.

Make reading git blame before refactoring a team norm. It’s a few minutes of investigation that prevents hours of debugging.

Want to move faster on legacy systems without breaking things? Let’s talk.

Chesterton’s Fence: Why Understanding Legacy Code Saves Software Projects

Leave a Reply

Your email address will not be published. Required fields are marked *