Ich arbeite an einem Projekt, in dem wir versuchen, sowohl domänenbasiertes Design als auch REST auf eine serviceorientierte Architektur anzuwenden. Wir sorgen uns nicht um 100% REST-Konformität. Es ist wahrscheinlich besser zu sagen, dass wir versuchen, ressourcenorientierte HTTP-APIs zu erstellen ( Stufe 2 von Richardsons REST-Reifegradmodell). Wir versuchen jedoch, die Verwendung von HTTP-Anforderungen im RPC-Stil zu vermeiden , dh wir versuchen, unsere HTTP-Verben gemäß RFC2616 zu implementieren, anstatt POST
dies IsPostalAddressValid(...)
beispielsweise zu tun .
Eine Betonung hierauf scheint jedoch auf Kosten unseres Versuchs zu gehen, ein domänengetriebenes Design anzuwenden. Mit nur GET
, POST
, PUT
, DELETE
und ein paar anderen selten verwendeten Methoden, neigen wir cruddy Dienste zu bauen, und cruddy Dienste sind in der Regel anämische Domänenmodelle haben.
POST
: Empfangen Sie die Daten, validieren Sie sie, speichern Sie sie in den Daten. GET
: Daten abrufen, zurückgeben. Keine wirkliche Geschäftslogik da. Wir verwenden auch Nachrichten (Ereignisse) zwischen den Diensten, und es scheint mir, dass der größte Teil der Geschäftslogik darauf aufbaut.
Sind REST und DDD auf einem gewissen Niveau angespannt? (Oder verstehe ich hier etwas falsch? Tun wir vielleicht etwas anderes falsch?) Ist es möglich, ein starkes Domänenmodell in einer serviceorientierten Architektur zu erstellen, während HTTP-Aufrufe im RPC-Stil vermieden werden?
IsPostalAddressValid(...)
Zweck zum Thema "Bereitstellen eines Datenblocks, z. B. des Ergebnisses der Übermittlung eines Formulars, für einen Datenverarbeitungsprozess" passen würde?Antworten:
Martin Fowlers erstes Gesetz über verteilte Systeme: "Verteilen Sie Ihre Objekte nicht!" Remote-Schnittstellen sollten grobkörnig und interne Schnittstellen feinkörnig sein. Häufig gilt das Rich Domain-Modell nur in einem begrenzten Kontext .
Die REST-API trennt zwei verschiedene Kontexte, die jeweils eigene interne Modelle haben. Die Kontexte kommunizieren über eine grobkörnige Schnittstelle (REST-API) unter Verwendung von "anämischen" Objekten (DTO).
In Ihrem Fall klingt es so, als würden Sie versuchen, einen Kontext über eine Grenze zu verteilen, die eine REST-API ist. Dies kann zu einer feinkörnigen Remote-Schnittstelle oder einem anämischen Modell führen. Abhängig von Ihrem Projekt kann es ein Problem sein oder auch nicht.
quelle
POST wurde absichtlich so konzipiert, dass es "absichtlich vage" ist. Das Ergebnis eines POST ist implementierungsspezifisch. Was hindert Sie daran, das zu tun, was Twitter und andere API-Designer tun, und jede POST-Methode im Nicht-CRUD-Teil Ihrer API gemäß Ihren spezifischen Anforderungen zu definieren? POST ist das Sammelverb. Verwenden Sie es, wenn keines der anderen Verben gut zu der Operation passt, die Sie ausführen möchten.
Anders ausgedrückt, Ihre Frage könnte genauso lauten: "Fördern 'intelligente' Objekte das Design im RPC-Stil?" Selbst Martin Fowler (der den Begriff "anämisches Domänenmodell" geprägt hat) räumt ein, dass reine DTOs einige Vorteile haben:
In Bezug auf das Richardson-Reifegradmodell können Sie Level 3 erreichen, ohne sich jemals um "Anämische Domänenmodelle" zu kümmern. Denken Sie daran, dass Sie das Verhalten niemals an den Browser übertragen werden (es sei denn, Sie planen, Javascript durch Ihre Modelle zu injizieren).
Bei REST geht es hauptsächlich um Maschinenunabhängigkeit. Implementieren Sie das REST-Modell in dem Maße, in dem Ihre Endpunkte Ressourcen darstellen sollen, und damit die Benutzer Ihrer API auf diese Ressourcen auf einfache Weise zugreifen und sie auf standardmäßige Weise verwalten können. Wenn das anämisch erscheint, dann soll es so sein.
Siehe auch
Ich brauche mehr Verben
quelle
Die REST-API ist nur eine Art von Präsentationsebene. Es hat nichts mit dem Domain-Modell zu tun.
Die Frage, die Sie gestellt haben, stammt aus Ihrer Verwirrung darüber, dass Sie sich irgendwie aneinander anpassen müssen. Das tust du nicht.
Sie ordnen Ihr Domain-Modell Ihrer REST-API so zu, wie Sie Ihr Domain-Modell einem RDBMS über ein ORM zuordnen - es muss diese Zuordnungsebene geben.
Domäne ← ORM → RDBMS-
Domäne ← REST-Zuordnung → REST-API
quelle
Ich glaube nicht, dass sie dazu neigen, anämische Domänenmodelle (ADMs) zu fördern, aber sie erfordern, dass Sie sich etwas Zeit nehmen und die Dinge durchdenken.
Zunächst einmal denke ich, dass das Hauptmerkmal von ADMs ist, dass sie wenig bis gar kein Verhalten aufweisen. Das soll nicht heißen, dass das System kein Verhalten aufweist, nur, dass es sich normalerweise um eine Art Service-Klasse handelt (siehe http://vimeo.com/43598193 ).
Und wenn das Verhalten im ADM nicht vorhanden ist, was dann? Die Antwort sind natürlich die Daten. Und wie ordnet diese REST-API zu? Nun, vermutlich sind die Daten dem Inhalt der Ressource und das Verhalten den HTTP-Verben zugeordnet.
Damit Sie über alles verfügen, was Sie zum Erstellen eines umfangreichen Domänenmodells benötigen, müssen Sie nur in der Lage sein, die Zuordnung der HTTP-Verben zu den Domänenvorgängen für die Daten zu überprüfen und diese Vorgänge dann denselben Klassen zuzuordnen, in denen Ihre Daten enthalten sind.
Ich denke, dass die Leute Probleme bekommen, wenn sie Schwierigkeiten haben zu sehen, wie die HTTP-Verben ihrem Domain-Verhalten entsprechen, wenn das Verhalten jenseits von einfachem CRUD liegt, dh wenn es Nebenwirkungen in anderen Teilen der Domain jenseits von gibt Ressource, die von der HTTP-Anforderung geändert wird. Eine Möglichkeit, dieses Problem zu lösen, sind Domain-Ereignisse ( http://www.udidahan.com/2009/06/14/domain-events-salvation/ ).
quelle
Dieser Artikel ist ziemlich themenbezogen und ich glaube, er beantwortet Ihre Frage.
Ein Kernkonzept, von dem ich denke, dass es Ihre Frage sehr gut beantwortet, ist im folgenden Absatz des erwähnten Artikels zusammengefasst:
"Es ist sehr wichtig, zwischen Ressourcen in der REST-API und Domänenentitäten in einem domänengetriebenen Design zu unterscheiden. Das domänengetriebene Design bezieht sich auf die Implementierung (einschließlich der API-Implementierung), während Ressourcen in der REST-API das API-Design und den Vertrag bestimmen. API-Ressource Die Auswahl sollte nicht von den zugrunde liegenden Details der Domänenimplementierung abhängen. "
quelle
Einige recht erfolgreiche Implementierungen, die ich gesehen / gebaut habe, beantworten die Frage, wie sie die Verb + Nomen-Metapher mit grobkörnigen, geschäftsfreundlichen Methoden mischen, die auf die Entitäten einwirken.
Legen Sie also anstelle der (zum Scheitern verurteilten)
getName()
Methode / des (zum Scheitern verurteilten) Dienstes Folgendes offengetPerson()
: Übergeben Sie einen Bezeichner vom Typ / ID, und geben Sie die gesamtePerson
Entität zurück.Da das Verhalten der Entität Person in einem solchen Kontext nicht angemessen vermittelt werden kann (und möglicherweise auch nicht in einem datenzentrierten Kontext sein sollte), ist es durchaus sinnvoll, ein Datenmodell (versus Objekt) für die Anforderungs- / Antwortpaare von zu definieren Die Dienste.
Die Dienste und definierten Verben selbst fügen einige domänenzulässige Verhaltensweisen, Steuerelemente und sogar Zustandsübergangsregeln für die Entitäten hinzu. Zum Beispiel würde es eine domänenspezifische Logik geben, was beim
transferPerson()
Serviceaufruf passiert , aber die Schnittstelle selbst würde nur die Ein- / Ausgabe-Entitäten / Daten definieren, ohne IHR internes Verhalten zu definieren.Ich würde Autoren widersprechen, die sagen würden, dass beispielsweise eine Implementierung eines Übertragungsverbs zur Klasse Person gehört oder mit einem personenbezogenen Dienst verknüpft ist. In der Tat wäre die Methode der Übertragung für a
Person
und Optionen davon (in diesem einfachen Beispiel) besser durch a definiertCarrier
, wobei diePerson
möglicherweise nicht einmal wissen, welche Übertragungsmethoden verfügbar sind oder wie die Übertragung überhaupt stattfindet (wer weiß, wie Düsentriebwerke funktionieren) sowieso).Macht das die
Person
Entität anämisch? Ich glaube nichtEs kann / sollte eine Logik zu personenbezogenen Dingen geben, die personenintern sind, wie z. B. ihr Gesundheitszustand, die nicht von einer externen Klasse definiert werden sollte.
Abhängig von den Anwendungsfällen ist es jedoch durchaus akzeptabel, dass eine Entitätsklasse in bestimmten Systemen kein wichtiges / relevantes Verhalten aufweist, z. B. bei einem Sitzzuweisungsservice in einem Transportsystem. Ein solches System kann durchaus REST-basierte Dienste implementieren, die sich mit Personeninstanzen und zugeordneten Kennungen befassen, deren internes Verhalten jedoch niemals definieren / implementieren.
quelle
Ist Ihr Problem, dass Sie versuchen, Ihr Modell in die grundlegenden Verben zu packen, indem Sie POST so oft wie möglich verwenden?
Es ist nicht notwendig - ich weiß, dass REST für die meisten Leute POST, GET, PUT und DELETE bedeutet, aber der http rfc sagt:
Und Systeme wie SMTP verwenden den gleichen Stil verbbasierter Methoden, jedoch mit einem völlig anderen Satz.
Es gibt also keinen Grund, warum Sie diese verwenden müssen, Sie können jeden Satz von Verben verwenden, den Sie mögen (obwohl Sie wirklich feststellen werden, dass Sie mit ein wenig Nachdenken alles tun können, was Sie in den Basic 4 brauchen). Was REST von den anderen Mechanismen unterscheidet, ist seine zustandslose und konsistente Art, diese Verben zu implementieren. Sie sollten nicht versuchen, ein Nachrichtenübermittlungssystem zwischen den Ebenen zu implementieren, da Sie dann im Grunde kein REST ausführen. Stattdessen führen Sie einen Nachrichtenübermittlungs-, RPC- oder Nachrichtenwarteschlangenmechanismus aus, durch den Sie zweifellos die Vorteile von REST (d. H Einfachheit, die es wirklich gut über eine http-Verbindung funktioniert).
Wenn Sie ein komplexes Messaging-Protokoll mit allen Funktionen möchten, erstellen Sie dieses (wenn Sie dies über das Web tun können, gibt es einen Grund, warum REST so beliebt ist), aber versuchen Sie ansonsten, sich an das Architekturdesign von REST zu halten.
quelle