Back to all posts

1,3 milioni di righe, 630 PR a settimana: come teniamo sana una codebase vibe-coded

1,3 milioni di righe, 630 PR a settimana: come teniamo sana una codebase vibe-coded

Nel luglio 2026, Robert C. Martin ha scritto che non legge più il codice prodotto dai suoi coding agent.

L'affermazione ha attirato molta attenzione. Il resto del suo post conta di più per capire come lavora. Martin circonda gli agent di unit test, test di accettazione in Gherkin, procedure di QA, mutation testing, controlli di copertura e metriche di qualità. Il codice si guadagna la sua fiducia attraversando quel sistema.

Aveva espresso un concetto simile qualche mese prima. Invece di ispezionare l'implementazione, guarda la copertura dei test, la struttura delle dipendenze, la complessità ciclomatica, la dimensione dei moduli e i risultati del mutation testing. Quando questo è stato interpretato come una rinuncia totale alla revisione, ha chiarito: «Reviso moltissimo — solo non il codice».

I suoi commenti descrivono un problema pratico dello sviluppo software ad alta intensità di IA. I coding agent producono modifiche più in fretta di quanto le persone riescano a leggerle. Quando il volume di codice generato supera la capacità di revisione del team, l'ispezione riga per riga non può restare l'unica fonte di fiducia.

In vm0 affrontiamo lo stesso problema da otto mesi. La maggior parte dell'implementazione nel nostro repository è scritta da agent — vibe coding, nella formula corrente — mentre sei ingegneri restano responsabili di ciò che quel codice fa in produzione.

La versione breve

vm0 è una codebase vibe-coded: gli agent scrivono la maggior parte dell'implementazione e sei ingegneri rispondono di ciò che fa in produzione. Dopo otto mesi il repository conta 1.329.170 righe e in una sola settimana sono state unite 630 pull request. Cinque meccanismi reggono il carico di qualità che la revisione riga per riga non regge più da sola.

  • Ambienti convergenti. Ingegneri e agent lavorano nello stesso dev container e ogni pull request può avere il proprio branch di database. Un comando che ha funzionato per un agent funziona per una persona.
  • Vincoli eseguibili. TypeScript stretto, circa 135 moduli di contratto API tipizzati, Oxlint, ESLint e regole architetturali, con una CI che non accetta warning. Una regola verificabile in modo meccanico non viene lasciata alla revisione.
  • Test ai confini. Un trofeo dei test invece di una piramide: test di integrazione attraverso i confini pubblici dei moduli, PostgreSQL e migrazioni reali, mock solo sui sistemi esterni. Il codice di test è circa il 36 per cento del repository.
  • Cicli di feedback completi. Gli agent avviano applicazione e database, eseguono le migrazioni e guidano un browser reale, poi riportano i comandi eseguiti, il percorso testato e gli screenshot. La pull request mediana viene unita in circa 53 minuti.
  • Pulizia continua. Knip rimuove il codice morto in modo deterministico, workflow quotidiani tolgono l'AI slop che nessun linter sa nominare, e un pattern che ricorre abbastanza spesso diventa una regola di lint o un vincolo di tipo.

Cosa significano davvero vibe coding e agentic coding

Vibe coding significa chiedere codice a un LLM, eseguire ciò che produce, chiedere modifiche e non prestare alcuna attenzione al codice generato. La definizione di Martin Fowler è volutamente stretta, e mette in evidenza l'idea di "dimenticare che il codice esista". Va bene per prototipi, software usa e getta e piccoli strumenti con conseguenze limitate.

Agentic coding, che Fowler chiama programmazione agentica, è ciò che fanno i team quando intendono mantenere il risultato. Un agent legge il repository, modifica file, esegue test e lavora da solo per un periodo prolungato, mentre le persone restano proprietarie di struttura e comportamento e rivedono le prove prodotte da ogni esecuzione: risultati dei test, segnali di qualità, preview e comportamento in produzione.

