First, I apologize for bailing on you guys tomorrow. It is particularly egregious of me as I told #krug I'd be showing up ready to talk about something.
What something? Well, Jason posted a
pithy quip and Chuck followed up with
meatier anecdote from the developer of net-ssh. Summarized, their common message is that dependency Injection is nice when you need it in a language like Java, but you don't really need it in a language like Ruby.
I thought "I use and like DI in a project at work and I often hear Ruby people say that it's nice but not really necessary in the Ruby world, I think I'll research why and talk about it." Then I said I would. Now I'm bailing. Classy, I know. Anyway, here is what I was going to say:
Three questions I immediately wanted to answer: what is Dependency Injection? What does 'a language like Java' mean, and what does 'a language like Ruby' mean? First, let me say that
this presentation from OSCON covers this topic (What is DI and why doesn't Ruby really need it?) very well.
What is Dependency Injection? (see the
wikipedia entry and this
Martin Fowler post for more...)
At work we are writing a Java client/server app. We use Spring's DI and it is nice. To me it is basically a super powerful configuration tool that allows me to choose a configuration xml at runtime to switch the app from a mock-testing mode to hitting real servers.
More formally, Depedency Injection is a blanket term for methods that allow you to specify at a generic level how a group of objects are wired together, and to defer certain specifics about the actual implementation until runtime. During testing you may specify mock objects, and for production deployment you will want the real classes in there. This gets beyond configuring filepaths and message files. This is a way to defer the decision on which concrete code will execute when a method is called.
What is a Language like Java?
Being completely ambiguous about exactly what bytecodes you'll be using until runtime is actually pretty tricky in Java. Java has closed classes. That means that during runtime a class's bytecode is read-only and can't be changed (easily). You run with the logic you're given, the concrete implementations you've been passed during construction, etc.
Secondly, Java is a compiled language. You change the source and you must recompile your classes and THEN run.
So if you go with the flow in Java the implementation you get when your program starts up is set in stone, and it takes a bit of time for the stone to
set in the first place, as it were. You gotta make a new mold (change the source), pour it and allow it to set (compile it). There are ways around these restrictions, and DI is one of them.
What is a Language like Ruby?Ruby has open classes. At runtime you can change what methods a class or even a specific instance has. You can modify the implementation of a method as well, during runtime. Also, the "compile time" doesn't really exist. When you run a Ruby program the interpreter is running your every line fresh and new.
So it is very easy to defer the actual definitions of classes you'll be using until you run the program, as simple as changing the '-rmockobjecs' instead of '-rprodobjecs' on the commandline as you execute your Ruby script. When you can dynamically do something this horrible how much more flexibility do you need?
PowerPlant = case(mode)
when :development : MockPowerPlant
when :production : ProductionPowerPlant
else eval('mode') # mode is ruby code that returns a class,
e.g. "class FooPowerPlant; def get_power; puts "poop!"; end; end; FooPowerPlant;"
end
PowerPlant.new.get_power # does what you expect as long as the class has a new with no arguments and a #get_power method.
Ruby is flexible in ways that most often Depedency Injection is just an unneeded layer on top.