E-LEGA-1: Comment s’attaquer au legacy code

Projet laid

Le code suivant servira de base pour le refactoring : https://github.com/GLO4002UL/officiel-lab-account-billing

Le besoin d’affaires de ce code est de pouvoir canceller une facture et redistribuer les paiements existants sur cette facture vers les autres factures impayées de ce client.

Votre but : rendre ce code sexy

Conseils en vrac pour le legacy code

Dans du code legacy, les règles changent. On ne peut plus faire parfait à chaque fois, on doit faire de notre mieux. Donc :

Étape 1 : Refactor avec l’IDE

À cette étape, votre but est de comprendre le code. Vous pouvez renommer ou déplacer des choses, pourvu que vous utilisiez l’IDE qui lui ne se trompera pas. Ne vous faites absolument pas confiance.

N’essayez pas trop d’améliorer le code. Si vous tentez d’améliorer du code avant de l’avoir comprit à 100%, vous risquez d’avoir un “refucktoring” (le penchant du refactoring). À cette étape, faites seulement ce qui vous aide à comprendre. Au pire, vous referez git reset --hard HEAD pour tout annulé!

Étape 2 : Tests de caractérisation

Ajoutez un filet de sécurité autour du code, avec les cas que vous avez identifiés. Encore une fois, seul le refactoring par l’IDE est permis.

Personnellement j’ai vu 10 comportements que j’ai traduits en tests. Vous pourriez en avoir plus ou moins. Le but n’est pas non plus de couvrir tous les edges cases ou de laisser couler l’implémentation. C’est un filet de sécurité temporaire.

Ne faites pas de mock, sauf si c’est pour vous simplifier la vie (i.e. les DAO qui ne marchent pas dans notre cas).

Votre meilleur outil ici est l’outil de coverage (eclemma ou autre).

Truc : Testez à partir de la branche la moins profonde. Dans notre cas, c’est le throw de l’account non trouvé.

Truc 2 : Pour injecter le DAO, extraire tous les appels dans des methodes protected. Dans votre test, faire une classe qui hérite du service et faire un @Override des méthodes en question. C’est le truc le plus simple pour injecter vos mocks… mais en fait, vous pouvez tout le faire sans mock. Simplement à retourner une variable directement (ou une liste).

Truc 3 : À chaque fois que vous faites un test correctement, il devrait déjà passer. Pour prouver qu’il est bon, commenté la ligne ciblé et regardez si le test échoue.

Truc 4 : Contrairement à tout ce qu’on a vu à date, faites seulement des tests de résultats (i.e. des assert, pas des verify). Par exemple, cancellez le bill et regardez si bill.isCancelled est true… pas verify(bill).cancelled().

Vous pouvez écouter rapidement les ~25 premières minutes du vidéo en référence au bas de ce laboratoire si vous êtes un peu perdus avec tout ça!

N’oubliez pas le commit. Vous pouvez même en faire un après chaque test.

Étape 3 : Refactoring pour vrai!

Vous avez ici plusieurs méthodes de refactoring. Il existe plusieurs techniques, dont beaucoup se trouvent dans le livre de Michael Feathers “Working Effectively with Legacy Code”.

La règle générale est que les règles n’existent plus à l’exception de la suivante : faites de très petits pas.

Faites fréquemment des commits.

L’astuce ici est de commencer par la branche la plus profonde. Donc on test en premier les branches la branche la moins profonde, mais on extrait la branche la plus profonde. On peut extraire une méthode privée, mais encore mieux on peut simplement déléguer aux objets (à bill dans ce cas-ci).

Important : vos tests ne devraient jamais échouer! Ils peuvent peut-etre être déplacés par contre.

Étape 3.1 : séparer le code en couches

Afin d’aider à réfléchir plus clairement aux différents refactorings possibles, je vous conseille de commencer par imaginer les couches applicatives. Prennez le code actuel: dans quelle couche devrait se située cette classe?

On peut assumer que cette classe se veut un application service. Par contre, clairement elle en fait trop! Si on a 3 autres couches : UI (interfaces), Domaine, Persistance (infrastructure), imaginez où déplacer chacune des différentes lignes de code. Qu’est-ce qu’il reste dans l’application service par la suite?

Étape 4 : Détruire les tests de caractérisation

Ce n’est pas demandé dans le lab, mais l’étape suivante serait de couvrir de bons tests unitaires toute l’application afin de jeter le plus rapidement possible nos tests de caractérisation.

Références

Voir ce vidéo qui explique vraiment bien comment s’attaquer au code legacy.