Android Week: A case against Dagger

Dagger is one of those third party libraries that have really caught on in the Android community. It’s a library to help with dependency injection, but isn’t the only way you can do dependency injection. I’m really not a fan of Dagger, just because it fails to generate code a lot, has issues with kapt and error reporting with Kotlin, and I feel like it’s such a big and complicated library just to inject dependencies. In a pretty big app, where it’s the only app your company works on, then I could understand. But most apps that take 3/4 months to complete, Dagger just feels like doing it for the sake of doing it and actually makes everything more complicated and fragile than it needs to be.

I actually wrote about this same topic last week for iOS, which you can read here. Today I’ll give a brief overview of how you do that same thing with Android.

The idea is that there’s an object, like a module in Dagger, which contains all your dependencies. Any class that wants to use one of these dependencies will ask the module for it, and the module will provide it with a specific implementation. Finally, in the constructor of your classes that use these dependencies, you make their default value a call to this module. Let’s take a quick look:

First define a module (split modules up how you see fit) which contains your dependencies. Here’s just a mock I’ve made. This is in a file called DataModule.kt:

Each dependency is typed as an interface, and the returned implementation is something that conforms to that interface. If your dependency requires something be passed in, like a context, you can have a function instead, the function takes the parameter and passes it to the initialisation of the dependency.

Now say I have a class that wants that RoomDatabase dependency. I just define it requires it in the constructor of the object, and initialise it with a default value like so:

Now, in my unit tests, I can just override that value with something else when I create an instance of it. But in my actual code I can just initialise it with an empty constructor. For 99% of the projects I work on, doing dependency injection in this way is fantastic because you have no autogenerated code, no errors from kapt or Dagger when it can’t build, unit testing becomes a lot easier since, again, you don’t have to struggle with Dagger, and bringing more junior devs onto a project is a lot easier too. Dagger has a place, but for the majority of projects it’s such overkill and makes things so much more difficult than they need to be.