Wie werden die Aggregatgrenzen entworfen?

10

Ich möchte eine Anwendung wie E-Commerce schreiben.

Und Sie wissen, dass Produkte in ähnlichen Anwendungen unterschiedliche Eigenschaften und Merkmale haben können. Um eine solche Gelegenheit zu simulieren, habe ich die folgenden Domänenmodellentitäten erstellt:

Kategorie - dies ist so etwas wie "Elektronik> Computer", dh Arten von Produkten. СKategorien enthalten eine Liste von Eigenschaften (Liste <Eigenschaft>).

Eigenschaftsunabhängige Entität, die den Namen, die Maßeinheiten und den Datentyp enthält. Zum Beispiel "Name", "Gewicht", "Bildschirmgröße". Dieselbe Eigenschaft kann unterschiedliche Produkte haben.

Produkt - enthält nur den Namen und eine Liste der Werte für Eigenschaften. Wert ist ein Objekt, das nur das Wertfeld und die Feld-ID der Eigenschaft enthält.

Ich habe ursprünglich beschlossen, die Kategorie in diesem Schema wie ein einzelnes Aggregat zu gestalten, da ich beispielsweise beim Hinzufügen eines neuen Produkts alle Daten zur aktuellen Kategorie kennen muss, einschließlich der Eigenschaften zur aktuellen Kategorie ( category.AddNewProduct (Produkt) ). Aber was soll ich tun, wenn ich nur eine neue Eigenschaft hinzufügen muss, die keiner Kategorie angehört? Zum Beispiel kann ich diese Kategorie nicht ausführen. AddNewProperty (Eigenschaft), da eindeutig angegeben ist, dass wir die Eigenschaft einer bestimmten Kategorie hinzufügen.

Ok, im nächsten Schritt habe ich eine separate Eigenschaft in ein separates Aggregat umgewandelt, aber dann wird es eine Liste mit einfachen Entitäten sein.

Natürlich kann ich so etwas wie PropertyAggregate erstellen, um die Liste der Eigenschaften und Geschäftsregeln beizubehalten, aber wenn ich ein Produkt hinzufüge, muss die gesamte Liste der zu dieser Kategorie gehörenden Eigenschaften in der Kategorie enthalten sein, um die Invarianten zu überprüfen. Mir ist aber auch bewusst, dass es eine schlechte Praxis ist, die Links innerhalb des Aggregats auf anderen Aggregaten zu belassen.

Welche Möglichkeiten gibt es, um diesen Business Case zu entwerfen?

Cephei
quelle
Könnten Sie ein vollständigeres Beispiel für eine Kategorie, eine Eigenschaft und ein Produkt liefern? Elektronik oder Computer wären eine Kategorie, iPhone X wäre ein Beispiel für ein Produkt und eine Eigenschaft wäre was genau? 11 "Zoll Display?
Neil
Du hast fast recht. Ich habe einige Klarstellungen hinzugefügt
Cephei
Anscheinend betrachten Sie das Aggregatdesign ausschließlich aus der Perspektive eines "Datencontainers". Möglicherweise möchten Sie auch über Anwendungsfälle Ihrer Anwendung nachdenken und dabei Transaktionsaspekte, Zusammenarbeit / gleichzeitigen Zugriff, Ereignisse,
Statusübergänge

Antworten:

7

In der DDD Sicht Category, Productund Propertysind Einheiten: sie alle entsprechen den Objekten , die ihre eigene Identität haben.

Option 1: Ihr ursprüngliches Design

Sie haben Categorydie Wurzel eines einzelnen Aggregats erstellt. Auf der einen Seite ist dies sinnvoll, da das Aggregat Konsistenz gewährleisten soll , wenn seine Objekte geändert werden, und Productmuss die haben Propertiesseiner Category:

Geben Sie hier die Bildbeschreibung ein

