In meinem aktuellen Projekt (ein Spiel in C ++) habe ich beschlossen, Test Driven Development zu 100% während der Entwicklung zu verwenden.
In Bezug auf die Codequalität war dies großartig. Mein Code war noch nie so gut gestaltet oder fehlerfrei. Beim Anzeigen von Code, den ich vor einem Jahr zu Beginn des Projekts geschrieben habe, schaudert es nicht, und ich habe ein viel besseres Gespür dafür erlangt, wie man Dinge strukturiert, nicht nur leichter testbar, sondern auch einfacher zu implementieren und zu verwenden .
Es ist jedoch ein Jahr her, seit ich mit dem Projekt begonnen habe. Zugegeben, ich kann nur in meiner Freizeit daran arbeiten, aber TDD verlangsamt mich immer noch erheblich im Vergleich zu dem, was ich gewohnt bin. Ich habe gelesen, dass die langsamere Entwicklungsgeschwindigkeit mit der Zeit besser wird, und ich denke mir Tests definitiv viel leichter aus als früher, aber ich bin jetzt seit einem Jahr dabei und arbeite immer noch im Schneckentempo.
Jedes Mal, wenn ich über den nächsten Schritt nachdenke, der Arbeit erfordert, muss ich jedes Mal anhalten und darüber nachdenken, wie ich einen Test dafür schreiben würde, damit ich den tatsächlichen Code schreiben kann. Ich werde manchmal stundenlang stecken bleiben und genau wissen, welchen Code ich schreiben möchte, aber nicht wissen, wie ich ihn fein genug aufschlüsseln kann, um ihn vollständig mit Tests abzudecken. In anderen Fällen überlege ich mir schnell ein Dutzend Tests und schreibe eine Stunde lang Tests, um einen winzigen Teil des realen Codes zu erfassen, dessen Erstellung ansonsten einige Minuten gedauert hätte.
Oder nachdem ich den 50. Test abgeschlossen habe, um eine bestimmte Entität im Spiel und alle Aspekte ihrer Erstellung und Verwendung abzudecken, schaue ich auf meine To-Do-Liste und sehe die nächste Entität, die codiert werden muss weitere 50 ähnliche Tests, um es umzusetzen.
Es ist zu dem Punkt gekommen, dass ich angesichts der Fortschritte des letzten Jahres in Erwägung ziehe, TDD aufzugeben, um "das verdammte Projekt fertig zu stellen". Ich freue mich jedoch nicht darauf, die damit verbundene Codequalität aufzugeben. Ich fürchte, wenn ich aufhöre, Tests zu schreiben, werde ich es mir nicht mehr zur Gewohnheit machen, den Code so modular und testbar zu machen.
Mache ich vielleicht etwas falsch, um noch so langsam dabei zu sein? Gibt es Alternativen, die die Produktivität beschleunigen, ohne die Vorteile vollständig zu verlieren? BISSCHEN? Weniger Testabdeckung? Wie können andere Menschen TDD überleben, ohne die Produktivität und Motivation zu beeinträchtigen?
quelle
Antworten:
Lassen Sie mich zunächst danken, dass Sie uns Ihre Erfahrungen mitteilen und Ihre Bedenken zum Ausdruck bringen ... was ich zu sagen habe, ist keine Seltenheit.
Und das bringt mich zur letzten Frage: Wie werde ich besser? Meine (oder eine) Antwort lautet Lesen, Reflektieren und Üben.
In letzter Zeit behalte ich die Übersicht
quelle
Sie benötigen keine 100% ige Testabdeckung. Sei pragmatisch.
quelle
a = x + y
und gab, obwohl alle Zeilen im Code in Tests ausgeführt wurden, wurden die Tests nur für den Fall getestet, in dem y = 0 ist, so dass der Fehler (es hätte sein sollena = x - y
) in Tests nie gefunden wurde.Das ist eigentlich falsch.
Ohne TDD verbringen Sie einige Wochen damit, Code zu schreiben, der meistens funktioniert, und verbringen das nächste Jahr damit, viele (aber nicht alle) Fehler zu "testen" und zu beheben.
Mit TDD schreiben Sie ein Jahr lang Code, der tatsächlich funktioniert. Anschließend führen Sie einige Wochen lang einen abschließenden Integrationstest durch.
Die verstrichene Zeit wird wahrscheinlich gleich sein. Die TDD-Software wird eine wesentlich bessere Qualität haben.
quelle
Ich frage mich daher, wie sehr Sie den "Refactor" -Schritt von TDD verfolgen.
Wenn alle Ihre Tests bestanden sind, müssen Sie den Code überarbeiten und Duplikate entfernen. Während die Leute sich normalerweise daran erinnern, vergessen sie manchmal, dass dies auch die Zeit ist, ihre Tests zu überarbeiten, Duplikate zu entfernen und Dinge zu vereinfachen.
Wenn Sie zwei Entitäten haben, die zu einer zusammengeführt werden, um die Wiederverwendung von Code zu ermöglichen, können Sie auch deren Tests zusammenführen. Sie müssen wirklich nur inkrementelle Unterschiede in Ihrem Code testen . Wenn Sie Ihre Tests nicht regelmäßig warten, können sie schnell unhandlich werden.
Einige philosophische Punkte zu TDD, die hilfreich sein könnten:
EDIT: Zum Thema Philosophie des Unit- Testings halte ich es für interessant, Folgendes zu lesen: The Way of Testivus
Und ein praktischerer, wenn auch nicht unbedingt sehr hilfreicher Punkt:
quelle
Sehr interessante Frage.
Was wichtig ist, ist, dass C ++ nicht einfach zu testen ist und Spiele im Allgemeinen auch ein sehr schlechter Kandidat für TDD sind. Sie können nicht einfach testen, ob OpenGL / DirectX mit Treiber X ein rotes Dreieck und mit Treiber Y ein gelbes Dreieck zeichnet. Wenn der normale Bump-Map-Vektor nach Shader-Transformationen nicht gespiegelt wird. Sie können auch keine Clipping-Probleme mit Treiberversionen mit unterschiedlichen Genauigkeiten usw. testen. Undefiniertes Zeichenverhalten aufgrund falscher Aufrufe kann auch nur mit genauer Codeüberprüfung und verfügbarem SDK getestet werden. Sound ist auch ein schlechter Kandidat. Multithreading, das wiederum für Spiele von großer Bedeutung ist, ist für den Unit-Test so gut wie unbrauchbar. Es ist also hart.
Grundsätzlich ist Gaming eine Menge GUI, Sound und Threads. Die GUI ist selbst mit Standardkomponenten, an die Sie WM_ senden können, nur schwer zu testen.
Was Sie also testen können, sind Modelllade-Klassen, Texturlade-Klassen, Matrix-Bibliotheken und einige andere, die nicht viel Code enthalten und nicht sehr oft wiederverwendbar sind, wenn es nur Ihr erstes Projekt ist. Außerdem sind sie in proprietäre Formate gepackt, sodass es nicht sehr wahrscheinlich ist, dass Eingaben von Drittanbietern stark voneinander abweichen können, es sei denn, Sie geben Modding-Tools usw. frei.
Andererseits bin ich kein TDD-Guru oder Evangelist, also nimm das alles mit einem Körnchen Salz.
Ich würde wahrscheinlich einige Tests für Hauptkernkomponenten schreiben (zum Beispiel Matrixbibliothek, Bildbibliothek). Fügen Sie
abort()
jeder Funktion eine Reihe unerwarteter Eingaben hinzu. Und vor allem konzentrieren Sie sich auf widerstandsfähigen / belastbaren Code, der nicht leicht zu knacken ist.Wenn es um einen Fehler geht, hilft der kluge Einsatz von C ++, RAII und einem guten Design, ihn zu vermeiden.
Grundsätzlich muss man viel tun, um die Grundlagen zu besprechen, wenn man das Spiel veröffentlichen möchte. Ich bin mir nicht sicher, ob TDD helfen wird.
quelle
Ich stimme den anderen Antworten zu, möchte aber auch einen sehr wichtigen Punkt hinzufügen: Refactoring-Kosten !!
Mit gut geschriebenen Komponententests können Sie Ihren Code sicher neu schreiben. Erstens liefern gut geschriebene Komponententests eine hervorragende Dokumentation der Absicht Ihres Codes. Zweitens werden alle unglücklichen Nebenwirkungen Ihres Refactorings in der vorhandenen Testsuite erfasst. Auf diese Weise haben Sie garantiert, dass die Annahmen Ihres alten Codes auch für Ihren neuen Code gelten.
quelle
Das ist völlig anders als meine Erfahrungen. Sie sind entweder unglaublich intelligent und schreiben Code ohne Fehler (z. B. durch einen Fehler), oder Sie wissen nicht, dass Ihr Code Fehler enthält, die Ihr Programm daran hindern, zu funktionieren, und sind daher nicht wirklich fertig.
Bei TDD geht es darum, die Demut zu haben, zu wissen, dass Sie (und ich!) Fehler machen.
Für mich spart das Schreiben von Unittests mehr als nur Zeit beim Debuggen von Projekten, die von Anfang an mit TDD erstellt wurden.
Wenn Sie keine Fehler machen, ist TDD für Sie vielleicht nicht so wichtig wie für mich!
quelle
Ich habe nur ein paar Anmerkungen:
Sie versuchen anscheinend, alles zu testen . Sie sollten es wahrscheinlich nicht tun, nur die Hochrisiko- und Randfälle eines bestimmten Teils des Codes / der Methode. Ich bin mir ziemlich sicher, dass die 80/20-Regel hier zutrifft: Sie schreiben zu 80% Tests für die letzten 20% Ihres Codes oder für Fälle, die nicht abgedeckt sind.
Priorisieren. Steigen Sie in die agile Softwareentwicklung ein und erstellen Sie eine Liste dessen, was Sie wirklich wirklich wirklich tun müssen, um in einem Monat zu veröffentlichen. Dann loslassen, einfach so. Dies lässt Sie über die Priorität von Funktionen nachdenken. Ja, es wäre cool, wenn dein Charakter einen Backflip machen könnte, aber hat er geschäftlichen Wert ?
TDD ist gut, aber nur dann, wenn Sie keine 100% ige Testabdeckung anstreben, und nicht dann, wenn Sie keinen tatsächlichen Geschäftswert erzielen (dh Funktionen, Dinge, die Ihrem Spiel etwas hinzufügen).
quelle
Ja, das Schreiben von Tests und Code kann länger dauern als nur das Schreiben von Code. Das Schreiben von Code und den zugehörigen Komponententests (mit TDD) ist jedoch weitaus vorhersehbarer als das Schreiben und anschließende Debuggen von Code.
Bei der Verwendung von TDD entfällt das Debuggen fast vollständig - was den gesamten Entwicklungsprozess viel vorhersehbarer und letztendlich deutlich schneller macht.
Ständiges Refactoring - ohne umfassende Unit-Testsuite ist kein ernsthaftes Refactoring möglich. Der effizienteste Weg, dieses auf Unit-Tests basierende Sicherheitsnetz aufzubauen, ist während der TDD. Gut überarbeiteter Code verbessert die Gesamtproduktivität des Designers / Teams, das den Code verwaltet, erheblich.
quelle
Erwägen Sie, den Umfang Ihres Spiels einzuschränken und zu ermitteln, wo jemand es spielen kann oder wo Sie es veröffentlichen. Behalten Sie Ihre Teststandards bei, ohne zu lange auf die Veröffentlichung Ihres Spiels warten zu müssen. Dies ist möglicherweise ein Mittelweg, um Sie zu motivieren. Das Feedback Ihrer Benutzer kann langfristig Vorteile bringen, und Sie können sich beim Testen mit den Ergänzungen und Änderungen wohlfühlen.
quelle