Slide 1

Slide 1 text

CakePHPで学ぶDIコンテナ PHPカンファレンス2020 @itosho

Slide 2

Slide 2 text

こんにちは!

Slide 3

Slide 3 text

Discordみてるので、盛り上げてください!

Slide 4

Slide 4 text

どんな25分になるか? This session’s goal

Slide 5

Slide 5 text

今日話すこと ・DIとDIコンテナについての概要 ・CakePHPに新しく導入されるDIコンテナの使い方 ・DIコンテナがCakePHPに導入される意味

Slide 6

Slide 6 text

今日話さないこと ・DI関連の突っ込んだ話  ・例えば、Autowiringやサービスロケーターパターンとの比較は話しません ・CakePHPのDIコンテナの実装の詳細  ・今回は裏側ではなく、使い方にフォーカスします ※ちょっと聴きたい発表と違うな…と思った方はTrack2の「今こそ理解する、PHPの日時計算」がおすすめです! (弊社の同僚が登壇しているので宣伝)

Slide 7

Slide 7 text

皆さんをこんな気持ちにしたい! ・(DIに馴染みがない人)DIやDIコンテナを使ってみよう! ・(CakePHP使っている人)CakePHPでもDIコンテナを使ってみよう! ・普段使っているフレームワークの今後について考えてみよう!

Slide 8

Slide 8 text

自己紹介 ・伊藤 翔 @itoho  ・コネヒト株式会社 執行役員兼CTO ・Backend Engineer / CakePHP Contributor  ・エンジニアキャリア(12年): 金融系SIer->Web系受託->CGMサービス->コネヒト(コミュニティサービス)  ・FW遍歴: 独自のFW->Ruby on Rails->CakePHP->echo ・バイアスがあると思うので、切り口の一つとして聞いてください  ・議論のきっかけになればいいなと思っています!

Slide 9

Slide 9 text

DIとDIコンテナを知る What’s a DI and a DI Container?

Slide 10

Slide 10 text

そもそも、DIとは? ・DI = 「Dependency Injection」の略 ・日本語で言うと「依存性の注入」 “依存性の注入とは、コンポーネント間の依存関係をプログラムのソースコードから排除するために、外部の設定ファ イルなどでオブジェクトを注入できるようにするソフトウェアパターンである。”(Wikipediaから引用)

Slide 11

Slide 11 text

そもそも、DIとは? ・DI = 「Dependency Injection」の略 ・日本語で言うと「依存性の注入」 “依存性の注入とは、コンポーネント間の依存関係をプログラムのソースコードから排除するために、外部の設定ファ イルなどでオブジェクトを注入できるようにするソフトウェアパターンである。”(Wikipediaから引用) なるほど、分からん

Slide 12

Slide 12 text

DIの歴史を知る ・DIという言葉自体はマーティン・ファウラー氏が作成(2004年頃) ・似た概念として「Inversion of Control」(制御の反転)が存在  ・Ioc自体は1994年頃、ロバート・C. マーチン氏(ボブおじさん)が提唱 “制御の反転とは、なんらかの種類のプログラムにおいて、プロシージャを「呼び出す側」と「呼び出される側」が、 従来のプログラムとは逆になるようにする、ということである。”(Wikipediaから引用)

Slide 13

Slide 13 text

DIの歴史を知る ・DIという言葉自体はマーティン・ファウラー氏が作成(2004年頃) ・似た概念として「Inversion of Control」(制御の反転)が存在  ・Ioc自体は1994年頃、ロバート・C. マーチン氏(ボブおじさん)が提唱 “制御の反転とは、なんらかの種類のプログラムにおいて、プロシージャを「呼び出す側」と「呼び出される側」が、 従来のプログラムとは逆になるようにする、ということである。”(Wikipediaから引用) コードで話そう

Slide 14

Slide 14 text

