Before diving into the deep end, let me explain what classic dependency is with a simple example. Let’s take a look at the following flowchart:
Imagine you have an automated factory that produces walls from lumber. As your factory produces a wall (UI)(ViewController) it reaches a point where it needs a door (NetworkLayer) to fully function as a wall. This door (NetworkLayer) is what gives the wall all of its functionality. Now as you keep producing more walls (ViewController), there is no reason to keep making new doors each time with raw materials, but instead we have pre-made doors that allow each wall to be able to be different. However, when it comes to using the doors (testing them) you have to fully take out the door because there is nothing allowing the door to open and close (to be tested) while it is on the wall. This is the basic classic dependency injection method.
Nonetheless, it is not the most optimal way that you would want your wall (ViewController) to function, given that every time you take out the door (for testing), the wall cannot function until the door is set back in place. In more real coding terms, your User Interface (wall) will not be able to function because it will have nothing injecting data into it (no door); since the class or NetworkLayer (door) is out for testing.
As you probably noticed, the classical dependency injection method is not the best when it comes to testing, co-working, and usability. If you want to build a different kind of door (NetworkLayer), you have the possibility that it won’t work with the existing wall (ViewController). This is where the Dependency Inversion Principle comes in.
The dependency inversion principle basically allows the door frame to have hinges (NetworkLayerType), allowing for the usage (testing) as well as being able to use different doors while others are taken out with ease (allowing for mock doors (MochNetworkLayer) to be set in place while the main door (NetworkLayer) is worked on). Let's refer to the image below, which is a more completed previous classical dependency injection image above.
This principle allows simultaneous working on both the wall and the door, because you can always plug in another door while the other one is out for testing. Meaning you can work on your wall (UI) while you work on the door (NetworkLayer), unlike the classical method. Then all you have to do is plug the main door back in after testing or updating. This method allows for better and more flowing work, with less downtime for testing as well as a very simple and easy coding technique.
Dependency Injection is a flexible way to make our code style easy to change and develop in both small teams and large teams.
First, let’s talk about traditional dependency injection, it injects one code class into the other. For example, the NetworkLayer class is injected directly into the ViewController class. So, these two classes are tightly coupled, this means that we cannot change anything within the NetworkLayer class. If we do change anything, it will affect some point in the ViewController class. Lastly, we cannot run any tests with this style.
Did you see the problem with this code? Let’s analyze the problems:
-You cannot change your NetworkLayer implementation
-You cannot create mock data when your server is down
-If someone in your team is developing this function you need to wait until he/she finalizes what they are doing
-You cannot do unit testing with this traditional dependency injection
We need to follow the S.O.L.I.D (SOLID) principle, which is a software development principle developed by Uncle Bob. But we will pick only one of these approaches. The term SOLID is a mnemonic acronym for five design principles intended to make software designs more understandable, flexible and maintainable. So, what does this acronym stand for?
S - Single-responsibility principle
O - Open-closed principle
L - Liskov substitution principle
I - Interface segregation principle
D - Dependency Inversion Principle
The Dependency Inversion Principle will allow our code to be more flexible, easily testable, and with simple maintenance.
In our case, we want to make our NetworkLayer class flexible to change in the ViewController class. That’s why using the Dependency Inversion Principle will be ideal for this kind of situation. The principle states:High-level modules should not depend on low-level modules. Both should depend on abstractions.Abstractions should not depend on details. Details should depend on abstractions.
// UML Diagram
Now we change our code to this:
Suppose that your server is down. You can swap your implementation like this:
What changed here is that our ViewController class is no longer dependent on the NetworkLayer class, it now depends on NetworkLayerType. Therefore, the NetworkLayer class and ViewController class are separated by the NetworkLayerType.
Moreover, if your team leader wants to update to a new functionality in request() method, you can easily change it without affecting the old implementation. This can be done by creating a new class and conforming it to that protocol. The last step is to then swap the implementations and you are done!
Lastly, if you are a UI engineer you don’t need to wait for the real implementation to take place, you can create mock data by yourself instead of waiting for the NetworkLayer to be completed and implemented. In other words, you can work simultaneously with your partners. Now that's real functionality.
I personally believe that this is the best concept for professional coding. I can guarantee amazing benefits while using this approach when developing a large application. Your code will be clean as well as having mobility, re-usability, test-ability, and maintainability. This is mostly due to the ability to provide results with little to no downtime between sections.
For the next step in your coding journey, I would like to encourage you to read all five concepts of the S.O.L.I.D principle. The S.O.L.I.D principle will become your weapon of the choice in coding. You can fight with tightly coupled and spaghetti code. Subsequently, you will feel confident to write professional code and enjoy coding even more.