SlideShare une entreprise Scribd logo
1  sur  151
Télécharger pour lire hors ligne
http://bit.ly/timewarning
http://bit.ly/speedwarning
–Me, ~2 years ago
“My future team will ❤ me for all this Dagger work
I’m doing!”
–The team, ~2 months ago
“We hate Dagger and we hate you.”
Don’t use Dagger 2
Don’t use Dagger 2
👍
Dagger 2, 2 Years
Later
Dagger 2, 2 Years
Later
––Erik Dietrich, “How Developers Stop Learning: Rise of the Expert
Beginner”
“…in software, feedback cycles tend to be on the
order of months, if not years…It’s during the full
lifetime of a project that a developer gains
experience writing code…modifying it, testing it,
and living with previous design and architecture
decisions during maintenance phases. With
everything I’ve just described, a developer is lucky
to have a first try of less than six months…”
––Erik Dietrich, “How Developers Stop Learning: Rise of the Expert
Beginner”
“…in software, feedback cycles tend to be on the
order of months, if not years…It’s during the full
lifetime of a project that a developer gains
experience writing code…modifying it, testing it,
and living with previous design and architecture
decisions during maintenance phases. With
everything I’ve just described, a developer is lucky
to have a first try of less than six months…”
–Jake Wharton, “The Future of Dependency Injection with Dagger 2”
“The entire public API of Dagger 2 is right here [on
this single slide]…so the only hard part about using
Dagger 2 is really understanding the fundamentals
of dependency injection and the concept of each
one of these individual things: how you provide
dependencies, how you request dependencies, and
then the component interface of how you link the
two together.”
–Donn Felker
“When Dagger 1 came out it was just simpler and
then Dagger 2 [came out and] I felt like it got really
complicated”
–Donn Felker
“When Dagger 1 came out it was just simpler and
then Dagger 2 [came out and] I felt like it got really
complicated”
“I think there’s a shared understanding that there’s
something wrong [with Dagger 2]. Something’s not
working.”
–Kaushik Goupal
“Episode 133,” Fragmented
“Something’s not working”
Why?
–John Dewey
“A problem well put is half solved”
(philosopher 🙌)
class ScheduleFragment : MainNavigationFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
!// Set up search menu item
binding.includeScheduleAppbar.toolbar.run {
setOnMenuItemClickListener { item ->
if (item.itemId !== R.id.search) {
analyticsHelper.logUiEvent("Navigate to Search", AnalyticsActions.CLICK)
} else {
//…
}
}
}
analyticsHelper.sendScreenView("Schedule", requireActivity())
}
}
class ScheduleFragment : MainNavigationFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
!// Set up search menu item
binding.includeScheduleAppbar.toolbar.run {
setOnMenuItemClickListener { item ->
if (item.itemId !== R.id.search) {
analyticsHelper.logUiEvent("Navigate to Search", AnalyticsActions.CLICK)
} else {
//…
}
}
}
analyticsHelper.sendScreenView("Schedule", requireActivity())
}
}
class ScheduleFragment : MainNavigationFragment() {
@Inject lateinit var analyticsHelper: AnalyticsHelper
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
!// Set up search menu item
binding.includeScheduleAppbar.toolbar.run {
setOnMenuItemClickListener { item ->
if (item.itemId !== R.id.search) {
analyticsHelper.logUiEvent("Navigate to Search", AnalyticsActions.CLICK)
} else {
//…
}
}
}
analyticsHelper.sendScreenView("Schedule", requireActivity())
}
}
class AnalyticsHelper constructor(
context: Context,
signInViewModelDelegate: SignInViewModelDelegate,
preferenceStorage: PreferenceStorage
)
class AnalyticsHelper @Inject constructor(
context: Context,
signInViewModelDelegate: SignInViewModelDelegate,
preferenceStorage: PreferenceStorage
)
class ScheduleFragment : MainNavigationFragment() {
@Inject lateinit var analyticsHelper: AnalyticsHelper
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
!// Set up search menu item
binding.includeScheduleAppbar.toolbar.run {
setOnMenuItemClickListener { item ->
if (item.itemId !== R.id.search) {
analyticsHelper.logUiEvent("Navigate to Search", AnalyticsActions.CLICK)
} else {
//…
}
}
}
analyticsHelper.sendScreenView("Schedule", requireActivity())
}
}
dagger-android or
boilerplate?
AnalyticsHelper
com.other.library.AnalyticsHelper
@Provides
fun providesAnalyticsHelper(
context: Context,
signInDelegate: SignInViewModelDelegate,
preferenceStorage: PreferenceStorage
): AnalyticsHelper = …
What module does
this go in?
@Provides
fun providesAnalyticsHelper(
context: Context,
signInDelegate: SignInViewModelDelegate,
preferenceStorage: PreferenceStorage
): AnalyticsHelper = …
Binds vs. Provides?
In Kotlin?
@Binds
abstract fun providesAnalyticsHelper(
context: Context,
signInDelegate: SignInViewModelDelegate,
preferenceStorage: PreferenceStorage
): AnalyticsHelper
Scoped? Which one?
@Binds
abstract fun providesAnalyticsHelper(
context: Context,
signInDelegate: SignInViewModelDelegate,
preferenceStorage: PreferenceStorage
): AnalyticsHelper
@Singleton
@Binds
abstract fun providesAnalyticsHelper(
context: Context,
signInDelegate: SignInViewModelDelegate,
preferenceStorage: PreferenceStorage
): AnalyticsHelper
Do I need a qualifier?
@Singleton
@Binds
abstract fun providesAnalyticsHelper(
context: Context,
signInDelegate: SignInViewModelDelegate,
preferenceStorage: PreferenceStorage
): AnalyticsHelper
@Singleton
@Binds
@Named(“😢”)
abstract fun providesAnalyticsHelper(
context: Context,
signInDelegate: SignInViewModelDelegate,
preferenceStorage: PreferenceStorage
): AnalyticsHelper = …
Late-bound
dependencies?
interface AppComponent : AndroidInjector<MainApplication> {
@Component.Factory
interface Factory {
fun create(@BindsInstance application: MainApplication): AppComponent
}
}
Builder? Factory?
AssistedInject?
🔁???
• dagger-android or boilerplate?

• If I can’t just add @Inject to the constructor, what module does this go in?

• What about @Binds vs. @Provides in Kotlin?

