84. Trade-Offs in a Microservices Architecture – 97 Things Every Java Programmer Should Know

Chapter 84. Trade-Offs in a Microservices Architecture

Kenny Bastani

Is there an optimal software architecture?  What does it look like? How do we measure “optimal” when it comes to building and operating software? An optimal software architecture is one that has maximal flexibility for change at the lowest possible cost. Here, cost is measured in terms of certain qualities that represent a software architecture’s design and implementation—in addition to the cost of the infrastructure to operate it. The defining trait of a software quality is that it can be tangibly measured and has an impact on other qualities.

For example, if a software architecture requires strong consistency guarantees, there is an impact on qualities like performance and availability. Eric Brewer created the CAP theorem to describe a set of measurable trade-offs where you can only choose two out of three guarantees for running a database: consistency, availability, and partition tolerance. The theorem states that when applications share state across the boundaries of a network, you must choose between consistency or availability, but you cannot have both.

One of the main problems with microservices is that there is no single comprehensive definition. Moreover, microservices are a collection of concepts and ideas that are based on a set of constraints for delivering a services architecture. A microservice, or any piece of software you build, is a history of choices—which will affect your ability to make new choices today.

Microservices may not have a single definition, but they do most commonly have the following characteristics:

  • Independent deployability

  • Organized around business capabilities

  • Database per service

  • One application, one team

  • API-first

  • Continuous delivery

As you go out into the world of software development, you will eventually find that there is no such thing as the right choice. Indeed, most developers or operators might believe there is a best choice, and you may find that they argue strongly in favor of that choice. As you encounter more and more opportunities to make a decision between multiple choices, for instance, which database to use, you’ll eventually come to discover that all available options introduce certain trade-offs. That is, you will usually have to lose something to gain something.

Here is a short list of trade-offs you might encounter when making a decision to include a dependency for your microservice:

Availability How often is my system available to its users?
Performance What is the overall performance of my system?
Consistency What guarantees does my system provide about consistency?
Speed How fast can I deploy a single line of code change to production?
Composability What percentage of an architecture and codebase can be reused instead of duplicated?
Compute What is the cost of my system’s compute under peak load?
Scalability What is the cost of adding capacity if peak load continues to increase?
Marginality What is the average diminishing marginal return of adding developers to my team?
Partition tolerance If a partition in the network causes an outage or latency, will my application experience or cause a cascading failure?

How does answering one question affect answering the others?

You will find each of these questions often has some kind of relation to the other questions. If you ever find yourself making a tough decision in a software architecture that uses microservices, come back to this list of questions.