Domain-Driven Design (DDD) in Practice — Experience with Context Mapper

November 23, 2022

Context Mapper is an open source DSL and tool for Domain-driven design (DDD), resulting from joint work by Stefan Kapferer and Olaf Zimmermann. This post and a sibling give a feature overview and reflect on project experience with it.

Domain-driven design (DDD) has established itself as a versatile method for decomposing software systems and crafting domain models. DDD models are typically developed on a whiteboard or with Post-it notes. Few software tools support the creation and maintenance of such models. Our blogposts reflect on project experience with Context Mapper, an open source tool for DDD.

Context Mapper Website (contextmapper.org)

Why Domain Driven Design (DDD)?

There are (at least) three reasons why we like to model a lot in our projects (as postulated by DDD):

In our view, tactical DDD within an application is a modern and mature approach to object-oriented analysis and design [Lar04]. And we use strategic DDD as pragmatic enterprise architecture management ("city planning") to understand or specify which tactical design applies where and to what extent - and what the power and influence relationships are between the models and their creators. No attempt is made to reach company-wide agreement on vocabulary, data structures, value ranges and technical relationships. For example, not all banks are the same: A private, an investment and a river bank differ significantly in their behavior, properties and relationships, depending on the application context.

Why have we developed a tool-supported Domain-Specific Language (DSL) for DDD and not just practice DDD? Agile modeling and event storming focus on the whiteboard. That's good, but isn't it a pity that the emerging insights and results might get stuck on the board? The state of the art is “remember”, “photograph” or “start programming from scratch”. In our experience, the painstakingly developed understanding of the domain, but also the meaning of the DDD patterns, can quickly be lost. Is an Aggregate just a data pot? Or an object cluster with coordinated behavior and shared persistence and associated consistency, integrity, and invariant management? What exactly is the difference between Published Language and Ubiquitous Language? And when do you choose the roles of Open Host Service plus Conformist instead of Customer/Supplier? For reasons of space, we won't explain these patterns here, but refer to the book "Domain-Driven Design Distilled" [Ver16] as well as the Context Mapper website and the Hover Helps in the tool itself.

The Tool: Context Mapper

Most of the modeling tools available on the market today are not designed for DDD, and are sometimes expensive and learning-intensive. Context Mapper [ContextM] closes this gap. This open source tool makes it possible to model software systems with the strategic and tactical DDD patterns. It is available under the Apache 2 license.

Context Mapper offers a formal and thus machine-readable language for DDD Context Maps. Until now, there were no tools for these diagrams. With the Context Mapper DSL (CML), we can specify Context Maps as well as individual Bounded Contexts and their relationships in text form and have graphical visualizations and other representations generated automatically. The tool also supports tactical domain modeling. These domain models are formulated using tactical DDD patterns such as Aggregates, Entities, and Value Objects. See the CML Language Reference for more information.

The following figure shows an exemplary context map from the insurance industry with different contexts in this domain such as “Customer Management Context”; each of these contexts contains a self-contained tactical domain model. The figure shows one such model (zoom in):

Figure 1: Strategic vs. tactical domain-driven design (DDD)

Strategic vs. tactical domain-driven design (DDD)

Listing 1 shows how such a Context Map can be modeled in CML (the example is shortened for reasons of space). CML supports all strategic patterns and concepts that we know from the "Blue Book" [Eva03] and the "Red Book" [Ver13]: Upstream (U), Downstream (D), Customer (C), Supplier (S), Open Host Service (OHS), Published Language (PL), Anticorruption Layer (ACL), Conformist (CF), Shared Kernel (SK) or Partnership (P).

Listing 1: Context Map written in CML (simplified)

ContextMap {
  contains CustomerManagementContext
  contains CustomerSelfServiceContext
  contains PrintingContext
  contains PolicyManagementContext
  contains RiskManagementContext
  
CustomerSelfServiceContext [D,C]<-[U,S] CustomerManagementContext CustomerManagementContext [D,ACL]<-[U,OHS,PL] PrintingContext PrintingContext [U,OHS,PL]->[D,ACL] PolicyManagementContext RiskManagementContext [P]<->[P] PolicyManagementContext }

Listing 2 models a single Bounded Context. Such a context typically consists of one or more Aggregates. The tactical DDD syntax supports the most important tactical patterns such as Entity, Value Object, Domain Event, Service and Repository. Aggregates are composed from instances of these patterns.

Listing 2: Example domain model (tactical DDD)

BoundedContext CustomerManagementContext {
  Aggregate Customers {
    Entity Customer {
      aggregateRoot
      
- CustomerId id String firstname String lastname - List<Address> addresses }
ValueObject CustomerId { String value }
Entity Address { String street String city } } }

Context Mapper is currently available for Visual Studio Code (extension) and for Eclipse (plug-in). The models can even be created online using browser IDEs such as Gitpod [GitPod]. The models can be transformed into several graphic representations with generators. Examples are graphical context maps [Ver13], UML component diagrams and UML class diagrams for the domain models of the bounded contexts (PlantUML) as well as platform-independent API interface descriptions (MDSL, see this post). The tool also comes with automated architectural refactorings and a Command Line Interface (CLI). The refactorings and other transformations enable users to refine their models in an agile manner and to continuously develop them further while preserving the domain concepts.

Developing a tool is one thing, but does it work in real project life?

Case Study: "Digitalization project in der MedTech/Printing Domain (eIFU)"

