yoshitaka272 - Fotolia
Migration from a legacy application system often requires heavy code rewrite processes. But rather than do a complete overhaul and take the system offline, it might be possible to implement a pattern that slowly deprecates a legacy system over time while incrementally adding new functionality.
This approach, coined by Martin Fowler as the strangler pattern, gradually updates monolithic application systems -- colloquially known as the "big ball of mud" -- while still keeping them running in production. Today, we'll explore what the strangler pattern is and how to implement it, along with use case examples.
What is the strangler pattern?
Picture a motorcycle that works, but could stand to undergo extensive overhauls that will make it run better. One option would be to completely take the motorcycle apart and spend months rebuilding until it works. However, how sure are you that it will run after you've finished replacing every part? And what if you want to use the motorcycle in the next few weeks, but can't while it's in the garage?
The solution there is to replace parts one at a time, ensure it works as expected, and move on to the next once it's done. This provides two major benefits. The first is that you can likely still run the motorcycle as parts are incrementally replaced, rather than having to wait for the rebuild. The second is that if a fix or replacement doesn't work, you'll have a much easier time identifying the problem since you do not have to examine everything at once. Eventually, you will end up with an updated motorcycle that never really stopped running.
The strangler pattern works in a very similar way. Rather than completely disassemble an application system and rewrite its code, this pattern offers development teams a way to incrementally update sections of code and functionality without the need to completely shut the system down. Eventually, all the services and components will be refactored to integrate with a new application system, and the legacy system can retire.
This means that the migration process can proceed as an iterative process rather than a complex rip-and-replace scramble. Development teams do not have to worry so much about implementing a second code base, but rather can focus on refactoring one service or function at a time. It also eliminates the need to create two separate teams -- one that manages the old code and another that manages the new code.
How to implement the strangler pattern
The strangler pattern might seem complex on the surface. However, provided you follow the correct procedure, it's actually quite simple to implement.
The diagrams below illustrate the steps involved with a strangler pattern implementation.
One of the biggest components of the strangler pattern is the facade interface, which acts as the main point of interaction between the legacy system and the external apps and systems that call it. When code resides in a single module that tightly couples multiple services, external systems will not be able to identify which blocks of code are associated with a particular function, slowing down response times and making it virtually impossible to perform accurate testing on individual services. This is the problem that the facade solves.
The facade interface will help external apps and systems identify the code associated with a particular function, and obscure the underlying legacy system code. To deal with this, the strangler pattern involves creating a facade interface that helps developers expose those individual services and functions as they break them out from the monolith. Eventually, the code behind the facade will shrink as developers write, test and deploy new code.
The strangler pattern in practice
Example 1: Object-oriented programming
A single class that contains thousands or tens of thousands of lines of code is sometimes referred to as a god class. Modifying this kind of class is often one of the most painful parts of code update projects. Because these classes sit above the methods, any method can access and potentially modify variables it was never intended to. That means a change in one place might have unintended consequences elsewhere.
To apply the strangler pattern to an object-oriented system, clump all variables into object-based data structures. When you need to modify a chunk of code associated with a particular function, store that code in the object that links to the appropriate data structure. Implement that structure into the class you create for the new system you intend to migrate to, and reflect that implementation in the legacy code. Eventually programmers will make changes to these new batches of well-structured code, and the god class will slowly deteriorate.
Example 2: Web applications
The strangler pattern can turn traditional server-based Java applications into dynamic web-based services. You can start doing this by incrementally replacing hard-coded SQL statements with a language that can support and call web services directly, such as JSON. Eventually, the legacy Java code will finally be refactored into the new language. Once the entire application is converted to web services, you can simply "turn off" the traditional server-based logic.
Example 3: Database
Most enterprise-grade databases now work on trigger-based mechanisms that run code in response to events and automatically record the changes that occur. This makes it possible to maintain a second system that can also run and track those events. Whenever a change occurs in your legacy system, configure your new system to capture those changes and provide reporting. Over time, you can modify those events to route directly to the second system. Eventually, you'll be able to completely retire that old database.
Transitioning from a monolithic architecture to a microservices-based approach has become the new norm, yet many organizations are still wrapping their heads around the underlying process and strategy that entails. This collection will walk readers through the process -- from deciding if a migration to microservices is worth it, down to the details of decomposing a monolithic database for distributed services.
It's critical to remember that when you want to make a change to ugly code or a big ball of mud, you need to consider how to pull out a change and put it in a better place. Some of the examples above involve moving platforms, while others don't. Do it often enough, and you will someday grow something new around the old.
Or just keep making patches that make the whole system a little worse each time. It's up to you.