Architektur und Agilität

Will man einmal richtig Spaß haben, so werfe man in eine Gruppe von „Agilisten“ und „Traditionalisten“ das Stichwort „Architektur“: Als hätte man ein Zündholz in einen Strohhaufen geworfen entflammt sofort eine äußerst emotionale Diskussion, deren Randbereiche zwei Statements markieren: „Ohne eine saubere Anfangsanalyse und solide Anfangsarchitektur kommt kein ernsthaftes Projekt aus“ und „Wir brauchen keinen Architekten, die Architektur entsteht beim Programmieren“. Zwischen diesen beiden Extremen findet man fast jede denkbare Zwischenposition.

Ich habe viele dieser Diskussionen verfolgt und bin mittlerweile zu dem Schluss gelangt, dass hier mindestens drei verschiedene Themen munter durchmischt werden:

  • Wann wird die Architektur erstellt? Ist die Architektur eine eigene Phase zu Projektbeginn, wird sie zu Beginn jeder Iteration erstellt, oder entsteht Sie während des Programmierens durch Refaktorisieren?
  • Wie wird die Architektur repräsentiert? Existiert ein eigenes Dokument oder repräsentiert der Code die Architektur — wobei dann oft Werkzeuge eingesetzt werden, um grafische Darstellungen aus dem Code zu extrahieren und wichtige Eigenschaften zu prüfen, zum Beispiel automatisierte Test, um Abhängigkeiten zu prüfen.
  • Wer ist für die Architektur verantwortlich? Gibt einen oder mehrere Architekten? Als Entscheider oder als Moderatoren? Oder ist das Entwicklungsteam gemeinsam verantwortlich?

Ich denke, auf welche „Seite“ man sich bei diesen drei Fragen schlägt, hängt entscheidend von der Frage ab, was man sich von der Architektur erwartet. Die Antwort darauf wird oft stillschweigend als „selbstverständlich“ vorausgesetzt, ohne zu sehen, dass dort der eigentliche Konflikt liegt:

In traditioneller Sicht soll die Architektur Änderungen an bestehendem Code vermeiden. Sie sollte also so flexibel sein, dass zukünftige oder absehbare Anforderungen möglichst schon abgedeckt sind und ohne Änderungen an bestehendem Code oder zumindest der Architektur implementiert werden können. Architektur versucht die zukünftige Entwicklung vorauszusehen.

In agiler Interpretation soll Architektur Änderungen des Codes und ihrer selbst ermöglichen. Eine gute Architektur kann schnell an neue funktionale und nicht-funktionale Anforderungen angepasst werden. Sie ermöglicht möglichst viele zukünftige Entwicklungen. Änderbarkeit ist daher das Leitmotiv agiler Praktiken wie einfaches Design, testgetriebene Entwicklung, Refaktorisieren und Redundanzvermeidung.

Steht man auf dem Standpunkt, Änderungen an der Architektur seien schlecht und zu vermeiden, so wird man fast zwangsläufig zu dem Ergebnis kommen, dass die Architektur vor der Realisierung von einem starken Architekten erstellt werden müsse und daher nicht im Code repräsentiert werden kann.

Sieht man Änderungen als willkommenes Designwerkzeug, kann man die drei Fragen deutlich entspannter angehen. Die Antworten können sich nach anderen Faktoren richten, wie Kritikalität, Team- und Führungskultur und Erfahrung in der Domäne. Fast alle Kombinationen sind hier möglich; viele von ihnen auch in bestimmten Situationen sinnvoll.

In meinen Projekten kamen einige Teams ohne Architekten aus, andere ernannten irgendwann ein Mitglied zum Hüter der Architektur. Immer waren durch Refaktorisieren entstehende Architekturen in fast allen Qualitätsmerkmalen den zu Beginn erstellten Architekturen deutlich überlegen — und dazu auch noch wesentlich billiger. Zudem halte ich mir gerne Optionen offen.

Praktiken II: Automatisierte Akzeptanztests

Nach längerer Zeit nun der zweite Teil meiner Serie über agile Prakitken. Bisher finden Sie in dieser Kategorie die folgenden Einträge:

Der zweite Teil beschäftigt sich mit automatisierten Akzeptanztests:

Auch agile Entwicklung startet mit den fachlichen Anforderungen. Allerdings werden sie direkt als Akzeptanztests aufgeschrieben, statt in Anforderungsdokumenten. Akzeptanztests sind fachliche Beschreibungen dessen, was das System können soll und zwar so, dass sie automatisch ausgeführt werden können. Automatisch ausführbare Tests steuern die Anwendung und überprüfen deren Ergebnisse ohne menschlichen Eingriff. Der Weg zu diesen Akzeptanztests ist noch eher uneinheitlich, man geht aber in der Regel von den geplanten geschäftlichen Abläufen aus (siehe dazu auch „Use Cases oder User Stories„).

Weiterlesen

Praktiken I: Retrospektiven

