https://kotlinlang.org logo
#dagger
Title
# dagger
g

ghedeon

02/01/2019, 12:54 AM
I'm stuck with multi-module setup (
app
gradle module depends on
feature
library module). The general advice that I often see: if you don't want to get lost in dagger — don't bring Components to the library modules. It's easier if you just connect all your dagger modules from libraries in the final
app
module under one Component. That works, up to a point. Let say you need to do some manual injection in one of the libraries. But Component is in the
app
, so you don't have a direct reference. What are my options here?
d

dkhusainov

02/01/2019, 5:00 AM
Define component in feature, extend your app component from it, and then pass it to the library
👍 1
g

ghedeon

02/01/2019, 7:37 PM
Thank you, that's what I ended up doing!
j

Joe

02/01/2019, 7:44 PM
in that case is it possible for the feature component to include some modules and the app component extension will automatically include those, or do those need to be reconfigured for each app component extension?
g

ghedeon

02/01/2019, 7:55 PM
is it possible for the feature component to include some modules
not in this setup. It's just an interface in the feature, not a real component, so you can't attach modules to it. Ex: 1.
FeatureComponent
interface and
FeatureModule
is defined in
feauture
library. Plus, some kind of a singleton, where you set you component later. 2. In the app,
AppComponent
is a real dagger component, that extends
FeatureComponent
interface and uses
FeatureModule
3. Once you have
AppComponent
instance, set it to your singleton, that you defined in the feature. Now it can be used in the feature library.
j

Joe

02/01/2019, 7:58 PM
ok that's what i suspected, thanks for verifying!
g

ghedeon

02/01/2019, 7:59 PM
After a few years with Dagger I'm still never sure if I'm cooking it right and it's mostly try and fail.
d

David

02/01/2019, 8:29 PM
that advice around not using components in libs is widespread yes but questionable
I have a component per (gradle) module and build the graph via @Component dependencies.
It works out at the cost of giving up any heavy use of scoping outside of your top-level app & @Subcomponents.
heavy use of scoping => lifecycle control via scoping annotations
j

Joe

02/01/2019, 8:37 PM
One thing i've done with guice is have the "app" modules be able to provide bindings for the "feature" modules. in a brief trial, it seemed like component dependencies didn't allow for that, but the strategy ghedeon described would work?
d

David

02/01/2019, 8:43 PM
What I’ve always been gunning for with modularisation (Android or otherwise) is self-contained modules. I want to be able to “launch” my Android library if it contains a UI with no additional bootstrap code (just config help within a manifest). This ideal prohibits app-> module tangle like that.
In fact, since we’re talking Guice…the module install approach I used back there in ’09 (!) inspired much of how I have used later DI frameworks
So, upon building the graph within the app entry point. I have a series of module “installs” which are basically a wrapper method for the Dagger generated builders that generate on the back on
@BindsInstance
type annotations
and those child modules too, can “install” based on their dependencies. All crawling the tree of @Component dependencies
This ideal prohibits app-> module tangle like that.
I lied. I always have a module API that needs a
Context
. But genuinely, that’s it
Been wanting to write more about this for over a year after I see all the cruft out there with advice about DI, and dagger in particular. Problem is, the blog-o-sphere and talk-o-sphere is saturated with conflicting advice on DI. So much of it is terrible advice for more serious apps (Andorid or otherwise)
I think the problem is getting worse with the GDE program putting more emphasis on blogging etc.
j

Joe

02/01/2019, 8:57 PM
cool thanks for sharing!
g

ghedeon

02/01/2019, 8:58 PM
@David that would be the best, to have your idea supported by some diagrams and a sample app. Otherwise, it's difficult to consume the whole abstraction 🙂
one concern about "self-contained modules" is a diamond dependency. Right now my simplified dependency tree looks like this:
Copy code
app
      /     \
feature1 feature2
      \     /
       core
meaning that core dependencies are shared by the feature modules.
d

David

02/01/2019, 9:07 PM
understood. My “core” if you like (termed “basement” in the diagram) is mainly styling config. I’m ok with that kind of base. I’m not ok with (a) the name core [although basement isn’t much better, stole it from Play Services] and (b)
:core
becoming a dumping ground. So long as it is lean (XML, Styles, annotations etc.) I think you’re good. Unless the diamond shape is some antipattern I’m unaware of!
I use degraph to see how my graph is evolving-highly recommend. Blog post there in itself. https://github.com/schauder/degraph
My
:model
module is a bit of an antipattern as is
:domain
. The models and DAOs to which they map are migrating to feature modules as I complete my IA and move onto Dynamic Feature Modules
g

ghedeon

02/01/2019, 9:12 PM
unfortunately
:core
is not that light as you described it. Many times features are using similar entities and rest services, so core layer can get pretty advanced, most probably even splitted into
core-data/core-domain/core-ui
.
d

David

02/01/2019, 9:14 PM
I think that’s completely natural @ghedeon. You can’t reach modularisation nirvana in one fell swoop. I’ve had these odd looking modules whilst juggling things around in the graph. I think the vision is important if you are working with a wider team and agreeing the “lego bricks”. In that diagram I posted of my app graph you can see I build an “SDK” for my API (
:api-client
) and have this “blob” module called
:model
these aren’t finished
the next step if I were to “atomise” the graph and break my modules (molecules) down further would be to build;
:api-client-water
:api-client-tide
:api-client-weather
:model-water
:model-tide
:model-weather
i think that’s what you are describing in your “core” module.
I’ve come to the conclusion that there are diminishing returns at this point to move from molecules (the modules) to atoms. A larger app (or larger team) may still see benefits in going further.
1
and of course, good use of package visibility modifiers in your “core” will go a long way already. You don’t need to create more Gradle modules to be modularising
TL;DR- looks like you are on the right track. I’ll try and think of a snappy and annoying blog post title to describe yet again dagger in multi-module. I think the plaid app posts of late are very close to what I’m doing. I’ve very interested in what they’ll do with dagger scopes since they’ll hit the multiple scope conflict if they naïvely add scopes to their “CoreComponent”s. My money is on them using
@Reusable
for their DataAdapters and being done with it.
g

ghedeon

02/01/2019, 9:29 PM
oh, boy, It's a risky place to talk about package visibility) One of the kotlin's "million dollar mistakes" imho. But back to our business! I believe I've seen you in a similar topic in one of the dagger's issues on github. If you'll ever find a time and will to put up a minimal example with your take on DI, that would be much appreciated. Sadly, I don't see anything official on this matter, and it's about time. https://google.github.io/dagger/ keeps beating that coffee machine dead horse. Thank you.
💸 1
4 Views