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

依存関係と依存オブジェクト注入

 依存関係と依存オブジェクト注入

社内エンジニアの方々に依存関係と依存オブジェクト注入について布教しようと試みましたʕ◔ϖ◔ʔ

関連テーマ(ドメイン駆動設計と依存性逆転の原則):
https://speakerdeck.com/hiroki_hasegawa/domeinqu-dong-she-ji-toyi-cun-xing-ni-zhuan-falseyuan-ze

個人リポジトリ:
https://github.com/hiroki-it

プロフィール:
https://www.wantedly.com/id/h_hasegawa

7cb78d6108cc74bec0f2f001127f662a?s=128

Hiroki Hasegawa

June 25, 2021
Tweet

Transcript

  1. 依存関係 と 依存オブジェクト注入 株式会社ユニクエスト 長谷川広樹 github.com/hiroki-it

  2. 自己紹介 長谷川広樹(はせがわひろき) ▪ 経歴 『生き物の研究者になるぞ! ▶ IT技術おもしろいな... ▶ エンジニアになるぞ!』 を経て,バックエンドエンジニアになった.

    現在は,SRE をやっている. ▪ 関心のある技術領域 拡張性,保守性,可読性を高める技術: ドメイン駆動設計,アーキテクチャ,クラウドインフラ,IaC,コンテナ,CI/CD,Go,etc... github.com/hiroki-it
  3. 目次 ▪ なぜ,我々は依存関係を理解する必要がある? ▪ 依存(Dependency) ▪ 依存とは別視点のオブジェクト間関係性 ▪ 合成(Composition) ▪

    集約(Aggregation) ▪ 依存オブジェクト注入(Dependency Injection) ▪ 依存オブジェクト注入の種類 ▪ 依存オブジェクト注入コンテナ(DIコンテナ) ▪ 余談:ドメイン駆動設計のアーキテクチャがわかるぞ! ▪ 『依存性逆転の原則』についてはまた今度
  4. なぜ,我々は依存関係を理解する必要がある? オブジェクト間の依存関係を 意識しながら 実装されてますでしょうか??

  5. なぜ,我々は依存関係を理解する必要がある? 基本的なMVCから始まりアーキテクチャには オブジェクト間の依存関係を工夫して 保守性の高いシステムを開発しようとする思想がある ⇓ 依存関係を理解しなければ アーキテクチャを正しく使えない!(持論)

  6. 依存(Dependency) ▪ 依存とは クラスAがクラスBを引数/返却値として使用 ⇓ 『 A 』は『B 』に依存 ▪

    クラス図における依存 (例)UserクラスはUserNameクラスを使用 <?php namespace App\Domain\User\Entity; use App\Domain\User\ValueObject\UserName; final class User { // UserNameに依存 public function method(UserName $name): string { return "Hello! " . $name->getName(); } }
  7. 依存から少し離れて補足

  8. 依存とは別視点のオブジェクト間関係性 ▪ 合成と集約 クラスAがクラスBを『データとして保持』. ⇓ 『 A』と『B 』は 合成(Composition)/集約(Aggregation)の関係を持つ ▪

    両者の異なる点 クラスAによって,クラスBのインスタンス生成がどのように制限される かで分類
  9. 合成(Composition) ▪ 合成 クラスBはAありきで生成される ▪ クラス図における合成 (例)UserNameはUserありきで生成 <?php namespace App\Domain\User\Entity;

    use App\Domain\User\ValueObject\UserName; final class User { private UserName $name; // データとして保持 public function method(): string { $name = new UserName(); // 合成の関係 return "Hello! " . $name->getName(); } }
  10. 集約(Aggregation) ▪ 集約 クラスBはAと無関係に生成される関係 ▪ クラス図における集約 (例)UserNameはUserとは無関係に生成 <?php namespace App\Domain\User\Entity;

    use App\Domain\User\ValueObject\UserName; final class User { private UserName $name; // データとして保持 public function __construct(UserName $name) { $this->name = $name; } } <?php $name = new UserName(); $user = new User($name); // 集約の関係
  11. 依存の話に戻ります

  12. 依存(Dependency) ▪ 依存とは クラスAがクラスBを引数/返却値として使用 ⇓ 『 A 』は『B 』に依存 ▪

    クラス図における依存 (例)UserクラスはUserNameクラスを使用 <?php namespace App\Domain\User\Entity; use App\Domain\User\ValueObject\UserName; final class User { // UserNameに依存 public function method(UserName $name): string { return "Hello! " . $name->getName(); } }
  13. 依存オブジェクト注入(Dependency Injection) ▪ 依存オブジェクト注入とは クラスAに『引数として』クラスBに渡すこと. ▪ 依存性注入と訳さないこと  『依存性を注入する』 が概念を適切に説明していないという問題 ⇓

    『依存対象のオブジェクトを注入する』 = 依存オブジェクト注入 https://little-hands.hatenablog.com/entry/2018/05/27/dependency-injection
  14. 依存オブジェクト注入の種類(1) ▪ コンストラクタインジェクション(優勝!!!) constructメソッド経由で依存対象を渡す. ▪ メリット constructメソッドはインスタンス生成時のみ有効. ⇓ セッターを完全に無くした場合に インスタンス生成後に状態を変更不可能.

    ⇓ 不変的な(Immutable)オブジェクト ⇓ より安全なシステム <?php namespace App\Domain\User\Entity; use App\Domain\User\ValueObject\UserName; final class User { private UserName $name; public function __construct(UserName $name) { $this->name = $name; } } <?php $name = new UserName(); $user = new User($name); // インジェクション
  15. 依存オブジェクト注入の種類(2) ▪ セッターインジェクション セッターメソッド経由で依存対象を渡す. ▪ デメリット インスタンス生成後にオブジェクトの状態を変更可能 ⇓ 可変的な(Mutable)オブジェクト ⇓

    ビジネス上ありえない状態のオブジェクトを作れる. ⇓ セキュリティに穴のあるシステム <?php namespace App\Domain\User\Entity; use App\Domain\User\ValueObject\UserName; final class User { private UserName $name; public function setUserName(UserName $name) { $this->name = $name; } } <?php $user = new User(); $name = new UserName(); $user->setUserName($name); // インジェクション
  16. 依存オブジェクト注入の種類(3) ▪ メソッドインジェクション constructメソッドまたはセッター以外で依存対象 を渡す. ▪ デメリット セッターインジェクションと同じ. ▪ ただし

    セッターと同じように使うわけではなければ,用途 によっては問題はない. (コンストラクタインジェクションしか勝たん!) <?php namespace App\Domain\User\Entity; use App\Domain\User\ValueObject\UserName; final class User { public function method(UserName $name) { $name = $name->getName(); // 何らかの処理 } } <?php $user = new User(); $name = new UserName(); $user->method($name); // インジェクション
  17. 依存オブジェクト注入の種類(4) インターフェースインジェクションは割愛...󰢛

  18. 依存オブジェクト注入コンテナ(DIコンテナ) ▪ DIコンテナとは ・依存オブジェクト注入に特化したデザインパターン. ・多くの言語で必須パターンになっている. ▪ PHP ・Pimpleライブラリ ・LaravelのServiceContainer機能 ▪

    Go(ただしGoでは,DIコンテナが黒魔術扱い) ・Google製のWireライブラリ ・Uber製のDigライブラリ <?php use Pimple\Container; use App\Domain\User\Entity\User; use App\Domain\User\ValueObject\UserName; class Container { public function __construct() { $container["user_name"] = function ($container) { return new UserName("Hiroki"); }; // Userへの注入 $container["user"] = function ($container) { return new User($container["user_name"]); }; } }
  19. 余談:ドメイン駆動設計のアーキテクチャがわかるぞ!(1) ▪ オニオンアーキテクチャ(@little_hand_s さんの資料がおすすめ) ・依存関係が,ビジネスロジックを置くドメイン層に向かうように実装. ・ドメイン層は,それ以外のロジック層や外部ライブラリに一切依存しない. little hands' lab(https://little-hands.hatenablog.com/entry/2017/10/11/075634)

  20. 余談:ドメイン駆動設計のアーキテクチャがわかるぞ!(2) ▪ クリーンアーキテクチャ(@nrslib さんの資料がオススメ) ・依存関係が,ビジネスロジックを置くエンティティ層に向かうように実装. ・エンティティ層は,それ以外の層や外部ライブラリに一切依存しない. https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html

  21. 『依存性逆転の原則』についてはまた今度 『依存性逆転の原則』 抽象(インターフェース)に依存するように実装する思想 話が長くなるのでまた今度... 󰢛

  22. 最後に テーマと関係ないけど Gopherくん超かわいい!!! by Takuya Ueda (https://twitter.com/tenntenn) The Gopher character

    is based on the Go mascot designed by Renée French.