TDD 2.0

Ralf Westphal schreibt in seinem Artikel Ab ins Grüne in der dotnet pro Ausgabe 04/2013 über die Probleme mit TDD. Auf den Punkt gebracht, schildert er seinen Eindruck, dass die Fokussierung auf T(est)D(riven) einen Lösungsansatz perpetuiert hat, der D(evelopment) zu wenig bis gar nicht integriert. Will heißen: Durch die Konzentration auf das Schreiben und Lösen der Tests, wird die Analyse- und Lösungsphase fast gänzlich außer Acht gelassen. Deshalb stünden, so seine Meinung, in Coding Dojos am Ende auch nur selten fertige Ergebnisse.

Aus meiner Sicht trifft Ralf damit voll ins Schwarze. Persönlich störte ich mich seit längerer Zeit an diesem Problem. Ich denke sogar, dass das Development der weit schwierigere Teil ist. Test zu schreiben und den Code dafür entsprechend zu präparieren ist eine Art Training wie das Lösen von Gleichungen 2ter Ordnung in der Schule. Je nach Kenntnisstand des Entwicklers werden noch Vereinfachungen oder schnellere Lösungsansätze wie die binomische Formel erkannt. Ein solides Level stellt sich allerdings nach relativ kurzer Zeit ein. Neue Probleme wie Gleichungen vierter Ordnung bedürfen aber der analytische Fähigkeiten.

Deshalb haben wir bei unseren Coding Dojos die Anregungen aufgegriffen und implementiert. Interessanterweise, was ich persönlich als sehr positiv empfinde, gab es im ersten Dojo mit dem neuen Verfahren keine einzige Codezeile, da eine Stunde lang das Problem eruiert und Begrifflichkeiten diskutiert wurden. Wohlgemerkt handelte es sich dabei um ein echtes Szenario aus einer unserer Problemdomäne, d.h. wir verwendeten keine der üblichen Katas. Umso schneller kamen wir dann im zweiten Training zu einer fertigen Lösung. Mit ein wenig Überziehung erreichten wir nach 1.15h die Ziellinie.

TDD 2.0 empfinde ich als längst überfällige Erweiterung bzw. Kritik. Wir werden in Zukunft auf diese Weise weiterarbeiten. Ein Punkt, der für mich allerdings weiterhin in Frage gestellt werden sollte: Müssen Coding Dojos an Katas durchgeführt werden? Warum nicht an einem echten, auf ein notwendiges Minimum reduzierten Praxisbeispiels aus der Problemdomäne trainieren? Oder alternativ für die Administration ein kleines Hilfsprogramm schreiben, dass die tägliche Arbeit automatisiert? Kürzlich half ich meinem ehemaligen Fussballverein beim Realisieren des DFB Reglements bzgl. Stammspieler. Gelöst habe ich es vorerst über Excel, sodass immer noch Handarbeit seitens des Vorstands notwendig ist. Doch dieses Thema kommt auf unsere Coding Dojo Agenda. Es gibt viele gemeinnützige Organisationen oder Sportvereine, die sich über Hilfe der IT zu kleinen Wehwehchen freuen würden!

Mit Tag(s) versehen:

