Les objets de domaine dans la conception pilotée par domaine sont-ils uniquement censés être en écriture seule?

13

Je lis sur la conception pilotée par domaine depuis près de deux ans et j'ai prudemment introduit certains concepts dans mon travail quotidien ou au moins fait des plans pour que les choses que je fais régulièrement puissent être faites dans une conception pilotée par domaine.

Une conclusion à laquelle je commence à venir, en particulier en réponse à la lecture de plus sur le sourçage d'événements et la séparation des responsabilités de requête de commande (CQRS) que les objets de domaine sont peut-être destinés à être utilisés uniquement à des fins d'écriture. Pour être plus clair, il semble que ce que les gens suggèrent subtilement dans une grande partie de la documentation que j'ai lue, c'est que les objets de domaine sont responsables des opérations / calculs centrés sur le domaine, de la validation, puis sont principalement là pour fournir une route vers la persistance à travers l'infrastructure fournie dans une implémentation du référentiel. Bien que j'aime le fait que cela simplifie considérablement le modèle de domaine car il supprime la responsabilité d'exposer l'état.

S'il est effectivement exact que les objets de domaine doivent être principalement utilisés en tant qu'objets en écriture seule, cela soulève pour moi des questions auxquelles j'espère que quelqu'un pourrait répondre.

  1. Comment effectue-t-on des tests unitaires sur un objet qui a des setters, ou des méthodes qui modifient l'état d'un objet mais qui ne fournissent pas d'interface publique extérieure pour lire l'état à partir de tels que les accesseurs de propriété en C #? Est-il correct d'exposer l'état uniquement dans le but de rendre cet objet testable?
  2. Comment afficher à un utilisateur les résultats de calculs ou d'opérations effectués dans le domaine sans avoir à les conserver, puis extraire les résultats du magasin de persistance en dehors du contexte du domaine? Est-il correct d'exposer l'état uniquement dans le but d'afficher des résultats?

La règle générale est-elle que les seuls getters de propriété (get accessors) devraient être ceux qui sont également accessibles en écriture dans le domaine? Ou dit différemment, les propriétés en lecture seule devraient-elles être la seule chose à éviter car elles ne sont là qu'à des fins de lecture et ne jouent donc pas un rôle nécessaire dans le modèle de domaine réel?

Matériel connexe:

  1. TDD, DDD et encapsulation
jpierson
la source

Réponses:

9

Je ne suis pas sûr qu'il existe une réponse «à sens unique» pour une approche de conception qui, pour être honnête, est toujours en évolution. Premièrement, DDD et CQRS ne sont pas la même chose bien que les gens du CQRS semblent avoir dérivé d'un point de départ influencé par DDD.

Il y a beaucoup de choses dans l'état d'esprit DDD et cela a beaucoup à voir avec les limites correctement définies des problèmes, la communication entre les parties prenantes et l'interaction entre les systèmes, pas nécessairement une implémentation spécifique dans le code, donc je ne pense pas être trop difficile - le noyau est une vertu.

Vous voyez peut-être une partie du débat sur la question de savoir si et comment les objets de domaine doivent être modifiables, et quelle fonction un objet de domaine sert dans un système dans son ensemble. Le CQRS divise un système en chemins de lecture et d'écriture, il est donc judicieux de conclure que vous n'avez pas réellement besoin d'un accès en lecture lorsque vous êtes sur le chemin d'écriture. La lecture devient alors quelque chose que vous faites contre les événements déclenchés par certains objets de domaine et consommés (gérés) par d'autres. Si vous remontez un peu dans l'histoire du CQRS, vous trouverez des arguments selon lesquels les objets de domaine ne devraient pas avoir de setters, seulement des getters et une seule méthode de 'handler'. La logique ici est que seuls les événements de consommation doivent entraîner un changement d'état et que ce changement est entièrement géré en interne par l'objet domaine.

Vous montrez les résultats du changement en les traitant comme des artefacts de changement séparés, en les plaçant dans une structure persistante distincte plate (par exemple, un tableau) et en le lisant comme si vous veniez de lire un rapport sur l'état actuel et historique du système . Par exemple, vous pouvez consommer un événement en extrayant les données dont vous avez besoin pour les lire et en les enregistrant dans une table de base de données qui correspond étroitement à une seule vue (par exemple, un écran) de votre système.

Si vous expérimentez ce style, sachez que d'autres programmeurs ne connaîtront probablement pas cette approche et qu'il existe relativement peu de scénarios (mais intéressants) où cela peut se justifier en tant qu'approche de conception.

