Analysieren einer Anwendung und Einschränkungen bei der Zerlegung

Abgeschlossen

Fabrikam muss die aktuelle Anwendung analysieren und den Bereich und die Grenzen der einzelnen Microservices bestimmen, um die Anwendung in eine Microservicesarchitektur zu verschieben. Für diese Bewertung verwenden sie das DDD-Framework (Domain-Driven Design, an der Domäne ausgerichteter Entwurf). Wir betrachten nun, wie Fabrikam dieses Framework auf die Anwendung anwendet.

Hinweis

In diesem Artikel wird keine vollständige und umfassende Domänenanalyse gezeigt. Wir haben das Beispiel absichtlich kurz gehalten, um die wichtigsten Punkte besser verdeutlichen zu können. Weitere Informationen zu DDD finden Sie im Abschnitt „Weitere Informationen“ in der Zusammenfassung am Ende dieses Moduls.

Was ist ein am Geschäftsbereich ausgerichteter Entwurf?

Domain-Driven Design (DDD) ist ein Ansatz für Systemdesign, den Erik Evans 2005 erstmals im Buch Domain-Driven Design: Tackling Complexity in the Heart of Software eingeführt hat. Dieser Ansatz umfasst drei wichtige Elemente:

  • Konzentration auf die Kerndomäne und Domänenlogik.
  • Strukturieren des Entwurfs für ein Domänenmodell.
  • Fördern der iterativen Zusammenarbeit zwischen den Technikteams und Geschäftspartnern für stetige Verbesserung des Systems.

DDD bietet ein Framework, mit dem Sie am meisten von den ausgereiften Microservices profitieren können. DDD verfügt über zwei separate Phasen: eine strategische und eine taktische Phase. In der strategischen DDD-Phase definieren Sie die übergeordnete Struktur des Systems. In dieser Phase können Sie sicherstellen, dass Ihre Architektur klar auf die geschäftlichen Funktionen ausgerichtet ist. In der taktischen DDD-Phase wird eine Gruppe von Entwurfsmustern bereitgestellt, die Sie zum Erstellen des Domänenmodells verwenden können. Zu diesen Mustern gehören Entitäten, Aggregate und Domänendienste. Diese taktischen Muster sind hilfreich beim Entwerfen von Microservices, die lose gekoppelt und kohäsiv sind.

Diagram of the steps for domain-driven design.

Während der strategischen DDD-Phase entwerfen Sie die Geschäftsdomäne und definieren Kontextgrenzen für Ihre Domänenmodelle. In der taktischen DDD-Phase definieren Sie Ihre Domänenmodelle mit größerer Genauigkeit. Die taktischen Muster werden nur in einem Kontextgrenzbereich angewendet. Bei einer Microservicesarchitektur sind wir an den Entitäts- und Aggregatmustern interessiert. Die Anwendung dieser Muster hilft uns dabei, natürliche Grenzen für die Dienste in unserer Anwendung zu identifizieren. Es gilt das allgemeine Prinzip, dass ein Microservice nicht kleiner als ein Aggregat und nicht größer als eine Kontextgrenze sein sollte.

Allgemein kann dieser Prozess in vier Schritte gegliedert werden:

  1. Analysieren der Geschäftsdomäne, um die funktionsbezogenen Anforderungen der Anwendung zu verstehen. Das Ergebnis dieses Schritts ist eine informelle Beschreibung der Domäne, die zu einer formelleren Gruppe von Domänenmodellen verfeinert werden kann.
  2. Definieren der Kontextgrenzen der Domäne. Jeder Kontextgrenzbereich enthält ein Domänenmodell, das eine bestimmte Unterdomäne der übergeordneten Anwendung darstellt.
  3. Wenden Sie innerhalb einer Kontextgrenze taktische DDD-Muster an, um Entitäten, Aggregate und Domänendienste zu definieren.
  4. Identifizieren der Microservices in Ihrer Anwendung mithilfe der Ergebnisse des vorherigen Schritts.

Wir sehen uns genauer an, was bei den einzelnen Schritten passiert.

