Microservices Architecture Principle #3: small bounded contexts over one comprehensive model
Microservices are a hot topic. To help organizations make the best of this new architectural style Xebia has defined a set of principles that we feel should be applied when implementing a Microservice Architecture.
Today we discuss the Domain Driven Design (DDD) concept of "Bounded Context" and how it plays a major role in designing Microservices.
One of the discussion points around Microservices, since the term was coined in 2013, is how big (or rather, how small) a Microservice should be. Some people, such as Fred George, claim services should be small, maybe between 100-1000 lines of code (LoC). However, LoC is a poor metric for measuring software in general and even more so for determining the scope of a Microservice. Rather, when identifying the scope of our Microservices, we look at the functionality that a service needs to provide, and how the service relates to other services. Our aim is to design Microservices that are autonomous, ie. have a low coupling with other services, have well defined interfaces, and implement a single business capability, ie. have high cohesion.
A technique that can be used for this is "Context Mapping". Via this technique we identify the various contexts in the IT landscape and their boundaries. The Context Map is the primary tool used to make boundaries between domains explicit. A Bounded Context encapsulates the details of a single domain, such as domain model, data model, application services, etc., and defines the integration points with other bounded contexts/domains. This matches perfectly with our definition of a Microservice: autonomous, well defined interfaces, implementing a business capability. This makes Context Mapping (and DDD in general) an excellent tool in the architects toolbox for identifying and designing Microservices.
Another factor in sizing our services is that we would like to have models that can "fit in your head", so as to be able to reason about them efficiently. Most projects define a single comprehensive model encompassing the full domain, as this seems natural, and appears easier to maintain as one does not have to worry about the interaction between multiple models, or translate from one context to the other.
For small systems this may be true, but for large systems the costs will start to outweigh the benefits: maintaining a single model requires centralization. Naturally the model will tend to fragment: a domain expert from the accounting domain will think differently about 'inventory' than a logistics domain expert, for example. It requires lots of coordinated efforts to disambiguate all terms across all domains. And worse, this 'unified vocabulary' is awkward and unnatural to use, and will very likely be ignored in most cases. Here bounded contexts will help again: they make clear where we can safely use the natural domain terms and where we will need to bridge to other domains. With the right boundaries and sizes of our bounded contexts we can make sure our domain models "fit in your head" and that we do not have to switch between models too often.
So maybe the best answer to the question of how big a Microservice should be is: it should have a well defined bounded context that will enable us to work without having to consider, or swap, between contexts.
[edited: 3 aug 2015 - added preamble and removed line "Over the next couple of days we will cover each of these principles in more detail in a series of blog posts."]