Why Rewrites Fail and Ugly Code Survives

Messiest parts of your codebase are usually the ones holding your entire business together. Rewriting them might be the fastest path to losing customers.

Why Rewrites Fail and Ugly Code Survives

There’s a meeting every engineering leader eventually has. It usually happens a few months after you join a team.

One of your senior engineers walks in looking tired. They open their laptop and show you a diagram of the system. It’s never a simple diagram. It looks like someone spilled noodles on the screen. They point to the billing module.

“We can’t keep working like this,” they say. “This thing is a ball of mud. The libraries are ancient. Every bug we fix breaks something else. We should just rewrite it.”

If you’ve written code before, you understand the feeling. Developers always imagine that if they could just throw everything away and start over, the result would be something clean and elegant. Everything would be organized correctly. There would be no mysterious functions or odd naming decisions. Life would be better.

But as a leader, you end up giving the answer nobody likes.

“No. We’re not rewriting it.”

This isn’t because anybody enjoys working with old code. It’s because that messy, unpleasant code is usually the most valuable thing the company owns. It works. Customers rely on it. And it has solved more real problems than you remember.

Here’s why the ugly version matters so much.

The ugliness is just a record of the business

When people talk about “legacy code,” they usually mean “code I didn’t write.” It never looks good. You find nested conditionals that go on forever. You find fields in the database that don’t match anything. You find comments that make no sense.

If you’ve been around long enough, you start to see something different. The ugliness isn’t random. It’s a collection of decisions the team made to handle every strange edge case a paying customer ever ran into.

That odd block of code in the login service? It handles a race condition that only happens for your biggest enterprise client. The strange workaround in the database layer? It’s there because a payment aggregator behaves differently when their servers are under load.

The mess is just history written down in code form. When you delete it, you’re not cleaning. You’re erasing years of learning. And unfortunately, the learning is the expensive part.

Netscape already proved this the hard way

Joel Spolsky wrote about Netscape’s rewrite twenty-something years ago, and the lesson hasn’t changed. Netscape had a browser that worked. It wasn’t pretty inside, but it ran. Then they decided the whole thing was too messy and paused development to rewrite it.

It took them years. That was all Microsoft needed.

While Netscape rewrote everything from scratch, Internet Explorer just kept shipping updates. They kept fixing bugs and adding features. By the time Netscape was ready with their beautiful new version, it didn’t matter. Their users were gone.

The point is simple: if you stop shipping, somebody else won’t.

The green-field plan sounds good until reality shows up

There’s a belief that rewrites are faster because “we already know the requirements.” This sounds reasonable as long as you don’t think about how the existing system got its current shape.

A lot of the important logic isn’t written down anywhere. Nobody remembers why a specific line of code is there. Nobody remembers which customer needed which behavior. All of that knowledge is baked into the mess.

When you rewrite, you recreate the original system without the years of fixes. You get the clean architecture. You just don’t get the correctness.

Companies end up with two systems:
- the old one that works
- the new one that looks good but doesn’t

You split the team, increase costs, and get stuck maintaining both. The rewrite becomes its own legacy system before it even launches.

It’s cheaper to refactor than replace

Of course the answer isn’t “do nothing.” Systems get worse if you ignore them. But the right approach is almost always incremental. A bit at a time.

The Strangler Fig Pattern works because it doesn’t pretend you can replace the whole system at once. You pick one domain. Maybe invoicing. You build the new service just for that small area. You send a tiny amount of traffic to it. You fix what breaks. Then you slowly expand.

It takes patience. It’s less exciting than a rewrite. But it means the business keeps running while the system improves. You don’t stop shipping. You don’t lose customers. And you never have two full systems to maintain.

This is the boring approach. It’s also the one that works.

We did something similar in a fantasy sports product I worked on. It started as one big monolith that handled everything: logs, payments, prize distribution, cron-based reporting, and score delivery. As traffic grew, especially during big tournaments, the weak spots became obvious. Instead of rewriting the whole thing, we pulled out services one by one. Logs went first. Then payments. Then prize distribution. Then the cron jobs that generated reports. Finally, the score delivery flow.

This took about six months. During that time, an IPL season and a World Cup went by. We were careful on match days, but we never froze development. Features kept shipping. The system kept running. And by the end of it, the monolith was smaller, the architecture was cleaner, and the business never had to wait for a grand relaunch that might never have arrived.

The bottom line

Developers don’t dislike legacy code because it’s bad. They dislike it because it’s not shaped the way they would have shaped it. The business doesn’t care about shape. It cares that the software does what customers expect.

That huge, tangled file that frustrates everyone isn’t a mistake. It’s a collection of solved problems. It survived production traffic. It survived customer complaints. It survived everything the real world threw at it.

A rewrite throws all of that away in exchange for a blank page.

You’re better off improving the system you have, one piece at a time.

Subscribe to Sahil's Playbook

Join Sahil Kapoor’s inner circle. Get instant access to every premium issue.
[email protected]
Subscribe
Mastodon