I can haz dependencies?

I hate IoC containers. Spring? Evil. Guice? The devil’s own work. Why? Because it leads to such slack, lazy, thoughtless programming.

Why the hate?

Ok, perhaps I better explain myself a bit. IoC is a great idea. What annoys me, is the way IoC frameworks end up getting used by normal people. I’ve ranted previously about how IoC containers lead us to implement anaemic domain models. The trouble is, once you have a hammer, everything starts to look like a nail. Especially those pesky fingers. Once you have a dependency injection framework, everything starts to look like a dependency that needs to be injected. Need to implement some business logic? First create a new class, test drive it, then make it injectable, inject it into the class where the calling code needs it, test driving it natch, then bingo – you just hit yourself on the finger.

Now I’ve got two classes, basically closely coupled, but the IoC container hides that fact from me. I see a nice, clean interface being injected in. Aren’t I a good little OO developer? No, you’re stupid and you’re lazy.

Before you know it, your class has a dozen or more dependencies, each of which have a dozen dependencies, each of which have a dozen dependencies, each of which… you get the picture. You’ve managed to build a rats nest of a dependency graph, little by little. What you’ve TDD’d isn’t a design. The technical name for it is The Big Ball of Mud.

An Alternative

Instead, I think dependency injection works best at application seams, at architectural boundaries. Say, for example, you’re building a web app. You’ve created a TradeEntryController that allows users to, well, enter trades. The TradeEntryController naturally has loads of dependencies on the rest of the system. It needs to fetch valid assets to invest in and prices, it needs to know what your balance is so you can’t buy more shares than money in the bank etc etc. A perfect example where life without an IoC container could become really cumbersome.

But, I don’t think you need one. I think what your controller needs is a few, specific dependencies – that define the architectural boundary the controller lives within. Above the controller is a HTTP request, a session and all that blah blah. Within it, is business logic. Below it is the database. So, the dependencies we inject should represent only the architectural context in which the controller operates. For the most part, this will be common to all my controllers – not just trade entry. Controllers for managing balances, lists of assets, user accounts – these all depend on knowing stuff about their session, and to be able to talk to the next layer down: the database (or in an n-tier setup, perhaps some web services).

So, why not just inject those dependencies?

public class TradeEntryController {
    public void setSessionManager(ISessionManager sessionManager) { ... }
    public void setTradeDatabase(ITradeDatabase tradeDatabase) { ... }
    public void setAccountDatabase(IAccountDatabase accountDatabase) { ... }
    public void setAssetDatabase(IAssetDatabase assetDatabase) { ... }
}

Then in my controller, I can fetch user information from the SessionManager; I can get the list of assets from the AssetDatabase; I can check the user’s balance via the AccountDatabase; and I can record the trade via the TradeDatabase. So far, so much the same as a normal IoC container.

So what’s different?

Rather than manage these dependencies via an IoC container. I think you should push them in manually. Yes, I’m suggesting you write your own dead simple dependency injection framework. What? Am I mad? Quite probably, but bear with me.

public interface ICanHazTradeDatabase {
    void setTradeDatabase(ITradeDatabase tradeDatabase);
}

public class TradeEntryController
    implements ICanHazTradeDatabase, ICanHazAssetDatabase...
{
    ...
}

public class ControllerFactory {
    public Controller createController(Class clazz) {
        Controller c = clazz.newInstance();
        if (c instanceof ICanHazTradeDatabase)
            ((ICanHazTradeDatabase) c).setTradeDatabase(tradeDatabase);
        if (c instanceof ICanHazAssetDatabase)
            ((ICanHazAssetDatabase) c).setAssetDatabase(assetDatabase);
        if ...

        return c;
    }
}

The exact mechanics of ControllerFactory of course depend on your MVC framework, but hopefully the idea is clear: when we instantiate a controller, we check it against a known set of interfaces and push in very specific dependencies. Is it pretty? Not really. Is it easy to write? Of course. Does it push dependencies into your controller? Well, yes. Where do they come from? Well, that’s an exercise for the reader. But I’m sure you can find a way to make ControllerFactory a singleton and instantiate all your dependencies in one place.

The Point

What, exactly, is the point of all this? Well, as a developer writing a controller – I can get easy access to all the dependencies that represent the architectural context I’m running within. The databases, services, message brokers, email server, blah blah blah that the application as a whole depends on. They’re right there – I just add the interface, one method and bang – ICanHazCheeseburger.

