Follow my new blog

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.

Freitag, 3. Januar 2014

Eklektische Programmierung

Jetzt hab ich genug. Mir hängt das ganze Gerede über Für und Wider von Objektorientierter Programmierung (OOP) und Funktionaler Programmierung (FP) zum Hals raus. Ich mag nicht mehr.

Es ist zwar nicht egal, ob OOP oder FP. Der eine Ansatz hat für manche Szenarien Stärken, der andere Ansatz für manche Szenarien Stärken. Und? Warum sollte ich mich deshalb entscheiden müssen? Warum sollte OOP gewinnen, warum FP die Welt erobern? Das ist doch alles Quatsch. Solche Überlegungen binden geistige Kapazität, die wir besser einsetzen können.

Es geht nicht um die Frage, ob OOP oder FP. Es geht nicht um entweder-oder. Es gibt keinen Grund, warum es nicht ein sowohl-als-auch geben sollte.

Und schon gar nicht geht es um eine bestimmte Programmiersprache. Vorgestern Java, gestern C#, Python, Ruby, nun Go, Clojure, Erlang, Elixir – und natürlich gestern wie heute JavaScript? Gott ist das langweilig.

Ich mag mich nicht mehr entscheiden müssen. Ich will beides: OOP + FP. Das ist die Frage, die ich an Sprachen in Zukunft stellen werden: Kannst du mir volle OOP-Power geben und (!) kannst du mir volle FP-Power geben? [1]

Deshalb beschäftige ich mich gerade auch mit F#. Das ist eine hybride Sprache, allerdings geboren aus der FP. Da kommt für mich vieles eklektisch zusammen. Ich kann z.B. einen Stack à la FP implementieren und nutzen:

image

Oder ich kann ihn à la OOP definieren und nutzen:

image

Das sieht dann ähnlich einer Implementation in C# aus – ist nur etwas knapper formuliert, weil F# Typinferenz und eine leichtgewichtigere Syntax bietet. Hier zum Vergleich C#:

image

Oder ich kann in F# Objekte aus C# (bzw. aus .NET Assemblies) nutzen – und umgekehrt.

Mit F# muss ich mich nicht mehr entscheiden. Ich habe die volle Power von OOP und FP “at my fingertips”.

Nun kann ich frei überlegen, wann ich welchem Paradigma den Vorzug gebe. Ist ein Stack besser mit FP- oder OOP-Mitteln implementiert? Wie steht es mit der Logik für ein Spiel? Wie steht es mit einem View Model? Wie mit einem EventStore? Wie mit dem Domänendatenmodell?

An den Grenzen meines Codes stoße ich dann allerdings auf Infrastruktur. Mit der muss ich mich arrangieren, die präsentiert sich mir in Form von APIs. Natürlich muss meine Sprache mir den Zugriff erlauben.

Und ansonsten… Freiheit!

Denn erst wenn wir beide Paradigmen gleichwertig zur Verfügung haben, können wir zum Wesentlichen kommen: Was denn in welchem Fall der geeignete Ansatz sei.

Solange Sprachen noch beim einen oder anderen Paradigma zurückstehen, verlieren wir uns schnell in Rechtfertigungen. Dann ist das kein Defizit, sondern ein Feature, weil das andere Paradigma es einfach nicht bringt.

Doch das ist Quatsch. Die Frage nach dem richtigen, wichtigen, seligmachenden Paradigma ist die falsche Frage. Nicht das eine oder das andere Paradigma ist seligmachend, sondern die Vielfalt. Pluralismus statt Monokultur.

Ich will eklektisch programmieren, d.h. mich aus einem Bauchladen bedienen. Was mir taugt, wird benutzt. Fertig.

imageDas mag Lernaufwand für mich bedeuten. Ok, dann wende ich den eben auf. So wie ich es gerade mit F# tue und in einem Buch dokumentiere: F# lernen Kata für Kata. (Damit mache ich es Ihnen dann vielleicht ein wenig leichter, wenn Sie sich auch für die eklektische Programmierung entscheiden.)

Lernaufwand zur Ermöglichung von Eklektizismus ist Aufwand. Aber Rechtfertigungen für das eine oder andere Paradigma und Workarounds, wo es eben nicht optimal passt, Sie jedoch darauf festgenagelt sind… das ist auch Aufwand. Und zwar kein unbeträchtlicher.

Klar, C# bietet schon einiges in Richtung FP. Aber eine wirklich hybride Sprache ist C# noch nicht und wird es auch nicht. F# hingegen wurde mit dieser Absicht entworfen.

Für mich ist 2014 das Jahr, in dem ich meine eigenen Entwicklungen auf F# umstellen werde. Damit kann ich eklektisch arbeiten, bleibe dem .NET-Universum aber verbunden.

Wer mit Java arbeitet, der hat ähnliche Möglichkeiten. Scala und Clojure scheinen mir auch den hybriden Ansatz zu verfolgen. Für meinen Geschmack ist das JVM-Universum jedoch zu weit weg. Außerdem hat mir Scala einen Grandiositätsanspruch, der mich ermüdet. Und Clojure ist mir syntaktisch dann doch im Moment zu anders.

Wie gesagt, am Ende geht es auch nicht um einzelne Sprachen, sondern um Paradigmen. Wenn ich mich über Softwareentwurf unterhalten will, dann interessiert mich die konkrete Syntax nicht sonderlich. Wichtig ist vielmehr, dass mein Gegenüber Paradigmen und Konzepte zur Verfügung hat.

Soviel zu meinem Vorsatz für 2014: Eklektische Programmierung mit F#.

Und was ist Ihr Vorsatz?

PS: Achso, dynamische Programmierung (DP) will ich übrigens auch :-) Von der steckt in C# etwas drin; F# ist in der Hinsicht schwachbrüstiger. Derzeit ist mir jedoch mehr FP-Power wichtiger. Mit etwas weniger DP kann ich leben. Oder ich werde noch eklektischer: Ich wechsle nicht nur das Paradigma in einer Sprache, ich wechsle gleich zwischen den Sprachen. Da C# und F# auf der CLR/BCL laufen, muss ich mich nicht mal zwischen ihnen entscheiden.

Endnoten

[1] Ich ahne es, irgendwer wird fragen, was denn “volle Power” für die beiden Paradigmen ist. Und darüber lässt sich womöglich trefflich streiten. Aber ich denke, es gibt da einen gewissen Konsens. Zu OOP gehören Interfaces, Polymorphie, Kapselung von veränderbarem Zustand, einfache Vererbung. Zu FP gehören Funktionen als Werte & höhere Funktionen, tail recursion, unveränderbare Werte/Datenstrukturen, pattern matching.

Mittwoch, 1. Januar 2014

Unordnung muss sein

