laboratorio / archivio corso

Debugging in laboratorio

Dal sintomo al fix verificato.

Un archivio operativo per imparare a trattare i bug come casi di studio: riproduzione, lettura degli errori, osservazione con strumenti, isolamento della causa, correzione minima e verifica di regressione.

metodo

Il corso allena una sequenza ripetibile, non una collezione di trucchi.

  1. 01

    Caso minimo

    Riduci il problema a input, passaggi, output atteso e output osservato. Se non lo puoi ripetere, non lo puoi ancora governare.

  2. 02

    Ipotesi

    Scrivi cosa pensi stia succedendo e quale prova può falsificarlo. Il debug è indagine, non caccia casuale.

  3. 03

    Osservazione

    Usa console, breakpoint, network, stato e test per vedere il programma mentre accade, non solo dopo che ha fallito.

  4. 04

    Fix controllato

    Applica una correzione piccola, leggibile e reversibile. Poi verifica il caso iniziale e almeno un caso vicino.

regole del laboratorio

Cinque abitudini da ripetere in ogni bug.

Metodo trasversale a ogni linguaggio. Gli esempi pratici sono prevalentemente JavaScript e ambiente web (browser, DevTools, HTTP, Node), con apertura a Python, Java, Swift e backend SQL nei moduli 8 e 9.

  1. 01 Riprodurre prima di correggere.
  2. 02 Descrivere il sintomo senza inventare subito la causa.
  3. 03 Cambiare una variabile alla volta.
  4. 04 Conservare una traccia: log, ipotesi, prove, diff.
  5. 05 Chiudere ogni fix con una verifica di regressione.

archivio moduli

Lezioni pianificate come casi di laboratorio.

