Slide 1

Slide 1 text

Dagger Reflect Nelson Osacky from runtime to compile time and back again

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

Me • Android for 9 years • Chocolate and Running • Previously at Square in SF on Build Tools • Currently Working at SoundCloud in Berlin • Maintainer of Fladle - Gradle Plugin for Firebase Test Lab https://github.com/runningcode/fladle

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

Why?

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

What is Dependency Injection?

Slide 8

Slide 8 text

public class Store {a private Item item; public Store()a{ item = new ItemImpl1(); }a }b

Slide 9

Slide 9 text

public class Store {a private Item item; public Store( )a{ itema=bnew ItemImpl1(); }a }b

Slide 10

Slide 10 text

public class Store {a private Item item; public Store( Itembitem )a{ this.item = item; }a }b

Slide 11

Slide 11 text

public class Store {a private Item item; public Store(Itembitem)a{ this.item = item; }a }b

Slide 12

Slide 12 text

Dependency Injection in the Java world

Slide 13

Slide 13 text

Spring

Slide 14

Slide 14 text

Spring

Slide 15

Slide 15 text

Java 1.5 added @Annotations

Slide 16

Slide 16 text

Guice

Slide 17

Slide 17 text

Guice public class Store {c private Item item; public Store(Item item) {d this.item = item; }a }b

Slide 18

Slide 18 text

Guice public class Store {c private Item item; @Inject public Store(Item item) {d this.item = item; }a }b

Slide 19

Slide 19 text

Dagger

Slide 20

Slide 20 text

Dagger public class Store {c private Item item; @Inject public Store(Item item) {d this.item = item; }a }b

Slide 21

Slide 21 text

Dagger @Module public class PlayerModule { @Provides public PlayerProvider providePlayerProvider(AppFeatures appFeatures) { return new PlayerProviderImpl(appfeatures); } }

Slide 22

Slide 22 text

No content

Slide 23

Slide 23 text

Dagger 2

Slide 24

Slide 24 text

@Component(includes = PlayerModule.class) public interface ApplicationComponent { }

Slide 25

Slide 25 text

Super rough comparison (not to scale) 0 25 50 75 100 Guice Dagger 1 Dagger 2 Compile Time Runtime

Slide 26

Slide 26 text

No content

Slide 27

Slide 27 text

No content

Slide 28

Slide 28 text

No content

Slide 29

Slide 29 text

Dagger Reflect

Slide 30

Slide 30 text

A reflection-based implementation of the Dagger dependency injection library for fast local builds.

Slide 31

Slide 31 text

MyApplication DaggerApplicationComponent

Slide 32

Slide 32 text

@Component public interface ApplicationComponent {b }a

Slide 33

Slide 33 text

@Component public interface ApplicationComponent {b }a DaggerApplicationComponent .factory() .create(this)

Slide 34

Slide 34 text

@Component public interface ApplicationComponent {b @Component.Factory interface Builder {b} }a DaggerApplicationComponent .factory() .create(this)

Slide 35

Slide 35 text

@Component public interface ApplicationComponent {b void inject(MyApplication application); @Component.Factory interface Builder {b} }a DaggerApplicationComponent .factory() .create(this)

Slide 36

Slide 36 text

@Component public interface ApplicationComponent {b void inject(MyApplication application); @Component.Factory interface Builder {b} }a DaggerApplicationComponent .factory() .create(this) .inject(this)

Slide 37

Slide 37 text

class MyApplication : Application(), HasAndroidInjector { override fun onCreate() { super.onCreate() DaggerApplicationComponent .factory() .create(this) .inject(this) } }

Slide 38

Slide 38 text

MyApplication DaggerApplicationComponent Generated by Dagger ~10,000 lines

Slide 39

Slide 39 text

public final class DaggerApplicationComponent { private void initialize(final ApplicationModule applicationModuleParam, final FacebookModule facebookModuleParam, final ApiModule apiModuleParam, final AppFeaturesModule appFeaturesModuleParam, final. BaseAnalyticsModule baseAnalyticsModuleParam, final AdAnalyticsModule adAnalyticsModuleParam, final AppBoyModule appBoyModuleParam, final Application applicationParam) { this.userTopTracksFragmentSubcomponentFactoryProvider = new Provider() { @Override public UserTopTracksModule_BindUserTopTracksFragment.UserTopTracksFragmentSubcomponent.Factory get( ) { return new UserTopTracksFragmentSubcomponentFactory();} }; this.soundRecorderServiceSubcomponentFactoryProvider = new Provider() { @Override public CreatorsModule_ProvidesSoundRecorder.SoundRecorderServiceSubcomponent.Factory get() { return new SoundRecorderServiceSubcomponentFactory();} }; this.recordFragmentSubcomponentFactoryProvider = new Provider() { @Override public CreatorsModule_ProvidesRecordFragment.RecordFragmentSubcomponent.Factory get() { return new RecordFragmentSubcomponentFactory();} }; this.recordAppWidgetProviderSubcomponentFactoryProvider = new Provider() { @Override public CreatorsModule_ProvidesRecordAppWidgetProvider.RecordAppWidgetProviderSubcomponent.Factory get( ) { return new RecordAppWidgetProviderSubcomponentFactory();} }; this.homescreenWidgetBroadcastReceiverSubcomponentFactoryProvider = new Provider() { @Override public HomescreenWidgetModule_HomescreenWidgetBroadcastReceiver.HomescreenWidgetBroadcastReceiverSubcomponent.Factory get( ) { return new HomescreenWidgetBroadcastReceiverSubcomponentFactory();} }; this.mainActivitySubcomponentFactoryProvider = new Provider() { @Override public ActivityBuilder_BindMainActivity.MainActivitySubcomponent.Factory get() { return new MainActivitySubcomponentFactory();} }; this.launcherActivitySubcomponentFactoryProvider = new Provider() { @Override public ActivityBuilder_BindLauncherActivity.LauncherActivitySubcomponent.Factory get() { return new LauncherActivitySubcomponentFactory();} }; this.resolveActivitySubcomponentFactoryProvider = new Provider() { @Override public ActivityBuilder_BindResolveActivity.ResolveActivitySubcomponent.Factory get() { return new ResolveActivitySubcomponentFactory();} }; this.changeStorageLocationActivitySubcomponentFactoryProvider = new Provider() { @Override public ActivityBuilder_BindChangeLocationStorageActivity.ChangeStorageLocationActivitySubcomponent.Factory get( ) { return new ChangeStorageLocationActivitySubcomponentFactory();} }; this.fullScreenVideoActivitySubcomponentFactoryProvider = new Provider() { @Override public ActivityBuilder_BindFullScreenVideoActivity.FullScreenVideoActivitySubcomponent.Factory get( ) { return new FullScreenVideoActivitySubcomponentFactory();} }; this.goOnboardingActivitySubcomponentFactoryProvider = new Provider() { @Override public ActivityBuilder_BindGoOnboardingActivity.GoOnboardingActivitySubcomponent.Factory get( ) {

Slide 40

Slide 40 text

MyApplication DaggerApplicationComponent Generated by Dagger ~10,000 lines

Slide 41

Slide 41 text

MyApplication DaggerApplicationComponent Generated by DaggeriReflect 20 lines long

Slide 42

Slide 42 text

MyApplication DaggerApplicationComponent Generated by DaggeriReflect 20 lines long DaggerReflect Dagger Reflect Runtime

Slide 43

Slide 43 text

MyApplication DaggerApplicationComponent DaggerReflect DaggerApplicationComponent

Slide 44

Slide 44 text

MyApplication DaggerApplicationComponent DaggerReflect DaggerApplicationComponent

Slide 45

Slide 45 text

MyApplication DaggerApplicationComponent Generated by DaggeriReflect DaggerReflect DaggerApplicationComponent Generated by Dagger

Slide 46

Slide 46 text

public final class DaggerApplicationComponent {a public static ApplicationComponent.Builder factory() {b return DaggerReflect.factory(ApplicationComponent.Builder.class); }c }d

Slide 47

Slide 47 text

public final class DaggerApplicationComponent {a public static ApplicationComponent.Builder factory() {b return DaggerReflect.factory(ApplicationComponent.Builder.class); }c }d Generated by Dagger Reflect

Slide 48

Slide 48 text

DaggerReflect.factory(ApplicationComponent.Builder.class);

Slide 49

Slide 49 text

DaggerReflect.factory(ApplicationComponent.Builder.class);

Slide 50

Slide 50 text

DaggerReflect factory

Slide 51

Slide 51 text

public final class DaggerReflect {a public static F factory(Class factoryClass) {b }c }d

Slide 52

Slide 52 text

public final class DaggerReflect {a public static F factory(Class factoryClass) {b }c }d In Dagger Reflect Library

Slide 53

Slide 53 text

public final class DaggerReflect {a public static F factory(Class factoryClass) {b return ComponentFactoryInvocationHandler.forComponentFactory(factoryClass); }c }d In Dagger Reflect Library

Slide 54

Slide 54 text

ComponentFactoryInvocationHandler.forComponentFactory(factoryClass); In Dagger Reflect Library

Slide 55

Slide 55 text

ComponentFactoryInvocationHandler In Dagger Reflect Library

Slide 56

Slide 56 text

InvocationHandler

Slide 57

Slide 57 text

InvocationHandler java.lang.Reflect

Slide 58

Slide 58 text

public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) } java.lang.Reflect

Slide 59

Slide 59 text

InvocationHandler handles method invocations on Proxy classes

Slide 60

Slide 60 text

Proxy classes

Slide 61

Slide 61 text

Proxy classes Implement interfaces at runtime when they are created

Slide 62

Slide 62 text

Create a proxy class at runtime implementing our Component Interface

Slide 63

Slide 63 text

MyApplication DaggerApplicationComponent Generated by DaggeriReflect 20 lines long DaggerReflect Dagger Reflect Runtime

Slide 64

Slide 64 text

MyApplication DaggerApplicationComponent DaggerReflect

Slide 65

Slide 65 text

MyApplication DaggerApplicationComponent Factory DaggerApplicationComponent ComponentFactoryInvocationHandler

Slide 66

Slide 66 text

MyApplication DaggerApplicationComponent.Factory DaggerApplicationComponent ComponentFactoryInvocationHandler

Slide 67

Slide 67 text

ComponentFactoryInvocationHandler.forComponentFactory(factoryClass); In Dagger Reflect Library

Slide 68

Slide 68 text

ComponentFactoryInvocationHandler forComponentFactory In Dagger Reflect Library

Slide 69

Slide 69 text

static F forComponentFactory(Class factoryClass) {a requireAnnotation(factoryClass, Component.Factory.class); Class> componentClass = requireEnclosingClass(factoryClass); return newProxy( factoryClass, new ComponentFactoryInvocationHandler( componentClass, () -> ComponentScopeBuilder.buildComponent(componentClass))); }b In Dagger Reflect Library

Slide 70

Slide 70 text

static F forComponentFactory(Class factoryClass) {a requireAnnotation(factoryClass, Component.Factory.class); Class> componentClass = requireEnclosingClass(factoryClass); return newProxy( factoryClass, new ComponentFactoryInvocationHandler( componentClass, () -> ComponentScopeBuilder.buildComponent(componentClass))); }b In Dagger Reflect Library

Slide 71

Slide 71 text

static F forComponentFactory(Class factoryClass) {a requireAnnotation(factoryClass, Component.Factory.class); Class> componentClass = requireEnclosingClass(factoryClass); return newProxy( factoryClass, new ComponentFactoryInvocationHandler( componentClass, () -> ComponentScopeBuilder.buildComponent(componentClass))); }b In Dagger Reflect Library

Slide 72

Slide 72 text

static F forComponentFactory(Class factoryClass) {a requireAnnotation(factoryClass, Component.Factory.class); Class> componentClass = requireEnclosingClass(factoryClass); return newProxy( factoryClass, new ComponentFactoryInvocationHandler( componentClass, () -> ComponentScopeBuilder.buildComponent(componentClass))); }b In Dagger Reflect Library

Slide 73

Slide 73 text

static F forComponentFactory(Class factoryClass) {a requireAnnotation(factoryClass, Component.Factory.class); Class> componentClass = requireEnclosingClass(factoryClass); return newProxy( factoryClass, new ComponentFactoryInvocationHandler( componentClass, () -> ComponentScopeBuilder.buildComponent(componentClass))); }b In Dagger Reflect Library

Slide 74

Slide 74 text

static F forComponentFactory(Class factoryClass) {a requireAnnotation(factoryClass, Component.Factory.class); Class> componentClass = requireEnclosingClass(factoryClass); return newProxy( factoryClass, new ComponentFactoryInvocationHandler( componentClass, () -> ComponentScopeBuilder.buildComponent(componentClass))); }b In Dagger Reflect Library

Slide 75

Slide 75 text

static F forComponentFactory(Class factoryClass) {a requireAnnotation(factoryClass, Component.Factory.class); Class> componentClass = requireEnclosingClass(factoryClass); return newProxy( factoryClass, new ComponentFactoryInvocationHandler( componentClass, () -> ComponentScopeBuilder.buildComponent(componentClass))); }b In Dagger Reflect Library

Slide 76

Slide 76 text

static F forComponentFactory(Class factoryClass) {a requireAnnotation(factoryClass, Component.Factory.class); Class> componentClass = requireEnclosingClass(factoryClass); return newProxy( factoryClass, new ComponentFactoryInvocationHandler( componentClass, () -> ComponentScopeBuilder.buildComponent(componentClass))); }b In Dagger Reflect Library

Slide 77

Slide 77 text

static F forComponentFactory(Class factoryClass) {a requireAnnotation(factoryClass, Component.Factory.class); Class> componentClass = requireEnclosingClass(factoryClass); return newProxy( factoryClass, new ComponentFactoryInvocationHandler( componentClass, () -> ComponentScopeBuilder.buildComponent(componentClass))); }b In Dagger Reflect Library

Slide 78

Slide 78 text

ComponentScopeBuilder.buildComponent(componentClass)) In Dagger Reflect Library

Slide 79

Slide 79 text

ComponentScopeBuilder buildComponent In Dagger Reflect Library

Slide 80

Slide 80 text

static ComponentScopeBuilder buildComponent(Class> componentClass) {a Component component = requireAnnotation(componentClass, Component.class); Set scopeAnnotation = findScopes(componentClass.getAnnotations()); return create(component.modules(), component.dependencies(), scopeAnnotation, null); }b In Dagger Reflect Library

Slide 81

Slide 81 text

static ComponentScopeBuilder buildComponent(Class> componentClass) {a Component component = requireAnnotation(componentClass, Component.class); Set scopeAnnotation = findScopes(componentClass.getAnnotations()); return create(component.modules(), component.dependencies(), scopeAnnotation, null); }b In Dagger Reflect Library

Slide 82

Slide 82 text

static ComponentScopeBuilder buildComponent(Class> componentClass) {a Component component = requireAnnotation(componentClass, Component.class); Set scopeAnnotation = findScopes(componentClass.getAnnotations()); return create(component.modules(), component.dependencies(), scopeAnnotation, null); }b In Dagger Reflect Library

Slide 83

Slide 83 text

static ComponentScopeBuilder buildComponent(Class> componentClass) {a Component component = requireAnnotation(componentClass, Component.class); Set scopeAnnotation = findScopes(componentClass.getAnnotations()); return create(component.modules(), component.dependencies(), scopeAnnotation, null); }b In Dagger Reflect Library

Slide 84

Slide 84 text

No content

Slide 85

Slide 85 text

Dagger Reflect Development

Slide 86

Slide 86 text

reflect reflect-compiler integration-tests codegen Project Gradle Setup

Slide 87

Slide 87 text

reflect Reflection based implementation of Dagger

Slide 88

Slide 88 text

reflect reflect-compiler integration-tests codegen Project Gradle Setup

Slide 89

Slide 89 text

reflect-compiler Generates the glue to link your code to the reflection based dagger implementation

Slide 90

Slide 90 text

reflect reflect-compiler integration-tests codegen Project Gradle Setup

Slide 91

Slide 91 text

integration-tests All the tests!

Slide 92

Slide 92 text

integration-tests Make sure we do the same thing as Dagger!

Slide 93

Slide 93 text

integration-tests Make sure we do the same thing as Dagger!

Slide 94

Slide 94 text

@Test public void componentProvider() {a ComponentProvider component = backend.create(ComponentProvider.class); assertThat(component.string()).isEqualTo("foo"); }b

Slide 95

Slide 95 text

@Test public void componentProvider() {a ComponentProvider component = backend.create(ComponentProvider.class); assertThat(component.string()).isEqualTo("foo"); }b @Component(modules = ComponentProvider.Module1.class) interface ComponentProvider { String string(); @Module abstract class Module1 { @Provides static String string() { return "foo"; } } }

Slide 96

Slide 96 text

@Test public void componentProvider() {a ComponentProvider component = backend.create(ComponentProvider.class); assertThat(component.string()).isEqualTo("foo"); }b

Slide 97

Slide 97 text

backend.create(ComponentProvider.class);

Slide 98

Slide 98 text

@RunWith(Parameterized.class) public final class IntegrationTest { @Parameters(name = "{0}") public static Object[] parameters() { return Backend.values(); } @Parameter public Backend backend = backend.create(ComponentProvider.class); }

Slide 99

Slide 99 text

Backend.values();

Slide 100

Slide 100 text

Backend values();

Slide 101

Slide 101 text

enum Backend {a REFLECT, CODEGEN }e

Slide 102

Slide 102 text

enum Backend {a abstract C create(Class componentClass); REFLECT, CODEGEN }e

Slide 103

Slide 103 text

enum Backend {a abstract C create(Class componentClass); REFLECT {b @Overridea aFacreate(ClassacomponentClass) { returnaDaggerReflect.create(componentClass); }c },d CODEGEN }e

Slide 104

Slide 104 text

enum Backend {a abstract C create(Class componentClass); REFLECT {b @Overridea aFacreate(ClassacomponentClass) { returnaDaggerReflect.create(componentClass); }c },d CODEGEN { @Override F create(Class componentClass) { return DaggerCodegen.create(componentClass); } }; }e

Slide 105

Slide 105 text

backend.create(ComponentProvider.class);

Slide 106

Slide 106 text

@RunWith(Parameterized.class) public final class IntegrationTest { @Parameters(name = "{0}") public static Object[] parameters() { return Backend.values(); } @Parameter public Backend backend = backend.create(ComponentProvider.class); }

Slide 107

Slide 107 text

backend.create(ComponentProvider.class);

Slide 108

Slide 108 text

@Test public void componentProvider() { ComponentProvider component = backend.create(ComponentProvider.class); assertThat(component.string()).isEqualTo("foo"); }

Slide 109

Slide 109 text

How to contribute

Slide 110

Slide 110 text

Try it and write tests

Slide 111

Slide 111 text

@Test public void justInTimeGenericNested()a{ ignoreReflectionBackend(); JustInTimeGenericNested component = backend.create(JustInTimeGenericNested.class); assertThat(component.thing()).isNotNull(); }b

Slide 112

Slide 112 text

pu()a{ ignoreReflectionBackend(); Jus asserTNu }

Slide 113

Slide 113 text

private void ignoreReflectionBackend() { assumeTrue("Not yet implemented for reflection backend", backend != Backend.REFLECT); }

Slide 114

Slide 114 text

@Test public void justInTimeGenericNested()a{ ignoreReflectionBackend(); JustInTimeGenericNested component = backend.create(JustInTimeGenericNested.class); assertThat(component.thing()).isNotNull(); }b

Slide 115

Slide 115 text

@Test public void justInTimeGenericNested() { JustInTimeGenericNested component = backend.create(JustInTimeGenericNested.class); assertThat(component.thing()).isNotNull(); }

Slide 116

Slide 116 text

integration-tests Make sure we do the same thing as Dagger!

Slide 117

Slide 117 text

integration-tests Run the Dagger tests on Dagger Reflect upstream

Slide 118

Slide 118 text

test.filter { // dagger-reflect does not produce the exact same behavior as dagger-compiler for @Reusable. excludeTest 'dagger.functional.ReusableTest', null // TODO reflect bug! Need something like ByteBuddy for proxying classes at runtime. excludeTest 'dagger.functional.builder.BuilderBindsInstanceParameterTest', null // TODO reflect bug! Generics don't work well. excludeTest 'dagger.functional.GenericTest', 'complexGenerics' }

Slide 119

Slide 119 text

Usage

Slide 120

Slide 120 text

Make sure to use @Component.Builder or @Component.Factory

Slide 121

Slide 121 text

@Component interface ApplicationComponent {a }d

Slide 122

Slide 122 text

@Component interface ApplicationComponent {a @Component.Factory interface Factory {b }c }d

Slide 123

Slide 123 text

class MyApplication : Application(), HasAndroidInjector { override fun onCreate() { super.onCreate() DaggerApplicationComponent .factory() .create(this) .inject(this) } }

Slide 124

Slide 124 text

Make sure Dagger Annotations have Runtime Retention

Slide 125

Slide 125 text

@Qualifier public @interface EventGatewayBaseUrl {a }b

Slide 126

Slide 126 text

@Qualifier @Retention(RetentionPolicy.RUNTIME) public @interface EventGatewayBaseUrl {a }b

Slide 127

Slide 127 text

@Qualifier @Retention(RetentionPolicy.RUNTIME) public @interface EventGatewayBaseUrl { } Structural Based Search Inspection

Slide 128

Slide 128 text

Swap Dagger for Dagger Reflect

Slide 129

Slide 129 text

implementation deps.dagger.dagger kapt deps.dagger.compiler

Slide 130

Slide 130 text

implementation deps.dagger.dagger kapt deps.dagger.compiler private fun useDaggerReflect() : Boolean { return properties["dagger.reflect"] == "true") }

Slide 131

Slide 131 text

private fun useDaggerReflect() : Boolean { return properties["dagger.reflect"] == "true") }