La differenza non sta in quanto codice scrive il modello, ma in dove va l'attenzione umana.

Vibe codingAgentic coding
Autonomia dell'agentPrompt, esecuzione, nuovo promptLegge il repository, modifica, testa, itera
Chi legge il codiceNessunoLe persone leggono ciò che comporta rischio
Cosa viene verificatoSe il risultato sembra giustoTipi, contratti, test, preview, segnali di produzione
Contesto adattoPrototipi e strumenti usa e gettaSoftware con un orizzonte di manutenzione
Fallimento tipicoCodice che nessuno capisceVerifica troppo debole per il volume

Gli agent che modificano un repository sono solo un ramo di uno spostamento più ampio; il versante non-sviluppatori lo abbiamo trattato a parte.

Chiamiamo spesso vm0 un progetto vibe-coded perché quell'espressione è diventata la scorciatoia comune per software scritto in prevalenza dall'IA. Nei termini di Fowler è più vicino all'agentic coding. I nostri ingegneri digitano meno implementazione di prima, pur continuando a possedere architettura, costo di manutenzione e comportamento in produzione.

Man mano che la generazione di codice è diventata più rapida, una parte maggiore di quella responsabilità si è spostata nell'ambiente di sviluppo, nel sistema di tipi, nella suite di test e nei workflow di manutenzione automatizzati.

Otto mesi di crescita in una codebase vibe-coded

Il repository di vm0 è stato creato a novembre 2025. Al momento del nostro ultimo report settimanale sulla scala ingegneristica, aveva circa otto mesi e mezzo.

Il repository conteneva:

MetricaValore
Righe logiche non vuote1.329.170
Righe di produzione850.913
Righe di test478.257
File sorgente5.549
File di test1.327
Pacchetti44
Commit sul branch principale14.005

Questi numeri provengono dal nostro report settimanale sulla scala ingegneristica per la settimana dal 20 al 26 luglio 2026, misurati direttamente nel monorepo.

Il codice di test costituiva circa il 36 per cento della base di codice misurata. È una quota del volume di codice, non un dato di copertura, ma dà un'idea di quanta implementazione si sia accumulata attorno alla verifica.

In tre settimane piene recenti, sei ingegneri hanno prodotto rispettivamente 541, 640 e 631 commit. Nella settimana dal 20 al 26 luglio, GitHub ha registrato 630 pull request unite. Sei ingegneri ne hanno firmate 556, mentre le restanti 74 sono state prodotte dall'automazione di rilascio.

Il tempo mediano dall'apertura di una pull request alla sua unione è stato di circa 53 minuti. Il 90° percentile si è attestato intorno alle 7,4 ore.

A questo ritmo di cambiamento, la revisione umana resta utile ma non può reggere l'intero sistema qualità. Servono segnali indipendenti in più punti del ciclo di vita di una modifica.

Il nostro approccio attuale ha cinque temi ricorrenti: ambienti convergenti, vincoli eseguibili, test focalizzati sui confini, cicli di feedback completi e pulizia continua.

Far convergere l'ambiente di sviluppo con i dev container

Molti guasti difficili da riprodurre nascono da stato che non compare mai in una pull request.

Uno sviluppatore può avere una variabile d'ambiente non documentata, uno strumento installato globalmente, un vecchio file di configurazione o un database che gira da mesi. Le persone si abituano a questi dettagli. Gli agent di solito non riescono a vederli.

Abbiamo gradualmente smesso di trattare la macchina host come ambiente di sviluppo standard. Ingegneri e agent lavorano dentro un dev container. L'immagine di sviluppo include la toolchain di progetto, PostgreSQL, pgvector, Chromium e utility di automazione del browser.

La CI gira su immagini di toolchain versionate, costruite dalla stessa famiglia di Dockerfile multistadio. Le immagini di sviluppo e di CI servono scopi diversi, e la produzione ha una propria forma di deployment. La proprietà utile è la convergenza: versioni degli strumenti, dipendenze e assunzioni di runtime sono esplicite e versionate.

