In this article I would like to cover industry’s hype on ‘Microservices vs Monolith’ debate and also try contemplate “how to make that hard decision” in this modern software era.
What is a Monolith? Is it Bad?
Monolith is not all that bad, don’t jump to any conclusions yet, read this post before you can reason out. Let us see how industry leaders define ‘Monolith’ as
A monolith is an architectural style or a software development pattern – see below common Monolithic style.
- Compile Time, The Code Units and their Relationship
If you have all of the code for a system in a single codebase that is compiled together and produces a single artifact. The code may still be well structured (classes and packages that are coherent and decoupled at a source level rather than a big-ball-of-mud) but it is not split into separate modules for compilation. This is called Module Monolith.
- Software and its Environment.
If you have all of the code shipped/deployed at the same time. In other words once the compiled code is ‘ready for release’ then a single version is shipped to all nodes/VMs. All running components have the same version of the software running at any given point in time. This is independent of whether the module structure is a monolith. This is called Allocation Monolith.
- Component Structure and their interaction during Runtime
If you have a single application or process performing the work of the system i.e multiple services under one umbrella service/system which may or may not have multiple external dependencies. Many applications have traditionally been built like this. This is called Runtime Monolith.
Martin Fowler described this quote in his blog about Monolith – makes sense yeah, agree?
…don’t even consider microservices unless you have a system that’s too complex to manage as a monolith. The majority of software systems should be built as a single monolithic application. Do pay attention to good modularity within that monolith, but don’t try to separate it into separate services.
Now lets look at microservices, yay!
What are the pros and cons of monoliths?
- Limited Agility
- Obstacles for CI/CD/Testing Automation
- One Technology Stack – so boring, really?
- Technical Debt – yup! big one for me!
- and more… you know it already 🙂
What are Microservices? Is it Good?
Microservices is nothing but an architectural style – an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms, often an HTTP resource API. These services are built around business capabilities and are independently deployable by a fully automated deployment machinery. There is bare minimum centralized management of these services, which may be written in different programming languages and use different data storage technologies.
Why someone would want to build Microservices?
- Service Model is around business domain – package structure and runtime dependencies are around business domain. To build services for business functions/verticals rather than end-to-end system.
- Testing and Automation (CI / CD / DevOps Culture) – easy because it is small to manage compared to those N-layers in ‘big-ball-of-mud’.
- Abstraction (hiding implementation details) – nothing new here, as OOP we always define interfaces, abstract classes, classes, etc..
- Decentralise everything – the services are still logically coupled, no matter how you split them.
- Autonomy (deployed and monitored independently) – easy to benchmark and fine tune each services
- Isolate blast radius / failures – now that’s potentially a good thing. If one module “fails”, you can just display “sorry, this functionality isn’t available right now” and handle the failure.
- Graceful degradation is another important aspect of microservices.
How does the above compare to monolithic world?
- You can automate the deployment of any application. Blue-Green Deployment for Monolith.
- Abstractions in the form of microservices brings network overhead whereas in monolith it is all in the same process/machine.
- ‘Decentralized’ is just a thing that sounds good, but in practice means nothing in this particular context.
- ‘Deployment Autonomy’ alone doesn’t give you anything over a monolith – where you can gather metrics (e.g. with statsd) or get profiling and performance information about each class or package or routine.
- Graceful degradation can be handled by monoliths too, it would require a little bit of extra code – e.g. feature toggle in case of failures
Other benefits such as “easy to modify” and “easy to understand” were claimed and hyped. But again, a well written, structured and tested monolith can be as easy to understand and modify. Software engineering, CI/CD, infrastructure management / Docker containers and other best practices are claimed to work very well with microservices, while in fact they work perfectly fine with a monolith.
Kewl, I’m not saying go and build monolith, read further.
But, why Microservices is also scary?
- Coordination between services – most often asynchronous, message based, orchestration adds complexity
- Sharing of Common Data – needs disciple, good architecture and engineering practise, and we can’t oversee the necessity to keep duplicated data in sync
- Lack of Transactions – CAP Theorem, Consistency vs Eventual Consistency
- Communication overhead – network overhead, all the serialization and deserialization, require reliable and fast network connections
- Usually hosted on Docker Containers which has CPU overheads
- Need for Service Discovery – The dynamic nature of a service’s endpoint address is handled by service registration and discovery.
- Can’t do lift and shift of existing codebase or application – need to be re-architect and re-design which often requires new CAPEX.
- Team communication overhead – updates in one team’s service does not break another’s team functionality
- Formal documentation overhead – to keep updated schemas and interface documents all the time
- Polygot technology stack – it leads to a problem of non uniform application design and architecture. It can increase maintenance costs in the long run.
- DevOps complexity – due to several moving parts of the application, it becomes complex and requires a level of expertise.
- Network security – Inter service communication needs to be secured to avoid any security breach. Due to several moving parts, these applications are more prone to security vulnerabilities.
- Testing of such applications is definitely harder in comparison to monolith applications. Plumbing all services, coordinating data store from production backup from production, configuration and coordinating testing efforts across various teams and their services will be a challenge.
So why choose Microservices? when to use?
There are real use cases for microservices, see below.
- Multiple Teams – Geo-separation, component autonomy,
- Team Skills – Technology Diversity, Multiple Programming Language, Framework
- Reversibility of a component architecture – R&D, Innovation and embrace fail-fast
- Short-lived, Spawned Workers – micro components, utility components
- Memory or CPU Intensive Components/Services
- To break synchronous, long running ‘Chain of Services’ (i.e. Service A ↔ Service B and Service B ↔ Service C) to a scalable asynchronous architecture.
Microservices architectural pattern has well-known advantages and can certainly help any business evolve faster as long as they can operate them efficiently. Consider the operational requirements of microservices in addition to the benefits before considering refactoring monolith to a microservices architecture. I think Architects need a take a middle ground – wisely choose monolith over microservices if your application isn’t complex, doesn’t churn drastically, doesn’t involve too many development teams. But let’s accept the fact that monoliths will stay with us for foreseeable future in this modern software era.