Dienstag, 28. Dezember 2010

Ein Paradigma, viele Implementierungen

Event-Based Components (EBC) werden vor allem mit C#-Events in Zusammenhang gebracht. Nicht zu unrecht natürlich. Darum ging es ja auch am Anfang: Funktionseinheiten über Events verbinden. So können sie “im Außen” zusammengesteckt werden; “im Innen” haben sie keine Abhängigkeiten mehr.

Inzwischen hat sich die Welt aber gedreht. Aus den EBC sind die Komponenten verschwunden. Und nun verschwinden auch die Events. Oder besser: sie bekommen einen anderen Platz zugewiesen.

Flow Design

In den letzten Monaten habe ich mit vielen Entwicklern über EBC diskutiert und in vielen Zusammenhängen damit gearbeitet. “EBC-Denke” hat auch die Clean-Code-Developer-Trainings, die ich mit Stefan Lieser veranstalte, stark beeinflusst. Sie macht es schlicht soviel leichter, Anforderungen in Lösungen zu transformieren.

Bei all dieser Beschäftigung mit dem Konzept bleibt es nicht aus, dass es sich verändert. Der Blick darauf wird differenzierter. Und so ist mein aktueller Standpunkt, dass EBC nur eine bestimmte Ausprägung eines Paradigmas ist.

Objektorientierung ist ein Paradigma, bei dem es um polymorphe “Dinger” geht, die Daten und Funktionen vereinen und voneinander abhängig sind.

Das hinter EBC stehende Paradigma nenne ich mal “Flussorientierung”. Bei dem geht es um “Dinger”, die Eingaben in Ausgaben transformieren, dabei auf Ressourcen zurückgreifen – und zu Sequenzen verbunden werden. Solche Sequenzen können wieder als “Dinger” betrachtet werden, weil sie als Ganzes Eingaben in Ausgaben transformieren. Im Fluss durch die Sequenzen sind also Daten; die Ausgaben eines “Dings” sind die Eingaben anderer “Dinger”.

Diese Flussorientierung sehe ich inzwischen als so wichtig weil grundlegend an, dass ich sie von den EBC getrennt nutzen möchte. Sie ist für mich sogar so universell, dass ich sie nicht auf die Modellierung, d.h. den Entwurf funktionaler Strukturen beschränken möchte. Flussorientierung ist für mich vielmehr das Ausgangsparadigma für Architektur und Modell. Denn nur mit einer Flussorientierung können wir komplizierte Systeme agil evolvierbar entwerfen, d.h. in dünnen Längsschnitten. Das behaupte ich mal keck :-)

Meine Begründung: Flussorientierung ist der Objektorientierung im Entwurf in mehrerlei Hinsicht überlegen.

  1. Erstens entstehen durch Flussorientierung keine Systeme mit funktionalen Abhängigkeiten;
  2. zweitens sind flussorientierte Systeme intuitiv auf beliebig vielen Abstraktionsebenen denkbar und darstellbar;
  3. drittens geht es bei Anforderungen immer um Verarbeitungsflüsse, so dass flussorientierter Entwurf näher an den Anforderungen verläuft.1)

Aller Softwareentwurf sollte daher, so meine ich derzeit, mit Flussorientierung beginnen.

Flow Architecture

Die nicht-funktionalen Anforderungen sollten konsequent mit einer flussorientierten Architektur erfüllt werden.2) Was da in Flüssen steckt, ist architekturspezifisch. Daten fließen in der Architektur (zumindest) zwischen Bounded Contexts, Apps, Maschinenen und BS-Prozessen.

Der Architekt definiert und bindet physische Funktionseinheiten zu Sequenzen zusammen. Einen Betriebssystemprozess kann man “anfassen” (s. Taskmanager), eine App kann man “anfassen” (s. die BS-Prozesse auf den zugehörigen Maschinen) usw. Mit diesen Funktionseinheiten kann am Ende auch ein IT-Admin etwas anfangen oder eine Einkaufsabteilung, weil hard- oder softwaretechnische Server gekauft werden müssen.

Flow Model

Die funktionalen Anforderungen sollten vor dem Hintergrund der flussorientierten Architektur dann ebenfalls flussorientiert angegangen werden. Das geschieht im Rahmen der Modellierung, die logische Funktionseinheiten definiert und zu Flüssen verbindet. Wo Architektur immer aus einer begrenzten physischen Hierarchie besteht, sind Modelle freier. Ihre Strukturelemente haben deshalb allgemeinere Namen: Platine und Bauteil. Bauteile sind atomare Funktionseinheiten, Platinen zusammengesetzte bzw. zusammensetzende Funktionseinheiten. Die Hierarchien der Funktionseinheiten von Modellen können beliebig tief geschachtelt sein.

Zum Trost der Freunde der Objektorientierung: Die Bauteile des Modells wie auch die in ihm fließenden Daten sind die “Taschen”, in denen für mich Objektorientierung weiterhin ihren Wert hat. Sie sind überschaubar und klar abgegrenzt, so dass Objektorientierung die Harmonie des Großen Ganzen des Entwurfs nicht zerstören kann. “Taschen voller Matsch” sind zwar misslich, aber immer noch viel besser als ganze Anwendungen als Brownfield.

Es obliegt Architektur und Modell, diese “Taschen” so klein zu halten, dass die Nachteile der Objektorientierung ihre Vorteile nicht überwiegen. Das halte ich aber für keine allzu schwierige Aufgabe.

Flow Implementation

Flüsse fließen also überall im Entwurf, in der Architektur und im Modell. Das bedeutet, es kann nicht nur eine Übersetzung für sie geben. Das hatten EBC suggeriert. Aber das ist eine unnötig einschränkende Sichtweise.

Einen Fluss wie

image

in Interfaces mit Events zu übersetzen wie hier

interface IA
{
  event Action<string> Output;
}

interface IB
{
  void Process(string input);
}

ist nur eine Möglichkeit. Sie ist einfach und naheliegend – doch letztlich ist es eben nur eine Möglichkeit.

Genauso gut können die Funktionseinheiten in Methoden übersetzt werden:

string A() {…}

void B(string input) {…}

Das tun Stefan und ich zum Beispiel gern in TDD-Seminaren, wenn wir kleine Aufgaben modelliert haben. Für die meisten Code Katas wäre die Übersetzung in Interfaces/Events ein zu großes Geschütz. Mit der Übersetzung in Methoden muss man nun aber nicht auf die Segnungen der Modellierung auch bei kleinen Aufgaben verzichten.

Und sonst? Es gibt weitere Übersetzungen für Modelle. In einem Blogartikel habe ich zum Beispiel mal mit expliziten Kanälen gearbeitet. Oder hier eine Übersetzung für die Java-Welt – auch ohne Events.

Auf Architekturebene sieht die Übersetzung dann noch wieder anders aus. Wie könnte ein Datenfluss zwischen zwei Bounded Contexts übersetzt werden?

image

Aus dem schlichten Pfeil im Architekturmodell auf hoher Abstraktionsebene kann z.B. ein ETL-Betriebssystemprozess3) auf niedrigerer Ebene werden:

image

Tendenziell werden allerdings flussorientierte Modelle direkt in recht simple programmiersprachliche Konstrukte übersetzt und flussorientierte Architekturen mit flussorientierten Modellen verfeinert.

Aus jeder Entwurfsperspektive gilt jedoch: Für “Kästchen” (oder “Kuller”) und Fluss-Pfeile sind je geeignete Übersetzungen zu finden. Welche das sind, hängt vom Abstraktionsgrad, zur Verfügung stehenden Technologien und nicht-funktionalen Anforderungen ab.

Fazit

Was mit EBC begonnen hat ist nun viel größer geworden. Auf Flussorientierung kann und will ich nicht mehr verzichten. Funktionale und nicht-funktionale Anforderungen möchte ich mit dem Paradigma angehen. Große und kleine Probleme möchte ich damit lösen. Synchron und asynchron möchte ich dabei denken können.

Die Trennung von Paradigma und Implementation, die in EBC ursprünglich nicht so direkt zu sehen war, hilft mir dabei. Ich denke auch, dass sie Flussorientierung attraktiver macht, weil sie keine bestimmte Implementation aufzwingt. Jeder kann einen flussorientierten Entwurf in objektorientierten oder prozeduralen oder funktionalen Code gießen, wie er mag. Je systematischer das geschieht, desto größer der Gewinn. Interfaces und Events sind nur eine Variante von vielen.

In diesem Sinne: Happy Flow-Designing!

Anmerkungen

1) Dass die Objektorientierung meint, bei Anforderungen ginge es vor allem um Daten, halte ich inzwischen für eine sehr tragische Verirrung. Sie ist tragisch, weil Objektorientierung dazu gedacht war “alles besser zu machen”. Endlich Software so strukturieren, wie die Welt uns entgegentritt: als Gewebe von Dingen, die Zustände haben und tätig sind und unterschiedlichen Kategorien angehören.

Klingt ja auch total cool. Klingt sogar philosophisch-richtig, weil hier These (Platon als Proponent einer Ideenwelt unabhängig von den Dingen –> Klassen) und Antithese (Descartes als Stellvertreter des modernen diesseitigen, mechanistischen Denkens –> Objekte) synthetisch vereint scheinen.

Leider ging der Schuss nach hinten los. Ich sehe nicht, dass die Objektorientierung die Softwareentwicklung ihrem Anspruch entsprechend leichter gemacht hat. Unsere Softwaresysteme sind heute größer als früher. Aber nicht wegen der Objektorientierung, sondern weil Rechner heute mehr leisten. Selbst wenn wir heute nur mit C oder Modula arbeiten würden, wären unsere Softwaresysteme größer als die in den 1970ern.

Schuldig geblieben ist die Objektorientierung, dass Softwaresysteme wirklich deutlich leichter entworfen werden können. Und dass Softwaresysteme leichter evolvierbar gemacht und gehalten werden können als zu zeiten von C oder Modula.

Wie an anderer Stelle schon gesagt: Objektorientierung hat ihren Wert. Ich möchte sie nicht missen. Aber sie ist nicht der Heilsbringer, den die Branche in ihr gesehen hat und sieht. Und erkennen lässt sich das an der kontraproduktiven Gewichtung von Daten bei der Analyse von Anforderungen, um die dann herum Funktionalität gruppiert wird. Das Ergebnis sind oft/meist ideal-naive oder schlicht falsche Repräsentationen der Welt.

2) Flussorientierte Architektur ist kein neuer Gedanke. Event-Driven Architecture (EDA) ist ein etabliertes Architekturmuster in diesem Sinne. Ich möchte jedoch darüber hinaus gehen. EDA ist heute vor allem in “großen Anwendungen” in Gebrauch. Das empfinde ich als unnötige Beschränkung, die vor allem einem Denken entspringt, EDA hätte mit spezieller oder gar teurer Infrastruktur zu tun.

Jede Software kann davon profitieren, wenn ihre Architektur flussorientiert ist. Höhere Evolvierbarkeit sollte kein Privileg großer Systeme sein.

3) Ein ETL-Prozess nimmt in der Architektur insofern eine besondere Bedeutung ein, als dass er nicht nur einem Bounded Context angehört. Eine eigene Ebene in der Strukturhierarchie der Architektur verdient er deshalb jedoch nicht. Er kann als App oder als BS-Prozess angesehen werden.

Montag, 27. Dezember 2010

Ein Team das hat zwei Modi, zwei Modi hat ein Team

Schade, dass in diesem Beitrag von Bernd Oesterreich das Team so einseitig gezeichnet ist. Es ist fast ausschließlich im operativen Modus beschrieben. Ein Fußballteam während des Spiels.

Ungleich und nicht gleichberechtig: so sollen Teammitglieder vor allem sein? Wussten wir das aber nicht immer schon und haben der sozialromantischen Version demokratischer Kuschelteams misstraut? Nun wissen wir endlich, dass wir damit richtig lagen.

Oder?

Für meinen Geschmack wurde hier bei allem systemischen Ansatz leider das Kind mit dem Bade ausgeschüttet.

