So here's my dilemma. I heart Ruby and have worked with it whenever possible since I learned it in 2002. Then this Heinemeier Hansson guy comes along and builds a web framework on it, markets the tar out of it, it becomes a killer app, and suddenly everybody from Slashdot to Scoble is making noise about Ruby. It's been astonishing and quite wonderful.
So why am I less than enamored with Rails? Maybe I'm just playing the contrarian, as I'm wont to do, but I think I may have some reasons. Since I keep thinking of specific reasons and forgetting them at key moments, I'll try blogging even smallish issues here with whatever useful discussion I can come up with. Maybe then I can connect the dots more meaningfully.
I'll start with a simple one:
I cringed when I saw this introduced. A nice, official-looking directory where I can put code that will screw with my Ruby environment only for tests, and for all tests.
Nooooooo! Why not just start coding with lots of global variables and be done with it?
Well-designed code has minimal dependencies at any one point, and its dependencies are on abstractions rather than implementations. This
test/mocksthing blesses the practice of reaching in and hacking on the dependencies of the code under test. This wouldn't be so bad for one or a small group of isolated tests; in fact it's one of the really nice things about Ruby that makes it great for test-driven development. But using
test/mocksapplies said hacks to all the tests!
Automated tests are worth the most when they can be confidently relied upon: "this test takes A, applies B and C, and I get D." Great. Now say I've changed all the B's in my system, let's call the new version "BB". My production code still uses B, but all of my tests use exclusively BB. How much confidence can a test like that give me when it matters most?
Instead, I should be writing code that can be passed its dependencies so I can use BB only in the tests where it's useful, and have the real McCoy available the rest of the time so my tests catch unexpected integration problems or whatever will happen in the real world where B lurks and my little hacked-up BB ain't.
I wish we could've scored a little chink in the Convention over Configuration armor for a sec back when Jamis wrote up a way to bring ubiquitous dependency injection to Rails. To me, Rails could be so much stronger as a framework with the flexibility and the attention to dependency management Jamis's proposal embodied..
And using the Needle dependency-injection tool this way wouldn't bring about the feared apocalypse of Rails2EE, wherein we do YAML situps to declare ServiceModuleAccessPointTriggers or whatever. It'd just add a spot where we can reach in and change which objects go where for a moment without screwing everything else up.
I really want to know if there's something I can do to help solve this problem. Please fire away with flames, suggestions, questions, or massive groundswell of support in the comments.
Reverie inspired by Stubbing Net::HTTP.get.
I went back and reread the pages from those few days in November 2004 when all this was shaking out. It looks like it may be possible to make a Needlizing plugin for Rails using Jamis's ideas and hacking the ActionController::Dependencies API.
And now for what might be perhaps the first Rails historical research project (?), wherein I'm trying to figure out who intended what, and what happened to those intentions:
- Jamis's proposal
- Dave Thomas hooks it up with some smart Ruby magic that turns class names into transparent accesses of the registry (looks like this became incorporated into Jamis's paper)
- DHH likes Jamis's idea and especially Dave Thomas' simplification of it, but isn't sure what it will do to Rails internals
- As Sam notes in the comments, Jamis says he's "not as convinced of the necessity of dependency injection in Ruby" as he once was.
- Did anything happen after that? Has there been a definite decision not to incorporate dependency injection into Rails?