SlideShare a Scribd company logo
1 of 13
DI/DIコンテナを一から学んでみた
TypeScriptでの軽量DI実装まで
DIとは?
- デザインパターンの1つ
- Dependency Injection(依存性の注入)
- 依存性は性質ではなく、依存対象はインスタンス
- あるクラスが使用する他のクラスのインスタンスをコンストラクタなどを通
じて外部から渡すようなクラス設計
- 一つの部品だけで開発・テストができ効率的
DIコンテナとは?
- DIの実現をお手伝いするためのフレームワーク
- コンテナ = 容器、入れ物
- すごく簡単にいうと、「hogeにこのクラスのオブジェクトを注入して」とい
う設定を書いておくと自動でインスタンスを渡してくれる
- 通常インスタンスを生成すると 直接 new するので 至るところに依存が生ま
れてしてしまう、見通しが悪くなるのを改善させる
DIコンテナとは?
何が嬉しいのか?
1. 依存関係逆転の原則がキレイに実装できる
2. 依存先の実装が終わらなくとも、import側の実装ができる
3. 依存先が変更されても、import側を修正しなくてもよい
4. 依存が引き剥がされているので、テスト時にmockを流すだけで良い
TypeScriptにおける課題
- JSには型が存在しない
- 解決策:ライブラリ
- InversifyJS:最もスターが多いが、最近は活発ではない
- TSyringe:Microsoftが主導で開発、現在も継続して開発が進められている
- 解決策:自作
- decorator:依存と注入対象のコードになんらかのマーキングをして、それだけで自動的に依
存関係の登録ができる
- Reflection:ES6から導入。JSの機能でインターセプトが可能な JavaScript 操作に対するメソ
ッドを提供するビルトインオブジェクト
- reflect-metadata:consturcotr からの引数取得と、interface 経由で injection するための一時
的に interface と実装との紐付けの保管
自作軽量DIに挑戦
- 今回はDIコンテナを使わないケースを自作
実際のコード: Repository
実際のコード: Application
自作軽量DIのコード
課題
- DIするInstanceが増えるとDIクラスが巨大になる
- import がドンドン増える
- Discriminated Unionなので、typeがドンドン増える
- Function Overloadingなので、ドンドン増える
- 全てのInstanceがDIされている訳ではない
- Nuxtで実装したので、次はpulaginへ差し込みたい
まとめ
- DIとは?
- デザインパターンの1つ
- Dependency Injection(依存性の注入)
- 依存性は性質ではなく、依存対象はインスタンス
- DIコンテナとは?
- DIの実現をお手伝いするためのフレームワーク
- コンテナ = 入れ物
- 何が嬉しいの?
- 依存関係逆転の原則がキレイに実装できる
- 依存先の実装が終わらなくとも、import側の実装ができる
- 依存先が変更されても、import側を修正しなくてもよい
- 依存が引き剥がされているので、テストやlocal開発時にmockを流すだけで良い
- 軽量DI自作してみて
- 思ったより型補完効いたけど、課題が残った
- 色々身になった

More Related Content

What's hot

ドメイン駆動設計 ( DDD ) をやってみよう
ドメイン駆動設計 ( DDD ) をやってみようドメイン駆動設計 ( DDD ) をやってみよう
ドメイン駆動設計 ( DDD ) をやってみよう増田 亨
 
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話
DDD x CQRS   更新系と参照系で異なるORMを併用して上手くいった話DDD x CQRS   更新系と参照系で異なるORMを併用して上手くいった話
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話Koichiro Matsuoka
 
ドメインロジックに集中せよ 〜ドメイン駆動設計 powered by Spring
ドメインロジックに集中せよ 〜ドメイン駆動設計 powered by Springドメインロジックに集中せよ 〜ドメイン駆動設計 powered by Spring
ドメインロジックに集中せよ 〜ドメイン駆動設計 powered by Spring増田 亨
 
【Unity道場スペシャル 2017京都】最適化をする前に覚えておきたい技術
【Unity道場スペシャル 2017京都】最適化をする前に覚えておきたい技術【Unity道場スペシャル 2017京都】最適化をする前に覚えておきたい技術
【Unity道場スペシャル 2017京都】最適化をする前に覚えておきたい技術Unity Technologies Japan K.K.
 
ドメイン駆動設計入門
ドメイン駆動設計入門ドメイン駆動設計入門
ドメイン駆動設計入門Takuya Kitamura
 
ドメイン駆動設計のための Spring の上手な使い方
ドメイン駆動設計のための Spring の上手な使い方ドメイン駆動設計のための Spring の上手な使い方
ドメイン駆動設計のための Spring の上手な使い方増田 亨
 
ネットワーク ゲームにおけるTCPとUDPの使い分け
ネットワーク ゲームにおけるTCPとUDPの使い分けネットワーク ゲームにおけるTCPとUDPの使い分け
ネットワーク ゲームにおけるTCPとUDPの使い分けモノビット エンジン
 
