Leçon 17/17 8 min

Garder le code simple

KISS, DRY, YAGNI : domptez le plus gros défaut de l'IA, la sur-ingénierie, et apprenez à exiger la solution la plus simple qui marche.

FR EN

Le problème : l'IA en fait toujours trop

Vous demandez à l'IA une fonction qui additionne deux nombres. Vous récupérez une classe Calculator avec une interface OperationStrategy, un système de plugins, une gestion d'erreurs pour le cas où l'un des arguments serait un objet exotique, et un fichier de config YAML « au cas où ». Vous vouliez a + b.

C'est le défaut numéro un de l'IA : la sur-ingénierie. Elle a vu des millions de bases de code « entreprise » bourrées d'abstractions, alors elle pense qu'un bon code, c'est un code compliqué. Elle ajoute des couches, anticipe des besoins imaginaires, gère des cas impossibles. Plus c'est gros, plus elle se croit utile.

Or, dans la vraie vie, le code simple gagne presque toujours. Il est plus rapide à lire, plus facile à corriger, et il casse moins. Votre travail de pilote de l'IA, c'est de la ramener vers la simplicité : parce qu'elle n'y va jamais seule.

Le piège de la sur-ingénierie : chaque abstraction, chaque couche de config, chaque « hook d'extension » que personne n'utilise est une dette. Du code que quelqu'un devra lire, comprendre et maintenir pour un besoin qui n'existe pas. Le code le plus sûr est celui qu'on n'a pas écrit.

Trois acronymes, une boussole

Trois principes vieux comme le métier suffisent à recadrer une IA trop ambitieuse :

  • KISS : Keep It Simple, Stupid. La solution la plus simple qui résout le problème est presque toujours la bonne. Pas la plus impressionnante : la plus simple.
  • DRY : Don't Repeat Yourself. Ne dupliquez pas la logique métier. Mais attention : trois lignes presque identiques valent mieux qu'une mauvaise abstraction qui les force à tenir dans le même moule. On abstrait quand le pattern est clair, pas avant.
  • YAGNI : You Aren't Gonna Need It. N'écrivez pas de code pour un futur hypothétique. Pas de paramètre « au cas où », pas de fonctionnalité « pour plus tard ». Quand le besoin arrivera vraiment, vous l'ajouterez.

Règle d'or : écrivez le code le plus simple qui résout le problème d'aujourd'hui. Pas celui d'un futur imaginaire. Vous ajouterez de la complexité quand un vrai besoin l'exigera : jamais avant.

DRY est le plus mal compris des trois. « Ne te répète pas » ne veut pas dire « abstrais tout ». Une abstraction prématurée, choisie avant de comprendre le pattern, coûte plus cher que la duplication qu'elle prétend éviter. La règle pratique : attendez la troisième occurrence avant de factoriser.

Avant / après : l'IA dorée vs la simple

Voici ce que l'IA produit spontanément quand on lui demande de valider qu'un nombre est positif :

// AVANT : sur-ingénierie typique de l'IA
class NumberValidator {
    constructor(options = {}) {
        this.strict = options.strict ?? true;
        this.allowZero = options.allowZero ?? false;
        this.rules = options.rules || [];
    }

    validate(value) {
        if (typeof value !== 'number' || Number.isNaN(value)) {
            throw new ValidationError('Not a number', { value });
        }
        for (const rule of this.rules) {
            if (!rule(value)) return false;
        }
        return this.allowZero ? value >= 0 : value > 0;
    }
}

const validator = new NumberValidator({ allowZero: false });
const ok = validator.validate(amount);

Et voici la même chose, ramenée à ce dont le projet a réellement besoin :

// APRÈS : la solution la plus simple qui marche
function isPositive(value) {
    return value > 0;
}

const ok = isPositive(amount);

La version « après » se lit en une seconde, ne casse jamais, et fait exactement le travail demandé. Le système de règles, les options de config et la classe d'erreur custom répondaient à des besoins que personne n'avait. Le jour où il faudra autoriser zéro, on ajoutera >= 0 : pas avant.

Prompter pour la simplicité

