Follow my new blog

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.

Dienstag, 7. Dezember 2010

Ein Traum von Softwareentwicklung

Lassen Sie für einen Moment mal alle eingefahrenen Vorstellungen von Objektorientierung und Agilität und Schichtenmodellen hinter sich. Folgen Sie mir einfach auf einer Traumreise in ein anderes Land der Softwareentwicklung…

Alles beginnt mit einem Unternehen. Das möchte eine Software in Auftrag geben. Es stellt sich den weltbesten online Shop vor, der es im Nu auf Augenhöhe mit Amazon, eBay und Expedia bringt. Das Budget hat der Vorstand schon fixiert. Die Wünsche wurden in den Fachabteilungen gesammelt. Und die IT hat auch schon ihren Senf dazu gegeben, denn irgendwer muss die Software hinterher ja auch betreiben. Es kann also losgehen…

Als Unternehmen, will es natürlich soviel wie möglich für sein Geld. Und als Teilnehmer an den komplexen Märkten des 21. Jahrhunderts will es gleichzeitig maximale Flexibilität auf dem Weg zum Maximum für sein Geld. Das scheint ein Widerspruch. Doch das Unternehmen hat einen Weg gefunden, beide Wünsche unter einen Hut zu bringen: Es vergleicht jeden Tag den Stand der Softwareentwicklung mit den Bedürfnissen der Anwender.

Jeden Tag ziehen sich die Anwender (bzw. ihre Vertreter für die Softwareabnahme während der Entwicklungsdauer) den aktuellen Stand der Software und probieren die hinzugekommene oder veränderte oder korrigierte Funktionalität aus. Das Entwicklungsteam stellt also jeden Tag ein neues Release bereit, das wieder etwas besser ist, als das vom Vortag. Und diese Verbesserungen sind immer anwenderrelevant; die Anwender können einen Unterschied erkennen, der ihnen wichtig ist – und sei der auch nur klein. So können sie jeden Tag feststellen, ob die Software noch auf Kurs zu ihrem Ziel ist. Sehen sie Abweichungen, steuern die Anwender nach, indem sie ihre Anforderungen verändern. Und das jeden Tag aufs Neue, wenn sie wollen.

Das Softwareentwicklungsteam unterstützt den Wunsch der Anwender, jeden Tag eine verbesserte Version testen zu wollen. Dafür hat es zunächst einen automatischen Build- und Deliveryprozess aufgesetzt, der dafür sorgt, dass alle Softwareartefakte jeden Tag gebaut, überprüft, verpackt und für den Download durch die Anwender bereitgestellt werden.

Die Überprüfung besteht aus automatisierten Tests und stellt vor allem sicher, dass die Software frei von Regressionsfehlern ist. Soweit möglich, sollen die Tests aber natürlich auch “beweisen”, dass hinzugekommene Funktionalität von vornherein keine Fehler enthält und den formalisierten Anforderungen (Akzeptanztests) entspricht.

Damit der automatische Build- und Deliveryprozess auch jeden Tag etwas zu tun hat, muss die Codebasis natürlich jeden Tag anwenderrelevante Änderungen aufweisen. Das Entwicklungsteam muss also jeden Tag etwas Auslieferbares fertigstellen. Ganze User Stories, wie sie das Unternehmen an das Entwicklungsteam heranträgt, sind natürlich viel zu groß, um sie in einem Tag umsetzen zu können. Auch Features herausgelesen aus User Stories passen noch nicht in einen Tag. Aber Features Slices, d.h. hauchdünne Längsschnitte durch Features, die lassen sich in einem Tag realisieren. Manchmal braucht es dafür ein wenig Phantasie, um sie in den Features zu erkennen, doch allermeistens klappt das.

So teilt das Team die Anforderungen in mehreren Schritten in Happen von Tagesumfang. Ob das 3, 4 oder 6 Arbeitszeitstunden sind, hängt vom Team und seiner Möglichkeit und Fähigkeit zur Fokussierung ab.

