1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

クリーンアーキテクチャを野球で理解する ── エンティティ・ユースケース・コントローラーをやさしく解説

1
Posted at

はじめに

クリーンアーキテクチャを勉強し始めたとき、自分はまず「Entity」「UseCase」「Controller」という言葉でつまずきました。

説明を読んでも、

結局、それぞれ何を担当するの?

という感覚がなかなか抜けませんでした。

そこで、自分が好きな野球に置き換えて考えてみたところ、それぞれの役割がかなりイメージしやすくなりました。

この記事では、クリーンアーキテクチャに登場する3つの役割を、

  • Entity
  • UseCase
  • Controller

の順番で、野球のたとえを使いながら整理していきます。

なお、実際のクリーンアーキテクチャはもう少し複雑です。

この記事ではまず全体像をつかむことを目的に、できるだけシンプルに説明します。


1. Entity編

野球でたとえると「変えられないルール」

まず、Entityです。

野球には、球場やチームが変わっても基本的には変わらないルールがあります。

たとえば、

  • 打ったら1塁に向かって走る
  • 3アウトになったら攻守交代する
  • ストライクが3つで三振になる

といったルールです。

東京ドームで試合をしても、甲子園で試合をしても、

今日は球場が違うので、打ったら3塁に走ってください

とはなりません。

つまり、野球という競技を成立させている中心的なルールです。

もちろん野球の公式ルール自体が将来的に変更される可能性はあります。

ここで重要なのは、

球場や道具、スタッフといった外側の事情によって簡単には変わらない

ということです。

技術的には「ビジネスの中心にあるルール」

クリーンアーキテクチャにおけるEntityも、これと似ています。

Entityは、

そのシステムのビジネスにおいて中心となるルール

を表します。

たとえばECサイトなら、

  • 注文金額は0円未満にはならない
  • 在庫がない商品は購入できない
  • 会員ランクによって割引率が決まる

といったビジネス上のルールです。

ここで大事なのは、

Laravelを使っているかどうかは関係ない

という点です。

Laravelから別のPHPフレームワークに移行したとしても、データベースをMySQLからPostgreSQLに変更したとしても、

在庫が0なら商品を購入できない

というビジネス上のルールそのものは変わりません。

野球でいえば、

球場が変わっても、3アウトでチェンジなのは変わらない

ということです。

一言でまとめると

Entity = 野球のルールブック

です。

アプリケーションの中でも、特に中心に置かれる存在です。


2. UseCase編

野球でたとえると「ルールの中でどう動くか」

次はUseCaseです。

野球には基本となるルールがありますが、そのルールの中でどう戦うかはチームごとに変わります。

たとえば、

  • 誰を1番バッターにするか
  • 誰をピッチャーにするか
  • バントをするか
  • 盗塁するか
  • 守備位置をどうするか

といった部分です。

「3アウトでチェンジ」というルールそのものをチームが勝手に変えることはできません。

しかし、そのルールの中で、

じゃあ、この試合ではどう動くか?

を決めることはできます。

これがUseCaseのイメージです。

技術的には「アプリケーションで何をするか」

UseCaseは、Entityが持つルールを利用しながら、

このアプリケーションで具体的に何をするのか

を表します。

たとえば、

「商品を購入する」

というUseCaseであれば、

  1. 商品を取得する
  2. 購入可能か確認する
  3. 注文を作成する
  4. 在庫を更新する
  5. 注文結果を返す

といった一連の流れを担当します。

野球でいえば、

野球のルールを前提として、監督やコーチが試合の進め方を決める

ようなイメージです。

Entityが「ルール」なら、

UseCaseは「作戦」です。

一言でまとめると

UseCase = ルールの中で何をするか決める作戦

です。


3. Controller編

野球でたとえると「必要な道具を選手に渡す係」

最後がControllerです。

Controllerを野球でたとえるなら、

選手にバットやグローブなど、必要なものを渡すスタッフ

のような存在です。

たとえば、

はい、このバットを使ってください

グローブはこちらです

と、選手がプレーするために必要なものを準備して渡します。

しかし、そのスタッフ自身が、

今日の1番バッターは誰にしよう

と作戦を決めるわけではありません。

ましてや、

今日から4アウトでチェンジにしよう

と野球のルールを変更することもありません。

あくまで、

外から受け取ったものを、実際にプレーする側が使える形にして渡す

役目です。

技術的には「外部からの入力をUseCaseへつなぐ入口」

LaravelのControllerも似ています。

HTTPリクエストから、

  • 名前
  • ID
  • 数量

などの値を受け取り、UseCaseが扱える形にして渡します。

たとえば、

$name = $request->input('name');

$useCase->execute($name);

といった処理です。

Controller自身に大量のビジネスロジックを書くのではなく、

外部から値を受け取り、UseCaseが扱える形にして渡す

という役割に絞るのがポイントです。

また、UseCaseの実行結果をHTTPレスポンスとして返すこともController側の役割になります。

一言でまとめると

Controller = 外部とUseCaseをつなぐ受付係

です。


4. なぜ役割を分けるのか

ここまでを野球で整理すると、次のようになります。

クリーンアーキテクチャ 野球
Entity 野球そのもののルール
UseCase ルールの中で決める作戦
Controller 必要なものを受け渡すスタッフ

では、なぜわざわざ役割を分けるのでしょうか。

自分はここも、野球で考えると理解しやすかったです。

たとえば、東京ドームから別の球場へ移ったとします。

球場が変われば、

  • ベンチの場所
  • ロッカー
  • 道具置き場
  • 入場口

などは変わるかもしれません。

しかし、

3アウトでチェンジ

というルールまで変更する必要はありません。

アプリケーションも同じです。

たとえば、

  • Laravelから別のフレームワークへ変更する
  • MySQLからPostgreSQLへ変更する
  • HTTP API以外にCLIからも処理を実行する

といった変更はありえます。

一方で、

そのサービスが提供している本質的なビジネスルール

は、それらの技術より長く使われることがあります。

そのため、

変わりやすいものと、変わりにくいものを分離しておく

というのがクリーンアーキテクチャの重要な考え方になります。


5. 依存する方向

ここで重要なのが、依存する方向です。

今回扱っている3つだけをシンプルに表すなら、

Controller → UseCase → Entity

という方向になります。

ControllerがUseCaseを利用し、

UseCaseがEntityを利用します。

重要なのは、

内側にあるものが、外側の都合に依存しない

ことです。

たとえば、

Entity → Controller

のような関係は避けます。

野球で考えると不自然ですよね。

野球のルールブックに、

道具を渡すスタッフは、この手順でバットを渡さなければならない

と書かれていたらおかしいです。

野球のルールは、道具係がどのように仕事をしているかを知る必要がありません。

同じようにEntityも、

  • HTTP
  • Laravel
  • Request
  • Controller

といった外側の事情を知らない状態にしておきます。

これがクリーンアーキテクチャでいう、

依存関係を内側に向ける

という考え方です。


6. Laravelでありがちな例

Laravelを使っていると、ついやってしまいやすい形があります。

それが、

Controllerで受け取ったRequestを、そのままUseCaseへ渡す

というものです。

たとえば、次のコードです。

public function store(Request $request)
{
    $this->useCase->execute($request);
}

そしてUseCase側でも、

use Illuminate\Http\Request;

public function execute(Request $request)
{
    $name = $request->input('name');

    // ビジネス処理
}

としてしまいます。

もちろん、このコード自体はLaravel上では動きます。

ただし、クリーンアーキテクチャの観点では少し問題があります。

このUseCaseは、

Illuminate\Http\Request

というHTTPやLaravel側の仕組みを知ってしまったからです。

つまり、

作戦担当であるUseCaseが、道具係の事情まで知っている

状態です。

野球でいえば監督が、

道具係が使っているバッグの3番ポケットからバットを取り出して、それを選手に渡して……

と指示しているようなものです。

監督が知るべきなのは、

この選手にはこのバットを使ってもらう

という情報だけで十分です。

バッグのどこにバットが入っているかまで知る必要はありません。

Laravelでも同じで、Controller側で必要な値を取り出してからUseCaseへ渡します。

public function store(Request $request)
{
    $name = $request->input('name');

    $this->useCase->execute($name);
}

UseCase側は、LaravelのRequestを知りません。

public function execute(string $name)
{
    // ビジネス処理
}

こうしておけば、将来的にHTTP以外から同じUseCaseを呼び出したくなった場合にも使いやすくなります。

たとえば、

  • CLI
  • バッチ処理
  • Queue
  • 別のWebフレームワーク

などから呼び出す場合です。

UseCaseがLaravelのRequestに依存していなければ、こうした変更の影響を受けにくくなります。


7. Laravel / PHPで簡単なコードを書いてみる

ここでは、

「選手をチームに登録する」

という簡単な処理を例にしてみます。

野球で対応させると、

  • Entity:選手として成立するためのルール
  • UseCase:選手を登録する処理
  • Controller:HTTPから値を受け取ってUseCaseへ渡す係

