domain-driven_design_ddd

Domain-Driven Design (DDD)

Return to Design-Driven Development (DDD), Test-Driven Design (TDD), Developing Incremental Architecture, Software Architecture Topics

Domain-driven design (DDD) is the concept that the structure and language of software code (class names, class methods, class variables) should match the business domain. For example, if a software processes loan applications, it might have classes such as LoanApplication and Customer, and methods such as AcceptOffer and Withdraw.

DDD connects the implementation to an evolving model.1)

Domain-driven design is predicated on the following goals:

The term was coined by Eric Evans in his book of the same title.2)


Introduction to Domain-Driven Design

Domain-Driven Design (DDD) is a software development methodology introduced by Eric Evans in his book “Domain-Driven Design - Tackling Complexity in the Heart of Software.” The approach focuses on creating a deep connection between the business domain and the software design, ensuring that the software accurately reflects and supports the business goals and processes.

Core Principles of DDD

The core principles of DDD include the importance of understanding the business domain, collaboration between technical and domain experts, and the use of a common language, known as the Ubiquitous Language. This shared language helps to bridge the gap between developers and business stakeholders, ensuring that everyone has a common understanding of the domain.

Ubiquitous Language

The Ubiquitous Language is a central concept in DDD. It is a language developed by the team to describe the domain and its processes, used consistently in all communication, code, and documentation. This common language ensures that the terminology is understood by all team members, reducing misunderstandings and improving collaboration.

Bounded Contexts

A key element of DDD is the concept of Bounded Contexts. A Bounded Context defines a specific boundary within which a particular model is applicable. Each context has its own Ubiquitous Language and its own distinct model. This helps manage complexity by clearly delineating different parts of the system and avoiding ambiguity.

Entities and Value Objects

In DDD, entities and value objects are fundamental building blocks. Entities are objects that have a distinct identity and lifecycle, such as a customer or an order. Value objects, on the other hand, represent descriptive aspects of the domain with no identity, such as a date range or an address. Distinguishing between entities and value objects helps in modeling the domain accurately.

Aggregates and Aggregate Roots

Aggregates are clusters of entities and value objects that are treated as a single unit for data changes. The Aggregate Root is a single entity within the aggregate that acts as the entry point for accessing the aggregate's members. This structure helps enforce consistency and encapsulates the internal state of the aggregate, providing a clear boundary for transactions.

Repositories

Repositories are used in DDD to provide an abstraction for data access. They encapsulate the logic required to retrieve and store aggregates, allowing the domain model to remain clean and focused on business logic. Repositories act as a collection of aggregates, providing a simple interface for querying and persisting data.

Factories

Factories are responsible for creating complex objects and aggregates in DDD. They encapsulate the creation logic, ensuring that the construction of objects adheres to the rules and constraints of the domain. By using factories, developers can simplify object creation and maintain consistency within the domain model.

Services

Domain services are operations or actions that do not naturally fit within an entity or value object. These services encapsulate domain logic that spans multiple entities or aggregates. By using services, DDD ensures that domain logic is centralized and reusable, promoting a cleaner and more maintainable design.

Modules

Modules are used to organize the domain model into cohesive groups. They help manage complexity by grouping related concepts together, making the model easier to understand and navigate. Modules should be designed to minimize dependencies and ensure that each module has a clear and focused responsibility.

Event-Driven Architecture

DDD often complements event-driven architectures, where domain events represent significant occurrences within the domain. These events can trigger actions in other parts of the system, promoting decoupling and enhancing the responsiveness and scalability of the application. Domain events are typically immutable and convey the state changes in the system.

Event Sourcing

Event sourcing is a technique used in DDD where state changes are stored as a sequence of events. Instead of storing the current state, the system reconstructs the state by replaying events. This approach provides a detailed audit trail and allows for more flexible handling of changes over time.

Command-Query Responsibility Segregation (CQRS)

CQRS is a pattern often used in conjunction with DDD, where the read and write operations are separated into different models. This separation allows for optimized handling of queries and commands, improving performance and scalability. CQRS helps manage complex domains by providing clear separation of concerns.

Anti-Corruption Layer

An anti-corruption layer (ACL) is used in DDD to protect the domain model from external systems. It acts as a translator, converting external models and data into the Ubiquitous Language and domain model, ensuring that the core domain remains unaffected by external changes. The ACL helps maintain the integrity and consistency of the domain model.

Strategic Design

Strategic design in DDD involves high-level architectural decisions that shape the overall structure and boundaries of the system. This includes identifying Bounded Contexts, defining relationships between contexts, and determining integration strategies. Strategic design helps align the software architecture with the business vision and goals.

