Incremental refactoring is a series of controlled slices
A legacy module becomes safer through a sequence of small changes with a clear purpose, not through one large rewrite. Each slice has bounded scope, non-goals, a safety net, a focused check, and a clear rollback.
If a bug fix, business-rule change, or new public contract is discovered during structural refactoring, stop and move it into a separate task.
One slice — one structural hypothesis
| Element | Example question |
|---|---|
| Goal | What one structural problem are we removing? |
| Allowed scope | Which files, symbols, or boundaries may be touched? |
| Non-goals | Which APIs, dependencies, and business rules are not changing? |
| Safety net | Which observable behavior do we compare before and after? |
| Stop condition | When must we return to the baseline or request a decision? |
Small-step cycle
- State the structural goal and list the forbidden changes.
- Check usages, tests, the current baseline, and dependency direction.
- Make the smallest change that tests the hypothesis.
- Run a focused check and compare the observable output.
- Read the complete diff and check the list of touched files.
- Create a logical checkpoint or commit only after review.
- Update the modernization record with the actual result and open risks.
What is not incremental refactoring
- mass renaming together with a behavior change;
- updating the framework or dependencies without a separate compatibility plan;
- moving code across dozens of modules without a safety net;
- adding a feature while cleaning up a legacy class;
- weakening a test to hide a regression.
Prompt for a controlled step
Goal: extract one internal responsibility
Allowed: <one module> and focused tests
Preserve: public API, outputs, errors, side effects
Forbidden: dependency updates, feature work, broad formatting
Check: <focused command>
Stop if: behavior or scope is unclearCanonical lesson source · JavaRush
Open JavaRush material