Fördert "Inversion of Control" das "anämische Domänenmodell"?

32

Als ich IoC Container in meinem letzten Projekt verwendet habe, bin ich zu anämischen Entitäten und dem größten Teil meiner Geschäftslogik in Stateless Services gekommen.

Ich habe Projekte von anderen Entwicklern gesehen, die "Inversion of Control" verwenden und die immer "anämisch" sind.

Ist es möglich, IoC und Rich Domain zu verwenden, da das "anämische Domänenmodell" ein Antimuster ist? Gibt es dafür gute Beispiele, Open-Source-Projekte?

Mag20
quelle
Ich denke, wir brauchen einige konkrete Beispiele für Ihren speziellen Fall, um zu helfen.
Martijn Verburg
1
Sorry, ich meinte Code-Schnipsel :)
Martijn Verburg

Antworten:

11

Für den Anfang: DI und IoC sind keine Synonyme. Es tut mir leid, aber ich muss darauf hinweisen (es scheint mir, dass Sie denken, dass sie sind).

Wie für Ihre Anfrage ... Nun, Dependency Injection ist nur ein Werkzeug. Wie Sie dieses Tool verwenden, ist eine völlig andere Sache. Es gibt auch andere Tools (Entwurfsmuster), die das Problem beheben können. Ich bin zum Beispiel der Meinung, dass eine breite Akzeptanz des MVC-Musters einer der Schlüssel zur Bildung des Antimusters des anämischen Domänenmodells ist: Controller (in einfacheren Anwendungen, in komplizierteren Anwendungen, die eine zusätzliche Service-Schicht darstellen würden) übernehmen die Verantwortung für die Validierung von Geschäftsregeln Dies erzwingt sie ebenso wie die Umwandlung von DB-Entitäten in nützliche Funktionen, während Business Layer zu einer einfachen Datenzugriffsschicht wird, die einfaches ORM mit einer Eins-zu-Eins-Zuordnung zu Datenbankentitäten ist.

Natürlich gestalten Sie Ihre Anwendung so, dass Sie nach Belieben ein korrektes Domänenmodell erstellen können, und all diese IoCs, DIs und MVCs halten Sie nicht auf. Was dich aufhalten könnte, ist dein Team. Sie müssen sie irgendwie davon überzeugen, den richtigen Weg einzuschlagen, und es kann schwierig sein, da viele Softwareentwickler keinen starken architektonischen Hintergrund haben.

Paweł Dyda
quelle
Ich füge hinzu, dass Sie vielleicht einen Blick auf den DDD-Ansatz werfen könnten, für den Eric Evans et al.
Martijn Verburg
1
Ich habe Eric Evans 'Buch gelesen. Es ist gut für die allgemeine Methodik und die allgegenwärtige Sprache, aber es fehlt etwas an Beispielen aus der Praxis.
Mag20
Vielen Dank, dass Sie auf den Unterschied zwischen DI und IoC hingewiesen haben. Ich denke, das Problem hatte mehr mit IoC als mit DI zu tun. Die Frage wurde geändert, um dies widerzuspiegeln.
Mag20
Nach meiner Erfahrung mit DI - Frameworks / Container (Frühjahr DI, CDI, Unity), in der Tat sie tun Sie stoppen , um ein „richtige Domain Model“ von der Erstellung, die mir , dass die Entwickler bedeutet nicht verwenden , wahr (dh Stateful) Objekte eingeschränkt werden . Aber DI unterstützt das nicht wirklich.
Rogério
8

Bei den meisten (wenn nicht allen) Anwendungen handelt es sich um eine Mischung aus Infrastruktur- und Domänenproblemen. Wenn Sie ein bestimmtes Maß an Komplexität erreichen, können Sie die Verwaltung vereinfachen, wenn die Domäne von der Infrastruktur getrennt ist, sodass Sie leichter überlegen und sich unabhängig voneinander entwickeln können.

Natürlich muss das Domänenmodell immer noch mit dem Rest des Systems kommunizieren, und dies wird normalerweise bei zustandslosen Diensten (die Teil der Domäne sind) der Fall sein, bei denen Infrastrukturprobleme (z. B. Datenbankzugriff) auftreten. Die Verwendung eines IoC-Containers entfernt diese Abhängigkeit nicht, sondern verschiebt seine Konfiguration in einen separaten Bereich.

Die Entitäten speichern den Status und sollten für die Geschäftsregeln verantwortlich sein. Wenn Ihre Dienste alle Invarianten und andere Geschäftsregeln durchsetzen, ist es wahrscheinlich, dass sich die Logik am falschen Ort befindet.

Wenn Sie die Logik an den richtigen Stellen haben und dennoch Services erhalten, die nichts anderes sind als Wrapper für Infrastruktur-Dinge und -Entitäten, die nur Eigentum sind, ist es sehr wahrscheinlich, dass die Domäne nicht komplex genug ist, um dies zu rechtfertigen der Overhead eines eigenen Modells. Fast alles, was Sie über DDD lesen, enthält einen Haftungsausschluss, der eigentlich nur für komplexe Domänen gedacht ist, der jedoch allzu oft vergessen zu werden scheint.

FinnNk
quelle
7

Gehe zur Quelle. Beginnen Sie mit Fowlers Beitrag über anämische Domänenmodelle . Er verweist auf Eric Evans Domain Driven Design als ein Beispiel für eine gute Praxis. Der Quellcode dafür ist hier . Lade es herunter.