In wenigen Stunden muss und will das Team also Anwendernutzen auf die Straße bringen. Dafür ist maximale Geschwindigkeit in der Umsetzung nötig. Die erreicht das Team dadurch, dass es alle Entwickler auf das Feature Slice des Tages ansetzt. Alle arbeiten daran parallel, so wie beim Formel 1 Boxenstopp die Mechaniker an einem Rennboliden.

Dass sich dabei die Teammitglieder nicht ins Gehege kommen, also durch Konflikte Zeit verlieren, stellt die Komponentenorientierung sicher. Jedes Teammitglied bekommt für die Dauer einer Feature Slice Realisierung eine Anzahl von Komponenten zugeteilt, für die es allein verantwortlich ist. Alle Arbeit findet dann pro Entwickler konzentriert an einer Komponente zur Zeit statt. Die Kontrakte der Komponenten stellen dabei sicher, dass Änderungen keine unerwartete Reichweite haben. Die Komplexität hält sich durch kontraktuelle Entkopplung in Grenzen und automatisierte Tests in Isolation helfen, die Fehlerzahl gering zu halten.

Komponenten und Entwicklerzuordnung (Feature Team) sind das Ergebnis der Arbeitsorganisation des Teams. Vor Beginn der Feature Slice Realisierung identifiziert es die betroffenen Komponenten und weist sie Teammitgliedern nach Kompetenz, Erfahrung, Wunsch, Verfügbarkeit usw. zu.

Welche Komponenten aber überhaupt zur Auswahl stehen, ergibt sich aus den Bauteilen eines Event-BasedComponents (EBC) Modells, die innerhalb eines Architekturrahmens und im Sinne maximal paralleler Realisierbarkeit zu Komponenten zusammengefasst werden. Das Modell definiert die Funktionseinheiten auf verschiedenen Abstraktionsebenen, die die Anforderungen erfüllen. Das tut es unabhängig von der Implementierung, um die Lösungsplanung schneller und flexibler zu halten.

Das Team modelliert die Lösung also, um ganz präzise zu wissen, welche Funktionseinheiten zu implementieren sind. Die werden bestimmt durch die Funktionalität, die User Stories/Features beschreiben. Andererseits sind aber auch nicht-funktionale Anforderungen zu erfüllen. Dafür direkt Funktionseinheiten während der Modellierung zu finden, hieße jedoch, die Modellierung zu überfrachten. Deshalb entwirft das Entwicklungsteam vor dem Modell eine Softwarearchitektur. Sie definiert einen Rahmen von architekturellen Funktionseinheiten, in den sich das Modell mit seinen Funktionseinheiten einpassen muss.

Präzise Kenntnis der zu implementierenden Funktionseinheiten, die die funktionalen wie nicht-funktionalen Anforderungen dienen, ist Voraussetzung für die tägliche Feature Slice Realisierung in Höchstgeschwindigkeit.

So wichtig ein guter Entwurf jedoch auch sein mag, um den Anwender ihre Flexibilität zur Kursänderung zu geben, er reicht nicht aus. Mit Höchstgeschwindigkeit können nur Entwickler arbeiten, die genau wissen, was sie tun. Wie genau kann nun aber Wissen sein, wenn sich nicht nur die Domäne bewegt, sondern vor allem der Markt der technischen Realisierungsmöglichkeiten?

Das Entwicklerteam trennt deshalb ganz klar zwischen “Performance”, d.h. Zeit, in der es in Höchstgeschwindigkeit entwickelt, und “Übung”. Feature Slices realisiert das Team selbstverständlich in seiner Performance-Zeit. Da sitzt jeder Handgriff. Alle arbeiten wie geschmiert miteinander. Was zu tun ist, liegt klar auf der Hand bzw. ist aus Architektur, Modell und Arbeitsorganisation für jeden abzulesen.

