Kurzfassung
Der Grund für DDD ist, dass Domänenobjekte Abstraktionen sind, die Ihre funktionalen Domänenanforderungen erfüllen sollten. Wenn Domänenobjekte diese Anforderungen nicht einfach erfüllen können, deutet dies darauf hin, dass Sie möglicherweise die falsche Abstraktion verwenden.
Das Benennen von Domänenobjekten mithilfe von Entitätsnomen kann dazu führen, dass diese Objekte eng miteinander gekoppelt werden und aufgeblähte "Gott" -Objekte werden, und sie können Probleme wie das in dieser Frage aufgeworfene wie "Wo ist der richtige Ort, um das zu platzieren?" Aufwerfen CreateOrder-Methode? ".
Um die Identifizierung des richtigen Aggregatstamms zu vereinfachen, sollten Sie einen anderen Ansatz in Betracht ziehen, bei dem Domänenobjekte auf den funktionalen Geschäftsanforderungen auf hoher Ebene basieren. Wählen Sie daher Substantive aus, die auf funktionale Anforderungen und / oder Verhaltensweisen verweisen, die Benutzer des Systems benötigen ausführen.
Lange Version
DDD ist ein Ansatz für OO-Design, der zu einem Diagramm der Domänenobjekte in der Geschäftsschicht Ihres Systems führen soll. Domänenobjekte sind für die Erfüllung Ihrer Geschäftsanforderungen auf hoher Ebene verantwortlich und sollten sich im Idealfall auf die Datenschicht verlassen können für Dinge wie die Leistung und Integrität des zugrunde liegenden persistenten Datenspeichers.
Eine andere Sichtweise könnten die Aufzählungspunkte in dieser Liste sein
- Entitätsnomen schlagen normalerweise Datenattribute vor.
- Domain-Nomen sollten Verhalten vorschlagen
- DDD- und OO-Modellierung befassen sich mit Abstraktionen, die auf funktionalen Anforderungen und der Kerndomänen- / Geschäftslogik basieren.
- Die Business Logic Layer ist dafür verantwortlich, die Domänenanforderungen auf hoher Ebene zu erfüllen
Eines der häufigsten Missverständnisse in Bezug auf DDD ist, dass Domänenobjekte auf einem physischen "Ding" der realen Welt basieren sollten (dh auf einem Substantiv, auf das Sie in der realen Welt verweisen können, das allen Arten von Daten / Eigenschaften zugeordnet ist), jedoch auf den Daten / Attribute dieser realen Dinge sind nicht unbedingt ein guter Ausgangspunkt, wenn versucht wird, funktionale Anforderungen festzulegen.
Natürlich sollte Business - Logik verwendet diese Daten, sondern Domain Objekte sich letztlich Abstraktionen , die funktionelle Domain Anforderungen und Verhaltensweisen darstellen sollten.
Zum Beispiel; Substantive wie Orderoder Customerimplizieren kein Verhalten und sind daher im Allgemeinen nicht hilfreiche Abstraktionen für die Darstellung von Geschäftslogik und Domänenobjekten.
Berücksichtigen Sie bei der Suche nach Abstraktionen, die für die Darstellung von Business Logic nützlich sein können, typische Anforderungen, die ein System möglicherweise erfüllen wird:
- Als Verkäufer möchte ich eine Bestellung für einen neuen Kunden erstellen, damit ich eine Rechnung für die zu verkaufenden Produkte mit ihren Preisen und Mengen erstellen kann.
- Als Kundendienstberater möchte ich eine ausstehende Bestellung stornieren, damit die Bestellung nicht von einem Lagerbetreiber ausgeführt wird.
- Als Kundendienstberater möchte ich eine Bestellposition zurücksenden, damit das Produkt in den Lagerbestand aufgenommen werden kann und die Zahlung über die ursprüngliche Zahlungsmethode des Kunden zurückerstattet wird.
- Als Lagerbetreiber möchte ich alle Produkte in einer ausstehenden Bestellung und die Versandinformationen anzeigen, damit ich die Produkte auswählen und über den Kurier versenden kann.
- usw.
Modellierung von Domänenanforderungen mit einem DDD-Ansatz
Berücksichtigen Sie anhand der obigen Liste einige potenzielle Domänenobjekte für ein solches Auftragssystem:
SalesOrderCheckout
PendingOrdersStream
WarehouseOrderDespatcher
OrderRefundProcessor
Als Domänenobjekte stellen diese Abstraktionen dar, die Eigentümer verschiedener Verhaltensdomänenanforderungen sind. in der Tat weisen ihre Substantive stark auf die spezifischen funktionalen Anforderungen hin, die sie erfüllen.
(Möglicherweise befindet sich dort auch eine zusätzliche Infrastruktur, z. B. eine EventMediatorBenachrichtigung für Beobachter, die wissen möchten, wann eine neue Bestellung erstellt wurde oder wann eine Bestellung versendet wurde usw.).
Zum Beispiel muss SalesOrderCheckoutwahrscheinlich Daten über Kunden, Versand und Produkte verarbeitet werden, hat jedoch nichts mit dem Verhalten für Versandaufträge, das Sortieren ausstehender Bestellungen oder das Ausstellen von Rückerstattungen zu tun.
Um SalesOrderCheckoutdie Domänenanforderungen zu erfüllen, müssen diese Geschäftsregeln durchgesetzt werden, z. B. verhindert werden, dass Kunden zu viele Artikel bestellen, möglicherweise eine Validierung durchführen und möglicherweise Benachrichtigungen für andere Teile des Systems auslösen. All diese Aufgaben können ausgeführt werden, ohne dass Sie sich darauf verlassen müssen der anderen Objekte.
DDD verwendet Entitätsnomen zur Darstellung von Domänenobjekten
Es gibt eine Reihe von möglichen Gefahren , wenn einfache Substantive wie die Behandlung Order, Customerund Productals Domain - Objekte; Zu diesen Problemen gehören diejenigen, auf die Sie in der Frage anspielen:
- Wenn eine Methode ein
Order, ein Customerund ein behandelt Product, zu welchem Domänenobjekt gehört sie?
- Wo ist die aggregierte Wurzel für diese 3 Objekte?
Wenn Sie Entitätsnomen auswählen, um Domänenobjekte darzustellen, kann eine Reihe von Dingen passieren:
Order, CustomerUnd Productsind in Gefahr , in „Gott“ Objekte des Wachsens
- Das Risiko, mit einem einzigen
ManagerGottobjekt zu enden , um alles zusammenzubinden.
- Diese Objekte laufen Gefahr, eng miteinander verbunden zu werden. Es kann schwierig sein, die Domänenanforderungen zu erfüllen, ohne sie zu bestehen
this(oder self).
- Das Risiko, "undichte" Abstraktionen zu entwickeln - dh Domänenobjekte, von denen erwartet wird, dass sie Dutzende von
get/ setMethoden offenlegen, die die Kapselung schwächen (oder, wenn Sie dies nicht tun, wird es wahrscheinlich später ein anderer Programmierer tun ..).
- Es besteht die Gefahr, dass Domain-Objekte durch eine komplexe Mischung aus Geschäftsdaten (z. B. Eingabe von Benutzerdaten über eine Benutzeroberfläche) und vorübergehendem Status (z. B. eine 'Historie' von Benutzeraktionen, wenn die Bestellung geändert wurde) aufgebläht werden.
DDD, OO Design und einfache Modelle
Ein häufiges Missverständnis in Bezug auf DDD und OO Design ist, dass "einfache" Modelle irgendwie "schlecht" oder "anti-pattern" sind. Martin Fowler schrieb einen Artikel, der das anämische Domänenmodell beschreibt - aber wie er in dem Artikel klarstellt, sollte DDD selbst dem Ansatz einer sauberen Trennung zwischen Schichten nicht „widersprechen“
"Es ist auch hervorzuheben, dass das Einfügen von Verhalten in Domänenobjekte nicht dem soliden Ansatz widersprechen sollte, mithilfe von Layering die Domänenlogik von Dingen wie Persistenz und Präsentationsverantwortung zu trennen. Die Logik, die in einem Domänenobjekt enthalten sein sollte, ist Domänenlogik - Validierungen, Berechnungen , Geschäftsregeln - wie auch immer Sie es nennen möchten. "
Mit anderen Worten, die Verwendung einfacher Modelle zum Speichern von Geschäftsdaten, die zwischen anderen Ebenen übertragen werden (z. B. ein Auftragsmodell, das von einer Benutzeranwendung übergeben wird, wenn der Benutzer einen neuen Auftrag erstellen möchte), ist nicht dasselbe wie ein "anämisches Domänenmodell". "Einfache" Datenmodelle sind häufig der beste Weg, um Daten zu verfolgen und Daten zwischen Ebenen zu übertragen (z. B. ein REST-Webdienst, ein Persistenzspeicher, eine Anwendung oder eine Benutzeroberfläche usw.).
Die Geschäftslogik verarbeitet möglicherweise die Daten in diesen Modellen und verfolgt sie möglicherweise als Teil des Geschäftsstatus. Sie übernimmt jedoch nicht unbedingt das Eigentum an diesen Modellen.
Die aggregierte Wurzel
Betrachtet man erneut das Beispiel Domain Objekte - SalesOrderCheckout, PendingOrdersStream, WarehouseOrderDespatcher, OrderRefundProcessores gibt noch keine offensichtlichen Aggregate Wurzel; Dies spielt jedoch keine Rolle, da diese Domänenobjekte völlig unterschiedliche Verantwortlichkeiten haben, die sich nicht zu überschneiden scheinen.
Funktionell ist es nicht erforderlich, mit dem SalesOrderCheckoutzu sprechen, PendingOrdersStreamda der Job des ersteren abgeschlossen ist, wenn der Datenbank eine neue Reihenfolge hinzugefügt wurde. Auf der anderen Seite PendingOrdersStreamkann der neue Aufträge aus der Datenbank abrufen. Diese Objekte müssen nicht direkt miteinander interagieren (möglicherweise kann ein Ereignisvermittler Benachrichtigungen zwischen den beiden bereitstellen, aber ich würde erwarten, dass die Kopplung zwischen diesen Objekten sehr locker ist).
Möglicherweise ist der aggregierte Stamm ein IoC-Container, der eines oder mehrere dieser Domänenobjekte in einen UI-Controller einfügt und auch andere Infrastrukturen wie EventMediatorund bereitstellt Repository. Oder vielleicht ist es eine Art leichter Orchestrator-Service, der auf der Business-Ebene sitzt.
Das Aggregatstammverzeichnis muss nicht unbedingt ein Domänenobjekt sein. Um die Trennung von Bedenken zwischen Domänenobjekten aufrechtzuerhalten, ist es im Allgemeinen eine gute Sache, wenn der aggregierte Stamm ein separates Objekt ohne Geschäftslogik ist.