J'ai vu le livre Travailler efficacement avec Legacy Code recommandé plusieurs fois. Quels sont les points clés de ce livre?
Y a-t-il beaucoup plus à faire avec le code hérité que l'ajout de tests unitaires/d'intégration puis la refactorisation?
Le principal problème avec le code hérité est qu'il n'a aucun test. Vous devez donc en ajouter (puis plus ...).
En soi, cela prendrait beaucoup de travail, comme l'a noté @mattnz. Mais le problème spécial du code hérité est qu'il n'a jamais été conçu pour être testable . Donc, typiquement, il s'agit d'un énorme gâchis alambiqué de code de spaghetti, où il est très difficile ou carrément impossible d'isoler de petites pièces à tester à l'unité. Donc avant les tests unitaires, vous devez refactoriser le code pour le rendre plus testable.
Cependant, pour refactoriser en toute sécurité, vous devez avoir des tests unitaires pour vérifier que vous n'avez rien cassé avec vos modifications ... C'est le hic 22 du code hérité.
Le livre vous apprend comment sortir de ce piège en apportant les modifications minimales et les plus sûres au code juste pour permettre les premiers tests unitaires. Ceux-ci ne sont pas destinés à rendre la conception plus agréable, mais uniquement à permettre des tests unitaires. En fait, parfois, ils rendent le design plus laid ou plus complexe. Cependant, ils vous permettent d'écrire des tests - et une fois que vous avez mis en place des tests unitaires, vous êtes libre d'améliorer la conception.
Il existe de nombreuses astuces pour rendre le code testable - certaines sont en quelque sorte évidentes, d'autres pas du tout. Il y a des méthodes auxquelles je n'aurais jamais pensé, sans lire le livre. Mais ce qui est encore plus important, c'est que Feathers explique quoi rend précisément une unité de code testable. Vous devez réduire les dépendances et introduire des barrières dans votre code, mais pour deux raisons distinctes:
Couper les dépendances en toute sécurité peut être délicat. Introduire des interfaces, des simulacres et injection de dépendance est propre et agréable comme objectif, mais pas nécessairement sûr à faire à ce stade. Donc, parfois, nous devons recourir à la sous-classe de la classe testée afin de remplacer une méthode qui, normalement, par exemple démarrer une demande directe à une base de données. D'autres fois, nous pourrions même avoir besoin de remplacer une classe/jar de dépendance par une fausse dans l'environnement de test ...
Pour moi, le concept le plus important introduit par Feathers est coutures. Une couture est un endroit dans le code où vous pouvez changer le comportement de votre programme sans modifier le code lui-même . Construire des coutures dans votre code permet de séparer le morceau de code testé, mais cela vous permet également de sentir le comportement du code testé même lorsqu'il est difficile ou impossible à faire directement (par exemple parce que l'appel fait des changements dans un autre objet ou sous-système, dont l'état n'est pas possible d'interroger directement depuis la méthode de test).
Cette connaissance vous permet de remarquer les germes de la testabilité dans le tas de code le plus méchant, et de trouver les modifications minimales, les moins perturbatrices et les plus sûres pour y arriver. En d'autres termes, pour éviter de faire des refactorisations "évidentes" qui risquent de casser le code sans que vous vous en rendiez compte - parce que vous n'avez pas encore ayez les tests unitaires pour le détecter.
Des moyens rapides pour obtenir les points clés de travailler efficacement avec le code hérité
Je travaille sur une base de code de millions de lignes de code, dont certaines remontent aux années 80. C'est juste un logiciel, donc c'est juste une question d'écrire quelques tests unitaires, donc vous pouvez aller le refactoriser et le rendre tellement meilleur.
Le mot clé ici est juste - c'est un mot à quatre lettres qui n'appartient au vocabulaire d'aucun programmeur, et encore moins à celui qui travaille sur des systèmes hérités.
Combien de temps pensez-vous qu'il faut pour écrire un test unitaire, pour tester une heure d'effort de développement? Pour la discussion, disons une autre heure.
Combien de temps est investi dans ce système hérité de 20 millions d'années? Disons, 20 développeurs pendant 20 ans fois 2000 heures/an (ils ont travaillé assez dur). Choisissons maintenant un nombre - vous avez de nouveaux ordinateurs et de nouveaux outils, et vous êtes tellement plus intelligent que les gars qui ont écrit ce morceau de $% ^^ en premier lieu - disons que vous en valez 10. Avez-vous 40 années-hommes, eh bien, avez-vous ...?
La réponse à votre question est donc qu'il y a beaucoup plus. Par exemple, cette routine qui fait 1000 lignes (j'en ai quelques-unes qui dépassent 5000), elle est trop complexe et c'est un morceau de spaghetti. Cela ne prendrait (encore un autre mot de quatre lettres) que quelques jours pour le re-factoriser en quelques routines de 100 lignes et quelques assistants de 20 lignes supplémentaires, non? FAUX. Dans ces 1000 lignes se cachent 100 corrections de bogues, chacune étant une exigence utilisateur non documentée ou un cas Edge obscur. C'est 1000 lignes parce que la routine originale de 100 lignes n'a pas fait le travail.
Vous devez travailler avec l'état d'esprit " si ce n'est pas cassé, ne le réparez pas ". Quand il est cassé, vous devez être très prudent lorsque vous le réparez - comme vous le rendez meilleur, que vous ne changez pas accidentellement autre chose. Notez que "cassé" peut inclure du code qui n'est pas gérable, mais qui fonctionne correctement, cela dépend du système et de son utilisation. Demandez "ce qui se passe si je fous ça et que ça empire", parce qu'un jour vous le ferez, et vous devrez dire au patron des patrons pourquoi vous avez choisi de faire ça.
Ces systèmes peuvent toujours être améliorés. Vous aurez un budget pour travailler, un calendrier, peu importe. Si vous ne le faites pas - allez en faire un. Arrêtez de l'améliorer lorsque l'argent/le temps est écoulé. Ajoutez une fonctionnalité, donnez-vous le temps de l'améliorer un peu. Corrigez un bug - encore une fois, passez un peu de temps supplémentaire et améliorez-le. Ne le livrez jamais pire qu'il ne l'était lorsque vous avez commencé.
Il y a deux points clés à retenir du livre.
Comme d'autres intervenants l'ont souligné, essayer de mettre à jour de manière préventive votre code hérité existant est un fool's errand . Au lieu de cela, chaque fois que vous devez apporter une modification au code hérité (pour une nouvelle fonctionnalité ou une correction de bogue), prenez le temps de supprimer son état hérité.
En un mot, Shell est vrai - l'ajout de tests et de refactorisation est ce dont il s'agit.
Mais le livre vous donne de nombreuses techniques différentes pour le faire avec du code qui est très difficile à tester et à refactoriser en toute sécurité.