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.7k
Achieving Testability in Presentation Layer
ishkawa
4
4k
Introducing Wire: Dependency Injection by Code Generator
ishkawa
12
1.5k
Declarative UICollectionView
ishkawa
28
8.7k
Nuxt.jsが掲げる"Universal Vue.js Applications"とは何者か
ishkawa
10
2.9k
実践クライアントサイドSwift
ishkawa
23
4.5k
JSON-RPC on APIKit
ishkawa
5
71k
RxSwiftは開発をどう変えたか?
ishkawa
12
4.3k
Other Decks in Technology
See All in Technology
スプシの手作業からの解脱 ~更新はClaude Codeに、見せ方と使い方はGASアプリに任せる~
kentarofujii
0
130
アウトプット初心者、半年間のふりかえり
4o1sobblue
0
370
AIにシークレットを見せない、WSL2で安全な開発環境
yazm
0
230
LambdaWebFunctionsを試してみた / exploring-lambda-web-functions
koukihosaka
0
230
hackers_champloo_2026_tidb
makocchi
0
150
メルペイ 会計システム概要と歴史
mewuto
1
220
Claude の新機能を、 出た日に触って社内に届けるまで
rfdnxbro
1
150
ブラウザとサーバーから考えるAI時代のフロントエンド監視
shogo4131
3
900
子育てエンジニアの可処分時間が減っても成長を諦めない戦い方
sudoakiy
6
4.6k
【Data Engineering Summit2026_登壇資料】医療ビッグデータ×AIエージェントを支えるデータ基盤とハーネスエンジニアリング
jmdc_presentation
0
150
不可逆な意思決定を避けながら10億超の顧客データを AI Ready にするデータ基盤設計
baseballyama
1
310
会社説明資料
persolserverworks
0
9.7k
Featured
See All Featured
Building a A Zero-Code AI SEO Workflow
portentint
PRO
0
780
From Legacy to Launchpad: Building Startup-Ready Communities
dugsong
0
350
Visual Storytelling: How to be a Superhuman Communicator
reverentgeek
2
710
sira's awesome portfolio website redesign presentation
elsirapls
0
450
Discover your Explorer Soul
emna__ayadi
2
1.3k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
25
2.1k
Designing Experiences People Love
moore
143
24k
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
56
3.5k
Ruling the World: When Life Gets Gamed
codingconduct
0
400
Embracing the Ebb and Flow
colly
88
5.2k
The AI Revolution Will Not Be Monopolized: How open-source beats economies of scale, even for LLMs
inesmontani
PRO
3
3.8k
Testing 201, or: Great Expectations
jmmastey
46
8.3k
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