Follow my new blog

Posts mit dem Label Theory of Constraints werden angezeigt. Alle Posts anzeigen
Posts mit dem Label Theory of Constraints werden angezeigt. Alle Posts anzeigen

Samstag, 10. Oktober 2015

Gelebte inkrementelle Dekomposition

Neulich war große Freude. Ein Produktentwicklungsteam eines Kunden zeigte mir, wie es meinen Vorschlag eines anderen Umgangs mit Anforderungen umsetzt - und dadurch flüssiger arbeitet.

Inkrementelle Dekomposition

Mein Vorschlag war und ist, Anforderungen des Kunden bzw. die User Stories eines Product Owners nach einem Schema “zu zermahlen”, um für die weitere Entwicklung sehr präzise Ausgangspunkte zu bekommen.

Ausführlicher habe ich dieses Schema in einem früheren Artikel beschrieben. Deshalb skizziere ich es hier nur noch und stelle es in einen Prozesszusammenhang.

Für mich sieht ein Teil des Softwareproduktionsprozesses so aus:

image

Ein Strom von unstrukturierten Anforderungen wird von einem Product Owner im Rahmen eines so genannten Story Development durchgekaut und in User Stories transformiert. Die sind klein, konkret, wertorientiert, priorisiert.

Allerdings sind User Stories rein aus der Sicht von Kunde/Anwender formuliert. Die Programmierung kann sie nicht einfach implementieren. Vielmehr muss darauf eine Vorverarbeitung stattfinden.

Entwickler (und Tester) sitzen dafür zunächst mit dem Product Owner zusammen und analysieren die User Stories. Bisher hat ja nur der Product Owner verstanden, was zu tun ist. Dieses Wissen muss in die Köpfe der Programmierer übertragen werden. Das bedeutet, die Welt des Problems muss an die Welt der Lösung angeschlossen werden. Es müssen Bezüge hergestellt werden, ein Mapping stattfinden.

Mit meinem Ansatz plädiere ich dafür, die User Stories “in einen Problemtrichter zu stopfen”, aus dem unten einzelne Funktionen mit zugehörigen Akzeptanzkriterien heraustropfen.

User Stories stellen die Anforderungen in Form von Inkrementen vor, d.h. für den Kunden wertvolle Zuwächse an Funktionalität oder Effizienz. Slices sind Inkremente mit konkretem Bezug zur Welt der Codierung, d.h. der Lösung.

Die Problemanalyse transformiert einen Strom von User Stories also in einen Strom von Slices unterschiedlicher Dicke. Hier die Liste der wichtigsten Slices mit den ihnen entsprechenden Programmierartefakten (Module):

  • Anwendung = Bibliothek
  • Dialog = Klasse
  • Interaktion = Funktion
  • Feature = Funktion

Jede User Story entspricht dann in der Hierarchie der Slices einem oder mehreren Pfaden der Form Anwendung/Dialog/Interaktion/Feature. Das ist für die weitere Programmierung sehr, sehr viel konkreter, als eine User Story. Die Programmierung fühlt sich auf diese Weise weniger allein gelassen mit Verständnis und Übersetzung von Anforderungen. Ja, die Programmierung bekommt durch die gemeinsame Problemanalyse mit dem Product Owner sogar schon konkrete Hinweise auf eine minimale Modularisierung des Codes. Und die spiegelt dann auch noch das agile Vorgehen wider.

Während üblicherweise User Stories nach der Implementation nicht mehr im Code zu erkennen sind, bleiben bei diesem Vorgehen Inkremente als Artefakte im Code erhalten. Das ist von unschätzbarem Wert für die Nachvollziehbarkeit und Verständlichkeit von Code.

Der ursprüngliche Strom von Anforderungen wird also in zwei Schritten zerlegt in Inkremente (inkrementelle Dekomposition):

  1. Story Development -> User Stories
  2. Problemanalyse -> Slices

Beide zusammen dienen der Qualitätssicherung des Input in die weitere Programmierung. Das ist wichtig, da einer der häufigsten Engpässe bei der Softwareproduktion die Implementation oder die anschließende QA ist. Hohe Inputqualität für den Engpass ist Voraussetzung für hohe Qualität seines Output. Und die ist wichtig, damit der Engpass später nicht mit Nachbesserungen belastet wird.

Soweit die Theorie. Jetzt die Praxis.

Im realen Projekt

Als Trainer in Sachen flüssige Softwareproduktion und Clean Code Development stelle ich diese Vorgehensweise vielen, vielen Entwicklern vor. Wir üben sie dann tapfer in Workshops. Doch die Übertragung solcher “Theorie” in den Arbeitsalltag fällt den Teilnehmern immer wieder sehr schwer. Über die Gründe kann man diskutieren und lamentieren - aber nicht heute. Heute möchte ich zur Abwechslung zeigen, wie der Transfer eben auch klappen kann.

Das Team bei meinem Kunden besteht im Wesentlichen aus 2 Entwicklern, 3 Testern und 1 Product Owner. Beide Entwickler hatten an 2 Schulungstagen der Clean Code Developer School teilgenommen, an denen wir uns auf den Umgang mit Anforderungen konzentriert hatten. Dann am Ende des dritten Schulungstages luden sie mich ein, sich ihre Umsetzung des Lernstoffes in ihrem team room einmal anzusehen.

An der Wand sah ich dort diesen Notizenbaum:

image

Die Anwendung, an der das Team arbeitet, steht außer Frage. Die muss nicht explizit modelliert werden.

Der Dialog, auf den sich die (derzeit) zu realisierenden User Stories beziehen, steht ebenfalls außer Frage. Die ganze Wand konzentriert sich auf diesen Dialogentwurf:

image

Aus diesem Grund ist der Dialog auch nicht an der Wand zu sehen. Das finde ich verständlich, aber meine Empfehlung ist, ihn dennoch dort ebenfalls zu visualisieren. Dadurch wird jedes Denken über Slices konkreter. Bei Diskussionen kann man leichter Bezug nehmen, um über Interaktionen und Features zu sprechen. Niemand muss im Zweifelsfall in irgendwelchen Dokumenten nach dem aktuellen Stand des Dialog-Layouts suchen.

Aber auch ohne Dialog finde ich die Darstellung an der Wand klasse. Dort sind nämlich die von mir vorgeschlagenen Slices systematisch als Baum zu sehen:

  • Quer über die Wand stehen grüne Karten für Interaktionen des Dialogs. Jede lässt sich einem Button oder dem Klick auf eine Liste usw. zuordnen.
  • Senkrecht stehen orange und gelbe für Features der jeweiligen Interaktion. Die Darstellung der Feature-Hierarchie ist an der Wand leider begrenzt. Mit Farben wurden zwei Ebenen unterschieden und es gibt eine gewisse physische Unterordnung. Letztlich kommt hier der Umgang mit Kärtchen aber an seine Grenzen. Doch das Team ist kreativ mit seinen Mitteln umgegangen. Super!

An diese Wand kann ich herantreten, eine beliebige Karten auswählen und bin sicher, dafür eine Entsprechung im Code zu finden. Da es sich um Interaktionen und Features handelt, gibt es für jede 1 Funktion im Code.

Das ist die Sicht der Entwickler. Gleichzeitig stellt jede Karte aber auch noch Wert für den Product Owner dar! Alle Karten repräsentieren Inkremente. Zu allen Karten kann der Product Owner Feedback geben, ob das gewünschte Verhalten schon nach seinem Geschmack umgesetzt wurde.

(Zu dieser Regel gibt es nur eine Ausnahme: Die zweite grüne Karte von Links steht nicht für eine Interaktion sondern für die Datenstruktur des Dialogs, d.h. für die Steuerelemente mit den zugehörigen Datentypen und einige Validationsregeln. Dass dies visualisiert wird, ist natürlich eine gute Sache. Doch ich empfehle eine deutliche Unterscheidung von den Slices, z.B. durch räumliche Trennung oder andere Farben.)

Diese Systematik zu sehen, hat mich schon begeistert. Doch das Team zeigte mir noch mehr. Es setzt nämlich auch meine Empfehlung um, einzelne Features dem Product Owner über einen Prüfstand zum Feedback vorzulegen.

Hier der Prüfstand für den Cluster von Features, den ich an der Wand hervorgehoben habe:

image

Der Product Owner (oder auch ein Tester) kann mit dem Prüfstand wie mit einer speziellen Messsonde gezielt einen kleinen Teil des Gesamtverhaltens prüfen, ohne die ganze Anwendung oder auch nur den ganzen Dialog zu bemühen.

Das macht erstens das Feedback einfacher. Zweitens wird der Product Owner damit frei, sich Features in quasi jeder beliebigen Reihenfolge zu wünschen. Und drittens können Features, Interaktionen, Dialoge nun viel einfacher parallel entwickelt werden.

Voraussetzung für den Prüfstand ist, dass Inkrement-Wünschen des Product Owners sehr konkrete Artefakte der Programmierung zugeordnet sind. Genau das leistet die inkrementelle Dekomposition mit der Herstellung von Slices jedoch.

Das Fazit von Entwicklern wie Testern sowie Product Owner bisher: die Softwareproduktion ist viel flüssiger geworden.

Darüber freue ich mich sehr! Und ich bin überrascht. Denn so eine pragmatische und zügige Umsetzung des in der CCD School vorgestellten Ansatzes hatte ich bisher noch nicht gesehen. Hier zeigt ein Team, was möglich ist, wenn man echt etwas verändern will. Die Initiative zweier motivierter Entwickler reichte aus, die anderen Teammitglieder waren offen für eine Veränderung und die Führungsebene darüber hat den Freiraum zu solcher Selbstorganisation gegeben.

Drei notwendige Faktoren sind bei diesem Kunden also glücklich zusammengekommen. Super!

Mehr Fluss, mehr Produktivität sind möglich mit systematischerer Softwareproduktion. Das so deutlich zu sehen, spornt mich an, nicht nachzulassen bei der Vermittlung von und Suche nach besseren Methoden.

Sonntag, 23. November 2014

Praktische Führung

Es wird ja viel über Führung und Management geschrieben. Die einen sind dafür, die anderen dagegen. Aber was ist eigentlich die Aufgabe von Führungspersonen?

Eine sehr gute Erklärung liefert aus meiner Sicht Reinhard K. Sprengers Buch “Radikal führen”. Danach hat Führung fünf Kernaufgaben:

  • Zusammenarbeit organisieren - Klar, das ist der Ausgangspunkt. Verschiedene Aktivitäten müssen so “verdrahtet” werden, dass ein Gesamtergebnis entsteht. Dazu gehört natürlich auch die Zielsetzung.
  • Transaktionskosten senken - Für die Zusammenarbeit müssen günstige Rahmenbedingungen geschaffen werden. “Irgendwie” kann man sich auch ohne Führung zusammenraufen. Mit Führung soll es ökonomischer sein.
  • Konflikte auflösen helfen - Irgendwas ist immer. Dann muss Führung helfen, wieder Kohärenz herzustellen.
  • Zukunftsfähigkeit sichern - Heute gut zusammenarbeiten, bedeutet nicht, dass das auch noch morgen funktioniert. Innen wie außen können sich Verhältnisse verändern; darauf muss Führung (proaktiv) reagieren.
  • Mitarbeiter führen - Nicht nur die Zusammenarbeit will geführt werden, auch der Einzelne. Immer geht es ja um Ziele, die erreicht werden sollen. Hilfe kann da nicht schaden. Und schließlich müssen auch noch Stellen in der Zusammenarbeit geeignet besetzt werden, damit es bei guter “Verdrahtung” auch wirklich fließen kann.

Wenn ich durch diese Brille auf Unternehmen schaue, dann verstehe ich sehr gut, was funktioniert und was nicht - und warum. Ein Schema, das mir schon sehr geholfen hat.

Aber trotzdem: Irgendwas hat mir noch gefehlt beim Verständnis. Und das ist mir heute klar geworden, als ich mit meiner Tochter einen Nähkurs bei Zick und Zack in Hamburg besucht habe.

image

Dort wurde uns nämlich gesagt, dass eine Nähmaschine Führung brauche.

Der zu nähende Stoff muss unter der stationären automatischen Nadel entlangbewegt werden, um eine Naht zu produzieren. Das übernimmt der Transporteur unterhalb der Nadel.

image

Er zieht den Stoff, den der Nähfuß auf ihn drückt, an der Nadel vorbei. Die Richtung ist einstellbar; normalerweise bewegt sich der Stoff weg vom Näher, aber der kann ihn auch zu sich hin wandern lassen.

Der Stoff ist also grundsätzlich in Bewegung, die Naht entsteht von allein. Irgendwie. Denn bisher ist da sozusagen nur “rohe Kraft am walten”.

Was jetzt noch fehlt, das ist… Führung.

Die “rohe Kraft” des Transporteurs muss auf ein Ziel ausgerichtet werden. Und zwar immer wieder.

Hier sehen Sie, wie ich zur Übung entlang auf den Stoff gezeichneter Linien nähe. Der Stoff bewegt sich zwar von allein - nur nicht unbedingt “linientreu”. Ich muss ihn immer wieder nach-führen.

image

Dazu gehört, dass ich die Richtung korrigiere, indem ich den Stoff unter der Nadel drehe. Wenn die Richtungsänderung zu krass ist wie bei einer Zickzack-Linie, muss ich den Nähvorgang dafür sogar unterbrechen.

Darüber hinaus muss ich die “globale” Geschwindigkeit regulieren. Das tue ich über einen Fußschalter. Der bestimmt, wieviel “Input” sich die Maschine zum Nähen holt. Der Transporteur zieht sich ja den Stoff selbst.

Das ist aber noch nicht alles. Mein Aha-Moment bestand darin, dass ich fühlen konnte, was Micro-Management bedeutet.

Micro-Management entsteht nämlich immer dann, wenn zusätzlich zum allgemeinen Arbeitsfluss noch versucht wird, im Detail zu optimieren. Man überlässt das Resultat nicht dem Prozess, sondern greift lokal immer wieder ein.

Das führt bei Menschen zu Unmut. Die fühlen sich bevormundet; man lässt sie ja nicht die Arbeit tun, für die sie einmal kompetent gehalten wurden, sondern greift ein. Wer micro-managet, der vertraut nicht.

Daraus resultieren in Bezug auf den Produktionsfluss Stockungung und Qualitätsverlust.

Und genau das habe ich eben spüren können: Sobald ich anfing, den Stoff in Transportrichtung auf die Nadel noch zusätzlich zu zu schieben (Druck, push), war das Ergebnis schlechter. Dito, wenn ich anfing, den Stoff in Transportrichtung noch zusätzlich hinter der Nadel zu ziehen (pull).

Die Naht war sofort ungleichmäßig und die Ausrichtung entlang einer Linie fiel sofort schwerer.

Führung bedeutet mithin, einen Prozess aufzusetzen - und sich dann weitgehend rauszuhalten. Wer über die im Prozess wirkenden Kräfte noch drückt oder zieht… der betreibt Micro-Management. Das Ergebnis sind Stauungen oder Risse. In jedem Fall gerät etwas aus dem Gleichgewicht und der Arbeitsfluss wird gestört.

Führung bedeutet, in Kontakt bleiben mit dem Prozess. Immer wieder schauen, ob der noch fließt und auch noch auf das Ziel ausgerichtet ist. Falls nicht, muss nachjustiert werden - aber vorsichtig. Und eher nicht an den einzelnen Prozesselementen (lokale Optimierung), sondern am Ganzen (globale Optimierung).

Wenn es mit der Naht bei mir nicht geklappt hat, dann aufgrund von Micro-Management und zu wenig Blick auf das Ganze. Schlechte Führung also.

Es schien einfacher, nah an der Nadel den Stoff zu ziehen/drücken, als die Gesamtgeschwindigkeit zu regulieren. Und es war attraktiver, überhaupt mit der Maschine zu nähen, statt das Nähen vorzubereiten. So habe ich zum Beispiel ein Band, das ich auf eine Tasche nähen wollte, nicht vorher mit Nadeln ausreichend fixiert. Ich dachte, ich kriege es durch Eingriffe nahe an der Nadel während des Stoffdurchlaufs hin, das Band gerade drauf zu nähen. So musste ich auf die harte Tour lernen, dass gute Vorbereitung hilft, den Durchsatz zu erhöhen.

Auch das gehört zu Führung: Bewusstsein dafür vermitteln, dass zu guter Zusammenarbeit auch darin besteht, auf Qualität von Input und Output zu achten. Systeme definieren sich ja durch das, was zwischen ihren Bestandteilen fließt.

Aber auch das ist eine Sache, die eben nicht während der Produktion geschehen sollte. Da müssen die Prozessschritte schon gut “verdrahtet” sein. Führung ist eine Sache des Rahmens, in dem Produktion stattfindet.

