Most organizations recognize the value microservices can bring, but many of them underestimate the complexity. Often, organizations use the technique where it doesn’t fit, which ends up creating a bigger challenge than they started out with.
To help you avoid missteps like this, let’s look at the nine biggest 'don’ts' to keep in mind when you begin your microservices journey.
Don’t adopt microservices unless you’re ready
Microservices involves moving from a large monolith to a multitude of smaller services, which demands prerequisites that are often overlooked, including:
Complete automation for provisioning servers and infrastructure components
Continuous delivery pipelines that can publish code to those servers
High-quality monitoring infrastructure to keep tabs on the service’s health and enable seamless collaboration
If your organization isn’t equipped or doesn’t have the appetite for these three needs, you’re not ready yet. However, organizational transformation — including building and nurturing autonomous, cross-functional teams — is one of the main triggers for adopting microservices. Our recommendation is to prepare your organization by setting up this structure before you adopt microservices.
Don’t let functional silos hang around
Siloed teams don’t do microservices well, so when you’re rethinking your existing team structures, be sure to:
Make your teams self-reliant to enable speed and eliminate blockers
Build cross-functional teams around business value
Enable effortless collaboration between different teams
Carefully decide on which components can be reused and what should be replicated because reusability can lead to bottlenecks
Of course, reorganizing the way teams work, coordinate and deliver isn’t simple. It requires a lot of time and a major cultural shift, but it’s essential for the successful adopting microservices.
Cross-functional teams with verticals
Don’t be too stuck on boundaries
The general rule of thumb for microservices boundaries is the single responsibility principle: each service does only one thing and does it really well.
In this context, how micro should your microservices be? The answer to that, like most things in life is, it depends.
Your services are too small if:
They only do Create, Read, Update and Delete (CRUD) operations on one entity
They’re tightly coupled with other services
You need to change two services to get one functionality
On the other hand, if your service, even if it began as a single functionality has grown into a small monolith, it’s time to break it down.
Be adaptable when you’re deciding boundaries — use domain-driven design, event storming and nonfunctional requirements to help you make the right decisions.
Don’t share your database
To be a self-reliant team, it’s important for each of the services to own and manage its data. Use domain-driven design principles to demarcate the data responsibilities between the services.
Ideally a service should never talk to the database of another service directly, only through well defined APIs.
Don’t create a distributed monolith
Often, if microservices are too tightly coupled to each other without clear roles and separation, one might end up with a ‘distributed monolith’ — with all the downsides of monoliths but few of the microservices benefits.
If a failure in the downstream service causes other services to fail or if you need complicated choreography to get changes out, you’re probably in a distributed monolith.
You can make services less coupled by:
Using load balancers or circuit breakers for your downstream communication, so the entire system doesn’t come to a standstill if one or two services fail
Using event-driven architecture to create a loose coupling between the services
Building your microservices in such a way that they’re deployable independently
Don’t reinvent the API wheel
When API strategies aren’t well defined, there’s a risk that APIs will become overwhelming for the organization.
Our recommendation is not to create microservices with varying protocols, data encoding formats, library support and so on. This will lead to microservices that use different techniques and frameworks, making them difficult to maintain.
It’s also important to provide a client library for microservices which can be used by their consumers, as it facilitates easy upgrades and versioning.
Don't reinvent the API wheel
Another way to do it is by using a sidecar. A sidecar allows you to deploy the same configuration automatically to each new microservice, giving you central control over anything that goes in or out through that sidecar. In execution, however, it’s highly decentralized and doesn't have computational bottlenecks.
While you’re doing this, though, be careful not to build over-ambitious middleware, where your business logic and orchestration also get built in the same layer.
Don’t take your eyes off observability
Observability is one of those nonfunctional requirements that’s often misunderstood or confused with monitoring.
While monitoring helps indicate what the problem is, observability helps you identify why something is going wrong. It also helps you refine the search space and get to the root cause sooner.
Good observability features two things: debug-ability that allows you to perform root cause analysis and auditability that enables you to trace bugs’ hops across the different services.
Don’t forget about testing
It’s important to test meticulously across all five layers of the microservices testing pyramid:
Unit testing for individual pieces of a class or function
Integration testing for integrated components such as database caches, elastic-search modules or any external services
Component and API testing, looking at external service dependencies
Contract testing to see whether your contract is in place
End-to-end testing to ensure microservices are collaborating with other microservices
Don’t let your tech landscape explode nor be too restrictive
Standardizing the tools or languages you use — like enabling reusable codebases to create an organization-wide library, for example — might accelerate development and deployment processes.
However, it could also limit possibilities — like the times when teams need Python for natural language processing (NLP) or data documentation. Success lies in finding the right balance.
As a team, be careful about providing guidelines that dictate a general direction without killing the spirit of innovation.
Find out more
Watch our webinar on 9 things to watch out for with microservices, for examples of how each of these 'don’ts' apply to real-world projects, explanations of other new concepts and answers to commonly asked questions.
Disclaimer: The statements and opinions expressed in this article are those of the author(s) and do not necessarily reflect the positions of Thoughtworks.