be warned this is mostly a stef.braindump
that was re-awakened by a discussion on Reddit
This document will also likely change and improve as the ideas iterate and mature.
Currently our dependency injection framework provides us with scope level injection rules, that typically run at app initialization.
App-wide Rules
(local rule-sets are possible, but not thoroughly hashed-out yet)
// assume app-wide scope
App.inject(thingToInjectOn, property, thingToInject);
App.register(thingToInject, factory);
App.register('store:main', Store);
// example form ED. Injection on all contorllers
App.inject('controller', 'store', 'store:main');
// injection on a specific controller
App.inject('controller:person', 'facebook', 'service:facebook');
Specifying Inter-controller dependencies:
For this we have lazy property style injections, but with at instantiation time verification. This means we donāt inject at construction time, but if you instantiate the controller, and its cannot be satisfied, we throw an exception. Also the āneededā things themselves are instantiated on demand.
B = Ember.Controller.extend({});
A = Ember.Controller.extend({
needs: ['b']
}};
The Concern
I feel the global rules are powerful, and enable many use cases, but I am concerned the locality of some of the global rules, specifically for injections related to a single object.
For example, when specifying the following rule, in an app initializer, their may be no mention of FacebookService
within the PersonController
.
App.inject('controller:person', 'facebook', 'service:facebook');
So, often to prevent this situation, my team and I, annotate our definitions.
PersonController = Ember.Controller.extend({
facebook: null // set by injection
})
Part of me thinks that this annotation feels as it should be the location of the rule itself.
An idea for the future
allow for at-design-time class level injection rules to be specified.
As the entity is resolved, we load additional rules that it provides. These rules should be limited to rules describing injections on itself.
If at instantiation time, or at factory lookup time these rules cannot be satisfied, we should error.
Some random API ideas
B = Ember.Controller.extend({
needs: ["service:facebook"] // by convention would become a property: services.facebook
injections: // some DSL for injections
// or maybe a more direct
facebook: Ember.inject("service:facebook"),
facebook: Ember.needs("service:facebook")
});
notes:
Now some may point-out that today a simple computed property could solve this.
facebook: function() {
return this.container.lookup('service:facebook')
}.property()
This is not entirely true, as this isnāt at design time, and isnāt verified possible until runtime. Which means, if the injection was forgotten, or something went wrong. You wont know until this code path is exercised.