Slide 1

Slide 1 text

循環的複雑度 30 超えのシステムに Laravel × Onion Architecture で 立ち向かっ(た)ている話 2020/07/08 【シューマイ】Tech Lead Engineerから最新技術を学べ!Laravel編 株式会社うるる NJSS事業部 プロダクト開発課 栗原 史明

Slide 2

Slide 2 text

Agenda ● はじめに ● 自己紹介 ● Onion Architecture って何? ● Laravel x Onion Architecture ● 具体例 ● 実際やってみてどうだったか ● まとめ

Slide 3

Slide 3 text

はじめに

Slide 4

Slide 4 text

● 今回お話すること ○ オニオンアーキテクチャの重要となる部分の解説 ○ Laravelで実装する場合の簡単な具体例 ○ 実際に導入してみて改善・実感できたことと課題のお話 ● 話さないこと ○ Laravelの基本的機能の解説 ○ オニオンアーキテクチャを使った詳細な実装のお話 ○ オニオンアーキテクチャの詳細な解説 ○ DDD(ドメイン駆動開発)の詳細なお話 はじめに

Slide 5

Slide 5 text

自己紹介 誰ですかあなた

Slide 6

Slide 6 text

自己紹介 ● 栗原 史明 ● 株式会社うるる ○ NJSS事業部 プロダクト開発課 ● Laravel / Lumen ● Docker / AWS / terraform / CDK ● 認定スクラムマスター ● あつ森で永遠と川を掘ってる

Slide 7

Slide 7 text

株式会社うるる では一緒に働く仲間を募集中! ● 「人のチカラで世界を便利に」 ○ 人のチカラ(クラウドワーカー)を活用したサービスを展開する会社です ● サーバーサイドエンジニア募集中!(2020/07/07現在) ○ 興味がありましたら是非お声掛けください! ○ うるるの歩みと未来 ○ うるるのエンジニア紹介

Slide 8

Slide 8 text

Onion Architecture って何? フレームワークではない、設計のお話

Slide 9

Slide 9 text

Onion Architecture 引用: https://buildersbox.corp-sansan.com/entry/2019/07/10/110000


Slide 10

Slide 10 text

このあたりの本も参考に

Slide 11

Slide 11 text

Q. オニオンアーキテクチャが 実現したいことってなんですか?

Slide 12

Slide 12 text

A. 「重要なもの」を「些細なもの」に 依存させない 引用: https://www.slideshare.net/ShoheiOkada/laravel-shuumai?next_slideshow=1

Slide 13

Slide 13 text

岡田正平さんのスライドが とても綺麗にまとまってます 参考: https://www.slideshare.net/ShoheiOkada/laravel-shuumai?next_slideshow=1

Slide 14

Slide 14 text

Onion Architecture が実現したいこと ● 重要なもの ○ ビジネスロジック ■ システム/プロダクトが目的とする処理を行うところ ■ 例:売上計算のルール、日付の依存関係のルール など ○ ● 些細なもの ○ フレームワーク、DB、テスト、インフラ、UI、ORM etc ○ ※あくまでも「クリーンアーキテクチャ」の考え方で判断した場合

Slide 15

Slide 15 text

Onion Architecture が実現したいこと ● 重要なもの ○ ビジネスロジック ■ システム/プロダクトが目的とする処理を行うところ ■ 例:売上計算のルール、日付の依存関係のルール など ○ 変更が発生しにくい ● 些細なもの ○ フレームワーク、DB、テスト、インフラ、UI、ORM etc ○ 簡単に変更できるもの/すべきもの ※あくまでも「クリーンアーキテクチャ」の考え方で判断した場合

Slide 16

Slide 16 text

Laravel x Onion Architecture では、なぜ我々は [ Laravel ] を選択したのか

Slide 17

Slide 17 text

プロジェクト発足時に抱えてた思い (エンジニア目線) ● メンテナンス性を上げたい ○ Fat Controller / Fat Model で読みづらい ■ メンテの度に4000行超えClass読むのしんどい ○ テストが存在しない、というか循環的複雑度30超え当たり前 のメソッドにテスト書くなんて無理 ● フレームワークであまり悩みたくない ○ フレームワークは開発を補佐するものであり、設計を考える ことに時間を使いたかった

Slide 18

Slide 18 text

なぜ、我々はLaravelを選択したのか ● フレームワークの自由度が高く Onion Architecture の ディレクトリ構成を表現しやすい ● Onion Architecture に必須なDIをデフォルトでサポート ● トラブルシューティングがしやすい

Slide 19

Slide 19 text

