Domain-driven Design: Wann sich die Methodik wirklich lohnt

Domain-driven Design ist eine Methodik, die komplexe Fachdomänen durch eine gemeinsame Sprache und klar gezogene Kontextgrenzen modelliert. Das Konzept wurde 2003 von Eric Evans geprägt und richtet die Softwarearchitektur konsequent an den fachlichen Regeln aus, nicht an der Datenbankstruktur. Der Nutzen zeigt sich schnell: weniger Missverständnisse zwischen Fachabteilung und Entwicklung, saubere Systemgrenzen und Modelle, die auch nach zwei Jahren noch verständlich sind.

Ob sich DDD für Ihr Projekt lohnt, lässt sich an drei Indikatoren festmachen:

  • Ihre Domäne hat viele Geschäftsregeln und Invarianten, die sich gegenseitig beeinflussen.
  • Mehrere Teams arbeiten an demselben System und brauchen klare Verantwortungsgrenzen.
  • Fehler in der fachlichen Logik verursachen echten wirtschaftlichen Schaden, etwa bei Abrechnungen oder Verträgen.

Trifft nichts davon zu, ist eine einfache CRUD-Architektur oft die schnellere und billigere Lösung.

Wichtige Erkenntnisse

Domain-driven Design funktioniert nur, wenn strategisches Domänenverständnis der taktischen Pattern-Implementierung konsequent vorausgeht.

Thema Details
Erst Domäne, dann Pattern Führen Sie Event Storming und Glossar-Arbeit durch, bevor Aggregates oder Repositories entstehen.
Aggregate klein halten Ziehen Sie Konsistenzgrenzen so eng wie möglich und koordinieren Sie darüber hinaus per Domain Events.
Cargo-Cult vermeiden Rechtfertigen Sie jedes taktische Muster mit einer konkreten fachlichen Regel, nicht mit einer Checkliste.
Microservice-Grenzen prüfen Schneiden Sie Services nie kleiner als ein Aggregate und nie größer als einen Bounded Context.
Aufwand realistisch abwägen Setzen Sie DDD dort ein, wo Komplexität, Teamanzahl und fachliche Kritikalität gemeinsam hoch sind.

Inhaltsverzeichnis

Was bedeutet domain driven design im Kern?

DDD steht auf sechs Grundbegriffen. Wer sie verinnerlicht, erkennt DDD-Muster in fast jedem Code, den er liest, egal ob sie explizit benannt sind oder nicht.

Die Ubiquitous Language (einheitliche Fachsprache) ist der Ausgangspunkt. Entwickler und Fachexperten benutzen exakt dieselben Begriffe, im Gespräch wie im Code. Wenn der Fachbereich von einer „stornierten Bestellung“ spricht, heißt die Klasse im Code nicht OrderState.Cancelled_v2, sondern schlicht StornierteBestellung. Diese Disziplin klingt banal, spart in der Praxis aber unzählige Übersetzungsfehler zwischen Meeting und Pull Request.

Ein Bounded Context (Kontextgrenze) markiert, wo ein Modell gilt und wo ein anderes beginnt. Der Begriff „Kunde“ bedeutet im Vertrieb etwas anderes als in der Buchhaltung. Statt ein universelles Kundenmodell zu erzwingen, bekommt jeder Kontext sein eigenes, in sich stimmiges Modell. Eine Context Map visualisiert, wie diese Grenzen zueinander stehen und wo Daten zwischen ihnen fließen.

Diagramm mit sechs zentralen DDD-Konzepten und deren Zusammenhängen

Das Aggregate definiert eine Konsistenzgrenze: eine Gruppe von Objekten, die als Einheit gespeichert und verändert wird. Jedes Aggregate hat genau eine Root-Entity, über die alle Änderungen laufen müssen. Ein Bestellaggregat lässt keine Bestellposition zu, die auf eine nicht existierende Bestellung zeigt, weil die Root diese Regel erzwingt.

Der Unterschied zwischen Entität und Wertobjekt liegt in der Identität. Eine Entität hat eine Identität, die über die Zeit erhalten bleibt, etwa ein Kunde mit fester ID, auch wenn sich Name oder Adresse ändern. Ein Wertobjekt wie ein Geldbetrag oder eine Adresse hat keine Identität. Zwei Wertobjekte mit identischem Inhalt sind austauschbar, und sie sollten unveränderlich (immutable) sein.

Domain Events (Domänenereignisse) halten fest, dass fachlich etwas Bedeutsames passiert ist, etwa BestellungVersandt oder ZahlungFehlgeschlagen. Andere Teile des Systems reagieren darauf, ohne dass das ursprüngliche Aggregate sie direkt kennen muss.

