Die Würgefeige
Das Muster, um ein Altsystem schrittweise zu ersetzen: neues Verhalten auf den neuen Code routen, Slice für Slice hinter einer Fassade migrieren und das Alte abschalten - so würde man ledger-legacy endlich ersetzen.
Deutsche Übersetzung in Arbeit
Diese Lektion ist noch nicht ins Deutsche übersetzt und wird daher auf Englisch angezeigt. Der Rest der Seite ist vollständig lokalisiert.
Auf dieser Seite
This whole path has refused to rewrite ledger-legacy - always evolving it instead. Now here's the pattern that
lets you replace even a large legacy system entirely, without a risky big-bang rewrite: the Strangler Fig.
Named by Martin Fowler after the vine that grows around a host tree, gradually enveloping it until the original
rots away and the fig stands on its own, it's how you migrate a running system piece by piece while it keeps
serving traffic the whole time.
Why not just rewrite?
The instinct with a painful legacy system is "throw it away and build it fresh." Big-bang rewrites are one of the most reliable ways to fail in software:
- They take far longer than estimated - the legacy encodes years of edge cases and business rules nobody documented.
- Meanwhile the old system keeps changing (the business doesn't freeze), so you're chasing a moving target.
- You deliver no value until the very end - a huge bet with a single, delayed payoff.
- You often reproduce the original mess, now with fresh bugs.
The strangler fig avoids all of this by making the migration incremental, low-risk, and always shippable - the evolutionary approach applied to replacement.
How the strangler fig works
Put a facade (or router/proxy) in front of the legacy system, so all traffic flows through it. Then migrate one slice of functionality at a time, redirecting just that slice to new code:
Step 1: Clients → [ Facade/Router ] → Legacy System (100%)
Step 2: Clients → [ Facade/Router ] ─┬→ New Service (the 'reports' slice)
└→ Legacy System (everything else)
Step 3: ... migrate more slices, the router sends each to new or old ...
Step N: Clients → [ Facade/Router ] → New System (100%) → delete the legacy- The facade is the seam. Because clients only ever talk to it, they never know (or care) whether a given request is served by old or new code.
- You migrate one capability at a time - start with a low-risk, well-understood slice - and route just that capability to the new implementation, leaving the rest on the legacy.
- Each migrated slice ships to production and delivers value immediately - the migration is a series of small, reversible steps, not one giant leap.
- When the last slice is migrated, the legacy system is serving nothing, and you delete it - the fig has strangled the tree.
Branch by Abstraction: strangling from the inside
The strangler fig routes at the edge; its in-code cousin, Branch by Abstraction, does the same inside a codebase you can't easily put a proxy in front of:
- Introduce an abstraction (an interface) over the piece you want to replace - all callers go through it.
- Build the new implementation behind that same abstraction, alongside the old.
- Gradually switch callers (or a feature flag) from old to new, verifying as you go.
- Delete the old implementation and, if you like, the abstraction.
It's the strangler fig at the class/module level, and it pairs perfectly with feature flags so you can migrate, test in production with a subset of traffic, and roll back instantly if the new path misbehaves.
Migrate a thin, low-risk slice first to prove the pipeline
The first slice you strangle shouldn't be the scariest - it should be a small, well-understood, low-risk capability. Its real purpose is to prove the whole machinery works: the facade routes correctly, the new service deploys and integrates, data flows, rollback works. Once that pipeline is trusted, subsequent slices are routine. Starting with the hardest slice risks stalling the entire migration on step one.
A big-bang rewrite is moving out, demolishing your house, and rebuilding from scratch - you're homeless for a year (no value delivered), it costs triple the estimate, and the new house has its own new problems. The strangler fig is renovating room by room while you keep living there: you finish the new kitchen and start cooking in it (that slice is live and delivering value) while the old rooms still work, then do the next room, and the next - never homeless, each room usable the moment it's done, and you can pause or adjust at any point. Eventually every room is renovated and the old structure is gone - but you were never displaced, and if a room's renovation went wrong you'd only lose that room, not the whole house.
The business finally wants to replace ledger-legacy entirely with a modern system, but it processes real financial transactions 24/7 and cannot go down or lose data. A three-month rewrite-and-cutover is proposed. Design a strangler-fig migration instead: where's the seam, what do you migrate first, and how does this de-risk the replacement compared to the big-bang cutover?
What is the Strangler Fig pattern?
Key takeaways
- Big-bang rewrites reliably fail: they overrun, chase a moving target, deliver no value until the end, and often reproduce the mess.
- The Strangler Fig replaces a legacy system incrementally - a facade routes traffic, and you migrate one capability at a time to new code.
- Each migrated slice ships to production immediately and steps are reversible; when the last slice moves, the legacy serves nothing and is deleted.
- Migrate a thin, low-risk slice first to prove the pipeline (routing, deploy, data, rollback) before tackling scarier capabilities.
- Branch by Abstraction is the in-code version: put an interface over the old code, build the new behind it, switch callers gradually (often via feature flags), then delete the old.