As you can tell I am a big fan of DI, but I kept hearing that DI is not needed with dynamic languages, so after using JS for many months I am happy to say that DI is important there as well. In other words dependency managment and controll matters. But it is different.
Say you have a class for greeting with DI.
class Greeter { String greeting; Greeter(String greeting) { this.greeting = greeting; } void greet(String name) { System.out.println(this.greeting + name); } }
Since the class only has one responsibility it only has one method. Now we can rewrite this in JavaScript in OO way like this:
function Greeter(greeting) { this.greeting = greeting; } Greeting.prototype.greet = function(name){ alert(this.greeting + name); };
While this code is fine, it does not follow the spirit of JavaScript which is a functional language. Why have a Greeter noun when you can just have greet verb. (see: Execution in the kingdom of nouns) So let’s rewrite it in functional style:
function greetFactory(greeting) { return function(name) { alert(greeting + name); }; }
so usage changes from:
var greeter = new Greeter('Hello '); greeter.greet('misko');
to:
var greet = greetFactory('Hello '); greet('Misko');
Notice that in all cases the DI of greeting is preserved just fine. Now here comes an interesting thing. Objects have scopes. For example the alert method in JavaScript (or System.out.println method in Java) needs to be DI as well since we want to verify that the right thing is printed in test. But the alert method needs to be injected not just into our function but most likely into hundreds of other functions in our application. It is kind of a singleton. So in java we have to do this:
class Greeter { String greeting; OutputStream out; Greeter(OutputStream out, String greeting) { this.out = out; this.greeting = greeting; } void greet(String name) { out.println(this.greeting + name); } }
The JavaScript equivalent would be:
function greetFactory(alert, greeting) { return function(name) { alert(greeting + name); }; }
But that means that we are no better than Java in injecting the same thing everywhere. The trick is in realizing that object injection is nested in scopes, and that every factory which needs alert share the same alert so we can rewrite this like this;
function createFactories(alert) { return { greetFactory: function(greeting) { return function(greet) { alert(greeting + greet); }; }, someOtherFactory: function(...) { return function(...){ alert(...); }; } }; }
When you are ready to bootstarap your app you can:
var factories = createFactories(myAlert); var greet = factories.createGreet('Hello '); greet('Misko');
21 responses so far ↓
I’m glad to see this post addressing the need for dependency injection in dynamic languages. Declaring a closure inline is the same as newing up a service object in the middle of business logic. It is just as easy to mix solutions into imperative code in a dynamic language as it is in a statically typed language. Regardless of the imperative construct (functions or classes), there needs to be a separation so that declarative solutions may be composed from the imperative building blocks. This is the heart of writing high-quality maintainable code.
@jon,
fully agree, but I find it interesting that closures offer a new way of doing dependency injection which is more concise.
I’m no JS expert but haven’t you mixed up some variable names (Greeter vs. Greeting, greetFactory vs. createGreet)?
When you have more than one global service would you do createFactories(global1, global2, …)?
Functional DI looks very concise! Thanks.
Nice. Yes, closures ftw.
Being able to use vars in outer scope, and write functions inline (lambdas) simplifies so many problems it is ridiculous…
Interesting post. It looks like the “Dependency Injection As Function Currying” (http://debasishg.blogspot.com/2010/02/dependency-injection-as-function.html) idea implemented in a language lacking syntactic support for currying.
But there are other ways to think about DI in other “dynamic languages”, for instance check out how Fabio Kung’s post on using ruby mixins to provide dependencies: http://fabiokung.com/2010/05/06/ruby-and-dependency-injection-in-a-dynamic-world/
Pedro Newsletter 31.05.2010 « Pragmatic Programmer Issues – pietrowski.info // May 31, 2010 at 1:54 pm
[...] Misko Hevery article: Dependency-injection and JavaScript closures. [...]
Yea a nice piece of script here i really appericiate this person who post his script and article
I would actually opt to inject the function as well:
(function greetFactory(out, greeting) {
return function(name) {
out(greeting + name);
};
})(alert, “Hello”)(“World”);
Nevermind… after a re-read I realized you did exactly this. Naming the callback “alert” confused me.
last lines should look like this:
var factories = createFactories(myAlert);
var greet = factories.greetFactory(‘Hello ‘);
greet(‘Misko’);
cheers
You’ve previously said that you think static functions are not OK and death to testability. But isn’t the createFactories function equivalent to a static function? Did you change your mind and accept that static functions are OK as long as you inject dependencies (in this case a pointer to another static-like function)?
Otherwise I’m a bit puzzled. You said before that the important part is that your tests must be able to prevent the execution of normal code path (or else you would end up with scenario tests instead of unit tests).
@ Johan,
I think I got caught red handed. You bring up a good point which I did not think about. You are correct that in this example the factory is a single method without a class which is a static method. But closures kind of undo the staticness of it. In java a static method is static and it has all of the issues I mentioned before, but in JavaScript the method has closure (variables declared outside of the method). This makes the method act as a class to which you pass the dependencies through the constructor (closure) and the class has single method which performs the action (equivalent to just calling the method).
So in JavaScript a method without a class has injection (closure) but it also has polymorphism, since the method is passed into the consumer, and you can always inject a different method for testing. So closure and methods as first class citizens undo the static method problem of Java.
How do you answer to critique like: http://discuss.joelonsoftware.com/default.asp?joel.3.219431 ? I understand that the motivation you present here is different than the one attacked by Joel – but still it is undeniable that very high level functions are just difficult to think about.
Thank you for a very interesting post.
What if the example had two verbs, acting on the same structure (f.ex in java service.start/service.stop). Would you still go for verbs like stopService/startService? Or would you introduce the service-noun to connect the two? (and what if there were 3, 4, 5 verbs etc. ? When would you use nouns/objects?)
@Sjur,
Nouns and verbs need to be in balance. So perhaps a class (noun) is needed in your case to join the two.
Misko,
I’m confused by this example and how to reconcile this with previous advice you’ve given about newables and injectables.
Is the Java Greeter class intended as an injectable or newable? It seems intended as an injectable since the article revolves around the ‘greet’ verb. But you’ve said previously (http://misko.hevery.com/2008/09/30/to-new-or-not-to-new/) that “Injectable can never ask for a non-Injectable (Newable) in its constructor”. Clearly though here ‘greeting’ is a newable since it is a String.
But if Java Greeter is not intended as an injectable and is instead intended as a newable, then the whole example kind of falls apart since the example is about injectables but newables can’t be injected into injectables, so I assume that Greeter is probably not intended as a newable.
In any case, I’m been trying to resolve this in my head unsuccessfully. Have you changed your mind about injecting newables into injectables or (more likely) am I misunderstanding something?
@Scott,
very good observation! The issue with newables and injecting them in, is that the injector does not know how to make a String. Not any string will do, only a specific one in this case. So the rule holds, but in this case the String acts as a configurable constant. You would not instantiate the constant in your code, like you may instantiate an array or a hash, instead you expect someone to give you the configuration constant. Hence it should be injected.
Thanks, Misko! I think that I understand what you are saying. Would it then be accurate to state the following?:
An injectable can ask for a newable (or a primitive type) in its constructor when the newable is used for configuration of the injectable and when the injectable treats the newable as a constant. So injecting, for example, an URL or a timeout value in an injectable might be an acceptable use when these are used by the injectable as constants for its configuration.
Is that understanding correct or did I mangle the message? Thanks!
@Scott,
yes, that is right on.
Some useful readings | Joshy's microblog // Jan 19, 2012 at 9:42 am
[...] http://misko.hevery.com/2010/05/29/dependency-injection-and-javascript-closures/ [...]
In AngularJS we rely on the framework to instantiate our services (dependencies). So what if our service needs constructor parameters. How would AngularJS instantiate such a service:
var RobotGreeter = function(name) {
return {
greet: function() {
console.log(‘Hello ‘+name);
}
};
};
greet() would surely return ‘Hello undefined’