Un assistant de génération produit du texte vraisemblable à partir de motifs vus ailleurs. Appliqué au code, ça donne des fichiers qui compilent, bien indentés, aux variables correctement nommées, et dont personne ne porte le raisonnement. C’est cette surface lisse qui me met en alerte quand on me confie la reprise.
Le code généré par IA a l’air fini, mais personne n’en porte le raisonnement. Avant de m’y fier, je vérifie ce qu’il fait réellement, par la lecture et par les tests, en traquant ce qui semble plausible et qui est faux.
Le porteur manquant
Quand j’écris une ligne, je sais pourquoi : quelle décision elle traduit, quels cas elle couvre, quel compromis j’ai accepté à cet endroit. Le code généré arrive amputé de ce porteur. On hérite d’un résultat plausible sans la pensée qui devrait le tenir, et on lui accorde du crédit parce qu’il a l’air sérieux. Tout le piège est là.
Ce que je traque, par ordre de gravité
Les dépendances fantômes d’abord. Le générateur invoque une fonction, un paramètre, parfois une bibliothèque entière qui n’existe pas ou qui ne fait pas ce qu’il imagine. L’an dernier, sur une reprise, je suis tombé sur un appel à une méthode d’un client HTTP avec un paramètre retry_backoff absent de cette version de la lib. Le code supposait que les tentatives s’espaçaient seules. Elles ne s’espaçaient pas. Sous charge, ça martelait l’API distante.
Viennent les incohérences cachées. Deux fichiers produits à des moments différents font des hypothèses contradictoires sur la même donnée : ici une date en chaîne ISO, là un timestamp. Sur le chemin nominal, rien ne se voit.
Puis les cas limites. Le scénario heureux est traité de façon convaincante ; les entrées vides, les valeurs aux bornes, une coupure réseau passent à la trappe en silence. Exactement ce qu’un développeur marqué par la production aurait anticipé.
La sécurité mérite une catégorie à part, parce que là le coût d’une erreur change de nature. J’ai vu des validations qui avaient l’allure d’une protection et laissaient tout passer : un contrôle d’accès qui vérifiait l’existence de l’utilisateur sans jamais regarder ses droits. Ça rassure à la lecture. Ça n’arrête personne.
Ma méthode de vérification
Je lis sans me soucier de l’élégance, en cherchant seulement si le code fait ce qu’il prétend. Toute ligne plausible dont je n’ai pas la preuve, je la note.
Ensuite j’écris des tests, en attaquant par les cas limites et les chemins d’erreur. C’est le moyen le plus direct de transformer « ça a l’air de marcher » en quelque chose de démontré. Comptez une bonne journée pour couvrir correctement un module de taille moyenne ; ce poste est presque toujours sous-estimé, justement parce que le code semble déjà fini. Enfin je le confronte à de vraies données, sales de préférence : encodages douteux, champs vides, valeurs hors plage. C’est là que les hypothèses fausses finissent par sortir.
L’image qui m’aide
Traitez ce code comme l’œuvre de quelqu’un de doué mais distrait, parti de la boîte, qui ne peut plus rien expliquer. Compétent en surface, sans garantie sur le fond. On ne s’y fie qu’après l’avoir fait parler.
Là où la méthode s’arrête
Reste à dire ce que cette discipline ne donne pas. Un audit prouve la présence d’un problème, jamais son absence : je peux relire, tester, rejouer des scénarios réels et passer quand même à côté d’une hypothèse fausse enfouie dans un chemin que je n’ai pas pensé à déclencher. Plus la base est grande, plus cet angle mort grandit. Ce que je vends, ce n’est donc pas un code certifié sain, mais une confiance gagnée ligne après ligne sur les zones qui comptent, et l’honnêteté de dire où je n’ai pas regardé.
À lire aussi
- J’hérite d’un projet sans documentation
- Ajouter des tests sur une base de code sans tests
- Cartographier ce qu’une application fait réellement
- Documenter l’essentiel pour ne plus dépendre d’une personne
- Décider quoi garder, refactorer ou remplacer
- Mettre un projet hérité sous contrôle de version propre