More interesting, is what I can’t do. I can’t decide that my TradeEntryController needs a TradePricingCalculator and inject that as a dependency. Well, I could, but I’d be making TradePricingCalculator available everywhere, and I’ve got a little more work to do than I would if I was using plain old Spring or Guice – I’ve an interface to create, a couple of lines to add to some scarily named GlobalControllerFactory. Why is this important? It adds some friction. It makes something bad hard to do. I’m forced instead to think about creating a TradePrices object and adding some functionality to it. I’m forced to have a rich domain, because I can’t just move all my functionality off into a TradePriceCalculatorVisitorFactoryManagerBuilder.

The choices we make and the technologies we choose make some things easy and other things hard. We need to think carefully about whether the things we make easy should be easy. It’s always possible to do the right thing, but sometimes we need to make it easier than doing the wrong thing.

9 thoughts on “I can haz dependencies?

  1. Good read, thanks David.

    However, I disagree with your premise. “Slack, lazy, thoughtless programming” doesn’t come from IoC containers, it comes from slack, lazy thoughtless programmers. Granted, that description is relative, and may describe any of us on our off days, or when a deadline is looming, or when we’re still learning.

    I believe there is friction that’s provided with automatic dependency injection, and that is your unit tests. When you: have to pass too many parameters; or the parameters you pass are often null because the code path leaves them untouched; or you extract a method in your test to construct the object, that is your tests telling you there’s something wrong with the design. Instead of abusing IoC containers, listen to the tests, take their feedback on board, and rethink your design.

    Now, you can always ignore your tests. Just like you could merrily get your IoC container to give you countless dependencies. Or, if there’s too much friction, you could just use global state, like static maps or a ThreadLocal. Yuk. I’d much prefer many injected dependencies over many hidden dependencies with global state.

    You are right, many injected dependencies are a smell, but I posit your anger at the tools is misdirected, because they are being misused. By listening to your tests, you get the best of both worlds: the friction to notice a bad design, and the IoC tools that get rid of factory boilerplate.

    Hope all is well with you 🙂

    1. Hehe quite right – slack, lazy, thoughtless programmers (i.e. me, on a bad day) only have themselves to blame. For me the trouble is, I’ve seen teams explain away “well, we’ve already got 15 constructor params, what does it matter if we add another?” – despite the tests screaming that it’s not right. So for me, I don’t think tests are enough friction. You can add code style rules, then developers disable them. Whatever you do, you can always subvert it. It’s a tough balancing act to encourage “correct” behaviour and discourage “incorrect” behaviour – I just think some tools make it too easy to do the wrong thing faster.

  2. Sandro and I spent some time arguing about this at SoCraTes. I mostly agree with you. I prefer writing out my dependencies manually rather than using a container because it lets me easily visualise what works with what, both in a concrete and an abstract sense. It can get pretty long if you’re not careful, but more and more I feel that that’s just telling you to break out another service and define an API.

    1. Exactly – explicit is good. If your dependencies are getting so hard to manage that you need a container to do it – that’s a smell – you must have a bigger design problem to fix.

  3. Great post David. Totally agree!! More course grained IoC is good to help isolate systems for testing etc, but abstracting and injecting at nearly every layer is totally over the top.

    I remember once pulling my hair out trying to work out what the hell was going on in an app that was using CDI. I worked it out in the end, but only after reading big parts of the CDI spec and pulling out some more hair. Sure CDI made the code look a bit cleaner. If I was just trying to read the code out of curiosity, to get a “general idea” of what was going on, then CDI did a good job making the code easier to read. But once I tried actually “working” with the code I needed to get a debugger and the spec to work out wtf was going on…. grrrrrrrrr. That to me is a maintenance nightmare and is what happens when you remove too much context from the code and hide it away in fancy containers and frameworks that work reflective magic in the background !!

    In general (not just IoC containers), I think some people are more often attracted to frameworks/containers more because of the “coolness” factor associated with them Vs the problem they have and how the framework helps them solve it in a maintainable way.

    1. Thanks! I think you’re dead right. Especially when frameworks have lots of magic – “look ma, no code”. And then when I need to debug it? Great, oodles and oodles of arcane reflective black magic.

      1. Jonas

        This statement alone cheered me up for this afternoon – lol. And I’m glad to see that someone working on something different than me now, has gravitated towards the same mindset on IoC, and the same kind of design as I want to give a go going forwards.

      2. Hey Jonas, glad it made you smile! It’s funny how I think there’s a general movement away from these over-arching frameworks again now – and magic-ful reflection heavy frameworks especially.

  4. I’m inclined to agree that IoC / DI frameworks are easy to abuse and can send you down the rabbit hole of turning everything into a dependency that needs to be injected leading to bad design. As a relative newcomer to DI I find I prefer to use it sparingly. I recently discovered the ServiceLoader mechanism in Java and believe it is a very useful tool for simple ‘provider’ style DI.

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.