Domain-driven Design (DDD) geht auf das gleichnamige Buch von Eric Evans zurück [1], das 2004 erschienen ist. Also ist DDD 15 Jahre alt. Die IT-Industrie behauptet von sich, sehr schnelllebig zu sein. Dann sollte ein Buch dieses Alters keine Rolle mehr spielen. Aber das Gegenteil ist der Fall: Das Buch verkauft sich immer noch sehr gut. Das Thema „DDD“ ist im Moment sogar so präsent, wie schon lange nicht mehr.
Für diese erstaunliche Entwicklung gibt es verschiedene Gründe. Das besondere an DDD drückt schon der Begriff aus: Die Domäne soll das Design treiben. Anders gesagt: Die Architektur und Implementierung orientieren sich konsequent an der Fachlichkeit. Da die meiste Software speziell für die Unterstützung fachlicher Prozesse implementiert wird, ist die Ausrichtung an der Fachlichkeit eigentlich eine offensichtliche Möglichkeit, um fachliche Prozesse noch besser zu unterstützen.
Kern von DDD ist die „Ubiquitous Language“ (allgegenwärtige Sprache). Diese Sprache besteht aus allen Begriffen, die Domänenexperten benutzen, wenn sie über die Domäne sprechen. Tatsächlich zeigt die Erfahrung, dass Projekte ihre ganz eigene Sprache entwickeln. Die Begriffe aus der Sprache sollen dann auch im Code und in der Datenbank genutzt werden, um Felder, Klassen, Spalten oder Tabellen zu benennen. Dadurch wird es einfacher, die Fachlichkeit in der Software umzusetzen: Die fachlichen Begriffe müssen nicht noch in andere Begriffe übersetzt werden, die bei der technischen Umsetzung genutzt werden. Damit verschwimmen die Grenzen zwischen den Modellen, die für Analyse, Implementierung und Architektur genutzt werden. Das vereinfacht Feedback über diese Modelle gerade von Domänenexperten.
DDD gibt sowohl Architekten als auch Entwicklern konkrete Techniken an die Hand, um die Fachlichkeit geschickt umzusetzen. Das ist eine wichtige Besonderheit von Domain-driven Design: Es betrachtet völlig verschiedene Ebenen wie Architektur und Code. Das strategische Design teilt ein System in grobgranulare „Bounded Contexts“ auf. Der Name „Bounded Context“ sagt schon, dass um das Begrenzen von etwas geht. Ein Bounded Context ist ein begrenzter Bereich, in dem eine „Ubiquitous Language“ definiert ist. In einer Bibliothek ist der Begriff „Buch“ für den Bounded Context „Suche“ ein Datensatz, wie man ihn früher auf eine Karteikarte geschrieben hat. Zu dem Buch gehören der Autor, der Titel oder die Schlagwörter. Für die Leihe ist das „Buch“ hingegen ein konkretes Exemplar, das ausgeliehen werden kann. Relevant ist dabei beispielsweise, ob das Buch so gut erhalten ist, dass es noch ausgeliehen werden kann. Der Begriff „Buch“ ist dabei sehr unterschiedlich definiert: Für die Suche hat ein Buch beispielsweise mehrere ISBNs, da die Druckausgabe und die eBooks unterschiedliche ISBNs haben, aber bei einem Suchergebnis zusammengefasst werden. Für die Leihe haben mehrere „Bücher“ dieselbe ISBNs. Das Buch in der Leihe ist also keineswegs identisch mit dem Buch in der Suche.
Indem die Definition auf einen Bounded Context eingeschränkt wird, kann ein Begriff wie „Buch“, der je nach Kontext oder Ansprechpartner unterschiedliche Bedeutungen hat, eindeutig definiert werden. Das erleichtert die Analyse. Gleichzeitig helfen Bounded Contexts dabei, das Software-System zu strukturieren. Jeder Bounded Context hat ein eigenes Domänenmodell. Also gibt es ein Domänenmodell für die Suche, das neben relevanten Informationen über die Bücher auch die Logik für die Suche und beispielsweise die Suchpräferenzen der Benutzer umfasst. Für die Leihe gibt es ebenso ein Domänenmodell, das Bücher im Sinne der Leihe, Ausleihen, Informationen über die Benutzer und die Logik für die Leihe enthält.
Neben dieser Aufteilung in Bounded Contexts umfasst DDD auch Techniken dafür, wie diese Domänenmodell umgesetzt werden können (Abb. 1). Dieser Bereich des taktischen Designs enthält Regeln, um ein gutes objekt-orientiertes Design zu erstellen. DDD ist also eine vollständige Architektur-Methode, die Techniken für alle Granularitätsebenen anbietet. Die Bereiche des strategischen und taktischen Designs sind nahezu unabhängig voneinander: Man muss Bounded Contexts nicht objekt-orientiert umsetzen, wie es das taktische Design vorschlägt, sondern dazu können auch funktionale Ansätze genutzt werden. Auch und gerade die funktionale Community unterstützt daher DDD, das ursprünglich aber als objekt-orientiertes Konzept gestartet ist.
Mit DDD zu guter Architektur und Implementierung
Es ist relativ klar, was eine gute Architektur auszeichnet: Lose Kopplung zwischen Modulen, hohe Kohäsion in einem Modul, Änderungen wirken sich auf möglichst wenige Module aus – die Liste lässt sich fortsetzen. Weniger klar ist, wie man zu einer solchen Architektur kommt.
Eine Möglichkeit ist, eine generische Architektur zu entwerfen, die möglichst stark von dem eigentlichen System abstrahiert. Da die Architektur generisch ist, solle sie gegenüber Änderungen relativ stabil sein. DDD predigt das Gegenteil: Die Lösung soll sich möglichst stark an der konkreten Fachlichkeiten orientieren. Es scheint so, als wäre eine DDD-Architektur daher schlecht auf zukünftige Änderungen vorbereitet, weil sie nicht abstrahiert.
Das wesentliche Problem mit zukünftigen Änderungen ist aber, dass sie schwer vorherzusagen sind. Ein generischer Ansatz kann nur dann funktionieren, wenn er gemeinsame Abstraktionen über verschiedene Änderungsszenarien umsetzt. Dazu müssen die Änderungsszenarien bekannt sein und gute Abstraktionen entwickelt werden. Das ist aber unmöglich, wenn die Änderungen nicht vorab bekannt sind – und das ist bei den meisten nicht der Fall. Daher sind Architekturen dann oft an Stellen generisch, wo das gar nicht nötig ist. Das macht die Architektur unnötig komplex. Die Generizität fehlt dann an den Stellen, wo sie dann doch benötigt wird. Dieses Problem ist kaum lösbar, weil vorab eben nicht klar ist, wo später Änderungen notwendig sein werden.
Eine konsequente Ausrichtung an der Fachlichkeit wie bei DDD kann durchaus gegen fachliche Änderungen stabil sein. Leihe und Suche werden immer ganz wesentliche Bestandteile einer Bibliothek sein. Es ist unwahrscheinlich, dass diese Aufteilung später zu einem Nachteil wird. Wenn es eine Änderung gibt, kann es sehr gut sein, dass sie auf einen dieser Bounded Contexts begrenzt ist. Wie Suche oder Leihe funktionieren sollen, wird sich eher ändern als das Zusammenspiel. So könnte es neue Suchmöglichkeiten mit neuen Attributen oder Kategorien geben. Und wenn die Fachlichkeit der Suche gut umgesetzt worden ist, sind diese Änderungen wahrscheinlich nicht schwer umzusetzen. Also ist nicht nur die Aufteilung in Bounded Contexts aus dem Strategic Design wichtig für die Änderbarkeit, sondern auch die Implementierung in den Bounded Contexts, die das taktische Design regelt.
Diese fachliche Aufteilung von DDD kann Änderungen recht einfach umsetzbar machen. So sollte eine DDD-Architektur zu einer änderbaren Architektur führen, die beispielsweise auch lose gekoppelt ist. Vor allem beschreibt DDD einen konkreten Ansatz, mit dem Teams solche Architekturen konstruieren können. Das ist wesentlich nützlicher als Techniken, mit denen man später eine Architektur nur bewerten kann. Lose Kopplung ist zwar ein Ziel, aber es ist kaum direkt erreichbar, sondern erst Konstruktionsansätze wie DDD führen zu solchen Zielen.
Vorgehensmodell
Domain-driven Design stellt also einen Architektur- und Implementierungs-Ansatz dar. Eigentlich sollte das Erstellen der Architektur unabhängig von dem Vorgehensmodell in dem Projekt sein. Die Abbildung der Fachlichkeit kann aber nur dann erfolgen, wenn es Zugang zu den Fachexperten gibt. Schließlich sind sie es, die genau wissen, wie die Domäne funktioniert. Genau dieses Wissen soll in der Software abgebildet werden. Ein Lastenheft kann dieses Wissen nur unzureichend transportieren.
DDD beschreibt daher einen Prozess des „Knowledge Crunching“, bei dem Entwickler und Domänenexperten gemeinsam an einem Modell arbeiten. Das löst das Problem der unvollständigen Anforderungen, die im Dialog geklärt werden. Aber auch ein solches agiles Vorgehen garantiert noch nicht, dass ein Modell erfolgreich erstellt wird. Dazu müssen die Entwickler nicht einfach Feature um Feature heruntercoden, sondern Wissen in ein gutes Modell verpacken und dieses Modell schrittweise weiterentwickeln. Die Domänenexperten können ein solches Modell nicht allein erstellen. Sie haben zwar das Wissen über die Domäne, aber ihnen fehlen die Modellierungstechniken. Außerdem muss ein Modell für die Implementierung in Software eindeutig sein. Ein Artefakt wie eine Klasse hat nur einen Namen und eine Beschreibung im Code. Leider sind Begriffe in der Sprache oft bei weitem nicht so eindeutig. Durch diesen Zwang zur Eindeutigkeit müssen Domänenexperten zusammen mit dem Software-Team das Modell solange weiterentwickeln, bis es eindeutig ist. Dazu müssen Begriffe aus der Ubiquitous Language geklärt werden. So führt die Erstellung der Software zu einem Lernprozess über das Wissen über die Domäne. Das ist natürlich ausgeschlossen, wenn man die fachlichen Anforderungen nur einmal aufschreibt und dann als fest betrachtet. Dann kann das Modell nicht weiterentwickelt werden und bleibt verbesserungswürdig.
Architektur und Organisation
So überschreitet Domain-driven Design die Grenze zwischen Architektur-Ansatz und Vorgehensmodell. Aber auch an einer anderen Stelle geht DDD über klassische Architektur hinaus: Bounded Contexts haben Abhängigkeiten. Wenn in der Bibliothek bei der Suche auch angezeigt werden soll, ob die Bücher aus dem Suchergebnis ausgeliehen werden können, dann muss der Bounded Context „Suche“ die Information, ob ein Buch ausgeliehen werden kann, von dem Bounded Context „Leihe“ erhalten. Eine klassische Architektur würde diese Beziehung als Abhängigkeit zwischen Modulen auffassen. Domain-driven Design stellt aber die Beziehungen zwischen den Teams, die für die jeweiligen Bounded Context verantwortlich sind, in den Vordergrund: Gibt das Team „Suche“ die Gestaltung der Schnittstelle vor oder ist es eher das Team „Leihe“? Damit verschwimmen die Grenzen zwischen einem Bounded Context als Gültigkeitsbereich einer Ubiquitous Language und einem Domänenmodell auf der einen Seite und dem Zuständigkeitsbereich eines Teams auf der anderen Seite.
DDD steht in der Tradition des Gesetzes von Conway von 1968. Dieses Gesetz stellt fest, dass die Architektur eines Systems mit den Kommunikationsstrukturen der Organisation übereinstimmt, die das System entwirft. DDD definiert Maßnahmen auf der Organisationsebene, mit denen die Architektur beeinflusst werden soll. So nutzt DDD das Gesetz von Conway aus, um die Architektur mit Hilfe der Organisation zu beeinflussen. Dieser Ansatz, Architektur und Organisation gemeinsam zu betrachten, ist im Rahmen des Microservice-Hypes wieder aktuell geworden. Der Ansatz ist notwendig, weil das Erstellen von Software ein Prozess ist, den wegen der Komplexität meistens nur ein Team bewältigen kann. Hinzu kommt, dass Teammitglieder mit Domänenexperten zusammenarbeiten müssen. Diese Kollaboration ist die wichtigste Herausforderung. Ein erfolgreiches Projekt und eine erfolgreiche Architektur können nur entstehen, wenn die Kollaboration erfolgreich ist.
DDD erfolgreich einsetzen
Aufgrund der vielen Techniken, die DDD umfasst, ist natürlich die Frage, wie man DDD erfolgreich einsetzt. Muss ein Team alle Techniken nutzen? Ist das überhaupt machbar?
Für die Beantwortung der Frage ist eine historische Betrachtung interessant: Kurz nach dem Erscheinen des ursprünglichen Buches hat sich die Diskussion im Wesentlichen auf taktisches Design und die Umsetzung von objekt-orientiertem Design mit DDD fokussiert. Damals hat dieser Teil wesentliche Probleme in einigen Projekten gelöst. Vielfach war nicht klar, wie ein gutes fachliches objekt-orientiertes Modell aussehen soll. Das strategische Design hingegen hat kaum eine Rolle gespielt. Vielleicht ist auch ein Grund dafür, dass taktisches Design am Anfang des Buchs diskutiert wird, so dass es besonders wichtig erschien und jeder vermutlich zumindest diesen Teil des Buches gelesen hat. Mittlerweile spielt das strategische Design die entscheidende Rolle, denn es beantwortet die Fragen nach einem grobgranularen fachlichen Modell und ist für die Aufteilung eines Systems in Microservices sehr wichtig.
Vermutlich stehen also je nach Problemstellungen unterschiedliche Teile von Domain-driven Design im Fokus. Allerdings bedeutet das auch, dass die Teile von DDD, die gerade nicht so relevant erscheinen, eben auch nicht beachtet werden. Das ist schade. Beispielsweise hätte das strategische Design schon viel früher genutzt werden können, um übermäßig komplexe Domänenmodell zu vermeiden, die es oft schon lange gibt. Also sollte man sich mit DDD als Ganzem auseinandersetzen, um tatsächlich den vollen Nutzen aus dem Ansatz zu ziehen.
Dazu stellt sich Frage, ob die schon diskutierten Bereiche des taktischen und strategischen Designs alles sind, was DDD zu bieten hat. Diese Frage vermeidet den Fehler, sich nur wieder auf einige Aspekte von DDD zu konzentrieren und andere zu vernachlässigen, die gegebenenfalls auch Lösungen für Probleme sein können. Dazu lohnt ein Blick in die Domain-driven Design Referenz. Sie kommt ebenfalls von Eric Evans, ist aus dem Jahr 2015 und daher aktueller als das ursprüngliche Buch. Außerdem ist sie deutlich kompakter, so dass man sie recht schnell durcharbeiten kann. Teil I der Referenz enthält Patterns für das grundlegende Vorgehen, also Ideen zum Knowledge Crunching. Teil II beschreibt die Patterns für das taktische Design. Teil IV und V erläutern strategisches Design. Der Teil III beschreibt grundlegende Praktiken für einen objekt-orientierten Entwurf und Teil IV einige Tipps für den Entwurf des Gesamtsystems. Es lohnt sich also, die Referenz durchzulesen und vielleicht gerade die Bereiche wie Teil III und IV zu lesen, die nicht zu den traditionellen Kategorien strategisches und taktisches Design gehören.
Am Ende ist DDD nur ein weiteres Werkzeug, um bessere Software zu schreiben. Es lohnt sich, DDD genauer zu betrachten, um so das Werkzeug möglichst genau kennen zu lernen. Das ist vor allem wichtig, weil Software-Entwicklung oft nicht effektiv ist, weil Konzepte nur halb verstanden oder umgesetzt werden. Aber DDD ist keine Religion, wie Eric Evans selber schon gesagt hat. Es ist also völlig in Ordnung, nur Teile von DDD zu nutzen oder die Konzepte weiterzuentwickeln. Meiner Ansicht nach ist es dafür aber notwendig, die Konzepte zu verstehen. Denn nur wenn man die Konzepte wirklich versteht, kann man sich mit ihnen fundiert auseinandersetzen und sie weiterentwickeln.
Neben den ursprünglichen Techniken aus dem Buch gibt es weitere Ansätze, die ebenfalls zu DDD gezählt werden. So beispielsweise Event Storming bei dem ein Team gemeinsam eine Domäne mit Hilfe der auftretenden Events analysiert. Auch so zeigt sich, dass DDD kein festes Verfahren ist, sondern sich weiterentwickelt, auch wenn das ursprüngliche Buch sich gegenüber der Fassung von 2004 kaum verändert hat.
Ebenso ändert sich die Implementierung von DDD: Während das ursprüngliche Buch objekt-orientierte Ansätze gezeigt hat, sind funktionale oder reactive Ansätze mittlerweile auch durchaus üblich. Auch das zeigt, dass DDD sich über die Zeit wandelt und so relevant bleibt, selbst wenn sich die technologische Basis ändert.
-
Eric Evans: Domain–driven Design: Tackling Complexity in the Heart of Software, Addison–Wesley, 2004, ISBN 978–0321125217 ↩