Ne deriva un'aspettativa netta. I comandi eseguiti da un agent devono essere riproducibili da un ingegnere nello stesso container di sviluppo. I controlli che passano durante lo sviluppo devono girare in CI sotto una toolchain molto simile.

Applichiamo un'idea analoga ai dati. Ogni anteprima di pull request può avere un proprio branch di database ed eseguire migrazioni e seed reali. Un agent può creare dati, modificarli e ripetere test distruttivi senza prendere in prestito il database di uno sviluppatore né ereditare stato da un'altra pull request.

Le modifiche all'ambiente viaggiano attraverso il repository. Aggiornamenti di strumenti, versioni del browser ed estensioni del database vengono revisionati e propagati come il codice applicativo.

Rendere eseguibili gli standard ingegneristici in tipi e regole di lint

Gli standard scritti aiutano le persone a comprendere le scelte di progettazione. Molto meno garantiscono che ogni modifica le rispetti, soprattutto durante lunghe sessioni di agent.

Le regole stabili le mettiamo nel sistema dei tipi, nei linter e in CI ogni volta che la regola può essere espressa in modo affidabile.

vm0 usa impostazioni TypeScript rigorose, tra cui strict e noUncheckedIndexedAccess. Alcuni pacchetti abilitano controlli aggiuntivi su valori inutilizzati e ritorni impliciti.

L'API usa uno strato di contratti REST tipizzato e schema-first, costruito con la macchina dei tipi di tRPC e schemi Zod. Drizzle collega l'accesso al database ai tipi TypeScript. Al momento di questa revisione, il repository conteneva circa 135 moduli di contratto.

Queste scelte non intercettano decisioni di prodotto sbagliate. Fanno però emergere presto la deriva delle interfacce. Quando un campo o una risposta cambia, i chiamanti coinvolti tendono a fallire già in analisi statica. L'errore risultante è di solito abbastanza specifico da essere utilizzabile da un agent nell'iterazione successiva.

Il linting copre un secondo gruppo di regole. La piattaforma esegue Oxlint, controlli type-aware ed ESLint, insieme a regole architetturali specifiche del progetto. La CI non accetta warning. I warning che possono restare a tempo indeterminato tendono a diventare rumore di fondo, e il rumore di fondo è facile da ignorare sia per le persone sia per gli agent.

Quando un problema si ripete, valutiamo dove collocare il controllo:

  1. Il sistema dei tipi può esprimerlo?
  2. Un linter o uno strumento strutturale può rilevarlo con precisione?
  3. Richiede giudizio semantico sull'intero repository?

I primi due danno feedback rapido e deterministico su ogni modifica. Il terzo gruppo lo gestiamo con i workflow ricorrenti descritti più avanti.

Restringere i pattern soggetti a errori nel codice generato dall'IA

Alcune funzionalità del linguaggio hanno usi legittimi e allo stesso tempo compaiono spesso in codice fragile generato dagli agent.

try/catch può sfumare un confine d'errore. Quando un agent incontra un fallimento, aggiungere un blocco catch e un fallback è un modo facile per tenere in vita il percorso corrente perdendo l'errore originale. Mescolare .then() e .catch() delle Promise con async/await distribuisce il flusso di controllo su più stili.

Lo useEffect di React crea un problema simile nella gestione dello stato. Viene spesso usato per copiare stato, sincronizzare due fonti di verità o codificare una dipendenza d'ordine difficile da vedere dal modello dei dati.

La piattaforma web centrale limita questi pattern per impostazione predefinita. Un'eccezione giustificata può rimanere, con una spiegazione esplicita accanto.

Il codice di produzione della piattaforma web centrale attualmente non contiene alcun useEffect. Usiamo ccstate e altri pattern privi di effetti per modellare dipendenze ed effetti collaterali in modo più esplicito. Un numero ridotto di chiamate useEffect in produzione esiste ancora altrove nel monorepo, soprattutto nel codice di UI condivisa e desktop: la portata dell'affermazione conta.

