Upgrade to Pro — share decks privately, control downloads, hide ads and more …

新卒 Laravel 初心者が成長していく中で 感じたコレジャナイ感/PHPerKaigi 2022

新卒 Laravel 初心者が成長していく中で 感じたコレジャナイ感/PHPerKaigi 2022

PHPer Kaigi 2022 の発表資料です.

Laravel って,便利な機能が沢山実装されているし,ディレクトリ構成もテンプレートがそのまま使えて初学者に優しいですよね.
かくいう僕も,ほとんど Laravel の実務経験が無いまま新卒で社内プロダクトを引き継いだ頃は「便利だ便利だ」とLaravelに乗っかりまくっていました.
そんな中,だんだん「これってどうなの」と思う点がチラホラ出てきました.
・Controller と Model だけに処理を記述すると,肥大化して責務が不明瞭になってしまう
・Facade はどこでも使えて便利だが,依存関係が分かりづらくなってテストや拡張がしずらくなってきた
n番煎じかもしれませんが,「Laravel・PHP 初学者だったらこうしがち,でもちょっとできる人はこうやるよ」という観点で,実際に僕が経験した Laravel のコレジャナイ感とその解決法をお話します.

ふわせぐ

April 07, 2022
Tweet

More Decks by ふわせぐ

Other Decks in Programming

