Über unsMediaKontaktImpressum
Nino Martincevic 22. November 2016

DDD: Context is King – Kein Context, keine Microservices

Die stetig wachsende Dynamik und Komplexität von Märkten bedingt eine schnelle und anpassungsfähige IT, sie ist in vielen Bereichen der kritische Faktor des Erfolgs. Doch ist vielerorts eine IT-Landschaft anzutreffen, die damit nicht mithalten kann. Und Technologie allein ist oftmals nicht allein der maßgebliche Erfolgsfaktor für die schnelle Anpassungsfähigkeit.

Egal ob man Microservices einsetzen oder monolithische Softwaresysteme modularer und flexibler machen möchte, um Schritt halten zu können: Ohne genaue Kenntnis der Problem- und Lösungsbereiche und vor allem ihrer Begrenzungen untereinander sind praktisch alle Ansätze wertlos.

Domain-driven Design (DDD) ist ein sehr erfolgreicher Ansatz, der die Komplexität von Software zu zähmen hilft. Im Zusammenspiel mit der agilen Softwareentwicklung bietet er mit seinen Patterns einen mächtigen Werkzeugkasten, um für die dynamische Zukunft gerüstet zu sein. Zwei der wichtigsten Werkzeuge möchte ich in diesem Artikel vorstellen.

Das Ziel: höchstmögliche Autonomie

Heutzutage gibt es praktisch kein IT- bzw. Softwaresystem (im Folgenden "System") mehr, das nicht in einem dynamischen und komplexen Umfeld operiert. Von daher sind Schnelligkeit, Anpassungsfähigkeit und die Möglichkeit, seine Ziele und Lösungen relativ einfach ändern zu können, essentiell.

Der schwerfällige zentralistische und monolithische Ansatz vieler bestehender Systeme ist nicht gut für diese Zukunft gerüstet. Vor allem deshalb nicht, weil die Vielzahl an Abhängigkeiten keine Schnelligkeit oder Anpassungsfähigkeit gewährleisten kann. Sie verhindern eine Modularisierung, unabhängige Entwicklung und Bereitstellung und sorgen immer wieder für unvorhergesehene Seiteneffekte. Von den Abhängigkeiten auf organisatorischer und fachlicher Ebene ganz zu schweigen. Sie sind sogar als wesentlich kritischer einzustufen als die verwendeten Technologien, denn viele Entscheidungen werden schon auf dieser Ebene getroffen, ohne sich ihrer Tragweite bewusst zu sein.

Aus diesen Gründen rücken Ansätze, die eine Modularisierung und Autonomisierung von Systemen anstreben, schon seit ein paar Jahren immer mehr in den Fokus: z. B. Microservices, SCS oder generell autonome Komponenten. Man versucht vor allem die Abhängigkeiten zwischen den Systemen aufzulösen oder zumindest zu minimieren und sie transparenter zu machen.

Autonomie = Autarkie?

Ein häufiges Gegenargument ist, dass man ja niemals in der Lage sein könne, vollkommene Autonomie zu erreichen. Das ist völlig richtig. Kein System, weder in der Software, noch in der "realen" Welt, ist völlig unabhängig, es gibt immer mindestens einen Bezugspunkt zu anderen Systemen.

Es geht aber nicht um Autarkie, was völliger Unabhängigkeit entspräche und die es nur theoretisch gibt, sondern um einen möglichst hohen Grad an Autonomie.

Ohne eine Anleitung, wie komplexe Systeme in kleinere und autonomere Einheiten aufzuteilen sind, wird das Vorhaben allerdings sehr schwierig oder führt mit der Zeit zu ähnlichen Systemen wie vorher. Wir benötigen also ein strategisches Werkzeug, um die Komplexität solcher Systeme beherrschbar zu machen. Da Komplexität nicht planbar ist, muss das Werkzeug auch den iterativen Ansatz in der Architektur unterstützen, so wie es Agilität in der Produktentwicklung tut.

Schnittmuster