Slide 132

Slide 132 text

implementation deps.dagger.dagger if ( useDaggerReflect() ) { implementation deps.dagger.reflectRuntime kapt deps.dagger.daggerReflectCompiler } else { kapt deps.dagger.compiler }

Slide 133

Slide 133 text

implementation deps.dagger.dagger if (useDaggerReflect()) { implementation deps.dagger.reflectRuntime kapt deps.dagger.daggerReflectCompiler } else { kapt deps.dagger.compiler }

Slide 134

Slide 134 text

Swap Dagger for Dagger Reflect

Slide 135

Slide 135 text

Swap Dagger for Dagger Reflect in every module

Slide 136

Slide 136 text

implementationadeps.dagger.dagger if (useDaggerReflect()) { implementation deps.dagger.reflectRuntime kapt deps.dagger.daggerReflectCompiler }celse {a kapt deps.dagger.compiler }b

Slide 137

Slide 137 text

implementationadeps.dagger.dagger implementationbdeps.dagger.daggerAndroid if (useDaggerReflect()) { implementation deps.dagger.reflectRuntime kapt deps.dagger.daggerReflectCompiler }celse {a kapt deps.dagger.compiler kapt deps.dagger.daggerAndroidCompiler }b

Slide 138

Slide 138 text

Swap Dagger for Dagger Reflect in every module

