This article summarizes the webinar ‘Breaking The Monolith’, presented by Daniel Gutiérrez Saavedra, Senior Software Engineer at Zartis. You can watch the full webinar, which also includes a Q&A session, here.
Are you working with monolithic systems and legacy applications? Are you looking for ways to modernize your architecture and switch to microservices?
This article will cover the ways you can break up a monolithic application into smaller pieces that make up a modular system.
Why Choose Microservices
Microservices are developed with business-oriented APIs to encapsulate a core business capability. The principle of loose coupling helps eliminate or minimize dependencies between services and their consumers.
Among other things they are:
At the end of the day, microservices architecture is much easier to test, it’s much easier to deploy. If we also add the DevOps mindset to the equation, in which we’ve got very small parts of code that can self test and be deployed in small chunks, the advantages become impossible to ignore.
The Challenges of Microservices
It is important to acknowledge here that microservices architecture does come with some challenges. There are some extra layers of complexity, as there will be many moving parts in the system, and testing microservices can get complicated.
Here are some of the main challenges you need to consider:
- Extra layers of complexity.
- If your software doesn’t change often, it may not fix anything.
- There is an additional cost to buying new products.
- Once you get into the cloud, that enables you to perform extra activities such as logging, additional security considerations, etc. Your team will need to train themselves to leverage these tools.
Breaking the Monolith
An effective way to move your system to microservices architecture is to start with identifying your core services and then refactoring & decoupling them. Let’s take a deeper look at how you can go about making these changes and review the best options for storing your application on the cloud.
Step 1: Identifying Core Services
It would be useful to start your migration by identifying the critical services, which may be the ones that bring more revenue to your business, or the ones that are the most used by your customer base. These services will be the hardest to split from the monolith.
The criticalness of your service is determined only by you. But the first thing you should do when moving towards microservices is identifying them. When it is time to slice things, it is easier to do it horizontally – just think about this in layers; you’ve got the business layer, the presentation layer, data layer, etc. Slicing vertically would mean trying to split up functionality, a feature that covers the whole spectrum of layers in your applications, which can lead to boilerplate and duplicate business logic.
To give an example, let’s take Domain Driven Design (DDD). In a microservice oriented system, maybe our domain is very big, which could cover many microservices and those microservices could function as sub-domains. So it’s a very similar way of thinking when it comes to system design and it is perfectly compatible with things like DDD, BDD, etc.
Step 2: Decoupling & Refactoring
So, we’ve seen how we can split everything but now how do we separate services from everything else and refactor them to become a bunch of microservices?
The first thing to know: the less communication, the better relations. It’s very easy, and very tempting to create lots of services, that are very easy to test from a singular standpoint, but as a whole, your system will get really complicated and tangled. It makes things difficult to track should a problem arise because you’ve got this enormous entanglement, and it may be hard to identify where the root of the problem lies.
Another important consideration is to enter events into the queue. Many times we have been told that we cannot break these into separate services because this thing has to be perfectly synchronized for events that happen in the next steps. Usually, that’s not true. Thanks to the queueing system and topic messaging systems that exist today, there are lots of ways to break synchronization. It’s true that you are adding an extra layer that could bring some latency problems but in the end, being able to break all the synchronicity will probably end up in improving your experience.
Step 3: The API & The Cloud
Now that we have done all the slicing, and we decoupled our code, where what do we put all this stuff?
Today, we’ve got plenty of solutions and these are just a small excerpt of what the cloud provides us with:
To name a few of the most common ones, we’ve got the Google Cloud (GCP), Microsoft Azure, and AWS as the three main contenders, but there are many more providers. These solutions usually provide out of the box microservices architecture, where you only have to draw some lines, and do some small training to get things up and running.
Then you have some solutions, should you need an on-premise solution, because you don’t want to have your services in the cloud. Using Spring Cloud services, for example, you can use your own servers and perfectly mimic public cloud structures.
How much could migration to microservices using Cloud solutions cost?
It is very easy to keep creating microservices on the cloud, but if you don’t have a clear plan that also makes it very easy to lose track of your project’s budget. If you wish to get an estimate of how much you may spend on cloud services, there are a couple of ways to get an estimate. Using the calculators that most cloud services provide which are very detailed, you can get a good estimate but for that you need to have a very clear view on how your customer base is, what is the volume of transactions, the volume of data and code, etc. If you have all these parameters, you can achieve a very good estimate of what your costs in the cloud will be. This is sadly not the case for on-premise providers like Spring Cloud services, which bear the varying cost of having an on-premise server.
Common Migration Strategies
Let’s check the most typical migration strategies that exist today, which can help you get a clearer idea of the path you may want to take.
The Strangler Pattern
One way to achieve this migration could be – in case your application is very big – to use the strangler pattern. This way, you can extract the most critical services into your microservice architecture.
In this case below, it was decided to extract all the customer side of the application into microservices architecture and leave the admin side on the monolith, which is perfectly fine. They enhanced their code by big numbers, and they could do it without stopping the development. But this shouldn’t be the final state of the application. Ideally, everything should end up on the right side of the image. As you can see, there’s DBF in there, which is a DB per service. It is not a must-have requirement, but it does help.
Another way to go about your migration would be to use the parallel development approach. This is more suited for smaller projects or projects that are not very advanced in development. This way, you can keep developing both the monolith architecture and the microservices architecture in parallel.
The main pitfall of this approach is that it usually doubles maintenance and code duplication, but eventually everything will be on the right side of the screen and if you wish to be on the safe side, this approach can help a lot.
Final Thoughts on Migrating to Microservices
It is important not to get ahead of ourselves when we are in the middle of a migration and try to execute changes in parallel or design them in advance.
Imagine that you are working on a parallel migration and you decided to do the migration in parallel with your development; should new functionality or feature arise, you need to duplicate this code and do the work twice. If you try to plan the migration ahead of time, while introducing changes to your main application, it will become hard to avoid complications.
Focus on how you got the current system that works in the way you migrated today and how it should work tomorrow or in the next few days.