Queste regole sono nate da fallimenti ricorrenti in questo repository. Quando un pattern crea ripetutamente lo stesso problema di manutenzione, lo spostiamo da indicazione di revisione a vincolo eseguibile.

Testare ai confini dei moduli: un trofeo dei test, non una piramide

vm0 non segue una piramide dei test convenzionale. La nostra guida al testing descrive un trofeo dei test: analisi statica alla base, test di integrazione come strato dominante e un numero ridotto di test end-to-end per i percorsi utente critici.

Gli unit test sono relativamente rari. Li usiamo in modo selettivo per logica sensibile alla sicurezza, algoritmi e macchine a stati. La maggior parte del comportamento di business viene testata attraverso il confine pubblico di un modulo.

I test di API chiamano l'applicazione reale attraverso i suoi contratti. I dati di test vengono preparati tramite endpoint di produzione dove è praticabile, e le asserzioni riguardano il comportamento pubblico. I test evitano di entrare direttamente in un servizio interno o di modificare tabelle del database, perché ciò li accoppierebbe all'implementazione corrente.

L'infrastruttura interna resta reale ovunque il costo sia ragionevole:

  • PostgreSQL e pgvector
  • migrazioni del database
  • il filesystem
  • i servizi interni
  • mock ai confini con i sistemi esterni

Questi test di integrazione girano più lentamente di unit test fortemente isolati e richiedono un ambiente più completo. In cambio riducono la distanza tra «il test è passato» e «l'applicazione sa eseguire questa operazione con un database reale».

I test di confine lasciano spazio a grandi refactor interni. Un agent può riorganizzare moduli, dividere un servizio o cambiare lo strato di accesso ai dati mentre il comportamento pubblico resta protetto.

Uncle Bob preferisce un dosaggio diverso, con largo uso di unit test, Gherkin e mutation testing. Il principio condiviso è la verifica indipendente. Il processo che ha generato il codice non dovrebbe essere l'unica fonte che afferma che quel codice funziona.

Dare ai coding agent un ciclo di feedback completo

Le nostre prime esecuzioni di coding agent finivano spesso con un resoconto familiare: il codice è stato modificato e TypeScript passa; per favore avvia l'applicazione e controlla la pagina.

Così metà del ciclo di sviluppo resta all'ingegnere. Qualcuno deve ancora preparare un database, avviare i servizi, aprire un browser, creare dati, osservare il guasto e ridescriverlo all'agent.

Gli agent ora hanno abbastanza ambiente di sviluppo per fare di più. Possono avviare applicazione e database, eseguire migrazioni, creare dati di test, visitare un'anteprima di pull request e compiere interazioni reali nel browser.

La verifica nel browser intercetta una classe di problemi che i controlli di tipo e i test di API coprono male: navigazione rotta, stati di caricamento che non si concludono mai, errori di permesso che compaiono solo in un flusso completo e regressioni visive.

Alla fine di un'esecuzione, l'agent riporta i comandi eseguiti, il percorso testato e ciò che ha osservato. Per le modifiche di interfaccia può includere screenshot. Un ingegnere può esaminare quell'evidenza prima di decidere se aprire personalmente l'anteprima.

Uno screenshot non è un test e non dimostra l'assenza di altri difetti. Abbassa però il costo di ricostruire il contesto dell'agent. Per una piccola modifica di interfaccia, passi riproducibili e uno screenshot finale sono molto più utili di un messaggio che dice che la modifica «dovrebbe essere sistemata».

La qualità del lavoro di un agent dipende in larga misura dal feedback che riesce a ottenere senza aspettare una persona.

Tenere corti i branch con il trunk-based development

Una generazione di codice rapida può produrre un grande inventario di branch.

I branch di funzionalità di lunga durata accumulano conflitti di merge, lavoro duplicato e contesto obsoleto. Man mano che le pull request crescono, la revisione diventa più difficile e lenta. Usiamo lo sviluppo trunk-based per tenere corti i branch e integrare di continuo attorno a main.

Le regole del nostro branch principale richiedono:

  • pull request per le modifiche
  • storia lineare e merge con squash
  • una merge queue
  • controlli Turbo, Rust e sicurezza
  • nessun bypass di routine dei gate obbligatori

L'automazione segue lo stesso percorso. Un agent può creare una pull request, e alcune attività di manutenzione a basso rischio possono abilitare il merge automatico, ma la modifica passa comunque per CI e merge queue.

Dimensione e durata delle pull request aiutano a spiegare come 630 di esse siano potute confluire in una settimana. Una modifica piccola porta meno contesto, è più facile da verificare ed è meno probabile che confligga con il lavoro di prodotto o con un'altra riparazione automatica.

Knip come garbage collection del repository: rimuovere il codice morto

La generazione di codice aggiunge naturalmente file e astrazioni. La cancellazione richiede spesso un prompt a parte.

Dopo un refactor, vecchi file possono restare nel repository. Rimuovere una funzionalità può lasciare indietro export, dipendenze e entry point. Questi residui raramente rompono i test, ma col tempo rendono la base di codice più difficile da percorrere.

Usiamo Knip per individuare file, export, dipendenze ed entry point inutilizzati. TypeScript può confermare che il codice è valido; Knip chiede se partecipa ancora al sistema.

Quel residuo ha un costo aggiuntivo per i coding agent. Il repository è una delle loro fonti di contesto più importanti. Un helper obsoleto o un'implementazione abbandonata può sembrare un pattern approvato al prossimo agent che lo legge.

Rimuovere codice morto migliora anche gli input disponibili per le esecuzioni future. Knip svolge la parte deterministica di questo lavoro abbastanza in fretta da diventare un controllo di qualità regolare.

Workflow ricorrenti di pulizia dell'AI slop

Knip ed ESLint hanno limiti chiari. Molte forme di degrado richiedono contesto di progetto e giudizio semantico.

Usiamo «AI slop» come etichetta pratica per questo residuo: fallback inutili, astrazioni duplicate, test che aggirano un confine pubblico o rami difensivi per stati impossibili. Ogni singolo caso può sembrare innocuo. Nell'insieme rendono il repository più difficile da capire e offrono cattivi esempi ai futuri agent.

Diversi workflow ricorrenti su vm0 scandagliano questi pattern.

Una pulizia quotidiana dell'AI slop cerca nuovo residuo e seleziona un piccolo insieme di correzioni ad alta confidenza e basso rischio. Altri workflow ispezionano test di API che entrano nei servizi interni, antipattern di React e ccstate, e debito tecnico gestibile in sicurezza.

Ogni workflow mantiene le proprie modifiche circoscritte. Apre una pull request e poi si affida ai consueti controlli di tipo, regole di lint, test e merge queue. Anche una pull request configurata per il merge automatico deve superare gli stessi gate.

Workflow automatizzato di manutenzione del repository, dalla scansione fino a CI e merge, con riparazione in caso di fallimento

I workflow non tentano di azzerare tutto il debito tecnico in una passata. Un piccolo lotto quotidiano è più facile da verificare e meno dirompente di una grande pulizia ogni pochi mesi.

Quando un workflow ricorrente trova lo stesso pattern abbastanza spesso, valutiamo di spostare il controllo in ESLint, Knip o nel sistema dei tipi. Il workflow semantico funge da luogo in cui osservare e affinare la regola prima di trasformarla in un controllo deterministico più economico.

Questi workflow vm0 ricorrenti girano su base pianificata.

Trasformare i test instabili in riparazioni automatiche

Un altro gruppo di workflow parte dai fallimenti di GitHub Actions.

