Vibe coding alla cieca: un gioco bellissimo da vedere e un codice che non scala

Tradotto dall'originale in spagnolo. Leggi in spagnolo

C’è molto hype attorno all’idea di lasciare che l’IA costruisca da sola. E sì, ci riesce: in circa 21 ore di lavoro con Claude ho costruito un gioco completo nel browser, con WebGL, mondi generati proceduralmente e suono sintetizzato. È bellissimo da vedere.

Il codice, no.

Ho fatto l’esperimento di proposito: lasciare l’IA in auto mode, senza guidance di architettura, e vedere cosa decideva da sola. Il risultato è un buon caso di studio di cosa succede quando fai vibe coding alla cieca — e del perché un processo di AI SDLC non è burocrazia, ma ciò che separa una demo da un prodotto.

L’esperimento

Il progetto è 5dimension.com.ar: fai clic, salti nell’iperspazio e arrivi ogni volta su un mondo diverso.

Le regole che mi sono dato:

  • Auto mode — l’IA esegue senza chiedere conferma a ogni passo.
  • Solo feature — chiedevo ciò che volevo vedere sullo schermo: pianeti, un drone, mini-giochi, un cockpit. Non ho mai chiesto architettura, test né lint.
  • Senza rivedere il codice — guardavo il gioco, non il diff.

Quanto è costato

  • Tempo totale — circa 21 ore di lavoro attivo.
  • Token totali — circa 613 milioni.
  • Costo di API — circa 240 USD a prezzo di listino (tra 225 e 270).

Il risultato: è bellissimo da vedere

Cosa ha costruito l’IA in quelle ore:

  • Dieci classi di pianeti e quattro luoghi segreti, generati a partire da un seed che sta nell’URL.
  • Un renderer WebGL fotorealistico, uno leggero per i telefoni e un fallback 2D.
  • Un ingresso atmosferico diverso su ogni mondo, un drone che vola dove guardi e un cockpit 3D.
  • Otto mini-giochi da 20 secondi, un album di pianeti, un mondo del giorno e suono sintetizzato con WebAudio.

Tutto funziona. Se il criterio è “gira?”, l’esperimento è un successo.

E qui arriva la parte scomoda: il codice

L’intero gioco viveva in un unico index.html di 4.486 righe: markup, CSS e JavaScript insieme.

L’IA non ha mai proposto di dividerlo. Per 33 commit ha continuato ad aggiungere feature allo stesso file. Ogni feature rendeva il file più difficile da modificare, e l’IA continuava a modificarlo comunque.

La conclusione: senza guidance, l’IA non ha scelto uno o due anti-pattern. Li ha scelti quasi tutti.

I 20 anti-pattern

Ogni cifra è misurata sul codice prima di qualsiasi correzione.

Architettura e modularità

  1. God Object / God File — un index.html di 4.486 righe con dentro tutto, cresciuto per 33 commit senza che nessuno proponesse di dividerlo.
  2. God entry point (hub dependency) — dopo lo split, main.js importava 25 moduli e frame() era un if/else di 107 righe su ogni stato.
  3. Big Ball of Mud — 32 file senza confini: il codice è stato distribuito, il design non è cambiato.
  4. Cyclic Dependency — cockpit → cruise → entry → cockpit.
  5. Temporal Coupling — importare un modulo eseguiva codice (listener, modifiche al DOM, scritture nello storage). L’ordine di caricamento contava e non era documentato.

Coesione e accoppiamento

  1. Low Cohesion — progress.js mescolava storage, scoring, unlock, il catalogo delle navi, HTML e toast.
  2. Global Mutable State — gli oggetti app, cam e input, scritti da 10 moduli.
  3. Shotgun Surgery — ogni mini-gioco sparso su 5-7 file. Modificarne uno significa toccarli tutti.
  4. Fat Interface — sound.js esportava 38 funzioni, una per ogni evento del gioco.