Profi-Tipp: Führen Sie ein lebendes Glossar der Ubiquitous Language, am besten direkt im Repository als Markdown-Datei. Sobald sich ein Fachbegriff ändert, muss die Änderung gleichzeitig im Glossar und im Code landen.

Microsofts Architekturleitfäden beschreiben genau diese taktischen Muster als Grundbausteine für Microservices-Architekturen, in denen jeder Service einen eigenen Bounded Context abbildet.

Was unterscheidet strategisches von taktischem DDD?

Strategisches DDD klärt, wie eine Domäne in Teilbereiche zerfällt und wie diese Teile zueinander stehen. Taktisches DDD liefert die konkreten Bausteine wie Aggregates, Repositories und Value Objects, mit denen ein einzelner Bounded Context implementiert wird. Die Reihenfolge ist kein Detail, sondern entscheidet über Erfolg oder Scheitern des ganzen Vorhabens.

Teams, die direkt mit Repositories und Aggregate-Klassen anfangen, bauen oft ein technisch elegantes Modell für eine Domäne, die niemand richtig verstanden hat. Derek Comartin beschreibt dieses Missverständnis treffend: DDD wird fälschlich als Checkliste taktischer Muster gelesen, während der eigentliche Wert im Prozess des Domänenlernens liegt. Wer diesen Schritt überspringt, bekommt zwar saubere Klassen, aber ein Modell, das die eigentlichen Geschäftsregeln verfehlt.

Die praktische Regel lautet deshalb: erst Domänenverständnis, dann Pattern. Das heißt konkret:

  • Workshops mit Fachexperten, bevor eine Zeile Code entsteht.
  • Ein geteiltes Vokabular etablieren, bevor Klassennamen festgelegt werden.
  • Bounded Contexts grob abstecken, bevor Aggregate-Grenzen gezogen werden.
  • Erst danach: taktische Muster für den ersten Kontext implementieren.

Event Storming ist dafür die wirksamste Technik. In einem moderierten Workshop sammeln Fachexperten und Entwickler gemeinsam alle relevanten Domänenereignisse auf Klebezetteln und ordnen sie chronologisch an einer Wand oder in einem digitalen Board. Pragmatische Praxisberichte zeigen, dass allein diese Übung Missverständnisse aufdeckt, die Monate später als teure Bugs aufgetaucht wären.

Wie funktionieren die wichtigsten taktischen Muster?

Sobald die Domäne grob kartiert ist, geht es an die Umsetzung. Vier Bausteine tragen dabei den Großteil der Last.

  1. Aggregate: Halten Sie es so klein wie möglich, aber so groß wie nötig, um Konsistenzregeln in einer Transaktion zu garantieren. Die Suche nach der richtigen Root-Entity beginnt bei der Frage: Welche Änderungen müssen atomar zusammen passieren? Alles, was auch getrennt konsistent bleiben kann, gehört in ein eigenes Aggregate.
  2. Entitäten und Wertobjekte: Modellieren Sie so viel wie möglich als Wertobjekt. Nur wenn ein Objekt über die Zeit verfolgt und wiedererkannt werden muss, braucht es eine Identität und wird zur Entität.
  3. Repository: Ein Repository lädt und speichert ganze Aggregate, nicht einzelne Felder. Es wird zum Problem, sobald Entwickler es als generische Datenzugriffsschicht missbrauchen und Abfragen hineinpacken, die eigentlich Domänenlogik sind.
  4. Domain Services vs. Application Services: Ein Domain Service enthält fachliche Logik, die nicht sauber in eine einzelne Entität passt, etwa eine Preisberechnung, die mehrere Aggregate berücksichtigt. Ein Application Service koordiniert dagegen nur den Ablauf, etwa Transaktionsstart, Aufruf des Repositories und Versand einer Benachrichtigung, ohne selbst Fachregeln zu enthalten.

Domain Events verbinden diese Bausteine über Aggregate-Grenzen hinweg, ohne dass ein Aggregate ein anderes direkt kennt. Ein typischer Workflow: Ein Bestellung-Aggregate wird abgeschlossen und feuert BestellungAbgeschlossen. Ein separater Handler reagiert darauf und reduziert den Lagerbestand in einem anderen Aggregate, in einer eigenen Transaktion.

Entwerfen Sie Aggregate so klein wie möglich, nur so groß, wie es die Konsistenzanforderungen tatsächlich verlangen. Nutzen Sie Domänenereignisse für die Koordination über Aggregate-Grenzen hinweg, und setzen Sie Sagas oder Orchestratoren nur dort ein, wo ein Geschäftsprozess wirklich mehrere Aggregate betrifft.

— Microsoft Learn, Tactical Domain-Driven Design

