Code Without DI In the following snippet, our class relies directly on FirebaseAnalytics. class ProfileViewModel() { fun onProfileLoaded() { Firebase.analytics.logEvent("viewed_profile") } } @AdamMc331 #DCSF22 5
Try Tes'ng It class ProfileViewModelTest { @Test fun verifyEventTracked() { val viewModel = ProfileViewModel() viewModel.onProfileLoaded() // No Ability To Verify Event Tracked } } @AdamMc331 #DCSF22 7
Updated Test class ProfileViewModelTest { @Test fun verifyEventTracked() { val mockAnalytics = FakeFirebaseAnalytics() val viewModel = ProfileViewModel(mockAnalytics) viewModel.onProfileLoaded() mockAnalytics.verifyEventLogged("viewed_profile") } } @AdamMc331 #DCSF22 12
Wait, Should We Mock Firebase? • We might change vendors in the future • Is it Firebase we're tes9ng, or just that some event was tracked? @AdamMc331 #DCSF22 13
With Our Own Implementa1on class FirebaseAnalyticsTracker : AnalyticsTracker { override fun trackEvent(eventName: String) { Firebase.analytics.logEvent(eventName) } } @AdamMc331 #DCSF22 15
Analy&cs Are Everywhere • Let's create one AnalyticsTracker to use in each screen • Let's ensure that we can swap out that tracker once and have each screen updated @AdamMc331 #DCSF22 21
Fetch Dependencies From Screens class ProfileActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val appDependencies = (this.application as MyApp).appDependencies val analyticsTracker = appDependencies.analyticsTracker val profileViewModel = ProfileViewModel(analyticsTracker) } } @AdamMc331 #DCSF22 24
They All Follow The Same Recipe • Create a collec+on of dependencies • Configure your Applica+on class as the container for those dependencies @AdamMc331 #DCSF22 27
They All Follow The Same Recipe • Create a collec+on of dependencies • Configure your Applica+on class as the container for those dependencies • Request dependencies as needed @AdamMc331 #DCSF22 27
Dependency Management Enables Several Benefits • Unit test support • Ability to change dependencies • Dependencies can be shared • One centralized configura:on of all dependencies @AdamMc331 #DCSF22 37
Applica'on Scoped Some dependencies should be maintained as a single instance for our en5re applica5on lifecycle. This can be true for database connec5ons, error reporters, analy5cs trackers, and similar far reaching func5onality. @AdamMc331 #DCSF22 40
Component Scoped Some dependencies should only be maintained as long as the components using them require it. For example, a presenter only needs to stay in memory if the screen using it is visible or in the backstack, or a cache layer only for a specific screen. @AdamMc331 #DCSF22 41
Library Differences How we manage scoping is different depending on the DI framework we choose, but in advanced situa;ons we should be aware of memory management and ensuring we either share or create new dependencies as necessary. @AdamMc331 #DCSF22 42
Manual Approach • Pro: No "magic" • Pro: Ability to use "find usages" • Pro: Easy to refactor with IDE tooling • Con: A lot of code to write and maintain ourselves @AdamMc331 #DCSF22 44
Manual Approach • Pro: No "magic" • Pro: Ability to use "find usages" • Pro: Easy to refactor with IDE tooling • Con: A lot of code to write and maintain ourselves • Con: ReinvenBng the wheel @AdamMc331 #DCSF22 44
DI Library • Pro: Reduced boilerplate code • Pro: Quick to get started • Pro: More complex situa9ons like scoping are solved for us @AdamMc331 #DCSF22 45
DI Library • Pro: Reduced boilerplate code • Pro: Quick to get started • Pro: More complex situa9ons like scoping are solved for us • Con: Can feel like "magic" @AdamMc331 #DCSF22 45
DI Library • Pro: Reduced boilerplate code • Pro: Quick to get started • Pro: More complex situa9ons like scoping are solved for us • Con: Can feel like "magic" • Con: Harder to trace usages of dependencies @AdamMc331 #DCSF22 45
DI Library • Pro: Reduced boilerplate code • Pro: Quick to get started • Pro: More complex situa9ons like scoping are solved for us • Con: Can feel like "magic" • Con: Harder to trace usages of dependencies • Con: Requires knowledge of DI as a concept and the tool used @AdamMc331 #DCSF22 45
Library Considera.ons • Some DI libraries can verify and manage dependencies at compile 8me • This can lead to increased build 8mes as complexity grows @AdamMc331 #DCSF22 46
Library Considera.ons • Some DI libraries can verify and manage dependencies at compile 8me • This can lead to increased build 8mes as complexity grows • Some DI libraries use a service locator concept to fetch dependencies at run8me @AdamMc331 #DCSF22 46
Library Considera.ons • Some DI libraries can verify and manage dependencies at compile 8me • This can lead to increased build 8mes as complexity grows • Some DI libraries use a service locator concept to fetch dependencies at run8me • This keeps builds consistent, but can lead to unexpected errors at run8me if our dependency graph is broken @AdamMc331 #DCSF22 46
Trust Yourself Whether you choose a manual DI approach or one of the libraries out there will be up to you and your team. Chose what you are comfortable with, or what you think provides the most benefit to the size and complexity of your project. @AdamMc331 #DCSF22 47
Remember The Fundamentals • The fundamental concepts of dependency injec5on provide support for be9er tes5ng, increasing our confidence in our products. @AdamMc331 #DCSF22 48
Remember The Fundamentals • The fundamental concepts of dependency injec5on provide support for be9er tes5ng, increasing our confidence in our products. • They also provide flexibility, and enable us to make broad changes to our product quickly. @AdamMc331 #DCSF22 48
Remember The Fundamentals • The fundamental concepts of dependency injec5on provide support for be9er tes5ng, increasing our confidence in our products. • They also provide flexibility, and enable us to make broad changes to our product quickly. • Having a dependency management system is a huge step in ensuring las5ng success of our applica5ons that can withstand the test of 5me. @AdamMc331 #DCSF22 48