Klar, im operativen Modus, wenn das Spiel läuft, wenn Arbeit weggeschafft werden muss, wenn es ums Koordinieren von Handgriffen geht, dann ist "Ansagen" ein probates Mittel. Dann sind die Teammitglieder ungleich, weil immer einer etwas mehr Überblick hat als andere. Im Tagesgeschäft sind demokratische Entscheidungen oder gar Konsens hinderlich, weil ineffizient. Dann gehts um Ausführen, ums abarbeiten.

Der operative Modus ist aber nicht alles. Kann es nicht sein, weil es in einen Rahmen braucht. Auf den spielt Bernd Oesterreich zwar an

[…] erst schaut das Team, wer entscheiden soll und fallbezogen kompetent ist, dann entscheiden die ausgewählten Entscheider.

aber der ist für ihn Nebensache. Schade. Denn hier bestünde die Chance, dem Team eine wahrhafte Selbstorganisation einzuräumen, ohne die operative Effizienz in Sozialromantik zu ersticken.

Der Schlüssel liegt aus meiner Sicht in einer klaren Separation of Concerns (SoC). Warum sollte die auch nur im Softwareentwurf vorteilhaft sein? ;-)

Entscheidungsmethoden und –wege im operativen Geschäft sind klar zu trennen von Entscheidungsmethoden und –wegen der Rahmendefinition. Ein selbstorganisierendes Team tut nicht nur etwas im Sinne seines Zwecks, sondern organisiert sich eben auch, um ihn in bester Weise zu erfüllen.

Wie die Organisation im operativen Geschäft aussieht, ist dabei gar nicht so spannend. Darüber schreibt Bern Oesterreich aber vor allem. Wer geglaubt hat, das Konzept der Selbstorganisation mache darüber eine Aussage oder würde gar Gleichberechtigung und Demokratie “während des Spiels” empfehlen, hatte es schon immer missverstanden.

Selbstorganisation bezieht sich vielmehr auf die Rahmengebung, d.h. auf die Metaebene. In der Selbstorganisation entscheidet das Team, also alle Mitglieder kollektiv, darüber, wie es sich für das operative Geschäft organisiert. Wie diese Entscheidungen ausfallen, ist egal. Wie sie getroffen werden, ist spannend.

Da kommt man nämlich nicht an Gleichheit und Gleichberechtigung vorbei, wenn Selbstorganisation noch irgendwie einen Unterschied machen soll. Selbstorganisation bedeutet schlicht, dass die Teammitglieder in allen Rahmenentscheidungen gleich und gleichberechtigt sind. In Rahmenentscheidungen entscheidet kein Einzelner, sondern das Team als Ganzes. Alles andere würde das Team in Bezug auf Rahmenentscheidungen zu einer Gruppe degradieren, für die gedacht und entschieden wird.

Gerade in der Gemeinsamkeit der Entscheidung für den eigenen Rahmen zeigt sich das, was ein Team unterscheidet von einer Gruppe. Dass Menschen im operativen Geschäft als Team arbeiten, mag schwierig sein. Aber es ist umso schwieriger, je weniger diese Menschen sich gemeinsam einen Rahmen geben können. Denn die gemeinsamen durchlaufenen Prozesse zur Rahmenfindung und der von allen getragene Rahmen sind wesentliche Bestandteile der Kultur eines Teams.

Wer Selbstorganisation als sozialromantisch abtut und auf die Wahl von Führern stutzt, verschenkt großes Potenzial für die Motivation und bremst die “kollektive Intelligenz” des Teams aus.

Aber alles wird einfach, wenn man die zwei Modi eines Teams klar unterscheidet: operatives Geschäft und Rahmengebung. Dann kann Ungleichheit und Gleichheit, dann kann “Ansagen” und gemeinschaftliche Entscheidung nebeneinander existieren. Kein entweder-oder, sondern sowohl-als-auch.

Samstag, 25. Dezember 2010

In Abhängigkeit refaktorisieren

imageRefaktorisieren ist überbewertet – zu der Überzeugung gelange ich immer mehr. Refaktorisieren ist eine Symptomkur, die das System, das Paradigma, das zu dem Zustand geführt hat, den sie auflösen soll, nicht verlässt.

Vielleicht ist das auch der Refaktorisierung selbst nicht anzukreiden. Das mag sein. Refaktorisierung bedeutet dann nicht nur eine funktionserhaltende Umstrukturierung, sondern genauer eine paradigmatische funktionserhaltende Umstrukturierung.

Dann ist es denen anzukreiden, die die Refaktorisierung – speziell die objektorientierte Refaktorisierung - so vertreten, als sei sie der Schlüssel zum Glück. “Schaffe dir die Refaktorisierungsmuster drauf, schaffe dir ein Tool wie ReSharper an – und schon ist der Weg aus dem Brownfield abgesteckt.” Oder auch: “Folge treu dem Dreischritt red-green-refactor und ein Platz auf der ewig grünen Wiese ist dir gewiss.”

Bullshit!

Selbstverständlich hat Refaktorisierung einen Wert. Sie ist ein Tool, das man zur rechten Zeit einsetzen kann und soll. Mein Eindruck ist nur, dass die jedem Tool eigene Begrenzung beim Lob der Refaktorisierung vergessen wird. Wo hat je ein Artikel gesagt: “Stopp! Ab hier hilft Refaktorisierung nicht weiter, um Evolvierbarkeit zu erreichen.” oder “Refaktorisierung macht nur in diesem oder jenem Rahmen Sinn.”

Klar, es wird schonmal erwähnt, dass man vorsichtig sein solle und Refaktorisierung nicht zum Selbstzweck werden darf. Refaktorisierung solle vor allem helfen, einen anderen Zweck zu erfüllen; refaktorisiere dann, wenn eine Veränderung es gebietet und nicht “auf Vorrat”.

Damit ist aber keine Grenze des Werkzeugs Refaktorisierung aufgezeigt, sondern nur die Intensität seiner Anwendung.

Mir tritt nun aber immer deutlicher eine solche Grenze ins Auge. Die üblicherweise beschriebene Refaktorisierung, die ReSharper-Refaktorisierung, hat ihre Grenze in der Objektorientierung. Refaktorisierung kann nur mit den Mitteln der Objektorientierung arbeiten. Der Code nach der Refaktorisierung ist immer noch objektorientiert.

Wie gesagt: Der Refaktorisierung selbst kann man das nicht anlasten, aber ihren Proponenten, die diese Grenze nicht aufzeigen – und sei es aus den löblichsten Beweggründen.

Eigentlich müsste ich deshalb wohl sagen: Objektorientierung ist überbewertet. Entzündet haben sich meine folgenden Gedanken aber an der Refaktorisierung. Deshalb habe ich es eingangs anders formuliert.

Und was stört mich nun an der Refaktorisierung bzw. am OO-Paradigma?

Mich stören die Abhängigkeiten.

imageMan mag lesen, Objektorientierung sei die Summe aus Kapselung plus Polymorphie plus Vererbung. Das ist natürlich nicht falsch, selbst wenn man sich trefflich darüber streiten kann, ob denn nun Vererbung ein unverbrüchliches Element der Objektorientierung sei.

Das Problem solcher Beschreibung von Objektorientierung ist nicht, was sie als Eigenschaften nennt, sondern das, was sie auslässt. Sie lässt – ganz natürlicherweise, übrigens – aus, das was der Objektorientierung zugrunde liegt. Sie lässt ihr Erbe aus. Das liegt in der prozeduralen Programmierung. Und noch tiefer liegt es in der von-Neumann-Maschine.

Es gibt keine wirkliche Einheit von Daten und Funktionen in unseren Rechnern, wie Objekte sie vorgaukeln. Zwar liegen Daten und Funktionen im grundsätzlich selben Speicher (Prozessadressraum), doch darin sind sie sauber getrennt. Das ist heute immer noch so wie zu Zeiten von Modula, C, Fortran, Assembler.

Objekte sind daher nur moderne Formen von C-Strukturen oder Pascal-Records. Und Methoden rufen sich immer noch mit einer call-Maschinencodeanweisung auf. Ob die zu einer virtuellen oder realen Maschine gehört, ob der Sprung direkt oder über eine Dispatch-Tabelle geht… das ist einerlei.

Objektorientierung abstrahiert von der notwendigen Trennung von Daten und Funktionen im Speicher. Das ist eine gute Sache. Aber das ist eben nicht alles. Sie bleibt dem Abhängigkeitsdenken, dem Callstack-Denken verhaftet. Wie Methoden einander nutzen, unterscheidet sich nicht davon, wie weiland C-Funktionen sich genutzt haben.

Das halte ich für ein Problem. Hier sehe ich die Grenze für die Nützlichkeit der Objektorientierung (wie der prozeduralen Programmierung oder auch Anteile der Funktionalen Programmierung).

Man mag dagegen halten, dass so die Welt sei und doch auch soviel machbar sei und funktioniere. Klar. Das ist unzweifelhaft.

Bis zum Beginn des 19. Jahrhunderts war aber auch viel machbar und hat funktioniert. Stonehenge, Pyramiden, Petra, Chinesische Mauer, Petersdom… all das wurde vor allem mit “menschlicher und tierischer Kraft” geschaffen. Die Werkzeuge haben sich in 5000 Jahren natürlich verändert. Was den Erbauern von Stonehenge noch sehr schwer gefallen war und Jahrzehnte gedauert hat, war für die Baumeister des Kölner Doms kein wirkliches Thema mehr.

Doch was ist dieser Fortschritt angesichts dessen, was dann ab dem 19. Jahrhundert passiert ist? Dampfmaschine, Explosionsmotor und Elektromotor haben das Bauen revolutioniert - genauso wie die Fortschritte in den Materialien Stahl, Beton, Glas, Kunststoff.

Alle Verbesserungen innerhalb des Paradigmas (oder Denkhorizonts) “menschliche und tierische Kraft” (oder “Materialien aus der Natur”) konnten nicht vorausahnen lassen, was passierte, als man dieses Paradigma sprengte.

Innerhalb der Grenzen von “menschliche und tierische Kraft” war viel möglich, sehr viel – arrogant wäre jedoch der gewesen, der behauptet hätte, damit sei die Grenze des Machbaren erreicht, der Gipfel der Baukunst erklommen.

So sehe ich es mit der Objektorientierung. Mit ihr im Speziellen und im Rahmen des zugrundeliegenden “Abhängigkeitsparadigmas” für Funktionalitätsnutzung ist viel möglich, sehr viel. Arrogant wäre jedoch der, der behauptete, damit sei die Grenze des Machbaren (oder Wünschenswerten), der Gipfel der Programmierkunst erreicht. Man müsse nur lernen, Objektorientierung sauber zu betreiben und schon sei nur noch der Himmel die Grenze.

I beg to disagree.

Menschliche und tierische Kraft und natürliche Baumaterialien waren und sind genauso beschränkend wie das “Abhängigkeitsparadigma” der prozeduralen und objektorientierten Programmierung. Und beim hochgelobten Refaktorisieren zeigt sich das für mich sehr deutlich. Hier ein Beispiel mit einer Folge von Anweisungen in einer Methode in einer Klasse:

image

Was würde daraus durch Refaktorisierung? Mit “Extract Method” würden Anweisungsgruppen ausgelagert in eigene Methoden:

image

Und mit “Extract Class” würden Methoden dann nochmal in separate Klassen rausgezogen:

image

Für einen Freund der Objektorientierung und des Refactoring sieht das alles normal aus. Prinzipien wie SPR und SLA werden in Anschlag gebracht und treiben eine differenzierte Struktur aus. Statt alles in einer Methode abzufrühstücken, wird auf kleinere Funktionseinheiten verteilt. Die LOC pro Methode sinken, die LOC pro Klasse sinken, die Cyclomatische Komplexität sinkt. Alles scheint in Butter.

Ich sehe das anders. Denn ich sehe eine Vervielfältigung von Abhängigkeiten. Vor der Refaktorisierung war der Code schlecht zu verstehen, weil er Anweisungen auf verschiedenen Abstraktionsebenen enthielt und verschachtelt war; dafür stand er “auf einem Haufen”. Nach der Refaktorisierung ist der Code aber immer noch schlecht zu verstehen. Denn erstens sind die algorithmischen Verschachtelungen nicht aufgehoben, sondern nur verschleiert worden. Und zweitens sind zu ihnen Indirektionen in Form von Abhängigkeiten getreten. Der vorherige Haufen ist jetzt nur kein Haufen mehr, sondern in alle Winde zerstreut.