Quando un test fallisce sul branch principale o nella merge queue, un workflow legge i log, cerca indizi di flakiness ed esamina retry, tempistiche e fattori ambientali. Se le evidenze sostengono una riparazione specifica, aggiorna il test o l'implementazione, apre una pull request ed esegue di nuovo l'intero percorso di CI.

Passare al retry non rende innocuo il fallimento originale. I team che si affidano al pulsante di retry perdono gradualmente fiducia nelle build rosse. Quando accade, i controlli falliti diventano un'altra forma di rumore di fondo.

Un workflow di riparazione automatica trasforma un fallimento intermittente in una modifica di codice tracciabile. Diagnosi, patch e verifica restano visibili nella pull request. Gli ingegneri possono esaminare le modifiche più rischiose, mentre le correzioni circoscritte con evidenze solide possono procedere nella merge queue.

Il nostro sistema qualità ha attualmente tre grandi strati:

FaseMeccanismiPreoccupazioni tipiche
Durante la scritturaTypeScript, contratti, Drizzle, ESLinterrori di tipo, deriva delle interfacce, pattern di codice noti
Prima del mergeKnip, test di integrazione, database reali, anteprime, merge queuecodice morto, comportamento dei moduli, risultati completi a runtime
Dopo il mergeworkflow vm0 pianificati e guidati da eventiAI slop, antipattern semantici, test instabili, deriva architetturale

Gli strati si alimentano a vicenda. I problemi trovati dai workflow possono diventare regole statiche. I fallimenti trovati in CI o in produzione possono diventare test e nuove linee guida ingegneristiche.

Far girare agent in modo continuo ha un costo, e abbiamo scritto separatamente su come ridurlo.

Dove va l'attenzione umana nella revisione di codice generato dall'IA

Gli ingegneri di vm0 leggono ancora il codice, in particolare per modifiche architetturali, lavoro sensibile alla sicurezza, pagamenti e migrazioni di dati. Non abbiamo trasformato «non leggere mai il codice» in una regola di squadra.

Ciò che è cambiato è la distribuzione dell'attenzione. Leggere il codice è un segnale tra contratti, confini dei test, comportamento delle anteprime, screenshot, metriche di qualità e diagnostica dei workflow.

Diverse decisioni richiedono ancora giudizio esperto:

  • se il requisito è completo
  • dove dovrebbero collocarsi i confini dei moduli
  • quali fallimenti sono recuperabili
  • quanto impatto di business potrebbe generare un difetto
  • se un modello di sicurezza è adeguato
  • quale nuovo pattern di fallimento le regole attuali non coprono

Gli ingegneri mantengono anche l'ambiente attorno agli agent. Quando un problema si ripete, decidiamo se aggiungere un vincolo di tipo, una regola di lint, un test o un workflow ricorrente. Il sistema di sviluppo è diventato a pieno titolo un artefatto ingegneristico importante.

Il codice leggibile conta ancora. Il prossimo lettore può essere un ingegnere o un altro agent. Un codice aggrovigliato consuma più contesto, allarga la portata delle modifiche future e rende la verifica meno affidabile.

Uno spostamento analogo è avvenuto sul lato design, dove il design-as-code ha portato le decisioni visive nello stesso repository e nello stesso percorso di revisione.

La sicurezza e i cambiamenti che non accelerano

La velocità non è distribuita in modo uniforme. vm0 tiene un elenco breve di modifiche che vanno al proprio ritmo: lavoro sensibile alla sicurezza, pagamenti, migrazioni di dati e decisioni architetturali. Un ingegnere le legge riga per riga, indipendentemente da chi o cosa le ha scritte.

