Adaptives Software Design mit DDD

Domain Driven Design (DDD) ist seit über 20 Jahren ein gefragtes Thema. Was die schnelllebige IT-Welt angeht, handelt es sich bei diesem Thema also um einen ungewöhnlichen Dauerbrenner, wie man bei den Software Architecture Trends von O`Reilly nachlesen kann.  Wir motivieren eingehend, warum ein adaptives Software Design insbesondere heutzutage ein zentraler Erfolgsfaktor in Geschäftsanwendungen ist. Danach zeigen wir, warum speziell Domain Driven Design viele gute Ansätze für die Gestaltung adaptiver Software-Architekturen bietet. Anschließend geben wir einen kurzen Überblick, welche Werkzeuge Domain Driven Design hierfür bereitstellt.

Wettbewerbsvorteile durch adaptive Systeme

Für ein langfristig stabiles Wirtschaften müssen Unternehmen mit Veränderungen umgehen können. Viele äußere Einflussfaktoren durch Änderungen am Markt und auch beispielsweise durch stetig neu erscheinende technologische Innovationen machen es erforderlich, dass sich Unternehmen als Ganzes darauf einstellen müssen. Beschrieben wird die dafür benötigte Reaktionsfähigkeit in diesem Zusammenhang oft mit dem Begriff „Business Agility“. Sich anpassen zu können und Veränderungen im Markt und in den Rahmenbedingungen zu seinem Vorteil nutzen können, wird immer wichtiger.

Für die zugrunde liegenden Systeme bedeutet dies, dass sie gute Adaptivitätseigenschaften aufweisen müssen. Diese bilden die Voraussetzung, um in Geschäftsanwendungen erforderliche Veränderungen schlussendlich umsetzen zu können. Das gilt insbesondere für individuelle Software-Lösungen, die für Unternehmen immer ein bedeutendes Investment darstellen. Sie müssen sich dementsprechend langfristig amortisieren und können nicht einfach mal schnell nebenbei neu entwickelt werden. Darüber hinaus bilden individuelle Lösungen oftmals den Kern eines für das Unternehmen zentralen digital abgebildeten oder unterstützten Wettbewerbsvorteils. Um so mehr spielen Adaptivitätseigenschaften in diesem Fall eine noch größere Rolle, da man diesen Wettbewerbsvorteil dauerhaft halten und gegebenenfalls langfristig durch Anpassung und Erweiterung der Lösung erweitern möchte.

Adaptivitätseigenschaften

Unter dem Begriff Adaptivitätseigenschaften werden je nach Betrachtungsweise unterschiedliche Aspekte und Qualitätseigenschaften subsumiert, wie beispielsweise Wartbarkeit, Erweiterbarkeit, Änderbarkeit oder auch die Anpassbarkeit eines Systems. Je nach Art der gewünschten oder notwendigen Veränderungen sind unterschiedliche Systembestandteile betroffen. Vor allem lassen sich nicht alle künftigen Änderungen vorhersehen. Besonders um diese Änderungen, die sich nicht klar vorhersehen lassen, soll es im weiteren Verlauf gehen. Also weniger um obligatorisch statt findende Library Versions Upgrades oder die konfigurative Anpassung des aktuell geltenden Mehrwertsteuersatzes. Sondern eher um Veränderungen, die in den grundsätzlichen Aufgabenbereich der betroffenen Software fallen, sich aber nur durch eine Anpassung der Implementierung bewerkstelligen lassen.

Ein Beispiel hierfür wäre bspw. ein Unternehmen, das seinen Kunden Mietmodelle für bestimmte Produkte anbietet. Nehmen wir an, dieses Unternehmen entschließt sich nun dazu, das zuvor rein zeitbasierte „Mietmodell“ auf eine nutzungsbasierte Abrechnung (pay-per-use) zu erweitern. Dann ist in der Folge klar, dass in einem Software gestützten Prozess viele Bereiche wie z.B. Angebots-, Vertragsverwaltungs- und Abrechnungsprozesse (und möglicherweise noch mehr) in irgendeiner Form von entsprechend notwendigen Anpassungen betroffen sind, die man zuvor so nicht im Blick hatte.

Abgrenzung zur klassischen Agilität bei der Software-Entwicklung

Heutzutage sind agile Vorgehensweisen (wie beispielsweise Scrum oder Kanban) die Grundlage für die Arbeitsorganisation eines Teams, welches an Software Produkten arbeitet. Es ist klar, dass sich Ziele im Rahmen eines größeren Entwicklungsprozesses ändern können. Ebenso hat sich die Erkenntnis im Rahmen von IT Projekten schon lange durchgesetzt, dass sich über regelmäßiges Feedback im Rahmen eines komplexen Entwicklungsprozesses wichtige neue Erkenntnisse gewinnen lassen. Ebenso zeigt die Erfahrung, dass die Berücksichtigung dessen in aller Regel über ein iterativ agiles Vorgehen schneller zu einer guten Lösung führt, als bei einem streng phasenorientierten Vorgehen. Adaptivität im Sinne der „Fähigkeit auf Veränderungen reagieren zu können“ spielt somit im Entwicklungsprozess und der Art und Weise, wie bei diesem Vorhaben kommuniziert wird, bereits eine zentrale Rolle.

Im Folgenden wird nun weniger auf ein agiles Vorgehen eingegangen, sondern es wird vielmehr erläutert was Ansätze sind, um Strukturen im Systemdesign (der Architektur) zu schaffen, die uns zu langfristig gute Adaptivitätseigenschaften gewähren. Dabei werden insbesondere die Werkzeuge in Betracht gezogen, die uns Domain Driven Design (DDD) bietet. Nebenbei gesagt, lassen sich diese Ansätze aber sehr gut mit den zuvor genannten agilen Vorgehensweisen kombinieren.

Ausschnitt eines beispielhaftes Domänenmodells

Beispielhafte Darstellung des Domänenmodells eines Online Shops.

Mehr Adaptivität durch DDD – Ein Überblick

Domain Driven Design umfasst ein sehr weites Feld. Es ist kaum möglich, alle Feinheiten und Details in einem Artikel zusammenzufassen. Deshalb wollen wir hier primär einige Grundgedanken und zentrale Ideen skizzieren, die einen Eindruck vermitteln, wie DDD zur Verbesserung von Adaptivitätseigenschaften beitragen kann.

Zum allgemeinen Verständnis von DDD

  • Der wesentliche Grundgedanke bei DDD steckt bereits im Namen: „Domain Driven Design“ könnte man übersetzen als „Durch die Fachlichkeit getriebenes Design“. Die Strukturen, Konzepte und Zusammenhänge der Fachdomäne wollen wir passend abbilden. Sie geben uns somit gewissermaßen „natürliche“ Leitlinien und Orientierungspunkte mit, an denen wir Designentscheidungen ausrichten können und in der Folge die Strukturen in unserer Software ableiten.
  • DDD bezieht sich im Kern immer auf ein Model getriebenes Vorgehen. Das bedeutet, wir versuchen Fachkonzepte zu modellieren, um so mehr Klarheit und Einsichten zu erlangen und sie dann passend zu implementieren. Dabei ist wichtig zu verstehen, dass die Modellierung und Implementierung idealerweise durchaus iterativ angepasst und verfeinert wird (kein Big UpFront Design „BUF“). Ebenso sollen die Modelle helfen, bei schwierigen Entscheidungen alternative Entwürfe zu vergleichen.
  • Unserer Meinung nach ist DDD als Werkzeugkasten zu verstehen, der methodische Ansätze und Techniken bietet, bei welchen man sich bedienen kann, wenn man das jeweilige Werkzeug für passend hält.

DDD legt viel Wert auf klare und unmissverständliche Beschreibungen der Fachkonzepte. Das Ziel ist es, eine speziell auf den jeweiligen Kontext (Bounded Context) bezogene Sprache zu etablieren, die sowohl von Technikern als auch dem zugehörigen Fachbereich gesprochen und verstanden wird (Ubiquitous Language).

DDD Prinzipien für verbesserte Adaptivität

Es gibt zwei wiederkehrende Prinzipien, welche sich durch alle Werkzeuge von DDD ziehen und gleichzeitig die Adaptivitätseigenschaften in Software-Strukturen verbessern:

  1. Verständlichkeit: Bei DDD werden implizite Konzepte und Zusammenhänge möglichst explizit in den Modellen und dann auch im Code abgebildet. Wenn man Software anpassen oder erweitern möchte, dann ist die Grundlage dafür, dass man die Ausgangssituation und zugehörige Zusammenhänge möglichst klar erfasst hat. Dadurch lassen sich unerwünschte Seiteneffekte besser ausschließen und man weiß genauer, was alles anzupassen ist. Über die Verankerung der Ubiquitous Language in der Kommunikation bei den handelnden Personen und direkt im Code werden Übersetzungsverluste und Missverständnisse stark reduziert. Software-Entwicklung ist Teamarbeit. Der größte Aufwand entsteht nicht dadurch, dass man mehr Zeilen Code schreiben muss. Vielmehr ist die größte Hürde, dass die zugrunde liegenden Fachzusammenhänge über mehrere Köpfe hinweg klar erfasst und in Code transferiert werden müssen.
  1. Grenzen setzen: Seit jeher ist Modularisierung ein zentrales Mittel in der Software-Entwicklung, um Komplexität kontrollierbar zu machen. Grenzen klar zu definieren erlaubt uns Abhängigkeiten zwischen Modulen klar zu definieren (Schnittstellen) und das Innere im Rahmen dieser Abhängigkeiten als „Black Box“ zu betrachten (Kapselung). So lassen sich die betroffenen Bereiche von Änderungen, Anpassungen und Erweiterungen schneller identifizieren und man muss sich nicht immer mit allen Details auseinandersetzen, wenn man die entsprechenden Dinge umsetzen will. Darüber hinaus werden auch hierüber unerwünschte Nebeneffekte besser unterbunden und vieles mehr. DDD bietet Methoden und Patterns, um Grenzen besser zu erkennen und sie zu klarer definieren. Die Patterns beinhalten Optionen und Vorschläge, wie sie besser in der Architektur und im Code umgesetzt werden können. Die Gestaltung von Abhängigkeiten ist von zentraler Bedeutung für gute Adaptivitätseigenschaften in Software-Lösungen. Das vielfach im DDD Kontext erwähnte Anti-Pattern „Big Ball of Mud“ erläutert auch warum. DDD hilft auf unterschiedlichen Ebenen des Designs (strategisches und taktisches Design) beim passenden Schnitt von Modulen und Komponenten und deren Grenzen.

Unterstützung für adaptives Design in allen Bereichen

Domain Driven Design lässt sich in drei große Bereiche ordnen:

  1. Domain Discovery: Grundlage für eine zielgerichtete Implementierung ist, dass die Problemstellung und die Zusammenhänge in einer Domäne gut verstanden werden. DDD bietet hierzu bekannte kollaborative methodische Ansätze, wie beispielsweise „Event Storming“ oder „Domain Story Telling“. Dieser übergreifende Wissensaufbau bildet ebenso die Grundlagen für die Verständlichkeit im Domänen getriebenen Design.
  2. Strategic Design: Eine Domäne muss im Design zerlegt werden. Das betrifft die oben besagte Grenzdefinition auf oberer Ebene. In diesem Bereich hat DDD im Zuge des Microservice Hypes wieder viel Wahrnehmung erfahren. Insbesondere als Hilfestellung bei Fragen wie beispielsweise „Wie schneide ich meine Microservices idealerweise?“. Die dort nutzbaren Patterns bringen aber insbesondere auch unabhängig vom verfolgten Architekturstil wertvolle Einsichten. Das strategische Design unterstützt dabei einen fachlichen und an den Organisationsstrukturen orientierten Schnitt zu erreichen. Dadurch wird erleichtert, Abhängigkeiten explizit zu formulieren und bestenfalls zu minimieren und so in der Folge die Adaptivitätseigenschaften der Lösung zu verbessern.
  3. Tactical Design: Im Kern geht es bei taktischem DDD um einen guten objektorientierten Programmierstil. DDD bietet hierzu einige Patterns, die dabei helfen zentrale Konzepte voneinander abzugrenzen (z.B. Aggregates). Das ultimative Ziel dabei ist, die Konzepte der Domäne möglichst passend im Code abzubilden (Zitat Vaughn Vernon: „the code is the model, and the model is the code“, siehe hier). Das hebt die Code-Qualität, indem Code Duplikationen vermieden und Zusammenhänge tendenziell besser passend logisch gebündelt werden und einiges mehr. Zudem werden implizite Konzepte explizit ausgedrückt, was die Verständlichkeit verbessert. All dies steigert langfristig die Adaptivitätseigenschaften im Ergebnis auf Code-Ebene.

Ein letzter Rat

Zum Abschluss noch eine Sache. DDD in vollem Umfang ist nicht einfach und die Vielfalt an Aspekten und Patterns schreckt anfangs oft ab. Besonders, wenn man mit dieser Welt bisher noch nicht viel zu tun hatte. Aus unserer Erfahrung sollte man DDD eher begreifen wie eine Reise, auf die man sich einlassen muss. Man kann auch erst mal klein anfangen und sich ein ausgewähltes Werkzeug greifen, das vielleicht zu einer konkreten Problemstellung Lösungsansätze verspricht. Es hilft zum Einstieg auch erst einmal zu versuchen eine Problemstellung über ein Modell abzubilden und besser zu verstehen (ohne direkt alle Patterns versuchen perfekt einzusetzen). Man gelangt oft auch so zu wertvollen Einsichten, bevor man an die Implementierung geht.

Bounded Context: Der Bounded Context definiert den Einsatzbereich eines Domänenmodells. Es umfasst die Geschäftslogik für eine bestimmte Fachlichkeit. Das Domänenmodell des Bounded Context für einen „Online Shop“ ist in der Abbildung oben dargestellt.

Aggregate: Ein Aggregat ist eine Gruppe von Domänenobjekten, die als eine Einheit behandelt werden. Ein Beispiel dafür ist eine Bestellung (siehe „Order“ im obigen Domänenmodell) und ihre Einzelposten („OrderItem“). Diese sind separate Objekte, aber es ist sinnvoll, die Bestellung (zusammen mit ihren Einzelposten) als ein einziges Aggregat zu behandeln.

Bei einem Aggregat ist eines seiner Komponentenobjekte die Wurzel des Aggregats (AggregateRoot). Alle Verweise von außerhalb des Aggregats sollten nur auf die Aggregatwurzel gehen. Die Wurzel kann somit die Integrität des Aggregats als Ganzes gewährleisten.

Aggregate sind das grundlegende Element für den Zugriff auf die Persistenz über Repositories.  Über Repositories werden zur Wahrung der Konsistenz nur ganze Aggregate geladen oder gespeichert. Transaktionen sollten keine Aggregatgrenzen überschreiten.

Anaemic Domain Model (Anti Pattern): Martin Fowler schreibt hierzu:

„Das grundlegende Symptom eines anämischen Domänenmodells ist, dass es auf den ersten Blick wie ein echtes Modell aussieht. Es gibt Objekte, von denen viele nach den Substantiven im Domänenraum benannt sind, und diese Objekte sind mit den reichhaltigen Beziehungen und Strukturen verbunden, die echte Domänenmodelle aufweisen.

Der Haken an der Sache ist, dass es kaum Verhalten für diese Objekte gibt, so dass sie kaum mehr als eine Ansammlung von Gettern und Settern sind. In der Tat sind diese Modelle oft mit Entwurfsregeln versehen, die besagen, dass man keine Domänenlogik in die Domänenobjekte einbauen soll. Stattdessen gibt es eine Reihe von Services, die die gesamte Domänenlogik erfassen, alle Berechnungen durchführen und die Modellobjekte mit den Ergebnissen aktualisieren. Diese Dienste leben oberhalb des Domänenmodells und verwenden das Domänenmodell für Daten.

Das Schlimme an diesem Muster ist, dass es dem Grundgedanken des objektorientierten Designs zuwiderläuft, nämlich Daten und Prozesse miteinander zu verbinden. Das anämische Domänenmodell ist in Wirklichkeit nur ein prozedurales Design, genau die Art von Dingen, die Objektfanatiker wie ich (und Eric [Evans]) seit unseren frühen Tagen in Smalltalk bekämpft haben. Noch schlimmer ist, dass viele Leute denken, dass anämische Objekte echte Objekte sind, und damit völlig verfehlen, worum es bei objektorientiertem Design überhaupt geht.“

Big Ball of Mud (Anti Pattern): Der Big Ball of Mud bezieht sich auf eine Architektur, der es an modularem Design mangelt und die daher nur eine Masse von unorganisiertem Code ohne echte Struktur ist. Dies entsteht oftmals durch Hinzufügen neuer Funktionen im Laufe der Zeit, ohne dass die erforderlichen Anstrengungen für eine modulare Ordnung unternommen wurden.

Wenn man versucht, die Architektur eines Softwaresystems zu dokumentieren und feststellt, dass es schwierig ist, Teilsysteme oder Verantwortlichkeiten abzugrenzen, ist es möglich, dass das System keine erkennbare Architektur hat und somit ein Big Ball of Mud ist.

Änderungen und Erweiterungen sind in einem Big Ball of Mud oft nur sehr schwer und langsam umsetzbar. Es dauert durch die fehlende Struktur sehr lange alle Stellen zu finden, die für ein konsistentes Verhalten angepasst werden müssen. Die Fehlerquote durch unerwünschte Nebeneffekte ist tendenziell sehr hoch.

Diese Themen könnten Dich auch interessieren

Flugzeug im Hangar - Visualisierung eines Artikels zum Thema Vom Cockpit zur Commandline

Vom Cockpit zur Commandline, Teil 1: Piloten

Ein Blick über den eigenen Tellerrand, der uns zeigt, wie wir Software noch besser entwickeln können.
Mensch auf Fahrrad als Illustration zum Thema Kombination von maschinellem Lernen, IoT und Radfahren für eine kostengünstige Infrastrukturüberwachung

Kombination von maschinellem Lernen, IoT und Radfahren für eine kostengünstige Infrastrukturüberwachung

Hier erfährst Du, wie wir mithilfe von Sensordatenerfassung, die Straßenzustände von Radwegen klassifizieren.
Ein umfassendes, dynamisches und futuristisches Bild, das das schnelle Wachstum und die Wirkung von ChatGPT seit seiner Einführung im November 2022 darstellt und seinen Meilenstein symbolisiert

Eigene GPTs mit OpenAI bauen

Lerne wie du einen eigenen GPT mit OpenAI erstellen kannst.

Nimm gerne Kontakt zu uns auf!

Hast Du Fragen zu DDD, Software- und Systemarchitektur oder digitalen Transformation im Allgemeinen? Dann freue ich mich immer über den Austausch mit Dir!

Sende mir gerne eine Mail, vernetze Dich mit mir oder hinterlasse Deine Kontaktdaten.

Mario Herb

Mario Herb
VP Digital Innovation & Digital Architect