It’s 2022. If I must tell you what Microservices are, this is probably not for you and feel free to spare your precious few minutes elsewhere. But if you’re that person who is overwhelmed with the success stories of microservices and compelled to get your hands dirty with the ‘panacea’, read on. Let me have the pleasure of disappointing you as well but in a couple of minutes.
Though the thought had been buzzing for a while, the need to pen it down was stamped after a recent, gripping conversation I have had with a couple of people. I was invited to be in a quorum to find an answer to an intriguing question. “What is Microservices and should we follow this architecture for our solution?”
Whilst the first part of the question was easy to tame, the second one stood tall and sensitive. A couple of minutes into the conversation and a few facts were clear.
· The beneficiaries were to apply the microservices architecture to their upcoming product, and they sought an affirmation.
· The quorum had a high number of non-technical presence. And the more ‘technical’ the conversation progressed, the irrelevant it became.
· The long pauses and the absence of queries were unfamiliar with web services, let alone microservices.
I wouldn’t condemn them for not knowing what a web service does or how microservices can benefit or damage them. After all, they were far superior at a job I was awful at. And they were to jump into the microservices wagon, not knowing the awaiting repercussions!
The first time I ever heard the word “microservices” was back in 2013, in a YouTube video explaining the architecture of Netflix services. It was overwhelming and I skipped them without much hesitation. It was too much for someone trying to get into the field of design principles back then. But it soon became an obsession when the new project proposal announced the adoption of microservices. The project’s design was fascinating, and it remains one of the best codebases I have ever laid my hand on.
I will be honest. The broad possibilities of modular design kept the liabilities far away from me. And me being just an ignorant developer, hiding away from the DevOps, added a layer of density. Fast-forward half a decade and I was working with a brand-new product and a brand new set of people. And my days were filled with problems that arose from poorly designed microservices, coupled with amateur DevOps tactics. The dense cloud was cleared soon enough, and I have exposed the fragility of microservices. It also made me look at the entirety of the architecture empirically. Pretty late, but better late than never!
Having seen microservices playing the role of both the protagonist and the antagonist, I exhort myself to be the devil’s advocate. If you’re an architect or a designer leaning towards microservices as a default architecture, I urge you to bite the bullet and ask a few questions to yourself.
Is your application large enough to be broken down into Microservices?
Let’s admit it. Not all applications are large enough to be broken down into smaller services. As the name implies, Microservices is a collection of smaller, individual services with a purpose. In an ideal world, we would expect each service to be a complete application in itself.
Here is a hypothetical representation of the “Cost per Line of Code” comparison between microservices and a monolithic service. Microservices incur a higher cost, even in their lighter form, due to the minimum resources it requires in terms of manpower and computational cost. And the cost is everyone’s concern, and if not, you probably shouldn’t be deciding at all.
Sure, your codebase will grow in future and it may as well add a new domain itself. But you should always remember; a well-designed codebase can always be switched to microservices as and when you approach the threshold.
Do you really need to scale Individual components of the Application?
Let’s assume. Your product owner approached you with an idea of an HRMS application to handle an organization with an employee size of 10k. The technology enthusiast in you had an instant solution: A Microservice architecture.
Sure, this is an extreme example, but you get the point!
One of the major advantages of using microservices architecture is the simplicity in scaling an individual component. We may find tons of applications where we will need the components to be individually scaled, but does your application need this?
Do you have transactions spanned across services?
This could probably be one of the hardest and strategic choices to make. Transactions spanning across multiple services are a liability to the whole architecture. Solving transactions across services means inter-locking between the services, a series of deadlocks that are hard to trace and race conditions that can cripple the health of your services and sometimes even the engineer’s.
REST services are stateless by definition. And they shouldn’t be participating in transactions where the boundary exceeds more than a single service. In the world of high performance, two-phase commits [ 2PC ] is an unnecessary evil. And the SAGA pattern will just add another layer of complexity you weren’t prepared for.
Microservices introduce eventual consistency issues because of their laudable insistence on decentralized data management. With a monolith, you can update a bunch of things together in a single transaction. Microservices require multiple resources to update, and distributed transactions are frowned on (for a good reason). So now, developers need to be aware of consistency issues and figure out how to detect when things are out of sync before doing anything the code will regret — Martin Fowler.
Is it possible to have transactions spanned across services?
But is it worth implementing a chain of actions throughout stateless services?
Is there a need for frequent communication between the services?
On a traditional, monolithic service, each microservice instance is represented by modules within the system. Communication between modules is in-memory and the latency is near zero. The introduction of microservices means that communication has just shifted from in-memory transactions to instructions through the wire.
There are numerous tried & tested solutions available, but they all come with a price — Latency. Moving from an in-memory transaction to network-based communication will change your latency unit from nanoseconds to microseconds. Imagine having three different services talking to each other over a network. Assuming each service call takes 100 ms [ which isn’t quixotic under load ], you will end up spending 300 ms just on the network alone.
And some of the applications are tightly integrated with components and services by nature. The added layer of communication can cause a catastrophic result in applications that process real-time data. Imagine having a communication delay in a surgical suit or on an airline traffic control!
And some more…
· The added complexity — Certainly, complexity cannot be quantified and can only be compared in relative terms. Though the microservices are originally designed to reduce complexity by breaking down the application into smaller pieces, the architecture is complex to deploy and maintain.
· The cost of distribution — Microservices are distributed systems with molecularity. But the same distribution does come with a price. Your monolithic service would have been deployed over a large VM or on a preferred container. But the services need to be independently deployed [in an ideal world] with multiple VMs or containers in the case of microservices. Sure, they can be small in size, but you do the maths. And remember, I haven’t talked about the cost involved in the service orchestration and maintenance yet.
· Adaptation of Devops — Depends on the angle you look from; this could be beneficial or detrimental. DevOps is a widely accepted and proven operational solution. But if you’re part of a smaller organization, building a DevOps team can cause more damage than progress. But if one thing is for sure, you cannot maintain and monitor microservices without the presence of a dedicated DevOps team.
· Tight integrations — Some applications are tightly coupled by nature. Decoupling them to ‘fit in’ within the architecture will be catastrophic.
· Lack of experience — Lack of experience is critical to any problem and they’re not just limited to SOA. But when it comes to microservices, it can enhance the damage due to the abstract definition it holds. If your microservice deployment pushes you onto the backseat by having an order of deployment or crashes when one of the dependency services goes down, you’re already too late.
· End to End testing — A typical monolithic application would let you launch and run your test almost instantaneously. Having multiple services with interdependency will delay the testing without a viable orchestration.
· Chaotic data contracts — Devising and holding the data contracts within the team is tremendously different from sharing them among teams. And when you’re working with microservices, your team may not be in the same region, let alone they all follow the same programming language. Carving out data contracts for special needs will cost you time and space.
· Legacy codebase — Let’s be honest. For most of us, handling legacy codebase is a day to day activity. It is the bread and butter of most organizations. The rapidly changing technology advancements are putting us ahead of the game, and at the same time, it’s also isolating us further away from the legacy codebase.
Are you sure the RabbitMQ framework you just developed works well with your legacy application hosted in an IBM AIX server?
· Debugging distresses — Each service will have its own set of log files to go through. More services = more log files.
Am I here to tell you “Not to use microservices”?
Microservices has maintained well-deserving notoriety from time to time. They have solved the problems that we all thought were insoluble. The Netflix story of adapting microservices has been an inspiration for many. And the list just doesn’t stop at Netflix. Uber, SoundCloud, and the giant Amazon are one of the examples you will find in real-time. And don’t think the success stories are limited to the consumer applications only. I have had my first-hand experience with a US healthcare giant and have been fascinated by the design possibilities every time I open up the source code.
I wouldn’t condemn your credulity if you jumped the wagon half a decade ago. The time was different, and all we can do now is, to be honest about it. But it’s 2020. We burnt our hands enough and we have too many roughhouses around us. By infusing microservices architecture gratuitously, you’re just going to turn your lousy code into an inadequate infrastructure.
I love an enthusiastic programmer. I once was and still am one. They worship what they do and go beyond expectations to solve their problems. But you cannot have the same energy in decision making, which can cost you and the organization a fortune. I’m sorry to disappoint you. Microservices shouldn’t be your default application architecture. They’re not the silver bullet you were looking for. Keep yourself steady with KISS and YAGNI.
As a technology advocate and enthusiast, you’re entitled to have your favourites. However, what makes you prominent is the ability to choose pragmatically when the options are between “the right choice” and “your favourite choice.”
This blog was originally published here: https://medium.com/swlh/stop-you-dont-need-microservices-dc732d70b3e0
(The author of this article is Ebin John, Team Lead- Engineering at Pine Labs. Views expressed in this article are that of the author.)