The Clean Slate and Its Costs

The rewrite always feels righteous.
You're standing in front of a codebase that's accumulated fifteen years of decisions made by people who are long gone, solving problems that no longer exist, using patterns that were best practice in 2009. The CSS is a nightmare. The business logic is scattered across layers that shouldn't know about each other. There's a function called handleSpecialCase that's 400 lines long and handles seventeen special cases, none of which are documented.
And someone says: "What if we just started over?"
The relief is immediate. Finally. Someone is being honest about the rot. Someone is willing to name the thing that everyone has been tiptoeing around. The current system isn't maintainable. It's not extensible. Every new feature takes three times longer than it should because you're fighting the architecture instead of building on it. The rewrite isn't just appealing. It feels necessary. It feels like the only honest response to what's actually in front of you.
I've been that person. More than once.
The Righteousness Problem
There was a social media startup. LinkedIn for college students, basically, focused on building communities around grant projects. Niche, but they had traction. The existing system was raw PHP without a framework. Spaghetti doesn't begin to describe it. Understanding any single feature required tracing code paths through dozens of files with no consistent naming conventions.
We came in to rewrite it. FastAPI and React. Modern stack. Clean architecture. Everything the old system wasn't.
And it felt good. The old codebase was genuinely terrible. The critique was legitimate. The new system was going to be maintainable, extensible, all the things you want.
The righteousness started feeling suspicious when we were creating our own tech debt inside the new application. They were running out of money. They needed to move fast. So we were doing the "move fast, break things" dance while simultaneously telling ourselves we were building something better than the mess we inherited.
They folded. Not just because they ran out of money. The rewrite blinded the business to its own sedimentary wisdom at the moment they were most vulnerable. While we were busy building clean abstractions, we were losing the accumulated knowledge of what their users actually did, what edge cases actually mattered, what kept the rickety thing running in the first place.
The scope of rewrites is always bigger than you think. That's not a guess. That's a pattern I've watched play out across every rewrite I've been part of or observed. And the reason is the thing nobody wants to hear: the mess you're looking at isn't just mess. It's accumulated interpretation. Those weird edge cases and special handlers and inexplicable conditionals? They're not arbitrary. They're the sedimentary record of every problem the system encountered and solved.
Remove them, and you don't get purity. You get yourself, doing all that interpretation alone, badly, without knowing that's what you're doing.
The Fence That Looked Like It Was Falling Down
I was working in the credit space. There was a system for making sure users didn't get their credit report run multiple times. Hard inquiries affect real people's real lives. The existing code for handling this was gnarly: nested conditionals checking name variations, middle initials, diminutives. Kenneth versus Ken. Steven versus Steve. With and without middle names. Every permutation someone might enter when they're not thinking about consistency.
The system had gotten to an untenable point. Something had to change. So I simplified it.
I knew the fence needed to be there. I wasn't removing protection, I was rebuilding it. Better. Cleaner. More maintainable.
Except I left a hole in it. A very common code path that would have allowed people to have their credit run multiple times. We caught it in UAT testing, thank God. Fixed it before it hit production. But the lesson stuck.
The "Steve vs. Steven" logic wasn't poorly written. It was a high-fidelity map of human behavior. When I "cleaned" it, I wasn't removing cruft. I was lowering the resolution of the system until it could no longer see the customers. The original developers hadn't been sloppy. They'd been observant. Every weird conditional represented a real person who had done a real thing that broke a simpler assumption.
I understood why the fence was built. I just didn't understand all the trade-offs that had been encoded into its rickety structure. The original implementation looked like cruft. It was actually load-bearing.
This is why I don't subscribe to "move fast and break things." Very rarely are people just arbitrarily making decisions. They're not sitting there thinking "let's add complexity for no reason." They're solving problems. And if you don't understand what problems they were solving, you don't get to remove their solutions yet.
Translation Layers as Contextual Integrity
There's a project I'm working on now with an identifier problem. This identifier means one thing to sales: it's a marketing tool, something salespeople use when talking to customers about products. They've built intuitions around it. They sell into the customer's recognition of it.
To engineering, the same identifier means something completely different: a bucket for performance characteristics, for technical specifications.
To accounting, it's yet another thing: a categorization tool for receivables.
These three meanings don't map cleanly onto each other. We've been trying to design a unified identifier, a clean abstraction that serves everyone. It's nearly impossible. The product owner can't get alignment. Every proposed change makes at least one group unhappy.
The instinct is to call this technical debt. To see the messy translation layers as obstacles to be removed. But that framing is wrong.
What we're looking at is contextual integrity. When we try to unify Sales, Engineering, and Accounting into one clean identifier, we perform lossy compression. We strip out the metadata of their specific needs, the particular ways each group has learned to use this thing for their particular purposes. A messy bridge that lets three groups communicate imperfectly is better than a clean wall that prevents communication entirely.
So we're building a new identifier in parallel. The old one keeps doing what it's doing for everyone who depends on it in their own ad hoc way. The new one becomes available for the analytics layer. People migrate when it makes sense for them.
This is the strangler fig pattern in action. You can't just burn it down because everybody's relying on it, in different ways, for different reasons. The middleware that makes everyone slightly unhappy? That's not failure. That's the record of three different groups discovering that their mental models don't align, and building bridges anyway.
The Reformation as Rewrite
Here's where I'm going to lose some people, but stay with me.
The Protestant Reformation was the most consequential "burn it down and start over" in Western history. And Luther's critique was legitimate. The corruption was real. The indulgences were a scandal. The institutional church had accumulated layers of practice and doctrine that had drifted far from their original purposes.
Luther looked at Catholicism the way a developer looks at a legacy codebase. All this accumulated complexity. All these intermediary layers between the believer and the source text. All this tradition that nobody could quite justify anymore. So he simplified. Sola Scriptura. Scripture alone.
Sola Scriptura is the original "self-documenting code." It assumes the text contains everything necessary for operation, that you can read the source and understand the system. But it ignores that the runtime, the community and its rituals, is what actually executes the intent. The Bible isn't a program that runs itself. It requires interpretation, formation, practice. The tradition Luther cut away wasn't middleware blocking access to God. It was the execution environment that made the text operational in human lives.
It felt righteous. It was honest about the rot.
And five hundred years later, I sit in a Protestant church that didn't mention Lent the Sunday before Ash Wednesday. That has worship services indistinguishable from TED talks with concert aesthetics. That offers what amounts to Christian-themed behavioral therapy: weekly group sessions on how to fix your life, heavy on introspection, light on participation in anything beyond yourself.
I'm writing this as a Protestant grieving from inside the tradition. Not scoring points against it. I still go. I still believe. But I feel the lack.
The translation layers that Luther removed, the liturgical traditions, the sacramental theology, the interpretive authority of the church, the participatory ontology that embedded individuals in community, those weren't just obstacles between believers and God. They were accumulated interpretation. They were the sedimentary record of how the church had learned, over centuries, to form people into a certain kind of life together.
Remove them, and you don't get purity. You get individuals doing interpretation alone, not knowing that's what they're doing.
What Gets Hollowed Out
The thing about subtracting load-bearing elements is that you don't notice immediately. The building doesn't collapse the day you remove the beam. It settles. It shifts. Cracks appear years later in places that seem unrelated.
Luther didn't intend to produce therapeutic self-help Christianity. He was trying to recover something he felt had been lost. But when you cut away the liturgical layers, you cut away the framework for theological participation. When you de-emphasize tradition and ecclesiastical authority, you de-emphasize the structures that form people over time. What fills the void is whatever the surrounding culture provides.
Five centuries of iteration later, we have churches that function as social clubs with a weekly group therapy session. Identity as something you create inside yourself rather than something you participate in through community. The feeling that everything is very superficial and that we aren't able to participate in Christian life to the degree that people used to.
I'm doing Lent right now. Fasting from video content: no YouTube, no movies, no shorts. It's not that video media is evil. It's that I'd been using it for distraction and numbing for a year or more. Lent is supposed to create space for preparation, for the celebration of the resurrection. But my church doesn't do Lent. Doesn't mention it.
So I'm participating in the tradition separately from my church life. This is the spiritual equivalent of shadow IT. When the main system removes load-bearing features, users build their own unmonitored workarounds to survive. I'm running unauthorized liturgical software because the official platform deprecated the features I need. That's its own kind of grief.
What surfaced in that created space? Dissatisfaction. Hunger. The recognition that I'd been numbing myself rather than confronting the thinness of what I'd inherited.
The Burden of Proof
I'm not arguing "never rewrite anything." That's not the lesson.
The lesson is that the burden of proof belongs to the ones who subtract. If you don't know why something is there, you don't get to remove it yet. The feeling of righteousness about starting fresh is itself a signal to slow down.
When you're in pain, when you're exhausted by the mess you've inherited, you don't want to go slow. You want to resolve the pain. You want to show off how clever you are. You want to innovate.
But history has taught us what happens when you move fast on systems that have accumulated wisdom you don't understand. You hollow them out. You lose things you didn't know were there. And by the time you notice, the cracks are everywhere and nobody remembers what the original structure was supposed to be.
Cut one thing. See what happens. Understand what you're looking at before you start making changes.
I have to watch myself all the time. The humility isn't natural. I'm self-critical almost to a fault, but that's not the same as humble. The instinct to simplify, to clean up, to finally do it right, that instinct is strong. And sometimes it's correct. Legacy code can be genuinely arbitrary. Hand-rolled validation libraries for every project when good packages exist. Technology choices that made sense to one person for reasons they can't articulate.
But the difference between a fence built for a forgotten reason and a fence that was never needed? You figure that out by asking, by understanding, by going slow enough to learn before you delete.
The rewrite always feels righteous.
Measure the cost of what you're deleting in years of lessons learned, not lines of code removed.