Fiabilisation de vieux code
Que ce soit du code refourgué par un prédécesseur, écrit à la vite, ou ayant accumulé un retard technologique sur plusieurs années... il est fréquent d'avoir à retravailler sur du vieux code. Il est tentant de vouloir tout réécrire, en repartant sur de bonnes bases. Mais:
- La plupart du temps le projet n'aboutit pas,
- Au bout de quelques années le nouveau projet est devenu tout aussi pourri.
Un vieux code de jeu à reprendre
Cas d'école: prenons le jeu Dink Smallwood, un chouette jeu sorti vers la fin des années '90, et dont le code a été libéré.
Le code est infect: une poignée de fichiers monolithiques, des fonctions de 1000+ lines, des noms de variables à coucher dehors... Plus grave : plus de 400 Dink Modules (D-Mods), de nouvelles aventures faites par des fans, sont disponibles, et beaucoup s'appuient sur des bugs du moteur...
Comment faire un portage GNU/Linux sans tout casser ? Avec des modifications locales sur les I/O (graphiques/sons/clavier/joystick), une bonne connaissance du moteur, un peu de culot, plusieurs cierges à l'église, et beaucoup de tests manuels, c'est possible : GNU FreeDink.
Reprendre le contrôle sur du code pourri
À présent : comment faire évoluer le code, ou pire encore, accepter des contributions extérieures donc non-fiables, sans risquer d'introduire de nouveaux bugs, et casser les D-Mods sans s'en rendre compte ? La peur de casser finit par tout paralyser.
Working Effectively with Legacy Code, de Michael Feathers, propose une approche TDD. Il définit: legacy code is simply code without tests. L'approche proposée est :
- Avant tout changement, introduire un maximum de tests unitaires dans la base de code,
- Pour introduire des tests unitaires, changer le code pour le rendre testable,
- Et pour sortir de ce cycle, amorcer avec des changements peu risqués :
- Casser les dépendances internes pour y introduire des tests - l'essentiel du livre expose différentes techniques
- Utiliser des outils de refactoring automatique
Pour C/C++, en libre, Eclipse CDT fournit quelques fonctions de refactoring, Rename et Extract Method.
Qu'est-ce que ça fout sur ce wiki ?
C'est ce que je fais en ce moment au hackerspace : se mettre au défi d'ajouter une armature de test autour de ce putain de code, et avoir confiance dans les prochaines modifs.