---
title: "Réinvention de la roue"
type: "ai-smell"
slug: "reinvented-wheel"
url: "http://localhost:3000/fr/ai-smells/reinvented-wheel.md"
category: "Structure"
description: "Le modèle écrit à la main du code sur mesure pour quelque chose qu'une bibliothèque standard, une dépendance existante ou un helper déjà présent dans le dépôt fait déjà — ajoutant une logique dupliquée et moins testée au lieu d'appeler ce qui existe déjà."
---
# Réinvention de la roue

> Le modèle écrit à la main du code sur mesure pour quelque chose qu'une bibliothèque standard, une dépendance existante ou un helper déjà présent dans le dépôt fait déjà — ajoutant une logique dupliquée et moins testée au lieu d'appeler ce qui existe déjà.

## Signs and Symptoms

Un relecteur repère une réinvention de la roue lorsqu'un diff introduit un morceau non trivial de logique « repartie de zéro » pour résoudre un problème déjà résolu — par le runtime du langage, par une dépendance déjà présente dans `package.json`, ou par un utilitaire qui existe déjà ailleurs dans le dépôt. Indices courants :

* Un `deepClone`, `debounce`, `groupBy`, `chunk`, `retry`, `slugify`, `deepMerge` ou `uuid` écrit à la main alors que le runtime ou une bibliothèque installée le fournit.
* Une **regex** d'e-mail/URL/UUID sur mesure au lieu d'un validateur qui est déjà une dépendance.
* Des calculs de dates, du parsing de query-string ou une logique de pagination sur mesure qui réimplémentent `Intl`/`URLSearchParams`/une fonctionnalité d'ORM.
* Deux ou trois helpers privés quasi identiques répartis dans des fichiers (la même roue retaillée par fonctionnalité) — la duplication qui apparaît dans les métriques de copier-coller.
* La version réinventée est subtilement **fausse** : elle gère le chemin heureux mais manque les cas limites que l'original éprouvé couvre.

```ts
// Écrit par IA : un deep clone sur mesure réinventé en ligne
function deepClone(obj) {
  if (obj === null || typeof obj !== 'object') return obj;
  if (Array.isArray(obj)) return obj.map(deepClone);
  const out = {};
  for (const k in obj) out[k] = deepClone(obj[k]);
  return out; // perd silencieusement Date, Map, Set, RegExp ; boucle sur les cycles
}
// ...alors même que le runtime fournit structuredClone(), ET
// que le dépôt exporte déjà cloneDeep() depuis src/utils/object.ts

```

La vérification la plus rapide : cherchez la capacité dans le dépôt et dans `node_modules` avant d'accepter le nouveau code. Si `structuredClone`, `lodash`, `date-fns` ou un helper local la couvre déjà, la nouvelle fonction est une roue réinventée.

## Reasons for the Problem

**Pourquoi les modèles le produisent**

* **Aucun contexte du dépôt par défaut.** Le modèle ne voit souvent pas votre `src/utils`, vos dépendances installées ni vos conventions maison, alors il recourt à la complétion statistiquement la plus probable : une implémentation autonome en ligne. Il réinvente la roue parce qu'il n'a jamais vu la vôtre.
* **Localité du token suivant.** Les LLM optimisent une suite localement plausible, pas une minimalité globale. Écrire `function groupBy(...)` est une séquence à forte probabilité ; s'arrêter pour découvrir que `lodash.groupBy` est déjà importé trois fichiers plus loin n'est pas ce que fait la prédiction de token.
* **Les incitations d'entraînement récompensent l'autonomie.** Une énorme part des données d'entraînement est constituée de tutoriels, de réponses Stack Overflow et d'extraits qui montrent délibérément l'implémentation complète. Le modèle a appris que « bien répondre » signifie émettre du code complet et autonome — exactement le mauvais instinct au sein d'une base de code mature.
* **Obsolescence due à la date de coupure d'entraînement.** Le modèle peut ignorer qu'une capacité a été promue dans la bibliothèque standard (par ex. `structuredClone`, `Array.prototype.at`, `Object.groupBy`) ou que votre dépôt a adopté un helper après sa coupure, alors il polyfille quelque chose qui existe déjà.
* **Complaisance / moindre résistance.** Quand on lui demande d'« ajouter X », le modèle ajoute X de la manière la plus directe plutôt que de rétorquer « on a déjà ça ». Il propose rarement de lui-même « tu n'as pas besoin d'écrire ça ».
* **Sur-spécification.** L'analyse par OX Security de plus de 300 dépôts a constaté que l'IA tend vers un codage « style vanille » qui reconstruit des fonctionnalités courantes au lieu d'utiliser des bibliothèques éprouvées, avec des solutions à portée étroite et non réutilisables dans environ 80 à 90 % des cas — chaque nouvelle variation reçoit du code frais au lieu d'être réutilisée.

