Vamos imaginar que tenho grupos e usuários e, quando o usuário deseja ingressar em um grupo, estou chamando o método groupsService.AddUserToGroup (group, user). No DDD eu deveria fazer group.JoinUser (user), que parece muito bom.
Mas o DDD também o incentiva a usar serviços (sem estado) para executar tarefas, se a tarefa em questão for muito complexa ou não se encaixar em um modelo de entidade. Não há problema em ter serviços na camada de domínio. Mas os serviços na camada de domínio devem incluir apenas lógica de negócios. As tarefas externas e a lógica do aplicativo (como o envio de um email), por outro lado, devem usar o serviço de domínio na camada do aplicativo, na qual você pode ter um serviço (aplicativo) separado, por exemplo.
O problema aparece se houver algumas regras de validação para adicionar um usuário ...
As regras de validação pertencem ao modelo de domínio! Eles devem ser encapsulados dentro dos objetos de domínio (entidades etc.).
... ou algumas tarefas externas precisam ser iniciadas quando o usuário é adicionado ao grupo. A realização dessas tarefas levará a entidade a ter dependências externas.
Embora eu não saiba de que tipo de tarefa externa você está falando, presumo que seja algo como enviar um e-mail etc. Mas isso não faz parte do seu modelo de domínio. Ele deve residir na camada de aplicação e ser mantido lá em imho. Você pode ter um serviço em sua camada de aplicativo que opera em serviços e entidades de domínio para executar essas tarefas.
Mas o fato de uma Entidade depender de alguns serviços / classes externos não me parece tão bom e "natural".
Não é natural e não deveria estar acontecendo. A entidade não deve saber sobre coisas que não são de sua responsabilidade. Os serviços devem ser usados para orquestrar interações entre entidades.
Qual é a maneira correta de lidar com isso no DDD?
No seu caso, o relacionamento provavelmente deve ser bidirecional. Se o usuário ingressa no grupo ou o grupo leva o usuário depende do seu domínio. O usuário entra no grupo? Ou o usuário foi adicionado a um grupo? Como isso funciona no seu domínio?
De qualquer forma, você tem um relacionamento bidirecional e, portanto, pode determinar a quantidade de grupos aos quais o usuário já pertence no agregado de usuários. Se você passa o usuário ao grupo ou o grupo ao usuário é tecnicamente trivial depois de determinar a classe responsável.
A validação deve então ser realizada pela entidade. A coisa toda é chamada de um serviço da camada de aplicação que também pode fazer coisas técnicas, como enviar e-mails etc.
No entanto, se a lógica de validação for realmente complexa, um serviço de domínio pode ser uma solução melhor. Nesse caso, encapsule as regras de negócios e chame a partir da camada de aplicativos.
A maneira como abordaria o problema da validação é assim: Crie um serviço de domínio chamado
MembershipService
:A entidade do grupo precisa ser injetada
IMemberShipService
. Isso pode ser feito no nível da classe ou no método. Vamos supor que fazemos isso no nível do método.O serviço de aplicativo:
GroupService
pode ser injetadoIMemberShipService
usando a injeção do Constructor, que pode ser transmitida para oJoinUser
método daGroup
classe.fonte