Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Beside testing, why do we need Dagger 2?

At this point, my understanding of Dependency Injection (DI) is only from this article. I'm interested to try, but I just need to clarify some things:

  1. Many refer DI as a tool to reduce boilerplate code. But according to that tutorial, the setup of Dagger 2 tends to create even more classes for configuration (module and component). I have not tried it, but by the looks of it, it isn't reducing the code, it is just splitting them so the main class can look tidier. Am I wrong on this one?
  2. Despite Dagger 2's claim that DI isn't just for testing, many are regarding its usage mainly for testing, including Android's own guide. Have you used Dagger 2 in production-ready app? How useful has it been to you?
  3. If I am perfectly comfortable with traditional dependency creation via constructor and such, should I still need to look at Dagger 2? I feel like this library might have the power to change how I code the way RxJava does, I'm just not sure the benefit of it is as much as RxJava gave me.

I know, comparing Dagger to RxJava is like comparing apple to orange. But in a sense, they are both a fruit just like Dagger and RxJava are third-party libraries that might make my project larger.

like image 337
Hendra Anggrian Avatar asked Jan 27 '17 14:01

Hendra Anggrian


People also ask

Why do you use Dagger 2?

Dagger 2 walks through the dependency graph and generates code that is both easy to understand and trace, while also saving you from writing a large amount of boilerplate code you would normally need to write by hand to obtain references and pass them to other objects as dependencies.

What is the benefit of Dagger?

Benefits of using Dagger Dagger frees you from writing tedious and error-prone boilerplate code by: Generating the AppContainer code (application graph) that you manually implemented in the manual DI section. Creating factories for the classes available in the application graph.

What is the use of Dagger in Android?

In Android, you usually create a Dagger graph that lives in your application class because you want an instance of the graph to be in memory as long as the app is running. In this way, the graph is attached to the app lifecycle. In some cases, you might also want to have the application context available in the graph.

Is Dagger 2 deprecated?

It's officially deprecated and you can pretty much ignore it. Google's framework, which became dominant in Android ecosystem, was originally called Dagger 2. Sometimes we still refer to it as such, but, in most cases, we simply call it Dagger today.


2 Answers

You've combined two separate questions, which should be evaluated separately: "Why do we need dependency injection?" and "why do we need Dagger 2?"

Dependency injection (inversion of control) is useful because it allows the consumer of your component to provide your component's dependencies. Take a log formatter, for example: Without dependency injection you might need to write three different versions of your class that log to stdout, a remote server, or a text file. By comparison, if you were to write a LogFormatter that accepts a Writer to which it writes, then you could write it once and pass in whichever Writer is most appropriate, including a test double (a FakeWriter you make, or a StringWriter, or a mock-framework-created mockWriter instance) for testing. Though it's written for Guice instead of Dagger, I wrote a separate SO answer that talks about the value of dependency injection in production usage and also test cases; most of the tutorials you see will focus on tests under the presumption that "production" and "test" are the two cases you know about up front, where other opportunities for reuse and repurposing will present themselves later.

Once you embrace the modularity, reusability, and testability benefits that dependency injection provides you, you'll probably be left with one question: How do I manage these enormously-long constructors? After all, to carry forward the LogFormatter example, you wouldn't be able to write your Application without caring where the logs go to.

MyApplication application = new MyApplication(
    new LoggingService(new LogFormatter(new StdOutWriter())),
    new DatabaseService(new MyApplicationDatabase(new File("my.db"))),
    ...);

This is where Dagger shines: It lets you have all the benefits of dependency injection while automatically managing the constructors for you. This allows it to encapsulate the responsibility of creating objects and make it cleaner and safer, the way that RxJava can encapsulate the responsibility of managing and propagating asynchronous events and make it cleaner and safer.

It's important to realize that Dagger 2's reduction in boilerplate is in comparison to manual dependency injection, not the raw constructor invocations that you're comparing to. If you stick with calling new directly, you'll probably avoid much of this object construction boilerplate entirely, but you'll also find yourself going through difficult acrobatics trying to shard the work out to multiple developers or trying to test or reuse the code you've written. The collective pain is why dependency injection is so popular of a concept, and why libraries like Spring, Guice, and Dagger are gaining popularity.

I can vouch for the use of Dagger 2 in several particularly large, well-known, and well-used production Android applications. :)

like image 66
Jeff Bowman Avatar answered Oct 14 '22 18:10

Jeff Bowman


I have only used Dagger 1 but this might still help you in some way or another:

Dagger builds up a (D)irected (a)cyclic (g)raph (thats also where i the name comes from) with modules for different target applications.

So within one app project we were able to build four different apps, pretty similiar to Jake Wharton's u2020 app. All these apps had different targets. One was internal testing, one was for the testing team (with a screenshot function), one was internal release and the other one was release.

So why do we need four different apps here? The answer is: So we don`t have to have debug or test code in our release application and we can separate code that does not belong together.

if(currentMode == Mode.DEBUG){
  Timber.i(...);
}

Something like that is not necessary any more.

The screenshot functionality mentioned earlier, does not belong in the production code, so it was only in the testing code. When building an app, the framework used the correct module and injected it.

Note: I am sure there are other use cases for dagger than that.

EDIT: This will not change how you write code in a way RxJava does, but you have to use DI a lot in your modules.

like image 26
Stefan Lindner Avatar answered Oct 14 '22 17:10

Stefan Lindner