Dependency injection for Node.js. What do you think?

1,269 views
Skip to first unread message

Eldar

unread,
Jul 27, 2012, 10:45:48 AM7/27/12
to nod...@googlegroups.com
Do we need this in Node?

My answer is yes we need some (simple) way to specify the app level dependencies  at runtime. Here is my take on this. Please checkout and let me know how do you feel about.

But the idea is very simple:

// inside any index.js
var R = require('runtime').patchNative()
var use = R(module).use

use('fs', 'node_modules/third/party', require('./smart-fs'))
That's it. Third party module just uses our smart file system

Rob Ashton

unread,
Jul 27, 2012, 11:07:12 AM7/27/12
to nod...@googlegroups.com
Do we need dependency injection in nodejs? Well - if you mean dependency injection literally, we have it already, it looks like this

function doSomething(dependency) {

}

doSomething(new FooDependency())

or

doSomething(new BarDependency())

or

var Animal = function(vocals) {
  this.vocals = vocals
}

var cat = new Animal(miaow)
cat dog = new Animal(woof)

etc

----------

If you're talking about  'container' support to support this, it's a road that has been trodden well by .NET and Java devs, and has been shown time and time again to lead full circle to the very beginning where you just build your object graphs manually and introduce extensibility points where you need them for either mocking out slow dependencies for testing or allowing consumers to control something about your code.

Trying to bake in support to this as part of the require system seems like asking for trouble, keep it explicit, keep it as needed and let the goodness follow.

My two cents.


--
Job Board: http://jobs.nodejs.org/
Posting guidelines: https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
You received this message because you are subscribed to the Google
Groups "nodejs" group.
To post to this group, send email to nod...@googlegroups.com
To unsubscribe from this group, send email to
nodejs+un...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/nodejs?hl=en?hl=en

Eldar

unread,
Jul 27, 2012, 11:17:49 AM7/27/12
to nod...@googlegroups.com, roba...@codeofrob.com
Did you actually have a look at the code behind? I you really find this (both implementation and rules introduced) adding complexity? 

Oliver Leics

unread,
Jul 27, 2012, 12:08:21 PM7/27/12
to nod...@googlegroups.com
var mockedModule = require.use('some-module', {'fs':
require('smart-fs'), 'path': require('smart-path'), ...})

That would make more sense, wouldn't it?
>>> nodejs+un...@googlegroups.com
>>> For more options, visit this group at
>>> http://groups.google.com/group/nodejs?hl=en?hl=en
>>
>>
> --
> Job Board: http://jobs.nodejs.org/
> Posting guidelines:
> https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
> You received this message because you are subscribed to the Google
> Groups "nodejs" group.
> To post to this group, send email to nod...@googlegroups.com
> To unsubscribe from this group, send email to
> nodejs+un...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/nodejs?hl=en?hl=en



--
Oliver Leics @ G+
https://plus.google.com/112912441146721682527

Martin Cooper

unread,
Jul 27, 2012, 12:47:29 PM7/27/12
to nod...@googlegroups.com
On Fri, Jul 27, 2012 at 8:07 AM, Rob Ashton <roba...@codeofrob.com> wrote:
> Do we need dependency injection in nodejs? Well - if you mean dependency
> injection literally, we have it already, it looks like this
>
> function doSomething(dependency) {
>
> }
>
> doSomething(new FooDependency())
>
> or
>
> doSomething(new BarDependency())
>
> or
>
> var Animal = function(vocals) {
> this.vocals = vocals
> }
>
> var cat = new Animal(miaow)
> cat dog = new Animal(woof)
>
> etc
>
> ----------
>
> If you're talking about 'container' support to support this, it's a road
> that has been trodden well by .NET and Java devs, and has been shown time
> and time again to lead full circle to the very beginning where you just
> build your object graphs manually and introduce extensibility points where
> you need them for either mocking out slow dependencies for testing or
> allowing consumers to control something about your code.
>
> Trying to bake in support to this as part of the require system seems like
> asking for trouble, keep it explicit, keep it as needed and let the goodness
> follow.

