I often meet companies that think their technology is failure-proof because they have implemented microservices, after all it’s an architecture that’s adopted by many tech giants. I even hear startups founders say things like “We have microservices so we’re ready to scale” before they’ve even launched! They think they’ve skipped ahead and learned from the “mistakes” others made implementing a monolith. The reality is, there is no single architecture that is superior to all others, microservices are not superior to monoliths. With all architectural decisions you need to be aware of the tradeoffs you’re making when choosing one. Your needs and capabilities are not like those of Netflix or Spotify, and to make the right decision for you, you need a better understanding of what those tradeoffs are.
Read on if you have doubts about whether microservices are right for you.
We need to be ready to scale
Companies love to dream about growth. Engineers love to solve hard problems like scaling. Being ready for scale seems like a good idea to everyone. But before you get too excited, ask yourself: Are you having scaling problems now? And how far are you from having them? Is your time better spent dealing with problems you have now?
If you’re an early stage startup, you’re light years away from having scaling problems. Your focus should be on iterating quickly and figuring out what people actually want, find your product/market fit first. The irony of me saying this is I was hired once when a startup that blew up in popularity overnight and had tons of scaling and performance issues. However, I still maintain that the likelihood of this happening is almost zero, that’s why when things like this happen, it makes the news.
Not to mention, many issues that get classified as “scaling” problems and prompt pointless re-architecting discussions are not actually scaling problems. If you’re dealing with performance issues despite having low load on your system, this is not a scaling problem, not in the real sense anyway. Most likely, you just wrote suboptimal code, look for the bottleneck and fix it.
Okay, but let’s say you’re actually dealing with scaling problems.
Microservices as the answer to scaling
Even when your scaling problems are real, a microservices architecture is not always the right solution or the only one. You’re just going to have different scaling challenges with different approaches.
Imagine you had a finance app that allowed users to generate monthly financial reports. With a microservices architecture, you may end up with a LogIn service that is heavily used, and a Financial Reports service that is used once a month per user at most. You can scale the LogIn Service without needing to scale your whole infrastructure. That’s great.
However, you can achieve the same scale with a monolith and one codebase. You can have the same code deployed to different clusters and discriminately route traffic to the Login or Financial Reports cluster. Clusters can then be scaled independently depending on their workload. This might be a reasonable choice if you already have a monolith and pressing scaling issues. Implementing this solution will take far less time than re-architecting and may be all that is needed.
Microservices impose better code
So it’s not only about scale, many people argue that microservices enable good programming practices like low coupling. While it might be true that it’s easier to enforce boundaries between modules with microservices, you can still write perfectly modular code in a monolith. In addition, if you don’t get your module boundaries right with microservices, you’re going to end up with an even bigger mess.
Problems you never had
A microservices architecture comes with its own challenges. While a single service is easier to understand on its own, understanding the system as a whole gets more complicated. That’s just the price you have to pay for any distributed system.
Your developers now need to write code that optimizes performance and lowers the effects of network latency. Imagine you had an API service that receives a request and needs to talk to three other services to assemble a response. The simplest code to write at the API layer sends those 3 requests sequentially. This is also the slowest implementation; the latency you get is the sum of all latencies. An alternative implementation is making 3 asynchronous calls. Now your latency is bound by the slowest call, so that’s a win. Unfortunately, asynchronous programming happens to be trickier and harder to debug.
Error handling and propagation is often a challenge as well. It gets harder to predict how a failure in one part of the system is going to affect the whole system. So, is your team ready for this added complexity?
Are microservices evil then?
No, microservices are not always a bad idea. The intention of this post is to highlight common misconceptions about microservices, that they’re necessary for scale, that they always lead to better code, and also draw attention to the complexity that a distributed microservices architecture introduces.
Of course, there are times when a microservices architecture is a reasonable choice. But that’s another blog post.