Der refaktorisierte Code ist selbstverständlich im OO-Paradigma geblieben. Die Abhängigkeiten sprießen. Und weil sie sprießen, muss nun auch noch über Praktiken wie IoC und Tools wie DI Container nachgedacht werden.

Etwas übertrieben gesagt: Die Objektorientierung ist eine so komplizierte Technologie, dass man sie nicht ohne eine Vielzahl von begrenzenden und stützenden Prinzipien, Praktiken und Tools einsetzen kann. Damit ist sie mehr ein Problem denn eine Lösung.

Mit so einem Statement mache ich mich natürlich unbeliebt. Das ist mir klar. Aber ich habe lange drüber nachgedacht und spreche es daher nicht leichtfertig aus. Die wahren Gewinne, die nur oder zumindest vor allem durch Objektorientierung erzielt wurden in der Softwareentwicklung, sind mir zu gering, als dass ich sagen wollte, sie sei eine einzige Erfolgsgeschichte. Und das sage ich, obwohl (oder weil?) ich seit 1990 objektorientiert programmiere.

Natürlich gibt es Gewinn durch Objektorientierung. Aber ich sage mal provokant: Wer hat je dagegen die Verluste durch Objektorientierung aufgerechnet? Ist die Bilanz wirklich positiv. Ich habe Zweifel.

Wie gesagt: Irgendwie funktioniert ja die OO-Software. Keine Frage. Aber wenn es heute unwartbare Systeme gibt, dann sind das Anwendungen auf OO-Basis. Man mag einwänden, das läge daran, dass ja vor allem mit OO-Sprachen entwickelt würde, deshalb müssten auch die unwartbaren System OO-Anwendungen sein. Haha. Ja, klar. Dagegen halte ich: Die Objektorientierung ist damit angetreten, genau das zu verhindern. Sie hatte versprochen, Softwareentwicklung “natürlich” zu machen – halt objektorientiert wie die Welt scheinbar ist und damit viel einfacher zu beherrschen als alles was vorher war – und damit eben auch evolvierbarer und korrekter. Und was ist rausgekommen?

Objektorientierung ist einfach kein Selbstgänger. Sie ist vielmehr so schwierig, dass sie deutlich in der Anwendung begrenzt werden muss, meine ich. Sie hat ihren Wert. Ich möchte sie nicht missen. Doch den sehe ich vor allem bei der “Programmierung im Kleinen”. Überschaubare Probleme, die in wenigen Hundert Zeilen Code zu lösen sind, die kann man objektorientiert angehen. Super! Volle Kraft voraus. Da entstehen dann Codegebilde, die man mit SOLID-Prinzipien und Refaktorisierung im Griff haben kann, deren Korrektheit man zeigen kann, die für sich evolvierbar sind.

Aber oberhalb dieser “Taschen der Objektorientierung”…? Was da? Helfen da Komponenten- oder Pakete wie sie die UML bietet? Nein. Die sind nur Objektorientierung in Verkleidung. Denn was Klassen/Objekten, Komponenten, Paketen gemeinsam ist, ist die Sicht auf die Welt durch eine Abhängigkeitsbrille. Die ist das Problem. Große Systeme lassen sich – so meine immer fester werdende Meinung – nicht wirklich agil und evolvierbar innerhalb eines fundamentalen Abhängigkeitsparadigmas realisieren.

Irgendwie geht das. Aber irgendwie geht irgendwie alles. Man kann auch mit Streichhölzern ein Formel 1 Auto bauen oder Kleidung aus Papier fertigen. Das sind hübsche Zeitvertreibe – nur wirklich praktischen Wert haben sie am Ende nicht. Oder wollte man sie praktisch einsetzen, wären große Probleme gleich zur Stelle.

Noch eine andere Analogie: Wir können auf der Basis Newtonscher Physik eine Menge Energie erzeugen mit Wind-, Kohle-, Wasserkraftwerken. Richtig, richtig viel Energie braucht dann aber ein anderes Paradigma: die relativistische Physik Einsteins und die Quantenphysik Heisenbergs. Nur damit sind Kernkraftwerke oder dermaleinst Fusionskraftwerke möglich.

Für mich bedeutet das zusammenfassend: Objektorientierung ist eine gute Sache. Ihr muss allerdings ein Platz und eine Reichweite zugewiesen werden, damit ihr Nutzen ihre Nachteile aufwiegt.

image

Im Bild sind das die “Taschen der Objektorientierung”. Sie sind überschaubar, innerhalb ihrer sind Abhängigkeiten in übliche OO-Manier erlaubt.

Außerhalb dieser “Taschen” jedoch… die “Taschen” selbst… da soll keine Objektorientierung im Spiel sein. Das Denken in Abhängigkeitsbeziehungen ist dort zu verrmeiden. Wie die “Taschen” nach außen beschaffen sind, woher sie kommen, das will ich an dieser Stelle offen lassen.

In der Natur finden sie keine Abhängigkeiten wie sie in objektorientierten Strukturen existieren. Die wahrhaft komplexen Systeme der Welt kommen ohne aus. Und auch die Teile menschengemachter Maschinen sind nicht abhängig voneinander wie es objektorientierte Funktionseinheiten sind.

Woher kommt da nur der Glaube, virtuelle, aber dennoch (oder gerade deshalb) riesige Softwaregebilde könnten geeignet auf einem Paradigma aufgebaut werden, in dessen Kern Abhängigkeiten stehen? Ich weiß nicht, ob ich diesen Glauben naiv oder arrogant nennen soll. In jedem Fall scheint es mir nun offensichtlich, dass er verfehlt ist.

Sobald ein Problem eine Größe hat, die sich mit OO-Mitteln in Hunderten LOC umsetzen lässt, finde ich Objektorientierung geeignet. Solange ein Problem jedoch umfangreicher ist, ist für Entwurf und Umsetzung die Objektorientierung und jedes andere Paradigma das auf “Abhängigkeitsdenken” basiert ungeeignet.

Hierarchie ist natürlich weiterhin ein wichtiges Strukturierungsmittel. Keine Frage. Doch das, was da in einer Hierarchie aufgespannt ist – die Funktionseinheiten, die zusammen die Lösung ergeben –, darf nicht über Abhängigkeiten verbunden sein. Das ist schlicht nicht überblickbar, nicht evolvierbar. Objektorierung bzw. OO-Denke verbietet sich also sogar doppelt: erstens, weil sie sich innerhalb des Abhängigkeitsparadigmas bewegt, zweitens weil sie kein Mittel zu natürlicher Hierarchisierung bietet.

Die üblichweise gemeinte Refaktorisierung ist mithin überbewertet, weil sie Objektorientierung perpetuiert. So wichtig sie in “Taschen” der OO nötig sein mag, so hilfreich dort Prinzipien wie SOLID oder Tools wie DI Container sein mögen… Ich bin der Meinung, dass man daraus nicht ableiten soll, Objektorientierung sei dazu geeignet, einfach/natürlich/intuitiv Größeres zu leisten.

Mittwoch, 22. Dezember 2010

Quotenlose Entwicklung

Was ist an diesen Bildern falsch?

image image

Zeigen Sie vielleicht keine echten Softwareentwickler? Doch. Zumindest auf dem linken Bild erkenne ich eine Person, von der ich weiß, dass sie Informatiker ist – weil ich mit ihr zusammen studiert habe.

Ist das Diagramm am Whiteboard des zweiten Bildes unrealistisch? Nein. Es folgt zwar keinem UML-Standard, würd ich sagen – aber das ist ja nichts Besonderes in der Branche :-) Die Inhalte sehen zumindest plausibel aus für eine Besprechung einer Web-Anwendung.

Stößt mir auf, dass die Bilder gestellt sind? Nein. Das finde ich normal für Werbebilder. Man muss nicht wissen, warum die Personen im ersten alle zum Himmel blicken. Erwarten Sie von dort die Niederkunft eines besseren Tools? Oder steigt von dort der neue Kollege herab? Auch “gute Aussicht” verbinde ich nicht mit einem Blick nach oben, sondern eher in die Weite, zum Horizont. Aber egal.

Gleichfalls sitzen die Personen im zweiten Bild etwas gezwungen um den Tisch. Der Laptop zeigt nichts; warum ist er aufgeklappt? Realistisch wäre, wenn dort ein Skype-Chat und eine FaceBook-Seite zu sehen wären oder zumindest ein Email-Client. Denn damit beschäftigen sich Menschen in Besprechungen, wenn sie ein Laptop dabei haben. Und dann die Armhaltung der Person rechts. Zu schlaff, um ernst gemeint zu sein, würde ich sagen. Aber egal.

Nein, ich meine etwas anderes. Ich meine das Mann-Frau-Verhältnis. Beide Bilder aus dem aktuellen ObjektSpektrum zeigen 5 Personen, nein, genauer: 5 Softwareentwickler – und davon sind 2 Frauen.

40% der abgebildeten Person sind weiblich. Das ist absolut unrealistisch. Weit von der Realität entfernt. Geradezu märchenhaft.

Meine aktuelle Zählung der weiblichen Mitglieder im Clean Code Developer XING-Forum ergibt einen Anteil von um die 3%. (Prämisse: Das Verhältnis im Forum spiegelt das Verhältnis in der Branche wider. Ich wüsste aber nicht, welcher Faktor CCD unattraktiver für Frauen als für Männer machen sollte. Eher umgekehrt. Auch glaube ich nicht, dass Frauen bei XING unterrepräsentiert sind.)

In der Softwareentwicklung haben wir eine bodenlose Frauenquote. Warum also mit solchen Bildern die Branche beschreiben? Soll es dadurch besser werden? Motto: “Wir zeigen mal die Verhältnisse, die wir uns wünsche, dann ziehen wir Frauen an, sich bei uns zu bewerben.”

Oder ist es eher wie bei Truckermagazinen? Motto: “Wir zeigen Mädels im Team, dann bewerben sich die hormongesteuerten männlichen Entwickler bei uns.” Wobei sowohl Trucker wie Entwickler wissen, dass nicht immer Mädels drin sind, wo sie drauf sind.

Tja… ich weiß nicht. In jedem Fall sind mir beide Bilder sehr ins Bewusstsein gesprungen ob ihrer Entfernung von der Realität. Das bedaure ich. Ich bedaure es sogar umso mehr, je öfter ich Trainings mache, in denen wir konsequent im Team Anforderungen analysieren/verstehen, Architektur und Modell entwerfen und schließlich die Arbeitsorganisation planen. All diese Teamtätigkeiten würden sehr von “weiblichen Elementen” profitieren. Dazu zähle ich unter anderem – man verzeihe mir eventuelle Klischeehaftigkeit – “weniger Technikverliebheit”, “mehr Kommunikationskompetenz”, “mehr Servicewille”, “mehr Blick für´s Ganze”.

Was müssen wir als Branche tun, um das zu ändern? Wie können wir die bodenlose Frauenquote erhöhen? Wie können wir unsere Arbeit für Mädchen/Frauen interessanter machen? Das ist natürlich vor allem eine Herausforderung der Ausbildung. Klar. Aber ich denke auch, dass es um Marketing geht. Wo ist die Branchendarstellung, die ein anderes Bild zeichnet von der Softwareentwicklung? Aber auch die Personalabteilungen sind gefordert. Sie sollten ihre Forderungen an den Entwickler(innen)markt überdenken. Sie sollten ihre internen Förderungen von noch-nicht Entwicklerinnen überdenken. Und es hilft sicherlich nicht, Wunschdarstellungen wie die obigen aus “political correctness” heraus zu bringen, ohne einen Plan zu haben, wie sie denn materialisiert werden könnten.

Ein kleiner Baustein für Veränderung mögen Initiativen wie diese sein:

image

Hier werden speziell Frauen angesprochen, sich einen Einstieg in die Softwareentwicklung vorzustellen. Etwas mehr Erklärung, warum das sinnvoll sein könnte jenseits von “Da kannst du Geld verdienen”, mag noch helfen. Klar. Aber es ist ein Anfang.

Wo sind weitere Initiativen, die sich an Mädchen/Frauen richten, um Ihnen zu zeigen, dass Softwareentwicklung von ihren “Gender-Kompetenzen” profitieren kann? Und dass das natürlich Spaß macht. Beiden Geschlechtern :-)

