Despite having studied Domain Driven Design
for a long time now there are still some basics that I simply figure out.
It seems that every time I try to design a rich domain layer
, I still need a lot of Domain Services
or a thick Application Layer
, and I end up with a bunch of near-anemic domain entities with no real logic in them, apart from "GetTotalAmount" and the like. The key issue is that entities aren't aware of external stuff, and it's bad practice to inject anything into entities.
Let me give some examples:
1. A user signs up for a service. The user is persisted in the database, a file is generated and saved (needed for the user account), and a confirmation email is sent.
The example with the confirmation email has been discussed heavily in other threads, but with no real conclusion. Some suggest putting the logic in an application service
that gets an EmailService
and FileService
injected from the infrastructure layer
. But then I would have business logic outside of the domain, right? Others suggest creating a domain service
that gets the infrastructure services
injected - but in that case I would need to have the interfaces of the infrastructure services
inside the domain layer
(IEmailService
and IFileService
) which doesn't look too good either (because the domain layer
cannot reference the infrastructure layer
). And others suggest implementing Udi Dahan's Domain Events and then having the EmailService and FileService subscribe to those events. But that seems like a very loose implementation - and what happens if the services fail? Please let me know what you think is the right solution here.
2. A song is purchased from a digital music store. The shopping cart is emptied. The purchase is persisted. The payment service is called. An email confirmation is sent.
Ok, this might be related to the first example. The question here is, who is responsible for orchestrating this transaction? Of course I could put everything in the MVC controller with injected services. But if I want real DDD all business logic should be in the domain. But which entity should have the "Purchase" method? Song.Purchase()
? Order.Purchase()
? OrderProcessor.Purchase()
(domain service)? ShoppingCartService.Purchase()
(application service?)
This is a case where I think it's very hard to use real business logic inside the domain entities. If it's not good practice to inject anything into the entities, how can they ever do other stuff than checking its own (and its aggregate's) state?
I hope these examples are clear enough to show the issues I'm dealing with.