Was sind die Nachteile der Test-First-Programmierung?

47

Es ist heutzutage der letzte Schrei. "Jeder" empfiehlt es. Das an und für sich macht mich misstrauisch.

Welche Nachteile haben Sie bei der ersten (testgetriebenen) Entwicklung festgestellt? Ich suche nach persönlichen Erfahrungen von sachkundigen Praktikern - ich kann die hypothetischen Überlegungen von hundert Möchtegern an anderer Stelle im Internet lesen.

Ich frage nicht, weil ich TDD hassen möchte, sondern weil es meine Aufgabe ist, den Softwareentwicklungsprozess zu verbessern. Je mehr wir über die Probleme der Menschen erfahren können, desto größer ist die Chance, dass wir den Prozess verbessern.

Alex Feinman
quelle

Antworten:

41

Es gibt einige, aber die Vorteile überwiegen bei weitem die Nachteile.

Es gibt eine steile Lernkurve.

Viele Entwickler scheinen zu erwarten, dass sie mit der Erstprogrammierung vom ersten Tag an effizient arbeiten können. Leider braucht es viel Zeit, um im gleichen Tempo wie bisher Erfahrungen zu sammeln und zu programmieren. Sie können es nicht umgehen.

Genauer gesagt ist es sehr leicht, sich zu irren. Sie können sehr leicht (mit sehr guten Absichten) eine ganze Reihe von Tests schreiben, die entweder schwierig zu pflegen sind oder die das falsche Zeug testen. Es ist schwierig, hier Beispiele zu nennen. Solche Probleme lassen sich nur mit Erfahrung lösen. Sie müssen ein gutes Gespür für das Trennen von Bedenken und das Entwerfen für die Testbarkeit haben. Mein bester Rat wäre, mit jemandem zu programmieren, der TDD wirklich gut kennt.

Du machst vorne mehr Codierung.

Test-first bedeutet, dass Sie keine Tests überspringen können (was gut ist) und dass Sie am Ende mehr Code schreiben werden. Das bedeutet mehr Zeit. Auch hier kann man nicht umgehen. Sie werden mit Code belohnt, der einfacher zu warten, zu erweitern und im Allgemeinen weniger Fehler enthält, der jedoch einige Zeit in Anspruch nimmt.

Kann für Manager ein schwerer Verkauf sein.

Software-Manager beschäftigen sich in der Regel nur mit Zeitplänen. Wenn Sie zu Test-First-Programmierung wechseln und plötzlich 2 Wochen brauchen, um eine Funktion anstelle einer zu vervollständigen, wird es ihnen nicht gefallen. Dies ist definitiv ein Kampf, den es wert ist, gekämpft zu werden, und viele Manager sind aufgeklärt genug, um ihn zu bekommen, aber es kann ein harter Verkauf sein.

Kann ein schwerer Verkauf an andere Entwickler sein.

Da es eine steile Lernkurve gibt, mögen nicht alle Entwickler die Erstprogrammierung. Tatsächlich würde ich vermuten, dass es den meisten Entwicklern zunächst nicht gefällt. Du kannst Dinge wie Pair-Programming machen, um sie auf den neuesten Stand zu bringen, aber es kann schwierig werden.

Am Ende überwiegen die Vorteile die Nachteile, aber es hilft nichts, wenn Sie die Nachteile einfach ignorieren. Wenn Sie von Anfang an wissen, womit Sie es zu tun haben, können Sie einige, wenn nicht alle Nachteile aushandeln.

