Refactoring Safely
Prompt refactors that change structure while provably preserving behavior: one goal at a time, tests first, small diffs.
TL;DR
- Refactoring changes structure, not behavior; make that the explicit rule in your prompt.
- Target one smell at a time and keep diffs small so you can verify behavior is unchanged.
- Have tests in place first; they are your proof the refactor preserved behavior.
Set The Rule
Behavior PreservedMake 'no behavior change' the first and firmest constraint.
"Refactor only. Same inputs ->
same outputs."Keep The APIProtect exported signatures that other code depends on.
"Do not change public signatures
or exports."Tests Stay GreenRequire the existing test suite to keep passing.
"All current tests must still pass."Name The Target
One SmellAddress a single, specific issue per refactor.
"Remove the duplication between
parseA and parseB."Concrete TechniqueName the refactoring you want, not a vague 'improve'.
"Extract a pure `validate()`; replace
nested ifs with early returns."Scope ItBound the refactor to one function or file at a time.
"Only touch orders.ts for now."Safety Net First
CharacterizeIf tests are missing, capture current behavior before changing anything.
"Write tests that pin the current
behavior of this function."Run BeforeConfirm the suite is green before the refactor starts.
npm test # green baselineRun AfterA still-green suite is your evidence behavior was preserved.
npm test # still green = safeReview Small Diffs
As A DiffAsk for a diff so moved code and changed logic are both visible.
"Return a unified diff."Spot Logic ChangesScan for any change that is not purely structural.
Moved lines = fine.
Changed conditionals = inspect.IterateLand one small refactor, verify, then prompt the next.
Refactor -> test -> commit -> repeat.Tips
- Say 'do not change behavior or the public API' and 'keep tests green' as hard constraints.
- Ask for the refactor as a diff so you can see exactly what moved and catch accidental logic changes.
Warnings
- Models often 'improve' behavior while refactoring; that is a behavior change in disguise, and a risk.
- A big sweeping refactor is hard to review; prefer a sequence of small, verifiable steps.
In Practice
A refactor request that pins behavior, names the exact smell and technique, and requires green tests and a diff. The result is reviewable and provably behavior-preserving.
- The prompt establishes behavior preservation as the top constraint.
- It names the specific smell and the technique to apply, not a vague cleanup.
- It requires the existing tests to stay green as proof of safety.
- Asking for a diff makes any non-structural change easy to catch in review.
Refactor the function below for readability only.
Hard rules:
- do not change behavior: same inputs -> same outputs
- do not change the signature or exports
- all existing tests must still pass
Target: the nested if/else is hard to follow.
- replace with early returns (guard clauses)
- extract the discount calculation into a pure helper
Scope: only this function. Return a unified diff.
If any behavior would change, stop and tell me instead.
<paste the function and its tests>FAQ
State it as a hard rule: 'refactor for readability only; do not change behavior, outputs, or the public API'. Have tests in place and require them to stay green. Review the diff for any logic change, not just moved lines, since models often 'fix' things while reorganizing.
Add characterization tests first, tests that capture the current behavior, before refactoring. You can ask the model to write them from the existing code. They become the safety net that proves the refactor preserved behavior.
No. Target one smell at a time, duplication, a long function, poor naming, and keep each diff small and reviewable. A sequence of small refactors is safer and easier to verify than one sweeping rewrite you cannot fully check.
Point at the specific smell and the goal. 'Extract the validation logic into a pure function' or 'replace the nested conditionals with early returns' is actionable; 'clean this up' invites unpredictable, sweeping changes.