I agree with this. If you need dependency injection, design it into
your system. Don't force it on unsuspecting modules.

A couple of things that come to mind off the top of my head:

* If I compel some module to use, say, 'my-funky-fs' instead of 'fs'
without knowing it, will that cause *its* dependencies to have their
usage of 'fs' replaced too? What if one of them was already replacing
it with something of its own choosing, perhaps using a different
mechanism (like maybe graceful-fs)?

* If someone reports an issue with one of my packages, and I spend a
bunch of my time debugging it, only to discover that the reporter
replaced one of my dependencies with some other flaky substitute and
that's the culprit, I'm not going to be happy about that. I design my
packages to work with their declared dependencies, or I specifically
design for dependency injection if it's needed.

> My two cents.

And mine. :)

--
Martin Cooper

Joe Developer

unread,
Jul 27, 2012, 3:32:33 PM7/27/12
to nod...@googlegroups.com
Erm, outside of the amateur hour projects just such functionality exists:

And yes, once you have had the pleasure of using it on non-trivial apps you miss it dearly when dealing with the ad-hoc structured or 'good enough rolled' alternatives. 

Rob Ashton

unread,
Jul 27, 2012, 5:27:26 PM7/27/12
to nod...@googlegroups.com
Yeah, sorry 

Not a real developer, never worked on a real project, excuse me for my ignorance.

Lol jking

Sigh

Sent from my iPhone

Joshua Holbrook

unread,
Jul 27, 2012, 5:57:42 PM7/27/12
to nod...@googlegroups.com
You might like this, Eldar:

https://github.com/flatiron/broadway

It gives you dependency injection and IoC. We use it a lot in
flatiron, it's pretty sweet.

--Josh
Joshua Holbrook
Head of Support
Nodejitsu Inc.
jo...@nodejitsu.com

Marak Squires

unread,
Jul 27, 2012, 6:02:05 PM7/27/12
to nod...@googlegroups.com
Yeah, that's pretty much the whole point of Broadway.

I use Broadway a lot of "plugin systems". Essentially, where you are requiring files as node.js modules, but you want programmatic hooks into the initialization and attachment process of the module.

Joe Developer

unread,
Jul 27, 2012, 6:10:12 PM7/27/12
to nod...@googlegroups.com
On Sat, Jul 28, 2012 at 4:27 AM, Rob Ashton <robashton...@gmail.com> wrote:
Yeah, sorry 

Not a real developer, never worked on a real project, excuse me for my ignorance.

Lol jking

Sigh

Yes, by all means get your panties in a twist over an imagined slight, princess.

I'd love to hear of your experience with dependency relationships captured across a sea of files and nested within them to boot. My experience is that it is the stuff of inefficiency, not many set out to have a static team, you are growing, rotating or thrashing - approachable dependency maps can save time and frustration. 

Then there is the matter of on-demand loading and optimizing request counts, so far I haven't seen a better value proposition in that regard than the YUI3 approach.  Static analysis can disallow patterns that you might otherwise want to make use of.  

It is quite possible that app environments that aren't subject to the somewhat unique demands and expectations as web apps are won't weigh or leverage options in the same way, who knew?

Brett Ritter

unread,
Jul 27, 2012, 6:15:51 PM7/27/12
to nod...@googlegroups.com
On Fri, Jul 27, 2012 at 3:10 PM, Joe Developer
<joe.d.d...@gmail.com> wrote:
> Yes, by all means get your panties in a twist over an imagined slight,
> princess.

Please play nice everyone. Name-calling and "amateur hour"
accusations don't help anyone individually and they don't help the
community. They certainly detract from the weight your experiences
will be given.

--
Brett Ritter / SwiftOne
swif...@swiftone.org

Joe Developer

unread,
Jul 27, 2012, 6:44:05 PM7/27/12
to nod...@googlegroups.com
On Sat, Jul 28, 2012 at 5:15 AM, Brett Ritter <swif...@swiftone.org> wrote:
On Fri, Jul 27, 2012 at 3:10 PM, Joe Developer
<joe.d.d...@gmail.com> wrote:
> Yes, by all means get your panties in a twist over an imagined slight,
> princess.

