Risposta diretta
La skill di Superpowers struttura l'investigazione dei bug difficili attraverso un processo scientifico, formulando ipotesi, testandole e misurandone gli effetti, raffinando la causa fino a raggiungere il fix deterministico. Ciò evita tentativi disordinati e sprecare tempo, consentendo di risolvere bug complessi in tempi più rapidi.
I bug facili si risolvono al primo tentativo, senza pensarci troppo. Sono
il novanta percento dei bug. Il restante dieci percento - quelli che
ti tengono sveglio di notte, quelli che pensavi di aver risolto e
tornano, quelli che sembrano random ma non lo sono - richiedono un
processo. La skill debugging di Superpowers
esiste per dare struttura a quella minoranza che divora ore se affrontata
a istinto.
Disclaimer di indipendenza: non sono affiliato a obra né ad
Anthropic. Tutto quanto segue è esperienza diretta sulla skill
debugging applicata a una sessantina di bug medium-to-hard
sul mio portfolio brownfield in circa un anno.
Perché serve un loop scientifico per i bug difficili
Un bug facile è una catena causale corta: clicca il bottone X, vedi l'errore Y, il fix è in un punto evidente. Un bug difficile ha tre caratteristiche almeno:
- La causa è lontana dal sintomo (errore nel modulo A, ma origine in B).
- La riproducibilità è imperfetta (succede il 30% delle volte, su specifiche condizioni).
- Più ipotesi sono plausibili (almeno tre cause potrebbero spiegare ciò che vedi).
Senza un processo, l'investigazione di un bug difficile diventa una serie di tentativi disordinati: cambi una cosa, ricarichi, vedi se va meglio, cambi un'altra cosa, ti confondi su quale modifica abbia avuto effetto, perdi un'ora e torni al punto di partenza con il sospetto che forse l'errore sia altrove. È il modo più diffuso di sprecare un pomeriggio di lavoro.
Il metodo scientifico applicato al debug è ovvio (formula ipotesi, testa,
misura, raffina), ma sotto pressione viene saltato. La skill
debugging impone il processo anche quando l'istinto
vorrebbe saltare i passaggi.
Cosa fa la skill, ciclo per ciclo
Una sessione di debug con la skill attiva segue una struttura ricorrente, ripetuta finché il bug non è risolto:
- Stato corrente: cosa sappiamo, cosa non sappiamo, cosa abbiamo escluso.
- Ipotesi: una sola, esplicita. "Il bug X dipende da Y." Niente "potrebbe essere A o B o C" - quelli sono ipotesi multiple e vanno testate separatamente.
- Test che la verifica: l'esperimento minimo che permette di confermare o rigettare l'ipotesi. Idealmente un test deterministico che riproduca il bug, ma a volte è un log strategico o una richiesta cURL specifica.
- Misurazione: cosa ti aspetti di vedere se l'ipotesi è corretta, cosa ti aspetti di vedere se è sbagliata. Importante: questa frase va scritta prima di eseguire il test.
- Esecuzione e risultato: esegui, registra cosa hai osservato, confronta con la misurazione attesa.
- Checkpoint: aggiorna stato corrente con quanto hai imparato. Decidi prossima ipotesi.
Il ciclo si chiude quando hai un test che fallisce in modo deterministico sul bug e passa dopo il fix. Quel test diventa la regression test permanente nel CI.
Esempio illustrativo: bug i18n hreflang del portfolio
Riassunto di una sessione debug reale (sintetizzata). Bug osservato: Google Search Console segnala "Alternate page with proper canonical tag" per 999+ URL del sito multilingua. Sintomo concreto: `/sv/blog/...` viene indicizzato sotto canonical `/en/blog/...` invece che mantenere il proprio canonical.
Stato corrente
- 18 lingue config in CLAUDE.md
- 7 lingue compilate AOT, 11 lingue runtime
- Hreflang dichiarato ma GSC rifiuta canonical /sv/
Ciclo 1
Ipotesi: hreflang malformato nel head HTML
Test: curl https://federicocalo.dev/sv/blog/X | grep hreflang
Atteso: 18 entries hreflang con codici corretti
Risultato: 18 entries corrette
Checkpoint: hreflang OK -> bug altrove
Ciclo 2
Ipotesi: content lingua effettiva non corrisponde al locale dichiarato
Test: curl /sv/blog/X | grep "lang=" | head
Atteso: lang="sv"
Risultato: lang="en" (!!)
Checkpoint: confermato content drift. SSR serve bundle EN sotto path /sv/.
Ciclo 3
Ipotesi: SSR route mapping /sv/ -> bundle EN se sv non compilato AOT
Test: ng serve --localize=sv (verifica bundle separato)
Atteso: bundle sv esiste OR fallback documentato
Risultato: sv NON compilato AOT, fallback automatico a EN bundle
Checkpoint: causa confermata. Fix: chrome runtime Transloco per sv +
altre 10 lingue runtime, gia documentato nel piano i18n 35.
Senza la skill avrei probabilmente provato due-tre cose a caso prima di arrivare alla causa. Con la skill, tre cicli strutturati = causa identificata in 20 minuti.
Il checkpoint pattern come memoria operativa
Il checkpoint pattern è la parte della skill che mi ha cambiato di più il modo di debuggare. Funziona così: dopo ogni ciclo, la skill produce un blocco di testo strutturato (lo "stato corrente" del ciclo successivo) che riassume:
- Ipotesi testate e loro esito (confermate / rifiutate / inconcludenti).
- Fatti accertati (cosa è stato osservato come vero).
- Ipotesi escluse (cosa è stato eliminato dal set delle cause possibili).
- Prossima ipotesi da testare.
Il checkpoint è di solito 200-400 parole. Se interrompi la sessione (chiamata urgente, fine giornata, kernel panic), riprendi il giorno dopo leggendo il checkpoint. Niente "come funzionava il debug ieri?". È tutto scritto.
Sul mio portfolio uso checkpoint anche dopo aver risolto il bug: incollato
nel git commit message come "investigation summary", o salvato in
docs/memory/ per bug ricorrenti su componenti che tornano a
darmi problemi. Negli ultimi sei mesi questa pratica mi ha permesso di
risolvere in 5 minuti bug che la prima volta avevo impiegato due ore a
diagnosticare.
Strategie di test efficaci nel ciclo
La parte "test che verifica l'ipotesi" è dove la skill fa la differenza tra debug efficiente e tentativi a caso. Quattro strategie pratiche:
- Test deterministico minimo. Riproduci il bug nel modo più piccolo possibile. Se il bug è in produzione su un endpoint API con dieci parametri, isolalo a uno script che chiama l'endpoint con un payload ridotto. Più piccolo è il test, più stretta l'ipotesi.
- Test binario. Formula il test in modo che il risultato sia binario: l'ipotesi è confermata o rifiutata. Evita test che producono output ambiguo.
- Misurazione pre-esecuzione. Scrivi prima di eseguire cosa ti aspetti di vedere. Senza questa scrittura, post-hoc-rationalize ogni risultato come "potrebbe confermare l'ipotesi". È il modo più diffuso di auto-ingannarsi.
- Test che lascia traccia. Aggiungi log strategici che sopravvivono al test. Se il bug si ripresenta in produzione tra una settimana, il log permette di ripartire da dove avevi lasciato.
Anti-pattern: ipotesi multiple in parallelo
La tentazione naturale è dire: "Forse è A, forse è B, forse è C, proviamo tutti e tre e vediamo cosa cambia." Errore. Se cambi tre cose e il bug scompare, non sai quale delle tre era la causa. Se il bug torna domani, non sai quale fix sia regredito.
La skill debugging impone una ipotesi alla volta.
Cicli più, ma ogni ciclo lascia un fatto accertato. Tre cicli singoli
sono più veloci di un "test multiplo" che richiede poi diecimila ulteriori
cicli per disambiguare.
Integrazione con TDD
La skill debugging è complementare a tdd-guide:
- tdd-guide forza RED-GREEN-REFACTOR su business logic nuova.
- debugging entra in gioco su business logic esistente che fallisce in modo non ovvio.
Pattern integrato:
- Bug osservato in produzione.
- Invoca
debugging, primo ciclo: ipotesi su causa. - Test che riproduce il bug deterministicamente (è il "RED" della parte TDD).
- Ipotesi confermata = causa identificata.
- Scrivi il fix che fa passare il test (è il "GREEN" della parte TDD).
- Refactor se necessario (RED-GREEN-REFACTOR completo).
- Commit + push, regression test resta nel CI.
Il test scritto durante l'investigazione (passo 3) non va buttato dopo il fix: diventa la regression test che ti protegge se qualcuno reintroduce il bug.
Quando la skill non basta: bug di sistema
Ci sono bug che la skill da sola non risolve. Casi tipici:
- Bug che vivono fuori dal codice: configurazione di infrastruttura, version drift su dipendenze, problemi di rete. L'ipotesi deve uscire dal repository e indagare l'ambiente. La skill guida il processo, ma il test richiede strumenti esterni (ssh + log inspection, monitoring dashboards, ecc.).
- Bug intermittente che non si riproduce in locale. L'ipotesi tipica è "race condition" o "timing dependent". La skill spinge verso strumenti di stress test (concurrent requests, fault injection) che richiedono setup non banale.
- Bug di percezione: l'utente segnala un comportamento che, investigato, è un fraintendimento del comportamento corretto. Qui il "fix" è documentazione o UX, non codice. La skill, applicata rigidamente, non lo coglie e ti fa cercare cause inesistenti.
In tutti e tre i casi la skill resta utile per strutturare l'investigazione, anche se la soluzione esce dal codice.
Sessione tipica: tempi e costi
Sul mio portfolio, una sessione debug tipica (bug medium-complexity) ha questi parametri:
- Cicli: 3-7 per bug medium, 8-12 per bug hard.
- Durata: 15-40 minuti per medium, 60-120 minuti per hard.
- Token consumati: 15-40k in/out per medium.
- Output finale: bug risolto + test regression + checkpoint summary committato.
Confronto: prima dell'adozione della skill, debug a istinto medio era 45-90 minuti per bug medium. Riduzione del 50-60% del tempo, con un bonus: il test regression resta nel CI come protezione futura.
Checklist invocazione skill debugging
- Il fix banale ha già fallito? Se no, prima prova quello (più veloce).
- Hai un sintomo osservabile (errore in log, test che fallisce, comportamento UI sbagliato)? Se no, la skill non ha materiale.
- Il bug è riproducibile (anche imperfetto)? Se totalmente non riproducibile, prima fase ipotesi è "come renderlo riproducibile".
- Hai 15+ minuti per la sessione? La skill ha overhead di setup; per debug rapidi (<5min) è overkill.
Variante custom: debugging con focus performance
Sul portfolio ho una variante custom della skill, specializzata su bug performance (LCP regressioni, INP issues, slow SSR endpoints). Frontmatter illustrativo:
---
name: debugging-performance
description: Use when investigating a performance regression (LCP > target,
INP > 200ms, SSR endpoint slow). Drives a scientific loop focused on
measurement first (real metrics from Lighthouse / CrUX), then hypothesis
on cause, then test. Stops when measured metric returns under target.
metadata:
type: rigid
---
La variante aggiunge al body principale due steps:
- "Measure first" - primo ciclo è sempre misurazione di baseline (no ipotesi).
- "Compare with target" - ogni ciclo successivo confronta misurazione attuale con target SLO esplicito.
Senza queste due aggiunte, la skill base tendeva a saltare alla "ipotesi su causa" senza prima misurare bene. La variante fissa il problema.
Cosa ho imparato scrivendo questo articolo
La cosa più sorprendente è quanto fosse "ovvio" il metodo scientifico letto e quanto fosse difficile applicarlo sotto pressione. Avevo letto libri sul debugging strutturato anni prima (Andy Hunt + Dave Thomas, il vecchio "Pragmatic Programmer"), ma in pratica continuavo a saltare i passaggi quando il bug era urgente.
La skill ha fatto la differenza non per il contenuto (che già sapevo) ma per la forma: avere una procedura esplicita scritta da qualcun altro a cui dover rispondere ("hai formulato l'ipotesi singola? hai scritto cosa ti aspetti di vedere?") attiva la disciplina meglio del buon proposito personale. È strano da ammettere ma è così.
Anti-pattern evitati
- Skip checkpoint per fretta. La tentazione, dopo aver risolto il bug, è di non scrivere il checkpoint finale ("ho capito, andiamo avanti"). Errore: tre mesi dopo lo stesso bug si ripresenta in forma leggermente diversa e non ricordi più i fatti accertati. Cinque minuti di checkpoint ti salvano due ore di re-debug.
- Ipotesi non falsificabile. "Forse il problema è nel framework" non è un'ipotesi testabile. La skill insegna a riformulare: "Se il problema è nel framework, il bug deve scomparire downgradando alla versione precedente. Test: downgrade alla 3.4.10 e verifica." Ora è testabile.
Una storia ricevuta che vale la pena condividere
Sezione segnaposto. Se hai un bug che hai risolto con metodo
scientifico (o uno che ti tormenta ancora), scrivimi a
federico@federicocalo.dev. La storia (pseudonimizzata, con
consenso) entra nel cluster successivo.
← Cluster precedente: Brainstorming skill Prossimo cluster: TDD enforcement skill →
Domande frequenti
Qual è la differenza tra un bug facile e uno difficile?
Un bug facile è una catena causale corta, mentre un bug difficile ha almeno tre caratteristiche: non è immediatamente evidente, richiede un processo strutturato per essere risolto e può sembrare casuale.
Perché la skill di Superpowers è necessaria per i bug difficili?
La skill di Superpowers è necessaria perché fornisce una struttura al processo di debug, aiutando a evitare tentativi disordinati e a concentrarsi su ipotesi specifiche.
Cosa fa la skill durante un ciclo di debug?
La skill produce un checkpoint dopo ogni ciclo, che è un blocco di testo strutturato che riassume lo stato corrente del ciclo successivo. Ciò aiuta a mantenere traccia dei progressi fatti e a riprendere facilmente la sessione di debug.
Quali sono le strategie di test efficaci utilizzate dalla skill?
La skill utilizza quattro strategie di test efficaci: formulare ipotesi singole, testare l'ipotesi, misurare e raffinare. Inoltre, la skill evita l'anti-pattern di formulare ipotesi multiple in parallelo.
Commenti
Caricamento commenti...
Accedi per commentare