modulo 06 / lezione 35

Dialogare con l'AI senza perdere controllo

Modifiche piccole, leggibili, reversibili: la regola del diff

Usare il diff come strumento principale di controllo, limitando la dimensione delle modifiche generate.

60 min Vibe Coding

Modifiche piccole, leggibili, reversibili: la regola del diff

Il diff è l’unità minima di fiducia. Non la chat, non la spiegazione del modello, non il riassunto: il git diff reale. Tutto il vibe coding si regge sulla disciplina di leggere ogni diff prima di accettarlo. Quando il diff è piccolo, lo leggi davvero. Quando è grande, scorri e accetti senza vedere. La regola: tieni il diff piccolo per scelta, non per caso.

Perché questa lezione conta

I bug più costosi nascono in diff non letti. Modifiche generate dall’AI che includono refactor laterali, dipendenze nuove, cancellazioni opache, nomi cambiati ovunque: ognuna invisibile nel mucchio. Diff piccoli sono leggibili, testabili, spiegabili, annullabili. Diff grandi sono ipotesi non verificate.

Obiettivo operativo

Alla fine devi saper:

  1. dimensionare un task in modo che il diff sia leggibile (idealmente < 100 righe modificate);
  2. riconoscere segnali di “diff pericoloso” durante revisione;
  3. fermare e ridurre scope quando il diff cresce troppo.

Nucleo della lezione

1. Perché il diff piccolo vince

Quattro vantaggi concreti:

Leggibilità: 50 righe modificate le leggi in 2 minuti. 500 righe le scorri. Sotto certa dimensione, attenzione cala.

Testabilità: piccola modifica = facile capire cosa testare. Modifica enorme = test affidabili difficili da scrivere.

Spiegabilità: commit message pulito con scope ristretto. Code review è veloce. Bug regression: se appare, sai dove guardare.

Reversibilità: revert pulito di una modifica piccola. Revert di modifica grande spesso porta via cose che volevi tenere.

Soglia pratica: < 100 righe modificate = piccolo. 100-300 = medio (giustificato se il task lo richiede). > 300 = grande, valuta se davvero necessario o se hai mescolato task.

2. Come delimitare un task

Tre criteri per dimensionare:

Un comportamento: il task deve aggiungere/modificare UN comportamento osservabile. “Validare email” è un comportamento. “Fare il form di iscrizione” sono cinque comportamenti.

Pochi file: idealmente 1-3 file modificati. Più file = stai toccando troppi posti, probabilmente stai facendo refactor che non era nel task.

Nessun refactor laterale: il task non rinomina cose esistenti, non sposta codice, non cambia struttura. Refactor è task separato, con suo diff suo commit.

Verifica esplicita: il task deve avere modo di essere testato (test automatico, manuale, criterio osservabile). Se non sai come verificare, il task non è ben dimensionato.

Quando il task non rispetta i criteri: spezzalo in più task piccoli, non forzare uno grande.

3. Segnali di diff pericoloso

Cosa cercare durante revisione del diff:

File non richiesti: l’AI ha modificato file che non avevi citato. Spesso “perché collegato”. Spesso scope creep.

Formattazioni massive: indentazioni cambiate ovunque, virgolette riformulate, commenti riformattati. Quasi sempre il formatter è stato applicato a tutto il file invece che alla sola modifica. Rumore puro.

Dipendenze aggiunte: package.json è cambiato. Nuova libreria? Decisione architetturale, non dettaglio. Verifica e approva esplicitamente.

Cancellazioni opache: righe rimosse senza chiaro motivo. “Era inutile” del modello = chiedi spiegazione, non fidarti.

Modifiche a config: tsconfig, eslint, next.config cambiati. Rischio: cambio comportamento globale per risolvere problema locale. Quasi sempre da rifiutare.

Rinomine senza warning: variabile che esisteva da tempo rinominata “per chiarezza”. Effetto a catena su altri file. Refactor che doveva essere task suo.

Logica di test cambiata: il modello ha cambiato un test invece di soddisfarlo. Test “aggiustato” può nascondere regressioni vere.

Magic numbers/string nuovi: 3600, “admin”, “/api/v2/” hardcoded → costanti mancanti, valore plausibile ma da convalidare.

Pratica: dopo l’AI propone diff, prima di accettare, leggi voce per voce delle 8 sopra. Se trovi qualcosa, fermati e chiedi.

Procedura pratica

Workflow per task con AI:

  1. Definisci scope: un comportamento, max 3 file, no refactor.
  2. Branch dedicato: git checkout -b feat/scope-piccolo.
  3. Stato pulito: nessuna modifica non committata prima di iniziare.
  4. Genera modifica.
  5. Diff completo: git diff — leggi tutto, ricerca segnali pericolosi.
  6. Test: comando di verifica. Passa? Test manuale del comportamento.
  7. Commit: messaggio chiaro, scope ristretto.
  8. Se task era più grande: procedi a passo successivo, dopo nuovo commit.