Autonomie der einzelnen Komponenten scheint also das Hauptziel zu sein. Deshalb versuchen wir unsere Systeme in sinnvolle und autonome Einheiten aufzuteilen. Es gibt viele Möglichkeiten, ein System aufzuteilen bzw. zu "schneiden". Doch welche ist die beste oder pragmatischste, wie groß dürfen die daraus entstehenden Einzelteile sein und wie arbeiten sie in einer Anwendung zusammen?

Ganz einfach: Ask The Business!

Welchen Ansatz man auch präferiert, was man zu erreichen versucht ist:

  • Unabhängige Auslieferbarkeit,
  • Unabhängige Implementierung und damit Anpassbarkeit,
  • Unabhängigkeit von Teams und
  • Unabhängigkeit von Domänenkonzepten.

Es gibt etliche Quellen, die alle möglichen Arten von Aufteilungen und Modularisierungen anpreisen. Die meisten sind technischer Natur oder zumindest ohne Berücksichtigung der Domäne und Fachkontexte, für die sie gemacht werden. Andere orientieren sich nur an organisatorischen Gegebenheiten. Und die Verwirrung ist groß.

Es gibt ein einfaches Hilfsmittel, das dabei hilft und das man auch aus der agilen Softwareentwicklung kennt: "Ask The Business (or User)!"

Die Domäne (als der Auftraggeber des Vorhabens und der Grund, warum die Software überhaupt existieren soll) gibt vor, welche Konzepte, Prozesse, Use Cases, Zusammenhänge, Daten usw. es gibt. Weil es die Grundlage der Domäne ist und weil es in erster Linie darum geht, dass wir ein Problem dieser Domäne lösen oder ein bestimmtes Ziel erreichen wollen. Und die Software nur eine mögliche Lösung ist oder es aber viele mögliche Lösungen gibt.

Wir brauchen also einen Ansatz, der es uns ermöglicht, das Problem erst mal zu verstehen und es dann analytisch und strategisch zu erforschen und zu designen. Immer unter der Prämisse, dass es jederzeit eine Abstimmung und Kommunikation mit "der Domäne" geben muss.

DDD – und was sind Domänen?

"Für die meisten Softwareprojekte sollte der Fokus auf der jeweiligen Domäne und Domänenlogik liegen. Und das Design komplexer Domänen sollte auf Modellen aufbauen."
Diese Kernaussage von DDD kann man für die meisten Domänen noch etwas schärfer formulieren: "Wenn man ein Problem nicht ohne Software lösen kann, kann man es mit Software (meist) auch nicht."

Denn die meisten Probleme einer Domäne sind nicht wegen einer Software entstanden, es gab sie bereits vorher und sie entstehen aus der Komplexität einer Domäne. In der Regel löst Software also nicht die Probleme einer Domäne, sondern sie erleichtert deren Lösung. Zusätzlich heißt das, dass man die Ziele, Dynamiken und Prozesse einer Domäne verstehen muss, um sie mit Hilfe von IT und Software unterstützen oder verbessern zu können.

Darauf basierend entstand die Idee von Eric Evans, Softwaresysteme so zu designen, dass sie primär die Realität in den Domänen reflektieren und sie so umzusetzen, dass sie bei der Lösung der Probleme helfen. Nicht erst seit der stärkeren Verbreitung von DDD im Zuge des Microservices-Hypes war klar, dass Softwareentwicklung primär und auch dauerhaft Analyse ist. Und zwar sowohl des Problem- als auch Lösungsraums. Ersteres, um es besser zu verstehen und Letzteres, weil es immer mehrere Möglichkeiten gibt, ein einzelnes Problem zu lösen. Dass dabei oft sehr nützliche Erkenntnisse für beide Seiten entstehen, in dem z. B. auch Entwickler fehlerhafte oder nicht optimale Prozesse entdecken und lösen können, ist ein positiver Seiteneffekt.

