Why does EK9 limit injection fields per component?
← Dependency Injection · Ref: Q862
Components with more than 4 injection fields (marked with '!') violate the Single Responsibility Principle. The compiler raises E11040 to enforce focused components.
WHY THE LIMIT EXISTS
A component with 5+ injected dependencies is doing too much. Each dependency represents a concern the component must manage. More than 4 suggests the component should be split.
THE FIX
Extract a facade component to group related dependencies:
1. Identify clusters of related injected services
2. Create a facade component that wraps the cluster
3. Inject the facade instead of individual services
THIS EXAMPLE
Shows a component with exactly 3 injection fields, well within the limit. Each dependency is clearly needed for the component's focused responsibility.
See Q227 for compile-time DI validation. See Q229 for circular deps. See Q325 for component patterns.
Example
defines module qa.di.injection.field.limit defines component <?- Abstract service contracts for injection. -?> Repository as abstract findById() as abstract -> identifier as String <- rtn as String? default operator ? Notifier as abstract notify() as abstract -> message as String default operator ? Auditor as abstract record() as abstract -> action as String default operator ? <?- Concrete implementations. -?> InMemoryRepository extends Repository override findById() -> identifier as String <- rtn as String: "item-" + identifier default operator ? ConsoleNotifier extends Notifier override notify() -> message as String Stdout().println("[NOTIFY] " + message) default operator ? ConsoleAuditor extends Auditor override record() -> action as String Stdout().println("[AUDIT] " + action) default operator ? <?- Correct: 3 injection fields, within the limit of 4. Each dependency is clearly needed for order processing. -?> OrderProcessor repo as Repository! notifier as Notifier! auditor as Auditor! processOrder() -> orderId as String item <- repo.findById(orderId) if item? notifier.notify(`Processing ${item}`) auditor.record(`Processed order ${orderId}`) default operator ? defines application OrderApp register InMemoryRepository() as Repository register ConsoleNotifier() as Notifier register ConsoleAuditor() as Auditor defines program InjectionLimitDemo() stdout <- Stdout() stdout.println("OrderProcessor has 3 injection fields (within limit of 4)") stdout.println("Components with 5+ injection fields trigger E11040")
Common mistakes
E11040 — 5 injection fields exceeds the limit of 4. Extract related services into a facade component and inject the facade instead. See ek9 -h E11040 for details.
Incorrect:
repo as Repository! notifier as Notifier! auditor as Auditor! extra1 as Repository! extra2 as Notifier!
Correct:
repo as Repository! notifier as Notifier! auditor as Auditor!
Other ways to ask this
- What is E11040 EXCESSIVE_INJECTION_FIELDS in EK9?
- How many injection fields can a component have?
- How do I fix too many injected dependencies?
Coming from another language?
Java: Spring has no limit on @Autowired fields (only advisory from SonarQube). Python: no limit. Kotlin: no limit. Go: no DI framework limits. Rust: no DI concept. EK9: E11040 compile-time limit of 4 injection fields per component.
Keywords: limit, injection, dependency, component, E11040, field, SRP, inject, clean-code, facade, quality