An der Nähmaschine habe ich ja auch nicht selbst die Naht hergestellt. Dazu greifen die Teile der Nähmaschine ineinander. Vielmehr habe ich in guten Moment einfach nur “sanft” geführt.

image

Das Ergebnis war dann doch passable und nützlich. Ich habe bei der Führung die Kurve gekriegt. Aber wie ist das im Tagesgeschäft? Kriegt Management da auch immer die Führungskurve? Das scheint mir nicht der Fall zu sein.

Da ist Micro-Management an der Tagesordnung - insbesondere, wenn irgendetwas sowieso nicht rund läuft. Da wird gedrückt und gezogen, statt auf den Gesamtprozess zu schauen. Wie sind die Prozessbeteiligten eigentlich grundsätzlich zueinander angeordnet? Wie ist die Qualität des Input? Wo gibt es einen Engpass?

Vielleicht würde ja mal ein Nähkurs für Führungskräfte helfen? Da kann man eine Menge lernen, nicht nur über Führung. Und Spaß macht es obendrein, mal wieder etwas Anfassbares mit den Händen hergestellt zu haben.

Dienstag, 11. November 2014

Die vielen Gesichter des Product Ownership

Wie sollte, wie kann Product Ownership aussehen? Stefan Rook hat dazu einen Vortrag gehalten:

Product Ownership hat also viele Gesichter. Diese Botschaft hat mir an dem Vortrag gefallen. Mir hat allerdings auch etwas gefehlt. Nämlich die Abstraktion. Was ist das Muster? Worum geht es im Kern?

Mag sein, dass das schon allen klar ist. Meine Erfahrung ist jedoch, dass die meisten Unternehmen genau da jedoch herumeiern. Denn wäre es ihnen klar, würde sich die Ermunterung von Stefan Rook, Product Ownership durchaus unterschiedlich zu leben, erübrigen.

Hier mein Versuch einer Abstraktion:

Die Hauptaufgabe des Product Owners (PO) nach Anschauen des Vortrags ist… die Priorisierung von Anforderungen.

Bei Wooga haben die Teams in einem Rahmen alle Freiheit und tun das selbst; in den Teams ist es der Product Lead, denke ich mal, der dafür verantwortlich ist, aber wohl sehr eng mit seinen wenigen Teamkollegen in dieser Hinsicht zusammenarbeitet.

Bei Jimdo ist es der Manager mit dem PO-Hut auf.

Bei der Zeitung gibt es dafür die Berechnungsvorschrift im Tagesgeschäft, die vom PO verwaltet wird.

Immer gibt es eine Reihe von Stakeholdern mit Wünschen; immer müssen diese Wünsche mit begrenzten Ressourcen erfüllt werden; also muss immer priorisiert werden. Ohne Priorisierung gibt es keine geordnete, verlässliche Umsetzung.

Ziele

Die besprochenen Szenarien unterscheiden sich darin nicht, sondern in der Zahl der Ziele, auf die hin die Wunscherfüllung priorisiert werden muss. Bei Wooga gibt es viele gleichzeitige Ziele; jedes Projekt hat seines. Bei Jimdo und der Zeitung hingegen gibt es nur eines.

Jedes Ziel hat viele Stakeholder und braucht daher einen PO der deren Wünsche auf die eine Umsetzungsressource hin priorisiert.

Wenn Sie Ihre PO-Strategie nun überdenken wollen, dann fragen Sie sich: Welche Ziele gibt es? Jedes verdient einen PO.

Gewichtung

Der PO hat in Bezug auf ein Ziel hin die Kompetenz (und Erlaubnis) zur Priorisierung. Und wie macht er das? Bei Wooga und Jimdo erfahren wir nichts darüber. Das kann “nach Gefühl und Wellenschlag” gehen. Bei der Zeitung hingegen, wird eine Formalisierung angedeutet. Dort wird “ohne Zorn und Eifer” priorisiert; alle Stakeholder stehen “im fairen Wettstreit”. Solange sie ihre Wünsche ehrlich in verschiedenen Kategorien bewerten, ergibt sich eine vorteilhafte Hitliste von Wünschen.

Dieser Unterschied ist für mich deutlich genug herausgekommen: Priorisierung kann mehr oder weniger formal geschehen. Jedes Unternehmen muss sich also fragen, wie nachvollziehbar die Priorisierung sein soll (oder auch kann).

Noch betrüblicher fand ich dann, dass die Bewertung bei der Zeitung so stehengelassen wurde. Als seien die Bewertungen gleichzeitig die Prioritäten.

Der PO als Herr über den ROI. Das wurde schon am Anfang gesagt. Kann er diese Aufgabe mit den Bewertungen in der Hand aber erfüllen? Nein.

Die Bewertungen, also Wertzuschreibungen die mehr oder weniger direkt auf erwartete verringerte Verluste oder vergrößerte Umsätze/Gewinne verweisen, sind nur ein erster Input für die Priorisierung. Schön, wenn Anforderung A bei Umsetzung 100.000 EUR einbrächte. Aber über welchen Zeitraum – und vor allem: mit welchem Aufwand?

Leistung ist nicht Arbeit und auch nicht Arbeit mal Zeit, sondern Arbeit pro Zeit. Die Aufgabe des PO bei der Priorisierung ist es, die Leistung zu optimieren. Die besteht darin, möglichst viel Wert mit möglichst wenig Aufwand zu schaffen.

Dieser Gedanke steckt auch in der Priorisierung mit “Weighted Shortest Job First” (WSJF). Einem Wert wird dort ein Aufwand gegenübergestellt, so dass sich ein Gewicht ergibt. Je gewichtiger dann ein Wunsch, desto eher sollte er umgesetzt werden.

Ein Wert von 100, der mit einem Aufwand von 10 realisiert werden kann (Gewicht: 100/10=10), hat ein geringeres Gewicht, als ein Wert von 50, der mit einem Aufwand von 4 realisierbar ist (Gewicht: 50/4=12,5).

Wie Wert und Aufwand ermittelt werden, ist von Ziel zu Ziel verschieden. Das finde ich wichtig herauszustellen. Um die Priorisierung gewissenhaft vornehmen zu können, muss ein PO also Wertmaßstäbe und Aufwandsmaßstäbe definieren.

Wer dann entscheidet, “das mache ich aus dem Bauch heraus”, muss nicht falsch liegen. Nachvollziehbar ist das jedoch kaum. Und was das für flüssige Kommunikation und Vertrauensaufbau bedeutet, kann man sich denken.

Aber… warum soll es nicht Situationen geben, wo das (zunächst) ausreicht? Entscheidend ist, dass man sich einmal dazu Gedanken gemacht hat – und in Retrospektiven die Annahmen immer wieder überprüft.

Abnahme

Am bedauerlichsten fand ich, dass der Vortrag nichts über die Aufgabe des POs als schließende Klammer der “Wertproduktion” gesagt hat. Es wurden nur Varianten der öffnenden Klammer gezeigt. (Was allerdings in der Tradition der Scrum-Darstellungen ist, die vor allem Backlog und Planning betonen – das Review bzw. die Abnahme demgegenüber jedoch vergleichsweise schwach ausleuchten.)

Das halte ich für einen Kardinalfehler, weil sich genau hier nämlich immer wieder das größte Problem von POs zeigt: Sie glauben, sie könnten Anforderungen “über den Zaun kippen” und bekommen dann “wie versprochen” Wert geliefert.

Das  ist der Ansatz “Stopfgans”. Da hilft auch nicht, am Anfang in schönem Einvernehmen mit Entwicklern über User Stories zu diskutieren.

Wenn der PO nicht an der “Wertschöpfung” zieht, entsteht kein rechter Fluss.

Hier spekuliere ich mal in Bezug auf die vorgestellten Szenarien: Bei Wooga und Jimdo ist das kein Problem, weil der PO besonders eng-agiert an den Entwicklern dran ist. Abnahme passiert hier ständig. Das große Ziel ist auch allen klar. Hohe Kohärenz der Energie aller Beteiligten. Bei Wooga nehme ich sogar an, dass die Entwickler wie bei Open Source Projekten z.T. ihre eigenen Kunden sind.

Schön, wenn das so ist – nur muss man eben wissen, warum es funktioniert. Co-location reicht da nicht aus. Es kommt auf den Willen des PO an.

Wie es bei der Zeitung ist, kann ich nur ahnen. Die Priorisierung ist explizit. Schön. Aber wie ist die Abnahme? Zieht da jemand an Wert? Wie groß sind die Brocken, die in die Entwicklung hineingekippt werden? Nach meiner Erfahrung mit größeren Unternehmen vermute ich, dass das nicht so einfach fließt wie bei Wooga und Jimdo. Man glaubt eher, dass “Reinkippen” schon ein Garant dafür ist, dass auch etwas rauskommt.

Aber ich kann nicht beurteilen, wie es dort ist. Ich kann nur betonen, wie wichtig eben die schließende Klammer Abnahme bei der Softwareentwicklung ist. Automatisierte Akzeptanztests sind nicht genug. Ein Mensch auf 2 Beinen erzeugt viel mehr Zug als ein paar Tests, die auf grün gehen müssen.

Der PO ist für mich die wichtigste Rolle in der Softwareentwicklung. Angesichts dessen, welch feste Strukturen in der Codierung entstehen und wie schwer es ist, dafür gute Leute zu finden, ist die Qualitätssicherung bei den Anforderungen immens wichtig. Vor der Codierung und nach der Codierung. Einen PO einzusetzen ist eine Maßnahme im Sinne des 3. Fokussierungsschritts der Theory of Constraints (TOC).

Ohne PO ist die Codierung der Engpass der Softwareproduktion. Mit PO… wird allerdings schnell der PO zum Engpass. Daher bin ich nicht überzeugt, dass das Jimdo-Modell oben auf der Liste zur Nachahmung stehen sollte. PO sein ist ein Vollzeitjob (außer bei trivialen Zielen). PO+Entwickler oder PO+Geschäftsführer sind für mich Anti-Patterns.

Bottom line

Ich stimme Stefan Rook zu, dass Product Ownership viele Gesichter haben kann. Welches zu einem Unternehmen passt, muss sich jedoch aus der Beachtung von Prinzipien ergeben:

  • Anforderungen im Rahmen eines Ziels müssen auf dem Weg zu den “Transformatoren” durch 1 Instanz gehen, den PO. Er ist die “single source of truth”.
  • Der PO priorisiert durch Gewichtung in angemessener Nachvollziehbarkeit. Er stellt dafür Wert und Aufwand gegenüber.
  • Was im System zur Umsetzung ist, muss möglichst schnell aus dem System herausgezogen werden. Erst dann entsteht Wert. Die vornehmste Aufgabe des PO ist daher der Zug am Ende der Produktionskette, die Abnahme. Die muss ab-so-lut verlässlich geschehen.

Im Rahmen dieser Prinzipien können Sie jede Form des Product Ownership wählen. Form Follows Function. Oder sie fragen sie mit diesen Prinzipien in der Hand, was Ihrem heutigen Product Ownership womöglich noch fehlt.

Montag, 13. Januar 2014

Rekursive Produktivität

Das drängendste Problem der Softwareentwicklung heute scheint mir Unzuverlässigkeit. Darin unterscheidet sie sich nicht von der Deutschen Bahn. Nicht Performance oder Skalierbarkeit oder Sicherheit oder Usability oder ein Mangel an Kunststücken sind das Problem. Allermeistens kann Technologie das, was gebraucht wird, um die nicht-funktionalen Anforderungen zu erfüllen. Das war vor 20-30 Jahren noch anders.

Nein, heute hapert es bei der Lieferung. Sie ist unzuverlässig, weil wir knietief im Brownfield waten. Sie ist unzuverlässig, weil der Herstellungsprozess unsystematisch ist. Es mangelt an Evolvierbarkeit und Produktionseffizienz.

Auch wenn ich mich viel und gern mit Evolvierbarkeit beschäftige, glaube ich jedoch, dass die Produktionseffizienz zuerst angegangen werden muss. Denn ohne ein systematisches Vorgehen gibt es auch keine Verlässlichkeit für Maßnahmen zur Erhöhung der Evolvierbarkeit.

Und wie die Produktionseffizienz steigern? Klar, mit der Einführung von Agilität! Leider ist das aber nicht so einfach. Teams und Unternehmen können nicht einfach einen Schalter umlegen und schon wird agil gearbeitet. Bei aller Einsicht und gutem Willen der Organisationen ist das auch sehr verständlich: Wie soll denn eine solche Veränderung verlässlich durchgeführt werden, wenn Verlässlichkeit das Grundproblem ist?

Die Einführung agiler Vorgehensweise versandet bzw. scheitert so oft, weil es an einem Meta-Prozess fehlt. Wer das Lernen verlernt hat, der hat es schwer, ein lernendes Vorgehen zu erlernen. Ist doch klar.

Zumindest in Scrum steckt zwar etwas von dieser Meta-Ebene: die Retrospektive. Doch die kommt mir dort wie ein Anhängsel vor. Andere Aspekte sind klarer formuliert. Und vor allem ist die Retrospektive in dem Prozess, der eingeführt werden soll, und nicht vor oder über ihm. Scrum kommt ohne Bootstrap.

Aber nicht nur auf der Meta-Ebene fehlt mir etwas. Am anderen Ende hapert es auch: bei der Verlässlichkeit jedes einzelnen. Die ganz persönliche Zuverlässigkeit ist oft mangelhaft. Joel Spolsky hat empfohlen, nach Bewerber nach zwei Kriterien auszuwählen: smart + gets things done. Mir scheint, das zweite Kriterium wird nur selten angewandt.

Bitte verstehen Sie mich recht: Überall wird fleißig, fleißig gearbeitet. Man bemüht sich redlich wegzuschaffen, was da täglich an Aufgaben auf den Schreibtisch schneit. Alle legen sich ins Zeug. An Einsatzfreude (bis zur Selbstaufgabe) habe ich es ganz selten mangeln sehen. Doch guter Wille allein führt ganz offensichtlich nicht zu Verlässlichkeit. Im Kleinen fehlt mithin die Grundlage für erfolgreiche Veränderungen.

Über die Gründe für diese Misere will ich hier nicht lange spekulieren. Vielmehr möchte ich mir Gedanken machen, wie sich daran etwas ändern ließe. Meine derzeitige Vorstellung: Wir müssen die Softwareentwicklung weiter von romantischen Vorstellungen befreien. Wir müssen genauer hinsehen. Wir müssen eine Bild dafür entwickeln, wie Softwareherstellung ganz fundamental als Prozess funktioniert.

Aber nun genug der Vorrede. Hier mein Ansatzpunkt:

Der Prozessor

Ich glaube, wir müssen uns leidenschaftslos als Prozessoren verstehen. Wir alle sind Informations- bzw. Materialprozessoren. Ständig, nicht nur bei der Arbeit. Aber auf die will ich mich hier konzentrieren.

Jeder Beteiligte an der Softwareherstellung ist dazu da, Input in Output zu verwandeln:

image

Anforderungen sollen in Code übersetzt werden. Die Kollegin bittet um Hilfe mit ein paar Screenshots. Der Vertrieb ruft an und möchte Auskunft über den Stand der Entwicklung. Tausenderlei Dinge sind zu erledigen. Aufgaben prasseln aus allen Richtungen auf uns ein.

Und das geht jedem so. Sie und ich sind nicht allein. Wir sind vielmehr in einem Netz von Aufgabenflüssen aufgehängt.

image

Manche Aufgaben fließen von außen in dieses Netzwerk ein. Andere entstehen erst im Netzwerk während der Erledigung solcher Aufgaben. Insofern entstehen manche Aufgaben auch in uns für uns.

So ist das: Wir sind “nur” Prozessoren in einem Netzwerk. Aber waren wir das nicht immer schon? Klar. Doch etwas hat sich verändert: Früher war das Netzwerk nicht so engmaschig. Früher waren wir getrennter von einander, weil es an Kommunikationswegen mangelte.

Heute ist jeder jederzeit erreichbar. Technisch ist das möglich. Und zusätzlich will heute auch noch jeder jederzeit erreichbar sein – oder muss. Das bedeutet, die Zahl der Einflüsse im wahrsten Sinn des Wortes, d.h. dessen, was wann in uns einfließen kann, ist explodiert.

Demgegenüber hat sich jedoch eines nicht verändert: Wie wir grundsätzlich funktionieren. Wir sind dieselben geblieben. Wir können immer noch nur eine Sache zur Zeit erledigen. Uns sind keine Prozessorkerne zugewachsen. Unsere Aufmerksamkeit ist begrenzt in Breite und Dauer. Auch wenn wir Prozessoren sind, sind wir doch keine Maschinen.

