Dans mon projet actuel (un jeu, en C++), j'ai décidé d'utiliser 100% de développement piloté par les tests pendant le développement.
En termes de qualité du code, cela a été formidable. Mon code n'a jamais été aussi bien conçu ni exempt de bogues. Je ne grince pas les dents lorsque je regarde le code que j'ai écrit il y a un an au début du projet, et j'ai acquis une bien meilleure idée de la façon de structurer les choses, non seulement pour être plus facilement testable, mais pour être plus simple à mettre en œuvre et à utiliser. .
Cependant ... cela fait un an que j'ai commencé le projet. Certes, je ne peux y travailler que pendant mon temps libre, mais TDD me ralentit encore considérablement par rapport à ce à quoi je suis habitué. J'ai lu que la vitesse de développement plus lente s'améliore avec le temps, et je pense vraiment à des tests beaucoup plus facilement qu'auparavant, mais j'y suis depuis un an maintenant et je travaille toujours à un rythme d'escargot.
Chaque fois que je pense à la prochaine étape qui a besoin de travail, je dois m'arrêter à chaque fois et réfléchir à la façon dont j'écrirais un test pour me permettre d'écrire le code réel. Je vais parfois rester bloqué pendant des heures, sachant exactement quel code je veux écrire, mais ne sachant pas comment le décomposer assez finement pour le couvrir complètement avec des tests. D'autres fois, je vais rapidement imaginer une douzaine de tests et passer une heure à écrire des tests pour couvrir un petit morceau de code réel qui aurait sinon pris quelques minutes à écrire.
Ou, après avoir terminé le 50e test pour couvrir une entité particulière dans le jeu et tous les aspects de sa création et de son utilisation, je regarde ma liste de tâches et je vois la prochaine entité à coder, et je grimace d'horreur à l'idée d'écrire 50 autres tests similaires pour le mettre en œuvre.
Il est arrivé au point que, en examinant les progrès de l'année dernière, j'envisage d'abandonner TDD pour "terminer le fichu projet". Cependant, abandonner la qualité du code qui l'accompagne n'est pas quelque chose que j'attends avec impatience. J'ai peur que si j'arrête d'écrire des tests, alors je vais perdre l'habitude de rendre le code si modulaire et testable.
Suis-je peut-être en train de faire quelque chose de mal pour être si lent à ce sujet? Existe-t-il des alternatives qui accélèrent la productivité sans perdre complètement les avantages? TAD? Moins de couverture de test? Comment les autres survivent-ils au TDD sans tuer toute productivité et motivation?
Permettez-moi de commencer par vous remercier de partager votre expérience et d'exprimer vos préoccupations ... qui, je dois le dire, ne sont pas rares.
Et cela m'amène à la dernière question: comment puis-je m'améliorer? Ma (ou une) réponse est lire, réfléchir et pratiquer.
par exemple. Dernièrement, je garde un œil sur
Vous n'avez pas besoin d'une couverture de test à 100%. Soyez pragmatique.
TDD me ralentit encore considérablement
C'est en fait faux.
Sans TDD, vous passez quelques semaines à écrire du code qui fonctionne principalement et passez l'année suivante à "tester" et à corriger de nombreux bugs (mais pas tous).
Avec TDD, vous passez un an à écrire du code qui fonctionne réellement. Ensuite, vous effectuez des tests d'intégration finaux pendant quelques semaines.
Le temps écoulé sera probablement le même. Le logiciel TDD sera de bien meilleure qualité.
Ou, après avoir terminé le 50e test pour couvrir une entité particulière dans le jeu et tous les aspects de sa création et de son utilisation, je regarde ma liste de tâches et je vois la prochaine entité à coder, et je grimace d'horreur à l'idée d'écrire 50 autres tests similaires pour le mettre en œuvre.
Cela me fait me demander combien vous suivez l'étape "Refactor" de TDD.
Lorsque tous vos tests sont réussis, il est temps pour vous de refactoriser le code et de supprimer la duplication. Bien que les gens s'en souviennent généralement, ils oublient parfois qu'il est également temps de refactoriser leurs tests , pour supprimer les doublons et simplifier les choses.
Si vous avez deux entités qui fusionnent en une seule pour permettre la réutilisation du code, envisagez également de fusionner leurs tests. Vous n'avez vraiment besoin que de tester les différences incrémentales dans votre code. Si vous n'effectuez pas régulièrement de maintenance sur vos tests, ils peuvent rapidement devenir lourds.
Quelques points philosophiques sur TDD qui pourraient être utiles:
EDIT: Sur le thème de la philosophie des tests unitaires, je pense que cela pourrait être intéressant pour vous de lire: The Way of Testivus =
Et un point plus pratique, sinon nécessairement très utile:
Question très intéressante.
Ce qui est important à noter, c'est que C++ n'est pas très facilement testable, et le jeu, en général, est également un très mauvais candidat pour TDD. Vous ne pouvez pas tester si OpenGL/DirectX dessine facilement le triangle rouge avec le pilote X et jaune avec le pilote Y. Si le vecteur normal de la carte de relief n'est pas inversé après les transformations de shader. Vous ne pouvez pas non plus tester les problèmes d'écrêtage sur les versions de pilote avec différentes précisions, etc. Le comportement de dessin indéfini en raison d'appels incorrects ne peut également être testé qu'avec une révision précise du code et un SDK à portée de main. Le son est également un mauvais candidat. Le multithreading, qui est encore très important pour les jeux, est à peu près inutile au test unitaire. C'est donc difficile.
Fondamentalement, le jeu est beaucoup de GUI, de son et de threads. L'interface graphique, même avec des composants standard auxquels vous pouvez envoyer WM_, est difficile à tester unitaire.
Donc, ce que vous pouvez tester, ce sont les classes de chargement de modèles, les classes de chargement de texture, les bibliothèques de matrices et autres, ce qui n'est pas beaucoup de code et, souvent, pas très réutilisable, si ce n'est que votre premier projet. De plus, ils sont emballés dans des formats propriétaires, il est donc peu probable que les entrées tierces puissent différer beaucoup, sauf si vous publiez des outils de modding, etc.
Là encore, je ne suis pas un gourou ou un évangéliste du TDD, alors prenez tout cela avec un grain de sel.
J'écrirais probablement quelques tests pour les principaux composants de base (par exemple la bibliothèque matricielle, la bibliothèque d'images). Ajoutez un tas de abort()
sur les entrées inattendues dans chaque fonction. Et surtout, concentrez-vous sur du code résistant/résilient qui ne se casse pas facilement.
Concernant les erreurs hors tension, une utilisation intelligente de C++, RAII et une bonne conception contribuent grandement à les éviter.
En gros, vous avez beaucoup à faire juste pour couvrir les bases si vous voulez sortir le jeu. Je ne sais pas si TDD va aider.
Je suis d'accord avec les autres réponses, mais je veux également ajouter un point très important: refactoring des coûts !!
Avec des tests unitaires bien écrits, vous pouvez sans risque réécrire votre code. Tout d'abord, des tests unitaires bien écrits fournissent une excellente documentation de l'intention de votre code. Deuxièmement, tout effet secondaire malheureux de votre refactoring sera détecté dans la suite de tests existante. Ainsi, vous avez garanti que les hypothèses de votre ancien code sont également vraies pour votre nouveau code.
Comment les autres survivent-ils au TDD sans tuer toute productivité et motivation?
C'est complètement différent de mes expériences. Vous êtes soit incroyablement intelligent et écrivez du code sans bogues, (par exemple, désactivé par une erreur) ou vous ne réalisez pas que votre code a des bogues qui empêchent votre programme de fonctionner, et ne sont donc pas réellement terminés.
TDD, c'est avoir l'humilité de savoir que vous (et moi!) Faites des erreurs.
Pour moi, le temps d'écriture d'unittests est plus qu'économisé en temps de débogage réduit pour les projets qui sont effectués en utilisant TDD depuis le début.
Si vous ne faites pas d'erreurs, le TDD n'est peut-être pas aussi important pour vous qu'il l'est pour moi!
Je n'ai que quelques remarques:
Il semble que vous essayiez de tester tout. Vous ne devriez probablement pas, juste les cas à haut risque et Edge d'un morceau de code/méthode particulier. Je suis presque sûr que la règle des 80/20 s'applique ici: vous passez 80% à écrire des tests pour les 20% de votre code ou cas qui ne sont pas couverts.
Prioriser. Entrez dans le développement de logiciels agiles et faites une liste de ce que vous devez vraiment vraiment faire pour sortir en un mois. Relâchez ensuite, juste comme ça. Cela vous fera réfléchir à la priorité des fonctionnalités. Oui, ce serait cool si votre personnage pouvait faire un backflip, mais a-t-il valeur commerciale?
TDD est bon, mais seulement si vous ne visez pas une couverture de test à 100%, et ce n'est pas si cela vous empêche de produire une valeur commerciale réelle (c'est-à-dire des fonctionnalités, des choses qui ajoutent quelque chose à votre jeu).
Oui, l'écriture de tests et de code peut prendre plus de temps que la simple écriture de code - mais l'écriture de code et les tests unitaires associés (à l'aide de TDD) sont beaucoup plus prévisibles que l'écriture de code et le débogage.
Le débogage est presque éliminé lors de l'utilisation de TDD - ce qui rend tous les processus de développement beaucoup plus prévisibles et au final - sans doute plus rapides.
Refactorisation constante - il est impossible d'effectuer une refactorisation sérieuse sans une suite complète de tests unitaires. Le moyen le plus efficace de construire ce filet de sécurité basé sur les tests unitaires est pendant le TDD. Un code bien refactorisé améliore considérablement la productivité globale du concepteur/de l'équipe qui gère le code.
Envisagez de restreindre la portée de votre jeu et placez-le là où quelqu'un peut y jouer ou vous le libérez. Maintenir vos normes de test sans avoir à attendre trop longtemps pour sortir votre jeu pourrait être un compromis pour vous garder motivé. Les commentaires de vos utilisateurs peuvent offrir des avantages à long terme et vos tests vous permettent de vous sentir à l'aise avec les ajouts et les modifications.