Pour les tests unitaires, deux approches peuvent vous convenir. La première, et la plus naturelle, consiste à vérifier que les événements que vous pensez voir déclenchés par vos objets de domaine sont corrects. Un objet de domaine peut déclencher un événement modifié générique contenant des informations sur la modification. Vous pouvez le vérifier. Vous pouvez vérifier le fait que l'événement a été déclenché du tout et que d'autres événements n'ont pas été déclenchés.

Une autre approche consiste à utiliser des espions de test qui exposent des attributs lisibles sur votre objet de domaine afin que vous puissiez vérifier les changements d'état. Par exemple, vous pouvez hériter de votre objet de domaine, ajouter des accesseurs pour lire ce qui serait autrement un état encapsulé et vérifier qu'il est correct.

Encore une fois, vous êtes confus parce que ces approches prêtent à confusion. Si vous cherchez à adopter de bonnes idées dans votre programmation, prenez d'abord les morceaux juteux. Les limites DDD et la explicitation des rôles sont des changements dans votre façon de penser à communiquer avec votre code. Le CQRS suggère au minimum que la lecture et l'écriture de données sont des opérations séparables. Cette perspicacité vous amène à réfléchir très clairement au rôle des données que vous devez présenter, à la quantité dont vous avez réellement besoin, à qui les consomme, à quel point doit-elle être fraîche, etc ... Vous n'avez pas besoin d'un mise en œuvre complète du sourcing d'événements pour adopter une meilleure encapsulation dans votre codage. Vous pouvez commencer par vous concentrer uniquement sur les opérations atomiques au sein de votre objet, les approches "Tell, Don't Ask" pour la conception de l'interface d'objet,

frites
la source
1
+1 pour commencer avec les bits jucy. De plus: mordre juste le CQS (sauter la partie «événements» pour l'instant) pourrait être un bon point de départ.
cottsak
1

Les objets de domaine dans la conception pilotée par domaine sont-ils uniquement censés être en écriture seule?

Non. CQRS peut être utilisé avec DDD.

NimChimpsky
la source
Mais la partie Requête du CQRS concerne-t-elle uniquement l'interrogation des données utilisées par le modèle de domaine pour écrire des modifications dans le modèle ou peut-elle être utilisée pour interroger les données de la couche application qui pourraient dire afficher les valeurs à l'utilisateur? J'entends certains dire que DDD est tout au sujet de la coordination des modifications et ne doit pas être utilisé pour lire à d'autres fins que pour coordonner les modifications d'un autre objet dans le modèle de domaine. La décision dans un sens ou dans l'autre signifierait une conception de modèle radicalement différente, étant donné que les données exposées sur les objets du domaine varieraient de manière limitée si elles n'étaient consommées que dans le domaine.
jpierson
0

Vos tests unitaires de modèle de domaine doivent vérifier que pour chaque commande exécutée, les événements de domaine corrects sont déclenchés. Vos commandes de domaine et les événements capturés peuvent être interrogés pour leur état.

Vous pouvez également remplacer ToString()vos commandes et événements de domaine pour fournir un rapport d'état lisible par l'homme.

Pour répondre à votre deuxième question, pour afficher les résultats des commandes, vous devez organiser la publication des événements de domaine sur votre modèle de lecture.

Ed James
la source
Pourriez-vous nous expliquer un peu si cela s'applique toujours lorsque vous n'utilisez pas la recherche d'événements?
jpierson
1
Sans recherche d'événements, ma suggestion ne fonctionnera peut-être pas; Je ne connais pas les voies de votre code. Pour un objet de domaine qui, dans l'idéal, n'expose aucune propriété, vous pouvez peut-être implémenter explicitement une interface de test qui expose les propriétés que vous souhaitez tester. Seul votre code de test «saura» convertir ces objets de domaine en interface de test.
Ed James
Merci pour cette suggestion. Je me sens un peu mal à l'aise à l'idée de modifier mes classes de domaine spécifiquement pour la testabilité, mais je suppose que cela peut être l'une de ces zones grises encore dans la conception pilotée par domaine si vous voulez qu'elle soit testable. Une autre pensée est que si l'on devait exposer la stabilisation et la testabilité via la même interface, au moins vous ne présenteriez qu'une seule dépendance d'infrastructure au lieu de deux. Qu'en pensent les autres?
jpierson