The classic refactor failure: you rename a shared utility, update all its direct callers, run the tests, green, merge, and then watch three services in production throw errors you didn’t expect. The callers you missed were in a different package. The tests didn’t cover them. The static analysis didn’t catch them.
This is not a discipline problem. It is a visibility problem. The refactor was planned from a file-centric view of the codebase, not a graph-centric one.
The refactor planning error
When engineers plan refactors, they typically think in terms of files they know about. They search for usages of the thing they’re changing. They find the obvious ones. They miss the indirect ones, the callers of callers, the modules that duck-type the interface, the factories that construct it.
A graph traversal finds all of them. Transitive reachability from the node you’re changing is the correct scope for a refactor plan, not "files I’m aware of."
The four-phase graph-first refactor
Phase 1, map the blast radius: before touching a single line, compute the blast radius of every node you plan to change. Sort descending. The highest-blast-radius nodes are your last step, not your first.
Phase 2, identify the leaf nodes: start with changes that have no downstream dependents. Pure leaf-node changes are safe to make in isolation. Ship them first, separately, with their own review and rollout.
Phase 3, work inward: as leaf nodes are stabilised, the blast radius of their callers decreases. Each layer you complete reduces risk for the next layer.
Phase 4, tackle the load-bearing nodes last: the high-BR nodes at the core of the graph are your last change. By this point, their callers have been updated in prior phases, and you know exactly what you’re modifying.
What "sequenced by blast radius" looks like
Example: you’re renaming a shared formatDate utility used across 30 files.
Old approach: rename it everywhere in one PR, update callers, cross fingers.
Graph-first approach:
- Identify all 30 callers by blast radius of
formatDate(1 query) - Add an alias, both names work; no callers break (deploy, ship, done)
- Update callers in batches, highest-BR last
- Remove the old name once every caller is updated (blast radius now 0)
The total change is the same. The risk profile is completely different.
Detecting refactor candidates automatically
A code graph also surfaces refactor candidates you weren’t looking for:
- High-betweenness nodes: files that bridge communities are tangled. Splitting them reduces coordination cost.
- God objects: nodes with very high in-degree and very broad community membership are god objects. They resist refactoring because everything depends on them, which is exactly why they should be refactored.
- Near-duplicate communities: two tightly-coupled communities that share a high-centrality bridge node are usually a sign that an abstraction is missing.
The test coverage overlay
Blast radius is most useful when combined with test coverage. The dangerous surface for any refactor is: high blast radius AND low test coverage on the callers.
Spiderbrain surfaces this intersection explicitly: "these 8 callers of your changed node have no test coverage." Those 8 files are where manual review effort should concentrate, not distributed equally across 30 callers.



