We have all heard about the benefits of Microservices vs the Monolith. But did anyone stop to think about the pitfalls?
In this article we will go through the pros and cons of Microservices along with a strategy for a smooth transition from your Monolith to the fabled Microservices architecture. We will determine the optimal path for the transition and discuss the trade-offs that will need to happen.
Before you start you’ve gotta ask yourself one question:
“Do i feel lucky?” Well, do ya, punk? – Harry Callahan
Seriously though, before porting your favourite monolith you should assess whether a microservice architecture is right for your specific needs 1. Only after concluding that microservices are the way to go, should you continue on with identifying the services you will need to pry apart.
As a general rule of thumb you should shy away from microservices if your monolith is not complex enough, or if it doesn’t show any of the following signs:
Generally speaking, monoliths are not a bad thing. Granted that they are well written, and have clearly defined components and moving parts, monoliths provide lots of benefits such as:
On the other hand, microservices also offer lots of benefits:
Re-writing the while monolith is all but out of the question in most cases. A viable approach would be to structure all new functionality as microservices and/or identifying and decomposing existing services.
All microservices should be self-contained and not have dependencies on the monolith (be that business logic or data). This would bind these services to the release lifecycle of the monolith. This also means that each service should rely on its own copy of the data, synced from the monolith’s persistent storage.
If such distinction cannot be achieved, a glue  service can be created on the monolith to aid with the integration of the new microservice.
You need to clearly identify the different modules in your monolith that you want to decompose into independent services. Good candidates are modules that change often and modules that rely on different resources than the rest of the monolith.
Identifying a component inside a monolith can be challenging work on its own. Key property of a component is the notion of independent replacement and upgradeability .
A codebase of several hundred thousands of lines of code can potentially be broken down to thousands of microservices. This would render the product virtually unmainainable. Several aspects such as developing, testing and deploying would become very complex. You have to remember that substituting a monolith consisting of a chain of function calls with several dozen HTTP calls will quickly kill your application performance.
Also taking under consideration that each one of these HTTP calls can potentially fail, you must be prepared for the worst case scenario. Not just dealing with it but designing for it 4.
Beware of a common anti-pattern: Decomposing a monolithic service into a new microservice but never retire the old service. One could argue that the team is now further away from the desired target than before. Developers need to learn multiple paths to the same goal while maintenance costs increase.
Another pitfall is reusing the same storage system across microservices. This is common in monoliths. It might be tempting to continue to use a common storage system even when switching to microservices. You don’t really want code duplication. Why use different data structures?
Using the same storage system couples services together. If a service changes the database schema then all other services using this schema will need to also be changed. This way more than one services are coupled together and should observe similar release lifecycles.
Another concern is not being able to support the switch to microservices. This might mean that your team is not ready to undertake such project. You need to be able to support this switch with appropriate infrastructure, testing and automation frameworks.
Microservices rely on a great deal of logging and monitoring. Your team should be able to monitor application / service health along with business reporting. Due to the nature of microservices, your application will deal with eventual consistency rather than full transactionality. Systems should be put in place to detect issues before they become problems. These systems could also perform self-correcting routines (syncing between different persistent storages etc).
Moreover, your application should be able to recover from services being unavailable either by service degradation or by other means. It is imperative that such systems are tested thoroughly. Engineers at Netflix are practicing taking random production systems offline at different times thus benchmarking and logging application behaviour 5.
Migrating from a monolith to microservices is a challenging undertaking. You will need to touch up on many concerns, isolate modules, train your team and update your infrastructure and deployment methodologies, which certainly takes time. While microservices might not be the best fit for every need, i strongly believe in the benefits that they provide.
A lot of companies have already undertaken such projects and came through better on the other end. Lots of engineering teams have documented their experiences on-line, both positive and negative. Be sure to read up on everything before attempting something like this. It is always easier to stand on the shoulders of giants.