nasa / openmct

A web based mission control framework.
https://nasa.github.io/openmct/
Other
11.99k stars 1.24k forks source link

[API] Decide on role of Angular #461

Closed VWoeltjen closed 8 years ago

VWoeltjen commented 8 years ago

Meeting scheduled for week of Jan 11. Need to decide on role of Angular within Open MCT Web. Want to capture results in a trade study.

From refactoring plan:

It will be necessary to have a decision about the role of Angular at this point; are extensions registered via provider configuration (Angular), or directly in some exposed registry?

VWoeltjen commented 8 years ago

@larkin's notes from meeting 1/12/2016:

Why are we having this discussion?

  • Angular 1 is going to be end-of-lifed, will need to transition
  • We want developers to be able to contribute without having to write angular code.
  • Angular doesn't like playing with other code.
  • Angular flow control is hard to reason about.

We don't feel that end of life or transition is bad, but we don't feel that we can commit 100% to angular, and a partial commitment to angular is bad.

The Angular Decision

  • [ ] The Whole Shebang (we're an angular shop)
  • [ ] Just a little bit (views? di? which api is this? confusion never ends)
  • [ ] Not at all (requires a lot of time.)
  • [x] Just a little bit on the way to not at all. (not to hot, not to cold, it's juuuust right)

What are we using angular for?

  • Dependency Injection / Modularization.
    • Alternative: RequireJS w/ some kind of service registry singleton
    • component needs a service registry. Constructor receives service registry. later, register it and expect registration to acquire dependencies?
  • General Separation of Concerns
    • MVC Ish.
    • factories / providers.
    • directives for reusable view components.
  • Routing (barely)
  • View Management (What content goes in a specific place)
    • Template Rendering (ng-show, ng-if, ng-repeat, ng-class, ng-style)
    • Event Binding (mct-drag, mct-click-elsewhere, mct-splitters, mct-popup, mct-resize, mct-scroll)
    • Region Management (mct-representation, mct-container, mct-include)
    • Data Binding / Interpolation (To all of the above)
    • Form Management (mct-control, mct-form, mct-toolbar, ng-model)
  • Data flow via scopes (how does each component receive dependencies)
  • Services libraries ($http, $q, $timeout, $interval, $log)
  • jqlite (simple dom manipulation)

Simplified: 3 things we use angular for

  • View Components (toolbars, buttons, etc)
  • Dependency Injection
  • Service Registries

Replacements:

  • Any sort of generic view system
  • requirejs for script loading & internal dependency loading
  • Custom type registries

@VWoeltjen's BLUE SKY

  • Web Components w/ custom elements for views (polymer as fallback)
  • script loading: requirejs.
  • no dependency injection system, just a style.
  • custom registries for extension mechanism.

@larkin's BLUE SKY

  • generic view registration (new View(options))
    • options is an option containing data the view needs to display.
    • view must have an 'element' property, a DOM element which must be attached to the DOM bythe dom element which must be added to a container);
    • view has a render method which rerenders it.
    • view may have a "show" method when it is fully visible in the DOM
  • some kind of router/controller/region management system
  • script loading: requirejs.
  • no dependency injection system, just a style.
  • custom registries for extension mechanism.

@akhenry's BLUE SKY

It's grey, actually. /londonjoke

@Costigan's BLUE SKY

  • react/mithril
  • same as above ish
  • unidirectional flow / stateful components

@larkin also summarizes the decision nicely:

I think we should put a blue sky stake in the ground and work towards that point over a number of releases. We have a lot on our plate with the current API revisions and will have to plan accordingly.

Near-term, the first step along that path is to refactor the registration API to be independent of Angular's DI mechanism. There's design/implementation work there (which would also be there if we were to go full-Angular, it would just look a lot different). Referring back to the refactoring plan (http://nasa.github.io/openmctweb/design/planning/APIRefactor.html), we can design/implement the general pattern first (allowing for a one-to-one mapping of our existing components), and then go case-by-case on some of the abstractions we want to change more fundamentally (views, capabilities, etc) in a priority-driven order.

The expectation is that the API refactoring approach will not bring us to our "blue sky stake in the ground", but that it brings us to a point where we:

VWoeltjen commented 8 years ago

Some notes on relevant trades:

Plugin Mechanism

Angular's DI is currently utilized to support "wiring up" software components introduced by plugins. Per API Redesign Proposals (#69), we wish to switch to an imperative approach to this. This imperative approach could be built on Angular, or not.

Basic requirements for basic parity with current bundle:

Example using Angular:

var myPlugin = angular.module('my-plugin', [ 'mct' ]);
// One-to-one
myPlugin.service('fooService', ['barService', function (barService) {
    return new FooService;
});
// Many-to-one, via registries
myPlugin.configure('fooRegistryProvider', function (fooRegistryProvider) {
    fooRegistryProvider.register([ 'bar', function (bar) {
        return new Foo(bar);
    });
});
// Decoration
myPlugin.decorate(barService, ['bazRegistry', '$delegate', function (bazRegistry, $delegate) {
    return new DecoratedBarService(bazRegistry, $delegate);
}]);

Example of non-Angular:

var mct = require('mct'), myPlugin = new mct.Plugin();
// One-to-one
myPlugin.fooService = new FooService(mct.barService);
// Many-to-one, via registries
mct.fooRegistry.register(new Foo());
// Decoration
mct.fooService = new DecoratedFooService(mct.fooService);
module.exports = myPlugin;

(Note that the above are illustrative only - they do not reflect priority, and may have sensitivity to execution ordering. These details are intended to be addressed in #461, in either case.)

Feature Angular Non-Angular
One-to-one Provided by Angular Needs some implementation
Many-to-one Need to implement RegistryProvider base classes Need to implement Registry base classes
Decoration Provided by Angular Needs some implementation
Priority ordering Needs implementation (hard to reconcile against Angular's normal behavior) Needs design, implementation

Using Angular to facilitate connecting application components reduces but does not remove implementation effort, and introduces barriers to handling priority ordering effectively. The non-Angular approach incurs that cost (expected to be modest) and provides additional benefits:

Given this, prefer to accept a modest increase in initial design/implementation cost (and corollary increase in scope of code maintained) in order to enjoy the various benefits above.

View Definition & Registration

Angular provides a powerful templating language and an effective paradigm for ensuring consistency of UI state and underlying data model. This frequently comes with a performance cost, and can cause difficulty when integrating non-Angular UI components; these need to be "wrapped" in an Angular directive or similar. (This was cited as a pain point for plugin developers in #69)

Due to the number of UI components currently written as Angular templates (and dependent on Angular controllers, etc.) it is impractical to move away from Angular in this area, at least in the immediate future.

Specific details are left to #463, but preferred approach here is to introduce (or use a third-party's version of) a simple, general-purpose interface which UI components can be wrapped in for interoperability.

Cost:

Benefits:

Service Libraries

Angular's various utility services ($http, $timeout, etc.) mostly exist to do one or more of the following:

  1. Integrate asynchronous behavior into Angular's digest cycle ($timeout, $q, $http)
  2. Interact directly with Angular concepts ($rootScope, $parse)
  3. Provide a simple interface for common tasks ($http)
  4. Encourage usage of dependency injection ($window)

1 and 2 only add value in the context of Angular; they do not factor in any trade for or against usage of Angular.

3 is valuable generally, but same benefits can be achieved with more narrowly-scoped libraries. (Or, may eschew "simple interface" and just use native APIs)

4 has value, but same value can be had by adopting DI as a coding style.

As such, Angular's library of services does not add sufficient value to factor into broader Angular trade.