Il rischio di sicurezza del codice generato dall'IA, nella nostra esperienza, riguarda meno le vulnerabilità esotiche e più il codice plausibile di cui nessuno si fa carico. I controlli che contano sono quelli ordinari, applicati con costanza:

  • I test unitari, che per il resto usiamo con parsimonia, li usiamo deliberatamente per logica sensibile alla sicurezza, algoritmi e macchine a stati.
  • I test mockano solo ai confini dei sistemi esterni. L'infrastruttura interna resta reale, così una modifica che rompe un contratto interno fallisce in CI e non in produzione.
  • Gli agent lavorano dentro il dev container su un branch di database per pull request, non sulla macchina di uno sviluppatore né su un database condiviso.
  • La merge queue e i check obbligatori non hanno scorciatoie di routine, nemmeno per una pull request aperta da un agent e marcata per il merge automatico.
  • try/catch è limitato per impostazione predefinita, così un errore non viene assorbito da un fallback aggiunto da un agent per tenere in piedi il percorso corrente.

La gestione delle credenziali è un problema di progettazione a sé, con una risposta propria: abbiamo descritto il pattern broker che tiene i token fuori dalla portata di un agent in un articolo dedicato.

Nulla di tutto ciò rende sicuro il codice generato di per sé. Riduce l'insieme delle modifiche in cui una decisione umana è l'unico controllo, e rende quell'insieme esplicito.

Cosa non mostrano questi numeri

Il report settimanale dimostra la scala del repository e la velocità di consegna. Di per sé non dimostra l'affidabilità in produzione.

Valutare l'effetto sulla qualità a runtime richiede disponibilità, tassi di errore in produzione, numero di incidenti, tasso di fallimento delle modifiche, frequenza di rollback e tempo medio di ripristino. Una CI verde descrive una parte del processo di consegna.

Continuiamo ad assemblare quelle misure di risultato. Le pratiche ingegneristiche spiegano come un sistema gestisce il rischio; i dati di produzione mostrano quanto bene quella gestione funzioni.

Domande frequenti

Che cos'è il vibe coding? Vibe coding significa chiedere codice a un LLM, eseguire ciò che restituisce, chiedere modifiche e non leggere il codice generato. La definizione di Fowler è stretta di proposito: si dovrebbe "dimenticare che il codice esista". Va bene per prototipi, software usa e getta e strumenti con conseguenze limitate.

Che cos'è l'agentic coding? L'agentic coding è una forma di sviluppo assistito dall'IA a esecuzione più lunga, in cui un agent legge un repository, modifica file, esegue test e itera da solo per un periodo prolungato. Le persone restano proprietarie di architettura e comportamento e rivedono le prove dell'esecuzione invece di ogni riga scritta.

Qual è la differenza tra vibe coding e agentic coding? L'attenzione, non la paternità del codice. Nel vibe coding il codice non viene mai ispezionato. Nell'agentic coding l'agent lavora da solo mentre gli ingegneri esaminano le prove attorno: risultati dei test, segnali di qualità, preview e comportamento in produzione. vm0 viene di solito descritto come vibe-coded; nei termini di Fowler è agentic coding.

Che cos'è l'AI slop? L'AI slop è il residuo lasciato dal codice generato dall'IA: fallback superflui, astrazioni duplicate, test che aggirano un confine pubblico, rami difensivi per stati impossibili. Ogni singolo caso sembra innocuo. Nell'insieme rendono il repository più difficile da capire e offrono cattivi esempi all'agent successivo.

Come si rivede codice generato dall'IA con 630 pull request a settimana? Non riga per riga. In vm0 la revisione umana va dove serve giudizio: architettura, lavoro sensibile alla sicurezza, pagamenti, migrazioni di dati. Il resto è retto da meccanismi: tipi stretti e contratti, test di integrazione ai confini dei moduli, database reali nelle preview per pull request, verifica nel browser, Knip e una merge queue senza scorciatoie di routine.

Quali sono le buone pratiche del vibe coding su larga scala? Cinque hanno retto in vm0 per otto mesi: far convergere l'ambiente di sviluppo perché agent e persone eseguano gli stessi comandi; rendere gli standard eseguibili in tipi, linter e CI invece che in documenti; testare ai confini dei moduli contro infrastruttura reale; dare agli agent un ciclo di feedback completo, browser incluso; e pulire di continuo anziché in rare passate grandi.

