practice

Seam Identification

Locating the places in a legacy system where behaviour can be intercepted and redirected, which determines whether an incremental migration is feasible at all.

A strangler migration requires a point at which traffic for one capability can be routed to new code while everything else continues unchanged. Finding those points is the first and hardest step, and where feasibility is actually decided.

Seams, roughly in order of convenience: an HTTP boundary where a facade or proxy can route by path; a message boundary, where a new consumer can subscribe alongside the old; a module or interface boundary inside the codebase where an implementation can be swapped; a database trigger or CDC feed when nothing else exists; and, least pleasantly, screen or file interfaces for systems with no programmatic surface.

What to do when there is no seam: create one. Introducing a facade in front of the legacy system, even one that initially forwards everything unchanged, is often the highest-value first increment because it converts an all-or-nothing rewrite into a sequence of small moves.

Two decisions that follow. Data is the harder half — a migrated capability usually needs data that still lives in the legacy store, which means synchronisation, dual writes or CDC for the duration of the migration, and that duration is measured in months.

And the old path must eventually be removed. A strangler migration that never deletes anything has produced two systems and doubled the maintenance, which is the most common way it fails.