We felt the code we were working on was in danger of getting out of hand. In particular we found ourselves passing a lot of parameters through methods or classes as they were dependencies of objects being used or created deeper in the stack. Testability was suffering as objects and methods were becoming tightly coupled and we were ending up using excessive numbers of mocks & test doubles.
A pet hate of mine is having lots of noise in tests. It makes test maintenance really difficult later when it’s hard to remember which bits of setup are really relevant to the scenario under test.
We felt that dependency injection would be a big help. Unfortunately we’re working on, of all things, an applet. Yeah, I know, 1995 called and wants its web technology back. Suffice to say we have our reasons. The technology may be a little old skool but it’s an interesting scenario in that size is a constraint. We can’t afford to integrate a large library or a big dependency graph. Spring is right out & even the comparatively lightweight Guice is a 544K jar.
We’d both recently seen tweets about Dagger and decided to take a look. As I understand it Dagger targets Android development so similar size concerns apply. Although it’s pre 1.0 right now we quickly found that Dagger is pretty capable. We were able to add annotations to our classes to define dependencies, create a class annotated with
@Module to provide those dependencies that needed special handling and inject
Provider instances into classes that need to construct new instances of objects that have their own dependencies.
We soon got to the point where we started to see things coming together as we were simplifying objects, removing coupling and deleting noise from tests.
Some Dagger features I really liked:
There’s no XML or incomprehensible stringly-typed DSLs to deal with.
Tests aren’t dependent on Dagger and unit-level tests can usually ignore it completely.
When you do want to use Dagger in a test it’s easy to extend the
Modulewith test doubles standing in for some objects.
Unsatisfied dependencies & other problems are reported at compile time.
It’s only necessary to define things in the
Modulewhen they can’t be constructed automatically by Dagger or need to be specific object instances (such as the applet itself in our scenario).
Vis some kind of domain object that has dependencies of its own means the class using the
Providerdoesn’t need to know anything about the dependencies of
Vin order to construct new instances.
Best of all Dagger is only 81K and has a single dependency on the
javax.inject framework (adding another 2.4K).