Microservices architecture has become popular over the last several years. Many organizations have seen significant improvements in critical metrics such as time to market, quality, and productivity as a result of implementing microservices. Recently, however, there has been a noticeable backlash against microservices. Some organizations that have attempted implementing microservices found themselves with more problems on their hands than they expected, sometimes ending up in a worse state than their starting point. As the CTO of a major company remarked to me, “We traded one giant pile of crap for hundreds of smaller piles.”
Most of the time, these problems should not be attributed to the microservices approach itself but, rather, to the mistakes and compromises made during design and implementation. Microservices is a powerful architectural model: it is applicable and beneficial in many situations. But it does come with complexity and requires an investment in architecture, delivery, and organizational models.
Organizations that are considering microservices architecture should be clear about the involved complexity as well as its cost and be ready to embrace them in order to realize the benefits.
In this three-part series, I discuss typical anti-patterns with implementing microservices, followed by solutions and suggestions for how to avoid these antipatterns. Parts 1 and 2 discuss the many antipatterns that my colleagues and I have encountered and suggestions for better approaches. Part 3 introduces ways to quantify benefits of microservices.
- When done properly, microservices architecture can offer significant quantifiable benefits.
- However, when shortcuts are taken microservices architecture can create more problems than benefits.
- Doing microservices properly requires investment in architecture, delivery, and organizational models.
What Are Microservices?
Let’s start by establishing a definition for microservices architecture.
Microservices is an architectural style where the overall system is decomposed into services with the following characteristics:
- Services are small and focused.
- Services are created around business capabilities.
- Services are loosely coupled, meaning the impact of changes is localized.
- Services are developed, delivered, and operated independently of each other.
- Service internals are encapsulated and are not visible to other services. Services interact with each other through formal APIs.
- Business problems are solved by services working in concert.
- No centralized workflow or state management exists – unlike traditional Service Oriented Architecture (SOA).
Avoid the Antipatterns!
We at Accenture | SolutionsIQ have worked with many companies who have adopted or attempted to adopt microservices. While many organizations have successfully gone through the transition and are realizing the benefits, others are struggling. Often, results do not live up to expectations. Sometimes, the resulting state of the system ends up being worse than the starting point.
These shortcomings and failures are not due to the microservices architectural model itself. In our experience, these problems are typically due to mistakes and compromises made during design and implementation of microservices.
Let’s review some of the often seen problems with microservices implementations.
Using microservices where the problem doesn’t justify the complexity
Microservices is a complex architectural model and the cost of complexity is significant – just look at the rest of this article for all the things that need to be setup right! Do expected benefits justify the complexity? Not necessarily. Often, the cost outweighs the benefits.
If the problem is simple and if scale is not required, are microservices really needed? Can the problem be addressed with a simpler architectural approach?
If you are considering microservices, make sure that expected benefits justify the investment.
Attempting to solve the problem with tools
This sometimes happens with established companies that have traditionally relied on COTS (Commercial Off The Shelf) software to solve their technological needs. The question we sometimes hear from companies is “I want microservices, what tool will do it for me?”
There are good tools out there – commercial and open source. And you will need tools to support microservices implementation. But tools are not a substitute for a proper architecture. Be suspicious of any tool that claims to implement microservices for you.
Start with designing the architecture, then find the right tools to support it.
Not architecting for scalability
One of the major benefits of microservices architecture is its ability to scale. However, we sometimes see companies not architecting for scale – typically in the areas of data and state management. While incurring the cost of complexity from implementing microservices architecture, these organizations are not realizing one of its major benefits.
If you are considering microservices architecture, make sure to architect for scalability.
Attempting to preserve the notion of transaction across services
Much time has been wasted by organizations of all shapes and sizes attempting to preserve the notion of database-like transactions across independent services. It never works in the end, wasting time and money.
Worse yet, if not cleaned up, remnants of the ill-fated attempt – whether in the fundamental architecture or in the code itself – can cripple the architecture and prevent scalability and resilience.
If you are reading this and thinking that you can somehow figure this out, you can’t. Make it easy for yourself and everybody else in your organization and abandon the idea.
Transactionality (i.e., immediate consistency) can easily be achieved within the bounds of a service. Across services, eventual consistency is the right approach to use.
Not architecting for resiliency
Another benefit of microservices architecture is its support for resilience. With properly designed and implemented microservices, availability of the application is not impacted at all or is only slightly diminished when failures occur (and they will occur).
But companies often fail to proactively architect for resilience. This can have catastrophic effects. Without proper design and implementation, the architecture can become brittle: local failures can cascade to become larger, even global, failures.
When working with microservices architecture, make sure to architect for resilience.
Not encapsulating data
This should not even be considered microservices, but it’s a frequent occurrence – a service opens its internals to other services. This results in coupling of services, where services can only be developed and operated in a coordinated fashion, which slows the organization down significantly. Additionally, this is often a symptom of poor architecture that is not designed for scale or resilience.
Make sure that services maintain proper encapsulation of data and interact with each other via formal APIs.
Not designing for inter-service communications
With microservices architecture, you can end up with hundreds or even thousands of independent services all needing to communicate with each other. Without proactive planning, this can lead to a hot mess – coupled services and brittle architecture. Results can have a negative impact on time to market, availability, scalability, and resilience.
Make sure to spend the time to design proper inter-service communication patterns to avoid getting yourself in trouble. And don’t forget that supporting infrastructure (gateways, meshes, event buses, etc.) might be required.
Another thing to ponder: excessive communication between services could be a sign that services were not scoped properly and are, therefore, coupled. Read on for ideas for how to properly scope services.
Clinging to Enterprise Service Buses (ESBs)
In practice, microservices architecture requires use of gateways and event buses. To organizations transitioning from traditional Service Oriented Architecture (SOA) these concepts are not new. They are used to similar functionality provided by Enterprise Service Buses (ESBs). As the result, they sometimes choose to retain the ESBs, arguing that, if used properly (i.e., no workflows or state management), it provides a lot of the needed functionality. The problem is that it also brings all the other baggage with it. An organization that is used to relying on ESBs for workflows and state management will almost inevitably revert to its old habits. This results in coupling of services and diminished scalability and resilience. I would go so far as to say that if you have ESB in the picture, you are most certainly not doing microservices.
If you want to transition to microservices, retire your ESBs and replace them with better tools.
Making services too big
It’s not uncommon for people to forget about the “micro” in “microservices” and give services too many responsibilities. As a result, the architecture does not produce the expected benefits.
As you design your services, make sure to scope them well. Good microservices are small and focused around business capabilities. Domain-driven design is your friend.
Making services too small
Breaking services down to the atomic level also leads to problems. A good service is cohesive. When cohesion is lost, services become hard to maintain: besides introducing additional complexity for no reason, natural evolution of services doesn’t match their physical manifestation and, as a result, they become coupled. Why break them up in the first place then?
Make sure to scope services so that cohesion is maintained. Once again, domain-driven design is your friend.
In Part 1 above, I defined microservices and identified typical antipatterns concerning Architecture. In Part 2, we’ll look at even more antipatterns in the areas of Delivery & Operations, Product, Organization, Technical Governance. And I’m excited to be hosting Agile Amped podcasts at the upcoming Deliver: Agile conference in Nashville next month.
Thank you to reviewers and contributors to this article: Matt Lancaster, Paulo Villela, and Ryan Keawekane.