Auf der anderen Seite bedeutet das einzelne Aggregat, dass alle seine Objekte mit einem Stamm verknüpft sind, dem sie gehören, und dass alle externen Verweise über diesen Aggregatstamm erfolgen müssen. Dies impliziert Folgendes:

  • eine bestimmte Productgehört zu einer und nur einer Category. Wenn das Categorygelöscht wird, ist es auch sein Products.
  • ein bestimmtes Propertygehört zu einem und nur einem Category. Wenn "Fernsehbildschirme" und "Computermonitore" zwei Kategorien wären, wären "Fernsehbildschirme: Größe" und "Computermonitore: Größe" zwei verschiedene Eigenschaften.

Der zweite Punkt entspricht nicht Ihrer Erzählung: " Aber was soll ich tun, wenn ich nur eine neue hinzufügen Propertymuss, die keiner Kategorie angehört? " Und es ist nicht klar, ob dasselbe Propertiesin verschiedenen verwendet werden kann Categories.

Option 2: Eigenschaft außerhalb des Aggregats

Wenn a Propertyunabhängig von existiert Categories, muss es außerhalb des Aggregats liegen. Und das Gleiche, wenn Sie Propertieszwischen beiden teilen möchten Categories(was für Höhe, Breite, Größe usw. Sinn macht). Dies scheint definitiv der Fall zu sein.

Die Konsequenz ist die Verknüpfung zwischen Propertyund Dingen, die zum Aggregat gehören: Während Sie vom Inneren des Aggregats zu navigieren können Property, dürfen Sie nicht mehr direkt von a Propertyzu den entsprechenden Werten wechseln. Diese Einschränkung der Navigationsfähigkeit kann in einem UML-Diagramm angezeigt werden:

Geben Sie hier die Bildbeschreibung ein

Beachten Sie, dass dieses Design nicht verhindert, dass Sie ein List<Property>In Categorymit einer Referenzsemantik (z. B. Java) haben: Jede Referenz in der Liste verweist auf ein gemeinsam nutzbares PropertyObjekt in einem Repository.

Das einzige Problem bei diesem Entwurf besteht darin, dass Sie ein ändern Propertyoder löschen können: Da es sich außerhalb des Aggregats befindet, kann das Aggregat die Konsistenz seiner Invarianten nicht berücksichtigen. Das ist aber kein Problem. Es ist die Folge der DDD-Prinzipien und der Komplexität der realen Welt. Hier ein Zitat von Eric Evans in seinem wegweisenden Buch " Domain-Driven Design: Komplexität im Herzen von Software angehen ":

Es wird nicht erwartet, dass eine Regel, die sich über AGGREGATES erstreckt , jederzeit auf dem neuesten Stand ist. Durch Ereignisverarbeitung, Stapelverarbeitung oder andere Aktualisierungsmechanismen können andere Abhängigkeiten innerhalb einer bestimmten Zeit aufgelöst werden. Die innerhalb eines AGGREGATE angewendeten Invarianten werden jedoch mit Abschluss jeder Transaktion erzwungen.

Wenn Sie also a ändern Property, müssen Sie sicherstellen, dass ein Dienst überprüft, ob die darauf verweisenden Kategorien bei Bedarf aktualisiert werden.

Option 3: Kategorie, Eigenschaft und Produkt in verschiedenen Aggregaten

Ich frage mich nur, ob die Annahme, dass a Productzu einer Single Categorygehört, begründet ist:

  • Ich sehe häufig Online-Shops, die einen Productunter mehreren vorschlagen Categories. Beispielsweise finden Sie "Laptop Marke X Modell Y" unter der Kategorie "Laptops" und der Kategorie "Computer" und einen "Multifunktionsdrucker Z" unter der Kategorie "Drucker", "Scanner" und "Fax".
  • Ist es nicht möglich, dass jemand eine Producterste erstellt und diese erst später Kategorien zuweist und die Werte ausfüllt?
  • Wenn Sie eine Kategorie aufteilen möchten, würden Sie ihre Produkte wirklich löschen und sie dann unter den neuen Kategorien neu erstellen?

