Was DDD ist — und was nicht
Domain-Driven Design (DDD) ist eine Herangehensweise an Softwareentwicklung, die die fachliche Domäne in den Mittelpunkt stellt — nicht das Framework, nicht die Datenbank, nicht das UI-Pattern. Eric Evans hat den Ansatz 2003 in „Domain-Driven Design: Tackling Complexity in the Heart of Software" geprägt. Zwei Jahrzehnte später ist DDD weniger ein Methodensatz als ein Denkrahmen, der drei Disziplinen zusammenbringt.
Erstens: eine gemeinsame Sprache zwischen Fachbereich und Entwicklung — Evans nennt sie die Ubiquitous Language. Begriffe, die im Geschäft vorkommen, kommen exakt so im Code vor. Ein „Vertrag" im Fachgespräch ist ein Vertrag im Code, nicht ein ContractRecord oder eine ContractDTO. Klingt trivial, ist es nicht: Wenn Fachbegriffe in der Übersetzung in den Code verschoben werden, wandern sie wieder zurück — in Form von Bugs, Missverständnissen und Spezifikationen, die niemand mehr versteht.
Zweitens: explizite Modelle, die die Domäne abbilden — nicht die Datenbank. Ein gutes Modell beschreibt, was ein Vertrag tut, welche Zustände er hat und welche Regeln gelten. Ein schlechtes Modell beschreibt, wie er gespeichert wird.
Drittens: eine Struktur, die Komplexität trennt. Wenige Systeme bestehen aus einer einzigen Domäne. Banken haben Kreditrisiko, Zahlungsverkehr und Beschwerdemanagement — alle drei haben eigene Sprachen, eigene Regeln, eigene Lebenszyklen. DDD bietet die Werkzeuge, diese Trennung sichtbar zu machen, statt sie zu verstecken.
DDD ist dabei kein Framework und kein Vorgehensmodell. Es ersetzt weder Scrum noch Microservices, weder TDD noch Hexagonale Architektur. Es ist orthogonal: Man kann mit oder ohne DDD agil arbeiten, monolithisch oder verteilt bauen. Aber wer einmal in einer Codebasis ohne DDD-Disziplin gearbeitet hat, kennt das Gefühl, dass „irgendwo etwas nicht stimmt" — und genau dort setzt DDD an.
Strategisches Design — wo die Grenzen verlaufen
Strategisches DDD beantwortet die Frage: Wie schneiden wir das Gesamtsystem? Drei Konzepte tragen die Antwort.
Bounded Context
Ein Bounded Context ist ein abgegrenzter Bereich, in dem ein Modell konsistent gilt. Innerhalb des Kontexts hat jeder Begriff genau eine Bedeutung. Außerhalb darf derselbe Begriff etwas anderes meinen — und das ist gewollt. Ein „Kunde" im Vertrieb (Lead, potenzielle Person) ist ein anderer „Kunde" als im Forderungsmanagement (Schuldner mit offener Rechnung). Beide existieren legitim, aber sie gehören in unterschiedliche Kontexte. Wer versucht, sie in einer einzigen Klasse zu vereinen, baut sich ein Monster, das beiden Bereichen wehtut.
Context Map
Eine Context Map zeigt die Beziehungen zwischen Bounded Contexts. Welcher Kontext schickt Daten an welchen? Wer ist Lieferant, wer ist Konsument? Welche Verträge gelten? Typische Beziehungsformen sind Shared Kernel (gemeinsames Kern-Modell), Customer-Supplier (Lieferant verpflichtet sich gegenüber dem Konsumenten), Conformist (Konsument muss nehmen, was kommt) und Anti-Corruption Layer (Übersetzungsschicht, damit fremde Modelle nicht eindringen).
Subdomains
Drei Arten von Subdomänen helfen, Investitionen zu priorisieren:
- Core Domain — das, womit das Unternehmen sich differenziert. Hier lohnt sich die meiste Sorgfalt, hier wird selbst gebaut.
- Supporting Subdomain — nötig, aber kein Differenzierungsmerkmal. Kann gebaut, kann zugekauft werden.
- Generic Subdomain — alle haben das (Authentifizierung, Logging, Rechnungsversand). Hier kauft oder integriert man Standardprodukte.
Wer in der Generic Subdomain selbst entwickelt, verbrennt Geld. Wer in der Core Domain zukauft, gibt seine Differenzierung auf. Die Klassifikation ist der erste Schritt jeder DDD-Strategie — und sie sollte nicht von der Entwicklung allein getroffen werden, sondern gemeinsam mit dem Management.
Taktisches Design — die Bausteine im Modell
Innerhalb eines Bounded Contexts liefert das taktische DDD die Bausteine, mit denen das Domänenmodell formuliert wird. Sechs Bausteine genügen, um den weit überwiegenden Teil aller Fälle abzudecken:
- Entity — ein Objekt mit Identität, die über die Zeit bestehen bleibt. Ein
Vertrag mit der Nummer V-2025-0042 ist eine Entity — selbst wenn alle seine Felder sich ändern, bleibt er derselbe Vertrag. - Value Object — ein Objekt ohne eigene Identität, definiert durch seine Werte. Ein
Geldbetrag von „120,50 EUR" ist ein Value Object; zwei Beträge mit identischen Werten sind ununterscheidbar. Value Objects sind unveränderlich (immutable); Änderung heißt: neues Value Object. - Aggregate — eine Gruppe von Entities und Value Objects, die als Einheit behandelt wird, mit genau einer Aggregate Root als Zugriffspunkt. Beispiel:
Bestellung ist die Root, Bestellpositionen gehören dazu, aber niemand greift direkt auf sie zu. Die Aggregate-Grenze schützt Konsistenz: Geschäftsregeln gelten innerhalb, zwischen Aggregaten arbeitet man mit Eventual Consistency. - Domain Event — etwas Fachliches ist passiert:
VertragGeschlossen, ZahlungEingegangen, BerechtigungEntzogen. Events sind unveränderliche Fakten; andere Bounded Contexts reagieren auf sie, ohne den ursprünglichen Kontext kennen zu müssen. - Repository — eine Abstraktion für das Laden und Speichern von Aggregates. Aus Sicht des Domänenmodells ist ein Repository eine Sammlung; dass darunter eine SQL-Datenbank, ein Event Store oder ein REST-API liegt, ist Infrastruktur, nicht Domäne.
- Domain Service — Logik, die nicht natürlich an eine Entity gehört. Beispiel: ein
PreisRechner, der Rabatte über mehrere Verträge hinweg anwendet. Vorsicht: Domain Services sind ein Ausweichgleis — wer zu viele baut, schiebt Logik aus den Entities heraus und landet beim anämischen Domänenmodell (siehe Stolpersteine).
Bausteine im Code
Wie das in der Praxis aussieht, zeigt ein knappes TypeScript-Beispiel — ein unveränderliches Value Object und eine Entity mit geschäftlicher Methode:
class Geldbetrag {
constructor(
readonly betrag: number,
readonly waehrung: 'EUR' | 'USD' | 'CHF'
) {}
addieren(other: Geldbetrag): Geldbetrag {
if (this.waehrung !== other.waehrung) {
throw new Error('Waehrungen unvereinbar');
}
return new Geldbetrag(this.betrag + other.betrag, this.waehrung);
}
}
class Vertrag {
constructor(
readonly id: VertragNummer,
private status: VertragStatus
) {}
abschliessen(): void {
if (this.status !== 'entwurf') {
throw new Error('Nur Entwürfe sind abschließbar');
}
this.status = 'aktiv';
}
}Das entscheidende Merkmal sieht man in der Methode abschliessen: Die Geschäftsregel („nur Entwürfe sind abschließbar") sitzt dort, wo der Zustand sitzt — nicht in einer Service-Klasse irgendwo daneben. Genau diese Verlagerung von Verhalten zur Entity unterscheidet ein lebendes Domänenmodell von einer datenstruktur-artigen Hülle.
Wie ein Modell entsteht
Wie kommt man zu einem Modell? Zwei Workshop-Methoden haben sich in Projekten bewährt und ergänzen einander — die Wahl hängt vom Charakter der Domäne ab.
Event Storming
Alberto Brandolini hat Event Storming als Workshop-Format entwickelt. Eine Gruppe aus Fachleuten und Entwicklern klebt orange Haftnotizen mit Domain Events („Bestellung aufgegeben", „Zahlung empfangen", „Mahnung erzeugt") chronologisch an eine Wand. Anschließend werden Kommandos, Akteure, Policies und Aggregate ergänzt. Das Ergebnis: ein gemeinsames Bild des Geschäfts in zwei bis vier Stunden. Wichtig: Es geht nicht um das System, das gebaut werden soll, sondern um das Geschäft, das stattfindet — egal mit welcher Technologie.
Domain Storytelling
Stefan Hofer und Henning Schwentner haben Domain Storytelling als Alternative geprägt. Hier erzählen Fachleute konkrete Geschichten („Wenn ein Antrag eingeht, prüft die Sachbearbeiterin zuerst …"), während ein Moderator sie als Pictogramme visualisiert. Die Methode ist langsamer als Event Storming, aber besser geeignet, wenn das Geschäft aus vielen sequenziellen Prozessen besteht — typischerweise in der öffentlichen Verwaltung.
Beide Methoden teilen einen Kern: Das Modell entsteht im Dialog, nicht im stillen Kämmerlein. Wer DDD versucht, ohne den Fachbereich an einen Tisch zu holen, bekommt am Ende ein Entwicklermodell — das im ersten Workshop mit dem Fachbereich wieder umgeschrieben wird.
Praxis-HinweisDer häufigste Fehler in DDD-Workshops ist es, zu früh über Technologie zu sprechen. Sobald Begriffe wie „Service", „Microservice" oder „Datenbank" fallen, kippt das Gespräch von der Domäne in die Architektur. Halten Sie den ersten Workshop technologiefrei — alles, was es braucht, sind Stifte, Klebezettel und eine leere Wand.
Stolpersteine in der Praxis
Vier Anti-Patterns treten in DDD-Projekten besonders häufig auf — und sie sind die häufigste Quelle für Enttäuschungen mit der Methode.
- Anämisches Domänenmodell. Entities ohne Verhalten — nur Datenstrukturen, deren Logik in Services ausgelagert ist. Resultat: prozeduraler Code mit objektorientierter Verkleidung. Heilmittel: Wenn eine Geschäftsregel an einer Entity gilt, gehört sie als Methode dorthin. Ein Vertrag, der sich nicht selbst abschließen kann, ist kein Vertrag — er ist eine Tabelle.
- Verteilter Monolith. Bounded Contexts als Microservices implementiert, aber synchron über REST gekoppelt. Jeder Service ruft jeden anderen. Resultat: alle Nachteile verteilter Systeme, keiner der Vorteile. Heilmittel: zwischen Kontexten asynchron, über Events. Synchron nur als bewusste Ausnahme, nicht als Default.
- Verfrühtes DDD. Auf einem Prototyp oder einem Drei-Tabellen-CRUD wird das volle DDD-Repertoire angewendet — Aggregates, Domain Events, CQRS. Resultat: drei Wochen Architektur, eine Woche Funktion. Heilmittel: DDD lohnt sich, wenn fachliche Komplexität vorhanden ist. Bei trivialen Apps reicht ein schlanker Layered Approach.
- Rein technisches DDD. Das Team kennt die taktischen Patterns (Entity, Value Object, Repository), aber niemand spricht mit dem Fachbereich. Resultat: ein hübsches Modell, das das Geschäft falsch beschreibt. Heilmittel: Ubiquitous Language ist nicht optional — sie ist die Eintrittskarte zur Methode.
Wann sich DDD lohnt — und was das für Low-Code bedeutet
DDD lohnt sich nicht für jeden Anwendungsfall. Eine ehrliche Einordnung — und ein Hinweis darauf, warum gerade die Verbindung zu Low-Code-Plattformen unterschätzt wird.
Klar lohnenswert:
- Komplexe fachliche Domänen mit vielen Regeln, Sonderfällen und langlebigen Workflows — typisch in Banken, Versicherungen, Energieversorgung und öffentlicher Verwaltung.
- Systeme, die über Jahre weiterentwickelt werden und in denen das Fachwissen die wichtigste Investition ist — Software, die mehrere Generationen von Entwicklern überdauert.
- Plattformen mit mehreren Teams, die unabhängig arbeiten sollen. Bounded Contexts geben jedem Team einen klaren Hoheitsbereich und reduzieren Koordinationsaufwand spürbar.
Kaum lohnenswert:
- Einfache CRUD-Anwendungen — wer 80 Prozent der Zeit Formulare über Tabellen schreibt, braucht keine Aggregates.
- Wegwerf-Prototypen. DDD ist eine Investition; auf zwei Wochen Projektdauer rentiert sie sich nicht.
- Technische Werkzeuge ohne Fachbezug (Build-Tools, Linter, Monitoring-Dashboards). Hier ist die „Domäne" technisch, nicht geschäftlich.
Im Low-Code-Kontext: DDD und Low-Code passen besser zusammen, als es auf den ersten Blick wirkt. Eine reife Low-Code-Plattform spricht in den Begriffen des Fachbereichs — also in der Ubiquitous Language. Wer eine solche Plattform aufbaut, modelliert nicht zufällig Entities, Value Objects und Aggregate; er gibt seinen Anwendern genau diese Bausteine in die Hand, nur ohne den Begriff zu nennen. Umgekehrt gilt: Eine Low-Code-Plattform, die ihre eigene Architektur nicht entlang Bounded Contexts strukturiert, wird ab einer mittleren Größe unwartbar — die Module verwischen, dieselben Begriffe meinen plötzlich Unterschiedliches, und jeder Release wird zur Rätselrunde. Wir behandeln DDD in unseren Low-Code-Lösungen deshalb nicht als optionale Theorie, sondern als Konstruktionsprinzip — sichtbar im Modul-Schnitt, in der Modellierungs-UI und in der Art, wie Domain Events zwischen Modulen fließen.
EmpfehlungWir starten DDD-Projekte selten mit dem vollen taktischen Repertoire. Den ersten Workshop investieren wir in Event Storming oder Domain Storytelling — das Ergebnis ist eine Sprache, ein Modell und eine grobe Kontextkarte. Auf dieser Basis entscheiden wir, welche Aggregate sich lohnen, welche Bounded Contexts welchen Detailgrad bekommen und wo ein schlanker CRUD-Service ehrlicher ist als eine Aggregate-Konstruktion. DDD wirkt am besten, wenn es selektiv eingesetzt wird — und genau dort, wo die Komplexität es verdient.