Certified Scrum Developer und implizites Wissen

Die Scrum Alliance arbeitet derzeit an einem „Certified Scrum Developer“. Nun gut, das bisherige Zertifizierungsprogramm aus Scrum Master, Product Owner, Practitioner, Coach und Trainer hat nicht unwesentlich zum Markterfolg von Scrum und Agilität beigetragen; und welche Folgen es für den Ruf von Scrum und agilen Verfahren hat, wenn 50.000 Scrum „Master“ mit einer jeweils zweitägigen Schulung unterschiedlicher Qualität die Industrie stürmen, um es jetzt „richtig“ zu machen, wird die Zukunft zeigen. Warum also das Erfolgsrezept nicht auch auf Entwickler ausdehnen?

Die Antwort ist einfach: Den Schaden, den ein schlechter Entwickler anrichten kann, ist für das Projekt noch bei weitem höher, als den, den ein schlechter Scrum Master anrichten kann: Den Scrum Master tauscht man zur Not aus und muss dann das Team wieder neu aufbauen und motivieren. Das kostet Geld, Zeit und Nerven, ist aber machbar. Schlechte Entwickler aber hinterlassen ihre Hypotheken im Code, die neue Hypotheken nach sich ziehen, ähnlich wie die Verpflichtungen der HRE.

Software Entwicklung ist in hohem Maße erfahrungs-getrieben. Dies gilt insbesondere für testgetriebene Entwicklung und emergente Architekturen, wie sie im Extreme Programming eingeführt und mittlerweile von allen agilen Verfahren inklusive Scrum übernommen wurden (leider nicht immer mit den gebotenen Referenzen). Erfahrungsgetrieben bedeutet aber, dass viel erfahrungsgebundenes implizites Wissen notwendig ist. Wikipedia beschreibt dieses Wissen folgendermaßen:

„Damit ist ein Wissen gemeint, das sprachlich nicht oder kaum weitergegeben werden kann. In solchen Fällen muss der Betreffende durch eigene Erfahrung oder am Modell lernen, das ihm vorzeigt, was nicht vorgesagt werden kann. Beispiel: Wer guten Nudelteig machen möchte, kann Rezeptbücher lesen. Aber in diesen Büchern steht offenbar nicht alles, was gute Teigköche wissen, weil dies nicht vollständig verbalisierbar ist. Das Gefühl für die richtige „Nässe“ des Teigs beispielsweise erwirbt man nur durch Erfahrung.“

Sicher, gerade die Patternbewegung hat sich erhebliche Verdienste erworben, Teile dieses impliziten Wissens zu heben und explizit zu machen, aber eben nur Teile. Die Eleganz eines Designs, die Strategie eines Umbaus lässt sich ebenso wenig explizieren, wie die Struktur eines Teiges. Hier hilft nur: Üben, üben, üben, viele Erfahrungen machen. Aber auch aus den Erfahrungen anderer lernen, fremden Code ansehen, fremde Architekturen — und zwar nicht nur den Beispielcode des MSDN.

Mir ist unbegreiflich, wie sich Informatik-Professoren damit schmücken können, in ihrem Leben keine 1000 Zeilen Code geschrieben zu haben, wie Architekten stolz darauf sein können „nicht mehr zu programmieren“ (man vergebe mir, dass ich hier keine Namen nenne). Kennen Sie einen Chirurgen, der sich damit brüstet, in seinem Leben kaum mehr operiert zu haben, als drei Platzwunden zu nähen? Würden sie ihm Ihr Leben anvertrauen? Davor schützt uns zum Glück die Ärztekammer. Programmieren aber gilt als niedere Tätigkeit, die man am besten möglichst weit weg schiebt, zum Beispiel nach Indien. Diese Missachtung der Programmierkunst ist ein fataler Irrtum, wie ich denke, der unsere Volkswirtschaft Milliarden Euro jedes Jahr kostet.

