Refactoring
The disciplined practice of improving internal code structure without changing external behaviour, keeping the codebase maintainable and reducing technical debt.
What it is
Refactoring is the process of restructuring existing code without changing its observable behaviour. It is not rewriting; it is not adding features; it is cleaning the kitchen while dinner is being served. The goal is to make the code easier to understand, cheaper to modify, and safer to extend.
Refactoring is a continuous activity, not a project. The Boy Scout Rule states: leave the code cleaner than you found it. When you touch a file to add a feature, spend a few minutes improving its structure. Over months, this compounds into a codebase that stays healthy rather than decaying.
Effective refactoring requires a test safety net. Without tests, you cannot prove that behaviour has not changed. With tests, refactoring becomes a low-risk, mechanical process of small, verifiable steps.
Refactoring is not rewriting. Rewriting discards working code and starts over. Refactoring preserves behaviour while improving structure. If you are deleting files and rebuilding from scratch, you are not refactoring.
When to use it
- Continuously: Every time you read code that is harder to understand than it should be, refactor it.
- Before adding features to complex areas: Clean the structure first, then add the new behaviour. This is the preparatory refactoring pattern.
- After code review: When reviewers flag unclear names or convoluted logic, refactor rather than documenting around the mess.
- When fixing bugs: Bugs cluster in confusing code. Refactoring the surrounding structure often reveals the root cause.
Tip: If a method takes you more than a minute to understand, it is telling you it wants to be refactored. Listen to the code.
Key concepts
Code Smells
Code smells are surface indicators of deeper problems: long methods, duplicated logic, mysterious names, classes that do too much. They are not bugs, but they signal that the design is resisting change. Martin Fowler’s Refactoring catalogues dozens of smells and the refactorings that cure them.
Extract Method
The most common refactoring: take a block of code that does one thing, give it a descriptive name, and turn it into a method. This reduces duplication, improves readability, and makes the code self-documenting.
Rename Variable
Do not underestimate the power of a good name. A variable called data tells you nothing. A variable called unprocessedInvoiceLines tells you exactly what it contains and what state it is in. Renaming is refactoring, and it is often the highest-impact change you can make.
Boy Scout Rule
Leave every file cleaner than you found it. This does not mean rewriting the whole file. It means: if you see a misleading name, rename it. If you see duplication, extract it. Small acts, repeated, prevent rot.
Test Safety Net
Refactoring without tests is like juggling flaming torches blindfolded. Tests prove that behaviour is preserved. If your codebase lacks tests, write them around the area you intend to refactor before touching the structure.
| Smell | Refactoring | Result |
|---|---|---|
| Long Method | Extract Method | Smaller, named methods that read like prose |
| Duplicated Code | Extract Class / Method | Single source of truth, easier maintenance |
| Poor Names | Rename Variable / Method | Self-documenting code, faster onboarding |
Common pitfalls
- Refactoring without tests. This is the fastest way to introduce regressions. Write tests first, then refactor.
- Large “refactoring projects.” Declaring a two-week sprint for refactoring usually means the codebase is already in crisis. Refactor continuously instead.
- Changing behaviour. If you fix a bug while refactoring, you have changed behaviour. Finish the refactoring first, then fix the bug in a separate commit.
- Gold plating. Refactoring is not an excuse to add features, switch frameworks, or chase perfection. Stop when the code is clean enough.
- Not explaining value to stakeholders. Non-technical stakeholders see refactoring as “rewriting working code.” Explain it as reducing future cost and risk, not as optional engineering hygiene.
Anti-pattern: A pull request titled “Refactoring” that touches fifty files and adds three features is not refactoring. It is a rewrite in disguise. Keep refactoring commits small and focused.
NZ context
New Zealand has a strong project-based consultancy culture. A team builds a system, delivers it, and moves on to the next client. In this model, neglected refactoring becomes a significant cost for the client who inherits the codebase. What was a quick delivery for the consultancy becomes a maintenance burden for the in-house team.
Professional NZ consultancies differentiate themselves by leaving clean, well-factored code behind. This builds reputation, generates follow-on work, and reduces the risk of being blamed for a “legacy” system six months later. For in-house teams, continuous refactoring protects the organisation’s investment in software assets.
Career level guidance
| Level | Focus | Milestones |
|---|---|---|
| Junior | Rename variables; extract small methods; follow the Boy Scout Rule | Can perform Extract Method safely; understands when to stop; writes tests before refactoring |
| Senior | Refactor across module boundaries; remove duplication at architecture level; mentor juniors | Leads codebase-wide clean-ups; identifies systemic smells; balances refactoring velocity with feature delivery |
| Test Lead | Ensure test coverage supports refactoring; measure technical debt; advocate for time allocation | Tracks code churn and defect rates pre/post-refactoring; secures stakeholder buy-in for continuous refactoring; audits test safety nets |
Tip for test leads: Measure refactoring success by how quickly new developers can make their first safe change to a module, not by lines of code cleaned. Maintainability is the metric that matters.