Anpassung an Veränderungen - AWS Präskriptive Leitlinien

Die vorliegende Übersetzung wurde maschinell erstellt. Im Falle eines Konflikts oder eines Widerspruchs zwischen dieser übersetzten Fassung und der englischen Fassung (einschließlich infolge von Verzögerungen bei der Übersetzung) ist die englische Fassung maßgeblich.

Anpassung an Veränderungen

Softwaresysteme neigen dazu, kompliziert zu werden. Ein Grund dafür könnten häufige Änderungen der Geschäftsanforderungen und die geringe Zeit sein, die Softwarearchitektur entsprechend anzupassen. Ein weiterer Grund könnten unzureichende Investitionen sein, um die Softwarearchitektur zu Beginn des Projekts einzurichten, um sie an häufige Änderungen anzupassen. Was auch immer der Grund sein mag, ein Softwaresystem kann so kompliziert werden, dass es fast unmöglich ist, eine Änderung vorzunehmen. Daher ist es wichtig, von Beginn des Projekts an eine wartbare Softwarearchitektur aufzubauen. Eine gute Softwarearchitektur kann sich leicht an Änderungen anpassen.

In diesem Abschnitt wird erklärt, wie wartbare Anwendungen mithilfe einer sechseckigen Architektur entworfen werden, die sich problemlos an nicht funktionale oder geschäftliche Anforderungen anpassen lässt.

Anpassung an neue nicht funktionale Anforderungen durch Verwendung von Anschlüssen und Adaptern

Als Kern der Anwendung definiert das Domänenmodell die Maßnahmen, die von außen erforderlich sind, um die Geschäftsanforderungen zu erfüllen. Diese Aktionen werden durch Abstraktionen definiert, die als Ports bezeichnet werden. Diese Anschlüsse werden durch separate Adapter implementiert. Jeder Adapter ist für eine Interaktion mit einem anderen System verantwortlich. Sie könnten beispielsweise einen Adapter für das Datenbank-Repository und einen anderen Adapter für die Interaktion mit einer Drittanbieter-API haben. Die Domäne kennt die Adapterimplementierung nicht, sodass es einfach ist, einen Adapter durch einen anderen zu ersetzen. Beispielsweise könnte die Anwendung von einer SQL-Datenbank zu einer NoSQL-Datenbank wechseln. In diesem Fall muss ein neuer Adapter entwickelt werden, um die vom Domänenmodell definierten Ports zu implementieren. Die Domäne hat keine Abhängigkeiten vom Datenbank-Repository und verwendet Abstraktionen, um zu interagieren, sodass am Domänenmodell nichts geändert werden müsste. Daher passt sich die sechseckige Architektur problemlos an nicht funktionale Anforderungen an.

Anpassung an neue Geschäftsanforderungen mithilfe von Befehlen und Befehlshandlern

In der klassischen geschichteten Architektur hängt die Domäne von der Persistenzschicht ab. Wenn Sie die Domain ändern möchten, müssten Sie auch die Persistenzschicht ändern. Im Vergleich dazu hängt die Domäne bei der hexagonalen Architektur nicht von anderen Modulen in der Software ab. Die Domäne ist der Kern der Anwendung, und alle anderen Module (Ports und Adapter) hängen vom Domänenmodell ab. Die Domain verwendet das Prinzip der Abhängigkeitsumkehrung, um über Ports mit der Außenwelt zu kommunizieren. Der Vorteil der Abhängigkeitsinversion besteht darin, dass Sie das Domänenmodell frei ändern können, ohne Angst zu haben, andere Teile des Codes zu knacken. Da das Domänenmodell das Geschäftsproblem widerspiegelt, das Sie zu lösen versuchen, ist es kein Problem, das Domänenmodell zu aktualisieren, um es an sich ändernde Geschäftsanforderungen anzupassen.

Bei der Entwicklung von Software ist die Trennung von Belangen ein wichtiger Grundsatz, den es zu beachten gilt. Um diese Trennung zu erreichen, können Sie ein leicht modifiziertes Befehlsmuster verwenden. Dies ist ein Verhaltensmuster, bei dem alle Informationen, die zum Abschließen einer Operation erforderlich sind, in einem Befehlsobjekt zusammengefasst sind. Diese Operationen werden dann von Command-Handlern verarbeitet. Befehlshandler sind Methoden, die einen Befehl empfangen, den Status der Domäne ändern und dann eine Antwort an den Aufrufer zurückgeben. Sie können verschiedene Clients verwenden, z. B. synchrone APIs oder asynchrone Warteschlangen, um Befehle auszuführen. Wir empfehlen, dass Sie Befehle und Befehlshandler für jeden Vorgang in der Domäne verwenden. Wenn Sie diesem Ansatz folgen, können Sie neue Funktionen hinzufügen, indem Sie neue Befehle und Befehlshandler einführen, ohne Ihre bestehende Geschäftslogik zu ändern. Die Verwendung eines Befehlsmusters erleichtert somit die Anpassung an neue Geschäftsanforderungen.

Entkopplung von Komponenten mithilfe der Servicefassade oder des CQRS-Musters

In der hexagonalen Architektur sind Primäradapter dafür verantwortlich, eingehende Lese- und Schreibanforderungen von Clients lose an die Domäne zu koppeln. Es gibt zwei Möglichkeiten, diese lose Kopplung zu erreichen: durch die Verwendung eines Service-Fassadenmusters oder durch die Verwendung des CQRS-Musters (Command Query Responsibility Segregation).