Um Probleme finden, analysieren und sie genau beschreiben zu können, sind neben dem Verständnis der Domänen zwei Bedingungen wichtig: das Verstehen und Beschreiben in einer unmissverständlichen Sprache und ein klar definierter Kontext, in dem das Lösungsmodell gültig und die Terminologie eindeutig ist. Im Prinzip das, was bei vielen Wissenschaften schon seit Jahrhunderten angewendet wird, um komplexe Sachverhalte verstehen und prüfen zu können. Die entsprechenden Werkzeuge von DDD dazu sind Ubiquitous Language und Bounded Context.

Sie sorgen dafür, dass ein geschäftsrelevantes Konzept bzw. eine Aussage eine ganz spezifische Bedeutung in einem definierten Kontext besitzen. Dadurch wird sichergestellt, dass es keine doppelten oder missverständlichen Konzepte und Definitionen woanders im System gibt, dass diejenigen, die es verstehen und bauen müssen, wissen was zu tun ist und dass dadurch überhaupt erst ein vernünftiger Schnitt zu machen ist. Und damit höchstmögliche Autonomie erst möglich wird.

DDD bietet weitergehend noch andere strategische und taktische Hilfsmittel an, um komplexe Domänen zu designen. Für diesen Artikel (bzw. diesen Kontext…) ist dies allerdings nicht weiter wichtig. Solange wir solch eine Abgrenzung haben, die nach außen klar definiert und kommuniziert wird, können wir uns innerhalb praktisch jeglichen Ansatzes der Umsetzung bedienen.

Probleme und ihre Lösungen

In den Domains versuchen wir ein Fachkonzept mit einem Modell (Domain Model) „begreifbar“ zu machen. Und Domain Models sind, wie alle Modelle in anderen Bereichen auch, Abstraktionen und Vereinfachungen eines Problems. Sie sind aber nicht deren Lösung und sie spiegeln nicht die tatsächliche Realität wider! Die notwendige Vereinfachung eines realen Problems fällt vielen Teams oft schwer, da zu viel in ein Modell gepackt wird und es alle Use Cases behandeln soll. Doch genau darin liegt die Kunst guten Designs: Reduziere so lange, bis du nichts mehr wegnehmen kannst.
Die meisten Aufgaben- und Problembereiche der Subdomänen sind im Kern relativ stabil.
Ein Kundenservice wird sich meist um Kundenanfragen und deren Beantwortung kümmern, ein Wareneingang die Korrektheit der Lieferung überprüfen. Einzelne Regeln oder Abläufe ändern sich natürlich auch dort ständig, die grundlegenden Problemstellungen bleiben jedoch relativ stabil.

Ungleich vielfältiger sind die Möglichkeiten der Lösung eines fachlichen Problems.
Ein Kundenservice kann per Telefon, E-Mail oder Facebook die Fragen und Wünsche seiner Kunden entgegennehmen. Er kann sie nach Datum sortieren oder intelligente Algorithmen verwenden, um die Fragen nach Themen zu clustern. Oder einen automatischen Agenten mit künstlicher Intelligenz zum Beantworten entwickeln. Und vieles mehr.
Nicht nur, dass die einzelnen Subdomänen unterschiedliche Problemstellungen haben, die sie lösen müssen, sie haben zusätzlich ihre eigenen Mittel und Wege, ihre Fachsprache (Jargon, Ontologie) optimiert und wissen was gemeint ist, wenn sie einen Fachbegriff verwenden.

Keine Organisation käme auf die Idee zwei Fachbereiche zusammenzulegen, die völlig unterschiedliche Problembereiche und Lösungsmodelle besitzen. Was macht ein bemitleidenswerter Mitarbeiter eines Kundendienstes, wenn er plötzlich im Wareneingang arbeiten muss und kein Wort mehr versteht?