Jaco Pretorius
quelle
Das sind gute Antworten, aber könnte es spezifischer um # 1 gehen? Ich bin besonders daran interessiert zu hören, wie / ob Sie Ihre Programmiergeschwindigkeit wiederherstellen konnten - was haben Sie erfahren, dass Sie nicht wussten, als Sie mit TDD begannen?
Alex Feinman
Zur Klarstellung aktualisiert
Jaco Pretorius
7
Wenn Sie jetzt testen, sollte sich die Gesamtzeit für die Entwicklung nicht wesentlich ändern. Es sieht nur so aus, als ob die Dinge länger dauern, weil Sie die Zeit beanspruchen, die zum Schreiben und Verwalten von Komponententests erforderlich ist.
ChrisF
1
@JeffO kennst du das "Ich werde mir einen Minivan schreiben!" Schule der Codierung?
Alex Feinman
1
@tvanfosson - weil sie versuchen, zwei Dinge gleichzeitig zu ändern - sowohl das Starten von Tests als auch TDD - was problematisch sein kann. Es erhöht auch die Zeitschätzung - ganz richtig - so dass Manager und Kunden nur den Anstieg im Voraus sehen, nicht, dass die Gesamtzeit tatsächlich (ausnahmsweise) bekannt ist und möglicherweise sogar kürzer ist. Wenn sie einige Tests durchführen, wird diese Zunahme geringer sein.
ChrisF
35

Test-first setzt voraus, dass Sie folgenden Code schreiben:

  • im Unit-Test prüfbar
  • Das, was Sie entwickeln, hat einen offensichtlichen Ansatz und erfordert kein umfangreiches Prototyping oder Experimentieren
  • dass Sie nicht zu stark umgestalten müssen oder die Zeit haben, Hunderte oder Tausende von Testfällen wiederholt umzuschreiben
  • nichts ist versiegelt
  • alles ist modular aufgebaut
  • alles ist injizierbar oder verspottbar
  • dass Ihre Organisation niedrigen Fehlern einen ausreichend hohen Stellenwert beimisst, um die Ressourcensenke zu rechtfertigen
  • dass es von Vorteil ist, auf einem Unit-Test-Level zu testen

Wenn Ihr Projekt diese Anforderungen nicht erfüllt, werden Sie Schwierigkeiten haben. Die Veranstalter von TDD haben keine guten Antworten darauf, was darauf hindeutet, dass Sie Ihr Produkt neu designen, um besser in diese Linien zu fallen. Es gibt Situationen, in denen dies unmöglich oder unerwünscht ist.

In der Praxis kann es auch ein großes Problem für mich sein, wenn Leute denken, dass die Test-First-Tests tatsächlich irgendetwas über die korrekte Funktion des Programms beweisen. In vielen Fällen ist dies nicht der Fall, aber selbst in den Fällen, in denen dies der Fall ist, ist dies alles andere als ein vollständiges Bild der Richtigkeit. Die Leute sehen Hunderte von bestandenen Tests und gehen davon aus, dass es sicher ist, weniger zu testen, da sie vor TDD sowieso nur ein paar Hundert Testfälle durchgeführt haben. Nach meiner Erfahrung bedeutet TDD, dass Sie noch mehr Integrationstests benötigen, da die Entwickler auch die falsche Sicherheit und den Schmerz haben, alle Tests zu ändern, um einen großen Redaktor zu erstellen. Dies kann Entwickler zu interessanten Workarounds führen.

Beispiele:

Mein persönliches bestes Beispiel ist das Schreiben von Sicherheitscode für asp.net. Wenn sie in einer feindlichen Umgebung in der Maschinenkonfiguration ausgeführt werden sollen, werden sie gestrichen, signiert und versiegelt, und da sie auf IIS-Gott-Objekten ausgeführt werden, ist es sehr schwierig, sehr viel richtig zu verspotten. Fügen Sie einige Einschränkungen für die Leistung und die Speichernutzung hinzu, und Sie verlieren sehr schnell die Flexibilität, Platzhalterobjekte in den verbleibenden Bereichen zu verwenden.

Jede Art von Mikrocontroller oder anderer ressourcenarmer Umgebungscode ist möglicherweise nicht für ein echtes Design im OO-Stil geeignet, da die Abstraktionen nicht optimiert werden und Sie über niedrige Ressourcenbeschränkungen verfügen. Dasselbe gilt in vielen Fällen auch für Hochleistungsroutinen.

Rechnung
quelle
Können Sie ein paar Gegenbeispiele geben? Wann würde ich nicht etwas schreiben, das sich im Unit-Test testen lässt? Warum würde ich keinen Code schreiben, der verspottbar oder injizierbar ist (anders als Legacy-Code, der ein Thema für sich ist)?
Alex Feinman
bearbeitet, um Beispiele hinzuzufügen
Bill
4
Einverstanden. Die Arbeit mit TDD scheint von einer Reihe von Annahmen über die Maschinen abhängig zu sein, mit denen Sie arbeiten. es scheint nicht für ungefähr 50% meiner Projekte zu gelten.
Paul Nathan
Ich stimme voll und ganz zu ... Tolle Antwort
Khelben
2
Es ist wie alles in diesem Spiel - passend für viele Situationen, ungeeignet für andere. Hüten Sie sich vor Personen, die in einem beliebigen Bereich der Softwareentwicklung einen One True Path befürworten .
Alan B
25

Der größte Nachteil, den ich gesehen habe, ist nicht bei TDD selbst, sondern bei Praktizierenden. Sie verfolgen einen dogmatischen und eifrigen Ansatz, bei dem alles auf die Probe gestellt werden muss . Manchmal (oft) ist das nicht nötig. Dies ist möglicherweise auch nicht praktikabel (z. B. Einführung einer Organisation in TDD).

Ein guter Ingenieur findet Kompromisse und wendet die richtige Balance zwischen dem Zeitpunkt, dem Ort und dem Verfahren an, bei dem der Test zuerst angewendet wird. Wenn Sie ständig mehr Zeit mit der Entwicklung von Tests verbringen als mit dem eigentlichen Code (um den Faktor 2-3 oder mehr), sind Sie in Schwierigkeiten.

Mit anderen Worten, sei pragmatisch und vernünftig mit TDD (oder irgendetwas in der Softwareentwicklung für diese Angelegenheit.)

luis.espinal
quelle
Ist das vielleicht der Ursprung der "neuen" Definition des Legacy-Codes (dh "Code ohne Tests") von Michael Feathers?
Phill W.
Diese Definition würde für mich nicht funktionieren :) Für mich ist jeder Code, der in der Produktion ausgeführt wird und der geändert werden muss, Legacy-Code, unabhängig von Code oder Testqualität. Wir assoziieren "Legacy-Code" normalerweise mit "fehlerhaftem Code" oder "veraltetem Code", wenn in Wirklichkeit fehlerhafter Code und veralteter Code bereits in Code vorhanden sind, der sich in der Entwicklung befindet und dessen Produktion noch nicht genutzt wurde. Unser Ziel sollte es sein, dass unser Code von Anfang an ein Vermächtnis ist und von solcher Qualität und Nützlichkeit ist, dass er jahrelang, jahrzehntelang in Gebrauch bleibt.
Luis.espinal
6

Ich habe Anfang August 2009 mit TDD begonnen und mein gesamtes Unternehmen überzeugt, im September / Oktober 2009 zu TDD zu wechseln. Derzeit ist das gesamte Entwicklerteam vollständig konvertiert, und das Festschreiben von nicht getestetem Code für das Repo wird als eine schlechte Sache angesehen und als problematisch eingestuft. Es hat für uns großartig funktioniert und ich kann mir nicht vorstellen, wieder auf Cowboy-Codierung umzusteigen.

Es gibt jedoch zwei Probleme, die ziemlich auffällig sind.

Die Testsuite muss gewartet werden

Wenn Sie TDD ernst meinen, werden Sie am Ende viele Tests schreiben . Darüber hinaus braucht es einige Zeit und Erfahrung, um die richtige Granularität der Tests zu erkennen (Übertreiben ist fast so schlimm wie Untertreiben). Diese Tests sind ebenfalls Code und für Bitrot anfällig. Dies bedeutet, dass Sie sie wie alles andere pflegen müssen: Aktualisieren Sie sie, wenn Sie Bibliotheken aktualisieren, von denen sie abhängen, und ändern Sie von Zeit zu Zeit die Einstellungen sogar schlicht falsch. Wenn Sie Glück haben, können Sie sie einfach löschen. Oft werden Sie jedoch die nützlichen Teile extrahieren und an die neue Architektur anpassen.

Das Testen von Abstraktionen läuft von Zeit zu Zeit aus

