Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Static Dependency Injection by Code Generation
Search
Yosuke Ishikawa
September 17, 2017
Technology
6.8k
15
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Static Dependency Injection by Code Generation
Yosuke Ishikawa
September 17, 2017
More Decks by Yosuke Ishikawa
See All by Yosuke Ishikawa
効率的な開発手段として VRTを活用する
ishkawa
1
250
アプリを起動せずにアプリを開発して品質と生産性を上げる
ishkawa
0
4.6k
Achieving Testability in Presentation Layer
ishkawa
4
4k
Introducing Wire: Dependency Injection by Code Generator
ishkawa
12
1.4k
Declarative UICollectionView
ishkawa
28
8.6k
Nuxt.jsが掲げる"Universal Vue.js Applications"とは何者か
ishkawa
10
2.9k
実践クライアントサイドSwift
ishkawa
23
4.4k
JSON-RPC on APIKit
ishkawa
5
69k
RxSwiftは開発をどう変えたか?
ishkawa
12
4.2k
Other Decks in Technology
See All in Technology
Eight Engineering Unit 紹介資料
sansan33
PRO
3
8.2k
[ChatGPT Work LT]事務作業が苦手な人のための バックオフィスの「半」自動化
chimaki_iot
0
270
ガバメントクラウドでのランサムウェア対策
techniczna
2
1.1k
社内の7割が使うデータ基盤を、 データチーム2人で回すためにやったこと
koh_yoshi
4
1.3k
Flutterをカメラで動かしたかった話
sony
1
130
MIRU 2026 チュートリアル
keisuke198619
0
880
つくって納得、つかって実感! 大規模言語モデルことはじめ ver2.0
recruitengineers
PRO
4
1.4k
メルカリのグローバルアプリで挑んだ AlloyDB 運用と課題解決の実践記
hatappi
0
240
OSPN.JPバージョンアップ作業進捗のご報告 / 20260801-osc26kyoto
akkiesoft
0
450
20分でわかるセキュアAPI
nwiizo
2
230
Master Dataグループ紹介資料
sansan33
PRO
1
4.8k
Agent 時代の Kaggle 展望 / kaggle-in-the-agentic-era
upura
1
690
Featured
See All Featured
Unsuck your backbone
ammeep
672
58k
The Straight Up "How To Draw Better" Workshop
denniskardys
239
140k
Leveraging Curiosity to Care for An Aging Population
cassininazir
1
460
How to Think Like a Performance Engineer
csswizardry
28
2.7k
SEOcharity - Dark patterns in SEO and UX: How to avoid them and build a more ethical web
sarafernandez
0
240
What the history of the web can teach us about the future of AI
inesmontani
PRO
1
650
Design of three-dimensional binary manipulators for pick-and-place task avoiding obstacles (IECON2024)
konakalab
0
530
Redefining SEO in the New Era of Traffic Generation
szymonslowik
1
380
The Hidden Cost of Media on the Web [PixelPalooza 2025]
tammyeverts
2
450
Paper Plane (Part 1)
katiecoart
PRO
1
10k
First, design no harm
axbom
PRO
2
1.2k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
16
2.1k
Transcript
コード生成による 静的な Dependency Injection
None
None
Dependency Injection(DI) の概要 DI をサポートする仕組みがなぜ必要か コード生成による静的なDI
DI = Dependency Injection
DI = 必要なものを外から渡す Dependency: 必要なもの Injection: 外から渡す
final class ImageDownloader { private let urlSession = URLSession.shared func
downloadImage(with url: URL, completion: (UIImage) -> Void) { let task = urlSession.dataTask(with: url) {...} task.resume() } }
final class ImageDownloader { private let urlSession: URLSession init(urlSession: URLSession)
{ self.urlSession = urlSession } func downloadImage(with url: URL, completion: (UIImage) -> Void) { let task = urlSession.dataTask(with: url) {...} task.resume() } }
dependency の切り替えが可能 dependency の詳細を必要以上に決めずに済む
IoC: Inversion of Control DIP: Dependency Inversion Principle
デメリットはあるの?
dependency の切り替えが可能 dependency の詳細を必要以上に決めずに済む
dependency のインスタンスを取得して渡す責務が外側に生じる
None
DI なし: 密結合だがインスタンスの生成は簡単 DI あり: 疎結合だがインスタンスの生成が面倒
DI なし: 密結合だがインスタンスの生成は簡単 DI あり: 疎結合だがインスタンスの生成が面倒 ???: 疎結合だしインスタンスの生成が簡単
DI をサポートする仕組み
右側のインスタンスの取得を自動化する
自動的にインスタンスを生成できる型を 方法とセットで登録しておく
インスタンスを自動的に取得する方法 DI 用のinitializer を登録する DI 用のprovider method を用意する
final class APIClient { @Inject APIClient(urlSession: URLSession, cache: Cache) {
... } } Dagger のDI 用のconstructor(Java)
None
provider method = インスタンスを提供するメソッド
@Module final class APIModule { @Provides static APIClient provideAPIClient(urlSession: URLSession,
cache: Cache) ... } } Dagger のDI 用のprovider method(Java)
各ノードの定義ができるようになった
グラフの生成
None
@Generated public final class DaggerAPIComponent implements APIComponent { private Provider<URLSession>
urlSessionProvider; private Provider<Cache> cacheProvider; private Provider<APIClient> apiClientProvider; private void initialize() { urlSessionProvider = ... cacheProvider = ... apiClientProvider = APIModule_APIClientFactory .create(urlSessionProvider, cacheProvider); } @Override public APIClient apiClient() { return apiClientProvider.get() } } 生成されたコードで依存関係の解決を表現(Java)
Swi での実践
DI に使用できるinitializer の定義 DI に使用できるprovider method の定義 コード生成による依存関係の解決
DI に使用できるinitializer
final class APIClient { @Inject APIClient(urlSession: URLSession, cache: Cache) {
... } } Dagger のDI 用のconstructor(Java)
protocol Injectable { associatedtype Dependency init(dependency: Dependency) } final class
APIClient: Injectable { struct Dependency { let urlSession: URLSession let cache: Cache } init(dependency: Dependency) {...} } Swi のDI 用のinitializer
DI に使用できるprovider method
@Module final class APIModule { @Provides static APIClient provideAPIClient(urlSession: URLSession,
cache: Cache) ... } } Dagger のDI 用のprovider method(Java)
protocol Resolver {}
protocol AppResolver: Resolver { func provideURLSession() -> URLSession func provideCache()
-> URLSession func provideAPIClient(urlSession: URLSession, cache: Cache) -> APIClient } Swi のDI 用のprovider method
依存関係を解決するコード生成
記述されているコードを解釈して、それを補完するコードを生成
SourceKitten
{ "key.accessibility" : "source.lang.swift.accessibility.internal", "key.kind" : "source.lang.swift.decl.struct", "key.name" : "A",
"key.inheritedtypes" : [ { "key.name" : "Injectable" } ] }
Resolver のprotocol extension に インスタンスを取得するメソッドを生やす
struct A: Injectable { struct Dependency { let b: B
} init(dependency: Dependency) {} } struct B {} protocol ABResolver: Resolver { func provideB() -> B }
extension ABResolver { func resolveA() -> A { let b
= resolveB() return A(dependency: .init(b: b)) } func resolveB() -> B { return provideB() } } provideB() の実装はABResolver の準拠側に委ねられる
final class AppABResolver { func provideB() { return B() }
}
None
プロトコルにした意味は? どう提供するかは決めていない状態でグラフを組める 必要なものが揃っていることがコンパイル時に保証される
自動的に取得できないdependency は?
すべてのdependency が自動的に解決できるものとは限らない ↓ resolve メソッドのパラメーターとして渡す必要がある場合もある
final class UserProfileViewController: UIViewController, Injectable { struct Dependency { let
userID: Int64 let apiClient: APIClient } init(dependency: Dependency) {} } final class APIClient {...} protocol AppResolver: Resolver { func provideAPIClient() -> APIClient }
extension AppResolver { func resolveAPIClient() -> APIClient { return provideAPIClient()
} func resolveUserProfileViewController(userID: Int64) -> UserProfileViewContr let apiClient = resolveAPIClient() return UserProfileViewController(dependency: .init(userID: userID, apiCl } }
None
デモ
https://github.com/ishkawa/DIKit