DDD ist keine Anweisung, wie etwas architektonisch oder technisch gestaltet werden muss. Es ist vielmehr ein analytischer Ansatz zur Gestaltung von komplexen fachlichen Zusammenhängen mit Hilfe von Modellen. Das Hauptziel ist die Gewährleistung konzeptioneller Integrität von Modellen eines fachlichen Problems. Nur wenn diese Integrität sichergestellt werden kann, d. h. alle Elemente eines Modells "an ihrem Platz sind" und alle Invarianten eingehalten werden, die einen jederzeit gültigen Zustand eines Modells garantieren, dann wird auch eine gute Implementierung möglich sein.

Domänen sind keine Kontexte

Ein häufig beobachteter Fehler bei der Anwendung von DDD im Microservices-Umfeld ist, dass Domains wie ein Bounded Context behandelt werden.

Für bestimmte Sachverhalte und Konzepte entwerfen wir Modelle, mit denen wir eine oder mehrere Aufgabenstellungen dieser lösen können, das sog. Domain Model.

Wir müssen zusätzlich einen Rahmen schaffen, in dem dieses Modell anwendbar ist. Aus diesem Grund wurde in DDD das Konzept des abgegrenzten Kontexts (Bounded Context (BC)) als ein zentrales strategisches Konzept eingeführt. Nur wenn es eine klare Abgrenzung der Anwendbarkeit eines Domain Models gibt, kann auch eine konzeptionelle Integrität gewährleistet werden.

Ein ähnliches Problem gibt es mit der Fachsprache einer Domäne. Es gibt durchaus Begriffe und Konzepte, die in der gesamten Domäne eindeutig verstanden werden. Doch es gibt auch sehr viele, die nur durch den Zusatz in welchem Kontext sie angewendet werden, eindeutig sind.

Nehmen wir das Konzept "Produkt". Selbst in einer Domäne "Handel", die sehr viel mit Produkten zu tun hat, wird sehr schnell klar, dass man sehr viele verschiedene Interpretationen dessen hat, was ein "Produkt" ist.

Einige Beispiele für "Produkt" in verschiedenen Subdomains:
Artikel, Posten, Ware, Lagerbestand, Variante, Angebot… oder Produkt.

Analog dazu für "Kunde" (Customer):
Customer, Buyer, Visitor, Debitor, User, Client, Premiumbuyer…

"Kunde" (oder Benutzer) ist ein häufiges und beliebtes Beispiel, dass gut zum Verständnis von DDD beitragen kann: Ist jemand schon ein "Kunde" wenn er den Laden betritt/die Website besucht? Oder erst nachdem er etwas gekauft hat?

Wenn es Unterschiede gibt, wie kann es dann sein, dass es nur ein Konzept für Kunde gibt, demgegenüber aber etliche unterschiedliche Use Cases und Ausprägungen? Wie kann ein einzelnes Modell des Kunden, all diesen Umständen gerecht werden? Und vor allem: Wie kann man das jemals stabil bauen, ohne ständig bei Änderungen in den Use Cases das Modell sauber und wartbar zu halten? Nicht durch Zufall werden solche Fragen bei der Ausarbeitung von Anforderungen für ein Produkt, von guten agilen Product Ownern auch gefragt.

Selbst in einer einzelnen Domäne (z. B. Einkauf) kann es mehrere Konzepte für ein Produkt geben, je nach Use Case. Man kann nun argumentieren, dass die Subdomain noch zu groß definiert ist. Oder aber man gibt dem Konzept den Kontext innerhalb der Domäne, in dem es eindeutig ist.

Eine sprachliche Eindeutigkeit kann nur in einem definierten und abgegrenzten Kontext sichergestellt werden.

Ich habe bewusst sprachlich hervorgehoben. Es kann durchaus gleiche Konzepte in verschiedenen Domänen und Kontexten geben, sie sind jedoch nicht dieselben. Die Sprache ist der erste und beste Gradmesser für die Konsistenz eines Designs. Denn wenn schon beim gemeinsamen Modellieren oder Designen von Modellen Unklarheiten bestehen, werden sie auch im System sein. Um das zu vermeiden, gibt es in DDD das Werkzeug Ubiquitous Language, es ist die Basis für den gesamten Design- und Produktlebenszyklus.