Wir können zwischen verschiedenen Aufgaben nicht so schnell Umschalten wie eine CPU. Je häufiger wir umschalten, desto größer der Umschaltaufwand. Und je häufiger wir umschalten, desto geringer die Qualität unserer Transformationen.

Ich denke, das wissen sie aus eigener Erfahrung.

Systematische Transformation

Wie nun angesichts dieser Begrenzungen transformieren? Das ist ganz einfach und hat sich in den letzten 5.000 Jahren wohl nicht verändert: konzentriert eins nach dem anderen.

Kein Strampeln und Schreien ändert daran etwas. So funktionieren wir einfach. Das ist eine Gesetzmäßigkeit wie die Gravitation oder der zweite Hauptsatz der Thermodynamik. Wir müssen uns damit arrangieren. All unsere Arbeit muss sich danach ausrichten.

Es ist so einfach – und doch so schwierig. Ich weiß. Jeden Tag ringe ich ja auch damit. Seit ich mich aber bemühe, die Situation systematischer zu betrachten, gelingt es mir immer besser. Früher ist der Mensch ja auch nicht geflogen – aber seit er sich systematisch mit den Naturgesetzen auseinandersetzt, haben wir es in dieser Hinsicht weit gebracht, würde ich sagen. So glaube ich daran, dann es auch unsere Produktivität beflügelt, wenn wir uns systematischer damit befassen.

Also: Als Prozessor können wir uns nur mit 1 Aufgabe zur Zeit befassen. Das ist die aktuelle Aufgabe. Darüber hinaus gibt es aber noch eine ganze Reihe weiterer Aufgaben, die auf unsere Aufmerksamkeit warten, um erledigt zu werden. Ständig kommen darüber hinaus neue hinzu. Und alle haben eine unterschiedliche Priorität und womöglich unbekannte Größe.

Ob wir uns überlastet fühlen oder nicht, hängt u.a. davon ab, ob Aufgaben schneller einfließen als Transformationsergebnisse ausfließen.

image

Die minimale Systematik besteht nun darin, denke ich, unsere Begrenzungen zu honorieren und nicht bei Eintreffen einer neuen Aufgabe die Bearbeitung der aktuellen zu unterbrechen.

Ja, das meine ich so: Lassen Sie sich nicht mehr unterbrechen!

Unterbrechungen sind das Grundübel heutiger Unproduktivität von “Knowledgeworkern”. Je mehr Teams ich sehe, je genauer ich auf meine eigene Arbeitsweise achte, desto klarer wird mir das.

Das Ziel muss lauten:

Zero Interrupts! Zero Notifications!

Was kann denn wichtiger sein, als dass Sie die aktuelle Aufgabe zuende führen?

Sie mögen einwenden, dass immer etwas Wichtigeres auf Sie zuströmen könnte. Denn was, wenn der Kunde nicht mit Ihrer Software arbeiten kann, wenn dort ein Fehler jede Minute viel Geld kostet? Sie haben Recht, dann muss sofort gehandelt werden. Aber: Müssen wirklich Sie handeln – oder gibt es dafür nicht vielmehr einen “Notfallprozessor”? Und wie oft tritt dieser Fall ein? Einmal im Monat? Dann müssen wir nicht darüber reden, denn mir geht es um das übliche Tagesgeschäft. Wir sollten uns nicht durch Sonderfälle davon abhalten lassen, für den Normalfall eine Systematik zu finden. Wenn wir die haben, dann können wir innerhalb derer auch Sonderfälle abarbeiten.

Wenn es nun keine Unterbrechungen – externe und selbst erzeugte – mehr gibt, hat das zweierlei zur Folge:

  • Wir brauchen einen Puffer (aka Warteschlange), in die neue Aufgaben einfließen, während wir noch mit der aktuellen beschäftigt sind.
  • Wir brauchen einen Mechanismus, um in Balance zu bleiben. Wir sind ja nicht allein, sondern brauchen andere, wie sie uns brauchen. Wir dürfen uns also nicht isolieren. Eine gewisse “responsiveness” ist nötig.

Der Puffer entkoppelt uns von anderen Prozessoren. In ihn schieben (push) die (oder wir selbst) Aufgaben hinein. Das stört uns aber gar nicht oder nicht sehr in unserer Konzentration. Wir arbeiten unsere aktuelle Aufgabe ruhig ab. Erst wenn wir damit fertig sind, entnehmen wir unserem Puffer eine neue (pull).

image

Das Ergebnis unserer Transformation schieben wir natürlich in den Puffer eines anderen Prozessors. Das mag der sein, von dem wir eine Aufgabe bekommen haben, oder ein anderer.

image

Das sieht doch schon ordentlicher aus, oder? Das Netzwerk ist zwar nicht weniger verwoben – wir werden aber nicht mehr von den fließenden Aufgaben überflutet. Sie laufen jetzt in das Auffangbecken unserer Puffer.

Manchmal gibt es dabei “Aufgabenkaskaden” im Rahmen von offiziellen Prozessen, z.B. dem Softwareentwicklungsprozess der vom Kundenwunsch bis zum Release reicht. Manchmal geht es aber auch nur um informelle Dialoge zwischen zwei Prozessoren, sozusagen ad hoc Microprozesse.

image

Wie nun die Aufgaben im Puffer priorisiert werden, lasse ich hier mal dahingestellt. In jedem Fall steht die jeweils dringlichste Aufgabe deutlich sichtbar darin. Ihr widmen wir uns, wenn wir wieder Zeit haben.

Und wann haben wir wieder Zeit? Eigentlich erst, wenn wir die aktuelle Aufgabe fertiggestellt haben. Wenn das jedoch Stunden, Tage, Wochen dauern sollte… dann dürfen wir nicht so lange von der Bildfläche verschwinden. Außerdem können wir womöglich gar nicht so lange konzentriert an einer Aufgabe arbeiten. Unsere Aufmerksamkeitsspanne ist begrenzt. Oder wir müssen auf Input warten, ohne den wir nicht weiterarbeiten können.

Es ergeben sich also aus unseren eigenen Begrenzungen bzw. aus den Aufgaben selbst durchaus Unterbrechungspunkte, gegen die wir nichts tun können. Die Konzentrationsfähigkeit scheint mir z.B. bei 30-45 Minuten und bei 90-120 Minuten natürliche Grenzen zu haben. Warum das nicht nutzen, um in Kontakt zu bleiben mit unserer Umwelt? Wir können ganz regelmäßig und damit verlässlich unseren Puffer durchsehen, ob etwas Dringenderes als die aktuelle Aufgabe unserer Aufmerksamkeit bedarf. Richten Sie es daher am besten so ein, dass Sie nur 1 Puffer haben. Dann gewinnen Sie am schnellsten Überblick über die wartenden Aufgaben.

Unvermeidliche Unterbrechungen können wir nutzen, um für andere direkt (synchron) ansprechbar zu bleiben. Ein Kollege, der sie gestern noch mit einer längeren Problemklärung unterbrochen hat, ist morgen sehr wahrscheinlich bereit, auf Ihre nächste “Sprechzeit” zu warten. Denn die ist im Mittel nur vielleicht 20 oder 60 Minuten entfernt. So lange können die allermeisten Themen warten.

Denken Sie daran: Zero Interruptions!

Dasselbe gilt auch für Emails, Chat (Skype, Whatsapp), Twitter, Facebook, Newsgroups, RSS-Feeds und was der Social Media mehr sind. Das alles kann eine Stunde oder gar länger warten. Ihre Aufgabe ist die konzentrierte, weil schnellstmögliche und bestmögliche Abarbeitung von Aufgabe, nicht die Verarbeitung von Notifikationen. Aufnahme und Einordnung neuer Aufgaben darf nur einen Bruchteil Ihrer Zeit verzehren.

Deshalb denken Sie auch daran: Zero Notifications!

Ziehen Sie sich Informationen/Aufgaben, wenn Sie bereit dafür sind. Das gilt für elektronische wie menschliche Quellen.

Was nun, wenn Sie eine Aufgabe noch nicht abgeschlossen haben, aber eine andere höhere Priorität hat? Dann können Sie nach einem natürlichen bzw. unvermeidlichen Unterbrechungspunkt die Aufgabe wechseln. Seien Sie sich allerdings bewusst, dass Sie damit ein Stück unverlässlich gegenüber der nun unterbrochenen Aufgabe werden. Sie sollten deshalb die Zahl der Aufgaben “on hold” begrenzen.

image

Haben Sie nie mehr als vielleicht 2 oder vielleicht 3 Aufgaben in Arbeit, d.h. begonnen (aus dem Puffer entnommen), aber noch nicht abgeschlossen. Das könnte eine sehr kleine für zwischendurch sein (ein Anruf), eine, an der sie danach aktiv weiterarbeiten, und eine, bei der Sie auf einen Input zur Weiterarbeit warten müssen.

Tun Sie sich diesen Gefallen der Work-in-Progress Limitierung. Sie werden entspannter arbeiten, sie werden verlässlicher liefern. Ihre Kollegen werden es Ihnen also auch danken – früher oder später.

Gleichfalls sollten Sie die Zahl der Aufgaben in Ihrem Puffer begrenzen. Von außen ist nämlich nicht immer einfach zu unterscheiden, ob Sie schon mit einer Aufgabe angefangen haben oder ob sie noch unbearbeitet im Puffer liegt. Für andere Prozessoren gilt eine Aufgabe als übergeben, wenn Sie im Puffer liegt.

Wenn Sie jedoch den Puffer begrenzen, dann können von anderen Prozessoren keine Aufgaben mehr darin abgelegt werden. Bzw. Sie können keine mehr annehmen und dort ablegen. Sie machen dann dicht – und üben sog. back pressure aus. Aufgaben können aus anderen Prozessoren nicht mehr zu ihnen weiter-/abfließen und müssen dort on hold gehen. Damit steigt deren WIP usw.

Das hört sich negativ an – aber für wen? Für Sie? Für den anderen Prozessor? Für das Gesamtsystem oder den Kunden?

Tatsächlich ist das jedoch kein Bug, sondern ein Feature solcher Systematik. Anders kann das Gesamtsystem – Team, Abteilung, Unternehmen – nämlich nur schwer bemerken, wann Überlastung eintritt. Solange Sie zu Unterbrechungen Ja sagen, solange Sie grenzenlos Aufgaben annehmen, scheint alles zu klappen – nur dass es zu mysteriösen Unzuverlässigkeiten und Qualitätsmängeln kommt. Und das, wo doch alle unter Hochdruck mit bestem Willen arbeiten.

Was ich hier empfehle, ist nichts anderes als so etwas wie Personal Kanban + Pomodoro Technique. Werden Sie zum preemptive multitasking Prozessor mit WIP Limit :-)

Ja, ohne ein gewisses Maß an Multitasking geht es nicht. Damit meine ich nicht, dass Sie während des Einparkens telefonieren und simsen sollen ;-) Das funktioniert nicht. Aber 2-3 verschiedene Aufgaben, zwischen denen wir im Verlaufe eines Tages springen, halten wir schon aus. Ohne geht es auch nicht, sondern isolieren wir uns zu stark von anderen. Und ich denke sogar, eine gewisse Vielfalt ist sogar bekömmlich. Ein Anruf zwischendurch macht auch mal den Kopf frei vom Bug Fixing. Eine Präsentation kann davon profitieren, zwischendurch mal eine technische Frage zu beantworten. Usw.

Hier ein Ausschnitt aus meinem Personal Kanban Brett bei leankit.com:

image

Links die Spalte für meinen Puffer. In der Mitte eine Aufgabe in Arbeit und eine kontinuierliche “Hintergrundaufgabe”, die mich jeden Tag ein paar Minuten kostet. Rechts das, was ich schon erledigt habe. Das blende ich jedoch meistens aus. Was interessieren mich meine Aufgaben von gestern? ;-)

An der aktuellen Aufgabe arbeite ich konzentriert: ununterbrochen, unnotifiziert. Zumindest, bis ich merke, dass meine Konzentration sinkt oder meine Pausenzeit erreicht ist. Dann wechsle ich mit meiner Aufmerksamkeit. Vielleicht schaue ich für ein paar Minuten Emails durch und trage neue Aufgaben in meinen Puffer ein. Vielleicht lese ich einen Artikel oder gehe Essen. Anschließend weiter mit meiner einen aktuellen Aufgabe.

So kriege ich wirklich was gebacken. Für mich und andere zufriedenstellend und verlässlich. Das Brett ist ein Fokussierungswerkzeug für mich. Gegenüber anderen ist es aber auch ein Rechtfertigungswerkzeug. Wenn ich nämlich dieses Brett mit seinem Füllstand von Puffer (linke Spalte) und Prozessor (mittlere Spalte oben) zeige, dann wird anderen schnell begreifbar, dass auch ich nur begrenzte Kapazität habe. Neue Aufgaben können also nicht einfach sofort begonnen werden. Manchmal sind sogar schon gepufferte Aufgaben zu entfernen zugunsten neuer – ein Preis, den ein Auftraggeber zu zahlen bereit sein muss.

Aber ich will mich hier auch nicht in Details des Umgangs mit so einem “Zeitmanagementbrett” ergehen. Mir war es erst einmal wichtig, Ihnen die Grundpfeiler für mehr persönliche Abarbeitungsverlässlichkeit vorzustellen. Jetzt möchte ich lieber das ganze skalieren…

Das Team als Multiprozessor

Was für uns alle persönlich gilt, gilt auch für ein Team: es ist ein Prozessor, der Input in Output transformieren soll.

image

Insofern gilt für das Team dasselbe wie für Sie: es braucht einen Puffer und Limits. Sonst kann es nicht verlässlich arbeiten. Sonst kann es dem Gesamtsystem nicht anzeigen, wenn es überlastet ist.

image

Organisationen sind also rekursiv. Als Ganzes, in Teilen und auf Ebene des einzelnen Mitarbeiters geht es um Prozessoren, die besser arbeiten, wenn man sie nicht unterbricht. Unzuverlässigkeit kann sich auf jeder Ebene einstellen – und tut das regelmäßig. Deshalb ist eine systematische Betrachtung so wichtig. Verlässlichkeit ist kein Zufall und nichts Softes, Zwischenmenschliches. Sie ergibt sich nicht aus gutem Willen. Ich würde sogar sagen: guter Wille ist oft ihr Gegner. Denn guter Wille (im Verein mit seiner dunklen Schwester Angst) ist begrenzungslos – bis eine physische Grenze erreicht ist.

image

Team und Unternehmen als Prozessoren sind nicht atomar. Das heißt, es können grundsätzlich Aufgaben parallel verarbeitet werden. Es treten mithin Prozesse deutlich in den Blick, d.h. die Transformation über mehrere Schritte hinweg. Dafür werden Unternehmen ja auch gegründet: um etwas in Zusammenarbeit mit niedrigeren (Transaktions)Kosten als ein Markt herzustellen.

Der Hauptprozess der Softwareentwicklung sieht dabei so aus:

image

Wobei jeder Produktionsschritt mit einem oder mehreren “Mitarbeiterprozessoren” besetzt sein kann, die dann wieder in gleicher Weise mit Puffer und WIP-Limit organisiert sind.

Jetzt verstehen Sie vielleicht besser, warum ich glaube, dass es sehr schwer ist, verlässlich ein neues Vorgehensmodell oder sonst eine Veränderung einzuführen. Solange nämlich nicht dieses Grundorganisationsprinzip verstanden ist, ist jegliche Maßnahme auf den Zufall angewiesen. Verlässlichkeit existiert ja nicht einmal auf der untersten Ebene. Wie soll sie da auf höheren Ebenen entstehen?

Zum Glück gelten auf jeder Ebene dieselben Gesetzmäßigkeiten. Es muss also nur einmal für alle Ebenen diese Systematik verstanden werden.

Der Rest ist dann Feinheit :-) Nein, leider nicht. Dann beginnt erst die Arbeit. Nämlich die an der Justierung der Puffer und Limits. Aber das ist eine Geschichte für ein anderes Mal :-) Darüber gibt es viel Literatur. Stichworte sind Theory of Constraints, Lean Production/Development, Kanban, Queueingtheorie usw.

Allen liegt jedoch derselbe Gedanke zugrunde: Dass wir alle auf vielen Ebenen in vernetzten Prozessen arbeiten. Und dass wir deshalb diese Prozesse möglichst sichtbar machen sollten. Denn sonst haben wir es schwer, sie zu verbessern.

Donnerstag, 21. März 2013

Softwareentwurf als ökonomische Notwendigkeit

