Imaginons que j'ai un groupe et des utilisateurs et lorsque l'utilisateur souhaite rejoindre un groupe, j'appelle la méthode groupsService.AddUserToGroup (groupe, utilisateur). Dans DDD, je devrais faire group.JoinUser (user), qui a l'air plutôt bien.
Mais DDD vous encourage également à utiliser des services (sans état) pour effectuer des tâches, si la tâche en cours est trop complexe ou ne rentre pas dans un modèle d'entité. C'est ok d'avoir des services dans la couche domaine. Mais les services de la couche domaine ne doivent inclure que la logique métier. Les tâches externes et la logique d'application (comme l'envoi d'un e-mail), d'autre part, devraient utiliser le service de domaine dans la couche application, dans laquelle vous pourriez avoir un service distinct (application) l'enveloppant par exemple.
Le problème apparaît s'il existe des règles de validation pour l'ajout d'un utilisateur ...
Les règles de validation appartiennent au modèle de domaine! Ils doivent être encapsulés à l'intérieur des objets de domaine (entités, etc.).
... ou certaines tâches externes doivent être démarrées lorsque l'utilisateur est ajouté au groupe. La possession de ces tâches entraînera l'entité ayant des dépendances externes.
Bien que je ne sache pas de quel type de tâche externe vous parlez, je suppose que c'est quelque chose comme l'envoi d'un e-mail, etc. Mais cela ne fait pas vraiment partie de votre modèle de domaine. Il devrait vivre dans la couche application et y être suspendu à mon humble avis. Vous pouvez avoir un service dans votre couche d'application qui fonctionne sur des services de domaine et des entités pour effectuer ces tâches.
Mais le fait qu'une entité dépende de certains services / classes externes ne me semble pas si bon et "naturel".
Ce n'est pas naturel et ne devrait pas se produire. L'entité ne doit pas être au courant de choses qui ne relèvent pas de sa responsabilité. Les services doivent être utilisés pour orchestrer les interactions d'entité.
Quelle est la bonne façon de gérer cela dans DDD?
Dans votre cas, la relation devrait probablement être bidirectionnelle. Que l'utilisateur rejoigne le groupe ou que le groupe le prenne dépend de votre domaine. L'utilisateur rejoint-il le groupe? Ou l'utilisateur est-il ajouté à un groupe? Comment ça marche dans votre domaine?
Quoi qu'il en soit, vous avez une relation bidirectionnelle et pouvez ainsi déterminer la quantité de groupes auxquels l'utilisateur appartient déjà dans le groupe d'utilisateurs. Que vous passiez l'utilisateur au groupe ou le groupe à l'utilisateur est techniquement trivial une fois que vous avez déterminé la classe responsable.
La validation doit ensuite être effectuée par l'entité. Le tout est appelé à partir d'un service de la couche application qui peut également faire des choses techniques, comme envoyer des e-mails, etc.
Cependant, si la logique de validation est vraiment complexe, un service de domaine pourrait être une meilleure solution. Dans ce cas, encapsulez les règles métier et appelez-les à partir de votre couche d'application.