# Refactoring Workflow

This skill orchestrates systematic code refactoring to improve quality without changing behavior.

## Workflow Overview

```
┌──────────────┐
│   Analyze    │ → Identify code smells & issues
└──────────────┘
       ↓
┌──────────────┐
│     Plan     │ → Plan refactoring strategy
└──────────────┘
       ↓
┌──────────────┐
│   Refactor   │ → Apply refactoring patterns
└──────────────┘
       ↓
┌──────────────┐
│     Test     │ → Ensure behavior unchanged
└──────────────┘
       ↓
┌──────────────┐
│   Validate   │ → Verify improvement
└──────────────┘
       ↓
    ✅ Done
```

## When to Refactor

### Good Reasons
- ✅ Code duplication (DRY violation)
- ✅ Long functions (> level limit)
- ✅ Too many parameters (> level limit)
- ✅ High complexity (> level limit)
- ✅ Poor naming (unclear intent)
- ✅ Inline comments (code smell)
- ✅ Architecture violations
- ✅ Mixed concerns

### Bad Reasons
- ❌ "I don't like this style"
- ❌ Premature optimization
- ❌ Changing working code for no reason
- ❌ "Let's use a new pattern I learned"

## Step-by-Step Process

### Step 1: Analyze

**Goal**: Identify code smells and violations

**Automated Analysis**:
```typescript
// Check violations
mcp__rules-validator__validate_code({
  code: currentCode,
  filePath: "...",
  level: detectedLevel
})

// Check architecture
mcp__architecture-guard__check_layer_boundaries({
  level: detectedLevel
})

// Check coverage
mcp__vitest__check_coverage({
  threshold: levelThreshold
})
```

**Manual Code Smells**:

1. **Long Functions**
   - Rapid: > 100 lines
   - Balanced: > 50 lines
   - Crafted: > 20 lines

2. **Too Many Parameters**
   - Balanced: > 3
   - Crafted: > 2

3. **Duplication**
   - Rapid: 3+ times
   - Balanced: 2+ times
   - Crafted: Any duplication

4. **Inline Comments** (ALWAYS a code smell)
   ```typescript
   // ❌ BAD
   // Loop through users
   users.forEach(u => ...)

   // ✅ GOOD (refactor instead)
   users.forEach(user => processActiveUser(user))
   ```

5. **Poor Naming**
   ```typescript
   // ❌ BAD
   function calc(x, y) { ... }

   // ✅ GOOD
   function calculateTotalPrice(basePrice: number, taxRate: number) { ... }
   ```

6. **Mixed Concerns**
   ```typescript
   // ❌ BAD (API + business logic + data access)
   export const productRouter = createTRPCRouter({
     create: procedure.mutation(async ({ input }) => {
       const product = await db.product.create({ data: input });
       await stripe.products.create({ ... });
       return product;
     }),
   });

   // ✅ GOOD (separated)
   export const productRouter = createTRPCRouter({
     create: procedure.mutation(({ input }) =>
       productService.create(input)
     ),
   });
   ```

**Output**: List of issues to fix

---

### Step 2: Plan

**Goal**: Decide refactoring strategy

**Consider**:
1. **Current level** (Rapid/Balanced/Crafted)
2. **Impact scope** (how much code will change?)
3. **Risk level** (high-traffic code? critical path?)
4. **Test coverage** (do we have tests?)

**Refactoring Strategies**:

**For Rapid → Balanced transition**:
- Extract services from routers
- Add test coverage (70%)
- Reduce function size (50 lines)
- Limit parameters (3 max)

**For Balanced → Crafted transition**:
- Extract domain layer
- Create value objects
- Create use-cases
- Ensure 100% domain coverage
- Remove all duplication

**For any level**:
- Remove inline comments → refactor
- Extract long functions
- Improve naming
- Remove duplication

**Output**: Refactoring plan

---

### Step 3: Refactor

**Goal**: Apply refactoring patterns systematically

**Refactoring Catalog**:

#### 1. Extract Function
```typescript
// ❌ BEFORE
function processOrder(order) {
  // Validate
  if (!order.items || order.items.length === 0) {
    throw new Error('Order must have items');
  }

  // Calculate total
  let total = 0;
  for (const item of order.items) {
    total += item.price * item.quantity;
  }

  // Apply discount
  if (order.discountCode) {
    const discount = getDiscount(order.discountCode);
    total = total * (1 - discount);
  }

  return total;
}

// ✅ AFTER
function processOrder(order: Order): number {
  validateOrderHasItems(order);
  const subtotal = calculateSubtotal(order.items);
  return applyDiscount(subtotal, order.discountCode);
}

function validateOrderHasItems(order: Order): void {
  if (!order.items || order.items.length === 0) {
    throw new Error('Order must have items');
  }
}

function calculateSubtotal(items: OrderItem[]): number {
  return items.reduce((sum, item) => sum + item.price * item.quantity, 0);
}

function applyDiscount(amount: number, code?: string): number {
  if (!code) return amount;

  const discount = getDiscount(code);
  return amount * (1 - discount);
}
```

