PHP Conferenve2018 聴講メモ #1 「独立したコアレイヤパターンによる PHP アプリケーションの実装」by shin1x1さん
※ 以下は私個人の解釈を多大に含んだメモ書きです。正確な講演内容はスライド等の公式資料をご覧ください。 (スライド公開してくださるそうです!)
独立したコアレイヤパターンによる PHP アプリケーションの実装
サンプルコード↓↓
テーマ
アプリケーションとフレームワークを分離するためのコアレイヤアーキテクチャ
テイクホームメッセージ
フレームワークを使うためにアプリケーションを作るのではなく、アプリケーションを作るためにフレームワークを使う
- コアレイヤパターン
- 実装
サンプルコードのとおり。コアレイヤでインタフェースを定義した時点でテストを書く。 - フレームワークを否定するものでは全くない。アプリケーションを作るためにフレームワークをうまく使う。
内容めも
背景
フレームワーク使ってアプリケーション作るのは今や当たり前だから、いっしょくたに語られがち。
でもアプリケーションとフレームワークの関係性、距離感はちゃんと考える必要がある。
なぜなら対象ドメインが違うから。アプリケーションが解決しようとしている問題と、フレームワークが解決しようとしている問題は違う。
- フレームワーク = Webアプリケーション開発
- アプリケーション = いろんなサービス・システム(Webに限らない)
問題を解決するためにアプリケーションを作る。フレームワークをうまく使うためにアプリケーションを作るのではない。
いろんなアーキテクチャを試してみた↓↓
① MVC + Service
MVCはどうしてもFat Controller, Fat Modelが生まれる。
→ ユースケース、コアロジックを Service レイヤーに切り出すようにした
→ が、思ったほど分離できなかった② レイヤードアーキテクチャ
DDD界隈でよく言われること。アプリケーションが解こうとしている問題のドメインを分析して、それを中心におく。
でもアプリケーションの問題とフレームワークの問題が混ざってしまう。
アプリケーションによってはちょっと too much になることも。
※ 今日の話はアプリケーションの設計だけにフォーカス。ドメイン分析は重要だけど今日は射程外。
まだ問題が残る。そこで、↓↓をベースにした新しいアーキテクチャパターンを紹介
- WHAT と HOW をレイヤで分ける
- コアロジックと技術詳細(フレームワーク等)の分離
- 守るべきシンプルなルールのみを決める
どうせ個別の開発シーンでは人々それぞれの「自分流の○○アーキテクチャ」が生まれてくるから
コアレイヤパターン
- コアレイヤ:コアロジック = WHAT を実装
プレーンなPHPを想定。コアレイヤのみに依存。ユースケースやドメインモデルなど。 - アプリケーションレイヤ:HTTP, RDBMS, 外部API等々 = HOW
コアレイヤが利用する技術のためのインタフェースを提供。
最初は「サービスレイヤ」と名付けていた。コアロジックから見ると「HTTPというサービスを提供してくれるレイヤ」
でも「MVC + Service」で使っていた同じ語で違う意味になっちゃうし伝わりにくいし迷ってやめた。
コアレイヤを中心に、サービスレイヤが外部(HTTP・RDBMS・外部API)との通信を担う。
「サービスレイヤを Laravel から CakePHP に変えても、コアレイヤはそのまま使える」のが理想。
インタフェースを実装したアプリケーションレイヤをコアレイヤにわたす。
ここでいう「インタフェース」は処理の共通化ではなく、「『自分たちは何をしたいのか』を表明するために使う」ものとして存在するもの。
例えばコアレイヤが直接 Eloquent を使うとコアレイヤがアプリケーションレイヤに依存することになる。
(コアレイヤ → アプリケーションレイヤ(特定のライブラリ))
そうではなくて、アプリケーションレイヤにやってほしいことをインタフェースとして定義する。
アプリケーションレイヤがそのインタフェースを実装することで、アプリケーションレイヤがコアレイヤに依存するようにする。
(コアレイヤ ← アプリケーションレイヤ)DIP!
アプリケーションレイヤは、コアレイヤで定義したインタフェースを実装する。
実装例:顧客のポイント管理(加算)
GitHub - shin1x1/phpcon2018-independent-core-layer: PHP カンファレンス 2018 独立したコアレイヤパターン
Laravel の一般的なディレクトリ構成に packages/Acme/Point
を追加
コアクラスの中で、データ操作のために2つのインタフェースを定義↓↓
- Query:read
- Command:write
↑↑定義した時点で、無名クラスを使ってテストを書く。
その後、アプリケーションレイヤの実装をする。
コアクラスは注入されたアプリケーションレイヤのメソッドを実行するだけ = 「やりたいこと」だけを書く。
アプリケーションレイヤは、インタフェースは2つだけど1クラスで実装してみた。
問題
- レイヤ分けに迷う
例:トランザクション 制御をインタフェース化して、BEGIN/COMMIT/ROLLBACK はアプリケーションレイヤで実装 - コアレイヤへの入出力
ユースケースへの引数、戻り値のデータ型は自由。スカラー型かドメインモデルになる。
フレームワーク固有の型は避ける。
まとめ
コアレイヤアーキテクチャは、アプリケーションとフレームワークを分離するためのパターン
- シンプルなルール:コアクラスではフレームワークさわらない → レビューの視点が明確になる
- フレームワークやライブラリはもちろん大事!
ただフレームワークをうまく使うためにアプリケーションを作るわけではない。アプリケーションを作るためにフレームワークを使う。
おまけ
- あくまで考えのひとつ
抽象的な話は強くなりがちだけど、引き出しに入れておいていただければw
質疑
- 開発途中は速度重視でフレームワーク依存になっちゃう状況もありそう、途中でコアクラスに分離するタイミングみたいなのは
明確な基準は特に無い。。。でも最初からコアレイヤパターンに移行することを想定して作っておくと分離しやすいかも
(ほかにもたくさんあったけどまとめきれなかった)
感想
何度も強調されていた「フレームワークをうまく使うためにアプリケーションを作るわけではない。アプリケーションを作るためにフレームワークを使う」、これ自体も確かにそうって思ったしこれを設計に反映させるのも面白かった。
よく見るいくつかの同心円に但し書きがされてる系の図、どこが違うねんと思うこともたまにあったけど()うしろにある背景というか問題意識とか価値観とかってそれぞれあるんだなとも思ったり。
サンプルコードもわかりやすかったし話も楽しく聞けたし良いセッションでした、@shin1x1さんありがとうございましたー!