Please play nice everyone.  Name-calling and "amateur hour"
accusations don't help anyone individually and they don't help the
community.  They certainly detract from the weight your experiences
will be given.

The same personality traits that seem to give a relative advantage in staying a developer also tend to ensure that the experiences of others are readily discounted. We couldn't do this without a keen sense of adventure and double dipping the irrational exuberance.

The deeply ironic thing is that I was in no way directing my initial comment to him, my response was triggered by the absurd dimensions of the self-obsession. Apologies to princesses everywhere.

My comment was in fact, an expression of frustration of just how many times I've seen snowball-self-rolling that not only keeps people from being as productive as they could ( though obviously the joy of creation at a different level of abstraction is still there, happy hacking champs! ), or reaching to higher levels of abstraction. Obviously the impetus for my comment was far from self-evident, that it was directed to anyone in particular seems a leap of faith reserved for the self-worshiping.

Anyways, for AOP I'd say that Events is the golden opportunity within JS, rather than actually injecting logic, its just a name guys - just a symbol to trigger a cascade - as with the best of things. 

       

--
Brett Ritter / SwiftOne
swif...@swiftone.org

mixu

unread,
Jul 28, 2012, 1:25:53 AM7/28/12
to nod...@googlegroups.com
I've never really needed to dependency inject into third party modules. If I did, I'd rather fork the third party dependency than do some sort of dynamic solution.

However, I do use dependency injection for (unit) testing my own stuff. There are a ton of ways to do this but my favorite way of doing this is:

var fs = require('fs');
function Foo() { };
Foo._setBackend = function(backend) {
  fs = backend;
};
module.exports = Foo;

Then in the test setup:

before: function() {
  Foo._setBackend(require('./smart-fs'));
},
after: function() {
  Foo._setBackend(require('fs'));
}

The nice part is that the mechanism is trivial and doesn't depend on any external modules or require() patching, without forcing me to make "fs" a part of the interface/params to Foo(). It doesn't work on 3rd party modules, but I haven't needed to do that thus far. Simplest thing that works and all that..

Eldar

unread,
Jul 28, 2012, 4:02:22 AM7/28/12
to nod...@googlegroups.com
Thank you for pointing to Broadway.

But yeah there are situations where hooks were not planed. For example: 

Once I tried to mock the file system. The goal were to define directory layout right in test. That's much more better and cleaner then having separate fixtures dir created by hand.  You have all information right were it used, you have instant understanding of what's going on, etc. But you can't mock file system if you need real IO right in the test and at the same time you are using third party! Anyway, even if you don't have such case, isn't it better to just use  "require" for things that semantically are nothing more then just a "require", rather then introduce  artificial hooks?

That's the reason why I'd like such thing to be officially supported. Actually the title of the topic is wrong. I had in mind feedback for proposal. 

>> >> For more options, visit this group at
>> >> http://groups.google.com/group/nodejs?hl=en?hl=en
>> >
>> >
>> > --
>> > Job Board: http://jobs.nodejs.org/
>> > Posting guidelines:
>> > https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
>> > You received this message because you are subscribed to the Google
>> > Groups "nodejs" group.
>> > To post to this group, send email to nod...@googlegroups.com
>> > To unsubscribe from this group, send email to

>> > For more options, visit this group at
>> > http://groups.google.com/group/nodejs?hl=en?hl=en
>>
>> --
>> Job Board: http://jobs.nodejs.org/
>> Posting guidelines:
>> https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
>> You received this message because you are subscribed to the Google
>> Groups "nodejs" group.
>> To post to this group, send email to nod...@googlegroups.com
>> To unsubscribe from this group, send email to

>> For more options, visit this group at
>> http://groups.google.com/group/nodejs?hl=en?hl=en
>
>
> --
> Job Board: http://jobs.nodejs.org/
> Posting guidelines:
> https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
> You received this message because you are subscribed to the Google
> Groups "nodejs" group.
> To post to this group, send email to nod...@googlegroups.com
> To unsubscribe from this group, send email to

