Fai il debug di bug segnalati da altri: un workflow pratico
Analizza bug segnalati da altri con un workflow pratico per riprodurre problemi, isolare UI/API/DB e richiedere una correzione AI minima e testabile.

Cosa rende difficili questi bug report (e cosa puoi controllare)
Fare il debug di un bug report che non hai scritto è più difficile perché ti manca la mappa mentale dell'autore. Non sai cosa è fragile, cosa è “normale” o quali scorciatoie sono state prese. Un piccolo sintomo (un pulsante, un refuso, una schermata lenta) può comunque provenire da un problema più profondo nell'API, nel database o in un job in background.
Un bug report utile ti dà quattro cose:
- l'azione esatta
- i dati esatti
- il risultato atteso
- il risultato reale
La maggior parte dei report dà solo l'ultimo: “Il salvataggio non funziona”, “è rotto”, “errore casuale”. Quello che manca è il contesto che lo rende ripetibile: ruolo utente, record specifico, ambiente (prod vs staging) e se è iniziato dopo una modifica.
L'obiettivo è trasformare un sintomo vago in una riproduzione affidabile. Una volta che riesci a farlo succedere a comando, non è più misterioso. È una serie di controlli.
Quello che puoi controllare subito:
- il set minimo di passi che attiva il problema
- i dati di test esatti (ID, email, payload, filtri)
- l'ambiente e la versione (build, feature flag, browser/dispositivo)
- la prova che è successo (timestamp, screenshot, testo d'errore, estratto di log)
- un risultato chiaro pass/fail che puoi rieseguire
“Fatto” non è “Penso di averlo risolto.” Fatto è: i tuoi passi di riproduzione passano dopo una piccola modifica e ritesti rapidamente i comportamenti vicini che potresti aver influenzato.
Prepara una baseline stabile prima di toccare nulla
Il modo più veloce per perdere tempo è cambiare più cose contemporaneamente. Congela il punto di partenza in modo che ogni risultato del test significhi qualcosa.
Scegli un solo ambiente e attieniti a quello finché non riesci a riprodurre il problema. Se il report viene da produzione, confermalo lì prima. Se è rischioso, usa lo staging. Locale va bene se riesci ad avvicinare dati e impostazioni.
Poi individua quale codice è effettivamente in esecuzione: versione, data di build e qualsiasi feature flag o config che influenzi il flusso. Piccole differenze (integrazioni disabilitate, URL base API diverso, job in background mancanti) possono trasformare un bug reale in un fantasma.
Crea una configurazione di test pulita e ripetibile. Usa un account nuovo e dati noti. Se puoi, resetta lo stato prima di ogni tentativo (logout, pulisci cache, parti dallo stesso record).
Annota le assunzioni mentre procedi. Non è lavoro inutile; ti evita di discutere con te stesso dopo.
Un template per le note di baseline:
- Ambiente: prod, staging o locale
- Versione/build: commit, tag o timestamp di build
- Config: feature flag, integrazioni, chiavi di test
- Identità di test: email/ruolo account, permessi
- Dati: ID record, elementi seedati, stato iniziale atteso
Se la riproduzione fallisce, queste note ti dicono cosa variare dopo, una manopola alla volta.
Traduci il report in passi e input testabili
La vittoria più rapida è trasformare una lamentela vaga in qualcosa che puoi eseguire come uno script.
Inizia riscrivendo il report come una breve user story: chi fa cosa, dove e cosa si aspettava. Poi aggiungi il risultato osservato.
Esempio di riscrittura:
"Come amministratore fatturazione, quando cambio lo stato di una fattura in Pagata e clicco Salva nella pagina della fattura, lo stato dovrebbe persistere. Invece, la pagina resta uguale e lo stato non cambia dopo il refresh."
Poi cattura le condizioni che rendono vero il report. I bug spesso dipendono da un dettaglio mancante: ruolo, stato del record, locale o ambiente.
Input chiave da annotare prima di cliccare in giro:
- Ruolo utente e tipo di account (admin vs standard, trial vs pagato)
- Stato dei dati (ID record, stato, dati correlati richiesti)
- Dettagli client (OS, versione browser/app)
- Impostazioni di locale e orario (lingua, timezone, range di date)
- Ambiente e build (prod vs staging, versione di rilascio, feature flag)
Raccogli prove mentre hai ancora il comportamento originale. Gli screenshot aiutano, ma una breve registrazione è meglio perché cattura i tempi e i clic esatti. Segna sempre un timestamp (inclusa la timezone) così puoi abbinare i log dopo.
Tre domande chiarificatrici che rimuovono la maggior parte delle congetture:
- Su quale account utente e ruolo è successo esattamente, e puoi fornire un ID record di esempio?
- Cosa ti aspettavi di vedere immediatamente dopo l'azione e cosa hai effettivamente visto?
- Succede sempre con gli stessi passi, o solo con dati specifici (stato, range di date, locale, inserimenti grandi)?
Riproduci il problema in modo affidabile
Non iniziare indovinando la causa. Fai succedere il problema di proposito, nello stesso modo, più di una volta.
Per prima cosa, esegui i passi del reporter esattamente come scritti. Non "migliorarli". Nota il primo punto in cui la tua esperienza diverge, anche se sembra banale (etichetta del pulsante diversa, campo mancante, testo d'errore leggermente diverso). Quella prima discrepanza è spesso l'indizio.
Un flusso semplice che funziona nella maggior parte delle app:
- Resetta a uno stato di partenza noto (caricamento pulito, stesso account, stessi permessi, stessi flag).
- Segui i passi uno per uno e registra gli input esatti usati (ID, date, filtri).
- Annota atteso vs reale al passo dove si rompe.
- Ripeti una volta per confermare che è ripetibile.
- Riduci ai passi minimi che ancora lo attivano.
Dopo che è ripetibile, varia una cosa alla volta. Test a variabile singola che spesso pagano:
- stessi passi, ruolo diverso
- stessi passi, record diverso (nuovo vs legacy)
- stessi passi, browser/dispositivo diverso
- stessi passi, sessione pulita (incognito, cache cancellata)
- stessi passi, rete diversa
Termina con uno script di repro breve che qualcun altro può eseguire in 2 minuti: stato iniziale, passi, input e la prima osservazione che fallisce.
Isola il livello che fallisce: UI, API o DB
Prima di leggere tutto il codice, decidi quale layer sta fallendo.
Chiediti: il sintomo è solo nella UI, o è anche nei dati e nelle risposte API?
Esempio: “Il mio nome profilo non si è aggiornato.” Se l'API restituisce il nuovo nome ma la UI mostra ancora il vecchio, sospetta lo stato UI/caching. Se l'API non lo ha mai salvato, sei probabilmente in area API o DB.
Domande rapide per il triage che puoi rispondere in pochi minuti:
- Riesci a riprodurlo su più browser/dispositivi?
- Un refresh forzato cambia qualcosa?
- Si attiva una richiesta di rete quando clicchi il pulsante?
- La risposta API è già sbagliata?
- Il database mostra la riga attesa dopo l'azione?
I controlli UI riguardano la visibilità: errori nella console, scheda Network e stato stantio (UI che non fa refetch dopo il salvataggio o legge da cache vecchia).
I controlli API riguardano il contratto: payload (campi, tipi, ID), codice di stato e body di errore. Un 200 con un body sorprendente può contare tanto quanto un 400.
I controlli DB riguardano la realtà: righe mancanti, scritture parziali, vincoli violati, update che toccano zero righe perché la WHERE non matcha.
Per restare orientato, abbozza una piccola mappa: quale azione UI invoca quale endpoint e quali tabelle legge o scrive.
Segui la richiesta end-to-end con log e timestamp
La chiarezza spesso arriva dal seguire una singola richiesta reale dal click fino al database e ritorno.
Cattura tre ancore dal report o dal tuo repro:
- tempo esatto (con timezone)
- identificatore utente (account/email/ID interno)
- correlation ID (request ID/trace ID/session ID)
Se non hai un correlation ID, aggiungine uno nel gateway/backend e includilo negli header di risposta e nei log.
Per evitare di annegare nel rumore, cattura solo ciò che serve a rispondere “Dove è fallito e perché?”:
- intervallo di timestamp (per esempio, 1 minuto prima a 1 minuto dopo)
- un user ID (e tenant/org ID se rilevante)
- correlation ID
- metodo, path, codice di stato, latenza
- il primo messaggio di errore significativo (non pagine di stack trace)
Segnali da tenere d'occhio:
- Timeout/latenze lunghe: query lente, chiamate esterne, lock.
- 401/403: problemi di permessi o contesto tenant.
- 400 errori di validazione: spesso mismatch di payload dalla UI.
Se “ieri funzionava” ma oggi no, sospetta deriva dell'ambiente: flag cambiati, segreti ruotati, migrazioni mancate o job che hanno smesso di girare.
Costruisci un caso minimo riproducibile (così le fix restano piccole)
Il bug più facile da fissare è un esperimento piccolo e ripetibile.
Riduci tutto: meno clic, meno campi, il dataset più piccolo che fallisce ancora. Se succede solo con “clienti con tanti record”, prova a creare un caso minimo che lo attivi. Se non ci riesci, è un indizio che il bug è legato al volume dei dati.
Separa lo “stato corrotto” dal “codice difettoso” resettando lo stato di proposito: account pulito, tenant o dataset fresco, build nota.
Un modo pratico per mantenere il repro chiaro è una tabella di input compatta:
| Given (setup) | When (azione) | Expect | Got |
|---|---|---|---|
| User role: Editor; one record with Status=Draft | Click Save | Toast "Saved" + updated timestamp | Button shows spinner then stops; no change |
Rendi il repro portabile così qualcun altro può eseguirlo rapidamente:
- 3–6 passi da uno start pulito
- un record di test (o un request body) riutilizzabile
- un segnale chiaro di successo (messaggio UI, codice HTTP, conteggio righe DB)
- dettagli esatti di ambiente (build/versione, ruolo, flag)
Trappole comuni che fanno perdere tempo
Il percorso più rapido è spesso noioso: cambia una cosa, osserva, prendi appunti.
Errori comuni:
- Risolvere il sintomo superficiale (mascherando un vero errore API/DB).
- Cambiare più variabili insieme (aggiornamenti di dipendenze + tweak di config + refactor).
- Testare su una baseline diversa da quella del reporter (env, dati, build, browser).
- Dimenticare permessi e ruoli (admin vs utente normale).
- Mancare feature flag o esperimenti che cambiano i flussi.
- Dichiarare vittoria senza verifica (nessuna riesecuzione del repro, nessun controllo degli effetti collaterali).
Un esempio realistico: un ticket dice “Export CSV è vuoto.” Tu testi con un account admin e vedi i dati. L'utente ha un ruolo ristretto e l'API restituisce una lista vuota a causa di un filtro di permessi. Se applichi solo una patch sulla UI per mostrare “Nessuna riga,” perdi la questione reale: quel ruolo dovrebbe poter esportare o il prodotto dovrebbe spiegare perché è filtrato?
Dopo ogni fix, riesegui gli stessi passi di repro, poi testa uno scenario vicino che dovrebbe ancora funzionare.
Checklist rapida prima di chiedere una fix
Otterrai risposte migliori da un collega (o da uno strumento) se porti un pacchetto compatto: passi ripetibili, un layer probabile che fallisce e prove.
Prima che qualcuno cambi codice, conferma:
- Riesci a riprodurlo due volte usando gli stessi input (stesso utente, stessi dati, stesso ambiente).
- Riesci a nominare il layer che fallisce (UI, API o DB) e fornire una ragione.
- Hai catturato prove: richiesta, risposta/errore, log rilevanti e un timestamp corrispondente.
- Hai ridotto il repro al caso più piccolo possibile.
- Hai scritto criteri di accettazione in una frase (esempio: "Il salvataggio aggiorna il record e mostra successo entro 2 secondi").
Poi fai una rapida passata di regressione: prova un ruolo diverso, un secondo browser/finestra privata, una funzionalità vicina che usa lo stesso endpoint/tabella e un input edge-case (vuoto, testo lungo, caratteri speciali).
Un esempio realistico: restringere un bug “Il pulsante Salva non fa nulla”
Un messaggio di supporto dice: "Il pulsante Salva non fa nulla nel form Modifica Cliente." Un follow-up rivela che succede solo per clienti creati prima del mese scorso e solo quando cambi la email di fatturazione.
Inizia dalla UI e assumi il fallimento più semplice. Apri il record, fai la modifica e cerca segni che il “nulla” sia in realtà qualcosa: pulsante disabilitato, toast nascosto, messaggio di validazione che non viene renderizzato. Poi apri la console del browser e la scheda Network.
Qui, cliccando Salva si innesca una request, ma la UI non mostra mai il risultato perché il frontend considera successo solo il 200 e ignora gli errori 400. La Network tab mostra una risposta 400 con un body JSON come: {\"error\":\"billingEmail must be unique\"}.
Ora verifica che l'API falli davvero: prendi esattamente il payload dalla richiesta e replayalo. Se fallisce anche fuori dalla UI, smetti di inseguire bug di stato frontend.
Poi controlla il database: perché la unicità fallisce solo per i record più vecchi? Scopri che i clienti legacy condividono una billing_email segnaposto di anni fa. Un controllo di unicità più nuovo ora blocca il salvataggio di qualsiasi cliente che ha ancora quel segnaposto.
Repro minimo che puoi consegnare:
- Prendi un cliente legacy con
billing_email = [email protected]. - Cambia qualsiasi campo e clicca Salva.
- Osserva che l'API risponde 400 con
billingEmail must be unique. - Osserva che la UI non mostra l'errore e lascia il form invariato.
Test di accettazione: quando l'API restituisce un errore di validazione, la UI mostra il messaggio, conserva le modifiche dell'utente e l'errore indica esattamente il campo che è fallito.
Prossimi passi: chiedere una correzione minima che puoi testare
Una volta che il bug è riproducibile e hai identificato il layer probabile, chiedi aiuto in modo da ottenere una patch piccola e sicura.
Prepara un semplice “case file”: passi minimi di repro (con input, ambiente, ruolo), expected vs actual, perché pensi sia UI/API/DB e l'estratto di log più piccolo che mostra il fallimento.
Poi rendi la richiesta stretta:
- proponi la modifica di codice più piccola che risolve il repro
- evita refactor a meno che non siano necessari
- spiega la causa in parole semplici
- includi un micro piano di test (come confermare la fix e cosa potrebbe rompersi vicino)
Se usi una piattaforma vibe-coding come Koder.ai (koder.ai), questo approccio con il case file mantiene la proposta focalizzata. I suoi snapshot e rollback possono anche aiutare a testare piccole modifiche in sicurezza e tornare a una baseline nota.
Affida a uno sviluppatore esperto quando la fix tocca sicurezza, pagamenti, migrazioni di dati o qualsiasi cosa che potrebbe corrompere i dati di produzione. Affida anche se la modifica continua a crescere oltre una patch piccola o non riesci a spiegare il rischio in parole semplici.
Domande frequenti
Qual è la prima cosa che dovrei fare con un report vago tipo “non funziona”?
Inizia riscrivendo il report in uno script riproducibile: chi (ruolo), dove (pagina/flusso), quali input esatti (ID, filtri, payload), cosa ti aspettavi e cosa hai visto. Se manca qualche pezzo, chiedi un account di esempio e un ID record così puoi eseguire lo stesso scenario end-to-end.
Come imposto una baseline così i miei test abbiano davvero senso?
Scegli un ambiente e resta su quello finché non riesci a riprodurre il problema. Registra poi build/versione, feature flag, configurazione, account/ruolo di test e i dati esatti usati. Questo ti evita di “risolvere” un bug che esiste solo perché il tuo setup non corrisponde a quello del reporter.
Come trasformo il report in una riproduzione minima che qualcun altro può eseguire velocemente?
Fallo succedere due volte con gli stessi passi e input, poi rimuovi tutto ciò che non è necessario. Punta a 3–6 passi da uno stato pulito con un record o body riutilizzabile. Se non riesci a ridurlo, spesso indica dipendenza da volume di dati, temporizzazione o job in background.
Devo iniziare indovinando la causa o riproducendolo?
Non cambiare nulla all’inizio. Esegui prima esattamente i passi del reporter e annota il primo punto in cui la tua esperienza diverge (etichetta del pulsante diversa, campo mancante, testo d’errore diverso). Quella prima discrepanza spesso indica la condizione reale che scatena il bug.
Come posso capire rapidamente se il bug è nella UI, API o database?
Controlla se i dati sono effettivamente cambiati. Se l’API restituisce il valore aggiornato ma la UI mostra ancora quello vecchio, è probabile uno stato UI, cache o mancato refetch. Se la risposta API è sbagliata o il salvataggio non avviene, concentra l’attenzione su API o DB. Se la riga DB non si aggiorna (o aggiorna zero righe), il problema è nella persistenza o nelle condizioni della query.
Quale evidenza dovrei catturare mentre riproduco il bug?
Verifica che una richiesta di rete venga inviata quando clicchi il bottone, poi ispeziona payload e body della risposta, non solo il codice di stato. Salva un timestamp (con timezone) e un identificatore utente così puoi incrociare i log di backend. Un 200 “di successo” con un body inaspettato può essere importante quanto un 400/500.
Qual è il modo migliore per testare bug che “succedono solo a volte”?
Varia un solo parametro alla volta: ruolo, record (nuovo vs legacy), browser/dispositivo, sessione pulita (incognito/cache svuotata) e rete. Testare a variabili singole ti dice quale condizione conta e ti impedisce di inseguire coincidenze causate dal cambiare troppe cose insieme.
Quali sono gli errori più comuni che fanno perdere tempo durante il debug?
Cambiare più variabili insieme, testare in un ambiente diverso da quello del reporter e ignorare ruoli/permessi sono le maggiori perdite di tempo. Un altro errore comune è correggere il sintomo superficiale in UI mentre sotto c’è ancora un errore di validazione API/DB. Dopo ogni modifica riesegui esattamente il repro e poi testa uno scenario vicino.
Cosa significa “finito” per una correzione, oltre a “funziona sulla mia macchina”?
Considera “done” come: il repro minimo originale ora passa e hai ritestato un flusso vicino che potrebbe essere impattato. Mantieni il controllo concreto, per esempio un messaggio di successo visibile, la risposta HTTP corretta o la modifica attesa nel DB. Evita “penso sia risolto” senza rieseguire gli stessi input sulla stessa baseline.
Come dovrei chiedere a un AI builder (o a un collega) una piccola correzione testabile?
Fornisci un case file conciso: passi minimi con input esatti, ambiente/build/flag, account e ruolo di test, expected vs actual e un pezzo di prova (request/response, testo d’errore o frammento di log con timestamp). Poi chiedi la patch più piccola che faccia passare il repro e includi un piccolo piano di test. Se usi Koder.ai, abbinare questo case file a snapshot/rollback aiuta a testare piccole modifiche in sicurezza e ripristinare se serve.