Why Microservices Are NOT The Answer For Most Software Development Teams
While there are lots of advantages from scalability to increased speed of development, the complexity often negates those advantages.
Moving to the cloud has enabled organizations to scale operations at the speed of demand. Imagine building Netflix with on-premise data centers, the maintenance and monitoring overhead would be significant - scaling would require a lot more planning.
But just moving applications into AWS, Azure, or other platforms doesn't mean you get scalability for free. What you quickly find out is the bottleneck is often the application architecture.
One particular software architecture that has gained prominence is microservices. The goal is to have individual services based on single responsibility such as a user management system. (The user management system maintains all user account operations). This means services could be:
Built with different languages
Have their own databases (so teams building them could use frameworks they were familiar)
The benefit of this is allowing those services to scale independently. This is a lot better than monolith applications (where all the components are written in a single self-contained application) in the cloud, a single service going down didn't impact the entire application.
The above diagram shows the different benefits of having microservices, and looking at them, it is a no brainer that most development teams would want to take advantage of it.
I’m here to tell you that this is not what you need when developing applications.
I’ve made this mistake, jumping in to using them but below are some hard learned lessons I have learnt about why they are not always the answer.
Issues with Microservices
Let's pair back some of the complexity it means for engineering teams support this architecture.
Security Overhead
When you're scaling fast, it's common to see new services pop up quickly. This is good when trying to roll out features and/or test things.
But these services need to be supported long term by development and DevOps teams. Given the nature of fast paced development, and the push to add news services, often times “failed” or legacy services are not cleaned up properly. This leads to dead services that are no longer used by the applications, but they are still available. From a hacker perspective, that's a great area to target. There's a high likelihood that the dependencies aren't managed and the code is poorly maintained if at all.
Any technical debt of this type should be monitored and planned to be managed (even if it hasn’t been done till today)
One of the other advertised benefits of microservices is that each service can be built with different languages and frameworks. This is great for teams when they're building, but it does introduce overhead for the business. I've seen some unique frameworks that were later deprecated which means the service needs to be reworked. If we scale this problem by thousands of services, it can be a nightmare to maintain software packages and can lead to requiring unique skills when it's not necessary.
If you're using static & dynamic application security tools, these have limits on which languages they support (depending on vendor), and some vendors are stronger with one language over another. Additionally, you're also going to want to manage the libraries used for development using software composition analysis tools, these have similar problems.
Governance at that scale also becomes tricky to manage. While decentralized governance is great for teams as speed improves for development, it can lead to incomplete coverage from a business perspective. Imagine incomplete coverage for compliances, or different encryption practices that could easily lead to security risks. Even inconsistencies in coding practices could lead to poor performance and readability beyond just security.
All of these invoke security vulnerabilities that can result in doing more harm than good.
Intercommunication Complexity
Imagine an e-commerce platform where a user wants to purchase a product, and the system is built using microservices. Take the following example a user selecting “Purchase Now” button on the site. The flow of between services might look something like this:
The Authentication Service confirms the user is logged in.
The Shopping Cart Service adds the product to the user's cart.
The Inventory Service verifies the product is in stock.
The Pricing Service calculates the total price.
The user proceeds to checkout, and the Payment Processing Service processes the payment.
Upon successful payment, the Order Management Service creates a new order record.
The Notification Service sends a confirmation email to the user.
The Shipping Service schedules the delivery.
The Analytics Service records the transaction details for future insights.
The point being communication required between services is significant. The complexity this creates includes:
The process of tracking dependencies
Managing service versions
The patterns required to communicate
By the nature of this architecture, the communication has to be asynchronous, so we need to be concerned about the idempotency of services.
This naturally creates an overhead for monitoring. For instance, the Mean Time to Repair (MTTR) increases as it takes longer to detect and diagnose the underlying problem, prior to repair and recovery which may include multiple services.
Pipeline Management
It's estimated that only 20-30% of repos out there are mono-repo with a single repository housing all code and scripts to deploy. In this case it's easier to set security tooling, stage gates, and best practices for deployment as part of governance.
To get the same level of control (for best practices) in a multi-repo setup is easier said than done, depending on languages and frameworks the scripts need to accommodate, the build process becomes tougher.
Most implementations are actually multi-repo, but that introduces overhead. Each team has their own pipeline, and the complexity of setting up governance processes, or security tooling across these pipelines becomes significant. Another scenario to consider is dependencies between services that might require specific versions to be available, these need to be planned.
So if microservices aren’t the answer, what is?
While it's tempting to build a solution that scales to meet future demand it's not the right choice for everyone. It requires significant resourcing and need to justify this type of architecture (at least properly done).
Other alternatives include:
Standardize with fewer services - one option is to minimize the number of services deployed and harmonize the languages/frameworks. This might even include adopting at an architecture pattern such as Self-Contained Services (SCS)
For smaller teams, look at traditional architecture - these can include monoliths, modular monoliths, or layered architectures. These traditional approaches have worked well and are systems most people have experience with supporting.
For enterprise or high data flow requirements - Service oriented architecture (SOA) or Event-driven architecture are great options. Enterprise teams tend to have legacy systems connected to enterprise service buses and SOA systems predate microservices they perform well in these scenarios. Event driven can be used in tandem with other architectures including monoliths and microservices.
While microservices may seem tempting at first, given its complexities, most development projects (at least in their early stages) can get away with not using them. Disagree? Comment Below on why.