> For more options, visit this group at
> http://groups.google.com/group/nodejs?hl=en?hl=en
>
> --
> Job Board: http://jobs.nodejs.org/
> Posting guidelines:
> https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
> You received this message because you are subscribed to the Google
> Groups "nodejs" group.
> To post to this group, send email to nod...@googlegroups.com
> To unsubscribe from this group, send email to

> For more options, visit this group at
> http://groups.google.com/group/nodejs?hl=en?hl=en



--
Joshua Holbrook
Head of Support
Nodejitsu Inc.
jo...@nodejitsu.com

--
Job Board: http://jobs.nodejs.org/
Posting guidelines: https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
You received this message because you are subscribed to the Google
Groups "nodejs" group.
To post to this group, send email to nod...@googlegroups.com
To unsubscribe from this group, send email to

Rob Ashton

unread,
Jul 28, 2012, 5:26:59 AM7/28/12
to nod...@googlegroups.com
Well, I think if you're writing code against fs, you should test against fs

If you want the rest of your tests to go fast, you should fake out the bit which uses fs, not fs itself

Speaking in a general tone anyway, more context required for specific scenarios

Sent from my iPhone

>> >> For more options, visit this group at
>> >> http://groups.google.com/group/nodejs?hl=en?hl=en
>> >
>> >
>> > --
>> > Job Board: http://jobs.nodejs.org/
>> > Posting guidelines:
>> > https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
>> > You received this message because you are subscribed to the Google
>> > Groups "nodejs" group.
>> > To post to this group, send email to nod...@googlegroups.com
>> > To unsubscribe from this group, send email to

>> > For more options, visit this group at
>> > http://groups.google.com/group/nodejs?hl=en?hl=en
>>
>> --
>> Job Board: http://jobs.nodejs.org/
>> Posting guidelines:
>> https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
>> You received this message because you are subscribed to the Google
>> Groups "nodejs" group.
>> To post to this group, send email to nod...@googlegroups.com
>> To unsubscribe from this group, send email to

>> For more options, visit this group at
>> http://groups.google.com/group/nodejs?hl=en?hl=en
>
>
> --
> Job Board: http://jobs.nodejs.org/
> Posting guidelines:
> https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
> You received this message because you are subscribed to the Google
> Groups "nodejs" group.
> To post to this group, send email to nod...@googlegroups.com
> To unsubscribe from this group, send email to

> For more options, visit this group at
> http://groups.google.com/group/nodejs?hl=en?hl=en
>
> --
> Job Board: http://jobs.nodejs.org/
> Posting guidelines:
> https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
> You received this message because you are subscribed to the Google
> Groups "nodejs" group.
> To post to this group, send email to nod...@googlegroups.com
> To unsubscribe from this group, send email to

> For more options, visit this group at
> http://groups.google.com/group/nodejs?hl=en?hl=en



--
Joshua Holbrook
Head of Support
Nodejitsu Inc.
jo...@nodejitsu.com

--
Job Board: http://jobs.nodejs.org/
Posting guidelines: https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
You received this message because you are subscribed to the Google
Groups "nodejs" group.
To post to this group, send email to nod...@googlegroups.com
To unsubscribe from this group, send email to

For more options, visit this group at
http://groups.google.com/group/nodejs?hl=en?hl=en

--
Job Board: http://jobs.nodejs.org/
Posting guidelines: https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
You received this message because you are subscribed to the Google
Groups "nodejs" group.
To post to this group, send email to nod...@googlegroups.com
To unsubscribe from this group, send email to

jg

unread,
Jul 28, 2012, 10:05:24 AM7/28/12
to nod...@googlegroups.com
No.

mlegenhausen

unread,
Jul 29, 2012, 7:33:21 AM7/29/12
to nod...@googlegroups.com
There is another DI System called intravenous: https://github.com/RoyJacobs/intravenous which is inspired by the DI system from AngularJS.

henry....@sharelatex.com

