Vibe coding à l'aveugle : un jeu superbe et un code qui ne passe pas à l'échelle
Traduit de l'original en espagnol. Lire en espagnol
Il y a beaucoup de hype autour de l’idée de laisser l’IA construire seule. Et oui, elle en est capable : en environ 21 heures de travail avec Claude, j’ai monté un jeu complet dans le navigateur, avec WebGL, des mondes générés de manière procédurale et du son synthétisé. Le rendu est superbe.
Le code, non.
J’ai fait l’expérience exprès : laisser l’IA en auto mode, sans guidance d’architecture, et voir ce qu’elle décidait d’elle-même. Le résultat est une bonne étude de cas de ce qui se passe quand on fait du vibe coding à l’aveugle — et de la raison pour laquelle un processus d’AI SDLC n’est pas de la bureaucratie, mais ce qui sépare une démo d’un produit.
L’expérience
Le projet, c’est 5dimension.com.ar : vous cliquez, vous sautez dans l’hyperespace et vous arrivez sur un monde différent à chaque fois.
Les règles que je me suis fixées :
- Auto mode — l’IA exécute sans demander de confirmation à chaque étape.
- Seulement des features — je demandais ce que je voulais voir à l’écran : des planètes, un drone, des mini-jeux, un cockpit. Je n’ai jamais demandé d’architecture, de tests ni de lint.
- Sans relire le code — je regardais le jeu, pas le diff.
Ce que ça a coûté
- Temps total — environ 21 heures de travail actif.
- Tokens au total — environ 613 millions.
- Coût d’API — environ 240 USD au prix catalogue (entre 225 et 270).
Le résultat : le rendu est superbe
Ce que l’IA a construit pendant ces heures :
- Dix classes de planètes et quatre lieux secrets, générés à partir d’un seed qui figure dans l’URL.
- Un renderer WebGL photoréaliste, un autre plus léger pour les téléphones et un fallback 2D.
- Une entrée atmosphérique différente sur chaque monde, un drone qui vole là où vous regardez et un cockpit 3D.
- Huit mini-jeux de 20 secondes, un album de planètes, un monde du jour et du son synthétisé avec WebAudio.
Tout fonctionne. Si le critère est « est-ce que ça tourne ? », l’expérience est un succès.
Et voici la partie inconfortable : le code
Tout le jeu vivait dans un seul index.html de 4 486 lignes : markup, CSS et JavaScript ensemble.
L’IA n’a jamais proposé de le découper. Pendant 33 commits, elle a continué d’ajouter des features dans le même fichier. Chaque feature rendait le fichier plus difficile à modifier, et l’IA continuait de le modifier quand même.
La conclusion : sans guidance, l’IA n’a pas choisi un ou deux anti-patterns. Elle les a choisis presque tous.
Les 20 anti-patterns
Chaque chiffre est mesuré sur le code avant toute correction.
Architecture et modularité
- God Object / God File — un
index.htmlde 4 486 lignes avec tout dedans, qui a grossi pendant 33 commits sans que personne ne propose de le découper. - God entry point (hub dependency) — après le split,
main.jsimportait 25 modules etframe()était unif/elsede 107 lignes sur chaque état. - Big Ball of Mud — 32 fichiers sans frontières : le code a été réparti, le design n’a pas changé.
- Cyclic Dependency — cockpit → cruise → entry → cockpit.
- Temporal Coupling — importer un module exécutait du code (listeners, modifications du DOM, écritures dans le storage). L’ordre de chargement comptait et n’était pas documenté.
Cohésion et couplage
- Low Cohesion —
progress.jsmélangeait storage, scoring, unlocks, le catalogue de vaisseaux, HTML et toasts. - Global Mutable State — les objets
app,cametinput, modifiés depuis 10 modules. - Shotgun Surgery — chaque mini-jeu réparti sur 5 à 7 fichiers. En modifier un oblige à les toucher tous.
- Fat Interface —
sound.jsexportait 38 fonctions, une par événement du jeu.
Encapsulation
- Encapsulation brisée — plusieurs modules ajoutaient des champs à l’objet world après sa création, y compris des GPU handles.
app.cruiseetapp.commsapparaissaient sans être déclarés.
Magic values
- Magic Strings — 9 états sous forme de strings isolées, écrits depuis 4 fichiers, et 268 comparaisons de strings sur state, mode, kind ou type. Une faute de frappe n’échoue jamais : elle ne matche simplement jamais.
- Magic Numbers — environ 7 800 constantes numériques inline dans le JavaScript, sans nom.
État et flux de contrôle
- State machine implicite — les transitions ont lieu partout où quelqu’un assigne
app.state. Pas de table de transitions, pas de validation, pas de hooks d’entrée ou de sortie. - Polling au lieu d’événements — 6
setTimeoutrevérifiaient l’état au déclenchement au lieu d’être liés à la transition. Ils pouvaient se déclencher lors d’une visite ultérieure au même état.
Separation of concerns
- Présentation dans la logique — 262 couleurs hardcodées en JS et 18 templates HTML montés à la main avec
innerHTML. - Contenu couplé à la logique — 286 appels
L(es, en)inline dans les modules du jeu. - Code as strings — 2 725 lignes de GLSL dans des template strings JavaScript, avec des variantes de qualité construites par text-replace.
- Règles du jeu couplées au renderer — la hauteur du sol pour le drone était lue depuis le GPU avec
readPixelstoutes les 50 ms. Une règle du jeu dépendait du pipeline de rendering, et le CPU attendait le GPU 20 fois par seconde.
Gestion des erreurs et sécurité
- Swallowed Exceptions — 7 blocs
catch {}vides, et aucune gestion du context loss de WebGL : après un reset du GPU, l’écran restait mort. - Données untrusted (non fiables) sans encoding — des noms stockés dans le localStorage entraient dans
innerHTMLsans échappement.
Restent hors de la liste les problèmes de lisibilité — 723 lignes de plus de 160 caractères, 218 avec cinq statements ou plus, des noms d’une ou deux lettres.
Ce qui n’est pas la faute du modèle
Il serait facile de lire tout cela comme « l’IA code mal ». Ce n’est pas ça.
L’IA a fait exactement ce que je lui ai demandé : des features. Elle les a faites vite et elles fonctionnent. Ce que je n’ai pas demandé — architecture, frontières entre modules, un modèle de données, des tests — est resté au default. Et le default d’un modèle qui optimise la tâche immédiate, c’est le chemin le plus court : ajouter la ligne là où se trouve déjà le reste du code.
Vibe coding à l’aveugle vs AI SDLC
Dans AI SDLC : un recueil de bonnes pratiques pour développer avec l’IA, j’ai décrit comment je travaille avec l’IA quand l’objectif est la production. Cette expérience en est le contraste exact.
- Design — à l’aveugle, l’architecture émerge seule, commit après commit, et elle émerge sous forme de god file. Avec AI SDLC, c’est vous qui décidez l’architecture avant d’écrire un seul prompt.
- Plan — à l’aveugle, l’IA exécute directement. Avec AI SDLC, vous demandez un plan détaillé, vous le relisez et vous le gardez dans un
.mdque vous pouvez modifier tous les deux. Le coût, c’est plus de temps au départ ; le gain, c’est de ne pas refactoriser 4 486 lignes ensuite. - Scope — à l’aveugle, chaque demande touche tout ce qu’il faut. Avec AI SDLC, chaque changement a un scope explicite et un test qui le vérifie.
- Revue — à l’aveugle, vous regardez le résultat à l’écran. Avec AI SDLC, vous relisez le diff, et les claims du commit message contre le code.
- Guardrails — à l’aveugle, il n’y a ni lint, ni tests dans la boucle, ni gate de deploy, sauf si vous les demandez. Avec AI SDLC, ils font partie du setup dès le premier jour.
- Human in the loop — à l’aveugle, le dev est un utilisateur qui demande des features. Avec AI SDLC, le dev est responsable du système.
