DDD - Ist das anämische Domänenmodell ein Antimuster? Sollen wir Rich-Domain-Modelle verwenden? [geschlossen]

11

Das anämische Domänenmodell wurde vor langer Zeit von Evans und Fowler kritisiert , da es offenbar gegen objektorientierte Prinzipien usw. verstößt. Die DDD-Community ist eindeutig auf diese Aussagen ausgerichtet.

In den letzten Jahren gab es jedoch nicht übereinstimmende Stimmen, die behaupteten, es sei überhaupt kein Antimuster und es sei ein Beispiel für die Befolgung von SOLID-Prinzipien.

Ich arbeite seit so vielen Jahren mit Spring Framework. Jedes Projekt in jedem Unternehmen hatte immer eine Service-Schicht, die die Geschäftslogik enthielt und Repositorys verwendete, die mit anämischen Modellen (JPA-Entitäten) arbeiten. Darüber hinaus zeigen die meisten Samples, sogar die offiziellen von den Spring-Jungs, diese Arbeitsweise.

Meine Fragen sind: Wird das anämische Domänenmodell immer noch als Antimuster betrachtet? Haben wir alle Dinge (in Bezug auf DDD) falsch gemacht? Denken Sie nicht, dass Rich Domain-Modelle gegen die SOLID-Prinzipien verstoßen?

codependent
quelle
2
" Wird das anämische Domänenmodell immer noch als Antimuster angesehen? " Von einigen ja. Von anderen, auch von mir, wird es die meiste Zeit als die bevorzugte Methode zum Schreiben von Code angesehen. Wenn das RDM jedoch zu Ihnen passt, verwenden Sie es. Stimmen Sie also ab, um dies als rein meinungsbasiert abzuschließen.
David Arno
1
Dies wäre eine fantastische Frage für ein Diskussions- / Debattenforum. Derzeit gibt es jedoch keine maßgebliche Antwort. Wir bevorzugen Fragen, die beantwortet und nicht nur diskutiert werden können.
VoiceOfUnreason

Antworten:

9

ADM ist ein gutes Muster für eine Lösung verteilter Dienste wie Microservices. Es passt zu vielen der heutigen webbasierten Geschäftsfälle.

Überlegen Sie, ob wir ein Order Domain-Objekt haben. Mit einem OOP-Ansatz würden wir Order.Purchase () Order.Cancel () usw. hinzufügen. Dies würde gut in einer Desktop-App funktionieren, in der wir Bestellungen im Speicher halten und mehrere Dinge mit derselben Instanz ausführen.

Aber wenn wir ein verteiltes System mit Programmen haben, die nur zu einer Sache gehören, dh auf eine Liste von Bestellungen zugreifen und jede nacheinander kaufen, oder eine Liste von Bestellungen abrufen und jede nacheinander stornieren, dann macht es nein, wenn beide Methoden auf demselben Objekt liegen Sinn. Wir müssten zwei Domänen oder begrenzte Kontexte haben:

PurchaseSystemOrder.Purchase()

und

CancelSystemOrder.Cancel();

Das einzige, was diese Objekte gemeinsam haben würden, wäre die Datenstruktur der Eigenschaften.

Wenn Sie mehr und mehr Microservices hinzufügen, erhalten Sie Dutzende von Auftragstypen. Es ist nicht mehr sinnvoll, von einer Bestellung als Domänenobjekt zu sprechen , obwohl es sich um dieselbe konzeptionelle Reihenfolge handelt, die von all diesen Systemen verarbeitet wird.

Es ist weitaus sinnvoller, ein anämisches Modell, Order, zu haben, das nur die Daten kapselt und Ihre Dienste entsprechend umbenennt:

PurchaseService.Purchase(Order order)

Jetzt können wir wieder über die Bestellung sprechen und alle neuen Services hinzufügen, die wir uns für die Verarbeitung vorstellen, ohne die anderen derzeit bereitgestellten Services zu beeinträchtigen.

Fowler und Co haben einen monolithischen Systemhintergrund. In ihrer Welt würde ein ADM-Ansatz bedeuten, dass eine einzige App mit all diesen separaten Diensten im Speicher instanziiert wird und das OrderDTO weitergegeben und mutiert wird. Dies wäre weitaus schlimmer, als die Methoden auf ein reichhaltiges Ordnungsmodell zu übertragen.

In einem verteilten System gibt es jedoch viele Programme, für die jeweils nur eine Bestellmethode erforderlich ist und die bei mehreren Aufträgen ausgeführt wird. Dabei wird jeder geladen, die Methode ausgeführt und anschließend verworfen. Es ist nur ein einziger Dienst und ein Datenstrom erforderlich.

Es ist sinnlos, ein umfangreiches Modell vollständig zu füllen und sich über die Anforderungen und Abhängigkeiten aller Methoden Gedanken zu machen, um nur ein einziges aufzurufen und das Objekt dann fast sofort zu verwerfen.