Iterative Modellierung

Im agilen Produktmanagement verfeinern wir ständig Anforderungen und ebenso werden in DDD Modelle und Kontexte kontinuierlich hinterfragt und verfeinert, umgebaut oder sogar entfernt. Dies ist ebenfalls ein iterativer und inkrementeller Prozess (Evans nennt dies "Model Exploration Whirlpool"). Nicht umsonst betrachte ich DDD als das ideale komplementäre Werkzeug für das Design von Systemen im agilen Umfeld, da beide Mindsets auf einem iterativen und empirischen Ansatz basieren.

PS: Im obigen Beispiel kann es theoretisch passieren, dass es zwei der Struktur nach identische Modelle für "Produkt" in verschiedenen Domänen gibt. Da es aber mit Sicherheit Unterschiede im Verhalten, der Umsetzung und der technischen oder nicht-funktionalen Anforderungen geben wird, sollten sie separat voneinander entwickelt werden.

Einzelne Domain Models werden in DDD in sog. Aggregaten manifestiert. Ein Aggregat ist prinzipiell eine Gruppe von Objekten, die als Einheit im Sinne einer Datenänderung und Integrität gesehen werden. Die grundlegenden Patterns dafür sind in DDD Entity und Value Object. Es sprengt den Rahmen dieses Artikels, näher darauf einzugehen, deshalb nur so viel dazu: Entity ist ein Objekt, dass über eine Identität verfügt und einen Lebenszyklus besitzt (Beispiel: Artikel mit Nummer 12562525), Value Objects sind prinzipiell nur Werte ohne Identität (Beispiel: 10 Euroschein, nicht wichtig welcher – der Wert zählt). Was Value Objects damit besonders interessant für Entwickler macht: Sie sind unveränderlich, ein Wert kann nur durch einen anderen ersetzt werden. Und damit haben sie keine Seiteneffekte und können global und beliebig oft verwendet werden.

Beispiele für zwei Iterationen eines Domain Models für "Produkt"

In der ersten Iteration gibt es nur einen Kontext (Product Context) mit zwei Aggregaten (Article und Product). Das Team erkannte jedoch nach weiteren Iterationen, dass sich beide Konzepte fachlich unabhängig voneinander entwickeln. Sie sind auch nicht voneinander abhängig im Sinne der Konsistenz der Daten. Und sie haben unterschiedliche Anforderungen an Geschwindigkeit, Datenvolumen und Änderungsfrequenz.

Daraus entwickelten sie die nächste Iteration des Modells:

Zwei Eigenschaften von Aggregaten sind dabei besonders hervorzuheben: Einzelne Elemente/Objekte eines Aggregats sind von außen nicht manipulierbar, dies geht nur über eine nach außen offene "Schnittstelle" (dem Aggregate Root). Zusätzlich verwalten Aggregate ihren Lebenszyklus selbst, von der Erstellung, der Zustandsänderung bis zur Terminierung. Zu beachten ist ferner, dass Aggregate keine Datenstrukturen sind! Sie organisieren Daten, mit Regeln und Invarianten, speichern sie aber nicht.

In der zweiten Iteration des Modells sieht man bspw., dass "Article" nur eine Referenz auf "Product" benötigt (da es nicht das Produkt beeinflusst, wenn es sich selbst ändert) und "ArticleData" eine Kopie der ursprünglichen Produktspezifikation (Specs) enthält. Da diese Value Objects sind (und damit problemlos verteilbar) ist das sehr einfach zu implementieren.

Die zweite Eigenschaft sorgt dafür, dass man eine große Freiheit bei der Implementierung hat und gleichzeitig das Modell nicht von konkreten Speichermechanismen abhängig ist.

Da ein Modell immer aus mindestens einem Aggregat besteht und einen Kontext benötigt, in dem seine Anwendbarkeit geregelt ist, gilt:

  • Der kleinstmögliche Bounded Context besteht aus einem Aggregat.
  • Der kleinstmögliche Microservice ist definiert durch einen Bounded Context mit einem Aggregat.

