Dagger: Provide an example relevant to java/android instead of coffee brewing

Created on 13 Nov 2015  Â·  36Comments  Â·  Source: google/dagger

The awkward coffee example is quite confusing and it's difficult to relate to anything we do in Java or Android. It makes it hard to understand dagger and doesn't clearly indicate the advantages of dependency injection.

Surely, we want dagger to be accessible to a larger audience. Maybe we can find an example that makes sense in a context beyond coffee brewing? Perhaps something like SharedPrefences or a clear comparison of accomplishing the same task with and without dagger to illustrate it's advantage.

dagger-android documentation feature request

Most helpful comment

No need to be hostile and combative. Perhaps you should go inject a thermosiphon into your coffee maker and have a nice latte and relax.

All 36 comments

agreed! For as something as complicated as Dagger, good documentation is as important as the quality of the library itself.

I recommend that this example provide three things:

  • Injecting @ApplicationScope (or @Singleton) scoped dependencies.
  • Injecting @ActivityScope/@FragmentScope dependencies. (subcomponents/subscopes)
  • How to effectively override @Provides methods on both these scopes when testing

For testing, I find it particularly difficult to override the @Provides methods for subcomponents. If I normally inject something in onCreate(), I don't know how to access the instance of that activity/fragment before onCreate is called to change the injection behavior.

please :)

Instead of complaining you can submit a PR and community with maintainers
will review and improve it. This how OSS works!

On Fri, Nov 13, 2015, 19:30 Janusz BagiÅ„ski [email protected]
wrote:

please :)

—
Reply to this email directly or view it on GitHub
https://github.com/google/dagger/issues/262#issuecomment-156480360.

@artem_zin

Dagger is not for Android only, so your more Android specific examples can bring about more confusion than clarification.

I agree with @artem-zinnatullin there is no point complaining when you actually haven't made enough effort to learn it, dagger 2 has a great following and there are tones of materials online to learn from.

I'm not an expert in that matter :(

On Fri, Nov 13, 2015 at 4:37 PM, Artem Zinnatullin <[email protected]

wrote:

Instead of complaining you can submit a PR and community with maintainers
will review and improve it. This how OSS works!

On Fri, Nov 13, 2015, 19:30 Janusz BagiÅ„ski [email protected]
wrote:

please :)

—
Reply to this email directly or view it on GitHub
https://github.com/google/dagger/issues/262#issuecomment-156480360.

@artem_zin

—
Reply to this email directly or view it on GitHub
https://github.com/google/dagger/issues/262#issuecomment-156482024.

best regards,
Janusz Bartosz Bagiński
http://goo.gl/x3aQ9X http://goo.gl/I96hnC http://goo.gl/f4D3ZG
UK+44 (0) 7445 934 298PL+48 (0) 662 117 269

@dlew are you kidding? People need to understand what injectection is and to play with Dagger no less than a month before reading all that high-level examples.

No need to be hostile and combative. Perhaps you should go inject a thermosiphon into your coffee maker and have a nice latte and relax.

Sorry if I was "hostile" somehow, this was not my intention. I just want to say that people who didn't work with DI before, need to start from really simple things, like "what is DI?", "why do we need DI?", the simplest possible (and workable real-life) example, etc.

Here's a good video about why DI is useful: https://www.youtube.com/watch?v=hBVJbzAagfs

We definitely wrote the early documentation for the context of people who did know that they wanted dependency injection, since there are lots of "what is dependency injection" talks related to Spring and Guice which cover the concepts. But we're working on a fairly strong documentation overhaul, and it will include at least some introduction to the concepts, or a very clear call-out for where to read if you need more theory about DI.

Now that we've finally gotten the codeline synced out, and as we start syncing out docs updates, we'll be in a better position to take pull requests and interact more. I would ask that people do keep a bit of a civil tone. We know our documentation is not the greatest at present. We're working on it. :)

@konmik well the coffee maker example only relates to developers with coffee related jobs, catering to a smaller population already.

