一键导入
refactoring-safely
Refactor with tests first, one change at a time, never mix refactoring with bug fixes or new features
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Refactor with tests first, one change at a time, never mix refactoring with bug fixes or new features
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
Fork, clone to ~/.clank, run installer, edit CLAUDE.md
RED-GREEN-REFACTOR for process documentation - baseline without skill, write addressing failures, iterate closing loopholes
Skills wiki intro - mandatory workflows, search tool, brainstorming triggers
Interactive idea refinement using Socratic method to develop fully-formed designs
Execute detailed plans in batches with review checkpoints
Execute implementation plan by dispatching fresh subagent for each task, with code review between tasks
| name | Refactoring Safely |
| description | Refactor with tests first, one change at a time, never mix refactoring with bug fixes or new features |
| when_to_use | Before refactoring any code. When improving code structure or naming. When extracting methods or classes. When code review requests changes. When you discover a bug during refactoring. When tempted to "fix while I'm here". When making multiple changes at once. When refactoring without tests. When mixing behavior changes with structure changes. When combining bug fix with refactoring. When extracting multiple methods simultaneously. When tests don't exist for code being refactored. When scope creep during refactoring. |
| version | 1.0.0 |
| languages | all |
Refactoring means changing code structure without changing behavior. Safe refactoring requires tests first, one change at a time, and NEVER mixing refactoring with bug fixes or features.
Core principle: Refactoring changes HOW code works internally. Bug fixes change WHAT code does. Never mix HOW and WHAT changes.
Violating the letter of this rule is violating the spirit of safe refactoring.
Use before any refactoring:
Critical moments:
LAW 1: TESTS BEFORE REFACTORING (NO EXCEPTIONS)
LAW 2: ONE CHANGE AT A TIME
LAW 3: NEVER MIX REFACTORING WITH BUG FIXES OR FEATURES
Violating any law makes refactoring unsafe.
Before refactoring ANY code, you MUST have passing tests.
No exceptions:
Process:
❌ Without tests (from baseline):
# Refactor immediately
def calc(x, y, z): # Bad names
...
# Refactor to:
def calculate_capped_product(first, second, multiplier):
...
# Hope it still works!
✅ With tests first:
# Step 1: Add tests
def test_calc():
assert calc(2, 3, 4) == 20
assert calc(10, 20, 5) == 100 # Capped
# Run - ALL PASS
# Step 2: Refactor
def calculate_capped_product(first, second, multiplier):
sum_of_addends = first + second
uncapped = sum_of_addends * multiplier
return min(uncapped, 100)
# Step 3: Run tests again - VERIFY STILL PASS
Tests prove refactoring didn't break behavior.
Make ONE structural change. Test. Commit. Repeat.
Don't:
Do:
❌ Multiple changes (risky):
# Change 1: Extract validation
# Change 2: Extract calculation
# Change 3: Extract persistence
# Change 4: Rename variables
# Change 5: Reorder statements
# Change 6: Add error handling
# If tests fail: which change broke it?
✅ Incremental (safe):
# Change 1: Extract validation
def validate_order(data):
...
# Run tests → PASS → Commit
# Change 2: Extract calculation
def calculate_total(items):
...
# Run tests → PASS → Commit
# If any test fails: know exactly which change broke it
From baseline: Agent chose incremental approach correctly. Skill reinforces this.
This is the critical discipline most developers violate.
Refactoring = change structure, preserve behavior Bug fix = change behavior to correct it
Never do both in the same commit.
You're refactoring and discover a bug:
# Extracting validation from larger function
def validate_order_items(order_data):
if not order_data.get('items'):
return None # ← BUG: should raise error
Tempting reasoning:
Why this is WRONG:
Diagnosis confusion: If tests fail after your commit, is it because:
Review confusion: Reviewer must evaluate:
Revert problems: If bug fix is wrong, reverting loses good refactoring
Violates single-change principle: One commit = one purpose
When you discover a bug during refactoring:
STOP refactoring immediately
STASH or commit refactoring work-in-progress
FIX the bug:
- Write failing test for bug
- Fix bug
- Verify test passes
- Commit bug fix separately
UNSTASH and continue refactoring
Concrete example:
# You're refactoring, discover bug
git stash # Save refactoring work
# Fix bug in separate commit
# 1. Write test
def test_empty_items_raises_error():
with pytest.raises(ValueError):
validate_order_items({'items': []})
# Run - FAILS (bug exposed)
# 2. Fix bug
def validate_order_items(order_data):
if not order_data.get('items'):
raise ValueError("Order must have items") # Fixed
# Run - PASSES
# 3. Commit bug fix separately
git add test_orders.py orders.py
git commit -m "fix: validate_order_items raises error for empty items"
# Now continue refactoring
git stash pop
# Continue extraction work
Result: Two clean commits:
Each can be reviewed, tested, reverted independently.
Before touching any code:
If any "no" → add tests first, watch them pass, THEN refactor.
Pick smallest possible refactoring:
Not:
After the change:
If tests pass:
For next refactoring:
From baseline test 3: Agents want to fix bugs while refactoring.
NO EXCEPTIONS - Separate the bug fix:
1. STOP refactoring
2. Stash or commit current refactoring work-in-progress
3. Fix bug:
- Write failing test
- Fix bug
- Verify test passes
- Commit bug fix separately ("fix: ...")
4. Return to refactoring:
- Unstash work
- Continue with structural changes
- Commit refactoring separately ("refactor: ...")
Even if:
DON'T MIX THEM.
Baseline rationalization: "The bug is right there, trivial fix, same code I'm touching"
Reality: Trivial bugs still change behavior. Behavior changes ≠ structural changes. Separate them.
Same principle applies:
While refactoring, you think "we should add error logging here."
NO. Don't add features during refactoring.
Why: Same diagnosis/review/revert problems as mixing bug fixes.
For large refactorings (300-line function → multiple smaller ones):
From baseline: Agent correctly chose incremental approach.
✅ Incremental (correct):
Extract section 1 → test → commit
Extract section 2 → test → commit
Extract section 3 → test → commit
...
Benefits:
❌ All-at-once (risky):
Extract all 6 sections → test → commit
Problems:
Always choose incremental.
❌ Refactoring without tests:
"It's simple, I can verify manually"
✅ Tests first, always:
Add tests → watch pass → refactor → verify still pass
❌ Mixing refactoring + bug fix:
# One commit with both structure change AND behavior change
"refactor: extract validation and fix null handling"
✅ Separate commits:
Commit 1: "fix: validate_order_items raises error for empty items"
Commit 2: "refactor: extract validate_order_items method"
❌ Multiple changes in one commit:
Extract 6 methods, rename 5 variables, reorder statements
✅ One change per commit:
Commit 1: Extract method A
Commit 2: Extract method B
...
Before starting:
During refactoring:
All of these mean: STOP current refactoring, address the issue separately.
From baseline testing:
| Excuse | Reality |
|---|---|
| "Bug is trivial, fix while refactoring" | Trivial bugs still change behavior. Separate commits. |
| "I'm touching this code anyway" | Touching ≠ should mix. Separate behavior from structure changes. |
| "Efficient to combine" | Efficient to write ≠ efficient to debug/review/revert. |
| "One coherent change" | No - one is behavior, one is structure. Different concerns. |
| "Tests will catch any issues" | Tests catch breaks, but can't tell which change broke it. |
| "Just while I'm here" | "While I'm here" scope creep ruins clean refactoring. |
Before starting refactoring:
After each refactoring change:
If discovered bug/feature:
| Situation | Action |
|---|---|
| No tests | Add tests first, watch pass, then refactor |
| Tests fail | Fix tests first, then refactor |
| Large refactoring | Break into small steps, test after each |
| Bug discovered | Stop, stash, fix bug separately, resume |
| Feature idea | Note it, finish refactoring, add feature after |
| Multiple changes planned | Do one, test, commit, repeat |
From Code Complete:
From baseline testing:
With this skill: Reinforce good practices, prevent mixing concerns.
For test discipline: See skills/testing/test-driven-development - tests before ANY code change, including refactoring
For bug fixes: See skills/debugging/systematic-debugging - bug fixes require root cause investigation, separate from refactoring
For focused routines: See skills/keeping-routines-focused - extraction is a common refactoring, do it incrementally