Hacker News new | past | comments | ask | show | jobs | submit login

Dependency injection is a basic tool of writing robust, testable code. The alternative is strict hard-wiring of the dependencies, which deprives you of places your code can be tested.

But do not confuse "dependency injection" with "massive heavyweight opaque framework with a billion bells and whistles that breaks constantly". Dependency injection includes things like passing in a handle to the SQL database instead of it being a global variable, which your test suite uses to switch between various test instances of the database instead of the target code being hard coded to some variable, or even hard coded with its own connection credentials.

If you're not using dependency injection you are almost by definition using a lot of global variables. I'm as happy or happier than the next programmer to be a contrarian, but, no, the collective wisdom on those is dead on. They're deadly and should be avoided. Dependency injection is the biggest tool for that.

Not having dependency injection creates more problems than it solves.

However, I'm not sure that most "frameworks" for it aren't creating more problems than they solve. Probably one of the classic examples of lopsided accounting, in this case looking at the benefits but neglecting the costs. Anything looks good if you do that. But a lot of "frameworks" seem to bring along a suite of middling, sort of convenient benefits at the cost of massive opacity, unreliability, and the bad kind of magic. Not a good trade for a lot of programs.




Dependency injection adds a lot of complexity even without a framework, and it has nothing to do with global variables, you can use global variables with dependency injection, and you don't have to use dependency injection to avoid global variables.

Dependency injection has to do with coupling. It is a weak coupling technique, and the point is to make components interchangeable. That's also the reason why it is considered good for testability, because it makes mocking easier: just replace the functional component with a test component. It sounds nice, but of course it has downsides, lots of them.

First is that is simply more code. Instead of calling B from A, you have to wrap B in an interface, instantiate it, pass it to A, and make the call. On small components, it can easily double the amount of code, or more. Of course, mechanically, more code means more development time, more things that can go wrong, more maintenance costs, etc...

You also lose track of what happens. When you call B from A, to see what is happening, it is obvious just by reading the code of A that you should look at B. Using dependency injection, there is no way to know what is called by just looking at A, you need to figure out what is instantiated first, which is not always an easy task.

Of course, there is performance too. Dispatching is expensive, typically requiring two or more memory reads to call a function. And all these little objects can take up valuable space in L1 cache.

Now, there is the argument of testability, ok, testability is good, but in many cases, there are ways of testing things even with a strongly coupled architecture. For instance, if you have a configuration file reader, you don't need to abstract it to write tests, just have test configuration files that are read by the reader. It saves you an abstraction and a bunch of dedicated test code.

Dependency injection has a place. Unix file descriptors are a kind of dependency injection and very few complain about them. It is just that it is an expensive pattern that should be used wisely and not all over the place.


> Instead of calling B from A, you have to wrap B in an interface, instantiate it, pass it to A, and make the call.

There is a place for interfaces, but not all dependencies need to be interfaces. The database handle mentioned in the previous comment is a good example of where dependency injection can be useful without the need for interfaces. In your configuration example, a string path to the configuration file might be the useful dependency.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: