Slide 1

Slide 1 text

Laravel × レイヤードアーキテクチャ を 実践して得られた 知見と 反省 Japan PHP Conference 2018 @okashoi WILLGATE, Inc.

Slide 2

Slide 2 text

岡田 正平(おかだ しょうへい)@okashoi • 株式会社ウィルゲート • PHP, Laravel, Vue.js • Golang はじめました 2 自己紹介 Slides:

Slide 3

Slide 3 text

Services Tech Blog Events ブログやってます!イベントやってます! 「ウィルゲート テックブログ」で検索!

Slide 4

Slide 4 text

4 今年の phpcon のテーマ = “GROWTH”

Slide 5

Slide 5 text

今日の目標:私たちの失敗を共有すること • 人や組織は「失敗」によって成長する • 成功には再現性はないが、失敗には再現性がある ➢ 私が携わった 2 つのプロジェクトについて 具体的な事例、特に失敗を共有し 皆さんの糧にしてもらいたい 5 今年の phpcon のテーマ = “GROWTH”

Slide 6

Slide 6 text

今回は「具体的にどのような実装になるか」 という話(※)はほとんど出てきません ※またどこか別の機会を得て話したい

Slide 7

Slide 7 text

• 背景 • Laravel とレイヤードアーキテクチャの親和性 • 失敗したこと • おわりに 7 目次

Slide 8

Slide 8 text

• 背景 • Laravel とレイヤードアーキテクチャの親和性 • 失敗したこと • おわりに 8 目次

Slide 9

Slide 9 text

プロジェクト A • 2018 年 4 月~ • Laravel で HTML を render して返す 典型的な web アプリケーション • PL + 実装者 2 名 + プロジェクト B • 2018 年 6 月~ • SPA(API を Laravel で実装) • PM + フロント 3 名 + サーバサイド 4 名 + 9 2 つのプロジェクト

Slide 10

Slide 10 text

• いずれも実装者のほとんどが Laravel 未経験 • なぜ Laravel? • 技術のキャッチアップのため • チーム横断人材の育成のため • の役割はアプリケーションアーキテクト • 別チームで Laravel をメインで使っていたので 白羽の矢が立った 10 2 つのプロジェクト

Slide 11

Slide 11 text

※ 2018 年 3 月ごろ 「チームはわざわざ『Laravel に切り替える』 というコストを払っている……」 11 自分が提供できる価値を考える

Slide 12

Slide 12 text

※ 2018 年 3 月ごろ 「Laravel をただの MVC フレームワークとして 使うのでは得られるものが少ないのでは?」 12 自分が提供できる価値を考える

Slide 13

Slide 13 text

かくして、チームを巻き込んだ レイヤードアーキテクチャへの 試行錯誤の旅が始まった

Slide 14

Slide 14 text

• 背景 • Laravel とレイヤードアーキテクチャの親和性 • 失敗したこと • おわりに 14 目次

Slide 15

Slide 15 text

• ディレクトリ構成を自由に設定できる • DI のための仕組みが充実 • Eloquent ORM などの豊富で強力な機能 15 Laravel の特徴

Slide 16

Slide 16 text

• ディレクトリ構成を自由に設定できる • DI のための仕組みが充実 • Eloquent ORM などの豊富で強力な機能 16 Laravel の特徴 →レイヤードアーキテクチャと相性がいい →どこまでその機能を活用するか悩ましい

Slide 17

Slide 17 text

• もとから Laravel に存在している 概念は該当する層の中に移動 • 依存性の逆転を発生させる際に DI の仕組みを活用 17 自由なディレクトリ構成と DI の仕組み

Slide 18

Slide 18 text

• もとから Laravel に存在している 概念は該当する層の中に移動 • 依存性の逆転を発生させる際に DI の仕組みを活用 18 自由なディレクトリ構成と DI の仕組み Application Infrastructure Domain 処理の流れ 依存の方向

Slide 19

Slide 19 text

出典: DDDパターンを活用したLaravelアプリケーション開発 /ddd-with-laravel https://speakerdeck.com/shin1x1/ddd-with-laravel (めちゃくちゃ参考にしました 感謝 ) 19 参考にさせていただいたもの

Slide 20

Slide 20 text

• 背景 • Laravel とレイヤードアーキテクチャの親和性 • 失敗したこと • おわりに 20 目次

Slide 21

Slide 21 text

失敗 1 Value Object が形骸化した

Slide 22

Slide 22 text

本来の意図 値の振る舞いや制約をオブジェクトで表現する • 例)「価格」 Value Object • マイナス値を取らない • 消費税込みの金額を算出できる など 実際に起きたこと 全カラムと 1 対 1 のクラスを作ることが目的に ➢ ロジックの無いクラスが大量生産される 22 Value Object の形骸化

Slide 23

Slide 23 text

value = $value; } /** * @return string */ public function value(): string { return $this->value; } } このようなクラスが DB のカラムの数だけ 作成された

Slide 24

Slide 24 text

どうすればよかったか? • Value Object に「どんなメリットがあるか」 をベースにしてメンバーの認識すり合わせる • 振る舞いや制約がない値は Value Object にしない • 自由入力形式のテキストや bool 値など 24 Value Object の形骸化

Slide 25

Slide 25 text

失敗 2 Domain 層に 整形処理を書いた

Slide 26

Slide 26 text

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()

Slide 27

Slide 27 text

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); } }

Slide 28

Slide 28 text

