Trouvez la racine agrégée DDD
On février 1, 2021 by adminJouons au jeu préféré de tout le monde, trouvez la racine agrégée. Utilisons le domaine de problème canonique Client / Commande / Lignes de commande / Produit. Traditionnellement, le client, la commande et le produit sont les AR, les lignes de commande étant des entités sous la commande. La logique sous-jacente est que vous devez identifier les clients, les commandes et les produits, mais une ligne de commande nexisterait pas sans commande. Par conséquent, dans notre domaine problématique, nous avons une règle commerciale indiquant quun client ne peut avoir quune seule commande non livrée. à la fois.
Cela déplace-t-il la commande sous la racine de lagrégat client? Je pense que oui. Mais ce faisant, cela rend le RA client assez volumineux et sujet à des problèmes de concurrence par la suite.
Ou, que se passerait-il si nous avions une règle commerciale stipulant quun client ne peut commander un produit particulier quune seule fois dans sa vie. Il sagit dune preuve supplémentaire exigeant que le client soit propriétaire de la commande.
Mais quand il sagit à lexpédition, ils font toutes leurs actions sur la commande, pas sur le client. Cest un peu stupide de devoir charger le client entier afin de marquer une commande individuelle comme livrée.
Cest ce que je propose:
class Customer { public Guid Id {get;set;} public string Name { get; set; } public Address Address { get; set; } public IEnumerable<Order> Orders { get; set; } public void PlaceOrder(ThingsInTheOrder thingsInTheOrder) { // Make sure there aren"t any pending orders already. // Make sure they aren"t ordering a Widget if they"ve already ordered a Widget in the past. // Create an Order object and add it to the collection. Raise a domain event to trigger emails and other stuff } } class Order { public Guid Id { get; set; } public IEnumerable<OrderLine> OrderLines { get; set; } public ShippingData {get;set;} public void Ship(ShippedByPerson shippedByPerson, string trackingCode) { // Create a new ShippingData object and assign it from the data passed in. // Publish a domain event } }
Ma plus grande préoccupation est le problème de la concurrence et le fait que lOrdre lui-même a des caractéristiques s dune racine agrégée.
Réponse
Quels sont les critères pour définir un agrégat?
Revenons aux bases du grand livre bleu:
Agrégat: Un cluster dobjets associés qui sont traités comme une unité aux fins des modifications de données . Les références externes sont limitées à un membre de lAGREGATE, désigné comme racine. Un ensemble de règles de cohérence s’applique dans les limites de l’AGGREGATE.
L’objectif est de conserver les invariants. Mais cest aussi bien gérer lidentité locale, cest à dire lidentification des objets qui nont pas de sens à eux seuls.
Order
et Order line
appartiennent définitivement à un tel cluster. Par exemple:
- Supprimer un
Order
, nécessitera la suppression de toutes ses lignes. - La suppression dune ligne peut nécessiter la renumérotation des lignes suivantes
- Lajout dune nouvelle ligne nécessiterait de déterminer la ligne nulber en fonction de toutes les autres lignes du même ordre.
- La modification de certaines informations de commande, comme par exemple la devise, peut affecter la signification du prix dans les éléments de campagne (ou nécessiter de recalculer les prix).
Voici donc lagrégat complet est nécessaire pour garantir des règles de cohérence et des invariants.
Quand sarrêter?
Maintenant, vous décrivez certaines règles métier et soutenez que pour les garantir, vous devez considérer le client dans le cadre de lagrégat:
Nous avons un busines s règle selon laquelle un client ne peut avoir quune seule commande non livrée à la fois.
Bien sûr, pourquoi pas. Voyons les implications: la commande serait toujours accessible via le client. Est-ce la vraie vie? Lorsque les travailleurs remplissent les boîtes pour livrer la commande, devront-ils lire le code-barres du client et le code-barres de la commande pour accéder à la commande «En fait, en général, lidentité dune commande est globale et non locale pour un client, et cette indépendance relative suggère de le maintenir en dehors de lagrégat.
De plus, ces règles commerciales ressemblent davantage à des politiques: c « est une décision arbitraire de la société pour exécuter son processus avec ces règles. Si les règles ne sont pas respectées, le patron peut être mécontent, mais les données ne sont pas vraiment incohérentes. De plus, pendant la nuit » par client, une commande non livrée à la fois » pourrait devenir » dix commandes non livrées par client » ou même » indépendamment du client, cent commandes non livrées par entrepôt « , afin que lagrégat ne soit plus justifié.
Réponse
Version courte
La raison dêtre de DDD est que les objets de domaine sont des abstractions qui devraient répondre aux exigences de votre domaine fonctionnel – si les objets de domaine ne peuvent pas facilement répondre à ces exigences, cela suggère que vous utilisez peut-être la mauvaise abstraction.
Nommage Les objets de domaine utilisant des noms dentité peuvent conduire ces objets à devenir étroitement couplés les uns aux autres et à devenir des objets « dieu » gonflés, et ils peuvent soulever des problèmes tels que celui de cette question. comme « Où est le bon endroit pour p ut la méthode CreateOrder? « .
Pour faciliter lidentification de la «bonne» racine dagrégation, envisagez une approche différente où les objets de domaine sont basés sur les exigences fonctionnelles de haut niveau de lentreprise, cest-à-direChoisissez des noms qui font allusion aux exigences fonctionnelles et / ou aux comportements que les utilisateurs du système doivent exécuter.
Version longue
DDD est une approche de la conception OO qui vise à générer un graphique des objets de domaine dans Business Couche de votre système – Les objets de domaine sont responsables de la satisfaction de vos exigences professionnelles de haut niveau et devraient idéalement pouvoir sappuyer sur la couche de données pour des éléments tels que les performances et lintégrité du magasin de données persistant sous-jacent.
Une autre façon de voir cela pourrait être les puces de cette liste
- Les noms dentités suggèrent généralement des attributs de données.
- Les noms de domaine devraient suggérer un comportement
- La modélisation DDD et OO concerne les abstractions basées sur les exigences fonctionnelles et le domaine principal / la logique métier.
- La couche de logique métier est responsable de la satisfaction des exigences de domaine de haut niveau
Lune des idées fausses courantes concernant DDD est que les objets de domaine doivent être basés sur une réalité physique. « chose » du monde (cest-à-dire un nom auquel vous pouvez pointer dans le monde réel, attribué avec toutes sortes de données / propriétés), mais les données / attributs de ces choses du monde réel ne constituent pas nécessairement un bon point de départ pour essayer de clouer les exigences fonctionnelles.
Bien sûr, Business Logic devrait utiliser ces données, mais les objets de domaine eux-mêmes devraient en fin de compte être des abstractions qui représentent les exigences et les comportements fonctionnels du domaine.
Par exemple; Les noms tels que Order
ou Customer
nimpliquent aucun comportement et sont donc généralement des abstractions inutiles pour représenter la logique métier et les objets de domaine.
Lorsque vous recherchez les types dabstractions qui pourraient être utiles pour représenter Business Logic, tenez compte des exigences typiques que vous pourriez vous attendre dun système à remplir:
- En tant que commercial, je souhaite créer une commande pour un nouveau client afin de pouvoir générer une facture pour les produits à vendre avec leurs prix et leur quantité.
- En tant que conseiller du service clientèle, je souhaite annuler une commande en attente afin que le La commande n’est pas exécutée par un opérateur d’entrepôt.
- En tant que conseiller du service client, je souhaite renvoyer une ligne de commande afin que le produit puisse être ajusté dans l’inventaire et que le paiement soit remboursé via le paiement initial du client
- En tant quopérateur dentrepôt, je souhaite afficher tous les produits dune commande en attente et les informations dexpédition afin de pouvoir choisir les produits et les expédier via le courrier.
- etc.
Modélisation des exigences de domaine avec une approche DDD
En vous basant sur la liste ci-dessus, considérez certains objets potentiels de domaine ts pour un tel système Order:
SalesOrderCheckout PendingOrdersStream WarehouseOrderDespatcher OrderRefundProcessor
En tant quobjets de domaine, ceux-ci représentent des abstractions qui sapproprient diverses exigences du domaine comportemental; en effet, leurs noms suggèrent fortement les exigences fonctionnelles spécifiques quils remplissent.
(Il peut y avoir une infrastructure supplémentaire là-dedans aussi, comme un EventMediator
à passer notifications pour les observateurs souhaitant savoir quand une nouvelle commande a été créée, ou quand une commande a été expédiée, etc.).
Par exemple, SalesOrderCheckout
doit probablement traiter les données sur les clients, lexpédition et les produits, mais nest pas concerné par le comportement des commandes dexpédition, du tri des commandes en attente ou des remboursements.
Pour SalesOrderCheckout
pour répondre aux exigences de son domaine comprend lapplication de ces règles métier telles que la prévention de la commande dun trop grand nombre darticles par les clients, éventuellement lexécution dune validation, et peut-être lémission de notifications pour dautres parties du système – il peut faire toutes ces choses sans nécessairement dépendre de nimporte lequel des autres objets.
DDD utilisant des noms dentité pour représenter des objets de domaine
Ther Il existe un certain nombre de dangers potentiels lors du traitement de noms simples tels que Order
, Customer
et Product
en tant quobjets de domaine; parmi ces problèmes, il y a ceux auxquels vous faites allusion dans la question:
- Si une méthode gère un
Order
, unCustomer
et unProduct
, à quel objet de domaine appartient-il? - Où se trouve la racine agrégée de ces 3 objets?
Si vous choisissez les noms dentités pour représenter les objets du domaine, un certain nombre de choses peuvent se produire:
-
Order
,Customer
etProduct
risquent de devenir des objets » god « - Risque de se retrouver avec un seul
Manager
god-object pour tout lier ensemble. - Ces objets risquent de devenir étroitement couplés les uns aux autres – il peut être difficile de répondre aux exigences du domaine sans passer par
this
(ouself
) - Un risque de développer des abstractions « qui fuient » – ieobjets de domaine censés exposer des dizaines de méthodes
get
/set
qui affaiblissent lencapsulation (ou, si vous ne le faites pas, alors un autre programmeur probablement plus tard ..). - Un risque que les objets du domaine deviennent gonflés avec un mélange complexe de données commerciales (par exemple, saisie de données utilisateur via une interface utilisateur) et détat transitoire (par exemple, un «historique» des actions de lutilisateur lorsque la commande a été modifiée).
DDD, OO Design et Plain Models
Une idée fausse courante concernant DDD et OO Design est que les modèles « simples » sont en quelque sorte » mauvais « ou » anti-pattern « . Martin Fowler a écrit un article décrivant le Modèle de domaine anémique – mais comme il le précise dans larticle, DDD lui-même devrait ne pas « contredire » lapproche de séparation nette entre les couches
« Il est également intéressant de souligner que la mise en place dun comportement dans les objets du domaine ne doit pas contredire lapproche solide de lutilisation de la stratification pour sepa Évaluer la logique du domaine à partir déléments tels que la persistance et les responsabilités de présentation. La logique qui devrait être dans un objet de domaine est la logique de domaine – validations, calculs, règles métier – comme vous voulez lappeler. «
En dautres termes, utiliser des modèles simples pour conserver les données métiers transférées entre dautres couches (par exemple un modèle de commande transmis par une application utilisateur lorsque lutilisateur souhaite créer une nouvelle commande) nest pas la même chose quun «modèle de domaine anémique». Les modèles de données « simples » sont souvent le meilleur moyen de suivre les données et de transférer des données entre les couches (comme un service Web REST, un magasin de persistance, une application ou une interface utilisateur, etc.).
La logique métier peut traiter le données dans ces modèles et peut les suivre dans le cadre de l’état de l’entreprise – mais ne sappropriera pas nécessairement ces modèles.
La racine agrégée
En regardant à nouveau les exemples d’objets de domaine – SalesOrderCheckout
, PendingOrdersStream
, WarehouseOrderDespatcher
, OrderRefundProcessor
il ny a toujours pas de racine agrégée évidente; mais esn « t réellement important parce que ces objets de domaine ont des responsabilités extrêmement distinctes qui ne semblent pas se chevaucher.
Fonctionnellement, il nest pas nécessaire que le SalesOrderCheckout
parle au PendingOrdersStream
car le travail du premier est terminé lorsquil a ajouté une nouvelle commande à la base de données; en revanche, PendingOrdersStream
peut récupérer de nouvelles commandes de la base de données. Ces objets nont pas besoin dinteragir avec chacun autre directement (peut-être quun médiateur dévénements pourrait fournir des notifications entre les deux, mais je mattendrais à ce que tout couplage entre ces objets soit très lâche)
Peut-être que la racine dagrégation sera un conteneur IoC qui injecte un ou plusieurs des ces objets de domaine dans un contrôleur dinterface utilisateur, fournissant également dautres infrastructures telles que EventMediator
et Repository
. Ou peut-être que ce sera une sorte de service Orchestrator léger assis au-dessus de la couche métier.
La racine d’agrégat n’a pas nécessairement besoin d’être un objet de domaine. Dans un souci de séparation des préoccupations entre les objets de domaine, c’est généralement une bonne chose lorsque l’agrégat root est un objet distinct sans logique métier.
Commentaires
- Jai voté défavorablement parce que votre réponse associe les concepts dEntity Framework, une technologie spécifique à Microsoft, à Domain Driven Design, qui provient dun livre écrit par Eric Evans du même nom. Vous avez des déclarations dans votre réponse qui sont en contradiction directe avec le livre DDD et cette question ne fait aucune mention dEntity Framework mais est spécifiquement étiquetée avec DDD. Il ny a ‘ aucune mention de persistance dans la question donc je ne ‘ pas voir où les tables de la base de données sont pertinentes.
- @RibaldEddie Merci davoir pris le temps de revoir la réponse et le commentaire, jaccepte la mention de données persistantes ‘ t vraiment besoin dêtre dans la réponse, donc je ‘ nous lavons reformulé pour le supprimer. L’objectif principal de la réponse pourrait être résumé comme suit: » Les noms d’entités ne sont souvent ‘ que de très bons noms de classes d’objets de domaine en raison de leur tendance à devenir des objets de Dieu gonflés étroitement couplés « , jespère que le message et le raisonnement des exigences fonctionnelles / du comportement du WRT sont plus clairs maintenant?
- Le livre DDD ne ‘ Jai ce concept IIRC. Il a des entités, qui sont simplement des classes qui, une fois instanciées, ont une identité persistante et unique, de sorte que deux instances séparées impliquent deux choses uniques et persistantes, ce qui contraste avec les objets de valeur qui ne ‘ t avoir une identité et ne pas ‘ persister dans le temps. Dans le livre, les objets Entities et Value sont des objets de domaine.
Réponse
dans notre domaine de problème, nous avons une règle commerciale indiquant quun client ne peut avoir quune seule commande non livrée à la fois.
Avant daller trop loin dans ce terrier de lapin, vous devriez examiner Greg Discussion de Young sur la cohérence densemble , et en particulier:
Quel est l’impact commercial d’un échec?
Parce que dans de nombreux cas, la bonne réponse n’est pas d’essayer d’empêcher la mauvaise chose se produit, mais à la place de générer des rapports dexceptions en cas de problème.
Mais, en supposant que plusieurs commandes non livrées sont une responsabilité importante pour votre entreprise ….
Oui, si vous voulez vous assurer quil ny a quune seule commande non livrée, alors il doit y avoir un agrégat qui peut voir toutes les commandes dun client .
Cet agrégat nest pas nécessairement lagrégat client .
Cela peut être quelque chose comme une file dattente de commandes, ou un historique des commandes, où toutes les commandes pour un le client entre dans la même file dattente. Daprès ce que vous avez dit, il na pas besoin de toutes les données de profil du client, donc cela ne devrait pas faire partie de cet agrégat.
Mais en ce qui concerne lexpédition, ils effectuent toutes leurs actions sur la commande, pas sur le client.
Oui, lorsque vous travaillez réellement avec lexécution et tirez les feuilles, la vue historique nest pas particulièrement pertinente.
La vue historique, pour appliquer votre invariant, na besoin que de lID de commande et de son état de traitement actuel. Cela na pas nécessairement besoin de faire partie du même agrégat que la commande – rappelez-vous, les limites de lagrégat concernent la gestion du changement et non la structuration des vues.
Il se peut donc que vous gériez la commande comme un agrégat et lhistorique des commandes en tant quagrégat séparé, et coordonnez lactivité entre les deux.
Réponse
Vous avez configuré un exemple de personne de paille. Cest trop simpliste et je doute que cela reflète un système réel. Je ne modéliserais pas ces Entités et leur comportement associé de la manière que vous avez spécifiée à cause de cela.
Vos classes doivent modéliser le état dune commande dune manière qui se reflète dans plusieurs agrégats. Par exemple, lorsque le client place le système dans létat où la demande de commande du client doit être traitée, je peux créer un agrégat dobjet dentité de domaine appelé CustomerOrderRequest
ou PendingCustomerOrder
ou même simplement CustomerOrder
, ou quelle que soit la langue utilisée par lentreprise, et il peut contenir un pointeur vers le client et les lignes de commande, puis avoir une méthode comme canCustomerCompleteOrder()
qui est appelé depuis la couche de service.
Cet objet de domaine contiendrait la logique métier permettant de déterminer si la commande était valide ou non.
Si la commande était valide et traitée, alors jaurais un moyen de faire la transition de cet objet vers un autre objet représentant la commande traitée.
Je pense que le problème avec votre compréhension est que vous utilisez un objet artificiel exemple simplifié dagrégats. Un PendingOrder
peut être son propre agrégat séparé dun UndeliveredOrder
et à nouveau séparé dun ou un CancelledOrder
ou autre.
Commentaires
- Bien que votre tentative au langage neutre est amusant, je noterais que les femmes ne se tiennent jamais dans les champs pour effrayer les corbeaux.
- @RobertHarvey que ‘ est une chose étrange sur laquelle se concentrer dans mon post. Des épouvantails et des effigies sont régulièrement apparus sous forme féminine tout au long de lhistoire.
- Vous nauriez pas ‘ fait la distinction dans votre message si vous navez pas ‘ t considère que cest important. Du point de vue linguistique, le terme est » homme de paille; » toute réserve sur le sexisme est presque certainement dépassée par le » de quoi diable parle-t-il » facteur créé en inventant votre propre terme.
- @RobertHarvey si quelquun sait quelle paille homme veut dire, je ‘ je suis sûr quils peuvent comprendre ce que signifie personne de paille sils nont ‘ entendu ce terme. Pouvons-nous nous concentrer sur le contenu de mon message sil vous plaît écrire un logiciel?
Réponse
Vaughn Vernon le mentionne dans son livre « Implémentation de la conception pilotée par domaine » au début du chapitre 7 (Services):
« Souvent, la meilleure indication que vous devez créer un service dans le modèle de domaine est lorsque lopération que vous devez effectuer se sent de place comme méthode sur un agrégat ou un objet de valeur ».
Donc, dans ce cas, il pourrait y avoir un service de domaine appelé « CreateOrderService » qui prend une instance Client et la liste des articles pour la commande.
class CreateOrderService { public Order CreateOrder(Customer customer, ThingsInTheOrder thingsInTheOrder) { // Get all the orders for the customer // Check if any of the things to be ordered exist in previous orders // If none have been previously ordered, create the order and return it // Otherwise return null } }
Commentaires
- Pouvez-vous expliquer plus en détail comment le service de domaine peut aider à résoudre le problème de concurrence dans la question?
Laisser un commentaire