By separating data structure from behavior, the data structure can be re-used across multiple applications which have different behavior for entities. Of course, this is a big trade-off: readability, maintainability, and encapsulation for reusability. Nothing is ever for free in this line of work.
The problem is that this is quintessentially anti-OO, and anti-domain-driven design. If you are ever to make the move to DDD in a company with a stated goal for object re-use, like mine, then this issue has to be addressed.
What if it’s true? Has OO failed? Is OO only good for textbook examples and toy applications? What does that say for a core part of DDD?
One could make the argument that DDD is not compatibile with the idea of a common object layer that multiple Bounded Contexts can reuse. In fact, in the Evans tome, Bounded Contexts are mentioned in concert with Translation Maps:
Identify each model in play on the project and define its BOUNDED CONTEXT. This includes the implicit models of non-object-oriented subsystems. Name each BOUNDED CONTEXT, and make the names part of the UBIQUITOUS LANGUAGE.
Describe the points of contact between the models, outlining explicit translation for any communication and highlighting any sharing.
Try making this argument to an Anemic Domain Modeler. You’ll be laughed at; why go through this translation layer, they’ll say, when you could just call some getters and setters?
This is an interesting question. Domain-driven design oozes isolation: isolated domain model, anti-corruption layer, bounded contexts, translation maps.
Even when it speaks of sharing, in the form of the Shared Kernel, it is more oriented towards sharing between two teams than organization-wide sharing:
Designate some subset of the domain model that the two teams agree to share.
Generic Subdomains are seemingly mentioned by Evans as a means for re-use, but not specifically between many teams. And the danger of Bloated Interfaces is mentioned as a disadvantage.
I said “seemingly.” Adding to the possibility that object / code re-use might just be against the philosophy of DDD, Evans expounds:
Note that while I have emphasized the generic quality of these sub-domains, I have not mentioned the reusability of code. Off-the-shelf solutions may or may not make sense for a particular situation, but assuming that you are implementing the code yourself, in-house or outsourced, you should specifically not concern yourself with the reusability of that code. This would go against the basic motivation of distillation: that you should be applying as much of your effort to the CORE DOMAIN as possible and investing in supporting generic subdomains only as necessary.
… you should seldom design for reusability …
Does this imply that domain-driven design, by its very nature of focusing on a specific problem domain, is not oriented towards general cross-project solutions?
One possibility is that we’re not trying hard enough. It might just be the case that there truly is common behavior that all projects can make use of. If this is the case, then simple composition, or possibly the Decorator pattern, can be used to add project-specific behavior to a common domain object.
In Evans-speak, this approach is similar to the Shared Kernel and Generic Subdomain approaches.
Assuming that the common layer of objects are true OO/DDD objects (i.e., the public methods mean something, no public accessors), they will need their own package structure, and that means their own repositories and factories.
You are in trouble when it comes to DTOs, though. You can’t pollute the common domain object layer with project-specific DTOs. This implies some sort of generic “export” interface that each common domain object could fill in.
This amounts to a field-seperated toString(), which itself is a few notches down the evolutionary latter from public accessors.
A second problem: composition and Decorator harm readability because they wrap up a set of fields, and possibly behavior, behind one object.
A third problem: Bloated Interfaces. You might not need everything in this common layer, or even all the methods in a single object. The only solution I can think of is to write a Facade to expose only the parts you want, ISP style, and use the Facade.
Pure Data Structures
That was a big “if”, though. If there really isn’t any truly common behavior, then you could create a common layer of domain objects with no public business methods. The only method I can think of is the generic, smelly fillIn(Export) method.
And since that is a few steps from token-seperated toString(), which is a few steps from public accessors, then maybe in this case, for the sake of simplicity, we add another player to the list of DDD cast members: Data Structures.
- Value Objects
- Data Structures*
* Brought to you by the EIP web-ring.
A Data Structure is exactly what it sounds like, with these properties:
- POJO / POCO / struct
- contains no behavior
- should never be referenced outside of entities and value objects
- instances should never be directly accessed outside of their containing entity or value object
- an entity or value object that contains a Data Structure must contain one and only one
Data Structures suffer from the same readability problem as common domain objects suffer from.
Another big problem is how you enforce properties 3, 4, and 5 of a Data Structure. These properties are key to containing the potential coupling of bags of getters and setters.
Another question, while we’re at it: do you provide repositories for these Data Structures, or do they exist purely to aid in object re-use?
And I just have to mention this one: what if you don’t want to use half of the fields in some Data Structure? This muddies your own model, does it not?
Your friends are with me now…
What do you do? Can it be done? Is DDD more than just a shift in design methodology? Why am I left with more questions than answers after I write a post?
|Announcer: You’re reading the EIP web-ring.|