XP-Days Germany 2009

Das Programm der XP-Days Germany 2009 ist jetzt online: http://xpdays.de/2009/programm.html

Ich selbst bin am Freitag mit einem Vortrag über “Inkrementelles Design” vertreten. Da ich ein Verfechter kurzer Vorträge bin, habe ich das Thema als 30-Minuten-Vortrag eingereicht. Einige der Reviewer hatten Zweifel, ob das Thema in 30 Minuten untergebracht werden kann. Das ist gut. Ich mag Herausforderungen.

Am Donnerstag halte ich eine Pecha-Kucha-Session zum Thema “Stop the Line in der Softwareentwicklung”. Pecha-Kucha ist ein modernes Vortragsformat, in dem genau 20 Folien für jeweils genau 20 Sekunden gezeigt werden. Der ganze Vortrag dauert dann exakt 6:40 Minuten. Bei der JAX 2009 haben wir das bereits einmal ausprobiert. Naja, ok: Ich habe ausprobieren lassen und mich auf die Organisation beschränkt. Auf den XP-Days muss ich jetzt selbst zeigen, ob ich das Format gut ausgefüllt bekomme.

Auf der JAX 2009 hatte mein Kollege Bernd Schiffer einen Pecha-Kucha-Vortrag über “Inkrementelles Design” gehalten, der jetzt auch als Video verfügbar ist. Für alle, die bei den XP-Days (oder der W-JAX oder sonstwo) einen Pecha-Kucha-Vortrag halten, ist das Video sicher eine ganz gute Inspiration und es zeigt auch, dass 20 Sekunden je Folie manchmal ziemlich lang sein kann 🙂

BDD for Prolog: How To