Collaborative Process

DDD emphasizes collaboration between developers, domain experts, and stakeholders throughout the development process. Regular communication and feedback loops ensure that the domain model evolves based on real business needs and insights. Workshops, domain modeling sessions, and continuous integration practices facilitate this collaboration.

Refactoring and Evolution

The domain model in DDD is expected to evolve as the understanding of the domain deepens and as business requirements change. Continuous refactoring ensures that the model remains relevant and accurate. DDD encourages iterative development, where the model is regularly reviewed and updated to reflect new insights and changes.

Benefits of DDD

DDD offers several benefits, including improved alignment between the software and business goals, enhanced communication and collaboration, and a more maintainable and flexible codebase. By focusing on the domain and using a shared language, DDD helps create software that truly addresses business needs and adapts to changing requirements.

Challenges of DDD

Despite its benefits, DDD also presents challenges, such as the initial learning curve, the need for deep domain knowledge, and the potential complexity of managing multiple Bounded Contexts. Successful implementation of DDD requires commitment from the entire team and continuous effort to refine and evolve the domain model.

Conclusion

Domain-Driven Design (DDD) is a powerful methodology for tackling complex software development projects. By focusing on the core business domain and fostering close collaboration between technical and domain experts, DDD helps create software that is closely aligned with business goals. Its principles and patterns, such as Ubiquitous Language, Bounded Contexts, and aggregates, provide a robust framework for designing and maintaining scalable and adaptable software systems.

Reference for additional reading


Domain-driven design (DDD) is a major software design approach,<ref name=“millet2015”>

</ref> focusing on modelling software to match a domain according to input from that domain's experts.<ref name=“vernon2013”>

</ref>

Under domain-driven design, the structure and language of software code (class names, class methods, class variables) should match the business domain. For example, if a software processes loan applications, it might have classes like LoanApplication and Customer, and methods such as AcceptOffer and Withdraw.

Domain-driven design is predicated on the following goals:

  • placing the project's primary focus on the core domain and domain logic;
  • basing complex designs on a model of the domain;
  • initiating a creative collaboration between technical and domain experts to iteratively refine a conceptual model that addresses particular domain problems.

Criticisms of domain-driven design argue that developers must typically implement a great deal of isolation and encapsulation to maintain the model as a pure and helpful construct. While domain-driven design provides benefits such as maintainability, Microsoft recommends it only for complex domains where the model provides clear benefits in formulating a common understanding of the domain.<ref>Microsoft Application Architecture Guide, 2nd Edition. Retrieved from http://msdn.microsoft.com/en-us/library/ee658117.aspx#DomainModelStyle.</ref>

The term was coined by Eric Evans in his book of the same title published in 2003.<ref name=“evans2004”>

</ref>

Overview

Domain-driven design articulates a number of high-level concepts and practices.<ref name=“evans2004” />

Of primary importance is domain, the subject area to which the user applies a program is the domain of the software. A software's domain governs its context, the setting in which a word or statement appears that determines its meaning. From this, developers build a domain model: a system of abstractions that describes selected aspects of a domain and can be used to solve problems related to that domain.

These aspects of domain-driven design aim to foster ubiquitous language, meaning that the domain model should form a common language shared by domain experts for describing system requirements, business users, sponsors and developers.

In domain-driven design, the domain layer is one of the common layers in an object-oriented multilayered architecture.

Kinds of models

Domain-driven design recognizes multiple kinds of models.

For example, an entity is an object defined not by its attributes, but its identity. As an example, most airlines assign a unique number to seats on every flight: this is the seat's identity.

In contrast, a value object is an immutable object that contains attributes but has no conceptual identity. When people exchange business cards, for instance, they only care about the information on the card (its attributes) rather than trying to distinguish between each unique card.

Models can also define events (something that happened in the past). A domain event is an event that domain experts care about.

Models can be bound together by a root entity to become an aggregate. Objects outside the aggregate are allowed to hold references to the root but not to any other object of the aggregate. The aggregate root checks the consistency of changes in the aggregate. Drivers do not have to individually control each wheel of a car, for instance: they simply drive the car. In this context, a car is an aggregate of several other objects (the engine, the brakes, the headlights, etc.)

Working with models

In domain-driven design, an object's creation is often separated from the object itself.

A repository, for instance, is an object with methods for retrieving domain objects from a data store (e.g. a database). Similarly, a factory is an object with methods for directly creating domain objects.

When part of a program's functionality does not conceptually belong to any object, it is typically expressed as a service.

