Dependency Inversion Principle: How Google Developers write code
Omar Ismail
Senior Software Engineer @ Digitinary | Java & Spring Expert ? | AWS & Microservices Architect ? | FinTech & Open Banking Innovator ?? | Digital Payments Expert ?? | Top 200 IT Content Creator in Jordan ?? | 40K+ ??
Thanks to the original writer and article :
https://paigeshin1991.medium.com/dependency-inversion-principle-how-google-developers-write-code-f6cbd3b530a6
To become a high-paid developer, you need to learn TDD. Basically, you have to develop software with TDD to get into a big company. If there are a few concepts you should know before doing TDD, it is?Dependency Inversion Principle?of SOLID Principle that you should know. It may not be easy for novice developers to understand, but luckily you have just found the easiest tutorial in the world. I am sure this short tutorial will be of great help to you in your career.
*TDD: Test Driven Development*
What is Dependency Inversion Principle?
Dependency Inversion Principle corresponds to?D?among SOLI’D’?Principles. Its principle starts with this statement.
High-level modules should not depend on low-level modules. Both should depend on abstractions.
Well-organized code always has a hierarchy. There is a high-level modules and low-level modules. But sometimes rookie developers misunderstand this concept, and they bring directly low-level modules to high-level modules.
Can you see what’s wrong with this code?
import java.util.Arrays;
import java.util.List;
// High Level Module
class ProductCatalog {
public void listAllProducts() {
SQLProductRepository sqlProductRepository = new SQLProductRepository();
List<String> allProductNames = sqlProductRepository.getAllProductNames();
// Display product names
}
}
// Low Level Module
class SQLProductRepository {
public List<String> getAllProductNames() {
return Arrays.asList("soap", "toothpaste", "shampoo");
}
}
What do you think? Do you see a problem??ProductCatalog?class is high-level module but it depends on its submodule?SQLProductRepository.
This is a mistake often made by novice developers.
Let me repeat again.?Dependency Inversion Principle?says
“High-level modules should not depend on low-level modules. Both should depend on abstractions.”
You are now seeing the violation of?Dependency Inversion Principle?because High Level Module?ProductCatalog?depends on its submodule?SQLProductRepository.
Now you understand the problem. Then how do you fix it? Before you fix it, let’s see what?abstraction?means in software design.
What is Abstraction?
(1) Code without abstraction
class Benz {
public void drive() {
}
}
class CarUtil {
public static void drive(Benz benz) {
benz.drive();
}
}
As you can see the code above, CarUtil class’s static drive method is dependent on Benz. You should provide?Benz?instance in order for CarUtil’s?drive()?method to function. In software design, it is called ‘tight-coupling’. This also means, when you change?drive()?method inside?Benz?class, CarUtil is directly affected. This is prone to make bugs.
Tight Coupling is the most undesirable feature in Software
领英推荐
(2) Code with Abstraction
interface Car {
public void drive();
}
class Benz implements Car {
@Override
public void drive() {
}
}
class Tesla implements Car {
@Override
public void drive() {
}
}
class CarUtil {
public static void drive(Car car) {
car.drive();
}
}
This code looks perfect. CarUtil’s static drive method doesn’t depend on Benz, but it depends on?Car?interface. Now, it can take any argument which implements Car Interface. This is called abstraction. It is also called ‘loose-coupling’.
Now, let’s go back to the previous code example.
Refactoring Previous Code with Abstraction
“Abstractions should not depend on details. Details should depend on abstractions.”
import java.util.Arrays;
import java.util.List;
// High Level Module
class ProductCatalog {
public void listAllProducts() {
// High Level Module depends on Abstraction
ProductRepository productRepository = new SQLProductRepository();
List<String> allProductNames = productRepository.getAllProductNames();
// Display product names
}
}
interface ProductRepository {
List<String> getAllProductNames();
}
// Low Level Module
class SQLProductRepository implements ProductRepository {
public List<String> getAllProductNames() {
return Arrays.asList("soap", "toothpaste", "shampoo");
}
}
Now,?ProductCatalog?depends on?ProductRepository?instead of?SQLProductRepository.
Why doing this again?
First,?you don’t know what database you are going to use. It may not be specifically?SQL.
Second,?ProductCatalog‘s?listAllProducts()?does not depend on a specific object. This means, when you change code in?SQLProductRepository,?ProductCatalog?is not directly affected. You just have achieved?loose-coupling.
What you have achieved now
Before refactoring,?ProductCatalog?was dependent on?SQLProductRepository.
After Refactoring,?ProductCatalog?depends on?ProductRepository?and?SQLProductRepository?is also dependent on?ProductRepository?.
Let me remind you of Dependency Inversion Principle again.
“High-level modules should not depend on low-level modules. Both should depend on abstractions.”
I think you now understand the sentence entirely!
One strep forward, Dependency Injection
import java.util.Arrays;
import java.util.List;
class ProductCatalog {
private ProductRepository productRepository;
public ProductCatalog(ProductRepository productRepository) {
this.productRepository = productRepository;
}
public void listAllProducts() {
List<String> allProductNames = productRepository.getAllProductNames();
// Display product names
}
}
interface ProductRepository {
List<String> getAllProductNames();
}
class SQLProductRepository implements ProductRepository {
public List<String> getAllProductNames() {
return Arrays.asList("soap", "toothpaste", "shampoo");
}
}
class EcommerceApplication {
public static void main(String[] args) {
ProductRepository productRepository = new SQLProductRepository();
ProductCatalog productCatalog = new ProductCatalog(productRepository);
productCatalog.listAllProducts();
}
}
You’re now injecting?ProductRepository?to?ProductCatalog. This is a common practice and even recommended way to build objects. You will understand its usefulness when you learn Mock and TDD concepts. But if I explain it now, I can’t keep the promise of?“The Easiest Tutorial of The World”.
Conclusion
If you can understand these two statements, you have fully understood Dependency Inversion Principle! Congratulations!
But if not, don’t worry. You can’t easily understand Dependency Inversion Principle unless you have experience. This also needs ‘intentional practice’.
Building @CrysPay on Aptos | ?? @RouterProtocol | Degree-ing ?? | Flutter + Web3?? | Pythoneer | DappDev | Sanskrit ????????| Contributor @PSF |
2 年Great ??
iOS Engineer, x-SadaPay
2 年Love it :) high cohesion, losely coupled code ??
Software Development | Python | PHP | Laravel | JS | ML | Certified Ethical Hacker
2 年Easily understandable writing. Thanks