Endlich: Context is King!

Fassen wir zusammen, warum ein klar abgegrenzter Kontext so grundlegend wichtig ist:

Kontext
Die Umgebung, in dem ein Wort oder eine Aussage auftritt und die seine Bedeutung festlegt.

Bounded Context
Die Bedingungen, unter denen ein bestimmtes Modell definiert, klar und anwendbar ist. Primär ist der Bounded Context eine sprachliche Begrenzung. Eine Änderung in der Sprache der Domäne ist gleichzeitig eine Änderung des Modells. Innerhalb des Kontextes muss die Sprache unmissverständlich sein, und damit möglichst auch die Benennung der Artefakte wie Code, Klassen, Module, Objekte usw.

In der Zusammenfassung von Eric Evans zum Bounded Context, entfaltet sich letztendlich die ganze Spannweite und Macht des Konzepts:

"Definiere explizit einen Kontext in dem ein Modell angewendet wird. Setze explizite Grenzen bezüglich Teamorganisation, Einsatz innerhalb spezifischer Teile der Applikation und physikalischer Manifestationen, wie Codebase oder Datenbankschema. Halte das Modell unbedingt konsistent innerhalb dieser Grenzen und lass dich nicht durch äußere Aspekte ablenken oder verwirren."

Entspricht das nicht weitgehend der aktuell häufigsten Beschreibung von Microservices und einem guten Ansatz zur Organisation solcher Systeme?

In der Praxis bedeutet dies, dass ein idealer BC auch eine eigenständige technologische Umsetzung und Datenhaltung haben kann – oder sogar haben sollte. Man sollte hier pragmatisch sein und nicht jeden BC komplett mit anderen Technologien oder Sprachen gestalten, doch in Einzelfällen kann dies sinnvoll sein.

Man wird jedoch selten erfolgreich autonome Komponenten bauen können, wenn sie über eine gemeinsame Datenhaltung verfügen. Was sich schwierig anhört, ist eigentlich eher eine Chance: Das Erstellen oder Ändern von Daten ist geschäftskritisch, das Lesen dagegen fast nie. Man kann Lesevorgänge jederzeit wiederholen. Die Wiederholung eines Geschäftsvorgangs, der Daten manipuliert, ist dagegen weniger trivial bis unmöglich. Ein zu DDD oft komplementäres Pattern hierzu ist CQRS.

Ein Konzept kann zudem durchaus auch in mehreren BCs vorkommen und dies ist in der Praxis auch häufig der Fall. In der Regel handelt es sich dabei aber nur um Kopien des eigentlichen Konzepts oder Referenzen darauf. Es gibt nur einen Hüter der Wahrheit eines Konzepts, benutzen lässt es sich allerdings an vielen Stellen.

Erfahrungen aus der Praxis

Begegnet man DDD zum ersten Mal, hört sich vieles sehr theoretisch und abstrakt an. Arbeitet man jedoch eine Zeitlang mit den essentiellen Patterns, erkennt man schnell die Mächtigkeit dieses strategischen Ansatzes. Mit der Zeit bekommt man relativ schnell ein Gespür dafür, dass Konzepte nicht schlüssig sind, die Umsetzung keinen Sinn macht oder Abhängigkeiten schon im Gespräch mit der Fachlichkeit erkannt werden. Damit ist zwar nicht gewährleistet, dass ein Team auch sofort weiß, wie man es technisch konkret umsetzt. Jedoch erleichtert es auch das, da man sich nun keine Gedanken um Dinge machen muss, die sowieso nicht in den Bounded Context gehören.

Bounded Context als Architekturkonzept klingt zuerst noch einfach, oftmals sind aber einige Iterationen nötig, um Stabilität in der Context zu bekommen. Eine weitere Hürde ist es, dass man sich damit anfreunden muss, dass selbst solche architektonisch grundlegenden Elemente jederzeit anpassbar sein müssen. Vor allem, wenn man aus der relativ starren Welt von Middleware, Monolithen und zentralen Datenbanken kommt.

