Every System Rots. Some Rot Better Than Others.

“Controlling complexity is the essence of computer programming.” ( Brian Kernighan )

I used to think good software meant clean software. Neat modules, clear naming, no surprises. Then I spent enough time in production codebases to understand that cleanliness is a snapshot, not a property. Every system starts clean. Given enough time and enough business pressure, none of them stay that way. And the ones that do stay clean pay a different price: velocity. You can hold the line, but the business will notice.

The War Story You Already Know

You have probably seen it. A codebase that generates serious money, that has been running for ten or fifteen years, that no one fully understands anymore. Methods that are three hundred lines long. Business rules buried in utility classes. A comment from 2011 that says “do not touch this, it will break everything” with no further explanation.

And yet the system works. It processes transactions. It generates revenue. It has survived longer than most of the engineers who wrote it.

Meanwhile, somewhere else in the company, there is a beautifully architected service. Clean interfaces, proper layering, excellent test coverage. It solves a problem that turned out not to matter. Nobody uses it.

The messy system didn’t win because it was messy. It won because it kept working. The mess never got in the way of that.

Clean Code Is Not Wrong, It Is Just Insufficient

This is not an argument against writing clean code. It is an argument against treating cleanliness as the goal.

Cleanliness is a local property. A function is clean. A module is clean. A service is clean. But systems are not the sum of their clean parts. They are the product of years of decisions, each made with incomplete information, under deadline pressure, by people who are no longer around to explain what they were thinking.

Entropy is not a failure of discipline. It is physics. Requirements change. The business pivots. A new regulation arrives. Someone fixes a critical bug at 2am and does not have time to do it properly. Given sufficient time, every system accumulates complexity it did not ask for.

You can fight it. Some teams do. They enforce strict review, refactor constantly, reject shortcuts. The codebase stays clean. But every hour spent on cleanliness is an hour not spent on features, and at some point the product manager starts asking questions. The market does not wait for your abstractions to be correct. Cleanliness maintained under pressure is a tradeoff, not a free virtue, and most organizations eventually stop paying for it.

The Shift: From Clean to Contained

Cleanliness is the wrong target. The right one is containment: not hiding complexity because you are embarrassed by it, but creating a boundary where the complexity on one side cannot contaminate the other.

A clean interface over a messy implementation is not a compromise. It is the design. This aligns closely with the concept of “deep modules” from John Ousterhout’s work (which I will explore in an upcoming post reflecting on his book A Philosophy of Software Design). The mess has to live somewhere. The question is whether it is localized or systemic. Whether it leaks across boundaries or stays where it belongs.

This is also what Domain-Driven Design (DDD) is actually about. Bounded contexts are not just organizational patterns; they are blast shields. When a billing context accumulates years of tax-rule edge cases, currency quirks, and payment-provider workarounds, that complexity stays in billing and does not propagate into user management.

The engineers who built Windows were not idiots. Some of the smartest systems programmers in the world have worked on that codebase. Windows carries thirty years of backward compatibility constraints so dense that Raymond Chen has been writing about the edge cases for two decades. But notice what kind of mess that is: it is mess held at a boundary. The Win32 API is the contract; whatever compromises live behind it to honor decades of external commitments are free to be as ugly as they need to be, because the boundary is what millions of applications actually depend on. That is containment working exactly as intended, at a scale most of us will never operate at.

A Practical Example: The Anti-Corruption Boundary

Consider a system processing shipping rates. Initially, it uses a simple, clean model. Over time, you integrate a legacy carrier with bizarre CSV-based protocols and weird surcharge rules.

Instead of letting carrier-specific quirks leak into your core order management, you construct an interface wrapper (an Anti-Corruption Layer) that isolates the mess.

The adapter will eventually become a swamp of raw string manipulation, hardcoded tax rates, and special case parsing. But the rot is contained. Your core OrderManager remains completely unaffected.

Some of that swamp is essential complexity: the carrier’s surcharge rules really are that weird, and no amount of clean code will make a legacy CSV format less arbitrary. That part you isolate, not eliminate. But some of it will be accidental: sloppy parsing, guessed edge cases, special-casing that exists because nobody understood the actual rule. That part is worth fighting even inside the adapter, because accidental complexity compounds and essential complexity doesn’t.

What This Means in Practice

If you are building something new, the goal is not a clean system. The goal is a system with clean boundaries, where the inevitable mess is contained rather than systemic. Design your interfaces as if the implementation behind them will eventually become a mess, because it will. The interface is the commitment. The implementation is an internal concern.

Accept that on a long enough timeline, you will have both kinds of mess. The active development phase, where the model is still plastic and changing shape, eventually gives way to maintenance. The codebase stops being a place where new ideas are expressed and starts being a place where existing behavior is preserved. The engineers working on it shift from building to archaeology. The systems that age well are not the ones that were cleanest at the start. They are the ones where the mess, when it arrived, had nowhere to spread.

Cleanliness Is a Virtue, Containment Is a Strategy

I still write clean code. I care about naming, about keeping functions small, about not leaving surprises for the next person. But I have stopped treating cleanliness as the measure of a good system.

The measure is whether the complexity is where it belongs. Whether a change in one place requires changes everywhere else. Whether the boundaries hold under pressure.

A messy system with strong boundaries will outlast a clean system with none. The hello world is clean. The thing that runs your business is not.