• 一方で「ユーザ一覧 API」では 次のようなレスポンス欲しくなった • 対応するために Entity に という プロパティをもたせて条件分岐させるようにした ➢ ドメインの関心ごと以外が混ざってしまった 28 整形処理の実装箇所 { "users": [ {"id": 1, "user_name": "jonedoe"}, {"id": 2, "user_name": "janedoe"}, // ... ] } $requestType

Slide 29

Slide 29 text

どうすればよかったか? その 1 • そもそも整形処理(レスポンス形式)自体が ドメインの関心ごとではない ➢ Application 層に整形を担う Presenter のようなクラスを設置する • 「Controller を薄くすること」を目的にしない • あくまで 1 つの指標に過ぎない 29 整形処理の実装箇所

Slide 30

Slide 30 text

どうすればよかったか? その 2 • CQRS を適用する • 副作用のある Command と 副作用のない Query で役割を分割する ➢ 「一覧取得」は Query で行い Entity を経由せずに、連想配列の形で扱ってしまう 30 整形処理の実装箇所

Slide 31

Slide 31 text

失敗? 3 作るシステムの 規模を考慮しなかった

Slide 32

Slide 32 text

プロジェクト A の場合 • 最初のリリースまでに 3 ヶ月程度 • リリース後に大きな追加開発はしない想定 • 一般に公開はしないクローズドなシステム ➢ システムの規模に対してクラスの種類が多く 機能実装のオーバーヘッドが大きくなっていたの ではないか? 32 規模に見合ったアーキテクチャか?

Slide 33

Slide 33 text

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 と比較して考慮するべき概念は増える

Slide 34

Slide 34 text

レイヤードアーキテクチャのメリット(私的解釈) • MVC をもう少し詳細に分割・責務を明確化 (”Model” が指すものは人によってまちまち) ➢ コードの可読性が保たれる中長期的なメリット • 「依存性の逆転」を活用して ドメイン知識を何にも依存させない(保護する) ➢ 複雑な問題を扱うシステムほどその効果が大きい 34 規模に見合ったアーキテクチャか?

Slide 35

Slide 35 text

どうすればよかったか? • 複雑でないシステムなら MVC でも充分 • レイヤードアーキテクチャに出てくる概念の 一部だけを適用するのも良い • 一方で、この挑戦によって得られた知見が たくさんあった事実も軽視できない ➢ これらを踏まえて、ステークホルダーの合意を 取ったうえで採用するのならば問題はない (今回は合意を取っていた) 35 規模に見合ったアーキテクチャか?

Slide 36

Slide 36 text

失敗? 4 ドメインモデリングと 設計が分かれていた

Slide 37

Slide 37 text

• いずれも実装者のほとんどが Laravel 未経験 • なぜ Laravel? • 技術のキャッチアップのため • チーム横断人材の育成のため • の役割はアプリケーションアーキテクト • 別チームで Laravel をメインで使っていたので 白羽の矢が立った 37 再掲:2 つのプロジェクト

Slide 38

Slide 38 text

• 別チームからの兼任なので サービスや業務フローへの理解が浅い状態 • アプリケーションアーキテクトとしての参加で 要件定義には参加していない • 一度要件に落とされたものをベースに設計 ➢ 伝言ゲーム形式になって 本質を突いた設計になっているかがわからない 38 モデリングと設計の分離

Slide 39

Slide 39 text

どうすればよかったか? • レイヤードアーキテクチャの恩恵を 存分に受けたければドメイン知識の理解は必須 • 理解が深い者が設計を行う • 設計者が理解を深める • ただし、実装パターンとして適用するだけでも 受けられる恩恵はあるので無意味とはいえない • テストコードが書きやすい • プルリクの粒度が小さくなった? など 39 モデリングと設計の分離

Slide 40

Slide 40 text

• 背景 • Laravel とレイヤードアーキテクチャの親和性 • 失敗したこと • おわりに 40 目次

Slide 41

Slide 41 text

レイヤードアーキテクチャの採用は正解だったのか? 41 おわりに

Slide 42

Slide 42 text

レイヤードアーキテクチャの採用は正解だったのか? (現時点では)正直わからない...... ➢ その設計が「良かった」かどうかは 数年後になって初めて判断できるようになる 42 おわりに

Slide 43

Slide 43 text

「設計として」正解かどうかはわからない だけど 取り組んだことそれ自体は 正解にすることができる (やったからには、何が何でも正解にしたい) 43 おわりに

Slide 44

Slide 44 text

• メンバーに Laravel の知識や レイヤードアーキテクチャの概念を伝搬する • 試行錯誤の過程で生まれたドキュメント等を 組織の資産にする • (失敗)事例は外に向けてアウトプットする ➢ 自分/組織/社会の成長の糧にする 44 やったからには余すこと無く価値に変える

Slide 45

Slide 45 text

• メンバーに Laravel の知識や レイヤードアーキテクチャの概念を伝搬する • 試行錯誤の過程で生まれたドキュメント等を 組織の資産にする • (失敗)事例は外に向けてアウトプットする ➢ 自分/組織/社会の成長の糧にする 45 やったからには余すこと無く価値に変える 今日、この場でお話ししているのも 「取り組んだことそれ自体」を正解にするため

Slide 46

Slide 46 text

46 さて、今年の phpcon のテーマは?

Slide 47

Slide 47 text

47 さて、今年の phpcon のテーマは?

Slide 48

Slide 48 text

挑戦して その結果を発信して みんなで”成長”しましょう 来年の phpcon で お待ちしています!