Spaces:
Sleeping
Workflow β Refactoring Code
Purpose
Read this file every time you need to refactor existing code. Refactoring means improving structure without changing behaviour. If behaviour changes β that is a feature, not a refactor.
Core Principle
Tests must pass before AND after every refactor. If tests fail after refactor β you changed behaviour. Revert and retry. Never refactor and fix a bug in the same commit.
Step 1 β Confirm Refactor Scope
Before touching any code, state this out loud:
Refactor target: [file or function] Reason for refactor: [why this needs to change] Behaviour change: none Files I will touch: [exact list] Files I will NOT touch: [everything else]
- Confirm with user that this refactor is needed now
- Confirm all current tests pass before starting:
bash scripts/test.sh
- Do not proceed if any test is currently failing
Step 2 β Identify What to Refactor
Valid reasons to refactor:
- Duplicate logic across multiple functions
- Function doing more than one thing
- Deeply nested conditionals reducing readability
- Magic numbers or hardcoded strings
- Missing or inconsistent error handling format
- Inconsistent naming conventions
- Dead code or unused imports
Not valid reasons:
- "It looks messy" without a specific structural problem
- Preference for a different syntax that does the same thing
- Rewriting working code during a bug fix session
Step 3 β Refactor in Small Steps
- Change one thing at a time
- Run tests after each individual change
- Do not batch multiple refactors into one step
- Keep original logic visible until new logic is confirmed working
Order of operations:
Extract repeated logic into a shared utility function Simplify conditionals (early returns over nested if/else) Rename for clarity (variables, functions) Remove dead code and unused imports Standardise error handling format per docs/debugging.md
Step 4 β Run Tests After Every Change
# After each individual change
npm test -- tests/unit/[affected-file].test.ts 2>&1 | tee logs/test.log
# After all changes complete
bash scripts/test.sh
- Every test that passed before must still pass
- If a test fails β revert the last change, do not chain fixes
Step 5 β Update Tests if Needed
Refactoring may require test updates only in these cases:
- A function was renamed β update test description and import
- A function was split into two β write tests for both
- A utility was extracted β write a unit test for the utility
Do NOT update tests to make them pass after a refactor. If a test fails after refactor β the refactor changed behaviour β revert.
Step 6 β Self Review Checklist
Before declaring refactor done:
- Behaviour is identical before and after
- All tests pass
- No new files created outside the plan in Step 1
- Error handling format matches
docs/debugging.md - No console.log left in code
- No dead code or unused imports remain
- No hardcoded values introduced
Step 7 β Update Docs
- Update
docs/architecture.mdif structure changed - Add one-liner to
docs/progress.md - Append one line to
session/phase-log.md - Update
session/summary.md - If a pattern was discovered that saves time β add to
docs/learnings.md
Step 8 β Git Commit Message
Provide one-liner commit message in this format:
refactor([scope]): [what was improved and how] Examples: refactor(auth): extract session validation into shared utility refactor(dashboard): replace nested conditionals with early returns refactor(db): standardise error handling across all supabase queries refactor(utils): remove dead code and unused imports from helpers
Do NOT push to GitHub. Hand the message to the user.
Step 9 β Confirm with User
- Show exactly what changed and in which files
- Show before/after for key changes
- Show test results confirming no behaviour change
- Show commit message
- Ask: "Refactor complete β ready to continue?"
- Do NOT proceed until user confirms
Refactor Decision Tree
Refactor needed? β βΌ All tests passing? β βββ No β fix failing tests first, then refactor β βββ Yes β confirm scope β refactor one thing at a time β βΌ Run tests after each change β βββ Pass β continue next change β βββ Fail β revert last change β reassess scope β do not chain fixes
Refactor Patterns
Extract repeated logic
// Before β same null check in 3 functions
if (!userId || userId === '') return null
// After β shared utility
function isValidId(id: string | null | undefined): boolean {
return !!id && id.trim() !== ''
}
Early returns over nested conditionals
// Before
function processUser(user: User | null) {
if (user) {
if (user.isActive) {
if (user.hasProfile) {
return user.profile
}
}
}
return null
}
// After
function processUser(user: User | null) {
if (!user) return null
if (!user.isActive) return null
if (!user.hasProfile) return null
return user.profile
}
Standardise error handling
// Before β inconsistent
try {
...
} catch (e) {
console.log(e) // wrong
}
// After β per docs/debugging.md
try {
...
} catch (err) {
handleError(err, 'lib/users.ts', 'processUser')
return null
}
What NOT to Do
- Do not refactor and fix a bug in the same commit
- Do not refactor files not listed in Step 1
- Do not update tests to force them to pass after refactor
- Do not batch all refactors into one large change
- Do not refactor during a feature build session
- Do not push to GitHub
- Do not start a refactor if any test is currently failing