← Back to articles

Rewrite or Repair: How I Decided to Start Over

Rewriting everything is almost always a bad idea. Here are the criteria that led me to do it anyway, and the method for not losing the product along the way.

The decision everyone advises against

Few rules are as widely shared in our trade:

You never rewrite software from scratch.

I repeat it to my own clients.

Existing code holds years of fixes, edge cases and forgotten decisions. Throwing it away means agreeing to rediscover each of them, one by one, in production.

And yet this year I decided to rewrite a platform I operate.

This article explains why, and above all how.


Why rewriting is almost always a mistake

The rule deserves to be taken seriously first.

A rewrite usually fails for three reasons:

  • you underestimate what exists: the old system does far more than anyone remembers;
  • you freeze the product: for months, users get nothing new;
  • you aim for a single cut-over: one big night when everything must work at once.

Most of the time the real motive is less respectable: other people’s code is painful to read, and your own, not yet written, always looks cleaner.

That is not a reason.


The questions I ask first

Before considering a rewrite, I try to answer four questions honestly.

1. Is the problem in the code or in the model?

Badly written code can be repaired piece by piece. A data model or a structure that no longer matches the product, much less so.

2. Do fixes propagate?

If every fix breaks another, the cost of repair is no longer linear.

3. Can you still ship?

When the build and deployment chain has itself become a risk, every change is paid for twice.

4. Can you describe precisely what the system must do?

This is the decisive question. Without a clear specification, a rewrite only produces a second vague system.

My answers, for Metalearn

The problem was indeed in the model, not in the code.

  • The architecture did not separate the backend clearly enough from the API dedicated to Workadventure.
  • Every change therefore had to stay compatible with that API, even when it only concerned billing, for example.
  • It had become almost impossible to add a feature independent of the others.

What tipped me over

The consequence of all this fits in one sentence: adding a new feature had become a technical question before being a practical one.

That is the opposite of how I see agility. Adding a feature should be the answer to a need, not to its feasibility.

When you start discarding useful ideas because the system would not support them, the product is no longer deciding. Its legacy is.

Even so, the decision was not made on a feeling.

It was made the day I could write down in black and white what the new system had to do, and see that the old one could not get there in steps.


Describe the system, not its bugs

A classic mistake is to specify the new version in opposition to the old one:

Like before, but without problem X.

That wording imports every design flaw of the old system, along with its habits.

I chose to describe what the platform must do as if the old one did not exist: the actors, the rules, the limits, the error cases.

The bug history then serves as a checklist. Not as a plan.


Cutting over without a big night

This is what separates a rewrite that lands from one that bogs down.

I did not try to replace the old system in one go.

The first step was, logically, to rewrite the API. With three requirements:

  • answer the calls of the previous version, so that what exists keeps working unchanged;
  • prepare the next version, without waiting for it to be finished;
  • become fully independent of the associated services, and centralise the data.

Old and new can therefore coexist. The cut-over happens piece by piece, and every step stays reversible.

The principles I hold myself to:

  • develop and validate in a separate environment, never directly in production;
  • promote to production only what has been validated;
  • keep the old system in working order until the final switch.

What I would do again, what I would avoid

What I would do again: write the specification.

When updates become time-consuming, when the question behind a feature is essentially technical, and above all when legacy takes over from novelty, writing the specification of a new version is not a waste of time.

Even if you finally decide not to rewrite, the result can surprise you.

What I would do differently: spend more time on it.

I would take more time to compare that new vision with what exists, point by point, before choosing the best path.


Conclusion

The rule still holds: in most cases, you should repair.

But a rule is not a decision. Sometimes a system was designed for a product that no longer exists, and every repair prolongs a misunderstanding.

In that case, the useful question is not:

“Can we rewrite everything?”

But rather:

“Can we describe what we want, and can we get there without ever switching off what exists?”

If the answer to both is yes, the rewrite stops being a bet. It becomes a project like any other.

A similar project?

Let's talk