mcpField
L
laravel-systematic-debugging

laravel-systematic-debugging

github.com/iserter開発48102 回インストール27 週間前に更新
リポジトリ

laravel-systematic-debugging について

Laravel 開発者向けのデバッグスキルです。根本原因の調査、パターン分析、仮説の検証、修正の確認という4段階で進めます。

主な機能

  1. 014段階のデバッグ手順
  2. 02根本原因の調査ガイド
  3. 03Laravel ログ、Telescope、Tinker の手法
  4. 04仮説に基づく最小限のテスト
  5. 05テストと修正結果の確認

活用シーン

  1. 01Eloquent クエリの問題調査
  2. 02ルート、キュー、バリデーション障害の診断
  3. 03N+1 クエリなどの性能問題の追跡

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/iserter/laravel-claude-agents --skill laravel-systematic-debugging

インストール後、Claude Code で/laravel-systematic-debuggingを入力して読み込まれたか確認します。

詳細

Laravel の体系的なデバッグ

概要

Laravel アプリケーションでの場当たり的な修正は、時間を浪費し、新たなバグを生みます。応急処置では根本的な問題を覆い隠してしまいます。

基本原則: 修正を試みる前に、必ず根本原因を見つけてください。症状への対処は失敗です。

このプロセスの文言だけでなく精神に反することは、デバッグの精神に反することです。

鉄則

NO FIXES WITHOUT ROOT CAUSE INVESTIGATION FIRST

フェーズ 1 を完了していない場合、修正を提案することはできません。

使用するタイミング

Laravel の技術的な問題には、どのようなものでも使用してください。

  • テストの失敗
  • Eloquent クエリの問題
  • 認証/認可のバグ
  • バリデーションの失敗
  • キュージョブの失敗
  • ルートのエラー
  • マイグレーションの問題
  • N+1 クエリの問題
  • パフォーマンスの問題

特に次のような場合に使用してください。

  • 時間に追われている
  • 「すぐにできる簡単な修正」が明らかに思える
  • すでに複数の修正を試した
  • 前回の修正が機能しなかった
  • 問題を十分に理解していない

4 つのフェーズ

次のフェーズに進む前に、各フェーズを必ず完了してください。

フェーズ 1:根本原因の調査

修正を試みる前に、必ず以下を行ってください。

  1. エラーメッセージを注意深く読む

    SQLSTATE[23000]: Integrity constraint violation
    → Check foreign key constraints, not a code bug
    
    Class 'App\Models\Post' not found
    → Check namespace, run composer dump-autoload
    
    Method Illuminate\Database\Eloquent\Collection::save does not exist
    → get() returns Collection, not Model. Use first() or update()
    
  2. Laravel のログを確認する

    # Main Laravel log
    tail -f storage/logs/laravel.log
    
    # Check for specific errors
    grep "SQLSTATE" storage/logs/laravel.log
    
    # Clear logs if too large
    > storage/logs/laravel.log
    
  3. デバッグモードを有効にする(ローカル環境のみ)

    APP_DEBUG=true
    APP_ENV=local
    
  4. Laravel Telescope を使用する

    composer require laravel/telescope --dev
    php artisan telescope:install
    php artisan migrate
    
    # Access at /telescope
    # View: Requests, Queries, Jobs, Events, Exceptions
    
  5. 最近の変更を確認する

    # What changed that could cause this?
    git log --oneline -10
    git diff HEAD~5
    
    # Check if migrations ran
    php artisan migrate:status
    
    # Check if config cached
    php artisan config:show
    
  6. 一貫して再現できることを確認する

    # Can you trigger it every time?
    php artisan tinker
    >>> App\Models\Post::first();
    
    # Try in different environments
    APP_ENV=testing php artisan test
    
  7. Eloquent の問題ではデータフローを追跡する

    // Enable query logging
    DB::listen(function ($query) {
        Log::debug('Query executed', [
            'sql' => $query->sql,
            'bindings' => $query->bindings,
            'time' => $query->time,
        ]);
    });
    
    // Or in specific code
    DB::enableQueryLog();
    $posts = Post::with('user')->get();
    dd(DB::getQueryLog());
    