Relationship to other ideas

Although domain-driven design is not inherently tied to object-oriented approaches, in practice, it exploits the advantages of such techniques. These include entities/aggregate roots as receivers of commands/method invocations, the encapsulation of state within foremost aggregate roots, and on a higher architectural level, bounded contexts.

As a result, domain-driven design is often associated with Plain Old Java Objects and Plain Old CLR Objects. While technically technical implementation details, specific to Java and the .NET Framework respectively, these terms reflect a growing view that domain objects should be defined purely by the business behavior of the domain, rather than by a more specific technology framework.

Similarly, the naked objects pattern holds that the user interface can simply be a reflection of a good enough domain model. Requiring the user interface to be a direct reflection of the domain model will force the design of a better domain model.<ref name=“book.haywood”>

.</ref>

Domain-driven design has influenced other approaches to software development.

Domain-specific modeling, for instance, is domain-driven design applied with domain-specific languages. Domain-driven design does not specifically require the use of a domain-specific language, though it could be used to help define a domain-specific language and support domain-specific multimodeling.

In turn, aspect-oriented programming makes it easy to factor out technical concerns (such as security, transaction management, logging) from a domain model, letting them focus purely on the business logic.

Model-driven engineering and architecture

While domain-driven design is compatible with model-driven engineering and architecture,<ref>MDE can be regarded as a superset of MDA</ref> the intent behind the two concepts is different. Model-driven architecture is more concerned with translating a model into code for different technology platforms than defining better domain models.

However, the techniques provided by model-driven engineering (to model domains, to create domain-specific languages to facilitate the communication between domain experts and developers,…) facilitate domain-driven design in practice and help practitioners get more out of their models. Thanks to model-driven engineering's model transformation and code generation techniques, the domain model can be used to generate the actual software system that will manage it.<ref>

</ref>

Command Query Responsibility Segregation

Command Query Responsibility Segregation (CQRS) is an architectural pattern for separating reading data (a 'query') from writing to data (a 'command'). CQRS derives from Command and Query Separation (CQS), coined by Greg Young.

Commands mutate state and are approximately equivalent to method invocation on aggregate roots or entities. Queries read state but do not mutate it.

While CQRS does not require domain-driven design, it makes the distinction between commands and queries explicit with the concept of an aggregate root. The idea is that a given aggregate root has a method that corresponds to a command and a command handler invokes the method on the aggregate root.

The aggregate root is responsible for performing the logic of the operation and yielding either a number of events, a failure response or just mutating its own state that can be written to a data store. The command handler pulls in infrastructure concerns related to saving the aggregate root's state and creating needed contexts (e.g., transactions).

Event sourcing

Event sourcing is an architectural pattern in which entities do not track their internal state by means of direct serialization or object-relational mapping, but by reading and committing events to an event store.

When event sourcing is combined with CQRS and domain-driven design, aggregate roots are responsible for validating and applying commands (often by having their instance methods invoked from a Command Handler), and then publishing events. This is also the foundation upon which the aggregate roots base their logic for dealing with method invocations. Hence, the input is a command and the output is one or many events which are saved to an event store, and then often published on a message broker for those interested (such as an application's view).

Modeling aggregate roots to output events can isolate internal state even further than when projecting read-data from entities, as in standard n-tier data-passing architectures. One significant benefit is that axiomatic theorem provers (e.g. Microsoft Contracts and CHESS<ref>a MS bug finding tool</ref>) are easier to apply, as the aggregate root comprehensively hides its internal state. Events are often persisted based on the version of the aggregate root instance, which yields a domain model that synchronizes in distributed systems through optimistic concurrency.

Notable tools

Although domain-driven design does not depend on any particular tool or framework, notable examples include:

  • CubicWeb, an open source semantic web framework entirely driven by a data model. High-level directives allow to refine the data model iteratively, release after release. Defining the data model is enough to get a functioning web application. Further work is required to define how the data is displayed when the default views are not sufficient.
  • OpenMDX, an open-source, Java-based, MDA Framework supporting Java SE, Java EE, and .NET. OpenMDX differs from typical MDA frameworks in that “use models to directly drive the runtime behavior of operational systems”.
  • Restful Objects, a standard for mapping a Restful API onto a domain object model (where the domain objects may represent entities, view models, or services). Two open source frameworks (one for Java, one for .NET) can create a Restful Objects API from a domain model automatically, using reflection.

See also

domain-driven_design_ddd.txt · Last modified: 2024/08/12 05:26 by 127.0.0.1

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki