Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Tester du Legacy Code - Mission Impossible

Tester du Legacy Code - Mission Impossible

Dans nos accompagnements techniques, nous observons régulièrement des problèmes de Legacy Code, aussi appelé Code Patrimonial. Ces problèmes surviennent notamment lorsque des équipes font un virage Agile et qu’on leur demande soudainement de faire des tests unitaires automatisés. Pas si facile que ça, car le système en question n’a pas été prévu pour des tests unitaires.
C’est ce qui nous a donné l’idée de monter une présentation en abordant le sujet avec les points suivants :
- Description de quelques techniques pour nous aider à tester le Legacy Code.
- Comment avoir le droit de travailler sur du code pour le rendre plus facile à travailler?
- Quelques pratiques et outils afin de s’en prémunir autant que possible, au jour le jour.

Karl Métivier

November 16, 2016
Tweet

More Decks by Karl Métivier

Other Decks in Programming

Transcript

  1. Bon après-midi, Ethan. • Votre mission, si vous l’acceptez, consiste

    à vous occuper d’un système informatique qui n’est pas nouveau ni trop vieux, mais qui n’a aucun tests automatisé. • Par contre, il est au cœur de plusieurs traitements d’affaires critiques. Vous allez avoir à ajouter de nouvelles fonctionnalités et a en faire l’entretien. • Nous avons observés les choses suivantes: – Classes de la logique d’affaire qui fait 32 000 lignes. – Une interface de 2000 lignes (incluant une ligne de commentaire par méthode) été créé récemment pour vous permettre d’introduire des tests. • Ce message s’auto-détruira dans 5 secondes …..
  2. Bon après-midi, Ethan. • Votre mission, si vous l’acceptez, consiste

    à vous occuper d’un système informatique qui n’est pas nouveau ni trop vieux, mais qui n’a aucun tests automatisé. • Par contre, il est au cœur de plusieurs traitements d’affaires critiques. Vous allez avoir à ajouter de nouvelles fonctionnalités et a en faire l’entretien. • Nous avons observés les choses suivantes: – Classes de la logique d’affaire qui fait 32 000 lignes. – Une interface de 2000 lignes (incluant une ligne de commentaire par méthode) été créé récemment pour vous permettre d’introduire des tests. • Ce message s’auto-détruira dans 5 secondes ….. MISSION
  3. Qui sommes-nous ? • Karl Métivier – Architecte Logiciel –

    Développeur – Coach Agile – Formateur • Yves St-Hilaire – Soutien au développement – Accompagnement, mentorat – Développement BI
  4. Histoire d’un système • On change notre processus, on passe

    à Scrum. • On nous demande d’ajouter des tests unitaires automatisés au code existant. – Oups, le système n’a pas été prévu pour cela… • Comment avoir le temps pour cela ? – Réunion pour discuter des bogues courants. – Documentation à mettre à jour. • Au final, problème de dette technique.
  5. Définitions pour le Legacy Code • Du code Legacy, c’est

    du code: – sans tests unitaires - Michael Feathers – plus vieux que ceux qui y travaillent – modifications en mode « patchage » – nécessitant un guide du marais pour s’y retrouver! • Enfreint constamment les principes SOLID • On n’ose pas y toucher. • Et les Legacy Systems ?
  6. Code « Legacy » Quand vous avez à travailler avec

    ça, c’est quoi votre feeling ?
  7. Pourquoi est-on pognés avec ça ? • Délais courts de

    développement • Plusieurs personnes y sont passées • Conception Legacy? –Architecture identique au dossier fonctionnel • Peu d’efforts alloués pour l’amélioration –Le système fonctionne, on n’y investit rien
  8. Le dilemme du refactoring • Pour faire du refactoring, on

    doit avoir des tests • Pour mettre en place des tests, on doit refactoriser.
  9. Cas 1 – Classe sans injection de dépendances • Pas

    de possibilité d’injecter un mock • Plusieurs appelants l’utilisent, souvent on ne peut les modifier
  10. Cas 1 – Classe sans injection de dépendances Comment ?

    • Pour la classe qu’on veut mocker : – Ajout d’une interface • À la classe à tester : – Ajout d’un constructeur permettant l’injection – On lui injectera l’instance à utiliser, ou une Factory • Les appelants ne sont pas impactés • On permet l’injection, mais les appelants existants ne l’utilisent pas
  11. Cas 1 – Ajout d’injection – Comment public class MyClass

    { private IFileReader reader; public MyClass(string fileName) { // original code // ... reader = new MyFileReader(fileName); } public MyClass(IFileReader injectedReader) { // original code // ... reader = injectedReader; } }
  12. Cas 1b – Classe sans injection de dépendances Comment ?

    • Autre technique : Patron « Test Specific Subclass » • Classe à mocker : ajout d’une interface à la classe • Classe à tester : – Ajout d’une méthode virtuelle « ObtenirInstanceClasseAppelee » • Dans le projet de test : – Hériter de la classe à tester – Implémenter notre propre « ObtenirInstanceClasseAppelee »
  13. Cas 1b – Test specific subclass – Comment? public class

    MyClass { protected int someProtectedInfo = 42; private IFileReader reader; public MyClass(string fileName) { reader = GetReader(fileName); } protected virtual IFileReader GetReader(string fileName) { return new MyFileReader(fileName); }} public class MyClassSpecificSubclass : MyClass { public IFileReader InsertMockHere; public MyClassSpecificSubclass(IFileReader aReader) { InsertMockHere = aReader; } protected override IFileReader GetReader(string fileName) { return InsertMockHere; } public int GetInternalInfo() { return someProtectedInfo; }}
  14. Cas 2 – La classe iceberg • Reconnaissable facilement –

    Grosse • Milliers, dizaines de milliers de lignes – Peu de méthodes publiques • Comptées sur une seule main • C’est quoi le problème? – Grande complexité cyclomatique – Interdépendances entre les méthodes – Donc difficile à tester
  15. Cas 2– La classe iceberg – Comment? • Identifier les

    différentes responsabilités – Noms de méthodes – #Region ou zones de commentaires • Refactoriser en plusieurs classes • Si impossible : – Identifiez les méthodes qui seraient publiques avec un refactoring – Changer la visibilité et testez ces méthodes
  16. Cas 3 – Méthode statique • Une méthode statique, l’équivalent

    d’un singleton • Une seule version possible pour tout le système – Donc pas mockable • Pas un problème pour la tester • Mais un véritable problème pour tester les méthodes qui l’appellent
  17. Cas 3 – Méthode statique – Comment? • Ajout d’une

    interface à la classe • Ajout de méthodes d’instance correspondant aux méthodes statiques – DRY : la méthode d’instance peut appeler la méthode statique! – Les appelants ne sont pas affectés • Éventuellement on pourra enlever complètement les méthodes statiques
  18. Cas 3 – Méthode statique – Code public class ClassUnderTest

    { public void MethodUnderTest() { // ... var number = AnotherClass.GetNumber(); if (number > 0) { } else { } // ... } } public class AnotherClass { public static int GetNumber() { return 4; } }
  19. Cas 3 – Méthode statique – Code public class ClassUnderTest

    { private IAnotherClass _anotherClass; public ClassUnderTest() { _anotherClass = new AnotherClass(); } public ClassUnderTest(IAnotherClass anotherClass) { _anotherClass = anotherClass; } public void MethodUnderTest() { // ... var number = _anotherClass.GetNumber(); if (number > 0) { } else { } // ... } } public class AnotherClass: IAnotherClass { public static int GetNumber() { return 4; } int IAnotherClass.GetNumber() { return AnotherClass.GetNumber(); } }
  20. Mais en avez-vous vraiment besoin ? • Parfois, l’ajout de

    tests unitaires demande beaucoup d’efforts pour peu de gains • Évaluer d’autres opportunités – CodedUI / Selenium – Tests intégrés, mocker uniquement les données – Tests comparatifs • Pas toujours les meilleures pratiques, mais faut s’adapter au contexte!
  21. Comment le BDD m'a aidé dans mon débogage • Partir

    d’un cas d’utilisation (déjà implémenté) et le descendre en étape BDD du début (contrôleur UI), passer par le service et aboutir dans une BD en mémoire • C’est long • On vérifie toutes les dépendances et on traverse toutes les couches • C’est long, mais après coup notre compréhension du code s’est vraiment améliorée • En plus, le test BDD reste et peut être rejoué !
  22. État d’esprit pour déboguer de Legacy Code • Voir le

    code comme une scène de crime • Faire un profil de l’agresseur (ou de ce qui cause le problème) • Analyser les hot-spots • Calculer la complexité • Faire la dissection de l’architecture • Cartographier une carte de connaissances de votre système • Impact sur l’existant
  23. C’est impossible d’en faire chez nous car… • Nous autres,

    c'est différent • On a un système de mission critique à l'entreprise • Nos utilisateurs ont le contrôle et le budget • Notre système est très complexe • On a des données nominatives • …
  24. C’est notre devoir d’être professionnel Du code propre n’apparaît pas

    de lui-même: • Vous avez à le produire • Vous avez à le maintenir • Vous en faites un engagement professionnel
  25. Combattre le résistance en discutant • La plupart des gestionnaires

    défendent leurs échéanciers et les requis avec passion. – Cela fait partie de leurs responsabilités. • Votre responsabilité : – Défendre également le code avec passion. • Ayez le courage de dire la vérité et de travailler pour arriver à un terrain d’entente. • Discuter avec votre PO ou votre chef d’équipe. Il devrait être sensible à la qualité produite. Donc de supporter l’équipe quand il sent qu’un refactoring est nécessaire.
  26. Il faut alors être stratégique • Cela ne donne pas

    grand chose de travailler sur du code qui va bien et qui n’a pas de problème régulièrement. Don’t fix it, if it’s not broken. • Trouver les points chauds de votre système: – Bogues réguliers – Difficiles à travailler – Modification à faire prochainement – Logique d’affaires importante • Progresser par la technique des petits pas.
  27. Bien évaluer Valeur de cet investissement : • Potentiel •

    Bloquant actuel • Criticité du système • Nombre de personnes impactées • Durée de vie du système • Refonte prévue?
  28. La résistance peut donc être combattue • C’est souvent le

    premier pas le plus difficile. • Ne pas oublier : – Être stratégique – Évaluer le tout • Y aller un test à la fois: – Et son Refactoring de code qui le suit.
  29. Comprendre le code • Les tests nous apportent une façon

    de comprendre le code. • D’une certaine manière, les tests nous font travailler dur pour arriver à cette compréhension. • Il est facile de faire des tests en présence d’une bonne conception.
  30. Ne pas hésiter à utiliser des outils modernes • Legacy

    != outils désuets • Exemples : – Intégration continue – Dernière version de l’IDE – Dernières versions des librairies et frameworks – Système Legacy dans Docker
  31. Ne pas oublier les bases • OOP • Clean Code

    • Maîtrisez et appliquez les principes SOLID • Boy Scout Rule • Agile Modeling (Scott Ambler)
  32. Se prémunir contre le Legacy Code à la base •

    Les développeurs doivent demander Quoi, Pourquoi et pour Qui avant de trouver le Comment. • Ce n’est pas aux analystes et utilisateurs de leur dire le Comment. • On veut savoir du client/PO qu’est-ce qu’ils veulent, pourquoi ils le veulent et pour qui cela va être utile.
  33. Faire la conception en équipe • Les meilleures conceptions sont

    effectuées en équipe, et non par une seule personne. • La compréhension de l’architecture ainsi que son adoption est répandue dans toute l’équipe. • Pourquoi s’en passer ?
  34. Ou du Mob Programming ! • Approche où l’équipe complète

    (client, analyste et PO aussi) travaille sur la même chose : – Au même endroit – En même temps – Sur le même ordinateur • Un peu similaire au pair programming
  35. En résumé, nous avons vu… • C’est quoi du Legacy

    Code • Comment faire pour le tester • Comment affronter la résistance • Comment s’en prémunir au jour le jour
  36. Alors, tester du du Legacy Code, • Met à l’épreuve

    et renforce nos habilités en: – Programmation Orientée-Objet – Conception & Architecture • Offre un challenge qui peut donc être instructif et amusant ! • Nous rend plus professionnel en bout de ligne.
  37. Références 1/2 • Podcast Hanselminutes 2016-08-05 « Learning to love

    Legacy Code with Andrea Goulet from CorgiByte » – http://hanselminutes.com/539/learning-to-love-legacy-code- with-andrea-goulet-from-corgibytes • Patron « Test Specific Subclass » – http://xunitpatterns.com/Test-Specific%20Subclass.html • XKCD Goto – https://xkcd.com/292/
  38. Pour nous rejoindre • Karl Métivier – Courriel: [email protected]

    LinkedIn: https://www.linkedin.com/in/karlmetivier/fr – Twitter: @karlmet – Blogue: https://excellenceagile.com/ • Yves St-Hilaire – Courriel: [email protected] – LinkedIn: www.linkedin.com/in/yves-st-hilaire – Twitter: @sthiy