David Green is a developer and aspiring software craftsman. He has been programming for 20 years but only getting paid to do it for the last 10; in that time he has worked for a variety of companies from small start-ups to global enterprises. David co-founded the London Software Craftsmanship Community (http://www.londonswcraft.com/) - a group of professional programmers who meet regularly to exchange ideas and improve their craft. David is a DZone MVB and is not an employee of DZone and has posted 25 posts at DZone. You can read more from them at their website. View Full User Profile

I Can Haz Dependencies?

09.09.2012
| 6968 views |
  • submit to reddit

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.

 

Published at DZone with permission of David Green, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Michal Xorty replied on Mon, 2012/09/10 - 12:21pm

Hmmm not sure if this article is ironic or retarted. If you're serious then happy constructing object graphs manually I hope you enjoy it especially with loads of legacy services :D

Lund Wolfe replied on Sun, 2012/09/09 - 1:45am

Agreed.  Keep It Simple Stupid.  IOC is useful when you have more than one implementation of an interface that isn't obvious to runtime code.  It can also be useful when you need a test implementation or stubs for parallel development.  99.9% of the time, though, You Aren't Gonna Need It.

It's nice to be extensible, but don't be extensible in the wrong direction.  The next developer might not know the application and the requirements as well as you so don't make it easy for them to fail.  If four dependencies are really one, then make it clear that it is one.

Xavier Dury replied on Sun, 2012/09/09 - 11:12am

Funny, your ICanHaz* interfaces look a lot like Spring's *Aware interfaces...

Jonathan Fisher replied on Mon, 2012/09/10 - 12:12am

I was about to to say the same thing as Xavier... Spring and IOC _are_ being abused by overzealous architects. Used minimally, they are an amazing tool.

Andreas Schilling replied on Mon, 2012/09/10 - 1:14am

well, I *do* understand where your point comes from, but as usual I wouldn't blame the frameworks.

if people can't use the tools it's not necessarily the tools but the people that cause the problem. you also can kill someone with a kitchen knife.

to me, the usage of a IoC container helps me to think more about the structure and the dependencies of my classes without having to care about the nasty crap around it or, to put it short, it helps me to write more modular and better designed software. yes, if I would also start using dependency injection on plain domain objects now, then it would be the time to better stop and think about it a second time.

but in general my observation is that projects that don't use DI end up with huge classes and a totally non-modular structure because as you already said, people are lazy. and lazy people don't like writing manual DI crap

neither do I. that's why I use an IoC container.

David Cypers replied on Mon, 2012/09/10 - 5:01am in response to: Andreas Schilling

I completely agree with Andreas. You can't blame the tool for being misused.

Bozhidar Bozhanov replied on Mon, 2012/09/10 - 5:37am

So, "do the same, but harder, so that you can't misuse a given framework"? I disagree. (related blog post of mine)

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.