modulo 10 / lezione 52
Capstone: bug reale end-to-end
Capstone: indagine guidata
Applicare osservazione, isolamento e delta debugging per arrivare a una causa verificata, mantenendo il taccuino.
In parole semplici
Hai il bug report e le ipotesi della sessione 1. Ora indaghi. Novanta minuti. Tre cicli ipotesi/prova/esito. Alla fine devi avere la causa radice verificata, non solo “ho sistemato”.
Cosa impari (rivedere applicare)
- Modulo 3: log strutturati, breakpoint condizionati, Network analysis.
- Modulo 4: ipotesi falsificabile, ricerca binaria, delta debugging.
- Modulo 7: race condition, doppio submit (se applicabile).
- Modulo 8: contratti API, idempotenza (se applicabile).
Sessione di indagine: scaletta 90 minuti
0–10 min: rilettura del taccuino
Riapri il taccuino di sessione 1. Riallineati:
- Bug report.
- Ipotesi pianificate.
- Stato corrente: cosa è confermato, cosa è ipotesi.
10–35 min: ciclo 1 — prima ipotesi
Ipotesi 1 (dall’esempio della sessione 1): doppio submit del pulsante “Conferma”.
Prova: in DevTools, conta le richieste POST /api/ordini in 10 tentativi con doppio click rapido.
Procedura:
- Apri Network. Filtra per
ordini. - Click rapido due volte sul pulsante.
- Conta le richieste.
- Annota: # request, status, response body.
Esito: vedi 2 richieste in 4 tentativi su 10. Confermato il pattern.
Aggiorna taccuino:
10:25 — Ipotesi 1: doppio submit
PROVA: 10 tentativi con doppio click rapido (< 200ms).
ESITO: 4 tentativi su 10 mostrano DUE richieste POST /api/ordini.
CONSEGUENZA: il pulsante non disabilita dopo click. Ma:
- in 2 dei 4 casi, entrambe le richieste creano un ordine (duplicato).
- in 2 casi, una sola crea ordine.
Sotto: lato server non c'è idempotenza.
35–60 min: ciclo 2 — seconda ipotesi
Ipotesi 2: il server non gestisce idempotency-key, quindi due POST simultanei creano due ordini.
Prova: lato server, leggi POST /api/ordini handler. Cerca:
- Header
Idempotency-Key. - Logica di deduplicazione (vincolo unique, controllo “ordine già creato in ultimi X secondi”).
Procedura:
- Apri repo capstone, file server (es.
server/routes/ordini.js). - Leggi la funzione handler.
- Esegui due richieste manuali (
curl) con stessa idempotency-key. Cosa succede?
curl -X POST localhost:3000/api/ordini \
-H "Content-Type: application/json" \
-H "Idempotency-Key: test-123" \
-d '{"items":[{"id":1,"qta":1}]}'
# poi:
curl -X POST localhost:3000/api/ordini \
-H "Content-Type: application/json" \
-H "Idempotency-Key: test-123" \
-d '{"items":[{"id":1,"qta":1}]}'
Esito: due ordini creati con la stessa idempotency-key. Confermato: il server non rispetta l’idempotenza.
11:00 — Ipotesi 2: server non rispetta idempotency-key
PROVA: due curl con stesso header. Due ordini creati.
ESITO: il server ignora `Idempotency-Key`.
CONSEGUENZA: il bug nasce dal doppio submit, ma è amplificato dalla mancanza di idempotenza lato server.
60–80 min: ciclo 3 — terza ipotesi (case scomparsi)
Ipotesi 3: gli ordini “scomparsi” (non duplicati) sono causati da una race condition tra creazione e refresh della lista.
Prova:
- Crea un ordine con click singolo.
- Subito dopo (entro 100ms) ricarica la lista ordini.
- Misura: la chiamata
GET /api/ordiniarriva al server prima o dopo che il POST sia stato “committed” al DB?
Procedura:
- In Network, vedi l’ordine delle richieste e i loro
Initiator. - Lato server, aggiungi un log nel handler
POST /ordini(timestamp) eGET /ordini(timestamp). - Riproduci 5 volte. Confronta timestamp.
Esito: in 1 caso su 5, il GET arriva mentre il POST è ancora dentro la transazione DB. La lista esclude il nuovo ordine. Dopo qualche secondo, l’ordine appare.
11:30 — Ipotesi 3: race tra POST e GET ordini
PROVA: timestamp lato server. POST e GET sovrapposti.
ESITO: il GET legge stato pre-commit. L'utente vede "ordine scomparso", ma è ricomparirà.
CAUSA RADICE COMBINATA:
- doppio submit lato client (manca disable durante richiesta)
- mancanza di idempotency lato server
- race tra POST commit e GET (mancanza isolamento "read your writes")
80–90 min: chiusura indagine
Aggiorna taccuino:
SINTESI
Causa diretta: doppio submit del pulsante + race con refresh.
Causa radice:
1. UI: pulsante non disabilitato durante richiesta.
2. Server: idempotency-key non rispettata.
3. Tempo: chiamate GET non isolate dalle scritture in volo.
Direzione fix (sessione 3):
1. Lato client: disable button + AbortController.
2. Lato server: store idempotency-key (Redis o tabella DB).
3. Lato lettura: aspetta breve, o usa "read your writes" consistency.
Decisione di scope: il fix completo include tutti e tre.
Iniziamo da (1) e (2): elimina la causa primaria. (3) è mitigation.
Quando il ciclo non porta a una causa
Se dopo 90 minuti non hai una causa verificata:
- Non inventare. Documenta cosa hai escluso.
- Pianifica una sessione 2-bis con ipotesi nuove.
- Considera: pair debugging (modulo 6.3) o chiedere aiuto (modulo 6.1).
Esito atteso
Alla fine dei 90 minuti, hai:
- ✅ Una causa radice verificata da prove, non da intuizione.
- ✅ Taccuino con tre cicli completi.
- ✅ Direzione di fix con scope deciso.
- ✅ Lista delle prove rifatte se necessario (per la prossima sessione).
Errori frequenti del capstone
- Più ipotesi attive insieme. Una alla volta.
- “Quasi capito” prematuro. Verifica con prova, non con intuito.
- Saltare il log dei timestamp. Per bug di timing è essenziale.
- Dichiarare “una sola causa”. Spesso le cause sono composte: documenta tutte.