Fractional Architect

Mastering Strategic Domain-Driven Design – 6. Context Map

Cover Image for Mastering Strategic Domain-Driven Design – 6. Context Map
Maciej 'MJ' Jedrzejewski - Fractional Architect
Maciej 'MJ' Jedrzejewski - Fractional Architect

The final important part of strategic Domain Driven Design is to define the integration and relationships between different bounded contexts, third party systems and teams.

In Chapter 5 I showed you how to define a bounded context using the Bounded Context Canvas. This allowed us to plan the inbound and outbound communication, types, patterns and business rules of a single bounded context. But almost every system is built on top of many contexts, third-party systems, and so on. Furthermore, each of them needs to communicate with others in one way or another - same as teams who are responsible for them.

In other words, we need to build interaction and relationships.

This is where a concept called Context Mapping comes into play. And there is nothing to be afraid of, although I know from the past that there is a lot of fear of it because it seems difficult. Despite appearances, it is a fairly simple concept, but you have to approach it from the right side.

However, before I explain to you how I approach this, I would like to introduce you to the various context mapping patterns. Here, as usual, we are helped by material from the DDD Crew:

Context Map Cheat Sheet

As you can see above, there are many patterns to choose from. Which one to choose?

My first step is to write down all the bounded contexts I have. In our case it will be all that belongs to Fitness Studio domain:

Bounded Contexts

Now I am ready to look back at the Bounded Context Canvas, which was used to define all my bounded contexts. Let's have another look at the Contracts bounded context that we defined in the previous chapter:

Bounded Context Canvas

All the inbound communication comes directly from frontend, so there is no other bounded context involved. But there is outbound communication that goes to Risk Assessments and Passes bounded contexts. This means that there is interaction between them and the Contracts.

Let's focus first on the communication between Contracts and Passes. There are 2 actions being handled:

  • When the contract is signed, this bounded context informs Passes about that fact
  • Passes registers a new pass for the customer and the customer is ready to enter the fitness studio

One of context mapping concepts is to define upstream and downstream systems:

  • Upstream is the provider or source of data, services, or functionality. It often acts as the sender in a relationship
  • Downstream is the receiver or consumer of data, services, or functionality provided by the upstream system. It relies on the upstream system for certain elements of its operation

In the case above, we can clearly define that Contracts will be the upstream system - as it delivers the triggering information about contract signature, while Passes will be downstream - as it reacts to a triggered event. Let's mark this on the diagram:

Contracts Passes Map

Now that we have the definition of which context is upstream and which is downstream, we can try to find the best pattern for their interaction. Let's say we want to communicate between them using simple messaging:

  • Contracts will send the event to a message broker when a contract is signed
  • Passes will subscribe to this message broker and when the event arrives it will consume it and register the pass

There are at least 2 things to consider:

  • It would be nice if we could define a common language between the two bounded contexts
  • Changes that happen inside upstream bounded context should not directly affect downstream - it would be nice to have a public interface exposed by Contracts

The first requirement can be addressed by using a pattern called Published Language. It allows us to define a common language between both contexts. The second can be handled with Open-Host Service - any changes that happen internally in Contracts will not affect Passes as long as the public interface remains unchanged. Our diagram should now look as follows:

Contracts Passes Map

We are ready with the context map between Contracts and Passes. Another interaction that will be very similar in our business domain is the one between Passes and Offers:

  • Passes will send the event to a message broker when a pass is marked as expired
  • Offers will subscribe to this message broker and when the event arrives it will consume it and prepare a new offer

However, this time Passes will be the upstream bounded context and Offers will consume it (downstream):

Passes Offers Map

Next we take a look at Risk Assesment. In our case it is a third party - you can imagine a national credit rating system - that provides a public API. It acts as an upstream and also uses the Open Host Service pattern. Our Contracts bounded context will call it directly (temporary tight-coupling) and get a response. However, this response contains a really bad structured model and we do not want to be a Conformist.

That's why we choose another pattern on the downstream (Contracts) called Anti-Corruption Layer.

It is very useful when working with legacy or third party systems - we usually do not want to let the model from the upstream system (or bounded context) flow into ours. Often such models are messy, contain too much information, or their language does not fit our rules. This is where you use this pattern, which translates the model into your own model.

You might ask - why not to use it always? Sometimes we have to be conformists. This is usually due to legal requirements, where data from the public system must always be stored in the same format as in the original system. In this case there is nothing we can do about it (as much as we would like to) and we have to accept it as Conformists.

What does our Context Map look like now after these changes?

Risk Contracts Map

NOTE: In addition to the Conformist and Anti-Corruption Layer patterns for the downstream calling the Open-Host Service upstream, it is possible that there will be a Customer-Supplier relationship - imagine your company is the trendsetter whose ideas will be defined as standards in a few years time. It affects the whole industry and there is a chance that it can act as a customer in a Customer-Supplier relationship - as desired by the public API provider. This is a rare situation, but it can happen.

Then you repeat the process for each bounded context. In the end you have a ready to use Context Map.

That's it! I hope you have enjoyed the whole series on strategic Domain-Driven Design. There is a free ebook coming out in the next few weeks that will summarise the whole series and perhaps expand on it in some places thanks to your feedback.

FREE Case Study: How did I introduce Domain-Driven Design in large scale organisation? Book an appointment with me to know more!