フェーズ 2:パターンの分析

修正する前にパターンを見つけてください。

  1. Laravel にある正常に動作する例を見つける

    # Search for similar working code
    grep -r "belongsTo" app/Models/
    grep -r "middleware" app/Http/
    
    # Check Laravel docs for the pattern
    # Check other models that work correctly
    
  2. Laravel の規約と照らし合わせる

    // ❌ What you have
    class Post extends Model {
        public function author() {
            return $this->hasOne(User::class, 'id', 'user_id');
        }
    }
    
    // ✅ Laravel convention
    class Post extends Model {
        public function user(): BelongsTo {
            return $this->belongsTo(User::class);
        }
    }
    
  3. Laravel のドキュメントを確認する

    • 該当するセクションを斜め読みせず、最後まで読む
    • まずは例に正確に従う
    • 理解した後でのみカスタマイズする
  4. 違いを特定する

    // Working model
    class User extends Model {
        protected $fillable = ['name', 'email'];
    }
    
    // Broken model - difference: missing mass assignment protection
    class Post extends Model {
        // No $fillable or $guarded defined
    }
    
フェーズ 3:仮説とテスト

科学的手法に従ってください。

  1. 仮説を 1 つ立てる

    Hypothesis: "Posts aren't saving because mass assignment 
    protection is blocking the 'user_id' field"
    
    Expected: Adding 'user_id' to $fillable will fix it
    
  2. 最小限のテストを行う

    // Before (broken)
    protected $fillable = ['title', 'content'];
    
    // Test change (ONE variable)
    protected $fillable = ['title', 'content', 'user_id'];
    
    // Don't change multiple things at once
    
  3. Tinker で検証する

    php artisan tinker
    >>> $post = Post::create(['title' => 'Test', 'content' => 'Test', 'user_id' => 1]);
    >>> $post->user_id; // Should be 1
    
  4. 分からない場合

    • 「なぜ X が起きているのか分かりません」と伝える
    • 同様の問題について Laravel の GitHub の課題を確認する
    • 詳細を添えて Laravel の Discord/フォーラムで質問する
    • 分かったふりをしない
フェーズ 4:実装

症状ではなく、根本原因を修正してください。

  1. 失敗するテストケースを作成する

    use Illuminate\Foundation\Testing\RefreshDatabase;
    
    test('user can create post', function () {
        $user = User::factory()->create();
        
        $response = $this->actingAs($user)
            ->post('/posts', [
                'title' => 'Test Post',
                'content' => 'Test content',
            ]);
        
        $response->assertRedirect();
        
        expect(Post::where('title', 'Test Post')->exists())->toBeTrue();
        expect(Post::first()->user_id)->toBe($user->id);
    });
    
    // Run and watch it FAIL first
    php artisan test --filter=user_can_create_post
    
  2. 修正を 1 つ実装する

    // ONE fix for the root cause
    protected $fillable = ['title', 'content', 'user_id'];
    
    // NO bundled improvements like:
    // - Adding casts
    // - Refactoring methods
    // - Changing other code
    
  3. 修正を検証する

    # Test passes now
    php artisan test --filter=user_can_create_post
    
    # All tests still pass
    php artisan test
    
    # Manual verification
    php artisan tinker
    >>> $post = Post::create([...]);
    
  4. 修正が機能しない場合

    • 停止する
    • これまでに何回修正を試したか数える
    • 3 回未満の場合:新しい情報をもとにフェーズ 1 に戻る
    • 3 回以上の場合:停止して、アプローチを見直す
  5. 3 回以上の修正に失敗した場合:アーキテクチャを見直す

    Pattern indicating architectural problem:
    - Each fix reveals new shared state/coupling
    - Fixes require "massive refactoring"
    - Each fix creates new symptoms elsewhere
    
    STOP and question fundamentals:
    - Is this Laravel pattern correct?
    - Should we use a different approach (repository/service)?
    - Are we fighting the framework?
    
    Discuss with team before attempting more fixes.
    

Laravel 固有のデバッグ手法

Eloquent のデバッグ
// See actual SQL
$posts = Post::where('status', 'published');
dd($posts->toSql(), $posts->getBindings());