**Pourquoi c'est nuisible**

* **Maintenabilité et dette technique.** C'est le visage mesurable du déclin de la qualité du code IA. L'analyse par GitClear de 211 millions de lignes a constaté que le code copié-collé est passé de 8,3 % (2020) à 12,3 % (2024), que les blocs de 5 lignes dupliquées et plus ont été multipliés par \~8 en 2024, et que les lignes « déplacées » (refactorisées) sont tombées de 24,1 % à 9,5 % — 2024 a été la première année où le copier-coller a dépassé le refactoring. Les roues réinventées sont la porte d'entrée de cette duplication.
* **Correction.** La version sur mesure saute les cas limites que l'implémentation mature a gagnés au fil d'années de rapports de bugs (fuseaux horaires, Unicode, cycles, échappement). Elle a l'air juste et échoue dans la longue traîne.
* **Sécurité.** Réécrire la cryptographie, l'authentification, l'assainissement ou la validation au lieu d'une bibliothèque éprouvée est la façon dont le code écrit par IA « viole les bonnes pratiques d'ingénierie » à grande échelle (l'effet « Armée de juniors » d'OX) — des schémas vulnérables atteignent la production plus vite que la revue ne peut les attraper.
* **Charge de revue.** Les relecteurs doivent désormais lire, comprendre et tester 40 lignes de logique sur mesure au lieu de reconnaître un seul appel de bibliothèque éprouvée — multiplié sur chaque PR.

## Treatment

**Tactiques de revue et de prompting**

* **Donnez au modèle le contexte qui lui manque.** Avant de générer, pointez-le vers vos utilitaires et dépendances : "Réutilise les helpers de `src/utils/*` et les bibliothèques déjà présentes dans `package.json` ; n'en ajoute pas de nouvelles sans demander." Collez les dépendances pertinentes de `package.json` et l'index de vos utils.
* **Faites de « chercher d'abord » une règle.** Donnez la consigne : "Avant d'écrire un helper, vérifie si la bibliothèque standard, une dépendance existante ou un utilitaire du dépôt le fait déjà ; si oui, appelle-le." Les outils agentiques devraient d'abord grep le dépôt.
* **Remettez en question chaque nouveau helper privé en revue.** Pour chaque utilitaire écrit à la main, demandez : le runtime fait-il cela ? une dépendance le fait-elle ? l'avons-nous déjà ? Si oui, c'est une réinvention de la roue — remplacez-la.
* **Exécutez la chaîne d'outils.** Un détecteur de duplication (jscpd / PMD CPD / SonarQube) en CI signale automatiquement la facette copier-coller ; câblez-le dans la barrière pour que les roues retaillées fassent échouer le build.

**Le refactoring** — c'est le classique **Code dupliqué** et **Réinventer la roue** ; le correctif est **Substituer un algorithme** (remplacer le corps sur mesure par l'appel à la bibliothèque/au standard) et, là où plusieurs copies existent, **Extraire une fonction** / remonter vers un seul helper partagé.

```ts
// AVANT — réinventé, partiellement correct, dupliqué par fonctionnalité
function deepClone(obj) {
  if (obj === null || typeof obj !== 'object') return obj;
  if (Array.isArray(obj)) return obj.map(deepClone);
  const out = {};
  for (const k in obj) out[k] = deepClone(obj[k]);
  return out;
}
const copy = deepClone(state);

```

```ts
// APRÈS — appeler ce qui existe déjà (cas limites corrects, zéro nouveau code)
const copy = structuredClone(state);
// ou, si le standard du dépôt est le helper local :
import { cloneDeep } from "@/utils/object";
const copy = cloneDeep(state);

```

Si la roue a été réinventée dans plusieurs fichiers, supprimez toutes les copies et routez chaque appelant via la source unique de vérité. Résultat net : moins de lignes, moins de bugs, et les métriques de duplication repartent dans le bon sens.

## Detected by

- **jscpd** `duplication` — Détection de copier-coller (min-tokens / seuil) (https://github.com/kucherenko/jscpd)
- **PMD** `cpd` — CPD (Copy/Paste Detector) (https://docs.pmd-code.org/latest/pmd_userdocs_cpd.html)
- **SonarQube** `common-duplications` — Blocs dupliqués / duplicated_lines_density (https://docs.sonarsource.com/sonarqube-server/latest/analyzing-source-code/test-coverage/duplications/)
