Dependency Inversion Principle
- Definition
- High-level modules should not depend on low-level modules, but both should depend on abstractions
How does it work?
The principle has two aspects:
- High-level modules should not import anything from low-level modules. Both should depend on abstractions (e.g., interfaces).
- Abstractions should not depend on details. Details (concrete implementations) should depend on abstractions.
When should you use it?
- Testing and Mocking: DIP facilitates unit testing and the use of mock objects. By depending on abstractions and injecting dependencies, it becomes easier to substitute real implementations with mock or test-specific implementations during unit testing.
- Parallel Development: In collaborative development environments where different teams or developers work on different components of the system independently, DIP can provide a clear separation of concerns, enabling parallel development without tight coupling.
Problems
- Abstraction Overhead: Introducing abstractions (interfaces or abstract classes) to implement DIP can lead to additional code and complexity, especially in smaller projects where the benefits may not outweigh the costs.
- Over-Engineering: Over-application of DIP, especially in simpler projects, can result in unnecessary abstraction layers, leading to over-engineering and increased development time and effort.
- Increased Number of Interfaces: As the number of abstractions increases, the codebase may end up with a large number of interfaces, potentially making it harder to manage and navigate.