Softwareentwurf ist selbstverständlich kein neues Thema. Früher war Softwareentwurf als der Codierung vorgelagerte Tätigkeit sogar ein zentraler Punkt jeder Informatikerausbildung. Das war dem Mangel an Prozessorkapazität und Speicher geschuldet. Die Turnaround-Zeiten bei der Codierung waren so lang, dass man sich besser gut überlegte, was man schreibt und dann der Übersetzung übergibt und dann laufen lässt. Das Motto lautete geradezu Think before coding. Fehler waren teuer. Ausdrücklicher Softwareentwurf war also ein ökonomisches Gebot.

Ab der zweiten Hälfte der 1980er begannen sich die Verhältnisse jedoch umzukehren, glaube ich. Der Preis für Fehler beim Codieren fiel plötzlich stark. Zuerst wurde die Hardware besser und verfügbarer (Stichwort PC), dann wurden die Codierungswerkzeuge besser (Stichwort RAD).

Der Engpass „Werkzeug“ wurde bald so weit, dass er durch einen anderen abgelöst wurde. Code war nicht länger das Problem, sondern Codierer. Es kam einfach nicht soviel Funktionalität auf die Straße, wie Kunden sich das wünschten. Das hatte mehrere Folgen:

  • Codierer konzentrierten sich mehr und mehr aufs Codieren. Der Softwareentwurf fiel aus der Gnade, da er scheinbar wertvolle Codierkapazität raubte. Man fühlte sich von der Knechtschaft durch die Maschine befreit und schüttelte daher gern damit bisher verbundene Notwendigkeiten ab.
  • Die Ausbildung der Codierer wurde „entformalisiert“, so dass sich schneller mehr von ihnen auf den Markt bringen ließen. Softwareentwurf war Ballast im Curriculum.
  • Man sann auf Mittel, sich das Codieren überhaupt zu sparen. „Wiederverwendbarkeit herstellen!“ wurde zum Schlachtruf der Softwareentwicklung.

Während viele Jahrzehnte lang (die 1950er bis 1980er) die Softwareentwicklung sich im Grunde um sich selbst drehen musste aufgrund einer eklatanten Mangelsituation bei der Hardware, verschob sich ab den 1990ern endlich der Fokus auf den Kunden. Und der ist seitdem unersättlich. Der Hunger nach Software ist ungebrochen, nein, sogar im stetigen Wachsen begriffen. Mehr Software und länger lebende Software sind gefragt. Berge an funktionalen und nicht-funktionalen Anforderungen soll die Softwareentwicklung erfüllen. Und zwar ASAP!

Software überhaupt auf die Straße zu bekommen, ist seitdem wichtiger, als alles andere. Nachfrage nicht zu bedienen kommt teurer als fehlerhafte Software. Nur in wenigen Bereichen ist die ökonomische Priorität bisher anders geblieben: da wo es um Menschenleben geht.

Doch dieses Bild verschiebt sich. Der Engpass hat sich wieder verschoben. Codierer sind nicht mehr das Problem, auch wenn weiterhin Softwareentwickler fehlen. Die grundsätzliche Kapazität von Codierern ist heute durch Hardware, Softwareinfrastruktur, Tools, Bibliotheken sowie Entwicklungs- und laufzeitplattformen so hoch... dass sie sich selbst durch ihre Produktionsweise behindern.

Der Engpass ist von Ressourcen – zuerst Hardware, dann Softwarewerkzeuge und Menschen – zu einem Grundsatz gewandert. Die Theory of Constraints nennt das einen Policy Constraint. Der lautet salopp formuliert: „Wir hauen den Code raus so schnell die Finger tippen!“

Dieser Grundsatz limitiert heute den Durchsatz der Softwareentwicklung. Die kommt nicht ins Stocken, weil sie unter Hardwaremängeln leidet oder softwaretechnisch irgendetwas nicht umsetzbar wäre. Nein, sie stockt, weil ihr Grundsatz einer überholten Ökonomie angehört.

Der Preis dafür, Nachfrage nicht zu bedienen, ist nämlich gesunken. Oder genauer: Der Preis dafür, Nachfrage heute nicht zu bedienen, ist gesunken. Er ist gesunken gegenüber dem Preis für die Auslieferung fehlerhafter Software. Vor allem wird er aber immer kleiner im Vergleich zu dem, was es kostet, morgen Nachfrage nicht mehr bedienen zu können.

Modern ausgedrückt ist der langjährige Grundsatz nicht nachhaltig.

Das war früher kein Problem. Genauso wie es früher kein Problem war, wenn eine Handvoll Menschen in einem großen Wald Bäume für den Hüttenbau und das Herdfeuer abholzte.

Für große, hungrige Zivilisationen funktioniert derselbe Umgang mit dem Wald jedoch nicht.

Wenn bei naiver Nutzung der Ressourcenbedarf über der „Ressourcenauffrischung“ liegt, dann ist das kein nachhaltiger Umgang mit Ressourcen. Dann kann man heute daraus Nutzen ziehen – aber morgen nicht mehr.

So ist das auch bei „naiver“ Softwareentwicklung. Die funktioniert solange auf grüner Wiese codiert wird. Das war viele Jahrzehnte der Fall. Der Markt war grün, die Software war grün. Es gab keine Altlasten. Und der Hunger nach Funktionalität war so groß, dass alles andere nur wenig zählte. Da konnte man überall seine „braunen Flecken“ hinterlassen. (Von drastischerem Vokabular sehe ich hier einmal ab.)

Doch das hat sich in den letzten 10-15 Jahren verändert. Die Kunden werden anspruchsvoller, sie tolerieren immer weniger Bugs. Vor allem aber muss heute Software schneller und enger am Kunden entwickelt werden. Die Budgets sind gesunken. Und Software ist umfangreicher denn je, muss also länger leben. Auch das ist eine Budgetfrage.

Die grüne Wiese ist bis zum Horizont ein braunes Feld geworden.

Deshalb ist nachhaltige Softwareentwicklung das Gebot der Stunde. Deshalb ist der bisherige Grundsatz der neue Engpass als Policy Constraint.

Daraus folgt für mich aber nicht nur, dass mehr Qualitätssicherung und automatisierte Tests und agile Vorgehensmodelle sein müssen. Es folgt auch, dass Softwareentwurf wieder einen festen Platz in der Softwareentwicklung bekommen muss. Das scheint mir eine ökonomische Notwendigkeit im Rahmen der historischen Bewegungen unserer Disziplin. Denn ausdrücklicher Softwareentwurf macht sich Gedanken über das Big Picture und das Morgen. Wer ständig über dem Code hängt und dort lokale Optimierung betreibt, der fliegt am Ziel Nachhaltigkeit vorbei.

Auszug aus dem Buch “Flow-Design – Pragmatisch agiler Softwareentwurf”, an dem ich nun endlich doch arbeite. Jeden Tag 4 Stunden schreiben… Puh… Demnächst mehr dazu hier im Blog.

PS: Gerade stolpere ich über eine Aussage von Dijkstra:

“[The major cause of the software crisis is] that the machines have become several orders of magnitude more powerful! To put it quite bluntly: as long as there were no machines, programming was no problem at all; when we had a few weak computers, programming became a mild problem, and now we have gigantic computers, programming has become an equally gigantic problem.”

Das entspricht ganz meinem Gefühl – auch wenn das, was er 1972 mit “gigantic computers” gemeint hat, heute lächerlich wirkt.

Freitag, 1. April 2011

Skalierbarkeit als Gläserne Decke in der Agilität

Agile Softwareentwicklung fokussiert sich auf verlässliche Lieferung von Nutzen. Je schneller sie den liefert, desto besser. Meistens. Die Frage ist nur, wie die Geschwindigkeit erhöht werden kann. Wie skaliert Softwareproduktion?

Skalieren ganz allgemein

Skalieren oder skalierbar sein heißt, auf mehr Bedarf so reagieren zu können, das er gedeckt wird. Wenn ein Website normalerweise 10 Transaktionen in der Sekunde verarbeitet, zu Weihnachten aber 1000 Transaktionen pro Sekunde anfallen würden, die Technik die jedoch nicht verarbeiten kann, dann skaliert der Website schlecht.

Einen Produktionsschritt wie “Transaktion verarbeiten” oder “Supportanfrage beantworten” oder “Briefe zustellen” können Sie skalieren, indem Sie die Ausführung beschleunigen (scale-up) oder mehr Ressourcen für die Ausführung bereitstellen (scale-out).

image

Supporter könnten schneller sprechen oder weniger lange überlegen müssen für eine Antwort, Briefzusteller könnten schneller radeln oder weniger mit Passanten plaudern. Beides würde die jeweiligen Produktionsschritte beschleunigen, so dass in derselben Zeit mehr Anfragen beantwortet oder mehr Briefe zugestellt würden.

Oder der steigende Bedarf wird auf mehr Ressourcen verteilt; die Supporter und Briefträger werden nicht schneller, aber es gibt einfach mehr. Wenn 1000 Briefe nicht mehr von einem, sondern 10 Briefträgern zugestellt werden, dann braucht das sicherlich nur noch ein zehntel der Zeit.

Skalieren durch scale-up (Aufbau) ist eigentlich immer grundsätzlich möglich. Bessere Ressourcen schaffen einfach mehr weg.

Skalieren durch scale-out (Ausbau) ist jedoch nicht immer möglich. Manche Tätigkeiten lassen sich nicht auf mehr Ressourcen verteilen. Einen Roman zu schreiben, lässt sich z.B. nicht dadurch beschleunigen, dass man 5 Autoren damit beschäftigt statt einem.

Was nicht heißt, dass man die Romanproduktion nicht mit mehr Ressourcen beschleunigen könnte. Die “Produktionswerkstatt” von Ken Follett macht es vor.

Daraus folgt, dass es noch einen weiteren Weg gibt, zu skalieren: Fokussierung. Ressourcen schaffen mehr, wenn sie sich auf ihre eigentliche Tätigkeit besser konzentrieren können.

image

Ich nenne das mal scale-in, um auszudrücken, dass hierfür eine Wendung nach innen, eine Besinnung auf das Wesentliche nötig ist.

Die Softwareproduktion skalieren

Auf die Softwareentwicklung als Produktionsprozess lassen sich die Skalierungsmuster natürlich übertragen.

image

Was tun, um mehr “Packerl” zu produzieren? Wenn der Bedarf steigt, dann müssen die Kaufwilligen befriedigt werden. Jeder Kunde bekommt ein “Packerl”. Natürlich müssen diese “Packerl” nicht alle gleich aussehen. Der erste Kunde kann als “Packerl” die Softwareversion 1.0.0.0 bekommen, der nächste die Version 1.0.0.1, der übernächste ebenfalls 1.0.0.1, der vierte 1.0.0.2 usw. Manche Kunden bekommen einfach die aktuelle Version, für andere wird speziell ein Feature eingebaut, ohne das sie nicht kaufen würden.

Nochmal: Wie kann die Softwareproduktion eine steigende Nachfrage befriedigen? Auf dieser Abstraktionsebene kann die Antwort nur lauten: scale-up. Die Softwareproduktion als ganzes muss schneller werden. Sie muss neue Wünsche schneller in “Packerl” transformieren oder sie muss einfach nur mehr “Packerl” hinten rausschieben (also Kunden mit einer existierenden Softwareversion befriedigen).

Und wie kann die Softwareproduktion als Ganzes schneller werden? Keine Ahnung. Für eine Antwort ist mehr Detail nötig. Wie funktioniert die Produktion im Einzelnen?

image

Jetzt gibt es Ansatzpunkte. Zum Beispiel könnte der Vertrieb beschleunigt werden, am ehesten wohl durch scale-out. Aber das lohnt natürlich nur, wenn es genug zu verkaufen gibt, d.h. die Softwareentwicklung mehr liefert als bisher in den existierenden Bedarf hinein abgesetzt werden konnte.

Wenn die das aber nicht tut, wenn sie der Engpass ist, wie könnte die Softwareentwicklung skalieren?

Die Softwareentwicklung skalieren

Mein Gefühl ist, dass Unternehmen sich mit der Skalierung der Softwareentwicklung schwer tun. Sie erkennen sie zwar als Engpass – doch sie reagieren unangemessen.

Kann nicht sein – Scale-in

Das die Softwareentwicklung skalieren könnte, dass sie mehr Kapazität hätte und schneller wäre, wenn sie sich denn mehr auf ihr eigentlichen Geschäft konzentrieren könnte, das haben viele Entscheider nicht im Blick. Es kann doch nicht sein, dass die Softwareentwicklung heute etwas Kontraproduktives tut; alles, was sie tut, muss sie tun. Das ist nötig. Support durch Softwareentwickler muss sein. Teilnahme an vielen Besprechungen muss sein. Statusreports und Timetracking muss sein. Dokumentationen müssen gepflegt werden.

Da ist einfach kein Fett, was weggeschnitten werden könnte.

So sehen es viele Entscheider und können also nicht denken, dass ein scale-in hilfreich wäre.

Allerdings denken Sie das, wenn ein Training oder andere Fortbildungsmaßnahme vorgeschlagen wird. Da haben sie das Gefühl, dass das etwas Unnötiges ist.

Darf nicht sein – Scale-up

Wo jedoch Fortbildung (oder gar Ausbildung) fehlt, da kann auch kein scale-up stattfinden. Denn nur durch Lernen kann die Softwareentwicklung mit den gegebenen Ressourcen ja schneller werden. Das kostet zwar erstmal Zeit, doch dann wird noch mehr Zeit gespart.

Flüssigere Technologiebedienung, bessere Prozesse, geschmeidigere Kommunikation: all das kann man lernen, all das bringt höhere Produktivität. Doch das kostet Zeit und Geld. Also sind Entscheider, die in der “Kostendenke” stecken, sehr unwillig, scale-up-Maßnahmen zu bewilligen.

Muss sein – Scale-out

So bleibt denn nur ein scale-out, um die Softwareentwicklung zu beschleunigen. Die Softwareentwicklung muss sozusagen multipliziert werden:

image

Das bedeutet, die Anforderungen werden von mehreren “Entwicklungsinstanzen” parallel bearbeitet.

Hört sich plausibel an, oder? Entspricht auch der Sichtweise auf Software. Die wird nämlich meist als ein Ganzes, als ein Programm, eine Anwendung so gesehen, wie der Auftraggeber sie ordert.

“Entwickeln Sie für uns eine Faktura!” – also kommt am Ende eine EXE (mit ein paar DLLs) heraus.

Dasselbe Spiel bei einer AVA-Software, einer Warenwirtschaft, einer Branchensoftware für den Rolladen- und Jalousiebau… der Markt will eine Lösung, also wird eine EXE produziert.

image

Die Erfüllung des Kundenwunsches hängt von einer Anwendung ab. Die wiederum hängt davon ab, dass alle Anforderungen erfüllt werden. Und die hängen davon ab, dass sie in einer EXE (mit zugehörigen DLLs) platziert werden.

Scale-out als Gläserne Decke

Die Softwareentwicklung mit scale-out zu beschleunigen, hört sich plausibel an, oder? In jedem Fall ist das das übliche Vorgehen. Wo 5 Entwickler sind, da werden 5 Anforderungen (Features) gleichzeitig in Angriff genommen. Na, vielleicht 4, denn manchmal ist eine Anforderung so schwierig umzusetzen, dass sich besser zwei Entwickler darum kümmern.

In jedem Fall wird bei Produktionsengpässen in der Softwareentwicklung reflexhaft zu scale-out gegriffen. Damit scheinen alle Probleme gelöst. Erstens kann man so alle Entwickler auslasten. Zweitens geht es doch so am schnellsten voran. Oder? Drittens kann man das quasi aus dem Stand. Und umso besser, je mehr Anforderungen schon vorliegen. Man muss dann nur noch ein paar mehr Entwickler dran setzen. Am besten solche, die billiger sind.

Leider entstehen die erwarteten Vorteile dabei – wenn überhaupt – nur kurzfristig. Scale-out auf der Basis von Anforderungen führt nämlich zu einigen Problemen:

Problem #1: Konflikte

Anforderungen sind Durchstiche. Für jede Anforderung muss daher potenziell an allen Schichten einer Codebasis geändert werden. Das kann zu Konflikten führen. Das können physische Konflikte in den Quelldateien sein, die ein Versionskontrollsystem anzeigt. Das können aber auch noch schlimmere Konflikte bei logischen Abhängigkeiten sein.

Problem #2: Verzahnung

