I've bean reading a lot about DDD lately. I had some basic knowledge (and used it in practice) but now I've decided to go (almost) 100% DDD. Of course I've encountered problems right away.
I got 3 layers for each module (feature): application, domain and infrastructure. I use hexagonal architcture pattern, which basically means that I got my core logic in domain classes, application layer uses it (but domain layer is not aware of application layer at all), infrastructure implements my ports from domain (db repositories) and some interfaces from app layer etc.
Now, when I'm handling some use case in application services I have to work with my root aggregate and perform some logic and finally map it to some DTO for UI. The problem is that to perform such mapping I have to provide getters/setter for most of my attributes which kills me. I want to avoid anemic model by providing a lot of business methods and only very few getters/setters.
I can see 2 solutions:
Any other solutions, how do you people handle such common problem in your apps? I know it's really hard to go purly DDD in reality and it's ok not to follow all the rules but I noticed that having as small number of getters/setters as possible helps me hugely with my design but at the same time it's clear DTO doesnt belong to domain at all.
The problem is that to perform such mapping I have to provide getters/setter for most of my attributes which kills me.
Yup - I fought with that for a long time. The real answer is that there is no magic.
If you want the aggregate to be useful, you need to be able to get information out of it somehow. Write only databases aren't very interesting; if there isn't some query available on the interface, then there's not a lot of point to putting information into the thing in the first place.
A domain specific query to get a value out of the aggregate is acceptable. The key restrictions
It should not be possible to change the state of the aggregate by manipulating the returned value. So we tend to return either objects that have no mutators, or copies of those objects.
We should not be encouraging idioms where a consumer queries us, performs some operations on the result of the query, and then chooses a command based on the result of those operations.
// Don't do this: int x = o.X(); x = x + 1; o.Y(x)
There are a few things you can do, to make the code overall look "cleaner".
1) Have the aggregate respond to queries with value objects, then query those value objects for the information you need to build your DTO.
2) Pass a factory method into the aggregate to get the data that you need
<T> T query(API<T> api)
Where API<T> is a builder/factory thing that the aggregate can interact with.
3) Have two separate interfaces implemented by the aggregate (one for queries, one for commands), and only give the caller access to the interface that they need.
4) Have a single query point to get "the current state" out of the aggregate, and then build everything else from that.
Vaughn Vernon deals with that in chapter 14 (application) of the red book, in the "user interface" section (page 512) he exposes some alternatives:
Hope it helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With