diffox
Blog

Cos’è il blast radius: cosa tocca una pull request fuori dal diff

Il blast radius è il codice che una modifica raggiunge fuori dal diff. Su una pull request reale ti mostriamo come trovarlo nel codice, senza frecce sbagliate.

CondividiXLinkedIn

In sintesi. Il blast radius (raggio d’impatto) è il codice che una modifica raggiunge al di fuori di sé: i file che chiamano o importano il codice modificato. Questo articolo spiega come trovare il blast radius di una pull request partendo solo dal codice, senza un modello. Spiega anche perché la ricerca per nome disegna frecce sbagliate e come trasformare il risultato in un diagramma su GitHub. Abbiamo verificato il comportamento degli strumenti nella loro documentazione il 14 ottobre 2026. L’esempio è una pull request già unita della libreria requests.

  • Il diff non mostra chi chiama il codice. Mostra le righe modificate, non i file che le usano. Nel nostro esempio cambiano due file, e altri 9 file dipendono da loro.
  • La ricerca per nome disegna frecce sbagliate. Ne abbiamo trovati quattro tipi in un output reale: un’altra definizione con lo stesso nome, un commento che si limita a citare il nome, una seconda copia dell’albero e un import collegato al file sbagliato.
  • Una freccia si disegna solo se l’import punta al file modificato. Poche frecce ma esatte valgono più di molte frecce che il lettore deve verificare una per una.
  • Se non si legge tutto, il diagramma non si disegna. Un diagramma a metà fa pensare che «nessuno chiama questo codice».

Che cos’è il blast radius?

4tipi di freccia sbagliata, trovati in un output reale
9file che nell’esempio arrivano dall’esterno
8riquadri al massimo in un diagramma

Il termine viene dall’ingegneria delle infrastrutture e descrive fin dove si propaga un guasto. Secondo la guida di AWS sull’architettura basata su celle, dividere il sistema in celle isolate tra loro riduce il blast radius. E questo aiuta non solo con il traffico, ma anche quando si rilascia una nuova funzionalità o una correzione di bug (fonte).

Nella code review la domanda è più circoscritta: fuori da questa pull request, chi chiama o importa il codice che modifica? Se cambia il tipo di ritorno di una funzione, ogni punto che la usa ne risente, quindi chi fa la review deve tenere conto anche di quei file. L’argomento si cerca anche come «change impact analysis» (analisi d’impatto delle modifiche).

In questo articolo limitiamo il blast radius al suo anello più vicino: i file che chiamano o importano direttamente il file modificato. Per disegnare questo diagramma solo con frecce reali servono quattro regole.

4 regole per disegnare solo frecce reali. Il diagramma del blast radius, dal codice e senza modello. 1. Segui l’import fino al file. Decide la riga di import, non il nome. 2. Leggi solo il codice. Un nome nei commenti non è una freccia. 3. Solo nomi definiti una volta. Con due definizioni non si sa di chi è. 4. Non disegnare a metà. Un diagramma a metà dice «nessuno chiama».
Le quattro regole per disegnare il blast radius di una pull request senza modello, solo dal codice.

Cosa non mostra il diff

Quando apri una pull request, GitHub ti mostra i file e le righe modificati. I file che non cambiano ma usano il codice modificato su quella schermata non ci sono; deve pensarci chi fa la review.

Un esempio reale: la pull request 7441 della libreria requests modifica due file, _types.py e models.py, e nel diff ci sono solo questi due. Scansionando l’albero all’ultimo commit della pull request abbiamo trovato altri 9 file che li usano. Per esempio sessions.py e adapters.py usano direttamente la classe PreparedRequest di models.py; una modifica a quella classe può cambiare anche il comportamento di questi due file.

Nel resto dell’articolo spieghiamo come siamo arrivati a questo numero e perché alcune frecce non le disegniamo di proposito.

Tre modi comuni per trovare chi chiama

  • Ricerca testuale. git grep -w nome trova ogni riga in cui il nome compare come parola intera (documentazione). È veloce e non richiede configurazione. Però trova il nome anche nei commenti, nelle stringhe e in altre funzioni con lo stesso nome; sta a te capire quali sono le chiamate vere.
  • Language server. «Find All References» nell’editor invia la richiesta textDocument/references del Language Server Protocol, e il language server restituisce tutti i riferimenti al simbolo sotto il cursore nell’intero progetto (specifica). Il risultato è esatto, ma vale per un simbolo alla volta e richiede che il progetto sia configurato nell’editor. La navigazione del codice di GitHub nel browser, invece, usa tree-sitter e, secondo la sua documentazione, scorre tutte le definizioni e i riferimenti di un repository per trovare le entità con un dato nome (documentazione). In pratica, cerca per nome.
  • Strumenti per il grafo delle chiamate. Strumenti come pyan per Python e madge per JavaScript estraggono il grafo dell’intero repository. pyan definisce la propria analisi «piuttosto superficiale» (fonte); madge invece disegna le dipendenze tra moduli, non le chiamate di funzione (fonte). Entrambi guardano l’intero repository e non una singola pull request, e il loro risultato non sta in un commento di review.