Damit Performance-Zeit möglich ist, reflektiert das Entwicklerteam jedoch ständig darüber, was es noch nicht genau weiß. Es hinterfragt ständig sein Wissen in Bezug auf Domäne und Technik. Und wo es Wissenslücken auftut, da setzt es ausdrückliche Übungszeit an, um sie zu schließen. Ist die Wissenslücke projektspezifisch technisch, dann wird sie im Rahmen einer Spike Solution angegangen. Ist die Wissenslücke allgemein, dann wird sie durch Fortbildung geschlossen.

Domänenwissenslücken schließlich trägt das Entwicklerteam an die Anwender heran. So schließt sich der Kreis. Der Anwender repräsentiert durch die Rolle ProductOwner ist die entscheidende Klammer um die Softwareentwicklung.

Der Anwender “zieht täglich am Team”, weil er den Fortschritt der Entwicklung kontinuierlich gegen seine Anforderungen halten will. Nur so kann er schnell reagieren. Nur so bekommt er auch das Maximum für sein Geld.

Und das Team “zieht täglich am Anwender”, um dessen Anforderungen von vornherein möglichst genau zu treffen. Das heißt, der Anwender steht immer für Rückfragen zur Verfügung, um das Team in seiner täglichen Feature Slice Produktion nicht zu behindern.

Damit der gegenseitige Zug wirklich funktioniert, braucht es abschließend natürlich eines: Verlässlichkeit. Das Entwicklerteam muss verlässlich Anforderungen in Software mit Anwendernutzen transformieren. Der Anwender muss die Software verlässlich sofort abnehmen. Und der Anwender muss verlässlich für Rückfragen zu den Anforderungen bereitstehen.

Ohne Verlässlichkeit ist die ganze Softwareentwicklung nichts. Oder wenn sie etwas ist, dann zumindest nichts, das wie geschmiert und mit Höchstgeschwindigkeit abläuft.

Und ohne Verlässlichkeit kein Vertrauen. Denn Vertrauen kann man nicht befehlen; es entwickelt sich nur, wo Verlässlichkeit erfahren wird.

Das hat das Unternehmen begriffen und verzichtet daher auf den üblichen Festpreismodus für die Entwicklung des online Shops. Es hat sein Budget fixiert, es hat Wünsche gesammelt – und dann überträgt es die Realisierung einem Entwicklungsteam, zu dem es Vertrauen hat, dass es die Realisierung in Höchstgeschwindigkeit beherrscht.

Da Vertrauen immer gegenseitig sein muss, stellt das Unternehmen natürlich sicher, dass es selbst dem Entwicklungsteam ein verlässlicher Partner ist, der die erwartete Höchstgeschwindigkeit mittragen will und kann.

Und so wird am Ende der Traum wahr: Das Unternehmen bekommt ohne Budgetüberschreitung das immer wieder flexibel neu bestimmte Maximum.

Jetzt können Sie die Augen wieder öffnen. Lassen Sie den Traum aber noch etwas nachwirken. Vielleicht bewirkt er ja etwas bei Ihnen. Vielleicht machen Sie sich ja auf den Weg, aus dem Traum Realität werden zu lassen… Ich glaube, das ist möglich.

Montag, 6. Dezember 2010

Was ist Softwarearchitektur – Teil 2

Softwarearchitektur ist eine der beiden Entwurfsdisziplinen der Softwareentwicklung. Ihr Ergebnis ist die fundamentale Struktur einer Software im Hinblick auf die nicht-funktionalen Anforderungen.

Das ist für mich schon eine recht präzise Definition – allerdings eine allgemeine. Sie beantwortet noch nicht alle Fragen in der Praxis. Gehört die Entscheidung für IIS und gegen NT Service eine Architekturentscheidung? Ist die Entscheidung für eine Aufteilung der Rechtschreibprüfung in Textzerlegung und Wortprüfung eine Architekturentscheidung? Oder ist die Entscheidung für die Zusammenfassung von Funktionalität zu einer Komponente eine Architekturentscheidung?

Um diese und andere Fragen zu beantworten, müssen Sie erstens mein allgemeines Verständnis von Struktur kennenlernen und zweitens meine Vision davon, wie Architektur Strukturen konkretisiert.