Wo Anforderungen parallel umgesetzt werden ohne nähere Planung - Warum sollte es die auch geben, denn ein scale-out auf dieser Ebene soll sie ja gerade vermeiden? Wer mehr plante, der müsste kein scale-out nach Anforderungen betreiben. – da entstehen schnell viele Abhängigkeiten im Code. Code der einen Anforderung nimmt Bezug auf Code, der von einer anderen stammt, weil zwischen beiden ja keine Barriere existiert. Entwickler, die auf Anforderungen konzentriert sind, durchforsten die gesamte Codebasis nach hilfreicher, schon existierer Funktionalität und binden sich daran.

Problem #3: Geringe Geschwindigkeit

Jede Anforderung wird nur von einem Entwickler bearbeitet. Der mag das zwar so schnell tun, wie er kann, doch auf das Gesamtsystem gesehen, ist das nicht die maximale Geschwindigkeit. Bei 5 Entwicklern wird jede Anforderung nur mit 20% der Kapazität bearbeitet. Ihre Umsetzung dauert also 5 mal so lange wie (theoretisch) nötig.

Anforderungen parallel in einem Team bearbeiten entspricht Multithreading-Code. Mehrere Threads im Hintergrund nehmen dem Vordergrundthread Arbeit ab; der friert nicht ein. Doch dafür werden die einzelnen Aufgaben nicht mit maximaler Geschwindigkeit bearbeitet. Der Nutzen: es wird Latenz verborgen.

Ist das aber, was Softwareentwicklung soll? Soll sie möglichst schnell mit vielen Aufgaben beginnen, um den Kunden (oder die Anforderungsdefinition) wieder frei zu geben für anderes Kaum.

Softwareentwicklung soll vielmehr jede Anforderung so schnell wie möglich umsetzen. Erstens, um dem Kunden möglichst schnell Nutzen zu bieten. Es geht also nicht um Entlastung von upstream Produktionsschritten, sondern um Bedienung von downstream Produktionsschritten bzw. des Marktes.

Zweitens um so schnell wie möglich Feedback darüber zu bekommen, ob überhaupt erfolgreich umgesetzt wurde. Denn das wissen wir ja: Nur weil irgendwo Anforderungen stehen, kommt am Ende nicht unbedingt Code heraus, der Gefallen beim Kunden findet. Also muss die Softwareentwicklung daran interessiert sein, mit höchster Geschwindigkeit zu jeder Anforderung Feedback zu generieren. Latenz ist mithin nicht zu verbergen, sondern zu reduzieren.

Problem #4: Hoher WIP

Jede Anforderung wird also nur mit ein Anteil von 1/n bei n Ressourcen umgesetzt. Das heißt, jede Anforderung verweilt sehr lange in der Softwareentwicklung. Immer sind also viele verschiedene Anforderungen in Produktion (work in progress, WIP).

Ob diese Produktion ein Erfolg ist und Geld bringt, stellt sich allerdings erst am Ende heraus, wenn der Kunde sie abgenommen hat. Viele Anforderungen gleichzeitig zu bearbeiten, ist zwar sehr geschäftig, verdient an sich jedoch kein Geld, sondern kostet erstmal nur welches.

Jede Anforderung, die begonnen, jedoch noch nicht fertiggestellt und abgenommen ist, kann potenziell Geld verbrennen. Deshalb ist der WIP zu minimieren. Am besten ist der WIP sogar 1.

Bis eine Anforderung fertiggestellt und abgenommen ist, ist sie auf Halde produziert. Sie ist im System und kostet gerade Geld, weil an ihr gearbeitet wird. Oder sie liegt fertig herum, ohne abgenommen worden zu sein und hat damit Geld gekostet. In beiden Fällen ist es ungewiss, ob der ganze Aufwand gelohnt hat; Kapital ist in ihr gebunden. Das ist betriebswirtschaftlicher Quatsch.

Ob es in besonderen Fällen betriebswirtschaftlich günstig sein kann, Anforderungen auf Halde zu produzieren, um einen Puffer zu haben für nachfolgende Produktionsschritte, lasse ich mal außen vor. Darüber kann man reden. Ich glaube nur nicht, dass daran jeman denkt, der scale-out für die Softwareentwicklung anordnet.

Grenze für die Agilität

Wenn Agilität schnell Kundennutzen herstellen will, wenn Agilität daran glaubt, dass häufiges Feedback nötig ist, um zufriedenstellende Software zu entwickeln, dann kann scale-out nicht der richtige Weg sein.

Scale-out auf Anforderungsebene widerspricht der Agilität oder begrenzt sie zumindest. Das heißt, wer Scrum o.ä. einführt in der Hoffnung, nun endlich maximal schnell Software zu produzieren, der lügt sich in die Tasche, solange er die Features im Sprint parallel entwickeln lässt.

Zu einem agilen Vorgehen muss also noch mehr kommen, um das Ziel der Agilität wirklich zu erreichen. Das geht nur, wenn jede Anforderung mit maximal möglicher Geschwindigkeit bearbeitet wird und der WIP minimal ist.

Architektur erhöht Teamskalierbarkeit

Ich verstehe, dass scale-out so verführerisch ist. Es scheint einfacher zu implementieren zu sein als scale-up oder scale-in. Bei scale-up und scale-in geht es ans Eingemachte, an die Kultur eines Unternehmens. Bei scale-out kann (scheinbar) alles/viel mehr beim Alten bleiben. Deshalb ist als erstes zu fragen, ob scale-out nicht doch irgendwie möglich ist?

Aus meiner Sicht lautet die Antwort ja. Scale-out ist möglich, wenn man ein wenig Architektur betreibt. Statt nämlich die Anforderungen des Kunden einfach nur in eine Anwendung umzusetzen, sollte überlegt werden, wie daraus mehrere Anwendungen werden können.

image

Die Zerlegung eines großen Wunschkonvolutes kann im Rahmen der architektonischen Planung über die Zerlegungsebenen Bounded Context und Partition/App geschehen. Jede App steht dann für eine EXE, die einer Nutzerrolle dient.

Mit scale-out kann dann gleichzeitig an Anforderungen verschiedener Apps gearbeitet werden. Das macht einen gewissen Sinn, weil die Zielgruppen verschieden sind. Gegenüber jeder Zielgruppe beginnt die Arbeit an einer Anforderung also möglichst schnell; die Latenz zu verbergen schafft Zufriedenheit.

Dass die Umsetzung der Anforderungen dann immer noch langsam ist, ist nicht so schlimm (Problem #3), denn die Probleme #1, #2 und #4 verschwinden. Ja, selbst #4 verschwindet, weil WIP pro Anwendung gerechnet werden kann, da die Abnahme pro Anwendung erfolgt.

Der Agilität ist damit durchaus Genüge getan. Pro App wird maximal schnell gearbeitet und Feedback eingeholt. Gleichzeitig kommt aber auch das Gesamtsystem voran.

Eine Zerlegung des großen Ganzen in Bounded Contexts und Apps bringt aber nicht nur für die Skalierbarkeit des Teams Vorteile. Auch die Evolvierbarkeit und die Usability steigen.

A little architecture can go a long way ;-)

Arbeitsorganisation erhöht Teamskalierbarkeit

Was aber, wenn sich das Ganze nicht gut in Apps zerlegen lässt? Oder was, wenn es weniger Apps als Entwickler gibt?

Für noch mehr scale-out Effekt reicht es nicht, die Anforderungen in Apps zu gruppieren. Wirklich höchste Geschwindigkeit pro Anforderung erreicht die Softwareentwicklung nur, wenn sie alle Entwickler (soweit sinnvoll) an eine Anforderung setzt. WIP=1 und Minimierung der Latenz sollten im Sinne agiler Softwareentwicklung das Ziel sein.

Das lässt sich erreichen durch Zerlegung der Anforderungen in Aufgaben. Soweit allerdings nur ein erster Schritt. Probleme #3 und #4 mögen damit gelöst sein. Um jedoch auch noch #1 und #2 in den Griff zu bekommen, ist als zweiter Schritt Komponentenorientierung unverzichtbar.

image

Mit Komponenten können alle Entwickler ungestört an ihren Aufgaben arbeiten. Ob dann ein Entwickler immer in einer Komponente Aufgaben umsetzt oder nur Aufgaben für eine App realisiert, das sei dahingestellt. Hier ist nur wichtig, dass komponentenorientierte Aufgaben der Schlüssel zu maximaler Teamperformance ist.

Nur mit Komponenten lassen sich Anforderungen echt parallel realisieren, um Kunden schnellstmöglichen Nutzen zu bieten und von ihnen Feedback zu bekommen. Ohne Komponenten stoßen Teams an eine gläserne Decke bei der Skalierbarkeit.

Mit Komponenten jedoch bekommt die Softwareentwicklung nicht nur echtes scale-out Potenzial, sondern macht den Code einfacher testbar, erhöht die Evolvierbarkeit und hat bessere Chancen auf Wiederverwendung von Funktionseinheiten.

Aber das bedeutet natürlich nicht, dass deshalb scale-up und scale-in vernachlässigt werden sollten. Auch da gilt es Potenzial zu aktivieren, um schneller und kostengünstiger Software produzieren zu können.

Dienstag, 29. März 2011

Flow im Unternehmen – Teil 3 – Engpass Programmierung

Wenn die Softwareproduktion insgesamt besser werden soll, dann muss am Engpass angegriffen werden. Das ist die Programmierung, die Anforderungen in Release Candidates transformiert.

Ober genauer formuliert: Auf einer bestimmten Detaillierungsstufe ist die Programmierung der Engpass. Tritt man weiter zurück, dann ist es die gesamte Softwareentwicklung bestehend aus Programmierung und Qualitätssicherung. Und tritt man näher heran, dann wird sich der Engpass sicher noch präzisieren lassen.

Wie sieht also die Programmierung im Detail aus? Welche Schritte sind nötig, um aus Anforderungen Release Candidate Code zu machen? Ich denke mir das so:

image

Softwareentwicklung ist offensichtlich mehr als “code slinging”. Code entsteht nicht einfach so, sondern sollte das Ergebnis eines systematischen Vorgehens sein. Dazu gehören die Schritte:

  1. Anforderungsanalyse: Definierte Anforderungen müssen von der Programmierung verstanden werden, bevor sie sie umsetzt. Die Anforderungsdefinition ist dafür nicht zuständig; sie formuliert nur Wünsche der Marktes in einer Weise, dass die Programmierung überhaupt einen Ansatzpunkt hat. Erst in der Anforderungsanalyse machen sich dann die Entwickler die Anforderungen zu eigen.

    Anforderungsdefinition und Anforderungsanalyse bilden den Übergang von Außenwelt (Kunden-/Anwendersicht) zu Innenwelt (Entwicklersicht). Den in zwei Schritte mit unterschiedlichem Schwerpunkt zu splitten, halte ich für notwendig, um Anforderungen in top Qualität zu bekommen. Denn sonst wird der ultimative Engpass nicht optimal genutzt.
  2. Sind die Anforderungen verstanden, muss die Implementierung geplant werden. Von Anforderungen “in den Code zu springen”, ist kein geeignetes Vorgehen. Es führt zu mittelfristig schlechter Qualität der Codebasis und nutzt die ultimativ knappe Ressource nicht optimal.
    1. Den Anfang der Planung macht der Architekturentwurf. Er definiert die Grobstruktur des Codes (und der Daten) in Bezug auf die nicht-funktionalen Anforderungen. Hier werden auch die wesentlichen Technologieentscheidungen getroffen.
    2. Im Rahmen des Architekturentwurfs entwirft der nächste Schritt ein Modell des Codes zur Erfüllung der funktionalen Anforderungen. Das Team definiert die nötigen Funktionseinheiten in einer codeunabhängigen Form, um sich nicht in Details zu verlieren. Hier ist auch nochmal Gelegenheit, Technologieentscheidungen zu treffen.
    3. Sind Architektur und Modell für eine Menge an Anforderungen entworfen, ist die Arbeit zu ihrer Umsetzung zu organisieren. Dass alle Teammitglieder optimal im Sinne des Ganzen eingesetzt werden, ergibt sich nicht von selbst. Die Arbeitsorganisation ist mithin die abschließende Maßnahme, um den Engpass mit Input in höchster Qualität zu versorgen.
  3. Schließlich folgt die Implementierung der mit Architektur und Modell formalisierten Anforderungen. Hier liegt der wahre Engpass der Softwareentwicklung, denn hier werden die ursprünglichen Wünsche in Code fixiert. Das kostet im Verhältnis zu den anderen Schritten am meisten Entwicklerkapazität pro Wunsch, weil dieser Schritt das abstrakteste Resultat produziert und höchster technologischer Kompetenz bedarf. Jeder Entwickler ist bei der Implementierung auch auf sich allein gestellt; das Fehler-/Fehlentscheidungspotenzial ist hier in verschiedener Hinsicht am größten.
  4. Zur Qualitätssicherung der Implementierung folgt ihr ein Review. Denn wie auf höherer Ebene klar geworden ist, muss die Softwareentwicklung bzw. die Programmierung als Engpass top Qualität liefern, um nicht durch vermeidbare Nachbesserungen belastet zu werden.

Wenn insbesondere die Prozessdetaillierung für Sie wie ein Wasserfall aussieht, dann verstehe ich das. Aber es wäre ein Missverständnis, bei Anblick eines Flows zu denken, dass am Anfang nur ein Input hineinginge, der dann in einem Durchfluss zu einem Komplettergebnis führen würde.

Der Produktionsprozess macht vielmehr keine Aussage darüber, wie oft er durchlaufen wird und wie groß insbesondere der ursprüngliche Input-Happen ist. Die für die Agilität zentrale Schleife des iterativen Vorgehens ist vielmehr in diesem Prozess von Anfang an enthalten: der Markt bzw. der Kunde steht am Beginn und am Ende des Prozesses.

image

Wasserfall und agiles Vorgehen (oder auch nur iterative Entwicklung, die es ja schon in den 1980ern gab) unterscheiden sich mithin eigentlich nur in der Zahl der Durchläufe durch den Prozess. Und die hängen davon ab, wie groß die Wünsche am Anfang und wie zahlreich die Release am Ende sind.

  • Wasserfall: 1 Wunsch und wenige Releases
  • Agilität: Viele Wünsche und viele Releases

Geschachtelte Engpässe

Ich habe es schon angedeutet: Einen Engpass gibt es in Bezug auf die Abstraktionsebene eines Prozesses. Wenn der Produktionsprozess nun schrittweise verfeinert verschiedene Abstraktionsebenen hat, dann gibt es sozusagen mehrere Engpässe – die allerdings ineinander stecken.

image

Wer die Softwareentwicklung nun verbessern will, der muss zweierlei tun:

  1. Die Engpässe auf allen Ebenen ausreizen, d.h. die Implementierung von allem befreien, was nicht zu ihrer Kernaufgabe gehört: Code für neue Wünsche produzieren, die Implementierung topfit machen in puncto Codegenerierung, die Implementierung Code von top Qualität herstellen lassen. Und dann die Programmierung als umfassenden Produktionsschritt ausreizen. Und dann die Softwareentwicklung als noch umfassenderen Schritt ausreizen.
  2. Die Qualität des Input für die Engpässe im Rahmen des Möglichen maximieren. Das sind zum einen die Anforderungen und zum anderen die “Arbeitspakete” für die Implementierung. Das heißt, Input und Output der Planung sind das A und O für eine top Implementierung.

Klingt eigentlich ganz normal, oder? Wer etwas Gutes herstellen will, der braucht erstens eine gute Vorstellung davon, was das sein soll (Anforderungen).

Und der braucht zweitens einen guten Plan, wie das Ergebnis effizient hergestellt werden und wie es aussehen soll. Bei all der Diskussion um agiles Vorgehen ist das nur, so scheint es, in Vergessenheit geraten. Da meinen viele, gerade die Planung sei überflüssig. Hauptsache, die Anforderungen schnell in Code gießen und ab damit zum Kunden.

Doch weit gefehlt! Aus der Theory of Constraints (TOC) können wir ableiten, dass dann der Engpass heiß läuft. Denn wo nicht auf Qualität geachtet wird, kehrt der Code mit Macht zurück und belastet den Engpass mit Nachbesserungen. Der kommt dann immer weniger dazu, seinen eigentlichen Job zu machen. Die TOC sagt also das voraus, was immer wieder in Softwareunternehmen zu sehen ist: überlastete Entwickler, die mit der Lieferung von neuen Features nicht hinterherkommen.

Besser leben mit dem Engpass

Was im Detail ausmacht, dass der Engpass nicht mal seine grundsätzliche Kapazität für neue Wünsche an den Start bringen kann, ist erstmal gar nicht so wichtig. Viel wichtiger ist die Anerkennung, dass es erstens überhaupt einen Engpass gibt. Und zweitens dass der für das Wichtigste freigehalten werden muss, das er dann mit Qualität produzieren muss. Also nicht nur überhaupt produzieren, sondern eben mit Qualität, innerer Qualität.