// Check relationship loading
$post = Post::first();
$post->relationLoaded('user'); // false
$post->load('user');
$post->relationLoaded('user'); // true

// Prevent lazy loading (catch N+1)
Model::preventLazyLoading(!app()->isProduction());
ルートのデバッグ
# List all routes
php artisan route:list

# Find specific route
php artisan route:list --name=posts

# Check route exists
php artisan tinker
>>> route('posts.show', 1);
キューのデバッグ
# See failed jobs
php artisan queue:failed

# Retry failed job
php artisan queue:retry <id>

# Work queue with verbose output
php artisan queue:work --verbose

# Check job payload
php artisan tinker
>>> DB::table('jobs')->first();
バリデーションのデバッグ
// See exact validation errors
protected function failedValidation(Validator $validator)
{
    Log::debug('Validation failed', [
        'errors' => $validator->errors()->toArray(),
        'input' => $this->all(),
    ]);
    
    parent::failedValidation($validator);
}

危険信号 — 停止して手順に従ってください

次のように考えていることに気づいたら:

  • 「とりあえず応急処置をして、後で調査しよう」
  • 「X を変更して、動くか試してみよう」
  • 「効果があるか確認するために protected $guarded = [] を追加しよう」
  • 「テストを省略して、手動で確認しよう」
  • 「おそらくリレーションの定義が原因だろう」
  • 「Eloquent を十分に理解していないけれど、これで動くかもしれない」
  • 「ドキュメントには X と書いてあるけれど、違う方法で応用しよう」
  • 「もう 1 回だけ修正を試そう」(すでに 2 回以上試している場合)

これらはすべて、停止してフェーズ 1 に戻るべきサインです。

Laravel のよくあるデバッグシナリオ

シナリオ 1:N+1 クエリの問題
Phase 1: Detect it
- Enable Model::preventLazyLoading()
- Exception thrown showing the problem

Phase 2: Find the pattern
- Check working code that uses with()
- Identify which relationship is lazy loading

Phase 3: Hypothesis
- "Adding with('user') will prevent the N+1"

Phase 4: Fix
- Add test that counts queries
- Add with('user') to the query
- Verify query count reduced
シナリオ 2:ルートモデルバインディングが機能しない
Phase 1: Investigate
- Check route definition: /posts/{post}
- Check controller parameter: Post $post
- Check if using custom key

Phase 2: Pattern
- Compare with working route binding
- Check Post model for getRouteKeyName()

Phase 3: Hypothesis
- "Parameter name doesn't match or model not found"

Phase 4: Fix
- Ensure route parameter matches method parameter
- Or customize: public function getRouteKeyName() { return 'slug'; }
シナリオ 3:一括代入の例外
Phase 1: Error says "Add [field] to fillable property"
Phase 2: Check other models' $fillable arrays
Phase 3: Hypothesis: "Field not in $fillable"
Phase 4: Add field to $fillable, test

Laravel エージェントとの連携

  • Laravel 固有のデバッグ支援には laravel-debugger を使用する
  • 失敗するテストの作成(フェーズ 4)には laravel-testing-expert を使用する
  • リレーションのデバッグには eloquent-specialist を使用する
  • パフォーマンスの問題には laravel-performance-optimizer を使用する

クイックリファレンス

フェーズLaravel 固有の作業成功基準
1. 根本原因ログ、Telescope、Tinker、最近の変更を確認する問題の内容と原因を理解する
2. パターン動作する Laravel の例を探し、ドキュメントを確認する違いを特定する
3. 仮説仮説を立て、Tinker でテストする仮説を確認するか、新しい仮説を立てる
4. 実装Pest テストを作成し、修正して検証するバグが解決し、テストが成功する

忘れないでください

  • Laravel のエラーメッセージは非常に優れているため、最後まで読みましょう
  • 包括的なデバッグには Telescope を使いましょう
  • 仮説の検証には Tinker が役立ちます
  • Laravel の規約に従いましょう。フレームワークに逆らうとバグの原因になります
  • 「Laravel の奇妙な動作」の 95% は、フレームワークへの理解不足が原因です

常に体系的に調査して根本原因を把握し、正しい方法で一度で修正しましょう。

コメント