The author of this post, Stefan Kapferer, used DDD and Context Mapper in a digitalization project in the printing industry. The customer, Paul Büetiger AG from Switzerland, is a printer specializing in so-called “Instructions for Use” (IFUs) in the MedTech sector. These leaflets and instructions for use, or IFUs, nowadays can also be provided digitally in certain cases. Büetiger AG would like to set up a platform that allows customers to offer IFUs online [eIFU]. The customer can download the IFUs from the platform as a PDF or order a printed version to be sent to their home address with just a few clicks. The IFUs are stored in a structured manner on the platform and enriched with industry-specific metadata. These allow end customers to find IFUs using various search parameters (full-text indexing).

In this project it was possible to start on a “green field”. From the initial phase, in which the requirements were worked out with the customer, the project proceeded in a domain-driven manner, yielding a domain model. At first, this model was created and maintained with a graphical UML tool. During implementation, onion architecture and tactical DDD were set based on the architect's experience and the know-how within mimacom. The Java classes in the core were annotated with jMolecules annotations in order to assign the ring of the onion architecture [Gra] and the corresponding tactical DDD pattern (entity, value object, etc.) to the objects. Only towards the end of the development of the Minimum Viable Product (MVP) the project team started maintaining the model with Context Mapper in the Git repository. Two reasons drove this change.

The first reason was the need for documentation. The Context Mapper generators, most notably its PlantUML [PlantUML] generator, could be integrated into the architecture documentation, written in AsciiDoc. As a result, the developers and architects no longer had to maintain graphic models; a change in the CML model automatically led to a new version of the architecture document via the CI/CD pipeline. The second reason is model-code consistency. A graphical domain model that needs to be maintained manually, and the code typically diverges quickly. In the course of a project, changes may be made that only make it into the code, but not into the graphical model and documentation. With the help of the ArchUnit extension in Context Mapper, the DDD model always reflects the code: For example, if a developer inserts a new entity or a new value object in the code that is not present in the model, an ArchUnit test will fail. Extensions in the code necessarily lead to an update of the model. This in turn automatically initiates an update of the documentation.

In this project, Context Mapper was primarily used by the architect. A future goal is that requirements engineers who operate a little further away from technology can also maintain the model. With this approach and the use of the tool, we ensure that the code corresponds to the ideas of the business and that the same terminology is used.

Experience with DDD Practices, DSLs and Context Mapper

Text DSLs such as CML have an advantage over images when creating models: one focuses on content instead of layout. However, in our opinion, graphic representations should continue to have a prominent place in the tool kit of the "reflective practitioner" - because, as is well known, a picture is worth a 1000 words. Our Context Mapper tool proved to be stable, easy to use and useful. Some additional quick fixes for fast-forward engineering and more discoverers can make working with the tool even more pleasant and efficient in the future.

The tactical DDD syntax, which we “inherited” from another open source project, is sometimes a bit unintuitive, but also very expressive. The numerous examples and constructive error messages in the Context Mapper help you get started. Some of the DDD language constructs seem quite technical and (almost too) similar to program code to experts and requirements engineers who do not program in everyday life.

Both in the further development of the language and tool as well as in the project use, it is important to find a balance between the accuracy and simplicity of models and language concepts. A model alone is often not enough to cover the entire breadth of the subject matter; requirements engineers then describe certain aspects, such as technical rules, processes or justifications for design decisions, in plain text. It remains to be seen how these two worlds can be better integrated (“hybrid domain engineering”).

DDD is more underrated than overrated in our opinion. It has great potential for usage in practice, and research and development opportunities exist as well [ZiSt]. With Context Mapper, we hope to contribute to further increasing the accessibility of key software engineering topics such as a common, business-oriented language and modeling, while demonstrating the associated benefits of DDD concepts. Since its inception, Context Mapper has matured into a Domain Modeller, Architecture Validator (via the ArchUnit Extension and jQAssistant Plugin) and Integration Flow Designer.

Acknowledgment and Sibling Post

This post is an updated and shortened version of the article "Domain-Driven Design in der Praxis - Erfahrungen mit dem Open-Source-Tool Context Mapper" by Stefan Kapferer and Olaf Zimmermann, first published in JavaSPEKTRUM 6/2021, pages 20–23.

Its sibling post on the blog of Olaf Zimmermann features the other case study example from our German article and additional lessons learned.

We hope you find our article and these blogposts helpful.

– Stefan (and Olaf)

Bibliography

[ContextM] Context Mapper - A Modeling Framework for Strategic Domain-driven Design, https://contextmapper.org/

[eIFU] eIFU - Ihre Gebrauchsanweisung. Aber elektronisch, Paul Büetiger AG, https://www.buetiger.ch/kernkompetenz/e-ifu

[Eva03] E. Evans, Domain-Driven Design - Tackling Complexity in the Heart of Software, Addison-Wesley, 2003

[GitH] Context Mapper ArchUnit Extension, https://github.com/ContextMapper/context-mapper-archunit-extension

[GitPod] Gitpod - Always Ready to Code, https://www.gitpod.io/

[Gra] H. Graça, "DDD, Hexagonal, Onion, Clean, CQRS, … How I put it all together", 16.11.2017

[jQAss] jQAssistant Context Mapper Integration, https://jqassistant.org/jqassistant-context-mapper-integration-released

[Lar04] C. Larman, Applying UML and Patterns, Prentice Hall, third edition, 2004

[PlantUML] PlantUML, https://plantuml.com/

[Ver13] V. Vernon, Implementing Domain-Driven Design, Addison-Wesley, 2013

[Ver16] V. Vernon, Domain-Driven Design Distilled, Addison-Wesley, 2016

[ZiSt] O. Zimmermann und M. Stocker, Design Practice Reference, eBook, Leanpub, 2021

About the author: Stefan Kapferer

Stefan Kapferer is a software architect with mimacom in Zurich. Among other software engineering topics, he is especially interested in the subject of Domain-driven Design (DDD). He is open source contributor and the founder of the Context Mapper modeling tool.

Comments
Join us