用語の整理 ・サービス: 特定の機能を提供するオブジェクト / 使われる(依存される)側  ・例: AWS SESを使ったメール送信機能を持つクラス、SendGridを使ったメール送信機能を持つクラスなど ・クライアント: サービスを利用するオブジェクト / 使う(依存する)側  ・例: 上述のメール送信機能を利用するコントローラークラスなど ※以降のスライドで登場するサンプルコードの置き場所: https://github.com/itosho/x-cakephp-di-container (スライド内では重要な部分のみを抜粋しています)

Slide 15

Slide 15 text

■サービスのコード

Slide 16

Slide 16 text

■DIじゃないコード

Slide 17

Slide 17 text

問題点 ・一言で言うと、クライアントとサービスが密結合になっている ・クライアントのテスト時にSESが必要になる(実際に送信されてしまう) ・SESからSendGridへ変更する場合、クライアントの修正が必須

Slide 18

Slide 18 text

問題点 ・一言で言うと、クライアントとサービスが密結合になっている ・クライアントのテスト時にSESが必要になる(実際に送信されてしまう) ・SESからSendGridへ変更する場合、クライアントの修正が必須 そこで登場するのがDI

Slide 19

Slide 19 text

■DIなコード(具体に依存)

Slide 20

Slide 20 text

DIの特徴 ・オブジェクトの生成と利用の分離  ・これにより、クライアントの修正なしにSESの送信先を変更することが出来る ・制御の反転  ・❌クライアントがサービスを呼ぶ  ・⭕サービスが外部からクライアントに注入  ・今回の注入方法は「コンストラクターインジェクション」 ・クライアントが具体のサービスに依存していることには変わりがない

Slide 21

Slide 21 text

■サービスのコード(インタフェースあり)

Slide 22

Slide 22 text

■DIなコード(抽象に依存)

Slide 23

Slide 23 text

実装ではなく抽象に依存させる ・一言で言うと、クライアントとサービスが疎結合になっている ・モックを利用することができ、クライアントのテストが容易になる ・SESからSendGridへ変更してもクライアントの修正は不要  ・実際にクライアントの修正が全く必要ないケースは稀だが、影響範囲は相対的に軽微になるはず

Slide 24

Slide 24 text

DIの課題 ・注入するオブジェクトが増えると…? ・オブジェクトの依存関係が複雑になると…? ・オブジェクトを生成するコードの管理が大変なことに!

Slide 25

Slide 25 text

DIの課題 ・注入するオブジェクトが増えると…? ・オブジェクトの依存関係が複雑になると…? ・オブジェクトを生成するコードの管理が大変なことに! そこで登場するのがDIコンテナ

Slide 26

Slide 26 text

DIコンテナ ・アプリケーションにDI機能を提供する仕組み ・オブジェクトの生成を一手に引き受ける ・PHPでの活用 / 実装例: PSR-11, Pimple, league/container, PHP-DIなど

Slide 27

Slide 27 text

■DIコンテナ(league/container)を用いたコード

Slide 28

Slide 28 text

ここまでのまとめ ・DIはソフトウェアを密結合から疎結合にする手法  ・外部からオブジェクトを注入することでモジュール間の依存関係を薄くする  ・具体の実装ではなく、抽象に依存させるのがポイント ・DIコンテナはDI対象となるオブジェクトの管理を一箇所にまとめた箱

Slide 29

Slide 29 text

CakePHPのDIコンテナを試す Try a DI Container on CakePHP

Slide 30

Slide 30 text

CakePHPとDIコンテナ ・CakePHPはこれまでDIコンテナとは距離を取っていた(と思う)  ・下記はDIコンテナについてのIssueの冒頭: https://github.com/cakephp/cakephp/issues/14865

Slide 31

Slide 31 text

CakePHPにおける依存関係管理の歴史 ・Controllerなどに外部からオブジェクトを注入する場合、サービスロケー ター的な手法を採用してきた  ・サービスロケーターと言い切っていいかは自信がない…(つぶやき) ・CakePHP2系: ClassRegistryというグローバルなレジストリを使用 ・CakePHP3系: 局所的なレジストリを作る方針に変更  ・Componentに対してはComponentRegistry、Behaviorに対してはBehaviorRegistryなど

