When a developer wants to rewrite a working system, the honest answer is usually no — not yet. A rewrite discards years of hard-won bug fixes and edge-case handling for new code that has neither. Before you approve one, demand evidence that an incremental fix cannot solve the problem.
Key Takeaways
- Rewrites fail more often than they succeed because they throw away production-tested behaviour.
- The developer's frustration is real, but frustration is not a technical justification for a rewrite.
- An incremental refactor or the strangler fig pattern usually delivers value sooner at lower risk.
- Demand a written problem statement: what specifically breaks, how often, and what it costs the business.
- Set a measurable success criterion before any rewrite starts; without one, scope creeps.
- Keep the old system running in parallel until the new one passes the same tests under real traffic.
- Our team can help you audit the code and decide whether a rewrite is actually warranted.
Why does a developer want to rewrite a working system?
A developer wants to rewrite when the codebase feels hostile: tangled dependencies, no tests, outdated frameworks, and every change breaks something unexpected. The frustration is genuine, but it usually measures the developer's comfort, not the system's value. Production systems accrete fixes for real-world edge cases that a fresh codebase will not have.
The urge often comes from unfamiliarity. A new developer inherits code written by people who have left, with no tests and a framework two major versions behind. Every small task takes a day because the code fights back. The developer concludes the code is wrong. In practice, the code is just undocumented. The fix for that is documentation, tests around the scary parts, and time — not a rewrite.
There is an old engineering rule called Chesterton's fence: do not remove a fence until you know why it was put there. The same applies to code. That strange conditional in the checkout flow exists because a specific payment gateway returned a malformed response in 2019. A rewrite will not know that until the same bug ships again.
When is a rewrite actually justified?
A rewrite earns its cost when the existing stack blocks a business need that refactoring cannot unblock — for example, a language runtime out of support, a data model that cannot scale, or licensing that bars a required integration. Justify it with a specific, dated blocker, not a general feeling that the code is old.
The clearest cases are end-of-life runtimes and unsupported dependencies. If the framework no longer receives security patches, every week of delay is a growing risk. If the database cannot handle the transaction volume the business now has, no amount of refactoring fixes the storage engine. If the language is so obscure that hiring is impossible, the system becomes a staffing liability.
Each of these has a measurable consequence: a CVE that cannot be patched, a queue that backs up daily, a role open for six months. If the developer cannot name the blocker and its consequence, the rewrite is a preference, not a requirement.
When should you say no to a rewrite?
Say no when the system still earns revenue, the bugs are ordinary, and the developer's main complaint is that the code is messy. Messy code that works is an asset; it encodes years of customer behaviour. The safer move is a bounded refactor of the specific modules that cause the most pain.
A common mistake we see is approving a rewrite because the current system is embarrassing in a demo. Embarrassment is not a production failure. If the site converts, invoices go out, and reports run, the system is doing its job. The comparison to make is not "old code versus new code" but "what breaks today versus what a rewrite would break tomorrow."
This is the same judgement call as choosing between custom software and an off-the-shelf product: the existing system has switching costs you only discover after you leave it.
How does an incremental refactor compare to a rewrite?
An incremental refactor changes one module at a time while the system keeps serving traffic, so every change ships to production independently and can be rolled back. A rewrite replaces the whole system at once, which concentrates risk into a single cutover. The strangler fig pattern formalises the incremental path: new code takes over routes one by one.
The strangler fig works like its namesake plant. You build a new service beside the old one, route a small slice of traffic to it, and gradually move endpoints across. If the new checkout service fails, you route back to the old one in minutes. There is no big-bang switchover, no weekend of white-knuckle deployment, and no single point of total failure.
A rewrite, by contrast, has one cutover. Every untested integration, every forgotten edge case, every data migration bug surfaces at the same moment. The blast radius is the entire business. That is why a refactor almost always wins on operational risk, even when it takes longer in calendar months.
What does a rewrite actually cost in production?
A rewrite costs the original build again, plus the interest on everything learned since. You pay engineer time to rediscover edge cases, write migrations, run two systems in parallel, and retrain users on a new interface. Vendor costs are secondary; the dominant expense is senior engineer time over months, not a one-off fee.
The cost drivers are team size, data complexity, and integration surface. A system with three external payment providers, a custom reporting layer, and a ten-year-old database costs far more to rewrite than a simple CRUD app. Every integration must be rebuilt and re-tested against a live third party. Every report must match the old numbers exactly, or someone in finance will notice.
There is also an opportunity cost. While the team rewrites, it is not shipping features. A competitor that keeps improving its working system will pass you. That hidden cost is often larger than the engineering bill.
What are the common failure modes of a rewrite?
The classic failure is the second-system effect: the new version tries to fix every historical complaint, doubles in scope, and never ships. Other common failures include data migration bugs, missing parity with old reports, and losing the old system's operators before cutover. Watch for scope creep in the first month.
When a rewrite stalls, check scope first. Count the features that have been added to the plan since it started. If the number is growing, the project is not a rewrite any more — it is a product redesign with no deadline. Then check test parity: does the new system have tests for every bug the old one fixed over the years? If not, those bugs will return.
Data migration is the next place to look. A dry-run migration against a copy of production data usually reveals encoding issues, missing nulls, and orphaned records that nobody documented. Run it early, not the week before cutover. This is the same failure pattern you see when a developer stops responding mid-project: the riskiest work gets left until last.
How do you evaluate a rewrite proposal step by step?
Treat a rewrite proposal like any other large spend: require a written case, a bounded experiment, and a definition of done. The steps below force the developer to prove the rewrite is necessary, not just desirable, and they give you a paper trail if the project later slips.
- Ask for a written problem statement. List the top three failures, how often each occurs, and what each costs the business in lost time or revenue.
- Ask what a refactor of just those three areas would cost and block. If the answer is "less than the rewrite," the decision is made.
- Demand a definition of done. Which metrics must match or beat the old system — error rate, page load time, report accuracy, data completeness?
- Run a spike. Rewrite one small module end-to-end, including its data migration, and ship it behind a feature flag.
- Review the spike. How long did it take? What surprised the team? Multiply that by the number of modules remaining.
- Decide in writing. Record why the chosen path wins. If the project later goes wrong, the reasoning is there to revisit.
How do you verify the new system is safe to cut over?
Run the new system in parallel with the old one and compare their outputs before routing real traffic. Replay a day of production requests, diff the reports, and check row counts in every migrated table. Only when the numbers match and the error rate is no worse should you consider cutover.
Verification is not a demo. A demo shows the happy path. Verification replays the unhappy paths: failed payments, duplicate submissions, users with special characters in their names, customers who have been on the system since 2014. These are the cases the old code handles and the new code has never seen.
Keep the old system running read-only for at least one full billing cycle after cutover. If a user disputes an invoice or a report does not tie out, the old system is your reference. Decommission it only when nobody has needed it for a month.
Rewrite, refactor, or strangle: which fits?
The choice between a full rewrite, an incremental refactor, and a strangler fig migration depends on how much risk you can carry and how urgently the business needs the change. The table below maps each approach to its trade-offs; the diagram that follows shows the same mapping visually.
| Approach | Risk | Time to value | When it fits |
|---|---|---|---|
| Full rewrite | High — single cutover | Months to years | Runtime unsupported, data model cannot scale |
| Incremental refactor | Low — per-module rollback | Weeks | Messy code, ordinary bugs, working system |
| Strangler fig | Medium — gradual takeover | Weeks per route | Legacy system with a few painful modules |
| Leave it alone | None | Immediate | System earns revenue, complaints are cosmetic |
A realistic scenario: the e-commerce site that wanted a rewrite
Imagine a Nepali e-commerce site on an older PHP framework, with a custom reporting layer and a payment integration that has been patched twice. The new developer wants to rewrite it in a modern framework. The business owner asks our team to look before approving.
We audit the code and find the real pain is slow report generation and a brittle checkout that fails on one specific bank's redirect. The rest of the system is stable. Instead of a rewrite, we recommend a strangler fig approach: rebuild the checkout module first, route a small share of traffic to it, and keep the reports on the old stack until the checkout is proven. Three months later the checkout is faster, the failing bank works, and no full rewrite was needed.
That is the pattern we have applied on projects like Business Nepal: replace the part that hurts, keep the part that works, and let evidence drive the scope.
What mistakes do teams make when a developer wants to rewrite?
Most rewrite failures share the same root causes: approving without a problem statement, underestimating data migration, and letting the rewrite absorb new features. Each of these is avoidable if you catch it in the first month.
- Approving on frustration. The developer hates the code, so the rewrite becomes therapy rather than engineering.
- Adding features mid-flight. The new system must also support the roadmap, so scope doubles and the deadline dies.
- Ignoring the operators. The people who run the old system hold knowledge the new code does not capture.
- No rollback plan. If the cutover fails, there is no way back to the old system without days of downtime.
- Skipping the data dry-run. The migration is tested on a tiny sample, then fails on real production volume.
This is the same dynamic as changing developers mid-project: the incoming person wants to redo everything because the existing work is not theirs. The right response is a bounded review, not a blank cheque.
What security risks does a rewrite introduce?
A rewrite replaces audited, battle-tested code with new code that has never been attacked. The new system must re-implement authentication, authorisation, input validation, and data access controls from scratch — and every one of those is a place where a subtle flaw can leak customer data.
Pay particular attention to auth parity. If the old system has role-based access control with a dozen roles, the new system must reproduce every check exactly. A single missing check means a user can read another user's order. Hardcoded secrets in the new codebase are another common slip: developers rush and leave API keys in the repository.
While the two systems run in parallel, keep the old one patched and monitored. It is still serving traffic and still a target. Treat the new code as less trusted than the old until it has passed the same penetration tests and code review the old one survived.
In short
A developer wants to rewrite for understandable reasons, but the safer answer is usually a bounded refactor or a strangler fig migration. Demand a written problem statement, a definition of done, and a data dry-run before you approve anything. Keep the old system running until the new one proves itself under real traffic. The code you already have is worth more than the code you might get.
People also search for
- Custom software versus off-the-shelf: which costs less in the long run
- What happens when you change web developers mid-project
- What to do when a developer stops responding
- Why web development quotes vary so much
- Questions to ask a web developer before you hire them
- When a static site is the right call for your business
If your developer wants to rewrite and you are not sure the case holds up, contact our team. We will audit the existing system, separate real blockers from frustration, and recommend the lowest-risk path — whether that is a bounded refactor, a strangler fig migration, or a rewrite with a clear definition of done. Our software development service exists for exactly this kind of judgement call.












0 comments
Be the first to share your thoughts.
Leave a comment
Replying to — cancel