17

I have a thorough background in .NET but have been using Python and Ruby lately. I found myself pondering how to best provide dependencies to objects that need them in Ruby.

At first thought, I did not actually think DI and IoC frameworks would be required to interact with dependencies because of the leniency of dynamic languages (a la redefinition, mixins, stubs, etc). Then, however, I came across answers as to why DI/IoC frameworks are not needed in dynamic languages. The reasons provided don't sit too well with me. I'm hoping I can see an example that might clear things up.

Recommended suggestions that I kind of disagree with:

Reason 1: A dependent class can be changed at run time (think testing)

In Why are IOC containers unnecessary with dynamic languages we see that a dependent class (non-injected), say X, can be stubbed or mocked in a test. Sure, but that requires us to know our System Under Test is depending on something called X. If our System Under Test suddenly depends on N instead of X, we must now remember to mock N instead of X. The benefit of using DI is we'd never accidentally run a test with production dependencies because we'd always be passing in mocked dependencies.

Reason 2: Subclass or use constructor injection for testing

In everyone's favorite goto resource for all things DI + Ruby, LEGOs, Play-Doh, and Programming, we see an example of subclassing a System Under Test to mock dependencies. Alternatively, we can use constructor injection. Okay, so B depends on A. We call B.get_dependency which provides B with an instance of A. But what if A depends on N which depends on X? Must we call get_dependency on each successive object in the chain?

Reason 3: Dependencies can be mixed in or monkeypatched

Fabio mentions we can just use mixins/monkeypatch. So X is mixedin to N. But The issue is what if X depends on A which depends on B? Do we just use mixins for every dependency down the chain? I see how that can work but it could get messy and confusing quickly.


Side note: Many users say DI frameworks are not needed in dynamic languages. However, Angular.JS has really benefited from implementing a pretty solid DI system. Angular is built on JavaScript, a dynamic language. Is this approach comparable to Ruby or Python?

Please keep in mind I'm not saying I want to force DI/IoC into Ruby, Python, etc.

Community
  • 1
  • 1
Scott Coates
  • 2,462
  • 5
  • 31
  • 40
  • 4
    I agree with your assessment. Dynamic languages are less coupled than statically compiled languages, that doesn't mean the same sane software engineering principles don't apply. Implicitly substituting a whole class definition for another is not the same as mocking and injecting a dependency. – deceze Dec 14 '12 at 11:33
  • 1
    http://weblog.jamisbuck.org/2008/11/9/legos-play-doh-and-programming - a great read on the subject. – Jonas Elfström Dec 14 '12 at 13:02
  • http://fabiokung.com/2010/05/06/ruby-and-dependency-injection-in-a-dynamic-world/ is a good reply to Jamis Buck's article. – Jonas Elfström Dec 14 '12 at 13:06
  • @JonasElfström I referred to that first post (Jamis Buck) in my original question. I actually don't think it's that great of a read. Refer to Reason 2 in my original question. Thanks. – Scott Coates Dec 15 '12 at 05:58
  • 2
    For me, Dependency Injection is a technique enabling me to write composable code. The lightbulb moment for me was seeing my code split neatly into two distinct responsibilities: 'wiring' and 'building blocks'. I look for a way to achieve this in whatever language I am using. – Nigel Thorne Dec 15 '12 at 10:15
  • Sorry for my, apparently, sloppy read of your question. Since you didn't like the article and I did I guess it was of even less help to you. What is that `get_dependency` you mentioned? I couldn't find it in Buck's article and I don't quite understand what you are getting at. – Jonas Elfström Dec 15 '12 at 20:50
  • No worries. In Buck's article, uses `B.new_client`. I called it `get_dependency` in my SO questions because it was more generic and was afraid people who didn't read the article wouldn't know what I meant. If you have any suggestions, I'd love to see them. – Scott Coates Dec 15 '12 at 23:33
  • 1
    I agree with Nigels description. The first question you must ask yourself is do you really need DI, there are many other ways to achieve good separability. For examples look at: http://martinfowler.com/articles/injection.html – SpagnumMoss Dec 16 '12 at 14:30
  • 2
    The cat is once again out of the bag! http://david.heinemeierhansson.com/2012/dependency-injection-is-not-a-virtue.html – Jonas Elfström Jan 06 '13 at 23:38

1 Answers1

2

While many think DI is not needed, I agree with you, that it's indeed needed a lot; but sometimes it gets mixed with other techniques Python provides. I suggest you to look at venusian, it may kind of verbose, but if you come from .NET you'll see the relation. In a word: venusian allows you to annotate your methods without changing their behavior. Thus, you may write venusian decorators so that your unit-testing does not get affected. Pyramid uses venusian to annotate views, for instance.

manu
  • 3,544
  • 5
  • 28
  • 50