Dienstag, 21. Dezember 2010

Bei Anforderung vorgehen – Teil 2

Neulich hab ich ein Szenario vorgestellt und ermuntert mal zu überlegen, wie die Anforderugen umgesetzt werden könnten. “Wann sieht der Kunde welche Funktionalität?” war für mich die Kernfrage, denn daran scheiden sich die Geister, wenn es um Auslieferung in kleinen Inkrementen geht. Die zu sehen, scheint notorisch schwierig für Softwareentwickler.

Heute stelle ich zu dieser Frage nun meine Antwort vor.

Schritt 1: Anforderungen klären

Worum geht´s eigentlich? Das ist natürlich als erstes zu klären. Das Szenario ist hier nur sehr pauschal beschrieben und der Auftraggeber steht nicht zur Verfügung. Deshalb kann dieser Schritt hier auch nur sehr allgemein ausfallen. Spekulation erlaubt :-)

Es geht um eine Anwendung, die Produktionsabhängigkeiten aufzeigen soll.

User Story: Der Materialplaner gibt eine Teilenummer ein und bekommt ein Diagramm angezeigt, das darstellt, wie das Teil in der Produktion benötigt wird.

Wie das Diagramm aussehen soll, ist hier uninteressant. Wahrscheinlich weiß der Kunde das selbst nicht so genau ;-) Wir müssen also mit so einer simplen Beschreibung weitermachen.

Eine User Story enthält für mich typischerweise mehrere Features. Ein Feature wird durch eine Interaktion “getriggert” und hat Eingaben, ggf. Ausgaben oder ggf. Seiteneffekte. Wie sieht es damit hier aus? Ich erkenne ein Feature:

F1: Produktionsabhängigkeitsdiagramm anzeigen
  Interaktion: Benutzer klickt auf einen Button
  Eingabe: Teilenummer
  Ausgabe: Diagramm
  Seiteneffekte: keine
  Benötigte Ressourcen: DB, Mainframe

Für dieses Feature erbitte ich vom Kunden natürlich Akzeptanzkriterien, d.h. Eingaben und zugehörige Ausgaben.

Schritt 2: Architektur entwerfen nach nicht-funktionalen Anforderungen

Zuerst sind aus den Anforderungen die nicht-funktionalen Anforderungen herauszulesen. Sie zu erfüllen ist Aufgabe der Architektur, d.h. des Grundgerüstes, des Fundaments jeder Software.

Nach dem hier vorgestellten Metamodell für Architektur identifiziere ich für die hiesigen Anforderungen…

  • einen Bounded Context: Das angeforderte Anwendungssystem besteht nur aus einer Domäne. Es greif zwar auf andere Bounded Contexts zu (existierende Datenbank und Mainframe), aber es selbst stellt einen eigenen Bounded Context dar. (Aus größerer Entfernung betrachtet könnte man fragen, ob das Anwendungssystem nicht eher in einen schon existierenden Bounded Context gehört. Aber das lasse ich hier beiseite, weil der Auftraggeber nicht zur Verfügung steht für eine Diskussion.)
  • eine App: Die Anforderungen können mit nur einer App umgesetzt werden. Nur eine erkennbare Rolle interagiert mit dem Anwendungssystem.
  • eine Maschine: Die App kann ohne Probleme auf einer Maschine betrieben werden – allerdings greift sie auf andere Maschinen zu.
  • ein Prozess: Die App kann ohne Probleme in einem Prozess betrieben werden. Eine WPF-EXE als Host für die Funktionalität reicht. Die App ist also eine typische “C/S-Anwendung”. Sie wird auch nur gelegentlich und von wenigen Anwendern benutzt. (Das nehme ich der Einfachheit halber mal an ;-)
  • die Concerns: GUI, DB-Zugriff, Mainframe-Zugriff, Domänenlogik; Security ist lt. Anforderungen kein Thema

Damit ist Grobstruktur für die Lösung beschrieben. Sie ist einfach. Aber es geht ja hier nicht um Kompliziertheit, sondern um Schrittfolge im Vorgehen.

Schritt 3: Modellieren nach funktionalen Anforderungen

Im Rahmen der Architektur entwerfe ich anschließend ein Modell für das Anwendungssystem. Das tue ich mit Flow-Oriented Modelling und komme für das einzige Feature auf den Fluss…

GUI -> Order in Zeitraum ermitteln (DB) -> Teile zu Orders sammeln (Mainframe) -> Orders nach gesuchtem Teil filtern (Logik) -> Diagramm berechnen (Logik) -> GUI

Annahmen, die ich mal mache, die aber natürlich im richtigen Leben mit dem Kunden besprochen werden müssten:

  • Ich brauche die Orders eines Zeitraums aus der DB, um die zugehörigen Teile aus dem Mainframe zu ziehen.
  • Die Abfragen bei DB und Mainframe sind recht pauschal, deshalb ist hinterher ein eigener filter nötig.

Die Architektur ist einfach, deshalb werden alle Funktionseinheiten des Modells im einzigen Prozess der einzigen App laufen. Die Concerns sind im Modell berücksichtig.

Schritt 4: Spike Solutions

Zumindest ich, der ich keine Ahnung von der Domäne habe und mit den Ressourcen keine Erfahrung habe, würde hier zwei Unsicherheiten erkennen: Zugriff auf DB und Zugriff auf Mainframe. Die würde ich mit Spike Solutions ausräumen, d.h. kleinen "Forschungsprojekten". Die weise ich an 1 Entwickler in meinem Team zu. Der soll im Verlauf von 1 Tag herausfinden, wie das geht, ob und wie wir an die daten herankommen.

Da ich optimistisch bin, dass es überhaupt geht, muss ich darauf erstmal nicht warten. Die Implementierung kann beginnen.

Schritt 5: Arbeitsorganisation

Die Arbeitsorganisation lasse ich hier aus. Sie würde aus Modell und Architektur Komponenten synthetisieren, die dann im Team parallel im Sinne eines Features implementiert werden können. Hier gäbe es mindestens 4 solcher Komponenten.

Komponenten dienen der Entkopplung von Entwurf und Unternehmens/Teamstruktur. Software sollte eine Struktur haben, die ihrem Zweck angemessen ist. Ohne weitere Maßnahmen spiegelt sich jedoch die Unternehmens(kommunikations)struktur in der Software wider. So sagt es Conway´s Law. Dem ist bewusst entgegen zu wirken. Das geschieht, indem Architektur und Modell eben nicht als Ziel haben, die Einheiten der Implementation zu definieren. Die sind vielmehr das Ergebnis einer ausdrücklichen Arbeitsorganisation, die die Entwurfsergebnisse in Komponenten verpackt, um sie Teammitgliedern zuzuweisen.

Die Zusammenfassung geschieht aus arbeitsorganisatorischem Blickwinkel, bewegt sich aber dennoch im Rahmen der architektonischen Mindestanforderungen. Es gibt keine Komponenten über Concerns hinweg.

Schritt 6: Implementierung

Bei der ganzen Aufgabe ging es mir eigentlich nur um diesen Schritt. Denn hier scheiden sich sehr schnell die Geister. Wie kann man solche Anforderungen an den Kunden bringen?

Eine Schätzung für den Aufwand gebe ich bewusst nicht ab. Soviel ist zwar klar: wir reden über Tage und nicht Wochen. Aber eine nähere Schätzung bringt nichts. Stattdessen sage ich dem Kunden, dass wir sehr schnell Risikofaktoren ausräumen werden – mit seiner Mithilfe. So kann er nach geringem Einsatz noch die Notbremse ziehen. (Ob dafür 1, 2 oder 5 Entwickler nötig sind, ist nicht so wichtig für das Weitere. Das Team sollte allerdings wg. der Spike Solution schon aus min. 2 Entwicklern bestehen.)

Was aber nun tun in den folgenden Tagen? Den Auftrag dankend entgegennehmen und am Ende liefern? Oder wie?

Meine Devise lautet: jeden Tag liefern. Ja, wirklich jeden Tag. Und immer in Inkrementen, mit denen der Kunde etwas anfangen kann. Also immer Längsschnitte durch die Anforderungen. Keinen Tag verschwenden mit Infrastrukturprogrammierung.

Das nutzt dem Kunden. Das nutzt dem Entwickler. Denn so wird jeden Tag wertvolles Feedback generiert.

An Tag 0 wurden die Anforderungen geklärt, die Architektur bestimmt und modelliert. Die Aufgabe ist ja überschaubar. (Wie gesagt, es geht um nicht mehr als beschrieben. Jetzt also nicht den Zeigefinger heben und einwänden, dass ja gar nicht über Security oder Internationalisierung oder Portabilität usw. gesagt wurde. Es ist einfach so einfach wie beschrieben. Es lohnt auch nicht das Philosophieren darüber, ob der Kunde nicht besser bedient wäre mit einem Business Process Reengineering oder so, damit das Anwendungssystem überflüssig wird.)

Tag 1:

Die Implementierung schreitet tageweise voran. Am Ende des ersten Tages ist natürlich nicht alles fertig. Also muss ich mich der kompletten Realisierung annähern.

Auf die Spike Solutions warte ich nicht. Sie laufen parallel. Ich habe also noch keine Adapter für DB- und Mainframe-Zugriff. Macht aber nichts.

Am ersten Tag enthalten die aus dem Modell übersetzten Funktionseinheiten für DB-Zugriff und Mainframe-Zugriff deshalb nur fixe Daten (s. Akzeptanzkriterien).

Die Filterung scheint mir aber einfach zu sein. Also implementiere ich sie vollständig.

Deshalb liefere ich am Ende von Tag 1 eine Anwendung, die auf festen Daten schonmal vollständig filtert - aber sie zeigt noch kein Diagramm, sondern nur eine Liste von Ergebnissen. Damit kann der PO überprüfen, ob ich bei gegebenen fixen Beispieldaten die Filterung korrekt verstanden habe und also die korrekten Ergebnisdaten anzeige (s. Akzeptanzkriterien). 

Ein Tag Entwicklung liefert dem Kunden einen kleinen Nutzen.

Tag 2:

Ich ersetze die Liste der Aufträge durch das Diagramm. Ich kann mich den ganzen Tag darauf konzentrieren. Der Kunde kann dann beurteilen, ob ich seinen Wunsch einer Ergebnisvisualisierung verstanden habe.

Ein Tag Entwicklung liefert dem Kunden einen kleinen Nutzen.

Tag 3:

Die Spike Solutions haben ergeben, wie ich auf die Ressourcen zugreifen kann. Damit fange ich beim Mainframe an.

Ich suche mir von Hand einige Aufträge aus der DB heraus. Die werden nun als fixe reale Daten in die DB-Abfrage-Funktionseinheit eingetragen. Dann lasse ich die Mainframe-Abfrage damit laufen; die ist nun real. Der Kunde kann beurteilen, ob Daten aus der DB zu korrekter Interaktion mit dem Mainframe führen.

Ein Tag Entwicklung liefert dem Kunden einen kleinen Nutzen.

Beachte: Die wesentliche Infrastrukturprogrammierung hat im Rahmen der Spike Solutions stattgefunden. Da ist sie nicht sauber gewesen, dafür schnell und auf den Punkt. Meine Unsicherheiten sind beseitigt. Der Mainframe-Zugriff kann nun mit hoher Geschwindigkeit für den Produktionscode sauber implementiert werden. Copy & Paste ist dabei ok.

Tag 4:

Schließlich implementiere ich den DB-Zugriff. Auch den haben ja die Spike Solutions auf den Punkt gebracht.

Die Anwendung läuft nun komplett mit realen Daten.

Ein Tag Entwicklung liefert dem Kunden einen kleinen Nutzen.

Zusammenfassung

Man mag einwänden, dass bei diesem Vorgehen erst nach Tag 4 alles wirklich und real für den Kunden überprüfbar sei. Das stimmt natürlich in Bezug auf die Gesamtanforderungen.