Wir verwenden Django, das ein ziemlich gutes Test-Framework hat. Manchmal werden jedoch Annahmen getroffen, die leicht im Widerspruch zur Realität stehen. Beispielsweise kann eine Middleware die Tests unterbrechen. Einige Tests gehen von einem Caching-Backend aus. Wenn Sie eine "echte" Datenbank (nicht SQLite3) verwenden, wird die Vorbereitung der Datenbank für die Tests viel Zeit in Anspruch nehmen. Sicher, Sie können (und sollten) SQLite3 und eine In-Memory-Datenbank für Tests verwenden, die Sie lokal durchführen. Einige Codes verhalten sich jedoch je nach verwendeter Datenbank anders. Die Einrichtung eines Continuous Integration Servers, der in einer realistischen Konfiguration ausgeführt wird, ist ein Muss.

(Einige Leute werden Ihnen sagen, dass Sie alle Dinge wie die Datenbank verspotten sollten, oder Ihre Tests sind nicht "rein", aber das ist nur eine ideologische Aussage. Wenn Sie Fehler in Ihrem Verspottungscode machen (und glauben Sie mir, das werden Sie), Ihre Testsuite wird wertlos sein.)

Die beschriebenen Probleme machen sich jedoch erst bemerkbar, wenn Sie mit TDD weit fortgeschritten sind ... Wenn Sie gerade erst mit TDD beginnen (oder an kleineren Projekten arbeiten), ist das Umgestalten von Tests kein Problem.

Ryszard Szopa
quelle
3
+1. "muss gepflegt werden": Dies ist weitaus weniger ein Problem beim Testen von wiederverwendbarem Code, da seine Schnittstelle und sein Verhalten normalerweise stabil sein müssen. Aus diesem Grund mache ich normalerweise nur TDD für unsere wiederverwendbare Bibliothek.
Dimitri C.
4

Für mich gibt es ein tiefes psychologisches Problem mit Tests, wenn ich versuche, sie ausgiebig anzuwenden, wie bei TDD: Wenn sie vorhanden sind, codiere ich schlampig, weil ich darauf vertraue, dass die Tests Probleme aufdecken werden. Aber wenn es keine Tests gibt, um ein Sicherheitsnetz bereitzustellen, codiere ich sorgfältig, und das Ergebnis ist ausnahmslos besser als bei Tests.

Vielleicht bin es nur ich. Aber ich habe auch irgendwo gelesen, dass Autos mit allen möglichen Sicherheitsmechanismen häufiger abstürzen (weil die Fahrer wissen, dass die Sicherheitsmerkmale vorhanden sind). TDD kann mit einigen Personen nicht kompatibel sein.

Joonas Pulakka
quelle
Das kommt mir merkwürdig vor, da ich durch das Schreiben von testbarem Code in der Regel langsamer werde und mehr darüber nachdenke, was ich codiere. Ich bekomme heutzutage tatsächlich ein bisschen nervöses Programmieren ohne Tests.
Matt H
1
Es zeigt nur, dass verschiedene Menschen tatsächlich unterschiedlich reagieren. Ich schlage TDD nicht - offensichtlich finden es nicht wenige nützlich -, aber die Tatsache ist, dass es nicht für jedermann geeignet ist.
Joonas Pulakka
2
Ich stimme zu 100% zu%. Ich schreibe Code besser und schneller ohne automatisierte Tests. Natürlich wäre es absurd, nicht zu testen, ich denke nur, Automatisierung ist eine schlechte Wahl (zumindest für mich). Ich finde manuelle Tests sowohl schneller als die Wartung einer Testsuite als auch sicherer - aber ich bin auch ein erfahrener Entwickler, daher weiß ich sehr gut, was zu testen ist und wo und warum Regressionsfrei.
Ben Lee
1
Obwohl ich darauf hinweisen sollte, dass sowohl das Team, mit dem ich zusammenarbeite, als auch die Projekte so klein sind, dass ich ein gutes Gefühl für die gesamte Architektur habe - in einem großen Team oder in einem sehr großen Projekt -, könnte ich automatisierte Tests als nützlicher ansehen, weil dann würde kein einzelner Entwickler notwendigerweise riechen können, wo er testen sollte, um Regressionen zu vermeiden.
Ben Lee
Lassen Sie den Refactoring-Schritt aus?
rjnilsson
2

