Summary
Fully encapsulate and privatize the Container and Registry classes by
exposing a select subset of public methods on Application and
ApplicationInstance.
Motivation
The Container and Registry classes currently lead a confusing life of
semi-private exclusion within Ember applications. They are undocumented
publicly but not fully private either, as knowledge of their particulars is
required for developing both initializers and unit tests. This situation has
become untenable as the new Registry class has been extracted from
Container, and the complexity of their usage has grown across
Application and ApplicationInstance classes.
We can bring sanity to this situation by continuing the work started at the
Application level to expose methods such as register and inject from the
internally maintained Registry.
Furthermore, once Container and Registry are fully private, their
architecture and documentation can be cleaned up. For instance, a
Container can freely reference its associated Registry as registry
rather than _registry, as it can be assumed that only framework developers
will reference this property.
Detailed design
Application will expose the following methods from its internally maintained
registry:
registerinjectregisterOptions- mapped toRegistry#optionsregisterOptionsForType- mapped toRegistry#optionsForType
ApplicationInstance will also expose the the same methods. However, these
methods will be exposed from its own internally maintained registry, which
has the associated Application's registry configured as a "fall back". No
direct path will be provided from the ApplicationInstance to the
Application's registry.
ApplicationInstance will also expose the following methods from its
internally maintained container:
lookuplookupFactory
ApplicationInstance will cease exposing container, registry, and
applicationRegistry publicly.
Application initializers will receive a single argument to initialize:
application.
Likewise, ApplicationInstance initializers will receive a single argument
to initialize: applicationInstance.
Container and Registry will be made fully private and documented as
such. Each Container will freely reference its associated Registry as
registry rather than _registry.
ember-test-helpers
will provide an isolatedApplicationInstance method instead of an
isolatedContainer for unit testing. A mechanism will be developed to specify
which initializers should be engaged in the initialization of this instance.
In this way, we can avoid duplication of registration logic, as is currently
done in a most un-DRY manner in the isolatedContainer.
Drawbacks
This refactor will require maintaining backwards compatibility and deprecation warnings until Ember 2.0. This will temporarily increase internal code complexity and file sizes.
Alternatives
The obvious alternative is to make Container and Registry fully public
and documented. An application's registry would be available as a registry
property. An application instance's container would remain available as
container.
We could still pass an Application into application initializers
and an ApplicationInstance into application instance initializers.
If this alternative is taken, I would suggest that Application should
deprecate register and inject in favor of calling the equivalents on its
public registry.
Regardless of which alternative is chosen, we should ensure that the public aspects of container and registry usage are well documented.
Unresolved questions
Are the public methods listed above sufficient or should any others be exposed?
What mechanism should be used to engage initializers in unit and integration tests? Should test modules simply have an
initializersarray, similar to the currentneedsarray?Given the semi-private nature of containers and registries, we may not need to worry about semver for deprecations. However, we should be good citizens and properly deprecate as much as possible. Some real world use cases in initializers will no doubt be a surprise, so we need to tread carefully.