Archive for August, 2012

Advanced dependency injection with Guice

The more I use dependency injection (DI) in my code, the more it alters the way I see both my design and implementation. Injection is so convenient and powerful that you end up wanting to make sure you use it as often as you can. And as it turns out, you can use it in many, many places.

Let’s cover briefly the most obvious scenarios where DI, and more specifically, Guice, are a good fit: objects created either at class loading time or very early in your application. These two aspects are covered by either direct injection or by providers, which allow you to start building some of your object graph before you can inject more objects. I won’t go too much in details about these two use cases since they are explained in pretty much any Guice tutorial you can find on the net.

Once the injector has created your graph of objects, you are pretty much back to normal and instantiating your “runtime objects” (the objects you create during the life time of your application) the normal way, most likely with “new” or factories. However, you will quickly start noticing that you need some runtime information to create these objects, other parts of them could be injected.

Let’s take the following example: we have a GeoService interface that provides various geolocation functions, such as telling you if two addresses are close to each other:

public interface GeoService {
/**
* @return true if the two addresses are within @param{miles}
* miles of each other.
*/
    boolean isNear(Address address1, Address address2, int miles);
}

Then you have a Person class which uses this service and also needs a name and an address to be instantiated:

  public class Person {    // Fields omitted
    public Person(String name, Address address, GeoService gs) {
      this.name = name;
      this.address = address;
      this.geoService = gs;
    }
    public boolean livesNear(Person otherPerson) {
      return geoService.isNear(address, otherPerson.getAddress(), 2 /* miles */);
    }
  }

Something odd should jump at you right away with this class: while name and address are part of the identity of a Person object, the presence of the GeoService instance in it feels wrong. The service is a singleton that is created on start up, so a perfect candidate to be injected, but how can I achieve the creation of a Person object when some of its information is supplied by Guice and the other part by myself?

Guice gives you a very elegant and flexible way to implement this scenario with “assisted injection”.

The first step is to define a factory for our objects that represents exactly how we want to create them:

public interface PersonFactory {
  Person create(String name, Address address);
}

Since only name and address participate in the identity of our Person objects, these are the only parameters we need to construct our objects. The other parameters should be supplied by Guice so we modify our Person constructor to let Guice know:

  @Inject
  private Person(@Assisted String name, @Assisted Address address,
      GeoService geoService) {
    this.name = name;
    this.address = address;
    this.geoService = geoService;
  }

In this code, I have added an @Inject annotation on the constructor and an @Assisted annotation on each parameter that I will be providing. Guice will take care of injecting the rest. Note that I also made this constructor private, so that nobody (except Guice) will ever be able to call it. This is what we want, since this constructor contains private information that callers should never know about.

Finally, we connect the factory to its objects when creating the module:

    Module module1 = new FactoryModuleBuilder()
        .build(PersonFactory.class);

The important part here is to realize that we will never instantiate PersonFactory: Guice will. From now on, all we need to do whenever we want to instantiate a Person object is to ask Guice to hand us a factory:

@Inject
private PersonFactory personFactory;
// ...
Person p = personFactory.create("Bob", new Address("1 Ocean st"));

If you want to find out more, take a look at the main documentation for assisted injection, which explains how to support overloaded constructors and also how to create different kinds of objects within the same factory.

Wrapping up

Let’s take a look at what we did. First, we started with a suspicious looking constructor:

public Person(String name, Address address, GeoService s) {

This constructor is suspicious because it accepts parameters that do not participate in the identity of the object (you won’t use the GeoService parameter when calculating the hash code of a Person object). Instead, we replaced this constructor with a factory that only accepts identity fields:

public interface PersonFactory {
  Person create(String name, Address address);
}

and we let Guice’s assisted injection take care of creating a fully formed object for us. By doing so, we have also maximized encapsulation by making sure that private implementation details of the class are never leaked outside of that class.

This observation leads us to the Identity Constructor rule:

If a constructor accepts parameters that are not used to define the identity of the objects, consider injecting these parameters.

Once you start looking at your objects with this rule in mind, you will be surprised to find out how many of them can benefit from assisted injection.

A note on null pointers

It’s the second time in a few weeks that I have read something along the lines of:

In a year at foursquare, I’ve seen exactly one null pointer exception.

To me, this kind of statement is similar to

Ever since I switched to BASIC, I haven’t seen a single stack trace.

and it shows a fundamental misunderstanding of what a programming error is. Similarly, hearing Tony Hoare say that introducing null was a “one billion dollar mistake” makes me really question if he understands the fundamental idea behind crashes.

Null pointer exceptions, stack traces, core dumps, guru meditations, etc… are usually all the manifestation of a simple phenomenon: unexpected values. Somehow, your code expected a value but received another one. This is a programming error, also known as a bug.

If you are using a language that supports monadic Option/Maybe types, by definition, you will not be seeing any null pointer exceptions, but this doesn’t mean that you have solved the “unexpected value” problem.

In languages such as Java or C, null pointers translate into crashes that are hard to miss and usually easy to diagnose. What would be the equivalent of this in Scala?

The answer is easy: receiving a None when you expected a Some. Because of the way you thread monads through your functions, such a bug will not trigger any exceptions nor any crash: your None value will happily make its way through monadic transforms and will simply result in a no-op every time it’s being mapped. Of course, your program will yield an unexpected value that you will take notice of at some point, and then you will have to go through the painful process of retracing all the Options that your transformations have gone through to find out which one returned None when it should have returned a Some.

At this point, you should probably ask yourself: if this piece of code should never return a None, why return an Option at all? In such cases, you are better off unboxing your Option and returning its raw value. Of course, the downside of this is that you might have to lift your value again if the following computations happen in the Option monad as well.

As you can see, Options come with their own trade offs and hard design decisions as well. No such thing as a free lunch.

Which leads us to the next big misconception about this class: Option doesn’t solve null pointer exceptions nor unexpected values, it just saves you from having to test against null. And actually, doing so (e.g. pattern matching your option against Some/None) is usually considered bad practice, even though it’s sometimes necessary for Java interoperability reasons.

Personally, I favor the way Groovy, Fantom and Kotlin address the problem over having to lift all my values into Option. For example, here is how Kotlin lets you ignore null values encountered along a chain of invocations:

bob?.department?.head?.name

If either of these accesses returns null, the result of this expression will be null. No need to put your values into monadic boxes nor mapping through them, just use the standard composition operator you are familiar with if you are using a C family language.

By all means, do use Option whenever you can if you are programming in Scala (and you will probably realize that you can’t use it as much as you would like because Java libraries, and some Scala ones, are just not implemented to take Option parameters), but don’t listen to people who tell you that because you are no longer seeing any null pointer exceptions, your code is safer. It’s not. You still have to fix your bugs.