• Does this need to be scoped? If so, which one?

• Do I need a qualifier?

• Late-bound dependencies?

• Builder, Factory, or Assisted inject?

• Are the dependencies of this dependency in the graph? If not, 🔁
It gets worse
• dagger-android or boilerplate?

• If I can’t just add @Inject to the constructor, what module does this go in?

• What about @Binds vs. @Provides in Kotlin?

• Does this need to be scoped? If so, which one?

• Do I need a qualifier?

• Late-bound dependencies?

• Builder, Factory, or Assisted inject?

• Are the dependencies of this dependency in the graph? If not, 🔁
• dagger-android or boilerplate?

• If I can’t just add @Inject to the constructor, what module does this go in?

• What about @Binds vs. @Provides in Kotlin?

• Does this need to be scoped? If so, which one?

• Do I need a qualifier?

• Late-bound dependencies?

• Builder, Factory, or Assisted inject?

• Are the dependencies of this dependency in the graph? If not, 🔁
• dagger-android or boilerplate?

• If I can’t just add @Inject to the constructor, what module does this go in?

• What about @Binds vs. @Provides in Kotlin?

• Does this need to be scoped? If so, which one?

• Do I need a qualifier?

• Late-bound dependencies?

• Builder, Factory, or Assisted inject?

• Are the dependencies of this dependency in the graph? If not, 🔁
• dagger-android or boilerplate?

• If I can’t just add @Inject to the constructor, what module does this go in?

• ☝, but don’t forget testing

• What about @Binds vs. @Provides in Kotlin?

• Does this need to be scoped? If so, which one?

• Do I need a qualifier?

• Late-bound dependencies?

• Builder, Factory, or Assisted inject?

• Are the dependencies of this dependency in the graph? If not, 🔁
–Your teammate, helpfully
“Don’t try to instantiate that until X”
public static synchronized Database getInstance(Context context,
AccountProvider accountProvider) {
sInstance = new Database();
sInstance.initialize(context, accountProvider)
return sInstance;
}
public static synchronized Database getInstance(Context context,
AccountProvider accountProvider) {
sInstance = new Database();
sInstance.initialize(context, accountProvider)
return sInstance;
}
• dagger-android or boilerplate?

• ☝, but don’t forget testing

• If I can’t just add @Inject to the constructor, what module does this go in?

• What about @Binds vs. @Provides in Kotlin?

• Does this need to be scoped? If so, which one?

• Do I need a qualifier?

• Late-bound dependencies?

• Builder, Factory, or Assisted inject?

• Are the dependencies of this dependency in the graph? If not, 🔁
• dagger-android or boilerplate?

• ☝, but don’t forget testing

• If I can’t just add @Inject to the constructor, what module does this go in?

• What about @Binds vs. @Provides in Kotlin?

• Does this need to be scoped? If so, which one?

• Do I need a qualifier?

• Late-bound dependencies?

• Builder, Factory, or Assisted inject?

• Do I need to inject Lazy<T> or Provides<T>?

• Are the dependencies of this dependency in the graph? If not, 🔁
Why?
Why?
Cost
App Size
Service
Locator
Dagger
Manual DI
Cost
App Size
Manual DI
Is DI worth the cost
here and now?
Is DI worth the cost
here and now?
–Martin Fowler, “Is TDD Dead?” Pt 5 ~35:00
“I’m actually always suspicious when I’m writing up
a pattern or a technique if I can’t talk about reasons
when you shouldn’t use and trade-offs against it. If I
can’t find arguments against it, then I’m worrying
that I’m not really analyzing things properly.”
Is DI worth the cost
here and now?
UseCase
UseCaseRepo
UseCaseRepoDataSource
UseCaseRepoDataSource…
val viewModel = ScheduleViewModel(
LoadFilteredUserSessionsUseCase(
DefaultSessionAndUserEventRepository(
FirestoreUserEventDataSource(FirebaseFirestore.getInstance()),
DefaultSessionRepository(
ConferenceDataRepository(
NetworkConferenceDataSource(
context,
NetworkUtils(context)
),
BootstrapConferenceDataSource,
AppDatabase_Impl()
)
)
)
)
)
val userEventRepository = DefaultSessionAndUserEventRepository(
FirestoreUserEventDataSource(FirebaseFirestore.getInstance()),
DefaultSessionRepository(
ConferenceDataRepository(
NetworkConferenceDataSource(
context,
NetworkUtils(context)
),
BootstrapConferenceDataSource,
AppDatabase_Impl()
)
)
)
val preferenceStorage = SharedPreferenceStorage(context)
val viewModel = ScheduleViewModel(
LoadFilteredUserSessionsUseCase(
userEventRepository
),
LoadEventFiltersUseCase(
TagRepository(
ConferenceDataRepository(
NetworkConferenceDataSource(
context,
NetworkUtils(context)
),
BootstrapConferenceDataSource,
AppDatabase_Impl()
)
)
),
SignInViewModelDelegate(),
StarEventAndNotifyUseCase(
userEventRepository,
StarReserveNotificationAlarmUpdater(
SessionAlarmManager(context)
)
),
ScheduleUiHintsShownUseCase(
preferenceStorage
),
FcmTopicSubscriber(),
SnackbarMessageManager(preferenceStorage),
GetTimeZoneUseCase(preferenceStorage),
RefreshConferenceDataUseCase(
ConferenceDataRepository(
)
)
)
…🙄
val viewModel = ScheduleViewModel()
Is DI worth the cost
here and now?
–50% of the audience
“Yes! Because SOLID.”
–50% of the audience
“Yes! Because SOLID.”
–Uncle Bob, Principles and Patterns
“…Clearly such a restriction is draconian…if you
have tried and true modules that are concrete, but
not volatile, depending upon them is not so bad.”
public MovieLister() {
finder = new ColonDelimitedMovieFinder("movies1.txt");
}
–Martin Fowler, “IoC Containers and the Dependency Injection pattern”
“Now if I'm using this class for just myself, this is all
fine and dandy.”
–Testing Fans
“But what about testing?!”
@Test
fun reservationReceived() {
!// !!...
val loadSessionsUseCase = createTestLoadUserSessionsByDayUseCase(source)
val viewModel = createScheduleViewModel(
loadFilteredSessionsUseCase = loadSessionsUseCase,
!// !!...
)
}
class ScheduleViewModel constructor(
private val sessionsUseCase: LFUserSessionsUseCase = LFUserSessionsUseCase()
!//…
) : ViewModel()
class ScheduleViewModel constructor(
private val sessionsUseCase: LFUserSessionsUseCase = LFUserSessionsUseCase()
!//…
) : ViewModel()
val viewModel = ScheduleViewModel()
Cost
App Size
Manual DI
Cost
App Size
Dagger
• dagger-android or boilerplate?

