Question regarding the usage of `@Singleton` and `...
# dagger
s
Question regarding the usage of
@Singleton
and
@Inject
inside the code instead of
Module
? I have a personal opinion of creating
Modules
and defining all my dependencies there instead of marking classes with the above annotations? Reason being: 1. It help me understand the dependencies and configurations from a single file i.e
Module
. 2. It avoid mixing code with configuration(annotations). What are your opinion on this? I don’t prefer the following code:
Copy code
@Module
class BookingDatabaseModule {

    @Provides
    fun provideBookingDao(database: BookingDatabase) = database.bookingDao()
}
Following is my preferred way of doing it:
Copy code
@Module
class BookingDatabaseModule {

    @Provides
    @Singleton
    fun provideDatabase(context: Context) = BookingDatabase.newInstance(context)
    
    @Provides
    fun provideBookingDao(database: BookingDatabase) = database.bookingDao()
}
What are your opinions?
i
It’s a matter of taste. If you use @Inject, it will save a LOT of code, with the downside of the dependency graph being less evident -> you can use https://github.com/arunkumar9t2/scabbard to make it more visual if you want
👍 2
It’s better to discuss it with your team than here. Any approach works and you need to choose which one makes your team more confortable IMO
g
We use constructor injection everywhere where it's possible, it saves a lot of code Personally I don't find that it makes graph less understandable, a bunch of modules with boilerplate, especially without good structure, doesn't make it better
👍 2
There are different opinions on topic, some think it's make hard to understand source of dependency, but as I said, I personally don't see such problem
s
@gildor how if you want to change the DI library someday? Which basically doesn’t work with these annotations?
g
What is problem with it? It's just an annotation on constructor, it doesn't add any dependency on any library. You can even drop DI library completely and rewrite graph manually, it wouldn't require any changes on dependency level
s
Yeah it’s basically how people are comfortable with. I personally want to keep these DI configurations in one place.
g
Also @Inject is part of JSR-330 standard and supported by many DI frameworks: spring, juice, toothpick
Keep configuration in one place? What kind place? Isn't huge dagger module with all classes of your app (or even Gradle module) is a mess? So you have to split to multiple modules it it's possible, but it'w also not so easy to manage
s
I meant, if you have a room database implementation..you will create a database module which will hold the creating of database logic and if required by a LocalSource class.
g
Usually every feature has own module (or a few modules connected to graph), but most of them are just bind declaration, so you connect interfaces with implementation, tho it looks similar, but because of constructor injection for constructor it requires much less code and more declarative
👍 1
Database module sure, if you need config on DI level, but usually you have very few such dependencies, andost of classes just require other classes, and no special config
We have thousands classes which we inject, I just cannot imagine also write manual constructor injection for all of them... I mean it's possible, but disadvantage is huge for me
s
Right! Make sense to me. @gildor
c
Interesting discussion. I'm learning dagger and feel a lot of the same points. I would love to open up a single package with a whole bunch of modules defined and then you can very easily find out which Modules/Dependencies are available to you. Using @Inject feels like you're hiding the dependency, but I just started working with dagger, so I don't really know. It's just how I feel at this point. I will say that I think it's crazy that Scabbard keeps being brought up here because... like... what did you do before Scabbard? If I'm brand new to a team and writing a new feature, how do I know what dependencies are available to me, etc? So many questions. 😄
💯 1
s
So true @Colton Idle Even I also feel the same.
g
Why do you want to have all modules in the same package, if those modules are not related? Why do you want to know which dependency is available to you, if essentially every class is available? When you inject everything no need to know what is available, also dagger will check it for you on compile time Why inject is hiding dependency? You hide or expose dependency by making them public/internal, not by defining provides method for them
c
@gildor
Why do you want to have all modules in the same package, if those modules are not related?
For me, it's because when I start a new project, I think it would be really nice to have one spot to look at and find out what dependencies I can start injecting into whatever new feature I'm working on. A lot of times when I'm new to an existing codebase and it uses Dagger... I'm left thinking "What the hell is available for me to use?" So I'm not advocating to have all modules in the same package, I'm just saying that I wish there was an easy way to to just see all modules or all provides methods, or just really... What is everything that I can start injecting? That's what I find hard as a 2 week user of Dagger. People mention scabbard, but it seems crazy that if Dagger is used to help provide dependencies in a consistent way, that there would be a way to quickly view what dependencies are injectable if I want them.
Why do you want to know which dependency is available to you, if essentially every class is available? When you inject everything no need to know what is available, also dagger will check it for you on compile time
Let me give you another example. I started working on a project with a barebones Dagger setup. It was basically just used for sharing OkHttp/Retrofit instance. They plan on using dagger more. Okay cool. Makes sense. I code up a new feature in Android with SharedPreferences and then in code review they tell me "Oh this is actually available through Dagger" and it's like. 🤦 I wish there was an easy way to see what dependencies have been set up in dagger for me to use. On the opposite side of the spectrum I've worked on projects with like 1000 dependencies and it's literally impossible to know what I have available to me when building my feature until I kind of start guessing. I guess maybe this could just be solved by docs in the project keeping a master list of everything that's available. Maybe this isn't a problem at all! Maybe I'm just making it up because I'm new to dagger. /shruggie This is a beginner perspective. Would love for someone with more experience to break me out of that thinking.
Why inject is hiding dependency? You hide or expose dependency by making them public/internal, not by defining provides method for them
Similar to what I said above. You are making sense, but it still doesn't help me in the use case where I'm new to a project, and I jump in and start writing a feature "Hmm I'm going to need Retrofit and SharedPreferences (purely hypothetical example) I search for all classes that end in Module, and only find one (in this hypothetical example) and the only thing it provides is Retrofit. So now I'm like, Okay, I will Inject retorfit as a field, but now I need sahredPreferences. Then at code review time, they tell me "Oh actually we have this SharedPrefWrapper class that has an @Inject on it's constructor, so you can use that". I'm complaining about visibility and not knowing what's there quickly.
💯 1