{ by david linsin }

November 16, 2009

Dependency Injection Obscures Your Code

During listening to Software Engineering Radio's Episode 148 - "Software Archaeology with Dave Thomas", I got quite annoyed by a comment made by one of the respected authors of "The Pragmatic Programmer".

To quote Dave Thomas correctly, here's what he said at around 23 minutes into the podcast:

... that is one of the reasons why I, in general, are not very happy with the DI style of development, because I actually think it obscures the code quite a lot, when it comes to reading it ..... what it actually does is, it give you another dimension, that you have to read in order to understand the code.


My first reaction was "What the deuce!?!". I mean how can someone claim, that Dependency Injection obscures code and makes reading code harder? Are all those hours I spent blogging and promoting DI in vain? Are the SpringSource guys wrong or is Dave Thomas just crazy?

However, his statement and even his argument are completely reasonable, if you listen to the first couple of minutes of the podcast. Dave said at around 11 minutes into the podcast:

.... actually, I don't typically use an IDE, I use an editor like Textmate on the Mac.


And there you go! No wonder, you'll find it harder to read and understand code, if you compare the following two screenshots from a bunch of code, using Spring:

di_1.png

di_2.png

If you are reading the code above and don't understand where those two dependencies in the constructor come from, your IDE gives you a hint, without leaving the context of that particular file. You know that, they'll be injected by Spring. In addition to that, you can even directly navigate to the configuration file with a single click.

Now if you are using a text editor, you really have no idea where to look for. I guess you would have to grep for new TxTestService(). In case of using Spring, not even that would give you any more clues.

Don't get me wrong, if Dave likes Textmate better than an IDE - fair enough! I just think everyone should use the right tool for the right job! Frankly, an IDE makes a much better job here than a plain text editor.

I think the Java world has amazing tooling and in my opinion there's almost the philosophy, that if there is no tool support for a technology - it sucks. I don't fully agree with that. However, I do think that, when it comes to Java, tool support can definitely
assist you reading and thus understanding code.

15 comments:

Olivier said...

I'm not in Dave Thomas'mind but I agree with him: DI make harder to understand a piece of code by reading it...
Tooling does not really matter: without simple naming convention, you can't "read" the code! You have to click here, and there, and back...
BTW: i don't see any difference between the 2 screenshots... ;-)
Of course, if you're reading YOUR own code, there will be no problem... but if you need to read anyone else's code, you'll spend some time figuring what it does because you'll have to understand the bindings "browsing" the code in the IDE...
So, tooling helps with working on an already known source code but doesn't help understand it. And DI makes things worst in this view...
IMHO

Shantanu Kumar said...

DI done by hand does not obscure your code -- it keeps the organization clean. Use of IoC containers is probably what you intended by saying DI?

Ollie said...

If you claim DI obscures your code, you probably suck at naming interfaces. The purpose of an interface is to describe the role an implementation takes in regard of the current client. So the art probably is to define meaningful interfaces, that express, what the client wants to achieve without bothering with implementation details.

If one has problems with getting dependencies injected rather than looking up herself, here's a small question. Suppose two classes: one looking up it's dependencies via a factory inside the constructor and the second class expecting to get the dependencies injected via constructor arguments. Now, looking at the classes interface (its constructor and method signatures). In which version do find out which dependent components are needed by the class to work.

IMHO hiding dependencies inside the implementation obscures code.

Casper Bang said...

By relying on a DI container you have introduced another layer of abstraction and have lost the ability to statically assert relationships in a vanilla context.

As we know, introducing one layer of abstraction might solve a problem but often also introduce a new problem.

Now, using IoC may be worth it in some scenarios (like course-grained components) but overall I would have to agree with Dave, of course code without DI is easier to read. You need no special tooling or knowledge.
Let's not get religious, often it's sufficient to rely on SPI's to obtain a form of IoC through the classpath.

Bob said...

I agree with Ollie on the point of naming interfaces.

If only all of us follows the naming conventions and create good names for our interfaces and class then most probably DI won't be as obscured as others think.

Alan said...

I can also sympathize with Dave Thomas' view after programming with Ruby on Rails. Why use a DI container when using sensible conventions will do the job? How often do you have multiple implementations of the same service? Or the same repository?

On the other hand, if I were using Spring, I would prefer to use autowired beans with annotations to declare other assumptions such as the url of a controller or the transactional semantics of a service.

Geir said...

"How often do you have multiple implementations of the same service?"

Every time I write a test for a client of the service you are referring to, I would create some kind of mockup implementing the same interface.

That said, not everything should be exposed as a service.

David Linsin said...

If you read my post carefully, you'll notice that I do agree with Dave. If you don't have tools helping you with DI, then it does obscure your code.

If you want to understand code structurally, using an IDE is the way to go. A couple of months ago, I was in the position, where I had to understand a fairly complex bag of code, heavily using DI with Spring and AOP. Without my IDE I would have been lost! It helped me getting to know the code, navigating from configuration files to code and back. It highlighted where an Aspect was applied to the code and pointed me to the corresponding configuration.

All of that would have been a big hassle and I would even say almost impossible if I didn't have my IDE to assist me. Without the right tooling, I wouldn't have been able to get productive within a couple of hours.

That said, I don't think it helped me understanding the domain or even what the code does. That was still up to me, to figure out what a class did and how to use it. When I refer to understanding, I do mean structurally, after all that's what Dave was referring to in the podcast.

Semantically, having interfaces, classes and methods which are speaking for itself, that's so much of a help when browsing a code base - when it comes to the structure, architecture and deployment, you definitely need a tool!

Jordan Zimmerman said...

I've been saying the same thing for a long time. Here's my blog post from last year about it: http://javaoldschool.blogspot.com/2009/01/dependency-injection-makes-code.html

developer minds said...

Hi, I don't agree on the topic that DI make it harder to understand a piece of code. Take into consideration JSR330 (Spring, Guice and Weld) what is the difference in understanding?

WITH DI:
@Inject
public ServiceA(ServiceB sB) {
...
}

WITHOUT DI:

public ServiceA(ServiceB sB) {
...
}

It is exactly the same. The difference came only from the fact, which piece instantiates and fulfills the dependencies. In one case the DI container and in other case a factory. So what's the point?
M2C

Anonymous said...

Well, imho, if you write code that requires an IDE to understand, you're writing pretty bad code.

David Linsin said...

@anonymous

If you have ever worked on a fairly large codebase, you know how much classes, interfaces and other artifacts you need to structurally grasp and put into context. Now you can do it without an IDE, but you don't want to.

David Linsin said...

@developer minds

I guess the argument Dave Thomas made was more like:

public ServiceA(ServiceB sB) {
...
}

vs

public ServiceA() {
this.sb = new ServiceB();
}

Ashitkin Alexander said...

I just don'tunderstand where the pragmatic bounds.Why he's coding in textmate and not in notepad. Does he assemble applications with shells sripts and merge files with his phenomenal memory? Does he go towork by bike only because a car isn't pragmatic? Geeks who says 'you need text editor only' just geeks. Pragmatism - isto use right things to solve right tasks, and DI has reasonable advantages and obscures nothing.

iSilver Labs said...

We just developed a open source Light Weight Ioc / Dependency Injection framework.

http://blog.isilverlabs.com/2010/08/lightweight-ioc-dependency-injection-framework/


com_channels

  • mail(dlinsin@gmail.com)
  • jabber(dlinsin@gmail.com)
  • skype(dlinsin)

recent_postings

loading...