Montagmorgen, Sie öffnen den Kalender und stellen fest, dass zwischen den ganzen Abstimmungsmeetings mit verschiedenen Teams gar kein Platz mehr für Ihre eigentliche Arbeit ist. Sie sind Softwarearchitekt:in und entwickeln geschäftliche Software für ein Unternehmen.

Wünschen Sie sich nicht auch, mehr Zeit für die wesentlichen Dinge, wie dem Arbeiten an fachlich kniffligen Problemen? Und dennoch fließt in meiner Erfahrung eine Menge Zeit in die Abstimmung zwischen Teams.

Selbst wenn Sie bereits eine „Microservices”-Architektur mit weitgehend unabhängigen Teams anstreben, finden Sie es eventuell schwer, die Vorteile des Architekturstils auszuschöpfen. Meiner Erfahrung nach reicht es nicht nur Dinge in Container/Module zu packen. Ob wir die erwünschte Unabhängigkeit bekommen oder nicht, entscheidet sich vielmehr mit der Gestaltung der Schnittstellen.

Monolithen und Microservices

Viele Softwaresysteme, die für erfolgreiche Firmen entwickelt werden, leiden unter ihrer Größe. Eine ungeheure Menge fachlicher Funktionen wurden über die Jahre in das zentrale System eingebaut, bis es zu einem großen, unbeherrschbaren Monolithen herangewachsen ist – einem System, das nur in einer ‚Alles-oder-nichts-Manier‘ geplant, entwickelt und ausgeliefert werden kann.

Alle Versuche, ein solches System schneller auszuliefern oder weiterzuentwickeln, scheitern daran, dass alle an dem System Beteiligten auf eine gemeinsame Planung und gemeinsames Verständnis und Vorgehen bei der Weiterentwicklung dieses Systems angewiesen sind. Als Architekt:in würden wir vielleicht sagen, alle enthaltenen fachlichen Funktionen sind „stark gekoppelt“. Und das ist oft nicht nur ein Problem bei der Arbeitsteilung – häufig passiert es hier, dass die Änderung der einen Funktion an einer ganz anderen, unbeteiligten Ecke der Software, unerwünschte Seiteneffekte einführt.

Ein Gegenmittel zu diesem weit verbreiteten Problem verspricht beispielsweise der Architekturstil der „Microservices“, der im Jahr 2015 von Sam Newman im Buch „Building Microservices“ beschrieben wurde. Das Buch spricht von unabhängiger Deploybarkeit und Erweiterbarkeit und das nicht nur in kleinen, sondern auch in sehr großen, komplexen Softwaresystemen. Für viele Teams war das wohl ein Grund, diesen Architekturstil auszuprobieren und kleinere, unabhängigere Softwaresysteme anzustreben. Mal mit mehr und mal mit weniger erfolgreichen Ergebnissen. Es scheint, als fehlt einigen Implementierungen etwas ganz Entscheidendes.

Sam Newman beschreibt eine Microservices Architektur wie folgt: “Microservices sind unabhängig deploybare Dienste, die um eine geschäftliche Domäne herum modelliert sind” [1]. Interessanterweise ist in dieser Definition kein Bezug auf die Größe eines Microservices zu finden. Dennoch kommt es immer wieder vor, dass Teams, das “Micro” in Microservices als “möglichst klein” fehlinterpretieren und viele kleine Deployables bauen. Dann jedoch finden Sie sich in einer Situation wieder, in der sie eher stärker voneinander abhängig wurden, da diese vielen kleinen Deployables ein dichtes Netz aus Abhängigkeiten bilden. Folglich müssen sie ihr Deployment und ihre Entwicklungsarbeit noch sehr viel enger miteinander abstimmen. Das genaue Gegenteil von dem, was eigentlich mit dem Architekturstil bezweckt werden soll.