La simplicité ne vient pas toute seule : il faut l'exiger explicitement. Glissez ces consignes dans vos prompts (ou directement dans votre CLAUDE.md) :

  • « Donne-moi la solution la plus simple qui marche. »
  • « Pas d'abstraction prématurée. »
  • « Ne gère que les cas réels, pas les cas hypothétiques. »
  • « Pas de config ni de paramètre dont je n'ai pas besoin maintenant. »

Et quand l'IA en a quand même trop fait (ce qui arrivera) n'hésitez pas à lui demander de couper : « C'est trop compliqué pour le besoin. Simplifie, retire tout ce qui ne sert pas le cas réel. » L'IA est très douée pour dégraisser son propre code quand on le lui ordonne. Elle ne le fera juste jamais d'elle-même.

Conseil : le code « malin » coûte cher en maintenance. À chaque relecture, demandez-vous : « est-ce que je comprends ça en cinq secondes ? » Si non, c'est un candidat à la simplification, pas une preuve d'intelligence.

The problem: the AI always does too much

You ask the AI for a function that adds two numbers. You get back a Calculator class with an OperationStrategy interface, a plugin system, error handling for the case where one argument is some exotic object, and a YAML config file "just in case". You wanted a + b.

This is the AI's number-one flaw: over-engineering. It has seen millions of "enterprise" codebases stuffed with abstractions, so it thinks good code means complicated code. It adds layers, anticipates imaginary needs, handles impossible cases. The bigger it gets, the more useful it feels.

Yet in real life, simple code almost always wins. It is faster to read, easier to fix, and it breaks less. Your job as the AI's pilot is to drag it back toward simplicity — because it never goes there on its own.

The over-engineering trap: every abstraction, every config layer, every "extension hook" nobody uses is debt. Code someone will have to read, understand and maintain for a need that does not exist. The safest code is the code you did not write.

Three acronyms, one compass

Three principles as old as the trade are enough to rein in an over-ambitious AI:

  • KISSKeep It Simple, Stupid. The simplest solution that solves the problem is almost always the right one. Not the most impressive: the simplest.
  • DRYDon't Repeat Yourself. Do not duplicate business logic. But beware: three nearly identical lines beat a wrong abstraction that forces them into the same mold. Abstract when the pattern is clear, not before.
  • YAGNIYou Aren't Gonna Need It. Do not write code for a hypothetical future. No "just in case" parameter, no "for later" feature. When the need actually arrives, you will add it.

Golden rule: write the simplest code that solves today's problem. Not some imaginary future's. You will add complexity when a real need demands it — never before.

DRY is the most misunderstood of the three. "Don't repeat yourself" does not mean "abstract everything". A premature abstraction, chosen before you understand the pattern, costs more than the duplication it claims to avoid. The practical rule: wait for the third occurrence before factoring out.

Before / after: gilded AI vs simple

Here is what the AI produces spontaneously when asked to validate that a number is positive:

// BEFORE — typical AI over-engineering
class NumberValidator {
    constructor(options = {}) {
        this.strict = options.strict ?? true;
        this.allowZero = options.allowZero ?? false;
        this.rules = options.rules || [];
    }

    validate(value) {
        if (typeof value !== 'number' || Number.isNaN(value)) {
            throw new ValidationError('Not a number', { value });
        }
        for (const rule of this.rules) {
            if (!rule(value)) return false;
        }
        return this.allowZero ? value >= 0 : value > 0;
    }
}

const validator = new NumberValidator({ allowZero: false });
const ok = validator.validate(amount);

And here is the same thing, cut down to what the project actually needs:

// AFTER — the simplest solution that works
function isPositive(value) {
    return value > 0;
}

const ok = isPositive(amount);

The "after" version reads in a second, never breaks, and does exactly the job asked. The rule system, the config options and the custom error class answered needs nobody had. The day you must allow zero, you add >= 0 — not before.

Prompting for simplicity

Simplicity does not come for free: you have to demand it explicitly. Drop these instructions into your prompts (or straight into your CLAUDE.md):

  • "Give me the simplest solution that works."
  • "No premature abstraction."
  • "Handle only the real cases, not hypothetical ones."
  • "No config or parameter I do not need right now."

And when the AI overdoes it anyway — which it will — do not hesitate to ask it to cut: "This is too complex for the need. Simplify, remove everything that does not serve the real case." The AI is great at trimming its own code when told to. It just never does it on its own.