Slide 32

Slide 32 text

■これまでのCakePHPの依存管理

Slide 33

Slide 33 text

CakePHPにDIコンテナがやって来た! ・4.2系からDIコンテナが導入される!  ・2020/12/11時点でRC1版がリリース  ・ちなみにコンストラクターインジェクションではなく、メソッドインジェクションが採用された ・ライブラリとしては「league/container」を利用  ・PSR-11に準拠していれば、ライブラリは差し替えることが出来そう ・「EntryPoint」(Controller, Command)のみDIすることが出来る  ・View, Helper, Table, Mailer, Behaviorは出来ない(アプリケーション層から遠くDIする難易度が高いため)  ・DIコンテナの持つ自由度とCakePHPの持つ制約を両立させた?

Slide 34

Slide 34 text

CakePHPにDIコンテナがやって来た! ・4.2系からDIコンテナが導入される!  ・2020/12/11時点でRC1版がリリース  ・ちなみにコンストラクターインジェクションではなく、メソッドインジェクションが採用された ・ライブラリとしては「league/container」を利用  ・PSR-11に準拠していれば、ライブラリは差し替えることが出来そう ・「EntryPoint」(Controller, Command)のみDIすることが出来る  ・View, Helper, Table, Mailer, Behaviorは出来ない(アプリケーション層から遠くDIする難易度が高いため)  ・DIコンテナの持つ自由度とCakePHPの持つ制約を両立させた? 実際に試してみよう!

Slide 35

Slide 35 text

■DIコンテナを利用したCakePHPの依存管理(サービス)

Slide 36

Slide 36 text

■DIコンテナを使用したCakePHPの依存管理(DIコンテナ)

Slide 37

Slide 37 text

■DIコンテナを使用したCakePHPの依存管理(コントローラー)

Slide 38

Slide 38 text

ここまでのまとめ ・CakePHPはこれまでサービスロケーター的な手法のみを採用してきた ・4.2系からDIコンテナを導入! ・DIコンテナ自体は比較的簡単に取り入れることが出来る  ・サービスクラスを含めた設計の難しさは当然存在する

Slide 39

Slide 39 text

DIコンテナが導入される意味を考える Think about adding a DI Container

Slide 40

Slide 40 text

改めて、CakePHPの特徴 ・RailsライクなシンプルなMVCフレームワーク ・CoC(設定より規約)を重視  ・Pros: チーム開発において「縛り」が効果的、どの案件でも似た構成でスキルのポータビリティ性が高い  ・Cons: 「Cake Way」を学ぶイニシャルコスト、「Cake Way」をはみ出すと途端に苦しくなる ・「90%の解を目指す」(UNIXの哲学)  ・密結合で速く走るためのフレームワーク  ・Laravelのような自由度や柔軟性はない≒Fatなビジネス要件に対処することが相対的に難しい  ・しかし、(いわゆるWeb系の世界では)シンプルなMVCの構成で十分なことが多い

Slide 41

Slide 41 text

改めて、CakePHPの特徴 ・RailsライクなシンプルなMVCフレームワーク ・CoC(設定より規約)を重視  ・Pros: チーム開発において「縛り」が効果的、どの案件でも似た構成でスキルのポータビリティ性が高い  ・Cons: 「Cake Way」を学ぶイニシャルコスト、「Cake Way」をはみ出すと途端に苦しくなる ・「90%の解を目指す」(UNIXの哲学)  ・密結合で速く走るためのフレームワーク  ・Laravelのような自由度や柔軟性はない≒Fatなビジネス要件に対処することが相対的に難しい  ・しかし、(いわゆるWeb系の世界では)シンプルなMVCの構成で十分なことが多い 本当にそうなのか?

Slide 42

Slide 42 text

