Slash Your Wiring Code With Dagger

May 07, 2013

I hate the wiring code that creeps in as my app grows. The SyncService needs an HttpClient and the AccountProfile needs a PhotoPicker. In each case I need either a difficult-to-test direct dependency, or to write a clumsy Factory thingy:

// Ew, boilerplate.
public class HttpClientFactory {
  private static HttpClient httpClient;

  public static synchronized void set(HttpClient httpClient) {
    HttpClientFactory.httpClient = httpClient;
  }

  public static synchronized HttpClient get() {
    if (httpClient == null) {
      httpClient = new DefaultHttpClient();
    }
    return httpClient;
  }
}

public class SyncService {
  HttpClient httpClient = HttpClientFactory.get();

  public void sync() {
    // The fun code starts here.
  }
}

Dependency injection is the solution to this problem. Instead of looking up the HttpClient from a factory or calling a specific constructor, I inject a field and let a framework take care of finding the implementation.

public class SyncService {
  @Inject HttpClient httpClient;

  public void sync() {
    // The fun code starts here.
  }
}

That @Inject annotation first showed up in Guice in 2007. Guice was created to power complex web apps like AdWords and Gmail. At Square we use Guice in all of our Java services. We also tried Guice in our Android apps, but it didn’t fit as well as we’d hoped.

Server apps enjoy heavy-duty hardware with lots of memory and processing power. Each process can run for weeks at a time and serve thousands of customers. If your process is going to run for 3 weeks, it doesn’t much matter if it takes a couple seconds to start up.

Mobile is the opposite: apps run on battery-powered hardware for minutes at a time. If the app doesn’t launch quickly, it might as well not launch at all. Nobody wants to wait for apps to boot up.

Dagger is a new dependency injector specifically optimized for Android and interactive Java apps:

  • It checks dependencies at compile time. This way you don’t wait for dependency validation every time you launch your app.
  • It generates code to avoid reflection, since that’s particularly slow on older Android VMs.

On one older device that we measured, switching to Dagger shaved seconds from our app's start up time. With our performance goals satisfied and a modest feature set that meets our needs, we're ready to promote a major release.

Dagger 1.0

Today we cut Dagger 1.0. If you want to chop boilerplate from your codebase, you should take a stab at dependency injection with Dagger.

The project website has a how-to guide, Maven information and downloads.

This post is part of Square's "Seven Days of Open Source" series.

Jesse Wilson
Seeker of pun and games in Waterloo, Canada.

Comments

Get support help at squareup.com/support. We'll delete off-topic comments.