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.