Das Servicefassadenmuster bietet eine nach vorne gerichtete Schnittstelle, um Kunden zu bedienen, z. B. die Präsentationsebene oder einen Microservice. Eine Servicefassade bietet Kunden mehrere Lese- und Schreibvorgänge. Es ist dafür verantwortlich, eingehende Anfragen an die Domain zu übertragen und die von der Domain empfangene Antwort den Clients zuzuordnen. Die Verwendung einer Servicefassade ist für Microservices, die eine einzige Verantwortung mit mehreren Vorgängen haben, einfach. Bei der Verwendung der Servicefassade ist es jedoch schwieriger, den Prinzipien einer einzigen Verantwortung und offenen Prinzipien zu folgen. Das Prinzip der einzigen Verantwortung besagt, dass jedes Modul nur für eine einzelne Funktionalität der Software verantwortlich sein sollte. Das Prinzip der offenen Tür besagt, dass der Code für Erweiterungen offen und für Änderungen geschlossen sein sollte. Wenn die Servicefassade erweitert wird, werden alle Vorgänge in einer Oberfläche gesammelt, mehr Abhängigkeiten werden darin eingekapselt, und mehr Entwickler beginnen, dieselbe Fassade zu modifizieren. Daher empfehlen wir, eine Servicefassade nur zu verwenden, wenn klar ist, dass sich der Service während der Entwicklung nicht stark ausdehnen würde.

Eine weitere Möglichkeit, Primäradapter in einer hexagonalen Architektur zu implementieren, ist die Verwendung des CQRS-Musters, das Lese- und Schreibvorgänge mithilfe von Abfragen und Befehlen trennt. Wie bereits erläutert, handelt es sich bei Befehlen um Objekte, die alle Informationen enthalten, die erforderlich sind, um den Status der Domäne zu ändern. Befehle werden mit Command-Handler-Methoden ausgeführt. Abfragen hingegen ändern nicht den Zustand des Systems. Ihr einziger Zweck besteht darin, Daten an Kunden zurückzugeben. Im CQRS-Muster werden Befehle und Abfragen in separaten Modulen implementiert. Dies ist besonders vorteilhaft für Projekte, die einer ereignisgesteuerten Architektur folgen, da ein Befehl als Ereignis implementiert werden könnte, das asynchron verarbeitet wird, wohingegen eine Abfrage mithilfe einer API synchron ausgeführt werden kann. Eine Abfrage kann auch eine andere Datenbank verwenden, die dafür optimiert ist. Der Nachteil des CQRS-Musters besteht darin, dass die Implementierung mehr Zeit in Anspruch nimmt als eine Servicefassade. Wir empfehlen, das CQRS-Muster für Projekte zu verwenden, die Sie skalieren und langfristig beibehalten möchten. Befehle und Abfragen bieten einen effektiven Mechanismus für die Anwendung des Prinzips der einzigen Verantwortung und die Entwicklung lose gekoppelter Software, insbesondere bei Großprojekten.

CQRS hat auf lange Sicht große Vorteile, erfordert jedoch eine Anfangsinvestition. Daher empfiehlt es sich, Ihr Projekt sorgfältig zu evaluieren, bevor Sie sich für das CQRS-Muster entscheiden. Sie können Ihre Anwendung jedoch strukturieren, indem Sie Befehle und Befehlshandler von Anfang an verwenden, ohne Lese- und Schreibvorgänge voneinander zu trennen. Auf diese Weise können Sie Ihr Projekt problemlos für CQRS umgestalten, falls Sie sich später für diesen Ansatz entscheiden.

Organisational

Eine Kombination aus sechseckiger Architektur, domänengetriebenem Design und (optional) CQRS ermöglicht es Ihrem Unternehmen, Ihr Produkt schnell zu skalieren. Nach dem Gesetz von Conway neigen Softwarearchitekturen dazu, sich weiterzuentwickeln, um die Kommunikationsstrukturen eines Unternehmens widerzuspiegeln. Diese Beobachtung war in der Vergangenheit negativ konnotiert, da große Organisationen ihre Teams häufig auf der Grundlage von technischem Fachwissen wie Datenbanken, Enterprise Service Bus usw. strukturieren. Das Problem bei diesem Ansatz ist, dass die Produkt- und Funktionsentwicklung immer mit Querschnittsthemen wie Sicherheit und Skalierbarkeit einhergeht, die eine ständige Kommunikation zwischen den Teams erfordern. Die Strukturierung von Teams auf der Grundlage technischer Merkmale führt zu unnötigen Silos in der Organisation, was zu schlechter Kommunikation, mangelnder Eigenverantwortung und dem Verlust des Gesamtbildes führt. Schließlich spiegeln sich diese organisatorischen Probleme in der Softwarearchitektur wider.

Das Inverse Conway Maneuver hingegen definiert die Organisationsstruktur auf der Grundlage von Bereichen, die die Softwarearchitektur fördern. Zum Beispiel erhalten funktionsübergreifende Teams die Verantwortung für eine bestimmte Reihe von begrenzten Kontexten, die mithilfe von DDD und Event Storming identifiziert werden. Diese begrenzten Kontexte könnten sehr spezifische Merkmale des Produkts widerspiegeln. Beispielsweise könnte das Account-Team für den Zahlungskontext verantwortlich sein. Jedes neue Feature wird einem neuen Team zugewiesen, das eng miteinander verzahnte Verantwortlichkeiten hat, sodass sie sich ausschließlich auf die Bereitstellung dieser Funktion konzentrieren und die Zeit bis zur Markteinführung verkürzen kann. Teams können entsprechend der Komplexität der Funktionen skaliert werden, sodass komplexe Funktionen mehr Ingenieuren zugewiesen werden können.