Sollte der „Certified Scrum Developer“ implizites Wissen wirklich abdecken, könnte er tatsächlich eine Qualifikation transportieren. Sollte er das nicht leisten, wäre es ein weiterer Versuch, den Markt zu segmentieren in Zertifizierte und Ent-Zertifizierte. Darüber hatten Johannes Link und ich uns ja schon Gedanken gemacht. Das wäre schade, war die Agile Bewegung doch einst als innovativer Gruppenprozess gestartet.

Beiträge zu den Entwicklertagen in Karlsruhe

Logo EntwicklertageVom 22. bis zum 26. Juni finden in Karlsruhe die Karlsruher Entwicklertage statt, zu denen ich mit zwei Vorträgen und einem Worshop beitrage:

Kommen Projekte ohne Architektur aus?

Ich höre immer wieder den Vorwurf an Teams, die mit XP arbeiten, sie hätten „keine Architektur“. Das halte ich für eine fundamentale Fehlinterpretation des Begriffs „Architektur“. Jedes Programm hat eine Architektur. Die mag adäquat sein, oder nicht, sie mag explizit dokumentiert sein, durch Tests abgesichert sein, oder unbewusst entstanden. Aber immer gibt es eine Architektur.

Die Vorstellung, man müsse eine Architektur explizit vor Beginn der Realisierung dokumentieren, damit sie kontrollierbar bleibe, halte ich ebenfalls für falsch. Ich habe viele Architekturdokumentationen erlebt, die zwar nett aussahen, mit der realen Architektur aber höchstens noch rudimentäre Ähnlichkeit besaßen. Umgekehrt habe ich exzellente Architekturen erlebt, die nirgends explizit dokumentiert waren. Sie waren höchstens durch Unit Tests und Mockobjekte abgesichert.

Wenn es um den wirtschaftlichen Nutzen einer Architektur geht, zählt die reale Architektur im Code. „Architekturen“, die nur auf der virtuellen Powerpointmaschine existieren und nichts mit dem real existierenden Code zu tun haben, sind wertlos. Ich habe eindrucksvolle und gut funktionierende Architekturen gesehen, die in traditioneller Technik zu Projektbeginn entworfen wurden. Gerade in XP Projekten entstehen aber auch immer wieder ausgezeichnete Architekturen ohne den großen ersten Wurf.

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.

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

Performance Tuning

Regelmäßig führe ich die folgende Diskussion mit Entwicklern:

Ich: „Wenn man hier noch eine polymorphe Indirektion/lokale Variable/Methodenaufruf einzieht, wird das ganz deutlich besser testbar/lesbar/änderbar.“
Entwickler: „Oh nein, dadurch wird die Peformance zu schlecht, den Code können wir nicht ändern.“

Diese Entgegnung gründet meistens in einem sehr begrenzten Verständnis von dem, was moderne Compiler, Laufzeitumgebungen und Prozessoren leisten. Aber dazu komme ich gleich.

