Code répétitif verbeux.
Les assistants IA alourdissent une logique simple de commentaires redondants, de cérémonie défensive et de blocs quasi dupliqués copiés-collés au lieu de réutiliser ou d'extraire le code existant, gonflant le nombre de lignes sans ajouter de valeur.
##Signs and Symptoms
Un relecteur repère le code répétitif verbeux quand un diff est bien plus long que le problème ne le justifie : chaque ligne est narrée par un commentaire qui se contente de la reformuler, les expressions simples sont enveloppées dans des échelles défensives de null/undefined, et la même forme de code réapparaît deux ou trois fois au lieu d'être factorisée en un seul helper. L'indice est un fort ratio commentaire/logique et ligne/comportement, plus des blocs qui auraient pu tenir en trois lignes de code idiomatique.
// Fonction pour obtenir le nom complet de l'utilisateur
function getFullName(user: User): string {
// Vérifie si l'utilisateur est défini
if (user === null || user === undefined) {
// Retourne une chaîne vide quand aucun utilisateur n'est fourni
return "";
}
// Récupère le prénom, par défaut chaîne vide
const firstName = user.firstName ? user.firstName : "";
// Récupère le nom, par défaut chaîne vide
const lastName = user.lastName ? user.lastName : "";
// Concatène le prénom et le nom avec un espace
const fullName = firstName + " " + lastName;
// Supprime les espaces et retourne le résultat
return fullName.trim();
}
Trois lignes de comportement enterrées dans ~12 lignes de cérémonie. Dans une vraie PR, on voit typiquement ce même schéma copié-collé en getDisplayName, getLabel et getInitials, chacun réécrivant à la main une logique qu'un util formatName() couvre déjà — l'odeur classique du Code dupliqué. Autres indices : constructeurs/wrappers vides de transmission, cérémonie try { ... } catch (e) { throw e }, et un validateur d'e-mail/URL sur mesure assis à côté du module de validation existant du projet.
##Reasons for the Problem
Pourquoi les modèles le produisent
- Biais de verbosité du token suivant. Les LLM sont entraînés sur d'énormes volumes de code de tutoriel, de Stack Overflow et de débutant où les commentaires pas à pas et la cérémonie explicite sont la norme. La suite la plus probable est la plus abondamment expliquée, pas la plus concise.
- Le RLHF récompense l'« apparence de minutie ». L'ajustement à l'utilité/la verbosité pousse les modèles vers une sortie qui paraît complète et auto-explicative — des commentaires sur chaque ligne, des vérifications défensives partout — que les évaluateurs et les utilisateurs récompensent même quand cela n'apporte aucune valeur.
- Aucun contexte du dépôt = aucune réutilisation. Sans la base de code environnante en contexte, le modèle ne peut savoir qu'un util
formatName()ouvalidateEmail()existe déjà, alors il le réécrit en ligne. C'est exactement la Sur-spécification d'OX Security (« des solutions hyper-spécifiques, à usage unique, au lieu de composants généralisables et réutilisables », trouvée dans 80 à 90 % du code IA) et l'Évitement des refactorings (80 à 90 %). - Génération, pas consolidation. Les agents émettent du code frais à chaque prompt et ne reviennent jamais dédupliquer. L'analyse 2025 par GitClear de 211 millions de lignes modifiées a constaté que le code copié-collé est passé de 8,3 % (2020) à 12,3 % (2024) et a dépassé pour la première fois les lignes « déplacées » (refactorisées), tandis que les lignes refactorisées chutaient d'environ 24 % à 9,5 % et que les blocs dupliqués de 5 lignes et plus étaient multipliés par ~8.
- Tout-commenter par défaut. OX Security a trouvé « des commentaires partout » dans 90 à 100 % du code généré par IA.
Pourquoi c'est nuisible
- Maintenabilité : plus de surface à lire et à modifier ; les commentaires redondants se désynchronisent du code et deviennent activement trompeurs (odeur des Commentaires de Fowler).
- Correction et sécurité : les blocs dupliqués signifient qu'un bug ou une vulnérabilité doit être corrigé en N endroits — les Bugs déjà-vu d'OX (70 à 80 %). Le code cloné corrèle avec 15 à 50 % de défauts en plus.
- Charge de revue : les gros diffs à faible signal masquent les vrais changements et induisent la fatigue du relecteur, si bien que de véritables problèmes passent à travers.
- Dette technique cumulative : chaque quasi-doublon rend l'extraction suivante plus difficile, enracinant le problème que le modèle ne peut pas voir d'un fichier à l'autre.
##Treatment
Tactiques de revue / prompting
- Forcez la réutilisation avant la génération : "Cherche dans la base de code les helpers existants (
formatName,validate*) et réutilise-les ; ne réimplémente pas." Fournissez les utils pertinents en contexte. - Budgétez la sortie : "Garde ceci sous ~15 lignes ; aucun commentaire qui reformule le code — uniquement des commentaires expliquant le pourquoi."
- Faites exécuter les outils par le modèle : exigez
eslint/ruffet une passe de duplicationjscpd, et faites-lui rapporter et corriger les violations avant de renvoyer. - Demandez le plus petit diff et une étape de déduplication explicite : "Si un bloc se répète, extrais une seule fonction partagée (Extraire une fonction) et appelle-la."
- Consolidez en revue : quand vous voyez la troisième quasi-copie, appliquez Extraire une fonction, Remonter une méthode ou Consolider des fragments conditionnels dupliqués, et Remplacer un commentaire par du code (renommez pour que le code se documente lui-même).
Refactoring (avant → après)
// après : commentaires supprimés (le code parle de lui-même), cérémonie réduite,
// util partagé réutilisé au lieu d'être réécrit
function getFullName(user?: User): string {
return [user?.firstName, user?.lastName].filter(Boolean).join(" ");
}
Et éliminez carrément les doublons — si getDisplayName/getLabel faisaient la même chose, supprimez-les et pointez les appelants vers une seule fonction (Supprimer le code mort / Insérer une fonction). Remplacez le validateur écrit à la main par l'import du module existant au lieu de garder une copie parallèle.
Règle empirique pour le catalogue : traitez tout bloc IA où les commentaires dépassent les lignes de logique, ou où vous pouvez nommer un helper existant qu'il a ignoré, comme candidat à la suppression-par-réutilisation — le correctif le plus rapide pour le code répétitif est généralement moins de code, pas plus.
##Detected by
- jscpd duplication threshold (--min-tokens / --threshold) — Détection de copier-coller (seuil min-tokens)
- SonarQube / SonarCloud typescript:S4144 — Les fonctions et méthodes ne doivent pas avoir des implémentations identiques
- SonarQube / SonarCloud typescript:S1192 — Les littéraux de chaîne ne doivent pas être dupliqués
- SonarQube / SonarCloud javascript:S1871 — Deux branches d'une structure conditionnelle ne doivent pas avoir exactement la même implémentation
- ESLint (eslint-plugin-sonarjs) sonarjs/no-identical-functions — Les fonctions ne doivent pas avoir des implémentations identiques
- ESLint (eslint-plugin-sonarjs) sonarjs/no-duplicate-string — Les littéraux de chaîne ne doivent pas être dupliqués
- ESLint (core) no-useless-constructor — Constructeur vide redondant / code répétitif de transmission
- ESLint (core) max-lines-per-function — Longueur de fonction excessive/verbeuse (indicateur partiel)