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
Oracle Exadata Database Service on Cloud@Customer X11M (ExaDB-C@C) サービス概要
oracle4engineer
PRO
2
8.4k
「守りたい体験」を渡すだけで E2E を生成させられるようになった話
hinac0
1
880
AI時代のYAGNI:「爆速で無駄になった機能」からの学び / 20260720 Naoki Takahashi
shift_evolve
PRO
3
440
副作用のある Lambda でも Lambda Power Tuning は使えるのか / lambda-power-tuning-side-effects
koukihosaka
1
130
AI Coding Agent時代のcdk-nagガードレール 〜組織ルールを強制CIで守り抜く設計の挑戦〜
mhrtech
3
460
AIが実装を自走する時代の認知負債との戦い
lycorptech_jp
PRO
2
970
ボーイスカウトルールでメモリやスキルを改善しよう
azukiazusa1
4
1.5k
変更し続けられるシステムをどう保つか — AI時代のSSoTという設計原則
kawauso
1
580
インシデント事例と パッケージの全量解析に学ぶ ソフトウェアサプライチェーンの守り方 / supply-chain-attack-defense
flatt_security
0
470
Network Firewallやっていき!
news_it_enj
0
180
Claude Code 再入門 会話の渡し方の4つの道具 - Claude Codeスキル・ハーネス社内勉強会
colopl
0
150
Genie Ontologyは銀の弾丸かを考える / Is Genie Ontology a Silver Bullet?
nttcom
0
420
Featured
See All Featured
AI Search: Implications for SEO and How to Move Forward - #ShenzhenSEOConference
aleyda
1
1.3k
brightonSEO & MeasureFest 2025 - Christian Goodrich - Winning strategies for Black Friday CRO & PPC
cargoodrich
3
750
The Spectacular Lies of Maps
axbom
PRO
1
860
Done Done
chrislema
186
16k
From π to Pie charts
rasagy
0
240
SERP Conf. Vienna - Web Accessibility: Optimizing for Inclusivity and SEO
sarafernandez
2
1.5k
Why Mistakes Are the Best Teachers: Turning Failure into a Pathway for Growth
auna
0
180
4 Signs Your Business is Dying
shpigford
187
22k
Ten Tips & Tricks for a 🌱 transition
stuffmc
0
150
AI: The stuff that nobody shows you
jnunemaker
PRO
8
840
Darren the Foodie - Storyboard
khoart
PRO
3
3.4k
The Mindset for Success: Future Career Progression
greggifford
PRO
0
430
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