オブジェクト指向できていますか?
オブジェクト指向できていますか?オブジェクト指向できていますか?
オブジェクト指向できていますか?Moriharu Ohzu
 
オブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツオブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツ増田 亨
 
ドメイン駆動設計 モデリング_実装入門勉強会_2020.3.8
ドメイン駆動設計 モデリング_実装入門勉強会_2020.3.8ドメイン駆動設計 モデリング_実装入門勉強会_2020.3.8
ドメイン駆動設計 モデリング_実装入門勉強会_2020.3.8Koichiro Matsuoka
 
3週連続DDDその2 深いモデルの探求(ドメイン駆動設計 第3部)
3週連続DDDその2  深いモデルの探求(ドメイン駆動設計 第3部)3週連続DDDその2  深いモデルの探求(ドメイン駆動設計 第3部)
3週連続DDDその2 深いモデルの探求(ドメイン駆動設計 第3部)増田 亨
 
Unity開発で使える設計の話+Zenjectの紹介
Unity開発で使える設計の話+Zenjectの紹介Unity開発で使える設計の話+Zenjectの紹介
Unity開発で使える設計の話+Zenjectの紹介torisoup
 
ドメイン駆動設計 基本を理解する
ドメイン駆動設計 基本を理解するドメイン駆動設計 基本を理解する
ドメイン駆動設計 基本を理解する増田 亨
 
リッチなドメインモデル 名前探し
リッチなドメインモデル 名前探しリッチなドメインモデル 名前探し
リッチなドメインモデル 名前探し増田 亨
 
私がドメイン駆動設計をやる理由
私がドメイン駆動設計をやる理由私がドメイン駆動設計をやる理由
私がドメイン駆動設計をやる理由増田 亨
 
新入社員のための大規模ゲーム開発入門 サーバサイド編
新入社員のための大規模ゲーム開発入門 サーバサイド編新入社員のための大規模ゲーム開発入門 サーバサイド編
新入社員のための大規模ゲーム開発入門 サーバサイド編infinite_loop
 
それはYAGNIか? それとも思考停止か?
それはYAGNIか? それとも思考停止か?それはYAGNIか? それとも思考停止か?
それはYAGNIか? それとも思考停止か?Yoshitaka Kawashima
 
DDDオンライン勉強会#2 「集約・境界付けられたコンテキスト」
DDDオンライン勉強会#2 「集約・境界付けられたコンテキスト」 DDDオンライン勉強会#2 「集約・境界付けられたコンテキスト」
DDDオンライン勉強会#2 「集約・境界付けられたコンテキスト」 Koichiro Matsuoka
 
ドメイン駆動設計(DDD)の実践Part2
ドメイン駆動設計(DDD)の実践Part2ドメイン駆動設計(DDD)の実践Part2
ドメイン駆動設計(DDD)の実践Part2増田 亨
 
現場で役立つシステム設計の原則
現場で役立つシステム設計の原則現場で役立つシステム設計の原則
現場で役立つシステム設計の原則増田 亨
 

What's hot (20)

ドメイン駆動設計 ( DDD ) をやってみよう
ドメイン駆動設計 ( DDD ) をやってみようドメイン駆動設計 ( DDD ) をやってみよう
ドメイン駆動設計 ( DDD ) をやってみよう
 
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話
DDD x CQRS   更新系と参照系で異なるORMを併用して上手くいった話DDD x CQRS   更新系と参照系で異なるORMを併用して上手くいった話
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話
 
ドメインロジックに集中せよ 〜ドメイン駆動設計 powered by Spring
ドメインロジックに集中せよ 〜ドメイン駆動設計 powered by Springドメインロジックに集中せよ 〜ドメイン駆動設計 powered by Spring
ドメインロジックに集中せよ 〜ドメイン駆動設計 powered by Spring
 
【Unity道場スペシャル 2017京都】最適化をする前に覚えておきたい技術
【Unity道場スペシャル 2017京都】最適化をする前に覚えておきたい技術【Unity道場スペシャル 2017京都】最適化をする前に覚えておきたい技術
【Unity道場スペシャル 2017京都】最適化をする前に覚えておきたい技術
 
ドメイン駆動設計入門
ドメイン駆動設計入門ドメイン駆動設計入門
ドメイン駆動設計入門
 
ドメイン駆動設計のための Spring の上手な使い方
ドメイン駆動設計のための Spring の上手な使い方ドメイン駆動設計のための Spring の上手な使い方
ドメイン駆動設計のための Spring の上手な使い方
 
ネットワーク ゲームにおけるTCPとUDPの使い分け
ネットワーク ゲームにおけるTCPとUDPの使い分けネットワーク ゲームにおけるTCPとUDPの使い分け
ネットワーク ゲームにおけるTCPとUDPの使い分け
 
オブジェクト指向できていますか?
オブジェクト指向できていますか?オブジェクト指向できていますか?
オブジェクト指向できていますか?
 
オブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツオブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツ
 
ドメイン駆動設計 モデリング_実装入門勉強会_2020.3.8
ドメイン駆動設計 モデリング_実装入門勉強会_2020.3.8ドメイン駆動設計 モデリング_実装入門勉強会_2020.3.8
ドメイン駆動設計 モデリング_実装入門勉強会_2020.3.8
 
3週連続DDDその2 深いモデルの探求(ドメイン駆動設計 第3部)
3週連続DDDその2  深いモデルの探求(ドメイン駆動設計 第3部)3週連続DDDその2  深いモデルの探求(ドメイン駆動設計 第3部)
3週連続DDDその2 深いモデルの探求(ドメイン駆動設計 第3部)
 
Unity開発で使える設計の話+Zenjectの紹介
Unity開発で使える設計の話+Zenjectの紹介Unity開発で使える設計の話+Zenjectの紹介
Unity開発で使える設計の話+Zenjectの紹介
 
ドメイン駆動設計 基本を理解する
ドメイン駆動設計 基本を理解するドメイン駆動設計 基本を理解する
ドメイン駆動設計 基本を理解する
 
リッチなドメインモデル 名前探し
リッチなドメインモデル 名前探しリッチなドメインモデル 名前探し
リッチなドメインモデル 名前探し
 
私がドメイン駆動設計をやる理由
私がドメイン駆動設計をやる理由私がドメイン駆動設計をやる理由
私がドメイン駆動設計をやる理由
 
新入社員のための大規模ゲーム開発入門 サーバサイド編
新入社員のための大規模ゲーム開発入門 サーバサイド編新入社員のための大規模ゲーム開発入門 サーバサイド編
新入社員のための大規模ゲーム開発入門 サーバサイド編
 
それはYAGNIか? それとも思考停止か?
それはYAGNIか? それとも思考停止か?それはYAGNIか? それとも思考停止か?
それはYAGNIか? それとも思考停止か?
 
DDDオンライン勉強会#2 「集約・境界付けられたコンテキスト」
DDDオンライン勉強会#2 「集約・境界付けられたコンテキスト」 DDDオンライン勉強会#2 「集約・境界付けられたコンテキスト」
DDDオンライン勉強会#2 「集約・境界付けられたコンテキスト」
 
ドメイン駆動設計(DDD)の実践Part2
ドメイン駆動設計(DDD)の実践Part2ドメイン駆動設計(DDD)の実践Part2
ドメイン駆動設計(DDD)の実践Part2
 
現場で役立つシステム設計の原則
現場で役立つシステム設計の原則現場で役立つシステム設計の原則
現場で役立つシステム設計の原則
 

Similar to DiI/DIコンテナを一から学んでみた

コンソールアプリケーションでDIを使う
コンソールアプリケーションでDIを使うコンソールアプリケーションでDIを使う
コンソールアプリケーションでDIを使うCore Concept Technologies
 
Spring勉強会
Spring勉強会Spring勉強会
Spring勉強会gaaupp
 
iOSやAndroidアプリ開発のGoodPractice
iOSやAndroidアプリ開発のGoodPracticeiOSやAndroidアプリ開発のGoodPractice
iOSやAndroidアプリ開発のGoodPracticeKen Morishita
 
2010/12/16 FxUG Robotlegsの発表資料
2010/12/16 FxUG Robotlegsの発表資料2010/12/16 FxUG Robotlegsの発表資料
2010/12/16 FxUG Robotlegsの発表資料豊 満石
 
T35 ASP.NET MVCを使ったTDD入門
T35 ASP.NET MVCを使ったTDD入門T35 ASP.NET MVCを使ったTDD入門
T35 ASP.NET MVCを使ったTDD入門normalian
 
Do you know Dependency Injection ?
Do you know Dependency Injection ?Do you know Dependency Injection ?
Do you know Dependency Injection ?Masayuki IZUMI
 
Net なプロジェクトでも jenkins を使ってみた
Net なプロジェクトでも jenkins を使ってみたNet なプロジェクトでも jenkins を使ってみた
Net なプロジェクトでも jenkins を使ってみたOda Shinsuke
 
レガシーコード改善ガイド 第7章 いつまでたっても変更作業が終わりません
レガシーコード改善ガイド 第7章 いつまでたっても変更作業が終わりませんレガシーコード改善ガイド 第7章 いつまでたっても変更作業が終わりません
レガシーコード改善ガイド 第7章 いつまでたっても変更作業が終わりませんTakahiro Okada
 

Similar to DiI/DIコンテナを一から学んでみた (10)

コンソールアプリケーションでDIを使う
コンソールアプリケーションでDIを使うコンソールアプリケーションでDIを使う
コンソールアプリケーションでDIを使う
 
Spring勉強会
Spring勉強会Spring勉強会
Spring勉強会
 
iOSやAndroidアプリ開発のGoodPractice
iOSやAndroidアプリ開発のGoodPracticeiOSやAndroidアプリ開発のGoodPractice
iOSやAndroidアプリ開発のGoodPractice
 