Ist also nichts dran am Versprechen von mehr Unabhängigkeit durch Microservices und andere fachlich geschnittene, lose gekoppelte Architekturstile? Damit Teams unabhängiger voneinander arbeiten können, ist es Voraussetzung, dass bei einer Änderung an einem Baustein, alle anderen Bausteine mit sehr hoher Wahrscheinlichkeit nicht auch geändert werden müssen. Wir sprechen hier in der Softwarearchitektur auch gerne von „loser Kopplung”. Wenn ich also für nahezu jede fachliche Änderung an meiner „Produktsuche“ z. B. den „Produktservice” auch ändern muss, haben wir ein eher stark gekoppeltes System vorliegen. Verteile ich nun diese stark gekoppelten Bausteine an verschiedene Teams, werde ich die Software nur so schnell weiterentwickeln und ändern können, wie es die Koordinationsarbeit zwischen den Teams zulässt.

Was sind Bausteine?

Was sind Bausteine?

Module, Komponenten, Systeme, Services, Microservices, Container. Leider können wir uns in der IT nicht auf weitgehend verstandene, gemeinsame Definitionen von diesen und weiteren Begriffen einigen. Deshalb ist oft unklar, wie wir unsere Werks- und Teilstücke nennen sollen, aus denen sich unsere Softwarearchitekturen auf einer sehr hohen Ebene zusammensetzen. In diesem Artikel verwenden wir deshalb inspiriert von Gernot Starke [2] durchgehend den Begriff des „Bausteins“ für etwas, was durch eine Schnittstelle von etwas anderem abgegrenzt werden kann. Die hier getroffenen Aussagen zur fachlichen Schnittstellengestaltung sind für alle gängigen Modularisierungstechniken anwendbar. Sie haben dadurch einen hohen Gestaltungsspielraum. Mit dem in diesem Artikel beschriebenen Vorgehen können Sie also genauso gut einen modularen Deployment Monolithen bauen, der aus OSGi Modulen zusammengesetzt ist, wie auch eine stark verteilte Anwendung nach dem Muster der Self-contained Systems oder Microservices, die sich aus unabhängig betriebenen Docker Containern ergibt

Falls Sie jemals einem SAFe Planning Meeting beigewohnt haben, werden Sie sich eventuell an ein Planning Board mit vielen „Schnüren” (oder im digitalen Board: Pfeilen) erinnern, dass die Abhängigkeiten zwischen den Aufgaben verschiedener Teams visualisiert. Sie blicken quasi auf das Ausmaß der Kopplung Ihrer Architektur. Was aber wäre, wenn Sie viele dieser “Schnüre” durch geschicktes Systemdesign loswerden könnten? Wenn Sie dies nicht durch besonders kleine Bausteine erreichen können, worauf kommt es dann bei einer erfolgreichen Systemarchitektur an? Die Antwort darauf finden wir im zweiten Teil von Sam Newmans Definition: Um mehr Unabhängigkeit zu erhalten, müssen wir Bausteine (wie auch Microservices) „um eine fachliche Domäne herum modellieren“. Wie genau das geht, werden wir uns nun im Rest dieses Artikels ansehen.

Fachliche Bausteine gesucht

Suchen wir nach fachlichen Bausteinen, brauchen wir erst einmal eine Idee davon, was die verschiedenen fachlichen Aktivitäten sind, die Nutzer:innen mit unserem System durchführen. Dabei kann es helfen, zunächst einen größeren Teil der Fachlichkeit mit all ihren Facetten visuell unter die Lupe zu nehmen. In der Domain-driven Design Community haben sich in den vergangenen Jahren einige verschiedene Techniken (siehe Info-Box 2 „Kollaborative Modellierung“) wie das „Big Picture Event Storming“ von Alberto Brandolini [3] oder das „Domain Storytelling“ von Henning Schwentner und Stefan Hofer entwickelt [4]. Diese Techniken helfen dabei, ein Inventar der verschiedenen fachlichen Funktionen, Regeln und Ereignisse zu erhalten. Dieses kann uns Ideen geben, wie wir die Software in verschiedene fachliche Bausteine (im Domain-driven Design sprechen wir häufig im Rahmen der Analyse von Subdomänen) zerlegen können.

Kollaborative Madellierung

Kollaborative Modellierung?

