Domain-Driven Design: Tackling Complexity in the Heart of Software
Rate it:
Open Preview
Read between May 28, 2022 - September 10, 2023
20%
Flag icon
Rather than focusing on the attributes or even the behavior, strip the ENTITY object’s definition down to the most intrinsic characteristics, particularly those that identify it or are commonly used to find or match it.
20%
Flag icon
Add only behavior that is essential to the concept and attributes that are required by that behavior.
20%
Flag icon
In this example, the phone and address attributes moved into Customer, but on a real project, that choice would depend on how the domain’s customers are typically matched or distinguished.
20%
Flag icon
For example, if a Customer has many contact phone numbers for different purposes, then the phone number is not associated with identity and should stay with the Sales Contact.
20%
Flag icon
As mentioned earlier, object-oriented languages have “identity” operations that determine if two references point to the same object by comparing the objects’ locations in memory.
20%
Flag icon
This kind of identity tracking is too fragile for our purposes.
20%
Flag icon
In most technologies for persistent storage of objects, every time an object is retrieved from a database, a new instance is created, and so the initial identity is lost. Every time an object is transmitted across a network, a new instance is...
This highlight has been truncated due to consecutive passage length restrictions.
20%
Flag icon
When there is no true unique key made up of the attributes of an object, another common solution is to attach to each instance a symbol (such as a number or a string) that is unique within the class.
20%
Flag icon
Once this ID symbol is created and stored as an attribute of the ENTITY, it is designated immutable.
20%
Flag icon
This is why identity-assigning operations often involve human input. Checkbook reconciliation software, for instance, may offer likely matches, but the user is expected to make the final determination.
21%
Flag icon
Because the most conspicuous objects in a model are usually ENTITIES, and because it is so important to track each ENTITY’s identity, it is natural to consider assigning an identity to all domain objects.
21%
Flag icon
Analytical effort is required to define meaningful identities and work out foolproof ways to track objects across distributed systems or in database storage.
21%
Flag icon
An object that represents a descriptive aspect of the domain with no conceptual identity is called a VALUE OBJECT.
21%
Flag icon
In software for a mail-order company, an address is needed to confirm the credit card, and to address the parcel.
21%
Flag icon
But if a roommate also orders from the same company, it is not important to realize they are in the same location.
21%
Flag icon
Address is a VALU...
This highlight has been truncated due to consecutive passage length restrictions.
21%
Flag icon
We don’t care which instance we have of a VALUE OBJECT. This lack of constraints gives us design freedom we can use to simplify the design or optimize performance.
21%
Flag icon
This involves making choices about copying, sharing, and immutability.
21%
Flag icon
The economy of copying versus sharing depends on the implementation environment. Although copies may clog the system with huge numbers of objects, sharing can slow down a distributed system.
21%
Flag icon
When a copy is passed between two machines, a single message is sent and the copy lives independently on the receiving machine. But if a single instance is being shared, only a reference is passed, requiring a message back to the object for each interaction.
21%
Flag icon
Sharing is best restricted to those cases in which it is most valuable ...
This highlight has been truncated due to consecutive passage length restrictions.
22%
Flag icon
In a relational database, you might want to put a particular VALUE in the table of the ENTITY that owns it, rather than creating an association to a separate table. In a distributed system, holding a reference to a VALUE OBJECT on another server will probably make for slow responses to messages; instead, a copy of the whole object should be passed to the other server. We can freely make these copies because we are dealing with VALUE OBJECTS.
22%
Flag icon
But, while bidirectional associations between ENTITIES may be hard to maintain, bidirectional associations between two VALUE OBJECTS just make no sense.
22%
Flag icon
Without identity, it is meaningless to say that an object points back to the same VALUE OBJECT that points to it.
22%
Flag icon
A good SERVICE has three characteristics.
22%
Flag icon
Many domain or application SERVICES are built on top of the populations of ENTITIES and VALUES, behaving like scripts that organize the potential of the domain to actually get something done.
23%
Flag icon
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).
23%
Flag icon
But just as model objects tend to start out naive and concrete and then gradually transform to reveal deeper insight, MODULES can become subtle and abstract.
23%
Flag icon
Letting the MODULES reflect changing understanding of the domain will also allow more freedom for the objects within them to evolve.
23%
Flag icon
Refine the model until it partitions according to high-level domain concepts and the corresponding code is decoupled as well.
23%
Flag icon
MODULES need to coevolve with the rest of the model. This means refactoring MODULES right along with the model and code.
23%
Flag icon
Such changes can be disruptive to team communication and can even throw a monkey wrench into development tools, such as source code control systems.
23%
Flag icon
As a result, MODULE structures and names often reflect much earlier forms of the model than the classes do.
24%
Flag icon
This kind of framework design is attempting to address two legitimate issues. One is the logical division of concerns:
24%
Flag icon
One object has responsibility for database access, another for business logic, and so on.
24%
Flag icon
This is not a book on framework design, so I won’t go into alternative solutions to that problem, but they do exist. And even if there were no options, it would be better to trade off these benefits for a more cohesive domain layer.
24%
Flag icon
Elaborate technically driven packaging schemes impose two costs.
26%
Flag icon
An AGGREGATE is a cluster of associated objects that we treat as a unit for the purpose of data changes.
26%
Flag icon
Each AGGREGATE has a root and a boundary. The boundary defines what is inside the AGGREGATE.
26%
Flag icon
The root is a single, specific ENTITY contained in the AGGREGATE. The root is the only member of the AGGREGATE that outside objects are allowed to hold references to, although objects wit...
This highlight has been truncated due to consecutive passage length restrictions.
46%
Flag icon
Intention-Revealing Interfaces
46%
Flag icon
If a developer must consider the implementation of a component in order to use it, the value of encapsulation is lost.
46%
Flag icon
If someone other than the original developer must infer the purpose of an object or operation based on its implementation, that new developer may infer a purpose that the operation or class fulfills only by chance. If that was not the intent, the code may work for the moment, but the conceptual basis of the design will have been corrupted, and the two developers will be working at cross-purposes.
46%
Flag icon
to force your thinking into client developer mode.
46%
Flag icon
In the public interfaces of the domain, state relationships and rules, but not how they are enforced; describe events and actions, but not how they are carried out; formulate the equation but not the numerical method to solve it. Pose the question, but don’t present the means by which the answer shall be found.
46%
Flag icon
point. It is unsatisfying at this point because the code in the test doesn’t tell us what it is doing. Let’s rewrite the test to reflect the way we would like to use the Paint objects if we were writing a client application.
46%
Flag icon
Entire subdomains can be carved off into separate modules and encapsulated behind INTENTION-REVEALING INTERFACES.
46%
Flag icon
Interactions of multiple rules or compositions of calculations become extremely difficult to predict. The developer calling an operation must understand its implementation and the implementation of all its delegations in order to anticipate the result. The usefulness of any abstraction of interfaces is limited if the developers are forced to pierce the veil. Without safely predictable abstractions, the developers must limit the combinatory explosion, placing a low ceiling on the richness of behavior that is feasible to build.
47%
Flag icon
Place as much of the logic of the program as possible into functions, operations that return results with no observable side effects. Strictly segregate commands (methods that result in modifications to observable state) into very simple operations that do not return domain information. Further control side effects by moving complex logic into VALUE OBJECTS when a concept fitting the responsibility presents itself.
47%
Flag icon
SIDE-EFFECT-FREE FUNCTIONS, especially in immutable VALUE OBJECTS, allow safe combination of operations. When a FUNCTION is presented through an INTENTION-REVEALING INTERFACE, a developer can use it without understanding the detail of its implementation.