2
votes

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:

  • introduce DTOs in my domain layer, which is agains DDD, and have methods toDTO() in my entities
  • provide getters/setters and use it only in mappers

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.

3
I would avoid both because you may have many DTOs transverse different models. A DTO may carry a username from a User and a collection of Street and number from an Address. While another DTO could have the user's First name and last name, and the number of times visited a website. - Juan
Yeah exactly but what's the alternative? - pzeszko
I can tell you what I do, not sure it is the answer you are looking for. I put DTOs in the presentation layer. In the service layer work with the model and at the time of returning a result create and populate the DTO. To get the data from the model I use getters. And the DTOs have all public attributes with no methods. - Juan
You don't need setters, just getters to read it - Tseng

3 Answers

2
votes

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

  1. 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.

  2. 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.

2
votes

Vaughn Vernon deals with that in chapter 14 (application) of the red book, in the "user interface" section (page 512) he exposes some alternatives:

  • dtos
  • mediator
  • domain payload objects
  • state representations
  • use case optimal repository queries (closed to cqrs)
  • data transformers

Hope it helps.

0
votes

Applying CQRS you can avoid having getters in your AR. Also, you can even reduce the number of attributes you have in your AR to only those which are need to satisfy some invariant.

Let me explain better.

CQRS (Command Query Responsibility Segregation) differentiates completely the Command and the Query operations your app provides.

The Command operations change the state of your application by executing some use case. The result of executing a Command is a Domain Event which contains the info of the change.

Then, the Domain Event (which is modeled as a DTO) is used to build your view model, which holds all the data you need to return from your queries. The view model is a DTO easy to be serialized and sent over the wire.

Therefore, your Query operations (the ones used to populate your UI with info) don't even hydrate your ARs. They work on your view model so any change on it does not have any impact on your AR.

Finally, as I mentioned at the beginning, most of the time we have tons of attributes in our ARs just to persist that info in our database. However, this info is never used to satisfy any invariant. For instance, when we save the name of an User but we never use that data again in any other use case. If the info is already persisted in the domain event and projected in your view model, you can query it, so you can avoid having that field in your AR keeping them as clean as possible.