0% completed
Strangler Pattern: A Detailed Example
On This Page
The Legacy System
The New System
The Facade
Replacing One Method at a Time
Here is a Java example of the Strangler Fig Pattern, using a small banking system.
The Legacy System
The legacy system is one class, LegacySystem, with methods for createAccount(), deposit(), withdraw() and checkBalance().
public class LegacySystem { public void createAccount(String name) { // ...Old logic for creating an account... } public void deposit(int amount) { // ...Old logic for depositing money... } public void withdraw(int amount) { // ...Old logic for withdrawing money... } public int checkBalance() { // ...Old logic for checking balance... return 0; // placeholder } }
The New System
The new system has the same four methods, with new logic behind them. It is built beside the legacy system rather than replacing it.
public class NewSystem { public void createAccount(String name) { // ...New logic for creating an account... } public void deposit(int amount) { // ...New logic for depositing money... } public void withdraw(int amount) { // ...New logic for withdrawing money... } public int checkBalance() { // ...New logic for checking balance... return 0; // placeholder } }
The Facade
The facade is what the outside world calls. It holds both systems and decides which one handles each request.
At the start every request goes to the legacy system. As each piece is rebuilt, the facade begins sending that one to the new system.
public class BankingFacade { private LegacySystem legacySystem; private NewSystem newSystem; public BankingFacade(LegacySystem legacySystem, NewSystem newSystem) { this.legacySystem = legacySystem; this.newSystem = newSystem; } public void createAccount(String name) { if(newSystemReadyFor("createAccount")){ newSystem.createAccount(name); } else { legacySystem.createAccount(name); } } public void deposit(int amount) { if(newSystemReadyFor("deposit")){ newSystem.deposit(amount); } else { legacySystem.deposit(amount); } } public void withdraw(int amount) { if(newSystemReadyFor("withdraw")){ newSystem.withdraw(amount); } else { legacySystem.withdraw(amount); } } public int checkBalance() { if(newSystemReadyFor("checkBalance")){ return newSystem.checkBalance(); } else { return legacySystem.checkBalance(); } } private boolean newSystemReadyFor(String functionality) { // ...Check if new system is ready for given functionality... return false; // placeholder } }
Every caller talks to BankingFacade. No caller knows which system did the work, which is what lets the work move without changing them.
Replacing One Method at a Time
Say createAccount has now been rebuilt. You change newSystemReadyFor to return true for createAccount, and every new account is created by the new system. Nothing else moves.
Each further method is migrated the same way: rebuild it, change its answer in newSystemReadyFor, then watch it. When all four return true, the legacy system is receiving nothing and can be removed. The example leaves out one thing. Both systems have to read and write the same account balances. A deposit taken by the new system must be visible to a balance check still served by the old one.
In a real system that check reads from configuration rather than from code, so a piece can be moved back without a deployment.
On This Page
The Legacy System
The New System
The Facade
Replacing One Method at a Time