home / skills / skillcreatorai / ai-agent-skills / code-refactoring

code-refactoring skill

/skills/code-refactoring

This skill helps you apply proven refactoring techniques to improve code quality, readability, and maintainability without altering behavior.

npx playbooks add skill skillcreatorai/ai-agent-skills --skill code-refactoring

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
5.1 KB
---
name: code-refactoring
description: Code refactoring patterns and techniques for improving code quality without changing behavior. Use for cleaning up legacy code, reducing complexity, or improving maintainability.
source: wshobson/agents
license: MIT
---

# Code Refactoring

## Refactoring Principles

### When to Refactor
- Before adding new features (make change easy, then make easy change)
- After getting tests passing (red-green-refactor)
- When you see code smells
- During code review feedback

### When NOT to Refactor
- Without tests covering the code
- Under tight deadlines with no safety net
- Code that will be replaced soon
- When you don't understand what the code does

## Common Code Smells

### Long Methods
```typescript
// BEFORE: Method doing too much
function processOrder(order: Order) {
  // 100 lines of validation, calculation, notification, logging...
}

// AFTER: Extract into focused methods
function processOrder(order: Order) {
  validateOrder(order);
  const total = calculateTotal(order);
  saveOrder(order, total);
  notifyCustomer(order);
}
```

### Deeply Nested Conditionals
```typescript
// BEFORE: Arrow code
function getDiscount(user: User, order: Order) {
  if (user) {
    if (user.isPremium) {
      if (order.total > 100) {
        if (order.items.length > 5) {
          return 0.2;
        }
      }
    }
  }
  return 0;
}

// AFTER: Early returns (guard clauses)
function getDiscount(user: User, order: Order) {
  if (!user) return 0;
  if (!user.isPremium) return 0;
  if (order.total <= 100) return 0;
  if (order.items.length <= 5) return 0;
  return 0.2;
}
```

### Primitive Obsession
```typescript
// BEFORE: Primitives everywhere
function createUser(name: string, email: string, phone: string) {
  if (!email.includes('@')) throw new Error('Invalid email');
  // more validation...
}

// AFTER: Value objects
class Email {
  constructor(private value: string) {
    if (!value.includes('@')) throw new Error('Invalid email');
  }
  toString() { return this.value; }
}

function createUser(name: string, email: Email, phone: Phone) {
  // Email is already validated
}
```

### Feature Envy
```typescript
// BEFORE: Method uses another object's data extensively
function calculateShipping(order: Order) {
  const address = order.customer.address;
  const weight = order.items.reduce((sum, i) => sum + i.weight, 0);
  const distance = calculateDistance(address.zip);
  return weight * distance * 0.01;
}

// AFTER: Move method to where the data is
class Order {
  calculateShipping() {
    return this.totalWeight * this.customer.shippingDistance * 0.01;
  }
}
```

## Refactoring Techniques

### Extract Method
```typescript
// Identify a code block that does one thing
// Move it to a new method with a descriptive name
// Replace original code with method call

function printReport(data: ReportData) {
  // Extract this block...
  const header = `Report: ${data.title}\nDate: ${data.date}\n${'='.repeat(40)}`;
  console.log(header);

  // ...into a method
  printHeader(data);
}
```

### Replace Conditional with Polymorphism
```typescript
// BEFORE: Switch on type
function getArea(shape: Shape) {
  switch (shape.type) {
    case 'circle': return Math.PI * shape.radius ** 2;
    case 'rectangle': return shape.width * shape.height;
    case 'triangle': return shape.base * shape.height / 2;
  }
}

// AFTER: Polymorphic classes
interface Shape {
  getArea(): number;
}

class Circle implements Shape {
  constructor(private radius: number) {}
  getArea() { return Math.PI * this.radius ** 2; }
}

class Rectangle implements Shape {
  constructor(private width: number, private height: number) {}
  getArea() { return this.width * this.height; }
}
```

### Introduce Parameter Object
```typescript
// BEFORE: Too many parameters
function searchProducts(
  query: string,
  minPrice: number,
  maxPrice: number,
  category: string,
  inStock: boolean,
  sortBy: string,
  sortOrder: string
) { ... }

// AFTER: Parameter object
interface SearchParams {
  query: string;
  priceRange: { min: number; max: number };
  category?: string;
  inStock?: boolean;
  sort?: { by: string; order: 'asc' | 'desc' };
}

function searchProducts(params: SearchParams) { ... }
```

### Replace Magic Numbers with Constants
```typescript
// BEFORE
if (user.age >= 18 && order.total >= 50) {
  applyDiscount(order, 0.1);
}

// AFTER
const MINIMUM_AGE = 18;
const DISCOUNT_THRESHOLD = 50;
const STANDARD_DISCOUNT = 0.1;

if (user.age >= MINIMUM_AGE && order.total >= DISCOUNT_THRESHOLD) {
  applyDiscount(order, STANDARD_DISCOUNT);
}
```

## Safe Refactoring Process

1. **Ensure tests exist** - Write tests if they don't
2. **Make small changes** - One refactoring at a time
3. **Run tests after each change** - Catch regressions immediately
4. **Commit frequently** - Easy to revert if something breaks
5. **Review the diff** - Make sure behavior hasn't changed

## Refactoring Checklist

- [ ] Tests pass before starting
- [ ] Each change is small and focused
- [ ] Tests pass after each change
- [ ] No behavior changes (only structure)
- [ ] Code is more readable than before
- [ ] Commit message explains the refactoring

Overview

This skill provides practical code refactoring patterns and techniques to improve code quality without changing behavior. It focuses on identifying code smells, applying safe refactorings, and preserving functionality through tests. Use it to clean legacy code, reduce complexity, and improve maintainability.

How this skill works

The skill inspects common code smells (long methods, deep nesting, primitive obsession, feature envy) and recommends targeted refactorings like extract method, replace conditional with polymorphism, introduce parameter objects, and replace magic numbers with constants. It guides a safe refactoring process: ensure tests, make small incremental changes, run tests frequently, and review diffs. Examples and a checklist help enforce reproducible, low-risk changes.

When to use it

  • Preparing to add new features so the codebase is easier to change
  • Cleaning or modernizing legacy code with unclear structure
  • Reducing cyclomatic complexity or long methods that hinder understanding
  • After tests are green (red-green-refactor) or during code review feedback
  • When repetitive primitives or conditionals indicate a missed abstraction

Best practices

  • Always have tests covering the behavior before refactoring
  • Make one small, focused change at a time and run tests after each change
  • Prefer descriptive names and extracted methods to explain intent
  • Replace conditionals with polymorphism when behavior varies by type
  • Turn correlated parameters into parameter objects to simplify signatures
  • Use constants for magic numbers and document domain meaning

Example use cases

  • Extract a 100-line order processing function into validate, calculate, save, and notify methods
  • Replace nested guard conditions with early returns to improve readability
  • Introduce value objects (Email, Phone) to centralize validation and reduce primitive checks
  • Move a shipping calculation from a service into the Order class to resolve feature envy
  • Refactor a switch-based shape area calculation into polymorphic Shape classes

FAQ

What if there are no tests for the code I want to refactor?

Do not refactor yet; write tests that capture current behavior first. Tests provide a safety net to detect regressions.

How large should a refactoring commit be?

Keep commits small and focused: one refactoring per commit is ideal. Frequent commits make it easier to review and revert if necessary.