Code Refactoring Assistant
Systematically improve code structure and quality through targeted refactorings. Identifies opportunities, suggests improvements, and applies changes while preserving behavior.
Core Capabilities
1. Code Smell Detection
Identify refactoring opportunities:
- Long methods/functions - Functions doing too much
- Large classes - Classes with too many responsibilities
- Duplicate code - Repeated logic across codebase
- Long parameter lists - Functions with many parameters
- Primitive obsession - Using primitives instead of objects
- Feature envy - Methods using other classes more than their own
- Data clumps - Same group of data appearing together
- Switch statements - Complex conditionals that could be polymorphic
2. Structural Refactorings
Improve code organization:
- Extract Method - Pull out code into new function
- Extract Class - Split class responsibilities
- Inline Method/Variable - Remove unnecessary indirection
- Move Method/Field - Relocate to appropriate class
- Rename - Improve naming clarity
- Change Function Signature - Update parameters
- Introduce Parameter Object - Group parameters into object
- Replace Conditional with Polymorphism - Use inheritance/interfaces
3. Simplification Refactorings
Reduce complexity:
- Decompose Conditional - Simplify complex if/else
- Consolidate Conditional - Combine related conditions
- Remove Dead Code - Delete unused code
- Simplify Boolean Expression - Make logic clearer
- Replace Magic Number with Constant - Named constants
- Replace Nested Conditional with Guard Clauses - Early returns
- Replace Loop with Pipeline - Use functional operations
4. Generalization Refactorings
Improve abstraction:
- Extract Interface - Define contracts
- Extract Superclass - Pull up common behavior
- Replace Type Code with Class - Use objects not constants
- Replace Conditional with Strategy - Pluggable behavior
- Form Template Method - Define algorithm skeleton
- Replace Constructor with Factory - Flexible object creation
Refactoring Workflow
Step 1: Identify Refactoring Opportunity
Recognize code that needs improvement:
Questions to ask:
- Is this function/method too long? (>20-30 lines)
- Does this class have too many responsibilities?
- Is this code duplicated elsewhere?
- Are these names clear and descriptive?
- Is this logic overly complex?
- Would a design pattern help here?
Example identification:
# Long method doing multiple things
def process_user_order(user_id, items, payment_info, shipping_address): # 150 lines!
# Validate user
# Validate items
# Calculate prices
# Apply discounts
# Process payment
# Update inventory
# Create shipment
# Send emails
# Update analytics
# ...
# Opportunity: Extract Method refactoring
# This should be broken into focused functions
Step 2: Choose Appropriate Refactoring
Select the right transformation:
Refactoring catalog:
| Code Smell | Refactoring Solution |
|---|---|
| Long Method | Extract Method, Replace Temp with Query |
| Large Class | Extract Class, Extract Subclass |
| Long Parameter List | Introduce Parameter Object, Preserve Whole Object |
| Duplicate Code | Extract Method, Pull Up Method, Form Template Method |
| Complex Conditional | Decompose Conditional, Replace Conditional with Polymorphism |
| Primitive Obsession | Replace Type Code with Class, Introduce Value Object |
| Feature Envy | Move Method, Extract Method |
| Data Clumps | Extract Class, Introduce Parameter Object |
Example selection:
# Problem: Long Parameter List
def create_user(first_name, last_name, email, phone, street, city, state, zip_code, country):
pass
# Solution: Introduce Parameter Object
# Create Address and User classes to group related data
Step 3: Plan the Refactoring
Ensure safe transformation:
Pre-refactoring checklist:
- Code is under version control
- Tests exist and pass
- Understand current behavior completely
- Identify all callers/dependencies
- Plan small, incremental steps
- Know how to verify correctness
Refactoring plan example:
Refactoring: Extract Class for Address information
Current state:
- User class has 8 address-related fields
- Address logic scattered across User methods
Steps:
1. Create new Address class
2. Add address fields to Address
3. Add Address field to User
4. Update User constructor to accept Address
5. Update all address-related methods
6. Run tests after each step
7. Remove old address fields from User
Risk: Medium (many callers to update)
Estimated time: 1-2 hours
Step 4: Apply Refactoring Incrementally
Make changes in small, safe steps:
Guidelines:
- Make one change at a time
- Run tests after each step
- Commit after each successful refactoring
- If tests fail, revert and try smaller steps
- Keep working code compiling/running
Example incremental approach:
# Step 1: Extract method (just one piece)
def process_order(order):
# Before: All inline
total = 0
for item in order.items:
total += item.price * item.quantity
# ... rest of function
# Step 1a: Extract just the calculation
def calculate_total(items):
total = 0
for item in items:
total += item.price * item.quantity
return total
def process_order(order):
total = calculate_total(order.items)
# ... rest of function
# Run tests → Pass → Commit
# Step 2: Extract next piece (validation)
# Step 3: Extract next piece (payment)
# etc.
Step 5: Verify and Document
Confirm behavior preservation:
Verification steps:
- All existing tests pass
- No new warnings or errors
- Code review for correctness
- Manual testing of critical paths
- Performance not degraded
Documentation:
# Document the refactoring in commit message
"""
Refactor: Extract Address class from User
- Created Address value object with street, city, state, zip
- Moved address validation to Address class
- Updated User to use Address instead of separate fields
- All tests passing, behavior unchanged
Benefits:
- Address logic now centralized
- Easier to add address validation
- Can reuse Address in Order, Shipping, etc.
"""
Common Refactoring Patterns
Pattern 1: Extract Method
Before:
def print_owing(invoice):
print_banner()
# Print details
print(f"name: {invoice.customer}")
print(f"amount: {invoice.amount}")
# Calculate outstanding
outstanding = 0
for order in invoice.orders:
outstanding += order.amount
print(f"outstanding: {outstanding}")
After:
def print_owing(invoice):
print_banner()
print_details(invoice)
print_outstanding(invoice)
def print_details(invoice):
print(f"name: {invoice.customer}")
print(f"amount: {invoice.amount}")
def print_outstanding(invoice):
outstanding = calculate_outstanding(invoice)
print(f"outstanding: {outstanding}")
def calculate_outstanding(invoice):
return sum(order.amount for order in invoice.orders)
Benefits:
- Each function has single purpose
- Easier to understand and test
- More reusable components
- Better naming reveals intent
When to use:
- Function is too long (>20-30 lines)
- Code needs commenting to explain what it does
- Difficult to understand at a glance
- Want to reuse part of function elsewhere
Pattern 2: Introduce Parameter Object
Before:
def calculate_shipping(street, city, state, zip_code, country, weight, dimensions):
# Too many parameters!
pass
def validate_address(street, city, state, zip_code, country):
# Same address params repeated
pass
def format_label(name, street, city, state, zip_code, country):
# Same address params again
pass
**Afte