Fertig!
25.05.2007 Permalink Vor kurzem erst habe ich mich mit einem Bewerber für eine PL-Position darüber unterhalten, was man in einem Software-Projekt während der Entwicklung tun kann, um schon vor einem Systemtest möglichst viel Qualität in die entwickelte Anwendung zu bringen. "Viel Qualität" heißt hier konkret:- wenige Defekte
- bestehende Fehlerwirkungen können schnell auf Fehlerursachen zurückgeführt werden
- kaum Seiteneffekte während der Defektbehebung
- geringer Refactoring-Bedarf
Warum macht die frühe Herstellung höherer Qualität Sinn?
Damit man sich eine vorhersehbare böse Überraschung spart. Denn wenn man erst
nach offiziellem Entwicklungsende Acht auf innere und äußere Qualitätsmerkmale
gibt, dann kann das Team längst in der Falle sitzen: jede Defektbehebung kostet
Zeit, und die kann vor der Auslieferung schnell zu knapp werden. Die Folge ist
ein gerissener Termin oder miese Auslieferungsqualität. Beides verursacht
letztlich erschreckend viel Aufwand und bringt dazu noch Ärger und vielleicht
zusätzlichen finanziellen Schaden ein.
Im Gesamtprozess kann man dagegen Zeit sparen, wenn das Team direkt während der Entwicklung Wert auf Fehlervermeidung legt. Man spart sich dadurch bei jedem Fehler, der im Systemtest nicht mehr auftaucht, das Entdecken, Reproduzieren, Melden, Zuweisen, Suchen, Beheben und Nachtesten des Fehlers.
Zahlen, die ich in meiner Vergangenheit sammeln konnte, zeigen, dass die
Rechnung aufgeht:
Die Qualitätssicherung (QS) eines Stücks Entwicklungsarbeit kostet vielleicht
1-2 PT, die Analyse und Behebung von nur einem Defekt während des Systemtests
kostet im Schnitt 0,5 bis 1 PT. Und zwar ohne erste Entdeckung und Nachtest. Und
dabei ist auch nicht eingerechnet, dass statistisch eine von fünf Behebungen
nicht wirkt oder einen Folgefehler produziert. D.h. bei nur einer Handvoll
Fehler pro Arbeitspaket würde das späte Finden teurer als die
entwicklungsbegleitende QS... mehr Argumente braucht's -- finde ich -- nicht.
Was kann man als PL konkret tun?
1. Verständnis und Kultur schaffen.
Die böse Überraschung trifft nicht nur den PL, und schlechte Qualität ist nicht
das Problem des Tests. Stress und Ärger trifft vor allem die Entwicklung, die
"den Dreck" wieder wegräumen muss. Denn wer sollte das sonst tun?
Jeder im Team wird anfänglich einen eigenen Begriff von Qualität haben. Es gilt,
im Team eine gemeinsame Vision zu erschaffen, was man durch kleine Referate zu
Einzelthemen und anschließende Diskussion fördern kann.
Auf diese Weise kann man das Verständnis für die Durchführung von QS im Team
schaffen, aber Vorsätze, Bitten und Appelle sind ohne konkrete Handlungen
nutzlos. Um eine wirksame Qualitätskultur zu begründen, ist es besser,
unbeholfen aber konkret mit QS zu starten, als nur darüber zu diskutieren und QS
aus Angst vor Nicht-Perfektion letztlich zu unterlassen.
Es wird anfänglich holpern und rumpeln, und die QS-Ergebnisse werden auch nicht
immer Anlass zur Freude sein... es ist eben ein Lernprozess.
2. Anders planen.
QS kostet Geld, in Summe zwar kein zusätzliches, aber das wenige eben früh
sichtbar. Man sollte sich bei Planungs- und Schätzaufgaben daran gewöhnen, dass
die Arbeit an einem Stück Code nicht damit abgeschlossen ist, dass der
verantwortliche Mitarbeiter "Fertig!" meldet.
Es folgt die QS, die man als eigenes Arbeitspaket direkt an den Anschluss des
jeweiligen Arbeitspakets der Entwicklung stellt. Je schneller das Feedback
kommt, desto billiger ist seine Berücksichtigung. Durchgeführt wird das
QS-Arbeitspaket von einem Entwickler-Kollegen. Die Kosten sollten je nach
Baustelle bei 0,5 bis 2 PT liegen. Einen zentralen QS-Verantwortlichen braucht
man, wenn das Team sehr groß ist und/oder man als PL das notwendige Grundwissen
zu den Methoden nicht mitbringt.
3. Außensicht: Fachliche Funktionalität prüfen.
Was dem Systemtest auffallen könnte, kann ein anderer Kollege möglicherweise
durch unsystematisches Blackbox-Testen selbst finden. Das Ziel ist,
offensichtliche Fehler aufzudecken und ohne besondere Form an den zuständigen
Entwickler zurückzumelden. Die Prüfgrundlage ist das Konzept oder die
Feature/Use Case Beschreibung und immer der gesunde Menschenverstand.
4. Innensicht: Code und Unittests prüfen.
Die Funktionalität ("was der Code macht") sollte sich dem Code durch seine
Struktur und durch Kommentare entnehmen lassen. Er sollte der konkreten
technischen Architektur, anerkannten Design-Prinzipien und einem Code-Styleguide
gehorchen. Das lässt sich mithilfe von Werkzeugen (s.u.) und natürlich Sichtung
durch Kollegen prüfen.
Die Unittests sollten den Code funktional mindestens soweit abdecken, dass die
zentralen Use Cases und deren Szenarien geprüft werden. Diese Beurteilung kann
nur ein Mensch vornehmen. Ein Coverage-Werkzeug erlaubt zusätzlich das
Identifizieren auffällig unabgedeckter Codestellen, was ein gutes Indiz für
fehlende Tests ist. Dass die Unittests grün sind (also fehlerfrei ausführbar)
versteht sich von selbst.
Während bei der Außensicht-Prüfung die Kommunikation der Prüfergebnisse in
Fire-and-Forget-Manier z.B. per Mail ausreicht, lohnt es sich nach der
Innensicht-Prüfung besonders, Prüfer und Code-Autor vor einem Monitor
zusammenzubringen. Dadurch entsteht ein wertvoller Erfahrungsaustausch.
5. Messungen durchführen.
Mit Code- und Design-Metriken lassen sich potentielle Schwachstellen aufspüren.
Eine hohe CCN (>20) lässt z.B. komplizierten Code vermuten, der sehr anfällig
für Defekte ist. Klassen mit nicht-trivialen Aufgaben sollten durch Unittests
zumindest in Teilen abgedeckt werden, was man durch Coverage-Messungen
sicherstellen kann. Auch das Package-Design kann man mit Maßzahlen zu
Instabilität und Abstraktion unter die Lupe nehmen, um gröbere Design-Schnitzer
aufzudecken.
6. Build- und IDE-Integration.
Unittest-Ausführung und Messungen, am besten mit Prüfungen gegen Referenzwerte,
sollten in den täglich oder gar kontinuierlich auszuführenden Build und die IDE
integriert werden, denn je schneller ein Missstand auffällt, desto günstiger
ist seine Beseitigung. Hier beginnt dann schon die höhere Kunst, denn es sind
einige Werkzeuge wie z.B. Eclipse, Ant oder Maven, CruiseControl, Cobertura,
JDepend, JavaNCSS, CheckStyle und ähnliche ins Zusammenspiel zu bringen.
Die oben genannten Elemente reichen aus, um spürbar besser zu werden. Schon die ersten drei helfen, peinliche Ausfälle beim Start des Systemtests zu vermeiden. Die übrigen drei kosten mehr, sind aber im Sinne einer qualitätsoptimierten Entwicklung die logische Konsequenz.
Mehr Formalismus und Kontrolle (z.B. durch definierte Vorgabedokumente, Prüfprotokolle und einen Tool-gestützten Fehlerbehebungsprozess) kann nötig sein, sollte aber beim ersten Start in der Schublade bleiben. Und bei all dem nicht vergessen: lieber erstmal starten, dranbleiben und besser werden, als Perfektion anzustreben und am eigenen Anspruch zu verzweifeln.