Enable javascript in your browser for better experience. Need to know to enable it? Go here.
Nine common microservices mistakes — and how to avoid them

Nine common microservices mistakes — and how to avoid them

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.

Keep up to date with our latest insights