Beachten Sie, dass Inversion of Control verwendet wird (Suche nach @Autowired), Serviceklassen (BookingService) und "Business Process" -Klassen (z. B. ItAdvisorUpdater) vorhanden sind.

Fowlers Originalartikel beginnt den Weg zu dem Beispiel, das Sie suchen.

jamie
quelle
Diese Beispiel-App stimmt in der Tat nicht mit DDD überein, wie im Buch beschrieben. Ein spezifischer Widerspruch zum Buch ist, dass es das Konzept der "Infrastruktur" völlig verletzt, indem es ihm erlaubt, domänenspezifischen Code zu enthalten. Beispielsweise VoyageRepositoryHibernatehängt die Klasse, die in die Infrastrukturebene eingefügt wurde, tatsächlich jedoch von der Domänenebene ab.
Rogério
Ja, das Buch sagt auf Seite 73, dass sich die Infrastrukturschicht "unterhalb" der Domänenschicht befindet und "keine besonderen Kenntnisse über die Domäne haben sollte, für die sie zuständig ist". Das ergab für mich einfach keinen Sinn. Stellen Sie sich ein Projekt mit zwei VoyageRepository-Implementierungen vor: VoyageRepositoryHibernate und eine VoyageRepositoryJDBC-Klasse. Ihre Implementierungen sind notwendigerweise sehr unterschiedlich und technologiebezogen. Gehören diese in die Domain-Schicht? Oder die Infrastrukturschicht? In unserem Code machen wir es laut Buch rückwärts: Die Infrastrukturebene kann auf die Domänenebene verweisen, aber nicht umgekehrt.
Jamie
Sie gehören in die Domänenschicht, ja. Die JDBC-basierte Implementierung würde SQL-Code enthalten, der an domänenspezifische Tabellen und Spalten in der Anwendungsdatenbank gebunden ist. Das Einfügen von domänen- oder anwendungsspezifischem Code in die Infrastrukturschicht ist einfach falsch, da "Infrastrukturcode" nur zur Lösung technischer Probleme verwendet werden sollte und (idealerweise) zwischen verschiedenen Anwendungen und Domänen vollständig wiederverwendbar sein sollte. Die Lösung für "Low-Level" -Code (z. B. SQL) in der Domänenschicht besteht darin, ihn nicht vollständig zu verschieben, sondern auf einer besseren Infrastruktur wie ORM zu implementieren.
Rogério
Die Implementierung von save (MyDomainObject foo) ist für mich ein rein technisches Anliegen. YMMV.
Jamie
Nur wenn Sie nicht gegen die Grundregel einer Schichtarchitektur verstoßen: Eine niedrigere Schicht kann nicht von einer höheren Schicht abhängen. Wenn Sie also save(foo)Code implementieren , der sich ändern kann, wenn sich das Domänenmodell ändert (wenn beispielsweise ein neues Attribut hinzugefügt wird MyDomainObject), muss er (per Definition) zur Domänenschicht gehören. Ansonsten kann man einfach nicht mehr über "Ebenen" sprechen.
Rogério
7

ist es möglich, IoC und Rich Domain zu verwenden? Gibt es dafür gute Beispiele, Open-Source-Projekte?

Ich nehme an, Sie meinen DI anstelle von IoC, und das Projekt, an dem Sie gearbeitet haben, verwendet einen DI-Container wie Spring. IoC hat zwei Hauptvarianten: DI und Locator-Muster. Ich verstehe nicht, warum das Locator-Muster ein Problem sein sollte, also konzentrieren wir uns auf DI.

Ich denke nicht, dass es möglich ist oder zumindest sehr unpraktisch wäre. Der Hauptaspekt von DI-Containern besteht darin, dass sie die Erstellung von Objekten steuern, wenn sie in andere Objekte ("verwaltete Objekte") eingefügt werden. Die Gruppe verwalteter Objekte, die bei Ausführung des Projekts aktiv ist, ist unabhängig davon, welche Domänenelemente in Ihrem Projekt vorhanden sind, hängt jedoch davon ab, wie Objekte verkabelt sind und welche Bereiche (Singleton, Prototyp) ihnen zugewiesen sind.

Aus diesem Grund möchten Sie nicht, dass der DI-Container Ihre Domänenobjekte verwaltet. Wenn Sie Objekte jedoch manuell erstellen (mit new), können Sie keine anderen Objekte in Ihre Domänenobjekte einfügen. (Potenzielle Umgehungsmöglichkeiten mit manueller Verkabelung bleiben hiervon unberührt.) Da Sie diese Injektionen benötigen, um Implementierungen durch andere zu ersetzen, können Sie die Funktionalität von Rich-Domain-Objekten mit DI nicht ersetzen. Daher möchten Sie keine Funktionalität in Domänenobjekte einfügen, oder Sie würden die Funktionen der DI verlieren.

Ich verstehe nicht, wie ein hypothetischer DI-Container funktionieren könnte, der Ihre Objekte nicht verwaltet, und keine der vorhandenen Implementierungen lässt dies zu. Man kann also mit Recht behaupten, dass DI auf die Verwaltung von Objekten angewiesen ist. Sie werden daher immer versucht, potenzielle Rich Domain-Objekte in eine anämische Klasse und eine oder mehrere Transaktionsskriptklassen aufzuteilen.

Wolfgang
quelle
Diese Antwort trifft den Nagel auf den Kopf, wenn es um die Spannung zwischen einem Rich Domain Model und Dependency Injection geht.
Jrahhali