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.