SlideShare a Scribd company logo
1 of 152
Download to read offline
MAINTAINING A DEPENDENCY GRAPH WITHMAINTAINING A DEPENDENCY GRAPH WITH
WEAVERWEAVER
THÉOPHANE RUPINTHÉOPHANE RUPIN
@thrupin
DI ContainerDI Container
DI ContainerDI Container
An object able to instantiate, retain, and resolve other
objects’ dependencies.
Dependency GraphDependency Graph
final class Foo {
let bar: Bar
init(bar: Bar) {
self.bar = bar
bar.foo = self
}
func barDidSomething() { ... }
}
final class Bar {
weak var foo: Foo?
func doSomething() { foo?.barDidSomething() }
}
Weaver is a code generation tool which makes it easy
to inject dependencies.
https://github.com/scribd/Weaver
WHY?WHY?
WHY?WHY?
I could not nd any satisfying compile time DI solution,
so I gave it a try.
ADVANTAGESADVANTAGES
ADVANTAGESADVANTAGES
1. Mimics manual DI technics. No black box.
ADVANTAGESADVANTAGES
1. Mimics manual DI technics. No black box.
2. Compile time errors. Fails fast.
ADVANTAGESADVANTAGES
1. Mimics manual DI technics. No black box.
2. Compile time errors. Fails fast.
3. Type safety. If it compiles, it works!
ADVANTAGESADVANTAGES
1. Mimics manual DI technics. No black box.
2. Compile time errors. Fails fast.
3. Type safety. If it compiles, it works!
4. Declarativeness.
ADVANTAGESADVANTAGES
1. Mimics manual DI technics. No black box.
2. Compile time errors. Fails fast.
3. Type safety. If it compiles, it works!
4. Declarativeness.
5. No optionality. If it's declared, it's there.
ADVANTAGESADVANTAGES
1. Mimics manual DI technics. No black box.
2. Compile time errors. Fails fast.
3. Type safety. If it compiles, it works!
4. Declarativeness.
5. No optionality. If it's declared, it's there.
6. Thread safety. Immutability. No lazy loading.
ADVANTAGESADVANTAGES
1. Mimics manual DI technics. No black box.
2. Compile time errors. Fails fast.
3. Type safety. If it compiles, it works!
4. Declarativeness.
5. No optionality. If it's declared, it's there.
6. Thread safety. Immutability. No lazy loading.
7. No additional framework to ship.
DRAWBACKSDRAWBACKS
DRAWBACKSDRAWBACKS
1. More code to compile. Can be optimized.
DRAWBACKSDRAWBACKS
1. More code to compile. Can be optimized.
2. Meta-programmation is hard.
DRAWBACKSDRAWBACKS
1. More code to compile. Can be optimized.
2. Meta-programmation is hard.
3. Use of pseudo annotations.
DRAWBACKSDRAWBACKS
1. More code to compile. Can be optimized.
2. Meta-programmation is hard.
3. Use of pseudo annotations.
4. Experimental.
LET'S SEE IN PRACTICELET'S SEE IN PRACTICE
A logical dependency graph
HOW COULD WE PROVIDEHOW COULD WE PROVIDE URLSessionURLSession??
Sharing an instance of URLSession
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
}
Sharing an instance of URLSession
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
static var shared: AppDelegate? {
return UIApplication.shared.delegate as? AppDelegate
}
}
Sharing an instance of URLSession
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
static var shared: AppDelegate? {
return UIApplication.shared.delegate as? AppDelegate
}
let urlSession: URLSession = {
let config = ...
return URLSession(configuration: config)
}()
}
Using the shared instance of URLSession
final class APIClient {
func get(_ url: URL, completion: @escaping (Data?) -> Void) ->
}
}
Using the shared instance of URLSession
final class APIClient {
func get(_ url: URL, completion: @escaping (Data?) -> Void) ->
AppDelegate.shared.urlSession.dataTask(with: url) {
...
}.resume()
}
}
Not so good...
Injecting a shared instance of URLSession in
APIClient
final class APIClient {
func get(_ url: URL, completion: @escaping (Data?) -> Void) ->
}
}
Injecting a shared instance of URLSession in
APIClient
final class APIClient {
private let urlSession: URLSession
func get(_ url: URL, completion: @escaping (Data?) -> Void) ->
}
}
Injecting a shared instance of URLSession in
APIClient
final class APIClient {
private let urlSession: URLSession
init(urlSession: URLSession = AppDelegate.shared.urlSession)
self.urlSession = urlSession
}
func get(_ url: URL, completion: @escaping (Data?) -> Void) ->
}
}
Injecting a shared instance of URLSession in
APIClient
final class APIClient {
private let urlSession: URLSession
init(urlSession: URLSession = AppDelegate.shared.urlSession)
self.urlSession = urlSession
}
func get(_ url: URL, completion: @escaping (Data?) -> Void) ->
urlSession.dataTask(with: url) { ... }.resume()
}
}
Using APIClient in MovieManager
final class MovieManager {
func getMovies(_ completion: @escaping ([Movie]?) -> Void) {
}
}
Using APIClient in MovieManager
final class MovieManager {
func getMovies(_ completion: @escaping ([Movie]?) -> Void) {
APIClient().get("http://my_movie_api/movies") { ... }
}
}
Using APIClient in MovieManager
final class MovieManager {
func getMovies(_ completion: @escaping ([Movie]?) -> Void) {
APIClient().get("http://my_movie_api/movies") { ... }
// ^ No URLSession to pass in.
}
}
Try again...
Passing down an instance of URLSession in
APIClient
final class APIClient {
private let urlSession: URLSession
init(_ urlSession: URLSession) {
self.urlSession = urlSession
}
func get(_ url: URL, completion: @escaping (Data?) -> Void) ->
urlSession.dataTask(with: url) { ... }.resume()
}
}
Passing down an instance of URLSession in
APIClient
final class APIClient {
private let urlSession: URLSession
init(_ urlSession: URLSession) { // <- No default anymore
self.urlSession = urlSession
}
func get(_ url: URL, completion: @escaping (Data?) -> Void) ->
urlSession.dataTask(with: url) { ... }.resume()
}
}
From MovieManager to APIClient
final class MovieManager {
func getMovies(_ completion: @escaping ([Movie]?) -> Void) {
}
}
From MovieManager to APIClient
final class MovieManager {
private let apiClient: APIClient
func getMovies(_ completion: @escaping ([Movie]?) -> Void) {
}
}
From MovieManager to APIClient
final class MovieManager {
private let apiClient: APIClient
init(urlSession: URLSession) {
apiClient = APIClient(urlSession)
}
func getMovies(_ completion: @escaping ([Movie]?) -> Void) {
}
}
From MovieManager to APIClient
final class MovieManager {
private let apiClient: APIClient
init(urlSession: URLSession) {
apiClient = APIClient(urlSession)
}
func getMovies(_ completion: @escaping ([Movie]?) -> Void) {
apiClient.get("http://my_movie_api/movies") { ... }
}
}
From HomeViewController to MovieManager
final class HomeViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
}
From HomeViewController to MovieManager
final class HomeViewController {
private let movieManager: MovieManager
override func viewDidLoad() {
super.viewDidLoad()
}
}
From HomeViewController to MovieManager
final class HomeViewController {
private let movieManager: MovieManager
init(_ urlSession: URLSession) {
movieManager = MovieManager(urlSession: urlSession)
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
From HomeViewController to MovieManager
final class HomeViewController {
private let movieManager: MovieManager
init(_ urlSession: URLSession) {
movieManager = MovieManager(urlSession: urlSession)
}
override func viewDidLoad() {
super.viewDidLoad()
movieManager.getMovies { ... }
}
}
From AppDelegate to HomeViewController
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func applicationDidFinishLaunching(_ application: UIApplicati
}
}
From AppDelegate to HomeViewController
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func applicationDidFinishLaunching(_ application: UIApplicati
let configuration = ...
let urlSession = URLSession(configuration: configuration)
}
}
From AppDelegate to HomeViewController
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func applicationDidFinishLaunching(_ application: UIApplicati
let configuration = ...
let urlSession = URLSession(configuration: configuration)
let controller = HomeViewController(urlSession)
...
}
}
Well done!
WHY IS THIS BETTER?WHY IS THIS BETTER?
WHY IS THIS BETTER?WHY IS THIS BETTER?
MODULARITYMODULARITY
What if ImageManager needs a bigger HTTP cache?
final class ImageManager {
}
What if ImageManager needs a bigger HTTP cache?
final class ImageManager {
init() {
}
}
What if ImageManager needs a bigger HTTP cache?
final class ImageManager {
init() {
let configuration = ...
}
}
What if ImageManager needs a bigger HTTP cache?
final class ImageManager {
init() {
let configuration = ...
config.urlCache?.diskCapacity = 1024 * 1024 * 50
config.urlCache?.memoryCapacity = 1024 * 1024 * 5
}
}
What if ImageManager needs a bigger HTTP cache?
final class ImageManager {
init() {
let configuration = ...
config.urlCache?.diskCapacity = 1024 * 1024 * 50
config.urlCache?.memoryCapacity = 1024 * 1024 * 5
let urlSession = URLSession(configuration: configuration)
}
}
What if ImageManager needs a bigger HTTP cache?
final class ImageManager {
private let apiClient: APIClient
init() {
let configuration = ...
config.urlCache?.diskCapacity = 1024 * 1024 * 50
config.urlCache?.memoryCapacity = 1024 * 1024 * 5
let urlSession = URLSession(configuration: configuration)
apiClient = APIClient(urlSession)
}
}
What if ImageManager needs a bigger HTTP cache?
final class ImageManager {
private let apiClient: APIClient
init() {
let configuration = ...
config.urlCache?.diskCapacity = 1024 * 1024 * 50
config.urlCache?.memoryCapacity = 1024 * 1024 * 5
let urlSession = URLSession(configuration: configuration)
apiClient = APIClient(urlSession)
}
func getImage(_ image: String, completion: @escaping (UIImage
apiClient.get("http://my_movie_api/images/(image)") { ..
}
}
That was easy!
Great! But this is too much code to write...
In a real project, we'd have to pass down dozens of
dependencies
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func applicationDidFinishLaunching(_ application: UIApplicati
let controller = HomeViewController(
)
}
}
In a real project, we'd have to pass down dozens of
dependencies
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func applicationDidFinishLaunching(_ application: UIApplicati
let controller = HomeViewController(
sessionManager: sessionManager,
)
}
}
In a real project, we'd have to pass down dozens of
dependencies
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func applicationDidFinishLaunching(_ application: UIApplicati
let controller = HomeViewController(
sessionManager: sessionManager,
analyticsManager: analyticsManager,
)
}
}
In a real project, we'd have to pass down dozens of
dependencies
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func applicationDidFinishLaunching(_ application: UIApplicati
let controller = HomeViewController(
sessionManager: sessionManager,
analyticsManager: analyticsManager,
reachabilityManager: reachabilityManager,
)
}
}
In a real project, we'd have to pass down dozens of
dependencies
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func applicationDidFinishLaunching(_ application: UIApplicati
let controller = HomeViewController(
sessionManager: sessionManager,
analyticsManager: analyticsManager,
reachabilityManager: reachabilityManager,
logger: logger,
)
}
}
In a real project, we'd have to pass down dozens of
dependencies
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func applicationDidFinishLaunching(_ application: UIApplicati
let controller = HomeViewController(
sessionManager: sessionManager,
analyticsManager: analyticsManager,
reachabilityManager: reachabilityManager,
logger: logger,
...
)
}
}
In a real project, we'd have to pass down dozens of
dependencies
Ouch!
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func applicationDidFinishLaunching(_ application: UIApplicati
let controller = HomeViewController(
sessionManager: sessionManager,
analyticsManager: analyticsManager,
reachabilityManager: reachabilityManager,
logger: logger,
...
)
}
}
THAT'S WHERE WEAVER COMES HANDY.THAT'S WHERE WEAVER COMES HANDY.
WHAT METHODOLOGY HAVE WE USED SO FAR?WHAT METHODOLOGY HAVE WE USED SO FAR?
WHAT METHODOLOGY HAVE WE USED SO FAR?WHAT METHODOLOGY HAVE WE USED SO FAR?
1. Looked at the code.
WHAT METHODOLOGY HAVE WE USED SO FAR?WHAT METHODOLOGY HAVE WE USED SO FAR?
1. Looked at the code.
2. Built a representation of the dependency graph.
WHAT METHODOLOGY HAVE WE USED SO FAR?WHAT METHODOLOGY HAVE WE USED SO FAR?
1. Looked at the code.
2. Built a representation of the dependency graph.
3. Made sure the dependency graph was ok.
WHAT METHODOLOGY HAVE WE USED SO FAR?WHAT METHODOLOGY HAVE WE USED SO FAR?
1. Looked at the code.
2. Built a representation of the dependency graph.
3. Made sure the dependency graph was ok.
4. Used a DI technique to implement the graph.
WEAVER DOES THE SAMEWEAVER DOES THE SAME
WEAVER DOES THE SAMEWEAVER DOES THE SAME BUT AUTOMATICALLYBUT AUTOMATICALLY
WEAVER DOES THE SAMEWEAVER DOES THE SAME BUT AUTOMATICALLYBUT AUTOMATICALLY
1. Scans the code, looking for annotations.
WEAVER DOES THE SAMEWEAVER DOES THE SAME BUT AUTOMATICALLYBUT AUTOMATICALLY
1. Scans the code, looking for annotations.
2. Builds a representation of the dependency graph.
WEAVER DOES THE SAMEWEAVER DOES THE SAME BUT AUTOMATICALLYBUT AUTOMATICALLY
1. Scans the code, looking for annotations.
2. Builds a representation of the dependency graph.
3. Validates the dependency graph.
WEAVER DOES THE SAMEWEAVER DOES THE SAME BUT AUTOMATICALLYBUT AUTOMATICALLY
1. Scans the code, looking for annotations.
2. Builds a representation of the dependency graph.
3. Validates the dependency graph.
4. Generates the code to implement the graph.
BACK TO OUR EXAMPLEBACK TO OUR EXAMPLE
Referencing to URLSession in APIClient
Referencing to URLSession in APIClient
final class APIClient {
func get(_ url: URL, completion: @escaping (Data?) -> Void) ->
}
}
Referencing to URLSession in APIClient
final class APIClient {
private let dependencies: APIClientDependencyResolver
init(injecting dependencies: APIClientDependencyResolver) {
self.dependencies = dependencies
}
func get(_ url: URL, completion: @escaping (Data?) -> Void) ->
}
}
Referencing to URLSession in APIClient
final class APIClient {
private let dependencies: APIClientDependencyResolver
// weaver: urlSession <- URLSession
init(injecting dependencies: APIClientDependencyResolver) {
self.dependencies = dependencies
}
func get(_ url: URL, completion: @escaping (Data?) -> Void) ->
}
}
Referencing to URLSession in APIClient
final class APIClient {
private let dependencies: APIClientDependencyResolver
// weaver: urlSession <- URLSession
init(injecting dependencies: APIClientDependencyResolver) {
self.dependencies = dependencies
}
func get(_ url: URL, completion: @escaping (Data?) -> Void) ->
dependencies.urlSession.dataTask(with: url) { ... }.resum
}
}
Referencing to URLSession in APIClient
GENERATED CODEGENERATED CODE
Referencing to URLSession in APIClient
GENERATED CODEGENERATED CODE
protocol APIClientInputDependencyResolver {
var urlSession: URLSession { get }
}
Referencing to URLSession in APIClient
GENERATED CODEGENERATED CODE
protocol APIClientInputDependencyResolver {
var urlSession: URLSession { get }
}
protocol APIClientDependencyResolver {
var urlSession: URLSession { get }
}
Referencing to URLSession in APIClient
GENERATED CODEGENERATED CODE
protocol APIClientInputDependencyResolver {
var urlSession: URLSession { get }
}
protocol APIClientDependencyResolver {
var urlSession: URLSession { get }
}
final class APIClientDependencyContainer: APIClientDependencyReso
let urlSession: URLSession
init(injecting dependencies: APIClientInputDependencyResolver
urlSession = dependencies.urlSession
}
}
Registering APIClient in MovieManager
final class MovieManager {
func getMovies(_ completion: @escaping ([Movie]?) -> Void) {
}
}
Registering APIClient in MovieManager
final class MovieManager {
private let dependencies: MovieManagerDependencyResolver
init(injecting dependencies: MovieManagerDependencyResolver)
self.dependencies = dependencies
}
func getMovies(_ completion: @escaping ([Movie]?) -> Void) {
}
}
Registering APIClient in MovieManager
final class MovieManager {
private let dependencies: MovieManagerDependencyResolver
// weaver: apiClient = APIClient
init(injecting dependencies: MovieManagerDependencyResolver)
self.dependencies = dependencies
}
func getMovies(_ completion: @escaping ([Movie]?) -> Void) {
}
}
Registering APIClient in MovieManager
final class MovieManager {
private let dependencies: MovieManagerDependencyResolver
// weaver: apiClient = APIClient
init(injecting dependencies: MovieManagerDependencyResolver)
self.dependencies = dependencies
}
func getMovies(_ completion: @escaping ([Movie]?) -> Void) {
dependencies.apiClient.get("http://my_movie_api/movies")
}
}
Registering APIClient in MovieManager
GENERATED CODEGENERATED CODE
Registering APIClient in MovieManager
GENERATED CODEGENERATED CODE
protocol MovieManagerInputDependencyResolver {
var urlSession: URLSession { get }
}
Registering APIClient in MovieManager
GENERATED CODEGENERATED CODE
protocol MovieManagerInputDependencyResolver {
var urlSession: URLSession { get }
}
protocol MovieManagerDependencyResolver {
var apiClient: APIClient { get }
}
Registering APIClient in MovieManager
GENERATED CODEGENERATED CODE
protocol MovieManagerInputDependencyResolver {
var urlSession: URLSession { get }
}
protocol MovieManagerDependencyResolver {
var apiClient: APIClient { get }
}
final class MovieManagerDependencyContainer: MovieManagerDependencyResolv
let urlSession: URLSession
var apiClient: APIClient {
let dependencies = APIClientDependencyContainer(injecting: self)
return APIClient(injecting: dependencies)
}
init(injecting dependencies: MovieManagerInputDependencyResolver) {
urlSession = dependencies.urlSession
}
}
Registering APIClient in MovieManager
GENERATED CODEGENERATED CODE
protocol MovieManagerInputDependencyResolver {
var urlSession: URLSession { get }
}
protocol MovieManagerDependencyResolver {
var apiClient: APIClient { get }
}
final class MovieManagerDependencyContainer: MovieManagerDependencyResolv
let urlSession: URLSession
var apiClient: APIClient {
let dependencies = APIClientDependencyContainer(injecting: self)
return APIClient(injecting: dependencies)
}
init(injecting dependencies: MovieManagerInputDependencyResolver) {
urlSession = dependencies.urlSession
}
}
extension MovieManagerDependencyContainer: APIClientInputDependencyResolv
Registering MovieManager in
HomeViewController
final class HomeViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
}
Registering MovieManager in
HomeViewController
final class HomeViewController {
private let dependencies: HomeViewControllerDependencyResolve
init(injecting dependencies: HomeViewControllerDependencyReso
self.dependencies = dependencies
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
Registering MovieManager in
HomeViewController
final class HomeViewController {
private let dependencies: HomeViewControllerDependencyResolve
// weaver: movieManager = MovieManager
init(injecting dependencies: HomeViewControllerDependencyReso
self.dependencies = dependencies
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
Registering MovieManager in
HomeViewController
final class HomeViewController {
private let dependencies: HomeViewControllerDependencyResolve
// weaver: movieManager = MovieManager
init(injecting dependencies: HomeViewControllerDependencyReso
self.dependencies = dependencies
}
override func viewDidLoad() {
super.viewDidLoad()
dependencies.movieManager.getMovies { ... }
}
}
Registering MovieManager in
HomeViewController
GENERATED CODEGENERATED CODE
Registering MovieManager in
HomeViewController
GENERATED CODEGENERATED CODE
protocol HomeViewControllerInputDependencyResolver {
var urlSession: URLSession { get }
}
Registering MovieManager in
HomeViewController
GENERATED CODEGENERATED CODE
protocol HomeViewControllerInputDependencyResolver {
var urlSession: URLSession { get }
}
protocol HomeViewControllerDependencyResolver {
var movieManager: MovieManager { get }
}
Registering MovieManager in
HomeViewController
GENERATED CODEGENERATED CODE
protocol HomeViewControllerInputDependencyResolver {
var urlSession: URLSession { get }
}
protocol HomeViewControllerDependencyResolver {
var movieManager: MovieManager { get }
}
final class HomeViewControllerDependencyContainer: HomeViewControllerDepe
let urlSession: URLSession
var movieManager: MovieManager {
let dependencies = MovieManagerDependencyContainer(injecting: sel
return MovieManager(injecting: dependencies)
}
init(injecting dependencies: HomeViewControllerInputDependencyResolve
urlSession = dependencies.urlSession
}
}
Registering MovieManager in
HomeViewController
GENERATED CODEGENERATED CODE
protocol HomeViewControllerInputDependencyResolver {
var urlSession: URLSession { get }
}
protocol HomeViewControllerDependencyResolver {
var movieManager: MovieManager { get }
}
final class HomeViewControllerDependencyContainer: HomeViewControllerDepe
let urlSession: URLSession
var movieManager: MovieManager {
let dependencies = MovieManagerDependencyContainer(injecting: sel
return MovieManager(injecting: dependencies)
}
init(injecting dependencies: HomeViewControllerInputDependencyResolve
urlSession = dependencies.urlSession
}
}
extension HomeViewControllerDependencyContainer: MovieManagerInputDepende
COMPILING...COMPILING...
COMPILING...COMPILING...
Oops!
URLSession cannot be resolved
Registering URLSession in AppDelegate
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
}
Registering URLSession in AppDelegate
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
private let dependencies = AppDelegateDependencyContainer()
}
Registering URLSession in AppDelegate
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
private let dependencies = AppDelegateDependencyContainer()
// weaver: urlSession = URLSession
}
Registering URLSession in AppDelegate
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
private let dependencies = AppDelegateDependencyContainer()
// weaver: urlSession = URLSession
// weaver: urlSession.scope = .container
}
Registering URLSession in AppDelegate
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
private let dependencies = AppDelegateDependencyContainer()
// weaver: urlSession = URLSession
// weaver: urlSession.scope = .container
// weaver: urlSession.builder = AppDelegate.makeURLSession
}
Registering URLSession in AppDelegate
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
private let dependencies = AppDelegateDependencyContainer()
// weaver: urlSession = URLSession
// weaver: urlSession.scope = .container
// weaver: urlSession.builder = AppDelegate.makeURLSession
static func makeURLSession(_: AppDelegateDependencyResolver)
let configuration = ...
return URLSession(configuration: configuration)
}
}
Registering URLSession in AppDelegate
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
private let dependencies = AppDelegateDependencyContainer()
// weaver: urlSession = URLSession
// weaver: urlSession.scope = .container
// weaver: urlSession.builder = AppDelegate.makeURLSession
static func makeURLSession(_: AppDelegateDependencyResolver)
let configuration = ...
return URLSession(configuration: configuration)
}
// weaver: homeViewController = HomeViewController
}
Registering URLSession in AppDelegate
GENERATED CODEGENERATED CODE
Registering URLSession in AppDelegate
GENERATED CODEGENERATED CODE
protocol AppDelegateDependencyResolver {
var homeViewController: HomeViewController { get }
}
Registering URLSession in AppDelegate
GENERATED CODEGENERATED CODE
protocol AppDelegateDependencyResolver {
var homeViewController: HomeViewController { get }
}
final class AppDelegateDependencyContainer: AppDelegateDependencyResolver
let urlSession: URLSession
var homeViewController: HomeViewController {
let dependencies = HomeViewControllerDependencyContainer(injectin
return HomeViewController(injecting: dependencies)
}
init() {
urlSession = URLSession.makeURLSession(self)
}
}
Registering URLSession in AppDelegate
GENERATED CODEGENERATED CODE
protocol AppDelegateDependencyResolver {
var homeViewController: HomeViewController { get }
}
final class AppDelegateDependencyContainer: AppDelegateDependencyResolver
let urlSession: URLSession
var homeViewController: HomeViewController {
let dependencies = HomeViewControllerDependencyContainer(injectin
return HomeViewController(injecting: dependencies)
}
init() {
urlSession = URLSession.makeURLSession(self)
}
}
extension AppDelegateDependencyContainer: HomeViewControllerInputDependen
It works!
STILL MODULAR?STILL MODULAR?
STILL MODULAR?STILL MODULAR?
YESYES
Registering URLSession with a bigger HTTP cache in
ImageManager
final class ImageManager {
}
Registering URLSession with a bigger HTTP cache in
ImageManager
final class ImageManager {
private let dependencies: ImageManagerDependencyResolver
init(injecting dependencies: ImageManagerDependencyResolver) { self.d
}
Registering URLSession with a bigger HTTP cache in
ImageManager
final class ImageManager {
private let dependencies: ImageManagerDependencyResolver
// weaver: urlSession = URLSession
// weaver: urlSession.scope = .container
// weaver: urlSession.builder = ImageManager.makeURLSession
init(injecting dependencies: ImageManagerDependencyResolver) { self.d
}
Registering URLSession with a bigger HTTP cache in
ImageManager
final class ImageManager {
private let dependencies: ImageManagerDependencyResolver
// weaver: urlSession = URLSession
// weaver: urlSession.scope = .container
// weaver: urlSession.builder = ImageManager.makeURLSession
init(injecting dependencies: ImageManagerDependencyResolver) { self.d
static func makeURLSession(_: ImageManagerDependencyResolver) -> URLS
let configuration = ...
configuration.urlCache?.diskCapacity = 1024 * 1024 * 50
configuration.urlCache?.memoryCapacity = 1024 * 1024 * 5
return URLSession(configuration: configuration)
}
}
Registering URLSession in ImageManager
GENERATED CODEGENERATED CODE
Registering URLSession in ImageManager
GENERATED CODEGENERATED CODE
protocol ImageManagerDependencyResolver {
var apiClient: APIClient { get }
}
Registering URLSession in ImageManager
GENERATED CODEGENERATED CODE
protocol ImageManagerDependencyResolver {
var apiClient: APIClient { get }
}
final class ImageManagerDependencyContainer: ImageManagerDependencyResolv
let urlSession: URLSession
var apiClient: APIClient {
let dependencies = APIClientDependencyContainer(injecting: self)
return APIClient(injecting: dependencies)
}
init() {
urlSession = URLSession.makeURLSession(self)
}
}
Registering URLSession in ImageManager
GENERATED CODEGENERATED CODE
protocol ImageManagerDependencyResolver {
var apiClient: APIClient { get }
}
final class ImageManagerDependencyContainer: ImageManagerDependencyResolv
let urlSession: URLSession
var apiClient: APIClient {
let dependencies = APIClientDependencyContainer(injecting: self)
return APIClient(injecting: dependencies)
}
init() {
urlSession = URLSession.makeURLSession(self)
}
}
extension ImageManagerDependencyContainer: APIClientInputDependencyResolv
Works out of the box
ROOM FOR IMPROVEMENTROOM FOR IMPROVEMENT
ROOM FOR IMPROVEMENTROOM FOR IMPROVEMENT
Adopt Weaver more widely at Scribd.
ROOM FOR IMPROVEMENTROOM FOR IMPROVEMENT
Adopt Weaver more widely at Scribd.
Dependency graph visualizer.
ROOM FOR IMPROVEMENTROOM FOR IMPROVEMENT
Adopt Weaver more widely at Scribd.
Dependency graph visualizer.
Dependency graph optimizations.
ROOM FOR IMPROVEMENTROOM FOR IMPROVEMENT
Adopt Weaver more widely at Scribd.
Dependency graph visualizer.
Dependency graph optimizations.
Detect retain cycles.
ROOM FOR IMPROVEMENTROOM FOR IMPROVEMENT
Adopt Weaver more widely at Scribd.
Dependency graph visualizer.
Dependency graph optimizations.
Detect retain cycles.
Detect suspicious graph shapes.
ROOM FOR IMPROVEMENTROOM FOR IMPROVEMENT
Adopt Weaver more widely at Scribd.
Dependency graph visualizer.
Dependency graph optimizations.
Detect retain cycles.
Detect suspicious graph shapes.
...
THE END.THE END.