Slide 139

Slide 139 text

Swap Dagger for Dagger Reflect in every module and for Dagger Android

Slide 140

Slide 140 text

Swap Dagger for Dagger Reflect in every module and for Dagger Android and for every new module

Slide 141

Slide 141 text

It’s high maintenance

Slide 142

Slide 142 text

No content

Slide 143

Slide 143 text

apply plugin: 'com.soundcloud.delect'

Slide 144

Slide 144 text

Dagger Reflect Gradle Plugin

Slide 145

Slide 145 text

apply plugin: 'com.soundcloud.delect'

Slide 146

Slide 146 text

buildscript { classpath 'com.soundcloud.delect:delect-plugin:0.1.0-SNAPSHOT' } apply plugin: 'com.soundcloud.delect'

Slide 147

Slide 147 text

echo "dagger.reflect=true" > ~/.gradle/gradle.properties

Slide 148

Slide 148 text

echo "dagger.reflect=true" > ~/.gradle/gradle.properties

Slide 149

Slide 149 text

Delect

Slide 150

Slide 150 text

implementation deps.dagger.dagger if (useDaggerReflect()) { implementation deps.dagger.reflectRuntime kapt deps.dagger.daggerReflectCompiler } else { kapt deps.dagger.compiler }

Slide 151

Slide 151 text

