---
name: refactoring
description: Use for refactoring, behavior-preserving change, legacy seams, tests, and safe rewrites.
---

# Refactoring

## Iron Law

`GREEN BEFORE THE REFACTOR. GREEN AFTER EACH STEP. NEVER MIX STRUCTURE AND BEHAVIOR IN ONE COMMIT.`

## When to Use

- Legacy refactors, large renames, extractions, migrations, branch by
  abstraction, strangler fig, Mikado planning, characterization tests,
  or big-bang rewrite avoidance.

## When NOT to Use

- Behavior-first feature work; use `proof`.
- Commit grouping or git history surgery after changes already exist;
  use `git-workflow`.

## Core Ideas

1. Preserve behavior first; add characterization tests where coverage
   is missing. Separate structural from behavior changes: every commit
   is one or the other, never both.
2. Name the tangle before cutting it: data shape, side effect, module
   boundary, ownership, time, transport, persistence, or compatibility.
3. Make every step small, reversible, and shippable.
4. Validate the target shape before moving large amounts of code.
5. Use parallel change for public interfaces: expand, migrate callers,
   contract. Prefer strangler or branch-by-abstraction over big-bang
   rewrites.
6. Delete old paths only when traffic/callers have moved and
   verification proves it.
7. Do not assume backward compatibility is free or required. Ask which
   callers, data, and releases must keep working before adding shims,
   dual paths, or migration complexity.
8. Simplification is refactoring: remove accidental complexity only after
   naming the behavior preserved and the coupling reduced. Load workflow's
   `references/simple-not-easy.md` when shorter code, new helpers, or
   removed paths might hide state, compatibility, ownership, or proof risk.

## Workflow

1. Define the current behavior that must not change. Add or identify
   tests that catch regressions at the public boundary.
2. Name the concern being separated and its current coupling point.
3. Pick the smallest safe pattern: rename, extract, move, parallel
   change, branch by abstraction, or strangler.
4. Record a preservation Proof Contract: unchanged behavior claim,
   relevant invariant, public boundary, before/after check, evidence.
5. For simplification, remove only complexity that has a named cost:
   hidden mutable state, unnecessary layer, broad helper, scattered
   behavior, compatibility shim, dead flag, or duplicated rule with
   divergent meaning.
6. Make one structural step, run focused tests, commit. Track any old
   path left behind with owner and removal condition.

## Verification

- [ ] Tests were green before the refactor; characterization coverage
      exists for legacy behavior touched.
- [ ] The tangle being separated was named before code moved.
- [ ] Each commit is structural or behavioral, not both; the system is
      shippable at every commit.
- [ ] Public interface changes use expand-contract or compatibility
      shims; old and new paths both work during migration.
- [ ] Backward compatibility expectations were confirmed or inherited
      from an explicit public contract before compatibility machinery
      was added.
- [ ] Simplification claims name the removed complexity and the preserved
      behavior; behavior preservation has before/after evidence.
- [ ] Deleted tests were replaced by equal or stronger behavior
      coverage.
- [ ] Leftover migration/deletion work has owner and deadline.
- [ ] Every behavior-preservation claim has before/after proof
      evidence, or the refactor is reported as unproven.

## Tripwires

| Trigger | Do this instead | False alarm |
|---|---|---|
| "Tests are green, that's enough" | Name the behavior-preservation proof and add characterization where coverage is missing. | Existing tests explicitly cover the changed public behavior. |
| "Small mix of structure and behavior is fine" | Split structural and behavioral changes before committing. | Mechanical change generated by a tool and reviewed as one operation. |
| "A common helper/layer will clean this up" | First name the behavior, state, effect, or boundary being separated; extract only the smallest proven surface. | Existing duplicated domain rule with the same meaning at every call site. |
| "This is simpler because it is shorter" | Check whether it hides state, effects, compatibility, ownership, or independent behavior. | Mechanical deletion of proven-dead code. |
| "Rename and extract in one commit saves time" | Commit the rename separately from the extraction. | The extraction cannot compile until the rename lands and both are still reviewable. |
| "Tiny tweak while I'm here" | Put the tweak in a separate behavior commit or leave it out. | The tweak is required to keep the structural change compiling. |
| "Just delete the old path, callers are gone" | Prove no callers remain or use expand-contract migration. | Private dead code proven unreachable by search and tests. |
| "Big-bang is fine for this one" | Define the next safe slice or branch-by-abstraction path. | Throwaway prototype with no compatibility promise. |

## Handoffs

- Use `proof` for refactor preservation evidence, characterization, and
  boundary tests.
- Use `git-workflow` to group resulting changes cleanly.
- Use `domain-modeling` when the refactor is mainly about untangling
  effects or domain shape.
- Use `architecture` when the refactor is about module boundaries,
  domain/feature locality versus horizontal layers, or DDD tactical
  patterns.
- Use workflow's `references/simple-not-easy.md` when the refactor's value
  depends on reducing real coupling rather than making a local edit easier.

## References

- _Refactoring_: <https://martinfowler.com/books/refactoring.html>
- _Working Effectively with Legacy Code_:
  <https://www.oreilly.com/library/view/working-effectively-with/0131177052/>
- Branch by abstraction:
  <https://martinfowler.com/bliki/BranchByAbstraction.html>
- Strangler fig: <https://martinfowler.com/bliki/StranglerFigApplication.html>