Analysieren der Geschäftsdomäne

Beim DDD-Ansatz wird zuerst die Geschäftsdomäne modelliert und ein Domänenmodell erstellt. Das Domänenmodell ist ein abstraktes Modell der Geschäftsdomäne. Hiermit wird das Domänenwissen zusammengefasst und organisiert und eine gemeinsame Sprache für Entwickler und Domänenexperten gefunden.

Beginnen Sie, indem Sie alle Geschäftsfunktionen und ihre Verbindungen zuordnen. Diese Analyse ist ein Gemeinschaftsprojekt, in das Domänenexpert:innen, Softwarearchitekt:innen und andere Projektbeteiligte einbezogen werden. Es muss kein bestimmter Formalismus eingehalten werden. Skizzieren Sie ein Diagramm, oder verwenden Sie ein Whiteboard.

Beim Erstellen des Diagramms könnten Sie damit beginnen, einzelne Unterdomänen zu identifizieren. Welche Funktionen sind eng verwandt? Welche Funktionen sind für das Geschäft besonders wichtig, und welche Funktionen erfüllen Hilfszwecke? Was ist das Abhängigkeitsdiagramm? Während dieser ersten Phase geht es nicht um Technologien oder Implementierungsdetails. Ihnen sollte aber bewusst sein, an welchen Stellen die Anwendung in externe Systeme integriert werden muss (z. B. Systeme für CRM, Zahlungsverarbeitung oder Abrechnungen).

Diagram of the business domain.

Definieren von Kontextgrenzen

Das Domänenmodell enthält Darstellungen von realen Dingen: Benutzer, Drohnen, Pakete. Dies bedeutet aber nicht, dass jeder Teil des Systems für dieselben Dinge die gleichen Darstellungen verwenden muss.

Beispielsweise müssen Subsysteme, die Drohnenreparatur und Vorhersageanalysen verarbeiten, viele physische Merkmale von Drohnen darstellen. Zu diesen Merkmalen zählen Wartungsverlauf, Geschwindigkeit, Alter, Modellnummer und Leistungsdetails. Wenn es aber um die Planung einer Lieferung geht, kümmern wir uns nicht um diese Dinge. Das Subsystem für die Planung muss nur wissen, ob eine Drohne verfügbar ist und welcher geschätzte Zeitpunkt (Estimated Time of Arrival, ETA) für Abholung und Lieferung gilt.

Wenn wir versuchen, ein gemeinsames Modell für beide Subsysteme zu erstellen, ist dies unnötig komplex. Außerdem wird es schwieriger, das Modell im Laufe der Zeit weiterzuentwickeln, da alle Änderungen die Zustimmung mehrerer Teams erhalten müssen, die an separaten Subsystemen arbeiten. Häufig ist es besser, separate Modelle zu entwerfen, bei denen die gleiche reale Entität (in diesem Fall eine Drohne) in zwei unterschiedlichen Kontexten dargestellt wird. Jedes Modell enthält nur die Features und Attribute, die im jeweiligen Kontext relevant sind.

Bei dieser Herangehensweise wird auf das DDD-Konzept der Kontextgrenzen zurückgegriffen. Eine Kontextgrenze bezeichnet einfach den abgegrenzten Bereich innerhalb einer Domäne, in dem ein bestimmtes Domänenmodell gilt. Wenn wir uns das obige Diagramm ansehen, können wir die Funktionalität danach gruppieren, ob von den einzelnen Funktionen ein Domänenmodell gemeinsam genutzt wird.

Diagram of the bounded contexts for the drone application.

Definieren von Entitäten, Aggregaten und Diensten

In der taktischen DDD-Phase definieren Sie Ihre Domänenmodelle mit größerer Genauigkeit. Die taktischen Muster werden nur in einem Kontextgrenzbereich angewendet. Bei einer Microservicesarchitektur sind wir an den Entitäts- und Aggregatmustern interessiert. Die Anwendung dieser Muster hilft uns dabei, natürliche Grenzen für die Dienste in unserer Anwendung zu identifizieren. Es gilt das allgemeine Prinzip, dass ein Microservice nicht kleiner als ein Aggregat und nicht größer als eine Kontextgrenze sein sollte.

