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.

90 min Debugging

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:

  1. Apri Network. Filtra per ordini.
  2. Click rapido due volte sul pulsante.
  3. Conta le richieste.
  4. 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:

  1. Apri repo capstone, file server (es. server/routes/ordini.js).
  2. Leggi la funzione handler.
  3. 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/ordini arriva al server prima o dopo che il POST sia stato “committed” al DB?

Procedura:

  1. In Network, vedi l’ordine delle richieste e i loro Initiator.
  2. Lato server, aggiungi un log nel handler POST /ordini (timestamp) e GET /ordini (timestamp).
  3. 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.