Für Entscheider ergeben sich daraus vor allem vier Fragen:

1. Wie halte ich den Engpass frei für das Wesentliche?
2. Wie sichere ich hohe Qualität für den Output des Engpasses?

Beide betreffen das Ausreizen des Engpasses (exploiting the constraint). Dazu kommt dann noch die Frage, was zu tun ist an den Nicht-Engpass Prozessschritten (subordination of non-constraints). Denn die müssen nicht mehr auf Volllast laufen.

3. Wie steigere ich die Qualität des Outputs vor dem Engpass?

Und schließlich:

4. Wie steigere ich die Kapazität des Engpasses?

Verbesserungsmaßnahmen lassen sich diesen Fragen zuordnen und somit priorisieren. Meine Rangfolge sieht so aus:

1. Qualität des Inputs für den Engpass erhöhen. Weniger Garbage in bedeutet weniger Garbage out – und insofern weniger Nachbesserungen. Die Qualität vor dem Engpass zu erhöhen, ist einfacher als im Engpass, weil die Schritte vor ihm ohnehin mehr Kapazität haben. Upstream Prozessschritte sollten Sie von Engpass-überlastenden Ausstoßmengen umstellen auf höhere Qualität.

2. Den Engpass frei halten für das Wesentliche. Das ist auch noch relativ einfach möglich, weil dafür meist keine Investitionen nötig sind, sondern nur die Veränderung von kontraproduktiven Grundsätzen.

Nach Maßnahmen dieser beiden Kategorien kann sich der Engpass mit seinen – womöglich beschränkten - Kompetenzen und Methoden zumindest voll auf die Umsetzung qualitativ hohen Inputs konzentrieren. Er tut das Wichtigste so gut er eben kann.

3. Die Qualität des Engpass-Outputs erhöhen. Mit der Kapazität, die dem Engpass nun zur Verfügung steht, sollte er unbedingt bemüht sein, die inzwischen hohe Qualität seines Input zu halten.

4. Die Produktivität des Engpass steigern. Am Schluss stehen Maßnahmen, die die vorhandenen Ressourcen stärken oder die Ressourcenzahl vergrößern. Das lohnt jetzt erst, da andere Probleme sonst nur kaschiert würden.

Und was sind nun Maßnahmen in diesen Kategorien? Wie lässt sich konkret mit dem Engpass umgehen? Mir fallen da einige Maßnahmen ein, von denen manche üblich und manche eher selten sind:

Input-Qualität erhöhen

Anforderungen

image

Anforderungen können in zweierlei Hinsicht verbessert werden.

Als erstes ist dazu die Frage zu stellen: “Braucht der Kunde das wirklich?” Der sagt reflexartig natürlich, “Klar! Das will ich haben.” Doch die Anforderungsdefinition sollte sich davon nicht beirren lassen. Jede Reduktion oder besser Fokussierung von Anforderungen hilft, den Engpass zu entlasten. Dazu gehört auch die Priorisierung. Wenn es denn wirklich wahr ist, das der Kunde etwas haben möchte, dann gleich nachhaken, “Ist das sehr wichtig, muss es sofort sein – oder kann es warten?” Dazu gehören auch Überlegungen, ob ein Wunsch komplett realisiert werden muss oder ob zumindest manches weggelassen oder niedriger priorisiert werden kann.

Als zweites ist dann für jede Anforderung die tatsächlich, tatsächlich an die Softwareentwicklung gehen soll eine absolute Präzisierung (im Rahmen des Möglichen) vorzunehmen. Unsicherheit des Kunden ist dabei wieder ein Zeichen dafür, dass die Anforderung abgelehnt werden sollte. Das ist ihm klar zu machen. Wenn er dennoch darauf besteht, dann nachhaken und Akzeptanztestfälle einfordern. Eingabe/Interaktionen und erwartete Ausgaben/Seiteneffekte sind zu protokollieren. Je maschinenlesbarer desto besser.

Requirements Engineering ist die Kunst der Anforderungsdefinition. Nicht umsonst hat sich diese Disziplin herausgebildet. Es ist schwer, Anforderungen von hoher Qualität aus dem Kunden herauszubekommen. Aber es ist nötig, um den Engpass zu schonen. Hier schlummert enormes Verbesserungspotenzial in den meisten Projekten; denn üblich ist es, sich mit Schwammigem zufrieden zu geben, weil es einen (unausgesprochenen) Grundsatzengpass gibt der lautet, man solle sich nicht solange damit aufhalten und lieber das Codieren anfangen. Und außerdem dürfe man den Kunden nicht so mit penetranten Fragen nerven oder gar Wünsche ablehnen, denn es sei ja der König Kunde, mit dem man es zu tun habe.

Bitte verstehen Sie mich richtig: Mir geht es hier um die Qualität (!) der Anforderungen, nicht die Quantität. Aus dem Produktionsprozessdiagramm leitet sich nicht ab, dass man zuerst alle Anforderungen und auch noch in höchster Qualität sammeln müsse. Im Gegenteil. So wenige Anforderungen wie möglich sollten gesammelt werden; nur soviele, bis die Architektur halbwegs festgezurrt werden kann und nur soviele bis ein erster nicht trivialer Nutzen für den Kunden produzierbar ist. Dafür sind immer wieder erstaunlich wenige Anforderungen nötig, wenn man es ausnutzt, das die ja auch auf verschiedenen Abstraktionsniveaus formuliert sein können.

Mit der Erfahrung lernen Sie aber, zwischen wichtig und weniger wichtig zu unterscheiden. Und Sie werden mutiger, mit einer kleineren Menge zu beginnen, wenn Sie wissen, dass Sie in der Programmierung Methoden einsetzen, die Strukturen produzieren, die leicht angepasst werden können.

Denn eines ist zu erkennen: Möglichst viele Anforderungen wollen nur die erheben, die Angst haben, sich mit weniger in eine Code-Ecke zu pinseln, aus der sie dann nicht mehr herauskönnen. Je korrekter und evolvierbarer Ihre Codebasis jedoch ist, desto weniger Angst müssen Sie in dieser Hinsicht haben. Je höher die Qualität der Arbeit der Programmierung, desto fitter wird sie für kleine, hochqualitative Anforderungen.

Gut verdaubar ist der Input von der Anforderungsdefinition für die Softwareentwicklung also auch, wenn er in kleinen Happen ankommt. Das ist der inhärenten, durch keine noch so peinliche Kundenbefragung zu vermeidenden Unschärfe auch ansonsten hochqualitativer Anforderungen geschuldet. Kunden können Anforderungen nicht besser formulieren als sie ihre Wünsche selbst kennen – und das ist oft nicht sehr genau. Anforderungen sorgen daher immer für ein gewisses Maß an Nachbesserung. Ohne iterative Annäherung an die Kundenzufriedenheit geht es nicht. Je kürzer die Feedbackschleife, desto besser.

Aufgaben

image

Was produziert schneller ein Ergebnis, die Verteilung von mehreren Aufgaben auf mehrere pseudo-gleichzeitige Threads auf einem Prozessor oder die echt gleichzeitige die Bearbeitung einer Aufgabe auf mehreren Prozessorkernen? Die Antwort sollte klar sein: Die Multi-Core-Verarbeitung einer Aufgabe ist schneller.

Multithreading macht Sinn, um Latenz zu verbergen. Wenn der Anwender eine langdauernde Verarbeitung anstößt, soll das UI nicht einfrieren bis zum Ergebnis. Also wird die Verarbeitung in einen Hintergrundthread ausgelagert. Dass die Verarbeitung lange dauert, ist dem Anwender somit verborgen. Stößt er mit der gewonnen Bewegungsfreiheit dann aber noch eine und noch eine Verarbeitung im Hintergrund an, dann laufen all die Bearbeitungen nur pseudo-parallel (auf einem Prozessor). Jede einzelne dauert viel zwei- oder dreimal länger als wäre sie das einzige, mit dem sich der Prozessor beschäftigt.

Gegenüber dem Kunden ist es jedoch kontraproduktiv, die Dauer der Implementierung zu verbergen. Gerade angesichts der nicht auszuräumenden Unsicherheit, die auch in hochqualitativen Anforderungen steckt, ist es wichtig, jede Anforderung so schnell wie möglich zu codieren. Latenz darf nicht verborgen, sondern muss reduziert werden.

Die Aufgaben, die die Planung an die Implementierung weitergibt, müssen deshalb so formuliert sein, dass das Implementierungsteam sie mit höchster Geschwindigkeit in Code transformieren kann. Nur so fließt zügig etwas zurück zum Kunden, zu dem er Feedback geben kann.

Das bedeutet, die Aufgaben müssen möglichst alle Teammitglieder parallel (!) an einer (!) Anforderung (bzw. einer Anforderungsscheibe) zum Einsatz bringen. Das ist sozusagen Multi-Core-Implementierung in action. Alle Ressourcen ziehen dann an einem Strang, um eine Anforderung umzusetzen.

Wenn Aufgaben das ermöglichen, ist das allerdings nur eine Facette hoher Qualität. Eine andere, nicht zu vernachlässigende ist, dass Aufgaben keine Implementierungsunsicherheiten enthalten sollten. Als Aufgabe sollte ans Implementierungsteam nur gehen, wofür 100%ige Kompetenz existiert. Ausprobieren, Lernen, Forschen: das sind keine Tätigkeiten im Produktionsschritt Implementierung. Wenn Anforderungen Elemente enthalten, die über die technische/methodische Kompetenz des Implementierungsteams hinausgehen, dann dürfen daraus (noch) keine Aufgaben gemacht werden.

Unsicherheiten und fehlende Kompetenz sind in einem separaten Prozess auszugleichen. Spike Solutions oder Prototypen sind ein probates Mittel, um Technologien wie Lösungsansätze für konkrete Anfordeurgen zu evaluieren, bevor sie an die Implementierung gehen. In die Planung im obigen Diagramm habe ich sie jedoch nicht eingezeichnet, um das Verständnis des Hauptproduktionsflusses zu erleichtern.

Konzentration auf das Wesentliche

Wenn die Input-Qualität am Engpass stimmt, dann gilt es, den Engpass ballastfrei zu machen. Er soll sich volll auf seine Aufgabe konzentrieren. Das ist die Transformation von Anforderungen in Code.

Tun das Softwareentwickler denn aber nicht den ganzen Tag? Nein. Ich kenne keinen Entwickler, der sich nicht in seiner Transformationsarbeit gestört fühlt. Es gibt keinen, der seine acht täglichen Arbeitsstunden voll den Tätigkeiten dieser Kette von Transformationsschritten im Sinne der Produktion neuer Features widmet:

image

Die Störungen fallen für mich in drei Kategorien:

  • Unterbrechungen: Jede Form von Unterbrechung behindert den Engpass. Selbst wenn der Grund der Unterbrechung zur Engpasstätigkeit gehören sollte, reduziert sie seine Kapazität. Unterbrechungen, d.h. ein nicht selbstbestimmter Fokuswechsel, haben einfach zur Folge, dass anschließend Zeit zur Refokussierung aufgewandt werden muss. Mentaler Zustand lässt sich nicht einfach auf einen Stack legen wie aktuelle Parameter einer Methode. Der unterbrochene Entwickler muss also mindestens Aufwand treiben, um “wieder reinzukommen” in was auch immer er vor der Unterbrechung getan hat.

    Leider herrscht an vielen Arbeitsplätzen eine "Unterbrechungskultur”. Jeder kann jederzeit “reinschneien” und die Arbeit anderer unterbrechen. Ein deutliches Symptom dafür sind Entwickler, die mit Kopfhörer arbeiten oder besonders früh/spät anwesen sind, “um endlich mal in Ruhe arbeiten zu können.”

    Die Agilitätsbewegung mag sogar dazu beigetragen haben, Hemmschwellen bei Unterbrechungen abzutragen. Denn wer echt agil arbeiten will, der steckt alle Entwickler in einen Raum, den Team Room. Informationen können dort maximal frei fließen.

    Das ist wahr – hat aber seinen Preis. Ob der aber immer im Blick ist? Der Preis ist Defokussierung und damit eine Vergrößerung der Wahrscheinlichkeit, dass sich Fehler einschleichen. Denn ungestörte Konzentration ist ein wesentlicher Bestandteil hoher Qualität.

    Aber auch die übliche hierarchische Struktur in Unternehmen sorgt gern für Unterbrechungen. Ein Vorgesetzter darf ja schließlich jederzeit Auskunft verlangen oder die Arbeit dirigieren. Die Steigerung ist dann die Unterbrechung durch den ultimativen Vorgesetzten: den Kunden. Wenn der Support auf die Softwareentwicklung durchgreifen kann, ist oft kein Halten; Unterbrechungen, die bis zur Änderung der aktuellen Aufgabe führen, sind dann möglich.

    Gemeinschaftliche Arbeit, ein Team sein und Unterbrechungsfreiheit stehen in einem Spannungsverhältnis. Beides ist nötig. Mir scheint jedoch, dass aus Gründen der Mitarbeiterführung und falsch verstandener Methodik derzeit das Pendel zur Seite einer “Unterbrechungskultur” ausschlägt. Wo alle in einem Raum sind und jederzeit unterbrochen werden kann, da kann kontrolliert werden. Hinzu kommt, dass größere Räume für viele Entwickler kostengünstiger sind als individuelle Büroräume für einen oder max. zwei Entwickler.

    Aber es gibt auch löbliche Gegenbeispiele. Von Microsoft kann man halten, was man will, aber erfolgreich ist das Unternehmen. Und es hat einen ungeheuren Ausstoß. Begründet ist der auch im Umgang mit den Mitarbeitern, die (in den USA) alle ihr eigenes Büro haben – egal wie klein das ist –, in dem sie sich einrichten können, wie sie mögen.

    Andere Maßnahmen gegen Unterbrechungen sind “Bitte nicht stören”-Schilder am “Entwicklerraum” zumindest für einige Stunden pro Tag. Oder die Möglichkeit, Homeoffice-Tage einzulegen. Oder die Einhaltung eines minimalen Prozesses, der verhindert, das Vorgesetzte jederzeit ihr persönliches Informationsbedürfnis bei jedem Entwickler befriedigen können. Oder ausdrückliche Supportzeiten, wenn denn der Support durch Entwickler nicht zu vermeiden ist.

    Unterbrechungen sind ein weit unterschätzter Kapazitäts- und Qualitätsfresser. Tun Sie etwas dagegen am Engpass. Nur so kommen Sie in die Nähe seiner theoretisch verfügbaren Kapazität für geldbringendes Neues.

 

  • Wiederholung: Wer etwas wiederholt, der schafft währenddessen nichts Neues. Entwickler sollen aber möglichst viel Neues schaffen – deshalb sollten sie sich nicht in Wiederholungen ergehen.

    Tätigkeiten, die mehr als drei Mal manuell ausgeführt werden, sollten auf den Prüfstand. Sind sie wirklich nötig, gar in Wiederholung? Wenn ja, lassen Sie sich automatisieren?

    Der Vorteil einer Automatisierung ist sogar dreifach: Nicht nur setzt die Automatisierung Entwicklerkapazität frei für Neues, sie reduziert auch die Fehlerträchtigkeit der Tätigkeit. Und das ist gut, weil Fehler zu Nachbesserungen führen, von denen ja nun hinreichend klar ist, dass sie unbedingt zu vermeiden sind.

    Automatisierbar ist viel. Tests auf allen Ebenen (vom Unit Tests bis zum Akzeptanztests); darüber gibt es hinlänglich Literatur. Aber auch das “Zusammenbauen” von Softwaresystem (Continuous Integration) und das Deployment (Continuous Delivery).

    Viele Softwareteams hängen da allerdings noch weit hinter dem Machbaren hinterher. Ein Release ist oft noch eine periodisch wiederkehrende Drohung für alle Mitglieder, die womöglich sogar mit Urlaubssperre belegt ist.

    Der dritte Vorteil der Automatisierung besteht in der Unabhängigkeit von bestimmten Personen. Sie löst Wissensmonopole auf. Jeder Vorgesetzte sollte schon deshalb daran interessiert sein, soviel wie möglich zu automatisieren, weil er sich damit unabhängig macht von den Grillen einzelner Entwickler.

    Automatisierung bedeutet allerdings nicht immer, dass eine Tätigkeit in Software gegossen wird. Auch die Delegation ist eine Form von Automatisierung. Wenn ein Ablauf so vereinfacht wird, dass ihn nicht mehr der teure Entwickler im Engpass, sondern vielleicht eine Hilfskraft oder gar eine anonyme Crowd-Sourcing-Menge durchführen kann, dann ist das ebenfalls ein Gewinn.

    Gegen die Automatisierung spricht für viele Entwickler und Entscheider, dass die selbst ja Zeit und damit Geld kosten würde. Das ist natürlich richtig erkannt – aber sie deshalb nicht in Angriff zu nehmen, ist zu kurz geschlossen. Wer mit dem spitzen Bleistift rechnet, der sollte richtig rechnen. Richtig bedeutet hier jedoch: auf das Gesamtsystem bezogen und nicht lokal optimierend. Dazu aber mehr in einem anderen Blog-Artikel. Die TOC hat einiges zum Thema Geld zu sagen unter dem Stichwort Durchsatzrechnungswesen (Throughput Accouting). Und danach kostet eine Stunde Entwicklerkapazität, die in eine Wiederholung geht, also den Entwickler für Geldbringendes blockiert, mehr als den Entwicklerstundenlohn. Viel mehr!

    Doch einstweilen mögen zumindest die Vorteile in Bezug auf Qualität und Personenunabhängigkeit dem Skeptiker Prozessoptimierungsfutter sein.

 

  • Abweichung: Wenn Programmierer gerade nicht unterbrochen werden oder sich in Wiederholungen ergehen, dann sind sie immer noch nicht notwendig mit dem Wesentlichen befasst. Ein noch größeres Übel als die beiden bisher behandelten Störungen sind Abweichungen vom Wesentlichen. Entwickler tun einfach häufig, was nichts mit der Produktion von Neuem zu tun hat. Das wird ihnen durch einen Grundsatzengpass aufgedrückt – oder sie wählen es selbst.

    Beispiele für verordnete Abweichungen sind Dokumentationsaufgaben, Support, allgemeine Besprechungen, Statusreports, minutiöse Zeiterfassung oder anderer “Formularkram”.

    Jede einzelne Abweichung hat für irgendwen irgendwann natürlich mal Sinn ergeben. Allemal in Summe sind die in den meisten Unternehmen jedoch parasitär. Sie rauben wertvolle Kapazität am Engpass. Hier eine Minute für eine Umständlichkeit, dort eine Stunde im unproduktiven Meeting… das summiert sich. Neulich hatte ich im Clean Code Developer Training eine Reihe von Entwicklern aus einem großen Unternehmen, die zwischen zwei Trainingsblöcken quasi nicht entwickelt haben, sondern nur dokumentiert. Das ist pure Verschwendung der Engpassressource.

    Doch nicht immer ist “das System” schuld an Abweichungen. Entwickler tendieren dazu, sich selbst vom Wesentlichen abzulenken. Typisch sind dafür in Make-or-Buy-Situationen Entscheidungen für Make.

    Statt ein Tool, eine Bibliothek von der Stange zu nehmen, wird selbst entwickelt. Typisch sind objektorientierte Datenzugriff-Frameworks oder Logging-Infrastruktur oder spezielle GUI-Steuerelemente, die 90% von dem replizieren, was Telerik & Co schon bieten, um 10% angeblich Wichtiges, nein, Zentrales, Unabdingbares für den Kunden hinzuzufügen.

    Immer wieder verschwenden Entwickler Ihre Kapazität in dem Glauben, es doch besser machen zu können (und zu brauchen), als auf eine Problemstellung fokussierte Anbieter am Markt. Das wird dann begründet mit einer Flexibilität und Unabhängigkeit, von der niemand weiß, ob sie überhaupt je relevant wird. Oder es wird mit Kundenwünschen begründet, die so unabdingbar wie exotisch seien, dass nur eine Eigenentwicklung sie abdecken könnte.

    Mein Gefühl ist jedoch, dass hier oft rationalisiert wird. Der wahre Grund für Make-Entscheidungen sind ein Gefühl von Kontrollverlust mangels Methode. Oder schlicht eine “Opferhaltung” gegenüber dem Kunden, die jedes “Widerwort” verbietet. Oder es herrscht Unkenntnis über die Möglichkeiten der kaufbaren Lösungen am Markt.

    Make-Entscheidungen verweisen mithin oft auf tieferliegende Probleme. Ihnen kann zum Beispiel entgegengewirkt werden mit besseren Anforderungen, die deutlicher Unterscheiden, was wirklich, wirklich essenziell ist und was nur nice-to-have. Die Anforderungsanylse in der Planung kann hier auch aufklärend tätig sein, indem sie aufzeigt, wie teuer Make wirklich ist. Denn nicht nur kostet Make fast immer mehr Zeit als Buy, es folgt aus Make auch die Notwendigkeit zur Pflege einer größeren Codebasis. Engpass-Kapazität wird damit doppelt abgezogen.

    Im Zweifelsfall sollte daher die Entscheidung für Buy und eine systematisch geplante Codestruktur fallen, die es erlaubt, die Entscheidung ggf. zu revidieren. Anfangen mit dem eingekaufen Persistenzframework – und zur Not später ersetzen, falls sich herausstellt, dass die Leistung nicht ausreicht. Saubere Separation of Concerns lautet der Name eines probaten Mittels gegen die Angst vor irreversiblen Entscheidungen.

    Abweichungen vom Wesentlichen, d.h. der Produktion von Neuem, lauern überall. Seien Sie sensibel dafür und schieben Sie ihnen einen Riegel vor. Das setzt ungeahnte Kapazität im Engpass frei.

