Download presentation
Presentation is loading. Please wait.
1
DOMAIN DRIVEN DESIGN Martin
2
Domain-driven design is not a technology or a methodology
Domain-driven design is not a technology or a methodology. It is a way of thinking and a set of priorities, aimed at accelerating software projects that have to deal with complicated domains.
3
PRINCIPLES principle (plural principles) A fundamental assumption.
A rule used to choose among solutions to a problem.
4
Separation of Concerns
5
Evolutionary Design
6
CONCEPTS concept (plural concepts)
Something understood, and retained in the mind, from experience, reasoning and/or imagination; a generalization (generic, basic form), or abstraction (mental impression), of a particular set of instances or occurrences (specific, though different, recorded manifestations of the concept).
7
Domain
8
Domain
9
Pick your favourites A good model resembles reality
‘The code is the model’ Models are best expressed through UML Everyone should use the same model Every application needs a domain model Design a model before starting to code I once dated a model I like model aeroplanes
10
Model
11
Model
12
Model
13
Model
14
CONTEXT context (plural contexts)
the surroundings, circumstances, environment, background or settings which determine, specify, or clarify the meaning of an event
15
TDD BDD XP DDD Agile SCRUM FDD DSDM Lean Group 1: TDD, BDD, DDD, FDD
Group 2: SCRUM, DSDM Group 3: Lean DSDM Lean
16
PROCESS process (plural processes)
A series of events to produce a result, especially as contrasted to product.
17
Modeling Out Loud
18
Use UBIQUITOUS LANGUAGE to Explore the Domain
Schilderij is ‘Toren van Babel’ , Pieter Bruegel de Oude, rond 1560
19
BUILDING BLOCKS pattern (plural patterns)
that from which a copy is made a series of steps, repeated the quality held in common by a pattern
20
Mutually exclusive choices
Services Repositories access with Express model with Entities access with Model-Driven Design Maintain integrity with Express model with Aggregates act as root of encapsulate with Express model with Mutually exclusive choices Value Objects encapsulate with encapsulate with isolate domain with Factories Smart UI encapsulate with Layered Architecture
21
Entities DEFINITION: Many objects are not fundamentally defined by their attributes, but rather by a thread of continuity and identity PROBLEM: Some objects are not defined primarily by their attributes. They represent a thread of identity that runs through time and often across distinct representations Sometimes such an object must be matched with another object even though attributes differ An object must be distinguished from other objects even though they might have the same attributes Mistaken identity can lead to data corruption SOLUTION: When an object is distinguished by its identity, rather than its attributes, make this primary to its definition in the model Keep the class definition simple and focused on life cycle continuity and identity Define a means of distinguishing each object regardless of its form or history Be alert to requirements that call for matching objects by attributes Define an operation that is guaranteed to produce a unique result for each object, possibly by attaching a symbol that is guaranteed to be unique This means of identification may come from the outside, or it may be an arbitrary identifier created by and for the system, but must correspond to the identity distinctions in the model The model must define what it means to be the same thing
22
Value Objects DEFINITION: Many object have no conceptual identity. These objects describe some characteristic of a thing PROBLEM: Tracking the identity of entities is essential, but attaching identity to other objects can hurt system performance, add analytical work, and muddle the model by making all objects look the same Software design is a constant battle with complexity We must make distinctions so that special handling is applied only where necessary However, if we think of this category of object as just the absence of identity, we haven’t added much to our toolbox or vocabulary In fact, these objects have characteristics of their own and their own significance to the model These are objects that describe things SOLUTION: When you care only about the attributes of an element of the model, classify it as a value object Make it express the meaning of the attributes it conveys and give it related functionality Treat the value object as immutable Don’t give it any identity and avoid the design complexities necessary to maintain entities
23
Value objects in one context can be modelled as entities in a different context
27
Associations Make associations more tractable by:
Imposing a traversal direction Adding a qualifier, effectively reducing multiplicity Eliminating nonessential associations
28
Aggregates
29
DEFINITION: Aggregates mark off the scope within which invariants have to be maintained at every stage of the life cycle. The following patterns, Factories and Repositories, operate on aggregates, encapsulating the complexity of specific life cycle transitions. PROBLEM: It is difficult to guarantee the consistency of changes to objects in a model with complex associations. Invariants need to be maintained that apply to closely related groups of objects, not just discrete objects. Yet cautious locking schemes cause multiple users to interfere pointlessly with each other and make a system unusable. SOLUTION: Cluster the entities and value objects into aggregates and define boundaries around each. Choose one entity to be the root if each aggregate, and control all access to the objects inside the boundary to the root only. Transient references to internal members can be passed out for use within a single operation only. Because the root controls access, it cannot be blindsided by changes to the internals. This arrangement makes it practical to enforce all invariants for objects in the aggregate and for the aggregate as a whole in any state change. AGGREGATE RULES: The root entity has global identity and is ultimately responsible for checking invariants Root entities have global identity. Entities inside the boundary have local identity, unique only within the aggregate Nothing outside the aggregate boundary can hold a reference to anything inside, except to the root entity. The root entity can hand references to the internal entities to other objects, but those objects can use them only transiently, and they may not hold on to the reference. The root may hand a copy of a value object to another object, and it doesn’t matter what happens to it, because it’s just a value, and no longer will have any association with the aggregate As a corollary to the previous rule, only aggregate roots can be obtained directly with database queries. All other objects must be found by traversal of associations Objects within the aggregate can hold references to other aggregate roots A delete operation must remove everything within the aggregate boundary at once. (with garbage collection, this is easy. Because there ar no outside references to anything but the root, delete the root and everything else will be collected.) When a change to any object within the aggregate boundary is committed, all invariants of the whole aggregate must be satisfied Aggregate root
31
Services DEFINITION: sometimes, it just isn’t a thing. In some cases, the clearest and most pragmatic design includes operations that do not conceptually belong to any object. Rather than force the issue, we can follow the natural contours of the problem space and include services explicitly in the model PROBLEM: Some concepts from the domain aren’t natural to model a objects Forcing the required domain functionality to be the responsibility of an entity or value object either distorts the definition of the model-based object or adds meaningless artificial objects SOLUTION: When a significant process or transformation in the domain is not a natural responsibility of an entity or value object, add an operation to the model as a standalone interface declared as a service Define the interface in terms of the language of the model and make sure the operation name is part of the ubiquitous language Make the service stateless A good service has 3 characteristics: The operation relates to a domain concepts that is not a natural part of an entity or value object The interface is defined in terms of other elements of the domain model The operation is stateless
32
Mutually exclusive choices
Services Repositories access with Express model with Entities access with Model-Driven Design Maintain integrity with Express model with Aggregates act as root of encapsulate with Express model with Mutually exclusive choices Value Objects encapsulate with encapsulate with isolate domain with Factories Smart UI encapsulate with Layered Architecture
33
LAYERING UI Logging Domain Security Infra-structure
34
Dependency inversion Order ILogger Infrastructure Logger
35
Repository DEFINITION: associations allow us to find an object based on its relationship to another. But we must have a starting point for a traversal to an entity or value in the middle of its life cycle. PROBLEM: A client needs a practical means of acquiring references to pre-existing domain objects. If the infrastructure makes it easy to do so, the developers of the client may add more traversable associations, muddling the model. On the other hand, they may use queries to pull the exact data they need from the database, or to pull a few specific objects rather than navigating from aggregate roots. Domain logic moves into queries and client code, and the entities and value objects become mere data containers. The sheer technical complexity of applying most database access infrastructure quickly swamps the client code, which leads developers to dumb down the domain layer, which makes the model irrelevant. A subset of persistent objects must be globally accessible through a search based on object attributes. Such access is needed for the roots of aggregates that are not convenient to reach by traversal. They are usually entities, sometimes value objects with complex internal structure, and sometimes enumerated values. Providing access to other objects muddies important distinctions. Free database queries can actually breach the encapsulation of domain objects and aggregates. Exposure of technical infrastructure and database access mechanisms complicates the client and obscures the model-driven design. SOLUTION: For each type of object that needs global access, create an object that can provide the illusion of an in-memory collection of all objects of that type. Set up access through a well-known global interface. Provide methods to add and remove objects, which will encapsulate the actual insertion or removal of data in the data store. Provide methods that select objects based on some criteria and return fully instantiated objects or collections of objects whose attribute values meet the criteria, thereby encapsulating the actual storage and query technology. Provide repositories only for aggregate roots that actually need direct access. Keep the client focused on the model, delegating all object storage and access to the repositories. Advantages: The present clients with a simple model for obtaining persistent objects and managing their life cycle The decouple application and domain design from persistence technology, multiple database strategies, or even multiple data sources The communicate design decisions about object access The allow easy substitution of a dummy implementation for use in testing (typically using an in-memory collection). Repository implementation: Abstract the type Take advantage of the decoupling from the client Leave transaction control to the client Distinction with factories: Factory makes NEW objects Repositories find OLD objects
37
Mutually exclusive choices
Services Repositories access with Express model with Entities access with Model-Driven Design Maintain integrity with Express model with Aggregates act as root of encapsulate with Express model with Mutually exclusive choices Value Objects encapsulate with encapsulate with isolate domain with Factories Smart UI encapsulate with Layered Architecture
38
Factories DEFINITION: When creation of an object, or an entire aggregate, becomes complicated or reveals too much of the internal structure, factories provide encapsulation. PROBLEM: Creation of an object can be a major operation in itself, but complex assembly operations do not fit the responsibility of the created objects. Combining such responsibilities can produce ungainly designs that are hard to understand. Making the client direct construction muddies the design of the client, breaches encapsulation of the assembled object or aggregate, and overly couples the client to the implementation of the created object. SOLUTION: Shift the responsibility for creating instances of complex objects and aggregates to a separate object, which may itself have no responsibility in the domain model but is still part of the domain design. Provide an interface that encapsulates all complex assembly and that does not require the client to reference the concrete classes of the objects being instantiated. Create entire aggregates as a piece, enforcing their invariants. REQUIREMENTS FOR GOOD FACTORIES: Each creation method is atomic and enforces all invariants of the created object or aggregate. A factory should only be able to produce an object in a consistent state. For an entity, this means the creation of the entire aggregate, with all invariants satisfied, but probably with optional elements still to be added. For an immutable value object, this means that all attributes are initialized to their correct final state. If the interfaces makes it possible to request an object that can’t be created correctly, the an exception should be raised or some other mechanism should be invoked that will ensure that no improper return value is possible. The factory should be abstracted to the type desired, rather than the concrete class(es) created. The sophisticated factory patterns in GoF help with this. Don’t use a factory when: The class is the type. It is not part of any interesting hierarchy, and it isn’t used polymorphically by implementing an interface. The client cares about the implementation, perhaps as a way of choosing a strategy. All of the attributes of the object are available to the client, so that no object creation gets nested inside the constructor exposed to the client The construction is not complicated A public constructor must follow the same rule as a factory: it must be an atomic operation that satisfies all invariants of the created object. An entity factory used for reconstitution foes not assign a new tracking ID A factory reconsituting an object will handle violation of an invariant differntly
40
DEFINITION: Modules are an old, established design element
DEFINITION: Modules are an old, established design element. There are technical considerations, but cognitive overload is the primary motivation for modularity. Modules give people two views of the model: they can look at the detail within a module without being overwhelmed by the whole, or they can look at the relationships between modules in views that exclude interior detail. The modules in the domain layer should emerge as a meaningful part of the model, telling the story of the domain on a larger scale. PROBLEM: Everyone uses modules, but few treat them as a full-fledged part of the model. Code gets broken down into all sorts of categories, from aspects of the technical architecture to developers’ work assignments. Even developers who refactor a lot tend to content themselves with modules conceived early in the project. It is a truism that there should be low coupling between modules and high cohesion within them. Explanations of coupling and cohesion tend to make them sound like technical metrics, to be judged mechanically based on the distributions of associations and interactions. Yet it isn’t just code being divided into modules, but concepts. There is a limit to how many things a person can think about at once (hence low coupling). Incoherent fragments of ideas are as hard to understand as an undifferentiated soup of ideas (hence high cohesion). SOLUTION: Choose modules that tell the story of the system and contain a cohesive set of concepts. This often yields low coupling between modules, but if it doesn’t, look for a way to change the model to disentangle the concepts, or search for an overlooked concepts that might be in the basis of a module that would bring the elements together in a meaningful way. Seek low coupling in the sense of concepts that can be understood and reasoned about independently of each other. Refine the model until it partitions according to high-level domain concepts and the corresponding code is decoupled as well. Give the modules names that become part of the ubiquitous language. Modules and their names should reflect insight into the domain. Cost of technically driven packaging schemes: If the framework’s partitioning conventions pull apart the elements implementing the conceptual objects, the code no longer reveals the model The is only so much partitioning a mind can stitch back together, and if the framework uses it all up, the domain developers lose their ability to chunk the model into meaningful pieces. Unless there is a real intention to distribute code on different servers, keep all the code that implements a single conceptual object in the same module, if not the same object. Use packaging to separate the domain layer from other code. Otherwise, leave as much freedom as possible to the domain developers to package the domain objects in ways that support their model en design choices. Modules
41
LAB pattern (plural patterns) that from which a copy is made
a series of steps, repeated the quality held in common by a pattern
42
THANK YOU pattern (plural patterns) that from which a copy is made
a series of steps, repeated the quality held in common by a pattern
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.