Blexor Technologies

Insights

Why a rewrite is usually the most expensive option

7 min readModernization, Legacy applications, Architecture

Every legacy modernization conversation starts in the same place. The application is ten or fifteen years old, it is expensive to change, nobody enjoys working on it, and someone has already drawn the box on a slide that says rebuild.

It is an appealing answer, because it is the only one that promises to make the problem go away completely. It is also, in most cases, the most expensive path available — not because rewrites are technically hard, but because of what a rewrite does to the shape of the work.

A rewrite postpones all of its value

An incremental modernization delivers value continuously. The runtime gets upgraded and the security exposure drops. The build gets automated and every subsequent change gets cheaper. A data store gets consolidated and two licences get cancelled. Each of those is independently useful, and each one is finished.

A rewrite delivers nothing until it is finished, and then delivers everything at once. That has two consequences that are usually underweighted at the point the decision is made.

The first is that the entire investment sits at risk for the whole duration. A modernization programme that is cancelled at month eight still leaves you with eight months of improvements. A rewrite cancelled at month eight leaves you with a branch.

The second is subtler and more damaging: while the rewrite is in progress, the original system still has to be maintained. So you are now paying for two systems, and every change to the business has to be made twice — once in the system that is running and once in the system that is being built. Teams routinely plan for the cost of the new build and forget the cost of the duplicated change.

The requirements you cannot see

The strongest argument for a rewrite is that the old system's behaviour is poorly understood, so it should be replaced with something well understood.

This is exactly backwards. A fifteen-year-old application that runs the business contains fifteen years of accumulated decisions, and only some of them are in the documentation. The rest are in the code: the edge case that a specific customer depends on, the rounding rule that reconciles with a partner's system, the retry that exists because an upstream service used to fail at month end.

None of that is visible in a specification, because nobody wrote a specification for it. It surfaces during the rewrite, one incident at a time, after go-live. This is the single most common reason rewrites overrun: not the work that was estimated, but the work that was invisible until the replacement was in production.

Incremental modernization does not solve the unknown-behaviour problem either — but it encounters it in small pieces, with the original still running beside the change as a reference.

What incremental actually looks like

"Incremental" is not a euphemism for doing less. The end state is often the same. What changes is the order and the size of the steps.

A typical sequence, roughly in order of return:

  1. Get onto a supported runtime. Unsupported platforms carry security exposure and extended-support licensing, and they block everything downstream. For .NET applications this is usually the highest-value single step available.
  2. Automate the build and the deployment. Until releases are cheap, every other improvement is throttled by the cost of shipping it.
  3. Isolate what is genuinely stuck. There is normally a dependency with no modern equivalent. Put an interface in front of it so it stops blocking the rest of the migration, rather than letting it set the pace for everything.
  4. Attack the expensive parts of the architecture. By this point you know which ones they are, because you have been working in the system rather than replacing it.
  5. Consolidate data. Usually the largest licensing and operational saving, and almost always the change with the most operational risk, which is why it comes late.

Note that the application is deployable at every point. There is no long-lived branch and no single cut-over that has to succeed first time.

When a rewrite is the right answer

Sometimes it is, and pretending otherwise is its own kind of dishonesty.

A rewrite is the right call when the existing system cannot express what the business now needs — not when it is merely awkward, but when the core model is wrong. If a system was built for one country and the business is now in twelve, or built for a product catalogue and the business now sells subscriptions, incremental change has nothing to converge on.

It is also right when the platform is genuinely at the end of its life: no supported runtime, no available skills, no viable hosting. At that point the choice is not between rewrite and modernization, it is between rewrite and continuing to operate a system that cannot be operated safely.

The distinction worth holding onto is that a rewrite is a strategic decision about the model, not a tactical response to maintenance cost. If the reason for the rewrite is that the application is expensive to maintain, that reason usually has a cheaper answer.

The question to ask first

Before choosing between the options, it is worth establishing where the maintenance cost actually comes from. In our experience it is rarely distributed evenly. It concentrates in a handful of places: an unsupported runtime, a manual release process, one module everything depends on, a data model that requires every change to touch three systems.

That analysis takes weeks, not months. It frequently shows that a small number of targeted changes remove most of the cost — and it tells you which parts of a rewrite would have been solving a problem you did not have.

Let’s Build a More Intelligent, Efficient Technology Environment

Have a Technology Challenge?

Let's find a smarter way forward.