Review

/laravel-agent:refactor

Analyze and refactor code for SOLID/DRY compliance

Overview

The /refactor command invokes the laravel-refactor agent to analyze your code and improve quality by applying SOLID principles (Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation, Dependency Inversion) and DRY (Don't Repeat Yourself) best practices. It detects code smells, proposes fixes, implements improvements incrementally, and verifies all tests pass.

Usage

/laravel-agent:refactor [target]

Parameters

  • target - File path, class name, or directory to refactor

Examples

# Refactor a specific controller
/laravel-agent:refactor app/Http/Controllers/OrderController.php

# Refactor by class name
/laravel-agent:refactor OrderService

# Refactor an entire directory
/laravel-agent:refactor app/Services/

What Gets Analyzed

The refactor agent examines your code for common quality issues:

Code Smell SOLID/DRY Principle Refactoring Applied
Long methods (>20 lines) Single Responsibility Extract smaller methods
God classes (>300 lines) Single Responsibility Split into focused classes
Duplicate code blocks DRY (Don't Repeat Yourself) Extract reusable methods/traits
Tight coupling Dependency Inversion Inject interfaces, use dependency injection
Complex conditionals Open/Closed Strategy pattern or polymorphism
Multiple responsibilities Single Responsibility Separate concerns into services
Feature envy Single Responsibility Move method to appropriate class
Primitive obsession Interface Segregation Create value objects or DTOs

Refactoring Process

The agent follows a systematic approach to ensure safe, incremental improvements:

  1. Analysis - Scan target code for SOLID/DRY violations and code smells
  2. Proposal - Present identified issues with suggested fixes
  3. Implementation - Apply refactorings incrementally, one improvement at a time
  4. Verification - Run tests after each change to ensure functionality is preserved
  5. Report - Summarize improvements with before/after metrics

Example Before & After

Before refactoring - controller with multiple responsibilities:

<?php

namespace App\Http\Controllers;

use App\Models\Order;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;
use App\Mail\OrderConfirmation;

class OrderController extends Controller
{
    public function store(Request $request)
    {
        // Validation mixed with business logic
        $validated = $request->validate([
            'customer_email' => 'required|email',
            'items' => 'required|array',
            'items.*.product_id' => 'required|exists:products,id',
            'items.*.quantity' => 'required|integer|min:1',
        ]);

        // Calculate total inline
        $total = 0;
        foreach ($validated['items'] as $item) {
            $product = Product::find($item['product_id']);
            $total += $product->price * $item['quantity'];
        }

        // Create order
        $order = Order::create([
            'customer_email' => $validated['customer_email'],
            'total' => $total,
            'status' => 'pending',
        ]);

        // Create order items inline
        foreach ($validated['items'] as $item) {
            $order->items()->create([
                'product_id' => $item['product_id'],
                'quantity' => $item['quantity'],
            ]);
        }

        // Send email directly in controller
        Mail::to($order->customer_email)->send(new OrderConfirmation($order));

        return response()->json($order, 201);
    }
}

After refactoring - separated concerns with dependency injection:

<?php

namespace App\Http\Controllers;

use App\Http\Requests\StoreOrderRequest;
use App\Http\Resources\OrderResource;
use App\Services\OrderService;

class OrderController extends Controller
{
    public function __construct(
        private OrderService $orderService
    ) {}

    public function store(StoreOrderRequest $request)
    {
        $order = $this->orderService->createOrder(
            $request->validated()
        );

        return new OrderResource($order);
    }
}

// app/Http/Requests/StoreOrderRequest.php
class StoreOrderRequest extends FormRequest
{
    public function rules(): array
    {
        return [
            'customer_email' => 'required|email',
            'items' => 'required|array',
            'items.*.product_id' => 'required|exists:products,id',
            'items.*.quantity' => 'required|integer|min:1',
        ];
    }
}

// app/Services/OrderService.php
class OrderService
{
    public function __construct(
        private OrderCalculator $calculator,
        private OrderNotifier $notifier
    ) {}

    public function createOrder(array $data): Order
    {
        $total = $this->calculator->calculateTotal($data['items']);

        $order = Order::create([
            'customer_email' => $data['customer_email'],
            'total' => $total,
            'status' => 'pending',
        ]);

        $this->createOrderItems($order, $data['items']);
        $this->notifier->sendConfirmation($order);

        return $order->fresh('items');
    }

    private function createOrderItems(Order $order, array $items): void
    {
        foreach ($items as $item) {
            $order->items()->create([
                'product_id' => $item['product_id'],
                'quantity' => $item['quantity'],
            ]);
        }
    }
}

Output Report Format

After refactoring completes, you'll receive a detailed summary:

## Refactoring Complete: OrderController

### Issues Fixed
| Issue | Fix Applied |
|-------|-------------|
| God class (150 lines) | Extracted OrderService, OrderCalculator, OrderNotifier |
| Multiple responsibilities | Separated validation, business logic, notifications |
| Tight coupling to Mail facade | Injected OrderNotifier dependency |
| Inline calculations | Extracted OrderCalculator service |

### Improvements
- Lines: 150 → 45 (70% reduction)
- Methods: 8 → 2 (focused on HTTP concerns)
- Cyclomatic complexity: 12 → 4
- Test coverage: 65% → 92%

### Tests: All passing ✓
- 24 tests, 89 assertions
- 0 failures, 0 errors

Focus Areas

The agent can focus on specific refactoring concerns by including hints in your command:

  • general (default) - All SOLID/DRY principles
  • extract methods - Break down long methods
  • reduce coupling - Add dependency injection
  • remove duplication - DRY principle focus
  • split classes - Single Responsibility focus

Best Practices

  1. Commit before refactoring - Ensure you can rollback if needed
  2. Have tests in place - Refactoring requires test coverage to verify behavior
  3. Refactor incrementally - The agent applies one change at a time for safety
  4. Review proposed changes - Understand each improvement before applying
  5. Run full test suite - Verify all tests pass after refactoring

When to Refactor

Consider refactoring when you notice:

  • Controllers exceeding 100 lines or methods exceeding 20 lines
  • Copy-pasted code blocks across multiple files
  • Difficulty adding new features without modifying existing code
  • Hard-to-test code due to tight coupling
  • Classes doing too many unrelated things
  • Complex nested conditionals or switch statements

Related Agent

This command uses the laravel-refactor agent with access to Task, Read, Glob, Grep, Bash, Write, Edit, and MultiEdit tools.

See Also