Microservices vs. monoliths: it's not a competition

JavaScript on a screen.
(Image credit: Pixabay)

In just five years, cloud computing microservices have blossomed into the default architecture for application deployment. ‘Modernizing software’ has become almost synonymous with microservices, for good reason: just look at the massive scalability, flexibility, and agility Amazon, Google, or Netflix have achieved by moving from monolithic architecture to microservices.

But you don’t have to turn everything into microservices. One preconception I’ve personally seen spawn from the microservices revolution is the myth that ‘monolith is bad’.

The Amazon’s Prime Video team recently dispelled that notion when they went the reverse direction, moving their audio/video monitoring service from a distributed microservice architecture back to a monolith application. It helped cut their costs by 90%.

In the aftermath, esteemed tech advisor Adrian Cockcroft humorously observed some dubious takes on the announcement flooding in from the developer community – perhaps best summarized as a mix of surprise and confusion. Was microservices perhaps not the right path forward after all?

Truthfully, it’s the wrong way to think about it because neither microservices nor monolith-based architecture is ‘better’ than the other. It depends entirely on your use case, and it’s not even a case of ‘either/or’. You can do both.

Why microservices-based architecture isn’t always the right answer

The technology allowing us to manage microservices has really exploded over the last decade – for example through containerization via Kubernetes. It’s dead-easy to spin up a Kubernetes cluster.

What’s not easy is taking that cluster to production. You have to make it highly available, secure, fault-tolerant, capable of disaster recovery, properly networked and allow provisions for storage. These aren’t new concerns for software deployment, but with Kubernetes it’s much more complex. Developers from traditional legacy application backgrounds often struggle to containerize applications once confronted with tasks they never previously dealt with on virtual machines, such as specifying the amount of computing resources to be allocated for CPU, GPU, and memory.

Managing a cluster and all its functions is also an ongoing commitment; eventually, you need to upgrade your software. When you do, you have to upgrade all your tools in lock-step with one another – including your observability, networking, storage tools, etc. – and there’s always a risk of compatibility between these tools breaking.

Deepak Goel

Deepak Goel, Chief Technology Officer, D2iQ.

So, it’s not that organizations don’t understand that microservices represent the ‘modern way of developing applications’. It’s just arduous because microservices present a trade-off between complexity and ease of deployment. Split your application too much, or too quickly, and your deployment becomes way more complex by default than it needs to be. Even so, I’ve personally witnessed some of the smartest people I’ve met overprovision and over-engineer their applications.

For many organisations and developers, that complexity is well worth it because of the agility afforded when rolling out applications. With microservices, you can update one specific component of an application – e.g. a logging tool – without touching the rest. But the path there is fraught with complexity. How do you deploy your software? Do you do it manually or through automation? Are your workflows imperative or declarative in nature? Have you adopted GitOps and an API-driven approach? These concepts won’t be super familiar to people not already deeply entrenched in the world of Kubernetes.

By contrast, deploying monolith applications is a lot simpler as you only have to upgrade that ‘one’ binary versus a whole lot of different functions that have been separated into microservices, which each require debugging, troubleshooting, general deployment, etc.

How do you know which part of the application to modernize?

Another big mistake people make when deciding between a monolith or microservices approach is assuming it must be one or the other, when it shouldn’t be a black-or-white situation. You can opt for something in the middle.

Some parts of applications need scalability, others don’t. In a typical application, you’ve got your control plane and data plane. The former is already pretty complex because it contains the logic of your application, and since it also usually contains tightly coupled components or functional units that cannot exist without each other, you might not want to break that plane down into microservices. The opposite is probably true for your data plane. The data plane generally contains independent functional units that can be scaled in proportion to the demand.

And that’s the beauty of a mixed architecture: you can build your application in a way so that its core is monolithic but the other components are microservices-based. What that means is you can mature your application as its popularity grows, i.e increase the proportion of your application that is broken into independent services. If you’re a startup, especially, you don’t need to take on the complexity on Day 1.

Some find this attitude controversial because they don’t necessarily think the conversion from monolith to microservice down the line is possible. It’s true that it’s not easy: components within monoliths make functional calls while components within microservices make API calls. To convert a monolith into microservices, you effectively need to turn functional calls into API calls. The latter has wildly different patterns compared to the former, but if you treat your function like an API and clearly define boundaries, you absolutely can make that transition later in your application lifecycle.

The danger of not going the mixed architecture route (easily done because developers tend to get lazy writing monolithic applications) is that leaning too much towards monolith could curtail your application’s capability to scale up at a later stage. On the other hand, going all in with microservice before it’s really necessary could increase the complexity of deployment early on. Applications built with a mixed architecture have a much better chance of scaling and keeping deployment simple.

For instance Istio, an open source service mesh, initially adopted a complete microservice based architecture so that even the control plan was split into different services which then increased the complexity of the deployment tremendously. Later versions consolidated the control plane into monolith simplifying the deployment while still keeping the data plane microservice based.

Platform engineering can make microservices easier

So, we’ve established that not every part of the application should necessarily be broken into microservice, and it doesn’t have to be on Day 1, but a lot of it will have to be eventually.

I’m of the strong belief that the right way to handle that challenge will be through abstraction, and that developers’ interaction with Kubernetes will largely resemble how a driver interacts with their personal car. As drivers, we never refer to our cars as ‘complex’. The car has everything we need to operate it – from the steering wheel to the brakes, accelerator, etc. We don’t worry about what’s under the hood, because that’s not our role. If it does break, that’s where the mechanics step in.

Kubernetes in today’s software development climate is like a car that asks you to be a master mechanic just to get from A to B. What organizations need to do is recognize not everyone can be that technically savvy – the skills gap the industry faces today simply makes that impossible. They need to instead invest in internal developer platforms that simplify user interfaces for developers, automate the functions of Kubernetes, and hide the inner workings ‘under the hood’ for the other developers who should be focusing on innovation, not maintaining the underlying infrastructure. These platforms should then be maintained by a small, bespoke team of ‘platform engineers’ – the mechanics of Kubernetes – who know the infrastructure inside out.

With that approach in place, the complexity of microservices should seem less daunting, mainly because most of the internal team won’t be dealing with it anymore. But that doesn’t mean you make everything microservices! Technology should serve developers, and by extension, their end users, not be used as a means to flex one’s technical problem-solving skills.

We've listed the best cloud storage.

Deepak Goel, Chief Technology Officer, D2iQ.