2010/12/16 FxUG Robotlegsの発表資料
2010/12/16 FxUG Robotlegsの発表資料2010/12/16 FxUG Robotlegsの発表資料
2010/12/16 FxUG Robotlegsの発表資料
 
T35 ASP.NET MVCを使ったTDD入門
T35 ASP.NET MVCを使ったTDD入門T35 ASP.NET MVCを使ったTDD入門
T35 ASP.NET MVCを使ったTDD入門
 
Do you know Dependency Injection ?
Do you know Dependency Injection ?Do you know Dependency Injection ?
Do you know Dependency Injection ?
 
Net なプロジェクトでも jenkins を使ってみた
Net なプロジェクトでも jenkins を使ってみたNet なプロジェクトでも jenkins を使ってみた
Net なプロジェクトでも jenkins を使ってみた
 
Jakarta CDI 4.0
Jakarta CDI 4.0Jakarta CDI 4.0
Jakarta CDI 4.0
 
レガシーコード改善ガイド 第7章 いつまでたっても変更作業が終わりません
レガシーコード改善ガイド 第7章 いつまでたっても変更作業が終わりませんレガシーコード改善ガイド 第7章 いつまでたっても変更作業が終わりません
レガシーコード改善ガイド 第7章 いつまでたっても変更作業が終わりません
 
Spring4Dの紹介
Spring4Dの紹介Spring4Dの紹介
Spring4Dの紹介
 

More from tak

可読性について リーダブルコード Part5(優れたテストコード2)
可読性について リーダブルコード Part5(優れたテストコード2)可読性について リーダブルコード Part5(優れたテストコード2)
可読性について リーダブルコード Part5(優れたテストコード2)tak
 
可読性について リーダブルコード Part4(優れたテストコード1)
可読性について リーダブルコード Part4(優れたテストコード1)可読性について リーダブルコード Part4(優れたテストコード1)
可読性について リーダブルコード Part4(優れたテストコード1)tak
 
可読性について リーダブルコード Part3(コードの再構築)
可読性について リーダブルコード Part3(コードの再構築)可読性について リーダブルコード Part3(コードの再構築)
可読性について リーダブルコード Part3(コードの再構築)tak
 
可読性について リーダブルコード Part2(ループとロジックの単純化)
可読性について リーダブルコード Part2(ループとロジックの単純化)可読性について リーダブルコード Part2(ループとロジックの単純化)
可読性について リーダブルコード Part2(ループとロジックの単純化)tak
 
可読性について リーダブルコード part1(表面上の改善)
可読性について リーダブルコード part1(表面上の改善)可読性について リーダブルコード part1(表面上の改善)
可読性について リーダブルコード part1(表面上の改善)tak
 
TypeScriptのdecoratorについて
TypeScriptのdecoratorについてTypeScriptのdecoratorについて
TypeScriptのdecoratorについてtak
 
Rust + web assemblyやってみた
Rust + web assemblyやってみたRust + web assemblyやってみた
Rust + web assemblyやってみたtak
 
第ⅴ部:clean architecture アーキテクチャ Part8
第ⅴ部:clean architecture アーキテクチャ Part8第ⅴ部:clean architecture アーキテクチャ Part8
第ⅴ部:clean architecture アーキテクチャ Part8tak
 
第ⅴ部:clean architecture アーキテクチャ Part7
第ⅴ部:clean architecture アーキテクチャ Part7第ⅴ部:clean architecture アーキテクチャ Part7
第ⅴ部:clean architecture アーキテクチャ Part7tak
 
第ⅴ部:clean architecture アーキテクチャ Part6
第ⅴ部:clean architecture アーキテクチャ Part6第ⅴ部:clean architecture アーキテクチャ Part6
第ⅴ部:clean architecture アーキテクチャ Part6tak
 
第ⅴ部:clean architecture アーキテクチャ Part5
第ⅴ部:clean architecture アーキテクチャ Part5第ⅴ部:clean architecture アーキテクチャ Part5
第ⅴ部:clean architecture アーキテクチャ Part5tak
 
第ⅴ部:clean architecture アーキテクチャ Part4
第ⅴ部:clean architecture アーキテクチャ Part4第ⅴ部:clean architecture アーキテクチャ Part4
第ⅴ部:clean architecture アーキテクチャ Part4tak
 
第ⅴ部:clean architecture アーキテクチャ Part3
第ⅴ部:clean architecture アーキテクチャ Part3第ⅴ部:clean architecture アーキテクチャ Part3
第ⅴ部:clean architecture アーキテクチャ Part3tak
 
第ⅴ部:clean architecture アーキテクチャ Part2
第ⅴ部:clean architecture アーキテクチャ Part2第ⅴ部:clean architecture アーキテクチャ Part2
第ⅴ部:clean architecture アーキテクチャ Part2tak
 
