modulo 07 / lezione 47
Leggere e verificare codice generato
Quando rifiutare il codice e ripartire dal prompt
Capire quando correggere localmente e quando il risultato è così fuori strada da richiedere una nuova richiesta.
Quando rifiutare il codice e ripartire dal prompt
A volte il codice generato si corregge in 5 minuti. A volte è così sbagliato che correggerlo richiede più tempo che rigenerare. Distinguere i due casi è scelta strategica. Continuare a patchare codice errato a livello di struttura è come dipingere una casa che ha le fondamenta storte.
Perché questa lezione conta
Persistenza è virtù in molte cose, non in revisione di codice generato. Quando un output ha problemi strutturali, correggerlo riga per riga porta a Frankenstein: tracce delle scelte sbagliate originarie + tue patch sopra. Risultato peggiore di rigenerare con prompt più chiaro. Sapere quando rifiutare salva tempo e qualità.
Obiettivo operativo
Alla fine devi saper:
- distinguere problemi locali (correggibili) da strutturali (rigenerare);
- valutare costo di riparazione vs rigenerazione;
- scrivere prompt di ripartenza che non ripete lo stesso errore.
Nucleo della lezione
1. Criteri per rifiutare
Cinque casi in cui rifiuto è preferibile a fix:
Requisito centrale ignorato: il codice non fa la cosa che hai chiesto. Non un dettaglio, il punto. Esempio: chiedi paginazione, ricevi solo lista. Patch = riscrivere tutto.
Architettura sbagliata: il codice mette logica nel posto sbagliato (validazione client invece di server, regole nel componente invece di backend, stato derivato salvato come indipendente). Patch toccherebbe ovunque; meglio rigenerare con vincoli architetturali espliciti.
Sicurezza compromessa: SQL injection, XSS, segreti hardcoded, autorizzazione assente. Rischio è che fix locale sia incompleto. Rigenerazione con sicurezza esplicita nel prompt.
Complessità inutile: 200 righe per quello che ne richiede 30. Astrazioni non necessarie, wrapper, pattern enterprise per script. Patch lasciare residui. Rigenerare semplificando.
Scope drasticamente espanso: chiedo X, ricevo X+Y+Z+W. Tutto modificato, refactor laterali ovunque. Patch impossibile, reset.
Combinazione di 2+ → quasi sempre rifiuto.
2. Costo riparazione vs rigenerazione
Equazione mentale rapida:
Costo riparazione:
- Tempo per leggere e capire codice esistente (può essere alto).
- Tempo per identificare cosa va, cosa no.
- Tempo per applicare modifiche evitando di rompere ciò che va.
- Rischio: residui invisibili che emergono dopo.
Costo rigenerazione:
- Tempo per scrivere prompt migliore (più vincoli, più chiarezza).
- Tempo per generare di nuovo.
- Tempo per verificare nuovo output.
- Beneficio: codice “tuo” da inizio (non eredita scelte sbagliate).
Soglia: se la riparazione richiede più di 30% del tempo di rigenerazione, rigenera.
Eccezione: se ti serve imparare dal codice esistente (capirne pezzi specifici), riparare ha valore didattico anche se più lento.
3. Prompt di ripartenza
Errore frequente: rigenerare con stesso prompt. Ottieni stesso risultato. Il prompt deve includere ciò che hai imparato dal primo tentativo.
Struttura del prompt di ripartenza:
Ho rifiutato il tentativo precedente. Ecco perché:
[1-3 problemi specifici del primo tentativo]
Ecco cosa NON voglio:
- [pattern del primo tentativo da evitare]
- [librerie scelte e da evitare]
- [scope da non superare]
Ecco cosa è ok mantenere (se nulla, salta):
- [pezzi del primo tentativo che andavano bene]
Vincoli aggiuntivi rispetto al prompt originale:
- [vincoli emersi dopo aver visto cosa è andato male]
Ora ricomincia da zero seguendo i vincoli.
Senza questa struttura, il modello replica gli stessi pattern. Con questa struttura, evita esplicitamente quelli sbagliati.
Matrice decisionale
Usa questa matrice quando sei indeciso:
| Segnale | Correggi localmente | Rigenera |
|---|---|---|
| Bug isolato in 1 funzione | sì | no |
| Requisito centrale ignorato | no | sì |
| Nomi brutti ma struttura corretta | sì | no |
| Auth o permessi assenti | raramente | spesso |
| Dipendenza inutile aggiunta | sì, se semplice rimozione | sì, se ha contaminato architettura |
| 8+ file modificati per task piccolo | no | sì |
| Test mancanti ma codice chiaro | sì | no |
| Modello dati sbagliato | raramente | sì |
Esempio: chiedi “aggiungi filtro per stato” e ricevi anche refactor globale del layout. Anche se il filtro funziona, il diff ha contaminazione. La scelta matura è rifiutare o chiedere una patch nuova limitata:
Rifiuto il diff perché modifica layout e componenti non richiesti. Riparti dal codice attuale e implementa solo il filtro per stato in `TaskFilters` e nella funzione `filterTasks`. Nessuna modifica CSS globale, nessuna rinomina, nessuna nuova dipendenza.
Al contrario, se il modello implementa il filtro nel file giusto ma dimentica il caso “tutti”, correggi localmente o chiedi patch minima. Non serve rigenerare tutto.
La decisione non è emotiva. È una stima di contaminazione: quanto del diff sbagliato entrerebbe nella base se lo accetti?
Procedura pratica
Dopo generazione che non torna:
- Pausa: non rispondere “fai meglio”.
- Diagnosi: i 5 criteri di rifiuto si applicano? Quanti?
- Calcolo costo: tempo riparazione stimato vs rigenerazione.
- Decisione: ripara o rigenera.
- Se rigenera: riparti da un checkpoint pulito (commit, branch o copia controllata), poi scrivi prompt di ripartenza. Usa comandi distruttivi solo se sai esattamente cosa stai eliminando.
- Se ripara: identifica le 2-3 modifiche necessarie, applicale localmente.
- Verifica esito del nuovo round.
Laboratorio guidato
Caso tipo: hai chiesto “implementa autenticazione semplice”. Output:
- Aggiunge libreria `passport` + 5 strategie + JWT + refresh token + sessione cookie + 2FA stub.
- Crea 12 file in `src/auth/`.
- Modifica `app.ts` con configurazione di tutto.
- Aggiunge `tsconfig` paths nuovi.
- Migrazione DB con tabella `users`, `sessions`, `tokens`, `auth_logs`.
- Test E2E che richiedono setup Docker.
Diagnosi:
- Requisito ignorato: chiedevo “semplice”, ricevuto “enterprise”.
- Architettura: complessa per scope.
- Scope: drasticamente espanso (2FA, refresh, audit log non chiesti).
- Complessità inutile: 5 strategie per 1 caso d’uso.
→ Quattro criteri di rifiuto. Decisione: rigenera.
Costo:
- Riparazione: rimuovere 60% del codice, rivedere 10 file. ~3 ore.
- Rigenerazione: prompt migliore, output mirato. ~1 ora.
Prompt di ripartenza:
Ho rifiutato il tentativo precedente. Problemi:
- 12 file per "auth semplice" è eccessivo
- libreria passport overkill, voglio implementazione esplicita
- 2FA, refresh token, audit log NON erano richiesti
- migrazione DB con 4 tabelle: troppe
NON voglio:
- libreria passport
- 2FA, refresh token, audit log (non richiesti)
- più di una tabella DB nuova
- più di 3 file modificati
- modifica a tsconfig
Voglio "auth semplice":
- email/password
- una tabella `users` (id, email, password_hash, created_at)
- 2 endpoint: POST /auth/signup, POST /auth/login
- sessione via cookie HttpOnly Secure
- bcrypt per hash
- max 3 file: handler, schema, client utility
Vincoli:
- TypeScript strict
- max 200 righe totali
Comincia con piano in 5 punti, aspetta OK.
Risultato: tipicamente prompt di ripartenza produce esito molto più aderente al primo tentativo, perché vincoli sono espliciti.
Output atteso
Un template “prompt di ripartenza” personale, riusabile. Salvato in snippet o note.
Studio passo passo
Studia questa lezione in tre passaggi, senza correre subito al prompt o al codice.
- Prima lettura: chiarisci l’obiettivo: capire quando correggere localmente e quando il risultato è così fuori strada da richiedere una nuova richiesta. Se non riesci a riscriverlo in una frase tua, rileggi il nucleo della lezione.
- Seconda lettura: trasforma i contenuti in domande operative:
- Criteri di rifiuto: requisito centrale ignorato, architettura sbagliata, sicurezza compromessa, complessità inutile.
- Costo della riparazione rispetto al costo della rigenerazione con specifica migliore.
- Come scrivere un prompt di ripartenza: cosa non andava, cosa mantenere, cosa evitare, nuovo scope.
- Applicazione: svolgi il laboratorio: valutare tre output AI e decidere per ciascuno se accettare, correggere o rigenerare. L’output da ottenere è: una matrice decisionale accetta/modifica/rifiuta con motivazioni tecniche.
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
- ho rifiutato almeno una volta codice generato (non solo chiesto modifiche locali);
- so distinguere problemi locali da strutturali;
- so tornare a un checkpoint pulito senza perdere lavoro utile o modifiche non collegate;
- i miei prompt di ripartenza non sono semplicemente “fai meglio”.
Errori comuni
Patchare problemi strutturali. Codice diventa Frankenstein. Lavoro doppio.
Persistere su brutto inizio. Sunk cost: hai già investito tempo, vuoi salvare. Spesso meglio buttare.
Rigenerare senza prompt migliore. Stesso prompt = stesso risultato.
Non capitalizzare cosa è andato bene. Anche output cattivo può avere parti decenti. Riusa quelle.
Rifiutare per perfezionismo. Codice 80% giusto è ok. Rifiuto per il 100% è perfezionismo.
Dimenticare contesto. Prompt di ripartenza in nuova sessione: serve ricordare contesto del progetto, non solo problemi del primo tentativo.
Prompt di lavoro
Ho rifiutato il tentativo precedente di implementare: [task originale]
Problemi specifici trovati (1-3):
1. [...]
2. [...]
3. [...]
NON voglio (basandomi su cosa è andato male):
- [pattern/libreria/scope da evitare]
Ok mantenere (se applicabile):
- [parti decenti del primo tentativo]
Vincoli aggiuntivi (emersi dal primo tentativo):
- [vincoli rigidi]
Specifica originale (rimanata valida):
- [...]
Procedura:
1. Conferma di aver capito vincoli (parafrasa).
2. Piano in 3-5 punti.
3. Aspetta OK.
4. Implementa.
NON ricominciare con stesso pattern del primo tentativo.
Esercizio finale
Riguarda 3 generazioni AI degli ultimi mesi che hai pesantemente patchato. Per ognuna chiediti: quanto avrei risparmiato rigenerando con un prompt migliore? In 1-2 casi su 3, la risposta è “molto”. Quel pattern personale (riparazione automatica vs valutazione strategica) è esattamente la decisione che la lezione ti chiede di affinare.