CakePHPの歴史と周辺技術の変遷 CakePHP 1.x~ CakePHP 2.x CakePHP 3.x~ CakePHP 4.x~ 2011 2006 2015 2019 PHP 7.x~ PHP 8.x~ PHP 5.3.x~ PHP ~5.3.x Web 2.0 PHP ~5.0 2004 Microservices Ajax Laravel Hack BFF GraphQL スマートフォンアプリ jQuery アフターデジタル X-Tech Composer SoR / SoE C10K PHP-FIG HTML5 Zend Framework Xdebug 2.0 PSR-0 PSR-1, 2 PSR-7 PSR-11 PSR-15 React REST ※時系列は正確ではありません(あくまで流れを掴む程度にご利用ください) ※当然ながら、全てを網羅しているわけでもありません(例: クラウド、IoTなど) Serverless

Slide 43

Slide 43 text

時代の流れ ・ここ10年ぐらいでソフトウェア開発は高度複雑化している  ・技術のコモディティ化や抽象化が進み、敷居は下がったが「フルスタック」であることの難易度は上がった  ・技術そのものの進化とソフトウェアが適用される分野が増えた ・ここ数年で「90%の解」が「80%」しか得られなくなってきた感覚がある  ・この感覚自体は個人の感想ですが、昨今「SOLID」なフレームワークが求められているのは間違いない ・その失われた10%を取り戻すのが今回のDIコンテナの導入ではないか?  ・Issueでも開発者のための機能と明言されている: https://github.com/cakephp/cakephp/issues/14865

Slide 44

Slide 44 text

今後どうなるのか? ・今の仕組み(サービスロケーター的な手法)を置き換えなかった ・あくまで実験的な機能としている ・CakePHPの思想を優先し、アドオン的な機能に留めた? ・アーキテクチャ観点で一定揺り戻しがあると考えた?  ・Smart UIパターンが再評価される世界: https://onk.hatenablog.jp/entry/2020/11/11/024531

Slide 45

Slide 45 text

今後どうなるのか? ・今の仕組み(サービスロケーター的な手法)を置き換えなかった ・あくまで実験的な機能としている ・CakePHPの思想を優先し、アドオン的な機能に留めた? ・アーキテクチャ観点で一定揺り戻しがあると考えた?  ・Smart UIパターンが再評価される世界: https://onk.hatenablog.jp/entry/2020/11/11/024531 分からない/(^o^)\

Slide 46

Slide 46 text

その上で、出来ること ・フレームワークを骨の髄まで味わい尽くす!  ・開発効率を高めるには、フレームワークが持つポテンシャルを120%引き出す必要がある  ・CakePHPに限った話ではないが、「CoC」系のフレームワークでは特に重要だと思う ・まずは、積極的にDIコンテナを使ってみる!  ・公式がDIコンテナをサポートした意義は少なくない   ・恐らく、最初はDIコンテナとComponentの使い分けのプラクティスを整理するところからかな…? ・そして、その結果をコミュニティへフィードバックする!

Slide 47

Slide 47 text

その上で、出来ること ・フレームワークを骨の髄まで味わい尽くす!  ・開発効率を高めるには、フレームワークが持つポテンシャルを120%引き出す必要がある  ・CakePHPに限った話ではないが、「CoC」系のフレームワークでは特に重要だと思う ・まずは、積極的にDIコンテナを使ってみる!  ・公式がDIコンテナをサポートした意義は少なくない   ・恐らく、最初はDIコンテナとComponentの使い分けのプラクティスを整理するところからかな…? ・そして、その結果をコミュニティへフィードバックする!  ・未来を予測する最善の方法は、それを発明することだ(by アラン・ケイ氏) よりよいソフトウェアを追求する旅路は続く…

Slide 48

Slide 48 text

まとめ tl;dr

Slide 49

Slide 49 text