Nur wenn der Engpass sich auf seine Hauptaufgabe konzentriert, kann er effizient etwas mit der hohen Qualität anfangen, die ihm geliefert wird. Zum Glück ist das nicht so schwer. Störungen der beschriebenen Art zu vermeiden, sollte im Grunde wenig bis gar nichts kosten. Das Unternehmen muss nur das Störende sein lassen. Das mag diejenigen schmerzen, die störende Grundsätze aufgestellt haben – doch als Gewinn winkt freigesetzte, fokussierte Kapazität, mit der Neues produziert werden kann.

Output-Qualität erhöhen

Was soll ein Engpass tun, der mit höchster Input-Qualität beliefert wird und darauf seine Kapazität störungsfrei anwenden darf? Er soll Qualität produzieren. Wie das?

Review Release

image

Von innen nach außen betrachtet ist der erste Engpass die Implementierung. Sie transformiert als Aufgaben formulierte Anforderungen in Code. Ihr Output ist ein Review Release. Die Implementierung muss bei ihrer Transformationsarbeit zweierlei sicherstellen:

  • Schadlosigkeit: Egal, was die Implementierung tut, ihre oberste Priorität muss sein, nicht zu schaden. Das heißt, sie darf funktionierenden Code nicht kaputt machen. D.h. die vornehmste Aufgabe der Implementierung ist es, Regressionsprobleme zu vermeiden. Code darf durch sie nicht in einen schlechteren Zustand zurückfallen. Und schlechter ist jeder Zustand, bei dem vormals Funktionierendes nicht mehr funktioniert. Das ist unter allen Umständen zu vermeiden, nicht nur weil es zu Nachbesserungen führt, sondern weil jede Regression am Vertrauen nagt, das Anwender gefasst haben.

    Anwender leben mit vielem. Sie leben sogar mit Bugs. Aber noch frustrierender als Bugs sind Bugs dort, wo vorher keine waren. Die untergraben jedes Gefühl von Verlässlichkeit, das sich eine Software mühevoll erarbeitet haben mag.

    Die Schadlosigkeit von Veränderungen lässt sich nur nachweisen, wenn die Software anschließend in allen Bereichen betestet wird. Funktionale Abhängigkeiten ziehen sich weit durch ein Softwaresystem, so dass nicht triviale Änderungen kaum vorhergesagt werden kann, auch welche Teile sie sich auswirken. Es ist daher am besten, schlicht immer alles wieder und wieder zu testen.

    Das ist natürlich nur ökonomisch machbar mit automatisierten Tests und automatisierter Integration. Der Hauptzweck von automatisierten Tests ist mithin nicht die Feststellung der Fehlerfreiheit neuen Codes, sondern die Regressionsfehlerfreiheit alten Codes zu “beweisen”.

    Hier ist eindeutig der Implementierer gefragt. Er stellt den Code her, also ist er für dessen Qualität zuständig. Regressionstest auf eine Qualitätssicherung (oder gar den Kunden) zu verlagern, ist falsch im Sinne sauberer Produktion.

 

  • Nützlichkeit: Veränderungen sind nur nützlich, wenn sie nicht nur die funktionalen wie nicht-funktionalen Anforderungen erfüllen, sondern das auch noch fehlerfrei tun. Dass bekannt ist, was diese Anforderungen sind, dafür sorgen hochqualitative Anforderungsdefinition und Planung. Die Implementierung muss sie dann “nur” noch in Code gießen.

    Das ist natürlich immer noch eine anspruchsvolle Aufgabe. Bei aller Planung bleibt für die Implementierung selbstverständlich Kreativitätsfreiraum. Code Cowboys sind dort jedoch fehl am Platze. Wer schneller Produktionscode raushaut als sein Schatten ziehen kann, ohne die Korrektheit solide geprüft zu haben, der dient nur bedingt der Nützlichkeit.

    Für die Nützlichkeit sind deshalb solides Domänenwissen unabdingbar, um die Anforderungen optimal zu verstehen. (Achtung: Die Domäne muss nicht unbedingt die Geschäftsdomäne des Softwaresystems sein! Auch Security oder Verteilte Systeme sind Domänen, in denen erheblicher Code nötig sein kann.) Dazu kommt solides Technologiewissen, um die Anforderungen/Aufgaben optimal umzusetzen. Und schließlich ist zu prüfen, dass diese Umsetzung tatsächlich gelungen ist. Fehlerfrei.

    Implementierer testen deshalb gegen aufgabenbezogene Akzeptanzkriterien, die von der Planung als Vorstufe der Implementierung geliefert werden müssen. Wenn ein Implementierer Code weiterreicht an den nächsten Prozessschritt, soll er ruhig und gewiss sein, dass er nicht nur für Funktionalität, sondern auch für Korrektheit gesorgt hat. Und zwar automatisiert, denn seine Tests müssen als Regressionstests zukünftig wiederholt werden können (s.o.).

    Im Implementierer als Kernengpass müssen Smartness und Sorgfalt vereint sein. Sie befähigen ihn, das Gewollte zu verstehen, es effizient und effektiv umzusetzen – und das auch noch fehlerfrei.

    Technologiekompetenz spielt dabei nur ein untergeordnete Rolle. Sie lässt sich vergleichsweise schnell erwerben (s.u. Produktivität steigern). Wichtiger ist eine Persönlichkeit mit schneller Auffassungsgabe und Verantwortungsbewusstsein. Wie Joel Spolsky schon sagte: “smart and getting things done”, so sollen Implementierer sein.

    Sollte es an solchen gut organisierten smarten Entwicklern im Team noch mangeln, dann kann Pair Programming helfen. Indem zwei Entwickler an einer Maschine sitzen, wird jeder einzelne entlastet. Innere und äußere Codequalität können durch zwei Personen repräsentiert werden, die jede für sich darauf achtet, dass ihre Werte Beachtung finden.

    Das dient dann nicht nur der Nützlichkeit, sondern auch dem Teamgeist sowie der Ausbildung. Ohne formale Instruktion kann hier Wissen weitergegeben werden.
Release Candidate

image

Die Programmierung ist der die Implementierung umfassende Engpass. Sie wandelt Anforderungen in Release Candidates um. Was sie verlässt, könnte aus ihrer Sicht zum Kunden gehen. Dessen ist sie sich zunächst einmal sicher, weil sie ihren Input einer Qualitätskontrolle unterzieht (Anforderungsanalyse) und die eigentliche Transformation durch die Implementierung sorgfältig vorbereitet.

Dennoch könnte der Transformationsoutput suboptimal ausfallen. Nicht unbedingt im Hinblick auf die (nicht) funktionalen Anforderungen, sondern in Bezug auf die innere Qualität. Die Fixierung von Anforderungenn in Code ist so essenziell, dass sie nicht einfach der Implementierung überlassen werden kann. Bei aller Sorgfalt soll die ja nicht die Aufgaben der Planung in Frage stellen. Dort aber können sich Unsauberkeiten oder gar Fehler eingeschlichen haben, die erst durch die Implementierung sichtbar werden.

Deshalb sollte die Programmierung im Anschluss an die Implementierung überprüfen, ob deren Output den Qualitätsansprüchen in jeder Hinsicht genügt. Nicht nur Fehlerfreiheit, sondern Konformität mit der Planung und Eignung der Planung vertragen einen genauen Blick. Die Umsetzung der Planung lässt sich auch nicht anders sicherstellen; den Code müssen sich Menschen anschauen.

Das Mittel dafür sind Codereviews. Hier sitzen Implementierer und Planer zusammen über der Frage, ob die Transformation den Erwartungen entspricht. Hält sie unmittelbar, was sie soll, d.h. ist sie funktional und korrekt? Und hält sie langfristig, was sie soll, d.h. ist sie evolvierbar. Reviews zurren die Qualität von innen fest, bevor der Code an den Kunden geht.

Darüber hinaus sind Reviews ideale Orte, um Wissen im Team zu verteilen. Technologieverständnis, Grundsätze, Konventionen breiten sich durch Reviews ganz natürlich aus. Reviews sind also nebenbei eine kostenlose Fortbildungsmaßname.

Release

image

Wenn die Programmierung mit dem Code zufrieden ist, dann ist das schon eine gute Sache. Aber ob ein Release Candidate wirklich reif für den Kunden ist, sollten nicht Programmierer festlegen. Dafür braucht es vielmehr den Blick einer codeunabhängigen Instanz.

Die Programmierung hat die Qualität des Code von innen festgezurrt. Der Markt (vertreten durch den Vertrieb) ist daran allerdings nur zum Teil interessiert. Er blickt von außen auf die Software. Deshalb sollte die Qualität auch noch von außen festgezurrt werden. Das ist die Aufgabe der Qualitätssicherung (QS).

Ihre Leistung besteht darin, einen schon grundsätzlich nützlichen Code daraufhin zu prüfen, ob er wirklich den Ansprüchen des Marktes genügt. Die misst den Code daher nochmal ganz anders an den Anforderungen. Hier geht es um Usability, flüssige Installation, Integration mit anderen Systemen, oder “Extremfälle” der Bedienung.

Die Programmierung hat nur einen begrenzten Horizont was den realen Einsatz ihres Codes bei den Anwendern angeht. Das ist notwendig so, weil Entwickler keine Anwender, keine Geschäftsdomänenexperten sind. Das sollen sie auch nicht sein. Dennoch oder gerade deshalb muss durch deren Brille eine Qualitätssicherung stattfinden - im Haus der Softwareentwicklung und nicht erst beim Kunden.

Die QS ist verbunden mit der Anforderungsdefinition. Beide sitzen im Grunde auf derselben Abstraktionsebene als Klammern um die Programmierung herum. Was vorne gefordert wird, muss hinten erfüllt sein. Das prüft die QS mittels möglichst automatisierter Tests. Dabei repliziert sie natürlich nicht alle Tests, die schon in der Implementierung gelaufen sind. QS-Tests sind Integrationstests. Sie checken, dass die Teile gut zusammen funktionieren.

Die QS braucht andere Kompetenz als die Programmierung. Deshalb sollten Programmierer nicht gleichzeitig QS-Beauftragte sein. Es ist auch zu vermeiden, dass sich durch Personalunion die QS “etwas in die Tasche lügt”. In gewisser Weise sind Programmierung und QS eher Antagonisten.

Während die Implementierung Unit Testing Frameworks einsetzt, benutzt die QS Tools wie FitNesse, Ranorex oder Scripting. Oder sie lässt sich von der Implementierung einen Prüfstand einrichten. In jedem Fall hat sie den Code nur Zugriff von außen.

Intermezzo: Qualitätsschalen

Der Engpass Softwareentwicklung ist kompliziert. Das liegt gar nicht mal so an der reinen Codierung, d.h. der Transformation von Anforderungen in textuellen Quellcode und dann lauffähige Software. Die Welt ist voll von Code, der Anforderungen erfüllt – irgendwie.

Die Herausforderung besteht darin, Code so herzustellen, dass er gleichzeitig den expliziten funktionalen wie nicht-funktionalen Anforderungen von außen dient – wie den impliziten Anforderungen von innen. Werden erstere erfüllt, kann der Vertrieb mit der Software heute Geld verdienen. Doch nur wenn letztere ebenfalls erfüllt sind, kann dieses Geld erstens zügig und zweitens auch noch morgen verdient werden. Erinnern Sie sich: Das Ziel eines Unternehmens ist es, gutes Geld heute und in Zukunft (!) zu verdienen.

