Beginner Series: Dependency Injection

Dependency Injection is a concept that did not immediately sound intuitive to my mind, especially as a non-native English speaker. I’ve read a bunch of different articles and resources about it, and found two that helped.

First, Dependency Injection Demystified. The article is quite short and I highly recommend going through it:

Dependency injection means giving an object its instance variables. Really. That’s it.

To understand what “dependency” means, here’s the famous graph about Android’s recommended app architecture:

Android's recommended app architecture

The arrows in the graph there are the dependencies. So Room depends on SQLite, the Repository depends on the Model, the ViewModel depends on the Repository, and the Activity/Fragment depends on the ViewModel.

The simplest form of dependency injection is like the primary constructor with parameter in Kotlin, like the following example:

class Person constructor(favoriteBook: Book) { /*...*/ }

Here, favoriteBook is the dependency, while the constructor parameter is the way to inject it into the Person object. This is in contrast with having the favoriteBook object created within the class.

The next question in my mind was, why do we need this?

This StackOverflow answer was the second resource that helped me with these two reasons:

Two important ones are the ability to control functionality from a central place (the Main() function) instead of spreading it throughout your program…

I think this is pretty obvious.

…and the ability to more easily test each class in isolation (because you can pass mocks or other faked objects into its constructor instead of a real value).

For testing purposes, it’s good if we can test the Person class individually and send dummy object to it (the favoriteBook object on the example above). Or, as the official manual dependency injection guide mentioned:

Dependency injection helps make these connections and enables you to swap out implementations for testing. For example, when testing a ViewModel that depends on a repository, you can pass different implementations of Repository with either fakes or mocks to test the different cases.

And the final question: if dependency injection is this simple, why are there complex tools made for it?

This is turns out relates to the first reason above:

The drawback, of course, is that you now have one mega-function that knows about all the classes used by your program. That’s what DI frameworks can help with.

Once a codebase gets really big and complex, it’s easy to imagine that manual dependency injections can go all over the place. The tools/frameworks eventually are meant to help with that.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s