La vie d'un développeur ce n'est pas toujours de travailler à la création d'une nouvelle application. Au contraire nous serons souvent amené à faire ce que j'appelle de l'Archéologie. Cela veut dire entrer dans du code écrit il y a quelques années, être capable de faire fonctionner une vieille application, et surtout, être capable de la moderniser sans l'abimer. J'ai regroupé quelques outils et quelques pratiques apprises ces dernières années, mais n'hésitez pas à compléter.
Règle 1 : respectez les pièces rares
Règle 2 : protéger avec une bâche
Règle 3 : prenez des radiographies du patient
Règle 4 : commencez par ce qui n'est pas cher
Règle 5 : utilisez des scanners pour détecter les peintures cachées
Règle 6 : mettez en place un suivi
Règle 7 : pensez au futur
Règle 1 : respectez les pièces rares
Dans chaque logiciel, dans chaque application que j'ai vu, il y a un petit coeur qui bat. Il y a souvent quelques classes particulièrement compliquées, dont l'historique sur Subversion est très chargé. Mon premier conseil : respectez le travail de vos anciens. Imaginez qu'à l'époque où ce code a été construit, ils n'avaient pas les outils, les blogs et l'information dont vous disposez. Soyez donc humble et ne critiquez pas à tort et à travers la qualité du code ou son architecture de l'époque. Avec un peu de chance, un EJB 2.1 Statefull codé en Facade avec des EJB 2.1 Stateless derrière prendra de la valeur avec les années… ou pas.
Plus sérieusement, il y a des parties de code qu'il convient de respecter. L'historique des bugs corrigés raconte une histoire, l'évolution du logiciel et les problèmes rencontrés par l'équipe. Je conseille de passer du temps avec les développeurs encore présent, et de bien faire attention à ne pas effacer ces fichiers, qui racontent une histoire.
Un bug corrigé c'est un bug corrigé…. Sur des problèmes compliqués comme le pricing d'une Option, croyez moi vous ne faîtes pas le fier.
Règle 2 : protégez avec une bâche
Lorsque vous vous lancerez dans du refactoring, il est important d'isoler votre travail du reste du projet. Identifiez clairement les dépendances et les limites de votre travail, et dîtes-vous : je m'arrêterai là. Utilisez par exemple mvn dependency:analyze et mvn dependency:tree pour regarder le couplage de vos modules, si vous utilisez Maven. Il est très important de définir le périmètre des classes ou des packages sur lesquel vous allez intervenir, et de vous y tenir. Sans quoi vous vous retrouvez à réécrire le gestionnaire de clic de la souris alors que vous aviez commencé à modifier une JTable…
Règle 3 : prenez des radiographies du patient
Peut-être la règle la plus importante : blindez le code existant avec des tests unitaires via JUnit, des mocks avec Mockito. Sachez qu'il est possible de mocker des classes concrètes avec EasyMock Class Extension 2.2 depuis fin 2007. Je préfère Mockito qui est plus léger et qui force à coder ses tests à la sauce Given/When/Then.
Les tests pour moi sont la radiographie du patient. C'est la garantie que votre amélioration ne casse pas le logiciel. Faites des tests d'intégration avec Fit par exemple, ou FitNess. Bref c'est de la non-régression, le B.A Ba du bon développeur.
Enfin si vous faîtes du tuning, prenez des mesures avant de commencer à modifier une ligne de code. Combien de temps pour traiter en moyenne un fichier de 50 000 lignes ? Combien de temps pour charger la 3ème page de la liste des produits ? Pensez à prendre scrupuleusement des notes et des chiffres avant de toucher quoique ce soit. Cela s'applique aussi au temps nécessaire pour compiler votre projet par exemple. Bref pensez chiffres.
Règle 4 : commencez par ce qui n'est pas cher
Ce qui est cher est risqué. Ce qui a plus de valeur par contre, c'est quelque chose de très compliqué que l'on peut corriger très rapidement. Première idée que j'ai en tête : passez à Java 6. Cela ne coûte rien, ou très peu. N'attendez pas que quelqu'un vous « autorise » à le faire. Le pilote de l'avion c'est vous. Le chirurgien c'est vous. Faîtes-le, allez voir le client ou les gens du métier, montrez-leur que le logiciel tourne mieux, et laissez-le ensuite s'occuper du psycho-rigide qui ne veut pas passer à Java 6 alors que vous êtes en Java 1.4. Vous pouvez lui faire peur en expliquant que Java J2SE 5 n'est plus supporté par SUN Microsytems depuis le 3 novembre 2009 afin qu'il se bouge un peu.
Ce qui ne coûte pas cher mais qui est un peu plus risqué, c'est les mises à jour des librairies. Vérifiez que vous êtes à jour quant aux différentes versions de vos Jars. Ce matin, nous avons trouvé un bug dans Hibernate 3.2.6 avec IBM WebSphere, et le lookup du Transaction Manager. En passant à une version plus récente d'Hibernate, le problème est résolu.
Ce qui demande un peu d'effort, c'est la partie Build. Si vous êtes avec Apache Ant et que vous en êtes content, restez avec celui-ci. Ne migrez pas à Maven ou Gradle pour être dans l'air du temps ou pour faire plaisir à un consultant. Si par contre votre build est un tas fumant et qu'il faut 23 minutes pour compiler le projet avec Maven 1, que personne ne sait vraiment comment cela marche… jetez tout. C'est ce que nous avons fait fin 2008 sur un projet avec 15 développeurs. Le build total est passé à 9mn, imaginez le temps gagné par développeur chaque jour.
Maven 2.2.x tourne vraiment bien, et il est rapide. Testez-le aussi, mais attention aux coûts cachés plus tard : il faut s'adapter à Maven afin d'en tirer le meilleur parti, plutôt que de le tordre et d'essayer de le faire marcher selon les noms de ses répertoires, et de son organisation.
Règle 5 : utilisez des scanners pour détecter les peintures cachées
J'ai l'image de ces 2 scientifiques, qui radiographient la Joconde et qui trouvent des traits de dessin de Leonard de Vinci. Imaginez leur surprise et leur joie…
Bon pour nous c'est un peu moins fun, mais attendez de voir où je veux vous emmener. Je vous conseille de tester des outils de profiling et de monitoring, afin d'identifier les points noirs de votre application. Que ce soit en terme de mémoire, comme en terme de CPU, mon préféré est yourKit que j'ai découvert chez Reuters avec Jean-Paul Schemali (spéciale dédicace) et aussi JProfiler, que j'ai beaucoup utilisé. Ces outils sont payants, mais croyez-moi, ils valent la dépense grâce à ce que vous allez économiser.
Sinon les outils de la JVM HotSpot de SUN Microsystems permettent aussi de regarder ce qu'il se passe à l'intérieur de l'application, et de corriger le tout.
Dans la série des autres scanners que j'utilise, je conseille FindBugs pour auditer le code source, et voir les bugs éventuels de l'application. Si vous voulez aller plus loin, vous pouvez installer et utiliser Sonar, j'en parle au point 6.
Un outil comme PMD est aussi gratuit et open-source. Il permet d'auditer l'ensemble du code, de signaler le code mort qui n'est jamais appelé, de vous informer des duplications et d'éventuels bugs.
Enfin je conseille aussi de nettoyer les classes : effacez le code en commentaire. De ma propre expérience, 9 fois sur 10 lorsque je décommente du code dans une classe, il ne compile plus. Le reste de la classe a changé, ou il ne sert à rien. Soyez sans pitié : effacez le code et utilisez le gestionnaire de version pour sauver vos anciennes versions. Rien ne se perd de cette façon.
Pensez aussi à nettoyer les dépendances Maven ou Ant, et à vous assurer que vous avez réellement besoin de toutes ces librairies. Avec Java 6 les choses ont changé, prenez le temps de nettoyer le code puis d'effacer les anciennes librairies.
Règle 6 : mettez en place un suivi
Une fois votre application modernisée, ou plutôt avant même d'y avoir touché, mettez en place des outils de suivi de la qualité du code, de la couverture des tests, de la performance en mémoire et CPU… Bref installez une Tour de contrôle avant de faire de l'archéologie.
Sans hésiter, installez Sonar afin de mettre votre dette technique sous contrôle. Il demande un peu d'efforts pour être correctement réglé, mais ce que j'aime beaucoup c'est le suivi. Il vous donnera un indicateur de progrès. Et il sera là aussi pour signaler aux développeurs qu'il surveille la qualité de votre produit.
Donc mettre en place un suivi du patient, afin de s'assurer qu'il ne revienne pas sur la table d'opération toutes les 3 semaines.
Règle 7 : pensez au futur
J'ai en tête la célèbre phrase du wiki C2 sur la page Code for the Maintainer :
« Always code as if the person who ends up maintaining your code is a violent psychopath who knows where you live. »
Ce qui donne
« Code toujours comme si tu savais que la personne qui maintiendra ton code est un psychopathe violent qui sait où tu habites… »
En fait il faut être eco-responsable. Vous faîtes du tri sélectif ? Et bien codez proprement. Pensez que ce sera peut-être vous dans 6 ans qui serez appelé pour corriger un problème sur votre logiciel. Ou peut-être votre fils qui aura trouvé votre nom sur Google dans un projet open-source Lambda dans 15 ans… Bref codez pour être fier de montrer votre programme à votre fils dans quelques années.
Conclusion
Je me demande si les projets et les applications passent la barre des 10 ans dans le monde Java. Je ne parle pas d'autres langages, je parle que de Java. Avec les projets ou les produits sur lesquels j'ai travaillé, j'ai déjà la réponse. Je sais ce qu'ils sont devenus. J'ai eu par contre à reprendre du code de nombreuses fois, et à faire ce travail de mise à jour, sans tout casser. Il y a donc une compétence « Docteur Love, maître du Lifting » à acquérir pour faire un bon développeur dans le monde Java.
Merci pour l'article, tout à fait d'accord sur la conclusion. Il ne faut pas hésiter à refactorer (quand on a pris ses précautions!).
Pour info, easymock class extension a été réintégré à easymock dans la version 3.0. Donc easymock le fait en natif maintenant 🙂
« Code toujours comme si tu savais que la personne qui maintiendra ton code est un psychopathe violent qui sait où tu habites… »
J'adore 😉
J'apprécie beaucoup ce petit tour d'horizon de l'archéologie, pour répondre à deux interrogations, mes deux premières expériences professionnelles en Java s'avèrent être des projets de plus de 10 ans en Java (un Java(5)/SWT/Oracle) et l'autre en Java(5).
Mais le monde de la banque est peut-être un microcosme, au moins pour la longévité des applications.
P.S. qq petits points :
– lien mort sur yourKit et lien à re-configurer pour fitNess
Vale
[Réponse de Nicolas= mreci, j'ai corrigé le lien de Fit, et par contre le site de YourKit est tombé, il ne marche plus pour l'instant]
Très bon article, ça donne envie de sortir sa blouse et son pinceau pour commencer à dépoussiérer du vieux code… qui sait sur quelle merveille on tombera ! Une erreur de logique ? Du lazy-loading des 3/4 de la base de données en 1 requête ? Voire pire, une méthode de 300 lignes de code non fluent sans commentaire… brrrr
Très intéressant.
J'aurais ajouté un mot sur quelques outils natifs d'Eclipse : Format, Organize imports, Sort members, Clean up (qui intègre les fonctionnalités des outils précités, et plus encore). Une fois bien configurés, ils permettent de faire une partie du ravalement pour un coût négligeable, pour peu qu'on les utilise de façon mesurée et intelligente.
En revanche, je ne connais pas les outils proposés par IntelliJ et Netbeans sur le même créneau.
« il faut s'adapter à Maven afin d'en tirer le meilleur parti, plutôt que de le tordre et d'essayer de le faire marcher selon les noms de ses répertoires, et de son organisation. »
Dans mon projet actuel GWT 2 + maven, il est resorti plutot l'inverse : adapter Maven à l'architecture de GWT 2.
Après des expériences comme RFS, la question est surtout comment avoir le budget pour mettre ces règles en place ? Parce que la c'est un véritable travaille de fond (mettre des tests, comprendre le fonctionnement de l'ensemble du plat de spaghetti).
@Yannick : le budget tu ne l'auras jamais. En fait tu auras tout un tas d'ennuis sur ton produit/ton projet si tu n'as pas ces outils. De longues soirées à essayer de faire marcher un machin… Donc je dirai qu'il faut travailler en préventif, non pas pour faire plaisir à un Architecte ou un Boss, mais simplement pour nous, pour éviter de rester à corriger du code obsolète, sans filet de sécurité. Je pense que cela fait partie des bonnes pratiques d'un bon développeur
Nicolas
Un ensemble de règles à garder en tête. Malheureusement, tant qu'on a pas fait soit-même un certain nombre d'erreurs, il est difficile de se contraindre à les mettre en pratique.
J'aime aussi pas mal la règle du boyscout : quand vous quittez une classe que vous avez ouvert précédemment, laissez l'endroit plus propre que vous ne l'avez trouvé en arrivant.
Ca peut être aussi simple qu'un changement de nom de variable, ou la correction d'une faute de français dans un commentaire…
Règle 2 : protégez avec une bâche ==> Je rajouterais:
Avant de faire du refactoring, vérifiez que le code à modifier est protégé par des tests unitaires. Si ce n'est pas le cas, ajoutez vous même les tests manquants: ils doivent représenter assez précisément le comportement du code avant refactoring. Dans ce cas, l'exercice du refactoring devra à tout moment conserver ce comportement, pour ne pas risquer de faire planter le reste de l'application ou de voir fleurir des bugs sur une longue période.
Il ne faut pas se fier à son bon sens. Imaginez que vous deviez refactorer une méthode qui créé une liste en découpant une chaîne de caractères par rapport aux espaces, genre « aa bb » -> [« aa », « bb »]. Mais cette méthode à la bonne idée de renvoyer une liste avec une chaîne vide lorsqu'on lui passe en paramètre une chaîne vide, genre « » -> [« »]. Et bien, dans ce cas, même si vous êtes du genre « » -> [], vous devrez aussi faire en sorte qu'après refactoring, votre nouveau code fasse « » -> [« »]. Donc mettez en place des tests unitaires qui seront exécutés régulièrement pour vérifier que votre code respect le comportement de l'ancien code.
Moderniser sans abimer, retoucher sans détruire, la maintenance de code ancien s'apparente souvent à la restauration de pièces de musée. Pas que l'oeuvre soit rare ou de qualité, mais juste ancienne et délicate.
Pour avoir mis la main plus que souvent dans du code de 5 à 10 ans, je plussoie l'ami Nicolas quand il parle de respecter le travail des anciens et de remettre le développement dans le contexte 'historique'.
Parce qu'il n'y avait pas le même niveau de JVM, de moteur, de framework de runtime, de test, parce que certaines contraintes techniques avaient été imposées, parce qu'à l'époque peut être on considérait que le Java ça allait bien pour faire de la page Web mais que le fonctionnel ou la richesse devait être ailleurs.
Au final, un vieux programme c'est une page ouverte sur le passé, et le connaitre c'est comprendre beaucoup de choses non écrites dans le programme ou les docs qui l'accompagnent 🙂
@Nicolas @hgomez: C'est en lisant des réflexions comme les vôtres qu'on fini par se dire que le logiciel à plus à faire avec la propriété intellectuelle qu'avec le brevet.
Excellent article, comme d'habitude. J'aime beaucoup la comparaison avec la médecine.
J'ai déjà mis en place ce genre de pratique dans nos développements. En ce qui concerne l'outillage (Hudson, Sonar, etc.), d'expérience, ça plait beaucoup à la hiérarchie… tant que le coût des licences est nul ! Par contre, pour ce qui est des produits propriétaires (yourKit que tu cites… mais je pense également par exemple à SonarJ pour le contrôle de l'architecture), c'est une autre paire de manches.
Hello,
Article très intéressant!
Dans les choses pas cher qui améliore considérablement la lisibilité du code et qui permet un refactoring dans de meilleurs conditions :
Le renommage des variables, méthodes, etc. Avec les outils de refactoring proposés par les IDEs actuels.
Le risque est quasi nul et la valeur ajoutée est énorme.
@Yannick G.
Ce qu'il y a d'extraordinaire avec le métier du développement logiciel, c'est que le budget est principalement une décision venant des développeurs eux-mêmes, du temps qu'ils décident, en leur ame et conscience, à allouer à telle ou telle activité.
Ce problème de budget, c'est un peu comme les éléphants de Ken Schwaber (*) : des personnes prennent des décisions qui n'ont pas de sens pour un observateur extérieur -par exemple modifier du code sans avoir pris le temps d'y mettre tous les tests qu'il fallait- parce que de mystérieuses forces les y conduisent.
(*) http://kenschwaber.wordpress.com/2010/07/27/the-elephant-in-the-room/
@l'auteur
Ce sont des régles de bon sens mais il ne faut pas sous-estimer le principal frein à leur mise en place : le collectif
Ces règles ne peuvent fonctionner que si l'ensemble des développeurs amenés à toucher au code acceptent de jouer le jeu. Et ça c'est parfois plus dur à obtenir qu'un budget…
Hello,
@Oaz : c'est une des principales difficultés que j'ai rencontrée dans mon équipe;concernant : « Ce sont des régles de bon sens mais il ne faut pas sous-estimer le principal frein à leur mise en place : le collectif
Ces règles ne peuvent fonctionner que si l'ensemble des développeurs amenés à toucher au code acceptent de jouer le jeu. Et ça c'est parfois plus dur à obtenir qu'un budget… »