This is the 11th article on the System Design and Software Architecture series. In this article, we are discussing the sub-topic of the design principle, DIP: Dependency Inversion Principle.
Previous articles
- Introduction to System Design and Architecture
- Values of system software
- Programming Paradigm
- Object-Oriented Programming
- Structured programming
- Functional programming
What is The Dependency Inversion Principle?
The general idea of the Dependency Inversion Principle is as simple as it is important: high-level modules that provide complex logic are easily reusable. Also do not affect changes to lower-level modules that provide utility features. To achieve that, you need to introduce a summary that decodes the high-level and low-level modules from each other.
According to the Robert c. Martin’s definition of the dependency inverse principle consists of two parts:
- High level
- Low level
High-level modules do not depend on low-level modules. Both must rely on abstractions. Does not depend on summary descriptions.
The details depend on the abstract.
An important detail of this definition is that it relies on the abstraction of high-level and low-level modules. The design principle not only changes the direction of dependence, as you might expect when you first read its name. It divides the dependence between high-level and low-level modules by introducing a summary between them. So in the end you get two dependencies:
- The higher level depends on the module abstraction, and
- The lower level depends on the same abstract.
High-level modules
High-end modules are the part that brings real value to our application. They are modules written to solve real problems and use cases.
They are more abstract and map the business domain. Many of us call this business logic. Whenever we hear the word business logic, we turn to the high-level modules that provide the features of our application. Top-level modules tell us what software should do, not how software should do it.
Low-level module
Low-level modules are the implementation information needed to implement business policies. As high-end modules tend to more abstract in nature. Also at some point, we will need a few specific elements that will help prepare our business executives. They are plumbing for the interior of a system. They tell us how the software should perform different functions. Therefore, high-level modules tell us what software should do, while low-level modules tell us how software should do different tux.
For example,
- Logging, Data Access, Network Communication, and IO.
- Summary
- Something non-concrete.
- Something we cannot “renew”. In Java applications, we tend to format abstract models using interfaces and abstract classes.
Key points:
Dependency vaccination is the implementation of the principle of dependence reversal.
One way in which the open-closing principle can be achieved is by using the dependent inverse principle.
The top-level modules in the DIP are the modules that appear at the top of the UML diagram and depend on the abstract layer. In the center of the diagram are the abstractions. The lower level modules are at the lower level of the diagram and are actual activations of the abstract layer.
Introduction to Dependency Injection
Dependence injections are widely used in line with the principle of dependence reversal. However, they are not the same thing. Let’s take a look at how PaymentProcessor dropped out of class.
Dependency injection is a technology that allows the creation of objects that depend on a class outside.
We have different ways to do this. One of them is the use of common kits to set those dependencies. However, this is not a good approach, as it can cause objects to become bootable.
Types of dependent vaccines
This can be done by using dependent vaccines:
- Builder injection
- Field injection
- Method of injection
Inversion of Control
The inverse of control allows us to create a larger system by removing the resistance to creating objects.
The reverse of control is the design principle that gives control of object design, configuration, and life cycle to a container or frame.
Controlling the creation and management of objects is reversed from programmer to directory. We no longer need new objects. Something else creates them for us and something else is commonly referred to as an IOC container or a DI container. Controlling object creation is the reverse. It is not the programmer but the container that controls those objects. It makes sense to use it for certain objects in an application, such as services, data access, or controllers.
However, for institutions, data exchange objects, or valuables, it does not make sense to use an IOC container. We can simply update those objects and from an architectural point of view, it is right.
There are many benefits to using an IOC container for our system.
- First, it makes it is very easy to switch between different activations of a particular class at the time it is activated.
- Then, it increases program modularity.
- Last but not least, it manages the life cycle of objects and their configuration.
Advantages
- Loose coupling
- Easy testing
- Laying better layers
- Interface based design
- Dynamic Proxy (AOP to segue)
Architecture
Dependent inversion has an architecture that is key to its definition. In each domain, it is the most important and it is abstract. Also, it shows the communication protocol between domains and defines the remaining packages or libraries.
Clean Architecture
In pure architecture, the domain is located in the center and if you look at the direction of the arrows indicating the dependence it becomes clear what are the most important and stable layers. The outer layers are considered unstable tools, so avoid relying on them.
Hexagonal architecture
It is similar to hexagonal architecture, with the domain also located in the center and the port being a summary of communication from outside the domino. Here again, it is clear that the domain is more stable and the traditional dependence is reversed.
Edit dependent inverse pattern normalization
In many projects, the principle of inverse inversion and pattern is considered to become a single concept that needs to generalize. Also applies to all interfaces between software modules.
There are at least two reasons for this:
- It is simple to see a good thought principle as a coding pattern. After encoding an abstract class or interface, the programmer may say: “I have done the abstract work”.
- As most unit testing tools depend on inheritance for mocking, it has become the norm to use standard interfaces between classes (not just between modules when using generality makes sense).
If the tool of mockery used is inherited, it is necessary to apply the dependent inverse pattern extensively.
This has major drawbacks:
- It is not enough just to activate an interface across a class to reduce connectivity; just thinking about the potential abstraction of interactions. And that can lead to a less connected design.
- Implementing common interfaces everywhere in a project is difficult to understand and maintain. At each step, the interface will ask itself what other implementations of this interface are, and the response is usually.
- Factories that typically rely on a dependency-injection framework require more plumbing code to normalize the interface.
- Interface generalization limits the use of programming language.
Conclusion
Thanks for reading the article DIP : Dependency Inversion Principle as an essential component in System design and architecture.
My articles on medium