imageNeulich habe ich mit meiner Freundin geheimwerkert. Sie wollte ihr Wohnzimmer mit einigen Fotos in selbstgebastelten Bilderrahmen anreichern. Holzprofile zuschneiden und zusammensetzen zu Rahmen, war eine Sache. Eine andere, die Bilderleiste im Wohnzimmer anzubringen, an der die Rahmen aufgehängt werden können. (Eine Bilderleiste statt Nägeln in der Wand für jeden Rahmen sollte es sein, damit die Rahmen flexibler gehängt werden können.)

Bei der Montage der Bilderleiste habe ich dann eine Erkenntnis gehabt:

Unordnung ist bei Veränderungen nicht zu vermeiden.

Wer Rahmen bastelt, eine Bilderleiste anbringt, einen Weihnachtsbaum herrichtet, ja, sogar wer aufräumt, erzeugt Unordnung. Das ist nicht zu vermeiden. Auch wenn am Ende die Entropie niedriger sein soll, wird sie zunächst erhöht.

Hier das Wohnzimmer während der Arbeit an den Bilderleisten in seiner ganzen Unordnungspracht:

image

Die Sitzbank ist bis aufs Holz abgeräumt, der Wohnzimmertisch ein Werkzeuglager, der Sessel beiseitegeschoben und mit Krimskrams beladen, Staubsauger und Bohrmaschine lungern in der Gegend herum… Nein, das ist nicht die übliche niedrig-entropische Gemütlichkeit.

Am Ende jedoch, wenn die Veränderungen an der Wand abgeschlossen sind, kommt alles wieder an seinen Platz. Dann herrscht wieder Ordnung. (Dass die Bilderrahmen in unterschiedlicher Höhe und Orientierung hängen, gehört zu dieser Ordnung ;-)

image

Ohne die zwischenzeitliche Unordnung wäre die Veränderung nicht umsetzbar gewesen. Oder der Aufwand wäre viel, viel höher ausgefallen. Ich denke, da werden Sie mir zustimmen.

Wer einen ordentlichen Zustand in einen anderen, “erweiterten” ordentlichen Zustand überführen will, der erzeugt auf dem Weg dahin Unordnung.

Vorher hat das Wohnzimmer gewisse funktionale und nicht-funktionale Anforderungen erfüllt. Jetzt erfüllt es neue nicht-funktionale Anforderungen. Vorher war es ordentlich, jetzt ist es wieder ordentlich. Alles wunderbar.

Nur bei Quellcode oder anderen Artefakten der Softwareentwicklung soll das anders sein?

Merkwürdig, oder?

Was Unordnung bei Quellcode genau ist, sei mal dahingestellt. Aber dass es Unordnung geben kann, nein, geben muss, sollte außer Zweifel stehen. Auch für einen Laien.

Und genauso sollte außer Zweifel stehen, dass eine Veränderung an Quellcode zu Unordnung führen muss. Zwangsläufig. Immer.

Zumindest halte ich das für absolut einsichtig unter der Voraussetzung, dass Quellcode nach erfolgreichem Abschluss von Veränderungen, ordentlich zurückgelassen wird. Es geht also so mit dem Quellcode:

Anforderungen A+B werden erfüllt –> Veränderungen für C anbringen –> Anforderungen A+B+C werden erfüllt

In Bezug auf die Ordnung sieht das so aus:

Ordnung –> Unordnung –> Ordnung

Wer hat also je überhaupt annehmen können, dass es ohne Clean Code, ohne Refactoring geht? Das war und ist widersinnig. So funktioniert die Veränderung von etwas Ordentlichem nicht.

Wenn professionelle Arbeit in etwas Ordentlichem resultiert – vom Klempner über den Arzt bis zum Softwareentwickler –, dann darf und muss zwischendurch im Verlauf der Arbeit Unordnung entstehen. Und die wird am Ende aufgeräumt. So ist das immer.

Und jetzt nochmal die Frage: Wer glaubt, dass bei der Veränderung von Quellcode zur Erfüllung neuer Anforderungen (oder auch zum Bug Fixing) ohne Unordnung abgehen kann?

Aus meiner Sicht sind das viele Entwickler. Und es sind noch mehr nicht-Entwickler. Der Glaube ist so weit verbreitet, dass Refactoring immer noch einer besonderen Begründung bedarf. Wie oft habe ich gehört, “Für Clean Code haben wir keine Zeit. Wenn uns jemand dabei sieht, wie wir ein Refactoring durchführen, dann haben wir Erklärungsnot.”

Aber das ist Quatsch. Nach dem Bilderleisteneinsatz im Wohnzimmer ist mir das nochmal ganz deutlich geworden.

  1. Professionelle Arbeit hinterlässt ein System in einem ordentlichen Zustand.
  2. Veränderungen an einem ordentlichen System führen zwangsläufig zu Unordnung. Die sollte man gar nicht erst vermeiden wollen.
  3. Um nach Veränderungen wieder ein ordentliches System zu haben, muss aufgeräumt werden.

Unordnung herstellen, um effizient Veränderungen vornehmen zu können – hier: Tisch verrücken, Polster von der Sitzbank nehmen, Werkzeuge bereitlegen – und Ordnung nach Abschluss der Veränderungen wieder herstellen, sind die Klammern professioneller Arbeit.

Ich glaube sogar, dass wir während der Veränderung unseres Quellcodes noch zuwenig Unordnung zulassen. Wir meinen, es ginge ohne. Wir versuchen, mit Überziehern an den Schuhen auf Sitzbankpolstern vorsichtig herumzutreten. Gebohrt wird nicht, denn das macht ja Dreck. Besser nur vorsichtig kleben. Und langsam arbeiten, damit nichts zerbrechliches umgeworfen wird.

Wir versuchen also, Strukturen zu verändern, ohne sie temporär zu “verstören”. Das ist gut gemeint – aber an der Realität effizienter Veränderungsarbeit vorbei, glaube ich.

Nicht nur ist es ganz normal, nach Veränderungsarbeit Ordnung herzustellen; Stichwort Refactoring. Es ist auch ganz normal, vor (!) Veränderungsarbeit Unordnung herzustellen, wenn das einer effizienteren Veränderung dient.

Also, haben Sie kein schlechtes Gewissen, wenn Sie für eine neue Anforderung mal Unordnung erzeugen. Haben Sie auch kein schlechtes Gewissen, hinterher immer aufzuräumen. Das ist normal, unvermeidbar, professionell. Widersetzen Sie sich Anweisungen, die das Gegenteil verlangen. Zur professionellen Arbeit gehört Ordnung im Ergebnis – genauso wie zwischenzeitliche Unordnung.

Samstag, 28. Dezember 2013

Was ist Zug?

Druck ist unökonomisch auf längere Sicht. Druck ist in den meisten Fällen kontraproduktiv. Der Schaden, den Druck erzeugt, besteht in Halden, die Kapital binden oder gar verbrennen, und in Verformungen von Ressourcen, die deren Leistungsfähigkeit schrittweise reduzieren. Darüber habe ich im vorherigen Posting geschrieben.

