patternjavascriptMinor
Backbone.js Dependency Injection API Design
Viewed 0 times
designdependencybackboneinjectionapi
Problem
I'm writing a dependency injection plugin for the Backbone javascript framework, and I'm not sure what the API for constructor argument injection should look like.
Just for reference, Backbone objects are defined as follows:
My plugin supports instance property injection as follows:
I'm quite happy with this, but I also want to support constructor argument injection. Here I have run into doubt regarding best way forward. Here are the options I've considered:
-
Add class method
This is clean, but it "hides" the injection to the bottom of the class definition. I feel the constructor injection configuration should be somewhere near the constructor, at the very least.
-
Wrap the
Now the injected arguments are right next to the constructor definition, but this gets a bit messy when you have more than one or two dependencies:
```
var LoginView = Backbone.View.extend({
initialize: needs.args(
{ foo:'Foo', bar:'Bar' },
'BazService',
'QuxFactory
Just for reference, Backbone objects are defined as follows:
var LoginView = Backbone.View.extend({
//constructor
initialize: function(options) {
//define an instance property
this.loginProvider = options.loginProvider;
},
//method
authenticate: function() { },
//prototypal property (available via instance, shared between all instances)
navigation: App.navigationService
});My plugin supports instance property injection as follows:
var LoginView = Backbone.View.extend({
//...
loginProvider: needs.property('LoginProvider')
});
var loginView = new LoginView();
loginView.loginProvider.doLogin(); //loginProvider is auto-injectedI'm quite happy with this, but I also want to support constructor argument injection. Here I have run into doubt regarding best way forward. Here are the options I've considered:
-
Add class method
injectvar LoginView = Backbone.View.extend({
initialize: function(options, bar) {
//property "foo" will be injected to options
//second argument "bar" will be injected
}
}).inject({foo:'Foo'}, 'Bar');This is clean, but it "hides" the injection to the bottom of the class definition. I feel the constructor injection configuration should be somewhere near the constructor, at the very least.
-
Wrap the
initialize methodvar LoginView = Backbone.View.extend({
initialize: needs.args({foo:'Foo'}, 'Bar', function(options, bar) {
//property "foo" will be injected to options
//second argument "bar" will be injected
}
});Now the injected arguments are right next to the constructor definition, but this gets a bit messy when you have more than one or two dependencies:
```
var LoginView = Backbone.View.extend({
initialize: needs.args(
{ foo:'Foo', bar:'Bar' },
'BazService',
'QuxFactory
Solution
If I had to pick, I would pick the second option. It's the clearest to me and aligns well with how the plugin injects properties. I don't think it's "lying" to the user because it's obvious that the needs.args function is doing something with the arguments before passing back control to the actual initialize function. But like you said, long arg lists will be annoying.
My only other note would be that I'm unsure how useful injection is in a dynamic language like javascript. I've used in statically typed languages like Java where it's definitely useful, but never entertained the idea in js. I'd definitely be curious to see the final result.
Edit: After some research there looks like another alternative - reflection: http://merrickchristensen.com/articles/javascript-dependency-injection.html
My only other note would be that I'm unsure how useful injection is in a dynamic language like javascript. I've used in statically typed languages like Java where it's definitely useful, but never entertained the idea in js. I'd definitely be curious to see the final result.
Edit: After some research there looks like another alternative - reflection: http://merrickchristensen.com/articles/javascript-dependency-injection.html
Context
StackExchange Code Review Q#21514, answer score: 2
Revisions (0)
No revisions yet.