Modernization

The strangler fig, twenty years on

Martin Fowler named the incremental-replacement pattern in 2004. Two decades later it is quoted more than it is followed, and the gap is where modernizations die.

Code, Noted4 min readModernization

Martin Fowler named the pattern in 2004, after the strangler fig: a plant that germinates in the canopy, sends roots down around its host, and over years becomes a free-standing structure while the original trunk rots away inside it. He was describing a way to replace a legacy system not by rewriting it but by growing a new one around its edges until the old one could be removed without ceremony. Twenty years later the metaphor is quoted more often than it is practiced, and the distance between the quotation and the practice is where most modernizations still go to die.

Blueprint schematic of a routing layer peeling traffic slice by slice from a legacy system to a new one

The pattern deserves a definition before it gets an argument. A strangler fig migration puts a routing layer in front of the system to be replaced. Requests arrive at that layer and are directed, at first, entirely to the old implementation. Then one capability at a time, a slice of that traffic is redirected to a new implementation built alongside, and once the new slice is trusted, the old code behind it is deleted. The system is never rewritten and never frozen. It is replaced in place, one intercepted call at a time, and the router is the only component that knows both worlds exist.

What the pattern is really an argument against is the big-bang rewrite. The case against that approach is old enough to have a canonical citation: Fred Brooks warned in 1975 about the second-system effect, the tendency of a team's replacement for a working system to collect every feature the first one lacked and collapse under the ambition. The modern version is quieter and more common. It is the rewrite that runs for eighteen months against a target that keeps moving, because the old system is still in production and still accruing the changes the business needs, so the new one is always chasing a version that shipped last quarter. That is the same failure this publication has described as the migration that stalls at eighty percent: the last twenty percent is the part nobody scoped, and the big-bang plan gave itself no way to ship the eighty that worked.

The strangler avoids that trap by making every increment a shipped increment. There is no branch that lives for a year. Each slice goes to production the month it is built, which means each slice is also tested by production, and the parts of the old system that turn out to be load-bearing announce themselves early, while the migration still has budget and attention. The failures are small and recoverable instead of catastrophic and terminal, and a migration made of small recoverable failures is one that finishes.

The routing layer is not a detail of the pattern. It is the pattern. It is where compatibility is enforced, where a bad slice is rolled back in one configuration change, and where the record of what has and has not moved actually lives. Teams that treat it as plumbing, a proxy to be configured once and forgotten, lose the one instrument that tells them how far along they are. Teams that treat it as the primary artifact, versioned and observed and owned, can answer the only question that matters in a long migration, which is whether it is still moving. A strangler with no visible progress is indistinguishable from a strangler that stopped, and the router is where progress is visible or it is nowhere.

Blueprint schematic of a legacy and new system both left running behind a permanent router

The discipline the pattern demands is the part the quotation leaves out. A strangler works only if each slice fully retires the old code behind it. When teams route new traffic to a new implementation but leave the old path in place "just in case," they have not strangled anything. They have built a second system and kept the first, and now they maintain both, plus the router that chooses between them, indefinitely. The fig is supposed to kill the tree. A strangler that keeps the host alive forever is not a migration. It is a permanent tax with a botanical name, and it is the most common way the pattern fails, because leaving the old path running is always the safe choice in the moment and never the safe choice across the year.

Blueprint schematic of a lattice growing around a central trunk that is being hollowed out

The honest counterargument is that some systems should be rewritten in one motion. A small system, one that a single team can hold in its head, may cost more to wrap in a routing layer and migrate in slices than to rebuild over a long weekend. Fowler said as much: the strangler is a pattern for systems too large or too critical to replace at once, and using it on a system that is neither adds ceremony without buying safety. The judgment call is the size of the blast radius. If a failed rewrite means a bad Monday, rewrite. If it means a bad quarter and a regulator's phone call, grow the fig.

What the twenty years have actually taught is that the pattern is not an architecture at all. It is a commitment to finish, expressed in infrastructure. The routing layer, the slice-by-slice cutover, the deletion of retired code are all mechanisms for making the migration impossible to abandon quietly, because each shipped slice raises the cost of turning back. A team that cannot commit to finishing will fail with the strangler too, only more slowly and with a more elegant diagram. The plant in the metaphor does not stop halfway. That is the whole point of it, and it is the part most often left in the canopy.