Un prompt di code review deve dire al modello cosa cercare, quanto è grave ogni problema trovato e quale prova fornire. "Rivedi questo codice" ottiene un elenco cordiale di suggerimenti in cui una falla di sicurezza sta tra un consiglio sulle docstring e una preferenza sui nomi. Un prompt di review con una checklist, livelli di gravità e una richiesta di diff ottiene un report su cui puoi agire, una segnalazione alla volta.
Da "rivedi questo" a una checklist con gravità
Il codice in entrambe le schede ha due bug reali. Confronta come li presenta ogni risposta.
def get_user(conn, username):
cur = conn.cursor()
cur.execute(f"SELECT id, email FROM users WHERE name = '{username}'")
row = cur.fetchone()
return {"id": row[0], "email": row[1]}Nel complesso la funzione è breve e facile da seguire. Qualche suggerimento:
- Aggiungi le annotazioni di tipo, per esempio
username: str, per rendere più chiara la firma. - Aggiungi una docstring che spieghi cosa restituisce la funzione.
- Usa query parametrizzate. Costruire SQL con le f-string può portare a SQL injection.
- Gestisci gli utenti mancanti.
fetchone()può restituireNone. - Nomi:
fetch_userpotrebbe descrivere meglio l'accesso al database.
La prima risposta ha trovato entrambi i bug, ed è proprio questo il problema nel giudicare una review da ciò che menziona. L'injection sta al terzo posto in un elenco di cinque, ammorbidita con un "può portare a", senza correzione, accanto a un consiglio sulle docstring. Chi la leggesse di corsa aggiungerebbe le annotazioni di tipo e passerebbe oltre.
Il secondo prompt ha cambiato quattro cose:
- L'ambito. "Solo bug, sicurezza e gestione degli errori. Ignora lo stile" toglie il rumore. Lo stile spetta a un linter e a un formatter, che sono più veloci e non si contraddicono mai.
- La gravità. Costringe il modello a mettere in ordine, e un elenco ordinato ti dice da dove cominciare.
- Un input che provoca il problema. "
x' OR '1'='1" trasforma un rischio vago in una dimostrazione che puoi eseguire. È anche il tuo miglior filtro contro i falsi positivi, come mostra l'ultima sezione. - I diff. Un piccolo diff per segnalazione si può applicare o rifiutare da solo. Una funzione riscritta mescola ogni correzione con modifiche che nessuno ha chiesto.
"Se non c'è nulla a un livello di gravità, non inventare niente" conta più di quanto sembri. Quando gli chiedi una review, un modello tende a produrre segnalazioni anche quando c'è poco da trovare, e quelle più deboli gonfiano l'elenco. Un permesso esplicito a non segnalare nulla a un certo livello riduce questo riempitivo.
Il contesto che serve al revisore
Un revisore umano sa a cosa serve il codice e da dove arrivano i suoi input. Il modello sa solo quello che incolli. "username arriva direttamente da un modulo di login" è la frase che fa della SQL injection una segnalazione di gravità alta invece che teorica. Contesto utile per una review:
- Da dove arrivano gli input: utenti, un altro servizio interno, un file di configurazione che controlli tu.
- Cosa chiama il codice e cosa si aspetta in cambio.
- L'ambiente di esecuzione: versione del linguaggio, framework, driver del database. La correzione dell'injection qui sopra usa
?perché sqlite3 usa quel segnaposto; altri driver usano%s. - Cosa ti importa di più in questa modifica: correttezza, sicurezza, prestazioni, o tutte e tre.
Un prompt di review riutilizzabile
Questo blocco trasforma la checklist in un template. Cambia il linguaggio, il focus e il codice, e mantieni le regole. Disattivare la parte dei vincoli è un modo rapido per vedere quanto rumore torna senza.
async function loadAll(ids) {
const results = [];
ids.forEach(async (id) => {
const res = await fetch(`/api/items/${id}`);
results.push(await res.json());
});
return results;
}1. Alta: la funzione restituisce prima che qualsiasi richiesta finisca (riga 3)
forEach non aspetta le callback asincrone. loadAll restituisce subito l'array results vuoto, e i push avvengono dopo. Chiunque la chiami riceve [].
2. Media: le richieste fallite vengono trattate come dati (riga 5)
Una risposta 404 o 500 non è un'eccezione in fetch. Un corpo di errore in JSON viene letto e aggiunto come se fosse un elemento, e un corpo non JSON fa sì che res.json() sollevi un'eccezione dentro una callback che nessuno attende.
Correzione per entrambi, che mantiene anche i risultati nello stesso ordine di ids:
async function loadAll(ids) {
- const results = [];
- ids.forEach(async (id) => {
- const res = await fetch(`/api/items/${id}`);
- results.push(await res.json());
- });
- return results;
+ return Promise.all(
+ ids.map(async (id) => {
+ const res = await fetch(`/api/items/${id}`);
+ if (!res.ok) throw new Error(`Item ${id}: HTTP ${res.status}`);
+ return res.json();
+ })
+ );
}
La riga del ruolo fissa uno standard ("problemi reali e nient'altro"), ed è lì che il role prompting aiuta di più. Se un programma legge la review, per esempio uno script che pubblica le segnalazioni come commenti su una pull request, chiedi un JSON con campi fissi invece della prosa; output strutturato mostra come.
Gestire i falsi positivi
Alcune segnalazioni saranno sbagliate. Il modello non può vedere il chiamante che valida l'input, il vincolo del database che rende impossibile un caso o il motivo per cui una riga dall'aspetto strano è voluta. Può anche sbagliarsi su come si comporta una libreria; allucinazioni dell'IA spiega perché un'affermazione sicura non è un'affermazione verificata.
Metti alla prova ogni segnalazione con il suo input. Se non riesci a produrre un input che arrivi al problema nel tuo sistema, contesta la segnalazione con il contesto mancante invece di accettare la correzione:
function formatPrice(cents) {
return `$${(cents / 100).toFixed(2)}`;
}
Viene chiamata solo da `renderCart`, che esce subito a meno che `Number.isInteger(cents)` sia vero. È ancora un problema? Se non lo è, ritira la segnalazione.Con quel controllo, no: formatPrice riceve sempre e solo un intero, quindi la segnalazione non si applica e la ritiro.
Una cosa che il controllo non copre: gli interi negativi superano Number.isInteger, e formatPrice(-500) restituisce "$-5.00". Se rimborsi o sconti possono arrivare a questa funzione, forse vuoi "-$5.00". Se non possono arrivarci, non c'è niente da cambiare.
Un modello a cui mostri una nuova prova dovrebbe ritirare la segnalazione oppure spiegare perché regge anche alla luce di quella prova. Entrambe le cose sono utili. Un modello che dà semplicemente ragione a ogni obiezione non sta facendo una review, quindi giudica la risposta dalle sue motivazioni, non dal fatto che ti abbia dato ragione. Per il codice scritto dal modello stesso, fai la review in una nuova conversazione, così la revisione non viene letta attraverso lo stesso ragionamento che ha prodotto il codice. Le stesse abitudini di ambito, contesto e test rendono il codice migliore fin dall'inizio; vedi prompt per scrivere codice.
Domande frequenti
Qual è un buon prompt per la code review?
Indica cosa controllare (bug, sicurezza, gestione degli errori), chiedi una gravità per ogni segnalazione ed esigi un input concreto che provochi il problema più un diff che lo risolva. Di' al modello di ignorare formattazione e nomi, a meno che tu non li chieda. Dagli il contesto che avrebbe un revisore umano: a cosa serve il codice e cosa lo chiama.
L'IA può sostituire la code review fatta da persone?
No, ma è una prima passata utile. È veloce ed è brava con gli schemi di bug comuni, come un None non gestito, un await mancante o un SQL costruito con le stringhe. Non conosce le regole del tuo prodotto, il resto del codebase o il motivo di una decisione, e alcune sue segnalazioni saranno sbagliate. Usala prima di una revisione umana, non al suo posto.
Perché una code review con l'IA segnala problemi che non esistono?
Il modello vede solo il codice che hai incollato. Se un valore viene validato dal chiamante, o un caso non può mai verificarsi nel tuo sistema, il modello non può saperlo, quindi segnala comunque il rischio. Chiedere un input concreto che provochi il problema ne filtra molti: una segnalazione senza alcun input realistico che la provochi di solito è un falso positivo.
Devo chiedere all'IA di riscrivere il mio codice durante una review?
Chiedi piccoli diff, uno per segnalazione, invece di un file riscritto. Una riscrittura completa mescola le correzioni con modifiche che nessuno ha chiesto, e dovresti rivedere anche la riscrittura. I diff ti permettono di accettare o rifiutare ogni segnalazione separatamente.