You’ve decided that migrating a monolith application to a microservice is the best approach to meet new application needs. Microservices are cloud native, scalable, and can be created in different languages for different services.
When you’re ready to migrate, you can use different strategies. Among the most common is the strangler pattern, often used with the anti-corruption layer pattern. Both design patterns deserve careful consideration.
Design patterns provide proven solutions
Why do you need to choose a design pattern when you’re migrating your monolith applications to microservices? Design patterns are general, proven, and well-known solutions for common application development problems. Experts recommend them and many people use them. These patterns are well-described, which makes them easy to understand.
Using design patterns help increase your microservice application quality and make it more supportable and better understandable by developers. Consider using design patterns as a best practice.
Why the strangler pattern remains the most popular
In the migration of monolith applications to microservices, the most used patterns are the strangler pattern with the anti-corruption layer pattern. As with all design patterns, they have many strong advantages, but none is perfect.
The main advantage of the strangler pattern is that it offers an incremental migration process without breaking the whole application functionality. It’s a more reasonable alternative to recreating the whole application from scratch.
Software development advisor Martin Fowler observed that microservices development often runs into problems. He noted the following points:
- Almost all the successful microservice stories started with a monolith that got too big and was broken up.
- Almost all the cases where I’ve heard of a system that was built as a microservice system from scratch have ended up in serious trouble.
The strangler pattern dates back to 2004 when Fowler was on a trip to Australia and observed the strangler fig trees:
They seed in the upper branches of a tree and gradually work their way down the tree until they root in the soil. Over many years they grow into fantastic and beautiful shapes, meanwhile strangling and killing the tree that was their host.
Applying the strangler pattern, we can think about newly created microservices as the strangler fig and the tree as the monolith. We start building microservices around the monolith until we cover all its functionality and eventually terminate the original monolith application. The process of breaking the monolith using the strangler pattern is also known as strangling the monolith.
With the strangler pattern, you define the independent functionality of your monolith and cut it off to the microservice. You have your monolith application working with one microservice. After that, you extract a second piece of your monolith the same way to another microservice, and you have your monolith with two microservices. You extract pieces until your monolith becomes a smaller microservice. It’s by far the most used pattern.
Making the microservice design independent of the monolith
The extracted microservice and the monolith are part of the bigger application and communicate with each other. Most likely, they use different domain models that are converted during the communication process. The process involves some glue code, which resides in the monolith, in the microservice, or on both sides. This code is called the anti-corruption layer.
In this case, anti-corruption means that the design solutions of the extracted microservice and the monolith don’t affect each other. In other words, the anti-corruption layer pattern is applicable to each extracted microservice and makes its design independent of the monolith design. You implement the anti-corruption layer. While extra work is needed, this choice enables you to extract a piece of functionality as a microservice. With the anti-corruption layer pattern, you take some code, extract it to a microservice, and design your monolith layer to allow you to work with that microservice.
Migrating Java EE-based monoliths to microservices–simplified
There’s a good chance your monolith application was built in Java. Java enterprise edition (Java EE), which is widely used for enterprise systems, was based on standards. One of the main advantages of standards are portability and backward compatibility. Java EE applications were portable between Java EE application servers’ solutions provided by different vendors.
Java EE is old, but not dead. It’s still developed and supported. In 2019, it was transferred to the Eclipse Foundation and got a new name: Jakarta EE. Now it’s truly an open source solution developed by the Java community and leading software vendors, such as Oracle, IBM, Red Hat, Payara, Tomitribe, and others, under an open specification process.
At the same time, there’s another modern standard solution for cloud native microservices called MicroProfile. It includes specifications that extend Jakarta EE functionality in better supporting clouds and microservices architecture, such as Config, HealthChecks, OpenTracing, and Metrics. MicroProflie is also the Eclipse Foundation project.
So, if your monolith is a Java EE or Jakarta EE application, it might make sense to use standards-based Java solution for your microservices, too. Your microservice has a similar design and use the same standard APIs, so you can copy some business logic to your microservices without serious modifications of the source code. In this case, I recommend using Helidon. Helidon is a modern Java microservices framework implementing MicroProfile and some well-known Jakarta EE components, such as JAX-RS, CDI, JPA, JSONP, and JSONB.
Still not sure migration is the right approach?
If you’re unsure whether migrating your monolithic application to microservices is the right strategy, read my earlier blog post, From Monolith to Microservice: When Should You Convert Your Java Applications? In this blog, I lay out the advantages and the drawbacks of microservices. This explanation can help you decide if a monolith-to-microservices migration is the best strategy for your specific application needs.