Follow my new blog

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.

Keine Kommentare: