Modeling and Key Patterns of DDD

Examine some key strategic patterns of DDD and their role in enhancing application development.

Modeling

The domain model is a product of the collaboration between domain experts and developers using the UL. What goes into the model should be limited to the data and behaviors that are relevant to the problem domain, not everything possible in an attempt at modeling reality. The point of a domain model is to solve problems identified in the domain.

Eric Evans suggests experimenting with several models and not getting stuck too long on minutia. We are trying to determine what is important from the conversation with the domain experts. Listen for connecting words to identity processes and behaviors, titles, and positions to identify actors, and, of course, the names of things to identify data. This should be captured on a large surface, such as a whiteboard, a large roll of paper, or a blank wall if we’re doing EventStorming.

The model should be free of technical complexities or concerns, such as mentioning any databases or inter-process communication methods, and should only focus on the problem domain.

Defining boundaries

Every model belongs to a bounded context, which is a component of the application. Because the model belongs to this context, care needs to be taken in keeping it safe from outside influences or enabling external control.

We have broken down the complexity into multiple domains and discovered the models hidden within our software. The boundaries that we see forming from our discovery efforts will be around the business capabilities of our application. Examples of business capabilities for the MallBots application are the following:

  • Order management

  • Payment processing

  • Depot operations

  • Store inventory management

All the domains should not have a singular view of any given model; they should be concerned with the parts that are relevant to a particular bounded context.

Every bounded context has its own UL, which should be taken to mean terms that might have different meanings when contexts change across an application. The products that are picked out by a customer will exist in several domains and, depending on the context, have completely different models with different purposes and attributes. When the domain experts and developers discuss products, they will need to include the context to which they’re referring. They could be talking about the inventory for a store, the line items in an order, or fulfillment and delivery at the depot.

A bounded context takes on a technical aspect in that its implementations introduce some technical boundaries around the models. For a distributed application, a bounded context typically takes on the implementation of a module or a microservice, but not always. A very distinct boundary exists where the context limits the mutations and queries of the model it has been created to maintain.

Bounded contexts are a difficult concept
To do DDD well, we must understand bounded contexts. We encourage you to read one of the suggested books or do a search and learn more about them. Finding or determining the right boundaries in an application is not a science and is very much an art.

Tying it back together

It may seem counterintuitive that so much effort is expended breaking down our problem domain into smaller domains and bounded contexts, only to later design how they should all interact again. The bounded contexts and their high walls now need to be made to work together and become integrated again. We use context mapping to draw the relationships between our models and contexts that we’ll need for our application to be functional.

The purpose of context mapping is to recognize the relationships the models will have with other models and to also show the relationship between teams. The patterns used in context mapping are of a descriptive value only. They do not give any hints about what technical implementations should exist to connect the models:

  • Upstream patterns:

    • Open host service: This context provides an exposed contract that downstream contexts may connect to.

    • Event publisher: This context publishes integration events that downstream contexts may subscribe to.

  • Midway patterns:

    • Shared kernel: Two teams share a subset of the domain model and maybe the database.

    • Published language: A good document shared language to translate models between contexts. It is often combined with an open host service.

    • Separate ways: Contexts that have no connections because integration is too expensive.

    • Partnership: A cooperative relationship between two contexts with joint management of the integration.

  • Downstream patterns:

    • Customer/supplier: A relationship where the downstream context may veto or negotiate changes to the upstream context.

    • Conformist: The downstream service is coupled with the upstream context’s model.

    • Anticorruption layer: A layer to isolate the downstream context from changes in the
      upstream context’s model.

Applying the preceding patterns to our application, we could end up with the following:

Get hands-on with 1400+ tech skills courses.