configurations.all config@ {a dependencies.all {b //bIf we depend on the daggerbruntime, also add the daggerbreflect runtime. ifb(group == daggerGroupId && name == "dagger") {c dependencies {d add([email protected], "$com.jakewharton.dagger:dagger-reflect:${extension.daggerReflectVersion}") }e }f }g resolutionStrategy {h dependencySubstitution {o // Substitute dagger compiler for dagger reflect compiler. substitute( module("$com.google.dagger:dagger-compiler“) ).apply { with(module("$com.jakewharton.dagger:dagger-reflect-compiler:${extension.daggerReflectVersion}")) because("We want to build faster.") }p substitute(module("$com.google.dagger:dagger-android-processor")) .with(module("$com.jakewharton.dagger:dagger-reflect-compiler:${extension.daggerReflectVersion}")) }q }r }s

Slide 152

Slide 152 text

configurations.all config@ {a dependencies.all {b //bIf we depend on the daggerbruntime, also add the daggerbreflect runtime. ifb(group == daggerGroupId && name == "dagger") {c dependencies {d add([email protected], "$com.jakewharton.dagger:dagger-reflect:${extension.daggerReflectVersion}") }e }f }g }s

Slide 153

Slide 153 text

configurations.all config@ {a dependencies.all {b //bIf we depend on the daggerbruntime, also add the daggerbreflect runtime. ifb(group == daggerGroupId && name == "dagger") {c dependencies {d add([email protected], "$com.jakewharton.dagger:dagger-reflect:${extension.daggerReflectVersion}") }e }f }g }s

Slide 154

Slide 154 text

configurations.all config@ {a dependencies.all {b //bIf we depend on the daggerbruntime, also add the daggerbreflect runtime. ifb(group == daggerGroupId && name == "dagger") {c dependencies {d add([email protected], "$com.jakewharton.dagger:dagger-reflect:${extension.daggerReflectVersion}") }e }f }g resolutionStrategy {h dependencySubstitution {o // Substitute dagger compiler for dagger reflect compiler. substitute( module("$com.google.dagger:dagger-compiler") ).apply { with(module("$com.jakewharton.dagger:dagger-reflect-compiler:${extension.daggerReflectVersion}")) because("We want to build faster.") }p substitute(module("$com.google.dagger:dagger-android-processor")) .with(module("$com.jakewharton.dagger:dagger-reflect-compiler:${extension.daggerReflectVersion}")) }q }r }s

Slide 155

Slide 155 text

configurations.all config@ {a resolutionStrategy {h dependencySubstitution {o // Substitute dagger compiler for dagger reflect compiler. substitute( module("$com.google.dagger:dagger-compiler") ).apply { with(module("$com.jakewharton.dagger:dagger-reflect-compiler:${extension.daggerReflectVersion}")) because("We want to build faster.") }p }q }r }s

Slide 156

Slide 156 text

configurations.all config@ {a resolutionStrategy {h dependencySubstitution {o // Substitute dagger compiler for dagger reflect compiler. substitute( module("$com.google.dagger:dagger-compiler") ).apply { with(module("$com.jakewharton.dagger:dagger-reflect-compiler:${extension.daggerReflectVersion}")) because("We want to build faster.") }p substitute(module("$com.google.dagger:dagger-android-processor")) .with(module("$com.jakewharton.dagger:dagger-reflect-compiler:${extension.daggerReflectVersion}")) }q }r }s

Slide 157

Slide 157 text

configurations.all config@ {a resolutionStrategy {h dependencySubstitution {o // Substitute dagger compiler for dagger reflect compiler. substitute( module("$com.google.dagger:dagger-compiler") ).apply { with(module("$com.jakewharton.dagger:dagger-reflect-compiler:${extension.daggerReflectVersion}")) because("We want to build faster.") }p substitute(module("$com.google.dagger:dagger-android-processor")) .with(module("$com.jakewharton.dagger:dagger-reflect-compiler:${extension.daggerReflectVersion}")) }q }r }s

Slide 158

Slide 158 text

configurations.all config@ {a dependencies.all {b //bIf we depend on the daggerbruntime, also add the daggerbreflect runtime. ifb(group == daggerGroupId && name == "dagger") {c dependencies {d add([email protected], "$com.jakewharton.dagger:dagger-reflect:${extension.daggerReflectVersion}") }e }f }g resolutionStrategy {h dependencySubstitution {o // Substitute dagger compiler for dagger reflect compiler. substitute( module("$com.google.dagger:dagger-compiler") ).apply { with(module("$com.jakewharton.dagger:dagger-reflect-compiler:${extension.daggerReflectVersion}")) because("We want to build faster.") }p substitute(module("$com.google.dagger:dagger-android-processor")) .with(module("$com.jakewharton.dagger:dagger-reflect-compiler:${extension.daggerReflectVersion}")) }q }r }s

Slide 159

Slide 159 text

Let’s talk build times

Slide 160

Slide 160 text

Dagger Reflect Build clean with unique java file 1m54s 1m35s Clean build 31s 26s No-op build 8s 7s Make change to DI 1m8s 1m1s Micro benchmark

Slide 161

Slide 161 text

No content

Slide 162

Slide 162 text

No content

Slide 163

Slide 163 text

No content

Slide 164

Slide 164 text

No content

Slide 165

Slide 165 text

No content

Slide 166

Slide 166 text

No content

Slide 167

Slide 167 text

The longer the build the longer the Dagger time

Slide 168

Slide 168 text

No content

Slide 169

Slide 169 text

No content

Slide 170

Slide 170 text

The current state of Dagger Reflect

Slide 171

Slide 171 text

• Slower startup time • Lazy reflection (doesn’t scan entire app at startup) • Different behavior than production • Not all Dagger features are supported yet • Poor error messages

Slide 172

Slide 172 text

Future of Dagger Reflect

Slide 173

Slide 173 text

• Match Dagger with Features • Improve Error Messages • Improve Runtime Performance • Kotlin Dagger Reflect

Slide 174

Slide 174 text

Relative build performance J genating J only K generating K only K & J generating K & J Time https://eng.uber.com/measuring-kotlin-build-performance/

Slide 175

Slide 175 text

At SoundCloud

Slide 176

Slide 176 text

At SoundCloud • Long running side project • Small number of devs using it on master since last week! • Currently running Dagger Reflect behind an opt-in gradle property • Using a fork of Dagger Reflect with our supported features

Slide 177

Slide 177 text

No content

Slide 178

Slide 178 text

Dagger Reflect a0.1.0a

Slide 179

Slide 179 text

Dagger Reflect a0.1.0a 0.1.0 Delect

Slide 180

Slide 180 text

• Thanks to Riccardo for testing Delect and help with open sourcing • Thanks to my team for testing out Dagger Reflect • Thanks to SoundCloud for letting me have the time to work on this • Thanks Jake Wharton for reviewing my code and building and releasing 0.1.0

Slide 181

Slide 181 text

More information • DIY: Build your own dependency injection library - Pierre- Yves Ricau - https://academy.realm.io/posts/android- pierre-yves-ricau-build-own-dependency-injection/ • Dagger Reflect: https://github.com/jakewharton/dagger- reflect • Dagger Reflect Gradle Plugin: https://github.com/ soundcloud/delect • A brief history of dependency injection http://mvpjava.com/ brief-history-dependency-injection/

Slide 182

Slide 182 text

Thanks [email protected] Let’s talk build speeds and productivity