Refactoring Safely
Safe refactoring strategies for Claude Code. Small steps, validated changes, easy rollback.
Quick Reference
| Principle | Description | |-----------|-------------| | Test First | Ensure tests pass before refactoring | | Small Steps | One change type at a time | | Commit Often | Create savepoints for rollback | | Verify Each Step | Run tests after each change | | No Behavior Change | Refactoring preserves functionality |
The Safe Refactoring Loop
1. Verify tests pass (baseline)
2. Make ONE small change
3. Run tests
4. If tests pass: commit
5. If tests fail: revert and retry smaller
6. Repeat
Before Any Refactoring
Prerequisites Checklist
- [ ] All tests passing
- [ ] Working directory clean (
git status) - [ ] On feature branch (not main)
- [ ] Tests cover the code being refactored
- [ ] Understand what the code does
Create Baseline
# Ensure clean state
git status
# Run full test suite
bun test
# Create savepoint
git commit -m "chore: checkpoint before refactoring"
Common Refactoring Patterns
Extract Function/Method
When: Duplicate code, long functions, complex conditionals
// Before: Long function with embedded logic
function processOrder(order: Order) {
// 20 lines of validation
// 30 lines of processing
// 10 lines of notification
}
// After: Extracted functions
function processOrder(order: Order) {
validateOrder(order);
executeOrder(order);
notifyCustomer(order);
}
Safe Steps:
- Identify code to extract
- Create new function with parameters
- Copy code to new function
- Replace original with function call
- Run tests
- Commit
Rename Symbol
When: Name doesn't reflect purpose, inconsistent naming
// Before
const d = new Date();
// After
const createdAt = new Date();
Safe Steps:
- Use IDE/editor rename refactoring if available
- Or use search-and-replace with word boundaries
- Check all references updated
- Run tests
- Commit
Move File/Module
When: Wrong directory, reorganizing structure
Safe Steps:
- Update imports in the file being moved
- Move file to new location
- Update all import statements referencing the file
- Run tests
- Commit
Inline Function
When: Function does too little, unnecessary indirection
// Before
function isAdult(age: number) {
return age >= 18;
}
const canVote = isAdult(user.age);
// After
const canVote = user.age >= 18;
Safe Steps:
- Verify function has single call site (or few)
- Copy function body to call site
- Adjust variables as needed
- Remove unused function
- Run tests
- Commit
Workflow: Basic Refactoring
Prerequisites
- [ ] Tests exist and pass
- [ ] Clean git state
- [ ] On feature branch
Steps
-
Establish Baseline
- [ ] Run
bun test- all pass - [ ] Create checkpoint commit
- [ ] Run
-
Plan Changes
- [ ] Identify what to refactor
- [ ] Choose ONE refactoring type
- [ ] List affected files
-
Execute
- [ ] Make the change
- [ ] Run tests immediately
- [ ] Fix any failures
-
Validate
- [ ] All tests pass
- [ ] Manual smoke test if needed
- [ ] No behavior changes
-
Commit
- [ ] Descriptive commit message
- [ ] Reference issue if applicable
Validation
- [ ] Tests pass before and after
- [ ] Same functionality preserved
- [ ] Code is cleaner/clearer
Test Coverage Considerations
Before Refactoring
# Check coverage for files you'll touch
bun test --coverage
# Identify untested code
# Add tests for uncovered critical paths
Minimum Coverage for Safety
| Risk Level | Minimum Coverage | |------------|------------------| | Critical business logic | 90%+ | | General application code | 70%+ | | Utility functions | 80%+ | | UI components | 60%+ |
Adding Tests First
If coverage is low:
- Write characterization tests (capture current behavior)
- Don't fix bugs during refactoring
- Document unexpected behavior for later
// Characterization test - captures current behavior
test('processOrder returns null for empty order', () => {
// This might be a bug, but document it first
expect(processOrder({})).toBeNull();
});
Rollback Strategies
Git-Based Rollback
# Undo last commit (keep changes staged)
git reset --soft HEAD~1
# Undo last commit (keep changes unstaged)
git reset HEAD~1
# Undo last commit (discard changes)
git reset --hard HEAD~1
# Revert specific commit (creates new commit)
git revert <commit-hash>
Stash-Based Recovery
# Save current work
git stash push -m "refactoring attempt 1"
# Try different approach
# ...
# If new approach fails, restore stash
git stash pop
Branch-Based Safety
# Create experimental branch
git checkout -b refactor/extract-auth-module
# Do refactoring work
# ...
# If successful, merge to feature branch
git checkout feature/my-feature
git merge refactor/extract-auth-module
# If failed, just delete the branch
git branch -D refactor/extract-auth-module
Common Mistakes
| Mistake | Consequence | Prevention | |---------|-------------|------------| | Multiple changes at once | Hard to identify what broke | One change type at a time | | Skipping tests | Silent regressions | Always run tests | | No commits | Lost progress | Commit after each successful change | | Refactoring on main | Risky deploys | Always use feature branch | | Changing behavior | Bugs introduced | Pure refactoring only | | No baseline | Can't verify preservation | Establish baseline first |
When to Stop Refactoring
- [ ] Tests are failing and you can't fix them quickly
- [ ] You're changing behavior, not just structure
- [ ] The refactoring scope is growing uncontrollably
- [ ] You're unsure what the code should do
- [ ] You've been refactoring the same area for hours
Stop, commit what works, and reassess.
Decision Guide: Which Refactoring?
| Symptom | Refactoring | |---------|-------------| | Duplicate code | Extract function | | Long function (>30 lines) | Extract function | | Long parameter list | Introduce parameter object | | Feature envy | Move method | | Data clumps | Extract class | | Primitive obsession | Replace with value object | | Switch statements | Replace with polymorphism | | Deep nesting | Extract function, early return | | Comment explaining code | Extract function with good name | | Unclear variable name | Rename |
Reference Files
| File | Contents | |------|----------| | STRATEGIES.md | Extract, inline, rename, move patterns | | LARGE-SCALE.md | Large-scale refactoring across files | | VALIDATION.md | Test coverage, validation, rollback |
Scan to join WeChat group