今北産業 DIとDIコンテナについての概要 ・DIはソフトウェアを密結合から疎結合にする手法 ・DIコンテナはDI対象となるオブジェクトの管理を一箇所にまとめた箱 CakePHPに新しく導入されるDIコンテナの使い方 ・CakePHP4.2系から実験的にDIコンテナを導入! ・DIコンテナ自体は比較的簡単に取り入れることが出来る DIコンテナがCakePHPに導入される意味 ・変化する時代の中で「失われた10%の解」を取り戻すための打ち手の一つ(なのでは?) ・進化を遂げたCakePHPの今後に期待!1エンジニアとしてもその進化に貢献していきたい!

Slide 50

Slide 50 text

参考資料1/2 【DI / DIコンテナの理解を深めるために参考にさせていただいたみなさん】 ・Inversion of ControlコンテナとDependency Injectionパターン: https://kakutani.com/trans/fowler/injection.html ・Google/Guice(DIコンテナ)のモチベーション: https://github.com/google/guice/wiki/Motivation ・History of Dependency Injection (DI): https://yauritux.wordpress.com/2011/04/03/history-of-dependency-injection-di/ ・何故DIコンテナが必要なのか: https://qiita.com/kabosu3d/items/200d14c68b8c0e5b2092 ・IoCとService LocatorとDIの関係: https://yotiky.hatenablog.com/entry/2018/09/28/IoCとService_LocatorとDIの関係 ・やはりあなた方のDependency Injectionはまちがっている。  http://blog.a-way-out.net/blog/2015/08/31/your-dependency-injection-is-wrong-as-I-expected/ 【アーキテクチャの変遷の理解を深めるために参考にさせていただいたみなさん】 ・Smart UI パターンが再評価される世界: https://onk.hatenablog.jp/entry/2020/11/11/024531 ・JetBrainsのPHP25周年インフォグラフィック: https://www.jetbrains.com/ja-jp/lp/php-25/

Slide 51

Slide 51 text

参考資料2/2 【CakePHPの理解を深めるために参考にさせていただいたみなさん】 ・CakePHPにDIコンテナが入った(る)と聞いて見学に行ってきました: https://daisuki.nichiyoubi.land/entry/cakephp-feature-di ・PSR-11対応のDIコンテナをCakePHP3で使う: https://nextat.co.jp/staff/archives/234 【CakePHP公式情報のみなさん】 ・DIコンテナについてのIssue: https://github.com/cakephp/cakephp/issues/14865 ・DIの使い方をまとめたドキュメント: https://book.cakephp.org/4.next/en/development/dependency-injection.html ・Lead DeveloperであるMark Story氏の発表資料: https://www.slideshare.net/markstory/dependency-injection-in-cakephp

Slide 52

Slide 52 text

おまけ Additional Time

Slide 53

Slide 53 text

最後に宣伝です!

Slide 54

Slide 54 text

与太話 ・尻切れトンボを防ぐために、宣伝を本編の外部から注入しました ・これを登壇における「制御の反転」と言います(言いません)

Slide 55

Slide 55 text

会社紹介 ・「あなたの家族像が実現できる社会をつくる」というビジョンを掲げ、  ママの3人に1人(※) が利用する「ママリ」などを運営しています。  ・12月1日にロゴを含めた会社のリブランディングを発表しました! ※:「ママリ」で2019年内に出産予定と設定したユーザー数と、厚生労働省発表「人口動態統計」の出生数から算出。

Slide 56

Slide 56 text

エンジニア向けのミートアップイベントやります! ・12/17(木)19:30〜21:00  ・https://connehito.connpass.com/event/197332/ ・サービス開発の悩みをぶっちゃける会  ・例: ぶっちゃけ上手くいかなかった施策は?  ・オンライン開催ですが、みんなでわいわい話す場になります! ・サービス開発に興味があれば誰でもOK!  ・もちろん、コネヒトに興味がある人でもOK!  ・先日公開した「Connehito Tech Vision」についても話します  ・https://connehito.com/recruit/tech/

Slide 57

Slide 57 text

ご清聴ありがとうございました!