Quali sono i rischi di sicurezza del codice generato dall'IA? Il rischio comune non è una vulnerabilità esotica ma codice plausibile di cui nessuno si fa carico. vm0 tiene in revisione umana il lavoro sensibile alla sicurezza, i pagamenti e le migrazioni di dati, usa i test unitari in modo deliberato per quella logica, mantiene reale l'infrastruttura interna nei test, limita pattern come try/catch che assorbono gli errori e non consente scorciatoie sui check obbligatori.

Il codice generato dall'IA crea debito tecnico? Ne crea un tipo specifico: codice che ancora compila e passa i test ma non partecipa più al sistema, più un residuo semantico che nessun linter sa nominare. Knip rimuove la parte deterministica. I workflow ricorrenti si occupano del resto in piccoli lotti quotidiani, e un pattern che ricorre abbastanza spesso diventa una regola di lint o un vincolo di tipo.

Quanta parte della codebase di vm0 è scritta dall'IA? La maggior parte dell'implementazione. Nella settimana dal 20 al 26 luglio 2026, sei ingegneri hanno firmato 556 delle 630 pull request unite e l'automazione di release il resto, e gli agent hanno scritto gran parte del codice contenuto in quelle pull request. Ciò che resta agli ingegneri è l'architettura, i vincoli e il comportamento in produzione.

Che cos'è un trofeo dei test e perché non una piramide? Un trofeo dei test mette l'analisi statica alla base, i test di integrazione come strato dominante e pochi test end-to-end in cima. vm0 lo usa perché i test scritti attraverso il confine pubblico di un modulo continuano a proteggere il comportamento mentre un agent riorganizza l'implementazione sottostante, cosa che un ampio strato di test unitari non fa.

Come si trova il codice morto in un repository scritto dall'IA? La generazione di codice aggiunge file e astrazioni; la cancellazione di solito richiede un'istruzione a parte. vm0 esegue Knip come controllo regolare per trovare file, export, dipendenze e punti di ingresso inutilizzati. TypeScript conferma che il codice è valido; Knip chiede se partecipa ancora al sistema, ed è la domanda che conta per il codice morto.

Il codice vibe-coded è sicuro in produzione? Dipende da che cosa lo verifica, non da chi lo ha scritto. I segnali che pretendiamo non sono cambiati: tipi e contratti, test attraverso confini pubblici, infrastruttura reale e una pipeline che deve essere verde. I numeri di questo articolo descrivono la scala del repository e la velocità di consegna; disponibilità, tassi di errore e change-failure rate rispondono alla domanda sulla produzione, e li stiamo ancora mettendo insieme.

Otto mesi dopo

Otto mesi sono troppo pochi per dichiarare un metodo definitivo. Modelli, strumenti per agent e repository continuano a cambiare, e le nostre regole e i nostri workflow cambiano con loro.

Uno spostamento è già chiaro. Man mano che la generazione di codice è diventata più veloce, ambiente, vincoli, test e sistema di feedback si sono presi una quota maggiore del carico di qualità. Gli ingegneri passano meno tempo a digitare implementazione e più tempo a definire comportamenti, progettare confini e migliorare la verifica.

La base di codice di vm0 continuerà a crescere. Knip rimuove il residuo deterministico. Le regole statiche bloccano i pattern di fallimento che già comprendiamo. I test di integrazione proteggono il comportamento dei moduli. I workflow ricorrenti gestiscono il degrado che non sappiamo ancora esprimere meccanicamente.

Il codice conta ancora. Ora usiamo più evidenze eseguibili dalla macchina per decidere se una modifica appartiene al branch principale, e se la sua implementazione debba restare nel repository.

Stay in the loop

// Get the latest insights on AI teammates and collaboration.

SubscribeJoin Discord