Incapsulamento

  1. Incapsulamento rotto — diversi moduli aggiungevano campi all’oggetto world dopo averlo creato, GPU handle inclusi. app.cruise e app.comms comparivano senza essere dichiarati.

Magic values

  1. Magic Strings — 9 stati come stringhe sciolte, scritti da 4 file, e 268 confronti di stringhe su state, mode, kind o type. Un refuso non fallisce mai: semplicemente non fa mai match.
  2. Magic Numbers — circa 7.800 costanti numeriche inline nel JavaScript, senza nome.

Stato e flusso di controllo

  1. State machine implicita — le transizioni avvengono ovunque qualcuno assegni app.state. Nessuna tabella delle transizioni, nessuna validazione, nessun hook di entrata o di uscita.
  2. Polling invece di eventi — 6 setTimeout ricontrollavano lo stato quando scattavano invece di essere legati alla transizione. Potevano scattare durante una visita successiva allo stesso stato.

Separation of concerns

  1. Presentazione dentro la logica — 262 colori hardcoded in JS e 18 template HTML costruiti a mano con innerHTML.
  2. Contenuto accoppiato alla logica — 286 chiamate L(es, en) inline dentro i moduli del gioco.
  3. Code as strings — 2.725 righe di GLSL dentro template string JavaScript, con varianti di qualità costruite tramite text-replace.
  4. Regole di gioco accoppiate al renderer — l’altezza del terreno per il drone veniva letta dalla GPU con readPixels ogni 50 ms. Una regola del gioco dipendeva dalla pipeline di rendering, e la CPU aspettava la GPU 20 volte al secondo.

Gestione degli errori e sicurezza

  1. Swallowed Exceptions — 7 blocchi catch {} vuoti, e nessuna gestione del context loss di WebGL: dopo un reset della GPU, lo schermo restava morto.
  2. Dati untrusted (non affidabili) senza encoding — nomi salvati nel localStorage finivano in innerHTML senza escape.

Restano fuori dalla lista i problemi di leggibilità — 723 righe oltre i 160 caratteri, 218 con cinque statement o più, nomi di una o due lettere.

Ciò che non è colpa del modello

Sarebbe facile leggere tutto questo come “l’IA programma male”. Non è così.

L’IA ha fatto esattamente quello che le ho chiesto: feature. Le ha fatte in fretta e funzionano. Ciò che non le ho chiesto — architettura, confini tra moduli, un modello dei dati, test — è rimasto al default. E il default di un modello che ottimizza il compito immediato è la strada più breve: aggiungere la riga dove si trova già il resto del codice.

Vibe coding alla cieca vs AI SDLC

In AI SDLC: una raccolta di buone pratiche per sviluppare con l’IA ho descritto come lavoro con l’IA quando l’obiettivo è la produzione. Questo esperimento ne è l’esatto contrario.

  • Design — alla cieca, l’architettura emerge da sola, commit dopo commit, ed emerge come god file. Con AI SDLC, sei tu a decidere l’architettura prima di scrivere un solo prompt.
  • Piano — alla cieca, l’IA esegue direttamente. Con AI SDLC, chiedi un piano dettagliato, lo rivedi e lo tieni in un .md che entrambi potete modificare. Il costo è più tempo all’inizio; il risparmio è non dover rifattorizzare 4.486 righe dopo.
  • Scope — alla cieca, ogni richiesta tocca tutto ciò che serve. Con AI SDLC, ogni modifica ha uno scope esplicito e un test che la verifica.
  • Revisione — alla cieca, guardi il risultato sullo schermo. Con AI SDLC, rivedi il diff, e i claim del commit message rispetto al codice.
  • Guardrail — alla cieca, non ci sono lint, né test nel loop, né gate di deploy, a meno che tu non li chieda. Con AI SDLC, fanno parte del setup fin dal primo giorno.
  • Human in the loop — alla cieca, il dev è un utente che chiede feature. Con AI SDLC, il dev è responsabile del sistema.

Maximiliano Díaz Doglia

AI Platform Engineer & Full-Stack Developer
Building Enterprise Integrations & Automations