Abschließend möchte ich ein paar Tipps aus meiner Praxis vorstellen, damit man eine bessere Idee davon bekommt, wann und wie das alles nützlich sein kann. Und wo Fallstricke lauern.

Wo und wie anfangen?

Bei allen Domänen gibt es Bereiche, die geschäftskritisch sind. Andere werden zwar benötigt, sind jedoch unkritisch, schon vielfach erfolgreich gelöst worden oder es gibt Tools, die man dafür kaufen kann. Dann gibt es noch diejenigen, die gar einen Wettbewerbsvorteil darstellen.

Praktisch analog zum agilen Vorgehen, sollte man dort anfangen, wo der größte "Schmerz" ist, ein hohes Risiko besteht oder es den größten Nutzen und idealerweise einen echten Wettbewerbsvorteil bringt.

Solche Bereiche einer Domäne werden in DDD als Core Domain bezeichnet. Sie sind der Grund, warum man das SW-System überhaupt (selbst) entwickelt. Sie haben eine Core Domain, oder? Es ist tatsächlich so, dass es in vielen Organisation keinen solchen Grund gibt, weil das Softwaresystem oder der angeblich entscheidende Teil davon nicht der entscheidende Faktor des Geschäftserfolgs ist. Und dennoch investiert man einen enormen Aufwand in die Entwicklung...

Eine Core Domain sollte so maximal autonom wie möglich sein, vor allem geschützt gegen externe und domainfremde Einflüsse wie Technologien, Datenbanken oder auch Prozesse. Sie sollte von den besten Leuten entwickelt werden, die man hat. Die weiteren untergeordneten Domänen (Subdomains) können am Anfang noch relativ abhängig sein, doch auch unter ihnen wird es wichtigere und unwichtigere geben, sodass die nächsten Schritte zu weiteren autonomen Komponenten führen.

Legacy

Unter Legacy verstehe ich Systeme, die – aus welchen Gründen auch immer – nicht mehr schnell oder sicher genug geändert oder gepflegt werden können. In der Realität sind die Abgrenzungen meist nicht so eindeutig bestimmbar. Vor allem beim Umbau von Altsystemen (Legacy) findet oder erkennt man, wenn überhaupt, Abgrenzungen, die ungefähr so aussehen wie in Abb.8.

Es ist natürlich viel Arbeit, so einen Monolithen (oder Big Ball of Mud) zu entflechten. Aber dauerhaft wird man nur Erfolg haben, wenn die Abgrenzungen nach und nach schärfer und genauer werden. Das Vorgehen ist analog zu der Arbeitsweise bei der Domain-Modellierung: Man kann relativ grob anfangen und die Modelle nach und nach verbessern. Auf der Ebene eines Gesamtsystems ist das zwar meist mit einem hohen Aufwand verbunden, die Alternative ist jedoch ein neues Legacy-System, also noch schlimmer [1].

Damit man bei einer Vielzahl von entstehenden Kontexten und ihren Beziehungen zueinander nicht den Überblick verliert, gibt es das einfache aber wirkungsvolle Werkzeug Context Map.

Wie organisiert man das alles?

Da ein Bounded Context eine Abgrenzung einer spezifischen Lösung eines Domänenproblems ist, sollte er auch genau von einem Team entwickelt werden. Und zwar in einem kompletten vertikalen Schnitt. Ein Team kann durchaus mehrere solcher Komponenten entwickeln, aber auf keinen Fall sollte eine davon auf mehrere Teams verteilt werden.

Die Übersicht – vor allem über die technischen und noch viel wichtiger: die organisatorischen Beziehungen und Abhängigkeiten – werden in DDD in einer sog. Context Map visualisiert. Ein Team kann, wie bei normalen Karten, verschiedene Maßstäbe benutzen oder auch zusätzliche Elemente darstellen, wie z. B. die Richtung der Abhängigkeit, die Art der technischen Umsetzung der Kommunikation untereinander oder die Kritikalität. Es gibt dabei verschiedene Arten der Beziehungen, die mehr oder minder aufwändig umzusetzen und zu organisieren sind.