Außerdem würde eine Änderung an einer einzelnen der Methoden die Aktualisierung aller verteilten Komponenten erfordern, da deren Logik alle vom Rich-Modell abhängt.

Ich habe in meinen Codebasen keinen Platz für Dinge, die sie nicht benötigen

Ewan
quelle
4
Ich habe abgelehnt, weil ich denke, dass DDD gerade aufgrund des begrenzten Kontextkonzepts besonders gut für Microservices geeignet ist. Ich denke, das Problem mit Ihrer Antwort ist, dass Ihr Bestellkonzept und Ihre Bestellklasse für jeden Mikrodienst gleich sind, aber ich denke, dass dies weder notwendig noch genau ist.
RibaldEddie
Ich bin nicht anderer Meinung, ADM kann DDD sein, wenn Sie Ihren PurchaseService CashRegister anrufen und ihn zu einem Teil Ihrer Domain-Sprache machen
Ewan
können Sie näher darauf eingehen? Ich habe immer gedacht, dass YMMV, wenn ADM und DDD in einer SOLID J2EE- oder .NET C # MVC EF-Codebasis sind.
RibaldEddie
Was ich damit meine ist, dass die begrenzte Kontextbestellung PurchaseSystemOrder.Purchase () ziemlich identisch mit CashRegister.Purchase (Bestellbestellung) ist, es ist nur eine Namensänderung in Ihrer Domain-Sprache. Ein Rich-Domain-Modell bedeutet, dass sowohl die Kauf- als auch die Abbruchmethode für dieselbe Klasse gelten.
Ewan
1
@RibaldEddie, In Anlehnung an die Dicke des Buches "JavaScript, die guten Teile" biete ich dieses Bild als (nicht ganz ernstes) Argument gegen die Verwendung von DDD zur Implementierung von Microservices an;)
David Arno
3

SOLID und DDD sind orthogonal zueinander, was bedeutet, dass sie wirklich in verschiedene Richtungen voneinander gehen. Sie sollten nicht sagen, dass eines unter Ausschluss des anderen verwendet wird, da sie wahrscheinlich zusammen in derselben Codebasis existieren können und sollten.

Anämische Domänenmodelle werden erst dann zu einem Anti-Pattern, wenn Ihre Problemdomäne viel Verhalten aufweist und Sie über Hunderte von Dienstmethoden mit viel kopierter Logik oder Abhängigkeiten verfügen, bei denen Dienstschichtmethoden andere Dienstschichtmethoden aufrufen müssen, um etwas zu erledigen.

DDD ist aufgrund des begrenzten Kontextkonzepts ein hervorragendes Paradigma für Mikrodienste .

Hüten Sie sich vor der Versuchung, Infrastrukturcode als Teil Ihrer Domain zu sehen. Infrastrukturcode ist alles, was Sie nicht selbst geschrieben haben oder was mit einem Framework oder einer Bibliothek gekoppelt ist, die mit einem System eines Drittanbieters interagiert. Datenbankverbindungen, SMTP-Mailer, ORM-Bibliotheken, Anwendungsserver-Laufzeiten, all diese Dinge sind Infrastrukturen, und Sie sollten sie nicht in Ihre Domäne aufnehmen oder sich darauf verlassen, wenn Sie dies vermeiden können.

SOLID-Prinzipien sind eine Reihe allgemeiner OOP-Konzepte, mit denen Sie besseren OOP-Code erstellen können. Mit ihnen können Sie eine gute DDD-Codebasis schreiben.

RibaldEddie
quelle
In Bezug auf die Trennung von Infrastrukturcode von der Domäne. Bisher hatte ich JPA-Entitäten als meine Domäne mit den folgenden Anwendungsebenen betrachtet: Controller -> Service -> Repository -> Domäne (JPA-Entitäten). Was wäre die richtige (oder eine der richtigen) Möglichkeiten, es gemäß Ihrem Standpunkt zu modellieren? So etwas wie: Controller -> Rich Model -> x? Wie und wo würde ich mit Transaktionen umgehen? Und was ist mit JPA Mapping? Müssten wir unser umfangreiches Modell nicht mit getrennten JPA-Entitäten duplizieren?
Codependent
Eine JPA-Entität ist ein einfaches altes Java-Objekt. Das Mapping ist Teil der Infrastruktur, die Klasse selbst muss es jedoch nicht sein. Wenn Sie es als Teil der Infrastruktur behandeln möchten, sollten Sie es als Datenübertragungsobjekt betrachten, das in der Factory oder im Repository zum Erstellen einer Domänenentität verwendet wird.
RibaldEddie
1

Eine reichhaltige Domain ist schön, wenn sie gut gemacht wird. Ein Albtraum, wenn nicht. Eine anämische Domäne ist immer schlecht. Aber es ist eine vertraute bequeme Art von schlecht.