Die Modellierung von Softwaressystemen hat in den vergangenen Jahren stetig an Bedeutung verloren. Selten noch findet man modellgetriebene Ansätze in der Literatur oder in Firmen wieder. Das ist sehr schade, denn nur wenn wir gemeinsame, verständliche Modelle von unseren Softwaresystemen bauen können, können wir auch gemeinsam Entscheidungen treffen und Zielbilder formulieren, wie eine Software aufgebaut sein soll. Bei diesem Trend ist die Domain-driven Design Community eine löbliche Ausnahme. Sie hat in den vergangenen Jahren Ansätze zur Modellierung gefunden, die sich durch ihre Leichtgewichtigkeit und ihre niedrige Einstiegshürde auszeichnen, wie Domain Storytelling oder Event Storming. Vorbei sind die Zeiten, in denen wir erst eine Modellsprache (wie UML) und die damit verbundenen Tools durchdringen und erklären müssen. Wir schnappen uns ein paar Klebenotizen und los kann es gehen! Egal, ob der Hintergrund einer Person in der Fachlichkeit oder in der Technik liegt, alle können mitreden und mitentscheiden. So funktioniert moderne, kollaborative Modellierung. Wer diese Techniken einmal hautnah erleben möchte, kann auch 2024 wieder das Como Camp in Wien besuchen.

Abbildung 1 zeigt das Ergebnis einer (hypothetischen) Big Picture Event Storming Session zu einer Baufinanzierungs-Domäne, wie sie vielleicht in einer Direktbank stattgefunden haben könnte. Dabei haben wir von der Antragstellung über das Scoring des Antrages, Antragsprüfung und Kreditentscheidung verschiedene „Phasen“ und verschiedene Ausgangsmöglichkeiten des fachlichen Prozesses beschrieben. Die quadratischen, orangenen Klebezettel entsprechen dabei fachlichen Ereignissen, die an einer Zeitleiste angeordnet werden. Die rechteckigen, violetten Klebezettel entsprechen einem externen System, das wir wie eine „Blackbox“ verwenden.

Auf Grundlage dieser Modelle können wir nun beginnen, die fachlichen Abläufe zu clustern, um daraus fachlich geschnittene Bausteine zu bilden. Einige Heuristiken und Erfahrungswerte können uns dabei helfen.

Abbildung 1: Beispiel für das Ergebnis einer Event Storming Session. Mit freundlicher Genehmigung von Michael Plöd.
Abbildung 1: Beispiel für das Ergebnis einer Event Storming Session. Mit freundlicher Genehmigung von Michael Plöd.

Fachliche, stabile Abstraktion an den Schnittstellen

Einige der gefundenen fachlichen Ereignisse wurden in der Session durch einen vertikalen grauen „Balken“ hinterlegt. Diese speziellen Events nennt Alberto Brandolini in seinem Buch „Pivotal Events“ [5], denn sie markieren einen signifikanten Statusübergang, an dem sich etwas stark verändert (z. B. Nicht-finales wird final, es können Dinge fortan getan oder entschieden werden, oder es wurde eine Entscheidung gefällt etc.). Diese Events werden deshalb betont, weil sie uns Struktur geben und sich als eine fachliche Schnittstelle zwischen verschiedenen Domänen anbieten können. Per Definition markieren sie, dass etwas Vorangegangenes beendet wurde. Es ist also der ideale Zeitpunkt, um zu verstecken, wie eine bestimmte Entscheidung getroffen wurde und nur noch zu fokussieren, was das Ergebnis dieser Entscheidung ist.

Betrachten wir beispielsweise das Scoring, stellen wir fest, dass es für die darauffolgende Antragsprüfung vollkommen irrelevant ist, wie viele Regeln im Scoring ausgewertet wurden oder wie genau diese implementiert wurden. Ob das Scoring intern mit K.-o.-Kriterien und Punkten oder mit Gummibärchen und Teesatz arbeitet, ist irrelevant - alles, was zählt, ist das Ergebnis: „Pre-Scoring grün“ bzw. „Pre-Scoring rot“. Wir haben also eine fachliche Abstraktion gefunden, die uns dabei hilft, Implementierungsdetails (in diesem Fall „wie funktioniert das Scoring“) vor den nutzenden Services zu verstecken.

