Domain-driven design

Last updated

Domain-driven design (DDD) is a major software design approach, [1] focusing on modeling software to match a domain according to input from that domain's experts. [2] DDD is against the idea of having a single unified model; instead it divides a large system into bounded contexts, each of which have their own model. [3] [4]

Contents

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 software processes loan applications, it might have classes like "loan application", "customers", and methods such as "accept offer" and "withdraw".

Domain-driven design is predicated on the following goals:

Critics 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. [5]

The term was coined by Eric Evans in his book of the same name published in 2003. [6]

Overview

Domain-driven design articulates a number of high-level concepts and practices. [6]

Of primary importance is a domain of the software, the subject area to which the user applies a program. Software's 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 a common language shared by domain experts, users, and developers—the ubiquitous language. The ubiquitous language is used in the domain model and for describing system requirements.

Ubiquitous language is one of the pillars of DDD together with strategic design and tactical design.

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.

Event types

There are different types of events in DDD, and opinions on their classification may vary. According to Yan Cui, there are two key categories of events: [7]

Domain Events

Domain events signify important occurrences within a specific business domain. These events are restricted to a bounded context and are vital for preserving business logic. Typically, domain events have lighter payloads, containing only the necessary information for processing. This is because event listeners are generally within the same service, where their requirements are more clearly understood. [7]

Integration Events

On the other hand, integration events serve to communicate changes across different bounded contexts. They are crucial for ensuring data consistency throughout the entire system. Integration events tend to have more complex payloads with additional attributes, as the needs of potential listeners can differ significantly. This often leads to a more thorough approach to communication, resulting in overcommunication to ensure that all relevant information is effectively shared. [7]

Context Mapping patterns

Context Mapping identifies and defines the boundaries of different domains or subdomains within a larger system. It helps visualize how these contexts interact and relate to each other. Below are some patterns, according to Eric Evans: [8]

Relationship to other ideas

A bounded context is analogous to a microservice. [9]

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, which are 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. [10]

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 model-driven architecture, [11] 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. [12]

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 Bertrand Meyer.

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 either yielding 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 track their internal state not 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 [13] ) 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:

See also

Related Research Articles

<span class="mw-page-title-main">Martin Fowler (software engineer)</span> American software developer, author and public speaker

Martin Fowler is a British software developer, author and international public speaker on software development, specialising in object-oriented analysis and design, UML, patterns, and agile software development methodologies, including extreme programming.

Object–relational mapping in computer science is a programming technique for converting data between a relational database and the memory of an object-oriented programming language. This creates, in effect, a virtual object database that can be used from within the programming language.

<span class="mw-page-title-main">Data model</span> Abstract model

A data model is an abstract model that organizes elements of data and standardizes how they relate to one another and to the properties of real-world entities. For instance, a data model may specify that the data element representing a car be composed of a number of other elements which, in turn, represent the color and size of the car and define its owner.

<span class="mw-page-title-main">Meta-Object Facility</span> Standard of Object Management Group

The Meta-Object Facility (MOF) is an Object Management Group (OMG) standard for model-driven engineering. Its purpose is to provide a type system for entities in the CORBA architecture and a set of interfaces through which those types can be created and manipulated. MOF may be used for domain-driven software design and object-oriented modelling.

<span class="mw-page-title-main">Model–view–controller</span> Software design pattern

Model–view–controller (MVC) is a software design pattern commonly used for developing user interfaces that divides the related program logic into three interconnected elements. These elements are:

Command-query separation (CQS) is a principle of imperative computer programming. It was devised by Bertrand Meyer as part of his pioneering work on the Eiffel programming language.

A modeling language is any artificial language that can be used to express data, information or knowledge or systems in a structure that is defined by a consistent set of rules. The rules are used for interpretation of the meaning of components in the structure of a programming language.

A domain-specific language (DSL) is a computer language specialized to a particular application domain. This is in contrast to a general-purpose language (GPL), which is broadly applicable across domains. There are a wide variety of DSLs, ranging from widely used languages for common domains, such as HTML for web pages, down to languages used by only one or a few pieces of software, such as MUSH soft code. DSLs can be further subdivided by the kind of language, and include domain-specific markup languages, domain-specific modeling languages, and domain-specific programming languages. Special-purpose computer languages have always existed in the computer age, but the term "domain-specific language" has become more popular due to the rise of domain-specific modeling. Simpler DSLs, particularly ones used by a single application, are sometimes informally called mini-languages.

In computer programming, a software framework is an abstraction in which software, providing generic functionality, can be selectively changed by additional user-written code, thus providing application-specific software. It provides a standard way to build and deploy applications and is a universal, reusable software environment that provides particular functionality as part of a larger software platform to facilitate the development of software applications, products and solutions.

