Dependency injection
Dependency injection is the design pattern where a component receives its dependencies as parameters rather than constructing them internally. The pattern decouples a component from the concrete implementations of its dependencies, making the component easier to test (inject mocks) and easier to reconfigure (inject different implementations).
DI is one face of inversion of control: instead of the component controlling which database client it uses, the caller (or a framework) decides and passes it in. The pattern's value scales with the testability and configurability needs of the component. In small codebases, DI can feel like over-engineering — passing five dependencies into a constructor that could just import them. In large codebases, DI is essential because the alternative (hardcoded imports) makes testing impossible and migration painful. Framework support (Spring, Angular, NestJS, .NET DI container) handles the wiring; manual DI (constructor params) is also fine for smaller surfaces.
Related terms
- Inversion of control
Inversion of control is the design principle that a component should not control the flow of its dependencies — instead, the framework or container controls flow and passes resources to the component when needed.
- Hexagonal architecture
Hexagonal architecture (also called ports and adapters), introduced by Alistair Cockburn in 2005, structures an application so the core domain logic depends only on abstract 'ports' — and concrete adapters (web framework, database, message bus) plug into those ports from outside.
- Test double
A test double is any object that stands in for a real dependency in a test — mock, stub, fake, spy, dummy.