← Back to blog
architectureengineeringmigrationtechnical decisions

The copy nobody tested is not a backup

2026-08-25

The copy nobody tested is not a backup

Every time a team swaps the foundation of something, the same proposal shows up. New database, new provider, rewritten service. The sentence is always roughly the same:

"Let's keep both running for a while, just in case."

Nobody argues. It sounds responsible, it sounds mature, it sounds like what a grown-up would decide. And most of the time it is the wrong call.

Not because redundancy is bad. Deliberate, tested redundancy with a clear rule about which side wins is one of the best tools we have. The problem is that this is almost never what we mean by "just in case." What we mean is: keep the old system running, because nobody trusts the new one yet, and nobody wants to say that out loud.

That is not redundancy. That is indecision with a nicer name.

What "just in case" is actually saying

Translating the sentence is worth doing before discussing costs, because the translation solves half the argument on its own.

When someone proposes keeping both sides alive, what they are saying is: I don't have enough evidence that the new path works. That is valuable information and a completely legitimate feeling. The mistake is not having it. The mistake is answering it with infrastructure instead of answering it with a test.

Lack of confidence is a knowledge problem. You fix knowledge problems with experiments. Leaving the old system running produces no knowledge at all. It just postpones the question and charges rent in the meantime.

Three costs nobody puts in the budget

1. Two sources, no truth

The moment two live copies of the same data exist, someone has to decide which one wins. If that decision isn't written down, versioned, and obvious to whoever shows up later, it will be made by accident.

And it will be made in the worst possible way: six months later, at eleven at night, by someone who wasn't in the room when the migration was planned, staring at two different values and picking the one that looks more reasonable.

The cost here isn't storage. It's the entire class of bug that now exists. Data that diverges quietly doesn't fire alerts, doesn't break builds, and doesn't show up in tests. It shows up in a report months later, when someone asks why two numbers that should match don't.

2. "For a while" never has a date

Notice that the original proposal never comes with a deadline. It's not "both until the 30th." It's "for a while."

With no date, the decision to shut the old side down has to be made actively, by someone, some day, with nothing forcing it. That almost never happens. What was meant as a transition becomes a permanent state through inertia, and the cost disappears because it got spread across several small line items nobody questions individually.

There's a quick test for this. Ask who turns it off, and on what date. If the answer is silence or "we'll see later," you are not running a transition. You are making a permanent addition to the system, and you should budget it that way.

3. The safety net blocks the learning

This is the most expensive cost and the least visible one.

While the old path is up, nobody really exercises the new one. Traffic splits, the weird edge cases keep landing on the familiar side, and the team never finds out where the new path breaks. Worse: when something goes wrong, the natural reaction is to fall back instead of investigating. It's faster, it resolves the incident, and it postpones the learning one more time.

You built a safety net that prevents exactly the fall that would have taught you to walk.

Systems earn reliability by being used under pressure and fixed. A path that never carries the real load will never be trustworthy, no matter how many months it sits there in parallel. Time is not a substitute for exposure.

The question I use

I've reduced this to one question that tends to end the discussion quickly:

Is the new path trustworthy enough to be the only one?

If the answer is no, it isn't ready for production. Running it in production with a crutch doesn't make it more ready. It just spreads the uncertainty across two places.

If the answer is yes, then the old copy isn't insurance. It's debt. And debt needs a due date.

What makes this question useful is that it forces the real conversation. It turns "let's keep both just in case" into "what exactly is missing before we trust this?" The second question has an actionable answer. The first one only has a bill.

The middle ground that actually works

There is a legitimate middle ground, but it isn't running both in production. It's this:

  • Exercise the new path with throwaway data, at real volume, including the ugly cases
    • Force the scenarios that scare you instead of waiting for them
      • Measure the thing that would let you sleep, and pick the number before you look at the result
        • When the doubt is gone, flip everything and shut the old side down

        Notice the difference. In both cases the old system sticks around for a while. But in one of them it's serving real traffic and has quietly become part of the architecture, and in the other it's on its way out with a date on the calendar while you buy confidence through experiments.

        The question that separates them is simple: is this teaching me something, or just letting me delay the decision?

        When keeping both is the right answer

        It would be dishonest to end without this, because there are clear cases where redundancy isn't indecision at all.

        Keeping both sides makes sense when the operation is irreversible and the data can't be rebuilt. Deleting is final; if the source doesn't exist anywhere else and can't be regenerated, caution is actually caution.

        It makes sense when there's an external requirement. Regulatory retention and customer contracts are not subject to your risk assessment.

        And it makes sense when the redundancy is the design, not the doubt. A replica with a defined role, failover tested on purpose, an explicit rule about which side is the source of truth. That's architecture, and the difference shows up in one detail: you can say, without hesitating, which copy wins and what happens when they disagree.

        If you can't answer that off the top of your head, what you have isn't redundancy. It's two similar things running at the same time.


        The summary I'd bring to the next migration meeting: a backup is one thing, architected indecision is another. The first has an owner, a rule, and a test. The second has a monthly bill and a bug waiting six months out.

        How long did your "just in case" last?

        📩 Let's talk