Gemeinsame Nutzung von DTO-Objekten zwischen Microservices

15

TL; DR - Ist es in Ordnung, eine POJO-Bibliothek zwischen Diensten zu teilen?

Im Allgemeinen möchten wir die gemeinsame Nutzung zwischen Diensten nach Möglichkeit strikt auf keine beschränken. Es gab einige Debatten darüber, ob der Dienst, der Daten gemeinsam nutzt, eine Client-Bibliothek für Clients bereitstellen sollte. Die client-lib ist im Allgemeinen für einen Client des Dienstes optional und kann die API nach Belieben verwenden, unabhängig davon, ob die client-lib verwendet werden soll oder eine alternative Sprache und die allgemeinen Aspekte der Bibliothek und dergleichen.

In meinem Fall - Ich betrachte einen Dienst, der ein Objekt von Daten erstellt. Nehmen wir an, dieses Objekt ist ein PET. Es ist NICHT die Datenbankentität, sondern ausschließlich ein POJO, das implizit die zugrunde liegenden Daten darstellt. Dieses POJO ist das, was die API definiert hat. Angenommen: Haustier - Alter, Gewicht, Name, Besitzer, Adresse, Art usw.

Service 1 - PetKeeper: Es wird aus irgendeinem Grund ein Haustier generiert und alle Daten gespeichert. Es muss auf diesen Service verweisen, um das Haustier zu erhalten, oder Änderungen am Haustier vornehmen, z API-Aufruf an diesen Service.

Service 2 - PetAccessor: Dieser Service sammelt die Haustiere und führt Validierungsprüfungen durch

Service 3,4 - Weitere Zwischenrufe

Service 5 - Benutzeroberfläche

Diese sind sehr willkürlich, aber der Punkt ist einfach. Die Benutzeroberfläche oder ein benutzerbezogener Dienst möchte dieses "PET" -Objekt auf irgendeine Weise präsentieren. Sie muss über eine API einen Dienst aufrufen, der einen Dienst aufruft, der einen Dienst aufruft usw., bis sie den Dienst erreicht, der die erforderlichen Informationen sammelt, und die Weiterleitung beginnt. Schließlich muss der UI-Service das PET-Objekt anzeigen.

Dies ist ziemlich verbreitet - aber mit unserer absoluten Mentalität haben wir das PET-Objekt in jedem Service dupliziert. Das DRY-Prinzip (wiederholen Sie sich nicht) gilt nur für Code INSIDE eines Dienstes und gilt nicht für alle Dienste, aber der Punkt ist immer noch da. Was ist, wenn wir ein Feld hinzufügen ... müssen wir jeweils 5 Dienste des POJO ändern.

- ODER - Wir können eine Pet-Objects-Bibliothek bereitstellen, die einige der Pojos aus der API enthält, und jeder Dienst kann importieren / von der Bibliothek abhängig sein. Es besteht keine Abhängigkeit von den Diensten selbst, sondern nur von der allgemeinen Bibliothek. Ich mag diese Idee, damit jeder Dienst den gleichen Objekttyp hat und Updates einfacher sind. Aber ich mache mir Sorgen um Gott-Objekte.

Was sind die Vor- / Nachteile - was ist das beste Design? Was haben Sie getan, um Daten zwischen Diensten zu übertragen, um die Wiederholung der gleichen POJO-Klassen zu minimieren und gleichzeitig die Kopplung zu vermeiden?

Aerith
quelle
@DaiKaixian: Sicherlich schlagen Sie nicht vor , dass die OP mit einem Gott-Objekt einhergeht , oder? Das wird routinemäßig als Anti-Pattern angesehen.
Makoto
Ich stimme der Antwort von @javaguy zu.
Und ich möchte auch sagen, dass Sie das Besuchermuster berücksichtigen können. de.wikipedia.org/wiki/Besuchermuster . Machen Sie das gesamte Feld und den Setter / Getter in einem POJO und teilen Sie es zwischen Microservices. Wenn Sie eine Operation am POJO in einem anderen Microservice ausführen möchten, schreiben Sie eine VisitorClass.
Vielen Dank. Ich zögere, diese "gemeinsame Bibliothek" zu haben, weil sie wachsen wird. Und es wird Objekte geben, die nur die Dienste 1 und 3 betreffen, oder 2 und 4 oder alle oder eine beliebige Kombination davon. Eine Art allgemeines DTO-Bibliothekspaket, das alle DTOs enthält, unabhängig davon, ob ich ein Besuchermuster oder ein einfaches DTO-POJO verwende oder was nicht. Ist es akzeptabel, alle diese Objekte einzuschließen, aber zu versuchen, sie so gut wie möglich zu pflegen? Zumindest die Objekte werden jedem zur Verfügung gestellt, der sie benötigt, WENN er sie verwenden möchte ...

Antworten:

5

Was ist das beste Design?

