Microservices surely have to be one of the most mis-understood technologies of our time. Plenty of people use the term, often without really understanding what they are. They’re definitely one of the current crop of buzz words, but what exactly are they? In this article I will attempt to demystify microservices and explain their uses, and when and why you would use them.
There is a misconception that microservices are simply lots of web services. This is wrong. Building microservices is hard. Very hard. They add complexity to an application. They require skill and a deep understanding of distributed architectures to get right. Oftentimes, a well built monolith will outperform an application built using microservices because it was not designed and architected correctly.
They take longer to build due to their complexity, and can be extremely difficult to debug and diagnose errors when things go wrong as there are now many more moving parts to your application. Attempting such an approach should not be taken lightly.
Make no mistake, many teams have attempted a microservices approach and failed. They’ve ended up instead with a poorly constructed application that doesn’t deliver on any of the benefits they were expecting. Even Amazon, Spotify and Netflix (which all use microservices in their applications) made many mistakes along the way from monolith to microservices. Companies with the resources of these huge tech giants made mistakes on their journeys.
I say all of this to make it clear that microservices are not a silver bullet and building an application using them is fraught with challenges and difficulties. In a monolith you have a single threaded application that is deployed as a single entity. In a microservices approach, you may have dozens of entities deployed, and each of them communicating with each other in a loosely coupled architecture. The complexity of such an application is exponential.
What is a microservice?
There are many definitions that can be found on the internet, so instead let’s focus on their common characteristics.
- They are completely self contained
- They are organised around business capabilities
- They aid in the componentisation of an application via services
- They are products not projects
- The have de-centralised governance
- They have de-centralised data management
- They are designed for failure
- They employ evolutionary design
- They have smart endpoints and dumb pipes
- They employ infratructure automation
A microservice is a self-contained service that is concerned with a single business capability that is designed for failure. They operate in concert with other microservices so that together they can deliver value as a cohesive application.
They are self-contained in the sense that they can and should be deployable completely independently of any other microservice. They are loosely coupled and therefore do not communicate directly with any other microservice. Instead they use messaging patterns such as Publish-Subscribe, Queues, Message-Buses etc. Since none of the other microservices communicate directly with each other, they can be deployed completely at the discretion of the team that built it. In fact, this is key to their success.
If the deployment of your microservice needs to be negotiated with another microservices team or the business then you’re doing it wrong.
Independent deployability is the key success factor with a microservices approach and is certainly one of the most important measures of your maturity building them.
To make it even clearer how independent a microservice should be, they should have their own source code repository, database and be built using their own set of tools and technologies. One microservice may be built using Java with an Oracle database, and another may be built using C# with an MS SQL database. It doesn’t matter because they can and should be completely independent from each other.
They can and should be deployable on their own release schedules without consideration to any other release schedule or to any microservice that may be consuming it. If designed correctly from the outset using a loosely coupled architecture, then nothing ever communicates directly with it anyway.
Building microservices is not just a change in your technology and how you design your application. It will also change how you organise your development teams. Your teams should be organised around the microservice they are responsible for building, not the monolithic applications from before. Your teams need to be completely independent, and have their own developers, testers and product owner. The product owner needs to have the authority to make decisions without having to gain the consensus of other areas of the business. The teams that build microservices also need to be completely independent. One team per microservice. Each team usually having between 6 to 12 people.
Your teams, and by extension your microservices should be grouped around the notion of a bounded context. A bounded context is a term that comes from the language of Domain-Driven Design (DDD) by Eric Evans. A bounded context is the boundary at which you group and design your microservices. All the entities within your bounded context will work in concert to provide the business capability mentioned earlier. Therefore to build microservices well, you need a good understanding of DDD. Your application should be decomposed into bounded contexts that make sense to the business.
Examples of bounded contexts may include shipping, order-fulfilment, stock-replenishment, payment etc. These form the boundaries at which your microservices need to be defined and implemented. Your teams need to be organised around these boundaries.
When should you use microservices?
There is no single answer to this as every application and organisation is different.
- One reason why you might want to choose a microservices approach is to leverage the distributed nature of such an approach, and to benefit from the scale they can bring if designed and implemented well. You can distribute your microservices across your infrastructure to match the priority they have within the application. You may want to deploy your order-processing microservice on your highest tier infrastructure to give them the highest priority. Likewise, you may deploy your shipping microservice on your lower tier infrastructure (the order has been fulfilled at this point). You deploy your microservice according to their priority to the business.
- Another benefit is that a microservices approach can be highly resilient due to their distributed nature. If your monolith fails or encounters a catastrophic problem, it can take down the entire application. This is not the case with a microservices approach. Only the affected microservice will fail. If designed well, the other microservices will be unaware of any failure and will continue to operate. Your microservices need to have retry patterns built into them so that any failure, from transient to catastrophic, doesn’t affect any of the other microservices. In fact, it should be perfectly possible to take a microservice offline for maintenance without affecting the application in the slightest.
Building applications using a microservices approach is difficult and is fraught with challenges. They bring added complexity to an application and require skill to design and build. However, if implemented well your application will benefit from higher resiliency, scale and autonomy. Using them though does not just require a change in your technology, but also a change to how you organise your teams and even some organisational changes. You need to give your teams the authority to deploy their microservices when they choose without any mandate from the business. You need to organise your teams around bounded contexts, not applications. Moving from monolith to microservice is a technical, cultural and organisational change. To stand the greatest chance of success from adopting a microservices approach requires commitment from the whole business.