unread,
Jul 29, 2012, 8:12:59 AM7/29/12
to nod...@googlegroups.com
The problem basically comes down to being able to mock/stub out the require module system, I am yet to see a nice simple way of doing it (if you have one please let me know!). This is solved in other languages like C# which uses Dependency injection with a container but in ruby you don't need to inject dependencies as its possible to directly mock things out (if I remember correctly). So DI is not it is not necessarily the best technique for javascript.

@Oliver Leics that looks a bit like how node-sandboxed works

@Rob Ashton For a unit test I don't really want to be hitting an external environment. A good example is if you make a http call to another api, at the unit test level you just want to make sure you are hitting the right url with the correct data. You can then write an integration test against this api to make sure you know how it behaves. 

>> >> For more options, visit this group at
>> >> http://groups.google.com/group/nodejs?hl=en?hl=en
>> >
>> >
>> > --
>> > Job Board: http://jobs.nodejs.org/
>> > Posting guidelines:
>> > https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
>> > You received this message because you are subscribed to the Google
>> > Groups "nodejs" group.
>> > To post to this group, send email to nod...@googlegroups.com
>> > To unsubscribe from this group, send email to

>> > For more options, visit this group at
>> > http://groups.google.com/group/nodejs?hl=en?hl=en
>>
>> --
>> Job Board: http://jobs.nodejs.org/
>> Posting guidelines:
>> https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
>> You received this message because you are subscribed to the Google
>> Groups "nodejs" group.
>> To post to this group, send email to nod...@googlegroups.com
>> To unsubscribe from this group, send email to

>> For more options, visit this group at
>> http://groups.google.com/group/nodejs?hl=en?hl=en
>
>
> --
> Job Board: http://jobs.nodejs.org/
> Posting guidelines:
> https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
> You received this message because you are subscribed to the Google
> Groups "nodejs" group.
> To post to this group, send email to nod...@googlegroups.com
> To unsubscribe from this group, send email to

> For more options, visit this group at
> http://groups.google.com/group/nodejs?hl=en?hl=en
>
> --
> Job Board: http://jobs.nodejs.org/
> Posting guidelines:
> https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
> You received this message because you are subscribed to the Google
> Groups "nodejs" group.
> To post to this group, send email to nod...@googlegroups.com
> To unsubscribe from this group, send email to

> For more options, visit this group at
> http://groups.google.com/group/nodejs?hl=en?hl=en



--
Joshua Holbrook
Head of Support
Nodejitsu Inc.
jo...@nodejitsu.com

--
Job Board: http://jobs.nodejs.org/
Posting guidelines: https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
You received this message because you are subscribed to the Google
Groups "nodejs" group.
To post to this group, send email to nod...@googlegroups.com
To unsubscribe from this group, send email to

For more options, visit this group at
http://groups.google.com/group/nodejs?hl=en?hl=en

--
Job Board: http://jobs.nodejs.org/
Posting guidelines: https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
You received this message because you are subscribed to the Google
Groups "nodejs" group.
To post to this group, send email to nod...@googlegroups.com
To unsubscribe from this group, send email to

Rob Ashton

unread,
Jul 29, 2012, 8:33:40 AM7/29/12
to nod...@googlegroups.com
I didn't say unit test.

If you want to stick a name on what I am saying, it's just classic ports and adapters http://c2.com/cgi/wiki?PortsAndAdaptersArchitecture

In your example, shifting it to the 'fs' sample, you'd be saying "write tests against 'fs' to make sure you know how it works" - but that's not a good use of time or energy, you're best of writing tests on the adapter that uses 'fs' to make sure your assumptions of how fs works are valid - it's a subtle difference, but an important one. You can then run those tests against an in memory version of your adapter, which you can make available for the rest of your tests - easily being able to switch these things around has a lot of value in some cases.

And just to be a pedant, use of a container in C# is how some folk in that world do dependency injection, some of us shy away from that and build up our object graphs manually and organically.

