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 wenig Zeit sein, um die Softwarearchitektur entsprechend anzupassen. Ein weiterer Grund könnten unzureichende Investitionen für die Einrichtung der Softwarearchitektur zu Beginn des Projekts sein, um sie an häufige Änderungen anpassen zu können. Was auch immer der Grund sein mag, ein Softwaresystem könnte 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 verwaltbare Anwendungen mithilfe einer hexagonalen Architektur entworfen werden können, die sich leicht an nicht funktionale oder geschäftliche Anforderungen anpassen lässt.

Anpassung an neue, nicht funktionale Anforderungen mithilfe von Anschlüssen und Adaptern

Als Kern der Anwendung definiert das Domänenmodell die Aktionen, 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 Ports werden durch separate Adapter implementiert. Jeder Adapter ist für die Interaktion mit einem anderen System verantwortlich. Beispielsweise haben Sie möglicherweise einen Adapter für das Datenbank-Repository und einen anderen Adapter für die Interaktion mit einer Drittanbieter-API. 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 durch das Domänenmodell definierten Ports zu implementieren. Die Domäne hat keine Abhängigkeiten vom Datenbank-Repository und verwendet Abstraktionen für die Interaktion, sodass am Domänenmodell nichts geändert werden müsste. Daher passt sich die hexagonale Architektur mühelos an nichtfunktionale Anforderungen an.

Anpassung an neue Geschäftsanforderungen mithilfe von Befehlen und Befehlshandlern

In der klassischen Schichtarchitektur 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 einer 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 Domäne verwendet das Prinzip der Umkehrung von Abhängigkeiten, um über Ports mit der Außenwelt zu kommunizieren. Der Vorteil der Abhängigkeitsumkehrung besteht darin, dass Sie das Domänenmodell frei ändern können, ohne Angst haben zu müssen, andere Teile des Codes zu beschädigen. 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 Unternehmensbereichen ein wichtiger Grundsatz, den es zu beachten gilt. Um diese Trennung zu erreichen, können Sie ein leicht modifiziertes Befehlsmuster verwenden. Dabei handelt es sich um ein Verhaltensmuster, bei dem alle für den Abschluss eines Vorgangs erforderlichen Informationen in einem Befehlsobjekt zusammengefasst sind. Diese Operationen werden dann von Befehlshandlern 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, für jeden Vorgang in der Domäne Befehle und Befehlshandler zu verwenden. Mit diesem Ansatz 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 Dienstfassadenmusters oder durch die Verwendung des CQRS-Musters (Command Query Responsibility Segregation).

Das Service-Fassadenmuster bietet eine nach vorne gerichtete Oberfläche für die Bedienung von Clients, z. B. der Präsentationsebene oder einem Microservice. Eine Servicefassade bietet Kunden mehrere Lese- und Schreiboperationen. Sie ist dafür verantwortlich, eingehende Anfragen an die Domain zu übertragen und die von der Domain empfangene Antwort den Clients zuzuordnen. Die Verwendung einer Service-Fassade ist für Microservices, die eine einzige Verantwortung mit mehreren Vorgängen haben, einfach. Bei der Nutzung der Servicefassade ist es jedoch schwieriger, den Prinzipien der Einzelverantwortung und der offenen und geschlossenen Struktur zu folgen. Das Prinzip der Alleinverantwortung besagt, dass jedes Modul nur für eine einzige Funktionalität der Software verantwortlich sein sollte. Das Prinzip der offenen und geschlossenen Version besagt, dass Code für Erweiterungen offen und für Änderungen geschlossen sein sollte. Mit der Erweiterung der Service-Fassade werden alle Operationen in einer Oberfläche zusammengefasst, mehr Abhängigkeiten werden darin zusammengefasst und mehr Entwickler beginnen, dieselbe Fassade zu modifizieren. Daher empfehlen wir, eine Service-Fassade nur dann zu verwenden, wenn klar ist, dass der Service während der Entwicklung nicht wesentlich erweitert werden 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 voneinander trennt. Wie bereits erläutert, handelt es sich bei Befehlen um Objekte, die alle Informationen enthalten, die zur Änderung des Status der Domäne erforderlich sind. Befehle werden durch Befehlshandler-Methoden ausgeführt. Abfragen ändern dagegen 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 für sie optimiert ist. Der Nachteil des CQRS-Musters besteht darin, dass die Implementierung mehr Zeit in Anspruch nimmt als die Implementierung einer Servicefassade. Wir empfehlen, das CQRS-Muster für Projekte zu verwenden, die Sie langfristig skalieren und verwalten möchten. Befehle und Abfragen bieten einen effektiven Mechanismus zur Anwendung des Prinzips der alleinigen Verantwortung und zur Entwicklung lose gekoppelter Software, insbesondere bei Großprojekten.

CQRS hat auf lange Sicht große Vorteile, erfordert jedoch eine Anfangsinvestition. Aus diesem Grund empfehlen wir Ihnen, Ihr Projekt sorgfältig zu prüfen, bevor Sie sich für die Verwendung des CQRS-Musters entscheiden. Sie können Ihre Anwendung jedoch von Anfang an strukturieren, indem Sie Befehle und Befehlshandler verwenden, ohne Lese- und Schreibvorgänge 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.

Organisatorische Skalierung

Eine Kombination aus sechseckiger Architektur, domänengesteuertem Design und (optional) CQRS ermöglicht es Ihrem Unternehmen, Ihr Produkt schnell zu skalieren. Gemäß dem Gesetz von Conway entwickeln sich Softwarearchitekturen in der Regel so, dass sie die Kommunikationsstrukturen eines Unternehmens widerspiegeln. Diese Beobachtung hatte in der Vergangenheit negative Assoziationen, da große Unternehmen ihre Teams häufig auf der Grundlage von technischem Fachwissen wie Datenbanken, Enterprise Service Bus usw. strukturieren. Das Problem bei diesem Ansatz besteht darin, dass die Entwicklung von Produkten und Funktionen immer mit Querschnittsfragen 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, die zu schlechter Kommunikation, mangelnder Eigenverantwortung und dem Verlust des Gesamtbildes führen. Letztlich spiegeln sich diese organisatorischen Probleme in der Softwarearchitektur wider.

Das Inverse Conway-Manöver hingegen definiert die Organisationsstruktur auf der Grundlage von Bereichen, die die Softwarearchitektur fördern. Funktionsübergreifenden Teams wird beispielsweise die Verantwortung für eine bestimmte Gruppe von begrenzten Kontexten übertragen, die mithilfe von DDD und Event Storming identifiziert werden. Diese begrenzten Kontexte können sehr spezifische Merkmale des Produkts widerspiegeln. Beispielsweise könnte das Account-Team für den Zahlungskontext verantwortlich sein. Jede neue Funktion wird einem neuen Team zugewiesen, das sehr kohärente und lose miteinander verknüpfte Verantwortlichkeiten hat, sodass es sich nur auf die Bereitstellung dieser Funktion konzentrieren und die Markteinführungszeit verkürzen kann. Teams können entsprechend der Komplexität der Funktionen skaliert werden, sodass komplexe Funktionen mehr Technikern zugewiesen werden können.