バニラ PHP で学ぶクリーンアーキテクチャ その 1
クリーンアーキテクチャの概要を PHP のサンプルコードを見ながら学びます。
対象
基本的には素の PHP ですが、 ある程度モダンな環境にしたかったので Composer, PHPUnit, PHP-CS-Fixer, PHPStan は入れてます。 大規模なフレームワークを使ってないくらいに考えてください。
題材
例として、商品情報管理ツールを作ります。
- 実行すると、指定された商品情報に税込価格を追加して表示する
- 税込価格は軽減税率を考慮して算出する
- コマンドラインツールとして作る。商品 ID を引数で指定する
- 商品情報は LTSV 形式で標準出力に表示する
- 商品情報として以下の項目がストレージに保存されている
- 商品 ID
- 商品名
- 税抜価格
- 軽減税率対象か
- ストレージはメモリ上に保存される
リポジトリは ここ にあります。 記事を読みながら見るとよいです。
クリーンアーキテクチャのレイヤ
クリーンアーキテクチャといえば、 元記事の図 が有名ですが、ここで 以下のレイヤが定義されています。
- Frameworks & Drivers
- Interface Adapters
- Application Business Rules
- Enterprise Business Rules
それぞれについて説明します。
Frameworks & Drivers
- html を生成するテンプレートエンジン
- DB にアクセスするライブラリ
- web フレームワーク
などの具体的な処理をおこないうものが含まれます。 ソースでは src/Infrastructure/ が対応します。 今回は引数の処理とストレージの実装をおこなっています。
Interface Adapters
外部との仲介をおこないます。
- リクエストパラメータのバリデーション、正規化
- ロジックの呼び出し
- 出力のフォーマット
- ストレージからデータを取得し、Entity に変換
などを担当します。 ソースでは src/Adapter/ が対応します。
今回は
- 引数のバリデーション、正規化
- ビジネスロジックの呼び出し
- LTSV の生成
をおこなっています。
Application Business Rules
アプリケーション固有のビジネスロジックを実装します。
ソースでは src/Application/ が対応します。
今回は以下をおこなっています。
- ストレージへのアクセス
- ドメインロジックの呼び出し
- エラー時の制御
Enterprise Business Rules
アプリケーションによらないビジネスロジックを実装します。 分かりにくいですが、私の解釈では 「アプリケーションがなくても存在するようなロジック」 をここに書きます。 今回の場合だと「消費税率の計算」は アプリがなくても存在する(法律で規定されている) ため、ここに記述しています。
ソースでは src/Domain/ が対応します。
今回は税込価格の計算ロジックを実装しています。
依存の向きと依存性逆転の原則について
方針 (Policy) を詳細 (Detail) に依存させないために、 依存性逆転の原則 (DIP) を使います。
各レイヤは Detail -> Policy の順に
Frameworks & Drivers -> Interface Adapters -> Application Business Rules -> Enterprise Business Rules
となっており、この逆の依存はさせないようにします。 元記事 の図でいうと、外 -> 中は OK ですが、中 -> 外への依存は NG になります。
とはいえ、ビジネスロジックから DB 等にアクセスする事はあるので、 その際は Interface を定義し、それに依存するように実装します。
今回の場合 ItemInteractor (ビジネスロジック)から ItemRepository (DB 等にアクセス) を使う必要がありますが、 直接は参照できないため、IItemRepository インタフェースを定義して ItemRepository には依存させないようにしています。
実装でも ItemInteractor は IItemRepository インタフェースのみを参照しています。 また、ソースを 'use' で検索しても外 -> 中の参照しかないことが分かります。
このようにすることで、例えばストレージが DB から Web API に変わったとしても、 内部(Application, Domain) への影響をおさえる事ができます。
まとめ
という事で、今回は各レイヤの説明をしました。 次回、ソースコードの説明をします。
サンプルの動かし方
実際に動かしてみたり、変更してみたりするとよいかもです。 PHP 7.4.9 で動作確認しています。
$ git clone https://github.com/yosugi/clearn-architecture-with-vanilla-php.git $ cd clearn-architecture-with-vanilla-php $ composer install $ php ./src/main.php 1 id:1 name:itemA price:100 isReducedTaxRate:false priceIncludingTax:110 $ php ./src/main.php 99 item id 99 is not found.