Bewegung in Richtung eines Ziels kann aber nicht nur durch Druck (push) stattfinden. Druck mag zwar naheliegen und eine lange Geschichte haben – aber es geht auch anders. Es geht auch mit Zug (pull).

Zug ist das Gegenteil von Druck. Aber woran kann man Zug erkennen, wie kann man Zug herstellen?

Ich glaube, Zug braucht nicht viel. Arbeit findet schon im pull-Modus statt wenn sie...

  • …selbstbestimmt und…
  • …auf ein selbstgewähltes Ziel ausgerichtet ist.

Das sind die primären Merkmale von Zug.

  • Das Ziel sichert zu, dass ein Ergebnis entsteht.
  • Selbstgewählt muss das Ziel sein, um Verformungen zu vermeiden. Wer nicht tut, was er möchte, wer nicht versteht, was er tun soll, der verbiegt sich auf Dauer. Das bedeutet natürlich nicht, niemand dürfte einem anderen ein Ziel vorschlagen. Mehr aber auch nicht. Ein Vorschlag ist ein Angebot, das man ablehnen kann. Eine Bitte äußert nur, wer auch ein Nein akzeptieren kann. Ohne Angebot, ohne Bitte findet jedoch keine Wahl statt; es gibt ja keine Entscheidungsfreiheit.
  • Selbstbestimmt muss die Arbeit sein, um Verformungen zu vermeiden. Im Zug besteht Freiheit der Wahl im Hinblick auf Zeit, Ort, Mittel, um das Ziel zu erreichen. Dazu gehört natürlich auch, Begrenzungen dieser Selbstbestimmung zu akzeptieren.

Zug setzt also fundamental Wahl voraus. Wer keine Wahl hat, wem keine alternativen Optionen offenstehen, der gerät leicht unter Druck.

Bedeutet das aber Chaos? Nein. Lässt sich damit ein Unternehmen betreiben oder eine Software auf den Markt bringen? Ja. Das beweist nämlich jedes Unternehmen durch seine Existenz. Unternehmen sind per definitionem selbstbestimmte Einheiten, die ein selbstgewähltes Ziel verfolgen.

Unsere ganze Marktwirtschaft basiert auf Zug. Denn Nachfrage ist nichts anderes als Zug. Unternehmen reagieren auf Nachfrage mit Produktion. In der Marktwirtschaft gibt es keinen Druck. Der könnte zwar durch systemrelevante Größen entstehen, doch davor schützen (weitgehend) Regulierungsmaßnahmen.

Das Gegenteil hat man im Kommunismus versucht. Dort herrschte Druck. Dort wurde Produktion verordnet und Konsum quasi erzwungen. Unternehmerische Selbstbestimmung gab es nur in Ausnahmefällen. Die historische Quittung für einen solchen Versuch der Steuerung über Druck ist ausgestellt. Es hat nicht funktioniert. Historisch gesehen ist der Kommunismus mit seiner Planwirtschaft ein Experiment von kurzer Dauer gewesen.

Was im Großen wunderbar funktioniert und kein Unternehmer und auch kein Manager missen möchte, soll nun im Kleinen, d.h. Unternehmen nicht funktionieren. Viel, viel einfachere Gebilde als eine Nation oder auch die ganze Welt sollen mit Zug nicht erfolgreich sein können? Das kann ich nicht glauben.

Zugegeben, mit Druck Ziele zu erreichen, ist zunächst einfacher. Aber ist es auf Dauer erfolgreicher? Ist es erfolgreicher für ein Unternehmen? Ist es erfolgreicher für die Gesellschaft? Ich glaube weder das eine noch das andere.

Selbstbestimmte Arbeit auf selbstgewählte Ziele führt nicht ins Chaos. Sie ist vielmehr die Bedingung für die Möglichkeit von mehr Flexibilität, Reaktionsschnelligkeit, Innovationsfähigkeit und Freude.

Denn wer sagt, dass selbstbestimmte Projektbeteiligte nicht dasselbe wollen können? Wer sagt, dass die nicht kohärent und konsequent auf dasselbe Ziel hin arbeiten können?

Selbstbestimmung und Entscheidungsfreiheit bedeuten nicht, dass es keine Einschränkungen geben darf. Sich die nächsten 3 Jahre auf die Entwicklung eines CRM-Systems zu konzentrieren, sich auf die Nutzung von Java und Eclipse zu beschränken, alle Arbeit im Büro zu verrichten, sich bei der Arbeit durch zugerufene Aufträge unterbrechen lassen… all das ist mit Selbstbestimmung und Entscheidungsfreiheit vereinbar. Es ist sogar mit ihr vereinbar, den Weisungen von jemandem anderen zu folgen.

Das alles schränkt Selbstbestimmung und Entscheidungsfreiheit nicht ein, solange es immer wieder in Frage gestellt werden darf. Solange Beschränkungen freiwillig sind und nicht die Reflexion über sie inklusive Möglichkeit zur Veränderung aushebeln, sind sie Mittel, die der Erreichung des Zieles dienen können.

Manche Mittel mögen dabei träger sein als andere. Unternehmensstandort oder Geschäftsmodell stehen eher weniger häufig zur Disposition als Arbeitszeit oder Entwicklungsplattform. Letztlich sollte es jedoch kein Tabu geben.

Umgekehrt bedeutet das, je mehr Beschränkungen es gibt, je größer Tabuzonen, je seltener und enger die Reflexion, desto geringer Selbstbestimmung und damit auch Zug.

Und wie soll nun ein Unternehmen seine Ziele erreichen können, wenn seine grundsätzliche interne Funktionsweise die einer Marktwirtschaft ist? In Prozessen. Wie denn sonst? Das funktioniert doch auch im Großen. Wo bedarf ist, bilden sich Prozesse, die Rohstoffe in Produkte umwandeln.

Sie haben Strom, Wasser, ein Dach über dem Kopf, einen überquellenden Supermarkt, ein Auto, einen Computer, Bücher… Sie leben nicht “von der Hand in den Mund”, d.h. ohne Prozesse. Sie sind vielmehr Endpunkte und Bestandteile eines komplexen Prozessnetzwerks.

Für ein Papierbuch greifen Holzproduktion, Papierproduktion, Druck, Vertrieb, Buchhandel ineinander, um Ihnen den Gegenstand in die Hand zu bringen. Damit der auch noch einen Inhalt hat – sonst hätten Sie das Buch kaum nachgefragt –, stößt von der Seite ein zweiter Prozesse beim Druck dazu. Da greifen Autor, Lektor, Layout ineinander.

Alle arbeiten autonom. Überall herrscht Zug [1]. Und das Ganze funktioniert. Es gibt keinen Mangel an Büchern.