@konmik The question is about a sample in the context of Android, which is (I thought) exactly what u2020 provides. Sorry.

@littledot I don't have coffee in my programs. I have UI, network, storage, multithreading, event processing, etc. So despite the fact that coffee brewers are real, this is not a real-life example.

@sameb Looks good, but it is for Guice, so if one wants to study Dagger he need to study Guice first. They have a good example with twitter client.

@dlew Don't need to sorry, this is a very good example, but it is for advanced usage. :)

Hey guys, I also think that Dagger is awesome and it can have a much better spreading over Java developers than it has now if we could only break that hard-to-study barrier!

I'm not a dagger developer and I'm also not a native english-speaker, so I can not pretend to write official articles myself. But I have https://github.com/konmik/konmik.github.io/wiki/Snorkeling-with-Dagger-2, some find it to be useful for beginning. The main article idea is to be easily catchable by newcomers - goals of Dagger are visible, all terms have definitions, it has an easy-to-complex studying sequence, conceptual schemas, some "how it works" info, and examples are from real life. Feel free to reuse its plot / any parts of it.

No simple example will ever be a real life example. The power of the
library cannot be conveyed in something trivial, and thus the trivial
examples must be convoluted. The names in the coffee example might as well
be Gizmo, Trinket, Widget, and Fizzbang as they're just showing a
representative composition of how injection can be used rather than
introducing you to DI or even to the library.

On Fri, Nov 13, 2015 at 3:27 PM Konstantin Mikheev [email protected]
wrote:

@littledot https://github.com/littledot I don't have coffee in my
programs. I have UI, network, storage, multithreading, event processing,
etc. So despite the fact that coffee brewers are real, this is not a
real-life example.

@sameb https://github.com/sameb Looks good, but it is for Guice, so if
one wants to study Dagger he need to study Guice first. They have a good
example with twitter client.

@dlew https://github.com/dlew Don't need to sorry, this is a very good
example, but it is for advanced usage. :)

Hey guys, I also think that Dagger is awesome and it can have a much
better spreading over Java developers than it has now if we could only
break that hard-to-study barrier!

I'm not a dagger developer and I'm also not a native english-speaker, so I
can not pretend to write official articles myself. But I have
https://github.com/konmik/konmik.github.io/wiki/Snorkeling-with-Dagger-2,
some find it to be useful for beginning. The main article idea is to be
easily catchable by newcomers - goals of Dagger are visible, all terms have
definitions, it has an easy-to-complex studying sequence, conceptual
schemas, some "how it works" info, and examples are from real life. Feel
free to reuse its plot / any parts of it.

—
Reply to this email directly or view it on GitHub
https://github.com/google/dagger/issues/262#issuecomment-156547878.

@JakeWharton When you teach someone by example, you give him an example and you expect that the person will extrapolate the tools application to a more general use case.

The opposite happens _very_ rarely. Most of the times when people see an abstract example, they think "oh, it is too complex and I don't see how I can use it anyway" and leave.

This is why your U+2020 is so cool - it is a real life example that people can take as a pattern and extrapolate to their usage as they become more familiar with it. But most of us need a simpler real-life example, U+2020 is too complex for an average Java/Android developer.

But that's the fundamental problem here. Not only is Dagger high-leverage,
it's high-barrier of entry. This is especially compounded by the fact that
most don't what dependency injection is as a pattern before they look to a
library to solve the problem.

I'm not saying it's impossible, it's just that this example was never meant
to be for beginners. Focusing on it is the wrong approach because it's
actually a good example of all the features available. What this issue
should be about is a set of new and incremental examples which introduce
concepts instead of just showing them off.

On Fri, Nov 13, 2015, 3:47 PM Konstantin Mikheev [email protected]
wrote:

@JakeWharton https://github.com/JakeWharton When you teach someone by
example, you give him an example and you expect that the person will
extrapolate the tools application to a more general use case.

