Hexagonal (Ports/Adapters) Architecture
What has to be mentioned here is so-called Hexagonal (Ports/Adapters) Architecture [Vernon, the red book p. 125]. It is very convenient to place objects that represent data for the external (outside the domain & the application) comsumers. The architecture is the great addition to Layered Architecture generally implied by DDD.
Here is the example.
Along with ports/adapters for a DBs, email services etc.
We may define a ports/adapters/http/ui/myestore/ShoppingCartResponse.valueobject.ext
(assume we use some imaginary programming language EXT) that contains the data your UI application MyEStore
will use to show the end user his shopping cart state.
ShoppingCartResponse.valueobject.ext
is created by ports/adapters/http/ui/myestore/EStoreHTTP.adapter.ext
(for brevity it could be a synonim for a very slim HTTP REST API controller from REST world in our example).
The adapter asks the domain service ShoppingCart.service.ext
for aggregates, entities, other value objects. Then it creates the desired ShoppingCartResponse.valueobject.ext
from them (by itself or with creators - factories, builders etc.). Then sends the value object as an HTTP response to the consumer.
DTO or Value Object?
Whether ShoppingCartResponse
would be a value object or a DTO (.dto.ext
) you should decide based on
- The particular structure of your Ports/Adapters object hierarchy;
- If it is justified to have another type of object, a DTO, in the system, or it is better to keep only value objects only;
- A semantic meaning of DTO vs value objects in object hierarchy;
- The responsibilities differentiation between them: say your value object would do some invariants logic-keeping, whereas DTO could be just a dumb object with no logic.
I would prefer starting with the simplest approach, allowing only for value objects, and add DTOs only as the clear architectural need in them appears.
This approach gives much flexibilty yet it keeps code design clean and simple. Ports/Adapters section accommodates objects that belong together (the adapter, VO or DTO, their creators) and keeps Application Layer clean keeping the space for more relevant application layer objects.