Architecting Large-Scale Systems with Laravel 12

2026年05月15日

Laravel 12を用いた大規模システム開発において、コードの肥大化を防ぎ保守性を高めるための具体的な戦略を解説しています。標準的な構成に依存せず、ドメイン駆動設計の視点を取り入れたディレクトリ構成や、ビジネスロジックを独立させるActionパターンの導入を強く推奨しています。また、データベースのクエリ最適化や非同期処理の徹底、APIリソースの活用といった技術的な規約の重要性についても詳しく述べています。最終的には、単にコードを書くのではなく、将来の変更コストを抑える設計こそが大規模開発の成功の鍵であると説いています。さらに、現代的な開発手法としてAIを活用したドキュメント駆動開発との親和性についても触れています。

AI駆動開発とLaravelの規約をどのように組み合わせればよいですか?

AI駆動開発とLaravelの規約を組み合わせることで、AIのコード生成能力を最大限に引き出し、大規模システムでも変更容易性を保つ強力な開発体制を構築することができます。

ソースによると、Laravelは規約が強く、構造が読みやすいうえに、CRUDが定型化されており、Request/Resourceが明確でmigrationベースであるため、そもそもAI生成と非常に相性が良いフレームワークです。

この強みを活かすために、以下のように規約とAI駆動開発を組み合わせるのが効果的です。

1. Action / UseCase パターンの徹底 大規模開発では、ControllerやModelを肥大化させないために「Action / UseCase パターン」を採用し、機能単位でディレクトリを分割することが推奨されています。 業務ロジックをActionクラス(例: CreateOrderAction)に切り出すことで、責務が明確になり、Issue単位に分割しやすくなります。これにより、AIによるコード生成がしやすくなるだけでなく、RAG(検索拡張生成)との相性も抜群に良くなります

2. 役割の明確化とAIへの指示の定型化 AIに正確なコードを生成させるためには、「どこに何を書くか」というルール(開発規約)を最初に決めておくことが重要です。

  • Controller: SQLや業務ルール、if文の地獄を作らず、Actionを呼び出すだけの「薄い」状態を保つ。
  • Model: Active Recordと割り切り、RelationやScopeなどの軽量なロジックのみに留め、重い業務処理は書かない。
  • APIレスポンス: return response()->json() を乱発せず、必ずAPI Resource (UserResource::make($user) など) に統一して将来の崩壊を防ぐ。 このような明確な境界と規約を設けることで、AIに対して「この仕様のActionクラスを作成して」「このRequestクラスでバリデーションを定義して」といった的確なプロンプトが出しやすくなります。

3. ドキュメント駆動・Issue駆動(AI Native Document Driven Development) Laravelの定型化された構造を活かし、「Issue駆動」や「ドキュメント駆動」で開発を進めるアプローチが非常に効果的です。 仕様や規約をドキュメントとして整備し(ドキュメント同期)、それをもとにIssueを発行してAIに生成を補助させる「AI Native Document Driven Development」は、Laravelの特性と深くマッチします。

まとめ 「Laravel12(API/業務基盤)」「Actionベース」「Issue駆動」「AI補助生成」「ドキュメント同期」を組み合わせた構成は、非常に強力な開発手法となります。AIを単なるコーディング支援として使うのではなく、「アーキテクチャやルールを明確に定義し、それに沿った部品(ActionやResourceなど)をIssue単位でAIに生成させる」という形で規約と組み合わせるのが最適です。

大規模開発で肥大化を防ぐための具体的なディレクトリ構成案を教えて

ソースで提案されている具体的なディレクトリ構成案は以下の通りです。

