In the previous article we left with a problem whereby we had two entities which looked similar but not the same. We will now see how we got around this issue with the help of Domain Driven Design (DDD).
Quick system overview of the case under discussion:
“A description of a boundary (typically a subsystem, or the work of a particular team) within which a particular model is defined and applicable.”
Taking a leaf out of the DDD book:
“Keep the model consistent within this boundary and don’t be confused by issues from outside”
We tried to make Order part of the Payment and Subscription Processing but it didn’t fit.
We then tried to duplicate it in Payment and Subscription Processing system but any change to Order entity by the Commerce System caused a ripple effect in the Payment and Subscription Processing system, quite unnecessarily.
Finally, we split the Context into Bounded Contexts and suddenly we realized that Order should not be part of the Payment and Subscription Processing system’s core model after all!
Since the interaction between these bounded contexts is via APIs, they cannot be oblivious of each other’s models. The Payment and Subscription Processing system understands Order just enough to communicate with Commerce System but not to make it part of its core model.
So, we ended up splitting it into Bounded Contexts in this way.
Note that we have renamed the Commerce System as Order Management System as a result of this exercise.
It seems like a pretty good rule of thumb that an Aggregate usually maps onto a microservice.
When we started building the microservices in the Payment and Subscription Processing context, it became clear that the models for Subscription and Payment are quite distinct. So we split the Payment and Subscription Processing Bounded context in two – Payment Processing Bounded context and Subscriptions Processing Bounded context. In fact, we would have been able to discover this much earlier had we paid more attention to the ubiquitous language. The name “Payment and Subscription Processing system” itself suggests that there is more than one bounded context at play here.
But are Aggregates the only things that can be microservices? Let’s delve deeper into what’s now the Subscription Processing context and Payment Processing Context.
In the diagram above you can see the microservices which provide additional “services” in the bounded context. These services are the Housekeeping service which is essentially the framework mechanism that maintained the Subscription’s invariants. The other is the reporting service. These services don’t have models of their own but instead utilize the same core models as the Payment Processing Context and the Subscription Processing Context – This is the Shared Kernel Strategic design pattern which we will in a minute.
Now that we have split our application into Bounded Contexts, we can see that there are multiple settings/contexts and we know that they interact but the diagram of Bounded Contexts does not really show those interactions. This where Context Maps become useful.
“An individual bounded context leaves some problems in the absence of a global view. The context of other models may still be vague and in flux. People on other teams won’t be aware of the context boundaries and will unknowingly make changes that blur the edges, or complicate the interconnections.”
The Context Map for our Shared Payment Service will look something like this.
An approach to the division of Microservices
- Draw a Model and begin to implement it
- As you draw it and code it, listen to the Language and cultivate your Model accordingly
- Identify your Aggregates – these are your starter Microservices
- When you hit pain points (indicated by the Language) split into different Bounded Contexts to resolve
- Revisit your Bounded Contexts now you know more about how each Aggregate – you may end up splitting them
Part III will focus on “Ignored but vital bits of DDD – The Strategic Patterns”.