Dass das mit Code auch in Zukunft geht, ist kein Selbstgänger. Das ist nur möglich, wenn die Implementierung verlässlich schadlos arbeitet und das, was sie produziert eine Form hat, die sich dem stetigen Fluss des Neuen anpassen lässt. Damit das der Fall ist, darf ein Implementierer auch nicht direkt mit dem Kunden die Anforderungen aufnehmen und sofort in Code gießen. Das Ergebnis zeigen die vielen durch RAD unwartbar gewordenen Anwendungen. Erstes Symptom sind Massen an Code in GUI-Eventhandlern.

Nein, für das komplexe Geschäft der Softwareentwicklung ist – wenn es nachhaltig betrieben werden soll – eine systematischere Überführung von Wünschen in Code nötig. Mir scheint das Bild von Qualitätsschalen passend:

image

Die äußere Schale kümmert sich darum, dass Vorschläge in eine Software überführt werden, die dem Kunden Freude macht. Dafür prüft sie die Vorschläge und formalisiert sie in Form von Anforderungen; und am Ende prüft sie den Code aus Sicht des Kunden in der Qualitätssicherung. Die äußere Schale steht für eine reine Außensicht auf die Software

Eingeschachtelt in die äußere Schale ist eine Schale, deren Thema die Strukturierung der Software ist. Sie leitet aus den Anforderungen einen Architektur- und Modellrahmen ab, sie konzeptioniert die Lösung. Und am Ende prüft sie, ob das Konzept vom Code eingehalten wird. Diese Schale bildet den Übergang von äußerer Sicht zu innerer Sicht. Sie steht unter Spannung, weil sie unmittelbare Qualität für den produzieren und gleichzeitig die Nachhaltigkeit der Programmierung sichern soll. Diese Spannung existiert immer; nur durch eine Schale jedoch, die dafür konzipiert ist, sie auszuhalten, verhindert die Softwareproduktion, sich daran aufzureiben. Die mittlere Schale ist sozusagen Schmierstoff zwischen Außensicht und Innensicht, die in entgegengesetzte Richtungen rotieren.

image

Im Kern steht schließlich die Codierung. Sie bewegt sich im Architektur- und Modellrahmen und ist nach innen gewandt. Ja, sie muss sich in einem solchen Rahmen bewegen, um effizient zu sein, ohne die Korrektheit und Evolvierbarkeit aus den Augen zu verlieren. Der Architektur- und Modellrahmen isoliert sie von der ewig unverständigen Außenwelt – und umgekehrt isoliert der Rahmen die Außenwelt von vom unverständlichen Code.

Die Außenwelt ist volatil, Code ist – trotz seiner Unstofflichkeit – vergleichsweise starr. Wenn also nur “irgendwie” Vorschläge in Code gegossen werden, dann befriedigt das höchstens kurzfristig das Kundenbedürfnis. Langfristig jedoch zerreibt sich das System ohne Schmiermittel an der Gegenläufigkeit Spähren von Kunde und Implementierer.

Wenn Software unwartbar geworden ist, dann ist das eigentlich ein Ergebnis mangelnder Entkopplung zwischen Anforderungen und Code.

Kapazität steigern

Wenn die Input-Qualität beim Engpass stimmt, kommt es darauf an, wie der seine Kapazität einsetzt.

Wenn der Engpass seine Kapazität störungsfrei einsetzen kann, kommt es darauf an, dass er das Richtige tut.

Wenn er das Richtige tut, kommt es darauf an, wieviel Kapazität überhaupt vorhanden ist.

Es kann dann sein, dass der Engpass immer noch zuwenig Kapazität dafür hat, das Richtige mit hochqualitativem Input in ausreichender Menge zu tun. Extrembeispiel: Ein schlecht ausgebildeter langsamer Entwickler hat weniger Kapazität als 5 gut ausgebildete schnelle Entwickler.

Um den Engpass endgültig aus seiner Rolle herauszuheben, sind also womöglich weitere Maßnahmen nötig. Im einfachsten Fall bestehen die darin, dem Engpass mehr Personal zuzuordnen. Das trifft allemal zu, wenn ein Prozessschritt bisher gar nicht besetzt ist, z.B. keine Qualitätssicherung betrieben wird. Die schiere Nichtexistenz eines Schrittes macht ihn per definitionem zum Engpass.

Sobald jedoch Personal im Engpass arbeitet, lautet die Frage, wie dessen Kapazität erhöht werden kann. Als erstes mögen da Anreize in den Sinn kommen. Würden Implementierer nicht das Richtige schneller erledigen, wenn man ihnen einen Bonus für frühere Auslieferung verspricht? Wie die Forschung der letzten 50 Jahre zeigt, funktioniert das leider nicht für kreative/problemlösende Tätigkeite. Jedem Entscheider sei zu diesem Thema dieses Buch empfohlen: Drive von Dan Pink. Oder zum Schnuppern im Thema dieses Video:

Nein, mehr Produktivität beim Richtigen gibt es nicht so einfach. Weder Zuckerbrot noch Peitsche helfen bei einer Arbeit wie der Softwareentwicklung.

Unterm Strich helfen wohl nur zwei Strategien: Scale-Out und Scale-Up. Mehr Entwickler oder bessere Entwickler sind der Weg zu mehr Kapazität.

Scale-Out

Scale-out bedeutet, mehr Personen in der Softwareentwicklung zu beschäftigen. Ob die dann im Hause sitzen oder in einem fernen und viel billigeren Land, ist erstmal egal. Voraussetzung ist in jedem Fall, dass die Planung es hergibt, dass mehr Entwickler auch mehr wegschaffen.

Brooks´ Law sagt, dass es kontraproduktiv sei/sein kann, Manpower einem Projekt hinzuzufügen. Die zusätzlichen Personen wollen koordiniert sein und erzeugen zusätzliche Kommunikation. Das ist selbstverständlich ganz grundsätzlich wahr – doch es gibt Regler, mit denen ein nachteiliger Effekt zumindest gemildert, wenn nicht auch bis zu einem gewissen Grad ganz vermieden werden kann.

Mehr Entwickler konflikfrei und nutzbringen zu beschäftigen, so dass sie den Engpass wirklich weiten, ist nicht unmöglich. Allerdings ist dafür Planung notwendig. Wer die Kapazität mit Scale-out erhöhen will, tut daher gut daran, den Entwicklungsprozess zu systematisieren und eine entsprechende Arbeitsorganisation vorzunehmen.

Die meisten Projekte sind in dieser Hinsicht noch schlecht aufgestellt. Sie planen die Softwarestrukturen nur ungenügend und allemal nicht mit Blick auf ein Scale-out. Deshalb fällt es ihnen schwer, diesen Weg zur Kapazitätserhöhung gehen zu können.

Ohne vernünftige Architektur, Modellierung und darauf basierend eine Arbeitsorganisation für “Multi-Core-Entwicklung” nutzt mehr Entwicklerpersonal wirklich kaum oder ist gar hinderlich.

Scale-out scheint so einfach zu sein. In Wirklichkeit ist Scale-out jedoch nur für fortgeschrittene Teams, die ihre Produktion systematisch betreiben und im Griff haben. Beim Hausbau mögen doppelt soviele Maurer ganz einfach die Bauzeit verkürzen. Bei der Softwareentwicklung geht es nicht so direkt – ist jedoch nicht prinzipiell unmöglich.

Prozessschritte, die noch nicht besetzt sind, sollten besetzt werden. Darüber hinaus allerdings Zurückhaltung beim “Entwicklerkauf”.

Scale-Up

Vor dem Zukauf von Kapazität steht die Entwicklung der vorhandenen Kapazität. Statt mehr Entwickler lieber die vorhandenen besser machen. Das hat übrigens einen zwiefachen Effekt: Nicht nur erhöht sich damit die Kapazität der Entwickler, so dass dieselben mehr verkaufbares Neues pro Zeiteinheit schaffen können. Es erhöht sich auch die Motivation und damit die Bindung ans Unternehmen. Und das ist unschätzbar, da Fluktuation einer der größten Geldverschwendungsposten ist. In einer nicht trivialen Domäne kostet der Verlust eines eingearbeiteten Entwicklers schnell 100.000 EUR und mehr.

Man rechne also einmal: Wenn alle 2 Jahre ein Entwickler geht, dann kostet es im Schnitt pro Jahr 50.000 EUR, einen neuen Entwickler einzuarbeiten. Falls irgendeine Maßnahme nun dafür sorgt, dass nur noch alle 4 Jahre ein Entwickler das Team verlässt, dann kostet sein Ersatz im Schnitt nur noch 25.000 EUR pro Jahr. Jede Maßnahme, für die weniger als 25.000 EUR pro Jahr aufgewandt werden muss, um die Fluktuationsfrequenz von 2 auf 4 Jahre zu senken, ist damit ihr Geld wert.

Entwickler besser zu machen, ist so eine Maßnahme, sogar eine mit doppeltem Effekt. Verbesserung sollte also ganz oben auf der Prioritätenliste jedes Entscheiders stehen. Die Mittel dazu sind vielfältig. Manche kosten gar nichts oder wenig, andere kosten mehr. Am Ende macht es der Mix. Regelmäßige Fachlektüre gehört dazu wie der regelmäßige Austausch mit anderen Entwicklern (online in Diskussionsgruppen oder offline bei User Groups), ebenso der Besuch von Konferenzen und Trainings.

Trainings für Methoden sind hierbei solchen für Technologien vorzuziehen. Der Grund: Technologien lassen sich leichter allein lernen, da das Feedback, ob man es schon gelernt hat, unmittelbar von der Maschine kommt. Entweder hat man WPF, WCF, WF usw. richtig bedient oder nicht. Bei Methoden jedoch, bei neuen Verhaltensweisen, da ist solches Feedback schwerer oder nur verzögert zu erhalten. Autodidaktentum hilft in diesen Fällen nur begrenzt. Besser ist es, wenn man sich von Erfahrenen/Lehrern in das Thema einführen und beobachten lässt.

Fortbildung allein ist aber nicht alles. Die legt nur den Samen für Kapazitätswachstum. Zur Fortbildung müssen Spielräume (im doppelten Sinne) treten. Eigentlich soll die Softwareentwicklung eines: performen. Das ist wie die Aufführung für einen Künstler. Da darf es keine Patzer geben.

Aber natürlich kann das ein Entwickler genauso wenig wie ein Künstler aus dem Stand. Also ist wie beim Künstler auch Übung notwendig. Wer performen soll, der muss Zeit zum Üben bekommen; allemal Neues muss erst geübt werden, bevor es in der Produktion für den Kunden zum Einsatz kommt. Wer top fit sein und bleiben will, für den ist Freiraum zum Lernen wichtig; ein Raum, in dem Fehler gemacht werden können und sollen. Nur so kann am Engpass die nötige Leistung gebracht werden.

Aber Achtung: Es wäre ein Fehlschluss zu glauben, dass Fortbildung unnötig sei, wenn man mit geringerer Performance zufrieden ist. Fehlende Kompetenz führt nämlich nicht einfach nur zu geringerer Geschwindigkeit, sondern auch noch zu geringerer Qualität. Fehlende Kompetenz ist eine doppelte Bremse. Ein halb so guter Entwickler ist nicht nur halb so schnell, sondern unterm Strich wahrscheinlich nur ein viertel so schnell wie ein guter Entwickler.

Ich behaupte daher mal: Es gibt eine inverse Korrelation zwischen Fortbildungskultur und Druck im Team. Wird Fortbildung groß geschrieben, dann ist der Druck eher gering – und umgekehrt. Dazu fällt mir ein, “Wenn du es eilig hast, gehe langsam.” Wer ein hochperformantes Team will, der muss Zeit für Fortbildung und anschließendes Üben einräumen, auch wenn das die so wertvolle Kapazität des Engpasses scheinbar reduziert.

Investition in Verbesserung ist kontraintuitiv: Da wird Geld ausgegeben für Zeit, die bei der Produktion von Nützlichem fehlt und am Ende ist dann alles besser?

Ja. Definitiv. So ist das (Aus)Bildung. Erst stecken wir in Kinder und Jugendliche ja auch mehr als ein Jahrzehnt an Ausbildung, bevor Unternehmen mit ihnen Geld verdienen. Und danach hört der Kausalzusammenhang zwischen “mehr Bildung” und “mehr Wertschöpfung” ja nicht einfach auf. Das kann nur glauben, wer auch glaubt, dass die Softwareentwicklung ein eher statisches Geschäft ist, vielleicht wie die Maurerei oder die Arbeit an der Brötchentheke. Das Gegenteil ist jedoch der Fall. Also kann die Konsequenz nur lauten: Wer auch nur gut bleiben will, muss eine Lernkultur im Unternehmen etablieren. Lernen darf nicht zum Privatvergnügen verkommen.

Doch nicht nur Fortbildung sorgt für Kapazitätssteigerung. Jede Reduktion von Gängelung weckt Kapazitätspotenziale bei Entwicklern. Denn wer unter Druck steht – und das tut der Engpass ja ständig –, der kann damit besser umgehen, wenn er im Gegenzug Autonomie bekommt, um zu entscheiden, wie er mit dem Druck am bekömmlichsten umgeht.

Kontraproduktive Gängelungen sind z.B. die Fixierung von Ort und Zeit für die Arbeit für alle. “Gearbeitet wir in diesem Büro zu diesen Konditionen in diesen Zeiträumen.” Das ist normal, deshalb aber nicht der Motivation förderlich. Warum sollen Entwickler sich nicht selbst organisieren in Bezug auf Arbeitszeit und Ort – solange die Resultate stimmen? Dieser Gedanke ist nicht neu, seine Gefolgschaft unter dem Banner ROWE wächst. Es winken mehr Produktivität und größere Zufriedenheit.

Oder wie wäre es, die Softwareentwicklung nicht mehr in ein Budget zu zwingen? Es ist eine vergleichsweise preiswerte Anreizmaßnahme, Entwicklern zuzugestehen, dass sie alles, was sie meinen, für ihre Arbeit zu brauchen, auch anschaffen dürfen. Ja, alles. Wer meint, 3 Monitoren seien besser als 2 für seine Tätigkeit, der sollte darüber nicht lange diskutieren müssen. ReSharper für alle? Klar. Eine Lavalampe als Signal für den Buildprozesserfolg? Kein Problem. Laptops mit 256 GB SSD für jeden? Absolut. Noch ein Fachbuch, noch eine Fachzeitschrift? Immer her damit.

Vertrauen Sie darauf, dass der Engpass diese Befreiung nicht ausnutzt. Ich habe noch keinen Entwickler gesehen, der den Bogen überspannt hat. Allemal als Experiment sollte jedes Unternehmen sich darauf einmal einlassen.

Wie gesagt, es winkt doppelter Gewinn für die Reduktion von Gängelungen: nicht nur stärkere Bindung entsteht – Wer würde nicht um alles in der Welt in einem Unternehmen arbeiten wollen, in dem er arbeiten kann wann und wo er will und auch noch alle Gadgets/Tools bekommt, die er sich erträum? –, nicht nur wird das Unternehmen attraktiver und zieht bessere Leute an, es steigt einfach die Motivation und damit der Arbeitseinsatz in der vorhandenen Zeit.

Boni sind untaugliche Anreize; aber ein Milieu, eine Kultur der Autonomie, der Selbstorganisation, der Orientierung am Resultat ist sehr reizvoll. Echte Wertschätzung in Form von Vertrauen ist am Ende billiger und bindender als jeder Bonus.

Zwischenstand

Puh, das ist ein langer Artikel geworden. Aber irgendwie hängt alles zusammen am Engpass. Ich habe keine rechte Sollbruchstelle gesehen, wo ich ihn hätte auftrennen können.

Wer seine Softwareentwicklung verbessern will, der muss am Engpass ansetzen. Meist ist das die Softwareentwicklung. Also, was tun, vor allem, wenn der Engpass auf unterschiedlichen Abstraktionsebenen existiert? Es gibt eine Menge Ansatzpunkte.

Als erstes sind alle Produktionsschritte zu besetzen. Das ist in den meisten Teams die vordringlichste Aufgabe. Wo kein Entwurf, kein Review, keine Qualitätssicherung existiert, da muss überhaupt mal die Produktionsmaschine angeworfen werden.

Aber danach geht es los mit der Verbesserung des Input für den Engpass, seiner Ausnutzung, seiner Qualität und schließlich der Kapazitätssteigerung.

Bleibt nur die Frage, was sich dann am meisten lohnt? Und wie das alles bezahlen? Verbesserungen kosten doch erstmal Geld. Dazu beim nächsten Mal mehr. Dann binde ich den Produktionsfluss an das liebe Geld an. Denn ultimativ muss sich jede Veränderung am Geld messen. Jede Veränderung muss ja dem Ziel des Unternehmens dienen: Geld verdienen heute und in der Zukunft.