Was ist eine Struktur?

Als Struktur verstehe ich “etwas”, das aus Elementen besteht, die in Beziehung zu einander stehen.

image

Strukturen mit vielen Elementen und/oder Beziehungen sind unübersichtlich. Deshalb gehört zu Struktur auch noch die Abstraktion. Ein System wie im Bild beschreibt eine Struktur also nur auf einer Abstraktionsebene, andere können darunter/darinnen liegen…

image

oder darüber/darum…

image

Wer eine Struktur entwirft, muss sich also drei Fragen stellen:

  1. Welche Abstraktionsebenen hat die Struktur?
  2. Welche Elemente enthält eine Abstraktionsebene (innerhalb eines womöglich umschließenden Elements einer höheren Abstraktionsebene)?
  3. Wie sind die Elemente in einer Abstraktionsebene verbunden?

Die Abstraktionsebenen und Strukturelemente der Softwarearchitektur

Mit einem allgemeinen Strukturverständnis bewaffnet können Sie nun verstehen, dass Softwarearchitektur als Entwurf auf verschiedenen Ebenen betrieben werden sollte. Ohne diese Ebenen ist die Kompliziertheit eines Systems nicht in den Griff zu kriegen.

imageDie Abstraktionsebenen der Softwarearchitektur sind für mich diese:

  1. Das gesamte Anwendungssystem
  2. Bounded Contexts
  3. Partitionen/Apps
  4. (Virtuelle) Maschinen
  5. Betriebssystemprozesse
  6. Belange/Concerns

Ein paar Worte zu den Ebenen:

Anwendungssystem

Ein Entwicklungsauftrag wird gewöhnlich auf der Ebene des Anwendungssystems erteilt: “Schreiben Sie mir eine Software, die dies und jenes kann.” Das kann eine Warenwirtschaft sein, ein TicTacToe-Spiel oder eine Textverarbeitung. Wenn implementiert, erfüllt das Anwendungssystem alle Anforderungen.

Bounded Contexts

Das Gesamtsystem zerlegt der Architekt in Bounded Contexts, d.h. funktionale Untermengen, die unterschiedliche Datenmodelle haben. Sie gehören innerhalb des Gesamtsystems, der Anwendungsdomäne verschiedenen Sub-Domänen an. Bei einem Faktura-Anwendungssystem könnten das Rechnungslegung und Rechnungsverfolgung und Stammdatenverwaltung sein.

In jedem Bounded Context können Daten anders persistiert werden. Das drückt die kleine Tonne im Bild aus.

Nicht-funktionale Anforderungen, die auf dieser Ebene vor allem bedient werden: Evolvierbarkeit, Skalierbarkeit, Sicherheit

Apps

Innerhalb eines Bounded Context kann die Funktionalität weiter aufgeteilt werden auf Partitionen oder – neuerdings von mir so genannt – Apps. Jede App steht für eine klar umrissene Funktionalität, die durch ein spezifisches Userinterface bedient wird. iPhone/iPad Apps spiegeln diesen Gedanken sehr schön wider, finde ich. Oder die vielen kleinen Tools unter Unix.

Alle Apps in einem Bounded Context benutzen dieselbe Datenbasis.

Nicht-funktionale Anforderungen, die auf dieser Ebene vor allem bedient werden: Usability, Evolvierbarkeit

Maschinen

Jede App läuft auf mindestens einer Maschine – vom Server über den Desktop bis zum Smartphone –, kann aber auch mehrere Maschinen überspannen wie bei einer Web-Apps, die sowohl im Browser wie im IIS wie in einem Application Server wie in der Datenbank Codeteile hat.

Nicht-funktionale Anforderungen, die auf dieser Ebene vor allem bedient werden: Skalierbarkeit, Performance, Sicherheit, Verfügbarkeit, Robustheit

Prozesse

Auf jeder Maschine einer App läuft deren Code mindestens in einem Prozess, es können aber auch mehrere sein. Zum Beispiel könnten ein Application Server und ein Reporting Server auf derselben Maschine betrieben werden.