Wenn eine anämische Domäne alles ist, was Sie jemals wollen, haben Sie die falsche Sprache gewählt, als Sie eine Allzwecksprache gewählt haben. Sprachen der 4. Generation sind auf eine bestimmte Verwendung spezialisiert. Wenn Anämie gut genug ist, hätte ihre Verwendung Ihr Leben leichter gemacht.

Viele Frameworks dringen in den Sprachraum ein, bis Sie den Job nicht mehr als Java-Job bewerben können. Es ist ein Java / Spring-Job. Abgesehen davon, dass sie Sie von ihnen abhängig machen, verwandeln sie eine Allzwecksprache in eine Bastardform einer Sprache der 4. Generation.

Ist das eine bewährte Methode oder ein Anti-Muster? Nun, Ihr Chef kümmert sich meistens nur darum, ob Sie Leute einstellen können, die an der Codebasis arbeiten. Wenn wir also so tun müssen, als würden wir eine Allzwecksprache verwenden, um Leute einzustellen, werden wir es tun.

Wenn du damit einverstanden bist, ist das in Ordnung. Sie sind sicherlich nicht der einzige.

Aber sag mir nicht, dass es so sein muss. Sag mir nicht, dass es mehr für mich tut als es ist. Ich weiß, wie ich ohne leben kann. Ich weiß, wie man es herausdrückt, so dass nur wenige Dinge davon abhängen. Wenn du mich bittest, nachzugeben und alles übernehmen zu lassen, nur weil es zu schwer ist, dagegen anzukämpfen, dann denke ich, dass das schlecht ist.

Ich habe keinen Platz in meiner Codebasis für Dinge, die ich nicht brauche.

Was SOLID und die anderen Designprinzipien betrifft, kann ich diesen auch in einem anämischen Bereich weitgehend folgen. Wenn Sie ihnen nicht folgen, entsteht ein anderes Problem.

candied_orange
quelle
Ich freue mich über Ihre Antwort und stimme absolut zu, dass einige Frameworks wie Spring oder JPA-Hibernate die Java-Landschaft erobert haben. Es ist jedoch auch nicht zu leugnen, dass sie eine Reihe von bewährten Methoden und Vereinfachungen bereitgestellt haben, die Java (JEE) überhaupt nicht oder falsch angesprochen hat. Ich bin wirklich begeistert von DDD und möchte alle Prinzipien verstehen, die sie erzählen Was sind die besten Plattformen / Sprachen / Frameworks für die Arbeit mit reinen DDD-Apps (mit Rich Domain-Modellen)? Gibt es ein gutes Github-Beispiel, das Sie kennen? Wie Sie sagen, ich möchte die Dinge gut machen und mich nicht an schlechte Praktiken halten.
Codependent
Wir geben hier keine Ressourcenempfehlungen ab. Aber ich glaube, eine richtige Infrastrukturschicht, die sich mit Frameworks befasst, bedeutet, dass Sie jede Art verwenden können, die Sie möchten. Behandle sie einfach wie eine Bibliothek. Halten Sie das Wissen über sie außerhalb der Domäne. Verlassen Sie sich auch nicht auf Magie. Widerstehen Sie dem Drang, Dinge zu verwenden, die Sie selbst nicht herstellen konnten. Denn eines Tages müssen Sie möglicherweise.
candied_orange
Zurück zum ursprünglichen Punkt. Was ist mit SOLID-Prinzipien? Rich-Domain-Modelle übernehmen viele Verantwortlichkeiten, Persistenz (JPA), Geschäftslogik (die sich mit Transaktionsfähigkeit befassen muss) usw. Anämische Modelle kümmern sich dagegen nur um die Persistenz mit getrennten Diensten, die sich mit Geschäftslogik befassen. Klingt auch einfacher zu testen. Was ist dann so falsch daran?
Codependent
Die Hauptsache ist, dass Sie anfangen, Entwurfsentscheidungen basierend auf den Systemanforderungen und nicht auf semantischen Anforderungen zu treffen. Es ist subtil, leicht zu ignorieren, die Kosten sind nicht offensichtlich und schwer zu rechtfertigen. Kurz gesagt, es ist wie zu argumentieren, dass Stromleitungen eher vergraben werden sollten als bei Umfragen. Sobald sich die Leute an die günstige Alternative gewöhnt haben, wird sich dies wahrscheinlich nicht ändern. Selbst wenn Hurrikane die Stromversorgung ausschalten.
candied_orange
1
Ich wollte Ihnen den Vorteil des Zweifels über Ihre Behauptung geben, dass "eine reiche Domain schön ist, wenn sie gut gemacht wird. Ein Albtraum, wenn nicht." Vielleicht habe ich es einfach noch nie gut gesehen, aber dann behaupten Sie unsinnig: "Eine anämische Domäne ist immer schlecht." Meinungsloser Unsinn macht Ihre Antwort wertlos. -1
David Arno