Skip to main content
← All articles
ProductionEngineering

Rewrite or Refactor? How to Decide Honestly

By Evertech Digital5 min read

Every engineering team eventually reaches the meeting where someone says it would be faster to start over. Sometimes they're right. Usually they're not, and the reason is a bias worth naming.

You are comparing a real system, whose flaws you can see in detail, against an imagined system, whose flaws haven't been discovered yet. The existing codebase has a list of known problems. The replacement has none — because it doesn't exist. That's not a fair comparison, and it's why rewrite estimates are so reliably wrong.

Here's a procedure that holds up against that instinct.

What the old system actually contains

A working codebase is not just its features. It's also every bug fix, edge case, and unglamorous conditional that accumulated while real customers used it.

That weird branch handling a specific date format? A customer hit it in production. The retry with the odd back-off? Someone's payment failed at 2am. None of it is documented, most of it looks like cruft, and a rewrite discards all of it and rediscovers it one angry support ticket at a time.

This is the single most underestimated cost. Not writing the features again — writing the invisible corrections again.

Four genuine reasons to rewrite

Rewriting is right when the problem is structural — when no amount of incremental improvement gets you there.

  1. The data model is wrong for what the product became. You built for one location per customer and the business is now multi-location. Every table, query and screen encodes the old assumption. This is the most common legitimate reason.
  2. You can't hire for it. The language or framework has no meaningful talent pool left. This is a business risk, not an aesthetic one.
  3. The platform is a dead end. A vendor discontinued it, licensing changed, or it can't run on supported infrastructure.
  4. The security architecture is unfixable. Not "it has vulnerabilities" — those get patched. This is when the design itself assumes something unsafe, like a single shared trust boundary with no way to introduce tenancy.

Four reasons that feel real and aren't

  1. "It's ugly." Aesthetics are not a business case. Ugly code that works and nobody touches costs nothing.
  2. "It uses an old framework." Old and supported is fine. Old and unsupported is reason 3 above — but check which one you actually have.
  3. "The new team wants to." Understandable, and expensive. Engineers prefer writing to reading. That's a preference, not an argument.
  4. "It's slow." Performance is almost always fixable in place, and far more cheaply. Profile before you conclude the architecture is at fault.

The two-week test

The most useful diagnostic we know, and it takes no analysis:

Pick a real, moderate feature request. Can a competent developer ship it in two weeks without breaking something unrelated?

  • Yes → the system is workable. Your problem is specific debt, not the architecture. Refactor.
  • No, because they can't find where things happen → a knowledge problem. Documentation and tests are cheaper than a rewrite and fix more of it.
  • No, because one change breaks three unrelated things → real structural coupling. Now the conversation is legitimate.

Most teams who are certain they need a rewrite discover they're in the second case. That's the debt with no author problem, and it responds to writing things down.

The third option almost nobody considers

The choice isn't binary. You can strangle the old system instead.

Put a stable interface in front of the existing code, then replace one piece at a time behind it. New work goes into the new structure; old work stays until it's touched. Over months the old system shrinks until whatever remains isn't worth moving.

This is slower per component and dramatically safer overall, because:

  • You never have a period with no shippable product.
  • Each slice is independently verifiable, so a mistake is small.
  • You can stop at any point and still be better off, which a half-finished rewrite cannot claim.
  • The business keeps getting features throughout.

For most teams asking this question, this is the right answer and they haven't considered it.

If you do rewrite, three rules

  1. Keep the old system running and authoritative until each slice is genuinely replaced. No big-bang cutover.
  2. Add no new features during the rewrite. If the target keeps moving you'll never converge, and this is how rewrites become permanent.
  3. Port the odd bits deliberately. Go through the strange conditionals and decide, case by case, whether each is obsolete or load-bearing. Don't discard them wholesale — that's how you reintroduce three years of bugs.

Budget realistically. A rewrite of a system that took a year is not a three-month project, whatever the enthusiasm in the room suggests.

The honest summary

Rewrite when the structure is wrong. Refactor when the code is messy. Strangle when it's somewhere in between, which it usually is.

And be suspicious of the certainty itself — the confidence that a rewrite will be fast comes from not yet knowing what the current system does. That knowledge arrives either way; the only question is whether it arrives during planning or during an outage.

If you'd like a second opinion before committing months to this, that's a conversation we have regularly and often talk clients out of. See how we approach SaaS development, or send us the repo.

Ready to build it? Let's talk about your project.

SaaS & Mobile Apps
Ready to build?

Your next digital product
starts here.

Tell us what you're building. We'll respond within 24 hours with honest advice and a clear path forward.

Start my project →

We use cookies to improve your experience on our website. You can accept or decline non-essential cookies. Privacy Policy