Nicht-funktionale Anforderungen, die auf dieser Ebene vor allem bedient werden: Skalierbarkeit, Performance, Evolvierbarkeit, Flexibilität

Concerns

Die Zerlegung des Anwendungssystems bis in Prozesse führt zu autonomen Funktionseinheiten. Die arbeiten jede für sich vor sich hin. Jede läuft auf mindestens einem eigenen Thread. Die Kommunikation ist mithin ganz fundamental nur asynchron zwischen ihnen möglich.

Diese autonomen Funktionseinheiten zu identifizieren, ist die vornehmste Aufgabe des Architekten.

Als Vorbereitung für die Modellierung und Implementierung ist das allerdings noch nicht genug, finde ich. Einen Schritt weiter sollte der Architekt noch gehen. Er sollte innerhalb der Prozesse auch noch die grundsätzlichen Concerns herausarbeiten, d.h. Bereiche, die gezielt nicht-funktionale Anforderungen realisieren. Das sind z.B. Frontend, Persistenz, Kommunikation, Sicherheit, Domänenlogik.

Die Modellierung hat es dann einfacher, zu einem Entwurf zu kommen, weil die Concerns eine Grundeinteilung für die Funktionseinheiten des Modells vorgeben. Wenn das Modell sich um Funktionalität kümmert, dann muss es wissen, um welche Funktionalität es geht. Domänenfunktionalität ist nicht die einzig zu modellierende.

Beziehungen in Abstraktionsebenen

Auf welchen Abstraktionsebenen der Architekturentwurf stattfindet, ist geklärt. Die wesentlichen Strukturelemente sind Bounded Context, App, Maschine und Prozess. Aber wie werden die mit Beziehungen innerhalb einer Ebene zu einem System verwoben? Ich denke, das sollte auch definiert sein, denn dann lassen sich weitere Fragen leichter beantworten.

Bounded Context

Bounded Contexts sind durch Datensynchronisationen miteinander verbunden. Sie teilen weder Datenbanken noch Datenmodelle, also müssen die Daten explizit zwischen Bounded Contexts synchronisiert werden. Das dauert natürlich seine Zeit. Deshalb ist über Bounded Contexts hinweg nur Eventual Consistency zu erwarten.

Fragen für die Kommunikation: Wie soll die Datensynchronisation implementiert werden? Gibt es Tools (Stichwort ETL)? Wie groß das die maximale Verzögerung sein? Kann es Konflikte geben, wie werden die behandelt?

Apps

Apps müssen nicht direkt miteinander kommunizieren, sondern teilen sich eine Datenbasis. Sie ist das Bindeglied. Zentral für die Apps eines Bounded Context ist daher das eine Datenmodell.

Fragen für die Kommunikation: Welche Persistenztechnologie soll verwendet werden (RDBMS, Dokumentendatenbank, Graphendatenbank, Dateisystem usw.)? Wie sieht das Schema aus?

Maschinen

Maschinen sind über (virtuelle) Leitungen miteinander verbunden; sie teilen keinen physischen Adressraum. Die Kommunikation kann daher nur nachrichtenorientiert und asynchron ablaufen. Und ich würde noch hinzufügen: Die Kommunikation sollte zwischen Maschinen auch immer als asynchron in der Implementierung zu sehen sein.

Fragen für die Kommunikation: Welche Kommunikationstechnologie soll zum Einsatz kommen, insb. wenn die Maschinen mit unterschiedlichen Betriebssystemen betrieben werden? Wie sollen Leitungsunterbrechungen behandelt werden?

Prozesse