15 thoughts on “TDD 2.0

  1. Ralf Westphal 14. April 2013 um 14:44 Reply

    Freut mich, dass euch TDD 2.0 so gut geholfen hat. (Ich frag jetzt auch nicht, ob ihr bei der Implementierung von red zu green mit TDD as if you meant it vorgegangen seid ;-)

    Die Idee, Vereinen zu helfen, find ich interessant. Da ist das Budget klein, da sind Domänenkenner, da ist die Domäne auch eher noch übersichtlich – aber es ist eben realer, als eine Code Kata.

    Wer aber keinen Verein kennt, der kann sich trotzdem an größeren Aufgaben versuchen. Warum nicht eine Application Kata? http://clean-code-advisors.com/ressourcen/application-katas

    Gefällt mir

  2. Daniel Minigshofer 25. April 2013 um 12:39 Reply

    Hallo Herr Armbruster,

    die Lösung der Aufgabe in einem Coding Dojo stellt meiner Meinung nach nicht im Fokus. Der eigentliche Fokus in einem Dojo besteht für mich das Erlernen von Praktiken. Arbeiten im Paar, kleine Schritte und TDD-Patterns anwenden um nur einige Sachen zu nennen.

    Ich sehe in TDD 2.0 eine wesentliche Gefahr in ein Bottom-Up Design zu verfallen. Kent Beck spricht ja auch vom Responsive Design. Lieber nach dem Lean Prinzip „Stop Starting, Start Finishing“ übertragen auf das Design.

    Im Rahmen eines Dojo eine Aufgabe für die Praxis zu machen kann ich nur empfehlen. Diese Vorgehensweise kann zu einem besseren Allgemeinverständnis führen und genauso auch zu einem Wir-Gefühl beitragen.

    Auch ein Refactoring einer historisch gewachsenen Komponente kann im Rahmen eines Dojos eine sehr schöne Abwechslung sein.

    Viele Grüße,
    Daniel

    Gefällt mir

    • RalfW 25. April 2013 um 13:43 Reply

      Wenn im Dojo der Fokus auf „Arbeiten im Paar, kleine Schritte und TDD-Patterns“ liegt, dann muss bis dahin alles vorgegeben werden. Mindestens muss dann die Lösung präsentiert werden und auch ein API.

      Das kann man machen. Habe ich aber noch nicht gesehen. Deshalb scheitern Dojos immer wieder. Die Teilnehmer verzetteln sich. Weder finden sie eine Lösung (im Sinne eines programmiersprachenunabhängigen Entwurfs), noch implementieren sie eine Lösung. Sie „humpeln“ durch die Gegend mit ihren Praktiken: im Pair, in mehr oder weniger kleinen Schritten, von Rot nach Grün.

      Und am Ende? Da freuen sich alle, wenn die Stimmung locker geblieben ist.

      Meine Erfahrung mit dieser Art Dojos ist breit: viele Events, viele Plattformen.

      Das widerspricht auch der grundlegenden Geisteshaltung von Entwicklern. Die wollen nämlich nicht l’art pour l’art betreiben, sondern was (er)schaffen. Also Ergebnisse produzieren und etwas zum Laufen bringen.

      „Stop starting, start finishing“? Da bin ich dabei. Aber das ist orthogonal zu einem sauberen Prozess. Wer einfach nur loslegt, um zur Finish-Linie zu kommen, der übt am Ende nichts wirklich. Der will einfach nur Spaß am Basteln haben, d.h. daran, etwas hinzubekommen.

      Das ist auch ne schöne Sache. Aber Lernen, deliberate practice ist was anderes.

      Und es wird ja nicht mal thematisiert, was „stop starting, start finishing“ bedeuten könnte. Wenn denn das noch geschehen würde… Aber über wahrlich inkrementelles, kleinschrittiges, nutzenorientiertes Vorgehen macht sich im Dojo keiner Gedanken. Wie denn auch? Ohne Lösung und API kann man nicht wirklich Testfälle priorisieren. Und deshalb kann man sich nicht überlegen, welche Ziellinien man den in welcher Reihenfolge erreichen will.

      Refactoring? Klar. Eine schöne Abwechslung. Aber wenn da eine Stunde nur über Namen diskutiert wird, man sich in der Kenntnis von ReSharper-Shortcuts übertreffen will und noch ein Schüppchen SOLID versucht nachzulegen, dann ist auch das aus meiner Sicht zuwenig.

      Beim Refactoring sollte mal ein Gedanke darüber verloren werden, worum es denn eigentlich geht, wie eine Lösung aussehen könnte, bevor man sich in Patterndetails ergeht.

      Gefällt mir

  3. Daniel Minigshofer 25. April 2013 um 15:07 Reply

    Hallo Ralf,

    natürlich muss das Grundverständnis für TDD bei den TN relativ gleich sein. Es bringt auch nichts die TN einfach drauf los zu coden lassen im Dojo. Es ist möglich in der ersten Runde die Aufgabe von den TN nach Ihrem Wissen machen zu lassen aber dann Ihnen helfen und coachen. Danach machen Sie die Aufgabe in einer zweiten Runde mit den neuen Kenntnissen.

    Ich hebe explizit nochmal hervor, dass das Lösen der Kata nicht zwingend relevant ist. Selbst aus einer nicht gelösten Aufgabe kann ich einiges ziehen. Es geht nach meiner Auffassung um die Praktiken, diese sollen in Fleisch und Blut übergehen um sich hier nicht mehr lange auf zu halten.

    Welche Intension siehst Du in Katas wenn ich Dich so fragen darf? Meine Erfahrung mit Dojos ist auch breitgefächert, jedoch habe ich gute Erfahrungen gemacht wenn die TN gecoacht werden und Ihnen gezeigt wird welche Schritte zu einem fehlerhaften Status führten.

    Was erschaffen? Machen das die meisten Entwickler nicht Tag für Tag? Nur leider meistens nicht Test First. Das Dojo gibt Ihnen einen geschützten Rahmen für das erschaffen eines neuen Denkens in Ihnen und den glauben zu finden. Zu sehen wie Sie mit Tests Ihr Design treiben und wie Sie hier auch mal was ausprobieren können.

    Warum wird TDD meistens so komplex beschrieben? Es ist eine relativ einfache Praxis. Während jemand sich noch überlegt welche Prio der Testfall hat kann man schon den einen oder anderen Red-Green-Refactor Zyklus durchlaufen haben.

    Lernen heißt tägliches Üben und Verbessern. Dafür sind die Katas meiner Meinung nach gedacht. Ausprobieren am produktiven Umfeld wird selten in einer Firma gern gesehen. Die Ziellinie hängt von jedem selbst ab. Meine Ziele sind zum einen das Verständnis der Test-API, Shortcuts, IDE und dazu noch neue Wege zu probieren. Die Aufgabe z.B. ohne ein if-Statement zu lösen. Das sind Auszüge welche ich immer mal wieder probiere.

    Wenn solche Fälle eintreten, dass über eine Stunde an Namen herumgenörgelt wird dann läuft meiner Meinung nach schon was anderes falsch. Da hilft auch kein Dojo sondern nur ein Coach der auch mal sagt Namen sind Schall und Rauch…. Wir arbeiten nach Collective Codeownership somit kann jeder dieser Methode einen neuen Namen geben. Test-Methoden können IMHO auch erst mal „Bla“ heißen und sich vom Assert leiten lassen. Aus dem Assert leite ich dann den Testnamen her. Meist trifft dieser viel besser zu als ein Name den ich mir vor dem Assert überlegen würde.

    Refactoring sollte natürlich im Brain-On-Modus betrieben werden und sollte sich nicht an Patterns festhalten. TDD heißt ja nicht nur Test Driven Development sondern auch Test Driven Design, d.h. ich treibe mein Design durch meine Tests ja weiter voran. Dabei hilft mir zum einen der Test und zum anderen das Refactoring.

    Gefällt mir

    • RalfW 26. April 2013 um 7:14 Reply

      Katas sind Übungsaufgaben. Der Begriff ist idiomatisch; ich sehe da nur eine grobe Nähe zu den Katas von budo Sportarten. Dort geht es um das Einschleifen von Bewegungsabläufen, um am Denken vorbei zu kommen. Es geht um Automatisation. Reflexartige Reaktion. Immer höhere Effizienz – die am Ende in ihrem Minimalismus Eleganz ist.

      Beim Programmieren ist es nett, manches auch einfach automatisch zu tun. Nicht mehr nachdenken, sondern einfach machen. Beispiel: Überhaupt TDD oder VCS oder CI benutzen und nicht darüber diskutieren, „ob“ das sinnvoll ist.

      Jenseits dessen jedoch geht es bei der Softwareentwicklung jedoch eben nicht um Reflexe, sondern ums Nachdenken. Wir müssen mehr im Neokortex tun statt im Stammhirn.

      Deshalb halte ich die Dojo-Praxis, die Teilnehmer in eine Aufgabe stürzt mit der Anweisung „Nun übt mal einfach XYZ“ für kontraproduktiv. Da kommt vor allem Frust raus. Das passiert ja auch nicht im Karate. Wenn schon Kata, dann aber richtig. Bei Karate gibt es zwar ein Dojo, aber da drin macht man nicht nur Katas. Bevor man Katas macht, übt man Bewegungsabläufe isoliert. Katas sind Integrationen.

      Das isolierte Üben findet in Coding Dojos aber nicht statt.

      Auch das ist ein Grund, warum ich mit Stefan Lieser die http://ccd-school.de/ gegründet habe. Wir wollen dort beides bieten: „Bewegungen“ einzeln üben und auch integriert. Und begleitet. Denn im Karate Dojo kommt auch einer rum und leitet jeden Einzelnen an in seinem Üben.

      Und niemand käme übrigens auf die Idee, Karate allein mit Youtube Videos zu lernen. Und niemand käme auf die Idee, Karate während des Straßenkampfes zu lernen. Gelernt wird in geschützter Umgebung von Leute, die schon mindestens einen Schritt weiter sind.

      Auch das passiert in Coding Dojos nicht. Da wird sogar bewusst eine Kultur von „eigentlich weiß keiner mehr als die anderen“ gepflegt. Alle tappen im Dunkeln und versuchen den Lichtschalter zu finden.

      Ich behaupte nicht, dass es einen Guru geben muss im Dojo. Aber zumindest einen, der schon mehr Erfahrung hat. Und einen, der die Reflexion über das Dojo anleitet.

      Beides existiert auch am Arbeitsplatz eher selten. Von der Schwierigkeit, sich am Arbeitsplatz Zeit zu nehmen zum Üben. Üben während des Gefechts funktioniert nicht beim Karate und auch nicht beim Programmieren.

      Ein Coding Dojo hat also die Aufgabe, dafür einen Raum zu schaffen abseits des Alltags. Und die Aufgaben sollen Lernen stimulieren – aber nicht Reflexe.

      Und wenn du TDD mit Test-Driven Design übersetzt, dann verstehe ich gar nicht, dass du dich gegen das Nachdenken beim TDD wehrst. Design kommt nicht von ungefähr. Das will erdacht sein.

      Dass man im Dojo keine Lösungen schaffen muss… Darauf kommt es tatsächlich nicht in erster Linie an. So wie bei Olympia dabei sein alles ist. Aber eine Medaille gewinnen ist noch schöner. Ebenso ist es noch schöner beim Dojo, wenn man eine Lösung hat. Warum auch nicht. Wie die aussieht, ist ja mal eine zweite Frage. Auch da hilft Anleitung, um den TN Differenzierung nahezubringen.

      Gefällt mir

  4. Sebastian Keller 29. April 2013 um 9:11 Reply

    Ich habe selbst schon an einigen Dojos teilgenommen und habe viel Katas gemacht und gesehen (auch mit YouTube-Videos). Außerdem habe ich schon viele Dojos als (wie Daniel es nennt) Coach veranstaltet und Teilnehmer Katas im Pair machen lassen.

    Dabei habe ich festgestellt, dass zwei Dinge für mich entscheidend sind damit die Teilnehmer an einem Dojo oder an Katas in die richtige Richtung laufen und am Ende zufrieden sind.

    1. Zeige den Teilnehmern zuerst wie es gedacht ist. D.h. ich führe eine Kata vor. Danach oder auch mal mittendrin frage ich: „Was habt ihr beobachtet?“. Oft kommt dann: „Ich bin erstaunt, wie lange du im Refactoring-Schritt bleibst.“ Genau das ist einer der Ideen die ich vermitteln will. Design passiert im Refactoring-Schritt darum muss man hier richtig viel nachdenken. Den nächsten Test schreiben… einfach. Ihn grün machen… einfach. Produktiv- und Test-Code sauber machen und schön designen… das ist das spannende. Das Ziel für mich ist so schnell wie möglich grün zu werden um dann auf einem grünen Pfad zu Refaktorisieren bzw. zu designen. Man kann vielleicht sagen: Test-First ist Mittel um D mit einem Sicherheitsnetz zu machen :)

    2. Es sollte jemanden geben der den Moderator spielt. Für Katas sollte diese Person sich gut mit dem Fokus der Kata auskennen z.B. TDD oder die Programmiersprache damit er/sie den Teilnehmern helfen kann. Bei einem Kampfsporttraining kommt der Meister auch vorbei und erinnert immer wieder: „Rücken gerade! Knie gebeugt!…“
    Bei Dojos lasse ich die Teilnehmer gerne auch mal einfach in eine Richtung laufen, auch wenn sie vielleicht nicht gerade die Beste ist. Ich stoppe aber das Dojo nach ca. 15 Minuten und frage „Was ist passiert? Wo stehen wir gerade? Wo wollen wir hin? Was ist der nächste Schritt?“ Das führt die Teilnehmer oft wieder auf einen besseren Pfad und das Dojo kann weiter gehen.

    Ich habe den TDD 2.0 Artikel (noch) nicht gelesen. Wenn ich es aber richtig verstehe geht es u.a. darum sich vorher Gedanken zu machen bevor man mit dem ersten Test loslegt. Das finde ich sehr wichtig. Oft geht es schief wenn man einfach lostippt. Darum empfehle ich den Teilnehmern von Katas oder dem ersten Pair in einem Dojo sich zu überlegen: Was ist das Problem? Was sind die ersten 2-3 Testfälle? Das Design ist für mich dabei aber noch nicht wichtig. Vielleicht sagt jemand kurz wie die Methodensignatur aussieht aber das müssen wir uns ja eh gleich ausdenken wenn wir den ersten Test schreiben. Ich habe lieber etwas Code bevor ich mich über Design unterhalte. Dann hole ich auch gerne den Block heraus und male ein paar Kästchen und Pfeile um mir klarer zu werden, wo ich hinrefaktorisieren will.

    Wenn TDD 2.0 bedeutet, dass ich mir vorher über das Problem klar werde aber nicht über das Design finde ich das gut. Ich verstehe aber nicht warum es 2.0 heißen sollte. Dieses Vorgehen wird meiner Meinung nach schon in Kent Becks Buch vor 10 Jahren beschrieben.

    Gefällt mir

    • Ralf Westphal 29. April 2013 um 10:59 Reply

      @Sebastian: Wenn du in der Weise anleitend und moderierend durch ein Dojo führst, find ich das schon deutlich besser als das, was ich sonst meist sehe.

      Wie jedoch jemand auf die „ersten 2-3 Tesfälle“ kommt, ohne zumindest ein Mindestmaß an Design betrieben zu haben, verstehe ich nicht. Testfälle brauchen einen API, für den sie formuliert sind. Woher kommt der ohne Design?

      Also: Auch eine Methodensignatur ist schon Design. Wenn die Katas so trivial wie üblich sind, ist da natürlich nicht mehr zu leisten. Dann geht es mehr um das Design hinter der einen Funktion, die zu schreiben ist. (Wie irreal das im Vergleich zu Praxis ist, muss ich nicht betonen, denke ich. Da ist eine Aufgabenstellung nicht mit 1 Methodenaufruf abgetan.)

      Und dann? Das Coding soll beginnen, ohne eine Lösung? Das kann kaum sein, denn sonst gibt es keine Testfälle oder zumindest keine priorisierten Testfälle, die das Coding leiten. Das soll ja mit den Testfällen in kleinen Schritten von einfach zu komplizierter fortschreiten. Wie weiß ich aber, was einfacher und was komplizierter ist bei Testfällen jenseits des Trivialen? Das kann ich nur beurteilen, wenn ich eine Lösungsidee habe.

      Wenn die jedoch vorhanden ist, dann weiß ich auch automatisch schon etwas über das Design. Denn wenn das Design nicht den Lösungsansatz widerspiegelt, dann ist doch etwas falsch. Was wir brauchen ist „Screaming Design“ oder gar „Screaming Code“ (frei nach Bob Martin´s „Screaming Architecture“).

      Wieso sollte ich mich also beim Coden dümmer stellen als ich bin? Refactoring ist doch kein Selbstzweck. Mein Tag wird nicht produktiver durch mehr Refactoring. Ich bin für „code smart, not hard“. Ein Refactoring, das ich durch einen Moment Nachdenken hätte vermeiden können, ist ein schlechtes Refactoring.

      Aber wahrscheinlich sind die üblichen Code Katas einfach so klein, dass wir hier nicht zu einander kommen. Wer FizzBuzz mit TDD löst, der erzeugt ja nicht mal ein Design, das der Rede wert wäre. Wo am Ende 10 oder 20 Zeilen Code rauskommen, da kann ich an einem Algorithmus ein bisschen rumrefaktorisieren. Aber was ist gewonnen? Das ist alles irreal klein. Und wenn man dann vor richtigen Aufgaben steht… dann fühlt man sich wieder hilflos.

      TDD ist eine wichtige Praktik. Ohne Frage. Aber Kent Beck hat dazu nicht alles gesagt. Sein Buch ist immer noch lesenswert. Aber wenn daraus dann TDD Vorführungen werden, wie sie online überall zu sehen sind, dann weiß ich nicht, ob es gelesen wurde. Oder dann hilft wohl die Lektüre nicht. Und deshalb lohnt es, manches nochmal zu sagen, vielleicht pointierter. Dann tut etwas mehr explizite Struktur im Vorgehen gut. Die liefert TDD 2.0.

      Da ist nichts erfunden. Aber es ist etwas ausdrücklich gesagt, das oft ungesagt bleibt und deshalb unter den Tisch fällt. Von der Praktik „TDD as if you meant it“ mal ganz zu schweigen, die erst wirklich Druck auf das Refaktoring ausübt. Denn ansonsten ist das immer sehr optional. Kann man machen, muss man aber nicht.

      Gefällt mir

      • Sebastian Keller 29. April 2013 um 13:16 Reply

        @Ralf: Ich glaube die Angst die ich (und ich lese das auch auch bisschen bei Daniel) habe ist, dass Leute anfangen ein Problem „fertig“ zu designen mit Klassen, Interfaces, Methoden, Patterns, Algorithmen usw. und dann die Tests nachziehen. Die schwere Frage ist meiner Meinung nach: Wann höre ich mit dem initialen Designen auf? Oder wie viel vorheriges Designen brauche ich um auf eine gute Lösung zu kommen?

        Du schreibst: „Das Coding soll beginnen, ohne eine Lösung? Das kann kaum sein,…“ Das würde ich gerne besser verstehen. Speziell was du mit Lösung meinst. Ich versuche meine Tests möglichst fachlich zu beschreiben (also das Was) und ich verstehe unter einer Lösung das Wie. Und mit Wie meine ich wieder: Methoden, Klassen, Patterns, Algorithmen.

        Seitdem ich TDD mache habe ich interessante Dinge festgestellt. Wenn ich mir keine Gedanken über das Design am Anfang mache, komme ich oft im Refactoring Schritt zu einem Punkt wo ich mir Denke „Na da sieht man ja jetzt, dass eine Klasse raus will“ oder „Das sieht verdächtig nach einem typischen Problem aus, dass mit dem Design Pattern XY schön lösen könnte“. Ich glaube das hat auch Daniel mit Brain-On Modus gemeint. Ich finde es spannend, dass es möglich ist, dass Design auch während dem Programmieren entstehen kann bzw. mir der Code irgendwann sagt: „Willst du das jetzt wirklich _so_ lösen?“ Das setzt voraus, dass man ständig auf das verletzten von Design Prinzipien achtet und bedeutet für mich: Erst denken, dann Refaktorisieren.

        Ich glaube unsere Meinungen sind nicht so weit entfernt. Ich stimme dir zu und habe es oft genug beobachtet, dass auf das Refactoring und das Design viel zu wenig geachtet wird. Ich finde auch, dass man sich zu beginn Gedanken machen sollte. Und glaube, dass uns TDD als Werkzeug dabei hilft, dass wir Design-Entscheidungen während dem Programmieren treffen können, die wir dann auf einem Grünen-Pfad ausprobieren können.

        Gefällt mir

        • Ralf Westphal 29. April 2013 um 15:09 Reply

          Ich bin natürlich auch nicht dafür, „alles“ zuerst „fertig“ zu haben. Früher haben wir auch den Code schon auf Papier hingeschrieben, bevor wir ihn in einem Editor erfasst und übersetzt haben. Das war noch zu TTY Zeiten…

          Ne, ne, darum geht es nicht.

          Wenn ich sage, man solle einen Lösungsansatz haben, bevor man codiert, dann meine ich… tja, was eigentlich? Ich würd sagen: egal. Es ist egal, wie du den deutlich machst. Aber Code ist es nicht.

          Vielleicht ist der Lösungsansatz ein Zustanddiagramm. Vielleicht ist es ein Algorithmus in Pseudocode. Vielleicht ist es ein Flow-Design. Vielleicht ist es irgendeine andere Notation, die du dir ausdenkst. Erkennbar und erklärbar muss nur sein, wie du dir vorstellst, dass der Code nachher tut, was er tun muss. Nicht in jedem Detail, aber prinzipiell.

          Mir scheint, solche Beschreibungen herstellen zu können, fällt heute vielen schwer. Sie haben das nicht gelernt und nie geübt. Sie können nur eine Sprache sprechen: die des Codes.

          Das ist bedauerlich. Denn das ist leider die Sprache, mit der man am langsamsten spricht und deren „Texte“ am schwersten zu verändern sind. Refactoring und Tools lassen grüßen.

          Aber nehmen wir zwei Beispiele:

          Kata Word Wrap: Mein Lösungsansatz lautet:

          1. Brich eine Zeile vom Text ab.
          2. Korrigiere den Abbruch, falls dabei ein Wort zu Schaden gekommen ist.
          3. Füge die abgebrochene Zeile dem umgebrochenen Text hinzu.
          Verfahre mit dem restlichen Text wie vor beschrieben (Rekursion).

          Dafür muss ich nicht studiert haben. Das kriege ich durch ca. 7 bis 10 Minuten Nachdenken heraus. Und damit habe ich ein Grunddesign für die Lösung. Erstens weiß ich schon, dass das mit einer Rekursion wunderbar geht. (Worüber Bob Martin in seiner Demo erst stolpern muss.) Zweitens kenne ich schon Aspekte, die es geben muss – die ganz natürlich zu Funktionen werden.

          Diese Aspektfunktionen kann ich getrennt entwickeln. Deren Tests sind total simpel. Ich muss nämlich nicht mehr alles durch die eine Wurzelfunktion Wrap() testen. Auf die setze ich nur noch einen Integrationstest an. (Den kannst du auch Akzeptanztest nennen, wenn du willst.)

          Kata Roman Numerals: Mein Lösungsansatz enthält im Kern eine Map, die ganze Zahlen in römische „Ziffern“ übersetzt, z.B.

          10=X
          9=IX
          5=V
          4=IV
          1=I

          Der Algorithmus zur Übersetzung von n in eine römische Zahl lautet dann:

          1. Finde die größte Zahl z in der Map, die noch in n enthalten ist. (Für n=9 ist das 9, für n=8 ist das 5.)
          2. Füge die römische Ziffer für z dem Ergebnis hinzu.
          3. Verringere n um z.
          Verfahre mit dem verbliebenen n wie vor beschrieben (Rekursion).

          So eine Beschreibung kann ich kurz mit den Kollegen durchsprechen. Wir können das mit 2-3 Beispielen an einem Whiteboard tun. Dabei finden wir auch interessante Testfälle, z.B.

          10 = weil das eine Zahl in der Map ist
          6 = weil das eine Zahl ist, die nicht in der Map steht
          16=weil das eine Zahl ist, die aus 3 „Ziffern“ zusammengesetzt ist

          Und sonst? Nix. Der Rest ergibt sich aus Induktion, würd ich sagen :-)

          Diese Testfälle kann ich nur als interessant festlegen, weil (!) ich einen Lösungsansatz habe. Habe ich den nicht, dann stochere ich herum. Dann finde ich vielleicht n=4 interessant, weil die römische „Ziffer“ aus zwei Zeichen besteht.

          Auch hier gibt mir der Lösungsansatz ein Grunddesign vor. Ich sehe 3 Aspekte und eine Rekursion. Dafür muss ich keine Zeile Code geschrieben haben.

          Und das ist gut so, denn dann muss ich nicht allein vor meiner IDE schlau sein, sondern kann im Team diesen Lösungsansatz finden.

          Für jeden Aspekt kann ich mir wieder überlegen, was Testfälle sind:

          Test 1.1: Zahl in Map
          Test 1.2: Zahl nicht in Map
          Test 2: haha ;-)
          Test 3: haha ;-)

          Dazu kommen die Integrationstests, die auch die Rekursion prüfen.

          Nun sagt mir bitte, ob ich hier spekuliert habe. Wenn ja, dann leben wir in verschiedenen Welten. Dann bin ich vielleicht schrullig und starrköpfig oder gehöre einfach zum alten Eisen, weil ich das mal vor knapp 30 Jahren so gelernt habe.
          Wenn nein, dann haben wir etwas gemeisam. Nur verstehe ich nicht, was ihr den Teilnehmern eines Dojos ersparen wollt. Was sie nicht üben sollen, weil sie sich dringend auf etwas anderes konzentrieren sollen.

          Zuviele Gedanken über Design sind auch nicht gut. Klar. Aber zu wenige ebenfalls nicht.

          Meine Vermutung ist, dass TDD auch ein Folgeproblem löst. Mit TDD soll versucht werden, das Problem der premature optimization der Objektorientierung zu kompensieren. Die startet nämlich oft mit Phantasieklassen, die am Ende niemand braucht.

          Klar, wer so arbeitet, der sollte zurückrudern und kleinere Schritte tun. Aber ich arbeite so schon lange nicht mehr. Für mich entstehen Klassen durch Abstraktion, wenn sie nötig werden. Dafür brauche ich aber eher kein TDD – sondern muss nur nicht mehr nach alter Väter Sitte objektorientiert denken.

          Gefällt mir

          • Sebastian Keller 29. April 2013 um 16:26 Reply

            @Rolf: Speziell die letzten 3 Absätze passen mit meiner Meinung und meinem Gefühl zu Design und TDD super zusammen.

            Spannend finde ich auch deine Beschreibung der Katas. Ich gehe da anders vor. Um auf die Testfälle von z.B. der RomanNumbers-Kata zu kommen bespreche ich bei einem Dojo die (ich nenne sie mal) „Konzepte“ des Problems, hier die Römischen Zahlen. Es gibt einzelne Zahlen „I“, „V“ usw. Es gibt additive Zahlen „II“, „VI“… und es gibt subtraktive Zahlen „IV“, „IX“. Das sind für mich 3 Konzepte. Gibt es noch Sonderfälle? Nun ja die 0 vielleicht und alles was kleiner ist. Ich habe somit 4 Möglichkeiten mit meinen Tests anzufangen:
            * Literal(e),
            * additive Zahlen,
            * subtraktive Zahlen und
            * Sonderfälle.

            Über das Wie mache ich mir keine Gedanken.

            Dann frage ich welches der Konzepte am einfachsten klingt. Somit beginnen wir mit einem Literal. Schnell kommen wir zu einer Lösung wie deine Map. If then else-if mit Konstanten ist ein mapping und schreit nach einer Map und das merkt man schon nach dem „V“. Ein X alleine ist dann nicht so spannend. Addition ist dann spannend und klingt einfacher als subtraktion.

            I, II, III

            Rekursion?… hm irgendwie schon aber wo? Welcher Test kann mir helfen? XV Aha!

            Das steht also in meinem Code und der Code schreit nach Rekursion:
            I + „“
            I + I
            I + II
            X + V also muss die Rekursion nach hinten.

            usw.

            Ich habe versucht mich zu erinnern wie ich das erste mal diese Kata gemacht habe. Ich hab an die Rekursion nicht gedacht. Wenn mir jemand gesagt hätte, das es mit „Rekursion“ geht hätte ich sie sicher schnell gefunden. Map hatte ich auch nicht im Kopf aber schnell gemerkt, dass ich sowas brauche und der Code dann viel besser ausschaut.

            Wenn ich mir sowas wie die Stack Kata anschaue (die nicht so algorithmisch ist) gehe ich ähnlich vor. Was gibt es für Konzepte push und pop, isEmpty, Underflow und ggf. Overflow. Das sind für mich 3 Konzepte: Queries, Commands und Sonderfälle. Gut „pop“ ist irgendwie ein Query-Command. Klingt kompliziert. Damit fange ich nicht an. Queries klingen doch einfach. Dann sind meine Tests
            * empty Stack is empty
            * after push stack is not empty
            * after push and pop stack is empty
            * pop after push returns the pushed object
            * two pushes pops LIFO
            * pop on empty stack throws Underflow Exception

            Mich vorher hinzusetzen und mir über die Lösung Gedanken zu machen ist wie du ja schon gesagt hast bei solchen Beispielen trivial. Bei komplizierteren Beispielen die sich in meine bestehende Anwendung auch noch irgendwie Integrieren muss tue ich mir oft schwer vorher auf eine gute Lösung zu kommen. Ich kann mich hinsetzen und mir eine Design überlegen aber auf die coolen kleinen Lösungen komme ich erst, wenn ich TDD mache und mitten im Code bin.

            Ganz nach dem TDD-Pattern „obvious implementation“ ist das eine Frage der Schrittgröße und was ich mir zutraue.

            Gefällt mir

            • Ralf Westphal 29. April 2013 um 19:04 Reply

              Tja, schon spannend…

              Die Testfälle mit den „additiven“ und „subtraktiven“ Zahlen sind natürlich Akzeptanztests. Du hast keine Ahnung, wie es funktioniert, aber du siehst halt interessante Muster. Ob die in der Implementation überhaupt einen Unterschied machen… Du weißt es nicht. („V“ und „IV“ machen ja z.B. bei meinem Lösungsansatz keinen Unterschied.) Du stellst dich dumm wie ein Anwender, der einfach nur ein paar wichtige Fälle abgedeckt wissen will, um Vertrauen in die Lösung zu gewinnen.

              Und dann gehst du schon an die Implementation.

              Kann man machen. Muss man aber nicht ;-)

              Das ist ja mein Punkt. Müssen wir wohl so stehenlassen. Du machst das so. Es wird so allerorten promotet. Ich tue es nicht. Ich erlaube mir, hinter diese Muster zu schauen und über eine Lösung nachzudenken.

              Die finde ich in 5 Minuten – und bin mir sicher, dass du per TDD länger brauchst. Und nicht nur das. Da du sie per TDD findest, kannst nur du sie finden. Du allein sitzt vor der IDE. Ein Team kann dir dabei nicht helfen. Ich hingegen denke ja öffentlich darüber am Whiteboard nach, mit dem Team. Da ist kollektive Intelligenz am Werk. Hoffentlich ;-)

              Und dann siehst du die Rekursion gar nicht oder erst bei „X + V“? Du bist überrascht. Für mich unterscheidet sich „I + I“ aber nicht von „X + V“.

              Um diese Überraschung geht es mir auch. Die passiert immer mal wieder. Aber ich halte es für Zeitverschwendung, sich da überraschen zu lassen, wenn man es vermeiden kann. Das kann man aber nur wissen, wenn man dem Denken vor dem Codieren Raum gibt.

              Gerade bei der Kata Roman Numerals habe ich es erlebt: 10 Teams bei einem Dojo am Werk. Und keines (!) hat die Aufgabe gelöst. Dass auch nur eines etwas Dolles angesichts dieser Miniaufgabe im Hinblick auf TDD gelernt haben sollte, verneine ich mal.

              Dito bei einem Dojo zum Thema „Zeckendorf-Sequenz“ (http://de.wikibooks.org/wiki/Aufgabensammlung_Programmierung/_Zeckendorf-Sequenz).

              Wer keine Lösungsidee hat, stochert im Nebel herum. Dass die Lösung aber nicht auf dem Tisch liegt wie bei FizzBuzz ist doch normal. Deshalb sind solche Katas so irreal. Die kann man einmal machen – und dann weitergehen zu realerem Zeugs. Aber dann muss man auch den Modus ändern.

              Kata Stack: Auch schön. Ist mal etwas anderes, weil es da um Zustandshaltung geht. Nur Problemlösung muss man da auch nicht betreiben. Der API ist klar. Die Lösung ist klar. Jetzt ein bisschen tüfteln, ob alles nur durch den API getestet werden darf oder auch anders. Nett. Nur, bitte, weit von der Realität entfernt.

              Du sagst, bei komplizierteren Aufgaben tust du dich schwer, vorher auf „die Lösung“ zu kommen. Das kann ich verstehen. Damit sprichst du ja vielen Entwicklern aus der Seele.

              Ich halte nur den Schluss für falsch, es dann nicht zu versuchen, sondern besser mal mit dem Code zu beginnen.

              Der Weg ist da, wo der Schmerz ist – heißt es ;-) Warum also nicht mal überlegen, warum das Überlegen so schwer ist? Irgendwann muss man damit natürlich aufhören. Nur gar nicht zu beginnen, halte ich für… nun, unökonomisch.

              Früher wurde gelehrt, Probleme zu lösen. In anderen Disziplinen wird das immer noch gelehrt. In der „Programmierausbildung“ ist das Thema aber seltsam abwesend. Oder gar nicht seltsam. Wo soll es denn auch adressiert werden in der Ausbildung „Anwendungsentwickler Fachinformatiker“ oder beim Autodidakten? Alle kümmern sich um Technologien und Technologien und Technologien. Noch eine Tool, noch ein API, noch ein Framework. Das alles ist viel handfester und scheinbar wichtiger als… ein bisschen Nachdenken.

              Und dann kommt TDD daher und sagt: „Brauchste auch gar nicht!“ Wie genial! Dann mal los.

              Aber das ist erstens falsch verstanden – weil Kent Beck es nicht so gesagt hat. Sondern für den ist Nachdenken ganz selbstverständlich. Und ich bin mir sicher, auch für Bob Martin ist es selbstverständlich. Die tun es auch – nur zeigen sie es nicht. Oder nur ganz, ganz selten wie Bob Martin hier: http://de.slideshare.net/lalitkale/bowling-game-kata-by-robert-c-martin – Das nennt er dann „Design Session“ macht aber eigentlich nur eine Analyse, weil er am Ende die bildlichen Artefakte nicht so handfest im Code auftauchen.

              Zum Thema „Nachdenken“ gibt es im Grunde nichts. Keine Beispiele. Es wird entweder nicht nachgedacht, weil das Problem wirklich trivial ist. Oder es wurde nachgedacht, doch man versteckt das und tut bei der Implementation überrascht. Oder man hat so lange drüber nachgedacht, dass man ein dolles großes Ding zaubert: BDUF.

              GOOS macht da in gewisser Weise eine löbliche Ausnahme. Wirklich nachvollziehbar finde ich es am Ende aber doch nicht. Viel Code, viel Gerede (Worte) – aber keine einfach nachzuvollziehende Entwickler im Bild. Denn nur da können Strukturen ja übersichtlich vermittelt werden. Und auch keine skalierbare Methode. Denn TDD skaliert nicht. Die Software, die sie da bauen, kann nur einer so bauen. Es gibt keinen Hinweis, wie man mit mehreren Leuten gleichzeitig das Projekt hätten vorantreiben können. (Geht ja auch nicht, weil das Design durch TDD entsteht.)

              Du siehst: Ich bin kein Gegner von TDD 1.0. Aber es ist für mich zu wenig. Es kommen zu selten und zu wenig reproduzierbare Ergebnisse dabei heraus. Und der Aufwand ist hoch für das erreichte Design. Ich möchte fast sagen, TDD erzeugt vorzeitig optimierte Designs. Es ginge mir weniger „eleganten“, dafür aber schneller hingelegten und besser lesbaren auch.

              Deshalb: TDD 2.0. Um es mehr Entwicklern leichter zu machen durch mehr Anleitung als Teil der Methode.

              Gefällt mir

  5. Anonymous 29. April 2013 um 20:12 Reply

    „Ein Refactoring, das ich durch einen Moment Nachdenken hätte vermeiden können, ist ein schlechtes Refactoring.“

    Warum?

    Ich vermute wir sind uns einig, dass ein gutes Design es wert ist, darin zu investieren. Nach meiner Erfahrung entstehen durch gekonntes Refactoring die besseren Designs.

    Und meine Erfahrung aus Dojos ist, dass viele Entwickler zwar Code lesen und schreiben können, aber keine Code Smells erkennen, oder nicht wissen, wie man auf sie reagiert. Und das lernen sie nur durch am Code arbeiten.

    Gefällt mir

    • Ralf Westphal 29. April 2013 um 20:21 Reply

      Wenn ich durch 30 Sekunden Nachdenken herausbekommen kann, dass eine Funktion f() zwei Aspekte a1 und a2 hat, dann weiß ich, dass diese Aspekte auch im Code ausgedrückt werden sollten. Es sollte also zwei Funktionen a1() und a2() geben.

      Sowas kommt bei TDD 1.0 eventuell raus. Sowas kommt bei TDD 2.0 bei der Codierung ganz sicher heraus (weil darin mit „TDD as if you meant it“ gearbeitet wird).

      Aber sowas muss ich nicht unbedingt durch Codieren und dann Refaktorisieren erst mühsam „passieren lassen“, sondern kann es eben vorher wissen. Nicht immer – aber immer öfter, wenn ich mir mal etwas Nachdenken erlaube.

      Diese Funktionen a1() und a2() dann nicht von vornherein anzulegen und auch direkt zu testen, ist – wie soll ich sagen – mindestens unökonomisch bis fahrlässig.

      Refactoring ist kein Selbstzweck. Das kostet Zeit. Das kostet Geld meines Kunden. Wenn ich ihm das ersparen kann… dann wunderbar.

      Zum vorherzusehenden Einwand, dass durch Nachdenken doch kein optimales Design entstehen könne: Mag sein. Vielleicht. Aber wer sagt denn, dass optimales Design überhaupt wünschenswert ist in einer Welt widerstreitender Werte?

      Gutes Design (Evolvierbarkeit) in Balance mit guter Performance in Balance mit Produktionseffizienz in Balance mit… whatever: das zeichnet Proficode aus.

      Insofern bin ich für „good enough“ Design, wenn es denn einige Mindestanforderungen erfüllt. Deshalb kann ich offen dafür sein, nicht TDD benutzen zu müssen, wenn es zu langsam ist, um zu diesem „good enough“ Design zu kommen. Denn perfekt… kommt sowieso nie dabei heraus. (Und das ist ja auch offensichtlich, denn perfekt als Superlativ lässt keine Alternativen zu. Im Internet sind aber alle Code Katas auf ganz unterschiedliche Weise mit TDD schon gelöst worden. Das bedeutet, keines der Designs kann perfekt sein. Und wenn das so ist, dann kann ich zu imperfekten Design durchaus auch auf anderem Wege kommen – insbesondere wenn es schneller geht.)

      Gefällt mir

  6. Carsten 1. Mai 2013 um 7:37 Reply

    Interessant finde ich im Artikel die Aussage:

    „Deshalb haben wir bei unseren Coding Dojos die Anregungen aufgegriffen und implementiert. Interessanterweise, was ich persönlich als sehr positiv empfinde, gab es im ersten Dojo mit dem neuen Verfahren keine einzige Codezeile, da eine Stunde lang das Problem eruiert und Begrifflichkeiten diskutiert wurden“

    Keinen Code zu produzieren, scheint wieder an Wert zu gewinnen. Welcome to the 90ies.

    Gefällt mir

  7. […] TDD 2.0 […]

    Gefällt mir

Schreibe einen Kommentar

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s

%d Bloggern gefällt das: