The Transition Is Part of the Architecture

How to design safer system migrations with small boundaries, routing logic, transformation pipelines, production evidence, and removable temporary code.

Most architecture diagrams show two systems:

  • today's system
  • tomorrow's system

What they rarely show is the six months in between.

That missing period is where most migration risk lives.

The biggest lesson I've learned from modernization projects is simple:

The transition is part of the architecture.

By transition, I mean the period where the old and new systems coexist while traffic, data, and responsibilities gradually move from one system to the other.

During a migration, we often write temporary production code whose only purpose is to help us move safely from one system to another. This may include feature flags, routing logic, transformation pipelines, or mapping components. Although we expect to remove this code after the migration, it still runs in production and deserves the same level of testing, monitoring, and ownership as any permanent service.

Designing the transition means making a few decisions explicit: which system owns each responsibility and dataset, which invariants must hold while both systems coexist, what evidence allows the migration to continue, what rollback can and cannot reverse, who owns each temporary mechanism, and what conditions allow us to remove it.


Design the Journey, Not Only the Destination

A clean target architecture is only half of the problem.

The other half is answering questions like:

  • How do we migrate without unnecessary disruption?
  • How do we validate that the new system behaves correctly?
  • How do we stop or recover safely if something goes wrong?

These questions should be answered during architectural design, not left until implementation.

Routing traffic back is not the same as restoring state. The new system may already have written data, published messages, or triggered external side effects. A transition design must account for what has already happened, not only where the next request will go.


Start With the Smallest Meaningful Boundary

Instead of asking:

How do we migrate the whole system?

Ask:

What is the smallest meaningful piece we can migrate safely while delivering value?

Meaningful does not simply mean small. The boundary should represent a coherent responsibility or ownership seam that can be routed, observed, and reversed independently without breaking its data or transactional invariants.

When those conditions hold, smaller boundaries reduce the size of each deployment and limit the blast radius when something goes wrong. They can also simplify rollback, provided the old path remains operational and compatible with the state created during the transition.


Two Patterns That Make Migrations Safer

Routing Logic

During a migration, there is often a period where two systems coexist.

Something has to decide which one should handle a request. That decision may come from a feature flag, a proxy, an API gateway, or another routing component.

Its responsibility is simple:

Decide where traffic goes.

It does not transform data. It decides which system should serve the request.

Routing logic allows the old and new systems to coexist while traffic moves incrementally instead of through one large cutover. It can redirect future requests, but it cannot undo writes, messages, in-flight work, or external effects already produced by the new path. Those require compatible state, reconciliation, or a separate recovery plan.


Transformation Pipeline

Different systems rarely use the same data model.

A transformation pipeline bridges that gap by receiving data from one system, enriching or combining it when necessary, transforming it into the target model, and persisting the result.

The pipeline describes the overall flow. Inside it, mapping components perform the individual conversions.

The harder architectural questions sit around that flow: Which system is the source of truth? Who owns partial failures? Can a transformation be replayed safely? How are ordering problems or divergent results detected and reconciled?

Thinking in terms of a pipeline makes the movement of data easier to reason about, but the transition is safe only when those responsibilities are explicit.


Build Evidence Before Confidence

Successful migrations do not rely on hope. They rely on evidence that the new system produces the expected business outcome.

One useful pattern is to let the new system process the same production events while the existing system continues serving users. During this stage, the new path should be non-authoritative, with customer-visible side effects suppressed or isolated.

Its outputs can then be compared with expected business invariants or with the results from the existing system. Differences should be visible, investigated, and assessed against explicit acceptance criteria before traffic moves.

Do not validate only that the system is running. Validate that the business behaviour is still correct.

Instead of asking only:

  • Did the request return HTTP 200?

Also ask:

  • Was the correct data stored?
  • Did the expected business action happen?
  • Would the customer receive the expected result?

Infrastructure metrics tell you whether the system is healthy. Business metrics tell you whether it is behaving correctly. Good observability measures both.


Temporary Doesn't Mean Disposable

Feature flags, routing logic, and transformation pipelines may exist only during the migration. While they are in production, they should be:

  • tested
  • monitored
  • documented
  • owned

Each temporary mechanism also needs an explicit exit condition and planned time for removal. The transition is not complete merely because the new system has been deployed. Traffic, state, and operational responsibility must have moved as well.

If temporary migration code survives after it has served its purpose, it stops being a safety mechanism and starts becoming technical debt.


Principles I Try to Follow

When designing a migration, I try to remember five ideas:

  1. Design the transition, not only the destination.
  2. Start with the smallest meaningful boundary.
  3. Build evidence before building confidence.
  4. Treat temporary architecture as production architecture.
  5. Remove temporary architecture once traffic, state, and responsibility have moved.

Early in my career, I thought migrations were mainly about replacing one system with another. Over time, I realized the real design challenge is everything that happens while both systems coexist. The destination matters, but the path that gets us there is architecture too.