Eine Situation, in der mir Test-First wirklich im Weg steht, ist, wenn ich schnell eine Idee ausprobieren und prüfen möchte, ob es funktionieren kann, bevor ich eine ordnungsgemäße Implementierung schreibe.

Mein Ansatz ist normalerweise:

  1. Implementieren Sie etwas, das ausgeführt wird (Proof of Concept).
  2. Wenn es funktioniert, konsolidieren Sie es durch Hinzufügen von Tests, Verbessern des Designs und Umgestalten.

Manchmal komme ich nicht zu Schritt 2.

In diesem Fall hat TDD für mich mehr Nachteile als Vorteile:

  • Das Schreiben von Tests während der Implementierung des Proof of Concept verlangsamt mich nur und unterbricht meinen Gedankenfluss: Ich möchte eine Idee verstehen und keine Zeit damit verschwenden, Details meiner ersten groben Implementierung zu testen.
  • Es kann länger dauern, um herauszufinden, ob meine Idee etwas wert ist oder nicht.
  • Wenn sich herausstellt, dass die Idee unbrauchbar war, muss ich sowohl meinen Code als auch meine schön geschriebenen Komponententests wegwerfen.

Wenn ich also einige neue Ideen erforschen muss, verwende ich kein TDD und führe Unit-Tests nur dann ein, wenn ich das Gefühl habe, dass der neue Code irgendwo ankommt.

Giorgio
quelle
1
Es hört sich so an, als würden Sie Prototypcode mit verwendbarem Code verwechseln. Der Prototypcode ist ein Testcode . Es muss nicht getestet werden, und Sie sollten keine Tests erstellen, die dagegen ausgeführt werden. Der Schritt, den Sie vermissen, liegt zwischen 1. und 2. Sie sagen "Konsolidieren durch Schreiben von Tests". Das Problem ist, dass Sie nicht etwas zu konsolidieren haben, sondern etwas zu schreiben. Planen Sie , den Prototypcode umzuschreiben, und nicht, ihn erneut zu verwenden. Die Wiederverwendung bietet viel Platz für Kompromisse. Das Umschreiben formalisiert die Aufteilung zwischen Ihrer Explorationsphase und Ihrer "Qualitätscode" -Phase.
utnapistim
3
@utnapistim: Ich verwechsle Prototypcode nicht mit verwendbarem Code, sondern TDD-Eiferer verwechseln sie und schlagen vor, TDD auch für Prototypcode zu verwenden. Oder vielmehr, sie gehen davon aus, dass es überhaupt keinen Prototypcode gibt. Ich stimme Ihnen auch zu, dass Sie häufig Änderungen vornehmen müssen, wenn Sie vom Prototyp zur tatsächlichen Implementierung übergehen. Manchmal können Sie Teile des Prototypcodes wiederverwenden, aber Sie müssen bereit sein, den Code umzuschreiben. Sie müssen sich wirklich von Fall zu Fall entscheiden.
Giorgio
3
@utnapistim: Siehe auch die Antwort von luis.espinal: "Der größte Nachteil, den ich gesehen habe, ist nicht die TDD selbst, sondern die der Praktiker. Sie verfolgen einen dogmatischen und eifrigen Ansatz, bei dem alles auf den Prüfstand gestellt werden muss."
Giorgio
1

Nachteile oder Kosten von TDD

Hinweis: Es gibt verschiedene Arten von TDDs. Unabhängig von Einheit, BDD, ATDD oder anderen Varianten bleiben viele der Schwierigkeiten bestehen

Nebenwirkungen

Unabhängig davon, ob es sich um Verspottungen, Fixtures oder Funktionstests handelt, sind Abhängigkeiten von externen Zuständen oder Systemen häufig die Ursache für die größte Komplexität bei Tests, Unklarheiten bei der Testdurchführung und das größte Risiko, Fehler zu machen. Einige Probleme, die ich gesehen habe:

  • Verspotten: Vergessen Sie, die Reihenfolge der Anrufe zu bestätigen
  • Verspotten: Die Verspottung stimmt nicht mit dem tatsächlichen Anruf oder der tatsächlichen Antwort überein
  • Fixture: Test basiert auf unrealistischen Daten, die andere Probleme maskieren
  • Vorrichtung: Testen Sie einen unmöglichen Zustand in der Produktion
  • Funktionell: Falsche Build-Unterbrechungen, da abhängiges System vorübergehend nicht verfügbar ist
  • Funktionell: Testgeschwindigkeit ist sehr langsam