In dem Beispiel ist die Beziehung zwischen dem Optimal Aquisition und dem Prizing Context ein BC Pattern Partnership. Das bedeutet, dass sich beide Team abstimmen, wenn sie etwas ändern, was den jeweils anderen Kontext beeinflussen könnte. Im Prinzip planen sie ihr Vorgehen gemeinsam und entwickeln parallel.

Eine weniger freundliche Beziehung besteht zwischen Inventory und ERP. Dieser in der Praxis häufig vorkommende Fall, dass Alt- oder Fremdsysteme angebunden werden müssen, bedarf besonderer Sorgfalt. Da diese Systeme i. d. R. nicht von uns geändert werden können, müssen wir Mechanismen einführen, die eine "Beschädigung" unseres Kontexts verhindern. Wenn sich dort etwas ändert. Und umgekehrt sind wir oft dazu gezwungen, bestimmte Vorgaben dieser Systeme zu übernehmen. Im Idealfall bauen wir uns einen sog. Anti-corruption Layer (ACL) vor unseren Kontext. Er ist eine Art Übersetzer zwischen den verschiedenen Welten und sorgt dafür, dass unser Domain Model sauber und geschützt gegen diese äußeren Einflüsse bleibt [1].

Diese Karte wird vom gesamten Produktteam regelmäßig gepflegt, denn natürlich kann sich global auch ständig etwas ändern oder die Beziehungen verschieben sich. Sie ist in der Regel aber eine relativ einfache und dennoch mächtige Möglichkeit, den Gesamtüberblick zu behalten. Und auf die Gegebenheiten zu reagieren oder sie zu gestalten.

Fazit

Die Welt wird immer komplexer und die Software, die viele Branchen unterstützt, mindestens ebenso. Es genügt nicht mehr mit den alten Werkzeugen zu arbeiten, um dauerhaft mithalten zu können. Nicht umsonst trat Agile so einen enormen Siegeszug an, in dem es die Ziele, Zusammenhänge und die Lösungen eines Produkts iterativ und inkrementell etwas beherrschbarer macht. Immer mit dem Fokus auf kleine Schritte und schnelles Feedback. Und vor allem das allgemeine Verständnis der Domäne durch alle Beteiligten.

Dies halte ich auf der Umsetzungsseite für mindestens genauso wichtig. Und dieses agile Vorgehen wird sehr gut durch DDD und seinen wichtigsten strategischen Werkzeugen unterstützt.

Inzwischen gibt es kein System mehr, dass nicht komplex ist. Mindestens deshalb, weil sein Umfeld komplex geworden ist. Aus diesem Grund empfehle ich grundsätzlich bei jedem Vorhaben, bei der Planung und Strategie DDD als Werkzeug einzusetzen, idealerweise in Kombination mit Agilität.

Ob man das System danach mit den taktischen Patterns von DDD weiterentwickelt, ist dabei völlig irrelevant. Im Gegenteil, DDD ist dazu völlig agnostisch, selbst gegenüber seinen eigenen Patterns (was nicht heißt, dass man sie nicht trotzdem mal genauer anschauen sollte). Sich mit Ubiquitous Language und Bounded Context zu beschäftigen und es anzuwenden, kann ich grundsätzlich für jedes Vorhaben empfehlen.

Quellen
  1. Nino Martincevic: legacy.org => agile.org

Autor

Nino Martincevic

Nino Martincevic ist ein radikaler agiler Problemlöser der codecentric AG aus Solingen. Sein Fokus liegt auf einem holistischen Ansatz der agilen Softwareentwicklung für die erfolgreiche Umsetzung und die Schließung der immer...
>> Weiterlesen
botMessage_toctoc_comments_9210