Warum nun sollte die Arbeit in selbstorganisierten Prozessen innerhalb (!) von Unternehmen nicht funktionieren? Unternehmen, die so nicht arbeiten können, d.h. wollen, und behaupten, das ginge nicht, sind für mich keine Experten. Würden wir denen glauben, hätten wir auch keine Eisenbahn. Denn Reit-Experten hatten vor deren Erfindung vorausgesagt, dass der Mensch bei größerer als Galoppgeschwindigkeit schlicht ersticken würde.

Damit selbstbestimmte Einheiten in Prozessen nicht unter Druck geraten, muss allerdings noch eine Voraussetzung geschaffen werden. Die Einheiten müssen entkoppelt sein. Ohne Entkopplung keine Autonomie.

Das Mittel zur Entkopplung sind Warteschlangen. Der Materialfluss zwischen Prozessschritten ist also nicht synchron, sondern asynchron. Eine upstream Einheit darf der folgenden Einheit nichts diktieren. Es gibt nicht einmal einen direkten Kontakt zwischen beiden Einheiten. Zwischen ihnen steht vielmehr eine Warteschlange oder allgemeiner ein Puffer.

Upstream Einheiten schieben ihre Erzeugnisse lediglich in Puffer. Auf die dürfen sie Druck ausüben. Das sichert auch ihnen Autonomie zu.

Downstream Einheiten entnehmen aus ihnen vorgelagerten Puffern das Material, an dem sie arbeiten wollen. Wann sie wollen. Das sichert ihnen Autonomie zu.

In den Prozessen der Marktwirtschaft gibt es überall diese Puffer. Der Holzproduzent kann einen solchen Puffer haben: das sind Stapel geschlagenen Holzes im Wald. Der Papierproduzent kann einen solchen Puffer im Eingang haben – er lagert eingekauftes Holz bis zur Verarbeitung – und/oder im Ausgang – er lagert produziertes Papier bis zum Verkauf. Der Drucker hat auch einen solchen Puffer im Eingang usw.

Es gibt sogar Marktteilnehmer, die das Puffern zu ihrem Geschäft gemacht haben: Grossisten, Logistiker, Supermärkte…

Dass es in der Marktwirtschaft einen Trend zu kleineren Puffern und zu mehr just-in-time Produktion gibt, widerspricht nicht dem pull-Prinzip. Selbst wenn es keine Puffer mehr gäbe, weil alles ad hoc JIT produziert und geliefert werden könnte, würde immer noch ausschließlich nach Bedarf produziert. Das bedeutet, es würde nur auf Zug produziert [2].

Dass selbstbestimmte Einheiten entkoppelt durch Warteschlangen in Prozessen erfolgreich arbeiten, ist natürlich kein Selbstgänger. (Dass Einheiten unter Druck erfolgreich arbeiten, aber auch nicht.)

Mehrerlei ist ständig zu beobachten:

  • Sind die Prozesse und die Produktionseinheiten auf das Ziel ausgerichtet (Kohärenz, Alignment)?
  • Wie sind die Puffer dimensioniert und ausgelastet? 
  • Wie sind die Kapazitäten der Produktionseinheiten dimensioniert und ausgenutzt?
  • Wie sind die Kapazitäten der Produktionseinheiten auf einander abgestimmt?

An all diesen Parametern kann und muss man schrauben für ein optimales Ganzes.

Aber das ist der Trick: Es geht um ein optimales Ganzes und nicht einheitenbezogene Optimierung. Und es steht vor allem eines nicht zur Debatte: die Autonomie der Produktionseinheiten. Deren Aufgabe ist schlicht, ihre Kapazität auf die Entnahme von Material aus Puffern, dessen Transformation und die Übertragung von Resultaten in Puffer zu konzentrieren.

Aus Puffern arbeiten für Puffer. Darum geht es. Alles daran geschieht in Selbstbestimmung – aber nicht auf Kosten des Ganzen. Dafür wird durch periodische Reflexion gesorgt. Dafür sorgen aber auch Puffer- und Kapazitätsbegrenzungen. Ultimativ ergeben die sich aus dem Markt für den die Prozesse produzieren. Dessen Begrenzungen wirken zurück auf den Prozess. Sie üben “back pressure” aus, dem sich die Dimensionierungen von Puffern und Produktionseinheiten nicht dauerhaft entziehen können.

Aber auch wenn hier Druck ins Spiel kommt, widerspricht das nicht dem Prinzip der Produktion im Zug. Im Gegenteil! Dem Druck von außen kann am ehesten entsprochen werden, wenn intern die Organisation möglichst flüssig ist. Und das ist sie, wenn sie aus lose gekoppelten autonomen Einheiten besteht. Der Beweis kommt wieder aus der Marktwirtschaft. Wenn sie sich nicht als flexibel, ja geradezu antifragil erwiesen hat, was dann?

Nochmal zum Abschluss:

Zug herrscht umso mehr, je selbstbestimmter entkoppelte Produktionseinheiten in einem Prozess auf ein Ziel ausgerichtet sind.

Inwiefern das bei Ihnen der Fall ist, können Sie ja mal überlegen. Wie selbstbestimmt fühlen Sie sich in Ihrer Arbeit? Welche Begrenzungen gibt es, wieviele davon dürfen Sie hinterfragen oder gar aufheben? Findet Hinterfragen (Reflexion) statt? Was sind die Ziele Ihrer Arbeit? Wieviele und auf welcher Ebene davon sind wirklich Ihre eigenen? Wie klar sind die Prozesse zur Erreichung dieser Ziele? Gibt es Puffer, wie sichtbar sind sie? Haben die Puffer eine definierte Kapazität? Geschieht der Materialfluss ausschließlich über Puffer und in Autonomie?

 

PS: Ich habe mir selbst auch diese Fragen gestellt. Die Antworten waren ernüchternd. Als Selbstständiger arbeite ich natürlich grundsätzlich autonom. Aber ich habe mich selbst unter Druck setzen lassen, indem ich Puffer abgebaut habe. Das Ergebnis: Ich habe wichtige Aufgaben nicht verlässlich erledigt. Bedient wurde vor allem das Dringende.

Darauf habe ich nun reagiert. Ich habe alle Notifikationen abgestellt. Ich lasse mich nicht mehr unterbrechen, nicht von Email, nicht von Twitter, Facebook, einem Newsreader, SMS oder Telefon [3]. Alle Informationen, die zu mir fließen, fließen in Puffer. Aus denen Bediene ich mich, wenn ich Lust oder Bedarf habe. So schütze ich meine Autonomie.

Das bedingt natürlich, dass ich diese Puffer auch tatsächlich prüfe, um für meine Umwelt verlässlich zu sein. Doch das ist eben meine selbstgewählte Aufgabe. Wenn ich Beziehungen haben will – berufliche wie private –, dann muss ich mich um deren Input kümmern. Das bedeutet jedoch nicht, dass ich mich von ihm bestimmen lasse. Ich kümmere mich, wann ich will – mit allen Konsequenzen.

Endnoten

