- Code Refactoring
- When to use this skill
- Code review
-
- Discovering complex or duplicated code
- Before adding new features
-
- Cleaning up existing code
- After bug fixes
-
- Removing root causes
- Resolving technical debt
-
- Regular refactoring
- Instructions
- Step 1: Extract Method
- Before (long function)
- :
- function
- processOrder
- (
- order
- :
- Order
- )
- {
- // Validation
- if
- (
- !
- order
- .
- items
- ||
- order
- .
- items
- .
- length
- ===
- 0
- )
- {
- throw
- new
- Error
- (
- 'Order must have items'
- )
- ;
- }
- if
- (
- !
- order
- .
- customerId
- )
- {
- throw
- new
- Error
- (
- 'Order must have customer'
- )
- ;
- }
- // Price calculation
- let
- total
- =
- 0
- ;
- for
- (
- const
- item
- of
- order
- .
- items
- )
- {
- total
- +=
- item
- .
- price
- *
- item
- .
- quantity
- ;
- }
- const
- tax
- =
- total
- *
- 0.1
- ;
- const
- shipping
- =
- total
- >
- 100
- ?
- 0
- :
- 10
- ;
- const
- finalTotal
- =
- total
- +
- tax
- +
- shipping
- ;
- // Inventory check
- for
- (
- const
- item
- of
- order
- .
- items
- )
- {
- const
- product
- =
- await
- db
- .
- product
- .
- findUnique
- (
- {
- where
- :
- {
- id
- :
- item
- .
- productId
- }
- }
- )
- ;
- if
- (
- product
- .
- stock
- <
- item
- .
- quantity
- )
- {
- throw
- new
- Error
- (
- `
- Insufficient stock for
- ${
- product
- .
- name
- }
- `
- )
- ;
- }
- }
- // Create order
- const
- newOrder
- =
- await
- db
- .
- order
- .
- create
- (
- {
- data
- :
- {
- customerId
- :
- order
- .
- customerId
- ,
- items
- :
- order
- .
- items
- ,
- total
- :
- finalTotal
- ,
- status
- :
- 'pending'
- }
- }
- )
- ;
- return
- newOrder
- ;
- }
- After (method extraction)
- :
- async
- function
- processOrder
- (
- order
- :
- Order
- )
- {
- validateOrder
- (
- order
- )
- ;
- const
- total
- =
- calculateTotal
- (
- order
- )
- ;
- await
- checkInventory
- (
- order
- )
- ;
- return
- await
- createOrder
- (
- order
- ,
- total
- )
- ;
- }
- function
- validateOrder
- (
- order
- :
- Order
- )
- {
- if
- (
- !
- order
- .
- items
- ||
- order
- .
- items
- .
- length
- ===
- 0
- )
- {
- throw
- new
- Error
- (
- 'Order must have items'
- )
- ;
- }
- if
- (
- !
- order
- .
- customerId
- )
- {
- throw
- new
- Error
- (
- 'Order must have customer'
- )
- ;
- }
- }
- function
- calculateTotal
- (
- order
- :
- Order
- )
- :
- number
- {
- const
- subtotal
- =
- order
- .
- items
- .
- reduce
- (
- (
- sum
- ,
- item
- )
- =>
- sum
- +
- item
- .
- price
- *
- item
- .
- quantity
- ,
- 0
- )
- ;
- const
- tax
- =
- subtotal
- *
- 0.1
- ;
- const
- shipping
- =
- subtotal
- >
- 100
- ?
- 0
- :
- 10
- ;
- return
- subtotal
- +
- tax
- +
- shipping
- ;
- }
- async
- function
- checkInventory
- (
- order
- :
- Order
- )
- {
- for
- (
- const
- item
- of
- order
- .
- items
- )
- {
- const
- product
- =
- await
- db
- .
- product
- .
- findUnique
- (
- {
- where
- :
- {
- id
- :
- item
- .
- productId
- }
- }
- )
- ;
- if
- (
- product
- .
- stock
- <
- item
- .
- quantity
- )
- {
- throw
- new
- Error
- (
- `
- Insufficient stock for
- ${
- product
- .
- name
- }
- `
- )
- ;
- }
- }
- }
- async
- function
- createOrder
- (
- order
- :
- Order
- ,
- total
- :
- number
- )
- {
- return
- await
- db
- .
- order
- .
- create
- (
- {
- data
- :
- {
- customerId
- :
- order
- .
- customerId
- ,
- items
- :
- order
- .
- items
- ,
- total
- ,
- status
- :
- 'pending'
- }
- }
- )
- ;
- }
- Step 2: Remove Duplication
- Before (duplication)
- :
- async
- function
- getActiveUsers
- (
- )
- {
- return
- await
- db
- .
- user
- .
- findMany
- (
- {
- where
- :
- {
- status
- :
- 'active'
- ,
- deletedAt
- :
- null
- }
- ,
- select
- :
- {
- id
- :
- true
- ,
- name
- :
- true
- ,
- :
- true
- }
- }
- )
- ;
- }
- async
- function
- getActivePremiumUsers
- (
- )
- {
- return
- await
- db
- .
- user
- .
- findMany
- (
- {
- where
- :
- {
- status
- :
- 'active'
- ,
- deletedAt
- :
- null
- ,
- plan
- :
- 'premium'
- }
- ,
- select
- :
- {
- id
- :
- true
- ,
- name
- :
- true
- ,
- :
- true
- }
- }
- )
- ;
- }
- After (extract common logic)
- :
- type
- UserFilter
- =
- {
- plan
- ?
- :
- string
- ;
- }
- ;
- async
- function
- getActiveUsers
- (
- filter
- :
- UserFilter
- =
- {
- }
- )
- {
- return
- await
- db
- .
- user
- .
- findMany
- (
- {
- where
- :
- {
- status
- :
- 'active'
- ,
- deletedAt
- :
- null
- ,
- ...
- filter
- }
- ,
- select
- :
- {
- id
- :
- true
- ,
- name
- :
- true
- ,
- :
- true
- }
- }
- )
- ;
- }
- // Usage
- const
- allActiveUsers
- =
- await
- getActiveUsers
- (
- )
- ;
- const
- premiumUsers
- =
- await
- getActiveUsers
- (
- {
- plan
- :
- 'premium'
- }
- )
- ;
- Step 3: Replace Conditional with Polymorphism
- Before (long if-else)
- :
- class
- PaymentProcessor
- {
- process
- (
- payment
- :
- Payment
- )
- {
- if
- (
- payment
- .
- method
- ===
- 'credit_card'
- )
- {
- // Credit card processing
- const
- cardToken
- =
- this
- .
- tokenizeCard
- (
- payment
- .
- card
- )
- ;
- const
- charge
- =
- this
- .
- chargeCreditCard
- (
- cardToken
- ,
- payment
- .
- amount
- )
- ;
- return
- charge
- ;
- }
- else
- if
- (
- payment
- .
- method
- ===
- 'paypal'
- )
- {
- // PayPal processing
- const
- paypalOrder
- =
- this
- .
- createPayPalOrder
- (
- payment
- .
- amount
- )
- ;
- const
- approval
- =
- this
- .
- getPayPalApproval
- (
- paypalOrder
- )
- ;
- return
- approval
- ;
- }
- else
- if
- (
- payment
- .
- method
- ===
- 'bank_transfer'
- )
- {
- // Bank transfer processing
- const
- transfer
- =
- this
- .
- initiateBankTransfer
- (
- payment
- .
- account
- ,
- payment
- .
- amount
- )
- ;
- return
- transfer
- ;
- }
- }
- }
- After (polymorphism)
- :
- interface
- PaymentMethod
- {
- process
- (
- payment
- :
- Payment
- )
- :
- Promise
- <
- PaymentResult
- >
- ;
- }
- class
- CreditCardPayment
- implements
- PaymentMethod
- {
- async
- process
- (
- payment
- :
- Payment
- )
- :
- Promise
- <
- PaymentResult
- >
- {
- const
- cardToken
- =
- await
- this
- .
- tokenizeCard
- (
- payment
- .
- card
- )
- ;
- return
- await
- this
- .
- chargeCreditCard
- (
- cardToken
- ,
- payment
- .
- amount
- )
- ;
- }
- }
- class
- PayPalPayment
- implements
- PaymentMethod
- {
- async
- process
- (
- payment
- :
- Payment
- )
- :
- Promise
- <
- PaymentResult
- >
- {
- const
- order
- =
- await
- this
- .
- createPayPalOrder
- (
- payment
- .
- amount
- )
- ;
- return
- await
- this
- .
- getPayPalApproval
- (
- order
- )
- ;
- }
- }
- class
- BankTransferPayment
- implements
- PaymentMethod
- {
- async
- process
- (
- payment
- :
- Payment
- )
- :
- Promise
- <
- PaymentResult
- >
- {
- return
- await
- this
- .
- initiateBankTransfer
- (
- payment
- .
- account
- ,
- payment
- .
- amount
- )
- ;
- }
- }
- class
- PaymentProcessor
- {
- private
- methods
- :
- Map
- <
- string
- ,
- PaymentMethod
- >
- =
- new
- Map
- (
- [
- [
- 'credit_card'
- ,
- new
- CreditCardPayment
- (
- )
- ]
- ,
- [
- 'paypal'
- ,
- new
- PayPalPayment
- (
- )
- ]
- ,
- [
- 'bank_transfer'
- ,
- new
- BankTransferPayment
- (
- )
- ]
- ]
- )
- ;
- async
- process
- (
- payment
- :
- Payment
- )
- :
- Promise
- <
- PaymentResult
- >
- {
- const
- method
- =
- this
- .
- methods
- .
- get
- (
- payment
- .
- method
- )
- ;
- if
- (
- !
- method
- )
- {
- throw
- new
- Error
- (
- `
- Unknown payment method:
- ${
- payment
- .
- method
- }
- `
- )
- ;
- }
- return
- await
- method
- .
- process
- (
- payment
- )
- ;
- }
- }
- Step 4: Introduce Parameter Object
- Before (many parameters)
- :
- function
- createUser
- (
- name
- :
- string
- ,
- :
- string
- ,
- password
- :
- string
- ,
- age
- :
- number
- ,
- country
- :
- string
- ,
- city
- :
- string
- ,
- postalCode
- :
- string
- ,
- phoneNumber
- :
- string
- )
- {
- // ...
- }
- After (grouped into object)
- :
- interface
- UserProfile
- {
- name
- :
- string
- ;
- :
- string
- ;
- password
- :
- string
- ;
- age
- :
- number
- ;
- }
- interface
- Address
- {
- country
- :
- string
- ;
- city
- :
- string
- ;
- postalCode
- :
- string
- ;
- }
- interface
- CreateUserParams
- {
- profile
- :
- UserProfile
- ;
- address
- :
- Address
- ;
- phoneNumber
- :
- string
- ;
- }
- function
- createUser
- (
- params
- :
- CreateUserParams
- )
- {
- const
- {
- profile
- ,
- address
- ,
- phoneNumber
- }
- =
- params
- ;
- // ...
- }
- // Usage
- createUser
- (
- {
- profile
- :
- {
- name
- :
- 'John'
- ,
- :
- 'john@example.com'
- ,
- password
- :
- 'xxx'
- ,
- age
- :
- 30
- }
- ,
- address
- :
- {
- country
- :
- 'US'
- ,
- city
- :
- 'NYC'
- ,
- postalCode
- :
- '10001'
- }
- ,
- phoneNumber
- :
- '+1234567890'
- }
- )
- ;
- Step 5: Apply SOLID Principles
- Single Responsibility
- :
- // ❌ Bad example: multiple responsibilities
- class
- User
- {
- constructor
- (
- public
- name
- :
- string
- ,
- public
- :
- string
- )
- {
- }
- save
- (
- )
- {
- // Save to DB
- }
- sendEmail
- (
- subject
- :
- string
- ,
- body
- :
- string
- )
- {
- // Send email
- }
- generateReport
- (
- )
- {
- // Generate report
- }
- }
- // ✅ Good example: separated responsibilities
- class
- User
- {
- constructor
- (
- public
- name
- :
- string
- ,
- public
- :
- string
- )
- {
- }
- }
- class
- UserRepository
- {
- save
- (
- user
- :
- User
- )
- {
- // Save to DB
- }
- }
- class
- EmailService
- {
- send
- (
- to
- :
- string
- ,
- subject
- :
- string
- ,
- body
- :
- string
- )
- {
- // Send email
- }
- }
- class
- UserReportGenerator
- {
- generate
- (
- user
- :
- User
- )
- {
- // Generate report
- }
- }
- Output format
- Refactoring Checklist
- -
- [ ] Function does one thing only (SRP)
- -
- [ ] Function name clearly describes what it does
- -
- [ ] Function is 20 lines or fewer (guideline)
- -
- [ ] 3 or fewer parameters
- -
- [ ] No duplicate code (DRY)
- -
- [ ] if nesting is 2 levels or fewer
- -
- [ ] No magic numbers (extract as constants)
- -
- [ ] Understandable without comments (self-documenting)
- Constraints
- Mandatory Rules (MUST)
- Test first
-
- Write tests before refactoring
- Small steps
-
- Change one thing at a time
- Behavior preservation
-
- No functional changes
- Prohibited (MUST NOT)
- Multiple tasks simultaneously
-
- No refactoring + feature addition at the same time
- Refactoring without tests
-
- Risk of regression
- Best practices
- Boy Scout Rule
-
- Leave code cleaner than you found it
- Refactoring timing
-
- Red-Green-Refactor (TDD)
- Incremental improvement
-
- Consistency over perfection
- Behavior preservation
-
- Refactoring involves no functional changes
- Small commits
- Commit in focused units Behavior Validation (Code Simplifier Integration) Step A: Understand Current Behavior Fully understand current behavior before refactoring:
Behavior Analysis
Inputs
[list of input parameters]
[types and constraints]
Outputs
[return values]
[side effects]
Invariants
[conditions that must always be true]
[edge cases]
Dependencies
[external dependencies]
[state dependencies] Step B: Validate After Refactoring
1. Run tests
npm test -- --coverage
2. Type check
npx tsc --noEmit
3. Lint check
npm run lint
4. Compare with previous behavior (snapshot tests)
npm test -- --updateSnapshot Step C: Document Changes
Refactoring Summary
Changes Made 1. [ Change 1 ] : [reason] 2. [ Change 2 ] : [reason]
Behavior Preserved
[x] Same input → same output
[x] Same side effects
[x] Same error handling
Risks & Follow-ups
[potential risks]
[follow-up tasks]
Test Status
[ ] Unit tests: passing
[ ] Integration tests: passing
- [ ] E2E tests: passing
- Troubleshooting
- Issue: Tests fail after refactor
- Cause
-
- Behavior change occurred
- Solution
-
- Revert and isolate the change, then retry
- Issue: Code still complex
- Cause
-
- Multiple responsibilities mixed in one function
- Solution
-
- Extract into smaller units with clear boundaries
- Issue: Performance regression
- Cause
-
- Inefficient abstraction introduced
- Solution
-
- Profile and optimize the hot path
- Multi-Agent Workflow
- Validation & Retrospectives
- Round 1 (Orchestrator)
-
- Validate behavior preservation checklist
- Round 2 (Analyst)
-
- Complexity and duplication analysis
- Round 3 (Executor)
- Test or static analysis verification Agent Roles Agent Role Claude Refactoring plan, code transformation Gemini Large-scale codebase analysis, pattern detection Codex Test execution, build verification Workflow Example
1. Gemini: Codebase analysis
ask-gemini "@src/ extract list of high-complexity functions"
2. Claude: Refactoring plan and execution
Work based on IMPLEMENTATION_PLAN.md
3. Codex: Verification
- codex-cli shell
- "npm test && npm run lint"
- References
- Refactoring (Martin Fowler)
- Clean Code (Robert C. Martin)
- SOLID Principles
- Metadata
- Version
- Current Version
-
- 1.0.0
- Last Updated
-
- 2025-01-01
- Compatible Platforms
- Claude, ChatGPT, Gemini