バニラ PHP で学ぶクリーンアーキテクチャ その 2

前回はクリーンアーキテクャの各レイヤの説明をしました。 今回は実装の説明をしていきます。

今回はソースコードの説明をします。 まずは前回の商品情報管理ツールの仕様を再掲。

  1. 実行すると、指定された商品情報に税込価格を追加して表示する
    • 税込価格は軽減税率を考慮して算出する
  2. コマンドラインツールとして作る。商品 ID を引数で指定する
  3. 商品情報は LTSV 形式で標準出力に表示する
  4. 商品情報として以下の項目がストレージに保存されている
    • 商品 ID
    • 商品名
    • 税抜価格
    • 軽減税率対象か
  5. ストレージはメモリ上に保存される

こんな仕様でした。 では、実装を順に説明していきます。 リンクを張っておくので、ソースコードを見ながら 説明を読むとよいかもです。

main 関数

書籍のクリーンアーキテクチャの 26 章にも出てくる 最も抽象度の低い関数です。 オブジェクトの生成と呼び出しのみ担当しています。

Command

main 関数と Controller のつなぎをやります。 この場合、以下をおこなっています。

  • main 関数から渡された引数から必要なもののみ抜き出す
  • Controller を呼び出す
  • Controller から返ってきた文字列を標準出力に表示
  • 例外が発生した場合、メッセージを標準エラー出力に表示

Controller

入力された引数を受け取って、 Interactor を呼び出します。 その後、Presenter でフォーマットしたものを外部に出力しています。 Presenter では Interactor から取得した結果を LTSV 形式に変換しています。

Validator

入力された引数が正しいか検査し、正規化して返します。

Interactor

入力された商品 ID を元に リポジトリから商品 Entity を取り出します。 その後、消費税計算ロジックを呼び出し、結果を Controller に返します。

Repository

本体は Adapter 層ですが Interactor から利用したいので、 インタフェース(IItemRepository)を作っています。 商品情報を取得し、Entity に変換して返します。

StorageClient

メモリ上で商品情報を管理します。 本体は Infrastructure 層ですが Repository から呼び出したいので、 インタフェース(IStorageClient)を作っています。

Entity, Logic

商品を示すクラス(ItemEntity)と それにまつわるビジネスロジックです。

今回、Logic には消費税の計算ロジックを実装します。

※ Entity にビジネスロジックを書くやり方もありますが、 今回は両者を分けています。

Presenter

Controller で呼び出され、 Entity を表示形式(この場合 LTSV)に変換します。

ユニットテスト

以下が今回作成したユニットテスト(UT)になります。

各クラスの責務が明確なので、読み書きしやすいと思います。 今回は外部との入出力をおこなわないメソッドについてのみ UT を作っています。 こうすることで、モックなしてテストができ、 テストケースの作成・保守がかなり楽になります。

まとめ

クリーンアーチテクチャを実現した ソースコードの説明をしました。 各ファイルの use 文を見てもらえれば参照方向が Infrastructure -> Adapter -> Application -> Domain となっており、逆向きの参照がない事が分かると思います。

という事で、 「方針(policy) を詳細(detail) に依存させない」 実装になっていると思います。

※ 注意として、こればあくまで私の解釈で実装したものであり、 これが唯一の正解ではありません。

サンプルの動かし方

実際に動かしてみたり、変更してみたりするとよいかもです。 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.