Diese letztliche Konsistenz (Eventual Consistency) ist gewöhnungsbedürftig, wer aus einer klassischen, transaktionsgetriebenen Welt kommt. Sie ist aber der Preis dafür, dass Aggregate unabhängig skalieren und sich verändern können.

Wie hilft DDD bei Microservice-Grenzen?

Die häufigste Frage bei der Aufteilung eines Monolithen lautet: Wo schneiden wir? DDD liefert dafür eine klare Faustregel statt Bauchgefühl.

Hände, die Holzklötze als Grenzen von Microservices anordnen

Ein Microservice sollte niemals kleiner als ein einzelnes Aggregate sein, sonst zerreißen Sie eine Konsistenzgrenze über Netzwerkaufrufe hinweg, was zu verteilten Transaktionen und fragilen Kompensationslogiken führt. Ein Service sollte aber auch nicht größer als ein Bounded Context sein, sonst vermischen sich mehrere fachliche Sprachen in einem Deployment und die Kopplung zwischen eigentlich unabhängigen Teams steigt wieder.

Innerhalb eines Bounded Context reichen interne Domain Events. Zwischen Kontexten braucht es dagegen explizite Integrationsereignisse, oft über ein Message Broker System wie Kafka oder RabbitMQ verteilt. Der Unterschied ist bewusst: Ein internes Event darf sein Schema jederzeit ändern, ein Integrationsereignis ist ein Vertrag mit anderen Teams und braucht Versionierung.

Für Prozesse, die mehrere Bounded Contexts betreffen, etwa eine Bestellung, die Zahlung, Versand und Lager anstößt, sind Sagas oder Event-driven-Orchestrierung das Mittel der Wahl. Wichtig dabei:

  • Jeder Bounded Context gehört genau einem Team, das seine API-Verträge eigenständig verantwortet.
  • Änderungen am internen Modell dürfen niemals ohne Versionierung nach außen durchschlagen.
  • Konsumierende Teams sollten gegen einen stabilen Vertrag testen, nicht gegen die interne Implementierung.

Wer diese Regel beim Wechsel von Monolith zu Microservices ignoriert, endet meist mit einem verteilten Monolithen, der alle Nachteile beider Welten kombiniert.

Woran erkennt man Cargo-Cult DDD und anämische Modelle?

Zwei Anti-Patterns tauchen in beinahe jedem gescheiterten DDD-Projekt auf, und beide sind gut erkennbar, wenn man weiß, wonach man sucht.

Cargo-Cult DDD bedeutet: Ein Team übernimmt Aggregates, Repositories und Value Objects, weil ein Blogartikel oder ein Kollege das empfohlen hat, ohne die eigentliche Domäne verstanden zu haben. Genau dieses Muster ist der Grund, warum manche Entwickler DDD für gescheitert erklären, obwohl eigentlich nur die mechanische Anwendung ohne Domänenlernen gescheitert ist. Die Gegenstrategie: Jedes Pattern muss eine konkrete fachliche Regel rechtfertigen. Kein Pattern „weil es DDD ist“.

Das Anemic Domain Model ist die zweite Falle: Entitäten bestehen nur aus Gettern und Settern, während die eigentliche Logik in separaten Service-Klassen liegt. Das Modell selbst kann seine eigenen Invarianten nicht mehr schützen. Die Reparatur besteht darin, Verhalten konsequent zurück in die Entität zu verschieben, etwa eine Methode stornieren() statt eines externen Services, der den Status per Setter ändert.

  • Prüfen Sie regelmäßig, ob Ihre Entitäten mehr können als nur Daten zu halten.
  • Fragen Sie bei jedem neuen Pattern: Welches konkrete Problem löst das hier?
  • Vermeiden Sie Over-Modelling für triviale Teile der Domäne genauso wie Under-Modelling für die kritischen Kernregeln.

Profi-Tipp: Führen Sie Architektur-Reviews ein, bei denen jemand aus dem Fachbereich stichprobenhaft prüft, ob der Code noch die reale Geschäftslogik widerspiegelt. Das deckt Modell-Drift früher auf als jeder Unit-Test.

Wann lohnt sich Domain-driven Design wirklich?

Nicht jedes Projekt braucht diesen Aufwand. Drei Kriterien helfen bei der Entscheidung:

  1. Komplexität der Fachregeln: Viele verschachtelte Invarianten und Ausnahmefälle sprechen für DDD, eine einfache Datenverwaltung meist nicht.
  2. Anzahl beteiligter Teams und Stakeholder: Sobald mehrere Teams an derselben Domäne arbeiten, verhindert eine klare Kontextgrenze, dass sich alle gegenseitig blockieren.
  3. Fachliche Kritikalität: Wo Fehler direkten finanziellen oder rechtlichen Schaden verursachen, etwa in Versicherungs- oder Finanzsystemen, zahlt sich die Sorgfalt aus.