Laravel x Onion Architecture ● フレームワークの自由度が高く Onion Architecture の ディレクトリ構成を表現しやすい ○ 基本的なMVCモデルではないディレクトリの切り方でも、 Laravelなら対応できる ■ 自分たちの特性に合わせたディレクトリ構成を組みやすい ○ やっぱり何かと便利なEloquent ○ 足りない機能をComposerで補う動きもやりやすい

Slide 20

Slide 20 text

Laravel x Onion Architecture ● Onion Architecture に必須なDIをデフォルトでサポート ○ Interface から実体Classを呼ぶための機能 ○ Providerに対して app->bind() で設定することができる

Slide 21

Slide 21 text

Laravel x Onion Architecture ● トラブルシューティングがしやすい ○ 公式DocやQiitaなど日本語のドキュメントが豊富 ○ Laravel起因のエラーは大体誰かが経験している ■ ggrな状況になっても割とどうにかなる ○ 挑戦的なアーキテクチャの導入は最初は迷いやすいので、フ レームワーク起因のトラブルが対処しやすいのは迷うポイン トを減らす観点で大きなメリット

Slide 22

Slide 22 text

For Example 簡単な例からイメージを

Slide 23

Slide 23 text

具体例 ● こういう要件があったとする ○ ユーザ情報を保存するAPIを作りたい ○ 保存する内容は 名前 / ニックネーム / メアド ○ ユーザ識別詞としてメアドをsha256でハッシュ化する ※「こんな要件本当に存在するのか?」  という質問については一例なので気にしたら負けです。

Slide 24

Slide 24 text

具体例

Slide 25

Slide 25 text

具体例 データベースを変更したら死ぬ ぴえん

Slide 26

Slide 26 text

要件の実現は出来ている 【が】 「重要なもの」が 「些細なもの」の変更で 処理が壊れてしまう

Slide 27

Slide 27 text

Laravel でどうやって実現するか ● ビジネスロジックの実装 ○ app配下にビジネスロジックを配置するディレクトリを作成 し、そこに集約する ● 永続化層を抽象化 ○ 特定のインフラに依存するものは抽象化する ○ 抽象化したクラスをProviderで紐付ける

Slide 28

Slide 28 text

ビジネスロジックの実装 ● アプリ固有の機能/ルールをClass化しDomain層に表現 ○ Laravelではディレクトリを自由に切りやすい 「メアドでsha256する」という ビジネスロジックが Domain層に表現される

Slide 29

Slide 29 text

永続化層の抽象化 ● Interfaceを定義し、実体Classを実装 ○ EloquentやMySQLなどの処理はここに記述する

Slide 30

Slide 30 text

永続化層の抽象化 ● Interfaceと実体Classを紐付ける LaravelではDIを標準サポート

Slide 31

Slide 31 text

永続化層の抽象化 ● Interfaceで型宣言を しているが、実際の処 理では実体クラスが渡 される

Slide 32

Slide 32 text

A. 「重要なもの」が「些細なもの」に 依存しない形にすることができた! ビジネスロジック DB / フレームワーク / ORM 等

Slide 33

Slide 33 text

実際やってみてどうだったか Laravel を通じて変化に強いコードへ

Slide 34

Slide 34 text

プロジェクト発足時に抱えてた思い (エンジニア目線) ● メンテナンス性を上げたい ○ Fat Controller / Fat Model で読みづらい ■ メンテの度に4000行超えClass読むのしんどい ○ テストが存在しない、というか循環的複雑度30超え当たり前 のメソッドにテスト書くなんて無理 ● フレームワークであまり悩みたくない ○ フレームワークは開発を補佐するものであり、設計を考える ことに時間を使いたかった

Slide 35

Slide 35 text

改善・実感できたこと ● 可読性向上! ○ まだ途中ではありますが、現時点でClass循環的複雑度の平均 値は 5 まで下がりました ○ データベースの構造に依存していたビジネスロジックを分割 することができた ○ これにより関心ごとがClassごとに表現され、可読性が向上

Slide 36

Slide 36 text

改善・実感できたこと ● テストが書けるようになりバグ抑制に繋がった ○ 責務を考えてクラスを分割しているのでその責務に特化した テストを書くことができるようになった ○ DIが使えるためFeatureTestの際にMockを作ってException ケースを検証することも容易 ○ 機能改修/拡張をする際も実装済テストがあることでデグレ検 知ができる安心感

Slide 37

Slide 37 text

改善・実感できたこと ● トラブルシューティングがしやすい ○ 当初狙っていた「ドキュメントの充実」に起因したトラブル シューティングのしやすさは享受出来た ○ オニオンアーキテクチャの設計に悩んでも、Laravelの使い方 に悩むことは少なかった

