Monolith to microservice patterns

Monolith to microservice patterns

Two pattern that can help you with carving out functionality from a monolith

·

3 min read

Your team owns a monolith application and now it's time to split part of it into a separate microservice. The reasons can be multiple: the microservice should be owned by a different team and your team wants to restrict changes to the monolith or you may simply want to scale up the microservice but not the entire monolith. Whatever reasons your team has, they have to act in a way that minimises risk but also provides a fallback in case the new microservice faces problems in production.

Strangler fig pattern also known as the Proxy pattern or Strangler Facade

You identify the functionality you want extracted from the monolith and begin the work of incremental refactoring until the entire functionality is carved out. It's similar to how a strangler fig vine wraps around a tree branch to eventually replace it.

Untitled Diagram.drawio.png

This pattern works when you can intercept client calls to your monolith's functionality. A proxy service is placed to intercept consumer calls and it will redirect the calls appropriately to either the monolith or the new microservice.

If the service you want to extract from the monolith is not on the surface (such that a Proxy can intercept the calls) but rather deep inside the monolith - such as a Notification service which sends customer notifications after an order has been placed - then another pattern comes to the rescue, the branch by abstraction.

Branch by abstraction

To extract the relevant functionality in this case, we create an abstraction (interface in OOP) and have the service we want extracted implement this interface. The interface should be used everywhere in the monolith and a new implementation will be created which calls the remote microservice. By using an interface, it will allow us to swap implementations from using the monolith's local functionality to calling a remote service. It will also allows us to control the implementation by use of a feature toggle.

Untitled Diagram.drawio (1).png

We can also have parallel runs in which we check if the system is functionally equivalent by comparing results. The results are compared by calling both the remote service and monolith and checking for equality. Using this approach we can also do metrics and performance checks.

What about the data layer? In both patterns a refactoring of the data layer is likely because now the microservice probably owns a subset of the tables which are directly accessed by the monolith. As a first step the microservice can be connected to the same database as the monolith but to avoid tight coupling and promote separation of concerns the microservice should be the owner of its data.

In this case the microservice will have a new database and the relevant tables moved to this database. All the join operations which have cross-cutting concerns will be moved at the application layer with API calls providing the necessary data.