Oops, you're right, thanks, I was running the buil...
# dagger
d
Oops, you're right, thanks, I was running the build with intellij and it didn't give me dagger error that I was missing a
@Provides
, only when I ran in terminal, I saw it, now everything works! Your 'did you see `kaptGenerateStubs`' question made me look there ... 😊
g
I see compile error in Idea with good error message that explains problem with lack of
@Provides
Do you have ā€œDelegate IDE build/run actions to gradleā€ option enabled?
d
Oh, maybe not, because I need to pass some local environment vars for service configuration... could that be done in gradle?
g
Yes, of course. Gradle can read environment variables. Also you can use gradle properties for that, to specify some config variables
Also Idea allow you to set environment variables
d
With ā€œDelegate IDE build/run actions to gradleā€ option enabled?
g
Yes
I don’t know exactly your case so cannot recommend more specific solution. Usually with gradle I don’t use environment variables locally (but use on CI), but use property files
d
Docker recommends all configs should be through env. vars, also in Docker Swarm services are harder to configure per environment w/ config files... we also have Jenkins that will need to run the tests... How do you manage your config loading, straight in the dagger module while instantiating deps or through a common config class?
g
Yeah, if you run using Docker no problem, just pass them as environment variables. I’m talking about local development
Don’t exactly understand you question about config loading. Usually I try to have as less as possible code in dagger module, in 99% only constructor/factory invocation. So for config I would instantiate some class that implements this config and return as dependency But maybe I understand you question incorrectly
Also it’s pretty common case in our app when we provide particular config property directly without exposing full config for clients. Something like:
Copy code
@Provides
@Named("some_config_property")
fun provideSomeProperty(config: MyConfigInterface): String {
    return config.someProperty()
}
and use it on client side:
Copy code
class SomeClientClass @Inject constructor(@Named("some_config_property") someProperty: String)
d
For example, instantiating a db client needs multiple config vars, so currently I have a
provideDbClient
that has lots of `System.getenv("...")`s in the constructor, also I run a login function in an xmlrpc dep. in
provide XmlrpcClient
, but I was wondering if that should also be abstracted in factory classes? Or maybe that's part of the point of DI is to take care of providing objects that are ready for use... Also, I'm still not clear on when to use inject on a constructor, if I still have to write a provider function for it...
g
My opinion that you always should avoid to call
System.getenv
in a class constructor or anywhere in your business logic. You can do that in DI (module) or in some special config implementation, something like
MyConfigEvnVarsImplementation
I’m pretty sure, DI should provide ready to use object if you need config class with multiple values or just single config value
when to use inject on a constructor
There are different opinions about that. Imo
@Inject constructor
is really useful, reduces boilerplate. Also you can use it even in case of polymorphic dependency with
@Binds
annotation on module method. So our internal guideline: use
@Inject constructor
as much is possible and use provide method when it’s impossible to do or you want to override some dependency. But some people has opposite guidelines, to use only provide methods, but I’m not sure that ā€œkeep everything in one placeā€ is good reason.
šŸ‘šŸ¼ 1
I have a
provideDbClient
that has lots of
System.getenv("...")
For example in your case I would use constructor inject for you DbClien (probably with
@Bind
if client is polymorphic) and to provide all client config properties use some class with configuration properties:
Copy code
class XmlrpcClient @Inject constructor(config: DbConfig) // Probably use named config instead
Copy code
class SystemEnvDbConfig @Inject constructor() // And just init instance using System.getenv in constructor
Copy code
interface MyDbModule {
    @Binds fun provideDbClient(impl: XmlrpcClient): DbClient
    @Binds fun provideDbConfig(impl: SystemEnvDbConfig): DbConfig
}
So that’s all. You can use XmlrpcClient or DbClient as dependency of any other class, Dagger will build graph for you
Of course it’s just one of solutions, depends on how many abstraction level do you need and how flexibly graph do you need. You can avoid DbConfig abstraction and use your current approach, where you just use
@Provides
method that constructs DbClient using
System.getenv