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.
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:
- dimensionare un task in modo che il diff sia leggibile (idealmente < 100 righe modificate);
- riconoscere segnali di “diff pericoloso” durante revisione;
- 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:
- Definisci scope: un comportamento, max 3 file, no refactor.
- Branch dedicato:
git checkout -b feat/scope-piccolo. - Stato pulito: nessuna modifica non committata prima di iniziare.
- Genera modifica.
- Diff completo:
git diff— leggi tutto, ricerca segnali pericolosi. - Test: comando di verifica. Passa? Test manuale del comportamento.
- Commit: messaggio chiaro, scope ristretto.
- 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:
- Aggiungi colonna
usernamea tabellausers(migrazione + tipo). - Aggiungi campo input “username” al form profilo (UI + state).
- Aggiungi validazione username (lato server, regex + uniqueness).
- 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.
- 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.
- 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.
- 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.