Sie können dasselbe Pet DTO- Objekt unter den Back-End- Services wiederverwenden (die die typische Geschäftslogik verarbeiten). In Bezug auf die Präsentationsebene (Benutzeroberfläche) empfiehlt es sich jedoch im Allgemeinen, ein FormBean (ein anderes Bean mit hinzugefügten Feldern) zu verwenden für Präsentationslogik), so dass eine klare Trennung zwischen Präsentationslogik und Geschäftslogik besteht .

Dies ist erforderlich, da Services wiederverwendbar sein sollten und ein einzelner Service von mehreren / verschiedenen Endpunkten (wie dem Frontend oder einem anderen Webservice usw.) verfügbar gemacht / wiederverwendet werden kann . Für jeden dieser Endpunkte sind möglicherweise zusätzliche Felder erforderlich, die von ausgefüllt werden die entsprechenden Controller oder Layer (wie Adapter) über den Diensten.

Was haben Sie getan, um Daten zwischen Diensten zu übertragen, um die Wiederholung der gleichen POJO-Klassen zu minimieren und gleichzeitig die Verbindung zu trennen?

Wenn Sie eine einzelne Bean zwischen Business- und Web-Tiers verwenden, koppeln Sie die Präsentationslogik eng mit der Business-Logik, was keine gute Praxis ist, und Sie werden die Services für eine Anforderung im Frontend ändern (z. B. ein anderes Datumsformat) in der Benutzeroberfläche angezeigt werden). Um diesen Prozess des Auffüllens / Kopierens der Daten über die Beans hinweg (wie DTO nach FormBean oder Viceversa) durchzuführen, können Sie Bibliotheken wie Apache BeanUtils.copyProperties() oder Dozer verwenden , um den Code des Boilerplates zu vermeiden .

Entwickler
quelle
Ich bin damit einverstanden, dass die Präsentationsebene die eingehende Nutzlast nach Bedarf als Präsentations-Bean mit verschiedenen Attributen deserialisieren sollte. Aber im Allgemeinen ist es in Ordnung, dieselben DTO-Objekte in allen Backend-Diensten wiederzuverwenden? Wir würden im Allgemeinen versuchen, diese DTO-Pakete für nur die wenigen Dienste, die sie benötigen, in kleinere Pakete aufzuteilen. Ich bin es leid, einen Junk-Drawer eines DTO-Bibliothekspakets zu haben, der DTOs für mehr als 75 Microservices enthält, von denen alle Dienste abhängen. Es sei denn, das ist in Ordnung, da nur DTO-Objekte optional sind.
Ja, Sie können dasselbe DTO-Objekt natürlich für alle Backend-Services der gleichen Art wie für Ihre wiederverwenden PetServices, um Doppelungen zu vermeiden. Aber es geht mir nicht darum, Backend und Frontend eng zu koppeln, das war's.
Entwickler
4

Wenn der DTO in allen Mikrodiensten dieselbe Geschäftseinheit darstellt, sollte es nur eine Klasse geben, die von den Diensten gemeinsam genutzt wird. Es ist (fast) nie richtig, doppelten Code für dasselbe Objekt zu haben.

Jim Garrison
quelle
3
Das Teilen von DTOs über Microservices hinweg ist ein Albtraum. "Hat diese Version schon dieses Feld? Hm vielleicht?" Sie werden nach einer Weile mit einem echten Durcheinander enden. Duplizierter Code ist in diesem Fall gut.
Mejmo
1

Die Art und Weise, wie ich es jetzt vorhabe, ist, dass jeder Dienst nur DTOs paket und sie als jar lib in Nexus ablegt. Wenn andere Dienste diese benötigen, werden die DTO-Bibliotheken als Abhängigkeit in manve / gradle abgerufen. Wenn eine neue DTO-Version für einen Dienst veröffentlicht wird, ist dies in Ordnung, solange gleichzeitig auch die alte Version unterstützt wird. Brechen Sie also nicht die Abwärtskompatibilität, Versionierung usw. auf. Um eine Abhängigkeit von der Umgebung zu vermeiden, sollten Sie den Service besser von der dto-Verpackung trennen

Schauen Sie sich jetzt das Backend-to-Frontend an und umgekehrt. Ich bin mit früheren Kommentaren nicht einverstanden, dass sich die Benutzeroberfläche als Präsentationsebene unterscheidet. ES IST NICHT!!! UI ist für mich nur ein weiterer Microservice, der auch Events konsumiert und produziert.

Backend-to-Frontend-Richtung Ich konvertiere POJO (dtos) in Typescript-Interfaces und packe sie in NPM und lade sie auch in Nexus. Das auf dem UI-Knoten basierende Projekt verwendet diese dann. Dies ist ein Service für die Benutzeroberfläche.

Frontend-to-Backend-Richtung Für UI-to-Service-Layer-Ereignisse konvertiere ich Typescript-Interfaces und konvertiere sie in POJOs (dtos), packe sie als JAR und lade sie in Form von JAR auf Nexus (oder ein Repo) hoch, damit sie von Backend-Diensten verwendet werden können.

Diese Prozesse können leicht von CI-Prozessen (Travis, Gitlab CI usw.) gehandhabt werden.

Alle Kommentare zu diesem Ansatz sind willkommen.

Kensai
quelle