Ein Versicherungssystem mit komplexen Tarifregeln, mehreren Vertragstypen und langlebigen Verträgen ist ein Lehrbuchfall für DDD. Eine interne Terminverwaltung mit fünf Feldern und einem CRUD-Formular ist es meist nicht, dort produziert DDD nur zusätzlichen Aufwand ohne Gegenwert. Praxisnahe Einschätzungen bestätigen, dass strategisches DDD besonders in Domänen wie Finanzen, Versicherung und Logistik skaliert, weil dort die Zahl der Teams und die Komplexität der Regeln gemeinsam wachsen.

Rechnen Sie den Mehraufwand für Workshops und Modellierung realistisch gegen den Wert, den ein robusteres Modell über die Lebensdauer des Systems liefert, nicht nur gegen den Aufwand des ersten Release.

Wie starten Sie in den ersten 90 Tagen mit DDD?

Der Einstieg gelingt am besten in einer festen Abfolge, nicht als Big-Bang-Umbau.

  1. Vorbereitung: Laden Sie die relevanten Fachexperten und mindestens zwei Entwickler pro betroffenem Bereich ein. Definieren Sie vorab ein klares Ziel, etwa „Wir verstehen den Bestellprozess von Anfang bis Ende“.
  2. Event Storming durchführen: Timeboxen Sie den Workshop auf zwei bis drei Stunden, moderiert von jemandem außerhalb des Kernteams. Ergebnis ist eine chronologische Wand aus Domänenereignissen, aus der sich erste Bounded Contexts und Aggregate-Kandidaten ableiten lassen.
  3. Iterative Prototypen bauen: Beginnen Sie mit dem kleinsten sinnvollen Aggregate in einem einzelnen Bounded Context, nicht mit dem gesamten System.
  4. Teststrategie festlegen: Unit-Tests prüfen die Invarianten innerhalb eines Aggregates, Contract-Tests sichern die Schnittstellen zwischen Bounded Contexts ab, Observability-Metriken decken unerwartete Konsistenzprobleme in Produktion früh auf.

Profi-Tipp: Halten Sie den ersten Prototypen bewusst klein genug, dass er in zwei Wochen live gehen kann. Ein zu großer erster Schnitt tötet den Schwung, den ein guter Event-Storming-Workshop erzeugt hat.

Wie unterstützt Outwork Teams bei Domain-driven Design?

Outwork begleitet Softwareprojekte über den gesamten Lebenszyklus, von der ersten Domänenmodellierung bis zum produktiven Betrieb komplexer CRM-, ERP- und Individuallösungen. In der Praxis heißt das: Workshops zur Domänenklärung, Architekturberatung für Bounded Contexts und die Umsetzung taktischer Muster in maßgeschneiderter Softwareentwicklung.

Für Teams, die zusätzliche Kapazität für die Umsetzung brauchen, bietet Developer Outsourcing von Outwork eine Möglichkeit, erfahrene Entwickler projektbezogen einzubinden, ohne die Domänenverantwortung an ein externes Team abzugeben.

Was die Praxis über Domain-driven Design wirklich zeigt

Die verbreitetste Fehleinschätzung zu DDD ist, es als Sammlung von Code-Patterns zu behandeln, die man in ein bestehendes Projekt einbaut wie ein neues Framework. Das greift zu kurz. Der eigentliche Hebel liegt im Event-Storming-Workshop, im Glossar, im mühsamen Aushandeln, was ein Begriff in welchem Kontext bedeutet. Aggregates und Repositories sind danach die leichtere Übung.

Konventionelle Ratgeber überbetonen oft die taktischen Muster, weil sie sich leichter in Code-Beispielen zeigen lassen als eine gute Moderationsfrage in einem Workshop. Das führt dazu, dass Teams technisch korrekte, aber fachlich hohle Modelle bauen. Und selbst wenn generierter Code durch KI-Tools künftig mehr Boilerplate übernimmt, ändert das nichts an der Notwendigkeit klarer Grenzen und Invarianten. Eher im Gegenteil: Je mehr Code automatisch entsteht, desto wichtiger wird ein Modell, das die Regeln explizit macht, statt sie implizit im Kopf eines einzelnen Entwicklers zu belassen.

Wer heute mit DDD beginnt, sollte zuerst in Moderation und Domänenwissen investieren, nicht in die perfekte Aggregate-Struktur. Der Rest folgt danach fast von selbst.

— Outwork

Quellen

Empfehlung