What’s the deal with this microservices thing everyone talks about?
If you go to a developer conference next week, chances are that half of the talks will be about microservices (the other half about new and hip programming languages). Microservices are hot and trendy in the industry, some might even say a bit too trendy. But what are they?
Martin Fowler writes this short definition (here):
The term “Microservice Architecture” has sprung up over the last few years to describe a particular way of designing software applications as suites of independently deployable services. While there is no precise definition of this architectural style, there are certain common characteristics around organization around business capability, automated deployment, intelligence in the endpoints, and decentralized control of languages and data.
That’s a good starting point in order to understand what they are, but let’s elaborate a bit. As Martin writes, there is no precise definition so see this as my biased and opinionated view of microservices. That’s true about most of the things in this post, I am not trying to convey some unquestionable truth here, I’m merely sharing my thoughts and experiences.
Organized around Business Capabilities
This means that one service, or a set of related services preferably owned by a single team, can process an entire business capability (“A customer signs up”, “A customer places an order”, “A reminder is sent by email”). The main driver for this in my opinion is to facilitate autonomous, cross functional teams that take complete ownership of business capabilities. Coordination efforts are reduced, thereby reducing the risk of bugs and increasing the speed of change.
The opposite of this strategy would be to organize teams and services (this goes hand in hand, see Conway’s Law described by Thoughtworks here) around technology layers. With this strategy implementing the “A reminder is sent by email” feature might involve the UI team, the DBA team, the invoicing team, the email/communications team etc. Expect blockers to show up on many of those teams’ scrum boards.
Won’t this lead to duplicated code if many services want to send emails? Yes, potentially. If you are duplicating business logic, stop doing that and create a new service. But for everything else, Please Repeat Yourself. The cost of duplicating a bit of code is a lot lower than the cost of introducing tight coupling through something like shared libraries (bye bye autonomous team). As with most everything there could be exceptions to this rule for cross cutting concerns, but unless your business is creating a framework stay away from building shared libraries as much as you can.
Automated deployments
I wouldn’t say this is something specific to microservices, I would actually hope that you have automated the deployment of your monolith as well. But with microservices, it’s essential or you will never get anything done.
With microservices, doing continuous deployment is a lot more feasible than with a monolith. Continuous deployment aims at decreasing the time between developing a feature and it being rolled out to end users, taken all the way this would mean that you deploy a new version into production for every push to your version control system (given that the change passes all your quality assurance steps in the pipeline). With this strategy, you will likely deploy new things into production many times per day. Benefits include greater speed of change and lowered risk by keeping every change small.
Microservices are independently deployable, meaning that you would only need to test and deploy the services (all owned by your team if you’re lucky) involved in that business capability. With a monolith you would typically need to deploy and test the entire system as a whole, again leading to lots of coordination and lead time (you can’t deploy right now because some other team is currently rolling out their new feature).
Intelligence in the endpoints
Also sometimes described as Smart endpoints, dumb pipes. This basically means that all logic resides in the services and not in the transportation layer (which is the case in the centralized ESB of the SOA world).
Decentralized control of languages and data
With microservices, each service can be highly specialized and you can choose to implement it using whichever programming language you want. The same is true about how you store data. Each service owns it’s own data and the only way for other services to access that is via an API (or by consuming events produced by the service), meaning you can choose MySQL, MongoDB, ElasticSearch or whatever best fits the need of the service.
This being said, I wouldn’t recommend that you build your 20 microservices with 20 different languages and 20 different databases, for many reasons. But you have the option to.
Benefits of using microservices
As I see things, these are the main benefits of implementing a microservice based architecture.
- They facilitate autonomous teams and fast iterations.
- The services are independently deployable, can be highly specialized and can be scaled independently (vertically and/or horizontally).
- If done right (please read up on cascading failures, circuit breakers and bulkheads) the risk of total system outages is reduced.
- The smaller, single purpose (business capability!) microservices are easier to reason about.
Challenges
There are lots of challenges with a microservice based system and I would certainly not recommend it for everyone. There are many factors to consider, e.g.: the size and experience of your engineering department and the company as a whole, your ways of working and the way you communicate, where you are running the system (cloud provider or bare metal?) and of course the product itself. I won’t go into that in this post, but the main challenges I’ve seen are:
- Things will fail (hello network) and if you don’t expect it to, bad things will happen.
- If you want your system to be highly available it will most likely be eventually consistent (see the CAP theorem to understand why), which can be hard to wrap your head around at first.
- Monitoring becomes (even more) crucial. And tricky. You might want to have a look at things like Prometheus and Zipkin.
- Debugging production issues becomes harder. Spend some time on standardizing logging and use some kind of correlation id that propagates through the system and ties things together.
- If you fail to organize services around business capabilities you will end up in coordination hell.
- Testing is tricky and there will probably be as many opinions as there are employees. What do you test before rolling something out to production? Just the service you’ve changed with all it’s dependencies mocked/stubbed? A set of services together? The entire system together? This deserves an entire post (at least) by itself.
In short, writing a robust system which can change quickly and frequently is a tough job with a microservice based architecture. Don’t attempt it unless the benefits outweigh the challenges.
Stay tuned for more posts on why and how we plan to use microservices and things like event collaboration and CQRS to fight corruption. I’m sure we’ll struggle, and we’ll let you know about those struggles as well.