[1] Zug herrscht selbstverständlich im Herstellungsprozess des physischen Buches. Die Beteiligten sind Unternehmen. Zug herrscht auch zwischen Lektor und Autor. Lektor und Layout und Vertrieb sitzen traditionell jedoch in einem Verlag. Der mag als Unternehmen intern noch über Druck organisiert sein. Das vernachlässige ich hier aber einmal. Es geht ja auch anders, wie freie Lektoren und freie Layouter beweisen. In Zukunft wird sich auch gerade hier einiges durch die Möglichkeiten des self-publishing verändern. Autoren sind nicht mehr auf Verlage angewiesen. Die Buchveröffentlichungskompetenz der Verlage schrumpft damit auf ihren Vertrieb bzw. ihre Reichweite zur Sichtbarmachung von Titeln zusammen.

[2] Ein Merkmal von Druck sind Halten. Was ist der Unterschied zwischen einer Warteschlage bzw. einem Puffer und einer Halde? Halden sind ungewollte Puffer. Halden entstehen, wo die Kapazität von Puffern überschritten wird. Das geschieht natürlich sofort, wo die Puffergröße 0 ist und angeliefertes Material (oder ein Auftrag) nicht sofort verarbeitet wird.

Wo das Material im Fluss wenig materiell ist – hört sich nach einem Gegensatz an, oder? ;-) -, also bei “Knowledgeprozessen” wie der Softwareentwicklung, sind Halden allerdings selten sichtbar. Sie sind nicht sichtbar, weil es sie scheinbar nicht gibt. Man lässt neue Aufgaben sich einfach nicht irgendwo zwischen Produktionsschritten auftürmen, sondern nimmt sie an. Man tut so, als würde man sofort mit der Verarbeitung beginnen. Der Wille dazu mag auch da sein – nur die Kapazität ist es oft nicht. Denn mit jeder weiteren angenommenen, aber noch nicht abgeschlossenen Aufgabe sinkt die Kapazität zur Bewältigung einer Aufgabe. Dazu kommen “Umschaltkosten” für den Wechsel zwischen Aufgaben.

Das Ergebnis ist Unzuverlässigkeit der Produktionseinheit. Aber da keine Halde sichtbar ist, da noch nicht einmal sichtbar ist, wieviele Aufgaben gerade in Arbeit sind, ist die Unzuverlässigkeit immer wieder ein Mysterium – dem man mit mehr Druck versucht Herr zu werden.

[3] Nur noch für Privates lasse ich mich durch Whatsapp unterbrechen.

Montag, 23. Dezember 2013

Was ist Druck?

Zug ist ökonomischer als Druck. Davon bin ich überzeugt. Aber was ist denn Zug? Wie kann man Zug (pull) von Druck (push) unterscheiden? Die Antwort bin ich noch Kommentator Mike M schuldig.

Bisher schien es mir einfach, Zug zu erkennen. Liegt der denn nicht auf der Hand, wenn er vorhanden ist? Aber Mikes Nachfrage hat mich widererwarten ein bisschen ins Schwitzen gebracht. “Ich erkenne ihn, wenn ich ihn sehe” ist zu wenig. Also: Was ist Zug?

Um das zu beantworten, ist erstmal zu klären, was Druck ist. Zug ist ja nicht nur die Abwesenheit von Druck, sondern das Gegenteil. Das habe ich ja auch mit der kleinen Bilderserien hier verdeutlichen wollen. Ein anderes Beispiel, das mir später eingefallen ist: der Umgang mit Anhängern.

Stellen Sie sich vor, diese Anhänger nicht zu ziehen, sondern zu schieben. Das geht nicht. Das geht zumindest nicht, solange sie so flexibel gekoppelt sind.

Anders ist das bei einem Zug. Da ist der Name zwar normalerweise Programm: bei einem Zug wird mit einer Zugmaschine gezogen wie bei einem LKW-Gespann. Aber bei einem Zug können Waggons auch geschoben werden. Das Bild lässt also nicht erkennen, in welche Richtung der Zug gerade fährt.

Einen Zug über Druck zu bewegen – klingt widersprüchlich, oder? - ist trotz der relativ flexiblen Kopplung der Waggons möglich, weil die auf Schienen laufen. Das Gespann kann sich beim Druck nicht verziehen.

Womit wir bei der Definition von Druck wären. Wikipedia sagt:

“Der Druck ist ein Maß für den Widerstand, den Materie einer Verkleinerung des zur Verfügung stehenden Raumes entgegensetzt.”

Das versuche ich mal zu übersetzen und zu verallgemeinern, damit der Begriff Druck auch auf nicht-physikalische Systeme anwendbar ist:

Druck entsteht, wenn mehr Leistung bei gleicher oder reduzierter Optionenzahl erbracht werden soll.

Beispiel 1: Eine Maschine in einem Herstellungsprozess kann 4 Teile pro Minute verarbeiten. Bisher wurden ihr diese 4 Teile auch geliefert. Aber nun hat man entschieden, den Prozess upstream zu optimieren und es werden zukünftig 6 Teile pro Minute angeliefert. Die Maschine gerät damit unter Druck.

Beispiel 2: Das Entwicklungsteam hat sich für die Woche 4 User Stories vorgenommen. Am Donnerstag kommt der Geschäftsführer aber herein und sagt, er brauche ganz dringend noch eine Einschätzung zu einer Ausschreibung, an der man sich beteiligen wolle. Dafür seien 200 Seiten bis Freitag Mittag durchzuarbeiten und einzuschätzen. Das Team gerät damit unter Druck.

Druck entsteht in beiden Fällen, weil von einer Ressource mehr erwartet wird, ohne dass ihre Kapazität erhöht würde. Eine Maschine kann darauf gar nicht von sich aus reagieren; die ist emotionslos. Der Druck zeigt sich in einer wachsenden Warteschlange/Halde vor der Maschine. In einem Prozess stellt sie die Verformung dar, die wir in der physischen Welt so leicht als Zeichen von Druck erkennen.

Bei Menschen ist das anders. Die sind grundsätzlich autonom und können entscheiden, wie sie mit höherer Leistungsforderung umgehen. Deshalb ist es oft auch schwierig, Druck zu erkennen.

Die Industrie ist inzwischen sensibilisiert. Die Lean-Bewegung hat Druck als Problem und Warteschlangen als Symptom erkannt. Toyota hat demonstriert, welchen Gewinn es bringt, von Druck auf Zug umzustellen.

Ansonsten aber… entweder macht man sich keine Gedanken oder man hält Druck für unvermeidbar oder man findet ihn sogar wünschenswert. Warum auch nicht? Druck kann doch auch sexy sein, oder?

Nein, Druck ist nicht sexy. Bis zu einem gewissen Grad ist er natürlich, unvermeidbar und auch nicht schädlich, nein, sogar bekömmlich. Aber sorgloser Umgang mit Druck, Druck als Standardmittel zur Ergebniserzielung, das ist kontraproduktiv.

In Beispiel 2 entsteht Druck entweder durch die unausgesprochene Annahme, dass das Team nicht nur seine 4 User Stories erledigen, sondern auch noch das Dokument durcharbeiten wird. Oder er entsteht, weil das Team nicht glaubt, die Arbeit an den User Stories zugunsten des Dokumentes herunterfahren zu dürfen.

Ob die Zahl der Optionen tatsächlich eingeschränkt wird oder die leistende Ressource das nur so wahrnimmt, ist nicht ausgemacht und auch egal. Entscheidend ist das Gefühl von Druck.

Problematisch ist nun, wozu dieses Gefühl von Druck führt: zu Verformungen.

Menschliche Ressourcen verbiegen sich, um den höheren Anforderungen gerecht zu werden. Das wird auch als ganz normal angesehen. “Dienst nach Vorschrift” ist verpönt. Der ist nämlich Ausdruck von “Unverbiegbarkeit” [1].

Verformungen bei Menschen sind z.B.:

  • Überstunden, d.h. länger arbeiten
  • Erhöhung der Leistung, d.h. schneller arbeiten
  • Isolation, d.h. selbstbezogener arbeiten
  • Absenkung des Qualitätsanspruchs, d.h. weniger sorgfältig arbeiten

Diese Verformungen sind hoffähig oder gar erwünscht (z.B. Überstunden), teilweise sind sie aber auch nur schwer oder spät erkennbar (z.B. reduzierte Qualität). In jedem Fall führen sie auf Dauer zu Demotivation oder Schlimmerem [2]. Wer Druck sorglos einsetzt läuft Gefahr, Kosten durch eines der großen K´s zu erzeugen: Kündigung, Krankheit, Keine Lust, Kundenverlust.

Das mag dem Druckausübenden im Moment egal sein, so wie es einem upstream Produktionsschritt egal sein mag, vor einem downstream Schritt eine Halde zu erzeugen. Aufs Ganze gesehen ist es jedoch kontraproduktiv und teuer. Am Ende verdient eine Organisation ihr Geld ja nicht mit lokaler Optimierung, sondern als optimales Ganzes.

Lokale Optimierung hat immer einen begrenzten Horizont. Ihr Bezugspunkt sind daher vor allem Kosten. Ob lokal mehr Output wirklich zu einem besseren Ergebnis (Durchsatz, Ertrag) der gesamten Organisation führt, kann lokal nicht ermessen werden.

Und die Summe lokaler Optimierungen ist nicht automatisch ein optimales Ganzes.

Eine Maschine kann nur 4 Teile pro Minute verarbeiten, sie ist in dieser Hinsicht unverformbar. Also stauen sich Teile, die darüber hinaus angeliefert werden, vor der Maschine. Das ist das Ergebnis einer höheren Leistungsanforderung (6 statt 4 angelieferte Teile pro Minute) bei gleicher Optionenzahl (unveränderte Kapazität der Maschine).

Ein Team kann 4 User Stories pro Woche verarbeiten. Wenn eine weitere Leistungsanforderung auftritt, dann sind die Zahl der Optionen. Man darf nicht mehr soviele Fehler machen wie bei der ursprünglichen Planung einkalkuliert. Man darf nicht mehr soviel Freizeit haben, wie im Vertrag steht. Man darf sich die Zeit weniger frei einteilen, wie ursprünglich angenommen.

Das gilt umso mehr, je höher die ursprüngliche Auslastung war. Wenn 4 User Stories bedeutet hätten, das Team arbeitet jeden Tag nur 4 Stunden und spielt ansonsten am Kicker, dann würde das zusätzlich zu lesende Dokument keinen Druck erzeugen. (Klar, die Freiheit, sich zwischen Kicker und Arbeit zu entscheiden, würde abnehmen. Aber da Kicker spielen nicht der Zweck des Teams in der Organisation ist, halte ich das für vernachlässigbar ;-)

Teams, die nicht (nahezu) voll ausgelastet sind, kenne ich jedoch nicht. Deshalb erzeugen Änderungen an der geforderten Leistung oder gar Forderungen nach mehr Leistung unmittelbar Druck.

Das kann mit einer Autobahn verglichen werden. Wenn die nachts nur schwach befahren ist, kommt es durch zusätzlich auffahrende Fahrzeuge oder Unfälle kaum zu Behinderungen. Wenn die Autobahn in der Rush Hour jedoch ausgelastet ist, dann führt zusätzliche Last oder eine unerwartete Reduktion der Kapazität zu Staus oder sogar echten Autohalden bei Unfällen.

Druck ist allemal auf Dauer also nicht ökonomisch. Er ist lokal leicht zu erzeugen und führt lokal und kurzzeitig vielleicht auch zu einem Erfolg. Aufs Ganze gesehen jedoch ist Druck kontraproduktiv.

Endnoten

[1] “Dienst nach Vorschrift” ist natürlich kontraproduktiv. Da fehlen Respekt und Flexibilität. Beides ist nötig in Organisationen, weil es erstens um Menschen geht und zweitens sich menschliche Prozesse nicht optimal formalisieren lassen.

Dennoch finde ich es überlegenswert, inwiefern etwas mehr “Dienst nach Vorschrift” nicht auch heilsam für Organisationen sein kann. Denn dann kann es zu Haldenbildung wie in Industrieprozessen kommen. Damit gibt es dann sichtbare Ansatzpunkte für die Optimierung aufs Ganze hin.

[2] Menschen sind unterschiedlich belastbar. Wie stark sie sich verformen lassen oder können, wie schnell und weit sie anschließend auch wieder “back to normal” kommen… das ist ganz verschieden. In jedem Fall ist ihre Elastizität begrenzt. Bei ständigem Druck nimmt sie ab. Auch Menschen leiern sozusagen aus, werden schlaff – oder verhärten.

Dienstag, 10. Dezember 2013

Vergleich von Flow-Designs für Kata Ordered Jobs

So unterschiedlich können Flow-Designs sein. Ich hatte es schon geahnt, doch nun ist es öffentlich.

Am 1.11.2013 hatte ich ermuntert, Flow-Designs für die Kata Ordered Jobs “einzureichen”. Auslöser dahinter war ein Flow-Design, dass Entwickler eines Kunden von mir in einem Coding Dojo unter sich erarbeitet hatten. Sie wollten einfach Flow-Design üben. Das sah so aus, als sie mich schließlich um Rat fragten:

image

Was mich daran überraschte: Dem Lösungsansatz ist nicht anzusehen, um welches Problem es eigentlich geht. “Process”, “Release”, “Save”, “Output” sind ganz allgemeine Begriffe. Auch der fließende “Job” erhellt nicht wirklich, wie (!) die Lösung funktioniert. Die Musik spielt in “Process” – aber genau die Funktionseinheit wurde nicht verfeinert.

