Refonte et reprise de projet
Récupérer un développement mal fait
La norme internationale qui définit la qualité d’un logiciel, ISO/IEC 25010, compte neuf caractéristiques dans sa deuxième édition parue en novembre 2023. Deux de ces neuf tranchent ce que vaut un développement reçu d’une autre équipe, et elles ne portent pas sur la même chose. L’une range l’exactitude fonctionnelle, le degré auquel un produit fournit des résultats justes à ceux qui l’utilisent. L’autre porte sur ce qu’il en coûte de modifier ce produit une fois écrit, et elle s’appelle la maintenabilité. Un développement peut manquer l’une, l’autre, ou les deux, et la réparation ne se situe pas au même endroit selon le cas. L’expression « mal fait » les recouvre toutes les deux, si bien qu’à elle seule elle ne dit pas où porter la réparation. Les séparer sur votre projet demande deux relevés, l’un que vos équipes produisent sans développeur, l’autre qu’un outil rend en une seule lecture du code. Récupérer un développement mal fait commence par ce partage, avant tout chiffrage.
Deux défauts se cachent sous le même mot, et ils ne se prouvent pas de la même façon
La distinction compte parce que les deux défauts ne se constatent pas par les mêmes personnes. Le résultat faux se voit depuis vos écrans, par vos équipes, sur des dossiers qu’elles connaissent. Le second ne se voit que du côté du développement, et il ne vous atteint qu’en différé, sur le prix et le délai de la demande suivante. Les deux constats sont indépendants l’un de l’autre. Un développement peut rendre le bon résultat depuis sa mise en service et coûter cher à faire évoluer, et l’inverse existe aussi, un programme propre dont une règle de calcul donne un montant erroné.
Cette séparation change la question posée au moment de la reprise. Un résultat faux se répare sur la fonction concernée, et c’est l’état du module qui dit jusqu’où la réparation déborde. Un code coûteux à modifier ne se répare pas fonction par fonction, vous le payez à chaque changement, et sa remise à niveau se décide sur ce que vous prévoyez de modifier ensuite. Les deux entrent dans un chiffrage de reprise, chacun sur sa propre ligne.
Le résultat faux se constate sur vos propres dossiers
Ce constat ne réclame ni développeur ni accès au code source. Reprenez des dossiers réels déjà traités par vos équipes, ceux dont vous connaissez la réponse attendue parce qu’elle a été validée ailleurs, dans votre comptabilité ou dans un tableur tenu à part. Faites-les passer dans l’outil, en dehors de votre production, et notez l’écart entre ce qui sort et ce que vous attendiez.
Ce relevé vous donne un fait opposable, avec sa donnée d’entrée, son résultat obtenu et son résultat attendu. Il désigne une fonction précise et une seule, ce qu’aucune appréciation d’ensemble ne fait, y compris la vôtre.
Une troisième situation se glisse entre les deux et se traite ailleurs. Une fonction peut donner un résultat juste et différer de ce que vous aviez commandé. Le sujet devient alors contractuel, il se règle sur votre cahier des charges et vos comptes rendus de recette, et il rejoint les points à obtenir de l’équipe en place tant qu’elle travaille encore. Notez ces écarts à part, ils ne se chiffrent pas comme des corrections.
Vingt-neuf faiblesses nommées remplacent le jugement sur le code
Le second défaut se mesure par un audit de code, pas par une impression de lecture, et il a lui aussi sa norme. ISO/IEC 5055, publiée en 2021, mesure la structure interne d’un logiciel sur quatre plans, la sécurité, la fiabilité, l’efficacité des performances et la maintenabilité. Elle reprend à l’identique des mesures construites par le consortium CISQ, qui publie la liste des faiblesses retenues pour chaque plan. Celle de la maintenabilité en compte 29. Un outil les repère par analyse statique, c’est-à-dire en lisant le code sans l’exécuter, et il les compte.
Deux d’entre elles donnent la nature de ces mesures. La liste retient le code mort, des portions qui ne peuvent jamais s’exécuter, avec un seuil fixé à 5 pour cent de code logiquement mort et à zéro pour cent pour le code structurellement mort. Elle retient aussi la duplication de code, le même traitement recopié à plusieurs endroits, dont le seuil par défaut se fixe à 10 pour cent des instructions de la portion concernée. Sur cette seconde faiblesse, la liste prévoit qu’un autre seuil soit arrêté avant l’analyse. Arrêtez-le avec le prestataire qui lancera l’outil, plutôt que de le découvrir dans son rapport.
Le jugement « le code est mauvais » devient ainsi un compte, faiblesse par faiblesse, fichier par fichier. Demandez ce compte, et vous saurez si le défaut se concentre sur une partie du développement ou s’il court sur l’ensemble. Ces deux réponses n’engagent pas le même montant.
Le verdict vous arrive d’un développeur qui n’a pas écrit ce code
Le jugement « mal fait » se forme devant du code, et il vous parvient par un développeur à qui vous avez montré le travail d’un autre. Joel Spolsky décrivait cette position dès avril 2000, en une phrase qui tient tout son argument, « il est plus difficile de lire du code que d’en écrire ». Il y ajoutait le penchant du métier, les programmeurs étant selon lui des architectes dans l’âme, dont le premier réflexe devant un terrain occupé est de raser pour rebâtir.
Un développeur devant le travail de quelqu’un d’autre voit donc d’abord ce qu’il ne comprend pas, et ce qu’il ne comprend pas lui coûte du temps avant de lui apprendre quoi que ce soit. C’est ce mécanisme qui produit la réécriture de confort, celle qui remplace un travail qui fonctionne par un travail équivalent, écrit dans des habitudes que le nouvel intervenant maîtrise. Vous la payez au prix d’un développement neuf et vous en ressortez avec les mêmes fonctions.
Ce penchant ne disqualifie pas l’avis, il oblige à l’instruire. Un développeur qui annonce un code inexploitable a parfois entièrement raison, et il le démontre alors sur les trois pièces qui suivent.
Trois demandes qui transforment un avis en constat
Demandez d’abord un cas, c’est-à-dire quelle fonction produit un résultat faux, avec la donnée d’entrée qui le déclenche et le résultat que le développement aurait dû rendre. Une réponse qui reste au niveau du général décrit une gêne de lecture plutôt qu’un défaut.
Demandez ensuite le compte, le relevé des faiblesses trouvées, leur nombre et les fichiers où elles se concentrent. Un outil d’analyse statique rend ce relevé en une lecture, sur le code tel qu’il est, sans que personne ait à en réécrire une ligne.
Demandez enfin l’étendue, la part du développement réellement concernée, une fonction, un module ou la totalité. Un défaut qui se concentre sur une zone laisse le reste utilisable, et cette réponse écarte la réécriture complète avant même le chiffrage.
Ce que la réécriture complète efface, et les cas où elle reste la bonne réponse
Spolsky appelait la réécriture du code depuis zéro la pire erreur de stratégie qu’une entreprise de logiciel puisse commettre, et son argument portait sur ce qui disparaît au passage. Le vieux code a servi, il a été testé, quantité de bugs y ont été trouvés puis corrigés. Ces corrections tiennent parfois en une ligne, elles ont demandé des semaines d’usage réel avant d’être repérées, et elles s’en vont le jour où le développement recommence sur un fichier vide. Il en tirait une mesure du coût, celui d’offrir deux ou trois ans d’avance à ses concurrents.
Sur un développement d’entreprise, ces corrections portent vos cas limites. Un client facturé dans deux devises, un contrat qui change de barème en cours d’année, une exception accordée à un gros compte : ces règles ont été traitées une par une, et rien ne les répertorie ailleurs que dans le code lui-même. Un développement neuf les rencontrera à son tour, sur vos vrais dossiers cette fois. Quand elles ne figurent nulle part par écrit, le premier chantier consiste à remonter les règles appliquées depuis le code lui-même, et ce travail sert autant à la reprise qu’à la reconstruction.
Deux situations renversent malgré tout cette conclusion, et une troisième la rend sans objet. La première tient au périmètre, quand l’outil a été conçu pour une activité qui n’est plus la vôtre, et le sujet devient alors celui d’une application dont le découpage ne suit plus le métier. La seconde tient au socle, quand la remise à niveau technique dépasse à elle seule le coût d’un développement neuf, ce qui se rencontre sur un projet resté longtemps sans intervention. Reste le cas où vous ne détenez pas le code source, et il n’y a alors rien à trier tant que la récupération des fichiers auprès de celui qui les garde n’a pas abouti. Détenir les fichiers ne dit pas non plus qui détient les droits dessus : la cession de propriété intellectuelle sur un développement se prouve par un écrit distinct du seul dépôt du code, prestataire encore joignable ou non, et elle se vérifie avant tout chiffrage de la reprise.
La dette technique se chiffre en deux parts, et un devis n’en montre qu’une
Le rapport publié en novembre 2022 par le consortium CISQ sur le coût de la mauvaise qualité logicielle aux États-Unis découpe la dette technique en deux, et ce découpage sert directement à lire un devis de reprise. Le principal désigne le coût du refactoring, les travaux de remise à niveau du code jusqu’au niveau de maintenabilité visé. L’intérêt désigne l’effort supplémentaire que les développeurs dépenseront sur chaque modification tant que ces travaux n’ont pas eu lieu.
Un devis de reprise ne fait apparaître que le principal, puisque l’intérêt se paie plus tard, demande par demande. Les auteurs du rapport écrivent d’ailleurs qu’ils ne disposent pas encore de bonne estimation de cet intérêt, ce qui vous dispense de le réclamer à qui que ce soit. Le même rapport liste les signes d’une organisation qui porte trop de dette, et l’un d’eux tient en une ligne, une demande de modification pourtant simple qui se transforme en projet à part entière. Une remise à niveau chiffrée dans un devis vous demande donc de la comparer à une dépense que vous êtes seul à avoir vue passer, celle de vos évolutions précédentes.
Le tri fonction par fonction, sur vos cas à vous
Ce tri commence par la constitution de votre jeu de cas réels. Sortez entre dix et vingt dossiers déjà traités, en couvrant vos cas ordinaires et les exceptions que vos équipes savent nommer. Pour chacun, notez la réponse attendue avant la première exécution, faute de quoi c’est l’outil qui fixera la référence.
Remettez ensuite le développement en marche en dehors de votre production, sur un environnement dédié, et faites-y passer chaque dossier. Une fonction ressort alors dans l’un de deux états, elle rend le résultat attendu ou elle rend un résultat faux. Deux situations ne se laissent pas trancher ainsi, celle de la fonction absente alors qu’elle figurait à la commande et celle de la fonction qui existe et diffère de ce qui avait été commandé. Elles sortent du tri technique et rejoignent le relevé contractuel évoqué plus haut.
Rapprochez ce classement du relevé de faiblesses, fichier par fichier. Le croisement des deux produit la décision, fonction par fonction. Une fonction juste dans un module sain se garde telle quelle. Une fonction juste dans un module chargé de faiblesses se garde aussi, tant que vous ne prévoyez pas d’y toucher, parce que la maintenabilité ne se paie que sur ce que vous rouvrez. Une fonction fausse se répare dans les deux cas, et c’est l’état de son module qui dit à quel prix : dans un module sain la réparation reste locale, dans un module chargé de faiblesses elle rouvre le module, et c’est la seule situation où réécrire ce module se discute.
Un chiffrage bâti sur le seul mot « mal fait » saute cet arbitrage. Il vous fait payer d’un bloc la remise à niveau de portions de code que personne ne rouvrira jamais, quand la maintenabilité, elle, se paie au fil de vos évolutions. Rapprochez ce classement module par module de la liste de vos évolutions déjà prévues, et vous verrez quelles zones se remettent à niveau maintenant et lesquelles attendent.
Faire chiffrer le tri avant d’engager la reprise
Ce tri produit un document, module par module et fonction par fonction, avec le classement juste ou faux de chacune et le compte des faiblesses relevées. Vous le commandez sans engager la reprise, et n’importe quelle équipe peut le lire, y compris celle que vous choisirez de ne pas retenir.
La reprise d’un développement laissé par une autre équipe reprend ce tri dans un classement plus large, terminée, commencée, absente ou déviante. Une fonction juste ou fausse mais bien présente y ressort terminée. Une fonction s’ajoute à ce classement quand le code s’arrête avant la règle qui la rendrait juste ou fausse, elle ressort commencée. Les fonctions absentes ou déviantes y entrent aussi, sans que cela change le terrain contractuel où vous les traitez par ailleurs. Nous redémarrons le code chez nous, puis nous lui soumettons vos dossiers réels, un par un, et ce classement en sort. Quand le périmètre à examiner dépasse le seul développement et touche aux données, à l’hébergement ou aux accès, un état des lieux technique facturé seul couvre ces points sans engager la suite.
Le rendez-vous de chiffrage ne s’ouvre alors plus sur la valeur du travail reçu. Il s’ouvre sur une liste : ce qui se garde, ce qui se répare, et le montant de chacun.
Sources
ISO/IEC 25010:2023, Systems and software engineering, Systems and software Quality Requirements and Evaluation (SQuaRE), Product quality model, deuxième édition, novembre 2023, https://www.iso.org/standard/78176.html
ISO/IEC 5055:2021, Information technology, Software measurement, Software quality measurement, Automated source code quality measures, 2021, https://www.iso.org/standard/80623.html
List of Weaknesses Included in the CISQ Automated Source Code Maintainability Measure, CISQ, juin 2019, https://www.it-cisq.org/cisq-files/pdf/Maintainability-Weaknesses.pdf
The Cost of Poor Software Quality in the US: A 2022 Report, Herb Krasner, CISQ, novembre 2022, pages 28 et 29, https://www.it-cisq.org/wp-content/uploads/sites/6/2022/11/CPSQ-Report-Nov-22-2.pdf
Things You Should Never Do, Part I, Joel Spolsky, 6 avril 2000, https://www.joelonsoftware.com/2000/04/06/things-you-should-never-do-part-i/