Dagger and component graph
Dagger and Component Graph Deep Dive¶
Overview¶
Dagger gives fine-grained control over dependency graph architecture. It is powerful for complex systems but requires strong design discipline.
Core Concepts¶
- component defines injectable graph boundary
- subcomponent models child lifecycle scope
- module provides/binds dependencies
- compile-time validation catches wiring errors early
Layer Responsibilities¶
- Core platform modules:
- provide shared infra services
- Feature graph modules:
- declare feature-specific implementations
- Entry components:
- expose required dependencies to Android boundary classes
Data Flow¶
- Root component initializes global graph.
- Child/subcomponent is created per feature or lifecycle scope.
- Requested object graph is resolved through providers/bindings.
- Injected classes execute domain/data flow.
Internal Architecture¶
Graph design decisions:
- subcomponents vs component dependencies
- multibinding for extensibility points
- scope boundaries to prevent accidental object sharing
Complexity risks:
- cyclic dependencies through bindings
- over-centralized mega-modules
- slow builds due to graph explosion
Code Examples¶
@Singleton
@Component(modules = [NetworkModule::class, RepositoryModule::class])
interface AppComponent {
fun feedComponentFactory(): FeedComponent.Factory
}
@Subcomponent(modules = [FeedModule::class])
@FeatureScope
interface FeedComponent {
@Subcomponent.Factory
interface Factory {
fun create(): FeedComponent
}
}
Common Interview Questions¶
- Q: When to use subcomponents vs component dependencies? A: Answer by defining boundaries and ownership first, then place business rules in the correct layer, and finish with testability and change-resilience tradeoffs.
- Q: How do scopes map to Android lifecycles? A: State load and SLO assumptions first, identify the first bottleneck, choose scaling and consistency strategy, and explain fallback behavior for partial failures.
- Q: Why might Dagger builds become slow? A: Frame it around graph ownership: prefer constructor injection, align scopes to lifecycle boundaries, keep contracts explicit, and validate with test replacements.
- Q: How do you debug missing binding chains? A: Frame it around graph ownership: prefer constructor injection, align scopes to lifecycle boundaries, keep contracts explicit, and validate with test replacements.
Production Considerations¶
- keep module ownership per team/feature
- reduce public graph surface to essential contracts
- fail PRs on unauthorized graph coupling
- maintain graph diagrams for critical modules
Scalability Tradeoffs¶
- Pros:
- maximal flexibility and explicit control
- strong compile-time graph safety
- Cons:
- high setup/maintenance complexity
- steeper onboarding and debugging costs
Senior-Level Insights¶
Staff-level discussion should cover how graph governance evolves: ownership rules, build performance budgets, and strategies to prevent dependency sprawl.