Die Aggregate werden dadurch nicht vereinfacht, und Sie hätten noch mehr Regeln, die sich über Aggregate erstrecken. Ihr System wäre jedoch viel zukunftssicherer.

Christophe
quelle
Vielen Dank, dies ist eine sehr nützliche Erklärung. Aber ich möchte ein paar Punkte klarstellen. Ich möchte mit der zweiten Option beginnen und wer weiß, vielleicht komme ich zur dritten. Wenn ich Propertydie Grenzen des CategoryAggregats überschreite, bedeutet dies, dass es Propertyzu einem Aggregat für sich wird und ein Repository benötigt? Wenn es wahr ist, wie wird es dann List<Property>in die CategoryInstanz übergeben? Durch den Konstruktor? Es wird richtig sein? Und wie finde ich die Liste der PropertyIDs eines Categorynoch nicht erstellten heraus?
Cephei
@zetetic kurz gesagt: Ja, Sie benötigen ein unabhängiges Property-Repository. Entweder übergeben Sie eine Liste der vorhandenen Eigenschaften an die Factory der Kategorie, oder Sie erstellen leere Kategorien und füllen die Liste mit einer addProperty-Methode. Frage im Gegenzug: Stellen Sie sich vor, Sie möchten "obligatorische" und "optionale" Eigenschaften haben, und das obligatorische Merkmal hängt von der Kategorie ab. Wie würden Sie damit umgehen?
Christophe
Bei der Beantwortung Ihrer Frage fällt mir als Erstes ein, dass ich eine spezielle Entität erstellen kann Featureund diese nur der Product. und diese Entität wird nicht an der Suche teilnehmen. Was sagst du ?
Cephei
@ Zetetic warum nicht! Ich hätte die Werte so belassen, wie sie derzeit im Produkt enthalten sind, und die Funktion der Kategorie zugeordnet. Eine Kategorie hat n Merkmale (Teil ihres Aggregats), eine Eigenschaft definiert m Merkmale (der Link führt jedoch über das Merkmal Kategorie->. Sie haben dann die Viele-zu-Viele-Beziehung in besser verwaltbare Elemente zerlegt und die Aggregatgrenze geklärt. Schließlich zur Repository-Injektion: Dies ist nicht erforderlich, wenn Sie andere Aggregate nach Identität referenzieren (lesen Sie diesen Artikel informit.com/articles/article.aspx?p=2020371&seqNum=4 )
Christophe
5

Aus meiner Sicht können Sie dies auf zwei Arten lösen:

Kategorie ist eine spezielle Art von Produkt

Dies bedeutet, dass jedes Produkt in Ihrer Datenbank einen Fremdschlüssel enthält, der auf dasselbe Tabellenprodukt verweist. Ein Produkt ist nur dann ein Produkt, wenn keine Produkte vorhanden sind, deren Fremdschlüssel der ID des Produkts entspricht. Mit anderen Worten, wenn es keine Produkte enthält, ist es ein Produkt.

Dies würde die Dinge etwas vereinfachen. Produkte zu Immobilien haben eine Eins-zu-Viele-Beziehung, und daher haben auch Ihre Kategorien eine Eins-zu-Viele-Beziehung, da sie auch Produkte sind. Das Hinzufügen einer Eigenschaft zu einer Kategorie ist so einfach wie das Hinzufügen einer Eigenschaft zu einem Produkt in Ihrem Programm. Das Laden aller Eigenschaften würde bedeuten, dass die Eigenschaften des Produkts mit den Eigenschaften des zugehörigen Kategorieprodukts kombiniert werden, bis Sie ein Kategorieprodukt ohne übergeordnetes Produkt erreichen.

Ihre E-Commerce-Anwendung müsste diese Unterscheidung treffen. Wenn Sie jedoch wahrscheinlich Produkte einer Kategorie laden, ist es kein Leistungsverlust, zu wissen, ob es sich um eine Kategorie oder ein Produkt handelt. Es eignet sich auch gut für die Suche in Baumform auf Produktebene, da sich jedes Produkt (jede Kategorie) ohne viel zusätzlichen Aufwand für eine Liste von Unterprodukten öffnen würde.

Der Nachteil dabei ist natürlich, dass zusätzliche Informationen im Produkt vorhanden sind, die für eine Kategorie nicht sinnvoll sind und unangenehme, nicht verwendete Felder im Produkt erzeugen würden. Diese Lösung wäre in Ihrer Anwendung zwar flexibler, aber auch etwas weniger intuitiv.

Viele-zu-viele-Beziehung

Produkte stehen nicht mehr in einer zusammengesetzten Beziehung zum Eigentum. Sie erstellen eine ProductProperty-Tabelle mit Fremdschlüsseln sowohl der Produkttabelle als auch der Eigenschaftstabelle, die die beiden verknüpfen. Ebenso haben Sie eine Kategorietabelle mit einer Viele-zu-Viele-Beziehung zur Eigenschaftentabelle und eine CategoryProperty-Tabelle mit Fremdschlüsseln sowohl der Kategorietabelle als auch der Eigenschaftentabelle.

Das Produkt selbst hat eine Eins-zu-Eins-Beziehung zur Kategorie, sodass Sie im Wesentlichen eine Liste eindeutiger Eigenschaften erstellen können, die sich sowohl auf das Produkt als auch auf die Kategorie beziehen, und zwar über eine gut formalisierte select-Anweisung.

Aus Sicht der Datenbank ist dies definitiv sauberer und flexibler. Ihre Anwendung könnte wahrscheinlich größtenteils ohne direkte Bearbeitung von CategoryProperty oder ProductProperty auskommen, wenn die Abfrage ordnungsgemäß ausgeführt wird. Sie sollten jedoch weder Kategorie noch Produkt als Eigentümer von Eigentum behandeln. Es sollte eine eigene Entität in Ihrem Programm sein. Dies bedeutet auch, dass für die Verwaltung dieser Eigenschaften die Eigenschaft selbst erstellt und dann in zwei separaten Schritten einer Kategorie oder einem Produkt zugeordnet werden muss. Sicher mehr Arbeit als die erste Lösung, aber keineswegs schwieriger.

Darüber hinaus müssten Sie beim Löschen einer Kategorie oder eines Produkts eine zusätzliche Überprüfung durchführen, wenn eine der Eigenschaften von anderen verwendet wird (im Gegensatz zur ersten Lösung, bei der Sie alle zugehörigen Eigenschaften eines bestimmten Produkts / einer bestimmten Kategorie sicher entfernen könnten). .

Fazit

In einem professionellen Kontext würde ich die Kategorie Extrameile und Entfernung von Produkt und Produkt von Eigentum unter Verwendung des Viele-zu-Viele-Ansatzes wählen. Es gibt keine Möglichkeit einer Überlappung von Daten, und in gewissem Sinne ist es einfacher, jede dieser drei als ihre eigene Einheit zu begründen. Die erste Lösung ist jedoch keineswegs eine schlechte, da Sie damit auch eine einfachere Anwendung schreiben können. Wenn Sie dachten, Sie müssten möglicherweise irgendwann von einer Lösung zur anderen wechseln, wäre es wahrscheinlich nur in Ihrem Interesse, die zweite auszuwählen.

Viel Glück!

Neil
quelle
Danke für die ausführliche und interessante Antwort! Auf Datenbankebene habe ich bereits modelliert, wie Sie im zweiten Fall erklärt haben. Dieses Muster wird als Entity-Attribut-Wert bezeichnet, aber ich bleibe auf der Codeebene, nämlich der Definition von Aggregaten. In den meisten Fällen werden alle diese Entitäten zusammen verwendet. Es ist möglich, zu einem Aggregat zu kombinieren, aber es gibt Fälle, in denen Verzeichnisse gefüllt werden, die sinngemäß aus dem Aggregat herausgeschlagen werden.
Cephei