Prozesse laufen zwar im selben physischen Adressraum, werden vom Betriebssystem darin jedoch sauber getrennt. Die Kommunikation kann zwischen ihnen kann daher auch nur nachrichtenorientiert sein. Allerdings ist zu erwarten, dass Prozesse in der selben Maschine verlässlicher vorhanden/erreichbar sind als solche in anderen Maschinen. Deshalb ist zu überlegen, ob die Kommunikation zwischen Prozesse in derselben Maschine die Kommunikation immer als asynchron in der Implementierung zu sehen sein muss. Im Augenblick tendiere ich dahin, meine Position, dass das immer so sein muss, zu lockern. Das bedeutet jedoch: Wenn ein Architekt sich für eine synchrone Kommunikation zwischen Prozessen entscheidet, weil er sie auf derselben Maschine laufen sieht, dann können diese Prozesse später nicht auf verschiedenen Maschinen deployt werden. Denn die sollen asynchron kommunizieren (s.o.). Soviel Grundsatz sollte sein, finde ich.

Fragen für die Kommunikation: Welche Kommunikationstechnologie soll zum Einsatz kommen? Welche Hosts für den Code sollen benutzt werden (z.B. IIS, Desktopanwendung, NT Service)?

Concerns

Concerns sind funktionale Bereiche innerhalb von Prozessen. Sie kommunizieren also im selben Adressraum synchron via Stack oder globale Speicherbereiche.

Fragen an die Architektur

Mit diesen Konkretisierungen lassen sich die obigen Fragen und andere beantworten. Ist die Entscheidung für IIS oder NT Service eine Architekturentscheidung? Das ist natürlich eine Architekturentscheidung auf Prozessebene.

Wer sich über WCF vs NServiceBus unterhält, unterhält sich ebenfalls über Architektur. REST vs SOAP? Auch ein Architekturthema – mindestens auf Maschinenebene. Was ist mit OAuth? Ein Architekturthema. Was ist mit NoSql? Ein Architekturthema. Was ist mit WPF? Nur insofern ein Architekturthema als dass WPF auf bestimmten Devices (nicht) möglich sein könnte. Was ist mit Bubblesort vs Quicksort? Kein Architekturthema, auf wenn es um die nicht-funktionale Anforerung Performance gehen mag; denn die Unterscheidung ist keiner Abstraktionsebene der Architektur zuzuordnen. Code im Application Server oder im Datenbankserver laufen lassen? Ein Architekturthema.

Architektur hat mit der Verteilung von Funktionalität zu tun, um nicht funktionale Anforderungen zu erfüllen. Wenn Funktionalität verteilt wird, dann stellen sich Fragen dazu, wie die Funktionalität an ihren Orten gehostet werden soll und wie die verteilten Teile miteinander kommunizieren sollen.

Verteilt wird Funktionalität in zwei Weisen:

imageArchitektur macht zunächst auf den Abstraktionsebenen Bounded Context und App Längsschnitte durch das Anwendungssystem. Architektur schneidet es in dünne Scheiben. Die sind vollständig insofern, als dass sie vom Frontend bis zum Backend reichen.

Der Entwurf beginnt also damit zu überlegen, wie die gesamten Anforderungen in überschaubare Happen zerlegt werden können. Welche für den Anwender sinnvollen Subsysteme lassen sich finden, um nicht sofort und immer alles umsetzen zu müssen? Bounded Contexts und Apps sind daher auch fundamental für die Entkopplung von Code. Sie dienen unmittelbar der Evolvierbarkeit.

imageApp, Maschine und Prozess zerlegt die Architektur dann transversal weiter. Die funktionalen Scheiben werden “gewürfelt”, um insbesondere Skalierbarkeit, Performance und Verfügbarkeit zu erreichen. Jedes Teil stellt dann nicht mehr für sich einen Anwendernutzen her, sondern trägt nur dazu bei. (Hier ist die klassische Schichtenarchitektur anzusiedeln.)

Zusammenschau

Meine Erfahrung mit der Definition von Architektur in dieser Weise ist, dass sie sich leicht erklären lässt und Fragen beantwortet, bei denen zumindest ich früher “rumgeeiert bin”. Ich behaupte nicht, dass diese Definition vollständig ist; ich empfinde sie lediglich als pragmatisch-praktisch-gut ;-) Nützlichkeit sowie Kommunikationsfähigkeit stehen für mich hier höher als formale Reinheit.