Aber genau da liegt der Hase im Pfeffer: Kunden müssen in die Pflicht genommen werden, nicht nur Gesamtlösungen abnehmen zu wollen (oder auch nur große Meilensteine). Sie müssen täglich (oder von mir aus auch alle 2-3 tage) ran. Warum? Weil nur so die Entwicklung keinen Ausschnuss produziert, d.h. Abfall in Form von falsch verstandenen und umgesetzten Anforderungen. Je mehr ungeprüft auf Halde vor dem Kunden liegt, desto größer erstens das darin gebundene Kapital (Funktionalität entwickelt, aber nicht bezahlt). Und zweitens desto größer die Gefahr, dass die Halde Annahmen enthält, die falsch sind und auch noch in weiteren Code eingehen.

Kunden müssen lernen, "Vorläufigkeit" auszuhalten. Oben ist z.B. zuerst das UI nur vorläufig (Liste statt Diagramm) - aber in gewissem Umfang ist es funktional. Und das ist, was zählt. Es stellt einen kleinen Nutzen dar. Es ist eine Feature-Scheibe, ein dünner Längsschnitt durch das Anwendungssystem. Der Kunde kann mit dem Code etwas anfangen und Feedback geben.

Das ist es, was ich an dem Szenario einmal demonstrieren wollte: diese Denke in Längsschnitten. Das ist für mich im Kern von Agilität. Kein Big Design Up-Front (BDUF), keine Infrastrukturprogrammierung ohne Kundennutzen, sondern jeden Tag ein Scheibchen mehr Funktionalität.

Dass die nicht immer einsatzfähig ist, ist selbstredend. Darum geht es auch nicht. Wichtiger ist, dass Funktionalität nicht ohne Kundenfeedback als abgeschlossen betrachtet werden kann. Kommt das schnell, dann geht es auch schnell voran zur Einsatzfähigkeit. Ein weiterer Vorteil dieses Vorgehens: Der Kunde kann jeden Tag den Kurs ändern. Er hätte zum Beispiel nach Tag 1 sagen können, “Danke, eine Liste reicht mir. Ich hatte mir zwar eine Grafik vorgestellt, aber so geht es auch. Statt eines Diagramms möchte ich lieber die Möglichkeit, mehrere Teilenummern eingeben zu können.”

Jeder Tag ist Kursänderungstag für den Kunden. Jeder Tag ist Erfolgstag für den Entwickler. Das sind für mich wichtige psychologische Aspekte der Softwareentwicklung. Sie fördern die Vertrauensbildung und die Motivation. Tägliche Auslieferung ist daher aus meiner Sicht anzustreben.

PS: Zum Abschluss ein Wort an die ewigen Skeptiker, die da sagen werden, “Aber das geht nicht. Mann kann nicht alle Anforderungen so klein schneiden, dass man jeden Tag etwas Kundenrelevantes ausliefern kann.”

Also…

  • Habt ihr es probiert? Sehr wahrscheinlich nicht. Ich behaupte daher weiter, dass das geht. Im Zweifelsfall schickt mir eure Anforderungen und ich zeige euch, wie man sie in dünne Scheiben schneidet.
  • Vielleicht, ganz vielleicht geht es am Ende doch nicht und ihr müsste mal 2 oder 3 Tage ohne Auslieferung vor euch hinmokeln. Naja, dann sei das mal so. Aber weiterhin solltet ihr anstreben, zurück zu täglicher Lieferung zu kommen. Für euch selbst. Ihr profitiert davon. Es ist zu eurem Vorteil. Denn wer möchte nicht jeden Tag das gute Gefühl haben, etwas für den Kunden Relevantes fertiggestellt zu haben? Wer möchte nicht häufiges Feedback in kleinen Happen statt einmal alle 2 oder 4 ode 12 Wochen? Wer möchte nicht, wenn Kurswechsel durch den Kunden unvermeidlich sind, dass die stattfinden auf der Basis abgeschlossener Funktionalität?
  • Für den Kunden mögen tägliche Lieferungen ungewohnt sein. Er streubt sich, weil doch sein ProductOwner auch noch einen normalen Job hat und sich nicht immer mit den Releases rumschlagen kann. Dann nennt dem Kunden die Vorteile – wieder, weil ihr selbst eure Vorteile genießen wollt. Tut es aus eigenem Interesse. Die Vorteile für den Kunden sind: a) unmittelbares Feedback in einer Sache, in der er sehr wahrscheinlich selbst recht unsicher ist, b) jederzeitige Meinungsänderung, d.h. es wird wirklich immer nur gebaut und vertieft, was wichtig ist.

Samstag, 18. Dezember 2010

Vom Wert des Schätzens im Angesicht real möglicher Unproduktivität

Ob Softwareentwickler Aufwand schätzen können oder nicht… Das lasse ich zur Abwechslung heute mal dahingestellt. Stattdessen frage ich mal: Was sagen Schätzungen denn eigentlich aus?

Szenario 1: Ein Manager fragt seine Frau, wie lang sie für den Weihnachtsbraten wohl braucht. Sie schätzt, dass es wohl 3 Stunden sein werden.

Szenario 2: Ein Manager fragt den Klempner seines Vertrauens, wie lang er wohl für die Badezimmerrenovierung inkl. Austausch der Steigleitungen braucht. Er schätzt, dass es wohl 6 Tage sein werden.

Szenario 3: Ein Manager fragt seinen Entwickler, wie lang der wohl für eine Zahlungseingangs- und Mahnwesen-Anwendung braucht. Der schätzt, dass es wohl 5 Wochen sein werden.

Der geneigte Leser prüfe sich nun, wie er die Schätzungen in den drei Szenarien einschätzt. Sind die alle gleich vertrauenswürdig? Wenn nein, wodurch unterscheiden sich die Szenarien?

In allen Szenarien sind in der Sache grundsätzlich Erfahrene befragt worden. Ich hoffe, da sind wir uns einig. Ja, die Größenordnungen liegen auseinander – Stunden, Tage, Wochen –, aber da sehe ich nicht das Problem. Wenn Erfahrene sich verschätzen, dann doch wohl um einen nicht allzugroßen Prozentsatz, oder? Aus 3 Stunden könnten 4 werden; die Hausfrau hätte sich um 33% verschätzt – aber, hey, das kann doch passieren, oder? Aus 6 Tagen können 8 werden; hey, kein Problem, sowas kann passieren, oder? Oder aus 5 Wochen werden 6 Wochen. Wer hätte das nicht schon bei Softwareentwicklung erlebt. Alles normal, oder?

Das Problem sehe ich nicht beim Verschätzen. Ich glaube zwar immer noch, dass sich Hausfrau und Klempner weniger verschätzen als Softwareentwickler – aber für heute mal egal. Lassen wir sie alle gleich gut schätzen und sind wir mit 33% Überziehung zufrieden. Es könnte schlimmer kommen.

Nein, das Problem liegt woanders.

Szenario 1: Wie lange würde die Frau des Nachbarn des Managers für denselben Weihnachtsbraten wohl brauchen? Die schätzt auf 2 Stunden. Und der Mann der Chefin des Managers? Der würde auf 5 Stunden schätzen.

Szenario 2: Wie lange würde der Schwager des Managers als Heimwerker für die Badrenovierung brauchen? Vielleicht 10 Tage. Und wie lange würde der Großklempner am anderen Ende der Stadt schätzen? Vielleicht 4 Tage.

Bei Szenario 1 und 2 ist es relativ egal, wen man nach einer Schätzung fragt. Wenn der potenzielle Auftragnehmer einigermaßen erfahren in der Sache ist, dann werden die Schätzungen vielleicht um 50%-100% differieren. Hört sich viel an – ist es aber nicht. Denn:

Szenario 3: Wie lange würde der Schwager des Managers für die Anwendung brauchen? Vielleicht 5 Monate. Wie lange würde der Senior-Entwickler aus dem anderen Team brauchen, der leider unabkömmlich ist? Vielleicht 5 Tage.

Damit sind wir beim Kern des Schätzproblems der Softwareentwicklung: der ungewissen Produktivität.

In der Softwarebranche differiert die Produktivität einzelner Entwickler um mehr als eine Zehnerpotenz – unabhängig von der Erfahrung. D.h. der eine Entwickler braucht für eine Aufgabe 1 Stunde, der andere bis zu 10 Stunden und mehr. Das fängt schon beim Allersimpelsten an. Ich habe es selbst oft getestet mit Entwicklern, die ich in Trainings, in Bewerbungsgesprächen und bei Beratungen treffe. Denen gebe ich eine ganz, ganz einfache Aufgabe; manche brauchen dann 30 Sekunden, um sie zu lösen – und andere brauchen mehr als 3 Minuten. Wohlgemerkt für eine Sache, wo es keine zwei Meinungen gibt und das Ergebnis max. 5 Zeilen Code umfasst.

In anderen Branchen gibt es natürlich auch Produktivitätsunterschiede. Ein Koch mag doppelt so schnell sein wie der andere, ein Klempner gar dreimal so schnell wie der andere. Im Einzelfall ist es dann misslich, wenn man an den langsamen Vertreter einer Zunft gerät – aber eigentlich ist der Unterschied fast vernachlässigbar gegenüber dem in der Softwarebranche.

Das nun mal in Anschlag gebracht für das Schätzen: Wenn die Produktivität um den Faktor 10 differiert und ein Entwickler schätzt Aufwand… was sagt mir dann die Schätzung?

Sie sagt mir nur, dass der Entwickler ca. so lange braucht, wie er schätzt. Der Manager in Szenario 3 hört 5 Wochen, denkt sich seinen Teil, drückt den Entwickler dann auf 4 Wochen (weil Entwickler ja immer trödeln und Puffer einrechnen) – und ist zufrieden.

Was der Manager nicht weiß ist, wie produktiv der Entwickler ist. Er kennt die Güte des Entwicklers nicht oder höchstens in Bezug auf andere Entwickler in seinem Team, von denen er auch nicht weiß, wie gut sie sind. Der Manager weiß wahrscheinlich nicht einmal, dass der Faktor 10 und höher für den Produktivitätsunterschied in der Branche ist.

Dasselbe gilt natürlich für Teams. Vielleicht nivellieren sich im Team die Unterschiede aus – aber ist dann nur noch ein Faktor 5 gültig? Nein, ich denke er ist höher. Das liegt daran, dass die Ausbildung in unserer Branche so notorisch uneinheitlich und damit unzuverlässig ist. Wirklich gute Entwickler sind viel seltener – so mein Gefühl – als wirklich schlechte Entwickler.

Selbst wenn ein Kunde also Angebote einholt für ein größeres Projekt – die reichen von 2000 PT über 2500 PT bis zu 3200 PT –, weiß er nichts darüber, wieviel Geld er womöglich verschenkt, weil sich das Problem eigentlich auch in 750 PT erledigen ließe – wenn denn wirklich gute Teams geschätzt hätten.

Nun mag man sagen, “Tja, so ist es halt in der Softwareentwicklung…” Aber ich halte mal dagegen: Ist das nicht ein erbärmlicher Zustand? Wird da nicht volkswirtschaftlicher Schaden angerichtet, wenn die Produktivitätsunterschiede de facto so groß sind und es keiner in der Branche thematisiert und kein Kunde weiß?

Was hat da Schätzen noch für einen Wert? 6 Tage oder 10 Tage für die Badrenovierung… geschenkt. Mehrere Wochen statt 5 Tagen aber… da sollte jeder Manager, jeder Controller hellhörig werden. Das passiert aber nicht. Stattdessen reibt sich der Manager die Hände, weil er aus 5 Wochen Schätzung 4 Wochen gemacht hat. Er sieht nur das Geld, was er (vermeintlich) gespart hat, aber nicht das Geld, das er verpulvert, indem er einen schlechten Entwickler beschäftigt.

Fassen wir uns alle mal an die Nase und fragen: Wie produktiv bin ich eigentlich?

Und dann frage man sich: Wie produktiv könnte ich sein? Wie produktiv kann “man” sein? Wie stelle ich eigentlich fest, ob ich produktiver geworden bin über die Jahre?

“Ein Entwickler hat das im Gefühl” könnte die Antwort darauf frei nach Loriot sein. Aber ist das wirklich genug für eine Branche, die so wirtschaftsentscheidend ist wie die Softwarebranche? Das bezweifle ich.

Es ist zutiefst unbefriedigend, dass die Produktivitätsunterschiede so groß sind. Dafür kann der Ausbildung nur die Note 5 gegeben werden.

