DDD seems to have everything one would need to make a decent start on Microservices architecture. We saw that DDD’s tactical patterns such as Aggregates, Bounded Contexts, Context Maps are great sign posts for identifying the microservice boundaries. But, that’s not all that DDD has to offer.
DDD has a lot more to offer in terms of tools and patterns which can make our lives easier now that we have reached this point in our journey. There are untold benefits which DDD can bring us on the team-organization front. Benefits that rarely (almost never) get discussed, but that we think are real key to successful Microservices implementations.
Patterns for Model Sharing
We saw before that model sharing i.e. getting boundaries right and team interaction, are the hardest problems of microservices. They are also the most important thing.
Let’s revisit our Context Map, but now showing the relationships between the bounded contexts.
Now that we know the roles in these relationships, let’s see how we can act in these situations. To do that we need two more pieces of information. The shared cross-team control, and the communications capability (commitment) between them.
We can see there are a lot of patterns. We are only going to talk about the ones we have applied in our case study.
In our case study, we can see that the requests flow from Order Management System to Payment Processing system. Sometimes it is the other way around. We can define this relationship as a Partnership. It can also be called a Customer-Supplier relationship – but the roles reverses depending on the user journey. The relationship between Payment Processing system and the Payment Gateway is “Conformist”. this means there is an API exposed to us over which we have no power so we must conform.
We have already seen that within our microservices bounded contexts, there is a Shared Kernel between the other non-Bounded Context Microservices (Reporting, housekeeping etc.).
In situations where two or more teams are working on the same bounded context, the communication capability between the teams and the control over the teams is high. This means that part of the model can be shared between microservices. This is Shared Kernel pattern.
A Bounded context can contain one or more microservices which themselves are bounded contexts (for us this is the Subscription service, and Payment Service because they each enclose an aggregate or model which makes sense only within that boundary). It can also contain other microservices which are not necessarily bounded contexts. Meaning they don’t have models of their own but depend on the core model and core microservices. They cannot exist on their own from model perspective. They use Shared Kernels to leverage this.
“If the development of mutually dependent subsystems is not coordinated, delivery is most likely to fail. If a key feature is missing in one system, the other system may not be delivered “
From the DDD book:
Projects are interdependent when neither can succeed without the other. Therefore, institute a process for joint management of the integration of the two subsystems, which includes cooperation on the interface design, and allows for the co-operative evolution of that interface to accommodate the development needs of both systems.
Also, processes will be needed to govern the integration of the code. For example, a special test suite can be defined that proves the interface meets the expectations of the client system. It is not necessary, most of the time, for developers to understand the model of the other subsystem in detail, but they must co-ordinate their planning.
Interdependent features should be scheduled so that they are completed for the same release. when development in one system hits design problems that relate to the appropriateness of the interfaces, then joint examination of the issue is called for, to find a design solution that does not overly compromise either subsystem.
Customer – Supplier
Functionality is often partitioned such that one subsystem essentially feeds another. The second performs analysis or other functions that feed very little back into the first. In such cases, the two subsystems commonly serve very different user communities, with different jobs, where different models may be useful.
The freewheeling development of the upstream team can be cramped if the downstream team has veto power over changes, or if procedures for requesting changes are too cumbersome. The upstream team may even be inhibited, worried about breaking the downstream system. Meanwhile, the downstream team can be helpless, at the mercy of upstream priorities.
Again, reaching into the book, establish a clear customer/supplier relationship between the two teams. This means downstream priorities factor into upstream planning.
Agile teams can make the downstream team play the customer role to the upstream team. Jointly developed automated acceptance tests can validate the expected interface from the upstream. Adding these tests to the upstream team’s test suite, to be run as part of its continuous integration, will free the upstream team to make changes without fear of side effects downstream.
Upstream – Downstream
This pattern is an antidote for the adverse effects on downstream services caused by the upstream changes.
Translation layers can be simple, even elegant, when bridging well-designed bounded contexts with co-operative teams. But when control or communication is not adequate to pull off a shared kernel, partner, or customer-supplier relationship, the interface usually becomes more complex.
The translation layer takes on a more defensive tone. A large interface with an upstream system can eventually overwhelm the intent of the downstream model altogether. This causes it to modified to resemble the other system’s model in an ad hoc fashion. Yet the integration may be very valuable, or even required.
First, we started with a problem. Then we moved on to core concepts. Next, we dealt with the areas where we feel the greatest danger currently lies for any successful adoption of microservices – the finding of the Microservice boundaries – and gave you our recipe for successful navigation of these waters. We concluded with the benefits that seem rarely to get a mention, but which, having navigated your way through to a supple design, make the remaining team organization and delivery scheduling far easier.
Take home messages are:
- Find the right Microservices – or you’ll pine for the Monolith
- Don’t get confused about Bounded Contexts – they will fall out if you listen to the Language
- Organize the team around your services better – apply the Strategic Patterns
- Be inspired to do more Domain Driven Design