In software engineering, inversion of control (IoC) is a design principle in which custom-written portions of a computer program receive the flow of control from an external source. The term "inversion" is historical: a software architecture with this design "inverts" control as compared to procedural programming. In procedural programming, a program's custom code calls reusable libraries to take care of generic tasks, but with inversion of control, it is the external source or framework that calls the custom code.

The Shlaer–Mellor method, also known as object-oriented systems analysis (OOSA) or object-oriented analysis (OOA) is an object-oriented software development methodology introduced by Sally Shlaer and Stephen Mellor in 1988. The method makes the documented analysis so precise that it is possible to implement the analysis model directly by translation to the target architecture, rather than by elaborating model changes through a series of more platform-specific models. In the new millennium the Shlaer–Mellor method has migrated to the UML notation, becoming Executable UML.

Object-oriented analysis and design (OOAD) is a technical approach for analyzing and designing an application, system, or business by applying object-oriented programming, as well as using visual modeling throughout the software development process to guide stakeholder communication and product quality.

Model-driven engineering (MDE) is a software development methodology that focuses on creating and exploiting domain models, which are conceptual models of all the topics related to a specific problem. Hence, it highlights and aims at abstract representations of the knowledge and activities that govern a particular application domain, rather than the computing concepts.

Executable UML is both a software development method and a highly abstract software language. It was described for the first time in 2002 in the book "Executable UML: A Foundation for Model-Driven Architecture". The language "combines a subset of the UML graphical notation with executable semantics and timing rules." The Executable UML method is the successor to the Shlaer–Mellor method.

An architectural pattern is a general, reusable resolution to a commonly occurring problem in software architecture within a given context. The architectural patterns address various issues in software engineering, such as computer hardware performance limitations, high availability and minimization of a business risk. Some architectural patterns have been implemented within software frameworks. There are two main categories of architectural patterns: monolithic and distributed.

<span class="mw-page-title-main">Model–view–presenter</span> Software design pattern

Model–view–presenter (MVP) is a derivation of the model–view–controller (MVC) architectural pattern, and is used mostly for building user interfaces.

Model–view–viewmodel (MVVM) is an architectural pattern in computer software that facilitates the separation of the development of a graphical user interface —be it via a markup language or GUI code—from the development of the business logic or back-end logic such that the view is not dependent upon any specific model platform.

Data, context, and interaction (DCI) is a paradigm used in computer software to program systems of communicating objects. Its goals are:

<span class="mw-page-title-main">Object-oriented programming</span> Programming paradigm based on the concept of objects

Object-oriented programming (OOP) is a programming paradigm based on the concept of objects, which can contain data and code: data in the form of fields, and code in the form of procedures. In OOP, computer programs are designed by making them out of objects that interact with one another.

References

  1. Millet, Scott; Tune, Nick (2015). Patterns, Principles, and Practices of Domain-Driven Design. Indianapolis: Wrox. ISBN   978-1-118-71470-6.
  2. Vernon, Vaughn (2013). Implementing Domain-Driven Design. Upper Sadle River, NJ: Addison-Wesley. p. 3. ISBN   978-0-321-83457-7.
  3. Domain-Driven Design: Tackling Complexity in the Heart of Software. Addison-Wesley Professional. 2003. ISBN   978-0321125217.
  4. martinekuan. "Using tactical DDD to design microservices - Azure Architecture Center". learn.microsoft.com. Retrieved 2024-09-07.
  5. Microsoft Application Architecture Guide, 2nd Edition. Retrieved from http://msdn.microsoft.com/en-us/library/ee658117.aspx#DomainModelStyle.
  6. 1 2 Evans, Eric (August 22, 2003). Domain-Driven Design: Tackling Complexity in the Heart of Software. Boston: Addison-Wesley. ISBN   978-032-112521-7 . Retrieved 2012-08-12.
  7. 1 2 3 Cui, Yan. Serverless Architectures on AWS. Manning. ISBN   978-1617295423.
  8. Evans, Eric. Domain-Driven Design Reference: Definitions and Pattern Summaries. ISBN   978-1457501197.
  9. Fundamentals of Software Architecture: An Engineering Approach. O'Reilly Media. 2020. ISBN   978-1492043454.
  10. Haywood, Dan (2009), Domain-Driven Design using Naked Objects, Pragmatic Programmers.
  11. MDE can be regarded as a superset of MDA
  12. Cabot, Jordi (2017-09-11). "Comparing Domain-Driven Design with Model-Driven Engineering". Modeling Languages. Retrieved 2021-08-05.
  13. a MS bug finding tool
  14. Stefan Kapferer and Olaf Zimmermann: Domain-driven Service Design - Context Modeling, Model Refactoring and Contract Generation, 14th Symposium and Summer School On Service-Oriented Computing (SommerSoC 2020)