Ob das auch anderen Interessenten an Flow-Design so geht/gehen würde? Das wäre schade, denn ich glaube, so führt Flow-Design zu keiner großen Verbesserung der Verständlichkeit und Evolvierbarkeit von Software.

Es ist ja gerade der Trick an Flows, dass bei ihnen die Syntax so minimal ist, dass sie eine Domänensemantik nicht verrauscht.

Fünf “Einsendungen” hat es dann auf meinen Aufruf hin gegeben. Vielen Dank an die fleißigen Entwerfer! Die möchte ich hier allerdings nicht in ihrer Funktionstauglichkeit bewerten, sondern nur formal gegenüberstellen. Wie sich zeigt, gibt es nämlich mehrere Aspekte, in denen sie sich unterscheiden.

Darstellung

Flow-Design setzt auf… Flüsse. Der Name ist Programm. Die können handgemalt sein wie oben oder in einem Tool wie Visio ordentlich “gesetzt” werden:

image

Überrascht hat mich daher die folgende Darstellung:

image

Aber nicht wegen der “squiggly lines” bin ich überrascht, sondern wegen der Gewichtung der Darstellung. Hier sind zwar auch Pfeile im Spiel und stehen für Datenflüsse. Doch prominenter scheinen mit die Abhängigkeiten. Da ist ein DGraph von mehreren Flow-Funktionseinheiten abhängig. Oder? Nein, umgekehrt. Jetzt sehe ich es: Die Funktionseinheiten sind vom DGraph abhängig. Ich war nur einen Moment verwirrt, weil die Abhängigkeiten von unten nach oben zeigen. Das ist eher ungewöhnlich (in Flow-Designs allemal), finde ich.

Im oberen Entwurf gibt es auch eine Abhängigkeit (zu “nextOrderNumber”). Doch die ist zurückhaltender dargestellt; sie steht dem Fluss nicht im Weg.

Die Darstellung bzw. Gewichtung von Abhängigkeiten unterscheidet sich also in Flow-Designs durchaus. Das ist bis zu einem gewissen Grad auch ok, finde ich. Doch wenn die Abhängigkeiten scheinbar die Oberhand gewinnen, wenn der Fluss nicht mehr im Vordergrund steht, dann finde ich einen Vorteil von Flow-Design verschenkt.

Detaillierungsgrad

Wie das erste Diagramm zeigt, können Flow-Designs sehr unspezifisch sein. “Process” passt auf nahezu jedes Problem. Ähnlich empfinde ich aber auch noch bei “Sort” im dritten Diagramm – zumindest solange dann nicht weiter verfeinert wird. So bleibt die Lösung im Dunkeln; die Last liegt voll auf der Codierung und ist damit die Verantwortlichkeit nur eines Entwicklers.

Dito im folgenden Entwurf, wo noch klarer wird, dass die Aufgabe eigentlich nicht vom Flow, sondern von der Datenstruktur DGraph gelöst wird. So eine Datenstruktur samt Algorithmus zur topologischen Sortierung “einzukaufen”, ist natürlich legitim. In der Praxis würde man es womöglich sogar anstreben, um sich eigenen Aufwand zu sparen. Doch das funktioniert natürlich nur, wenn es eine Lösung “einzukaufen” gibt. Und hier war es an der Aufgabe vorbei, da es ja gerade darum ging, selbst einen Lösungsansatz zu formulieren.

image

Andererseits können Flows natürluch auch sehr detailliert sein:

image

In diesem und weiteren Flows der “Einreichung” wird der Algorithmus genau beschrieben. Jede Funktionseinheit wird mit 2-3 Zeilen Code umsetzbar sein, schätze ich. Für mich ist das sogar zu detailliert, zumindest für die Implementierung. Bei Entwurf mag man mal so tief einsinken… doch dann würde ich wieder einige Ebenen nach oben steigen beim Codieren. Nicht für jede Funktionseinheit lohnt wirklich eine eigene Funktion.

Lösungen können also zu grob sein, dann helfen sie nicht wirklich. Andererseits können sie auch zu detailliert sein, dann fangen sie an zu rauschen. Die Kunst besteht mithin darin, eine angemessene mittlere Granularität zu finden. Die ist natürlich ein Stück subjektiv und erfahrungsabhängig ;-)

Abstraktion

Flows entwerfen, ist etwas anderes als zu codieren. Es geht um Abstraktion von den Niederungen der textuellen Programmiersprachen. Nur dadurch gewinnt der Entwurf Geschwindigkeit und Überblickscharakter. Es geht darum, eine Karte zu schaffen, nicht eine (Miniatur)Landschaft zu herzustellen.

Auch hier gilt es, die Balance zu finden. Am einen Ende des Spektrums ist der Globus, d.h. eine sehr grobe Karte, die alles zeigt. Das ist völlig ok, nein, unumgänglich – sollte nur nicht wie im vorletzten Diagramm dabei bleiben. Die schrittweisen Verfeinerungen, die auch im Code erhalten werden können und sollen, machen das Flow-Design aus.

imageimageimageimage

In die falsche Richtung geht es aus meiner Sicht jedoch, wenn sich in die Karten Artefakte aus dem Terrain einschleichen. Das ist der Fall, wenn der Fluss nicht mehr deklarativ ist, sondern imperativ wird. Das ist hier z.B. der Fall:

image

Ein “ForEach” ist beim Flow-Design fehl am Platze; der Begriff steht erstens für eine explizite Kontrollanweisung, wo es doch um Datenflüsse geht, und zweitens ist er frei von jedem Domänenbezug.

Dicht darauf folgen Schleifen jeder Art, z.B.

image

Sie lassen sich einfach nicht mit dem Integration Operation Segregation Principle (IOSP) in der Implementation mit 3GL vereinbaren.

Ein Flow-Designs beschreiben Datenflüsse, dazu gehören mindestens zwei Punkte, um eine Strecke für den Fluss abzustecken und ihm eine Richtung zu geben. Andererseits dürfen die Flüsse aber auch nicht umkippen und zu Kontrollflüssen degenerieren. Abstraktion im Entwurf bedeutet also, soweit wie möglich eine deklarative Domänensprache zur Lösung eines Problems zu finden.

Anforderungstreue

Überrascht hat mich schließlich auch die Kreativität der Lösungen. Die Vorgaben waren ja klar. Es galt, ein Interface zu implementieren.

Doch das hat nicht in allen Lösungen dazu geführt, auch dieses Interface sichtbar zu machen. Manchmal wurde aus dem geforderten Register() nur ein AddJob(). Manchmal war solch eine Funktionalität aber auch gar nicht zu sehen:

image

image

Am anderen Ende des Spektrums dann wieder eine recht treue Abbildung der Anforderung:

image

