Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Static Dependency Injection by Code Generation
Search
Yosuke Ishikawa
September 17, 2017
Technology
6.9k
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
260
アプリを起動せずにアプリを開発して品質と生産性を上げる
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.5k
JSON-RPC on APIKit
ishkawa
5
70k
RxSwiftは開発をどう変えたか?
ishkawa
12
4.3k
Other Decks in Technology
See All in Technology
Issue 駆動でスペシャリストの意図を届ける、AI 実装のアクセシビリティ向上
thkt
0
130
エージェントはローカル、検証はMicroVM — Lambda MicroVMsでつくるServerless CI
fujioka6789
3
710
Railsのように考える: See through the Master
snoozer05
PRO
5
1.3k
AgentCore Runtime上にAgentic Coding基盤を構築・展開する際の設計ポイントと限界点 / Design considerations and limitations when building an agentic coding platform on AgentCore Runtime
har1101
5
690
AI時代の「技術的負債」の変質ー概念の終焉と再解釈、エージェントと共に向かう先
nwiizo
1
3.2k
現場で役立つ技術負債の効果的な返済方法
masuda220
PRO
11
5.1k
AI時代、データエンジニアが一番おもろい
genshun9
0
690
「どのログを見ればいい?」 から始めた サーバーレス障害解析
y_waka1
1
130
人間はどの意思決定を手放せるのか
kawasima
15
8k
Making AI Agents Safe and Fast- Jev, Obsidian, and the Meta-Harness
x5gtrn
PRO
0
120
「今盗んで、後で解く」に備える ― AWSのポスト量子暗号入門
yama3133
1
110
AIに賢く動いてもらうためのコンテキスト〜Snowflake女子会 vol.8
snowwmn0824
0
160
Featured
See All Featured
The Mindset for Success: Future Career Progression
greggifford
PRO
0
510
Measuring Dark Social's Impact On Conversion and Attribution
stephenakadiri
2
280
Understanding Cognitive Biases in Performance Measurement
bluesmoon
32
3k
YesSQL, Process and Tooling at Scale
rocio
174
15k
4 Signs Your Business is Dying
shpigford
187
23k
Designing for Timeless Needs
cassininazir
1
480
Bash Introduction
62gerente
615
220k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
35
2.6k
How to Get Subject Matter Experts Bought In and Actively Contributing to SEO & PR Initiatives.
livdayseo
0
200
Speed Design
sergeychernyshev
33
2.1k
Rails Girls Zürich Keynote
gr2m
96
14k
Optimizing for Happiness
mojombo
378
71k
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