Sur les projets neufs
Sur les projets neufs, je pratique TDD. C’est pour moi une condition de la qualité du logiciel, et donc un principe auquel je ne déroge que dans de rares cas, notamment lorsqu’il s’agit de dette technique assumée.
Plus précisément, je pratique un Outside-In Diamond TDD mâtiné de BDD. Je pars du comportement attendu du logiciel pour descendre progressivement vers les détails d’implémentation. Cette approche donne davantage de place aux tests fonctionnels et d’acceptation que la traditionnelle pyramide de tests, dont l’usage systématique a parfois conduit la profession à tester davantage le code que le logiciel.
Les tests d’acceptation sont mon pain quotidien. Ils décrivent, dans un
langage compréhensible par les deux parties, les comportements attendus
du logiciel. Je les construis avec vous et les reprends régulièrement
afin de vérifier que j’ai bien compris votre besoin.
Les tests contractuels et d’intégration vérifient ensuite les
interactions entre les différentes parties du logiciel et avec ses
dépendances. Ils constituent les clauses techniques de notre contrat :
ils permettent de vérifier que ce qui a été livré correspond bien à ce
qui avait été convenu.
Les tests de plus haut niveau, comme les tests de fumée ou
end-to-end, vérifient que le logiciel fonctionne réellement
lorsqu’il rencontre le monde extérieur. Ils peuvent également servir
de démonstration lors de la livraison d’une itération.
Je ne suis évidemment pas opposé aux tests unitaires. Ils sont
simplement utilisés avec discernement. Trop nombreux ou trop liés à
l’implémentation, ils peuvent rigidifier le code et rendre les
évolutions pénibles. Je les réserve notamment aux parties où la manière
de procéder compte autant que le résultat : algorithmes, performances,
cryptographie, calculs complexes, etc.
Sur les logiciels legacy
Je reprends ici la définition de Michael Feathers : le code legacy, c’est du code non testé que l’on ne peut pas simplement jeter. Lorsqu’on me confie un tel logiciel, je ne promets pas de le rendre propre du jour au lendemain. Sauf budget colossal, ce serait une promesse peu crédible.
Tout code nouveau ou modifié est en revanche testé comme du code neuf. Pour le code existant, je commence par construire un filet de sécurité adapté : des tests plus grossiers, notamment des tests de fumée, qui permettent de réduire progressivement le risque. Leur niveau dépend de vos besoins, du niveau de confiance recherché et du budget disponible.
Une fois le logiciel sécurisé, son assainissement peut se faire progressivement. Un budget de maintenance peut être consacré à cette réduction de la dette technique. Ce n’est pas de l’argent dépensé pour faire joli : c’est le prix à payer pour que le logiciel continue à évoluer lorsque votre métier, lui, ne cesse de changer.
En cas de défaut
Lorsqu’un bug est découvert, je cherche à faire en sorte qu’il ne puisse pas revenir. J’écris d’abord un test qui reproduit le défaut, puis je modifie le code pour faire passer ce test. Le test reste ensuite dans la suite de non-régression.
Je peux ainsi garantir quelque chose de précis : un bug corrigé ne reviendra pas sous la même forme sans que les tests ne le détectent. C’est beaucoup plus utile qu’une promesse vague de logiciel « sans bugs ».
Enzo Sandré