ProSpec is a RSpec (http://rspec.info) inspired BDD framework for Prolog. I created it during my experiments with Prolog. I suspect that I did some strange things. I would be pleased by any feedback on how to improve ProSpec or the examples. Send me an E-Mail: stefan AT stefanroock DOT de

Every ProSpec specification starts with describe(FixtureName) and ends with end_describe. Within these two predicates every specification is declared with it(SpecName/SpecCode).

We start with a very simple BDD spec for bowling.

bowling_spec.pro:

:- ensure_loaded('ProSpec.pro').
:- ensure_loaded('bowling.pro').

:- describe('Bowling'). 

generate_bowling_hits(_, 0).
generate_bowling_hits(Hit, Count) :- bowling_hit(Hit), Count2 is Count-1, generate_bowling_hits(Hit, Count2).

:- it('should score 0 for gutter game'/(
	generate_bowling_hits(0, 20),
	bowling_score(Score),
	assert_that(Score, equals:0)
)). 

:- end_describe.

bowling.pro:

bowling_hit(Count).
bowling_score(0).

With “run_specs.” the BDD spec runs:

Bowling...
...should score 0 for gutter game (passed)
Passed:1

1 specs passed

In the next step with specify the next behaviour increment:

bowling_spec.pro:

:- ensure_loaded('ProSpec.pro').
:- ensure_loaded('bowling.pro').

:- describe('Bowling'). 

generate_bowling_hits(_, 0).
generate_bowling_hits(Hit, Count) :- bowling_hit(Hit), Count2 is Count - 1, generate_bowling_hits(Hit, Count2).

:- it('should score 0 for gutter game'/(
	generate_bowling_hits(0, 20),
	bowling_score(Score),
	assert_that(Score, equals:0)
)). 

:- it('should sum hits of a game'/(
	generate_bowling_hits(2, 20),
	bowling_score(Score),
	assert_that(Score, equals:40)
)). 

:- end_describe.

“run_specs.” shows that this spec fails:

Bowling...
...should score 0 for gutter game (passed)
...should sum hits of a game
	Expected 40 equal to 0

We extend the bowling implementation:

bowling_hit(Count) :- assert(bowling_hit_def(Count)).

bowling_score(Score) :- 
	findall(Hit, bowling_hit_def(Hit), Hits),
	sumlist(Hits, Score).

Now the spec succeeds, but only once. The reason is the growing number
of “bowling_hit_def” facts. To avoid this problem ProSpec offers “setup_spec”.

bowling_spec.pro:

:- ensure_loaded('ProSpec.pro').
:- ensure_loaded('bowling.pro').

:- describe('Bowling'). 

generate_bowling_hits(_, 0).
generate_bowling_hits(Hit, Count) :- bowling_hit(Hit), Count2 is Count - 1, generate_bowling_hits(Hit, Count2).

:- dynamic(setup_spec/0).

setup_spec :- 
	retractall(bowling_hit_def(_)).

:- it('should score 0 for gutter game'/(
	generate_bowling_hits(0, 20),
	bowling_score(Score),
	assert_that(Score, equals:0)
)). 

:- it('should sum hits of a game'/(
	generate_bowling_hits(2, 20),
	bowling_score(Score),
	assert_that(Score, equals:40)
)). 

:- end_describe.

Now the spec succeeds every time.

There is a bunch of other assert_that predicates in ProSpec.pro. Have a look
and proceed: http://github.com/stefanroock/ProSpec/

Tippfehler in Fit/Fitnesse-Artikel

Im Artikel zu FIT/Fitnesse habe ich im Fixture-Code einen Tippfehler. Die Diffferenz-Methode darf natürlich nicht so aussehen:


public class TaschenrechnerFixture extends ColumnFixture {

    public int Zahl1, Zahl2;
    private Taschenrechner taschenrechner;

    public int Summe() {
        return taschenrechner.addiere(Zahl1, Zahl2);
    }

    public int Differenz() {
        return taschenrechner.addiere(Zahl1, Zahl2);
    }
}

Stattdessen muss es natürlich lauten:


    public int Differenz() {
        return taschenrechner.differenz(Zahl1, Zahl2);
    }

Danke an Sebastian für den Hinweis.

BDD mit Test-Technologien

Vor kurzem habe ich einen kurzen Vergleich zwischen TDD und BDD gewagt und BDD präferiert. Bernd Schiffer meinte, die TDD-Tests seien suboptimal und wenn man sie verbessert, sei TDD genauso gut wie BDD. Das sehe ich ähnlich. Man bekommt das vor allem dadurch hin, dass man BDD-Ansätze übernimmt. Und wie das geht, will ich in diesem Beitrag zeigen.

Tests je Fixture und nicht je Klasse
Der erste Punkt ist, dass man Tests um Fixtures (getestetes Objekt bzw. Objektgeflecht) gruppiert und nicht um Klassen. Diese Forderung gibt es auch schon lange in TDD, wird aber meist ignoriert. Die meisten Unittests werden um Klassen gruppiert. BDD erzwingt die Gruppierung um die Fixture durch sein Benennungsschema (a la it “should create new meetings”). Und so ein Benennungsschema kann man sich auch in Unitttests geben. Wir haben sehr gute Erfahrungen damit gemacht, die Testklasse wie die Fixture mit angehängtem “Test” zu benennen und die Testmethoden so, dass sie zusammen mit dem Fixturenamen einen Satz ergeben. Das sieht dann in Java z.B. so aus:

public class TerminkalenderTest {
    @Test
    public void erzeugtNeueTermine() {...}
}

Diese Art der Methodenbenennung ist zumindest in Java unüblich, aber der Nutzen überwiegt hier meiner Meinung nach deutlich. Mit TestDox gibt es übrigens ein Tool, dass aus solchen Tests Anforderungsspezifikationen in Prosa generiert in der Art:
Terminkalender

  • erzeugt neue termine

Nun ist “Terminkalender” natürlich erstmal eine ziemlich langweilige Fixture. So beginnt es häufig. Mit der Zeit wird im Test aber sehr deutlich, dass eine neue Fixture raus will. Das kann man leicht daran erkennen, dass in den Testmethoden zuerst die Fixture verbogen oder nur ein Teil der Fixture im Test benutzt wird.

Assertions
Der zweite Punkt betrifft die Überprüfungen im Test. xUnit bietet die klassischen assertXXX-Methoden an. In den neuen Versionen von JUnit findet sich mit Hamcrest eine Framework, um die Prüfungen in BDD-Stil beschreiben zu können. Mit RSpec heißt es z.B. termin.start_zeit.should == @jetzt. Mit Hamcrest für Java heißt es assertThat(termin.getStartZeit(), equalTo(jetzt));. Da hat man jetzt jede Menge nervige Klammern, aber das liegt an Java und nicht an TDD.

Fazit
Wenn man aus welchen Gründen auch immer Unittest-Frameworks einsetzen will oder muss, kann man viel von BDD auch für TDD adaptieren. Das geht immer und lohnt sich auf jeden Fall.

Vergleich: BDD und TDD

Als XP-Jünger der ersten Stunde wurde ich bereits früh von TDD (Test Driven Development) infiziert. Irgendwann kam eine neue Bewegung auf: BDD (Behaviour Driven Design). Wie viele andere TDDler habe ich lange nicht verstanden, was der Vorteil von BDD sein soll. Das ist mir inzwischen klar geworfen. Ich möchte versuchen, einige der Vorteile in diesem Artikel anhand eines Beispiels zu vermitteln.
Als Beispiel verwende ich mein Terminplaner-Beispiel in Ruby mit RSpec als BDD-Framework.

Im Terminplaner-Test testen wir beispielsweise das Erzeugen von Terminen:

class TerminkalenderTest < RUNIT::TestCase

    ...
    def test_termin_anlegen
        dauer_in_minuten = 180
        termin = @stefans_kalender.new_termin(@jetzt, dauer_in_minuten, "TDD-Dojo")
        assert @stefans_kalender.hat_termin(termin)
        assert_equal("TDD-Dojo", termin.bezeichnung)
        assert_equal(@jetzt, termin.start_zeit)
        assert_equal(dauer_in_minuten, termin.dauer_in_minuten)
        assert_equal(STEFAN, termin.autor)
    end
    ...
end

Als BDD-Spezifikation sieht das ganze noch sehr ähnlich aus:

describe Terminkalender do
    it "should create new meetings" do
        dauer_in_minuten = 180
        termin = @stefans_kalender.new_termin(@jetzt, dauer_in_minuten, "TDD-Dojo")
        @stefans_kalender.hat_termin(termin).should be_true
        termin.bezeichnung.should == "TDD-Dojo"
        termin.start_zeit.should == @jetzt
        termin.dauer_in_minuten.should == dauer_in_minuten
        termin.autor.should == STEFAN
    end
    ...
end

Strukturell sind Test und BDD-Spezifikation identisch. Die BDD-Spezifikation ist bei den Vergleichen lediglich etwas leichter lesbar.
Der Vergleich termin.bezeichnung.should == "TDD-Dojo" ist der natürlichsprachlichen Formulierung "Die Terminbezeichnung sollte 'TDD-Dojo' sein." ähnlicher als assert_equal("TDD-Dojo", termin.bezeichnung).

Wenn wir Test und BDD-Spezifikation weiter vergleichen, finden wir auch strukturelle Unterschiede. So ist am folgenden Test erstmal nicht so fürchterlich viel auszusetzen:

def test_teilnehmer_einladen_und_autor_ist_auch_teilnehmer
    termin = @stefans_kalender.new_termin(@jetzt, 180, "TDD-Dojo")
    termin.lade_teilnehmer_ein(MARTIN)
    termin.lade_teilnehmer_ein(HENNING)

    assert_equal([HENNING, MARTIN, STEFAN], termin.teilnehmer)
    assert_equal(@stefans_kalender.alle_termine, [termin])
    assert_equal(@hennings_kalender.alle_termine, [termin])
end

Wenn man versucht, diesen Testfall direkt nach BDD zu portieren, stößt man schon bei der Benennung auf ein Problem. Wie soll man das vernünftig mit "it" (=Terminkalender) am Satzanfang formulieren? it "invites participants and author is participant" kann man zwar aufschreiben. Zumindest bei mir stellen sich dann aber die Nackenhaare zu Berge. Viel natürlicher scheint mir eine Aufteilung des Tests in mehrere BDD-Spezifikationen:

describe Termin do
    ...

    it "should have the author as a participant" do
        @termin.teilnehmer.should include STEFAN
    end

    it "should invite participants" do
        @termin.lade_teilnehmer_ein MARTIN
        @termin.lade_teilnehmer_ein HENNING 
        @termin.teilnehmer.should == [HENNING, MARTIN, STEFAN]
    end
    ...
end

BDD führt also auf natürlichem Weg zu Spezifikationen, die jeweils kleiner und besser strukturiert sind als Tests.

Wir haben mit BDD also in Summe besser strukturierte, leichter lesbare Spezfikationen.

Call for Sessions für die XP-Days Germany online

Der Call-For-Sessions für die XP-Days Germany im November 2009 ist jetzt Online: http://xpdays.de/2009/callforsessions.html

Wie letztes Jahr wird es auch dieses Jahr wieder einen offenen Review-Prozess geben. Das bedeutet, dass alle Interessierten die eingereichten Beiträge bewerten können. Die Einreicher haben die Möglichkeit, auf Basis des Feedbacks ihre Beiträge zu verbessern. So können die Vortragsvorschläge schrittweise immer weiter verbessert werden.

Als Conference Chair 2008 kann ich sagen, dass dieser Review-Prozess sehr viel gebracht hat. Vortragsvorschläge, die man in der ersten Version nicht akzeptiert hätte, wurden schrittweise so verbessert, dass sie es dann doch ins Programm geschafft haben.

Also: Alle bitte mitmachen beim Einreichen aber auch beim Reviewen!

Stop the Line in der Softwareentwicklung

Die Idee, “Stop the Line” in der Softwareentwicklung anzuwenden erscheint Managern und Entwicklern zwar irgendwie einsichtig, aber auch gefährlich. “Sitzt dann der Großteil der Entwickler rum, weil sie nicht effektiv zur Problemlösung beitragen können? Wäre es nicht besser, man würde erstmal seine aktuelle Aufgabe zuende erledigen? Man kann doch die Leute nicht untätig rumsitzen lassen!”

Ich möchte in diesem Blogeintrag versuchen, etwas besser zu erklären, wie man “Stop the Line” in der Softwareentwicklung umsetzen kann. Vielleicht erscheint die Idee dann weniger gefährlich.

Stop the Line der Produktion
Beginnen wir mit dem Ursprung der Stop-the-Line-Idee: Lean Production / Toyota Production System. Tritt in der Produktion ein Problem auf (z.B. Kratzer auf einer produzierten Tür), wird die Produktion gestoppt. Dann wird geprüft, was die Ursache für das Problem ist und diese Ursache wird beseitigt. Und das alles sofort und schnell.

Dieses Vorgehen ist sinnvoll, weil die Ursache für das Problem meistens systematischer Natur ist. Das Wegpolieren des Kratzers beseitigt das ursprüngliche Problem (z.B. Maschine falsch eingestellt) nicht und das Problem tritt bei den folgenden Türen immer wieder auf.

Und es heißt “Stop the Line” und nicht “Stop the Plant”. Bei einem Kratzer hören also nicht alle Leute in der Fabrik auf zu arbeiten. Es hören die auf, die in der Produktionslinie arbeiten, in der das Problem aufgetreten ist.

Es ist nicht sinnvoll, wenn in der gestoppten Produktionslinie vorgelagerte Verarbeitungsschritte weiterarbeiten. Diese würden Zwischenprodukte auf Lager produzieren. Und gerade Lagerhaltung versucht man im Lean Production zu vermeiden. Dass physikalischer Lagerplatz Geld kostet, ist sicher ein Aspekt, aber nicht der entscheidene. Viel wichtiger ist, dass große Lagerbestände hohe Overheadkosten verursachen und Qualitätsprobleme verdecken.

Hohe Overheadkosten durch Lagerhaltung
Große Lagerbestände versurachen hohe Overheadkosten: Man muss das Zwischenprodukt ins Lager transportieren. Dort muss man einen geeigneten Lagerplatz finden und meistens noch vermerken, wo man das Zwischenprodukt abgelegt hat. Später muss man wieder ins Lager, das Zwischenprodukt wiederfinden und es zurück zur Produktionslinie transportieren. Und dabei besteht auch immer die Gefahr, durch Transport und Lagerung das Zwischenprodukt zu beschädigen.

Verdeckte Qualitätsprobleme durch Lagerhaltung
Qualitätsprobleme werden verdeckt, weil der Lackmustest für die Qualität eines Zwischenproduktes erst ganz am Ende erfolgt. Ob wirklich alles gut zusammenpasst, weiß man ganz sicher erst, wenn das Produkt (in unserem Fall das Auto) komplett montiert ist. Eine falsch eingestellte Maschine könnte z.B. dazu führen, dass die Tür wenige Millimeter zu breit ist und daher nicht richtig schließt.

Softwareentwicklung ist aber anders
Soweit, so gut. Natürlich ist Softwareentwicklung keine Autoproduktion, nicht mal annähernd. Daher ist erstmal Skepsis angebracht, wenn man versucht, Konzepte aus der Produktion in die Softwareentwicklung zu übertragen.

Lagerhaltung in der Softwareentwicklung
Beginnen wir mit der Lagerhaltung in der Softwareentwicklung. Gibt es sowas überhaupt? Klar. Alles, was nicht komplett fertig (Done) ist und an dem im konkreten Moment niemand arbeitet, liegt im Lager. Und die Läger finden wir in den lokalen Workspaces auf den Entwicklerrechnern wie auch in Branches in der Versionsverwaltung.

Aber ist Lagerhaltung in der Softwareentwicklung auch so schädlich wie in der Produktion? Plattenplatz kostet ja kein nennenswertes Geld mehr. Allerdings sind die Kosten für den Lagerplatz in der Produktion sicherlich auch nicht ausschlaggebend. Overheadkosten und Qualitätsprobleme sind bestimmend. Nehmen wir uns zunächst die Overheadkosten vor. Das Transportieren von Code in ein Lager (z.B. Branch) kann erstaunlich teuer sein. In vielen Unternehmen können Entwickler den Branch nicht selbst anlegen, sondern müssen den Branch von zentraler Stelle anlegen lassen. Aber das eigentliche Drama entsteht, wenn man den Code wieder aus dem Lager holt, um ihn wieder zu reaktivieren. Dann muss man in der Regel Mergen und das verursacht fast immer hohe Kosten. Zusammenfassand würde ich behaupten, dass die Overheadkosten für große Lagerbestände in der Softwareentwicklung sogar höher sein können als in der Produktion.

Sehen wir uns jetzt die Qualitätsprobleme an. Auch in der Softwareentwicklung weiß man erst ganz am Ende, ob alles gut zusammenpasst und man wirklich das gebaut hat, was Nutzen generiert. Dieses Phänomen ist in der Softwareentwicklung sogar noch viel stärker ausgeprägt als in der Produktion. Produktion kann man relativ genau vorausplanen und sie ist geprägt von repetitiven Arbeiten. Wenn man eine Tür korrekt produzieren kann, produziert man weitere Türen mit hoher Wahrscheinlichkeit auch korrekt. In der Softwareentwicklung haben wir es hingegen fast immer mit Einzelstücken zu tun. Dadurch ist die Vorhersagbarkeit viel eingeschränkter – nicht ohne Grund entwickeln wir Software agil, während Produktion eher nicht agil verläuft. Also gilt wie schon beim Overhead auch bei der Qualität: Die Qualitätsprobleme, die durch große Lagerbestände entstehen, sind in der Softwareentwicklung noch viel größer als in der Produktion.

Lagerhaltung sollte also gerade in der Softwareentwicklung vermieden werden!

Stop the Line in der Softwareentwicklung
Wenn wir jetzt Stop-the-Line in der Softwareentwicklung anwenden wollen, müssen wir zunächst definieren, bei welchen Probleme wir die “Linie” stoppen wollen und was überhaupt die “Linie” ist. Man sollte klein anfangen und sich dann schrittweise verbessern. Meistens ist ein guter Anfang, das Fehlschlagen von Tests in der Buildumgebung als stopp-würdiges Problem zu definieren. Wenn die Tests fehlschlagen, stoppen sofort alle Entwickler in dem Team ihre Arbeit, bis sich mind. ein Entwickler gefunden hat, der sich um das Problem kümmert. Während der Entwickler an dem Problem arbeitet, können die anderen Entwickler weiterarbeiten. Sie dürfen aber keinen Code in die Versionsverwaltung einchecken – schließlich funktioniert das Feedback über die Buildumgebung im Moment nicht. Das bedeutet meist, dass die Entwickler solange weiterarbeiten können, bis sie mit ihrem aktuellen Feature fertig sind. Wenn das Problem dann noch besteht, sollte man die Gruppe der Problemlöser schrittweise vergrößern, solange bis das Problem gelöst ist. Und das funktioniert ganz gut, weil man Problemlösung meistens gut parallelisieren kann. Dann probiert eben nicht ein Entwickler acht verschiedene Lösungsstrategien sequenziell aus, sondern acht Entwickler probieren jeweils eine Lösungsstrategie aus.

Und wenn dieses Verfahren gut läuft, kann man schrittweise die Bedingungen verschärfen. Findet der Product-Owner, ein Tester oder ein Entwickler einen Bug, dann Stop-the-Line. Ist die Arbeit an einer Anforderung durch Hindernisse blockiert, dann Stop-the-Line. Wenn ein Entwickler vergurkten Code findet, dann Stop-the-Line. Wenn die automatisierten Tests unvollständig sind, dann Stop-the-Line.

Erfahrungen
Jeder muss seine eigenen Erfahrungen sammeln. Meine Erfahrungen mit Stop-the-Line sind sehr gut. Gerade hat ein Team eines Kunden mit Stop-the-Line ein Problem an einem Tag beseitigt, dass vorher bereits 3 Wochen durch die Gegend eierte.
Ich kann jedem nur empfehlen, Stop-the-Line in der Softwareentwicklung auszuprobieren. Und das kann man mit überschaubarem Risiko auch immer tun. Und wer sich das nicht zutraut, den unterstütze ich als Coach gerne 🙂

Vielleicht haben Leser dieses Blogs ja ebenfalls Erfahrungen mit Stop-the-Line in der Softwareentwicklung gemacht? Dann schreibt das doch bitte in die Kommentare!