More Related Content

What's hot

Java Libraries You Can’t Afford to Miss
Java Libraries You Can’t Afford to Miss Java Libraries You Can’t Afford to Miss
Java Libraries You Can’t Afford to Miss Andres Almiray
 
Mobile Open Day: React Native: Crossplatform fast dive
Mobile Open Day: React Native: Crossplatform fast diveMobile Open Day: React Native: Crossplatform fast dive
Mobile Open Day: React Native: Crossplatform fast diveepamspb
 
distage: Purely Functional Staged Dependency Injection; bonus: Faking Kind Po...
distage: Purely Functional Staged Dependency Injection; bonus: Faking Kind Po...distage: Purely Functional Staged Dependency Injection; bonus: Faking Kind Po...
distage: Purely Functional Staged Dependency Injection; bonus: Faking Kind Po...7mind
 
Working Effectively With Legacy Code
Working Effectively With Legacy CodeWorking Effectively With Legacy Code
Working Effectively With Legacy Codescidept
 
Java Libraries You Can’t Afford to Miss
Java Libraries You Can’t Afford to MissJava Libraries You Can’t Afford to Miss
Java Libraries You Can’t Afford to MissAndres Almiray
 
Java EE 6 CDI Integrates with Spring & JSF
Java EE 6 CDI Integrates with Spring & JSFJava EE 6 CDI Integrates with Spring & JSF
Java EE 6 CDI Integrates with Spring & JSFJiayun Zhou
 