app/
 ├── Domains/           # 業務(ドメイン)領域
 │    ├── Order/
 │    ├── User/
 │    ├── Product/
 │    └── Payment/
 │
 ├── Applications/      # ユースケース(Actionクラスなど)
 │    ├── Orders/       # 例: CreateOrderAction.php など
 │    ├── Users/
 │    └── Payments/
 │
 ├── Infrastructure/    # DBや外部API通信などのインフラ領域
 │    ├── Repositories/
 │    ├── External/
 │    └── Services/
 │
 ├── Http/              # プレゼンテーション領域(Controller等)
 │    ├── Controllers/
 │    └── Requests/
 │
 └── Support/           # 共通処理やヘルパーなど

なぜこの構成が肥大化を防ぐのか?

  1. 機能単位での管理が可能になる DomainsApplications の下を「Order(注文)」「User(ユーザー)」といった機能(ドメイン)ごとに分割することで、関連するコードがどこにあるかが一目でわかり、開発メンバー全体がシステムを把握しやすくなります。
  2. Controllerの肥大化を防ぐ(薄いControllerの実現) Http/Controllers/ 内のControllerにはSQLや業務ルール、if文の地獄などを書かず、Applications/ ディレクトリに定義したActionクラス(例: CreateOrderAction)を呼び出すだけの役割に留めることができます。
  3. Modelの肥大化を防ぐ 重い業務ロジックをModelに記述するのではなく、機能ごとのActionクラス(Applications)に切り出すことで、Modelはリレーションやスコープなどの軽量なロジックのみを持つ「Active Record」として保つことができます。
  4. 責務の明確化とAIとの相性の向上 各ディレクトリの役割(アーキテクチャやモジュール境界)が明確になるため、テストがしやすくなるだけでなく、Issue単位でタスクを分割しやすくなります。これは、AIに対して特定のActionの生成を依頼するような「AI駆動開発(AI補助生成)」とも非常に相性が良い構成です。

ControllerやModelの責務をどう分離するのが最も効果的ですか?

ControllerとModelの肥大化を防ぎ、責務を効果的に分離するためには、「Action / UseCase パターン」を導入して業務ロジックを独立させるアプローチが最も効果的です。

ソースによると、大規模なLaravel開発では以下のルールを徹底してそれぞれの責務を分割することが推奨されています。

1. Controllerの責務:極限まで「薄く」保つ Controllerには、以下のような処理を書いてはいけません。

  • SQLの直書き
  • 業務ルールや複雑な条件分岐(if地獄)
  • 外部APIの呼び出し
  • トランザクション制御やメール処理

理想的なControllerは、Requestクラスによってバリデーションされた安全なデータを受け取り、後述するActionクラスを呼び出して、その結果を返すだけのシンプルな構造であるべきです。

2. Modelの責務:軽量な「Active Record」に徹する 大規模システムで一番破綻しやすいのがModelの肥大化です。そのため、Model内に重い業務処理(例:User::doSomethingComplicated() のような複雑なメソッド)を持たせることは避ける必要があります。 Modelに記述すべきなのは、以下のようなデータベースやデータ構造に直結する軽量なロジックのみに限定します。

  • リレーション(Relation)の定義
  • クエリスコープ(Scope)
  • 属性(Attribute)の設定
  • その他、データそのものに関する軽量なロジック

3. 業務ロジックの分離先:Actionクラスへの切り出し ControllerやModelから排除された「重い業務ロジック」の受け皿となるのがActionクラスです。 例えば、「注文を作成する」という機能であれば、専用の CreateOrderAction クラスを作成し、その中にトランザクションや関連する処理をカプセル化します。

この構成にすることで、以下のような大きなメリットが得られます。

  • どこに何が書かれているかという責務が明確になる
  • クラスが単一の機能を持つためテストしやすい
  • 機能(Issue)単位で分割しやすいため、AIにコードを生成させる際のプロンプトが書きやすくなる

まとめ Controllerは「入出力の制御」のみ、Modelは「データの定義と取得」のみに専念させ、実際のシステムの中核となる業務ルールは「Actionクラス」に分離して処理させるのが最適です。これにより、コードの散乱や肥大化を防ぎ、長期的な「変更容易性」を保つことができます。