Ein paar Gedanken zum Entwurf von Aggregaten

Nein, das ist kein Bild von Gipf-Oberfrick sondern...
Beitrag erstellt am: 17.03.23
TL;DR: Verbs are more important then nouns. Put together what changes together.
Eine der offensichtlich schwierigsten Dinge im taktischen DDD scheint der Entwurf guter Aggregate. Als Domain Architect habe ich gerade zu Beginn meiner Tätigkeit bei Digitec Galaxus viele Fragen zu diesem Thema erhalten.

Keine Angst: das wird kein ausufernder Artikel zu einem vielfach behandeltem Thema, an dessen Ende der Eindruck zurück bleibt, die Antwort falle einmal mehr in die bei Architekten so beliebte Kategorie "Es kommt darauf an", die einen oft doch eher ratlos zurück lässt.

Ich schicke voraus, dass ich in meinen eigenen Projekten schon seit längerem auf eigentliche Aggregate mittels DDD-Entities verzichte. Ich nutze stattdessen einen Ansatz, der konsequent auf CQRS und dem Metamodell von Event Modeling basiert: ich modelliere die Systeme mittels Lesemodellen, Kommandos und Ereignissen als eine Abfolge von Slices. Die Kommandos als Aufforderung für eine Zustandsänderung sind hierbei der Ort der Konsistenzprüfung: das Kommando ist nur erfolgreich, wenn die geltenden Invarianten erfüllt sind, ansonsten scheitert es. Mittlerweile setze ich Kommandos zudem als seiteneffektfreie Berechnungen um (Functional Core) und delegiere die darauf basierenden Seiteneffekte in entsprechende Adapter (Imperative Shell), doch das nur am Rande.
Gute Aggregate sind klein! Diese Aussage hören und lesen wir häufig. Wirklich hilfreich ist sie nicht, denn wann ist klein klein genug und auf welche Dimension genau bezieht sich diese Grössenbewertung: Die Zahl von Eigenschaften, die Menge involvierter Objekte, oder die Anzahl von Regeln, die das Aggregat einfängt?

Besinnen wir uns darauf, was ein Aggregat ist: Ein Konsistenzrahmen für transaktionale Änderungen zusammengehöriger Daten.  Hierzu definiert das Aggregat sog. Invarianten, die stets gültig sein müssen. D.h. keine Änderung darf je zu einem ungültigem Zustand führen, bei dem die Daten in sich nicht konsistent sind. So einfach, so mächtig und so schwierig.

Daher biete ich hier eine andere Betrachtung, die sich zumindest in meiner Arbeit als hilfreich erwiesen hat:

Verben sind wichtiger als Substantive!

Für Aggregate bedeutet dies: Ein gutes Aggregat fokussiert auf das fachliche Verhalten und nicht auf dessen strukturellen Aspekte (Attribute einer Klasse oder Felder einer Tabelle).
Wir beginnen also nicht mit der Frage, welche Eigenschaften beispielsweise ein Kunde in unserem System hat, sondern damit zu verstehen, was wir mit einem Kunden in einem bestimmten fachlichen Szenario tun:
  • Namen und Adressdaten verwalten
  • Altersfreigabe für bestimmte Inhalte überprüfen
  • Zahlungsart hinterlegen
  • Lieferadresse für Bestellung ändern
  • Kontaktdaten für Supportanfrage auswählen
Genau das meine ich, wenn ich sage: Verben sind wichtiger als Substantive. Um beim Beispiel des Kunden zu bleiben: Das Bestimmen einer Kreditlimite für einen Kunden benötigt andere Informationen und Konsistenzregeln als beispielsweise das Ändern des Nachnamens aufgrund einer Heirat oder das Korrigieren eines Schreibfehlers im Vornamen.

Naiver Aggregatsentwurf schaut auf den Kunden als strukturelle Einheit und ignoriert das Verhalten zumindest anfangs fast vollständig - das ist die schlechteste wenn auch recht verbreitete Variante klassenbasierter Entwürfe. Das war übrigens nicht immer so: Die älteren Semester unter uns mögen sich an die CRC-Karten erinnern, die das Verhalten und die Kollaborationen ins Zentrum stellten, anstatt auf die Strukturen zu fokussieren. Mit der zunehmenden Popularität von O/R-Mappern geriet diese Betrachtung leider mehr und mehr in den Hintergrund - CRUD und blutleere Domänenmodelle waren eine der Folgen, die bis heute nachwirken.  

Jedenfalls entstehen so Aggregate, die sich um mehr als einen Belang kümmern, weil der Fokus auf die strukturellen Aspekte die fachlich unterschiedlichen Belange vernebelt: Es gibt die Abstraktion Kunde, jeder Kunde hat gewisse Eigenschaften, die für bestimmte Dinge nötig sind, die wir tun müssen. Kommt dann noch Vererbung ins Spiel, um beispielsweise verschiedene Kundenarten zu unterscheiden, ist der Nutzen klar geschnittener Aggregate vollends verloren gegangen.

Die Trennung der Verantwortlichkeiten entlang des Verhaltens ist gerade für manche OO-Entwickler nicht offensichtlich und alles andere als eingängig. Eine Frage, die helfen kann, die Schwächen des strukturellen Fokus aufzudecken wäre im Fall des Kunden z.B. folgende: Bekommt der Kunde ein anderes Kreditlimit, wenn wir einen Schreibfehler in seinem Vornamen korrigieren? Die Frage ist absurd und genau deshalb hilfreich: Es wird offensichtlich, dass die Konsistenzregeln für das Kreditlimit des Kunden nichts mit dem Vornamen zu tun haben und daher mit Fokus auf das fachliche Verhalten nicht zusammen in einem Aggregat verwaltet werden sollten.

Und für alle, die versuchen, in einem bestehenden System, das auf einem vorhandenen meist relationalen Datenbankschema fusst, fachliche Domänenmodelle mit Hilfe von Aggregaten aufzubauen: Das wird nicht funktionieren! Aus den vorgenannten Gründen! Es wird kaum möglich sein, die Aggregate fachlich korrekt zu schneiden, da die darunter liegende Datenstruktur zu breit und eben nicht darauf vorbereitet ist, Datenänderungen entlang des fachlichen Verhaltens zu verarbeiten. In der Folge kommt es zu überlappenden Aggregaten im Code. Es gibt Wege damit umzugehen, doch ist ein Thema für einen eigenen Beitrag.

Fazit: Erfolgreicher Aggregatsentwurf heisst: Konsequenter Fokus auf das fachliche Verhalten, die Verben.

Tun wir dies konsequent, erhalten wir Aggregate, die tatsächlich klein sind, oder anders formuliert, die über hohe Kohäsion verfügen, weil die Dinge, die zusammen aus den gleichen Grund ändern, zusammen sind - put together what changes together.