On a side note I think we should be careful in this kind of conversation (if we're even going to have it) to separate the needs of testing, the needs of extensibility - and what we call dependency injection, dependency inversion and inversion of control containers.




Rob Ashton

unread,
Jul 29, 2012, 8:36:23 AM7/29/12
to nod...@googlegroups.com
And I don't think the problem boils down to stubbing out the require system, the problem boils down to writing code that specifically opens itself up to testing and extension - 'Broadway' is an example of how to do this.

On Sun, Jul 29, 2012 at 2:12 PM, henry....@sharelatex.com <henry....@sharelatex.com> wrote:

Rob Ashton

unread,
Jul 29, 2012, 8:40:10 AM7/29/12
to nod...@googlegroups.com
Oh, and apologies to everybody that I even linked to a GoF related article on a node mailing list, I'll try not to do this again in the near future.

Rod Vagg

unread,
Jul 29, 2012, 8:44:15 AM7/29/12
to nod...@googlegroups.com
On Sun, Jul 29, 2012 at 10:33 PM, Rob Ashton <roba...@codeofrob.com> wrote:
 
On a side note I think we should be careful in this kind of conversation (if we're even going to have it) to separate the needs of testing, the needs of extensibility - and what we call dependency injection, dependency inversion and inversion of control containers.

+1

But, to go back to the discussion on testing, it seems that a lot of people are unaware of how easy it is to mock modules in Node. Remember that modules are cached by Node once loaded, so you can mess with them all you like prior to calling the code that's going to use it (unless require.cache is messed with afterwards)

You can take a module and throw Sinon at it and mock out all you need; a technique I'm using extensively for unit tests to isolate just the component I want. I find it particularly handy for 'fs' calls as they are annoying to set up fixtures for and make a mess if actually executed. Consider the following unit test in Ender that is only testing a small write module that needs to take an object that will provide some source text and write it to an appropriate location: https://github.com/ender-js/Ender/blob/1.0-wip/test/unit/write-test.js -- the source object is mocked, as is 'fs', so the only active code is the module being tested. The mocks are provided by Sinon which is built in to the BusterJS test framework in this case (which is why they are initialised with `this` and there is no explicit mock verify or clean up, it's all done automatically). And note, these are mocks, not stubs, so they contain test logic which must be conformed to.

Back to the issue of IoC/DI frameworks, here's a few more that may be worth a look: http://microjs.com/#IOC

 -- Rod

 

Eldar

unread,
Jul 29, 2012, 10:15:00 AM7/29/12
to nod...@googlegroups.com
Yeah, the topic's name is completely wrong. I realized it just right after posting but couldn't fix.

What I actually mean is: 
   Look, require('foo') is nothing but global var 'foo' except that it is scoped on module's level. Typically "it is set" by Node depending on your dirs layout. But why it couldn't be set from javascript?

Why it is useful:
  The ability to have global vars is useful in general. The simplest use case this feature will enable is an mocking something that couldn't be mocked globally for the entire app. There are surely other good (perhaps rare) use cases.

Is it deserves to be adopted?
  That's a question. There is a corresponding topic in the nodejs-dev mailing list.

PS: Sorry for the wrong title. This topic associates too much in my mind with dependency injection. 
  

Alan Gutierrez

unread,
Jul 29, 2012, 1:22:49 PM7/29/12
to nod...@googlegroups.com
On Fri, Jul 27, 2012 at 10:25:53PM -0700, mixu wrote:

> I've never really needed to dependency inject into third party modules. If I
> did, I'd rather fork the third party dependency than do some sort of dynamic
> solution.

That's part of what has changed with development since the rise of `git` and
`GitHub`. IoC tries to address the complexity of project lifecycles using design
patterns, but these days we tend to that through communication; issues and pull
requests.

The ability to get a patch into the source has given programmers more confidence
in their dependenies. They are no longer deferring decisions by "programming to
interfaces", but instead making a commitment to a dependency. C# and Java are
afraid of commitment, they see it as a potential hostage situation.

--
Alan Gutierrez - http://github.com/bigeasy - http://twitter.com/bigeasy

Rob Ashton

unread,
Jul 29, 2012, 1:35:15 PM7/29/12
to nod...@googlegroups.com
Haha, nicely put - I think also that code that is easy and non brittle
to change is much preferable than some of the designs that bad usage
of IOC containers leads towards

Not that I am suggesting this is what the OP wants, just where it may lead. :)

