The Trap of Incremental Improvement
Rewrites have a terrible reputation in software. Most fail. They drag on, burn teams out, and set product roadmaps back by years. And yet, the biggest achievement in my career so far was exactly that: we abandoned our old codebase and built a new one from scratch. Ten months of work. A huge gamble. And it worked.
The question isn't whether rewrites are inherently good or bad. It's recognizing when the system you have and the business you're building have diverged too far to patch the gap.
Before we decided to rewrite, we spent nearly a year trying the sensible thing: tackle technical debt gradually, improve estimates, ship carefully. We had a full team with multiple developers. We knew the codebase had problems, but incremental improvement is usually the right strategy.
Except it wasn't working. Deadlines kept slipping. Estimates missed constantly. Not because the team was failing, but because the system kept surfacing new problems faster than we could solve old ones. CRON jobs malfunctioned without triggering alerts. Bugs appeared in unexpected places. Stability issues cropped up not from infrastructure, but from poor monitoring and poorly written background processes we'd forgotten existed.
We were working hard. We just weren't getting anywhere.
Most teams stay in this mode too long because it feels responsible. Incremental improvement minimizes risk. Each fix is small and reversible. A rewrite is binary - commit fully or don't do it at all. The psychological safety of "we're making progress" can mask the reality that progress has stalled.
The breaking point for us wasn't a sudden realization. It was circumstances changing. The business pivoted. Our value proposition shifted, and the product needed to reflect that. At the same time, we restructured the team and reduced headcount. What was barely maintainable with the full team became impossible with fewer people.
Looking back, I can distill it into clear signals. When the cost of operating and maintaining the system becomes inappropriate to what it delivers. When the system keeps failing and leaking despite constant patching. When deadlines slip and estimates are unreliable not occasionally, but consistently. When all three of these align, the system isn't just struggling - it's fundamentally misaligned with what the business needs it to do.
For us, the old codebase was built for a different product serving a different value proposition. We could've hacked it to fit the new direction. But every estimate for those hacks kept growing. At some point the question became: are we solving the problem, or just postponing it?
What made our rewrite work was that business and engineering were aligned on the destination. The business wanted to change direction, and the product couldn't support that change. Both sides saw the same problem. This is where most rewrites fail. Engineers push for a rewrite because the code is messy, but the business doesn't have a clear direction. That invites scope creep. Or the business expects it to be simple and fast while engineering knows it will take years. Misalignment on timeline or outcome kills the project before it starts.
We had clarity. The business pivot defined what we needed to build. The technical constraints defined what we couldn't carry forward. And we had a hard deadline: ten months. Either we shipped in that window or we didn't. We couldn't afford an eighteen-month rewrite. The constraint forced discipline.
Part of what made our rewrite successful was what we left behind. With the pivot, our value proposition changed. Features that only a small fraction of customers used? Gone. Low-income segments that drained more effort than they returned? Cut. Parts of the product where the cost of rewriting would never justify itself financially? We left them in the old system.
Not everything deserves to be saved. Old systems collect features over time that nobody really uses anymore, but teams keep maintaining them just because they're there. A rewrite forces the question: what actually serves the business we're trying to build?
The mindset shift isn't about being ruthless. It's about recognizing that everything carried forward has a price. Time to rewrite it. Complexity to maintain it. Cognitive load to remember it exists. Sometimes the cost of keeping something is higher than the cost of letting it go.
Technical execution mattered too. Before we wrote a line of code, we discussed frameworks, libraries, and design patterns. That gave us a clear vision for how the new system should be structured. Not "we'll figure it out as we go," but "here's the architecture we're building toward."
Migration was pragmatic. We ran the old and new systems side by side for a few months and moved clients in phases. We didn't build fancy automated migration tooling - we didn't have time. A semi-manual process gave us breathing room to onboard carefully and respond to feedback. Running two systems at once creates operational complexity. We had to prepare the legacy system carefully - close registrations, disable certain actions, communicate clearly to users. If you're not deliberate, you end up in a loop where neither system is fully in control. But the pilot approach let us validate the new system with real customers before committing fully.
Rewrites aren't about chasing perfection or satisfying engineers who want clean code. They're about aligning technology with the business it serves. When the gap between what the system was built for and what the business needs it to do becomes too wide, no amount of patching bridges it.
If you see one of the signals - cost, reliability, or delivery problems - it's worth evaluating. If two or three line up, you're probably past the point where incremental fixes make sense. And if the business direction has changed in a way the product can't support, the decision becomes clear.
The hard part isn't recognizing the signals. It's committing to the uncertainty. A rewrite is a long bet with no partial credit. But when business and engineering align on the destination, when you're disciplined about what to carry forward, and when you set hard constraints on scope and timeline, it stops being a gamble and starts being the only way forward.
Want more insights like this? I write monthly about leadership, building software, and lessons from the trenches. Subscribe to get new articles straight to your inbox.