Tre modi, tre punti deboli. Ricerca testuale: git grep -w. Dove sbaglia: Stesso nome. Anche commenti e altre definizioni. Language server: Find All References. Dove sbaglia: Un simbolo. Esatto, ma un nome alla volta. Grafo delle chiamate: pyan, madge. Dove sbaglia: Intero repo. Guarda il repo, non la pull request. Seguire l’import: file modificati. Cosa disegna: Frecce reali. Poche frecce, niente da verificare. La quarta scheda è la via che propone questo articolo.
Tre modi comuni per trovare chi chiama, e il quarto proposto da questo articolo. Fonte: la documentazione degli strumenti, 14 ottobre 2026.

Per una pull request serve una via di mezzo: un diagramma esatto come il language server, veloce come la ricerca testuale e limitato ai dintorni dei file modificati. Per ottenerlo bisogna seguire la riga di import, non il nome.

Quattro frecce sbagliate trovate in un output reale

Quando abbiamo scritto il passaggio di diffox che disegna il blast radius di una pull request, abbiamo letto uno per uno gli output delle prime versioni e trovato quattro tipi di frecce sbagliate. Ognuno ha la sua regola:

  1. Un nome definito in più punti. Una funzione di supporto con lo stesso nome era definita in tre strumenti diversi, e chi chiamava l’una veniva disegnato come chiamante dell’altra. Regola: per un nome che non è definito esattamente una volta in tutto l’albero non si disegna nessuna freccia.
  2. La seconda copia dell’albero. Un git worktree dentro il repository era una copia dell’intero albero; da lì venivano due terzi di ciò che la prima esecuzione aveva trovato. Regola: non si entra nelle cartelle il cui nome inizia con un punto.
  3. Una riga che cita solo il nome. Una riga di commento citava il nome della funzione come esempio. Regola: si legge solo il codice vero e proprio; tolti commenti e stringhe, deve restare una chiamata o un import.
  4. Un import collegato al file sbagliato. La riga from werkzeug.exceptions import NotFound è stata disegnata come chiamante del file exceptions.py del repository stesso, solo perché i due file avevano lo stesso nome. Regola: la freccia si disegna solo se la riga di import del chiamante punta proprio al file modificato. Un import relativo si risolve calcolando il percorso; gli altri si collegano a un solo file guardando i file presenti nell’albero.

La quarta regola ha un prezzo: un chiamante il cui import non si può seguire non entra nel diagramma. In Go e in Ruby l’import non lega un nome, quindi i file in questi linguaggi restano senza frecce; anche un metodo chiamato tramite un oggetto (obj.x()) non si collega a un file. Una freccia mancante non costa nulla al lettore. Una freccia sbagliata, invece, si porta via anche la fiducia nel resto del diagramma.

Come mantenere leggibile il diagramma

In un repository reale il numero di chiamanti cresce in fretta. Due cose aiutano.

  • Lascia fuori i test. Nel nostro repository, 16 delle 19 frecce disegnate dalla prima versione venivano da file di test. «I tuoi test chiamano questa funzione» non è un’informazione che serve a chi apre la pull request. Riconosci un test dal percorso, non dal contenuto: la cartella tests/, test_*.py, *.test.ts e simili. Quanto pesa dipende dal repository: nell’esempio di requests, contare i test avrebbe aggiunto un solo file.
  • Limita il numero di riquadri e di’ quanti ne restano fuori. Un diagramma con quaranta riquadri non si legge, e uno che non dice di essere stato limitato sembra completo. Noi disegniamo al massimo 8 riquadri e 6 chiamanti per file modificato, e contiamo il resto. Nell’esempio di requests, dei 9 file ne sono stati disegnati 6, e una sola frase sotto il diagramma indica i 3 rimanenti.

Come velocizzare la ricerca nelle modifiche grandi