Sent from my iPhone

Alexey Petrushin

unread,
Mar 23, 2013, 9:24:20 AM3/23/13
to nod...@googlegroups.com
I recently wrote Micon https://github.com/alexeypetrushin/miconjs simple Dependency Injector, it's designed for server use, not browser.

mgutz

unread,
Mar 23, 2013, 7:02:01 PM3/23/13
to nod...@googlegroups.com
I thought about this the other day and it seems to me, if you were to use something like AMD (require.js), your container would be a simple configuration. This line is basically asking a container to provide a data provider with an id.

define(['dataProvider'], function(provider) {
});

Switching out providers is fairly easy as your container would define a mock provider in testing and the real one in live mode. This isn't exactly the heavy DI that's common in C#/Java. I've learned to accept simplicity is a good thing.

Eldar

unread,
Apr 20, 2013, 3:34:19 PM4/20/13
to nod...@googlegroups.com
That was a crazy idea and my goal was to find simple and clear way to swap fs for mkdirp

On Saturday, April 20, 2013 9:23:50 PM UTC+4, Scott Corgan wrote:
Easier? https://github.com/scottcorgan/Injector

Tim Boudreau

unread,
Apr 23, 2013, 5:17:10 AM4/23/13
to nod...@googlegroups.com
On Sunday, July 29, 2012 1:22:49 PM UTC-4, Alan Gutierrez wrote:
The ability to get a patch into the source has given programmers more confidence
in their dependenies. They are no longer deferring decisions by "programming to
interfaces", but instead making a commitment to a dependency. C# and Java are
afraid of commitment, they see it as a potential hostage situation.

That's an interesting and thoughtful take on dependency injection.  And for the uses Node is put to, it is likely usually to be true.

I think there is another element to it, though:  The fork-it model only really works when
 - The dependencies are packaged inside the software
 - The software is a static bundle of code and you replace the whole thing, not update parts
 - It does not do any dynamic loading of stuff not packaged with it - aka any sort of *runtime* "plugin" architecture

in other words, as soon as you have dynamic code-loading, or customers assembling custom distributions, if you want to give as close to the guarantee of reliability you could offer if you packaged it all yourself, you're back in interface-land.  Those things aren't generally issues if you're deploying a webapp you wrote on servers you control, and are more common for desktop software, but they are things that, as a framework matures, people tend to start trying to do.

-Tim

Alexey Petrushin

unread,
Jan 10, 2014, 12:40:24 PM1/10/14
to nod...@googlegroups.com
At last I can show concrete example proving that IoC may be useful, even in dynamic languages.

I always liked the simplicity of IoC concept - "You don't have to know anything about environment, you'll be called by someone when needed"

But all IoC implementations I saw did exactly the opposite - they clutter the code with even more things than without it. So, I created my own IoC that works as I'd like it to be - it stays hidden and invisible 90% of time.

It works like this - register component once in config:

    app.register('db', function(){
      return require('mongodb').connect(config.dbPath)
    })
  
And use it anywhere in application

    app.db.findSomething()

You can see the full component definition code (with DB Connection and other stuff) here https://github.com/sinizinairina/mono/blob/master/mono.coffee

This is the only place when you have to tell IoC what to do, after that all those components will be created and wired automatically and you don't have to see IoC specific code in your application anymore.

P.S. 

It may seems stupid - use IoC when you can easily wrote something like 

    app.db = require('mongodb').connect(config.dbPath)

But actually it's not - one thing - in code from above your application startup will take more time because it will wait until connection to
db has been created. With IoC it will be lazy initialisation - app started instantly, and db initialised only when needed.

Another thing, it start to pay more when there are different configuration environments like (dev, prod, test) and when code getting bigger and also dynamic components (that can be created and destroyed dynamically according to some rules) added to play, take look at this 

    app.register('controller', {scope: 'request'}, function(){new Controller()})

A new controller will be initialised for every request scope and destroyed when request will be finished. You can also add multiple components to this scope and all of them will be automatically created and destroyed when scope started and ended.
Reply all
Reply to author
Forward
0 new messages