25 May 2015

What’s so bad about monoliths anyway…?!

Advocates of microservices often use a direct comparison with monolithic architectures to illustrate the benefits. This is a false dichotomy as there are many ways of designing a system to provide greater resilience, easier scaling and flexibility of implementation.

In this context “monolith” is often used as a pejorative term. This is unfair, as a well-written monolithic “core” can provide a perfectly scalable architecture through sharding. It doesn’t have to wind up like a big ball of mud.

Distributing complexity

When you design a monolith you still have to consider how responsibilities are allocated between modules. Code has to be cohesive in that related functionality is grouped together. The difference with microservices is that they apply this approach to independent, autonomous services.

This can have numerous advantages. You can scale aspects of the system differently and adopt technology solutions that are highly specialised for a specific task. It’s easy to make changes as a single service can be refactored or replaced more easily than a monolith.

However, once you start to distribute these responsibilities extra overhead comes into play, mainly related to the fallacies of distributed computing i.e. failed communications, network latency, security implications, and so on. In this sense, microservices don’t eliminate the complexity inherent in systems, they merely distribute it.

Any architecture decision involves a trade-off and there is no “free lunch” with microservices. They come with significant operational overheads that require relatively sophisticated infrastructure automation and monitoring. Interfaces between collaborating components need to be managed, whether you do so explicitly or not. You may have to accept a higher level of duplication as your system boundaries evolve.

Scaling a monolith

Scalability, resilience and agility can be achieved by monolithic architectures too.

A “cookie cutter” approach to scaling can be a simpler way of dealing with load in a system without all the complexity of distribution. High-volume services such as Etsy and Flickr have had success with architectures based on horizontally-scaled monoliths.

These organisations also put considerable faith in continuous deployment where small change sets are being pushed out all the time. This kind of agile, devops-orientated approach is generally associated with microservices but it is by no means exclusive to them.

Many of the problems associated with monoliths often have more to do with bad design and inappropriate process. It’s difficult to make changes. It takes too long to deploy builds. The application cannot scale. All of these issues can affect microservices as easily as they can monoliths and can even be exasperated by the fog of distribution.

A “monolith-first” strategy?

The hype surrounding microservices can be unhelpful as no pattern is a panacea. Caution is the better part of valour here as microservice architectures can only flourish in a particular kind of environment.

You need strong, confident agile teams with the right blend of development skill and operational awareness. You need a decentralised approach to decision making and management that is strong enough to allow it. You also need a fair grasp of the domain that you are working in so you can decompose services sensibly.

Even with this in place there is the danger of premature decomposition to consider. In the rush to create small and focused services you may decompose a system before you fully understand it.
This can give rise to services that are not properly autonomous or loosely coupled.

It could be that a carefully-built monolith is the best way to start a system. If close attention is paid to modular design then specialised services can be gradually re-factored away as the boundaries between them become clearer. After all, it’s always easier to decompose a monolith than it is to make sense of a bunch of tangled mess of prematurely optimised services.

Filed under Design patterns, SOA.