Und es ist zutiefst beängstigend, dass das Kunden offensichtlich nicht wirklich bemerken. Denn das zeigt einen verantwortungslosen Umgang mit dem hart erarbeiteten Geld ihrer Mitarbeiter.

Also: Bei der nächsten Schätzung die man einholt, einfach mal fragen: Wie gut ist der eigentlich, der da schätzt? Könnte es sein, dass es auch in der halben oder gar einem Viertel der Zeit ginge?

Wer darauf reagiert mit, “Kann ich ja eh nicht ändern. Hab nur den Entwickler/das Team”, der hat dann leider nicht begriffen, dass man mit Ausbildung und Übung die Produktivität steigern kann.

 

PS: Natürlich lässt sich darüber nachdenken, warum der Zustand in der Branche so ist, wie er ist. Das Umfeld muss es ja hergeben, dass solche Produktivitätsunterschiede überhaupt über Jahrzehnte existieren können. Meine Vermutung:

  1. Laien glauben nicht, dass es so sein kann. Deshalb hinterfragen sie die Leistungen nicht. Und Entwickler selbst glauben das auch nicht – bis sie mal mit ihren Leistungen im Vergleich konfrontiert werden.
  2. Das Metier ist so “ehrfurchtgebietend” oder esoterisch, dass sich Laien nicht an solch kritische Fragen trauen.
  3. Laien sind so glücklich darüber, dass es am Ende irgendwie überhaupt läuft, dass sie sich mit solchen Fragen nicht beschäftigen.
  4. Die Branche selbst hat kein Interesse, ihre hohen Aufwände zu reduzieren. Wenn sich mit billigen schlechten Entwickler Geld verdienen lässt, warum dann in gute investieren.
  5. Die formale Ausbildung ist an solch weltlichen Details wie Produktivität nicht interessiert. Und die Selbstbildung kann sowieso eher nicht leisten, Produktivität systematisch zu steigern.

 

PPS: Und nun? Ich behaupte mal: Wer diese Erkenntnis ernst nimmt und sein Team nur um 25% beschleunigt (auch das ja nur relativ zu bisheriger Performance), der hat die Nase vorn im Wettbewerb. Und ich behaupte sogar: Dabei kann die Qualität der Arbeit nur steigen – wie auch die Motivation. Warum? Weil Menschen, die sich ernst genommen fühlen, lieber arbeiten und gute Arbeit abliefern. Ganz zu schweigen davon, dass höhere Produktivität nur mit Mittel erreichbar ist, die auch höhere Qualität bringen. Command/Control und Zuckerbrot/Peitsche gehören nicht zu diesen Mitteln.

Bei Anforderung vorgehen – Teil 1

Neulich ging es ja hoch her in den Kommentaren zu meinem Schätz-Beitrag. Deshalb hier eine Aufgabe, anhand der ich ein wenig Licht auf mein Vorgehen beim Umgang mit Anforderungen werfen möchte. Die Aufgabe stammt von einem Entwickler aus einer Email-Kommunikation rund um das Schätzen:

Der Kunde stellt Kaffeemaschinen her, deren Komponenten der Besteller individuell zusammenstellen kann. Auf Grund eines Lieferantenwechsels muss ein Teil (z.B. die Tassenheizplatte) durch ein leicht modifiziertes anderes Teil ersetzt werden. Ob das Teil verbaut ist, hängt von der konkreten Bestellung ab.
Der Kunde benötigt nun eine Software, mit der er zu jeder Zeit feststellen kann, bis zu welcher Bestellung sein Lagerbestand des alten Teils noch reicht und ab welcher das neue verbaut werden muss.
Außerdem sagt der Kunde: Die Bestellungen bekommt man aus dem System XY- DB, Tabelle soundso, die Information welche Teile bei welchen Komponenten verbaut werden, kann man in der Applikation soundso nachsehen (z.B. bei einem SOA-Service oder einem Mainframe).

Und nun kommt ihr :-) Wer mag, überlegt mal, wie er die Anforderungen umsetzen würde. Dabei geht es nicht um die Implementation (“Wie kann ich mit .NET auf einen Mainframe zugreifen?”), sondern um die Planung(sschritte) und die Interaktion mit dem Kunden. Wann sieht der Kunde welche Funktionalität?

Welche Phasen würdet ihr durchlaufen? Wie käme Schätzen ins Spiel? Wann wäre Auslieferung?

Klar, die Anforderungen sind sehr allgemein; deshalb können eure Überlegungen auch nur sehr pauschal sein. Dennoch könnt ihr etwas draus machen und hier vielleicht in Kommentaren skizzieren, wie das aussähe. Ich stelle dann in den nächsten Tagen meinen Ansatz vor.

Samstag, 11. Dezember 2010

Maschinen bauen, aber Software verschärfen

Softwareentwicklung kann man nicht schätzen? Die Frage und meine verneinende Antwort haben einige Diskussion ausgelöst. Das verstehe ich gut. Nicht anders hatte ich es erwartet. Glaubenssätze, auch wenn sie wieder und wieder zu Schmerzen führen, werden ungern aufgegeben. Davon weiß die Psychotherapie ein Lied zu singen.

Und um einen Glaubenssatz handelt es sich, denn die ganze Branche ist seit 50 Jahren unfähig, Schätzungen mit einer Fehlermarge von vielleicht 5-10% verlässlich abzugeben. Oder selbst wenn das möglich wäre, ist sie zumindest unfähig, diese Kunst systematisch in der Ausbildung zu vermitteln. Oder habe ich etwas übersehen?

Hier will ich allerdings dieses Fass nicht nochmal aufmachen. Vielmehr geht es mir um eine Prämisse dieser und anderer Diskussion um Software. Ich glaube nämlich, dass so manche Diskussion in die falsche Richtung geht und so manche Argumentation zu falschen Schlüssen kommt, weil der Ausgangspunkt falsch ist.

Ich glaube, dass wir in vielerlei Hinsicht nicht weiterkommen, wenn wir uns nicht nochmal fragen, was denn “die Natur” von Software ist. Wie ist sie eigentlich so ganz fundamental?

Frust mit Maschinen

Das vorherrschende Bild scheint mir das einer Maschine. Software wird als Maschine angesehen, die man vor allem produzieren muss. Der Entwurf der Maschine ist für den Laien vor allem die Anforderungserhebung. Danach müssen diese Anforderungen nur noch produziert, d.h. in Code übersetzt werden. Eine Tätigkeit, die dem Bau eines Hauses oder der Fertigung eines Motors entspricht – so meint man weithin.

image

Deshalb wird auch immer wieder nach Schätzungen gefragt. Produktionsaufwände lassen sich nämlich sehr gut schätzen.

Und deshalb wird auch immer wieder sehnsüchtig nur eines erwartet: die Ablieferung der kompletten Software. Die herrschende Vorstellung ist, mit Software kann man erst etwas anfangen, wenn sie komplett realisiert ist. (Dem widersprechen auch nicht die üblichen, Monate oder gar Jahre auseinander liegenden Meilensteine in vielen Projekten.)

image

Und aus der Vorstellung einer Maschine oder eines Gebäudes resultiert ebenfalls, dass Software bottom-up zu produzieren ist: erst das Chassis/Fundament, dann das, was darauf aufsetzt usw. Das Schichtenmodell ist dafür eine weit verbreitete Blaupause. Immer wieder bekomme ich als Berater deshalb auch Anfragen, ob ich nicht vor Aufnahme der Entwicklung einer Anwendung mal einen Blick auf das Anwendungsframework werfen könne. Das zu realisieren war ja nötig, damit man die Anwendung überhaupt beginnen kann. Ein Framework ist damit dem Stahlrahmen eines Hochhauses gleichgesetzt. Ohne den kann man nicht anfangen, die Wände hochzuziehen.

Drei Probleme, dreimal eine Maschinenanalogie als Ursache:

  • Problem 1 – Planabweichung: Schätzungen liegen immer wieder weit neben der Realität.
  • Problem 2 – Zielabweichung: Der Kunde ist eigentlich nur mit dem Ganzen zufrieden und wird daher erst spät mit der Umsetzung seiner Anforderungen konfrontiert. Das führt zu großen Differenzen zwischen Wunsch und Realität.
  • Problem 3 – Mangelnde Kommunikation: Budget wird in Frameworks und Infrastruktur verbrannt, die man für grundlegend und unverzichtbar hält, ohne dass der Kunde in der Zeit Nutzen erhält.

Weil die allgemeine Vorstellung ist, Software würde produziert, mache im Wesentlichen nur als Ganzes Sinn und müsse auch aus Schichten von Querschnitten aufgebaut werden, frustrieren wir immer wieder uns und unsere Kunden.

Das behaupte ich mal, denn ich glaube, mit einer anderen Vorstellung von Software, verschwinden diese Probleme. Software wird nicht gebaut. Oder wenn, dann ist das eine kurze Sache, die man einem Buildscript überträgt. Softwareproduktion ist quasi kostenlos. Aber Softwareentwicklung, d.h. die Planung dessen, was gebaut werden soll, die kostet kaum schätzbaren Aufwand.

Spaß mit Bildern

Wie könnte eine weniger frustrierende Vorstellung von Software aussehen? Ich glaube, mit einem einer 3D CGI-Grafik kommen wir weiter.

image

Die Umsetzung der Gesamtanforderungen können wir dann als komplett gerendertes 3D-Modell ansehen. Jedes Detail ist brilliant gerechnet.

Doch das ist erst ganz am Ende der Fall. Vorher existiert auch schon das Gesamtbild, aber in gröberer Form: Drahtmodell, Drahtmodell mit wenigen Flächen, grob gerendertes Modell mit Flächen, feiner gerendertes Modell usw.

image

Der Trick bei Software ist, dass sie nicht wie eine Maschine bottom-up entwickelt werden muss. Wir können sie langsam scharf werden lassen, wie können sie immer feiner rendern, wie können ihr immer mehr Details hinzufügen. Aber vom ersten Moment an kann sie als Ganzes, d.h. als benutzbares Werkzeug existieren.

image

Software ist insofern eher fraktal. Dazu ein Zitat über den hier abgebildeten Farn:

After a few dozen repetitions or ITERATIONS the shape we would recognize as a Perfect Fern appears from the abstract world […]. How and Why can this be?

Ja, wie kann das sein? Es liegt daran, dass Software eben soft ist. Sie unterliegt nicht der Physik. Für das Feature “Ruhe Schlafstätte” muss ein Haus ein Schlafzimmer haben, dafür muss es ein Dach und Wände haben, dafür muss es ein Fundament haben. Wände können einfach nicht schweben ;-)

Bei Software ist das anders. Für die Funktionalität “Zahlungseingänge buchen” muss die Fakturasoftware kein komplettes Data Access Layer haben und kein vollständiges UI und keine umfassende Security und schon gar kein lückenloses Datenmodell – in Bezug auf den Gesamtzweck.

Software kann Feature-by-Feature schrittweise ausgeprägt werden in Längsschnitten. Und sie kann bei jedem Schritt überall eine Kleinigkeit hinzufügen. Etwas mehr UI-Detail, etwas mehr Funktionalität bei Data Access, ein wenig mehr Leistung in der Validation usw. usf.

Minimale Funktionalität im Backend kann sozusagen schon ein riesiges Frontend tragen, weil es keine physikalischen Gesetze gibt. Unvollständiges kann Vollständigem dienen. Lückenhaftes kann jederzeit nachträglich verspachtelt werden. Grobes kann jederzeit verfeinert werden.

Software können wir schrittweise wie den obigen Farn vollständiger, lebensechter, anforderungsnäher “rechnen”. Im ersten dünnen Längsschnitt – Feature Slice – ist ihre grundsätzliche Form schon zu erkennen.

image

Mit dem kann der Kunde dann noch nicht soviel anfangen. Zugegeben. Doch er bekommt schon einen Eindruck. Und wir als Entwickler auch. Das ist wie mit dem modernen Film. Da verlässt sich ein Regisseur wie Stephen Spielberg auf die pre-visualization:

Damit meine ich jetzt aber keinen Prototypen, sondern eben einen lauffähigen Längsschnitt, eine Teilfunktionalität. Sie stellt die Anwendung “durch alle Schichten” schon dar – nur eben noch unvollständig.

