The Dependency Inversion Principle (DIP) is sometimes skipped, as it can be a bit abstract at first sight.
You need interfaces or abstract classes to group your classes while keeping some flexibility.
In other words, you want to set some rules, but the particular implementation is not your responsibility. Besides, modifying dependencies is a common task (e.g., changing an adapter).
If you need to modify everything every time, it can be risky and time-consuming. You may even get blocked at some point.
It's also critical for testing. Decoupling helps you write unit tests. It's not optional, actually, and you will need this concept to test your app (highly probable).
SOLID is a great set of principles, but like any other toolbox, it will fail if you don't apply it correctly.
Even if you use frameworks, like Symfony, you may still write coupled classes if you skip service containers and dependency injections.
While there's no magic rule you can apply blindly to achieve your goals, these frameworks provide great rules and lots of magic to ease the pain.
The following tips can also help you:
- write small classes with a specific purpose
- create services you can easily inject in other classes (e.g., constructor and method injections)
More concretely, if you need to fetch some resources in a database and process the results in your controller, you may leverage a service and a repository instead of a direct request (e.g.,
By defining an interface that will force classes to define methods that fetch or write data for a specific entity, you can create a service that will inject a repository that implements this interface.
Then, your controller can inject the service, allowing you to only modify the particular implementation (the repository) when you need it, and not the service or the controller.
Yes, another acronym, and it's not "Indicator of compromise" ^^.
Here, IoC means Inversion Of Control. You may see it as the generic principle, and Dependency Injection as a particular way to implement it.
The idea is to provide some description to the container and let it resolve dependencies for you automatically.
You may consider this architecture a bit complex at the beginning, but it's rewarding.
Behind the scene, the code will use type hinting (and Reflection) to analyze the dependencies, instantiate them, which ultimately allows you to use the instances in your classes.
Dependency injection can help solve complex problems, like IoC or DIP.
Whether you need to scale or to fine tune workflows in your team (or both), it's a good way to tackle the issue.
If you have some difficulties in implementing Dependency Injection, just practice more. Framework can save significant time, so do not hesitate to leverage their containers that are specifically designed for that purpose.