Strangler-fig migrations: what the pattern leaves out
The incremental migration pattern is well understood in theory. Four things consistently go wrong in practice, and three of them are organisational rather than technical.
Every legacy modernisation proposal we see now cites the strangler-fig pattern. Almost none of them have costed the parts that make it work.
The pattern itself is simple: put a facade in front of the legacy system, route traffic through it, and progressively replace functionality behind the facade until nothing is left. It is unambiguously the right default for large replacements. But the literature describes the architecture and skips the operational reality, and that is where these programmes actually run into trouble.
1. Dual-run is the expensive part, and nobody budgets it
For any migration where correctness matters — payments, claims, billing, anything regulated — you will run old and new in parallel and reconcile every transaction. That reconciliation is a real system. It needs its own data model, its own alerting, its own team, and it needs to distinguish between a genuine discrepancy and a legitimate difference in the new implementation.
On our last four migrations, reconciliation infrastructure was between 12% and 19% of total build effort. We have never seen it in a vendor estimate.
2. The facade becomes a distributed monolith if you let it
The routing facade starts as a thin proxy. Then someone needs a field that exists in the new system but not the old one, so a transformation goes in. Then a business rule that has to apply regardless of which side serves the request. Eighteen months later the facade contains a material amount of domain logic and cannot be removed at the end, which was the entire point.
The facade must be the only component in the system that is allowed to know nothing about the domain.
The discipline that works: an architecture decision record that explicitly forbids domain logic in the routing layer, and a review gate on every PR that touches it. It sounds bureaucratic. It is cheaper than the alternative.
3. Sequencing by technical dependency instead of business value
Engineering teams naturally sequence by dependency — do the foundational domains first, build up from there. This produces eighteen months of investment before anything visible happens, which is exactly how programmes get cancelled in month fourteen.
Sequence by value, then solve the dependency problem with temporary anti-corruption layers. Yes, you will write code that gets deleted. Writing throwaway integration code is much cheaper than having the programme cancelled.
4. Nobody owns decommissioning
The benefit case for modernisation is usually dominated by removing the legacy run cost. That saving only lands when the old system is switched off, and switching it off requires proving nothing still depends on it — which is somebody's job, on a plan, with a date.
In the programmes we have reviewed, decommissioning slipped an average of fourteen months past the final migration wave. The engineering team had moved on, the remaining dependencies were owned by nobody, and the run cost stayed in the budget. The migration succeeded and the business case did not.
The short version
Budget the reconciliation. Keep the facade stupid. Sequence by value and accept throwaway code. Name a decommissioning owner in the original plan. None of this is in the pattern description, and all four will decide whether your programme works.