Dependency Injection, but why?
September 16th, 2020 by Matthew Gray – Senior Software Engineer
Dependency Injection
- The “D” in S.O.L.I.D. (Dependency Inversion)
- A form of Inversion of Control (more on this later)
- Helps with having to support multiple configurations (based on env)
- Makes testing dependency-laced code easier
- Most popular pattern is constructor injection, however, can be set explicitly as a public property of an object, or as an method argument
Inversion of Control
- A set of scary words that I can best describe as “loose coupling” and “reusability”, maybe even delegation
- Includes dependency injection (arguably the most popular type of Inversion of Control)
- Service locator pattern 🗺
- Template method pattern
But, why?
- Decouples the creation, configuration and usage of a dependency
- You can change the dependency without needing to change the object that depends on it (caveat: they need to share the same interface)
- Promotes well defined interfaces and reusable code ♻
- More flexibility with configuration of an application (using a no-op dependency object in test or development)
- Simplified testing 🙃
- NestJS leans heavily on DI
How do we do it?
Interfaces are key
- Consistent implementations of the dependency
- Type checked languages really shine ✨
- Can also be done with weak types, but more challenging since no type-checking (think duck-typing 🦆, base class inheritance)
Constructors
- 💉 Inject the dependency in the object’s constructor
- Can also be injected via a builder pattern
- Allows for dependencies to remain in the private interface of the dependent object
Testing made easy
- Implement null object pattern for easy testing
- No need for dependencies to be configured any deeper than the first level
- Can still spy on methods 👁
- Great for unit tests, no real improvement for integration testing
Dependency Injection in NestJS
- Configured through modules via imports, providers, and exports
- Actual injection handled by decorators inside constructors
- Dependencies are built once, and then held in memory with a unique identifier and fetched for injection
- Can look overwhelming at first glance
- Think of it as mixing DI and the Service Locator Pattern
But what about Ruby, and Rails?
- Dependency Injection can be performed anywhere you can write code 👩💻
- It does happen in Rails core libraries
- Mainly used in configuration
But what about React?
- You are already using dependency injection
- JSX calls the render function
- Inject callbacks/methods into a component as props
- Can adopt pattern in service classes, because you can use DI wherever you can write code 🤔
Share