• If I can’t just add @Inject to the constructor, what module does this go in?

• ☝, but don’t forget testing

• What about @Binds vs. @Provides in Kotlin?

• Does this need to be scoped? If so, which one?

• Do I need a qualifier?

• Late-bound dependencies?

• Builder, Factory, or Assisted inject?

• Do I need to inject Lazy<T> or Provides<T>?

• Are the dependencies of this dependency in the graph? If not, 🔁
• dagger-android or boilerplate?

• If I can’t just add @Inject to the constructor, what module does this go in?

• ☝, but don’t forget testing

• What about @Binds vs. @Provides in Kotlin?

• Does this need to be scoped? If so, which one?

• Do I need a qualifier?

• Late-bound dependencies?

• Builder, Factory, or Assisted inject?

• Do I need to inject Lazy<T> or Provides<T>?

• Are the dependencies of this dependency in the graph? If not, 🔁
–My team, naively
“We’ll just add Dagger as we go”
let go
• dagger-android or boilerplate?

• If I can’t just add @Inject to the constructor, what module does this go in?

• ☝, but don’t forget testing

• What about @Binds vs. @Provides in Kotlin?

• Does this need to be scoped? If so, which one?

• Do I need a qualifier?

• Late-bound dependencies?

• Builder, Factory, or Assisted inject?

• Do I need to inject Lazy<T> or Provides<T>?

• Are the dependencies of this dependency in the graph? If not, 🔁
–Joe Armstrong
“If you’re ever in a big project and you’re trying to
find out how it works and you talk to people and
they say, ‘I don’t understand how this works but
someone else understands,’ then you can be sure
that you’re in a project that’s going to go pear-
shaped”
• dagger-android or boilerplate?

• If I can’t just add @Inject to the constructor, what module does this go in?

• ☝, but don’t forget testing

• What about @Binds vs. @Provides in Kotlin?

• Does this need to be scoped? If so, which one?

• Do I need a qualifier?

• Late-bound dependencies?

• Builder, Factory, or Assisted inject?

• Do I need to inject Lazy<T> or Provides<T>?

• Are the dependencies of this dependency in the graph? If not, 🔁
• dagger-android or boilerplate?

• If I can’t just add @Inject to the constructor, what module does this go in?

• ☝, but don’t forget testing

• What about @Binds vs. @Provides in Kotlin?

• Does this need to be scoped? If so, which one?

• Do I need a qualifier?

• Late-bound dependencies?

• Builder, Factory, or Assisted inject?

• Do I need to inject Lazy<T> or Provides<T>?

• Are the dependencies of this dependency in the graph? If not, 🔁
Dagger components
as service locators
–Martin Fowler
“I've often heard the complaint that these kinds of
service locators are a bad thing because they aren't
testable because you can't substitute
implementations for them. Certainly you can design
them badly to get into this kind of trouble, but you
don't have to.”
@Singleton
@Component(modules = BluetoothComponent.Module.class)
public interface BluetoothComponent {
BluetoothAdvertiser ble();
}
public class MainActivity {
@Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
((Application) getApplication())
.getBluetoothComponent()
.ble()
.startAdvertising();
}
• dagger-android or boilerplate?

• If I can’t just add @Inject to the constructor, what module does this go in?

• ☝, but don’t forget testing

• What about @Binds vs. @Provides in Kotlin?

• Does this need to be scoped? If so, which one?

• Do I need a qualifier?

• Late-bound dependencies?

• Builder, Factory, or Assisted inject?

• Do I need to inject Lazy<T> or Provides<T>?

• Are the dependencies of this dependency in the graph? If not, 🔁
Consider avoiding
needless Interface/Impl
Pairs
@Module
abstract class ViewModelModule {
@Binds
internal abstract fun bindViewModelFactory(factory: IOSchedViewModelFactory):
ViewModelProvider.Factory
}
–Martin Fowler, “InterfaceImplementationPair”
“This isn’t…a technique that I've ever much liked.
Using interfaces when you aren't going to have
multiple implementations is extra effort to keep
everything in sync (although good IDEs help).
Furthermore it hides the cases where you actually
do provide multiple implementations.”
Consider avoiding
needless Interface/Impl
Pairs
Consider avoiding
needless Interface/Impl
Pairs
(or just depend on the implementation)
• dagger-android or boilerplate?

• If I can’t just add @Inject to the constructor, what module does this go in?

• ☝, but don’t forget testing

• What about @Binds vs. @Provides in Kotlin?

• Does this need to be scoped? If so, which one?

• Do I need a qualifier?

• Late-bound dependencies?

• Builder, Factory, or Assisted inject?

• Do I need to inject Lazy<T> or Provides<T>?