Se durante revisione trovi diff con segnali pericolosi: git reset --hard (perdi solo l’ultima modifica) e ridefinisci scope.

Laboratorio guidato

Esercizio: prendi una piccola feature (es: aggiungere campo “username” al profilo utente).

Round A — task non dimensionato: chiedi al modello “aggiungi username a profilo utente”. Osserva diff: probabilmente tocca form, schema DB, validazione, mostra in pagina, magari aggiunge anche search. 200+ righe in 8 file.

Round B — task dimensionato: spezza in 4 task piccoli:

  1. Aggiungi colonna username a tabella users (migrazione + tipo).
  2. Aggiungi campo input “username” al form profilo (UI + state).
  3. Aggiungi validazione username (lato server, regex + uniqueness).
  4. Mostra username in pagina profilo + header.

Ogni task: 1-2 file, 30-60 righe, commit suo.

Confronta: dopo Round A leggi davvero il diff? Dopo Round B sì. Quando trovi un bug, in quale round lo localizzi più veloce?

Output atteso

Una regola personale di dimensionamento task: parametri (max righe modifica, max file, criterio rifiuto). Esempio:

  • max 100 righe modificate
  • max 3 file
  • max 1 dipendenza nuova (e va approvata)
  • niente refactor non chiesto
  • se sfora, spezza in più task

Studio passo passo

Studia questa lezione in tre passaggi, senza correre subito al prompt o al codice.

  1. Prima lettura: chiarisci l’obiettivo: usare il diff come strumento principale di controllo, limitando la dimensione delle modifiche generate. Se non riesci a riscriverlo in una frase tua, rileggi il nucleo della lezione.
  2. Seconda lettura: trasforma i contenuti in domande operative:
  • Perché una modifica piccola è più facile da leggere, testare, spiegare e annullare.
  • Come delimitare un task: un comportamento, pochi file, nessun refactor laterale, verifica esplicita.
  • Segnali di diff pericoloso: file non richiesti, formattazioni massive, dipendenze aggiunte, cancellazioni opache.
  1. Applicazione: svolgi il laboratorio: far implementare una feature in tre micro-passaggi e confrontare la revisione con una generazione monolitica. L’output da ottenere è: una regola operativa per dimensionare i task prima di affidarli all’AI.

Prima di passare alla lezione successiva, controlla di avere un artefatto concreto: una tabella, un prompt, una checklist, un mini report, un diff commentato o una decisione scritta. Nel vibe coding la comprensione resta astratta finché non produce una traccia verificabile.

Checklist di verifica

  • so descrivere il task in 1 frase prima di iniziare;
  • ogni mio commit recente è < 100 righe modificate (con eccezioni motivate);
  • leggo diff completo prima di committare;
  • ho almeno una volta fatto reset perché il diff era fuori controllo, e ridotto scope.

Errori comuni

Task gigante “tanto è semplice”. Modello esegue un dump di 500 righe. Tu accetti. Bug in 2 settimane.

Diff non letto. Accetti riassunto, salti il diff. Modifica fuori scope passata inosservata. Bug emerge dopo.

Refactor mescolato a feature. “Già che ci sei sistema anche…”. Commit ibrido, revert impossibile.

Formatter applicato a tutto il file. Rumore in diff, modifiche reali nascoste. Configurare formatter per “format on save” + commit separato di soli format.

Niente branch dedicato. Modifiche AI in main, problemi in main, sistemazioni a caldo.

Dipendenze accettate senza riflettere. Ogni npm install proposta dall’AI è una decisione. Valuta sempre.

Prompt di lavoro

Task: [descrizione in 1 frase, un comportamento]

Vincoli operativi:
- max 3 file modificati
- max 100 righe modificate
- niente nuove dipendenze (chiedi se serve)
- niente refactor laterale (rinomine, ristrutturazioni di codice esistente fuori dal task)
- niente modifiche a configurazione globale (tsconfig, eslint, package.json se non per la dipendenza richiesta)

Procedura:
1. Conferma di aver capito.
2. Lista assunzioni.
3. Dichiara file che intendi toccare e perché.
4. Aspetta autorizzazione.
5. Mostra diff dopo modifica.
6. Esegui test (`[comando]`) e mostra output.

Se il task richiede più di quanto consentito sopra, fermati e propone decomposizione in passi separati.

Esercizio finale

Apri ultimi 10 commit dei tuoi progetti. Per ognuno: quante righe modificate? Quanti file? Quante categorie di cambio (feat, fix, refactor) mescolate? Quasi sempre c’è almeno un commit gigante con feat + refactor + format mescolati. Quel commit è quello che, fra sei mesi, sarà impossibile da debuggare se introduce regressioni. La regola del diff piccolo è prevenzione.