Kreativität ist bei der Findung eines Lösungsansatzes selbstverständlich wichtig. Allerdings sollte sie sich dort austoben, wo die Anforderungen notwendig Lücken haben. Das, was der Kunde beschreibt, das, was klar erkennbar ist, sollte hingegen treu übernommen werden. Sonst leidet die Verständlichkeit. Man bedenke immer den anderen Entwickler oder sich selbst in der Zukunft. Da wird dann U in den Anforderungen gelesen, aber im Entwurf ist ein X zu sehen…

Ich weiß, das ist manchmal schwer. Da hat man seine Coding-Standards. Da wallt die Erfahrung in einem auf. Das will alles berücksichtigt werden. Doch ich glaube, wir tun gut daran, uns solchen Regungen nicht gleich hinzugeben. Etwas Disziplin in der Beschränkung der Kreativität hilft der Verständlichkeit.

Fazit

Dass die Entwürfe so weit auseinander gehen, hätte ich doch nicht gedacht. Auch mit den überschaubaren Mitteln des Flow-Design ist also große Bandbreite möglich. Einerseits schön – andererseits aber auch wieder eine ernüchternd. Die guten alten Tugenden Maßhaltung und Genauigkeit und Fokussierung gelten auch im Flow-Design.

Mir hat der Vergleich der Entwürfe sehr geholfen. Und ich hoffe, dass es Ihnen ein bisschen auch so geht.

Samstag, 7. Dezember 2013

Bitte raustreten für besseren Fluss

Am Flughafen kann man lernen, Fluss herzustellen. So geschehen, als ich gestern von Hamburg nach Köln geflogen bin. Und gleich wird es wohl wieder geschehen, wenn ich zurückfliege.

Beim Boarding sollen ja in kürzester Zeit hunderte Passagiere durch ein Nadelöhr in die Maschine fließen. Da Nadelöhr ist die Prüfung der Bordkarte. Heute passiert das durch assistiertes Scannen.

Je Fluggast dauert das 4-5 Sekunden, schätze ich mal. Von Durchgehen kann da keine Rede sein. Und so entsteht ein ausgewachsener Stau vor den Scannern.

Das ist ok, die Passagiere murren nicht. Man fließt zwar nicht schnell, aber man fließt. Es ist absehbar, wann man drankommt, weil es vorwärts geht. Dafür sorgt das Flugsteigpersonal auch, indem es Variationen in der Durchschleusungsdauer von vornherein bedenkt. Menschen, die langsamer sind (Ältere, Behinderte, Kinder), werden gesondert zu Beginn durchgeschleust. Für die ist die Bearbeitungszeit länger oder gar unbestimmt lang, jenachdem, welche Hilfe sie benötigen. Damit will man den Fluss der Masse nicht aufhalten. Ein guter Gedanke.

Trotz dieser Maßnahme kann es jedoch passieren, dass die Prüfung bei den restlichen Passagieren unterschiedlich lange dauert. Mal 3 Sekunden, mal 6 Sekunden. Aber das ist ok. Die Variationen halten sich in Grenzen. Fluss entsteht.

Bis, ja, bis es zu einem Sonderfall kommt. Da rückt ein Passagier vor, der immer noch nicht seine Bordkarte gefunden hat. Da steht plötzlich ein Passagier am Scanner, der auf dem Smartphone seine Bordkarte nicht findet. Oder was auch immer. Es kann passieren, dass die Verarbeitungszeit für plötzlich und unerwartet stark ansteigt. Der langsame, jedoch stetige Fluss kommt zum Erliegen. Nach spätestens 20 Sekunden wir Murren laut. Köpfe recken sich. Was ist da los?

Solche Sonderfälle kann man nicht vermeiden. Trotz Vorsichtsmaßnahmen, trotz weitgehend homogenen Aufwands kann es immer zu Ausreißern kommen. Und das merkt man erst, wenn man die Verarbeitung schon begonnen hat. Was dann?

Bis zu einer gewissen Grenze muss das keine besondere Konsequenz haben. Shit happens. Also bleibt man ruhig und gibt dem Fluggast 10 Sekunden, um sich zu sortieren. Oder 12 Sekunden. Danach geht es wieder flüssig wie erwartet weiter.

Jenseits dieser Grenze jedoch, ist es klug, Maßnahmen zu ergreifen. Dann ist es klug, den "Störenfried" auszusondern. Raus mit ihm aus dem normalen Verarbeitungsfluss! Er muss den Weg freimachen für die anderen. Wer seine Bordkarte sucht, muss dafür nicht beim Scanner stehen. "Bitte treten Sie zur Seite!" Dort hat man dann alle Zeit der Welt oder kann sogar Hilfe in Anspruch nehmen.

Und genauso sollte es im Fluss der Softwareentwicklung sein. Um eine Homogenisierung der Größe von Features/User Stories sollte man sich bemühen. Dann kann Fluss entstehen. Für mich liegt diese Größe im Bereich von 0,5 bis 2 Tagen.

Bei aller Mühe gibt es jedoch keine Garantie, dass die Features/User Stories dann aber auch wirklich nur diesen Aufwand benötigen. Es kann mal schneller gehen - sehr schön, aber wohl eher selten. Es kann mal langsamer gehen - macht nichts, solange es im Rahmen ist. Dieser Rahmen ist vielleicht 0,5 Tage bei einer Aufgabe von geschätzten 2 Tagen.

Wird der Variationspuffer jedoch überschritten, gilt es, eine Konsequenz zu ziehen. Die lautet für mich: Raus aus dem Fluss!

Wenn eine Blockade auftritt, sollte das Feature/die User Story nicht einfach im Fluss belassen werden, um dort an ihr herumzudoktern. Stattdessen gilt es, den Weg für andere zu machen. Dann kann man abseits überlegen, wie das Problem gelöst werden kann.

Wer mit einem Taskboard arbeitet (oder einem Kanban-Brett), der sollte dafür eine eigene Schwimmbahn "Notaufnahme" oder so vorsehen. (Genauso, wie es eine für "Forschungsaufgaben" geben sollte.)

Dann wird deutlich, wo Hilfe nötig ist, ohne den Fluss zu behindern. Dann kann auch eine Repriorisierung stattfinden: Ist es jetzt wichtig, auf diesen Sonderfall weitere Ressourcen zu werfen? Oder ist es wichtig, andere Features/User Stories am Fließen zu halten?

Solange so ein Sonderfall einfach nur einen Platz des WIP-Limits im Hauptfluss belegt, stört er das ganze System. Klar, dann würde dieses Vorkommnis in einem CFD irgendwann zu sehen sein - aber das ist spät. In der Zwischenzeit ist es zu einem unnötigen Stau gekommen. Als würde ein liegengebliebener Wagen nicht von der Fahrbahn genommen.

Shit happens. Darauf sollte möglichst zeitnah reagiert werden, um nicht noch Folge-Shit entstehen zu lassen. Wie das geht, zeigt die Behandlung von unvorhersehbaren Variationen in der Passagierabfertigung am Flugsteig sehr schön, finde ich.