The opposite happens _very_ rarely. Most of the times when people see an
abstract example, they think "oh, it is too complex and I don't see how I
can use it anyway" and leave.

This is why your U+2020 is so cool - it is a real life example that people
can take as a pattern and extrapolate to their usage as they become more
familiar with it. But most of us need a simpler real-life example, U+2020
is too complex for an average Java/Android developer.

—
Reply to this email directly or view it on GitHub
https://github.com/google/dagger/issues/262#issuecomment-156552316.

@JakeWharton I absolutely agree that there should be small steps in studying. Smaller steps - more confidence. (Confidence + confidence) * confidence = knowledge.

What is wrong with the Twitter client example? If I remember properly, you also had it in some talks. I think it is real enough even for non-android users because it gives an idea about client-server communication most of us are familiar with.

I wish more people understood that it's okay to complain, or report a bug, even if you're not in a position to fix that problem yourself. As long as the report is constructive (which I think the initial request here was), it's still better than not reporting anything.

I completely agree that the coffee example is confusing. It's not easy to explain the value of Dagger but I'm sure we can come up with better examples than that. And yes, ideally, not an Android-centric one.

I think both Android and back end engineers alike can relate to an application that needs to make network calls and store data in a persistent storage. Maybe we can come up with an example around these concepts?

I wish more people understood that it's okay to complain, or report a bug, even if you're not in a position to fix that problem yourself.

Well, since I wrote:

Instead of complaining you can submit a PR and community with maintainers
will review and improve it. This how OSS works!

