Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Laravel × レイヤードアーキテクチャを実践して得られた知見と反省 / Practice of Laravel with layered architecture

1,053 views

Published on

DDD においてセットで語られるレイヤードアーキテクチャ。このたび 2 つのプロジェクトにおいて、Laravel 上でレイヤードアーキテクチャを実践する機会に恵まれたので、Laravel の機能・特徴にも焦点をあてながら、事例とともに得られた知見・反省などをお話します。

2018/12/15 開催の PHP Conference 2018 (http://phpcon.php.gr.jp/2018/) の発表資料です。

youtube: https://youtu.be/2D8Rs9SqFiU?t=13762
joind.in: https://joind.in/event/japan-php-conference-2018/laravel--

Published in: Software
  • Be the first to comment

Laravel × レイヤードアーキテクチャを実践して得られた知見と反省 / Practice of Laravel with layered architecture

  1. 1. Laravel × レイヤードアーキテクチャ を実践して得られた知見と反省 Japan PHP Conference 2018 @okashoi WILLGATE, Inc.
  2. 2. 岡田 正平(おかだ しょうへい)@okashoi • 株式会社ウィルゲート • PHP, Laravel, Vue.js • Golang はじめました 2 自己紹介 Slides:
  3. 3. Services Tech Blog Events ブログやってます!イベントやってます! 「ウィルゲート テックブログ」で検索!
  4. 4. 4 今年の phpcon のテーマ = “GROWTH”
  5. 5. 今日の目標:私たちの失敗を共有すること • 人や組織は「失敗」によって成長する • 成功には再現性はないが、失敗には再現性がある ➢ 私が携わった 2 つのプロジェクトについて 具体的な事例、特に失敗を共有し 皆さんの糧にしてもらいたい 5 今年の phpcon のテーマ = “GROWTH”
  6. 6. 今回は「具体的にどのような実装になるか」 という話(※)はほとんど出てきません ※またどこか別の機会を得て話したい
  7. 7. • 背景 • Laravel とレイヤードアーキテクチャの親和性 • 失敗したこと • おわりに 7 目次
  8. 8. • 背景 • Laravel とレイヤードアーキテクチャの親和性 • 失敗したこと • おわりに 8 目次
  9. 9. プロジェクト A • 2018 年 4 月~ • Laravel で HTML を render して返す 典型的な web アプリケーション • PL + 実装者 2 名 + プロジェクト B • 2018 年 6 月~ • SPA(API を Laravel で実装) • PM + フロント 3 名 + サーバサイド 4 名 + 9 2 つのプロジェクト
  10. 10. • いずれも実装者のほとんどが Laravel 未経験 • なぜ Laravel? • 技術のキャッチアップのため • チーム横断人材の育成のため • の役割はアプリケーションアーキテクト • 別チームで Laravel をメインで使っていたので 白羽の矢が立った 10 2 つのプロジェクト
  11. 11. ※ 2018 年 3 月ごろ 「チームはわざわざ『Laravel に切り替える』 というコストを払っている……」 11 自分が提供できる価値を考える
  12. 12. ※ 2018 年 3 月ごろ 「Laravel をただの MVC フレームワークとして 使うのでは得られるものが少ないのでは?」 12 自分が提供できる価値を考える
  13. 13. かくして、チームを巻き込んだ レイヤードアーキテクチャへの 試行錯誤の旅が始まった
  14. 14. • 背景 • Laravel とレイヤードアーキテクチャの親和性 • 失敗したこと • おわりに 14 目次
  15. 15. • ディレクトリ構成を自由に設定できる • DI のための仕組みが充実 • Eloquent ORM などの豊富で強力な機能 15 Laravel の特徴
  16. 16. • ディレクトリ構成を自由に設定できる • DI のための仕組みが充実 • Eloquent ORM などの豊富で強力な機能 16 Laravel の特徴 →レイヤードアーキテクチャと相性がいい →どこまでその機能を活用するか悩ましい
  17. 17. • もとから Laravel に存在している 概念は該当する層の中に移動 • 依存性の逆転を発生させる際に DI の仕組みを活用 17 自由なディレクトリ構成と DI の仕組み
  18. 18. • もとから Laravel に存在している 概念は該当する層の中に移動 • 依存性の逆転を発生させる際に DI の仕組みを活用 18 自由なディレクトリ構成と DI の仕組み Application Infrastructure Domain 処理の流れ 依存の方向
  19. 19. 出典: DDDパターンを活用したLaravelアプリケーション開発 /ddd-with-laravel https://speakerdeck.com/shin1x1/ddd-with-laravel (めちゃくちゃ参考にしました 感謝 ) 19 参考にさせていただいたもの
  20. 20. • 背景 • Laravel とレイヤードアーキテクチャの親和性 • 失敗したこと • おわりに 20 目次
  21. 21. 失敗 1 Value Object が形骸化した
  22. 22. 本来の意図 値の振る舞いや制約をオブジェクトで表現する • 例)「価格」 Value Object • マイナス値を取らない • 消費税込みの金額を算出できる など 実際に起きたこと 全カラムと 1 対 1 のクラスを作ることが目的に ➢ ロジックの無いクラスが大量生産される 22 Value Object の形骸化
  23. 23. <?php namespace App¥Domain¥Models¥News; /** * Class Title */ class Title { /** * @var string */ private $value; /** * @param string $value */ public function __construct(string $value) { $this->value = $value; } /** * @return string */ public function value(): string { return $this->value; } } このようなクラスが DB のカラムの数だけ 作成された
  24. 24. どうすればよかったか? • Value Object に「どんなメリットがあるか」 をベースにしてメンバーの認識すり合わせる • 振る舞いや制約がない値は Value Object にしない • 自由入力形式のテキストや bool 値など 24 Value Object の形骸化
  25. 25. 失敗 2 Domain 層に 整形処理を書いた
  26. 26. json API の実装において Entity や Value Object に を実装 26 整形処理の実装箇所 class User implements ¥JsonSerializable { // 略 public function jsonSerialize(): array { return [ 'id' => $this->id, 'mail_address' => $this->mailAddress, 'profile' => [ 'last_name' => $this->lastName, 'first_name' => $this->firstName, 'user_name' => $this->userName, 'sex' => $this->sex, ], ]; } } { "id": 1, "mail_address": "john@example.org", "profile": { "last_name": "Doe", "first_name": "John", "user_name": "johndoe", "sex": "male" } } jsonSerialize()
  27. 27. Controller が薄く、はじめは良い実装に見えた 27 整形処理の実装箇所 class UserController extends Controller { public function detail(User $user) { return response(['user' => $user]); } public function create(CreateRequest $request, UserRepository $userRepository) { $user = $userRepository->create($request->validated()); return response(['user' => $user], 201); } public function update(User $user, UpdateRequest $request, UserRepository $userRepository) { $user = $userRepository->update($user->id(), $request->validated()); return response(['user' => $user], 200); } }
  28. 28. • 一方で「ユーザ一覧 API」では 次のようなレスポンス欲しくなった • 対応するために Entity に という プロパティをもたせて条件分岐させるようにした ➢ ドメインの関心ごと以外が混ざってしまった 28 整形処理の実装箇所 { "users": [ {"id": 1, "user_name": "jonedoe"}, {"id": 2, "user_name": "janedoe"}, // ... ] } $requestType
  29. 29. どうすればよかったか? その 1 • そもそも整形処理(レスポンス形式)自体が ドメインの関心ごとではない ➢ Application 層に整形を担う Presenter のようなクラスを設置する • 「Controller を薄くすること」を目的にしない • あくまで 1 つの指標に過ぎない 29 整形処理の実装箇所
  30. 30. どうすればよかったか? その 2 • CQRS を適用する • 副作用のある Command と 副作用のない Query で役割を分割する ➢ 「一覧取得」は Query で行い Entity を経由せずに、連想配列の形で扱ってしまう 30 整形処理の実装箇所
  31. 31. 失敗? 3 作るシステムの 規模を考慮しなかった
  32. 32. プロジェクト A の場合 • 最初のリリースまでに 3 ヶ月程度 • リリース後に大きな追加開発はしない想定 • 一般に公開はしないクローズドなシステム ➢ システムの規模に対してクラスの種類が多く 機能実装のオーバーヘッドが大きくなっていたの ではないか? 32 規模に見合ったアーキテクチャか?
  33. 33. 33 規模に見合ったアーキテクチャか? MVC レイヤードアーキテクチャ • routing • Controller (Request) • Model (ORM) • View • routing • Controller (Request) • Use Case • Entity • Value Object • Domain Service • Repository (Interface) • Repository (Implementation) • ORM • View MVC と比較して考慮するべき概念は増える
  34. 34. レイヤードアーキテクチャのメリット(私的解釈) • MVC をもう少し詳細に分割・責務を明確化 (”Model” が指すものは人によってまちまち) ➢ コードの可読性が保たれる中長期的なメリット • 「依存性の逆転」を活用して ドメイン知識を何にも依存させない(保護する) ➢ 複雑な問題を扱うシステムほどその効果が大きい 34 規模に見合ったアーキテクチャか?
  35. 35. どうすればよかったか? • 複雑でないシステムなら MVC でも充分 • レイヤードアーキテクチャに出てくる概念の 一部だけを適用するのも良い • 一方で、この挑戦によって得られた知見が たくさんあった事実も軽視できない ➢ これらを踏まえて、ステークホルダーの合意を 取ったうえで採用するのならば問題はない (今回は合意を取っていた) 35 規模に見合ったアーキテクチャか?
  36. 36. 失敗? 4 ドメインモデリングと 設計が分かれていた
  37. 37. • いずれも実装者のほとんどが Laravel 未経験 • なぜ Laravel? • 技術のキャッチアップのため • チーム横断人材の育成のため • の役割はアプリケーションアーキテクト • 別チームで Laravel をメインで使っていたので 白羽の矢が立った 37 再掲:2 つのプロジェクト
  38. 38. • 別チームからの兼任なので サービスや業務フローへの理解が浅い状態 • アプリケーションアーキテクトとしての参加で 要件定義には参加していない • 一度要件に落とされたものをベースに設計 ➢ 伝言ゲーム形式になって 本質を突いた設計になっているかがわからない 38 モデリングと設計の分離
  39. 39. どうすればよかったか? • レイヤードアーキテクチャの恩恵を 存分に受けたければドメイン知識の理解は必須 • 理解が深い者が設計を行う • 設計者が理解を深める • ただし、実装パターンとして適用するだけでも 受けられる恩恵はあるので無意味とはいえない • テストコードが書きやすい • プルリクの粒度が小さくなった? など 39 モデリングと設計の分離
  40. 40. • 背景 • Laravel とレイヤードアーキテクチャの親和性 • 失敗したこと • おわりに 40 目次
  41. 41. レイヤードアーキテクチャの採用は正解だったのか? 41 おわりに
  42. 42. レイヤードアーキテクチャの採用は正解だったのか? (現時点では)正直わからない...... ➢ その設計が「良かった」かどうかは 数年後になって初めて判断できるようになる 42 おわりに
  43. 43. 「設計として」正解かどうかはわからない だけど 取り組んだことそれ自体は 正解にすることができる (やったからには、何が何でも正解にしたい) 43 おわりに
  44. 44. • メンバーに Laravel の知識や レイヤードアーキテクチャの概念を伝搬する • 試行錯誤の過程で生まれたドキュメント等を 組織の資産にする • (失敗)事例は外に向けてアウトプットする ➢ 自分/組織/社会の成長の糧にする 44 やったからには余すこと無く価値に変える
  45. 45. • メンバーに Laravel の知識や レイヤードアーキテクチャの概念を伝搬する • 試行錯誤の過程で生まれたドキュメント等を 組織の資産にする • (失敗)事例は外に向けてアウトプットする ➢ 自分/組織/社会の成長の糧にする 45 やったからには余すこと無く価値に変える 今日、この場でお話ししているのも 「取り組んだことそれ自体」を正解にするため
  46. 46. 46 さて、今年の phpcon のテーマは?
  47. 47. 47 さて、今年の phpcon のテーマは?
  48. 48. 挑戦して その結果を発信して みんなで”成長”しましょう 来年の phpcon で お待ちしています!

×