メシのタネ

めしのたねになるIT情報配信サイト


Laravelのアーキテクチャ、実は誰もわかってない説


  1. Laravel
  2. Laravelのアーキテクチャ、実は誰もわかってない説

~サービス層・リポジトリ・DDDを問い続ける開発者たちへ~

はじめに

読んだ後に、「あれ、自分のサービスクラスって何者だっけ?」「DDDって実は影しか見てなかったかも?」とモヤモヤしつつも、明日からの開発がほんの少しだけ楽しくなる——そんな記事を目指しています。

「サービス層? リポジトリ? DDD? それ、ちゃんと機能してる?」

Laravelで開発を進めていくと、ある時ふとこんな疑問が浮かぶかもしれません。
コントローラが肥大化してきたからサービス層を作り、Eloquentが便利だけどテストしにくいからリポジトリを入れ、DDDという概念がカッコよさそうだから用語を借りてみる——でも、気づいたら「なんか全部中途半端」になっている。

実はこの状態、「アーキテクチャごっこ」が始まっているサインかもしれません。本記事では、そんな「Laravelの設計は、実はみんな本当にわかってるの?」という問いを立てながら、サービス層・リポジトリ・DDDの話を、ちょっとだけ哲学的な角度で眺めてみたいと思います。
さらに、チーム開発やコミュニケーションという観点から、設計は孤独か、それとも対話なのかという一歩踏み込んだ話題まで掘り下げます。

目次

Laravelのサービス層、実は誰もわかってない説

Fat Service、第二のController問題

コントローラが太るからサービス層を作ろう」。Laravelで開発していると、よくこんな会話を耳にします。確かに、コントローラが膨らみすぎるとテストしづらいし、複数の責務を抱えてスパゲッティ化しがち。そこで「じゃあServiceクラスに分けよう!」となるのは自然な発想です。

しかし、いざサービス層を導入した結果、なぜかFat Serviceが誕生し、Controllerの責務がそっくり移動しただけになるケースを見たことがあります。

public function store(Request $request)
{
    return $this->userService->createUser($request->all());
}

// Serviceクラス
class UserService
{
    public function createUser(array $data)
    {
        // 結局やっていることは Eloquentの create() 呼び出しだけ
        return User::create($data);
    }
}

「あの……これ、Controllerと何が違うの?」
そう突っ込みたくなるコードが実に多いのです。意図としては「ビジネスロジックをサービス層に分離したい」のに、実際は「コントローラのやってたことをServiceクラスに丸ごと移植」しているだけ。

なぜ「サービス層」を誤用しやすいのか?

  • 目的が曖昧
    「とにかくFat Controllerを避けたい」だけで、サービス層を設ける本来の目的(ビジネスロジックの集約やテスト容易性の確保)が共有されていない。
  • 習慣的な命名
    「Controllerじゃない場所に書くからServiceと名付けておこう」という程度の発想。名前は変わったが、役割はあまり変わらない。
  • “わかったフリ”
    「みんなサービス層作ってるし、やっとけばアーキテクチャっぽいよね?」という空気。

ハイデガーの「壊れた道具」と手元性

ここで哲学的視点を入れてみましょう。ハイデガーは有名な手元性(ready-to-hand)という概念を提唱しています。

  • 普段はハンマーを当たり前に使っており、それを意識することはほとんどない。
  • しかし、そのハンマーが壊れたり使えなくなった瞬間、初めて「これは何のためにある道具なのか?」を意識する。

これをソフトウェア設計に当てはめると、「サービス層」という道具を、みんなが漠然と使っているけれど、いざ「これ何のため?」と問われたときに答えられなくなるケースがしばしば。

  • レビューで「これってコントローラとどう違うの?」と指摘される
  • 大規模リファクタのとき、サービスの目的がわからず削除できない
  • テストを書こうとしたら、サービス層が結局Eloquent呼び出しの薄いラッパでしかなく、意味を感じなくなる

壊れた道具として意識されるその瞬間に、「あれ、このサービス層って何のためにあるんだっけ?」と、存在理由が突如問題化するのです。

