We’ve been /web/20101225105933/http://code.google.com/p/google-guice/[Guicing up] XPay for a couple weeks. For those not familiar with Guice, it is a /web/20101225105933/http://en.wikipedia.org/wiki/Dependency_injection[dependency injection] framework.

Guice in Ten Seconds

You annotate your classes types’ primary constructors, create “modules” which bind concrete types or singleton instances to interface and abstract types, then ask Guice to create you one of some type. Guice will automatically create all dependencies (constructor parameters) for that type before invoking the primary constructor, and if any of those types require dependencies create those first, and so forth. For example, if your class Foo needs some kind of PackagingStrategy (presumably an interface) passed to its constructor, and your module binds PackagingStrategy.class to BinaryPackagingStrategy.class, then when you ask Guice for an instance of Foo, it will create a new BinaryPackagingStrategy, “newing up” its constructor parameters recursively, and pass this to Foo‘s constructor.

The benefits of this scheme are in the class of “hard to describe, but definitely there.” First and foremost, it improves system design, making interfaces clearer and more self-documenting by removing hidden dependencies on things like Singletons and Monostates. This improves testability because mucking with the global state encapsulated in Singleton and Monostate patterns requires a much deeper knowledge of classes under test and some often-shady practices. Without a good DI framework, passing a dependency down several layers of object graph is complicated and provides extra coupling, making the Singleton pattern much more attractive. With the DI framework, there’s really no inclination to make the dependency of a class anything other than a constructor parameter.

But, More Boilerplate?

There’s plenty of boilerplate that Guice removes, mostly in the “bean wiring” category, and this is good. Interestingly, there are areas in which I’ve found myself writing more boilerplate with Guice, and an instance of this is what I’d like to discuss today.

I work with some people who have become thoroughly disgusted with OOP and advocate for functional style with immutable data types. I appreciate functional style with immutable data types, but I must say that the /web/20101225105933/http://en.wikipedia.org/wiki/Strategy_pattern[Strategy pattern] is something OOP does well and not something that FP does nearly as well. I tend to use strategy pattern quite a bit in our XPay (and in our C++ product, DAS). One reason to /web/20101225105933/http://c2.com/cgi/wiki?SwitchStatementsSmell[prefer Strategy pattern to switch statements] is to have a single point of control over which strategy implementation to use. This use case usually conjures itself into being in a /web/20101225105933/http://en.wikipedia.org/wiki/Factory_method_pattern[Factory method pattern] which has the single switch statement which provides an instance of the concrete type based on input parameters.

In Guice, you can inject a Provider<Foo> and Guice will automatically create a type that produces instances of Foo. This is useful for dependencies. So our factory ends up looking something like this:

class FooFactory {

    private final Provider<TypeAFoo> typeAFooProvider;
    private final Provider<TypeBFoo> typeBFooProvider;
    private final Provider<TypeCAFoo> typeCAFooProvider;
    private final Provider<TypeCBFoo> typeCBFooProvider;
    private final Provider<TypeDFoo> typeDFooProvider;
    private final Provider<TypeEFoo> typeEFooProvider;

    @Inject
    public FooFactory(
            final Provider<TypeAFoo> typeAFooProvider,
            final Provider<TypeBFoo> typeBFooProvider,
            final Provider<TypeCAFoo> typeCAFooProvider,
            final Provider<TypeCBFoo> typeCBFooProvider,
            final Provider<TypeDFoo> typeDFooProvider,
            final Provider<TypeEFoo> typeEFooProvider
            )
    {
        this.typeAFooProvider = typeAFooProvider;
        this.typeBFooProvider = typeBFooProvider;
        this.typeCAFooProvider = typeCAFooProvider;
        this.typeCBFooProvider = typeCBFooProvider;
        this.typeDFooProvider = typeDFooProvider;
        this.typeEFooProvider = typeEFooProvider;
    }

    public Foo get(char type, boolean inverted) {
        switch (type) {
        case 'A':
            return typeAFooProvider.get();
        case 'B':
            return typeBFooProvider.get();
        case 'C':
            if (inverted)
                return typeCAFooProvider.get();
            else
                return typeCBFooProvider.get();
        case 'D':
            return typeBFooProvider.get();
        case 'E':
            return typeBFooProvider.get();
        default:
            throw new FooFactoryException("Can't determine type.");
        }
    }
};

Ugh!

This is “better” boilerplate than the bean wiring before in that it hints that we might be able to concoct a general solution; however, I haven’t yet found it. One solution which I’ve rejected is the “injecting an injector” solution:

class FooFactory {

    private final Injector injector;

    @Inject
    public FooFactory(final Injector injector) {
         this.injector = injector;
    }
    public Foo get(char type, boolean inverted) {
        switch (type) {
        case 'A':
            return injector.createInstance(TypeAFoo.class);
        case 'B':
            return injector.createInstance(TypeBFoo.class);
        case 'C':
            if (inverted)
                return injector.createInstance(TypeCAFoo.class);
            else
                return injector.createInstance(TypeCBFoo.class);
        case 'D':
            return injector.createInstance(TypeDFoo.class);
        case 'E':
            return injector.createInstance(TypeEFoo.class);
        default:
            throw new FooFactoryException("Can't determine type.");
        }
    }
};

The reason I’ve rejected this approach is that it prevents Guice from checking the entire dependency graph at boot – Guice doesn’t know which types you are going to create with the injector, and this has to defeat a lot of it’s validation magic.