Bei einem Auto oder einem Mixer oder einem Drucker wäre das nicht zu machen. Wie auch?

Oder anders: Bei Maschinen findet diese schrittweise “Verschärfung” über Modelle statt. Die Sukzession der Modelle bietet von Anfang an Funktionalität – aber nicht all das, was ein Kunde von heute erwartet. Ein Ford Model-T konnte Personen motorgetrieben befördern, hatte aber keine Sicherheitsgurte und schon gar kein ABS.  

Über die Zeit “verschärfen” sich Maschinen also auch. Ein Modell einer Maschine jedoch muss eben in ganz-oder-gar-nicht Manier entwickelt und gebaut werden. Das ist bei Software anders. Das macht Software fundamental anders als Maschinen.

Bilder mit Konsequenzen

Die “Bildhaftigkeit” von Software hat nun Konsequenzen, die wir nicht ignorieren sollten. Sie helfen die obigen Probleme lösen:

  • Konsequenz 1 – “Planlosigkeit”: Software wird eben nicht produziert, sondern entwickelt. Damit ist sie der Möglichkeit der maschinenbaulichen Dreifaltigkeit Fixpreis-Fixscope-Fixzeit beraubt. Entwicklung ist inhaltlich nicht zeitlich planbar so wie Produktion. So ist das mit kreativen Prozessen. Wer Software in Auftrag gibt, muss das verstehen, um nicht unglücklich daran zu werden.
  • Konsequenz 2 – Verschärfung: Software bietet nicht erst Nutzen, wenn sie 100% geliefert ist. Im Gegenteil! Wer sie erst sieht, wenn sie “voll gerendert” ist, der erlebt sehr wahrscheinlich sein blaues Wunder. Software muss wegen ihrer Kompliziertheit und Komplexität schrittweise verschärft werden – und sie kann es. Das ist das Schöne. Warum sollte man sie dann auf etwas Maschinenhaftes reduzieren? Nehmen wir doch Software endlich ernst und entwickeln sie in dünnen Längsschnitten. Agile Vorgehensmodelle haben das auch schon vorgeschlagen – aber aus meiner Sicht nehmen sie das noch nicht ernst genug. Und die Objektorientierung steht und da im Weg. Sie kommt aus dem Maschinenbauzeitalter. Für “development as rendering” ist OOP nicht wirklich geeignet. Andere Ansätze müssen her. EBC scheint mir da ein Weg zu mehr Kongruenz der Modellierung mit der Natur der Software.
  • Konsequenz 3 – Längsschnitte: Man höre endlich auf, in Schichten zu denken und zu entwickeln. Das ist nicht nötig; Software braucht kein Fundament oder Rahmenwerk. Das Geld des Kunden sollte nicht auf Wochen oder Monate versenkt werden in Programmierung, die ihm nichts bringt. Nutzen muss vom ersten Tag an her. Längsschnitte statt Querschnitte tun not. Aber dafür braucht es eine andere Entwicklungskultur. Denken und Teamorganisation müssen sich ändern, um Längsschnitte zu sehen und hochperformant zu realisieren.

In Summe glaube ich, dass wir noch gar nicht abschätzen können, wie anders und besser Softwareentwicklung sein kann, wenn wir endlich das überkommene Denken über Software aufgeben. Maschinen als Bild und von-Neumann-Denke waren lange erfolgreich – werden aber zunehmend ein Klotz am Entwicklerbein. Sie stehen uns im Wege dabei, dem Kunden schnell Nutzen zu liefern für sein Geld. Und sie stehen uns im Wege bei der Ausreizung moderner Prozessoren.

Verabschieden wir uns davon. Schreiben wir endlich schärfer und schärfer werdende Software. Jeden Tag.

Freitag, 10. Dezember 2010

Gesunde Anämie

Immer wieder gibt es Uneinigkeit darüber, wie zustandsbehaftete Domänenklassen mit Funktionalität ausgestattet werden sollen. Ist es eine Tugend, ein Kundenobjekt nach seiner Bonität befragen zu können? Die vorherrschende Meinung sieht das wohl so. Und wo sie zustandsbehaftete Domänenklassen auf die Datenhaltung reduziert sieht, spricht sie von einem anämischen Domänenmodell. Gestern bei einem TDD-Training und auch heute beim Architecture Open Space gab es dazu wieder einige Diskussion.

Aber warum wird denn überhaupt dazu soviel noch diskutiert? Ist es denn nicht klar, was richtig ist? Hat die Objektorientierung nicht schon seit Jahrzehnten eine gute Antwort gefunden? Anscheinend nicht. Es gibt immer noch oder schon wieder zwei Lager. Die einen bemühen sich, Domänenmodelle reich zu machen; da bekommt der Kunde seine Bonitätsprüfungsfunktion. Die anderen sehen das als kontraproduktiv an und argumentieren, Geschäftsregeln und Datenstrukturen seien auseinander zu halten. Ich gehörer letzterer Fraktion an, wie ich in früheren Blogartikeln schon klar gemacht habe.

Leider kann ich jedoch mit meinen Argumentationsversuchen nicht immer so leicht punkten, wie ich es mir wünsche. Deshalb bin ich immer auf der Suche nach neuen Gesichtspunkten, die meine Position stützen und erklären helfen – oder, ja, von mir aus auch einfach begreifbar widerlegen.

Heute nun habe ich wieder einen solchen Gesichtspunkt entdeckt. Und hätte der Architecture Open Space nicht auch sonst schon wegen des Community Erlebnisses Spaß gemacht, dann wäre er deshalb lohnenswert gewesen. Hier meine Erkenntnis:

Anämische Domänenmodelle sind eine Tugend, weil sie entkoppeln.

Ha! Wer hätte das gedacht? Wieder ist die Antwort auf hartnäckige Fragen “Entkopplung”. Abhängigkeiten, also Kopplung, ist einfach eines der Grundübel der Softwareentwicklung.

Meine Argumentation:

Abhängigkeiten jeder Art behindern die Evolvierbarkeit. Sie sind deshalb zu vermeiden oder zumindest zu minimieren.

Wenn eine Funktionseinheit A von vielen anderen Funktionseinheiten abhängig ist – U1, U2, U3, … –, d.h. eine hohe efferente Kopplung hat, dann ist das Risiko groß, dass A sich ändern muss, weil irgendwo bei U1, U2, U3 usw. eine Änderung vorgenommen wurde.

image

Wenn andererseits eine Funktionseinheit U von vielen abhängigen Funktionseinheiten A1, A2, A3 usw. gebraucht wird, d.h. eine hohe afferente Kopplung hat, dann ist das Risiko groß, dass eine Änderung an U sich auf alle A* auswirkt.

image

Wir können es also drehen und wenden, wie wir wollen, eine große Anzahl von Abhängigkeiten koppelt eng, weil die Abhängigkeitslinien Wege für die Ausbreitung von “Veränderungsschockwellen” sind.

Nun ist es natürlich unzweifelhaft, dass Abhängigkeiten nötig sind. Softwaresysteme wären keine Systeme, wenn sie nur Haufen unverbundener Funktionseinheiten wären. Also ist die Frage, wie können wir den potenziellen Schaden von Abhängigkeiten in Grenzen halten?

  1. Die Kopplung sollte so gering wie möglich und so stark wie nötig sein. Bewusstheit beim Aufbau von Abhängigkeiten ist also gefragt.
  2. Je größer die Kopplung, desto einfacher sollten die gekoppelten Funktionseinheiten sein. Kopplung und Kompliziertheit sollten umgekehrt proportional sein.
    Einfachheit lässt sich herstellen durch:
    • fokussieren der Verantwortlichkeit (Single Responsibility Principle)
    • verbergen von Details (Encapsulation)

Die zweite Regel verdient besondere Aufmerksamkeit. Schauen wir uns an, welche “Verhältnisse” sich ergeben, jenachdem ob die gekoppelten Funktionseinheiten einfach oder kompliziert sind:

Efferente Kopplung U* einfach U* kompliziert
A einfach überschaubar überschaubar
A kompliziert kompliziert komplex

Eine hohe efferente Kopplung ist unkritisch, wenn die abhängige Funktionseinheit einfach ist. Dann können sogar die unabhängiggen Funktionseinheiten kompliziert sein, denn falls Änderungen an ihnen “durchschlagen”, muss nur Einfaches angepasst werden - wenn überhaupt; was zu tun ist, ist dann überschaubar.

Ist die abhängige Funktionseinheit jedoch kompliziert, dann werden die Verhältnisse komplex. Denn dann ist nur schwer abschätzbar, was überhaupt als Anpassung zu tun ist, falls die Unabhängigen sich ändern.

Etwas schlimmer sieht es sogar noch bei der afferenten Kopplung aus:

Afferente Kopplung U einfach U kompliziert
A* einfach überschaubar komplex
A* kompliziert kompliziert komplex

Hier sind die Verhältnisse immer komplex, wenn die unabhängige Funktionseinheit kompliziert ist. Änderungen wirken sich ja potenziell auf viele andere Funktionseinheiten aus. Das ist schwer abzuschätzen.

Jetzt die Übersetzung auf die Modellierung:

  1. Event-based Components (EBC) packen das Thema Kopplung/Abhängigkeiten bei den Hörnern, indem sie Funktionseinheiten im Sinne der Funktionalität statisch und dynamisch unabhängig voneinander machen. Logische Kopplung existiert zwar weiterhin, aber zumindest müssen Bauteile sich nicht mehr untereinander kennen. Das ist ein guter Schritt voran bei der Entkopplung. Unmittelbar ist das daran zu erkennen, dass Sie zum automatisierten Testen von EBC-Bauteilen keine Mock-Frameworks brauchen.
  2. EBC entschärfen die efferente Kopplung, indem sie Abhängigkeiten auf die Verdrahtung beschränken. Nur Platinen sind abhängig von anderen Funktionseinheiten. Das mögen dann auch viele sein – doch das macht nichts, weil Platinen denkbar einfach sind. Ihr einziger Zweck ist die Verdrahtung mit trivialem Code. Die Verhältnisse sind überschaubar, auch wenn die verdrahteten Funktionseinheiten kompliziert sind (s. rechte obere Tabellenzelle bei der efferenten Kopplung).
  3. EBC geben Domänendatenmodellen einen klaren Platz in der Modellierung: als Typen für die Daten, die zwischen EBC-Funktionseinheiten fließen.

    image
    Das bedeutet jedoch, dass viele Funktionseinheiten von ihnen abhängig sind. Im Bild müssen A, B, C und D den Domänenobjektmodelltyp d kennen. Die afferente Kopplung von d ist also hoch.
    Das bedeutet – und das ist meine heutige Erkenntnis auf dem Architecture Open Space –, dass d nicht kompliziert sein darf.

Domänendatenobjekte haben per definitionem eine hohe afferente Kopplung. Das ist für mich der wesentliche Grund, warum sie so einfach wie möglich gehalten werden sollten. Prinzip schlägt Objektorientierung, möchte ich sagen. Es ist mir also egal, ob ein Domänenobjektmodell als anämisch angesehen wird oder nicht. Objektorientierung ist ein Tool. Mit diesem Tool sollte ich nicht gegen fundamentale Prinzipien – hier: Abhängigkeiten erzeugen Komplexität; Entkopplung reduziert Komplexität – verstoßen, auch wenn eine bestimmte Benutzung des Tools noch so toolgemäß aussehen mag.

Wo hohe Abhängigkeiten von zwischen Objekten bestehen, da muss auf die Kompliziertheit der Beteiligten sehr genau geachtet werden. Mit EBC sind wir da auf einem sehr guten Weg, würde ich sagen. Aber nun weiß ich auch, warum es nicht schlimm ist, wenn EBC irgendwie gegen die heilige Kuh “reichhaltiges Domänenobjektmodell” verstößt, weil Domänenobjektmodelle, die auf Drähten fließen, immer irgendwie blutleer wirken. Auch das ist nämlich eine Tugend, weil ihre Datentypen so weitreichend gekannt werden. Anämie kann also auch mal gesund sein, wie hier zu sehen ist :-)

Objektorientiertes Nachspiel

Mir ist jetzt auch klarer, wo Chancen und Grenzen der Objektorientierung liegen. Gegenüber der prozeduralen Programmierung bietet Objektorientierung Kapselung.

