modulo 07 / lezione 54

Leggere e verificare codice generato

Loop debug, fix, regression: evitare di rompere ciò che funzionava

Impostare un ciclo di correzione che verifica il bug senza introdurre regressioni silenziose.

75 min Vibe Coding

Loop debug, fix, regression: evitare di rompere ciò che funzionava

Fix di un bug è solo metà del lavoro. L’altra metà è verificare che il fix non abbia rotto nient’altro. Il ciclo debug → fix → regression è la disciplina che separa “ho risolto” da “ho spostato il problema”. Senza, ogni patch ne introduce due.

Perché questa lezione conta

Il fix più costoso è quello che risolve un bug e ne crea uno silenzioso che esce due settimane dopo. Senza ciclo formale di regression, il fix è scommessa. Con ciclo formale, ogni fix ha test che dimostra il bug risolto + verifica che ciò che funzionava continua a funzionare. Investimento di 10 minuti che salva ore.

Obiettivo operativo

Alla fine devi saper:

  1. eseguire il ciclo riproduzione → fix → regression in modo disciplinato;
  2. trasformare ogni bug fixato in test automatico (regression test);
  3. verificare cose vicine al fix per scoprire regressioni potenziali presto.

Nucleo della lezione

1. Riproduzione prima del fix

Regola: se non sai far apparire il bug, non sai dimostrare che è risolto.

Riproduzione minima: input più piccolo possibile + sequenza di passi più corta possibile. Idealmente:

  • una funzione, un input → output sbagliato;
  • una pagina, un click → comportamento sbagliato;
  • una richiesta API, una response → status sbagliato.

Strumenti per riproduzione:

  • script che chiama funzione con input specifico;
  • request HTTP via curl;
  • E2E test che simula click;
  • snapshot di stato (DB seed, fixture data).

Senza riproduzione: ogni “fix” è speculazione. Test post-fix dimostra niente.

2. Test di regressione

Una volta riprodotto il bug, trasformalo in test:

Forma: il test deve fallire SENZA il fix, passare CON il fix.

Posizione: nella stessa cartella del codice testato. Naming bug-NNN.test.ts o test specifico nel file di test esistente.

Riferimento: commento o nome che lega il test a issue/bug tracking. Esempio: // regression: utente non loggato dopo signup (bug-42).

Esempio:

// signup.test.ts
it('regression: dopo signup, sessione è creata immediatamente (bug-42)', async () => {
  const res = await request(app).post('/signup').send({ email: 'test@test.it', password: 'Test1234' })
  expect(res.headers['set-cookie']).toBeDefined()
  expect(res.headers['set-cookie'][0]).toMatch(/session=/)
})

Questo test diventa parte permanente della suite. Ogni futuro modifica esegue questo test. Bug non torna.

3. Verifica vicinato

Dopo il fix:

  • Riproduzione del bug: ora produce output corretto.
  • Test di regressione: passa.
  • Test esistenti: tutti continuano a passare.
  • Casi vicini: cose collegate al fix funzionano ancora?

“Casi vicini” sono la verifica preventiva contro regressioni:

  • se ho fixato signup, login funziona ancora?
  • se ho cambiato calcolo prezzo per scontistica X, scontistica Y/Z è inalterata?
  • se ho modificato validazione email, validazione altre form (recupero password, profilo) funziona?

Identifica casi vicini chiedendo: cosa condivide codice/dati con la parte che ho toccato? Test rapido di quei casi prima di mergiare.

Caso guidato

Bug: “dopo aver modificato il profilo, il nome aggiornato non compare nella navbar”.

Fix cieco tipico:

Aggiorna anche lo stato navbar quando salvo profilo.

Il modello patcha la navbar, ma rompe il refresh. Ciclo corretto:

  1. Riproduzione: salva profilo con nome “Luca”; navbar resta “Mario”.
  2. Ipotesi: profilo aggiornato su server, cache utente non invalidata.
  3. Verifica: Network mostra PUT /profile 200; GET /me non viene rieseguita.
  4. Fix minimo: invalidare cache me dopo PUT /profile.
  5. Regressione: test o checklist:
    • login mostra nome;
    • modifica nome aggiorna navbar;
    • refresh mantiene nome nuovo;
    • errore salvataggio non cambia navbar.

Prompt utile:

Non patchare la navbar direttamente. Il sintomo è navbar non aggiornata dopo PUT /profile. Network mostra PUT 200, ma nessun refetch /me. Proponi fix minimo per invalidare la sorgente dati utente e aggiungi verifica di regressione.

La regressione non è un test enorme. È la prova che il bug non torna nel punto in cui l’hai scoperto.

Procedura pratica

Per ogni bug:

  1. Riproduci (deterministico, minimo).
  2. Bug report in 6 sezioni (lezione 48).
  3. Diagnosi prima del fix (ipotesi, controllo).
  4. Fix mirato (più piccolo possibile).
  5. Verifica fix: riproduzione bug ora produce output corretto.
  6. Trasforma in test di regressione.
  7. Test esistenti passano.
  8. Casi vicini: verifica manuale o test mirati.
  9. Commit con messaggio che cita il bug.
  10. Documenta: opzionale, in note del progetto se il bug rivela pattern.

