J'aimerais commencer la conception directe du domaine, mais il y a plusieurs problèmes que j'aimerais résoudre avant de commencer :)
Imaginons que j'ai un groupe et des utilisateurs et lorsque l'utilisateur souhaite rejoindre un groupe, j'appelle groupsService.AddUserToGroup(group, user)
méthode. Dans DDD, je devrais faire group.JoinUser(user)
, qui a l'air plutôt bien.
Le problème apparaît si vous trouverez certaines règles de validation pour l'ajout d'un utilisateur ou que certaines tâches externes doivent être démarrées lorsque l'utilisateur est ajouté au groupe. Avoir ces tâches conduira à l'entité ayant des dépendances externes.
Un exemple pourrait être - une restriction que l'utilisateur ne peut participer qu'à 3 groupes Max. Cela nécessitera des appels dB de la méthode du groupe Inside Group.JoinSuser pour valider cela.
Mais le fait qu'une entité dépend de certains services/classes externes ne semble pas si bonne et "naturelle" pour moi.
Quelle est la bonne façon de traiter cela dans DDD?
Imaginons que j'ai des groupes et des utilisateurs et lorsque l'utilisateur souhaite rejoindre un groupe, j'appelle GroisSservice.Andusertogroup (groupe, utilisateur). Dans DDD, je devrais faire un groupe.JoinSuser (utilisateur), qui a l'air plutôt bien.
Mais DDD vous encourage également à utiliser des services (apatrides) pour effectuer des tâches, si la tâche à accomplir est trop complexe ou ne correspondrait pas à un modèle d'entité. Il est correct d'avoir des services dans la couche de domaine. Mais les services de la couche de domaine ne doivent inclure que la logique commerciale. Les tâches externes et la logique d'application (comme l'envoi d'un email) en revanche doivent utiliser le service de domaine dans la couche d'application, dans lequel vous pourriez avoir un service séparé (Application-) qui l'enveloppe par exemple.
Le problème apparaît si je présente certaines règles de validation pour ajouter 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. Avoir ces tâches conduira à l'entité ayant des dépendances externes.
Bien que je ne connaisse pas quel type de tâche externe vous parlez, je suppose que c'est quelque chose comme d'envoyer un email, etc. Mais cela ne fait pas vraiment partie de votre modèle de domaine. Il devrait vivre dans la couche d'application et être handé là-bas dans l'IMHO. Vous pouvez avoir un service dans votre couche d'application qui fonctionne sur les services de domaine et les entités pour effectuer ces tâches.
Mais le fait qu'une entité dépend de certains services/classes externes ne semble pas si bonne et "naturelle" pour moi.
Il n'est pas naturel et ne devrait pas se passer. L'entité ne devrait pas savoir sur des choses qui ne sont pas sa responsabilité. Les services doivent être utilisés pour orchestrer les interactions d'entité.
Quelle est la bonne façon de traiter cela dans DDD?
Dans votre cas, la relation devrait probablement être bidirectionnelle. Si l'utilisateur rejoint le groupe ou le groupe prend l'utilisateur dépend de votre domaine. L'utilisateur rejoint-il le groupe? Ou l'utilisateur est-il ajouté à un groupe? Comment fonctionne-t-il dans votre domaine?
Quoi qu'il en soit, vous avez une relation bidirectionnelle et peut donc déterminer la quantité de groupes que l'utilisateur appartient déjà à l'agrégat de l'utilisateur. Que vous transmetiez l'utilisateur au groupe ou que le groupe à l'utilisateur est techniquement trivial une fois que vous avez déterminé la classe responsable.
La validation devrait ensuite être effectuée par l'entité. Le tout est appelé à partir d'un service de la couche d'application qui peut également faire des trucs techniques, comme l'envoi d'e-mails, etc.
Toutefois, si la logique de validation est vraiment complexe, un service de domaine pourrait être une meilleure solution. Dans ce cas, encapsulez les règles de l'entreprise là-bas, puis l'appelez à partir de votre couche d'application.
La façon dont je voudrais aborder le problème de la validation est de cette façon: Créez un service de domaine appelé MembershipService
:
class MembershipService : IMembershipService
{
public MembershipService(IGroupRepository groupRepository)
{
_groupRepository = groupRepository;
}
public int NumberOfGroupsAssignedTo(UserId userId)
{
return _groupsRepository.NumberOfGroupsAssignedTo(userId);
}
}
L'entité de groupe doit être injectée avec IMemberShipService
. Cela peut être fait au niveau de la classe ou au niveau de la méthode. Permet de supposer que nous le faisons au niveau de la méthode.
class Group{
public void JoinUser(User user, IMembershipService membershipService)
{
if(membershipService.NumberOfGroupsAssignedTo(user.UserId) >= 3)
throw new BusinessException("User assigned to more than 3 groups. Cannot proceed");
// do some more stuff
}
}
Le service d'application: GroupService
peut être injecté avec IMemberShipService
à l'aide d'une injection de constructeur, qu'il peut ensuite passer à JoinUser
méthode de la classe Group
.