Zu den – neuen – Kerngedanken agiler Entwicklung gehört die Idee, den Prozess in die Verantwortung des Teams zu geben. Das entspricht zum einen dem agilen Manifest, das ja fordert, dass „Individuen und Interaktion wichtiger sind, als Prozesse und Werkzeuge“. Zum anderen wird hier einmal wieder ein Konzept aus dem „Lean Management“ umgesetzt: Bei Toyota haben die Arbeiter in der Produktion erheblichen Einfluss auf die Produktionsprozesse. Schließlich wissen sie am besten, was gut funktioniert und was nicht.

Die Verantwortung für den Prozess zu bekommen bedeutet freilich nicht, dass jeder tun und lassen kann, was er will. Das Team muss vielmehr definieren, wie es arbeitet und diesen Prozess ständig verbessern. In seinen Crystal Methoden hat Alistair Cockburn die „Methodology Shaping Workshops“ nach jeder Auslieferung als eine der wenigen bindenden Praktiken definiert. Seitdem vor sieben Jahren Norm Kerths Buch „Retrospectives“ erschienen ist (siehe unten), haben sich Retrospektiven in allen agilen Verfahren als zentrale Praktik entwickelt: Regelmäßig stattfindende Workshops, auf denen alle Beteiligten reflektieren, wie das letzte Release gelaufen ist und beschließen, was in Zukunft anders gemacht werden soll. Es handelt sich dabei um eine Reflexion der gelebten Projektpraxis, also nicht um ein Review eines Prozessdokuments und auch nicht um einen Audit.
Weiterlesen

Refactoring von Spaghetticode

Refactoring von Spaghetticode ist grundsätzlich anders, als Refactoring im Rahmen testgetriebener Entwicklung: Letzteres ist gut verstanden und bedarf keiner besonderen Beachtung während der Planung, die einzelnen Refactoringschritte dauern immer nur ein paar Minuten und sind in der Gesamtschätzung enthalten.

Wenn man aber versucht, alten Spaghetticode durch Refactoring wieder in einen wartbaren Zustand zu bringen, sieht die Sache ganz anders aus. Dies ist ein kaum planbares Unterfangen mit hohem Zeit- und Aufwandsrisiko. Der Nutzen kommt dabei häufig erst, wenn die Arbeiten deutlich voran geschritten sind; oft wird also Monate lang ohne greifbaren Nutzen entwickelt, bis sich der „Knoten“ plötzlich auflöst und ein deutlich besser wartbares Design entsteht, das exakt der alten Funktionalität entspricht – modulo der Fehler, die man üblicherweise während dieser Arbeit noch entdeckt und behebt.

Um die Situation etwas zu entschärfen, gehen wir bei solchen Vorhaben oft in mehreren Phasen vor, die sich bisher ganz gut bewährt haben (ich spreche hier von „wir“, weil ein solcher Umbau immer im Team oder mindestens von einem Paar durchgeführt werden muss, niemals von einem „Einzelkämpfer“):
Weiterlesen

Refactoring von C++

Programmiersprachen spielen keine wesentliche Rolle habe ich einst gelernt, es kommt vor allem auf die Qualität der Entwickler an. Diese Aussage stammt aus den frühen 80er Jahren, als Barry Boehm sein „Software Engineering Economics“ veröffentlicht hat. Und tatsächlich kann die beste Programmiersprache der Welt wenig ausrichten, wenn das Team inkompetent ist – und ein kompetentes Team wird auch mit altertümlichen Programmiersprachen noch etwas ausrichten können. Also alles in Butter? Gebt mir eine turingvollständige Sprache und ich wuppe Euch das Projekt? Wohl kaum.

Nur in wenigen Bereichen hat sich so viel in den letzten 25 Jahren verändert, wie bei Programmiersprachen und ihren Entwicklungsumgebungen. In den frühen 80ern hatte man im Wesentlichen noch die Auswahl zwischen C, COBOL, Pascal, PL/I und Assembler und bei den Entwicklungsumgebungen die Wahl zwischen vi, emacs und dem Host-Editor. Heute führen die Unterschiede zwischen den verschiedenen Sprachen und Umgebungen durchaus zu Produktivitätsunterschieden von einer Größenordnung, also um den Faktor 10; beim gleichen Team, wohlgemerkt.

Besonders fallen mir diese Unterschiede auf, wenn ich – wie heute einmal wieder – einem Kunden beim Umbauen einer C++ Anwendung helfe. Zur Erinnerung: C++ war der Versuch, dem guten alten C einige Konzepte überzustülpen, die bei flüchtiger Betrachtung als objektorientiert verkauft werden konnten. „Die C-Programmierer müssen dann nicht umlernen“ war die häufigste Begründung für diese Sprache. Ohne das belegen zu können, vermute ich, dass genau dieser Umstand – unreflektierter Einsatz objektorientierter Techniken von Programmierern, die nur in prozeduraler Programmierung ausgebildet sind – zu den häufigsten technischen Gründen für gescheiterte Projekte zählt.
Weiterlesen