In the previous post, I spoke about Ubiquitous Language and it’s importance in DDD. In this post I will discuss the concept of a Bounded Context (BC) as defined in DDD and the relevance, as well as the applicability of BCs in a Microservices architecture.
Subdomains and Bounded Contexts
A large and complex problem domain calls for a divide and conquer approach. The domain can be partitioned into smaller domains so as to get a handle on the complexity and size. The partitions are called subdomains. The subdomains are an abstract concept and it is not specific to DDD. It is a common practice to partition any large system into smaller parts. We just call them by different names. I have used the concept of subsystems/subdomains in designing various systems without applying DDD. However in DDD, the definition is made explicit, subdomains represent the business areas, capabilities and functionality of a system along business lines. Subdomains are not formed around technical concepts of the domain. This is the key differentiator and leads to better models, better products.
The subdomains are classified into one of three categories – Core, Supporting and Generic domains. Of these, the core domain is the most important one. It is the sole reason why your product is being built and represents your product’s unique selling point. As such, the core domain should be the primary focus and your best modelling effort needs to be expended on it. The supporting domains are there to support some aspect of the core domain and could be outsourced if needed. The generic domains are those that provide generic functionality and not specific to your business. They can be bought off the shelf if needed.
Subdomains are represented in DDD by domain models. You can think of the subdomain as being in the problem space and the model as being in the solution space. The model will detail the design used to fulfill the business use cases for that domain. In an ideal situation there is a one to one mapping between the subdomain and the model. However it is also possible to have multiple models within a subdomain or a model spanning multiple subdomains. In practice, a domain model is expressed by Ubiquitous Language and sketches/diagrams. These together explain the concepts,logic and relationships involved in fulfilling the use cases.
In a large system, there will always be multiple models at play. In order to handle business processes these models almost always interact with each other. The interactions are what lead to the slippery slope of entanglements. DDD proposes that each model maintain it’s focus and integrity when any interactions between models occur. The integrity is enforced by defining a context within which a model exists. Such a context is called the Bounded Context. Another way of defining this characteristic is to say that a BC encompasses a single responsibility, delimited with an explicit border. The Bounded Context has an internal model that is not shared with anything outside and an external interface used to interact with other components. If you look back and think about it, these same qualities and characteristics also define a Microservice. So we see that identifying Bounded Contexts as per DDD is compatible with identifying Microservices. Sam Newman in the book Building Microservices: Designing Fine-Grained Systems says this :
If our service boundaries align to the bounded contexts in our domain, and our microservices represent those bounded contexts, we are off to an excellent start in ensuring that our microservices are loosely coupled and strongly cohesive.
The figure shows a typical E-Commerce application that sells products online. For this example, I’ve shown just three business functionalities – Listing products, Ordering products and a Recommender system that recommends products to users based on some criteria. The concept of ‘Product‘ is used in all these functionalities. However the meaning and usage of ‘Product‘ differs between them. In the Listing area, the aspects of the product that matter are the attributes used for advertising it, the display, the user reviews etc. In the Ordering area, it is the price, return policy, method of payment, addressing etc. In the Recommender area it is about the category that the product belongs to, what the user has previously purchased, what similar users have purchased, it’s popularity, comparison aspects etc.
As you can see, although they are all dealing with the same term product, the attributes that matter are very different. Using a single representation of Product will lead to severe overload and entanglements due to shared data. So each is separated into subdomains and within each is a BC enclosing the precise product concept . Each BC ensures that it’s meaning of the term product is kept internally and not shared across it’s external interface. These BCs could very well represent the initial Microservices for this application.
A caveat to consider when relying on Bounded Contexts to identify Microservices, is that they are not necessarily guaranteed to be small. DDD does not focus on the size per se. A BC can be any arbitrary size in DDD. But for Microservices, being ‘micro’ in size is a core requirement. So how do you achieve a micro size once you have identified the BCs ? Well, the recommended practice is to apply additional patterns to increase the granularity of services within the Bounded Context. Event sourcing, Command Query Responsibility Segregation and Saga are a few well known patterns used to achieve this. I plan to cover them in subsequent posts.
If these terms and concepts seem confusing, rest assured, you are not alone. Identifying the Bounded Contexts correctly, right away, has a reputation for being rather hard to do. The authors and expert practitioners of DDD agree with this assessment. It is acknowledged that initially, the Subdomains and Bounded Contexts will be coarse grained. The boundaries might not be identified and separated correctly. And that’s ok, the thing is to start applying the principles and iterate as you go. With each iteration of the implementation, new insights and issues reveal themselves. It brings a deeper understanding of your domain over time. The understanding can be absorbed by refactoring the Bounded Contexts and the models within. So it is a continuous and circular process that aligns with agile practices. A piece of advise – do not get too attached to your implementation. Be easily willing to replace it as the design evolves. I know this is a hard one. We naturally tend to get attached to our design, code and our piece of the product (our babies, right ?), but given that these are much smaller in size it should be less painful to throw away and redo.