第ⅴ部:clean architecture アーキテクチャ Part1
第ⅴ部:clean architecture アーキテクチャ Part1第ⅴ部:clean architecture アーキテクチャ Part1
第ⅴ部:clean architecture アーキテクチャ Part1tak
 
第ⅳ部:Clean architecture コンポーネントの原則
第ⅳ部:Clean architecture コンポーネントの原則第ⅳ部:Clean architecture コンポーネントの原則
第ⅳ部:Clean architecture コンポーネントの原則tak
 
第ⅲ部:Clean architecture 設計の原則
第ⅲ部:Clean architecture 設計の原則第ⅲ部:Clean architecture 設計の原則
第ⅲ部:Clean architecture 設計の原則tak
 
第ⅱ部:Clean architecture 構成要素から始めよ
第ⅱ部:Clean architecture 構成要素から始めよ第ⅱ部:Clean architecture 構成要素から始めよ
第ⅱ部:Clean architecture 構成要素から始めよtak
 
第ⅰ部:Clean Architecture イントロダクション
第ⅰ部:Clean Architecture イントロダクション第ⅰ部:Clean Architecture イントロダクション
第ⅰ部:Clean Architecture イントロダクションtak
 

More from tak (19)

可読性について リーダブルコード Part5(優れたテストコード2)
可読性について リーダブルコード Part5(優れたテストコード2)可読性について リーダブルコード Part5(優れたテストコード2)
可読性について リーダブルコード Part5(優れたテストコード2)
 
可読性について リーダブルコード Part4(優れたテストコード1)
可読性について リーダブルコード Part4(優れたテストコード1)可読性について リーダブルコード Part4(優れたテストコード1)
可読性について リーダブルコード Part4(優れたテストコード1)
 
可読性について リーダブルコード Part3(コードの再構築)
可読性について リーダブルコード Part3(コードの再構築)可読性について リーダブルコード Part3(コードの再構築)
可読性について リーダブルコード Part3(コードの再構築)
 
可読性について リーダブルコード Part2(ループとロジックの単純化)
可読性について リーダブルコード Part2(ループとロジックの単純化)可読性について リーダブルコード Part2(ループとロジックの単純化)
可読性について リーダブルコード Part2(ループとロジックの単純化)
 
可読性について リーダブルコード part1(表面上の改善)
可読性について リーダブルコード part1(表面上の改善)可読性について リーダブルコード part1(表面上の改善)
可読性について リーダブルコード part1(表面上の改善)
 
TypeScriptのdecoratorについて
TypeScriptのdecoratorについてTypeScriptのdecoratorについて
TypeScriptのdecoratorについて
 
Rust + web assemblyやってみた
Rust + web assemblyやってみたRust + web assemblyやってみた
Rust + web assemblyやってみた
 
第ⅴ部:clean architecture アーキテクチャ Part8
第ⅴ部:clean architecture アーキテクチャ Part8第ⅴ部:clean architecture アーキテクチャ Part8
第ⅴ部:clean architecture アーキテクチャ Part8
 
第ⅴ部:clean architecture アーキテクチャ Part7
第ⅴ部:clean architecture アーキテクチャ Part7第ⅴ部:clean architecture アーキテクチャ Part7
第ⅴ部:clean architecture アーキテクチャ Part7
 
第ⅴ部:clean architecture アーキテクチャ Part6
第ⅴ部:clean architecture アーキテクチャ Part6第ⅴ部:clean architecture アーキテクチャ Part6
第ⅴ部:clean architecture アーキテクチャ Part6
 
第ⅴ部:clean architecture アーキテクチャ Part5
第ⅴ部:clean architecture アーキテクチャ Part5第ⅴ部:clean architecture アーキテクチャ Part5
第ⅴ部:clean architecture アーキテクチャ Part5
 
第ⅴ部:clean architecture アーキテクチャ Part4
第ⅴ部:clean architecture アーキテクチャ Part4第ⅴ部:clean architecture アーキテクチャ Part4
第ⅴ部:clean architecture アーキテクチャ Part4
 
第ⅴ部:clean architecture アーキテクチャ Part3
第ⅴ部:clean architecture アーキテクチャ Part3第ⅴ部:clean architecture アーキテクチャ Part3
第ⅴ部:clean architecture アーキテクチャ Part3
 
第ⅴ部:clean architecture アーキテクチャ Part2
第ⅴ部:clean architecture アーキテクチャ Part2第ⅴ部:clean architecture アーキテクチャ Part2
第ⅴ部:clean architecture アーキテクチャ Part2
 
第ⅴ部:clean architecture アーキテクチャ Part1
第ⅴ部:clean architecture アーキテクチャ Part1第ⅴ部:clean architecture アーキテクチャ Part1
第ⅴ部:clean architecture アーキテクチャ Part1
 
第ⅳ部:Clean architecture コンポーネントの原則
第ⅳ部:Clean architecture コンポーネントの原則第ⅳ部:Clean architecture コンポーネントの原則
第ⅳ部:Clean architecture コンポーネントの原則
 