まとめ: サービス層を導入したいなら、“どんなビジネスロジックをまとめ、何をテスト対象にするのか”をはっきりさせること。
「Fat Controller回避」は目的ではなく、副次的な結果
にすぎません。

ハンマーはいつ壊れる? — 道具論とコードレビュー

「道具が壊れて初めて、その本質に気づく」

コードレビューはしばしば「道具の破損」を顕在化させる場です。ふだん何気なく「Service」「Repository」と呼んでいるクラスが、
「え、それって本当にService? ただのラッパじゃない?」
と突っ込まれた瞬間、「壊れた道具」としての姿をさらけ出します。

問い: あなたのプロジェクトにある「サービス層」や「設計パターン」は、なぜそこにあるのでしょうか? もし答えが曖昧なら、その道具は実は壊れているのかもしれません。

リポジトリ、それって責任転嫁では?

EloquentとRepositoryが重複しがちな理由

続いて、Laravel界隈でよく議論になるRepositoryパターン
EloquentでActiveRecordをしているだけなのに、あえてRepositoryをかます意味があるのか?
といった声はよく聞かれます。

  • メリットとして語られること
    • データアクセスを抽象化できる
    • テスト時にモックしやすい
    • 複数のデータソースを扱う場合に有利
  • しかし、実情
    • ほとんどのプロジェクトはEloquentのみを利用
    • リポジトリクラスでModel::create()Model::find()を呼ぶだけ
    • 「これ…Eloquentを2回呼んでるだけじゃ?」という謎構造

要は「リポジトリを作る理由」が曖昧になりがち。気づくと、「作ったけどなんだか冗長」ということになるのです。

たねまる

Repositoryでドメイン変換を行ったり、Exceptionを投げ分けていたり、境界を明示にする役割があるRepositoryなら必要なのかな〜。

サルトルの「自由と責任」:選択の重み

哲学的に見ると、ここで参考になるのがサルトルの実存主義です。サルトルは有名なフレーズを残しています。

「人間は自由の刑に処されている」

要するに、「自由だからこそ、自分が下した選択に責任を負わなければならない」 ということ。
ソフトウェア開発も同様に、「この設計を採用する・しない」という自由を常に持っています。しかし、その選択があとでチームを苦しめたりメンテナンスコストを増やしたりしたら、「いや、あのとき導入しようと言ったのはあなたでしょ?」という責任問題が生じるわけです。

  • 「リポジトリを入れる」と決めたのはあなた。
  • そのせいでコードが2倍に増え、後任者が「これ何のため?」と混乱したら、あなたの責任。

パターンの導入は、ただの技術的メリットだけでなく、選択と責任という重い概念をはらんでいる。これが、サルトル的な視点で見る「設計パターン導入の自由と刑罰」と言えます。

まとめ: リポジトリを入れるなら、「Eloquent以外の何かを扱う予定」や「Mock化したテストが明確に必要」など、ハッキリした導入理由を定義しましょう。
「なんとなくみんなやってるから」は、最も危険な自由の行使です。

自由と選択の重さ — リポジトリを導入したのは誰?

「実存は本質に先立つ」 — サルトル

設計の本質(「正しさ」「美しさ」)が先にあるのではなく、まず「選択」という実践が先立ちます。あなたが「リポジトリを導入する」と決めたなら、そこからどう使い、どうメンテし、どう成果を出すかが後から意味づけされる。

問い: 「今このプロジェクトでは、なぜリポジトリが必要なのか?」
その答えを持てないのに導入するなら、それは単なる責任転嫁の道具に終わるかもしれません。

たねまる

あぁ…だから冗長な処理を抽象化したい!と気軽に提案をした時にプレッシャーを感じたんだね…

DDD、それはLaravelにとってイデアか幻か

DDD(ドメイン駆動設計)の理想と現実

DDDを取り入れてみよう!」と言うと、一気に設計が高尚に見える不思議な現象があります。

  • Application ServiceDomain ServiceRepository InterfaceEntityValue Object……
  • 用語だけを見ると、極めてスマートで体系的に感じる。