Making React Native UI Components with Swift
Making React Native UI Components with SwiftMaking React Native UI Components with Swift
Making React Native UI Components with SwiftRay Deck
 
50 common web developer interview questions [2020 updated] [www.full stack....
50 common web developer interview questions [2020 updated]   [www.full stack....50 common web developer interview questions [2020 updated]   [www.full stack....
50 common web developer interview questions [2020 updated] [www.full stack....Alex Ershov
 
React Native One Day
React Native One DayReact Native One Day
React Native One DayTroy Miles
 
Create Your Own Framework by Fabien Potencier
Create Your Own Framework by Fabien PotencierCreate Your Own Framework by Fabien Potencier
Create Your Own Framework by Fabien PotencierHimel Nag Rana
 
Flutter hooks tutorial (part 1) flutter animation using hooks (use effect and...
Flutter hooks tutorial (part 1) flutter animation using hooks (use effect and...Flutter hooks tutorial (part 1) flutter animation using hooks (use effect and...
Flutter hooks tutorial (part 1) flutter animation using hooks (use effect and...Katy Slemon
 
Seven Versions of One Web Application
Seven Versions of One Web ApplicationSeven Versions of One Web Application
Seven Versions of One Web ApplicationYakov Fain
 
Building maintainable app #droidconzg
Building maintainable app #droidconzgBuilding maintainable app #droidconzg
Building maintainable app #droidconzgKristijan Jurković
 
Ultimate Node.js countdown: the coolest Application Express examples
Ultimate Node.js countdown: the coolest Application Express examplesUltimate Node.js countdown: the coolest Application Express examples
Ultimate Node.js countdown: the coolest Application Express examplesAlan Arentsen
 
Паразитируем на React-экосистеме (Angular 4+) / Алексей Охрименко (IPONWEB)
Паразитируем на React-экосистеме (Angular 4+) / Алексей Охрименко (IPONWEB)Паразитируем на React-экосистеме (Angular 4+) / Алексей Охрименко (IPONWEB)
Паразитируем на React-экосистеме (Angular 4+) / Алексей Охрименко (IPONWEB)Ontico
 
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and JasmineSingle Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and JasminePaulo Ragonha
 
Dependency Injection, Zend Framework and Symfony Container
Dependency Injection, Zend Framework and Symfony ContainerDependency Injection, Zend Framework and Symfony Container
Dependency Injection, Zend Framework and Symfony ContainerDiego Lewin
 
Containers & Dependency in Ember.js
Containers & Dependency in Ember.jsContainers & Dependency in Ember.js
Containers & Dependency in Ember.jsMatthew Beale
 

What's hot (20)

Java Libraries You Can’t Afford to Miss
Java Libraries You Can’t Afford to Miss Java Libraries You Can’t Afford to Miss
Java Libraries You Can’t Afford to Miss
 
Mobile Open Day: React Native: Crossplatform fast dive
Mobile Open Day: React Native: Crossplatform fast diveMobile Open Day: React Native: Crossplatform fast dive
Mobile Open Day: React Native: Crossplatform fast dive
 
distage: Purely Functional Staged Dependency Injection; bonus: Faking Kind Po...
distage: Purely Functional Staged Dependency Injection; bonus: Faking Kind Po...distage: Purely Functional Staged Dependency Injection; bonus: Faking Kind Po...
distage: Purely Functional Staged Dependency Injection; bonus: Faking Kind Po...
 
Working Effectively With Legacy Code
Working Effectively With Legacy CodeWorking Effectively With Legacy Code
Working Effectively With Legacy Code
 
Completable future
Completable futureCompletable future
Completable future
 
Java Libraries You Can’t Afford to Miss
Java Libraries You Can’t Afford to MissJava Libraries You Can’t Afford to Miss
Java Libraries You Can’t Afford to Miss
 
Java EE 6 CDI Integrates with Spring & JSF
Java EE 6 CDI Integrates with Spring & JSFJava EE 6 CDI Integrates with Spring & JSF
Java EE 6 CDI Integrates with Spring & JSF
 
Making React Native UI Components with Swift
Making React Native UI Components with SwiftMaking React Native UI Components with Swift
Making React Native UI Components with Swift
 
50 common web developer interview questions [2020 updated] [www.full stack....
50 common web developer interview questions [2020 updated]   [www.full stack....50 common web developer interview questions [2020 updated]   [www.full stack....
50 common web developer interview questions [2020 updated] [www.full stack....
 
Building maintainable app
Building maintainable appBuilding maintainable app
Building maintainable app
 
React Native One Day
React Native One DayReact Native One Day
React Native One Day
 
Create Your Own Framework by Fabien Potencier
Create Your Own Framework by Fabien PotencierCreate Your Own Framework by Fabien Potencier
Create Your Own Framework by Fabien Potencier
 
Flutter hooks tutorial (part 1) flutter animation using hooks (use effect and...
Flutter hooks tutorial (part 1) flutter animation using hooks (use effect and...Flutter hooks tutorial (part 1) flutter animation using hooks (use effect and...
Flutter hooks tutorial (part 1) flutter animation using hooks (use effect and...
 
Seven Versions of One Web Application
Seven Versions of One Web ApplicationSeven Versions of One Web Application
Seven Versions of One Web Application
 
Building maintainable app #droidconzg
Building maintainable app #droidconzgBuilding maintainable app #droidconzg
Building maintainable app #droidconzg
 
Ultimate Node.js countdown: the coolest Application Express examples
Ultimate Node.js countdown: the coolest Application Express examplesUltimate Node.js countdown: the coolest Application Express examples
Ultimate Node.js countdown: the coolest Application Express examples
 
Паразитируем на React-экосистеме (Angular 4+) / Алексей Охрименко (IPONWEB)
Паразитируем на React-экосистеме (Angular 4+) / Алексей Охрименко (IPONWEB)Паразитируем на React-экосистеме (Angular 4+) / Алексей Охрименко (IPONWEB)
Паразитируем на React-экосистеме (Angular 4+) / Алексей Охрименко (IPONWEB)
 
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and JasmineSingle Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
 
Dependency Injection, Zend Framework and Symfony Container
Dependency Injection, Zend Framework and Symfony ContainerDependency Injection, Zend Framework and Symfony Container
Dependency Injection, Zend Framework and Symfony Container
 
Containers & Dependency in Ember.js
Containers & Dependency in Ember.jsContainers & Dependency in Ember.js
Containers & Dependency in Ember.js
 

Similar to Maintaining a dependency graph with weaver

Symfony tips and tricks
Symfony tips and tricksSymfony tips and tricks
Symfony tips and tricksJavier Eguiluz
 
Mastering the Sling Rewriter by Justin Edelson
Mastering the Sling Rewriter by Justin EdelsonMastering the Sling Rewriter by Justin Edelson
Mastering the Sling Rewriter by Justin EdelsonAEM HUB
 
Mastering the Sling Rewriter
Mastering the Sling RewriterMastering the Sling Rewriter
Mastering the Sling RewriterJustin Edelson
 
What's New In Laravel 5
What's New In Laravel 5What's New In Laravel 5
What's New In Laravel 5Darren Craig
 
How to code to code less
How to code to code lessHow to code to code less
How to code to code lessAnton Novikau
 
Enterprise Guice 20090217 Bejug
Enterprise Guice 20090217 BejugEnterprise Guice 20090217 Bejug
Enterprise Guice 20090217 Bejugrobbiev
 
Protocol-Oriented Programming in Swift
Protocol-Oriented Programming in SwiftProtocol-Oriented Programming in Swift
Protocol-Oriented Programming in SwiftOleksandr Stepanov
 
Real World Dependency Injection - IPC11 Spring Edition
Real World Dependency Injection - IPC11 Spring EditionReal World Dependency Injection - IPC11 Spring Edition
Real World Dependency Injection - IPC11 Spring EditionStephan Hochdörfer
 
Hibernate Presentation
Hibernate  PresentationHibernate  Presentation
Hibernate Presentationguest11106b
 
Real World Dependency Injection - phpday
Real World Dependency Injection - phpdayReal World Dependency Injection - phpday
Real World Dependency Injection - phpdayStephan Hochdörfer
 
Creating a modern web application using Symfony API Platform, ReactJS and Red...
Creating a modern web application using Symfony API Platform, ReactJS and Red...Creating a modern web application using Symfony API Platform, ReactJS and Red...
Creating a modern web application using Symfony API Platform, ReactJS and Red...Jesus Manuel Olivas
 
Bring the fun back to java
Bring the fun back to javaBring the fun back to java
Bring the fun back to javaciklum_ods
 
Overview of Android Infrastructure
Overview of Android InfrastructureOverview of Android Infrastructure
Overview of Android InfrastructureAlexey Buzdin
 
Overview of Android Infrastructure
Overview of Android InfrastructureOverview of Android Infrastructure
Overview of Android InfrastructureC.T.Co
 
-Kotlin_Camp_Unit2.pptx
-Kotlin_Camp_Unit2.pptx-Kotlin_Camp_Unit2.pptx
-Kotlin_Camp_Unit2.pptxRishiGandhi19
 
Using hilt in a modularized project
Using hilt in a modularized projectUsing hilt in a modularized project
Using hilt in a modularized projectFabio Collini
 

Similar to Maintaining a dependency graph with weaver (20)

Arquitecturas de microservicios - Medianet Software
Arquitecturas de microservicios   -  Medianet SoftwareArquitecturas de microservicios   -  Medianet Software
Arquitecturas de microservicios - Medianet Software
 
Symfony tips and tricks
Symfony tips and tricksSymfony tips and tricks
Symfony tips and tricks
 
Mastering the Sling Rewriter by Justin Edelson
Mastering the Sling Rewriter by Justin EdelsonMastering the Sling Rewriter by Justin Edelson
Mastering the Sling Rewriter by Justin Edelson
 
Mastering the Sling Rewriter
Mastering the Sling RewriterMastering the Sling Rewriter
Mastering the Sling Rewriter
 
What's New In Laravel 5
What's New In Laravel 5What's New In Laravel 5
What's New In Laravel 5
 
How to code to code less
How to code to code lessHow to code to code less
How to code to code less
 
Enterprise Guice 20090217 Bejug
Enterprise Guice 20090217 BejugEnterprise Guice 20090217 Bejug
Enterprise Guice 20090217 Bejug
 
Protocol-Oriented Programming in Swift
Protocol-Oriented Programming in SwiftProtocol-Oriented Programming in Swift
Protocol-Oriented Programming in Swift
 
Real World Dependency Injection - IPC11 Spring Edition
Real World Dependency Injection - IPC11 Spring EditionReal World Dependency Injection - IPC11 Spring Edition
Real World Dependency Injection - IPC11 Spring Edition
 
Hibernate Presentation
Hibernate  PresentationHibernate  Presentation
Hibernate Presentation
 
Android workshop
Android workshopAndroid workshop
Android workshop
 
Real World Dependency Injection - phpday
Real World Dependency Injection - phpdayReal World Dependency Injection - phpday
Real World Dependency Injection - phpday
 
Creating a modern web application using Symfony API Platform, ReactJS and Red...
Creating a modern web application using Symfony API Platform, ReactJS and Red...Creating a modern web application using Symfony API Platform, ReactJS and Red...
Creating a modern web application using Symfony API Platform, ReactJS and Red...
 
Bring the fun back to java
Bring the fun back to javaBring the fun back to java
Bring the fun back to java
 
Overview of Android Infrastructure
Overview of Android InfrastructureOverview of Android Infrastructure
Overview of Android Infrastructure
 
Overview of Android Infrastructure
Overview of Android InfrastructureOverview of Android Infrastructure
Overview of Android Infrastructure
 
-Kotlin_Camp_Unit2.pptx
-Kotlin_Camp_Unit2.pptx-Kotlin_Camp_Unit2.pptx
-Kotlin_Camp_Unit2.pptx
 
-Kotlin Camp Unit2.pptx
-Kotlin Camp Unit2.pptx-Kotlin Camp Unit2.pptx
-Kotlin Camp Unit2.pptx
 
Using hilt in a modularized project
Using hilt in a modularized projectUsing hilt in a modularized project
Using hilt in a modularized project
 
Rcp by example
Rcp by exampleRcp by example
Rcp by example
 

Recently uploaded

How to Track Employee Performance A Comprehensive Guide.pdf
How to Track Employee Performance A Comprehensive Guide.pdfHow to Track Employee Performance A Comprehensive Guide.pdf
How to Track Employee Performance A Comprehensive Guide.pdfLivetecs LLC
 
Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)Hr365.us smith
 
Introduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfIntroduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfFerryKemperman
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based projectAnoyGreter
 
Xen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdfXen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdfStefano Stabellini
 
Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsAhmed Mohamed
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackVICTOR MAESTRE RAMIREZ
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio, Inc.
 
Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureDinusha Kumarasiri
 
Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Andreas Granig
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...Christina Lin
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaHanief Utama
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideChristina Lin
 
CRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceCRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceBrainSell Technologies
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...soniya singh
 
SpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at RuntimeSpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at Runtimeandrehoraa
 
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...OnePlan Solutions
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityNeo4j
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEOrtus Solutions, Corp
 
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxTier1 app
 

Recently uploaded (20)

How to Track Employee Performance A Comprehensive Guide.pdf
How to Track Employee Performance A Comprehensive Guide.pdfHow to Track Employee Performance A Comprehensive Guide.pdf
How to Track Employee Performance A Comprehensive Guide.pdf
 
Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)
 
Introduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfIntroduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdf
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based project
 
Xen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdfXen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdf
 
Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML Diagrams
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStack
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
 
Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with Azure
 
Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief Utama
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
 
CRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceCRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. Salesforce
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
 
SpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at RuntimeSpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at Runtime
 
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered Sustainability
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
 
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
 

Maintaining a dependency graph with weaver

  • 1. MAINTAINING A DEPENDENCY GRAPH WITHMAINTAINING A DEPENDENCY GRAPH WITH WEAVERWEAVER
  • 4. DI ContainerDI Container An object able to instantiate, retain, and resolve other objects’ dependencies.
  • 6. final class Foo { let bar: Bar init(bar: Bar) { self.bar = bar bar.foo = self } func barDidSomething() { ... } } final class Bar { weak var foo: Foo? func doSomething() { foo?.barDidSomething() } }
  • 7. Weaver is a code generation tool which makes it easy to inject dependencies. https://github.com/scribd/Weaver
  • 9. WHY?WHY? I could not nd any satisfying compile time DI solution, so I gave it a try.
  • 11. ADVANTAGESADVANTAGES 1. Mimics manual DI technics. No black box.
  • 12. ADVANTAGESADVANTAGES 1. Mimics manual DI technics. No black box. 2. Compile time errors. Fails fast.
  • 13. ADVANTAGESADVANTAGES 1. Mimics manual DI technics. No black box. 2. Compile time errors. Fails fast. 3. Type safety. If it compiles, it works!
  • 14. ADVANTAGESADVANTAGES 1. Mimics manual DI technics. No black box. 2. Compile time errors. Fails fast. 3. Type safety. If it compiles, it works! 4. Declarativeness.
  • 15. ADVANTAGESADVANTAGES 1. Mimics manual DI technics. No black box. 2. Compile time errors. Fails fast. 3. Type safety. If it compiles, it works! 4. Declarativeness. 5. No optionality. If it's declared, it's there.
  • 16. ADVANTAGESADVANTAGES 1. Mimics manual DI technics. No black box. 2. Compile time errors. Fails fast. 3. Type safety. If it compiles, it works! 4. Declarativeness. 5. No optionality. If it's declared, it's there. 6. Thread safety. Immutability. No lazy loading.
  • 17. ADVANTAGESADVANTAGES 1. Mimics manual DI technics. No black box. 2. Compile time errors. Fails fast. 3. Type safety. If it compiles, it works! 4. Declarativeness. 5. No optionality. If it's declared, it's there. 6. Thread safety. Immutability. No lazy loading. 7. No additional framework to ship.
  • 19. DRAWBACKSDRAWBACKS 1. More code to compile. Can be optimized.
  • 20. DRAWBACKSDRAWBACKS 1. More code to compile. Can be optimized. 2. Meta-programmation is hard.
  • 21. DRAWBACKSDRAWBACKS 1. More code to compile. Can be optimized. 2. Meta-programmation is hard. 3. Use of pseudo annotations.
  • 22. DRAWBACKSDRAWBACKS 1. More code to compile. Can be optimized. 2. Meta-programmation is hard. 3. Use of pseudo annotations. 4. Experimental.
  • 23. LET'S SEE IN PRACTICELET'S SEE IN PRACTICE
  • 24.
  • 26. HOW COULD WE PROVIDEHOW COULD WE PROVIDE URLSessionURLSession??
  • 27. Sharing an instance of URLSession @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { }
  • 28. Sharing an instance of URLSession @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { static var shared: AppDelegate? { return UIApplication.shared.delegate as? AppDelegate } }
  • 29. Sharing an instance of URLSession @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { static var shared: AppDelegate? { return UIApplication.shared.delegate as? AppDelegate } let urlSession: URLSession = { let config = ... return URLSession(configuration: config) }() }
  • 30. Using the shared instance of URLSession final class APIClient { func get(_ url: URL, completion: @escaping (Data?) -> Void) -> } }
  • 31. Using the shared instance of URLSession final class APIClient { func get(_ url: URL, completion: @escaping (Data?) -> Void) -> AppDelegate.shared.urlSession.dataTask(with: url) { ... }.resume() } }
  • 32.
  • 34. Injecting a shared instance of URLSession in APIClient final class APIClient { func get(_ url: URL, completion: @escaping (Data?) -> Void) -> } }
  • 35. Injecting a shared instance of URLSession in APIClient final class APIClient { private let urlSession: URLSession func get(_ url: URL, completion: @escaping (Data?) -> Void) -> } }
  • 36. Injecting a shared instance of URLSession in APIClient final class APIClient { private let urlSession: URLSession init(urlSession: URLSession = AppDelegate.shared.urlSession) self.urlSession = urlSession } func get(_ url: URL, completion: @escaping (Data?) -> Void) -> } }
  • 37. Injecting a shared instance of URLSession in APIClient final class APIClient { private let urlSession: URLSession init(urlSession: URLSession = AppDelegate.shared.urlSession) self.urlSession = urlSession } func get(_ url: URL, completion: @escaping (Data?) -> Void) -> urlSession.dataTask(with: url) { ... }.resume() } }
  • 38. Using APIClient in MovieManager final class MovieManager { func getMovies(_ completion: @escaping ([Movie]?) -> Void) { } }
  • 39. Using APIClient in MovieManager final class MovieManager { func getMovies(_ completion: @escaping ([Movie]?) -> Void) { APIClient().get("http://my_movie_api/movies") { ... } } }
  • 40. Using APIClient in MovieManager final class MovieManager { func getMovies(_ completion: @escaping ([Movie]?) -> Void) { APIClient().get("http://my_movie_api/movies") { ... } // ^ No URLSession to pass in. } }
  • 41.
  • 43. Passing down an instance of URLSession in APIClient final class APIClient { private let urlSession: URLSession init(_ urlSession: URLSession) { self.urlSession = urlSession } func get(_ url: URL, completion: @escaping (Data?) -> Void) -> urlSession.dataTask(with: url) { ... }.resume() } }
  • 44. Passing down an instance of URLSession in APIClient final class APIClient { private let urlSession: URLSession init(_ urlSession: URLSession) { // <- No default anymore self.urlSession = urlSession } func get(_ url: URL, completion: @escaping (Data?) -> Void) -> urlSession.dataTask(with: url) { ... }.resume() } }
  • 45. From MovieManager to APIClient final class MovieManager { func getMovies(_ completion: @escaping ([Movie]?) -> Void) { } }
  • 46. From MovieManager to APIClient final class MovieManager { private let apiClient: APIClient func getMovies(_ completion: @escaping ([Movie]?) -> Void) { } }
  • 47. From MovieManager to APIClient final class MovieManager { private let apiClient: APIClient init(urlSession: URLSession) { apiClient = APIClient(urlSession) } func getMovies(_ completion: @escaping ([Movie]?) -> Void) { } }
  • 48. From MovieManager to APIClient final class MovieManager { private let apiClient: APIClient init(urlSession: URLSession) { apiClient = APIClient(urlSession) } func getMovies(_ completion: @escaping ([Movie]?) -> Void) { apiClient.get("http://my_movie_api/movies") { ... } } }
  • 49. From HomeViewController to MovieManager final class HomeViewController { override func viewDidLoad() { super.viewDidLoad() } }
  • 50. From HomeViewController to MovieManager final class HomeViewController { private let movieManager: MovieManager override func viewDidLoad() { super.viewDidLoad() } }
  • 51. From HomeViewController to MovieManager final class HomeViewController { private let movieManager: MovieManager init(_ urlSession: URLSession) { movieManager = MovieManager(urlSession: urlSession) } override func viewDidLoad() { super.viewDidLoad() } }
  • 52. From HomeViewController to MovieManager final class HomeViewController { private let movieManager: MovieManager init(_ urlSession: URLSession) { movieManager = MovieManager(urlSession: urlSession) } override func viewDidLoad() { super.viewDidLoad() movieManager.getMovies { ... } } }
  • 53. From AppDelegate to HomeViewController @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { func applicationDidFinishLaunching(_ application: UIApplicati } }
  • 54. From AppDelegate to HomeViewController @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { func applicationDidFinishLaunching(_ application: UIApplicati let configuration = ... let urlSession = URLSession(configuration: configuration) } }
  • 55. From AppDelegate to HomeViewController @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { func applicationDidFinishLaunching(_ application: UIApplicati let configuration = ... let urlSession = URLSession(configuration: configuration) let controller = HomeViewController(urlSession) ... } }
  • 56.
  • 58. WHY IS THIS BETTER?WHY IS THIS BETTER?
  • 59. WHY IS THIS BETTER?WHY IS THIS BETTER? MODULARITYMODULARITY
  • 60. What if ImageManager needs a bigger HTTP cache? final class ImageManager { }
  • 61. What if ImageManager needs a bigger HTTP cache? final class ImageManager { init() { } }
  • 62. What if ImageManager needs a bigger HTTP cache? final class ImageManager { init() { let configuration = ... } }
  • 63. What if ImageManager needs a bigger HTTP cache? final class ImageManager { init() { let configuration = ... config.urlCache?.diskCapacity = 1024 * 1024 * 50 config.urlCache?.memoryCapacity = 1024 * 1024 * 5 } }
  • 64. What if ImageManager needs a bigger HTTP cache? final class ImageManager { init() { let configuration = ... config.urlCache?.diskCapacity = 1024 * 1024 * 50 config.urlCache?.memoryCapacity = 1024 * 1024 * 5 let urlSession = URLSession(configuration: configuration) } }
  • 65. What if ImageManager needs a bigger HTTP cache? final class ImageManager { private let apiClient: APIClient init() { let configuration = ... config.urlCache?.diskCapacity = 1024 * 1024 * 50 config.urlCache?.memoryCapacity = 1024 * 1024 * 5 let urlSession = URLSession(configuration: configuration) apiClient = APIClient(urlSession) } }
  • 66. What if ImageManager needs a bigger HTTP cache? final class ImageManager { private let apiClient: APIClient init() { let configuration = ... config.urlCache?.diskCapacity = 1024 * 1024 * 50 config.urlCache?.memoryCapacity = 1024 * 1024 * 5 let urlSession = URLSession(configuration: configuration) apiClient = APIClient(urlSession) } func getImage(_ image: String, completion: @escaping (UIImage apiClient.get("http://my_movie_api/images/(image)") { .. } }
  • 67.
  • 69. Great! But this is too much code to write...
  • 70. In a real project, we'd have to pass down dozens of dependencies @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { func applicationDidFinishLaunching(_ application: UIApplicati let controller = HomeViewController( ) } }
  • 71. In a real project, we'd have to pass down dozens of dependencies @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { func applicationDidFinishLaunching(_ application: UIApplicati let controller = HomeViewController( sessionManager: sessionManager, ) } }
  • 72. In a real project, we'd have to pass down dozens of dependencies @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { func applicationDidFinishLaunching(_ application: UIApplicati let controller = HomeViewController( sessionManager: sessionManager, analyticsManager: analyticsManager, ) } }
  • 73. In a real project, we'd have to pass down dozens of dependencies @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { func applicationDidFinishLaunching(_ application: UIApplicati let controller = HomeViewController( sessionManager: sessionManager, analyticsManager: analyticsManager, reachabilityManager: reachabilityManager, ) } }
  • 74. In a real project, we'd have to pass down dozens of dependencies @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { func applicationDidFinishLaunching(_ application: UIApplicati let controller = HomeViewController( sessionManager: sessionManager, analyticsManager: analyticsManager, reachabilityManager: reachabilityManager, logger: logger, ) } }
  • 75. In a real project, we'd have to pass down dozens of dependencies @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { func applicationDidFinishLaunching(_ application: UIApplicati let controller = HomeViewController( sessionManager: sessionManager, analyticsManager: analyticsManager, reachabilityManager: reachabilityManager, logger: logger, ... ) } }
  • 76. In a real project, we'd have to pass down dozens of dependencies Ouch! @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { func applicationDidFinishLaunching(_ application: UIApplicati let controller = HomeViewController( sessionManager: sessionManager, analyticsManager: analyticsManager, reachabilityManager: reachabilityManager, logger: logger, ... ) } }
  • 77. THAT'S WHERE WEAVER COMES HANDY.THAT'S WHERE WEAVER COMES HANDY.
  • 78. WHAT METHODOLOGY HAVE WE USED SO FAR?WHAT METHODOLOGY HAVE WE USED SO FAR?
  • 79. WHAT METHODOLOGY HAVE WE USED SO FAR?WHAT METHODOLOGY HAVE WE USED SO FAR? 1. Looked at the code.
  • 80. WHAT METHODOLOGY HAVE WE USED SO FAR?WHAT METHODOLOGY HAVE WE USED SO FAR? 1. Looked at the code. 2. Built a representation of the dependency graph.
  • 81. WHAT METHODOLOGY HAVE WE USED SO FAR?WHAT METHODOLOGY HAVE WE USED SO FAR? 1. Looked at the code. 2. Built a representation of the dependency graph. 3. Made sure the dependency graph was ok.
  • 82. WHAT METHODOLOGY HAVE WE USED SO FAR?WHAT METHODOLOGY HAVE WE USED SO FAR? 1. Looked at the code. 2. Built a representation of the dependency graph. 3. Made sure the dependency graph was ok. 4. Used a DI technique to implement the graph.
  • 83. WEAVER DOES THE SAMEWEAVER DOES THE SAME
  • 84. WEAVER DOES THE SAMEWEAVER DOES THE SAME BUT AUTOMATICALLYBUT AUTOMATICALLY
  • 85. WEAVER DOES THE SAMEWEAVER DOES THE SAME BUT AUTOMATICALLYBUT AUTOMATICALLY 1. Scans the code, looking for annotations.
  • 86. WEAVER DOES THE SAMEWEAVER DOES THE SAME BUT AUTOMATICALLYBUT AUTOMATICALLY 1. Scans the code, looking for annotations. 2. Builds a representation of the dependency graph.
  • 87. WEAVER DOES THE SAMEWEAVER DOES THE SAME BUT AUTOMATICALLYBUT AUTOMATICALLY 1. Scans the code, looking for annotations. 2. Builds a representation of the dependency graph. 3. Validates the dependency graph.
  • 88. WEAVER DOES THE SAMEWEAVER DOES THE SAME BUT AUTOMATICALLYBUT AUTOMATICALLY 1. Scans the code, looking for annotations. 2. Builds a representation of the dependency graph. 3. Validates the dependency graph. 4. Generates the code to implement the graph.
  • 89. BACK TO OUR EXAMPLEBACK TO OUR EXAMPLE
  • 91. Referencing to URLSession in APIClient final class APIClient { func get(_ url: URL, completion: @escaping (Data?) -> Void) -> } }
  • 92. Referencing to URLSession in APIClient final class APIClient { private let dependencies: APIClientDependencyResolver init(injecting dependencies: APIClientDependencyResolver) { self.dependencies = dependencies } func get(_ url: URL, completion: @escaping (Data?) -> Void) -> } }
  • 93. Referencing to URLSession in APIClient final class APIClient { private let dependencies: APIClientDependencyResolver // weaver: urlSession <- URLSession init(injecting dependencies: APIClientDependencyResolver) { self.dependencies = dependencies } func get(_ url: URL, completion: @escaping (Data?) -> Void) -> } }
  • 94. Referencing to URLSession in APIClient final class APIClient { private let dependencies: APIClientDependencyResolver // weaver: urlSession <- URLSession init(injecting dependencies: APIClientDependencyResolver) { self.dependencies = dependencies } func get(_ url: URL, completion: @escaping (Data?) -> Void) -> dependencies.urlSession.dataTask(with: url) { ... }.resum } }
  • 95. Referencing to URLSession in APIClient GENERATED CODEGENERATED CODE
  • 96. Referencing to URLSession in APIClient GENERATED CODEGENERATED CODE protocol APIClientInputDependencyResolver { var urlSession: URLSession { get } }
  • 97. Referencing to URLSession in APIClient GENERATED CODEGENERATED CODE protocol APIClientInputDependencyResolver { var urlSession: URLSession { get } } protocol APIClientDependencyResolver { var urlSession: URLSession { get } }
  • 98. Referencing to URLSession in APIClient GENERATED CODEGENERATED CODE protocol APIClientInputDependencyResolver { var urlSession: URLSession { get } } protocol APIClientDependencyResolver { var urlSession: URLSession { get } } final class APIClientDependencyContainer: APIClientDependencyReso let urlSession: URLSession init(injecting dependencies: APIClientInputDependencyResolver urlSession = dependencies.urlSession } }
  • 99. Registering APIClient in MovieManager final class MovieManager { func getMovies(_ completion: @escaping ([Movie]?) -> Void) { } }
  • 100. Registering APIClient in MovieManager final class MovieManager { private let dependencies: MovieManagerDependencyResolver init(injecting dependencies: MovieManagerDependencyResolver) self.dependencies = dependencies } func getMovies(_ completion: @escaping ([Movie]?) -> Void) { } }
  • 101. Registering APIClient in MovieManager final class MovieManager { private let dependencies: MovieManagerDependencyResolver // weaver: apiClient = APIClient init(injecting dependencies: MovieManagerDependencyResolver) self.dependencies = dependencies } func getMovies(_ completion: @escaping ([Movie]?) -> Void) { } }
  • 102. Registering APIClient in MovieManager final class MovieManager { private let dependencies: MovieManagerDependencyResolver // weaver: apiClient = APIClient init(injecting dependencies: MovieManagerDependencyResolver) self.dependencies = dependencies } func getMovies(_ completion: @escaping ([Movie]?) -> Void) { dependencies.apiClient.get("http://my_movie_api/movies") } }
  • 103. Registering APIClient in MovieManager GENERATED CODEGENERATED CODE
  • 104. Registering APIClient in MovieManager GENERATED CODEGENERATED CODE protocol MovieManagerInputDependencyResolver { var urlSession: URLSession { get } }
  • 105. Registering APIClient in MovieManager GENERATED CODEGENERATED CODE protocol MovieManagerInputDependencyResolver { var urlSession: URLSession { get } } protocol MovieManagerDependencyResolver { var apiClient: APIClient { get } }
  • 106. Registering APIClient in MovieManager GENERATED CODEGENERATED CODE protocol MovieManagerInputDependencyResolver { var urlSession: URLSession { get } } protocol MovieManagerDependencyResolver { var apiClient: APIClient { get } } final class MovieManagerDependencyContainer: MovieManagerDependencyResolv let urlSession: URLSession var apiClient: APIClient { let dependencies = APIClientDependencyContainer(injecting: self) return APIClient(injecting: dependencies) } init(injecting dependencies: MovieManagerInputDependencyResolver) { urlSession = dependencies.urlSession } }
  • 107. Registering APIClient in MovieManager GENERATED CODEGENERATED CODE protocol MovieManagerInputDependencyResolver { var urlSession: URLSession { get } } protocol MovieManagerDependencyResolver { var apiClient: APIClient { get } } final class MovieManagerDependencyContainer: MovieManagerDependencyResolv let urlSession: URLSession var apiClient: APIClient { let dependencies = APIClientDependencyContainer(injecting: self) return APIClient(injecting: dependencies) } init(injecting dependencies: MovieManagerInputDependencyResolver) { urlSession = dependencies.urlSession } } extension MovieManagerDependencyContainer: APIClientInputDependencyResolv
  • 108. Registering MovieManager in HomeViewController final class HomeViewController { override func viewDidLoad() { super.viewDidLoad() } }
  • 109. Registering MovieManager in HomeViewController final class HomeViewController { private let dependencies: HomeViewControllerDependencyResolve init(injecting dependencies: HomeViewControllerDependencyReso self.dependencies = dependencies } override func viewDidLoad() { super.viewDidLoad() } }
  • 110. Registering MovieManager in HomeViewController final class HomeViewController { private let dependencies: HomeViewControllerDependencyResolve // weaver: movieManager = MovieManager init(injecting dependencies: HomeViewControllerDependencyReso self.dependencies = dependencies } override func viewDidLoad() { super.viewDidLoad() } }
  • 111. Registering MovieManager in HomeViewController final class HomeViewController { private let dependencies: HomeViewControllerDependencyResolve // weaver: movieManager = MovieManager init(injecting dependencies: HomeViewControllerDependencyReso self.dependencies = dependencies } override func viewDidLoad() { super.viewDidLoad() dependencies.movieManager.getMovies { ... } } }
  • 113. Registering MovieManager in HomeViewController GENERATED CODEGENERATED CODE protocol HomeViewControllerInputDependencyResolver { var urlSession: URLSession { get } }
  • 114. Registering MovieManager in HomeViewController GENERATED CODEGENERATED CODE protocol HomeViewControllerInputDependencyResolver { var urlSession: URLSession { get } } protocol HomeViewControllerDependencyResolver { var movieManager: MovieManager { get } }
  • 115. Registering MovieManager in HomeViewController GENERATED CODEGENERATED CODE protocol HomeViewControllerInputDependencyResolver { var urlSession: URLSession { get } } protocol HomeViewControllerDependencyResolver { var movieManager: MovieManager { get } } final class HomeViewControllerDependencyContainer: HomeViewControllerDepe let urlSession: URLSession var movieManager: MovieManager { let dependencies = MovieManagerDependencyContainer(injecting: sel return MovieManager(injecting: dependencies) } init(injecting dependencies: HomeViewControllerInputDependencyResolve urlSession = dependencies.urlSession } }
  • 116. Registering MovieManager in HomeViewController GENERATED CODEGENERATED CODE protocol HomeViewControllerInputDependencyResolver { var urlSession: URLSession { get } } protocol HomeViewControllerDependencyResolver { var movieManager: MovieManager { get } } final class HomeViewControllerDependencyContainer: HomeViewControllerDepe let urlSession: URLSession var movieManager: MovieManager { let dependencies = MovieManagerDependencyContainer(injecting: sel return MovieManager(injecting: dependencies) } init(injecting dependencies: HomeViewControllerInputDependencyResolve urlSession = dependencies.urlSession } } extension HomeViewControllerDependencyContainer: MovieManagerInputDepende
  • 119.
  • 120. Registering URLSession in AppDelegate @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { }
  • 121. Registering URLSession in AppDelegate @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { private let dependencies = AppDelegateDependencyContainer() }
  • 122. Registering URLSession in AppDelegate @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { private let dependencies = AppDelegateDependencyContainer() // weaver: urlSession = URLSession }
  • 123. Registering URLSession in AppDelegate @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { private let dependencies = AppDelegateDependencyContainer() // weaver: urlSession = URLSession // weaver: urlSession.scope = .container }
  • 124. Registering URLSession in AppDelegate @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { private let dependencies = AppDelegateDependencyContainer() // weaver: urlSession = URLSession // weaver: urlSession.scope = .container // weaver: urlSession.builder = AppDelegate.makeURLSession }
  • 125. Registering URLSession in AppDelegate @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { private let dependencies = AppDelegateDependencyContainer() // weaver: urlSession = URLSession // weaver: urlSession.scope = .container // weaver: urlSession.builder = AppDelegate.makeURLSession static func makeURLSession(_: AppDelegateDependencyResolver) let configuration = ... return URLSession(configuration: configuration) } }
  • 126. Registering URLSession in AppDelegate @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { private let dependencies = AppDelegateDependencyContainer() // weaver: urlSession = URLSession // weaver: urlSession.scope = .container // weaver: urlSession.builder = AppDelegate.makeURLSession static func makeURLSession(_: AppDelegateDependencyResolver) let configuration = ... return URLSession(configuration: configuration) } // weaver: homeViewController = HomeViewController }
  • 127. Registering URLSession in AppDelegate GENERATED CODEGENERATED CODE
  • 128. Registering URLSession in AppDelegate GENERATED CODEGENERATED CODE protocol AppDelegateDependencyResolver { var homeViewController: HomeViewController { get } }
  • 129. Registering URLSession in AppDelegate GENERATED CODEGENERATED CODE protocol AppDelegateDependencyResolver { var homeViewController: HomeViewController { get } } final class AppDelegateDependencyContainer: AppDelegateDependencyResolver let urlSession: URLSession var homeViewController: HomeViewController { let dependencies = HomeViewControllerDependencyContainer(injectin return HomeViewController(injecting: dependencies) } init() { urlSession = URLSession.makeURLSession(self) } }
  • 130. Registering URLSession in AppDelegate GENERATED CODEGENERATED CODE protocol AppDelegateDependencyResolver { var homeViewController: HomeViewController { get } } final class AppDelegateDependencyContainer: AppDelegateDependencyResolver let urlSession: URLSession var homeViewController: HomeViewController { let dependencies = HomeViewControllerDependencyContainer(injectin return HomeViewController(injecting: dependencies) } init() { urlSession = URLSession.makeURLSession(self) } } extension AppDelegateDependencyContainer: HomeViewControllerInputDependen
  • 131.
  • 135. Registering URLSession with a bigger HTTP cache in ImageManager final class ImageManager { }
  • 136. Registering URLSession with a bigger HTTP cache in ImageManager final class ImageManager { private let dependencies: ImageManagerDependencyResolver init(injecting dependencies: ImageManagerDependencyResolver) { self.d }
  • 137. Registering URLSession with a bigger HTTP cache in ImageManager final class ImageManager { private let dependencies: ImageManagerDependencyResolver // weaver: urlSession = URLSession // weaver: urlSession.scope = .container // weaver: urlSession.builder = ImageManager.makeURLSession init(injecting dependencies: ImageManagerDependencyResolver) { self.d }
  • 138. Registering URLSession with a bigger HTTP cache in ImageManager final class ImageManager { private let dependencies: ImageManagerDependencyResolver // weaver: urlSession = URLSession // weaver: urlSession.scope = .container // weaver: urlSession.builder = ImageManager.makeURLSession init(injecting dependencies: ImageManagerDependencyResolver) { self.d static func makeURLSession(_: ImageManagerDependencyResolver) -> URLS let configuration = ... configuration.urlCache?.diskCapacity = 1024 * 1024 * 50 configuration.urlCache?.memoryCapacity = 1024 * 1024 * 5 return URLSession(configuration: configuration) } }
  • 139. Registering URLSession in ImageManager GENERATED CODEGENERATED CODE
  • 140. Registering URLSession in ImageManager GENERATED CODEGENERATED CODE protocol ImageManagerDependencyResolver { var apiClient: APIClient { get } }
  • 141. Registering URLSession in ImageManager GENERATED CODEGENERATED CODE protocol ImageManagerDependencyResolver { var apiClient: APIClient { get } } final class ImageManagerDependencyContainer: ImageManagerDependencyResolv let urlSession: URLSession var apiClient: APIClient { let dependencies = APIClientDependencyContainer(injecting: self) return APIClient(injecting: dependencies) } init() { urlSession = URLSession.makeURLSession(self) } }
  • 142. Registering URLSession in ImageManager GENERATED CODEGENERATED CODE protocol ImageManagerDependencyResolver { var apiClient: APIClient { get } } final class ImageManagerDependencyContainer: ImageManagerDependencyResolv let urlSession: URLSession var apiClient: APIClient { let dependencies = APIClientDependencyContainer(injecting: self) return APIClient(injecting: dependencies) } init() { urlSession = URLSession.makeURLSession(self) } } extension ImageManagerDependencyContainer: APIClientInputDependencyResolv
  • 143.
  • 144. Works out of the box
  • 145. ROOM FOR IMPROVEMENTROOM FOR IMPROVEMENT
  • 146. ROOM FOR IMPROVEMENTROOM FOR IMPROVEMENT Adopt Weaver more widely at Scribd.
  • 147. ROOM FOR IMPROVEMENTROOM FOR IMPROVEMENT Adopt Weaver more widely at Scribd. Dependency graph visualizer.
  • 148. ROOM FOR IMPROVEMENTROOM FOR IMPROVEMENT Adopt Weaver more widely at Scribd. Dependency graph visualizer. Dependency graph optimizations.
  • 149. ROOM FOR IMPROVEMENTROOM FOR IMPROVEMENT Adopt Weaver more widely at Scribd. Dependency graph visualizer. Dependency graph optimizations. Detect retain cycles.
  • 150. ROOM FOR IMPROVEMENTROOM FOR IMPROVEMENT Adopt Weaver more widely at Scribd. Dependency graph visualizer. Dependency graph optimizations. Detect retain cycles. Detect suspicious graph shapes.
  • 151. ROOM FOR IMPROVEMENTROOM FOR IMPROVEMENT Adopt Weaver more widely at Scribd. Dependency graph visualizer. Dependency graph optimizations. Detect retain cycles. Detect suspicious graph shapes. ...