When I first mentioned the concept of microservices to my engineering team, I was surprised by how quickly everyone researched the idea and then jumped to the conclusion that our monolith should be split up into tiny APIs that were each responsible for a model in our existing Rails application.
Leaping before looking
From the research I'd done, I knew that it was dangerous to build a bunch of microservices without careful consideration about size, boundaries, and other tradeoffs. But no one on my team seemed concerned about it.
Table of Contents
What I found was that people on my team were jumping to conclusions based on shallow but dangerously firm notions of what a microservice was. They held knowledge that microservices were small API's pieced together to create whole systems. But they weren't aware of the intricate tradeoffs and design considerations that can mean the difference between success and failure. They were pitching architectures with little ability to justify or reason about them.
Why does this happen? And what is a microservice, anyway?
What's in a name?
For a profession that stresses the importance of naming things well, we've done ourselves a disservice with microservices. The problem is that that there is nothing inherently "micro" about microservices.
Microservices do not have to be small.
Some are, but size is relative and there's no standard of unit of measure across organizations. A "small" service at one company might be one million lines of code while far less at another.
The misconceptions don't just affect people who want to use microservices, it also stokes the fires of those that dismayed by the industry hopping on the microservices bandwagon without deep understanding of its concepts.
What is a Microservice?
There’s a lot of ambiguity around what microservices are in part because no precise definition exists. Like Agile, microservices are a collection of broad concepts rather than concrete practices.
The term "microservice" was discussed at a workshop of software architects near Venice in May, 2011 to describe what the participants saw as a common architectural style that many of them had been recently exploring. In May 2012, the same group decided on "microservices" as the most appropriate name.
Today’s leading definitions are fairly well aligned:
- Microservices are small, autonomous services that work together. - Sam Newman (ThoughtWorks)
- Fine grained SOA architecture done the UNIX way. - James Lewis (ThoughtWorks)
- Loosely coupled service oriented architecture with bounded contexts. - Adrian Crockford
In short, the microservice architectural style is an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms, often an HTTP resource API.
These services are built around business capabilities and independently deployable by fully automated deployment machinery. There is a bare minimum of centralized management of these services, which may be written in different programming languages and use different data storage technologies.
The problem with these definitions is that while they are helpful for introducing the idea of microservices, but when it comes to time put them into practice, they are not very helpful.
Using these definitions, how would you determine whether it makes more sense to have 10 tiny services versus five medium-sized ones?
Ambiguous descriptions of microservices aren’t useful other than as an introduction. When it comes time to put microservices into practice, you need to find other ways to align your team.
The most important thing when talking about microservices on a team is to ensure that you are grounded in a common starting point.
How do you align your team when no precise definitions of microservices exist?
On one team I worked on, we tried to not get hung up on definitions and instead, we first focused on defining the benefits we were trying to achieve by adopting microservices:
Shipping software faster
Our main application was a large codebase with several small teams of developers trying to build features for different purposes. This meant that every change had to try to satisfy the different groups. For example, a database change that was only serving one group would have to be reviewed and accepted by others that didn’t have as much context. This was tedious and slowed us down.
Having different groups of developers sharing the same codebase also meant that the code continually grew more complex in undeliberate ways. As the codebase grew larger, no one on the team could own it and make sure all the parts were organized and fit together optimally.
With a microservices architecture, we hoped to be able to divide our code up so different teams of developers could fully own them. This would enable teams to innovate much more quickly without tedious design, review, and deployment processes.
Flexibility with technology choices
Several parts of our application were hitting major performance issues that were difficult to fix and bringing down the rest of the application with it. We saw an opportunity to rewrite these parts of our application using a better approach, but inter-tangled our codebase was with the affected areas, this felt too big and costly to do. As time went on, our teams grew frustrated with the feeling of being trapped in a big codebase that was too big and expensive to fix or replace.
By adopting microservices architecture, we hoped that keeping individual services smaller would mean that the cost to replace them with a better implementation would be much easier to manage. We also hoped to be able to pick the right tool for each job rather than having to go with a one-size-fits-all approach.
We’d have the flexibility to use multiple technologies across our different applications as we saw fit.
Honestly answering tough questions
In addition to outlining the benefits we hoped to achieve, we also made sure we were being realistic about the costs and challenges associated with building and managing microservices.
Microservices involve distributed systems which introduce a whole host of concerns such as network latency, fault tolerance, transactions, unreliable networks, and asynchronicity.
Once we defined the benefits and costs of microservices we focused on the core problems we were trying to solve.
- How would having more services help us ship software faster in the next 6-12 months?
- Were there strong technical advantages to using a specific tool for a portion of our system?
- Did we foresee wanting to replace one of the systems with a more appropriate one down the line?
- How did we want to structure our teams around services as we hired more people?
- Was the productivity gain from having more services worth the foreseeable costs?
Our experiences taught us a great deal about achieving alignment on the seemingly unwieldy topic of microservices. In summary, here are the recommended steps for aligning your team that is jumping into microservices:
- Learn about microservices while agreeing that there is no “right” definition.
- Discuss and memorialize your anticipated benefits and costs of adopting microservices.
- Avoid too eagerly hopping on the microservices bandwagon–be open to creative ideas and spirited debate about how best to architect your systems. Stay rooted in the benefits and costs you have previously identified.
- Focus on making sure the team has a concretely defined set of common goals to work off of. It’s more valuable to discuss and define what you’d like to achieve with microservices than it is to try and pin down what a microservice actually is.
Definitions matter, but when it comes to microservices, trying to settle on a precise definition isn’t necessarily a good use of your team’s valuable time. Instead, focus on functionality and costs and benefits. Keeping your discussion about microservices grounded in what you’re actually trying to achieve will allow you to determine whether the microservice architectural style is right for your team.
For more content like this, check out our free eBook, Microservices for Startups.