Refactor Safely
Refactoring shared code without knowing who calls it is how you break production. Before touching anything, trace every downstream caller, every affected endpoint, and every module boundary the change crosses.
The workflow
1. Check the blast radius
Ask your AI tool:
What breaks if I change the formatMessage function?This triggers get_blast_radius. You get back:
Risk level - LOW, MEDIUM, or HIGH based on how many modules are affected
Every downstream caller grouped by module
Affected HTTP endpoints - the user-facing surfaces that depend on this function
Affected cron jobs - background processes that call it
Affected DB operations - database writes that flow through it
A function with 14 callers across 4 modules is a different refactoring task than one with 2 callers in the same file.
2. Trace module connections
Ask your AI tool:
How are the auth and db modules connected?This triggers query_dependencies. You get back:
Forward dependency paths (auth imports from db)
Reverse dependency paths (db imports from auth)
Circular dependency warnings
Shared dependencies (modules they both import)
If two modules depend on each other, refactoring one means understanding both.
3. Check if the old code is still live
Ask your AI tool:
This triggers check_reachability (Pro). It traces from production entry points - HTTP handlers, cron jobs, CLI commands - to determine whether a function is:
Entry point - it is a production entry point
Reachable - connected to at least one entry point through the call graph
Unreachable - no path from any entry point reaches it
What to look for
HIGH risk means callers span 3+ modules. A rename or signature change ripples across the codebase. Plan a phased migration instead of a single commit.
Affected endpoints are user-facing. Breaking them means downtime or degraded behavior that users notice immediately.
Affected cron jobs fail silently. A broken background job won't trigger a 500 error - it just stops running. These are harder to catch in testing.
Circular dependencies mean you can't refactor module A without understanding module B, and vice versa. If
query_dependenciesflags a cycle, resolve it before making structural changes.
Tips
Run blast radius before writing any refactoring code, not after. Knowing the impact upfront changes the approach - sometimes a wrapper function is safer than a rename.
If blast radius returns HIGH, consider a migration strategy: add the new version, migrate callers one module at a time, then remove the old version. Big-bang renames across many modules are where regressions hide.
Combine blast radius with reachability to find orphaned chains - functions that are technically called by other functions, but the entire chain is disconnected from any entry point. These are safe to remove together.
Last updated