Skip to content
All articles
  • Modernization
  • Legacy Systems
  • Software Architecture
  • Technical Debt

Rewrite or Refactor? How to Modernize a Legacy Application Without Stopping the Business

The full rewrite is the most tempting and most dangerous project in software. Here is how to choose between rewriting, refactoring and replacing, and how to modernize one piece at a time.

Arsalan Sadiq 5 min read
An old building being modernized section by section while it stays in use

It's Thursday afternoon, and someone in the planning meeting says it: "We can't release on Friday. Nobody wants to touch that part of the system."

If you've heard that sentence at your company, you have a legacy system. Not because it's old, but because people are afraid of it.

That fear usually leads to one of two outcomes. Either nothing changes and the system slowly holds the business back, or someone proposes the big rewrite: two years, a new stack, everything fixed at once. I've seen both. The second one tends to hurt more.

An engineer carefully re-routing cables in a server rack, tangled old cables on one side and tidy new ones on the other

Why the big rewrite usually fails

A full rewrite looks clean on a slide. In practice it runs into the same three problems.

The old system keeps changing. The business can't freeze for 18 months. Every new feature has to be built twice, once in the old system and once in the new one, or the new one falls behind before it launches.

The old system knows things nobody wrote down. Years of edge cases, tax rules and customer exceptions live in that code. You rediscover them one production incident at a time.

Nothing ships until everything ships. The business sees cost and no value for a very long time. Support for the project fades long before it's finished.

That doesn't mean a rewrite is never right. It means you need a better reason than "the code is ugly."

Rewrite, refactor or replace?

Use this as a starting point when deciding what to do with each part of the system.

What you're seeingUsually the better move
The code is messy, but the business logic is correctRefactor in place
The platform or framework is end-of-life or no longer secureMigrate piece by piece
A commodity function (billing, CRM, HR) was built in-houseReplace it with an off-the-shelf product
The business has changed so much that the core model is wrongRewrite that part, incrementally
A small app with a small team and well-understood behaviourA full rewrite can be reasonable

Most real systems need a mix. The skill is deciding which part gets which treatment.

The strangler fig approach

The approach I use most is the strangler fig pattern, a name Martin Fowler borrowed from a vine that grows around a tree until it can stand on its own. You build new components alongside the old system, route traffic to them one feature at a time, and retire the old code as it goes quiet.

Diagram of small new services growing around a large old system, with traffic arrows gradually shifting to the new parts

The key is a routing layer in front of everything, so you can move one path at a time and move it back if something breaks.

// A thin routing layer: send migrated paths to the new service and
// everything else to the legacy app. Turning the flag off rolls back.
const migrated = ['/invoices', '/customers/search'];
 
export function targetFor(path: string, flags: { useNewInvoices: boolean }) {
  const isMigrated = migrated.some((prefix) => path.startsWith(prefix));
  if (isMigrated && flags.useNewInvoices) return 'https://new-api.internal';
  return 'https://legacy.internal';
}

In production this usually lives in an API gateway or load balancer rather than in application code, but the idea is the same: small moves, each one reversible.

A five-step modernization plan

Step 1: Map what you actually have

Before touching anything, draw the system as it runs today. What talks to what, where the data lives, which parts change most often, and which parts cause the most incidents. The map usually surprises people, and it becomes the plan.

Step 2: Add a safety net

Legacy code rarely has good tests, and you don't need to fix that everywhere. Write characterization tests around the area you're about to change: tests that capture what the system does today, right or wrong, so you notice when behaviour shifts.

Step 3: Choose the first slice carefully

Pick something with real business value, clear boundaries and moderate risk. Not the scariest module, and not something so small nobody notices. The first slice proves the approach to everyone watching.

Step 4: Move it, run both, compare

Send a small share of traffic to the new component and compare its results with the old one. Increase gradually. Keep the rollback path open until you've gone a few weeks without surprises.

Step 5: Delete the old code

This is the step teams skip. If the old code stays "just in case," you're now maintaining two systems. Set a date, remove it, and celebrate it. Deleting code is progress.

How to know it's working

Modernization projects drift when nobody measures them. These are the numbers I'd put in front of leadership every month.

MetricWhat it tells you
Deployment frequencyWhether the team can ship safely and often
Lead time for changesHow long an idea takes to reach customers
Change failure rateWhether releases are getting safer
Time to restore serviceHow painful incidents are
Share of traffic on new componentsVisible progress the business can follow

The first four are the DORA metrics. They're widely used because they connect engineering work to outcomes a CFO cares about.

A laptop on a tidy desk showing a dashboard with rising charts in teal

Where to start on Monday

You don't need a two-year program to begin. Start with three things:

  1. Ask your team which part of the system they're most afraid to change, and why.
  2. Map that area and everything it depends on, on a single page.
  3. Write the tests that would let you change it safely.

That alone often turns "we can't touch it" into "we can touch it carefully." From there, every step is smaller than it looked.

If you're weighing a rewrite right now, a second opinion before you commit is cheap insurance. Get in touch and tell me what you're working with.

Views here are my own and don't represent any current or past employer or client. This is general information, not professional advice for your situation. Full disclaimer

Working on something similar?

I help businesses and founders design and build software like this. Book a free call or send a few details about your project.

Related articles