Confused about microservices and want a simple explanation? I’ll break down the pros and cons of both a monolith and microservices architecture and provide some guidance on when to use them.
Why do we need Microservices?
These days, there’s almost a stigma attached to developing a monolith application. How the heck did we get here? Seems like all the talk is about running microservices in containers. If the monolith application is so bad, how did we get away with such an architecture for so long?
I’ve developed and work on some successful monolith applications, so what gives? Should we be thinking of migrating to a microservices architecture? Should we start all new projects with a microservices architecture? These are all valid questions. After all, we all want to build the best software possible.
The truth is that the monolith application still has its place in the software industry. By the end of this post, you’ll be able to answer all those questions and more. For now, I’m initially going to place lots of blame on the monolith to describe the problem we’re trying to solve but afterwards you’ll understand that some problems are just limitations in flexibility. Flexibility you may not need.
What is considered a monolith application?
Very simply, an application (no matter the size) which can only offer its services if deployed as a single deployment unit.
If a single line of code is changed and this necessitates re-deploying the entire application, then you’re working with a monolith!
How did we get stuck with a monolith application?
The monolith is an architectural style composed of several well-known tiers. The most familiar are the graphical front end, the business and persistence layer tiers. These application tiers closely mirror how a company has organized its teams by technical ability.
This organizations division of technical ability into separate teams is what influences the architecture of the application and that is how we came to know the multi-tier monolith architecture.
What’s the problem with a monolith architecture?
Today, clients expect our software to be resilient, highly available and frequently released whether it be to fix a bug, patch a security vulnerability or roll out a new feature. It’s all about flexibility and that’s something the monolith just can’t deliver at the rate needed in today’s demanding landscape. Why?
The fact that our application is deployed as a single deployment unit gives root to several limitations listed below.
- Scaling: Unable to individually scale a business service due to a lack of isolation. If one business service is causing a bottleneck due to increased demand, then the entire application must be scaled. This is more expensive in the long run since you must run on more powerful machines – vertically scale.
- Slow Release Cycle: The fear of the dreaded release date … ALL HANDS ON DECK !!! Why are we so scared of the release date? Mainly because we are re-deploying the entire application. If the new deployment is unsuccessful (I have been part of too many!) then your release date is delayed, an investigation is warranted and your reputation takes a hit. Great shame follows 😉
- Sinking with the Ship: There’s also the risk the application crashes or becomes unresponsive after a successful deployment due to inadvertently introducing some bug like a null pointer exception or endless loop. This could potentially bring down the entire application or make it unusable. Monoliths are more susceptible to go down as a single unit (entire app) therefore are less fault tolerant. In order to mitigate this risk, we slow down the release cycle by deciding on a set of bug fixes and/or new features to be rolled out instead of very small, frequent releases. This has us justify the risk of re-deploying the entire application for at least a larger, useful set of changes. However, the more updates you group together for a release, the more can go wrong! It’s a balancing act. I current work on a project where we release every 2-3 months for this exact reason.
- Technology stack stagnation: The inherent lack of business service isolation can limit the adoption of new technologies. For example: If you wanted to develop a new business service dealing with customer order conflicts in C# instead of Java which is used in the rest of the app. What if you wanted to change database? While possible, this doesn’t always make good business sense, mainly due to the scale of the effort which cuts across the entire application. This discourages us in adopting new technologies that could possibly be a better solution for a new service. Over time, we keep investing in the same technology stack which in many years, might not be the ideal solution anymore as your client’s requirement have evolved.
- Shared Global State: All business services share the same monolith database. This makes it difficult to enforce data hiding as any service can directly contact the database instead (back door access) of going through the business service’s interface. This makes it harder to isolate and hide the implementation of one service from another (requires in-house discipline). Modifications to a shared database can cause a ripple effect of maintenance and side-effects in the application.
How do Microservices solve these Problems?
Microservices consist of multiple independent deployable services. The architecture is no longer split across multi-tier service boundaries which are organized by technical assets. Rather, business services are architected to contain the entire slice of functionality needed from end-to-end.
Example: Suppose you had a Customer profiles service. This microservice would contain the front-end code to display/enter the customer profile information, the business logic and its own data store. All this would be packaged within its very own independent deployment unit!
The big idea here is that each microservice would now be managed by separate smaller teams of experts responsible for it’s entire life-cycle – including deployment. This is an organization alignment shift which moves away from teams that are grouped by technical ability to smaller teams of experts assigned to each microservice. Several benefits are gained as listed below.
- Flexibility: We can deploy our microservice independently and at a higher frequency without the same fear we had with deploying the entire application. Microservices by definition are smaller and focused on a single business service, therefore deploying a new version for a single bug fix becomes a possibility. The risk is mitigated.
- Fault Tolerance: Improved fault tolerance since a failure in a microservice should result in a degradation of a service and not a crash of the entire application.
- Scalability: Each deployable service unit can scale independently from the other microservices. This opens the possibility to horizontal scaling which can help you save costs as you can run on cheaper hardware
- Technology agnostic: You can implement your services with different technology stacks. This can be an opportunity to safely experiment in adopting new technologies and ensuring the right tool for the job is used instead of a one size fits all approach.
- Local State: It’s easier to have an isolated service when you don’t depend on global state – like the single monolith database. Microservices hide their data locally by deploying their own private data source. Some microservices may deploy with their own NoSQL database while others instead choose a traditional relational database to better fit their access patterns
What are the disadvantages associated with Microservices?
The flexibility that microservices brings is great but it doesn’t come for free as various challenges must be overcome . All these challenges come from the fact that we are using a distributed architecture.
The development environment becomes more challenging in running all your microservices on a single developer machine due to hitting hardware resource limits. Perhaps developing on the cloud is something you need to explore if you find yourself surpassing your local resources.
You have to think of data modelling in a distributed architecture where the schema is spread out across all those microservices. Ensuring that we can still perform reporting queries and maintain data consistency via distributed transactions. This is especially difficult when decomposing a monolith to a microservices architecture.
With a monolith, everything is in the same process space so this makes troubleshooting many problems and sharing resources much easier. In a distributed architecture, troubleshooting is much harder! How are you going to figure out where the latency bottle neck is across your cluster of microservices? By definition a distributed architecture will introduce increased latency and therefore you need to be prepared to monitor this.
How are you going to handle logging if a microservice is making API calls over the network to other microservices running on other hardware and across multiple instances?
End-to-end testing is more complex and time consuming as multiple test fixtures for each microservice involved needs to be setup. Added testing for network failures and timeouts need to be considered.
In a distributed system, data is moving outside a single process space and flowing from one microservice to another, security is even more of concern.
What are the advantages of a monolith application?
The fact that a single process is deployed brings along several inherent advantages over its distributed counterpart. Development, testing, troubleshooting, log aggregation, deployment, and sharing code across the application are simplified. Again, this simplification comes at the cost of reduced flexibility, as described earlier.
Should I be using Microservices?
Not unless you have a reason to justify overcoming all those challenges! A microservices architecture is just another option and not the new standard on how to architect your next application. The following Q&A should clarify this.
- Does your application need the flexibility that microservices brings? Not all projects need to be deployed at a high frequency or handle variable scaling.
- Do you have a small team? If so, that’s most likely a bad fit since there is a lot that goes into not only developing and maintaining the service but deploying and monitoring it! New skill sets need to be learned like container orchestration. This can tie up significant resources in a small team and can take away development resouces. A larger team is a much better fit.
- Are you starting a new project? This can also be problematic as the interfaces between the microservices are subject to go under many modifications until they reach a stable maturity level. This causes costly maintenance among affected microservices.
- Who is deploying the application? If the application is a client deliverable and the client is responsible for the deployment then this could be a very bad way to go! Is the client technically competent to run a cluster of containers? Does the client have an operational team in place to ensure the smooth operation of tens or hundreds of microservices spread out over many machines? Are they aware of the hardware implications of running such an architecture? If you answered “yes” to all those questions, then you have a very close and long term relationship with the client and this is an option. Otherwise, no!
- A Great Fit: If you have a big team which needs to deploy a cloud-based application requiring 100% up–time and performing frequent releases then “yes”, that sounds like a great fit!
How big should a microservice be?
That’s really an impossible question to answer! It’s like asking “How big should your monolith be?” or “How many lines of code should an interface have?”. My advice is to keep your interface as small as possible. That will help in keeping your microservices as focused and as small as possible. Size should not be your determining factor, it’s not important. How many microservices can you handle? That’s something that you should be more concerned about.
Summary for Microservices | Simple Explanation For Beginners
Don’t believe the hype, microservices are just an optional architecture for projects that need the extra flexibility. The monolith architecture is alive and well and I would consider it as being the go to architecture unless valid reasons emerge to prove otherwise Nothing is free and microservices is no different. For the right price, you can buy your flexibility!