DI is generally used to solve one of three problems that are pretty much unique to Java:
Passing a function
Decoupling initialization from memory allocation (eg. making constructors work) (This problem is also shared by C# before 3.0 but you can kind of get around it by passing a function that does the initialization, or using an anonymous constructor in 3.0 and up)
Avoiding the FactoryFactoryFactory pattern where it's all factories all the way down which is a pattern designed to get around the constructor anti-pattern. Because constructors are somehow special and not just a function that returns a specific data-type.
So in C# you'll wrap a constructor in a function so it can be passed, and in Java you'll use DI.
(eg. Func<String> s = () => new string())
DI is primarily a euphemism for programming in XML or another language that sucks less than Java. Primarily it's a euphemism designed to assage the egos of Java programmers who don't want to admit you can't solve problems elegantly in Java so they move their code to other languages that interact with Java to pretend Java solves more problems than it creates.
I am not sure you understand what DI is: if you're programming to interfaces and are passing instances of an interface to a constructor, you're doing DI. You don't need a framework to do so. It's a great pattern to use in other object oriented languages, including ones that let you pass functions. The reason it's a "big deal" in C# and Java is due to these languages lack of support for mixins or multiple inheritance.
I've used DI in C++, Perl and Scala - the only difference being in these languages I didn't need a framework: I used mixins (or if mixins were not available, multiple inheritance in mixin-style) to "wire" the interfaces to implementations.
In Java I ended up either having a big class where I do all the wiring (in my current project: < https://github.com/voldemort/voldemort/blob/master/src/java/... >) or using Guice (Spring is a little too "enterprisey" to be my cup of tea). Yes it's more awkward, but it's certainly possible to write clean and readable (if more verbose) code in Java.
DI comes about as a reaction to use of static methods and more-harmful-than-useful design patterns such as singleton, which have the issue of making it more difficult to isolate specific layers of your code for unit testing.
This is not at all the definition of Dependency Injection. The wikipedia article [1] does a pretty good job of describing what it really is. DI is a pattern that is intended to reduce coupling between components in a large system. It applies to any OOP language, although it is true to say that the term first gained popularity in the "enterprise" Java world.
I also think it's wrong to conflate DI with XML. One of the first major DI frameworks, Spring, did use XML for configuring and wiring-up components, but it's also quite popular to do this part purely in the code, without any external configuration files.
To be honest, I didn't really understand what he was trying to say, but I am certain that the first two problems he mentions are not what DI is intended to solve.
DI is generally used to solve one of two problems that are pretty much unique to Java:
Passing a function
If you will pardon my English: What a load of bullshit.
I'm sure it can be used for that as well (i.e. in implementing the delegation pattern, due to lack of delegates and first class functions), but saying that is what it all that is good for simply makes you look inexperienced.
For any system with a reasonable complexity you will find yourself wanting to separate your code into modules. It might be that you want to thoroughly implement SOC (seperation of concerns), it might be that you want your code to be more flexible (i.e. be able to replace a file-store with a db-store later) or simply that you realize that your system is so big, that you need to be able to work with components separately to be able to properly test your modules.
Decoupling initialization from memory allocation
First you criticise Java, then you bring up a point which (usually) is not a very big concern in garbage-collected languages.
Maybe you mean "controlling initialization" which is crucial for testable code, but given how your first point is completely off base I'm not really sure I would give you the benefit of the doubt.
DI is primarily a euphemism for programming in XML
You can implement DI without any XML. And no, for reference, I don't do Java.
I know you can implement it with out XML, I do DI all day long with functions. I just don't call it DI, I call it passing functions. When people talk about DI they're generally talking about using a DI framework. My point is that the concept is trivial enough to implement in the language itself and doesn't require a framework to help 'manage' it.
What problems can be solved with DI that can't be solved by passing a function? Or 'controlling initialization'
Allocation issues are present in GC languages because of the overhead of GC when you could just reinitialize an existing piece of memory. (You also get to keep your L1/L2 caches hot by not initializing new memory when old will do) Allocation has non-trivial costs. This is why using the methods that allow you to pass a byte[] buffer are often more efficient than those that allocate their own buffer. And we're not even getting into the fragmentation that can occur when you're rapidly allocating memory and some of that memory is locked by the OS so it can't be collected.
How is it that DI frameworks are necessary for large code bases yet most operating systems don't have DI frameworks?
When most people writing OO code have a problem, they think 'I know I'll use a DI Framework', now they have two problems.
DI is about passing all that is needed through parameters instead of creating it or using globals - this is completely independent from the type of arguments passed - you can pass functions or scalars or objects or whatever. Of course all that passed stuff is still needed to be created somewhere - so DI is also about having a factory of objects - it creates a lot of objects - but creation alone should be simple (and indeed frequently it can even be automated by using a DI framework).
You ask: "What problems can be solved with DI that can't be solved by passing a function?" - OK, I never thought about it from that side - but how about the problem of globals? How do you solve it by using function passing? Let's say you have a global database connection - if you modify it and pass that connection (or more frequently objects created from it) as a parameter to all code that needs it - that is DI. How function passing fits here?
I know you can implement it with out XML, I do DI all day long with functions.
Non-sequitur. Most .Net DI frameworks (as opposed to DI in Java, or DI without a framework) use configuration in code. This is generally much more readable and flexible than config in XML. Only some of them use functions for some things.
What problems can be solved with DI that can't be solved by passing a function?
Any non-trivial interface implementation will have more than one function.
Let's say I have a core library which defines lots of possible actions for my application. This application will need to work with other applications although only one at a time (in my case, trough COM), however the operations which needs to be done in these applications remain the same. Applications, not one. Operations, not one.
Obviously this calls for a common interface (in a statically typed language) so that the you can make Application-proxy classes which handles the application interaction in a similar way.
Once you have those implemented as classes you typically pass those around, for instance via the constructor when setting up your instance. Even without a DI-framework this is DI.
For this case "passing a function around" would be very impractical as you would have to pass several functions around. You would have to make sure all functions were created at the same time, with closures referencing the same application COM instances etc.
In fact, passing functions around here would make your solution more complex and error-prone with little benefit what so ever.
Don't get me wrong: I love what function-passing enables. I've written tons of code where function-passing is used to simplify the solution and make it more reusable, more elegant and generally better to work with. Being able to pass functions is awesome.
That said, function passing can be considered a primitive and it's not one which solves all problems. DI is for when your problem domain is bigger, more complex and function-passing would be you were only allowed to pass primitive objects (int,string,etc) around as opposed to sending class-instances around.
They are very, very different and if you can't see that difference, you really should step back and take another look.
Allocation issues are present in GC languages because of the overhead of GC when you could just reinitialize an existing piece of memory
Sure. But your argument that this was one of "two" reasons to use DI is most certainly false. I've never seen anyone advocate DI because of memory issues. This is simply not an argument.
How is it that DI frameworks are necessary for large code bases yet most operating systems don't have DI frameworks?
Because you don't need a DI-framework to implement DI in your code. If you think DI needs "frameworks", you are obviously missing the core point about it: It's a way to structure your code.
Totally agree with you re: DI as a way to structure your code.
I tend to start with function passing and yeah, when it gets to 5 functions you start putting them in a class or other structure that allows you to pass them as a unit. I like using tuples to pass gobs functions because it works better with type-inference in F#
I've just never heard it referred to as DI except in OO (Java) circles.
> First you criticise Java, then you bring up a point which (usually) is not a very big concern in garbage-collected languages.
Of course it is for a number of reasons (instance sharing or reusing, caches, registries, ...), and most GC'd languages (significantly, not Java or C#) give separate access to these two operations (allocating an instance and initializing it).
See Ruby (new/initialize), Python (__new__/__init__), Obj-C (alloc, init), etc...
> The same basic problem you often get with object oriented programming, style rules and just about everything else. It's possible - very common, in fact - to do too much abstraction, and to add too much indirection, and to generally apply good techniques excessively and in the wrong places...[answer continues]
True. But what's even worse for your career is when you learn programming languages that don't need DI frameworks because that kind of clean separation is baked in (like Python) but then most jobs out there are Java :-(
I'll admit I've never done Java programming, but (so far as I understand the term) dependency injection is something I use a lot when writing Python code. For example, if I'm writing a method to transfer a file over a particular kind of connection, I'll make the connection object a parameter rather than have the method set up the connection itself. If I'm writing a class, I might make the connection object a parameter to the constructor, or just construct it in a helper method that I can override for testing purposes.
Am I missing some magic goo that makes Python not require DI, or do I just not understand what Java programmers mean by DI?
For languages such as Java and C#, wiring up these objects is quite a pain.
For duck typed languages such as Python and Ruby, it isn't that big of a pain. So we just do it. Just because you don't have an IoC framework doesn't mean you aren't practicing DI :)
Am I missing some magic goo that makes Python not require DI, or do I just not understand what Java programmers mean by DI?
Sometimes it's easier to assume Python-developers are blind to architectural problems and common solutions to those.
Not saying Python isn't used in large, complex problems or that all Python-code is spaghettti-code, but there are a lot of wannabe cool Python-hackers ("ninjas") out there and part of being "cool" in that sense is disregarding everything which looks even slightly like design patterns.
In those circles "Design patterns" means enterprisey, verbose code with FactoryFactories and not guidelines for how to structure your code to solve problems which have been solved before you.
There are a lot of design patterns for object oriented programming that were created specifically to overcome structural flaws in C++ and Java. These simply don't apply to some languages.
Dependency Injection is not one of these and actually has widespread applicability. Although the name always sounds wrong to me since it makes me think of dependency creep, one of the problems that it is intended to alleviate.
Design patterns have gained an "enterprisey" reputation because much of the time they are represented as if each one is a universal, language agnostic solution. They reek of cargo cult management.
Every language and/or ecosystem will have its own set of effective design patterns that will partially overlap with those of other ecosystems. Some communities care more about making names for the patterns, which could in itself be considered enterprisey.
Interestingly enough, the person that first told me about design patterns was a Python hacker.
I am curious about how this type of "clean separation" is generally handled in Python. I mostly have experience with Java, and I have some light Python experience but I've never worked in a large Python codebase.
Would you mind telling me how you would handle this in an example?
Let's say you were building a web app which had to communicate with some sort of payment gateway API. Naturally since you are communicating with some third-party API you want to prevent the rest of your codebase from knowing too much about the API - in case you ever need to change gateways - and so you wrap it up in an interface/module/etc to abstract away the details of Gateway X.
If it ever came time to switch payment gateway backends, in a Java application using DI you would just need to switch which implementation of your interface that the rest of your code is wired up with (either in XML, or if you are wiring up collaborators explicitly in your code, etc).
How would you generally manage this type of thing in a Python system? By giving the web/controller code a different payment module that implemented all of the same method signatures?
you want to prevent the rest of your codebase from knowing too much about the API - in case you ever need to change gateways
Maybe I'm naive, but I wouldn't usually bother:
1) Maybe I will never change gateways, then there was no point in writing a wrapper.
2) If I do change gateways, I can just write a wrapper that uses the old gateway's API as the interface for the new one.
If the new gateway is sufficiently different than the old one that it can't be mapped to the old API, then whatever wrapper I wrote back in the beginning before I needed it wouldn't have been sufficient anyway.
Your strategy sounds like YAGNI to me. I only write separate interfaces when I actually have different components that need to be swappable.
But maybe that's just because I'm using Ruby and I can be lazy like that?
"If it ever came time to switch payment gateway backends, in a Java application using DI you would just need to switch which implementation of your interface that the rest of your code is wired up with (either in XML, or if you are wiring up collaborators explicitly in your code, etc)."
You simply pass in the desired payment processor as a parameter. End of story.
This is part of the reason Java is such a terrible language for actually learning about programming. "Using Dependency Injection" is an absurd way of phrasing "pass in varying parameters as parameters to your function instead of using global variables". What should be the normal way of doing business has instead been elevated to Something Special (that Lesser Languages Can't Do because they don't call it Dependency Injection because they would never think of giving Passing Parameters to Functions a special name!) because Java makes something as easy as breathing and in some cases hard to avoid (try programming Haskell or Erlang with too many global variables) a production.
In Java, you use absurd and unnecessary machinery. In every other language, you just do it. It's hard to even explain how you do it because there's hardly any doing in the it. It's a parameter passed in. It hardly seems worth discussion.
For the sake of this example, let's say that the different gateways have vastly different APIs, messaging mechanisms, etc.
So in the code that you are passing a parameter to, you'd have to have some sort of branch based on the parameter value to choose to call Gateway A versus Gateway B - correct?
Which requires you, when switching gateways, to change the value of the parameter passed along with possibly updating the branch to be aware of what the different Gateway modules you might call would be - correct?
This is basic object orientation: You pass in an object that corresponds to the desired interface. "Facade pattern" if you need something to Google, but this is really basic language-agnostic OO stuff.
Another reason to dislike the Java cruft; it successfully hides the simple things going on behind immense machinery and complicated terminology.
The following is a comment from Frank Atanassow on a LtU discussion about the Curry Howard correspondence:
blah blah blah dependency injection blah blah blah
(This is a bit off-topic, but it came to mind, so what the hell.)
You are correct in your observations that given most programming languages (even those such as Haskell), it is difficult to see exactly how Curry-Howard is useful.
I recently stumbled across someone mentioning something called "dependency injection". I didn't know what it was, so I googled (I guess this is lowercase nowadays!) it and read Martin Fowler's article on it. It is a bit on the long side, and I kept waiting for the punch-line; you know, the point at which the author hits you with the insight which justifies the preceding verbosity and the hi-tech-sounding name ("dependency injection" — I can't help but think of "fuel injection", and gleaming motor engine showcases), but it seemed indefinitely postponed. And in the end, it turned out that "dependency injection" just means "abstraction" specifically by parametrization, by update and by what I think amounts to type abstraction plus update. (Apparently these are called — I kid you not — type 3 IoC, type 2 IoC and type 1 IoC...!)
To me this all seemed rather obvious and it got me thinking about why it isn't obvious to the author or his readership.
In Haskell, if I am given some type B which I need to produce somehow, and I realize that the B-values I need depend on some other values of type A, the first thing I do is write down "f :: A -> B". Then I write down "f a =", and then I start writing stuff after the equals sign until I have what I need. I do that because I know once I have the type that if there is an inhabitant of the type "A -> B" it can be expressed as "\a -> b" for some b, so the "f a =" part is always part of my solution and I will never have to change that unless I want to. So once I've written that down I feel one step closer to my solution.
I know that for three reasons. First, because of my experience as a functional programmer. Second, because it is part of the universal property of exponentials ("factors uniquely"), that is, of function types. And third, because by the Curry-Howard correspondence with natural deduction, I can start any proof of A which depends on B by assuming A, that is, adding it as a hypothesis.
So, why is it so obscure in Java? I think part of the reason is that in Java you have update, so there are complications and additional solutions. But part of the reason is also that it largely lacks structural typing, and that makes it hard to see that a class('s interface) is a product of exponentials. (With nominal typing, you tend to think of a class by its name, rather than its structure.)
You could also blame the syntax of method signatures, which obscure the relationship with exponentials and implication. But is the syntax the cause or just a symptom? (You know what I think about syntax...) If CH could be readily applied to Java, perhaps Java's designers would have chosen a more suggestive syntax. But even if they had decided to stick anyway with C-style syntax, the idea of using abstraction to handle dependencies would have been more obvious.
Dependency injection separates discovery from dependency. It's neither good nor bad but can be useful as well as abused beyond ad nauseum. End of story.
How can you tell how closely coupled a codebase is when you're in the interview process and not yet an employee?
This is the real challenge. I don't think many companies, outside of perhaps small startups, will let you view their code - at your own perusal so you know they aren't just showing off the good stuff - to candidates.
Passing a function
Decoupling initialization from memory allocation (eg. making constructors work) (This problem is also shared by C# before 3.0 but you can kind of get around it by passing a function that does the initialization, or using an anonymous constructor in 3.0 and up)
Avoiding the FactoryFactoryFactory pattern where it's all factories all the way down which is a pattern designed to get around the constructor anti-pattern. Because constructors are somehow special and not just a function that returns a specific data-type. So in C# you'll wrap a constructor in a function so it can be passed, and in Java you'll use DI. (eg. Func<String> s = () => new string())
DI is primarily a euphemism for programming in XML or another language that sucks less than Java. Primarily it's a euphemism designed to assage the egos of Java programmers who don't want to admit you can't solve problems elegantly in Java so they move their code to other languages that interact with Java to pretend Java solves more problems than it creates.