Ogni modulo parte da un sintomo concreto e termina con un output controllabile: scheda bug, mappa dello stack, log, test, diff o report di handoff.

  1. 00 alfabetizzazione

    4 ore / fondamenta

    Fondamenta del debug

    sintomo Non so neanche da dove cominciare a guardare.

    Costruire il vocabolario minimo e l'ambiente di lavoro: capire cos'è un bug, quali tipi esistono, dove osservarli e con quali strumenti aprire la sessione di laboratorio.

    competenza Riconoscere le categorie di errore, aprire console e DevTools del browser, leggere un terminale, distinguere editor, runtime e bundle.

    • browser moderno
    • DevTools
    • editor di codice
    • terminale
    • Node.js
    • glossario
    4 lezioni Programma lezioni
    1. Distinguere bug, limitazione, richiesta di funzionalità e malinteso d'uso; capire perché la stessa parola non può coprire tutto.

      Lab: Classificare dieci segnalazioni raccolte da forum pubblici come bug, non-bug o ambiguità da chiarire. Output: Tassonomia personale con criteri di classificazione.
    2. Capire perché alcuni errori fermano il programma prima di partire, altri durante l'esecuzione, altri ancora restano nascosti pur producendo un risultato sbagliato.

      Lab: Innescare di proposito tre errori della stessa famiglia in un piccolo programma di partenza. Output: Schema con esempio per ciascuna famiglia.
    3. Installare e configurare browser aggiornato con DevTools, editor con linter integrato, terminale e runtime locale.

      Lab: Eseguire un programma di prova in console del browser, in terminale Node e dall'editor, osservando gli stessi messaggi nei tre contesti. Output: Postazione pronta e screenshot di verifica.
    4. Costruire un vocabolario minimo: runtime, stack, heap, payload, fixture, regressione, throttling, source map, snapshot, postmortem.

      Lab: Compilare una scheda glossario riformulando ogni termine con parole proprie e un esempio personale. Output: Glossario personale del corso.
  2. 01 diagnosi iniziale

    6 ore / base

    Riprodurre il bug

    sintomo Funziona sul mio computer, ma in laboratorio no.

    Trasformare un errore raccontato male in un caso ripetibile, osservabile e condivisibile, e avviare la pratica del taccuino di laboratorio.

    competenza Scrivere bug report con ambiente, passi, risultato atteso, risultato osservato, caso minimo; mantenere un taccuino di indagine.

    • browser
    • editor
    • README
    • screenshot
    • registratore di sessione
    • taccuino di laboratorio
    5 lezioni Programma lezioni
    1. Distinguere descrizioni emotive, sintomi tecnici, passaggi riproducibili e ipotesi non verificate, usando un template canonico (titolo, ambiente, passi, atteso, osservato, evidenze, severità).

      Lab: Riscrivere tre segnalazioni vaghe in schede bug complete partendo dal template fornito. Output: Template bug report compilato.
    2. Classificare un difetto in modo che prossimo passo, severità e responsabile siano deducibili dalla categoria.

      Lab: Assegnare categoria, severità e priorità a sei segnalazioni di esempio. Output: Matrice categoria/severità/priorità.
    3. Capire quali informazioni rendono un errore confrontabile tra computer, browser, account e ramo di codice diversi.

      Lab: Confrontare due postazioni con comportamento diverso e annotare solo le differenze utili. Output: Scheda ambiente minima.
    4. Ridurre un problema senza cancellare proprio la condizione che lo fa comparire; conoscere acronimi MCVE/MRE come pratica condivisa.

      Lab: Partire da una pagina con più errori e arrivare a un file minimo che mostra un solo difetto, partendo dal repo didattico fornito. Output: Caso minimo e passaggi numerati.
    5. Separare cosa dovrebbe accadere, cosa accade davvero e quanto spesso accade, e iniziare a registrare la sessione in un taccuino strutturato (ipotesi, prove, esiti, link).

      Lab: Classificare bug deterministici, intermittenti e dipendenti da dati e tenere il primo taccuino completo. Output: Mappa dei sintomi più taccuino della sessione.
  3. 02 lettura del segnale

    6 ore / base

    Leggere errori e stack trace

    sintomo Cannot read properties of undefined.

    Usare messaggi, stack trace e codici di stato come indizi ordinati, multilinguaggio, e non come rumore da copiare.

    competenza Trovare punto di rottura, chiamante, dato mancante e primo file realmente responsabile in JavaScript, Python, Java/Kotlin, Swift e su HTTP.

    • console
    • stack trace
    • terminal
    • HTTP status
    • error.cause
    • source map (cenno)
    5 lezioni Programma lezioni
    1. Leggere tipo, messaggio, file, riga e contesto distinguendo Error, TypeError, RangeError, SyntaxError e usando name, message, cause senza fermarsi alla prima parola spaventosa.

      Lab: Annotare dieci errori comuni e tradurli in domande tecniche. Output: Glossario degli errori frequenti.
    2. Seguire la catena delle chiamate distinguendo punto in cui esplode e punto in cui nasce la causa, comprendendo l'ordine LIFO dello stack.

      Lab: Ricostruire la storia di una chiamata attraversando tre funzioni. Output: Mappa dello stack.
    3. Riconoscere lo stesso schema sotto messaggi diversi: NullPointerException (Java/Kotlin), nil (Swift), KeyError e TypeError (Python), Segmentation fault (C/C++), panic (Go, Rust).

      Lab: Confrontare lo stesso bug logico riprodotto in tre linguaggi del corso. Output: Tabella linguaggio/errore/equivalente JS.
    4. Capire perché non tutti gli errori parlano nello stesso modo e alcuni non generano eccezioni; introdurre il concetto di assert.

      Lab: Inserire volutamente tre difetti diversi nello stesso esercizio e riconoscerli. Output: Tabella sintomo/categoria.
    5. Leggere 400, 401, 403, 404, 409, 422, 429, 500, 502, 503, 504 come segnali su input, permessi, conflitti, rate limit, server e gateway; usare curl o httpie oltre al pannello Network.

      Lab: Analizzare richieste fallite dal pannello Network e replicarle da terminale. Output: Checklist per errori API.
  4. 03 strumenti

    7 ore / intermedio

    Osservare il programma

    sintomo Il valore sembra giusto, poi sparisce.

    Scegliere lo strumento giusto per vedere dati, stato, flusso e comunicazioni mentre il codice gira, senza riempire di rumore log e console.

    competenza Usare log strutturati, breakpoint condizionati, logpoint, watch, Network, Storage, DOM inspection ed estensioni di framework senza sommergere il programma di rumore.

    • DevTools
    • console.group
    • console.table
    • console.time
    • console.assert
    • breakpoint condizionati
    • logpoint
    • exception breakpoint
    • Network
    • localStorage
    • sessionStorage
    • IndexedDB
    • Cookies
    • Framework DevTools
    5 lezioni Programma lezioni
    1. Scrivere log che rispondono a una domanda precisa, usare console.group/table/time/assert per dare struttura e rimuoverli o trasformarli dopo la diagnosi.

      Lab: Sostituire log casuali con log a checkpoint e dati strutturati. Output: Traccia di log leggibile.
    2. Fermare il programma nel punto giusto con breakpoint condizionati e logpoint, osservare variabili e impostare exception breakpoint senza modificare il codice.

      Lab: Seguire un flusso di validazione passo per passo con almeno un breakpoint condizionato e un logpoint. Output: Sequenza commentata di osservazioni.
    3. Capire se il difetto vive nel client, nella richiesta, nel server o nei dati ricevuti; usare filtro per tipo, throttling e replay della richiesta.

      Lab: Diagnosticare una lista che resta vuota anche se l'interfaccia sembra corretta. Output: Scheda richiesta/risposta.
    4. Distinguere localStorage, sessionStorage, cookies, IndexedDB e cache del Service Worker; sapere quando il dato persiste e quando no.

      Lab: Debuggare un filtro che salva una preferenza sbagliata nello storage scorretto. Output: Mappa dato sorgente/dato persistito/dato renderizzato.
    5. Confrontare stato applicativo, DOM renderizzato e props/store del framework con estensioni dedicate (React DevTools, Vue DevTools, Svelte Inspector, Redux DevTools).

      Lab: Trovare lo scostamento tra stato dichiarato e DOM osservato in un componente reale. Output: Confronto stato/DOM annotato.
  5. 04 indagine

    8 ore / intermedio

    Isolare la causa

    sintomo Ci sono troppe cose che potrebbero essere rotte.

    Passare da una lista di sospetti a una causa verificata con prove piccole, ordinate e riproducibili.

    competenza Applicare ipotesi falsificabili, esperimenti controllati, rubber duck, ricerca binaria, disattivazione selettiva, delta debugging, feature flag e confronto tra versioni con Git.

    • rubber duck
    • git log
    • git diff
    • git bisect
    • git bisect run
    • feature flags
    • test mirati
    • fixture dati
    5 lezioni Programma lezioni
    1. Impostare prove che confermano o smentiscono una sola spiegazione possibile e usare la tecnica del rubber duck per esplicitare assunzioni nascoste.

      Lab: Scrivere tre ipotesi concorrenti e una prova economica per ciascuna, raccontandole a voce alta a un compagno-duck. Output: Registro ipotesi/prova/esito.
    2. Spegnere parti del sistema con feature flag o commenti chirurgici senza introdurre nuovi bug e senza perdere il sintomo.

      Lab: Isolare un difetto tra rendering, dati e gestione evento usando un flag e tre prove successive. Output: Percorso di riduzione documentato.
    3. Tagliare lo spazio di ricerca con confronti a metà, diff e cronologia Git; usare git bisect interattivo e git bisect run con uno script di verifica.

      Lab: Individuare il commit che introduce una regressione in una repo didattica, prima a mano e poi automatizzato. Output: Commit sospetto motivato e script di bisect.
    4. Capire il principio del delta debugging: ridurre input o codice in modo automatico fino al minimo che fa fallire il programma.

      Lab: Applicare una riduzione semi-automatica a un input di 100 elementi che provoca un bug. Output: Input minimo conservato come fixture.
    5. Riconoscere input incompleti, duplicati, ordinamenti inattesi, valori limite, NaN, null, stringhe vuote, encoding misti; collegare al testing classico (boundary value, equivalence partitioning).

      Lab: Costruire tre fixture che fanno emergere il difetto su confine, dominio e dominio fuori scala. Output: Set di dati di prova classificato.
  6. 05 fix

    8 ore / intermedio

    Correggere senza regressioni

    sintomo Il bug è sparito, ma ora si è rotto altro.

    Applicare fix piccoli, verificabili e documentati, evitando di rompere casi che funzionavano e scegliendo consapevolmente tra fix-forward e rollback.

    competenza Scrivere test di regressione, leggere il diff, scegliere il fix minimo, decidere tra fix-forward e revert, preparare commit e branch chiari.

    • test automatici
    • Playwright o Cypress (cenno)
    • checklist manuale
    • diff
    • git revert
    • git reset
    • branch hotfix
    • Conventional Commits
    5 lezioni Programma lezioni
    1. Separare la correzione necessaria da refactor e pulizie che rischiano di confondere la verifica, anche quando il codice toccato fa prudere le mani.

      Lab: Dividere un diff troppo grande in fix, refactor e modifiche non necessarie. Output: Diff annotato.
    2. Trasformare il bug trovato in una verifica automatica o E2E (Playwright/Cypress, snapshot, asserzioni mirate) che fallisce prima del fix e passa dopo.

      Lab: Scrivere un test o una checklist riproducibile per il caso rotto seguendo la regola test-first-bug-fix. Output: Test o procedura di regressione.
    3. Controllare il caso principale, un caso vicino, un caso limite e un caso che non deve cambiare prima di dichiarare chiuso il bug.

      Lab: Preparare una matrice di verifica prima di marcare il bug come risolto. Output: Checklist post-fix.
    4. Decidere consapevolmente tra correggere in avanti, fare git revert, usare git reset locale o aprire un branch hotfix, valutando rischio e urgenza.

      Lab: Davanti a tre scenari (bug locale, bug merged in main, bug in produzione) scegliere la strategia adeguata e applicarla in una repo didattica. Output: Albero decisionale fix-forward/revert.
    5. Rendere comprensibile nel tempo cosa è stato corretto, perché e come è stato verificato, usando Conventional Commits e la regola 50/72 per oggetto e corpo.

      Lab: Scrivere messaggi di commit e note di chiusura per tre bug diversi. Output: Commit message e nota di release breve.
  7. 06 handoff

    8 ore / intermedio

    Debugging collaborativo

    sintomo Un compagno deve continuare il debug da dove mi sono fermato.

    Gestire bug condivisi: passare contesto, chiedere aiuto, fare triage, revisionare fix e imparare dalla retrospettiva.

    competenza Preparare report, riproduzioni condivise, branch, note di indagine, presentazioni tecniche brevi e classificare ticket per priorità.

    • issue tracker
    • branch
    • pull request
    • gist o stackblitz
    • rubrica di valutazione
    • matrice triage
    5 lezioni Programma lezioni
    1. Formulare una richiesta che include contesto, prove già fatte e punto esatto in cui si è bloccati, prendendo spunto dalla tradizione How To Ask Questions The Smart Way.

      Lab: Riscrivere richieste di aiuto troppo generiche in richieste tecniche utili, condividendo riproduzioni via gist o stackblitz. Output: Messaggio di handoff e link di riproduzione.
    2. Classificare un ticket per impatto, urgenza, proprietario e scadenza così che la coda non diventi caos.

      Lab: Triagare dieci ticket di esempio assegnando severità, priorità e owner. Output: Matrice di triage compilata.
    3. Dividere ruoli tra chi guida, chi osserva, chi prende note e chi verifica, alternandoli con timer.

      Lab: Sessione a coppie con timer, registro ipotesi e cambio ruolo. Output: Registro di sessione.
    4. 04 Review del fix 55 min

      Valutare una correzione guardando diff, test, casi limite, retro-compatibilità, side effect e rischio di regressione, usando una checklist canonica di review.

      Lab: Revisionare due fix: uno minimo ma incompleto, uno largo e rischioso. Output: Commenti di review strutturati.
    5. Convertire un errore risolto in una regola, un test, una checklist o una decisione di progetto, usando il formato blameless postmortem.

      Lab: Scrivere una mini retrospettiva tecnica dopo il fix concentrando l'attenzione su sistemi e processi, non su persone. Output: Scheda lezione appresa.
  8. 07 flussi asincroni

    8 ore / avanzato

    Debugging asincrono e interfacce dinamiche

    sintomo Succede solo dopo alcuni click o quando la rete è lenta.

    Diagnosticare bug che nascono da timing, eventi, stato dell'interfaccia, promise, rendering non lineare, Service Worker e race condition.

    competenza Seguire event loop, microtask, macrotask, callback, promise, listener, stato e render fino al punto in cui il comportamento diverge; usare AbortController per terminare richieste e listener in sicurezza.

    • async stack trace
    • event listener panel
    • network throttling
    • source map
    • framework DevTools
    • AbortController
    • queueMicrotask
    • Service Worker DevTools
    5 lezioni Programma lezioni
    1. Capire perché codice scritto in una sequenza può produrre effetti in un ordine diverso durante l'esecuzione, distinguendo task, microtask (Promise, queueMicrotask) e rendering frame.

      Lab: Ricostruire una timeline di setTimeout, Promise, listener e callback che aggiornano lo stesso valore. Output: Timeline asincrona commentata.
    2. Riconoscere promise non attese, catch mancanti, stati pendenti, unhandled rejection e fallimenti che non arrivano in console.

      Lab: Debuggare un caricamento dati che a volte resta bloccato senza mostrare errore, intercettando unhandled rejection. Output: Mappa promessa/stato/esito.
    3. Riconoscere e prevenire race condition (doppio submit, stale closure, setState dopo unmount) e usare AbortController per cancellare fetch e listener.

      Lab: Correggere un componente che mostra il risultato della richiesta sbagliata quando l'utente digita velocemente. Output: Pattern di cancellazione documentato.
    4. Individuare listener duplicati, eventi non rimossi, propagazione inattesa, stato UI non sincronizzato e bug specifici del framework (stale closure React, reactivity Vue, store leak Svelte).

      Lab: Correggere un pannello che reagisce due volte allo stesso click e conserva uno stato vecchio. Output: Registro evento/stato/render.
    5. Diagnosticare bug provocati da cache di Service Worker o CDN, collegare codice sorgente, bundle e componente renderizzato attraverso le source map.

      Lab: Usare Service Worker DevTools per smascherare una cache che serve un vecchio bundle e ricondurre un errore minificato al sorgente originale. Output: Traccia sorgente/bundle/componente.
  9. 08 confini del sistema

    9 ore / avanzato

    Debugging di dati, backend e integrazioni

    sintomo Il frontend sembra corretto, ma i dati arrivano sbagliati o non arrivano.

    Diagnosticare difetti che attraversano client, API, autenticazione, database, configurazione, timezone, encoding e servizi esterni.

    competenza Verificare contratti, payload, permessi, query, migrazioni, variabili d'ambiente, formati locali e meccanismi di retry senza confondere il confine del problema.

    • API client (Postman, Insomnia, Bruno, httpie, curl)
    • schema dati
    • log server
    • query inspector
    • variabili d'ambiente
    • JWT debugger
    • DLQ (dead letter queue)
    6 lezioni Programma lezioni
    1. Controllare se richiesta, risposta e modello dati concordano su nomi, tipi, valori mancanti, formati e versione dell'API.

      Lab: Trovare perché una card renderizza valori vuoti nonostante la chiamata API risponda con 200. Output: Diff contratto/API/interfaccia.
    2. Distinguere errori di identità, permessi, cookie (SameSite, Secure, HttpOnly), token JWT (firma, scadenza, audience), CORS preflight OPTIONS e scadenza sessione.

      Lab: Analizzare tre richieste respinte con cause diverse ma sintomo simile nell'interfaccia. Output: Tabella causa/segnale/verifica.
    3. Riconoscere bug causati da ordinamenti, join, vincoli mancanti, migrazioni incomplete e record incoerenti.

      Lab: Isolare un errore che compare solo con un sottoinsieme di dati reali anonimizzati. Output: Fixture dati e query verificata.
    4. Riconoscere bug che dipendono da fuso orario, salvataggio in UTC vs locale, encoding misto (UTF-8 vs Latin-1), formattazione numerica e date.

      Lab: Diagnosticare una data che cambia giorno tra produzione e laboratorio e una stringa che mostra caratteri sbagliati nel CSV esportato. Output: Checklist locale/encoding/timezone.
    5. Capire come retry mal progettati creano duplicati, perché serve idempotency-key, quando un messaggio finisce in dead letter queue e come confrontarsi con servizi esterni instabili.

      Lab: Diagnosticare un pagamento duplicato in un sistema di esempio e progettare la chiave di idempotenza corretta. Output: Schema integrazione con strategia di retry.
    6. Trovare differenze tra locale, preview e produzione dovute a env, versioni, cache, build, lock file o servizi collegati.

      Lab: Confrontare due ambienti che eseguono lo stesso commit ma producono esiti diversi. Output: Matrice ambiente/configurazione.
  10. 09 sistemi in esecuzione

    9 ore / avanzato

    Performance, memoria e osservabilità

    sintomo Non esplode nulla, ma l'app diventa lenta, instabile o difficile da spiegare.

    Indagare lentezza, consumo di memoria, regressioni prestazionali e bug che emergono solo durante l'uso reale, distinguendo misura, causa e impatto.

    competenza Usare profili, timeline, heap snapshot, log strutturati JSON, metriche, trace distribuiti, Core Web Vitals e flamegraph per collegare sintomo, causa e impatto sull'utente.

    • Performance panel
    • heap snapshot
    • Lighthouse
    • Core Web Vitals (LCP, INP, CLS, TTFB)
    • User Timing API
    • log strutturati JSON (pino, winston, structlog)
    • metriche e SLO
    • trace OpenTelemetry
    • flamegraph (perf, py-spy, async-profiler)
    5 lezioni Programma lezioni
    1. Misurare prima di ottimizzare, distinguendo CPU, layout, rendering, caricamento asset e tempi di risposta; leggere LCP, INP, CLS e TTFB come segnali utente, usando User Timing API (performance.mark e performance.measure).

      Lab: Analizzare una pagina che sembra lenta, individuare il collo di bottiglia principale e collegarlo alla metrica utente più colpita. Output: Profilo prestazionale annotato con metriche.
    2. Riconoscere crescita anomala della memoria, listener rimasti attivi, timer pendenti, sottoscrizioni store e riferimenti trattenuti che impediscono la garbage collection.

      Lab: Riprodurre un consumo crescente aprendo e chiudendo ripetutamente la stessa vista e confermare la perdita con heap snapshot. Output: Confronto heap prima/dopo.
    3. Profilare un servizio backend (Node, Python, Java) e leggere flamegraph generati con perf, py-spy o async-profiler per individuare hot path.

      Lab: Analizzare un endpoint lento usando un flamegraph fornito e formulare una ipotesi di ottimizzazione verificabile. Output: Hot path annotato con piano di verifica.
    4. Costruire segnali utili in produzione (log JSON con livello e correlation id, metriche RED/USE, trace distribuiti) senza esporre dati sensibili e senza affogare l'indagine nel rumore; introdurre SLI, SLO ed error budget.

      Lab: Seguire una richiesta dall'interfaccia al backend usando correlation id, log strutturati e trace OpenTelemetry, valutando il consumo dell'error budget. Output: Traccia end-to-end con SLO discusso.
    5. Gestire un difetto già rilasciato: contenere l'impatto, aggiornare gli utenti via status page, coordinare la war room, scegliere rollback o fix-forward in coordinamento con il Modulo 5, poi documentare la causa.

      Lab: Simulare una regressione in produzione e ricostruire timeline, decisioni, comunicazioni e verifica finale in un postmortem blameless. Output: Postmortem tecnico breve.
  11. 10 verifica finale

    6 ore / capstone

    Capstone: bug reale end-to-end

    sintomo Devo dimostrare che il metodo funziona quando nessuno mi tiene per mano.

    Risolvere un bug reale, ramificato su client, backend e dati, applicando in sequenza tutti i moduli del corso e producendo un report verificabile.

    competenza Eseguire l'intero ciclo (riproduci → leggi → osserva → isola → correggi → collabora → verifica → racconta) su un caso integrato, gestendo tempo, ipotesi, prove, fix e comunicazione.

    • tutti gli strumenti dei moduli precedenti
    • taccuino di laboratorio
    • repo capstone fornito
    • rubrica di valutazione
    4 lezioni Programma lezioni
    1. Aprire il caso del capstone, leggere la segnalazione iniziale, costruire caso minimo riproducibile e pianificare le sessioni successive.

      Lab: Riprodurre il bug dal repo fornito, scrivere bug report completo, pianificare ipotesi e calendario. Output: Bug report e piano di indagine.
    2. Applicare osservazione, isolamento e delta debugging per arrivare a una causa verificata, mantenendo il taccuino.

      Lab: Eseguire almeno tre cicli ipotesi/prova/esito documentati, fino alla causa radice. Output: Taccuino di indagine con causa radice.
    3. Applicare fix minimo, scrivere test di regressione, eseguire matrice di verifica e preparare commit e branch.

      Lab: Aprire pull request con fix, test, descrizione, screenshot e checklist. Output: Pull request capstone pronta per la review.
    4. Presentare il caso a un compagno o docente in massimo dieci minuti, ricevere review, scrivere retrospettiva blameless e lezioni apprese.

      Lab: Demo del capstone, review incrociata e postmortem condiviso. Output: Presentazione e postmortem definitivi.