Domain-Driven Design: Tackling Complexity in the Heart of Software
Rate it:
Open Preview
22%
Flag icon
The fewer and simpler the associations in the model, the better.
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
Complex operations can easily swamp a simple object, obscuring its role. And because these operations often draw together many domain objects, coordinating them and putting them into action, the added responsibility will create dependencies on all those objects, tangling concepts that could be understood independently. Sometimes services masquerade as model objects, appearing as objects with no meaning beyond doing some operation. These “doers” end up with names ending in “Manager” and the like. They have no state of their own nor any meaning in the domain beyond the operation they host. ...more
22%
Flag icon
A SERVICE tends to be named for an activity, rather than an entity—a verb rather than a noun.
22%
Flag icon
But when an operation is actually an important domain concept, a SERVICE forms a natural part of a MODEL-DRIVEN DESIGN. Declared
22%
Flag icon
Statelessness here means that any client can use any instance of a particular SERVICE without regard to the instance’s individual history.
22%
Flag icon
the SERVICE does not hold state of its own that affects its own behavior, as most domain objects do.
22%
Flag icon
It takes care to distinguish SERVICES that belong to the domain layer from those of other layers, and to factor responsibilities to keep that distinction sharp.
22%
Flag icon
Most SERVICES discussed in the literature are purely technical and belong in the infrastructure layer. Domain and application SERVICES collaborate with these infrastructure SERVICES.
22%
Flag icon
Funds transfer has a meaning in the banking domain language, and it involves fundamental business logic. Technical SERVICES should lack any business meaning at all.
23%
Flag icon
We can dress up such external SERVICES with a FACADE that takes inputs in terms of the model, perhaps returning a Funds Transfer object as its result.
23%
Flag icon
Although this pattern discussion has emphasized the expressiveness of modeling a concept as a SERVICE, the pattern is also valuable as a means of controlling granularity in the interfaces of the domain layer, as well as decoupling clients from the ENTITIES and VALUE OBJECTS.
23%
Flag icon
A “doer” object may be satisfactory as an implementation of a SERVICE’s interface.
23%
Flag icon
There are technical considerations, but cognitive overload is the primary motivation for modularity.
23%
Flag icon
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.
23%
Flag icon
Yet it isn’t just code being divided into MODULES, but concepts.
23%
Flag icon
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).
23%
Flag icon
Whenever two model elements are separated into different modules, the relationships between them become less direct than they were, which increases the overhead of understanding their place in the design. Low
23%
Flag icon
This high cohesion of objects with related responsibilities allows modeling and design work to concentrate within a single MODULE, a scale of complexity a human mind can easily handle.
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
Choose MODULES that tell the story of the system and contain a cohesive set of concepts.
23%
Flag icon
Give the MODULES names that become part of the UBIQUITOUS LANGUAGE.
23%
Flag icon
should reflect insight into the domain.
23%
Flag icon
Developers can handle these problems if they understand the story the model is telling them.
23%
Flag icon
we need to look for ways of minimizing the work of refactoring MODULES, and minimizing clutter in communicating to other developers.
23%
Flag icon
In Java, unfortunately, there is no escape from importing into individual classes, but you can at least import entire packages at a time,
24%
Flag icon
If the framework’s partitioning conventions pull apart the elements implementing the conceptual objects, the code no longer reveals the model.
24%
Flag icon
There 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.
24%
Flag icon
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.
24%
Flag icon
“high cohesion/low coupling.”
24%
Flag icon
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 and design choices.
24%
Flag icon
One exception arises when code is generated based on a declarative design (discussed in Chapter 10). In that case, the developers do not need to read the code, and it is better to put it into a separate package so that it is out of the way, not cluttering up the design elements developers actually have to work with.
32%
Flag icon
A class diagram representing a model of the shipping domain
32%
Flag icon
SPECIFICATION pattern
32%
Flag icon
The diagram is telling the reader that there is a SPECIFICATION of delivery, and the details of that are not important to think about (and, in fact, could be easily changed later).
45%
Flag icon
When software doesn’t have a clean design, developers dread even looking at the existing mess, much less making a change that could aggravate the tangle or break something through an unforeseen dependency.
45%
Flag icon
In any but the smallest systems, this fragility places a ceiling on the richness of behavior it is feasible to build. It stops refactoring and iterative refinement.
46%
Flag icon
will clue the reader in enough to get started using the class, especially with the example the test provides.
46%
Flag icon
INTENTION-REVEALING INTERFACES
46%
Flag icon
As soon as this arbitrarily deep nesting is involved, it becomes very hard to anticipate all the consequences of invoking an operation. The developer of the client may not have intended the effects of the second-tier and third-tier operations—they’ve become side effects in every sense of the phrase.
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.
46%
Flag icon
First, you can keep the commands and queries strictly segregated in different operations. Ensure that the methods that cause changes do not return domain data and are kept as simple as possible.
46%
Flag icon
Perform all queries and calculations in methods that cause no observable side effects (Meyer 1988).
47%
Flag icon
A VALUE OBJECT can be created in answer to a query, handed off, and forgotten—unlike an ENTITY, whose life cycle is carefully regulated.
47%
Flag icon
VALUE OBJECTS are immutable, which implies that, apart from initializers called only during creation, all their operations are functions.
47%
Flag icon
VALUE OBJECTS, like functions, are safer to use an...
This highlight has been truncated due to consecutive passage length restrictions.
47%
Flag icon
An operation that mixes logic or calculations with state change should be refactored in...
This highlight has been truncated due to consecutive passage length restrictions.
47%
Flag icon
move the responsibility for the complex calculations into a VALUE OBJECT.
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
When a FUNCTION is presented through an INTENTION-REVEALING INTERFACE, a developer can use it without understanding the detail of its implementation.