Tip: "clever" code is expensive to maintain. On every review, ask yourself: "do I understand this in five seconds?" If not, it is a candidate for simplification, not proof of intelligence.

Avec l'IA

Demandez à l'IA de dégraisser un bout de code trop ambitieux :

Voici un bout de code que tu as généré : [colle le code]. Je le trouve sur-ingénié pour mon besoin réel, qui est simplement [décris le besoin réel]. Applique KISS, DRY et YAGNI : retire toute abstraction prématurée, toute option de config inutilisée et tout cas hypothétique. Donne-moi la solution la plus simple qui marche pour ce besoin précis, et explique en une phrase ce que tu as supprimé et pourquoi.
Ré-explique sans regarder

Sans relire la réponse de l'IA : avec tes mots, pourquoi l'IA sur-ingénie par défaut, et que dois-tu lui demander pour obtenir la version simple ?

Une bonne explication dit : l'IA a été entraînée sur des codebases « entreprise » bourrées d'abstractions, donc elle confond complexité et qualité ; elle ne simplifie jamais d'elle-même. Pour la ramener, exige-le explicitement : « la solution la plus simple qui marche », « pas d'abstraction prématurée », « ne gère que les cas réels ». Et si elle en fait trop quand même, demande-lui de couper avec KISS / YAGNI en tête.
Accepter ou rejeter le code de l'IA

Tu as demandé à l'IA une fonction qui formate un prix en euros. Voici ce qu'elle te rend. Ton rôle de relecteur : accepter tel quel ou rejeter, et dire pourquoi.

class PriceFormatter {
    constructor(options = {}) {
        this.currency = options.currency || 'EUR';
        this.locale = options.locale || 'fr-FR';
        this.fallback = options.fallback || '—';
        this.cache = new Map();
    }
    format(value) {
        if (this.cache.has(value)) return this.cache.get(value);
        if (typeof value !== 'number') return this.fallback;
        const out = new Intl.NumberFormat(this.locale, {
            style: 'currency', currency: this.currency
        }).format(value);
        this.cache.set(value, out);
        return out;
    }
}
const formatter = new PriceFormatter();
const label = formatter.format(amount);
Rejeter et demander plus simple. Le besoin réel tient en deux lignes : new Intl.NumberFormat('fr-FR', { style: 'currency', currency: 'EUR' }).format(amount). La classe, les options currency/locale/fallback que personne n'a demandées, et surtout le Map de cache (formater un prix coûte des microsecondes : ce cache n'optimise rien et ajoute un bug latent si on reformate après changement de locale) sont de la sur-ingénierie pure. YAGNI : tu ajouteras une option le jour où un deuxième appelant en aura vraiment besoin.
Exercice : Exigez la simplicité

L'IA vous a rendu une usine à gaz pour une tâche triviale. Écrivez un prompt qui lui demande de simplifier en s'appuyant sur les principes vus. Votre prompt doit mentionner au moins deux des notions suivantes : KISS / simple, YAGNI / pas de cas hypothétique, abstraction prématurée à retirer.

Rappel libre

Sans remonter dans la leçon : que disent KISS, DRY et YAGNI, et à partir de quelle occurrence d'un code presque identique vaut-il mieux factoriser ?

KISS (Keep It Simple) : la solution la plus simple qui résout le problème est presque toujours la bonne. DRY (Don't Repeat Yourself) : ne duplique pas la logique métier, mais sans abstraire à tout prix. YAGNI (You Aren't Gonna Need It) : pas de code pour un futur hypothétique. Pour la duplication, la règle pratique est d'attendre la troisième occurrence avant de factoriser : trois lignes presque identiques valent mieux qu'une mauvaise abstraction.
Quel est le défaut numéro un de l'IA quand elle code ?
Que signifie vraiment YAGNI ?
Face à trois lignes presque identiques, que faire ?
Prochaine étape

Vous avez maintenant tous les réflexes pour coder avec l'IA sans vous faire déborder. Reste à les ancrer là où ça compte vraiment : sur de vrais projets, du début à la fin, avec un rendu concret à montrer.

Passer aux projets →
Besoin d'un développeur pour votre projet ?

Réponse sous 24h · Sans engagement