#### 2. Extract Service (Rapid → Balanced)
```typescript
// ❌ BEFORE (Rapid - router with logic)
export const userRouter = createTRPCRouter({
  updateEmail: protectedProcedure
    .input(z.object({ email: z.string().email() }))
    .mutation(async ({ ctx, input }) => {
      const user = await ctx.db.user.findUnique({
        where: { id: ctx.session.user.id },
      });

      if (!user) {
        throw new TRPCError({ code: 'NOT_FOUND' });
      }

      const updated = await ctx.db.user.update({
        where: { id: user.id },
        data: { email: input.email },
      });

      return updated;
    }),
});

// ✅ AFTER (Balanced - service extracted)
// Router
export const userRouter = createTRPCRouter({
  updateEmail: protectedProcedure
    .input(updateEmailSchema)
    .mutation(({ ctx, input }) =>
      userService.updateEmail(ctx.session.user.id, input.email)
    ),
});

// Service
export const userService = {
  async updateEmail(userId: string, newEmail: string) {
    const user = await userRepository.findById(userId);

    if (!user) {
      throw new NotFoundError('User not found');
    }

    return await userRepository.updateEmail(user.id, newEmail);
  },
};

// Repository
export const userRepository = {
  findById: (id: string) => db.user.findUnique({ where: { id } }),
  updateEmail: (id: string, email: string) =>
    db.user.update({ where: { id }, data: { email } }),
};
```

#### 3. Introduce Value Object (Balanced → Crafted)
```typescript
// ❌ BEFORE (Balanced - primitive obsession)
export class User {
  constructor(
    public id: string,
    public email: string, // Just a string
    public name: string,
  ) {}

  updateEmail(newEmail: string) {
    // Email validation in multiple places (duplication)
    if (!newEmail.includes('@')) {
      throw new Error('Invalid email');
    }
    this.email = newEmail;
  }
}

// ✅ AFTER (Crafted - Value Object)
export class Email {
  private constructor(private readonly value: string) {}

  static create(email: string): Result<Email> {
    if (!Email.isValid(email)) {
      return Result.fail('Invalid email format');
    }
    return Result.ok(new Email(email));
  }

  private static isValid(email: string): boolean {
    return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
  }

  toString(): string {
    return this.value;
  }

  equals(other: Email): boolean {
    return this.value === other.value;
  }
}

export class User {
  private constructor(
    public readonly id: UserId,
    public email: Email, // Value Object
    public name: string,
  ) {}

  updateEmail(newEmail: Email): Result<void> {
    // No validation needed, Email is always valid
    this.email = newEmail;
    return Result.ok();
  }
}
```

#### 4. Replace Comment with Function
```typescript
// ❌ BEFORE
function processPayment(order: Order) {
  // Check if user is premium
  const isPremium = order.user.plan === 'premium' && order.user.active;

  // Calculate total with premium discount
  let total = order.amount;
  if (isPremium) {
    total = total * 0.9; // 10% discount
  }

  return total;
}

// ✅ AFTER
function processPayment(order: Order): number {
  const total = order.amount;
  return applyPremiumDiscountIfEligible(total, order.user);
}

function applyPremiumDiscountIfEligible(amount: number, user: User): number {
  if (!isPremiumUser(user)) {
    return amount;
  }

  return applyPremiumDiscount(amount);
}

function isPremiumUser(user: User): boolean {
  return user.plan === 'premium' && user.active;
}

function applyPremiumDiscount(amount: number): number {
  const PREMIUM_DISCOUNT_RATE = 0.1;
  return amount * (1 - PREMIUM_DISCOUNT_RATE);
}
```

**Validate Each Step**:
```typescript
mcp__rules-validator__validate_code({
  code: refactoredCode,
  level: detectedLevel
})
```

**Output**: Refactored code

---

### Step 4: Test

**Goal**: Ensure behavior is unchanged

**Critical Rule**: Tests MUST pass after refactoring

**Test Strategy**:

1. **Run existing tests** (must all pass)
   ```bash
   pnpm test
   ```

