Old school architectures making a return, part 1: Monoliths
Over the last decade, microservices have dominated the software landscape, but could we see a retracement of their use? I think this is almost a certainty.
Cloud native architectures brought about the technical viability of microservices. But what technical problems do they actually solve, and are monolithic architectures more viable under some circumstances?
Let’s answer the first question first:
There are very few technical reasons to use microservices. They are almost always a solution to a people problem: a means to scale an engineering organization without unfeasibly large and unproductive teams. They allow us to split an organization into multiple teams, all owning their own domain or slice of the company’s concerns.
It is no coincidence that microservices rose to prominence during the ZIRP (“Zero Interest Rate Policy”)-era: when Venture Capital was abundant, the capital needed to be used, usually to grow engineering. Growing engineering meant multiple teams needed to be created (we all know how detrimental massive teams are to productivity).
Microservices allows us to solve the problem of organizational growth, it answers the question of how do you split work across multiple teams, when multiple teams become necessary due to workload and headcount growth?
Surely, there are technical merits to microservices?
Yes, I can think of a few technical reasons for splitting into services, apart from organizational growth:
Independent scaling - you may split services based on read and write boundaries, if one is more performance intensive than the other. This allows us to scale services independently.
Observability - if you are at the top of your observability game (very few are!), the smaller functional surface of microservices allows us to more easily diagnose issues as they arise.
Distinct domains - perhaps the most obvious case, some things are simply completely distinct domains, and should be separate. However, experience tells us, that microservices frequently slice adjacent or related domains slightly wrong.
What are the issues with microservices?
Microservices come with several drawbacks:
Observability is challenging - I mentioned this as a benefit, but it is also a drawback. Very few organizations have the observability and ops maturity to pull off microservices.
Cascading reliability & coupling - many organizations set reliability goals, such as “99.9% uptime. But what happens if services are coupled, and multiple services with the same reliability goal need each other? Simple arithmetic dictates that the reliability goal becomes impossible to achieve: 0.999*0.999*.999 is less than 99.9%.
Poor industry understanding of asynchronous interaction patterns - leading on from the previous point: ideally, microservices should prefer asynchronous communication as much as possible, so they survive downtime of adjacent services. In practice though, people frequently implement synchronous RPC or REST interfaces, thus increasing coupling and overall system fragility. This is often done in the name of “simplicity”, simply because there is insufficient understanding and appreciation of asynchronous communication.
API impedance mismatches, performance issues & fragility - What one service provides to another does frequently not line up with what the user requires. This might lead to n+1 interaction patterns or worse (I’ve seen bulk downloads hammer services!). Not only that, but services must also consider API versioning and how changes may be breaking. It’s not uncommon to see breakages because some API or protocol was changed unilaterally, without thought to communicate changes and plan a migration path.
Lowered productivity - should come as no surprise that all of the above contribute to lower productivity, compared to working in a monolithic codebase. Even if under the control of a single team or empowered to make changes in adjacent services, working on multiple codebases across network boundaries is slower.
Are monoliths the answer?
Maybe, sometimes, it depends. Monoliths certainly address most of the issues effectively, and reduce the need for excellence in ops and observability.
One issue of the last decade is that too many organizations have defaulted to microservices without considering why they are doing so. Simply considering why you are choosing microservices, whether it is appropriate given the technical- and productivity costs in the light of your company’s engineering org growth plans. If headcount is likely to remain relatively static, or only grow slowly at times, maybe a monolithic architecture makes more sense.
In conclusion, I think we’ll see a return to more organizations defaulting to monoliths instead of microservices. There is no one-size-fits-all answer to the question of monoliths vs microservices, but moving from an unthinking default, to a considered decision given a set of trade-offs will naturally see monoliths becoming more popular again.
Stay tuned!
This post is part 1 of a four part series on old architectures becoming new again. I will post the next part next week, so if you want to read it first, please do sign up to the newsletter!