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. In this three-part article, I discuss typical antipatterns with implementing microservices, followed by solutions and suggestions for how to avoid these antipatterns. Part 1 and Part 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.
Part 2: More Microservices Antipatterns to Avoid
Delivery and Operations
Not automating software delivery, testing, operations
If you are successful in implementing microservices, your organization will need to continuously develop and operate hundreds or even thousands of independent services. Doing it manually is wasteful and, frankly, impossible. Additionally, manual interventions can cause quality issues (because humans are not reliable) and slowness (because humans are slow).
To realize the benefits of microservices make sure to automate software delivery, testing, and operations. And do not forget to design and provision for highly reliable, highly available tooling and infrastructure to support this level of automation. Additionally, supporting this level of automation by independent teams requires the supporting infrastructure to provide self-service capabilities so that teams can automate their delivery pipelines, testing, and operations. See below for more about decentralized execution.
Not automating resource provisioning
Getting hundreds of independent services through delivery to production if you aren’t able to programmatically provision resources sounds like a lot of pain, because it is! Yet companies still do it. Besides being wasteful and painful, this often leads to overprovisioning of physical resources.
Save yourself the pain (and money): embrace and operationalize programmatic provisioning of virtual resources – VMs, containers, etc. Or, when you can, avoid it altogether and go serverless!
Not building quality in
Although possible, achieving a high level of testing automation without addressing quality at the source – when the code is developed – is extremely wasteful. Addressing quality at the source is the most efficient and effective way to achieve high quality.
To achieve high quality, exercise “technical excellence” when developing software: unit testing, TDD, BDD, etc.
Not adjusting testing approaches
Testing hundreds of independent services acting in concert to solve business problems requires changes to testing approaches:
- Individual services must be tested to contracts.
- End-to-end functionality can only be tested in production, which, in turn, requires dedicated tooling and feature toggle infrastructure (or equivalent).
- Approaches to test data management must shift to favor dynamic data synthesis.
- Move from a probabilistic testing approach to a deterministic one – see my Don’t Test Your Software article for more details.
If not addressed, these issues can result in coupling of services and significantly diminished quality.
As you are designing microservices, make sure to update your approaches to testing.
Not adjusting user interfaces as your consistency model changes
When it comes to data consistency, microservices architecture favors eventual consistency. As a result, some things that are trivial with monoliths are often impossible with microservices. As an example, see Part 1 about transactions across microservices.
Product interfaces need to adjust to reflect the consistency model supported by the underlying architecture. Otherwise, this can lead to misleading product interfaces and data quality issues.
As you design your microservices architecture, be explicit about data consistency models, and make sure product properly reflects them.
Not decentralizing execution
Microservices, by definition, are developed, delivered, and operated independently of each other. Often, this is not possible in organizations with traditional operating models and traditional technical governance. Things that often get in the way: rigid hierarchies, shared services organizations, strict technical governance, release and compliance processes, etc.
Without addressing the operating model and governance up front, you run the risk that your microservices won’t be able to execute independently of each other. Even though the architecture might be perfectly decoupled, the execution will still be monolithic.
Addressing operating model and governance requires strong support from executives in charge of the organization and takes a long time to implement. Make sure to address these issues up front.
Organizing around software components or technologies
Teams should be organized around business capabilities and services that support them. If teams are organized around software components or specific technologies – as is most often the case – they end up supporting multiple services, creating a train wreck of execution dependencies between teams. This couples execution (development, delivery, operations) of services and kills speed.
To realize the benefits of microservices, organize teams around business capabilities and services that support them.
Keeping development teams and business separated
Organizing teams around business capabilities allows them to be closely aligned with business. Preventing close collaboration between business and development teams is a lost opportunity to improve speed and quality of value delivery to the end user. It can also lead to unnecessary churn and waste.
To improve speed and quality of value delivery to end user, make sure development teams and business collaborate closely around business capabilities.
Not setting people up for success
Proper implementation of microservices requires people to develop new skills including:
- New responsibilities on cross-functional teams – development, testing, delivery, operations, etc.
- Architecting for scalability, resiliency, cloud
- Domain-driven design
- Technical excellence practices – Unit Testing, TDD, BDD, etc.
Yet we often see organizations not investing in people enablement and development, which results in poor quality, poor architecture, and not achieving the expected benefits of microservices.
As you embark on microservices journey, invest in people skills to make sure the team is ready.
Not governing technical evolution in the organization
In a highly interconnected system, managing the evolution of services and technologies across the organization – versioning, technology lifecycle, end of life processes, etc. – becomes critical. When ignored, these issues can result in the accumulation of technical debt and can create unnecessary dependencies across services. This, in turn, leads to decreased speed of execution.
To keep your system in good health proactively manage evolution of services by developing the necessary procedures and protocols.
Not managing security
Microservices often create a multi-technology, polyglot environment. If not actively managed, this can increase security exposure and increase the number of attack vectors.
Additionally, people often combine microservices re-architecture with their first forays into public cloud, which introduces the need for different approaches to security.
When implementing microservices, make sure to develop and enact a proper security strategy and implementation.
Microservices Done Right…
Summarizing the points from the previous two parts of this series, your microservices architecture should have the following characteristics if you hope to achieve the expected benefits:
- Services are scoped around business capabilities
- Services are small, focused
- Service internals are encapsulated and are not visible to other services
- Services integrate through formal APIs with proper contracts, versioning, serialization, transport, etc.
- Architecture is designed for scalability
- Architecture is designed for resiliency
- Architecture is ready for the cloud, even if not planning to go to the cloud in the short term
- Inter-service communication patterns are established
- Design incorporates supporting communications infrastructure (gateways, service meshes, event buses, etc.)
- An organizational operating model is established to:
- Facilitate decentralized execution
- Facilitate technical evolution
- Support cross-functional teams organized around business capabilities, collaborating closely with business
- Cross-functional teams are organized around business capabilities, supported by services
- Services are developed, delivered, and operated independently of each other
- Technical excellence practices – unit testing, TDD, BDD, etc. – are employed
- Software delivery is automated
- Testing is automated
- Resource provisioning is automated
- Operations are automated
- Security is actively managed and integrated into software lifecycle
Getting your microservices implementation right requires an investment in architecture, delivery, and organizational models. However, if you do it right, you can see significant benefits for your organization, which I will quantify in Part 3 of this series. And don’t forget I’ll 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.