Slide 38

Slide 38 text

プロジェクト発足時に抱えてた思い (エンジニア目線) ● メンテナンス性を上げたい ○ Fat Controller / Fat Model で読みづらい ■ メンテの度に4000行超えClass読むのしんどい ○ テストが存在しない、というか循環的複雑度30超え当たり前 のメソッドにテスト書くなんて無理 ● フレームワークであまり悩みたくない ○ フレームワークは開発を補佐するものであり、設計を考える ことに時間を使いたかった Onion Architecture の導入で改善!! Laravel の導入で実現!!

Slide 39

Slide 39 text

● とにかく設計に悩んだ。悩んでる。(※現在進行形) ○ 慣れてないうちはどこの層に書けば良いのか悩んだ ○ 慣れてくると今度はどこまで責務分割させるか悩んだ、今も 悩んでる ■ 完璧に拘り過ぎるとClassの分割が多すぎてしんどい ■ 単純な実装の場合は却って複雑さを招く場合も ■ 私のチームでもインフラ依存の完全な分割はやりきれてないですし、敢えて割り 切っている部分もあります とはいえ課題もあります

Slide 40

Slide 40 text

● Fat Repository予備軍はある ○ データの依存関係が複雑なRepositoryの実装でmethod数が多 くなり、600行超えのものも ○ 今のところ、メンテナンスにはさほど影響を与えていないの で放置してるが悪化する前に責務を上手く切り分けて薄くし たい とはいえ課題もあります

Slide 41

Slide 41 text

まとめ Laravel を通じて変化に強いコードへ

Slide 42

Slide 42 text

Q. オニオンアーキテクチャが 実現したいことってなんですか?

Slide 43

Slide 43 text

A. 「重要なもの」を「些細なもの」に 依存させない 引用: https://www.slideshare.net/ShoheiOkada/laravel-shuumai?next_slideshow=1

Slide 44

Slide 44 text

Onion Architecture が実現したいこと ● 重要なもの ○ ビジネスロジック ■ システム/プロダクトが目的とする処理を行うところ ■ 例:売上計算のルール、日付の依存関係のルール など ○ 変更が発生しにくい ● 些細なもの ○ フレームワーク、DB、テスト、インフラ、UI、ORM etc ○ 簡単に変更できるもの/すべきもの ※あくまでも「クリーンアーキテクチャ」の考え方で判断した場合

Slide 45

Slide 45 text

なぜ、我々はLaravelを選択したのか ● フレームワークの自由度が高く Onion Architecture の ディレクトリ構成を表現しやすい ● Onion Architecture に必須なDIをデフォルトでサポート ● トラブルシューティングがしやすい

Slide 46

Slide 46 text

Laravel でどうやって実現するか ● ビジネスロジックの実装 ○ app配下にビジネスロジックを配置するディレクトリを作成 し、そこに集約する ● 永続化層を抽象化 ○ 特定のインフラに依存するものは抽象化する ○ 抽象化したクラスをProviderで紐付ける

Slide 47

Slide 47 text

プロジェクト発足時に抱えてた思い (エンジニア目線) ● メンテナンス性を上げたい ○ Fat Controller / Fat Model で読みづらい ■ メンテの度に4000行超えClass読むのしんどい ○ テストが存在しない、というか循環的複雑度30超え当たり前 のメソッドにテスト書くなんて無理 ● フレームワークであまり悩みたくない ○ フレームワークは開発を補佐するものであり、設計を考える ことに時間を使いたかった Onion Architecture の導入で改善!! Laravel の導入で実現!!

Slide 48

Slide 48 text

Q. オニオンアーキテクチャって 本当に効果あるの?

Slide 49

Slide 49 text

A. ビジネスロジックが複雑な プロダクトほど刺さると思います 逆にそんなに複雑じゃないよ、 という方が導入するとクラス管理が多くなるので しんどさの方が勝ってしまうかも

Slide 50

Slide 50 text

補足 ● PHP7.4 が使えるなら PHP7.4 以上を推奨 ○ プロパティ変数に型定義ができるので、型推論によりClassで 表現できる内容がより強化される ● 本日会話した内容は Lumen でも(ほぼ)そのまま実現可能 ○ 「Laravel側はAPIのみ」等の条件が揃えば Lumen でも実現可 能。速度要件があるなら一考の余地アリ ○ ただし、Laravel 拡張が使えないパターンがあるので、不安で あれば Laravel を選んでおくと間違いはない