Sie müssen Ihre Herangehensweise an das Codieren ändern, für einige wird es eine drastische Änderung sein.

Unterschiedliche Menschen codieren auf ganz unterschiedliche Weise. In TDD müssen Sie mit einem Test beginnen, der ein bestimmtes Verhalten bestätigt, und dann implementieren, damit der Test erfolgreich ist. Ich habe gesehen und war ein Programmierer, dessen Programmierung TDD nicht förderlich war. Es dauerte ungefähr zwei Monate, bis ich mich daran gewöhnt hatte, meinen Entwicklungsansatz zu ändern.

Es braucht Zeit, um zu verstehen, was Sie am Testen interessiert und was Sie nicht am Testen interessiert.

Jedes Team sollte eine explizite Entscheidung treffen, an welcher Stelle beim Testen die Grenze gezogen werden soll. Welche Dinge schätzen sie, die sie testen möchten, und welche nicht. Es ist oft ein schmerzhafter Prozess, zu lernen, wie man gute Tests schreibt und worauf es Ihnen beim Testen ankommt. In der Zwischenzeit wird der Code so lange im Fluss bleiben, bis Konsistenz sowohl im Stil als auch in der Herangehensweise besteht.

Unit Test spezifisch: große Refaktoren

Ein großer oder grundlegender Umbau einer signifikanten Codebasis mit Zehntausenden von Komponententests verursacht enorme Kosten, um alle Tests zu aktualisieren. Dies äußert sich oft in einer Zurückweisung gegen das Ausführen eines Refaktors, auch wenn dies nur aufgrund der damit verbundenen Kosten richtig ist.

dietbuddha
quelle
0

Meine Analogie sind Barrieren auf einer Scalextric-Spur. Wenn Sie sie anziehen, werden Sie weit weniger vorsichtig.

Die Leute bekommen auch ein bisschen Platz für ihre Tests - weil sie gut laufen, glauben sie, dass der Code vollständig getestet ist, während es nur der Anfang des Testprozesses ist.

Für mich ist TDD ein Sprungbrett für BDD. Eine Reihe von Tests, die ausgeführt werden, hilft Entwicklern nicht wirklich, ohne zu wissen, was die Tests bewirken. Bei BDD erfolgt die Testausgabe in Englisch, wodurch die Tests dokumentiert und das Verständnis des Systems verbessert werden.

Robbie Dee
quelle
-1

Der Vorteil von TDD besteht darin, dass Sie gezwungen sind, Ihren Code vor Leuten zu schützen, die ihn nicht verstehen. Ja, dazu gehören oft Sie. Aber was passiert, wenn der Code es nicht wert ist, geschützt zu werden? Es gibt eine Menge Code, der gar nicht erst vorhanden sein sollte! Das Problem mit TDD ist also, wenn es um Entwickler geht, die schlechten Code schreiben. TDD wird ihnen wahrscheinlich nicht dabei helfen, guten Code zu schreiben. Es ist viel wahrscheinlicher, dass sie auch schreckliche Tests schreiben. Somit wird TDD in ihrem Fall nur zu dem Durcheinander beitragen; Schlecht geschriebene und / oder redundante Tests machen nicht mehr Spaß als andere Arten von schlechtem Code.

Johan
quelle
1
Wenn Sie selbst Ihren eigenen Code nicht verstehen, wie kann eine Handvoll von Milliarden möglicher Testfälle möglicherweise verhindern, dass der Code falsch ist?
Michael Shaw
2
Weil du es verstanden hast, als du es geschrieben hast, aber es dabei vergessen hast?
Johan
+1 TDD schützt nicht vor Entwicklern, die eine Geschäftsanforderung falsch verstanden haben. Hier kommt BDD ins Spiel ...
Robbie Dee