Safe refactoring is a sequence of small steps
Incremental refactoring is not a broad “improve the whole class” effort. Each step has one goal, a safety net, a bounded area, targeted verification, and a separate rollback.
- State one narrow structural goal.
- Check CLAUDE.md, the harness, tests, and characterization.
- Limit the request to a specific method or file.
- Forbid changes to the public API, messages, dependencies, and unrelated files.
- Make the minimal change.
- Run the affected test, build, or lint.
- Read the complete diff.
- Create a separate commit after confirmation.
Example of a narrow request
Goal: extract validation from finalizeOrder
Allowed: one service file and its focused tests
Must preserve: public API, messages, order of business checks
Forbidden: dependency updates, formatting sweep, unrelated cleanup
Check: focused tests plus local harness
Stop: if another module or contract must changeThe diff matters more than a feeling of safety
A reviewer-agent can classify the result as behavior preservation, behavior change, or insufficient data. This is an additional check, not a replacement for human review.
- check file and module boundaries;
- find unnecessary changes and renames;
- check the public API and messages;
- match every line to the step goal;
- do not accept an unclear diff merely because tests are green.
When to stop and roll back
| Signal | Action |
|---|---|
| A file outside the module changed | Stop and narrow the scope |
| The diff is much larger than the goal | Remove extras or return to the plan |
| Tests fail after another attempt | Diagnose; do not layer on another patch |
| The purpose of lines is unclear | Return to the last checkpoint |
| A bugfix or contract change is discovered | Create a separate task |
Pause after every commit
Refactoring ends with a pause after a separate commit. The next transformation starts with a new plan and a new cycle, not as a continuation of an endless cleanup.
Canonical lesson source · JavaRush
Open JavaRush material