What is Dependency Injection and why we need it, in simple words

MohammadOsman
7 min readFeb 17, 2021

1. After all… what is this?

2. Is it extra bit of work, is it hard to learn?

3. Why we need it when our code is already working fine?

1. After all... what is this?

Well, let’s start from scratch. I’m gonna separate DI into two “Dependency” and “Injection”. First understand what is the meaning of Dependency.

When it comes to classes and objects in OOP(Object Oriented Programming) concept we deal with the classes and make objects of those classes. Classes could be user define or built-in. What if I say we were always been using DI, how’s that gonna sound? A bit strange but trust me, we were. We might have never heard of this complex word Dependency Injection (DI), maybe we’ve heard but never paid attention to it and the fact is we were always been using it, but how? Let’s understand with some example:

Let’s say there is a company that need some employees to work, but unfortunately there are no employees are currently available to work in the company, what happens? Well, a lot of bad things could have happened, extra usage of electricity when there is no employee in that big building, company can’t become a good competitor in market, bunch of other things. So what’s the result? In order to become good competitor in the market, company needs good workers/employees and if there is no employee then we know what would happen.

Here I’m going to drag this example slowly towards the DI concept, alright? In above example we learned company needs employee to become a good competitor. So company becomes Dependent of employees, alright? Now, if company is Dependent of the employees then what are the employees for company? And the answer is “Dependency”

“When a class “A” is dependent of class “B”, then class “B” becomes the Dependency of class “A”.

We often use library in android development in build.gradle file. What are those? They refer to the same concept. Sometimes we become dependent of some library like: AAC, liveData… that’s why those libraries becomes the dependencies of our project.
Enough talk let’s do some code:

This is simple example i made just to keep the atmosphere less complex.

Use case:
· There is “Employee” data class which contains only Boolean as data which is set to ‘true’ by default.
· There is “Company” a regular class which is going to print some output if there is any employee.

Note: We have make our use case in such way, that one class is dependent of other class to achieve the basic understanding of DI.

Employee.kt

data class Employee(
var isThereAnyEmp: Boolean = true
)

This is employee data class which has some data which specifies isThereAnyEmp if there is an employee we will be printing the output.

Company.kt

class Company constructor(
private val employee: Employee
) {
fun companyName() {
if (employee.isThereAnyEmp)
println(
"Yes, there are employee in company and name " +
"of Company is ABC Company.."
)
}
}

The Company class takes the employee as constructor argument and there is function in it which is printing the output based on Boolean condition.

fun main() {
val company = Company(Employee())
company.companyName()
}

This is just typical main function which has object initialization and creation and calling the function companyName().

Let’s look at the detail of this simple example:
Like it’s mention above if a class “A” is dependent of the other class “B”, this is the exactly what is happening over here. Class Company need of class Employee, why? Because company needs employee to become good competitor in the market if there are any employee working in the company then the company would be good competitor for others. That is why we used Employee as a Dependency of the Company. And we have pass the Employee as constructor arguments this is called Constructor Injection we have other ways also to inject dependency like Field Injection and we also have Function/Method Injection but most commonly used one is constructor injection and there are purpose of these injections types.
Here one thing we have to notice inside the main function, we did this:

val company = Company(Employee())

We have 2 classes in this example, what if we have may be 6 classes and after passing them as a dependency and at the end calling them in the main function this is how our function would look like:

val company = Company(Employee(
Experience(Resume(Education(Hobbies(Information))))))

That’s look so cool right? now imagine if we have 20 classes its gonna look super cool, Never mind.. this would be completely mess, trust me. But don’t worry there is amazing workaround for that. If i say we don’t need to call all those dependency we can still use them without calling them, how’s that sound? seems like magic but that’s true. If we are using DI frameworks like Dagger2, Hilt our above code would look like this:

@Inject 
lateinit var company : Company

That’s all, no need to call all those 2, 6 , 20 classes, Dagger, Hilt did this for us under the hood with the inject(@ Inject) annotation.

It appears that we understood meaning of DI, yes but not fully. let’s hop into the “Injection” now.

What is injection?

Seriously, what is injection? The first thing comes into our mind, doctor do something with injections, first they refill the injection with some dosage and next thing we know…
I think this exact same concept will be applied in programming first we refill the class with some dosage(functions/ variables) next we inject into other classes, to those classes which are dependent of that class.
The meaning of “Injection” we understand more when we work with DI frameworks like dagger, hilt etc. We literally use @inject there in fact we did that in above example in this article.

Now we can say that we have pretty basic understanding of Dependency Injection (DI).

2. Is it extra bit of work, is it hard to learn?

When I started learning DI for the first time, it was dagger and dagger is pretty complex to learn. After playing around for a while then I tried to implement it to some simple project, now what happened? initially I thought it is so complex and extra bit of work but with passage of time i started understanding the value of it and i really liked it in fact. Because using dagger or any other DI doesn’t only tell you that “you’ve to inject this class to that or that class to this” but also they provide really amazing features like scopes, components, modularization of code and last but no least testing. Since then I always use DI framework like dagger, hilt to my projects. They solve a lot of problems, we don’t have to worry about most of things and framework does for us under the hood.

Is it extra bit of work?
The answer is YES and NO. If you know what is the purpose of learning DI then it will not be that hard cause you know that you are learning it for some reason.
If you are initially considering it a burden or extra work, then the learning process will be complicated for you. The term i have been using ‘Extra work’, there is a reason for it because when we are in the initial stages of learning DI it feels like we doing it for no reason this problem could have solved through manual DI (manually passing the classes in constructor parameters), actually this is wrong cause when we are doing the basics of DI we only play around with one or two classes we don’t deal with 6 classes may be 10 classes, that’s why we feel like extra work and it doesn’t mean we should start with 10 classes, we have to start with 2 or three classes at least we could understand what is this framework actually.
It’s true DI framework like Dagger or Hilt are hard and complex, even though google android developers also claims learning DI or Dagger2 is pretty hard that’s why they made Hilt to make it more easy but that’s another topic to discuss. Anyway, on the other side once you know the value of DI, the main reason, the core concept then it will only be complex but not hard.

3. Why we need it when our code is already working fine?

There are some terms every programmer must have heard ‘Robust Code’ or ‘Concrete Code’ and also other words like `Modularization` not only these terms but also things like testing and other things are already discusses earlier in the article ‘Features of DI’. These are some reasons we use or we have to use DI in our projects.

Let’s say, if we are making some application which is only consist of one class may be two or three and if we are using DI framework like Dagger2 or Hilt there it will work but we won’t be able to see the proper value of it. But if we develop proper app based on Multiple classes or Some Architecture like MVVM, MVI or may be Clean Architecture then we will not only understand the DI’s purpose but actually we will feel that, why DI was needed from the first place in such scenarios.
Using of DI is not only for passing Dependencies but to make our code more readable, understandable, testable and also get rid of a lot boilerplate.

Conclusion

Should you learn it? Or not? Well if you don’t now, then later you still have to. Its an important concept and it is necessary to learn, not for just building your own apps but big tech companies also demand for developers who knows DI and it’s a big leverage on your skills. Everybody knows it’s hard and complex but once you grasp it, you won’t regret after that.

Once again, you should learn it.

--

--

MohammadOsman

My name is Mohammad Osman and I am Native Android Developer. I write Article about android and i also develop open source samples for android.