Monolith vs. Microservices: The Battle of the Century
Wondering when you should choose a monolithic business model vs microservices? What are the advantages and disadvantages of each? Read on to find out.
Join the DZone community and get the full member experience.Join For Free
Let me announce contenders. In the red corner is a former title champion in a super heavyweight category — Mr. Monolith. In the blue corner is a young and pumped-up gang of microservices in a featherweight category.
I saw several serious monoliths in my life. One of them had about 5+ hours of build time, and the company had to build their own CI to keep moving forward.
On the other hand, I saw people using a microservices architecture. They needed 17 load balancers to get their pre-Alpha application up and running. The fun part is that it was before the time of infrastructure as a code, so it was a really high number.
If you asked me about five years ago, I would say by default that the monolith is evil and microservices are good (and I would quote all standard things). However, the hands-on experience of these years taught me that going the microservices route may easily backfire.
Issues With Microservices
Let me skip talking about monolith problems (it doesn’t make sense to beat the dead horse), and let me concentrate a bit on the issues with microservices:
- There are many things beyond coding that need to be done to have a product ready (making a build, running tests, deploying, monitoring, scaling, etc.). All of this needs to be figured out just once for a monolith. However, it needs to be repeated for each of the microservices. In the best case, your microservices are based on a similar technology stack for reuse. In the worst case, you will need to reinvent the wheel for each of them. (A small note: Some of these pains are gradually solved by tooling, but only some of them).
- Who should wake up at 2 am if your service started to limp? A dedicated Ops team for the monolith usually has enough knowledge to solve the first level of problems (and allow you to handle the rest at 8 am). As soon as you have hundreds of microservices, you end up quite often with a couple of people (or maybe even just one) who know how to keep that specific service alive. It is not fun to be woken up at 2 am just because some monitoring had a false positive. Also, this incredibly increases operational risks: what happens when that one person who knows some specific microservice is on vacation somewhere without internet?
- Moving code within monolith and changing interfaces generally isn’t that bad. Moving code between microservices and changing interfaces (including handling versioning and backward compatibility) is incredibly expensive.
- This interface change story becomes especially painful if you didn’t partition your application perfectly the first time around and find that some pieces of logic belong to the wrong microservice (I can promise you didn’t partition it perfectly). It would be naïve to assume that initial thinking (which probably was implemented on day one) will be perfectly correct for subsequent years.
- Monolith uses the same language, framework, and so on. As a result, moving people between parts of a monolith is easy. Moving people between different microservices (which may have very different tech stacks) is hard.
- Debugging something across a set of microservices is painful, to say the least. Anybody who had to chase a bug across 4–5 microservices back and forth for days, to find that one of them didn’t do some validation would understand.
I am pretty sure there are many other cons. However, even this list makes me question microservices as a panacea.
Ok. Monolith is bad. Microservices are bad… Ahhhh… Everything is bad. There is nowhere to run. What do we do?
What Do We Do?
The biggest problem is not monolith per se (or microservices per se), but rather extremes that bring about. And unfortunately, teams/companies may not recognize problems in time and start addressing them until they get completely out of hand.
Monolith becomes big and tends to continue to grow and worsen. When you realize it’s a problem, it’s already so big and hairy that breaking it down becomes an almost impossible task.
Microservices are often used prematurely, they grow in numbers and complexity of their interactions. As a result, it brings all the problems which I described above.
My take on it is: you need to have right-size-services © :) First of all, I believe a good idea is to start with reasonably monolithic architecture (one or a couple of services). As they began to grow, look for natural cracks (pieces of code with very different attributes). These are the pieces that could be gradually separated into standalone services.
For example, I was working on a back-end service, and we found that one part was called way more often than others. It needs to scale horizontally way more aggressively than the rest. Also, we found that the current architecture for this piece was a bit problematic, and it had a reasonably small amount of dependencies on the rest of the backend. Here you have a perfect candidate to be extracted as a separate service.
Two additional warnings/notes:
- Keep an eye on the monolith. It’s easy to miss the point when it gets out of hand. It’s better to start separating things a bit prematurely than doing so too late. My gut feeling is that as soon as you begin spending around 5% of your time fighting monolith problems, it’s time to do something about it.
- A lot of companies are very resistant to non-trivial refactoring efforts. It comes from multiple places. Engineers always like to refactor things whether it’s necessary or not. As a result, management is pretty skeptical of this. Additionally, big refactoring or rewrites increase risk (which managers are not fond of). I would recommend you start preparing upfront (taking about benefits, stages, minimization of risks, and so on). This allows a way to build consensus and be ready to execute.
It’s hard to tell who wins in this fight between monolith and microservices. You have to balance between the two by starting with simple (monolith) and moving towards separating complexities (microservices).
Published at DZone with permission of Victor Ronin. See the original article here.
Opinions expressed by DZone contributors are their own.