Besser wär’s – Software-Architektur gemeinsam gestalten
von Maximilian AulingerDas Dilemma
Die Liste der „berühmten letzten Worte“ ist lang, einer ihrer vielen Einträge lautet nach meiner Erfahrung: „Bewusste Architekturentscheidungen? Machen wir nicht, wir sind ja agil“. Das mag im ersten Moment plausibel klingen. Agile Entwicklung ist iterativ-inkrementell und setzt auf kurze Feedbackzyklen. Architekturentscheidungen kommen, um zu bleiben. Das passt auf den ersten Blick nicht zusammen. Auf den Zweiten schon.
Bewusste Architekturentscheidungen, vom gesamten Team aus einem gemeinsamen Verständnis heraus getroffen, sind meiner Ansicht nach unverzichtbar. Weil unklare (Teil-)System- oder Modulverantwortungen schnell zu einem Wildwuchs werden, der einer steigenden Zahl von Bugs den perfekten Lebensraum bietet. Systemerweiterungen erweisen sich im günstigeren Fall als immer komplexer und im ungünstigeren als unbeherrschbar. Unsauber umgesetzte Architektur ist mit einem sehr hohen Risiko verbunden, eventuell kann das System die Bedürfnisse der Endkunden gar nicht erfüllen. Vielleicht sprengen auch die Kosten für die Weiterentwicklung und den Betrieb den ökonomisch sinnvollen Rahmen.
Bliebe als nur, die einmal getroffenen Architekturentscheidungen zu revidieren. Doch das ist seinerseits extrem teuer, umso mehr, als die Kosten oft nicht ausreichend gerechtfertigt werden können. Denn dazu wäre es erforderlich, den direkten Zusammenhang zwischen der Architektur hier und dem Problem dort zu beweisen. Was so linear meistens nicht geht.
Die Krux ist, dass sich die Auswirkung einer Architekturentscheidung meistens erst nach einigen Iterationen zeigt. Wie kann ein agiles Team also zu Entscheidungen kommen, die eine gute Grundlage haben, von allen gleich verstanden werden und daher auch ihren Weg in den Code finden?
Drei Experimente
Wenn es keine feste Blaupause für ein Vorgehen gibt, dann können Experimente helfen. Die folgenden Drei beziehen sich jeweils auf einen der Schritte im Umgang mit Architekturen:
- Entscheidbar machen: Mögliche Entscheidungen identifizieren
- Fundiert entscheiden: valide Informationen über verschiedene Optionen gewinnen
- Verständnis schaffen: Entscheidung kommunizieren und verstehen
Experiment eins: Das 2-Phasen Refinement
Die logische Grundlage jeder Architekturentscheidung sind die fachlichen Anforderungen und Wünsche an das System. Wobei wir davon ausgehen, dass sie sich zwar partiell ändern, aber nicht vollständig, sonst wäre dieses System in dieser Form ohnehin sinnlos. Damit rückt genau eine Frage in den Vordergrund: Welches Problem soll unser System lösen? Die Antwort darauf bildet die perfekte Basis für Architekturentscheidungen.
Abbildung 1: 2-Phasen-Refinement
Nun gehört es zum agilen Vorgehen im Refinement, im „hier“ und „jetzt“ verhaftet zu sein und sich auf das zu konzentrieren, was als Nächstes umgesetzt werden soll. Dennoch spricht nichts dagegen, einen kleinen Ausblick darauf zu wagen, was jenseits der nächsten drei Sprints liegt.
Dazu spendieren wir dieser längerfristigen Perspektive innerhalb des Refinements ein kurzes Zeitfenster. Praktisch kann das so aussehen, dass die ersten 15 Minuten eines insgesamt eine Stunde dauernden Refinements der Vorausschau dienen. Eine typische Frage kann z. B. lauten: Was möchten wir im nächsten Quartal mit unserer Anwendung erreicht haben?“ Daraus ergibt sich dann von selbst, dass anstehende Architekturentscheidungen dieses Ziel unterstützen sollen.
Abbildung 2: 2-Phasen-Refinement-Backlog
Beim Übergang zum „normalen“ Refinement ist das Ergebnis der Vorschau dann noch frisch im Bewusstsein, was sicherlich nicht schadet.
Experiment zwei: Double Pairs
Stellen wir uns vor, dass wir zwei mögliche Lösungsvarianten identifiziert haben. Um sich nun für eine davon zu entscheiden, brauchen wir viele gesicherte Informationen, wir müssen die Lösung sozusagen greifen können. Dazu finden sich bei den „Double Pairs“ zwei Gruppen, die jeweils eine der beiden Varianten durchstichartig oder als Prototyp umsetzen.
Eine der entscheidendsten Aufgaben dieses Experiments besteht darin, zu Beginn klare Abbruch- oder Akzeptanzkriterien festzulegen – als Erstes, was das Team anhand der Durchstiche lernen will. Welche Aspekte wollen die Teammitglieder vergleichen, was darf temporär vernachlässigt werden, obwohl es für den Produktionseinsatz erforderlich sein kann? Wann und nach welchen Kriterien werden die beiden Ansätze dann verglichen?
Im Zweifelsfall bietet es sich an, schlicht ein Zeitfenster festzulegen. Denn bei diesem Experiment geht es darum, vergleichbare Minimal-Lösungen entstehen zu lassen, mehr nicht. Es ist ausdrücklich nicht Sinn der Sache, dass eine Gruppe, einmal im Flow, ihren Ansatz fertig baut – immerhin besteht eine 50:50 Aussicht, dass eben dieser Ansatz anschließend verworfen wird. Es geht lediglich darum, ein Lernziel zu erreichen.
Abbildung 3: Double Pairs
Der Name „Double Pairs“ suggeriert, dass es sich um zwei Gruppen mit jeweils zwei Entwicklern handelt, das Experiment funktioniert jedoch auch mit größeren Gruppen oder mehr als zwei möglichen Lösungsvarianten.
Ganz wichtig ist, dass bei den „Double Pairs“ verschiedene Lösungsansätze miteinander konkurrieren, nicht die Gruppen untereinander und noch weniger ihre Mitglieder. Das wird nur unter zwei Bedingungen funktionieren: Erstens darf das Team autonom entscheiden, wie es vorgehen möchte, zweitens muss das Ergebnis dieses „Duells“ eine team-interne Angelegenheit bleiben, die von außen nicht bewertet wird.
Experiment drei: Mob Programming
Dieses Experiment beschreibt eine Variante des bekannten „Pair Programming“: Hier entwickeln nicht zwei Personen gemeinsam, sondern eine ganze Gruppe. Eine Person nimmt den Fahrersitz ein und implementiert Code, ohne die eigene Umsetzung zu kommentieren. Die Rolle des Navigators fällt jetzt dem „Mob“, allen anderen Teilnehmenden, zu. Der Mob macht sich über die Implementierung Gedanken, stellt Fragen und formuliert eventuell eigene Lösungsvorschläge. Nach einer kurzen Zeitspanne – beispielsweise 10 Minuten – wechseln die Rollen und ein Mitglied des Mobs löst den bisherigen „Driver“ ab. Diese häufigen Wechsel sind nötig, damit alle Anwesenden involviert bleiben.
Hintergrund dieses Experiments ist die Annahme, dass im Mob Wissensträger zur Architektur bzw. zu Architekturentscheidungen sind, die mittels ihrer Kommentare, Vorschläge und Erklärungen dabei helfen, die Architektur im Code umzusetzen und einzuhalten. Damit rückt die Architektur aus der abstrakten Kommunikationsebene hinein in eine Art lebendiges Objekt – den Code. Der Hintergrund wird begreifbarer und Rückmeldungen zeigen direkte Effekte. Letztendlich entsteht Architektur beim Schreiben des Codes.
Abbildung 4: Mob-Programming
Nun habe ich schon bei den „Double Pairs“ darauf hingewiesen, dass bestimmte Rahmenbedingungen gegeben sein müssen, damit das Experiment wunschgemäß ausgehen kann. Das gilt für das „Mob Programming“ erst recht. Um es direkt zu sagen: Diese Arbeitsweise kommt einem kollektiven „Die Hose herunterlassen“ aller Beteiligter gleich, auch der erfahrenen Entwicklerinnen und Entwickler. Das verlangt eine Menge Vertrauen innerhalb des Teams.
Wenn Bedenken bestehen, kann es helfen, eben dieses Vertrauen iterativ und inkrementell aufzubauen mit Pair Programming in wechselnden Konstellationen. Ob dann aus dem Pair ein Mob wird, entscheidet das Team.
Fazit
Die Schwierigkeit bei Architekturentscheidungen besteht darin, dass sich ihre Auswirkungen oft erst in einem größeren Kontext zeigen und nicht innerhalb von ein, zwei Iterationen. Die vorgestellten Experimente können dabei helfen, drei verschiedene Dinge zu erreichen. Das Refinement mit einem strategischen Ausblick soll eine gute Grundlage schaffen, auf der Architekturentscheidungen basieren können. „Double Pairs“ liefert messbare Kriterien, um verschiedene Architekturansätze zu vergleichen. Der Sinn des „Mob Programming“ besteht darin, getroffene Entscheidungen durch Wissensträger und das ganze Team zu begleiten – und zwar an der Stelle, an der sie wirksam werden. Denn letztendlich findet Architektur erst im Code statt.
Für eine gute Zusammenarbeit gibt es nicht das eine Patentrezept. Experimente können helfen den eigenen Rezeptfundus zu erweitern, um für die schwerwiegenden Entscheidungen – die Architekturentscheidungen – gut gerüstet zu sein.
Quellen und weiterführende Literatur
Martin Fowler zu Architektur: https://martinfowler.com/architecture/
David Farley: „Modernes Software Engineering“, mitp Verlag, 1. Auflage, 2003, Kapitel 8
Die Rollen im Pair Programming griffig erklärt: https://martinfowler.com/articles/on-pair-programming.html#HowToPair
Einfache Beschreibung eines Setups für Remote Mob Programming: https://www.remotemobprogramming.org/
Ein einfacher Einstieg in lösungsfokussierten Retrospektiven. Ein entsprechendes Format eignet sich hervorragend, um Experimente zu Identifizieren und mit Bezug auf ein Ziel zu bewerten:
Franziska Beck; "Lösungsorientiertes Coaching in Retrospektiven anwenden", Beitrag in dieser Blog-Reihe, veröffentlicht 24.01.2023