しかし、実際のLaravelプロジェクトに落とし込むと、「どこからどこまでがEntity?」「Eloquent Modelはどこに置くの?」 など、混乱が生まれがち。
さらに、開発スピードやチーム体制を優先すると、結局「名前だけDDD」のようになってしまうケースも珍しくありません。

プラトンのイデア論:完璧な形は洞窟の外?

ここでプラトンのイデア論を思い出しましょう。プラトンは「現実世界で見えているものは、本当の理想(イデア)の影にすぎない」と言いました。

  • DDDという「完璧なアーキテクチャ上のイデア」がある。
  • Laravelの現場は、複雑な要件・既存モデル・納期などによって、そのイデアをとしてしか再現できない。
  • 結果として、「DDDの洞窟の中で、影を見てイデアだと思い込んでいる」状態になる。

たとえば、DDDの書籍には「ドメインサービスはドメイン固有のビジネスルールを扱う」とある。しかしLaravelプロジェクトでは、DomainServiceと書かれたクラスにEloquent操作がべったり、なんて例がよくある。
本来のイデアからは大きくかけ離れているのに、名前だけ借りて「これはドメインサービスです!」と主張するわけですね。

それでも学ぶ価値はある

ただし、「現実がイデアに届かないからやめよう」という話ではありません。DDDが示す「ドメインを中心に考え、ユースケースやエンティティを明確化する」手法は、Laravelでも役立つ場面が多い。
「理想は理想、現実は現実」と割り切りつつ、それでもDDDがもたらす概念(ユースケース志向や明確な境界づけ)は、プロジェクトを整理する大きな手がかりになります。

まとめ: DDDはプラトンのイデアのような理想型かもしれません。Laravelの実装はどうしてもになりがちですが、影なりに学べることは多い。大事なのは、「名前だけDDD」にならないように、自分のコードとイデアの差異を意識しておくことです。

Laravelの影とDDDのイデア — 洞窟の比喩に学ぶ

「洞窟の中で影を見て、それを真実だと思い込んでいる」 — プラトン

あなたが見ている「DDD的なレイヤー分け」は、本当にイデアの姿なのでしょうか? もしかすると、Laravelという洞窟の中でうっすら映る“影”にすぎないのかもしれません。

問い: 「このクラスは本当にDomain Serviceなのか、それとも名前だけか?」
影とイデアを見極めるのは、あなたの目と意志次第です。

DDDは「複雑さを飼い慣らす手法」

DDDの目的

  • 複雑なビジネスルールをドメインモデルにまとめ、ユビキタス言語(共通言語)を使って開発者とステークホルダー間のギャップを減らす。
  • モデルやアーキテクチャを分割・整理することで、開発・保守をしやすくする。
  • つまり「何でもかんでも複雑にする」のではなく、既存の複雑性を正しく扱うための道具箱。

DDDが有効に機能する条件

1. ドメイン(ビジネス上の課題)が複雑であること

  • DDDは「ビジネスルールや概念が絡み合う大規模/複雑ドメイン」でその真価を発揮。
  • シンプルなCRUD主体のアプリだとDDDのコストに見合わない。

2. チーム全体でのコンセンサス

  • DDDは全員がドメインモデルやユビキタス言語に対して同じ理解を持ち、同じ意図でクラス分割・命名をする必要がある。
  • 一部の人が「DDDやるぞ!」と言っても他が理解していないと、命名や分割だけが増えて実質的効果が薄い。
  • 障壁の無い議論が活発になることが、組織文化によって軋轢になり得る。
    • 集約の名前を決めるのに1時間以上かかることもある。

3. 時間と学習コストの確保

  • DDD本来のメリット(変更に強い、保守性向上、スケーラビリティ)は、しっかりしたモデル設計やリファクタリング習慣が前提にある。
  • 納期優先の案件であったり、保守が前提でない案件に導入するのは中途半端になるので危険。
たねまる

どんな開発にもフィットする「ぎんのだんがん」みたいなのがあればいいのにね〜