Tempo: 30-90 min per bug medio. Senza disciplina, stesso tempo o più con risultato peggiore (regressioni nascoste).

Laboratorio guidato

Bug: form signup, dopo submit utente non loggato (esempio della lezione 48).

1. Riproduzione:

# repro.sh
curl -X POST http://localhost:3000/signup \
  -H "Content-Type: application/json" \
  -d '{"email":"test@test.it","password":"Test1234"}' \
  -i  # mostra headers

# Atteso: response include Set-Cookie: session=...
# Osservato: nessun Set-Cookie

2. Diagnosi: regressione introdotta ieri quando aggiunta email di verifica. Funzione setSession non chiamata dopo createUser.

3. Fix:

async function signup(req, res) {
  const user = await createUser(req.body)
+ await setSession(res, user.id)
  await sendVerificationEmail(user.email)
  res.json({ ok: true, userId: user.id })
}

4. Verifica fix: ripeti repro.sh, ora Set-Cookie presente.

5. Test di regressione:

it('regression: dopo signup, sessione è creata (bug-42)', async () => {
  const res = await request(app).post('/signup').send({ 
    email: 'test@test.it', 
    password: 'Test1234' 
  })
  expect(res.headers['set-cookie']).toBeDefined()
  expect(res.headers['set-cookie'][0]).toMatch(/session=/)
})

6. Test esistenti: npm test → tutti verdi.

7. Casi vicini:

  • Login: invio credenziali esistenti → set-cookie presente? (test esiste)
  • Magic-link verify: clic su link → set-cookie presente? (verifica manuale)
  • Logout: set-cookie cleared? (test esiste)

8. Commit:

fix(auth): set session dopo signup per evitare login richiesto post-registrazione (bug-42)

Bug fix completo + protezione futura.

Output atteso

Per il prossimo bug del tuo progetto, esegui ciclo completo. Risultato: bug fixato + test di regressione + casi vicini verificati.

Studio passo passo

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

  1. Prima lettura: chiarisci l’obiettivo: impostare un ciclo di correzione che verifica il bug senza introdurre regressioni silenziose. Se non riesci a riscriverlo in una frase tua, rileggi il nucleo della lezione.
  2. Seconda lettura: trasforma i contenuti in domande operative:
  • Riproduzione prima del fix: se non sai far apparire il bug, non sai dimostrare che è risolto.
  • Test di regressione: trasformare il bug in caso verificabile manuale o automatico.
  • Dopo il fix: rieseguire percorso principale, caso rotto, casi vicini e controllare il diff.
  1. Applicazione: svolgi il laboratorio: prendere un bug simulato, riprodurlo, correggerlo e aggiungere una verifica che fallirebbe senza la patch. L’output da ottenere è: un protocollo debug/fix/regression da applicare a ogni bug non banale.

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

  • riproduco bug prima di fix;
  • trasformo bug fixati in test;
  • eseguo suite completa dopo fix;
  • verifico almeno 1-3 casi vicini al fix;
  • commit message cita il bug.

Errori comuni

Fix senza riproduzione. “Forse era questo”. Speculazione, non risoluzione.

Niente test post-fix. Bug riapparirà. Test di regressione lo previene.

Test esistenti non eseguiti. Fix introduce regressione, non te ne accorgi finché non emerge altrove.

Niente verifica vicinato. Cambia validazione email in un punto, dimentichi che è usata anche in profile e password reset. Regressione lì.

Test che testa solo l’happy path post-fix. Magari ora signup funziona; ma test verificare specificamente la condizione del bug.

Test di regressione fragili. Snapshot enormi, dipendenze su timing. Fragili. Test specifico, mirato.

Commit senza riferimento. Sei mesi dopo, perché c’è questa modifica? Dimenticato. Riferimento al bug.

Prompt di lavoro

Ho appena fixato un bug. Aiutami a costruire test di regressione e check vicinato.

Bug originale:
[descrizione]

Riproduzione minima:
[script o sequenza]

Fix applicato (diff):
[INCOLLA DIFF]

Voglio:

1. Test di regressione: codice di test che FALLIREBBE senza il fix e PASSA con il fix. Specifico, mirato, non snapshot enormi.

2. Casi vicini: 3-5 cose collegate al fix che potrebbero rompersi. Per ognuna, controllo (test esistente che copre o suggerimento di test mirato).

3. Commit message: formato Conventional Commits, in italiano, riferisce il bug.

NON proporre altri fix oltre quello applicato. Voglio solidificare quello attuale.

Esercizio finale

Apri ultimi 3 bug fix del tuo progetto. Per ognuno: c’era riproduzione minima documentata? c’è test di regressione che ne previene il ritorno? hai verificato casi vicini? Tipicamente la risposta è “no” almeno una volta. Quel “no” è dove la prossima regressione apparirà. Aggiungi test ora, anche dopo il fatto. Pulisci debiti accumulati.