Im Grundstudium der Informatik wird häufig gelehrt, wie wir technische Implementierungsdetails hinter abstrakten Schnittstellen verbergen können, um Dinge wie eine konkret verwendete Hardware flexibel änderbar und austauschbar zu machen. Hier machen wir etwas Ähnliches - wir verstecken fachliche Implementierungsdetails hinter einer fachlichen Abstraktion - mit einem ähnlichen Effekt. Diese Form des Abstrahierens an Bausteingrenzen geht auf David Parnas zurück und wird von ihm „Information Hiding” genannt [6]. Genau genommen geht es aber eher darum, die Details der Implementierung zu verstecken als darum, bestimmte Daten oder Informationen zu verbergen. Die dabei entstehenden Abstraktionen sind sehr stabil, da sie sich nur selten auf inkompatible Weisen ändern. In unserem Beispiel nur dann, wenn die Fachlichkeit sich auch gravierend ändert (wie beispielsweise eine dritte Farbe zum Scoring einführen).

Leider lassen sich gute fachliche Abstraktionen nicht einfach „mechanisch“ ableiten. Manche sehr sinnvolle fachliche Abstraktionen, wie beispielsweise eine Immobilienbewertung (in Form von der Berechnung eines Markt- und Beleihwertes auf Grundlage von importierten Referenzimmobilien) lassen sich auch nicht durch das Finden von „Pivotal Events“ identifizieren. Sie sind aber eventuell für unsere Domänenexpert:innen offensichtlich sinnvoll. Es bietet sich also an, diese frühzeitig und häufig in solche Diskussionen einzubeziehen.

Manchmal finden wir dabei verschiedene attraktive Möglichkeiten, fachliche Funktionen zu kombinieren oder zu trennen. Auch hier hilft die enge Einbindung von Domänenexpert:innen in das Design, denn diese können uns in Hinsicht auf strategische Überlegungen zur Weiterentwicklung der Domäne beraten und eher abschätzen, welche Dinge sich zusammen ändern werden oder welche Aspekte in Zukunft wichtiger oder unwichtiger werden.

Nach einigen Iterationen sind wir so oft bei einer Aufteilung der Fachlichkeit angekommen, die im „Big Picture“ einfach verständlich ist und mit möglichst wenigen Interaktionen, zyklischen Abhängigkeiten punkten kann. In der Praxis verwenden wir hier häufig zur Kommunikation die Darstellung als eine Art „Domain Storytelling“, bei dem die Kandidaten für fachliche Bausteine die Rolle der „Akteure“ spielen. In der oben beschriebenen Fallstudie konnte die Aufteilung in fachliche Bausteine wie in Abbildung 2 beschrieben aussehen.

Abbildung 2: Aufteilung der Fachlichkeit in Bausteine. Mit freundlicher Genehmigung von Michael Plöd.
Abbildung 2: Aufteilung der Fachlichkeit in Bausteine. Mit freundlicher Genehmigung von Michael Plöd.

In diesem Diagramm werden die Schnittstellen zwischen den Akteuren (Gelb, klein) oder Bausteinen (Gelb, groß) sowie den externen Systemen (Pink) in Form von fachlichen „Work Objects“ beschrieben. Dabei sind fachliche Ereignisse („Domain Events“) auf orangenen „Klebezetteln“ dargestellt - in Anlehnung an unser Event Storming. Diese Events können dann beispielsweise in einem verteilten System asynchron über eine Message-oriented Middleware zwischen den Bausteinen ausgetauscht werden. Weitere ausgetauschte „Work Objects“ sind hier in Blau dargestellt. Diese könnten synchron über http transportiert werden. Die gewählte Transporttechnologie für die Daten ist hier aber zunächst noch unerheblich. Man liest das Diagramm, schließlich, indem man die Pfeile entsprechend der Nummerierung entlanggeht und jeweils Sätze mit Subjekt, Prädikat und Objekt bildet. So lautet beim Pfeil mit der Nummer 1 der entstehende Satz „Der/die Antragssteller:in füllt den Antrag aus in Antragserfassung- und Prüfung“.

Fachlichkeit im Zentrum – aber was ist mit den Daten?

