Comment concevoir les limites agrégées?


10

Je voudrais écrire une application quelque chose comme le commerce électronique.

Et vous savez que dans des applications similaires, les produits peuvent avoir des propriétés et des fonctionnalités différentes. Pour simuler une telle opportunité, j'ai créé les entités de modèle de domaine suivantes:

Catégorie - c'est quelque chose comme "électronique> ordinateurs", c'est-à-dire les types de produits. Les catégories contiennent une liste de propriétés (Liste <Propriété>).

Propriété - entité indépendante qui contient le nom, les unités de mesure et le type de données. Par exemple, "nom", "poids", "taille d'écran". La même propriété peut avoir différents produits.

Produit - contient uniquement le nom et la liste des valeurs relatives aux propriétés. La valeur est un objet qui contient uniquement le champ de valeur et l'ID de champ de la propriété.

J'ai initialement décidé de faire de la catégorie un seul agrégat dans ce schéma, car par exemple, lorsque j'ajoute un nouveau produit, j'ai besoin de connaître toutes les données liées à la catégorie actuelle, y compris les propriétés liées à la catégorie actuelle ( category.AddNewProduct (product) ). Mais que dois-je faire lorsque j'ai juste besoin d'ajouter une nouvelle propriété qui n'appartient à aucune catégorie. Par exemple, je ne peux pas faire cette catégorie.AddNewProperty (propriété) car cela dit clairement que nous ajoutons la propriété à une catégorie spécifique.

Ok, l'étape suivante, j'ai décidé de séparer la propriété en un agrégat distinct, mais ce sera une liste avec des entités simples.

Bien sûr, je peux créer quelque chose comme PropertyAggregate pour conserver la liste des propriétés et les règles commerciales, mais lorsque j'ajoute un produit, j'ai besoin d'avoir dans la catégorie la liste complète des propriétés appartenant à cette catégorie pour vérifier les invariants. Mais je suis également conscient que conserver les liens à l'intérieur de l'agrégat sur d'autres agrégats est une mauvaise pratique.

Quelles sont les options pour concevoir cette analyse de rentabilisation?


Pourriez-vous fournir un exemple plus complet d'une catégorie, d'une propriété et d'un produit? L'électronique ou les ordinateurs seraient une catégorie, l'iPhone X serait un exemple de produit et une propriété serait quoi exactement? Écran de 11 pouces?
Neil

vous avez presque raison. J'ai ajouté quelques clarifications
cephei

Il semble que vous envisagiez la conception globale uniquement dans une perspective de «conteneur de données». Vous pouvez également penser aux cas d'utilisation de votre application, en tenant compte des aspects transactionnels, de la collaboration / accès simultané, des événements qui se produisent, des transitions d'état, etc.
guillaume31

Réponses:


7

Dans la perspective DDD Category, Productet Propertysont des entités: elles correspondent toutes à des objets qui ont leur propre identité.

Option 1: votre design original

Vous avez créé Categoryla racine d'un seul agrégat. D'un côté, cela a un sens, parce que l'ensemble assure la cohérence en cas de modifications de ses objets, et Productdoit avoir le Propertiesson Category:

entrez la description de l'image ici

Mais d'un autre côté, le seul agrégat signifie que tous ses objets sont liés à une racine qui les possède, et toutes les références externes doivent être faites via cette racine agrégée. Cela implique que:

  • un spécifique Productappartient à un et un seul Category. Si le Categoryest supprimé, il en sera de même Products.
  • un spécifique Propertyappartient à un seul et unique Category. Autrement dit, si "Écrans de télévision" et "Écrans d'ordinateur" seraient deux catégories, "Écrans de télévision: taille" et "Écrans d'ordinateur: taille" seraient deux propriétés différentes.

Le deuxième point ne correspond pas à votre récit: " Mais que dois-je faire quand j'ai juste besoin d'ajouter un nouveau Propertyqui n'appartient à aucune catégorie ". Et il n'est pas clair si le même Propertiespeut être utilisé dans différents Categories.

Option 2: propriété en dehors de l'agrégat

Si un Propertyexiste indépendamment du Categories, il doit être en dehors de l'agrégat. Et la même chose si vous souhaitez partager Propertiesentre Categories(ce qui a du sens pour la hauteur, la largeur, les tailles, etc ...). Cela semble définitivement être le cas.

