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à
- God Object / God File — un
index.htmldi 4.486 righe con dentro tutto, cresciuto per 33 commit senza che nessuno proponesse di dividerlo. - God entry point (hub dependency) — dopo lo split,
main.jsimportava 25 moduli eframe()era unif/elsedi 107 righe su ogni stato. - Big Ball of Mud — 32 file senza confini: il codice è stato distribuito, il design non è cambiato.
- Cyclic Dependency — cockpit → cruise → entry → cockpit.
- 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
- Low Cohesion —
progress.jsmescolava storage, scoring, unlock, il catalogo delle navi, HTML e toast. - Global Mutable State — gli oggetti
app,cameinput, scritti da 10 moduli. - Shotgun Surgery — ogni mini-gioco sparso su 5-7 file. Modificarne uno significa toccarli tutti.
- Fat Interface —
sound.jsesportava 38 funzioni, una per ogni evento del gioco.
Incapsulamento
- Incapsulamento rotto — diversi moduli aggiungevano campi all’oggetto world dopo averlo creato, GPU handle inclusi.
app.cruiseeapp.commscomparivano senza essere dichiarati.
Magic values
- 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.
- Magic Numbers — circa 7.800 costanti numeriche inline nel JavaScript, senza nome.
Stato e flusso di controllo
- State machine implicita — le transizioni avvengono ovunque qualcuno assegni
app.state. Nessuna tabella delle transizioni, nessuna validazione, nessun hook di entrata o di uscita. - Polling invece di eventi — 6
setTimeoutricontrollavano lo stato quando scattavano invece di essere legati alla transizione. Potevano scattare durante una visita successiva allo stesso stato.
Separation of concerns
- Presentazione dentro la logica — 262 colori hardcoded in JS e 18 template HTML costruiti a mano con
innerHTML. - Contenuto accoppiato alla logica — 286 chiamate
L(es, en)inline dentro i moduli del gioco. - Code as strings — 2.725 righe di GLSL dentro template string JavaScript, con varianti di qualità costruite tramite text-replace.
- Regole di gioco accoppiate al renderer — l’altezza del terreno per il drone veniva letta dalla GPU con
readPixelsogni 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
- Swallowed Exceptions — 7 blocchi
catch {}vuoti, e nessuna gestione del context loss di WebGL: dopo un reset della GPU, lo schermo restava morto. - Dati untrusted (non affidabili) senza encoding — nomi salvati nel localStorage finivano in
innerHTMLsenza 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
.mdche 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.