I had to describe why I did so. (I'm not a maintainer of this project, so my opinion may differ from theirs)

OSS users usually see maintainers as persons who _obligated_ to help everyone who uses their project. Every day I see how people post pieces of code from their projects and try to use maintainers as bug fixers. OSS is free and maintainers get no$thing for it, that's why you can find "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND in the LICENSE.txt.

On StackOverflow it's okay to ask: "How to …? I tried this, this and this.". But if you ask "How to …? Please paste me working code" your question can be closed without an answer because, literally you're asking somebody to do your work. And that's why StackOverflow still works (and reputation, of course, everyone wants to be on the top of the rating).

After a couple of articles and videos about DI, awkward Coffee example becomes understandable and at the same time abstract enough, so you are not tied to concrete details like networking/db/etc libraries and other APIs!

Considering the documentation of a library should include how to make it work at a basic level out of the box, I don't think this is a scenario similar to how the "how do I do XYZ" questions work on Stack Overflow - considering they tell you to google it, look it up, _have a glance at the documentation_ and put it together yourself first.

Now, if the documentation is not that helpful as it only tells you vaguely how to build a coffee brewer factory maker, then there's obviously an issue.

The current documentation doesn't address:

  • field injection method in component that allows for generating a MembersInjector in the generated DaggerComponent class (void inject(CoffeeApp coffeeApp);) and that you need to manually call that injector method if you cannot specify a @Inject constructor
  • how to define a custom scope on top of @Singleton, subscopes in subcomponents/component dependencies (how it works, what it's good for, what are its limitations - for example, component dependencies to multiple scoped components is disallowed, or that you need to specify provision methods to inherit the superscope dependencies from your component dependency).
    The documentation also doesn't explicitly specify that you need to put the scope on the @Provides method as well to get ScopedProvider<T>, or every instance you inject will be a new instance.
  • example Gradle configuration would be nice.

@aashrairavooru there is a valid reason to complain if you specifically need to look at other resources beyond the official documentation to _start out with the basic setup of a simple project_ using that library.

I would be remiss if I said initially picking up Dagger was easy.

On my first foray with the Coffee example, I personally wasn't able to relate to it at all, and actually had to search for what terms like Thermosiphon meant - this coming from a native English speaker. I fear for non-native speakers trying to pick up the example.

Difficulty with me being unable to fully understand the sample and lack of time led me to set the library aside for a couple of weeks until I could find a better example to wrap my head around. I had a vague understanding of the basic idea, the example just didn't _click_ with me due to all the unfamiliar terminologies being thrown around. I was finally able to understand it by reading some blog posts with better easier to understand examples as well as looking into some open source libraries (u2020 and some other cool informative open source android apps).

Thinking back to my (and probably most of us') first introduction to OOP, I'm pretty sure most of us can still vividly remember the simple but clear abstract example; describing it using the idea of Shapes, inheriting and overriding Shape attributes as well as overriding its functions like draw() and name(). This what I think Dagger is missing and is the main cause of the initial hard barrier to entry.

I think having a more general use case example like building a complex Car object using dependency injection might be something a lot of people might find easier to wrap their heads around.

Like @JakeWharton said, there's really nothing wrong with adding more samples.
I just think it would be nicer to have a more relatable sample first for people to get their front foot in the door so to speak. And then for more advanced developers yearning for more, they can look into the Coffee-brewing example.

There are couple of different issues raised here.

First is vocabulary. It could be better, without a doubt. Unless you're a coffee-hipster it's unlikely you've ever heard about a thermosiphon.

Second thing is that unless you already have some experience with different DI frameworks you'll have a hard time learning Dagger using its current documentation. DI can really look like a time waster if you don't understand the context. I did a quick overview of how other DI libraries handle this issue and I really liked the Guice's approach: https://github.com/google/guice/wiki/Motivation.

Idea is simple. They show you a problem, then they show you a non-DI solution and then a DI solution, which is much cleaner. I believe Dagger needs something similar. Still, I believe the complexity of a Guice's sample could still be lower.

I was thinking about it for a while and I have an idea of a LED banner system. Imagine a LED banner at the restaurant's entrance, greeting its guests with different messages, depending on a context (e.g. "Good Morning" in the mornings and "Good Evening" in the evenings). If you try to model it in an OOP-way you may get something like this:

class Banner {
  @Inject Banner() { }
  void display(String message) {
    // some fuzzy assembly here
  }
}
class Greeter {

  private final Banner banner;
  private final String message;

  @Inject Greeter(Banner banner, String message) {
    this.banner = banner;
    this.message = message;
  }

  void greet() {
    banner.display(message);
  }
}
class Application {
  public static void main(String[] args) {
    // Dagger stuff here
    greeter.greet();
  }
}

Think about it.

  • Unlike a thermosiphon everyone saw a LED banner at least once in their lives.
  • It presents a constructor-based injection (Greeter, Banner)
  • It shows a usecase for a @Module and @Provides. You can't annotate String's constructor with @Inject.
  • It's easy to prove DI meaningfulness using this one. You probably want to test Greeter. And if you do, you probably want to mock Banner out. Perfect match for a motivational page!
  • You can build a story upon this. Like your non-coding friend having a restaurant needing your help. Then you can build some more-complex scenarios based on that story, so you can show some more complex mechanisms, like scopes.

PS: I'm totally against putting some Android-specific stuff in samples. For someone who's not into Android, SharedPreferences is even more enigmatic than Thermosiphon.

I'm totally against putting some Android-specific stuff in samples

The complexity of the Android application/activity lifecycle definitely needs to be taken into account. This is because the framework is in control of how activities/fragments/views are instantiated, which makes the process much more complicated. Android doesn't have to be the ONLY example, but definitely should be in there as an additional resource.

First is vocabulary. It could be better, without a doubt. Unless you're a coffee-hipster it's unlikely you've ever heard about a thermosiphon.

I think the car/engine example would be more universally understand. Jake's twitter example was good too.

This is loosely related, but the Android examples in /examples still contain a warning that they may not reflect recommended Dagger 2 patterns. An update was already requested in https://github.com/google/dagger/issues/176.

Vetting the examples then removing the warning, and slightly fleshing out one of those examples with an implementation of SharedPreferences or an SQLiteOpenHelper singleton, might go a small way to improving Android-related documentation. Indeed @cgruber left this comment // TODO(cgruber): Figure out a better example of something one might inject into the app in the android-activity-graphs example.

(Would also like to see a build.gradle added to the examples to help people understand where to source @Inject annotation as I understand there are multiple options, and many tutorials recommend org.glassfish:javax.annotation:10.0-b28 over javax.annotation:jsr250-api. I don't know enough to say why.)

@Inject comes from jsr330 whose dependency comes transitively (and thus
automatically) from dagger-runtime.

On Wed, Nov 18, 2015 at 5:21 PM Matthew Haughton [email protected]
wrote:

This is loosely related, but the Android examples in /examples still
contain a warning that they may not reflect recommended Dagger 2 patterns.
An update was already requested in #176
https://github.com/google/dagger/issues/176.

Vetting the examples then removing the warning, and slightly fleshing out
one of those examples with an implementation of SharedPreferences or an
SQLiteOpenHelper singleton, might go a small way to improving
Android-related documentation. Indeed @cgruber
https://github.com/cgruber left this comment // TODO(cgruber): Figure
out a better example of something one might inject into the app in the
android-activity-graphs example.

(Would also like to see a build.gradle added to the examples to help
people understand where to source @Inject annotation as I understand
there are multiple options, and many tutorials recommend
org.glassfish:javax.annotation:10.0-b28 over javax.annotation:jsr250-api.
I don't know enough to say why.)

—
Reply to this email directly or view it on GitHub
https://github.com/google/dagger/issues/262#issuecomment-157883440.

OK thanks. But I come full circle because if I remove javax.annotation:jsr250-api from build.gradle I get error: cannot find symbol class Generated because of Dagger's @Generated annotation in the generated code.

Then I found https://github.com/google/dagger/issues/95#issuecomment-67360117 where you said you'll always need to add the Glassfish dependency org.glassfish:javax.annotation on Android because its API doesn't support the annotation, then someone asks "why not use javax.annotation:jsr250-api?"...

So back it goes into build.gradle. Which is fine, it would just be good if this were officially documented by the project, or mentioned in the example projects.

We are working on better documentation, including for Android. And @gk5885 is working on better example applications.

Excellent.

My biggest request is a recommendation on how to manage sub-scopes on Android. Dagger is a breeze to use when you just store a singleton component in your Application, but it gets more complicated as you get down into an activity/fragment/scope. And then testing it.

Thanks!

@Zhuinden here's my problem.

Your activity calls onCreate(), which calls createComponent(). Then the activity lifecycle continues and data is loaded (likely within onStart() etc etc.

Because of the way Espresso works, once I call activityRule.launchActivity(), onCreate(), onStart() etc are all called. I have no easy way to swap out the component being used to load the data after the activity is launched but BEFORE onStart() is called. Once the activity has settled I can swap out the component, but the data has already been loaded by then.

tl;dr: I want to easily change the component that is provided by this method on a per test basis

protected StripeComponent createComponent(CustomApplication application) {
    return DaggerStripeComponent.builder()
            .applicationComponent(application.getApplicationComponent())
            .build();
}

Here's my experimental and minimum example https://github.com/kirisetsz/another-dagger2-android-example which should be a nice explanation about how to implement a DI pattern with dagger2 on Android.

I think I have picked up the idea of DI, but have no idea about whether I have chosen an appropriate name for abstractions :laughing: welcome to discuss your idea about it. And If that's the right way using dagger2 on android, there should be a helper library do something similar like the example does.

Any news about this one? It's been a while

Damn. Has it really been three years?

Any news about this one? It's been a while

OP here. My news is that I just had to suck it up and learn it the hard way 💪

Damn. Has it really been three years?

That's how I feel every day :smile:

Jokes aside, they really did make the docs better since.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

sagarwaghmare07 picture sagarwaghmare07  Â·  3Comments

pedrovarela86 picture pedrovarela86  Â·  3Comments

JakeWharton picture JakeWharton  Â·  3Comments

blackberry2016 picture blackberry2016  Â·  3Comments

SAGARSURI picture SAGARSURI  Â·  3Comments