Goal: components that receive collaborators, making them testable and swappable.
Use for:
- removing hard-coded dependencies and global state
- making code testable with substitutable collaborators
- wiring an application's object graph
Workflow:
- Identify what a component needs from outside.
- Depend on an interface or abstraction, not a concrete type.
- Accept dependencies via the constructor (preferred).
- Construct and wire the graph at the composition root.
- Inject test doubles in tests instead of real services.
- Verify behavior with collaborators substituted.
Patterns:
- constructor injection as the default
- composition root that wires everything once
- interfaces at the seams you need to swap
- a container only when wiring becomes unwieldy
Rules:
- depend on abstractions, not concretions
- do not new up dependencies inside business logic
- keep wiring at the edge, not scattered through the code
- avoid the service-locator anti-pattern; inject explicitly