La conséquence est sur le lien entre Propertyet les choses qui appartiennent à l'agrégat: alors que vous pouvez naviguer de l'intérieur de l'agrégat vers Property, vous n'êtes plus autorisé à passer directement de a Propertyaux valeurs correspondantes. Cette restriction de navigabilité peut être représentée dans un diagramme UML:

entrez la description de l'image ici

Notez que cette conception ne vous empêche pas d'avoir un List<Property>in Category, avec une sémantique de référence (par exemple java): chaque référence dans la liste fait référence à un Propertyobjet partageable dans un référentiel.

Le seul problème avec cette conception est que vous pouvez le modifier Propertyou le supprimer: comme il est en dehors de l'agrégat, l'agrégat ne peut pas prendre soin de la cohérence de ses invariants. Mais ce n'est pas un problème. C'est la conséquence des principes DDD et de la complexité du monde réel. Voici une citation d'Eric Evans dans son livre fondateur " Domain-Driven Design: Tackling Complexity in the Heart of Software ":

On ne s'attend pas à ce que toute règle qui couvre les AGREGATS soit à jour en tout temps. Grâce au traitement des événements, au traitement par lots ou à d'autres mécanismes de mise à jour, d'autres dépendances peuvent être résolues dans un délai spécifié. Mais les invariants appliqués au sein d'un AGRÉGAT seront appliqués à la fin de chaque transaction.

Donc oui, si vous modifiez un Property, vous devrez vous assurer qu'un service vérifie que les catégories qui s'y réfèrent sont mises à jour au besoin.

Option 3: catégorie, propriété et produit dans différents agrégats

Je me demande simplement si l'hypothèse selon laquelle un Productappartient à un célibataire Categoryest fondée:

  • Je vois souvent des boutiques en ligne en proposer une Productsous plusieurs Categories. Par exemple, vous trouverez "Laptop Brand X Model Y" dans la catégorie "Laptops" et la catégorie "Computers", et une "multifunction printer Z" dans la catégorie "printer", "scanner" and "fax".
  • N'est-il pas possible que quelqu'un crée une Productpremière, puis l'attribue plus tard aux catégories et remplisse les valeurs?
  • Si vous souhaitez diviser une catégorie, supprimeriez-vous vraiment ses produits, puis les recréeriez-vous sous les nouvelles catégories?

Cela ne simplifiera pas les agrégats et vous auriez encore plus de règles qui s'étendent sur les agrégats. Mais votre système serait beaucoup plus à l'épreuve du temps.


Merci beaucoup, c'est une explication très utile. Mais je voudrais clarifier quelques points. Je voudrais commencer par la deuxième option et qui sait, je vais peut-être en venir à la troisième. Si je Propertydépasse les limites de l' Categoryagrégat, cela signifie-t-il que cela Propertydevient un agrégat en soi et a besoin d'un référentiel? Si c'est vrai, alors comment passer requis List<Property>en Categoryinstance? Par le constructeur? Ce sera vrai? Et comment puis-je trouver la liste des Propertyidentifiants d'un Categoryqui n'a pas encore été créé?
cephei

@zetetic en bref: oui, vous aurez besoin d'un référentiel de propriétés indépendant. Soit vous passez une liste de propriétés existantes à l'usine de la catégorie, soit vous créez des catégories vides et remplissez la liste avec une méthode addProperty. Question en retour: imaginez que vous voulez avoir des propriétés "obligatoires" et "facultatives", et la caractéristique obligatoire dépend de la catégorie. Comment voulez-vous gérer cela ?
Christophe

Pour répondre à votre question, la première chose qui me vient à l'esprit est que je peux créer une entité spéciale Featurequi n'appartiendra qu'à la Product. et cette entité ne participera pas à la recherche. Que dis-tu ?
cephei

@zetetic pourquoi pas! J'aurais laissé les valeurs telles qu'elles sont actuellement dans le produit et j'aurais associé la fonctionnalité à la catégorie. Une catégorie a n fonctionnalités (une partie de son agrégat), une propriété définit m fonctionnalités (mais le lien passe par la fonctionnalité catégorie->). Vous avez ensuite décomposé la relation plusieurs-à-plusieurs en éléments plus faciles à gérer, clarifiant la frontière globale. Enfin sur l'injection de référentiel: cela n'est pas obligatoire si vous référencez d'autres agrégats par identité (lire cet article informit.com/articles/article.aspx?p=2020371&seqNum=4 )
Christophe

