Suggest and apply code refactorings to improve readability, maintainability, and code quality. Use this skill when improving existing code structure, eliminating code smells, applying design patterns, simplifying complex logic, extracting duplicated code, renaming for clarity, or preparing code for new features. Provides specific before/after examples, explains benefits, identifies risks, and ensures behavior preservation through tests.
76
67%
Does it follow best practices?
Impact
91%
1.26xAverage score across 3 eval scenarios
Passed
No known issues
Optimize this skill with Tessl
npx tessl skill review --optimize ./skills/code-refactoring-assistant/SKILL.mdSystematically improve code structure and quality through targeted refactorings. Identifies opportunities, suggests improvements, and applies changes while preserving behavior.
Identify refactoring opportunities:
Improve code organization:
Reduce complexity:
Improve abstraction:
Recognize code that needs improvement:
Questions to ask:
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 functionsSelect 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 dataEnsure safe transformation:
Pre-refactoring checklist:
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 hoursMake changes in small, safe steps:
Guidelines:
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.Confirm behavior preservation:
Verification steps:
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.
"""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:
When to use:
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
passAfter:
class Address:
def __init__(self, street, city, state, zip_code, country):
self.street = street
self.city = city
self.state = state
self.zip_code = zip_code
self.country = country
def validate(self):
# Validation logic here
pass
def format_label(self, name):
return f"{name}\n{self.street}\n{self.city}, {self.state} {self.zip_code}"
class Package:
def __init__(self, weight, dimensions):
self.weight = weight
self.dimensions = dimensions
def calculate_shipping(address, package):
address.validate()
# Cleaner signature
passBenefits:
When to use:
Before:
class Employee:
def __init__(self, name, employee_type):
self.name = name
self.type = employee_type # "engineer", "manager", "salesperson"
def calculate_pay(self):
if self.type == "engineer":
return self.base_salary + self.bonus
elif self.type == "manager":
return self.base_salary + (self.num_reports * 1000)
elif self.type == "salesperson":
return self.base_salary + (self.sales * 0.1)
else:
return self.base_salary
def get_benefits(self):
if self.type == "engineer":
return ["health", "dental", "vision", "401k"]
elif self.type == "manager":
return ["health", "dental", "vision", "401k", "stock_options"]
elif self.type == "salesperson":
return ["health", "dental", "commission"]
else:
return ["health"]After:
class Employee:
def __init__(self, name):
self.name = name
self.base_salary = 50000
def calculate_pay(self):
return self.base_salary
def get_benefits(self):
return ["health"]
class Engineer(Employee):
def __init__(self, name, bonus=0):
super().__init__(name)
self.bonus = bonus
def calculate_pay(self):
return self.base_salary + self.bonus
def get_benefits(self):
return ["health", "dental", "vision", "401k"]
class Manager(Employee):
def __init__(self, name, num_reports=0):
super().__init__(name)
self.num_reports = num_reports
def calculate_pay(self):
return self.base_salary + (self.num_reports * 1000)
def get_benefits(self):
return ["health", "dental", "vision", "401k", "stock_options"]
class Salesperson(Employee):
def __init__(self, name, sales=0):
super().__init__(name)
self.sales = sales
def calculate_pay(self):
return self.base_salary + (self.sales * 0.1)
def get_benefits(self):
return ["health", "dental", "commission"]Benefits:
When to use:
Before:
def calculate_charge(customer, usage, date):
if date.month < 6 or date.month > 8:
# Winter rate
if usage > 100:
charge = usage * 0.15 + 10
else:
charge = usage * 0.12 + 5
else:
# Summer rate
if usage > 150:
charge = usage * 0.20 + 15
else:
charge = usage * 0.18 + 8
if customer.is_premium:
charge = charge * 0.9
return chargeAfter:
def calculate_charge(customer, usage, date):
base_charge = get_base_charge(usage, date)
return apply_customer_discount(base_charge, customer)
def get_base_charge(usage, date):
if is_winter(date):
return calculate_winter_charge(usage)
else:
return calculate_summer_charge(usage)
def is_winter(date):
return date.month < 6 or date.month > 8
def calculate_winter_charge(usage):
if usage > 100:
return usage * 0.15 + 10
else:
return usage * 0.12 + 5
def calculate_summer_charge(usage):
if usage > 150:
return usage * 0.20 + 15
else:
return usage * 0.18 + 8
def apply_customer_discount(charge, customer):
if customer.is_premium:
return charge * 0.9
return chargeBenefits:
When to use:
Before:
def calculate_potential_energy(mass, height):
return mass * 9.81 * height
def calculate_circumference(radius):
return 2 * 3.14159 * radius
def is_valid_age(age):
return 0 <= age <= 120
def apply_discount(price):
if price > 100:
return price * 0.9 # What discount is this?
return priceAfter:
# Constants at module level
GRAVITY = 9.81 # m/s²
PI = 3.14159
MIN_AGE = 0
MAX_AGE = 120
BULK_ORDER_THRESHOLD = 100
BULK_DISCOUNT_RATE = 0.10
def calculate_potential_energy(mass, height):
return mass * GRAVITY * height
def calculate_circumference(radius):
return 2 * PI * radius
def is_valid_age(age):
return MIN_AGE <= age <= MAX_AGE
def apply_discount(price):
if price > BULK_ORDER_THRESHOLD:
return price * (1 - BULK_DISCOUNT_RATE)
return priceBenefits:
When to use:
Before:
def calculate_pay(employee):
result = 0
if employee.is_active:
if employee.hours_worked > 0:
if employee.hourly_rate > 0:
result = employee.hours_worked * employee.hourly_rate
if employee.is_overtime:
result = result * 1.5
else:
result = 0
else:
result = 0
else:
result = 0
return resultAfter:
def calculate_pay(employee):
if not employee.is_active:
return 0
if employee.hours_worked <= 0:
return 0
if employee.hourly_rate <= 0:
return 0
base_pay = employee.hours_worked * employee.hourly_rate
if employee.is_overtime:
return base_pay * 1.5
return base_payBenefits:
When to use:
Before:
class Order:
def __init__(self):
self.items = []
self.customer_name = ""
self.customer_email = ""
self.customer_phone = ""
self.shipping_street = ""
self.shipping_city = ""
self.shipping_state = ""
self.shipping_zip = ""
self.billing_street = ""
self.billing_city = ""
self.billing_state = ""
self.billing_zip = ""
def validate_shipping_address(self):
# Validation logic
pass
def validate_billing_address(self):
# Validation logic
pass
def format_shipping_label(self):
# Formatting logic
pass
def send_confirmation_email(self):
# Email logic
passAfter:
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 validate(self):
# Validation logic
pass
def format_label(self):
return f"{self.street}\n{self.city}, {self.state} {self.zip_code}"
class Customer:
def __init__(self, name, email, phone):
self.name = name
self.email = email
self.phone = phone
def send_email(self, subject, body):
# Email logic
pass
class Order:
def __init__(self, customer, shipping_address, billing_address):
self.items = []
self.customer = customer
self.shipping_address = shipping_address
self.billing_address = billing_address
def validate_addresses(self):
self.shipping_address.validate()
self.billing_address.validate()
def send_confirmation(self):
self.customer.send_email(
"Order Confirmation",
f"Your order will ship to:\n{self.shipping_address.format_label()}"
)Benefits:
When to use:
Before:
def get_rating(driver):
return more_than_five_late_deliveries(driver) ? 2 : 1
def more_than_five_late_deliveries(driver):
return driver.number_of_late_deliveries > 5After:
def get_rating(driver):
return 2 if driver.number_of_late_deliveries > 5 else 1Benefits:
When to use:
Before:
def get_high_value_active_customers(customers):
result = []
for customer in customers:
if customer.is_active:
if customer.total_purchases > 1000:
result.append(customer.name)
result.sort()
return resultAfter:
def get_high_value_active_customers(customers):
return sorted(
customer.name
for customer in customers
if customer.is_active and customer.total_purchases > 1000
)Benefits:
When to use:
Before:
def calculate_price(order):
return order.quantity * order.item_price - \
max(0, order.quantity - 500) * order.item_price * 0.05 + \
min(order.quantity * order.item_price * 0.1, 100)After:
def calculate_price(order):
base_price = order.quantity * order.item_price
quantity_discount = max(0, order.quantity - 500) * order.item_price * 0.05
shipping = min(base_price * 0.1, 100)
return base_price - quantity_discount + shippingBenefits:
When to use:
# Before refactoring, ensure tests exist
def test_calculate_total():
order = Order(items=[
Item(price=10, quantity=2),
Item(price=5, quantity=3)
])
assert calculate_total(order) == 35
# If tests don't exist, write them BEFORE refactoring
# This is your safety net# Bad: Trying to do too much at once
# - Extract 10 methods
# - Rename 20 variables
# - Move 5 classes
# - Change architecture
# All in one commit!
# Good: One refactoring at a time
# Commit 1: Extract calculate_total method
# Commit 2: Extract validate_order method
# Commit 3: Rename 'x' to 'total_price'
# Each commit: tests pass, code works# Refactoring should NOT change behavior
# Only change structure, not functionality
# If you need to change behavior:
# 1. Refactor first (structure improvement)
# 2. THEN add new feature (behavior change)
# Don't mix them!# Many IDEs have safe, automated refactorings:
# - Rename (updates all references)
# - Extract Method (handles scope correctly)
# - Move Class/Method (updates imports)
# - Change Signature (updates callers)
# Use these instead of manual find-replace!
# They're safer and handle edge cases# Always review what changed
git diff
# Ask yourself:
# - Did I change only what I intended?
# - Are there unexpected changes?
# - Did I accidentally change behavior?
# - Are all tests still passing?Problem:
# No tests exist
def complex_business_logic():
# 200 lines of critical code
pass
# Start refactoring anyway
# Break something
# Don't notice until productionSolution:
# First: Write characterization tests
def test_complex_business_logic_scenario_1():
result = complex_business_logic(input1)
assert result == expected1
def test_complex_business_logic_scenario_2():
result = complex_business_logic(input2)
assert result == expected2
# Now refactor safely with test coverageProblem:
# Rewrite entire module at once
# Change everything
# Break everything
# Take weeks
# Can't merge back to mainSolution:
# Incremental refactoring
# Week 1: Extract 3 methods, commit, deploy
# Week 2: Extract 3 more, commit, deploy
# Week 3: Introduce parameter object, commit, deploy
# Always working, always deployableProblem:
# Code is used in one place
# "But we MIGHT need it elsewhere!"
# Create abstract factory builder strategy pattern
# Never actually reused
# Just complex for no reasonSolution:
# Rule of Three: Wait for 3rd use case
# 1st time: Write inline
# 2nd time: Note the duplication
# 3rd time: Now extract/generalize
# Don't abstract before you need itProblem:
# Pull request:
# - Adds new feature
# - Renames 50 variables
# - Extracts 10 methods
# - Moves 5 classes
# - Changes architecture
# Impossible to review what's actually newSolution:
# Separate commits:
# Commit 1: Refactor (structure only)
# Commit 2: Add feature (behavior change)
# Each commit easy to review and understandDifferent languages have different refactoring idioms:
Python:
JavaScript/TypeScript:
Java:
Go:
0f00a4f
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.