lundi 19 mai 2014

Refactorer legacy même pas peur

tldr; L’approche classique des tests n’est pas adapté pour le refactoring dans le legacy. Il vaut mieux écrire des tests automatiques jetables. Du fait qu’il y ait 0 besoin de maintenance et avec l’outillage adapté cela est très TRES rapide. Ex : 200 lignes en 5min.

Cette fin de semaine c’est Agile France et je suis vraiment très heureux de présenter “Refactorer legacy, même pas peur!". Il y aura du code en live bien entendu! Enfin des tests en tout cas. Ma présentation, qui est celle de Rémy Sanlaville aussi bien qu’il  ne peut pas venir, cherche à remettre en cause comment en général on conçoit les tests sur legacy. Oui carrément! :) 


Le problème

Classiquement nous rencontrons un ou plusieurs problèmes lorsque nous tentons d’intervenir sur du code legacy

  1. Il est jugé trop long d’écrire les tests avant de toucher au code
  2. On met en place des tests (très) haut niveau, souvent assez longs à exécuter
  3. Les tests unitaires adhèrent au code et peuvent ralentir certains refactorings

C'est probablement maintenant que les esprits se chauffent. Justement c’est le moment de se calmer, je vais tout expliquer ;)


Trop long

Oui, ben parfois ca peut prendre des journées voire des semaines pour mettre en place des tests, notamment de haut niveau. Ca peut être justifiable mais ca peut aussi ne pas l’être. En tout état de cause, moins l’écriture de tests prend du temps plus on le fera.


Tests haut niveau, longs à exécuter

La durée d’exécution de ces tests sont plusieurs ordres de grandeur plus lent que les tests unitaires, parfois cela requiert le déploiement du code sur un serveur d’application et on compte des dizaines de minutes juste pour un lancement. Cela fait qu’on va plus lentement, on réfléchit plus longtemps, et généralement on va aller moins loin dans le refactoring et ainsi laisser plus de dette.


Tests unitaires et adhérence au code

Classiquement on teste l’interface de chaque classe, elle est rarement bien faite et lorsqu’on souhaite la changer, on doit non seulement changer le code de production mais aussi tous les tests. Pire on a souvent envie de tester qu'une partie de la classe et on crée ainsi une adhérence à des méthodes protected. Donc bien qu’elle permette le refactoring à l’intérieur les tests freinent le refactoring aux frontières.


Une alternative

Je ne parle pas de LA solution, ce que Rémy et moi tentons de vous faire voir est une approche complémentaire qui nous a bluffé par son efficacité, est une “nouvelle” façon de réfléchir aux tests. Qu’il s’agisse de tests haut niveau ou bas niveau c’est une approche différente et complémentaire elle s’applique à tous les niveaux des tests.

Une fois que le code est bien propre, il est facile et rapide d'écrire des tests unitaires et haut niveau avec le style tests provenant de TDD  ou BDD qui pour le coup sont maintenables.

Il y a deux clés à retenir dans notre présentation

  1. Écrire une assertion pour du legacy est une forme de gaspillage. Le résultat du premier lancement est LA référence. Record-Replay
  2. Il s’agit de tests temporaires, ils sont à jeter à la fin du refactoring. Donc nous passons zero énergie sur la maintenabilité

La combinaison de ces deux points produisent un gain de temps énorme et permet d’écrire des tests pour le besoin actuel sur mesure -  des tests rapides et résistants au refactoring.

Si vous êtes curieux de comment nous faisons ça et quel est l'outillage qui en découle - venez voir un exemple et passer du bon temps à Agile France!

Notes : Outillage exemple :

  • ApprovalTests
  • Couverture de code 
  • Moco (simuler des serveurs web) (Java)
  • XStream (sérialiser objets en chaîne) (Java)  
Mise à jour : slides

Mise à jour : inclure aperçu video