The great and powerful Dependency Injection

I have a confession: I used to believe in magic. More accurately, I used to believe that dependency injection was magic. Somewhere in the last nine years of Android development, I had a small realization that changed my view of it entirely. Here I hope to recount my journey to help others better understand.

The promise of libraries like Guice or Dagger to make your code more testable was alluring. But when I first started using them I felt like no one could possibly understand what they do under the hood. It took me almost a year of messing around with dependency injection libraries to realize that not only was I wrong, but there was no magic here at all.

Let’s start with an fictitious example:

class LoginTask() {
    val network = Network("http://william.best")

    fun login(username: String, password: String): Result {
        return network.credentials(username, password)
                      .post("/login")
    }
}

This code isn’t great from a testing standpoint because we always get the same Network class. If we wanted to be able to change the network object we could do two things.

Provide a setter for the variable:

class LoginTask() {
   // Note the 'var'
   var network = Network("http://william.best")
   ...

Or, provide a constructor:

class LoginTask(val network: Network) { ... }

And that was it; It dawned on me that this is all dependency injection was. Nothing magical, nothing special. These examples are respectively referred to as property and constructor injection. Up until then I had been conflating dependency injection with the “magic” of specific libraries. Yet, under the hood, any dependency injection library takes all the things you give it and basically performs one of those two operations. It constructs something, or it sets a variable.

Lets be clear, most of these libraries are complex. They do a lot for you and are designed to be general purpose. You have every right to be intimidated. However, all of the components and modules and annotations are just there to facilitate these actions. If you are having a hard time trying to figure out dependency injection tool to use, the best thing you can do is start working towards testable code. Because at the end of the day, they all do the same thing.

Leave a Reply

Your email address will not be published. Required fields are marked *