Safe Refactoring Skill
Safety-first refactoring protocol. Capture behavior, plan changes, verify continuously.
Usage
/refactor <description>
Philosophy
SAFETY OVER SPEED
Every refactoring step must:
- Have test coverage before changes
- Be small and atomic
- Pass all tests after
- Be reversible (git checkpoint)
Workflow
┌─────────────────────────────────────┐
│ Step 1: Snapshot Tests │
│ (Capture current behavior) │
└─────────────────┬───────────────────┘
↓
┌─────────────────────────────────────┐
│ Step 2: Identify Scope │
│ (Map all affected files/functions) │
└─────────────────┬───────────────────┘
↓
┌─────────────────────────────────────┐
│ Step 3: Plan Changes │
│ (Document in DECISIONS.md) │
└─────────────────┬───────────────────┘
↓
┌─────────────────────────────────────┐
│ Step 4: Incremental Apply │
│ (One logical change at a time) │
└─────────────────┬───────────────────┘
↓
┌─────────────────────────────────────┐
│ Step 5: Verify After Each │
│ (Tests pass after every change) │
└─────────────────┬───────────────────┘
↓
┌─────────────────────────────────────┐
│ Step 6: Rollback Ready │
│ (Git checkpoint before each step) │
└─────────────────────────────────────┘
Step 1: Snapshot Tests
Before ANY code changes, ensure test coverage:
Check Existing Coverage
# Run tests to see current state
pytest -v
# Check coverage for affected files
pytest --cov=src/module --cov-report=term-missing
Add Missing Tests
If coverage is insufficient:
class TestExistingBehavior:
"""Snapshot tests - captures current behavior before refactoring."""
def test_function_returns_expected_output(self):
# Document current behavior
result = function_to_refactor(input_data)
assert result == expected_output
def test_edge_case_handling(self):
# Capture edge case behavior
result = function_to_refactor(edge_case_input)
assert result == edge_case_output
Verify All Tests Pass
pytest -v
# All tests MUST pass before proceeding
Step 2: Identify Scope
Map everything that will be affected:
Use Planner Agent
Task(
subagent_type="planner",
prompt="""
Analyze scope for refactoring: [description]
Identify:
- All files that will change
- All functions/classes affected
- All call sites
- All imports that will change
- Test files that need updates
"""
)
Scope Document
## Refactoring Scope
### Target
[What we're refactoring]
### Affected Files
| File | Changes | Risk |
|------|---------|------|
| src/module/file1.py | Rename function | Low |
| src/module/file2.py | Update imports | Low |
| src/other/caller.py | Update call sites | Medium |
### Call Graph
function_a() └── function_b() [REFACTORING THIS] ├── called_by: module1.handler() ├── called_by: module2.process() └── calls: helper_func()
### Dependencies
- Internal: [list]
- External: [list]
Step 3: Plan Changes
Document the plan before execution:
Refactoring Steps
## Refactoring Plan
### Step 1: [Name]
**Files:** [list]
**Change:** [description]
**Risk:** Low/Medium/High
**Rollback:** git checkout [commit]
### Step 2: [Name]
...
### Order Rationale
[Why this order minimizes risk]
Record in DECISIONS.md
### Refactor: [Name]
**Date:** YYYY-MM | **Status:** Active
**Context:** Why we're refactoring
**Approach:** How we're doing it
**Trade-offs:**
- (+) Improved [maintainability/performance/etc]
- (-) Temporary code churn
Step 4: Incremental Apply
One logical change at a time:
Before Each Change
# Create checkpoint
git add -A
git commit -m "Checkpoint before step N"
Types of Atomic Changes
Rename:
# One function/class/variable at a time
old_name → new_name
# Update ALL references in same commit
Extract:
# Extract logic into separate function
# Original still calls new function
# Behavior unchanged
Inline:
# Replace function call with its body
# One call site at a time
Move:
# Move function/class to new file
# Update all imports
# Leave re-export in old location (optional)
Apply Change
# Make the single change
# Run tests immediately
pytest -v
# If tests pass, checkpoint
git add -A
git commit -m "Step N: [description]"
Step 5: Verify After Each
Tests must pass after every single change:
# After each step
pytest -v
# If tests fail
git checkout HEAD~1 # Rollback
# Analyze what went wrong
# Fix approach and retry
Use TDD Agent
Task(
subagent_type="tdd-guide",
prompt="""
Verify refactoring step maintained behavior:
- Run all existing tests
- Add any new tests needed
- Confirm no regressions
"""
)
Step 6: Rollback Ready
Always able to revert:
Git Checkpoints
# Before refactoring starts
git checkout -b refactor/[name]
# Before each step
git commit -m "Checkpoint: before [step]"
# After each step
git commit -m "Refactor: [step description]"
If Something Goes Wrong
# Rollback one step
git revert HEAD
# Rollback to start
git checkout main
git branch -D refactor/[name]
Agent Chain
For complex refactoring, use agent chain:
1. planner → Design refactoring approach
2. tdd-guide → Ensure test coverage
3. [apply changes incrementally]
4. code-reviewer → Review final result
Refactoring Patterns
Extract Method
1. Identify code to extract
2. Write test for extracted function
3. Create new function with extracted code
4. Replace original code with function call
5. Verify tests pass
Rename
1. Find all usages (grep, IDE)
2. Update definition
3. Update all call sites
4. Update all imports
5. Verify tests pass
Move to New File
1. Create new file
2. Copy code to new file
3. Add re-export from old file
4. Update tests to use new import
5. Remove re-export from old file
6. Update remaining imports
7. Delete old code
Replace Inheritance with Composition
1. Identify methods used from parent
2. Create component with those methods
3. Add component as instance variable
4. Delegate to component
5. Remove inheritance
6. Verify tests pass
Example
/refactor "Split UserService into UserAuthService and UserProfileService"
Step 1 - Snapshot Tests:
→ pytest --cov=src/services/user
→ Coverage: 85%
→ Add tests for uncovered paths
Step 2 - Scope:
→ src/services/user.py (split)
→ src/routes/auth.py (update imports)
→ src/routes/profile.py (update imports)
→ tests/services/test_user.py (split)
Step 3 - Plan:
1. Create UserAuthService with auth methods
2. Create UserProfileService with profile methods
3. Update auth routes
4. Update profile routes
5. Delete old UserService
6. Update tests
Step 4-5 - Apply:
→ git commit "Checkpoint before refactor"
→ Create UserAuthService, run tests ✓
→ git commit "Extract UserAuthService"
→ Create UserProfileService, run tests ✓
→ git commit "Extract UserProfileService"
...
Step 6 - Final:
→ All tests pass
→ Code review agent validates
→ git checkout main && git merge refactor/split-user-service