「コードに責任を持つ」とはどういうことか

設計は誰のため? とりあえず動けばいい?

これまで見てきたように、サービス層やリポジトリ、DDDをどれだけ取り入れても、「意味」が伴わなければ形骸化してしまいます。
ここで重要なのは、「自分の書くコードの責任をどう捉えているか」という姿勢。Laravelはとにかく開発がしやすいフレームワークです。しかし、容易さの一方で、思考停止のまま動くコードだけを書くという落とし穴もある。

  • 「この設計は誰が保守する? 自分だけか? チームか?」
  • 「将来的にドメインが拡張される可能性は?」
  • 「スケールさせる時に、このレイヤー分けは有効に働くのか?」

こうした問いを常に忘れたまま進めると、結果としてプロジェクトが進んでから「何だこのコード……?」と途方に暮れる未来が待っています。

ハイデガーの現存在(Dasein)と「問いかけ」

ハイデガーは「人間は自分の存在を問いかけることができる唯一の存在」だと説きました。これをソフトウェア設計に当てはめると、「開発者だけがコードを問い直すことができる」と言えます。フレームワークやデザインパターンが、勝手に設計を正してくれるわけではありません。

  • 問い続ける姿勢: 「今のサービスクラス、本当にビジネスロジックを集約してる?」
  • 他責ではなく自責で: 「なぜリポジトリを入れたのか? 自分のチームは理解できているのか?」
  • 変更を受け止める覚悟: 「DDDの用語を導入したけど、実際にはユースケースが肥大化している。修正しようか?」

人間(開発者)は考えることができるからこそ、責任あるアーキテクチャを構築できる。思考停止した瞬間に設計は死に、ただのファイル分割運動になってしまうのです。

まとめ: 「とりあえず動くからOK」ではなく、自分の選択に責任を持ち、常に問い続ける”ことが設計を生かします。

設計は孤独か、対話か?

チームで設計を議論できているか?

もう一つ忘れてはいけないのが、チーム開発という視点。個人開発なら、自分が納得できればそれで済むかもしれません。しかし、多くのLaravelプロジェクトはチームで進めるもの。そこには必ず「他者」が存在します。

  • 「あの人が作ったService、よくわからないから触りたくない」
  • 「リポジトリを導入したの誰? 書き方バラバラだよ……」
  • 「DDDって言ってたけど、結局みんな勝手に書いてる」

こんな悲しい会話が起きる背景には、設計段階でのコミュニケーション不足が大きい。

ガダマーの「対話的理解」:コードはコミュニケーション

哲学者ガダマーは「理解とは対話のプロセスである」と説きました。つまり、他者と対話する中で初めて、新たな理解が生まれるという考え方です。
これをソフトウェア設計に照らし合わせると、「設計とは、自分一人で完結するものではなく、常にチームや他の開発者との対話を通じて進化する行為」と捉えられます。

  • コードレビューで意図を説明しあう
  • 設計の段階でホワイトボードに図を描き、何をサービス層に置き、何をドメインサービスと呼ぶか、全員で議論する
  • 「自分しか理解できないアーキテクチャ」は優れた設計とは言えない

他者との対話が設計を洗練する

もしあなたのプロジェクトで「自分だけがServiceやリポジトリの意味をわかっていて、他のメンバーは形だけ合わせている」状態なら要注意。
チーム全員がこのレイヤーは何を期待され、どんな責務を負うかを共有し合い、場合によっては疑問をぶつけ合うことで、初めて意味のあるアーキテクチャが育ちます。

まとめ: 設計は孤独な思索ではなく、チーム内の対話・共有・フィードバックを通じて成熟するもの。ガダマー的にいえば、コードは他者へのメッセージでもあるのです。

コードは他者への手紙 — ガダマーと対話的理解

設計とは読む人への手紙とも言えるかもしれません。
「自分しか読めない手紙」には、本当の意味でのコミュニケーション機能がありません。
ガダマー流に言えば、他者の解釈を交えながら、絶えず理解を深めていくのが言語(=コード)の本質的な姿。