5

À mon avis, vous pouvez résoudre ce problème de deux manières:

La catégorie est un type de produit spécial

Cela signifie que pour tout produit donné dans votre base de données, il contient une clé étrangère pointant vers le même produit de table. Un produit n'est un produit que s'il n'existe aucun produit dont la clé étrangère est égale à l'id dudit produit. En d'autres termes, s'il n'a aucun produit en dessous, c'est un produit.

Cela simplifierait un peu les choses. Les produits aux propriétés auraient une relation un-à-plusieurs et, par conséquent, vos catégories ont également une relation un-à-plusieurs car elles sont également des produits. Ajouter une propriété à une catégorie serait aussi simple que d'ajouter une propriété à un produit dans votre programme. Le chargement de toutes les propriétés impliquerait de combiner les propriétés du produit avec les propriétés de son produit de catégorie associé et ainsi de suite jusqu'à ce que vous atteigniez un produit de catégorie sans parent.

Votre application de commerce électronique devrait faire cette distinction, mais si vous êtes de toute façon susceptible de charger des produits d'une catégorie, ce n'est pas une perte de performances de savoir si vous avez affaire à une catégorie ou à un produit. Il se prête également bien à la recherche arborescente au niveau du produit, car chaque produit (catégorie) s'ouvrirait à une liste de sous-produits sans beaucoup de travail supplémentaire.

L'inconvénient est bien sûr que des informations supplémentaires présentes dans le produit qui n'ont pas de sens pour une catégorie créeraient des champs inutilisés maladroits dans le produit. Bien que cette solution soit plus flexible dans votre application, elle est également un peu moins intuitive.

Relation plusieurs à plusieurs

Les produits ne sont plus dans une relation composite avec la propriété. Vous créez une table ProductProperty avec des clés étrangères de la table de produit et de la table de propriétés qui lient les deux. De même, vous avez une table de catégories avec une relation plusieurs-à-plusieurs avec la table de propriétés et une table CategoryProperty avec des clés étrangères de la table des catégories et de la table des propriétés.

Le produit lui-même aurait une relation plusieurs-à-un avec la catégorie, vous permettant essentiellement de créer une liste de propriétés uniques se rapportant à la fois au produit et à la catégorie via une déclaration de sélection bien formalisée.

Du point de vue de la base de données, c'est définitivement plus propre et plus flexible. Votre application pourrait probablement faire la plupart du temps sans traiter directement avec CategoryProperty ou ProductProperty si la requête est effectuée correctement. Cependant, vous ne devez pas non plus considérer la catégorie ou le produit comme le propriétaire d'un bien. Il doit s'agir de sa propre entité au sein de votre programme. Cela signifie également que la gestion desdites propriétés consisterait à créer la propriété elle-même, puis à l'associer à une catégorie ou à un produit en deux étapes distinctes. Certes, plus de travail que la première solution, mais en aucun cas plus difficile.

En plus de cela, vous devrez également effectuer une vérification supplémentaire lors de la suppression de la catégorie ou du produit si l'une de ses propriétés est utilisée par d'autres (contrairement à la première solution où vous pouviez éliminer en toute sécurité toutes les propriétés associées d'un produit / catégorie donné) .

Conclusion

Dans un contexte professionnel, j'irais dans la catégorie mile supplémentaire et distance du produit et du produit de la propriété en utilisant l'approche plusieurs-à-plusieurs. Il n'y aurait aucune possibilité de chevauchement des données, et dans un sens, il est plus facile de raisonner chacun de ces trois en tant qu'entité propre. Cependant, la première solution n'est en aucun cas mauvaise, car elle vous permet également d'écrire une application plus simple. Sachez simplement que si vous pensiez que vous deviez éventuellement passer d'une solution à l'autre, il serait probablement dans votre intérêt de choisir la seconde.

Bonne chance!


Merci pour la réponse détaillée et intéressante! au niveau de la base de données que j'ai déjà modélisé comme vous l'avez expliqué dans le deuxième cas, ce modèle est appelé entité-attribut-valeur mais je suis bloqué au niveau du code à savoir la définition des agrégats. Dans la plupart des cas, toutes ces entités sont utilisées ensemble. il est possible de les combiner en un seul agrégat, mais il y a des cas qui aiment remplir des répertoires qui, par sens, sont éliminés de l'agrégat.
cephei
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.