Vielleicht hat es Sie überrascht, dass in dem oben dargestellten Diagramm keine Bausteine für zentrale Entitäten wie „Kunde“ oder „Vertrag“ auftauchen. Der sehr beliebte Ansatz, zentrale Entitäten der Fachlichkeit als Bausteine im Systementwurf zu verwenden, hat sich in unserer Praxis als eher hinderlich herausgestellt, insbesondere wenn eine starke Unabhängigkeit zwischen Teams angestrebt wird.

Zentrale Services, die mit der Verwaltung von weit genutzten Entitäten betraut werden, werden häufig zum Flaschenhals für alle Änderungen. Das liegt daran, dass sie statt stabilen, schmalen Schnittstellen, die Implementierungsdetails verstecken, einfach nur alles, was jemand über gewisse Entitäten gespeichert hat, „nach außen“ geben. Man könnte sagen, statt „Information Hiding“ praktizieren wir hier „Datenexhibitionismus“. Dadurch entsteht starke semantische Kopplung zwischen allen Teams, die auf zentrale Dienste zugreifen. Einige Vordenker wie Michael Nygard bezeichnen deshalb diesen Ansatz gar als AntiPattern [7]. Werden Daten an verschiedenen Stellen im fachlichen Prozess immer wieder benötigt, müssen sie deshalb über die Schnittstellen mitgegeben werden. Aber auch hier ist eine Eigenschaft der „Pivotal Events“ sehr attraktiv: Sie markieren häufig das Ende eines Subprozesses, nachdem gewisse Ergebnisse (wie in unserem Fall die „Farbe“ des Scorings) sich nicht mehr ändern werden. Diese Eigenschaft erlaubt es uns, die Daten auch an anderer Stelle (eventuell sogar zeitverzögert) redundant abzulegen und dadurch die Systeme nicht nur im Hinblick auf die Laufzeitabhängigkeit, sondern auch auf die Modelle (wie diese Daten abgelegt werden) weitgehend voneinander zu entkoppeln. Dieses Muster wird auch als „Event-Carried State Transfer“ [8] bezeichnet.

  1. Sam Newman, Monolith to Microservices, 2019  ↩

  2. Gernot Starke, Effektive Softwarearchitekturen, 2018, Seite 163  ↩

  3. Alberto Brandonlini, Introducing Event Storming (Version 2021–08–26), Seite 82  ↩

  4. Henning Schwentner, Stefan Hofer, Domain Storytelling – Gemeinschaftlich, visuell und agil zu fachlich wertvoller Software, 2023  ↩

  5. Alberto Brandonlini, Introducing Event Storming (Version 2021–08–26), Seite 82  ↩

  6. David Parnas , On the Criteria To Be Used in Decomposing Systems into Modules in: Communications of the ACM  ↩

  7. Michael Nygard, The Entity Service Antipattern  ↩

  8. Martin Fowler, What do you mean by “Event–Driven”?  ↩

Conclusion

API gut – wirklich alles gut?

Wie Sie gesehen haben, spielen Schnittstellen eine entscheidende Rolle darin, wie unabhängig Softwaresysteme weiterentwickelt werden können. Würde man alle Codebestandteile eines Softwaresystems physisch in nur ein Deployable packen, aber die Zugriffe der Bestandteile nur über wohlüberlegte Schnittstellen zulassen, hätte man viele Vorteile der losen Kopplung und der damit verbundenen Modularisierung, auch wenn alle Artefakte physikalisch nicht modularisiert wurden. Es entsteht vielmehr eine logische Trennung und logische Modularisierung, denn durch die Schnittstellen steuern wir die Unterscheidung zwischen der „Innen-“ und „Außensicht“ auf die Bausteine. Schnittstellen sind viel zu wichtig, um nur ein Nachgedanke zu sein. Das gilt insbesondere, wenn es um die Entwicklung von losen gekoppelten Bausteinen wie Microservices oder Self-contained Systems gehen soll. Viele Techniken und Ansätze des Domain-driven Designs können deshalb helfen, gemeinsam mit Domänenexpert:innen bessere Schnittstellen zu definieren und von der damit gewonnenen Unabhängigkeit maximal zu profitieren. Beispielsweise, indem Sie weniger Zeit mit der Abstimmung zwischen Teams verbringen.