Skip to content

Why your developer wants to rewrite, and when to say no

  • Home
  • Blog
  • Why your developer wants to rewrite, and when to say no
Why your developer wants to rewrite, and when to say no

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.
How to evaluate a rewrite request before saying yes or noFour ordered stages from auditing the existing system to deciding with evidence.How to evaluate a rewrite request1Audit theexisting system2Pin down thereal pain3Try a smallrefactor first4Decide withevidence
The sequence to follow before approving a rewrite: audit what exists, isolate the real pain, test a bounded fix, then decide on evidence rather than frustration.

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.

Big-bang rewrite versus incremental refactor timelineTwo horizontal timelines: a single high-risk cutover for a rewrite, and frequent low-risk releases for a refactor.Risk over time: rewrite vs refactorBig-bang rewriteCutoverMonths of hidden work, one risky switchIncremental refactorShip module 1Ship module 2Ship module 3Ship module 4
The same system modernisation viewed as risk over time: a big-bang rewrite concentrates all risk into one cutover, while an incremental refactor spreads it across many small, reversible releases.

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.

  1. 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.
  2. 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.
  3. Demand a definition of done. Which metrics must match or beat the old system — error rate, page load time, report accuracy, data completeness?
  4. Run a spike. Rewrite one small module end-to-end, including its data migration, and ship it behind a feature flag.
  5. Review the spike. How long did it take? What surprised the team? Multiply that by the number of modules remaining.
  6. 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.

ApproachRiskTime to valueWhen it fits
Full rewriteHigh — single cutoverMonths to yearsRuntime unsupported, data model cannot scale
Incremental refactorLow — per-module rollbackWeeksMessy code, ordinary bugs, working system
Strangler figMedium — gradual takeoverWeeks per routeLegacy system with a few painful modules
Leave it aloneNoneImmediateSystem earns revenue, complaints are cosmetic
Which approach fits which rewrite situationRows mapping each approach to the situation where it is the right call.Which approach fits your situationFull rewriteOnly when a dated blocker makes the old stack unsupportableRefactorThe default when the system works and the bugs are ordinaryStrangler figWhen a few modules cause most of the pain and need replacing firstLeave itWhen the complaints are cosmetic and the revenue keeps arriving
How the common approaches to a legacy system map to the risk you can carry and the urgency of the business need.

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

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.

Frequently asked questions

  • Unfamiliar code reads worse than it is. Without automated tests, every small change risks breaking undocumented behaviour, so a rewrite can look cheaper than it really is. The developer is optimising for a clean mental model, not for business continuity. Ask for a behaviour inventory before accepting the comparison.

  • A refactor changes internal structure without changing observable behaviour, usually under a regression test suite. A rewrite replaces the system, often with a new language or framework. Refactoring can be done incrementally and shipped continuously; a rewrite usually freezes features until the replacement reaches parity. That freeze is the expensive part.

  • A rewrite makes sense when the runtime or framework is end-of-life with active CVEs, or when the data model and architecture cannot meet a hard scaling or compliance requirement. Even then, justify it with evidence: measure current error rate and p99 latency, and document that targeted fixes cannot close the gap.

  • You lose the undocumented business rules currently encoded in the old system, because nobody wrote them down. The rewrite team then recreates bugs you already fixed and adds new ones. You also pay parallel maintenance costs while the old system still serves traffic. Most rewrites take longer than the original estimate.

  • Ask for an inventory of every user-visible flow, API endpoint, background job and report, with its current error rate. Break effort into those items, not one line. Require a parity test plan before accepting an estimate. Our team can review that inventory via /contact; cloud and tooling costs change, so check the vendor's current calculator.

  • Ask what user-visible problem a refactor cannot solve, which hidden business rules the developer has listed, how parity will be measured, and what the rollback path is. Require the answer as a written feature inventory with automated tests. If the developer cannot name the current failure, you are approving a preference, not a plan.

  • Yes. The strangler fig pattern runs the new system behind the same DNS or proxy and routes individual endpoints to it, retiring old routes only after traffic confirms parity. Use percentage-based canary routing and compare error rates. This keeps the old system as a fallback and avoids a big-bang cutover.

  • Send shadow traffic through the new path without affecting users, then diff responses, error codes and database writes against the old. Compare p99 latency and error budget with the production baseline. After that, shift 5 percent of real traffic via canary and watch the same metrics for a full business cycle.

  • From The Mythical Man-Month: the second system an engineer designs tends to include every feature deferred from the first, so it becomes over-engineered and late. Control it by freezing scope to the current system's observable behaviour first, and treating every extra feature as a separate project with its own approval.

  • Add characterisation tests around the existing behaviour, then refactor the hot paths that actually cost you. Extract individual modules or services behind the existing interface, or use the strangler fig pattern for the parts that must change. This preserves undocumented rules and lets you ship improvements continuously.

0 comments

Be the first to share your thoughts.

Leave a comment

Chat on WhatsApp