Wo früher ein Record/struct nur Daten gehalten hat und die Funktionalität, die auf diesen Daten auch nur das Einfachste tun sollte, davon getrennt war, hat Objektorientierung Daten und Funktionalität zusammengezogen und unter einer “kleineren” Oberfläche verborgen. Die afferente Kopplung sinkt damit, weil U (s. zweite Abbildung oben) einfacher wird. Das ist gut so. Danke, Objektorientierung! Da liegt die Chance für uns mit der Objektorientierung.

Die Grenze der Objektorientierung ist jedoch erreicht, wenn ihre Möglichkeit zur Zusammenfassung von Daten und Funktionalität darüber hinaus gedehnt werden. Die Objektorientierung hat angefangen mit dem Begriff des ADT (Abstrakter Datentyp), d.h. einem “Objektmodell”, das Zustand hat und auf sich auch operieren kann. Beispiele dafür sind Stack, Baum oder Priority Queue usw. Gern auch ein “anämisches Objektmodell” mit Funktionen, die nicht über sich selbst hinausgreifen und keinen Zweck jenseits des “Zustandsorganisation” haben, der Konsistenzhaltung.

Wenn nun Objektorientierung über den ADT hinausgeht und ein reichhaltiges Domänenobjektmodell kreiert, dann mag die Kapselung immer noch ordentlich sein, auch wenn sie schwieriger wird. Vor allem aber wird der “Single Purpose” auf die Probe gestellt und die Kompliziertheit steigt schnell an.

Und genau das ist es, wo dann die Werte der Objektorientierung durch höhere Werte überstimmt werden. Wenn Objektorientierung die Entkopplung gefährdet, dann hat sie ihre Grenze erreicht. Das sehe ich beim reichhaltigen Domänenobjektmodellen. Sie überspannen den objektorientierten Bogen. Sie erzeugen – im allerbesten Willen – ungünstig hohe afferente Kopplung.

Objektorientierung ist nur ein Tool. Wer professionell Software entwickeln will, muss ihre Werte abwägen gegen andere. EBC tut das mit den bisherigen Übersetzungsvorschlägen für Modelle, würde ich sagen. Objektorientierung wird genutzt – solange der hohe Wert der Evolvierbarkeit repräsentiert durch das Prinzip “lose Kopplung, hohe Kohäsion” nicht kompromittiert wird.

Mittwoch, 8. Dezember 2010

Widerspruch gegen das Schätzen

Mir wird das Schätzen immer suspekter. Warum tun selbst agile Entwickler das? Mal ehrlich? Auf der einen Seite wissen wir – und ich meine wirklich “wissen” –, dass es unmöglich ist, den Aufwand von Softwareentwicklung zu schätzen. Denn da wo etwas Neu ist, seien es Tools, Techniken, Teammitglieder, Aufgaben, Kunden… da kann man einfach nicht sagen, wie lang es dauert, Anforderungen umzusetzen. Das geht nicht.

Und selbst, wo die Anforderungen und sonstigen Rahmenbedingungen scheinbar soviel präziser sind, haut es nicht hin. Die Hamburger Elbphilharmonie ist da nur eines von vielen aktuellen und weithin sichtbaren Beispielen in Deutschland. Auf anderen Kontinenten und in anderen Branchen ist es aber auch nicht besser: Wie ist es zu erklären, dass das US Militär “a long-standing track record of over-promising and under-delivering with virtual impunity” hat? Da geht es doch um handfeste “Maschinen” wie Flugzeuge und Schiffe. Schiffe kosten nicht 220 Millionen Dollar, sondern das doppelte; Flugzeuge kosten nicht 2,7 Milliarden Dollar, sondern 35% mehr, also knapp 3,6 Milliarden Dollar.

Merkt denn noch einer etwas? Schätzen haut außer in trivialen Fällen nicht hin. Schätzungen sind meistenteils Lügen – weil sie in Bewusstheit ihres Fehlers abgegeben werden – und wenn nicht, dann sind sie Fahrlässigkeiten.

Auf der einen Seite wissen wir also all das – und auf der anderen Seite tun Softwareentwickler es doch immer und immer und immer wieder. Warum? Weil es so schön weh tut? Ja, mir scheint, ein gewisser Hang zum Masochismus scheint da mitzuspielen. Der drückt sich auch immer wieder in der Sprache aus, die den Softwareentwickler bzw. seine Abteilung oder sein Unternehmen zu einem willenlosen Opfer des Kunden macht. Denn der Kunde will es so. Der will eine Schätzung. Entweder direkt, indem er fragt, “Wie lange dauert das? Wieviel kostet es?” Oder indirekt, indem er vorgibt, “Das darf nur soundsoviel kosten und soundsolange dauern!”

Und dann kuschen sie alle. Kopf und Schwanz einziehen und frisch geschätzt. Oder die Schätzungen von Inkompetenten einfach übernehmen. Wird schon hinhauen. Irgendwie. Denn wenn nicht… dann Gnade ihnen der Markt, der neue Gott. Dann wird abgestraft, weil die Softwareentwicklung sich nicht als wettbewerbsfähig erwiesen hat.

Ich kann das nicht mehr hören.

Die ganze Welt verschätzt sich allermeistens. Aber keiner will das wahrnehmen. Und das Wurzelproblem angehen will schon gar keiner. Das ist nämlich erstens eine Mentalität des “Ich will meinen Arsch retten” und zweitens eine Verkennung der Realität des 21. Jahrhunderts. Über Ersteres will ich mich hier nicht weiter auslassen. Ein andermal vielleicht. Und zu Letzterem sei nur gesagt: Das Charakteristikum des 21. Jahrhunderts ist die Komplexität. Bis ins 20. Jahrhundert mag die Welt kompliziert gewesen sein. Sie schien mit Zuckerbrot und Peitsche und Maschinen bewältigbar. Doch das ist vorbei. Autos, Fernseher, Gesundheit, Fußballmannschaften, Ehen, Märkte, nationale Sicherheit… das alles ist in der Komplexität angekommen – allemal die Software. Das heißt: Nachdenken, hartes Nachdenken und Rumrechnen führt zu keinem sicheren Ergebnis mehr.

Die Architekten und Bauunternehmer der Elbphilharmonie haben sicherlich hart über die Kosten des Bau nachgedacht und nicht leichtfertig den ursprünglichen Millionenbetrag genannt – und trotzdem haben sie meilenweit daneben gelegen. Ebenso die Ingenieure bei Flugzeug- und Schiffsbauern der US Streitkräfte.

Die schlichte Möglichkeit zu einer verantwortungsvollen, verlässlichen Schätzung ist überbewertet. Sie grenzt geradezu an Aberglauben, sage ich mal.

Und diesem Aberglauben will nun auch noch die Agilitätsbewegung dienen? Das ist doch Quatsch, oder?

Nein, man komme mir jetzt nicht wieder mit “Aber der Kunde will das und deshalb müssen wir.” Wenn wir so als Art immer gedacht hätten, dann säßen wir noch auf den Bäumen in der Afrikanischen Savanne. Nur weil irgendwo ein Widerstand ist, geben wir als Art nicht nach. Wir sind da anders gestrickt. Widerstand hat uns immer herausgefordert. Wie ist sonst zu erklären, dass der Mensch von der Savanne ins ewige Eis ausgewandert und dort geblieben ist? Eskimos trotzen jeden Tag Widerständen. Warum? Die könnten doch sagen, “Die Natur ist hier so unwirtlich, die will uns hier nicht. Also weichen wir besser…”

Achso, die armen Eskimos konnten nicht anders? Das ewige Eis war für sie das kleinere Übel. Deshalb mussten, nein, wollten sie dort bleiben. Da bin ich im Zweifel, aber lassen wir die Eskimos. Wenden wir uns ungezwungen extremen Zeitgenossen zu wie Rüdiger Nehberg, Reinhold Messner oder dem weniger erfolgreichen Samuel Koch, der während der Wetten-dass-Sendung verunfallte. Sie alle lieben den Widerstand. Sie leben für die Überwindung von Widerständen. Genauso Mutter Theresa oder Muhammad Yunus, die sich sozialer Probleme angenommen haben.

Also verstecke man sich nicht dahinter, dass der Kunde, der allmächtige, dumme, arrogante, naive, herrschsüchtige Kunde ein solches Problem sei, dass der menschliche Geist nicht überwinden könne. Die Vertriebler der Welt, die Einkäufer der Welt sind nicht zur Wirklichkeit zu erwecken? Das ist für die Art, die den Planeten verlassen hat, ein zu schwieriges Problem?

Ich würde sagen, hier wollen Menschen einfach nur nicht. Niemand will sich den Schuh anziehen, dieses Problem zu lösen. Keiner will den ersten Schritt machen. Noch nicht einmal – um wieder zur Softwareentwicklung zurückzukommen – die ach so innovativen Agilisten. Stattdessen schwenken sie den StoryPoint-Zauberstab, rufen “Aestimatus!” und glauben, mit relatiben Aufwänden und ein bisschen Beobachtung sei das Problem aus der Welt gewünscht. Bullshit!

Relative Aufwände sind nur das: relative Aufwände. Wenn Aufgaben A, B, C laut Schätzung im Verhältnis 1:2:3 stehen, dann weiß man am Ende nur genau das. Aber nicht, wie lange die Realisierung dauert. Nicht, wenn A oder B oder C dank der Marktes oder der Politik oder der Technik oder einer Unpässlichkeit etwas Unwägbares enthalten. Das ist aber beim Geschäft der Softwareentwicklung sehr wahrscheinlich. Sehr, sehr wahrscheinlich sogar. Sonst hieße die Softwareentwicklung auch nicht Software-Entwicklung, sondern Software-Bäckerei oder Software-Schusterei.

Entwicklung als Tätigkeit ist inhärent unwägbar aufwändig. Das liegt an ihrem Auftrag und an ihrem Stoff. Sie soll kreativ sein. Sie muss sich mit Materialien und Werkzeugen rumplagen, die sich in irrwitzigem Tempo ändern. Nicht zu reden vom wetterwendischen Kunden, der heute dies will und morgen jenes. Und egal, was er will, so ganz genau weiß er eh nicht, was das ist. “Machen Sie das mal, Sie als Softwareentwickler wissen das am besten.” – nur leider findet er es am Ende doch nicht so gut, was die Softwareentwicklung aus dieser Freiheit gemacht hat.

Ich widerspreche daher der immer noch gängigen Schätzpraxis. Schätzen zum Zwecke einer Aufwandsbestimmung zum Zwecke einer Preis- und/oder Dauerfestlegung funktioniert für die Softwareentwicklung nicht. Heute nicht und wahrscheinlich in Zukunft nicht. Da helfen keine StoryPoints und keine lustigen Pokerspiele darum und keine Geschwindigkeitskurven.

Man mag relative Aufwände schätzen, um danach zu priorisieren oder Ressourcen zu allozieren. Wenn Anforderung A weniger aufwändig ist als Anforderung B, dann sollte sie deshalb früher (oder später) angegangen werden. Oder wenn B ansteht, dann sollen noch zwei Entwickler mehr ins Team, um die “processing power” mit ihren “Kernen” zu erhöhen. (Dass dafür der Entwicklungsprozess und Entwurf passen müssen, ist selbstredend.)

Mehr als das lässt sich aus relativen Aufwänden aber nicht ablesen. Alles andere ist Illusion, Augenwischerei und Rumgezappelt vor dem drohenden Blick des allmächtigen Kunden - der Unmögliches will.

Deshalb: Widerspruch gegen das Schätzen.

Statt das Unmögliche zu wollen, sollten wir uns jeden Tag anstrengen, die Wirklichkeit den Blinden und Naiven und Ignoranten, die sie nicht sehen können oder wollen, nahezubringen. Lasst uns Licht anzünden und zu ihnen tragen. Dann mögen sie lesen und sehen, wie die Welt ist: unschätzbar, wenn es um Komplexes geht. Und wo sollte das nicht der Fall sein, wenn es interessant wird? Mit Komplexität lässt sich Geld verdienen. Aber ehrlicher und friedlicher und gesundheitsschonender als heute auf der Basis widernatürlicher Schätzungen.