Es gibt mehrere taktische DDD-Muster, die berücksichtigt werden müssen:

  • Entitäten: Eine Entität ist ein Objekt mit einer eindeutigen Identität, die bestehen bleibt. In einer Anwendung für Bankgeschäfte sind Kunden und Konten beispielsweise Entitäten.
  • Wertobjekte: Ein Wertobjekt hat keine Identität. Es wird von den Werten seiner Attribute definiert und ist unveränderlich. Typische Beispiele für Wertobjekte sind Farben, Datum und Uhrzeit und Währungswerte.
  • Aggregate: Ein Aggregat definiert eine Konsistenzgrenze für eine oder mehrere Entitäten. Der Zweck eines Aggregats ist die Modellierung von Transaktionsinvarianten. Reale Dinge weisen komplexe Beziehungsgeflechte auf. Kunden geben Bestellungen auf, Bestellungen enthalten Produkte, Produkte haben Lieferanten usw. Wenn von der Anwendung mehrere zusammengehörige Objekte geändert werden, wie kann dann die Konsistenz gewährleistet werden? Wie können Invarianten nachverfolgt und erzwungen werden?
  • Domänen- und Anwendungsdienste: In der DDD-Terminologie ist ein Dienst ein Objekt, mit dem Logik implementiert wird, ohne dass ein Zustand vorgehalten wird. Evans unterscheidet zwischen Domänendiensten, in denen die Domänenlogik gekapselt ist, und Anwendungsdiensten, mit denen die technische Funktionalität bereitgestellt wird. Anwendungsdienste umfassen in der Regel technische Funktionen, z. B. die Benutzerauthentifizierung oder das Senden einer SMS. Domänendienste werden häufig zum Modellieren von Verhalten verwendet, das mehrere Entitäten umfasst.
  • Domänenereignisse: Domänenereignisse können verwendet werden, um andere Teile des Systems zu benachrichtigen, wenn etwas passiert. Wie der Name bereits vermuten lässt, sollten Domänenereignisse eine bestimmte Bedeutung innerhalb der Domäne haben. Der Vorgang „ein Datensatz wurde in eine Tabelle eingefügt“ ist beispielsweise kein Domänenereignis. Der Vorgang „Lieferung wurde storniert“ ist ein Domänenereignis. Domänenereignisse sind besonders in einer Microservicearchitektur relevant. Da Microservices verteilt vorliegen und keine Datenspeicher gemeinsam nutzen, stellen Domänenereignisse eine Möglichkeit dar, wie sich Microservices untereinander koordinieren können.

Diagram of the drone domain model.

Das Entwicklungsteam von Fabrikam hat im System die folgenden Entitäten identifiziert:

  • Lieferung
  • Paket
  • Drohne
  • Konto
  • Bestätigung
  • Benachrichtigung
  • Tag

Die ersten vier Entitäten Lieferung, Paket, Drohne und Konto sind allesamt Aggregate, die für die Grenzen der Transaktionskonsistenz stehen. Bestätigungen und Benachrichtigungen sind untergeordnete Elemente von Lieferungen. Tags sind untergeordnete Elemente von Paketen.

Zu den Wertobjekten dieses Entwurfs gehören Standort, geschätzte Ankunftszeit, Paketgewicht und Paketgröße (Location, ETA, PackageWeight und PackageSize).

Es sind zwei Domänenereignisse vorhanden:

  • Während eine Drohne in der Luft ist, sendet die Drone-Entität DroneStatus-Ereignisse, mit denen der Standort und Status der Drohne beschrieben werden, z. B. Flug, gelandet.
  • Die Delivery-Entität sendet jeweils DeliveryTracking-Ereignisse, wenn sich die Phase einer Lieferung ändert. Beispiele hierfür sind DeliveryCreated, DeliveryRescheduled, DeliveryHeadedToDropoff und DeliveryCompleted.

