In the last article, we have discussed how and when to migrate from Monolith to Microservices. This article is focusing on the migrations patterns from Monolith to Microservices.
Here, we shall look at patterns that would work for black-box vendor software, legacy systems, or monoliths that you could plan to continue to maintain and evolve. Initially, we will consider only where the application code lives. Following are some of the most commonly used techniques for migration patterns.
Strangler-Fig Pattern is a frequently used technique for doing system rewrites. A key point in this type of pattern is that we could incrementally migrate new functionality to the new system and rollback easily if required.
This pattern is named after a small fig wraps around a large tree, starts to live within the tree, and finally eats up the tree and continues to live.
As shown in figure 1, this pattern allows you to move functionality over to your new services architecture without changing your existing systems. Moreover, it is beneficial when the monolith affects a black box system such as third-party system software or a SaaS service. Implementation in a Strangler fig pattern requires only three steps.
- Identifying parts of the existing system that you wish to migrate
- Implement this functionality into your new microservice
- Consider using a pattern like ‘parallel run’ to give more functionality to the system
We can use a reverse proxy to handle the request navigation. Strangler-Fig Pattern is one of the most used migration patterns where you would have minimal impact on the existing system. It is almost impossible to stop all your other support work and rewrite the system from scratch. Hence, this pattern would be suitable for most migrations.
Branch by Abstraction Pattern
We need to intercept/divert calls at our monolith’s perimeter for the strangler fig pattern to work. But the branch by abstraction pattern, as shown in figure 2, focuses on making improvements to the current codebase, allowing applications to coexist alongside each other without creating too much disruption in the same code version.
These are the six phases that are being followed in Branch by Abstraction:
- Build an abstraction for the functionality to be replaced.
- Implement the newly build abstraction in the existing module.
- Implement the new functionality in a new service. For some time, this implementation would be idle and would not connect to any functional flow.
- Implement a service provide or some kind of wrapper/face to communicate with the freshly build service by implementing the abstraction.
- Now your data flow is using the new service and you can get rid of the abstraction if you wish to.
- Remove the old module/ functionality.
Decorating collaborator pattern
Decorating collaborator pattern, which is shown in Figure 2, allows you to attach new functionality to existing functionality or data interface. Even though we have not changed the underlying Monolith, the Decorator shall make it appear that our Monolith is making calls to the services. Rather than changing the Monolith, we keep the Monolith functionality and build some form of a wrapper/facade to change the returning data to the requester. One good example of this pattern is to build a weightless data bundle for Mobile applications. The Thick clients and other heavy web application would be using the heavy Rest API, while the Mobile apps would be using this freshly build new API with the reduced payload.
Parallel Run Pattern
The strangler fig pattern and branch by abstraction patterns both allow old and new implementations of the same functionality to coexist in production simultaneously. Usually, both of these techniques let us execute either the old implementation in the monolith or the new Microservice based solution. To mitigate the risk of switching over to the new service-based implementation, these procedures allow us to quickly switch back to the previous implementation.
But in the Parallel run, as shown in Figure 3, both of the implementations are called out, giving us to compare the results to check their equivalency. For decades, this pattern was used even though it is usually used to run two systems in parallel. Most importantly, this method could be used to verify that new implementation is giving answers as same in the old and working and operating within acceptable nonfunctional parameters.
Thats all folks. Thanks for reading and I hope you learned something new from this.
Please find my video related to this in following link.