• Are the dependencies of this dependency in the graph? If not, 🔁
@Singleton
@Component(modules = [FakeNetworkModule!::class])
interface TestApplicationComponent : ApplicationComponent {
}
@Module
class FakeNetworkModule {
@Provides
fun provideLoginRetrofitService(): LoginRetrofitService {
return FakeLoginService()
}
}
@Singleton
@Component(modules = [FakeNetworkModule!::class])
interface TestApplicationComponent : ApplicationComponent {
}
Consider late-bound
dependencies instead of
“published” modules
@Component
interface ApplicationComponent {
@Component.Factory
interface Factory {
fun make(@BindsInstance loginService: LoginService): ApplicationComponent
}
}
@Component
interface ApplicationComponent {
@Component.Factory
interface Factory {
fun make(@BindsInstance loginService: LoginService): ApplicationComponent
}
}
!// Application code
ApplicationComponent.factory().make(loginService)
@Component
interface ApplicationComponent {
@Component.Factory
interface Factory {
fun make(@BindsInstance loginService: LoginService): ApplicationComponent
}
}
!// Application code
ApplicationComponent.factory().make(loginService)
!// Test code
ApplicationComponent.factory().make(fakeLoginService)
Consider component
dependencies instead of
“published” modules
@Component(dependencies = [NetworkComponent!::class])
interface ApplicationComponent {}
@Component
interface NetworkComponent {
fun loginService(): LoginService
}
!// Application Code
val networkComponent = DaggerNetworkComponent.factory()
.create(this)
applicationComponent = DaggerApplicationComponent.factory()
.create(
this,
networkComponent
)
!// Test Code
postListRepository = mock(PostListRepository!::class.java)
testApp.initializeApplicationComponent(object : NetworkComponent {
override fun repo(): PostListRepository = postListRepository
})
!// Test Code
postListRepository = mock(PostListRepository!::class.java)
testApp.initializeApplicationComponent(object : NetworkComponent {
override fun repo(): PostListRepository = postListRepository
})
Cost
App Size
Dagger
Dagger 2, 2 Years
Later
@philosohacker
(looking for a new challenge)
“Bonus Features”
The OG Reason for DI
“A common issue to deal with is how to wire
together different elements: how do you fit together
this web controller architecture with that database
interface backing when they were built by different
teams with little knowledge of each other…”
–Martin Fowler, “IoC Containers and the Dependency Injection pattern”
“A common issue to deal with is how to wire
together different elements: how do you fit together
this web controller architecture with that database
interface backing when they were built by different
teams with little knowledge of each other…”
–Martin Fowler, “IoC Containers and the Dependency Injection pattern”
–Kent Beck, “Is TDD Dead?” Pt. 1 ~21:05
“My personal practice is I mock almost nothing. If I
can’t figure out how to test efficiently with the real
stuff, I find another way of creating a feedback
loop…”
• dagger-android or boilerplate?

• If I can’t just add @Inject to the constructor, what module does this go in?

• ☝, but don’t forget testing

• What about @Binds vs. @Provides in Kotlin?

• Does this need to be scoped? If so, which one?

• Do I need a qualifier?

• Late-bound dependencies?

• Builder, Factory, or Assisted inject?

• Do I need to inject Lazy<T> or Provides<T>?

• Are the dependencies of this dependency in the graph? If not, 🔁
• dagger-android or boilerplate?

• If I can’t just add @Inject to the constructor, what module does this go in?

• ☝, but don’t forget testing

• What about @Binds vs. @Provides in Kotlin?

• Does this need to be scoped? If so, which one?

• Do I need a qualifier?

• Late-bound dependencies?

• Builder, Factory, or Assisted inject?

• Do I need to inject Lazy<T> or Provides<T>?

• Are the dependencies of this dependency in the graph? If not, 🔁
Have a strong opinion
on module location
–You, frustrated
“Why does this depend on a Context?”
Consider avoiding
needless Interface/Impl
Pairs
Don’t add a new provides
method for every “new”
Dagger 2, 2 years later

Contenu connexe

Tendances

Tendances (6)

Dagger 2
Dagger 2Dagger 2
Dagger 2
 
基於 Flow & Path 的 MVP 架構
基於 Flow & Path 的 MVP 架構基於 Flow & Path 的 MVP 架構
基於 Flow & Path 的 MVP 架構
 
"The Battle of the IDEs"
"The Battle of the IDEs""The Battle of the IDEs"
"The Battle of the IDEs"
 
Using Dagger in a Clean Architecture project
Using Dagger in a Clean Architecture projectUsing Dagger in a Clean Architecture project
Using Dagger in a Clean Architecture project
 
GWT Reloaded
GWT ReloadedGWT Reloaded
GWT Reloaded
 
Dark side of Android apps modularization
Dark side of Android apps modularizationDark side of Android apps modularization
Dark side of Android apps modularization
 

Similaire à Dagger 2, 2 years later

The State of Front-end At CrowdTwist
The State of Front-end At CrowdTwistThe State of Front-end At CrowdTwist
The State of Front-end At CrowdTwist
Mark Fayngersh
 
Java onguice20070426
Java onguice20070426Java onguice20070426
Java onguice20070426
Ratul Ray
 

Similaire à Dagger 2, 2 years later (20)

The State of Front-end At CrowdTwist
The State of Front-end At CrowdTwistThe State of Front-end At CrowdTwist
The State of Front-end At CrowdTwist
 
True Git
True Git True Git
True Git
 
Achieving Technical Excellence in Your Software Teams - from Devternity
Achieving Technical Excellence in Your Software Teams - from Devternity Achieving Technical Excellence in Your Software Teams - from Devternity
Achieving Technical Excellence in Your Software Teams - from Devternity
 
Алексей Ященко и Ярослав Волощук "False simplicity of front-end applications"
Алексей Ященко и Ярослав Волощук "False simplicity of front-end applications"Алексей Ященко и Ярослав Волощук "False simplicity of front-end applications"
Алексей Ященко и Ярослав Волощук "False simplicity of front-end applications"
 
Git Makes Me Angry Inside
Git Makes Me Angry InsideGit Makes Me Angry Inside
Git Makes Me Angry Inside
 
DevSecCon Singapore 2018 - Remove developers’ shameful secrets or simply rem...
DevSecCon Singapore 2018 -  Remove developers’ shameful secrets or simply rem...DevSecCon Singapore 2018 -  Remove developers’ shameful secrets or simply rem...
DevSecCon Singapore 2018 - Remove developers’ shameful secrets or simply rem...
 
