Use when adding new error messages to React, or seeing "unknown error code" warnings.
npx skills add josavicentevw/ai-agent-skills --skill "refactoring"
Install specific skill from multi-skill repository
# Description
Improve existing code structure and quality while preserving functionality through systematic refactoring techniques, code modernization, and technical debt reduction. Use when improving code quality, modernizing legacy code, eliminating code smells, or when user mentions refactoring, code improvement, or technical debt.
# SKILL.md
name: refactoring
description: Improve existing code structure and quality while preserving functionality through systematic refactoring techniques, code modernization, and technical debt reduction. Use when improving code quality, modernizing legacy code, eliminating code smells, or when user mentions refactoring, code improvement, or technical debt.
Refactoring
A comprehensive refactoring skill that helps improve code structure, readability, and maintainability while preserving existing behavior.
Quick Start
Basic refactoring workflow:
# Ensure tests exist (or create them first)
# Identify code smells and improvement opportunities
# Apply refactoring techniques incrementally
# Run tests after each change
# Commit frequently
Core Capabilities
1. Code Smell Detection & Resolution
Identify and fix common issues:
- Long Method: Break into smaller methods
- Large Class: Split responsibilities
- Duplicate Code: Extract common functionality
- Long Parameter List: Introduce parameter objects
- Feature Envy: Move behavior to appropriate class
- Data Clumps: Group related data
- Primitive Obsession: Create value objects
- Switch Statements: Replace with polymorphism
2. Refactoring Techniques
Apply proven refactoring patterns:
- Extract Method: Pull code into separate method
- Rename: Improve names for clarity
- Move Method/Field: Relocate to appropriate class
- Inline: Simplify unnecessary abstractions
- Replace Temp with Query: Remove temporary variables
- Introduce Parameter Object: Group related parameters
- Replace Conditional with Polymorphism: Use inheritance
- Extract Class: Split large classes
3. Design Pattern Implementation
Refactor to design patterns:
- Strategy: Replace conditionals with strategies
- Factory: Centralize object creation
- Observer: Decouple event handling
- Decorator: Add behavior without modification
- Template Method: Define algorithm skeleton
4. Code Modernization
Update to modern practices:
- Modern Language Features: Use latest syntax
- Async/Await: Replace callback patterns
- Type Safety: Add type hints/annotations
- Functional Patterns: Pure functions, immutability
- Dependency Injection: Improve testability
5. Performance Optimization
Improve efficiency while refactoring:
- Algorithm Optimization: Better data structures
- Caching: Avoid redundant computation
- Lazy Loading: Defer expensive operations
- Batch Operations: Reduce I/O overhead
- Database Optimization: Query improvement
Refactoring Catalog
Extract Method
Before:
def print_invoice(invoice):
print("***********************")
print("**** Invoice ****")
print("***********************")
# Print details
print(f"Name: {invoice.customer_name}")
print(f"Address: {invoice.customer_address}")
print(f"Total: ${invoice.total}")
After:
def print_invoice(invoice):
print_banner()
print_details(invoice)
def print_banner():
print("***********************")
print("**** Invoice ****")
print("***********************")
def print_details(invoice):
print(f"Name: {invoice.customer_name}")
print(f"Address: {invoice.customer_address}")
print(f"Total: ${invoice.total}")
Replace Conditional with Polymorphism
Before:
class Bird:
def __init__(self, bird_type):
self.type = bird_type
def fly(self):
if self.type == "sparrow":
return "Flying short distances"
elif self.type == "eagle":
return "Soaring high"
elif self.type == "penguin":
return "Cannot fly"
After:
from abc import ABC, abstractmethod
class Bird(ABC):
@abstractmethod
def fly(self):
pass
class Sparrow(Bird):
def fly(self):
return "Flying short distances"
class Eagle(Bird):
def fly(self):
return "Soaring high"
class Penguin(Bird):
def fly(self):
return "Cannot fly"
Introduce Parameter Object
Before:
def create_order(customer_name, customer_email, customer_address,
product_id, product_name, quantity, price):
# Create order with many parameters
pass
After:
from dataclasses import dataclass
@dataclass
class Customer:
name: str
email: str
address: str
@dataclass
class OrderItem:
product_id: int
product_name: str
quantity: int
price: float
def create_order(customer: Customer, item: OrderItem):
# Much cleaner interface
pass
Replace Temp with Query
Before:
def calculate_total(order):
base_price = order.quantity * order.item_price
discount_factor = 0.1 if base_price > 1000 else 0
return base_price * (1 - discount_factor)
After:
def calculate_total(order):
return base_price(order) * (1 - discount_factor(order))
def base_price(order):
return order.quantity * order.item_price
def discount_factor(order):
return 0.1 if base_price(order) > 1000 else 0
Extract Class
Before:
class Person:
def __init__(self, name, street, city, state, zip_code):
self.name = name
self.street = street
self.city = city
self.state = state
self.zip_code = zip_code
def get_full_address(self):
return f"{self.street}, {self.city}, {self.state} {self.zip_code}"
After:
class Address:
def __init__(self, street, city, state, zip_code):
self.street = street
self.city = city
self.state = state
self.zip_code = zip_code
def get_full_address(self):
return f"{self.street}, {self.city}, {self.state} {self.zip_code}"
class Person:
def __init__(self, name, address):
self.name = name
self.address = address
Refactoring Strategies
1. The Boy Scout Rule
Always leave code better than you found it.
# While fixing a bug, also:
# - Improve variable names
# - Extract complex expressions
# - Add missing tests
# - Update documentation
2. Incremental Refactoring
Make small, safe changes:
- One change at a time: Single refactoring per commit
- Run tests frequently: After each small change
- Commit often: Create restore points
- Stop if tests fail: Fix before continuing
3. Strangler Fig Pattern
Gradually replace legacy code:
Old System βββ
ββββΆ Facade βββΆ New System (grows)
New Code βββββ
- Create abstraction layer
- Route new features to new system
- Migrate old features incrementally
- Remove old system when complete
4. Branch by Abstraction
Refactor while keeping system working:
- Create abstraction: Interface for current implementation
- Implement new version: Behind same interface
- Switch gradually: Use feature flags
- Remove old implementation: When fully migrated
Language-Specific Refactoring
Python Modernization
Before (Python 2 style):
def process_data(data):
result = []
for item in data:
if item['value'] > 0:
result.append(item)
return result
After (Modern Python):
def process_data(data: list[dict]) -> list[dict]:
return [item for item in data if item['value'] > 0]
Advanced:
from typing import TypedDict
class DataItem(TypedDict):
value: int
name: str
def process_data(data: list[DataItem]) -> list[DataItem]:
"""Filter data items with positive values."""
return [item for item in data if item['value'] > 0]
JavaScript Modernization
Before (ES5):
var MyComponent = function(name) {
this.name = name;
};
MyComponent.prototype.greet = function() {
return 'Hello, ' + this.name;
};
After (Modern JavaScript):
class MyComponent {
constructor(name) {
this.name = name;
}
greet() {
return `Hello, ${this.name}`;
}
}
With TypeScript:
class MyComponent {
constructor(private name: string) {}
greet(): string {
return `Hello, ${this.name}`;
}
}
Callback to Async/Await
Before:
function fetchUserData(userId, callback) {
fetchUser(userId, function(err, user) {
if (err) return callback(err);
fetchPosts(user.id, function(err, posts) {
if (err) return callback(err);
fetchComments(posts, function(err, comments) {
if (err) return callback(err);
callback(null, { user, posts, comments });
});
});
});
}
After:
async function fetchUserData(userId) {
try {
const user = await fetchUser(userId);
const posts = await fetchPosts(user.id);
const comments = await fetchComments(posts);
return { user, posts, comments };
} catch (error) {
throw new Error(`Failed to fetch user data: ${error.message}`);
}
}
Refactoring Workflow
Step 1: Understand the Code
- Read the code thoroughly
- Identify entry points and dependencies
- Document current behavior
- Review existing tests
Step 2: Ensure Test Coverage
If tests don't exist, create them first:
# Characterization tests - document current behavior
def test_current_behavior():
# Even if behavior is wrong, test it first
result = legacy_function(input_data)
assert result == expected_output # Document what it DOES
Step 3: Plan Refactoring
- Identify code smells
- Prioritize improvements
- Choose refactoring techniques
- Plan sequence of changes
Step 4: Refactor Incrementally
for each_refactoring in plan:
1. Make one small change
2. Run tests
3. If tests pass:
- Commit
- Continue
4. If tests fail:
- Revert
- Adjust approach
Step 5: Clean Up
- Remove commented code
- Update documentation
- Verify all tests pass
- Review overall improvements
Refactoring Patterns
Replace Magic Numbers
Before:
if order.total > 1000:
discount = order.total * 0.1
After:
BULK_ORDER_THRESHOLD = 1000
BULK_DISCOUNT_RATE = 0.1
if order.total > BULK_ORDER_THRESHOLD:
discount = order.total * BULK_DISCOUNT_RATE
Introduce Null Object
Before:
def get_customer_discount(customer):
if customer is None:
return 0
if customer.is_premium:
return 0.15
return 0.05
After:
class Customer:
def get_discount(self):
return 0.15 if self.is_premium else 0.05
class NullCustomer(Customer):
def get_discount(self):
return 0
def get_customer_discount(customer):
return customer.get_discount()
Replace Error Codes with Exceptions
Before:
def save_user(user):
if not user.email:
return -1 # Error: No email
if not user.name:
return -2 # Error: No name
# Save user
return 0 # Success
After:
class ValidationError(Exception):
pass
def save_user(user):
if not user.email:
raise ValidationError("Email is required")
if not user.name:
raise ValidationError("Name is required")
# Save user
Anti-Patterns to Avoid
1. Big Rewrite
β Don't: Rewrite everything from scratch
β Do: Refactor incrementally
2. Refactoring Without Tests
β Don't: Change code without safety net
β Do: Create tests first, then refactor
3. Premature Optimization
β Don't: Optimize before measuring
β Do: Profile first, optimize bottlenecks
4. Over-Engineering
β Don't: Add complexity "just in case"
β Do: Keep it simple, refactor when needed
Best Practices
- Tests First: Ensure comprehensive test coverage
- Small Steps: Make tiny, incremental changes
- Commit Often: Create rollback points
- Run Tests: After every change
- One Thing at a Time: Single refactoring per commit
- Preserve Behavior: Don't change functionality
- Improve Names: Clear, descriptive naming
- Remove Duplication: DRY principle
- Simplify Logic: Reduce complexity
- Document Decisions: Explain non-obvious changes
When to Refactor
β
Good Times to Refactor:
- Before adding new features
- When fixing bugs
- During code reviews
- Scheduled refactoring sprints
- When code is hard to understand
β Bad Times to Refactor:
- Close to deadline
- Without tests
- Production is down
- You don't understand the code
- Scope is too large
When to Use This Skill
Use this skill when:
- Improving code quality
- Reducing technical debt
- Modernizing legacy code
- Preparing for new features
- Eliminating code smells
- Implementing design patterns
- Optimizing performance
- Improving testability
- Making code more maintainable
- Cleaning up after rapid development
Examples
See EXAMPLES.md for complete refactoring examples including:
- Legacy code modernization
- Design pattern implementation
- Performance optimization
- Test-driven refactoring
- Large-scale refactoring strategies
For refactoring checklists, see CHECKLISTS.md.
For refactoring scripts, see scripts/refactor_helpers.py.
# Supported AI Coding Agents
This skill is compatible with the SKILL.md standard and works with all major AI coding agents:
Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.