スキル一覧に戻る
alexborgognoni

refactor

by alexborgognoni

RentPath is a rental property management platform built for European landlords, property managers, and tenants.

0🍴 0📅 2026年1月23日
GitHubで見るManusで実行

SKILL.md


name: refactor description: Guide service layer extraction from fat controllers. Use when refactoring complex controllers, extracting business logic to services, creating action classes, or improving code organization. Auto-triggers on "refactor", "extract service", "too complex", "clean up controller", "service layer".

Service Layer Refactoring Guide

You are helping refactor RentPath code from fat controllers to a clean service layer architecture.

Arguments

This skill accepts optional arguments to specify what to refactor:

UsageBehavior
/refactorInteractive - ask what to refactor
/refactor ApplicationControllerRefactor that specific controller
/refactor ApplicationController::approveRefactor specific method
/refactor app/Http/Controllers/Analyze all controllers, suggest priorities
/refactor to serviceExtract current context to a service class
/refactor to actionExtract to a single-purpose action class

Argument interpretation:

  • Controller name - Focus on that controller
  • Controller::method - Focus on extracting that specific method
  • Path - Analyze complexity across files in path
  • Target (to service, to action) - Specify extraction pattern

Before You Start

  1. Read the current architecture: docs/architecture/overview.md
  2. Understand the target state: Controllers handle HTTP, Services handle business logic
  3. Check existing patterns: Look for any existing services in app/Services/

Tools to Use

TaskToolCommand/Action
Analyze controllerReadRead the controller file
Find usagesGrepSearch for method calls
Check modelReadRead related model files
Create serviceBashphp artisan make:class Services/[Name]Service
Run testsBashphp artisan test --filter=[Controller]

Extraction Decision Tree

Controller method > 50 lines?
├─ Yes -> Extract to Service
└─ No -> Is logic reused elsewhere?
    ├─ Yes -> Extract to Service
    └─ No -> Does it involve multiple models?
        ├─ Yes -> Extract to Service
        └─ No -> Are there complex business rules?
            ├─ Yes -> Extract to Service
            └─ No -> Keep in Controller (simple CRUD)

Step-by-Step Process

1. Analyze the Controller

# Check file size and complexity
wc -l app/Http/Controllers/[Name]Controller.php

# List all public methods
grep -n "public function" app/Http/Controllers/[Name]Controller.php

Key questions:

  • What are the main responsibilities?
  • Which methods have business logic vs HTTP handling?
  • What models are touched?

2. Identify Service Boundaries

Group related operations:

ApplicationService
├── submit()         # Business logic for submission
├── approve()        # Approval workflow
├── reject()         # Rejection workflow
├── withdraw()       # Withdrawal logic
└── scheduleVisit()  # Visit scheduling

PropertyService
├── publish()        # Publishing workflow
├── createDraft()    # Draft creation
├── updateSpecs()    # Spec updates
└── archive()        # Archival logic

3. Create the Service Class

php artisan make:class Services/ApplicationService --no-interaction

Service structure:

<?php

namespace App\Services;

use App\Models\Application;
use App\Models\TenantProfile;

class ApplicationService
{
    /**
     * Submit an application for review.
     */
    public function submit(Application $application): void
    {
        // Validate business rules
        $this->validateCanSubmit($application);

        // Create profile snapshot
        $this->createSnapshot($application);

        // Update status
        $application->update([
            'status' => 'submitted',
            'submitted_at' => now(),
        ]);

        // Dispatch events (future)
        // ApplicationSubmitted::dispatch($application);
    }

    private function validateCanSubmit(Application $application): void
    {
        if ($application->status !== 'draft') {
            throw new \InvalidArgumentException('Only draft applications can be submitted');
        }
    }

    private function createSnapshot(Application $application): void
    {
        $profile = $application->tenantProfile;

        $application->update([
            'snapshot_first_name' => $profile->user->first_name,
            'snapshot_last_name' => $profile->user->last_name,
            // ... more fields
        ]);
    }
}

4. Refactor the Controller

Before (fat controller):

public function submit(Application $application)
{
    // 50+ lines of business logic...
}

After (thin controller):

public function __construct(
    private ApplicationService $applicationService
) {}

public function submit(Application $application): RedirectResponse
{
    $this->applicationService->submit($application);

    return redirect()
        ->route('applications.show', $application)
        ->with('success', __('Application submitted successfully'));
}

5. Update Tests

// Test the service directly
test('application service submits draft application', function () {
    $application = Application::factory()->draft()->create();
    $service = new ApplicationService();

    $service->submit($application);

    expect($application->fresh()->status)->toBe('submitted');
});

// Test the controller integration
test('submit endpoint uses service', function () {
    $application = Application::factory()->draft()->create();

    $response = $this->actingAs($application->tenantProfile->user)
        ->post("/applications/{$application->id}/submit");

    $response->assertRedirect();
    expect($application->fresh()->status)->toBe('submitted');
});

Priority Refactoring Targets

Based on codebase analysis:

ControllerSizePrioritySuggested Services
ApplicationController115KBHighApplicationService, ApplicationSnapshotService
PropertyController35KBMediumPropertyService, PropertyPublishingService
TenantProfileController30KBMediumTenantProfileService, VerificationService

Action Classes (Single Operations)

For complex single-purpose operations, use Action classes:

php artisan make:class Actions/ApproveApplication --no-interaction
<?php

namespace App\Actions;

use App\Models\Application;

class ApproveApplication
{
    public function execute(Application $application, array $data): void
    {
        $application->update([
            'status' => 'approved',
            'approved_at' => now(),
            'approved_by_user_id' => auth()->id(),
            'approval_notes' => $data['notes'] ?? null,
        ]);
    }
}

Documentation References

  • docs/architecture/overview.md - Current architecture
  • docs/patterns/wizard.md - Wizard-specific patterns
  • docs/modules/applications.md - Application domain logic
  • docs/modules/properties.md - Property domain logic

Checklist

  • Analyzed controller complexity
  • Identified service boundaries
  • Created service class(es)
  • Moved business logic to service
  • Controller only handles HTTP concerns
  • Injected service via constructor
  • Updated/created tests
  • Verified existing tests pass

スコア

総合スコア

65/100

リポジトリの品質指標に基づく評価

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

0/10
説明文

100文字以上の説明がある

+10
人気

GitHub Stars 100以上

0/15
最近の活動

1ヶ月以内に更新

+10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

+5

レビュー

💬

レビュー機能は近日公開予定です