問い: 「このService、チームの他メンバーが読んだら“なるほど、こういう責務か”と納得できるか?」
もしそうでないなら、その設計は独りよがりの手紙かもしれません。

最後に — 自分のコードが何者なのか、問い続けよう

本記事では、Laravelアーキテクチャのあるあるを5つのテーマ(サービス層、リポジトリ、DDD、責任、チーム対話)に分け、さらに哲学の概念(ハイデガー、サルトル、プラトン、ガダマー)を軽く織り交ぜてきました。

  1. サービス層: 「Fat Controller」を避けるだけでは不十分。「何のビジネスロジックをどのようにまとめたいのか?」を意識する。
  2. リポジトリ: 自由に導入するのはいいが、選んだ責任もある。本当に抽象化が必要か吟味する。
  3. DDD: イデアのように崇高だが、Laravel上では影になりがち。それでも学ぶ価値はある。
  4. コードに責任を持つ: ただ動けばいい、ではなく「問い続ける姿勢」が設計の生命線。
  5. 設計は孤独か、対話か: 個人の納得だけで完結させず、チーム内で意図を共有し合うことで、設計は初めて生きる。

さらなる問いかけ

  • 「このサービスクラスは、何を実現するためにある?」
  • 「リポジトリを導入して、本当にテストが楽になった?」
  • 「DDDの用語を使うことで、ドメインが整理されたのか、あるいは混乱が増したのか?」
  • 「自分の書いた設計に、チームメイトはどんな感想を持っている?」

こうした問いを、自分自身や周囲の開発者に投げかけてみると、新たな発見や改善策が見えてくるはずです。「設計に正解はない」とよく言われますが、問いを重ねることでよりよい設計に近づいていくことは可能です。

最後に: あなたのLaravelコードは、ただのハンマー(道具)でしょうか? それとも「壊れた瞬間に本質を問い直す価値ある存在」でしょうか?
どうか、設計を疑う自由と、それに伴う責任を忘れず、明日もコントローラやサービス、リポジトリ、ドメインモデルと対話し続けてください。

たねまる

たねまるは…設計とかは正直わかんないけど、哲学ってやつ、意外と面白いかも…?
何かこう、責務とか自由とかイデアとか、頭がこんがらがるけど、
コードに向き合うときに『何のため?』って自問するのは大事だよね……ふにゃ。


コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

This site uses Akismet to reduce spam. Learn how your comment data is processed.

若い頃、「仕事中にハマったこと」や「誰かに共有したい技術的な気づき」をアウトプットしたくてブログを始めましたが、勢い任せでよく分からない記事を大量生産し、あえなく飽きて終了。

改めて今、キャリア15年分の経験や知識が、これからITエンジニアを目指す方や、同じような課題で悩んでいる現役エンジニアの「メシのタネ」になるような記事を残したいと思っています。
※過去の記事は見ると精神が崩壊するため、そっとしておいてください。

🛠 経歴という名の珍道中:
文系Fラン → 広告営業 → Web営業 → 通信営業 → Web進行 → 出版 → Web媒体運用 → ソフトウェアハウス → SES → フリーランス

専門教育も受けず、転職歴も多数。履歴書はまるで時系列の事故記録のようですが、試行錯誤を重ね、なんとかエンジニアとして食べています。

このブログでは、そんな「履歴書クラッシャー型エンジニア」が送る、
名古屋一敷居の低い、実務に役立つ技術ブログを目指します。

Laravel
LaravelのサービスコンテナとDI、「書いてるだけで動く」コードの正体New!!
Laravel
Laravelのアーキテクチャ、実は誰もわかってない説New!!
ガジェット
【解説】Bluetoothヘッドホンでマイクが使えない理由と回避策まとめ(Mac対応)New!!
Laravel
Laravel Collection入門: mapとeachの違い、ちゃんと説明できますか?New!!
Laravel
Eloquentのリレーション徹底解説New!!
Laravel
Eloquentは知ってる。でも“理解してる”って言えるのか?New!!