第ⅲ部:Clean architecture 設計の原則
第ⅲ部:Clean architecture 設計の原則第ⅲ部:Clean architecture 設計の原則
第ⅲ部:Clean architecture 設計の原則
 
第ⅱ部:Clean architecture 構成要素から始めよ
第ⅱ部:Clean architecture 構成要素から始めよ第ⅱ部:Clean architecture 構成要素から始めよ
第ⅱ部:Clean architecture 構成要素から始めよ
 
第ⅰ部:Clean Architecture イントロダクション
第ⅰ部:Clean Architecture イントロダクション第ⅰ部:Clean Architecture イントロダクション
第ⅰ部:Clean Architecture イントロダクション
 

DiI/DIコンテナを一から学んでみた

Editor's Notes

  1. 今回のテーマですが、「DI/DIコンテナを一から学んでみた」です。 なぜこのテーマにしたかですが、Clean Architectureで依存関係逆転の原則を本当にキレイに実装しようとすると、このDIの必要性が身に染みたからです。 また、DIとは?と説明しようとすると言葉でうまく説明できない = ちゃんと理解できていないので、より深く学ぼうとこのテーマにいたしました。 解説だけだと面白くないので、TypeScriptでの軽量DI実装までやっていきます。 https://qiita.com/sadnessOjisan/items/d05e35e34d2d1fb7e844 https://hira98.hatenablog.com/entry/2019/05/25/233000#:~:text=DI%E3%81%A8%E3%81%AFpendencyInjection(%E4%BE%9D%E5%AD%98,%E3%81%AE%EF%BC%91%E3%81%A4%E3%81%A7%E3%81%82%E3%82%8B%E3%80%82&text=DI%E3%81%AF%E3%80%81Ruby%E3%81%A7%E3%82%A2%E3%83%97%E3%83%AA,%E3%81%AB%E7%BD%AE%E3%81%8D%E6%8F%9B%E3%81%88%E3%82%8B%E3%81%93%E3%81%A8%E3%81%8C%E3%81%A7%E3%81%8D%E3%82%8B%E3%80%82 https://qiita.com/hinom77/items/1d7a30ba5444454a21a8 https://www.slideshare.net/yuiito94/di-56742600
  2. まず、DIとは?ですが、 DI自体は関心の分離を実現するためのデザインパターンの1つです。 そして、DIは「Dependency Injection」の略で、直訳すると「依存性の注入」です。 この日本語訳が意図が伝わりづらく混乱のもとになってしまいますが、依存性は性質ではなく、 依存対象を意味しており、注入される依存対象はオブジェクトのインスタンスです。 つまり、依存対象となるオブジェクトのインスタンスを外部から挿入するというデザインパターンです。 端的に申し上げると、「あるクラスが使用する他のクラスのインスタンスをコンストラクタなどを通じて外部から注入ようなクラス設計」になります。 DIを実現すると疎結合になるため、一つの部品だけで開発・テストができるようになり、開発効率が上がります。 このDIを内包した有名どころでは Spring/Angular などがあります。
  3. 続いては、DIコンテナについてです。 この点は非常に混乱しやすい点ですが、先程のDIとDIコンテナは別物です。 ここを混同して認識すると、混乱の元凶となってしまいますので、 区別が必要です。 では、何が違うのかですが、 DIコンテナは、DIという依存性の注入をお手伝いするためのフレームワークであるという点です。 つまり、DIコンテナがなくともDIは実現できます。 そして、DIコンテナの「コンテナ」とはそのまま、容器/入れ物という意味で、 どこにも依存していないプカプカ浮いた状態のインスタンスを入れておく容器になります。 呼び出し元から、このインスタンスが欲しい、とコールするだけでその時点でインスタンスを自動で渡してくれます。 これがなぜ素晴らしいかというと、通常インスタンスを生成すると 直接 new する必要があるので、 至るところに依存関係が生まれてしまい、インスタンスの量がどんどん増えると見通しも悪くなるのですが、 DIコンテナがこれら課題を解決してくれます。 https://backpaper0.github.io/ghosts/dicontainer/#1
  4. DIコンテナを図で表すと、このようになります。 上の図がDIコンテナを使用していないパターン、 下の図がDIコンテナを使用したパターンです。 DIコンテナ内にはどこにも依存していないプカプカ浮いたインスタンスが多数入っており、 これらを適宜取り出します。
  5. ではDIによるメリットとはなんでしょうか? 色々とありますが、ざっと挙げると以下の4点です。 1、依存関係逆転の原則がキレイに実装できます。 Interfaceへ依存させていくと通常の実装では限界があります。 2、依存先の実装が終わらなくとも、import側の実装ができる 疎結合になっているため、依存先の実装完了を待たずに、import側の実装が可能になります。 3、依存先が変更されても、import側を修正しなくても良い こちらも疎結合になっているため、import側が依存先の変更による影響を受けなくなります。 4、依存が引き剥がされているので、テスト時にmockを流すだけで良い テスト時にわざわざDBヘアクセスせずとも、DIによってmockへすり替えるだけでテスト可能になります。
  6. ここまでDI/DIコンテナによるメリットをお伝えいたしましたが、「DIって良さそう」と多少は感じて頂けたかなと思います。 しかし、TypeScriptで実現しようとすると課題が残ります。 DIは抽象に依存するようにinterfaceなどの型が重要になりますが、 TypeScriptは型検査時に使われるものでしかなく、JS自体は型が存在しないため、トランスパイルすると消えてしまいます。 そのため、TypeScriptでのDIコンテナは、interfaceに紐づいた詳細を見つけてインスタンスを注入することができません。 この解決策には2通りあります。 まず、ライブラリの活用です。 InversifyJS(インバーシフィJS):Git hubで最もスターが多くついていますが、最近は開発が活発ではありません TSyringe(Tシリンジ):TypeScriptのシリンジ(注射器)という意味ですが、Microsoftが主導で開発しており、現在も継続して開発が進められている これらライブラリを活用することが最も早い解決策になります。 そして2点目が自作です。 もしDIコンテナを自作するとなると、大きな課題が残ります。 DIコンテナは依存と注入対象のコードになんらかのマーキングをして、 それだけで自動的に依存関係の登録ができるようにしなければいけないのですが、 その実現方法として decorator があります。 decorator もデザインパターンの1つになり、 decorator での依存登録方法は、InversifyJS(インバーシフィJS)やTSyringe(Tシリンジ)、JavaのSpring等でも採用・推奨されている方法のようです。 このdecoratorは最終的にはただの関数ですが、引数が何へ当てるのかによって異なります。 例えばクラス全体へのdecoratorだと、constructorとなり、 メソッドだと、1つ目がprotType、2つ目がmethodName、3つ目がPropertyDescriptor といった具合です。 そしてこれらをdecorator factoryというもので手を加えてからreturnすることも可能です。 こういった引数が取れたり手を加えれることからも、 必ず必要という訳ではないですが、DIコンテナとdecoratorは相性がとても良いです。 続いてのReflection は ES6から導入されており、JavaScript エンジンが内部で使用している汎用的な関数(内部メソッド)を格納しているオブジェクトです。 ES5までは内部メソッドをコードから明示的に呼び出すことはできませんでしたが、Reflectionオブジェクトを通して呼び出す事ができます。 例えば、constructなどはその一例です。 しかし、これでも constructor の引数の情報を引っ張ってくることはできません。 そこでこの Reflectを拡張してくれるのが、次のreflect-metadataです。 reflect-metadata はReflectionを拡張することにより、より便利な機能を呼ぶ事ができます。 Reflect.getMetadata(designKey, target) その一つにgetMetadataというメソッドがあり、これはtarget(つまりclass や function)が持つ情報を取得することができます。 どのような情報を取得できるかは designKey で指定でき、それぞれ次のような情報が取得できます。 "design:type" = 引数の型 "design:paramtypes" = 引数の型の配列 "design:returntype" = 戻り値の型 これらにより、型の恩恵を存分に受けながら記述することが可能となります。 ただし、今回は学びを深めるために必要最低限の機能しか持たない、 シンプルで軽量なDIを自作してみたいと思います。 はじめに断っておきますが、DIコンテナの自作はハードルが高いため今回はDIのみに焦点を当てます。
  7. では自作軽量DIを作成してみましたので、そちらの解説を行ってまいります。 全体のアーキテクチャは図のようになります。 メインはDIを理解するという趣旨のため、ライトなレイヤーにしていますので、 参考にされる方はいらっしゃらないと思いますが、注意をお願いいたします。 簡単に左から解説いたしますと、外部のユーザーがUIを操作して、 ApplicationレイヤーにClean Architecture でいう所のUse Case と 具象のInteractor があります。 そして、Dataレイヤーの所に永続化のRepositoryがあり、 そして、Infrastructureがあり、そこから外部のDBと接続します。 また、Domainが最上位レベルで一番安定した場所にいます。 Clean ArchitecturではEnterprise Business Rules層で所謂Entityに該当します。 DDDのEntityとは別物です。 Clean Architecture Like に 各レイヤーを保護するため、レイヤーを跨ぐ依存は全て依存関係逆転の原則に則っています。 また、Repositoryも抽象のClientに依存しているため、mock DataとDBを容易に切り替える事ができます。 今回の実装で npm run local と叩くと expressが起動しmock Dataが帰ってくるようになっています。 それぞれ、抽象に依存しているため、通常であればどこかで new しなければいけませんが、 今回はApplicationレイヤーでその解消をしたいと思います。
  8. 続いては、実際のコードを見て行きます。 まずRepositoryですが、先程のアーキテクチャ図通りです。 constructor で 注入されるClientですが抽象に依存しています。 これにより、mockとの差し替えが容易になっています。 ごくごく普通の実装で特段何もありません。
  9. 続いては、Applicationです。 Clean ArchitectureではSOLID原則の1つに「インターフェイス分離の原則」があり、 使用していないものへの依存はしないという原則に則り、 このように1メソッドにつき、1インターフェイスとしています。 そして、こちらでも画像の通り、抽象に依存しています。 また、interactorを実行するという意味でメソッド名をexecuteに統一しています。 これにより、利用側はどのメソッド名かを知る必要がなくなります。 ここまでは特に問題ないのですが、このコードを実際に動くようなコードにしていくと問題が発生します。 それは、せっかく依存性をより上位にのみ向けて、制御の流れと依存方向を制御したのに、 どこかでnewしなければならず、結局具象に依存してしまうという点です。 そこでDIが効果を発揮します。
  10. 実際に私がやってみたコードは画像のようになります。 ご覧いただいているように new が 登場せず依存関係が綺麗になっています。 DIを使わないとL7でnew をしなければならず強制的に依存が生まれてしまいますが、 getInstanceというメソッドを作りそこから欲しいインスタンスだけを渡すようにしています。 L6に記載しているDiscriminated UnionとはTypeScriptの手法の1つなのですが、 これにより、typeの後のstringにも型補完が効き、予測で候補が出てきます。 更にconst で受けているuseCaseという変数も、ちゃんとFetchAllというInstanceとして認識できているため、 L8のawait useCase.でも補完が効きます。 実際にはメソッド名を知る必要はないので、executeのみで良いのですが、しっかり型の恩恵を受けられている状態です。
  11. では、どのようにインスタンスを返しているかですが、左側画像のようになります。 このDIクラスへ汚れ役を押し付けています。 正直あまりエレガントではないので、納得いってませんが、 L7でDiscriminated Union で補完が効くようにtypeの定義をしています。 このDiscriminated Union はL21の条件分岐の際にも補完が効きますし、 先程申し上げたように、getInstanceを実行する際にも補完が効きます。 こちらの定義はenumのような列挙型を使用すれば、よりタイプセーフになると思います。 そして、どのtypeがきたらどの型を返すのかという、Function OverloadingをL17で行っています。 これにより、「typeがfetchAll」の時にFetchAllという型が返り値として認識されるため、型の補完が効きます。 こちらをFunction OverloadingにせずにGenericsの方がキレイに実装できると思い右側の画像のようにやってみたのですが、 あまりキレイにできませんでした。 一応このコードで型の恩恵を受けつつ、newを隠蔽する事ができました。 しかし、このコードにもやはり課題が残ります。
  12. まず、DIするInstanceが増えるとドンドンDIクラスが巨大になります。 それは、 importがドンドン増える、 Discriminated Unionなので、typeをドンドン追加しないといけない、 Function Overloadingなので、オーバーロードをドンドン追加しかければいけない。 また、今回のアーキテクチャ的では、DIすべき箇所は一箇所でしたが、 完全に全てのInstanceがDIされる訳ではありません。 今回 new を隠蔽することに焦点を当てて軽量DI作成いたしましたが、 やはりDIコンテナがあればもっとキレイに実装可能だと感じました。 そして、DIコンテナをキレイに実装しようとすると、decoratorやReflection-metadataが相性が良く TypeScriptには標準でdecoratorがサポートされているため選択肢の一つだなと思いました。 こちらについては、個人的にdecoratorやReflectionを使用したDIコンテナをヒッソリといつか自作してみようと思っています。 今回の実装でも、かなり小規模であれば、ある程度はいけそな気もします。 大規模向けにはやはりDIライブラリの活用か、茶谷さんクラスの高スキルを持った方が開発される方が良いと思います。
  13. では、今回のまとめです。 まずDIとは?ですが、 あくまでデザインパターンの1つで、 Dependency Injection(依存性の注入)という意味ですが、 依存性は性質ではなく、依存対象はインスタンスです。 日本語訳がミスリードになるので、勘違いしないようにしましょう。 そしてDIコンテナとは? DIの実現をお手伝いするためのフレームワークで、 コンテナとは入れ物で、なんの入れ物かというと、インスタンスです。 DIとDIコンテナを混在してしまうと混乱の元になってしまうため、 しっかりと区別しましょう。 また、DIの何が嬉しいのか?ですが、 依存関係逆転の原則がキレイに実装できる 依存先の実装が終わらなくとも、import側の実装が進めれる 依存先が変更されても、import側は修正しなくても良い 依存が引き剥がされているので、テストやlocal開発時にDBに繋がずにmockを流すだけで良い そして、軽量DIを自作してみて 当初の目的のnewの依存を引き剥がすことはとりあえずできたのと、 思ったより型補完が効きました。 しかし、課題がいくつか残りました。 そして実際に手を動かしてみることで色々と身になる箇所が多くありました。 課題は残ってしまいましたが、今回は以上となります。 ご静聴有難うございました。