Related: How to Add Payments to Your App Without Regretting It Later
Every developer who inherits a codebase wants to rewrite it. That instinct is usually wrong, and expensive when acted on.
This is how to tell a genuine case from frustration.
Why rewrites go badly
The pattern is consistent.
- The old system knows things nobody wrote down. Years of small fixes for real situations. That odd conditional exists because a customer hit something in 2021. Rewrite from the specification and you reintroduce every bug that was already found and fixed.
- Estimates are made against the tidy version. People estimate the system as they imagine it, not the one with the four integrations, the reporting exports and the batch job nobody mentioned.
- The business does not stop. While you rewrite, the old system still needs fixes and new features. Now you maintain two systems and write everything twice.
- Nothing ships for a long time. Twelve months with no delivered value is hard to sustain politically. Rewrites often get cancelled at month nine, leaving you with the old system and a large bill.
Reasons that do not justify a rewrite
- "The code is messy." Messy code can be cleaned up incrementally while it keeps earning.
- "It uses an old framework." Old is not the same as unsupported. Check whether it still gets security updates.
- "Nobody here likes working on it." Real, and a morale problem worth solving. Not a rewrite.
- "We would do it differently now." You always would. That is true of whatever you build next, too.
- "It has no tests." Add tests. That is a smaller project than a rewrite and reduces risk immediately.
Reasons that do justify one
These are concrete and checkable.
- The platform is no longer supported and no longer receives security patches. This is a real deadline, not a preference.
- You cannot hire for it. If the language or framework has effectively no available developers, the risk is now a staffing risk.
- A required capability is genuinely impossible within the current architecture. Not difficult. Impossible. Be strict about this word.
- It cannot meet a hard compliance requirement and cannot be retrofitted to.
- Running cost exceeds the rebuild cost over a reasonable period, with the numbers written down.
Notice all of these are specific and verifiable. If your reason cannot be stated that plainly, it is probably frustration.
Replace piece by piece instead
The safest approach is incremental replacement, sometimes called the strangler pattern. New functionality grows around the old system until the old system has nothing left to do.
How it goes:
- Put a layer in front. A proxy or router that sends every request to the old system to begin with.
- Pick the most valuable piece. Highest pain, clearest boundary. Not the easiest, and not the biggest.
- Build that piece new behind the same interface.
- Route a little traffic to it. Compare results against the old path before committing.
- Move traffic over, then delete the old code for that piece. Actually delete it. Dead code left behind is a future trap.
- Repeat with the next piece.
What this buys you:
- Working software the whole time
- Value delivered every few weeks, not at the end
- Small reversible steps instead of one large irreversible one
- The option to stop halfway and still be better off
That last point matters most. A rewrite abandoned at sixty percent is a write off. An incremental replacement abandoned at sixty percent means sixty percent of the system is modern and everything still works.
Refactoring that actually helps
If you are staying and improving, order matters. Do this first:
- Get it into version control properly if it is not already, with a branch and release process people follow.
- Make deployment repeatable. One command or one merge. Everything else is harder while shipping is scary.
- Add tests around what you are about to change. Not everywhere at once. Around the part you are touching, so you can change it safely.
- Add error tracking. You cannot fix what you cannot see.
- Then start improving the code, one bounded area at a time, while it keeps serving users.
Teams often try to start at step five. It rarely holds, because without the first four every change is risky and progress gets rolled back.
Before deciding either way
Write down honest answers:
- What exactly is the blocker? One sentence, specific.
- What does it cost us per month right now, in money or hours?
- What breaks if we change nothing for a year?
- Who understands the current system, and are they still here?
- What undocumented behaviour exists, and how would we find it?
- Can we deliver anything useful in the first six weeks of the plan?
If you cannot answer the last one with a yes, the plan needs reshaping before it starts.
We are regularly asked to rewrite systems and often recommend against it. If you want a straight assessment of what you have, tell us about it. We read the code first and say honestly what shape it is in.
Comments