TDD - Seriously, try it! (updated '22)
TDD - Seriously, try it! (updated '22)TDD - Seriously, try it! (updated '22)
TDD - Seriously, try it! (updated '22)
 
Advanced Dagger talk from 360andev
Advanced Dagger talk from 360andevAdvanced Dagger talk from 360andev
Advanced Dagger talk from 360andev
 
Que nos espera a los ALM Dudes para el 2013?
Que nos espera a los ALM Dudes para el 2013?Que nos espera a los ALM Dudes para el 2013?
Que nos espera a los ALM Dudes para el 2013?
 
DevSecCon SG 2018 Fabian Presentation Slides
DevSecCon SG 2018 Fabian Presentation SlidesDevSecCon SG 2018 Fabian Presentation Slides
DevSecCon SG 2018 Fabian Presentation Slides
 
TDD - Seriously, try it! - Bucarest Tech Week
TDD - Seriously, try it! - Bucarest Tech WeekTDD - Seriously, try it! - Bucarest Tech Week
TDD - Seriously, try it! - Bucarest Tech Week
 
Java onguice20070426
Java onguice20070426Java onguice20070426
Java onguice20070426
 
Keeping your build tool updated in a multi repository world
Keeping your build tool updated in a multi repository worldKeeping your build tool updated in a multi repository world
Keeping your build tool updated in a multi repository world
 
“One man” development process model
“One man” development process model“One man” development process model
“One man” development process model
 
Release management with NuGet/Chocolatey/JIRA
Release management with NuGet/Chocolatey/JIRARelease management with NuGet/Chocolatey/JIRA
Release management with NuGet/Chocolatey/JIRA
 
Engage 2018 adm04 - The lazy admin wins
Engage 2018   adm04 - The lazy admin winsEngage 2018   adm04 - The lazy admin wins
Engage 2018 adm04 - The lazy admin wins
 
Engage 2018 adm04 The lazy admin wins
Engage 2018   adm04 The lazy admin winsEngage 2018   adm04 The lazy admin wins
Engage 2018 adm04 The lazy admin wins
 
Continuous delivery is more than dev ops
Continuous delivery is more than dev opsContinuous delivery is more than dev ops
Continuous delivery is more than dev ops
 
Developing for LinkedIn's Application Platform
Developing for LinkedIn's Application PlatformDeveloping for LinkedIn's Application Platform
Developing for LinkedIn's Application Platform
 
BDD in open source projects - Is it really beneficial?
BDD in open source projects - Is it really beneficial?BDD in open source projects - Is it really beneficial?
BDD in open source projects - Is it really beneficial?
 

Plus de K. Matthew Dupree

Plus de K. Matthew Dupree (8)

intro-to-metaprogramming-in-r.pdf
intro-to-metaprogramming-in-r.pdfintro-to-metaprogramming-in-r.pdf
intro-to-metaprogramming-in-r.pdf
 
Intro To Gradient Descent in Javascript
Intro To Gradient Descent in JavascriptIntro To Gradient Descent in Javascript
Intro To Gradient Descent in Javascript
 
An Introduction to RxJava
An Introduction to RxJavaAn Introduction to RxJava
An Introduction to RxJava
 
If Android Tests Could Talk
If Android Tests Could TalkIf Android Tests Could Talk
If Android Tests Could Talk
 
Writing testable android apps
Writing testable android appsWriting testable android apps
Writing testable android apps
 
Di and Dagger
Di and DaggerDi and Dagger
Di and Dagger
 
Functional Testing for React Native Apps
Functional Testing for React Native AppsFunctional Testing for React Native Apps
Functional Testing for React Native Apps
 
Testable android apps
Testable android appsTestable android apps
Testable android apps
 

Dernier

CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
9953056974 Low Rate Call Girls In Saket, Delhi NCR
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
VictorSzoltysek
 
The title is not connected to what is inside
The title is not connected to what is insideThe title is not connected to what is inside
The title is not connected to what is inside
shinachiaurasa2
 

Dernier (20)

Chinsurah Escorts ☎️8617697112 Starting From 5K to 15K High Profile Escorts ...
Chinsurah Escorts ☎️8617697112  Starting From 5K to 15K High Profile Escorts ...Chinsurah Escorts ☎️8617697112  Starting From 5K to 15K High Profile Escorts ...
Chinsurah Escorts ☎️8617697112 Starting From 5K to 15K High Profile Escorts ...
 
Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdf
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docx
 
LEVEL 5 - SESSION 1 2023 (1).pptx - PDF 123456
LEVEL 5   - SESSION 1 2023 (1).pptx - PDF 123456LEVEL 5   - SESSION 1 2023 (1).pptx - PDF 123456
LEVEL 5 - SESSION 1 2023 (1).pptx - PDF 123456
 
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfPayment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 
Exploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfExploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdf
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
 
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park %in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionIntroducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
 
Pharm-D Biostatistics and Research methodology
Pharm-D Biostatistics and Research methodologyPharm-D Biostatistics and Research methodology
Pharm-D Biostatistics and Research methodology
 
The title is not connected to what is inside
The title is not connected to what is insideThe title is not connected to what is inside
The title is not connected to what is inside
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 

Dagger 2, 2 years later

  • 1.
  • 2.
  • 4.
  • 5. –Me, ~2 years ago “My future team will ❤ me for all this Dagger work I’m doing!”
  • 6. –The team, ~2 months ago “We hate Dagger and we hate you.”
  • 10. Dagger 2, 2 Years Later
  • 11. Dagger 2, 2 Years Later
  • 12. ––Erik Dietrich, “How Developers Stop Learning: Rise of the Expert Beginner” “…in software, feedback cycles tend to be on the order of months, if not years…It’s during the full lifetime of a project that a developer gains experience writing code…modifying it, testing it, and living with previous design and architecture decisions during maintenance phases. With everything I’ve just described, a developer is lucky to have a first try of less than six months…”
  • 13. ––Erik Dietrich, “How Developers Stop Learning: Rise of the Expert Beginner” “…in software, feedback cycles tend to be on the order of months, if not years…It’s during the full lifetime of a project that a developer gains experience writing code…modifying it, testing it, and living with previous design and architecture decisions during maintenance phases. With everything I’ve just described, a developer is lucky to have a first try of less than six months…”
  • 14.
  • 15.
  • 16.
  • 17. –Jake Wharton, “The Future of Dependency Injection with Dagger 2” “The entire public API of Dagger 2 is right here [on this single slide]…so the only hard part about using Dagger 2 is really understanding the fundamentals of dependency injection and the concept of each one of these individual things: how you provide dependencies, how you request dependencies, and then the component interface of how you link the two together.”
  • 18. –Donn Felker “When Dagger 1 came out it was just simpler and then Dagger 2 [came out and] I felt like it got really complicated”
  • 19. –Donn Felker “When Dagger 1 came out it was just simpler and then Dagger 2 [came out and] I felt like it got really complicated” “I think there’s a shared understanding that there’s something wrong [with Dagger 2]. Something’s not working.” –Kaushik Goupal “Episode 133,” Fragmented
  • 21. Why?
  • 22. –John Dewey “A problem well put is half solved” (philosopher 🙌)
  • 23.
  • 24.
  • 25.
  • 26. class ScheduleFragment : MainNavigationFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { !// Set up search menu item binding.includeScheduleAppbar.toolbar.run { setOnMenuItemClickListener { item -> if (item.itemId !== R.id.search) { analyticsHelper.logUiEvent("Navigate to Search", AnalyticsActions.CLICK) } else { //… } } } analyticsHelper.sendScreenView("Schedule", requireActivity()) } }
  • 27. class ScheduleFragment : MainNavigationFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { !// Set up search menu item binding.includeScheduleAppbar.toolbar.run { setOnMenuItemClickListener { item -> if (item.itemId !== R.id.search) { analyticsHelper.logUiEvent("Navigate to Search", AnalyticsActions.CLICK) } else { //… } } } analyticsHelper.sendScreenView("Schedule", requireActivity()) } }
  • 28. class ScheduleFragment : MainNavigationFragment() { @Inject lateinit var analyticsHelper: AnalyticsHelper override fun onViewCreated(view: View, savedInstanceState: Bundle?) { !// Set up search menu item binding.includeScheduleAppbar.toolbar.run { setOnMenuItemClickListener { item -> if (item.itemId !== R.id.search) { analyticsHelper.logUiEvent("Navigate to Search", AnalyticsActions.CLICK) } else { //… } } } analyticsHelper.sendScreenView("Schedule", requireActivity()) } }
  • 29. class AnalyticsHelper constructor( context: Context, signInViewModelDelegate: SignInViewModelDelegate, preferenceStorage: PreferenceStorage )
  • 30. class AnalyticsHelper @Inject constructor( context: Context, signInViewModelDelegate: SignInViewModelDelegate, preferenceStorage: PreferenceStorage )
  • 31. class ScheduleFragment : MainNavigationFragment() { @Inject lateinit var analyticsHelper: AnalyticsHelper override fun onViewCreated(view: View, savedInstanceState: Bundle?) { !// Set up search menu item binding.includeScheduleAppbar.toolbar.run { setOnMenuItemClickListener { item -> if (item.itemId !== R.id.search) { analyticsHelper.logUiEvent("Navigate to Search", AnalyticsActions.CLICK) } else { //… } } } analyticsHelper.sendScreenView("Schedule", requireActivity()) } }
  • 33.
  • 36. @Provides fun providesAnalyticsHelper( context: Context, signInDelegate: SignInViewModelDelegate, preferenceStorage: PreferenceStorage ): AnalyticsHelper = …
  • 38. @Provides fun providesAnalyticsHelper( context: Context, signInDelegate: SignInViewModelDelegate, preferenceStorage: PreferenceStorage ): AnalyticsHelper = …
  • 40. @Binds abstract fun providesAnalyticsHelper( context: Context, signInDelegate: SignInViewModelDelegate, preferenceStorage: PreferenceStorage ): AnalyticsHelper
  • 42. @Binds abstract fun providesAnalyticsHelper( context: Context, signInDelegate: SignInViewModelDelegate, preferenceStorage: PreferenceStorage ): AnalyticsHelper
  • 43. @Singleton @Binds abstract fun providesAnalyticsHelper( context: Context, signInDelegate: SignInViewModelDelegate, preferenceStorage: PreferenceStorage ): AnalyticsHelper
  • 44. Do I need a qualifier?
  • 45. @Singleton @Binds abstract fun providesAnalyticsHelper( context: Context, signInDelegate: SignInViewModelDelegate, preferenceStorage: PreferenceStorage ): AnalyticsHelper
  • 46. @Singleton @Binds @Named(“😢”) abstract fun providesAnalyticsHelper( context: Context, signInDelegate: SignInViewModelDelegate, preferenceStorage: PreferenceStorage ): AnalyticsHelper = …
  • 48. interface AppComponent : AndroidInjector<MainApplication> { @Component.Factory interface Factory { fun create(@BindsInstance application: MainApplication): AppComponent } }
  • 51. • dagger-android or boilerplate? • If I can’t just add @Inject to the constructor, what module does this go in? • What about @Binds vs. @Provides in Kotlin? • Does this need to be scoped? If so, which one? • Do I need a qualifier? • Late-bound dependencies? • Builder, Factory, or Assisted inject? • Are the dependencies of this dependency in the graph? If not, 🔁
  • 53. • dagger-android or boilerplate? • If I can’t just add @Inject to the constructor, what module does this go in? • What about @Binds vs. @Provides in Kotlin? • Does this need to be scoped? If so, which one? • Do I need a qualifier? • Late-bound dependencies? • Builder, Factory, or Assisted inject? • Are the dependencies of this dependency in the graph? If not, 🔁
  • 54. • dagger-android or boilerplate? • If I can’t just add @Inject to the constructor, what module does this go in? • What about @Binds vs. @Provides in Kotlin? • Does this need to be scoped? If so, which one? • Do I need a qualifier? • Late-bound dependencies? • Builder, Factory, or Assisted inject? • Are the dependencies of this dependency in the graph? If not, 🔁
  • 55.
  • 56. • dagger-android or boilerplate? • If I can’t just add @Inject to the constructor, what module does this go in? • What about @Binds vs. @Provides in Kotlin? • Does this need to be scoped? If so, which one? • Do I need a qualifier? • Late-bound dependencies? • Builder, Factory, or Assisted inject? • Are the dependencies of this dependency in the graph? If not, 🔁
  • 57. • dagger-android or boilerplate? • If I can’t just add @Inject to the constructor, what module does this go in? • ☝, but don’t forget testing • What about @Binds vs. @Provides in Kotlin? • Does this need to be scoped? If so, which one? • Do I need a qualifier? • Late-bound dependencies? • Builder, Factory, or Assisted inject? • Are the dependencies of this dependency in the graph? If not, 🔁
  • 58. –Your teammate, helpfully “Don’t try to instantiate that until X”
  • 59. public static synchronized Database getInstance(Context context, AccountProvider accountProvider) { sInstance = new Database(); sInstance.initialize(context, accountProvider) return sInstance; }
  • 60. public static synchronized Database getInstance(Context context, AccountProvider accountProvider) { sInstance = new Database(); sInstance.initialize(context, accountProvider) return sInstance; }
  • 61. • dagger-android or boilerplate? • ☝, but don’t forget testing • If I can’t just add @Inject to the constructor, what module does this go in? • What about @Binds vs. @Provides in Kotlin? • Does this need to be scoped? If so, which one? • Do I need a qualifier? • Late-bound dependencies? • Builder, Factory, or Assisted inject? • Are the dependencies of this dependency in the graph? If not, 🔁
  • 62. • dagger-android or boilerplate? • ☝, but don’t forget testing • If I can’t just add @Inject to the constructor, what module does this go in? • What about @Binds vs. @Provides in Kotlin? • Does this need to be scoped? If so, which one? • Do I need a qualifier? • Late-bound dependencies? • Builder, Factory, or Assisted inject? • Do I need to inject Lazy<T> or Provides<T>? • Are the dependencies of this dependency in the graph? If not, 🔁
  • 63. Why?
  • 64. Why?
  • 65.
  • 68.
  • 69.
  • 70. Is DI worth the cost here and now?
  • 71. Is DI worth the cost here and now?
  • 72. –Martin Fowler, “Is TDD Dead?” Pt 5 ~35:00 “I’m actually always suspicious when I’m writing up a pattern or a technique if I can’t talk about reasons when you shouldn’t use and trade-offs against it. If I can’t find arguments against it, then I’m worrying that I’m not really analyzing things properly.”
  • 73. Is DI worth the cost here and now?
  • 74.
  • 79. val viewModel = ScheduleViewModel( LoadFilteredUserSessionsUseCase( DefaultSessionAndUserEventRepository( FirestoreUserEventDataSource(FirebaseFirestore.getInstance()), DefaultSessionRepository( ConferenceDataRepository( NetworkConferenceDataSource( context, NetworkUtils(context) ), BootstrapConferenceDataSource, AppDatabase_Impl() ) ) ) ) )
  • 80. val userEventRepository = DefaultSessionAndUserEventRepository( FirestoreUserEventDataSource(FirebaseFirestore.getInstance()), DefaultSessionRepository( ConferenceDataRepository( NetworkConferenceDataSource( context, NetworkUtils(context) ), BootstrapConferenceDataSource, AppDatabase_Impl() ) ) ) val preferenceStorage = SharedPreferenceStorage(context) val viewModel = ScheduleViewModel( LoadFilteredUserSessionsUseCase( userEventRepository ), LoadEventFiltersUseCase( TagRepository( ConferenceDataRepository( NetworkConferenceDataSource( context, NetworkUtils(context) ), BootstrapConferenceDataSource, AppDatabase_Impl() ) ) ), SignInViewModelDelegate(), StarEventAndNotifyUseCase( userEventRepository, StarReserveNotificationAlarmUpdater( SessionAlarmManager(context) ) ), ScheduleUiHintsShownUseCase( preferenceStorage ), FcmTopicSubscriber(), SnackbarMessageManager(preferenceStorage), GetTimeZoneUseCase(preferenceStorage), RefreshConferenceDataUseCase( ConferenceDataRepository( ) ) )
  • 82. val viewModel = ScheduleViewModel()
  • 83. Is DI worth the cost here and now?
  • 84. –50% of the audience “Yes! Because SOLID.”
  • 85. –50% of the audience “Yes! Because SOLID.”
  • 86. –Uncle Bob, Principles and Patterns “…Clearly such a restriction is draconian…if you have tried and true modules that are concrete, but not volatile, depending upon them is not so bad.”
  • 87.
  • 88.
  • 89. public MovieLister() { finder = new ColonDelimitedMovieFinder("movies1.txt"); }
  • 90. –Martin Fowler, “IoC Containers and the Dependency Injection pattern” “Now if I'm using this class for just myself, this is all fine and dandy.”
  • 91. –Testing Fans “But what about testing?!”
  • 92.
  • 93. @Test fun reservationReceived() { !// !!... val loadSessionsUseCase = createTestLoadUserSessionsByDayUseCase(source) val viewModel = createScheduleViewModel( loadFilteredSessionsUseCase = loadSessionsUseCase, !// !!... ) }
  • 94. class ScheduleViewModel constructor( private val sessionsUseCase: LFUserSessionsUseCase = LFUserSessionsUseCase() !//… ) : ViewModel()
  • 95. class ScheduleViewModel constructor( private val sessionsUseCase: LFUserSessionsUseCase = LFUserSessionsUseCase() !//… ) : ViewModel()
  • 96. val viewModel = ScheduleViewModel()
  • 99. • dagger-android or boilerplate? • If I can’t just add @Inject to the constructor, what module does this go in? • ☝, but don’t forget testing • What about @Binds vs. @Provides in Kotlin? • Does this need to be scoped? If so, which one? • Do I need a qualifier? • Late-bound dependencies? • Builder, Factory, or Assisted inject? • Do I need to inject Lazy<T> or Provides<T>? • Are the dependencies of this dependency in the graph? If not, 🔁
  • 100. • dagger-android or boilerplate? • If I can’t just add @Inject to the constructor, what module does this go in? • ☝, but don’t forget testing • What about @Binds vs. @Provides in Kotlin? • Does this need to be scoped? If so, which one? • Do I need a qualifier? • Late-bound dependencies? • Builder, Factory, or Assisted inject? • Do I need to inject Lazy<T> or Provides<T>? • Are the dependencies of this dependency in the graph? If not, 🔁
  • 101. –My team, naively “We’ll just add Dagger as we go”
  • 102.
  • 103. let go
  • 104. • dagger-android or boilerplate? • If I can’t just add @Inject to the constructor, what module does this go in? • ☝, but don’t forget testing • What about @Binds vs. @Provides in Kotlin? • Does this need to be scoped? If so, which one? • Do I need a qualifier? • Late-bound dependencies? • Builder, Factory, or Assisted inject? • Do I need to inject Lazy<T> or Provides<T>? • Are the dependencies of this dependency in the graph? If not, 🔁
  • 105. –Joe Armstrong “If you’re ever in a big project and you’re trying to find out how it works and you talk to people and they say, ‘I don’t understand how this works but someone else understands,’ then you can be sure that you’re in a project that’s going to go pear- shaped”
  • 106.
  • 107. • dagger-android or boilerplate? • If I can’t just add @Inject to the constructor, what module does this go in? • ☝, but don’t forget testing • What about @Binds vs. @Provides in Kotlin? • Does this need to be scoped? If so, which one? • Do I need a qualifier? • Late-bound dependencies? • Builder, Factory, or Assisted inject? • Do I need to inject Lazy<T> or Provides<T>? • Are the dependencies of this dependency in the graph? If not, 🔁
  • 108. • dagger-android or boilerplate? • If I can’t just add @Inject to the constructor, what module does this go in? • ☝, but don’t forget testing • What about @Binds vs. @Provides in Kotlin? • Does this need to be scoped? If so, which one? • Do I need a qualifier? • Late-bound dependencies? • Builder, Factory, or Assisted inject? • Do I need to inject Lazy<T> or Provides<T>? • Are the dependencies of this dependency in the graph? If not, 🔁
  • 109.
  • 111.
  • 112.
  • 113. –Martin Fowler “I've often heard the complaint that these kinds of service locators are a bad thing because they aren't testable because you can't substitute implementations for them. Certainly you can design them badly to get into this kind of trouble, but you don't have to.”
  • 114. @Singleton @Component(modules = BluetoothComponent.Module.class) public interface BluetoothComponent { BluetoothAdvertiser ble(); }
  • 115. public class MainActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ((Application) getApplication()) .getBluetoothComponent() .ble() .startAdvertising(); }
  • 116. • dagger-android or boilerplate? • If I can’t just add @Inject to the constructor, what module does this go in? • ☝, but don’t forget testing • What about @Binds vs. @Provides in Kotlin? • Does this need to be scoped? If so, which one? • Do I need a qualifier? • Late-bound dependencies? • Builder, Factory, or Assisted inject? • Do I need to inject Lazy<T> or Provides<T>? • Are the dependencies of this dependency in the graph? If not, 🔁
  • 118. @Module abstract class ViewModelModule { @Binds internal abstract fun bindViewModelFactory(factory: IOSchedViewModelFactory): ViewModelProvider.Factory }
  • 119.
  • 120. –Martin Fowler, “InterfaceImplementationPair” “This isn’t…a technique that I've ever much liked. Using interfaces when you aren't going to have multiple implementations is extra effort to keep everything in sync (although good IDEs help). Furthermore it hides the cases where you actually do provide multiple implementations.”
  • 122. Consider avoiding needless Interface/Impl Pairs (or just depend on the implementation)
  • 123. • dagger-android or boilerplate? • If I can’t just add @Inject to the constructor, what module does this go in? • ☝, but don’t forget testing • What about @Binds vs. @Provides in Kotlin? • Does this need to be scoped? If so, which one? • Do I need a qualifier? • Late-bound dependencies? • Builder, Factory, or Assisted inject? • Do I need to inject Lazy<T> or Provides<T>? • Are the dependencies of this dependency in the graph? If not, 🔁
  • 124.
  • 125. @Singleton @Component(modules = [FakeNetworkModule!::class]) interface TestApplicationComponent : ApplicationComponent { }
  • 126. @Module class FakeNetworkModule { @Provides fun provideLoginRetrofitService(): LoginRetrofitService { return FakeLoginService() } } @Singleton @Component(modules = [FakeNetworkModule!::class]) interface TestApplicationComponent : ApplicationComponent { }
  • 127. Consider late-bound dependencies instead of “published” modules
  • 128. @Component interface ApplicationComponent { @Component.Factory interface Factory { fun make(@BindsInstance loginService: LoginService): ApplicationComponent } }
  • 129. @Component interface ApplicationComponent { @Component.Factory interface Factory { fun make(@BindsInstance loginService: LoginService): ApplicationComponent } } !// Application code ApplicationComponent.factory().make(loginService)
  • 130. @Component interface ApplicationComponent { @Component.Factory interface Factory { fun make(@BindsInstance loginService: LoginService): ApplicationComponent } } !// Application code ApplicationComponent.factory().make(loginService) !// Test code ApplicationComponent.factory().make(fakeLoginService)
  • 131. Consider component dependencies instead of “published” modules
  • 132. @Component(dependencies = [NetworkComponent!::class]) interface ApplicationComponent {} @Component interface NetworkComponent { fun loginService(): LoginService }
  • 133. !// Application Code val networkComponent = DaggerNetworkComponent.factory() .create(this) applicationComponent = DaggerApplicationComponent.factory() .create( this, networkComponent )
  • 134. !// Test Code postListRepository = mock(PostListRepository!::class.java) testApp.initializeApplicationComponent(object : NetworkComponent { override fun repo(): PostListRepository = postListRepository })
  • 135. !// Test Code postListRepository = mock(PostListRepository!::class.java) testApp.initializeApplicationComponent(object : NetworkComponent { override fun repo(): PostListRepository = postListRepository })
  • 137. Dagger 2, 2 Years Later
  • 138.
  • 139. @philosohacker (looking for a new challenge)
  • 141. The OG Reason for DI
  • 142. “A common issue to deal with is how to wire together different elements: how do you fit together this web controller architecture with that database interface backing when they were built by different teams with little knowledge of each other…” –Martin Fowler, “IoC Containers and the Dependency Injection pattern”
  • 143. “A common issue to deal with is how to wire together different elements: how do you fit together this web controller architecture with that database interface backing when they were built by different teams with little knowledge of each other…” –Martin Fowler, “IoC Containers and the Dependency Injection pattern”
  • 144. –Kent Beck, “Is TDD Dead?” Pt. 1 ~21:05 “My personal practice is I mock almost nothing. If I can’t figure out how to test efficiently with the real stuff, I find another way of creating a feedback loop…”
  • 145. • dagger-android or boilerplate? • If I can’t just add @Inject to the constructor, what module does this go in? • ☝, but don’t forget testing • What about @Binds vs. @Provides in Kotlin? • Does this need to be scoped? If so, which one? • Do I need a qualifier? • Late-bound dependencies? • Builder, Factory, or Assisted inject? • Do I need to inject Lazy<T> or Provides<T>? • Are the dependencies of this dependency in the graph? If not, 🔁
  • 146. • dagger-android or boilerplate? • If I can’t just add @Inject to the constructor, what module does this go in? • ☝, but don’t forget testing • What about @Binds vs. @Provides in Kotlin? • Does this need to be scoped? If so, which one? • Do I need a qualifier? • Late-bound dependencies? • Builder, Factory, or Assisted inject? • Do I need to inject Lazy<T> or Provides<T>? • Are the dependencies of this dependency in the graph? If not, 🔁
  • 147. Have a strong opinion on module location
  • 148. –You, frustrated “Why does this depend on a Context?”
  • 150. Don’t add a new provides method for every “new”