Introduce lazy injection of internal services
Allows the declaration of service dependencies without initializing services until they are actually needed.
This can be desirable from the architectural point of view: the services required as dependencies may not be ready to be consumed at the injection time. It can also be used as a performance optimization to avoid the initialization of services that are not used in all scenarios.
Wrapping the dependency service type with a new LazyService<T> interface is all that is required to defer service initialization:
@Provides
protected MyService createMyService(
LazyService<ExpensiveService> lazyService
) {
// sometime later in the implementation
lazyService.getInstance();
}
In Kotlin, leveraging the delegated properties, it's possible to consumer the lazy service transparently:
class MyService(
store: LazyService<ConfigurationCacheStateStore>
) {
// the first call to the getter will initialize the backing service
val store: ConfigurationCacheStateStore by store
}
This capability is present in other DI frameworks, such as Lazy in Dagger.
This PR also demonstrates the new functionality on the DefaultConfigurationCache, by making it avoid manual management of dependent services for state storage and removing imperative late bindings between the services.
@bot-gradle test on linux without pts
I've triggered the following builds with parameters: -DenablePredictiveTestSelection=false for you. Click here to see all build failures.
@bot-gradle test without pts
I've triggered the following builds with parameters: -DenablePredictiveTestSelection=false for you. Click here to see all build failures.
I'm wondering what problem are we fixing here exactly. Expensive services being injected but then going unused sounds like a code smell to me. Are we paving over some architectural problems perhaps with this?
I'm wondering what problem are we fixing here exactly.
Here we are solving the problem of having to manually manage the lifecycle of services that cannot be instantiated at the dependency injection time. With LazyService in our vocabulary we can express the dependency declaratively via constructor without changing the runtime behavior.
Expensive services being injected but then going unused sounds like a code smell to me. Are we paving over some architectural problems perhaps with this?
The part in the PR description about the expensive services is something we could use LazyService for in the future. No changes in this PR makes use of that possibility.
This pull request has been automatically marked as stale because it has not had recent activity. It will be closed in 14 days if no further activity occurs. If you don't want the stale bot to close it, then set a milestone for it.
This pull request has been automatically marked as stale because it has not had recent activity. It will be closed in 14 days if no further activity occurs. If you don't want the stale bot to close it, then set a milestone for it.
This pull request has been automatically marked as stale because it has not had recent activity. It will be closed in 14 days if no further activity occurs. If you don't want the stale bot to close it, then set a milestone for it.
the services required as dependencies may not be ready to be consumed at the injection time
This feels wrong. It sounds like we are paving over some problem with added complexity, instead of solving it. What is the problem we cannot resolve with the existing tools?
There are multiple issues with the introduction of lazy services, but the biggest one is that it introduces the concept of an "unready" service. In the current codebase there is a more-or-less clear requirement that dependencies of a service should be initialized before being injected; this makes reasoning about the state of services relatively straightforward. If we allow injecting non-ready services, that adds a ton of complexity and "flimsiness" (for want of a better word) to the process of service initialization, making our service infrastructure significantly harder to comprehend.
We should be going in the opposite direction, and making things more explicit and simple to reason about. Let's fight the urge for a quick-and-dirty solution, dig deeper and understand better what the problem is, and then fix it.
This pull request has been automatically marked as stale because it has not had recent activity. It will be closed in 14 days if no further activity occurs. If you don't want the stale bot to close it, then set a milestone for it.
This pull request has been automatically closed due to inactivity.