Transcript

  1. ৽ଔ -BSBWFMॳ৺ऀ͕੒௕͍ͯ͘͠தͰ
    ײͨ͡ίϨδϟφΠײ
    @fuwasegu

    View full-size slide

  2. 自己紹介
    $aboutMe = [
    ‘📛’ => ‘竹下 拓秀(ふわせぐ)’,
    ‘🎂’ => CarbonImmutable::parse(‘1998-08-04 03:46:00’),
    ‘🏠’ => ‘長崎県出身・愛知県在住’,
    ‘🏢’ => ‘株式会社ゆめみ コーポレートエンジニア(フルサイクル)’,
    ‘👶’ => ‘2歳(男の子)’,
    ‘ ’ => ‘@fuwasegu’,
    ‘ ’ => ‘@lunain84’,
    ];
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション 2

    View full-size slide

  3. 3
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション
    -BSBWFM ࢖͍౗ͯ͠·͔͢ʁ

    View full-size slide

  4. 正に職人用フレームワーク
    Laravel の代表的な機能の例
    • サービスコンテナ
    • Eloquent ORM
    • Event / Job
    • Facade
    • MVC アーキテクチャのボイラープレート
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション 4

    View full-size slide

  5. 5
    丁寧なマニュアル
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション

    View full-size slide

  6. 6
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション
    Laravel に従いマニュアルに沿って開発すれば,
    なんとなく Web アプリが開発できる!
    \初心者にやさしい!/

    View full-size slide

  7. 7
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション
    そう思っていた時期が僕にもありました

    View full-size slide

  8. • 依存関係の混沌化
    • 責務の肥大化
    – 分割しようとしても責務が迷子に
    • 重くなるテスト
    8
    開発規模に比例して膨らむツラミ
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション

    View full-size slide

  9. 9
    Laravel 先生の言う通りにしたのに・・・
    なんで?
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション

    View full-size slide

  10. 犯人は Laravel 先生!?
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション 10
    • 依存関係の混沌化
    → Facade のせいで何が何に依存しているか分かりにくくなる
    • 責務の肥大化
    → Controller に処理を詰め込むと当然肥大化.安易に
    Model に処理を移そうとしても責務不明瞭で失敗しやすい
    • 重くなるテスト
    → Laravel の立ち上げ + DB 利用で実行に時間がかかる

    View full-size slide

  11. 11
    Laravel 先生も万能じゃない・・・
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション

    View full-size slide

  12. 12
    どうすればいいの?
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション
    • 依存関係の混沌化
    → Facade の使用を極力控え,Constructor で依存注入する
    • 責務の肥大化
    → レイヤー毎に求められる責務を意識してクラスを分割する
    • 重くなるテスト
    →ビジネスロジックを Laravel から切り離し UnitTest する

    View full-size slide

  13. 13
    今日話すこと
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション
    'BDBEF ཭ΕΛ͠Α͏
    .7$ ʹશͯΛ٧ΊΔͷ͸΍Ίʹ͠Α͏
    6OJU ςετΛॻ͜͏

    View full-size slide

  14. 👋Facade 離れをしよう
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション 14

    View full-size slide

  15. • こんなやつ
    – Auth,Cache,DB,Http,Log,Session,Validator
    etc …
    15
    Facade って
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション

    View full-size slide

  16. Facade に出会った僕
    • Facade って便利だと思ってた
    – どこからでも簡単に呼べるじゃん!
    – どんどん使っていく べきでは?
    • Facade は static メソッドの集まりだと思ってた
    – Laravel は static メソッドを作るのが主流?
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション 16

    View full-size slide

  17. 17
    政治問題
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション

    View full-size slide

  18. 思想がインスコされた僕
    • Facade はできるだけ使わない方がいい
    – 乱用すると秩序が乱れる
    – どこからでも呼べるのがむしろダメ
    – 部分的に使う分にはOK
    • Route,DB::transaction() とか
    • 全然 static メソッドじゃなかった
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション 18

    View full-size slide

  19. 19
    Facade の仕組み
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション
    • ただの Static メソッドに見えるけど実は全然違う
    – Static メソッドとしては存在していない
    Sample::method()
    Facade.php
    __callStatic()
    Facade.php
    getFacadeRoot()
    Facade.php
    resolveFacadeInstance()
    $instance = app()->
    make(Sample::class)
    $instance->method()
    ※ 若干簡略化しています サービスコンテナの機能
    = Laravel の立ち上げが必要
    実体は static じゃなかった!

    View full-size slide

  20. 20
    Facade を使ったとき
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション
    コンテナ
    OK!
    OK!
    また?
    まとめて言えよ
    FacadeA
    FacadeB
    __construct()
    methodA() methodB()
    FacadeC
    FacadeD
    Aを用意して!
    Bを用意して!
    Cを用意して!
    Dを用意して!
    FacadeA
    FacadeB
    Aを用意して!
    Bを用意して!

    View full-size slide

  21. • サービスコンテナを介しているので無駄
    に処理が複雑になる
    • コードを追わないと依存してるものが分
    かりづらい
    21
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション
    Facade を使ったとき

    View full-size slide

  22. 依存関係を確認したくても
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション 22
    • 呼び出し側から実装にジャ
    ンプできない
    • Laravel 標準 Facade は @see
    アノテーションがあるのでまだ
    マシ
    • 自作 Facade は明示的に
    @see を書く or サービスプロ
    バイダを見に行く必要がある
    • Facadeの実体 から 別の
    Facade を呼んだりするといよ
    いよ依存関係の確認が大変

    View full-size slide

  23. じゃぁどうする?
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション 23
    Constructor DI をしよう!

    View full-size slide

  24. 24
    コンストラクタDIを使ったとき
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション
    __construct(A,B,C,D)
    methodA() methodB()
    ご注文の A・B・C・D です
    準備完了!
    ClassD
    準備完了!
    ClassC
    準備完了!
    ClassB
    準備完了!
    ClassA
    準備完了!
    ClassB
    準備完了!
    ClassA

    View full-size slide

  25. • サービスコンテナを使わないので,依存
    注入の処理がシンプルになった
    • コンストラクタを見ただけで依存関係が
    分かるようになった
    25
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション
    コンストラクタDIを使ったとき

    View full-size slide

  26. 26
    既存 Facade どうするの?
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション
    実体をそのまま DI をしよう!

    View full-size slide

  27. 27
    Facade の基底クラス一覧
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション

    View full-size slide

  28. 28
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション
    Facade は 「使用上の注意」をよく読み,
    用法用量を守って正しくお使いください.
    体に異常がみられた方はすぐにご使用を中断し,
    医師にご相談ください.

    View full-size slide

  29. 🎓.7$ ʹશͯΛ٧ΊΔͷ͸
    ΍Ίʹ͠Α͏
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション 29

    View full-size slide

  30. はじまりの街
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション 30
    app
    Models
    Console
    Http
    Controllers
    • Laravel プロジェクトを新
    規作成すると現れるボイ
    ラープレート
    • すでになんか出来上がっ
    てる?

    View full-size slide

  31. Laravel のボイラープレート
    • MVC2 アーキテクチャで出来てる
    – Controller: HTTP リクエストの受け取り
    – (Eloquent)Model: DB アクセス
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション 31
    Web Browser
    Controller
    (Eloquent)Model
    View
    HTTP リクエスト
    DB 操作の依頼
    Database
    DB 操作
    結果の返却
    表示に必要なデータの
    受け渡し
    親の顔より見たアーキテクチャ図
    ビジネスロジックをどこに置く?
    • Controller
    • Model
    レンダリング結果
    レスポンス
    (HTML・JSON)

    View full-size slide

  32. Controller に置くつらみ
    • HTTP を扱う場所と,DB を扱う場所が同じところにな
    り,責務が不明瞭になる
    • HTTPリクエスト起点の大きな機能テストしか書けない
    – 一つのテストで考えることが多すぎる
    • リクエストバリデーション
    • ドメインバリデーション
    • ビジネスロジック
    • レスポンスの整形
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション 32

    View full-size slide

  33. Model に置くつらみ
    • すべてのビジネスロジックが Model と1対1で対応す
    るとは限らない
    • Model から 外部 API を叩く違和感
    • ビジネスロジックに関する例外を置く場所に困る
    – app/Models/Exceptions は違う
    – app/Exceptions はなんか遠い...
    • Eloquent Model が多くのメソッドを持つので,たまにメ
    ソッド名が衝突して命名に悩む
    – delete, update など
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション 33

    View full-size slide

  34. • Model にも Controller にも似たようなロジック
    が現れたり
    • Utility 系クラスとして切り出された謎のロジッ
    クが別のところに現れたり
    34
    ルールを定めないと...
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション

    View full-size slide

  35. 責務分散を助ける Laravel の機能
    • Policy
    – 認可処理の切り出し
    • FormRequest
    – フォームバリデーションの切り出し
    • Resource
    – レスポンス整形処理の切り出し
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション 35

    View full-size slide

  36. • 検索条件が細かいとき
    – if ($request->has(‘email’)) みたいなのが沢山ある
    • 外部 API が絡むとき
    – メッセージを生成して Slack へ通知を送る
    – 弊チームは Slack アプリ開発が多く,このツラミをよく感じ
    ています
    36
    それでも太るもんは太る
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション

    View full-size slide

  37. PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション 37
    最高のアーキテクチャに出会った

    View full-size slide

  38. どんなアーキテクチャ?
    • ビジネスロジックの置き場として UseCase を導
    入 👍
    • UseCase が Eloquent Model や Eloquent Builder に
    依存することを認めて使いやすく 👍
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション 38

    View full-size slide

  39. • HTTP の知識を剥がした純粋なビジネスロジックを置
    く場所が(Models/ 以外で)でき,明確な責務の分割
    ができた
    • Eloquent Model への依存は妥協することで厳格な
    クリーンアーキテクチャより導入コストが低い
    39
    ”なんちゃって” のここが良い!
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション

    View full-size slide

  40. 40
    設計に悩んだらとりあえず
    “なんちゃって”を使ってみよう!
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション

    View full-size slide

  41. 💯Unit テストを書こう
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション 41

    View full-size slide

  42. テスト書いてますか?
    • バグを発見できる
    • 実装のリファクタリングが安全にできる
    ようになる
    • テストを意識した実装をするようになり
    ,自然とコードが綺麗になる
    • 仕様把握にも使える
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション 42

    View full-size slide

  43. Laravel におけるテストの種類
    • Feature テスト
    – Httpリクエスト単位のテスト
    – リクエストを受けててレスポンスを返すまでの一連の流れ
    を検証する
    – 大きな単位のテストなので,時間がかかる
    • Unit テスト
    – メソッド単位のテスト
    – 各々のロジックが正しく動作するかを検証する
    – 小さな単位のテストなので,あまり時間がかからない
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション 43

    View full-size slide

  44. テストに必要な環境
    • Feature テスト
    – bootstrap() を使って Laravel アプリケーションの立ち
    上げが必要
    – DB アクセスを伴うこともある
    – Illuminate¥Foundation¥Testing¥TestCase を継承する
    • Unit テスト
    – PHP が動けば良い
    – PHPUnit¥Framework¥TestCase を継承で済む
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション 44

    View full-size slide

  45. つまり
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション 45
    Feature テストは Laravel に依存するテスト
    Unit テストは Laravel に依存しないテスト

    View full-size slide

  46. • ライブラリに切り出しにくい
    – PHP ライブラリとして切り出すなら大幅なリファクタリングが必要
    • 別のフレームワークで使い回せない
    – フレームワーク固有の機能を使ったコードはコピペでは動
    かない
    – この先ずっとそのフレームワークを使いづつける?
    – もし同じ言語でリプレースするなら,サービスのコアな部分(ビ
    ジネスロジック)はできるだけそのまま使いまわしたい
    46
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション
    (おまけ)「FW に依存する」ということ

    View full-size slide

  47. Laravel は基本 Feature テスト
    • Facade を使用している
    – サービスコンテナを使うためアプリケーション
    の起動が必須
    • Eloquent Model / Builder を使用している
    – DB アクセスを伴うためアプリケーションの起動が
    必須
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション 47

    View full-size slide

  48. ”なんちゃって” も Feature テスト
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション 48
    mpyw. “5年間 Laravel を使って辿り着いた,全然頑張らない「なんちゃってクリーンアーキテクチャ」という落としどころ”.
    Zenn, https://zenn.dev/mpyw/articles/ce7d09eb6d8117#テストどうするの? より抜粋

    View full-size slide

  49. UseCase は Unit テストがしたい
    • もちろん Feature テストは必須
    • しかし網羅性の担保を Feature テストに委ねるのは重す
    ぎる
    – 細かい分岐それぞれの検証でわざわざ一連のテストをする?
    • Unit テストは機能結合前のテストなので細かい分岐な
    どを網羅するのに向いている
    • UseCase などビジネスロジックを置くところでは,Unit テ
    ストを補助的に使えるように実装すべき
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション 49

    View full-size slide

  50. PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション 50
    どうやって?
    • Facade を使うのはもうやめた
    • あとは UseCase から Eloquent を剥がすのみ
    Laravel からロジックを切り離そう!

    View full-size slide

  51. • Entity を導入
    – Eloquent Model の詰め替え先を作る
    • Repository を導入
    – Eloquent Model,Eloquent Builder に依存する DB
    アクセスの処理を切り離す
    51
    UseCase,脱 Eloquent 計画
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション

    View full-size slide

  52. Entity
    • Constructor で属性を受
    け取る
    • Getter で属性を返す
    52
    実装例
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション

    View full-size slide

  53. Model
    • toEntity を実装するこ
    とで,メソッドチェ
    ーンで Entity へ変換が
    可能に
    53
    実装例
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション

    View full-size slide

  54. Repository
    • Eloquent を使って DB
    から値を取得し,Entity
    に変換して返す
    54
    実装例
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション

    View full-size slide

  55. UseCase
    • 依存するクラスはすべ
    て Constructor で注入
    • User データの取得を
    Repository 経由にする
    55
    実装例
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション

    View full-size slide

  56. • UseCase のロジックから Laravel に依存するも
    のがなくなった
    • データの取得部分をモックして,簡単に Unit
    テストが書けるようになった
    56
    Entity & Repository 導入で得られたもの
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション

    View full-size slide

  57. 🔖今回のまとめ
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション 57

    View full-size slide

  58. • Laravel は便利な機能が豊富だけど,Laravel標準の書
    き方で推し進めるとつらみが出てくるよ
    • Facade は依存関係を分かりづらくするよ
    • Model・Controller だけでは責務の分散がしづらいよ
    • Unit テストを適宜導入することで開発体験が向上する

    • なんちゃってクリーンアーキテクチャ はオススメだよ
    58
    今回のまとめ
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション

    View full-size slide

  59. 59
    最後に
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション
    Laravel は使っても使われるな!

    View full-size slide

  60. 60
    ྑ͍ -BSBWFM ϥΠϑΛʂ
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション

    View full-size slide

  61. 61
    次回予告
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション

    View full-size slide

  62. 62
    もっと大規模な Laravel プロジェクトを
    ガチモジュラモノリスでやってみた?
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション

    View full-size slide

  63. 63
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション
    from Yumemi

    View full-size slide

  64. 64
    モジュール境界を意識した
    「なんちゃってクリーンアーキテクチャ」からの進化系(仮)
    from @mpyw
    COMING SOON !!
    PHPerkaigi 2022 04/10 12:45 〜 Track B スポンサーセッション

    View full-size slide