Il modo più diretto per trovare chi chiama è cercare \bNOME\b in ogni riga dell’albero, per ogni nome definito dai file modificati. Una modifica grande definisce centinaia di nomi; in un albero di centinaia di file questo significa milioni di ricerche regex. In una grande pull request del nostro repository questo passaggio ha eseguito 19,1 milioni di ricerche, e sul server il diagramma ha sforato il suo budget di 20 secondi. Due interventi riducono il tempo:

  1. Filtra prima i candidati. Se un file non contiene mai il nome del file modificato come parola, non può importarlo: ogni riga di import, come from service.app import x o require("./app"), contiene l’ultima parte del percorso come parola a sé. Nel nostro vecchio strumento indicizzare l’intero albero richiedeva 51 secondi su 299 file; questo filtro l’ha portato a 38 file e 3,2 secondi, senza perdere nessuna freccia.
  2. Cerca per riga, non per nome. Secondo la documentazione di Python, \b è il confine tra un carattere di parola e un carattere che non lo è (documentazione). Per questo, per un nome fatto solo di caratteri di parola, \bNOME\b corrisponde solo se una delle parole della riga è esattamente quel nome. Un solo findall per riga dà la risposta per tutti i nomi insieme; resta solo un’intersezione di insiemi. I nomi che contengono altri caratteri, come $foo o valid?, continuano a essere cercati con il proprio pattern.
import re

WORD = re.compile(r"\w+")

def hits(lines, names):
    """I nomi presenti in ogni riga: un solo findall per riga invece di una regex per nome."""
    wanted = set(names)
    for number, line in enumerate(lines, 1):
        found = wanted.intersection(WORD.findall(line))
        if found:
            yield number, found

Quanto si guadagna dipende da quanti nomi si cercano. Abbiamo misurato i due modi sugli stessi alberi e sulla stessa macchina, e i due hanno trovato ogni volta esattamente gli stessi risultati:

tempo totale di scansione e indicizzazione · mediana di tre esecuzioni · portatile Apple M4 Django, 1 file (127 nomi · per nome): 0,94 s; Django, 1 file (per riga): 0,79 s; Django, 5 file (577 nomi · per nome): 5,30 s; Django, 5 file (per riga): 1,37 s; La nostra pull request (570 nomi · per nome): 12,70 s; La nostra pull request (per riga): 1,54 s.
Tre modifiche, ognuna con i due modi di ricerca: tempo totale di scansione e indicizzazione, mediana di tre esecuzioni. Su un portatile, il 14 ottobre 2026; il server è più lento.

In Django, quando cambia un solo file grande (127 nomi), la differenza tra i due modi è piccola. Quando la modifica si estende ai cinque file più grandi (577 nomi), la ricerca per riga è 3,9 volte più veloce; nella nostra pull request (570 nomi), 8,2 volte. Quindi questo intervento non rende più veloce ogni review; quando i nomi diventano tanti, riporta il diagramma dentro il budget. Il collo di bottiglia l’abbiamo trovato con il profiler, non a intuito: la maggior parte del tempo se ne andava in un solo ciclo.

Quando non disegnare il diagramma

Se una scansione si ferma a metà albero per un limite di tempo o di dimensione, ciò che ne esce non è un campione dei chiamanti. Un file che non è stato letto non ha chiamanti nel diagramma, e questo sembra «nessuno lo chiama». Per questo, nei casi seguenti il diagramma non si disegna affatto:

  • Il tempo è finito. Scansione e indicizzazione devono finire entro un budget; da noi 20 secondi.
  • Il file modificato non si è potuto leggere. È troppo grande, è un link simbolico o non è un file regolare.
  • Un limite è stato superato. Il numero di file letti, la dimensione totale o il numero di nomi cercati ha superato la soglia.
  • Non c’è nessun chiamante. Un riquadro senza frecce suggerisce un isolamento che i dati non confermano.

Non mostrare nulla al lettore è meglio che mostrargli qualcosa di sbagliato. Il motivo per cui il diagramma non è stato disegnato deve però finire nei log: solo lì si vede se è stato un errore o un’interruzione prevista.

Mostrare il diagramma su GitHub con Mermaid

Il modo più semplice per mostrare il diagramma al lettore è Mermaid. Secondo la documentazione di GitHub, i diagrammi vengono visualizzati nelle issue, nelle discussioni, nelle pull request, nei wiki e nei file Markdown; basta scrivere la sintassi Mermaid in un blocco di codice con l’etichetta di linguaggio mermaid (documentazione).

Il diagramma dell’esempio di requests, così come viene scritto in un commento di pull request:

```mermaid
flowchart LR
  n0["_types.py"]:::changed
  n1("utils.py")
  n2("adapters.py")
  n3("cookies.py")
  n4("sessions.py")
  n5["models.py"]:::changed
  n6("__init__.py")
  n7("exceptions.py")
  n1 -.->|"SupportsItems"| n0
  n2 -.->|"is_prepared"| n0
  n3 -.->|"is_prepared"| n0
  n4 -.->|"is_prepared"| n0
  n6 -.->|"Request, PreparedRequest +1"| n5
  n7 -.->|"Request, PreparedRequest +1"| n5
  n4 -->|"Request, PreparedRequest +1"| n5
  n1 -.->|"Request, PreparedRequest +1"| n5
  n2 -->|"PreparedRequest, Response"| n5
  classDef changed stroke:#3a6b8b,stroke-width:2px
```
ESEMPIO. Quattro parti, un diagramma. commento di pull request: flowchart LR /   n0["_types.py"]:::changed /   n5["models.py"]:::changed /   n4("sessions.py") /   n4 -->|"PreparedRequest"| n5 /   n4 -.->|"is_prepared"| n0 /   classDef changed stroke-width:2px. :::changed: Cornice: il file modificato. -->: Continua: almeno una chiamata. -.->: Tratteggiata: solo import. |"nome"|: Sopra la freccia, i nomi usati.
Le quattro parti dello stesso diagramma: la cornice del file modificato, la freccia continua, la freccia tratteggiata e i nomi sopra la freccia. Esempio: requests 7441.

Tre piccole scelte rendono il diagramma leggibile. I file modificati hanno una cornice a parte. Sopra la freccia si scrivono i nomi usati; oltre il secondo, quelli in più diventano un numero come «+1». Se un file importa soltanto il file modificato e non è stata trovata una chiamata diretta, la sua freccia è tratteggiata. E una sola frase sotto il diagramma dice che cosa non è stato disegnato.

Il blast radius in diffox

Ogni volta che diffox esamina una pull request, ripete questo passaggio sull’ultimo commit. Se trova chiamanti fuori dal diff, aggiunge al commento di riepilogo un diagramma Mermaid con il titolo «Cosa tocca questa modifica». Le regole sono quelle di questo articolo: nessun modello, solo frecce il cui import punta al file modificato, niente test, al massimo 8 riquadri, un budget di 20 secondi e nessun diagramma se la lettura non è completa. I linguaggi supportati sono Python, JavaScript/TypeScript e Java. Se non vuoi il diagramma, disattiva «Riepilogo della modifica» nella scheda Impostazioni della console.

Il diagramma mostra il blast radius; se qualcosa si rompe, sono i rilievi a dirlo. L’agente Blast Radius, uno dei 17 agenti specializzati, cerca chiamanti rotti, superfici API cambiate e modifiche di firma o di tipo di ritorno che rompono altri file (come funziona è spiegato in un articolo a parte).

Domande frequenti

Che cos’è il blast radius nel software?

È quanto si propaga l’effetto di un guasto o di una modifica. Nelle infrastrutture indica a quanti utenti arriva un guasto; nella code review, quali file fuori dalla pull request chiamano o importano il codice modificato.

Blast radius e change impact analysis sono la stessa cosa?

Sono concetti molto vicini. Change impact analysis (analisi d’impatto delle modifiche) è il nome generale dell’attività che cerca di capire in anticipo che cos’altro toccherà una modifica. Il blast radius di una pull request è l’anello più vicino di questa analisi: i file che usano direttamente il file modificato.

Come trovo chi chiama una funzione?

Nell’editor usa «Find All References»: il language server risolve tutti i riferimenti al simbolo. Per uno sguardo veloce basta git grep -w nome_funzione, ma le corrispondenze nei commenti e in altre definizioni con lo stesso nome le devi scartare a mano. Per tutti i file modificati di una pull request serve invece una scansione che risolva gli import nel file modificato.

I diagrammi Mermaid funzionano nei commenti delle pull request di GitHub?

Sì. GitHub disegna i diagrammi Mermaid nelle issue, nelle discussioni, nelle pull request, nei wiki e nei file Markdown. Basta scrivere la sintassi in un blocco di codice con l’etichetta di linguaggio mermaid.

Perché nel diagramma del blast radius non ci sono i test?

I test sono tra i file che chiamano più spesso il codice modificato e affollano il diagramma; nel nostro repository la maggior parte delle frecce della prima versione veniva dai test. Per chi apre la pull request la vera domanda è che cosa viene toccato nel codice di produzione.

Che cosa significano le frecce tratteggiate nel diagramma?

Una freccia tratteggiata indica che il file chiamante importa qualcosa dal file modificato, ma non è stata trovata una chiamata diretta. Una freccia continua significa che è stata trovata almeno una chiamata.

In quali linguaggi diffox disegna il blast radius?

Python, JavaScript/TypeScript e Java. In questi linguaggi l’import lega un nome e si può scoprire a quale file porta. In Go e Ruby l’import non lega un nome, quindi in questi linguaggi diffox non disegna frecce: invece di tirare a indovinare, lascia fuori la freccia.