The Two Sides of Domain-Driven Design (DDD)
This post explores Domain-Driven Design from the tactical and strategic perspectives with the goal of clearing confusion around these orthogonal axes. Motivation sourced from Outside In TDD versus DDD by Mark Seemann where the author examines this misunderstanding surrounding DDD.
It appears that many developers, myself included, initially attempt to harness Domain-Driven Design for the object-oriented programming patterns described by Eric Evans in the Domain-Driven Design book. This is no surprise because these patterns, which include concepts such as entities and repositories, are well founded, refined and hardened by years in service. Together, these patterns embody the tactical side of Domain-Driven Design. The other side of DDD consists of strategic principles and methodologies for analyzing and modeling domains as well as systematic techniques for catalyzing the development process.
The most common misconception is that the tactical patterns define DDD or are strictly coupled to DDD. In turn, this often leads to several problems. First, one can be lead to believe that if a design fails to adhere to tactical DDD patterns then it either isn’t DDD or DDD can’t be applied. For example, the anemic domain model anti-pattern is often utilized to demonstrate that a design is not a domain-driven design. This is somewhat misleading because implementation of aggregates, entities and value objects is only a part of the puzzle addressed by Domain-Driven Design. Moreover, the tactical patterns are relevant beyond DDD and can be traced back to established object-oriented design principles. For example, the repository pattern can be regarded as an application of the single-responsibility principle in that it assigns the responsibility of persistence to the repository and encapsulation of behavior to entities. Additionally, the repository facilitates the dependency inversion principle by allowing its implementation to depend on an abstraction declared in the domain layer. Aggregates, entities and value objects exhibit characteristics of the information expert pattern. There is nothing about these principles that is intimately intertwined with DDD - they bring value with or without. Historically, the concept of a domain model, referenced in PoEAA, surfaced before the broad emergence of DDD.
The other problem with fixating on the tactics is ultimately a consequence of the rapid pace of technological change. Principles such as CQRS and event sourcing, while arguably not new, beckon for novel implementation patterns. Designs in functional programming languages can exhibit entirely distinct characteristics as demonstrated in Domain-Driven Design with F# and EventStore. As a result, implementation tactics should remain flexible and open to innovation.
Perhaps more importantly than the tactics, one can overlook the very critical strategic patterns, which can harm the rest of the design regardless of how well applied the tactical patterns are. I’ve experienced this fist hand where a project became increasingly difficult to iterate due to lack of model boundaries. All of the tactical patterns were there - the entities, repositories, aggregates, value objects. Instead of providing value however, these patterns become a burden. It became a burden to ensure that entities contained all the data and behaviors required to fulfill the needs of its consumers. It became a burden to ensure repositories scaled as the number of use-cases increased. It became a burden to partition responsibilities among developers. In the end, the necessary patterns were the bounded context, a context map and a well defined ubiquitous language. The principles of core domain and generic sub-domain, as well as the various relationships between bounded contexts further address demands of complex projects.
The most significant message of the Domain-Driven Design strategy is the predominant importance of domain knowledge. Implementing software is difficult enough, but without distilled domain knowledge, how can we ever hope for it to make any sense? All too often, programmers are blinded by their precious patterns tacitly hoping for the emergence of order. Perhaps this is why Eric Evans, in stating what he’s learned since the book, expressed desire for greater emphasis on the strategic patterns. Luckily for the community, the recently published Implementing Domain-Driven Design by Vaughn Vernon fluently connects the high level strategic patterns to implementation tactics within modern architectures. This book breathes new life into DDD and highlights its ever increasing relevance for today’s software.