2. **Add tests if missing**
   - If coverage drops, add tests
   - Maintain level-appropriate coverage

3. **Manual testing** (if no tests exist)
   - Test affected functionality
   - Test edge cases

**Tools**:
```typescript
mcp__vitest__run_tests()
mcp__vitest__check_coverage({ threshold: levelThreshold })
```

**Output**: All tests pass ✅

---

### Step 5: Validate

**Goal**: Verify improvement

**Metrics to Check**:

1. **Code Quality**
   ```typescript
   mcp__rules-validator__validate_code()
   // Should have fewer violations than before
   ```

2. **Architecture**
   ```typescript
   mcp__architecture-guard__check_layer_boundaries()
   // Should pass or have fewer violations
   ```

3. **Type Safety**
   ```typescript
   mcp__typescript__check_types()
   // Should have no errors
   ```

4. **Test Coverage**
   ```typescript
   mcp__vitest__check_coverage()
   // Should maintain or increase
   ```

**Improvement Checklist**:
- ✅ Fewer lines of code (or same)
- ✅ Better function names
- ✅ Smaller functions
- ✅ Less duplication
- ✅ No inline comments
- ✅ Better separation of concerns
- ✅ Maintained or improved test coverage

**Output**: Refactoring validated ✅

---

## Example Usage

### User Request
> "This productRouter file is getting too long and hard to maintain"

### Execution

```bash
# 1. Analyze
mcp__filesystem__read_file({ path: "packages/api/routers/product.ts" })
# Result: 250 lines, logic mixed with API, duplication

mcp__crafted-context__get_architecture_info()
# Result: { level: "balanced" }

# Issues found:
# - Router has 250 lines (should be < 20 for Balanced)
# - Business logic in router (should be in service)
# - Duplication in price calculation (3 places)

# 2. Plan
# Strategy: Extract service layer
# 1. Create productService
# 2. Create productRepository
# 3. Move logic from router to service
# 4. Thin down router to < 20 lines per procedure

# 3. Refactor
# Extract service
export const productService = {
  async create(data: CreateProductInput, userId: string) {
    const priceInCents = convertToCents(data.price);
    const product = await productRepository.create({ ...data, userId, priceInCents });
    await stripeService.createProduct(product);
    return product;
  },

  async list(filters: ProductFilters) {
    return await productRepository.findMany(filters);
  },

  async update(id: string, data: UpdateProductInput) {
    const priceInCents = convertToCents(data.price);
    return await productRepository.update(id, { ...data, priceInCents });
  },
};

# Thin router
export const productRouter = createTRPCRouter({
  create: protectedProcedure
    .input(createProductSchema)
    .mutation(({ ctx, input }) =>
      productService.create(input, ctx.session.user.id)
    ),

  list: publicProcedure
    .input(listProductsSchema)
    .query(({ input }) =>
      productService.list(input)
    ),
});

# 4. Test
pnpm test
# All tests pass ✅

# 5. Validate
mcp__rules-validator__validate_code({ code: "...", level: "balanced" })
# ✅ No violations

# Before: 250 lines in router
# After: 15 lines in router, 80 lines in service, 40 lines in repository
# Improvement: Better separation, easier to test, follows Balanced architecture ✅
```

---

## Refactoring by Level

### Rapid → Balanced
**Goals**:
- Extract services from routers
- Add 70% test coverage
- Reduce function size to < 50 lines
- Limit parameters to 3

**Timeline**: Can be done incrementally

### Balanced → Crafted
**Goals**:
- Extract domain layer (entities, value objects)
- Create use-cases
- 100% domain coverage
- Remove ALL duplication
- Result pattern instead of exceptions

**Timeline**: Requires significant refactoring, plan carefully

### Within Same Level
**Goals**:
- Remove code smells
- Improve naming
- Reduce complexity
- Remove inline comments

**Timeline**: Can be done continuously

---

## Commands

```bash
# Invoke this skill
/refactor

# Or use slash command
/refactor "Extract service layer from productRouter"
```

---

## Tips

1. **Refactor with tests** - Always have tests first
2. **Small steps** - Refactor incrementally
3. **One thing at a time** - Don't mix refactorings
4. **Commit often** - Commit after each successful step
5. **Measure improvement** - Verify metrics improve

---

## Common Pitfalls

❌ **Don't**:
- Refactor without tests
- Change behavior during refactoring
- Mix refactoring with new features
- Refactor for the sake of refactoring

✅ **Do**:
- Run tests after each step
- Keep behavior identical
- Focus on code smells
- Measure improvement
- Follow level-appropriate rules