Beachten Sie, dass diese Ereignisse Dinge beschreiben, die innerhalb des Domänenmodells eine Bedeutung haben. Sie beschreiben einen Aspekt der Domäne und sind nicht an ein Konstrukt einer bestimmten Programmiersprache gebunden.

Das Entwicklungsteam hat noch einen weiteren Funktionalitätsbereich identifiziert, der nicht ohne Weiteres einer der bisher beschriebenen Entitäten zugeordnet werden kann. Ein Teil des Systems muss alle Schritte koordinieren, die an der Planung oder Aktualisierung einer Lieferung beteiligt sind. Das Entwicklungsteam hat dem Design zwei Domänendienste hinzugefügt. Die Schritte werden von einem Scheduler koordiniert. Ein:e Supervisor:in überwacht den Status jedes Schritts, um zu ermitteln, ob bei Schritten ein Fehler oder ein Timeout aufgetreten ist.

Identifizieren von Microservices

Nun sind wir bereit für den Schritt vom Domänenmodell zum Anwendungsentwurf. Mit dem folgenden Ansatz können Sie Microservices vom Domänenmodell ableiten.

  1. Beginnen Sie mit einer Kontextgrenze. Im Allgemeinen sollten die Funktionen in einem Microservice nicht mehr als einen gebunden Kontext umfassen. Eine Kontextgrenze markiert definitionsgemäß die Grenze eines bestimmten Domänenmodells. Falls Ihr Microservice verschiedene Domänenmodelle miteinander vermischt, müssen Sie Ihre Domänenanalyse möglicherweise optimieren.
  2. Betrachten Sie als Nächstes die Aggregate in Ihrem Domänenmodell. Aggregate sind häufig gute Kandidaten für Microservices. Ein sorgfältig entworfenes Aggregat weist viele Merkmale eines sorgfältig entworfenen Microservice auf:
    • Einem Aggregat liegen geschäftliche Anforderungen und keine technischen Aspekte wie Datenzugriff oder Messaging zugrunde.
    • Ein Aggregat sollte über eine hohe funktionale Kohäsion verfügen.
    • Ein Aggregat ist eine Persistenzgrenze.
    • Aggregate sollten lose gekoppelt sein.
  3. Auch Domänendienste sind gute Kandidaten für Microservices. Domänendienste sind zustandslose, aggregatübergreifende Vorgänge. Ein typisches Beispiel ist ein Workflow, der mehrere Microservices umfasst. Später sehen wir ein Beispiel für einen Domänendienst in der Anwendung für die Drohnenlieferung.
  4. Berücksichtigen Sie schließlich auch die nicht funktionalen Anforderungen. Betrachten Sie Faktoren wie Teamgröße, Datentypen und Technologien sowie Skalierbarkeits-, Verfügbarkeits- und Sicherheitsanforderungen. Auf der Grundlage dieser Faktoren könnten Sie einen Microservice ggf. in mehrere kleinere Dienste aufspalten oder aber mehrere Microservices zu einem einzelnen Dienst zusammenfassen.

Seien Sie unbedingt pragmatisch, und denken Sie daran, dass ein am Geschäftsbereich ausgerichteter Entwurf ein iterativer Prozess ist. Beginnen Sie im Zweifelsfall mit undifferenzierteren Microservices. Die Aufspaltung eines Microservices in zwei kleinere Dienste ist einfacher als das Refactoring der Funktionalität in mehrere vorhandene Microservices.

Diagram of the microservices.

Anwenden eines am Geschäftsbereich ausgerichteten Entwurfs auf die Drohnenanwendung

Bei der Fabrikam-Anwendung befinden sich alle diese Dienste in der vorhandenen monolithischen Anwendung. Nachdem sie bestimmt haben, wo ihre Anwendung in Microservices aufgeteilt werden kann, beginnen sie mit dem Paketdienst.

Der Paketdienst verfügt derzeit über ein dediziertes Entwicklungsteam, hat Leistungsprobleme im Zusammenhang mit der Skalierbarkeit und eignet sich hervorragend für die Aufteilung der Anwendung.