DI Sucks! -or- My Language Is Better Than Yours

This post was originally going to be an anti-dependency injection framework post, motivated by “Dependency Injection is a Virtue”, but then I read the article that prompted that post by David “DHH” Heinemeier Hansson, of course titled “Dependency Injection is not a Virtue”. And then I didn’t know what to write about.

DHH’s article on first read comes across as kind of a “Ha, Java sucks so much that you have to do terrible things to make it testable. Look at the awesomeness of Ruby!” And maybe I’m misreading it or this wasn’t the author’s intention, but it finishes with a subtle note of “Being a Ruby Programmer is better than being a Java Programmer”. Both very bold statements, and I’m not sure how I feel about them.

Languages as Tools

As I’ve said before, programming languages, design patterns, frameworks, all these things are just tools. We are all software developers with various skills, and some of us specialize in a certain set of tools compared to others. Of course using those tools is going to give us a bias towards the types of problems they solve. But the key is to know what tool to use, and identify that you might not have the most efficient tool for the job. That doesn’t make you a worse developer than someone else. In fact if you can reliably offer that kind of ‘tool analysis’ and be able to admit that the tool you use might not be well equipped to deal with a problem, you’re probably better than most developers.

And just like any tool a craftsperson might use, each comes with its own set of requirements and limitations. A power saw requires power, whereas a hacksaw doesn’t. Java requires statically defined class definitions, whereas Ruby doesn’t. Does this make Ruby a better language? No, it’s just a tool with a certain set of requirements that’s designed to solve a certain set of problems.

Oh Yeah, My Original Point!

Back to my original dependency injection rant: I’m personally not a fan. I haven’t really seen a case yet where implementing a DI framework is really justified. Sure, it’s a great idea in theory, but in practice having several implementations of an interface just doesn’t happen. And if it does, odds are you want some fine grained control or business logic over how those classes are instantiated anyways, so you’d use a factory pattern. DI for the sake of DI just seems like a waste of time and additional overhead your application doesn’t need.

I agree with a lot of the points made by one of the commenters of that original post: it introduces a level of indirection unnecessary in most cases, it’s very invasive by introducing a huge (i.e. your app won’t work without it) dependency on a framework, and it makes your code harder to traverse and harder to read.

Okay, Maybe for Testing

Here’s where I go all hypocritical :P We’ve used a “di-like” concept in our application, but only for testing. All the layers in our application interact through interfaces, with concrete implementations defined as a default property. But this is only done so that we can easily create unit tests without being too invasive in our production codebase. Because of this we can write all our methods the way we normally would, and when it comes time to unit test we just replace the propery on the class with a mock object and have it do whatever we want. But this doesn’t use any DI framework, it uses simple built-in .net functionality.

The only other use case we’ve talked about as a team for DI is for integration testing our web application. Because we run most of our integration tests from a browser context, we don’t actually have direct access to the executing code, which makes some testing tasks harder. Using a DI framework we’d be able to change our web app’s configuration and inject a mock object and create a partial system test, one where we mock out only the data layer for example. But even those cases are rare, and full end-to-end integration tests are preferred anyways.

Again, the idea is great – with one framework and a few lines of code your application becomes way more “modular”. But in practice – how often have you needed modularity? If your application calls for it, then by all means go for it; check out Castle Windsor, Spring.NET, Ninject, or others. But don’t add it because you can.

Comments