Refactoring
debt(d5/e5/b3/t5)
Closest to 'specialist tool catches' (d5) — code smells indicating refactoring candidates are detected by specialist tools like rector, phpstan, phpcs, and phpcpd listed in detection_hints, not by default linters or compiler errors.
Closest to 'touches multiple files / significant refactor in one component' (e5) — refactoring by definition involves restructuring, which spans methods/classes within a component; quick_fix emphasizes incremental changes with tests, which is multi-step work rather than a one-line patch.
Closest to 'localised tax' (b3) — refactoring as a practice imposes a modest discipline (require tests, small steps) but doesn't shape the entire system architecture; it's a continuous quality activity rather than a load-bearing structural choice.
Closest to 'notable trap' (t5) — the misconception that refactoring means rewriting is widespread; developers commonly conflate the two and skip the discipline of small steps with passing tests, a documented gotcha that most devs learn through painful experience.
Also Known As
TL;DR
Explanation
Refactoring (Martin Fowler's Refactoring: Improving the Design of Existing Code) is the disciplined process of restructuring code in small, verified steps without breaking existing functionality. Each step has a name (Extract Method, Rename Variable, Replace Conditional with Polymorphism, Introduce Parameter Object) and a defined safe transformation. Tests provide the safety net — never refactor without tests. Refactoring is distinct from rewriting: it is incremental, low-risk, and continuous, not a separate phase.
Common Misconception
Why It Matters
Common Mistakes
- Refactoring without tests — no safety net means refactoring introduces bugs.
- Big-bang refactors — large rewrites fail because they cannot be incrementally validated.
- Refactoring and adding features in the same commit — makes the diff unreadable and bugs hard to attribute.
- Never refactoring — treating the existing code as sacred creates unmaintainable codebases.
Avoid When
- Refactoring without test coverage — you cannot verify you have not broken behaviour.
- Refactoring and adding features in the same commit — separating concerns makes the diff reviewable.
- Big-bang rewrites instead of incremental refactoring — large rewrites fail more often than they succeed.
- Refactoring code you do not understand yet — understand the behaviour first, then improve the structure.
When To Use
- Before adding a new feature to code that is hard to extend — make the change easy, then make the change.
- When the same bug appears in the same area repeatedly — poor structure attracts bugs.
- After a code review that identified structural issues — address design feedback, not just functional bugs.
- As part of the boy scout rule — leave code slightly better than you found it on every touch.
Code Examples
// Refactoring without tests — dangerous:
function calcTotal($items) {
// 80 lines of complex discount logic, no tests
}
// Developer refactors to 'clean it up'
// Edge case in discount logic breaks silently
// No tests catch it until users complain
// Always write characterisation tests before refactoring complex legacy code
// Classic refactoring: Extract Method
// Before — long method doing too much
public function processOrder(Order $o): void {
// 10 lines validating items
// 15 lines calculating discounts
// 20 lines charging card
}
// After — each extracted method is testable and named
public function processOrder(Order $o): void {
$this->validateItems($o);
$total = $this->calculateTotal($o);
$charge = $this->chargeCard($o->customer, $total);
$this->sendReceipt($charge);
}
// Always refactor under a green test suite — tests catch regressions
// Commit before refactoring so rollback is easy
// Small, focused commits: one refactor per commit