Software Monoliths for Scale
Date: 2023-03-15 | technology | monoliths | software-architecture | simple-scalable-systems |
For years text books, university classes, and conference talks have preached that microservices are better than monoliths. I believe this is wrong for 95% of usecases.
In this post I'll dive into 3 reasons why Monoliths scale - often better than microservices.
Monoliths are Simple Scalable Systems
My primary philosophy for building software / businesses is to focus on Simple Scalable Systems. These are good strategies for 95% of usecases.
Over the past few years / decades, microservices have largely been sold as a panacea for many org's problems - from scalability to dev productivity.
But most orgs don't actually have these problems and if they do they often don't outweigh the new problems microservices bring with it.
The first reason why Monoliths scale is that they're generally simpler to understand. Simple systems are easier to understand which often translates into being easier to build, maintain, change, evolve, etc - all common activities we need to perform on software.
A few reasons for monoliths being generally simpler:
- All code is in one codebase - This makes it easier for code sharing (no packages needed), type sharing, integrations (call a function vs needing a network request), etc
- Less deployments overhead - Most monoliths are literally one blob of code. This means deployments is literally to serve this blob. As number of blobs increase, so too does the complexity to actually get this stuff running in concert.
- Easier to test end-to-end - Another benefit of having a single code blob and deployment process is that we now only need to spin up that blob to get a full working dev environment. Working dev environments that mirror prod are crucial to verifying whether code works or not - I've been consistently surprised how many orgs are unable to do this.
Examples where microservices are not simple:
Most companies that move to microservices typically need to invest heavily into new Developer Experience and Site Reliability roles to scale from one codebase to dozens+. This adds overhead on the entire dev process from integrating with core services (auth, logging, experimentation, etc) to figuring out how to test the full software suite to even getting new code deployed.
For microservices to make sense, you really need to make sure the benefits are worth the added complexity overhead.
For most companies, speed is the biggest problem / bottleneck. The world constantly changes and evolves and if your company can't keep up it'll lose ground to competitors.
For startups still trying to find product-market-fit, this problem is often more existential. You have a finite amount of cash to use to create a working business model so the slower you iterate the less chance you have of surviving.
Simplicity typically leads to faster code iterations because easier to understand code typically leads to easier to change code and changes tend to come with less bugs. This is a large reason why simplicity is a core part of my Simple Scalable System philosophy.
So because monoliths are typically simpler than microservices we can say that monoliths are typically faster to iterate on thus more directly solving a core problem for more orgs / usecases.
A common example where microservices are slow:
We spend a lot of time architecting and building / migrating to an extremely scalable microservices architecture, complete with full dev environments and robust deployment pipelines. That's awesome but if extreme scale is not your company's primary problem then this was likely premature optimization.
Monoliths have a bad reputation for scale. But the truth is that modern machines and clouds are consistently getting faster and cheaper to run meaning standard horizontal scaling techniques are getting better and better. This seems to mean that over time monoliths are going to get better at scale and they're already pretty fast.
Microservices can reach extremely scalable architectures that monoliths would be hard-pressed to reach. But they also come with a lot of other overhead costs that make them far from free. In many cases, microservices can actually be detrimental to the overall system as we move same-machine calls to require extra network requests in-between. The compute wins of microservices must outweigh the network overhead for this to make sense - this often makes sense in small, compute-heavy parts of an architecture but doesn't apply to the majority of usecases.
If the whole reason you want to move to microservices is the benefits of scalability but monoliths are scaling well-enough, then you're just incurring extra costs for little actual benefit for your usecase.
Example where monoliths scale: Meta / Instagram runs primarily on monoliths. Compute-heavy jobs (like video encoding) get moved out into their own services but a vast majority of standard application code lives in these giant horizontally-scaled monoliths. _Source: I worked at Meta / Instagram for 3+ years and this official Facebook interview from 2019.
Should you use monoliths or microservices?
The answer as always is it depends.
- For most: Monoliths (Simple Scalable System)
- For some: Microservices if extreme scale, code isolation is a core problem for your org
- You will know when microservices makes sense - when the pain of monoliths is enough to incur the costs of building and running
Personally I like to build service-based monoliths. This is a hybrid architecture that uses monoliths as a primary building block but breaks it out into large services as appropriate to help with simplicity and scale.
You can learn more about the architectures and boilerplate I use for most projects in Up and Running with CloudSeed (F# / SvelteKit boilerplate)