Aus meiner Erfahrung gibt es drei Gründe für schlechte Performance mit absteigender Bedeutung:

  1. Schlechtes Design, aus dem inperformante Datenbankzugriffe entstehen. Datenbanken sind sehr gut, wenn es darum geht, aus einer große Grundmenge schnell nach bestimmten Kriterien zu filtern. Sie sind aber langsam, wenn es darum geht, durch ein Geflecht von Objekten zu navigieren. Verliert ein Team durch schlechtes Design den Überblick über den Code, kommt es häufig dazu, dass Funktionalität, die in der Programmiersprache sehr schnell wäre, durch komplexe und langsame Datenbankoperationen abgebildet wird und umgekehrt langsame Suchoperationen im Speicher gemacht werden, für die die Datenbank besser geeignet ist. Um das abzustellen, muss man allerdings den Code oft ganz wesentlich umbauen. Andererseits habe ich durch solche Umbauten Systeme schon um einen Faktor 1000 schneller machen können. Ein Faktor 10 bis 100 ist fast immer machbar.
  2. Schlechtes Design, bei dem das Team die Übersicht verloren hat. Dies führt dazu, dass aufwändige Operationen immer wieder durchgeführt werden. Je nach Fachlichkeit kommt es bei diesen Problemen auch vor, dass entsprechende Umbauten das System um den Faktor 10 beschleunigt.
  3. Schlechtes Design, bei dem ungeeignete oder zu einfache Algorithmen und Datenstrukturen verwendet werden. Häufig tritt dieses Problem auf, wenn anstatt geeigneter Objektstrukturen und Bibliotheksklassen Arrays und Indexschleifen verwendet werden. Dies führt oft dazu, dass selbst einfache Algorithmen so komplex zu programmieren sind, dass an den Einsatz leistungsfähigerer Varianten gar nicht erst gedacht wurde. Ironischer weise erhalte ich auf die Frage, warum man hier keinen Vector oder eine Map eingesetzt habe oft die Antwort „Die sind ja viel langsamer, als ein Array“. Nicht selten führt der Umbau dann zunächst zu einer deutlichen Beschleunigung und eröffnet durch den übersichtlicheren Code auf einmal deutlich bessere und auch schnellere Alternativen.

Nun ist es nicht immer sinnvoll, die schnellste Variante zu wählen. Code, der nur einmal durchlaufen wird, ist weniger kritisch, als der Kern des Systems. Grundsätzlich gilt: Erst zum laufen bringen, dann messen und dann erst optimieren. Zum Messen empfehlen sich professionelle Profiler wie z.B. Rational Quantify, die sehr gute Möglichkeiten bieten, kritische Stellen im Code zu identifizieren und seine Energien dort einzusetzen, wo man echte Hebelwirkung hat.

Und was ist mit den Low-Level Optimierungen in der Programmiersprache? Anders als alte Assemblermakros führen moderne Compiler hochgradige Optimierungen durch, die weit über das hinausgehen, was man manuell noch beherrschen könnte; Prozessoren parallelisieren verschiedenste Operationen, so dass Indirektionen und Variablenzugriffe zum Teil höchstens noch einen zusätzlichen Zyklus (also 0,2 Milliardenstel Sekunden) brauchen, oft sogar kostenneutral sind; Virtuelle Maschinen wie die Java VM gehen sogar noch weiter und überwachen die Abläufe zur Laufzeit, um dann den Code bei Bedarf nach neuen Kriterien zu optimieren. Sie wählen unter verschiedenen Optimierungsvarianten die aus, die am besten zum aktuellen Laufzeitverhalten passt. Der Versuch, diese Mechanismen durch „geschickte Programmierung“ zu „unterstützen“ geht in mehr als 90% der Fälle nach hinten los: Die zusätzliche Komplexität hebelt den Optimierer aus, der Code wird langsamer, als vorher. Von der Gefahr, den Überblick über das Design zu verlieren und sich ernsthafte Performanceprobleme einzuziehen ganz zu schweigen.

Fast alle Teams, denen ich bisher bei der Optimierung dieses Codes geholfen habe, waren zuvor in diese Falle geraten. Zumindest bei betrieblichen Informationssystemen ist eine Optimierung auf unterster Ebene praktisch immer sinnlos und kontraproduktiv.

Ruth Leuzinger zu Kapselung

„Wenn ich etwas von Ihnen will, rede ich ja auch mit Ihnen und fasse Ihnen nicht einfach in’s Hirn!“

Mit diesem einprägsamen Vergleich hat Ruth Leuzinger, ehemalige Chef-Architektin der Zürich Versicherung, vor über zehn Jahren das Prinzip der Kapselung von Daten beschrieben. Ich habe in all den Jahren weder eine einzige Schwäche dieses Vergleichs gefunden, noch eine bessere Beschreibung des Prinzips.