です。


Entity:ルールを守る

まずEntityです。

<?php

namespace Domain\Entity;

class Player
{
    public function __construct(
        private string $name,
        private int $age,
    ) {
        if ($age < 6) {
            throw new \InvalidArgumentException(
                '選手は6歳以上である必要があります'
            );
        }
    }

    public function name(): string
    {
        return $this->name;
    }
}

ここでは例として、

選手として登録できるのは6歳以上

というビジネスルールをEntityに持たせています。

このコードには、

Request

も、

Controller

も登場しません。

Laravelを使っていることすら知りません。

野球のルールブックが、球場や道具係の事情を知らなくても成立するのと同じです。


UseCase:何をするか決める

次にUseCaseです。

<?php

namespace Application\UseCase;

use Domain\Entity\Player;

class RegisterPlayerUseCase
{
    public function execute(string $name, int $age): Player
    {
        $player = new Player(
            name: $name,
            age: $age,
        );

        // 本来はRepositoryなどを通して保存する

        return $player;
    }
}

UseCaseは、

  1. 名前と年齢を受け取る
  2. Playerを作る
  3. 必要であれば保存する
  4. 処理結果を返す

といった、

「選手を登録するために何をするか」

を担当します。

野球でいえば、監督やコーチが組み立てる作戦部分です。

ただし、

選手として成立するためには6歳以上でなければならない

というルールそのものはEntityに任せています。

UseCaseがルールをすべて抱え込むのではなく、Entityのルールを利用しながら処理を進めます。


Controller:値を受け取って渡す

最後がControllerです。

<?php

namespace App\Http\Controllers;

use Application\UseCase\RegisterPlayerUseCase;
use Illuminate\Http\Request;

class PlayerController extends Controller
{
    public function store(
        Request $request,
        RegisterPlayerUseCase $useCase,
    ) {
        $player = $useCase->execute(
            name: $request->string('name')->toString(),
            age: $request->integer('age'),
        );

        return response()->json([
            'name' => $player->name(),
        ]);
    }
}

Controllerが行っているのは、

  • HTTPリクエストを受け取る
  • 必要な値を取り出す
  • UseCaseへ渡す
  • UseCaseの結果をHTTPレスポンスとして返す

という処理です。

野球でいう、

バットはこちらです。グローブはこちらです。

と必要なものを準備して渡すスタッフに近い存在です。

「どんな作戦で試合をするか」はUseCaseに任せます。

「野球として何が正しいのか」というルールはEntityに任せます。

それぞれが自分の担当に集中するわけです。


8. もう一度、野球で整理する

ここまでをもう一度まとめます。

Entity

野球でいう、

3アウトでチェンジ、打ったら1塁へ走る、といったルール

です。

アプリケーションでは、

ビジネスの中心となるルール

を担当します。

LaravelやMySQLといった外部の技術に左右されにくい部分です。


UseCase

野球でいう、

打順、守備位置、バント、盗塁などの作戦

です。

アプリケーションでは、

Entityのルールを使いながら、具体的に何をするか

を担当します。


Controller

野球でいう、

選手にバットやグローブを渡すスタッフ

です。

アプリケーションでは、

外部から値を受け取り、UseCaseが扱える形にして渡す入口

を担当します。


まとめ

クリーンアーキテクチャを最初に学ぶと、

「Entity」

「UseCase」

「Controller」

という言葉がどうしても抽象的に見えます。

自分も最初は、それぞれの境界がよく分かりませんでした。

ですが、野球に置き換えてみると、

Controller
    ↓
UseCase
    ↓
Entity

という関係がかなりイメージしやすくなりました。

まとめると、

  • Entity = 野球の中心となるルール
  • UseCase = ルールの中でどう動くか決める作戦
  • Controller = 外部から必要なものを受け取って渡す受付係

となります。

そして、クリーンアーキテクチャを理解するうえで特に重要なのが、

野球のルールは、球場や道具係が変わったからといって影響を受けない

という点です。

同じようにアプリケーションでも、

ビジネスルールをLaravelやDB、HTTPといった外側の都合から守る

というのが、クリーンアーキテクチャの中心にある考え方のひとつです。

最初から完璧に役割を分ける必要はないと思います。

まずはコードを書くときに、

この処理は「ルール」なのか?

「作戦」なのか?

それとも「外部との値の受け渡し」なのか?

と一度考えてみるだけでも、設計の見え方はかなり変わってくるはずです。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?