Gaia/System/Refactoring Plan: Difference between revisions

From MozillaWiki
< Gaia‎ | System
Jump to navigation Jump to search
 
(26 intermediate revisions by 3 users not shown)
Line 1: Line 1:
== Meta bug ==
== Links ==
http://bugzil.la/system-app-v2
# [META] http://bugzil.la/system-app-v2
# [JSDOC] http://alivedise.github.io/gaia-system-jsdoc


== Target ==
== Target ==
The main purposes/targets are:
The main purposes/targets are:
# Minimize the memory usage of the system app
# More maintainable and testable
# Easier for a new contributor to jump in
# Scalable on multiple targets (TV, phone, tablet, ...)


# To be ready for a module loader, no matter it's harmony or require.
== Stages ==
# To figure out the dependency and unnecessary coupling
=== Stage.1 - Painless instantiation ===
# To document well by jsdoc. [SYSTEM-JSDOC] http://alivedise.github.io/gaia-system-jsdoc/
# To fit unit test well.
# To have scalability for different target devices like tablet, TV, or even PC.
# To be more friendly to be contributed.


== Stage.1 - Painless instantiation ==
'''Everything that has states need to be an instance, even if we only need one in the app.''' Rewrite all modules to be instantiable and rewrite unit tests, as well as JSDOC.  
Rewrite all modules to be instantiable and rewrite unit tests, as well as jsdoc.


The stage’s target is to make sure we could have the following pattern:
See [[Gaia/System/Refactoring_Plan#Stage_1_example|Stage 1 example]] for detail.
 
There are already bugs (87 bugs, excluding downloadmananger and fxaccounts for now. Take as you like!) of this stage for every js under the system app. See meta bug.
 
==== Initialization ====
 
'''We should not change where we initialize the instance of the module in this stage.''' We do this in Stage 1 to ensure we don't don't need to resolve the launching sequence puzzle for now. If the module your are dealing with simply start itself, feel free to add


<pre>
<pre>
// in bootstrap.js (main function, one line only expected.)
new System();


// in system.js
  /**
this.appWindowFactory = new AppWindowFactory(this);
  * Start ourselves
this.appWindowManager = new AppWindowManager(this);
  * XXX: To be moved.
this.screenManager = new ScreenManager(this);
  */
  window.foo = new Foo();
  window.foo.start();
 
</pre>
</pre>


With this pattern we are able to do unit test anywhere,
at the bottom of the file. If the module is initialized elsewhere, e.g. <code>bootstrap.js</code>, you can still safely do that there.
and there’s no architecture design involved in this stage.
 
Even a new employee could take one of the modules to rewrite it correctly.
'''Note'''
* You are required to resolve jshint errors in this stage and remove the file from blacklist.
* You are required to have unit tests in this stage.
* If you register any event listener in start(), '''remember to remove them in stop()'''. Otherwise, our unit tests will get confused because we run all unit tests in the same iframe and module dependencies will mess things up. For the self-initialized script, do call the <code>stop()</code> method on the "global" instance in the test <code>setup()</code>.


There are already bugs (87 bugs, excluding downloadmananger and fxaccounts for now. Take as you like!) of this stage for every js under the system app. See meta bug.
=== Stage.2 - Architecture love ===
==== Find out loading sequence and dependency relationships ====
1. File bugs to track all dependency resolving.


== Stage.2 - Architecture love ==
==== Do architecture review and rework case by case ====
# Find out loading sequence and dependency relationships
# Find the unnecessary module coupling and remove it.
# Do architecture review and rework case by case.
# Split a single "heavy-loading" module into different modules with its specific responsibility
## Find the unnecessary module coupling and remove it.
## For instance, split window manager into 3 pieces: manager, factory, and classes.
## Split a single "heavy-loading" module into different modules with its specific responsibility
# Move the static DOM elements into its responsible module and let the module render its own UI with whatever template engine.
### For instance, split window manager into 3 pieces: manager, factory, and classes.
# (optional) Use event emitter to replace DOM elements. (But we need to find out 'home' event replacement.)
## Move the static DOM elements into its responsible module and let the module render its own UI with whatever template engine.
# Find out patterns and figure out if we could group them.
## (optional) Use event emitter to replace DOM elements. (But we need to find out 'home' event replacement.)
## For example many modules are depending on a specific settings to be ON/OFF. Maybe we could lazy load them in a SettingsOberver.
## Find out patterns and figure out if we could group them.
### For example many modules are depending on a specific settings to be ON/OFF. Maybe we could lazy load them in a SettingsOberver.


Some candidate bugs for this stage:
==== Some candidate bugs ====
# Clean widget-like cost control
# Clean widget-like cost control
# Clean rocketbar
# Clean rocketbar
Line 51: Line 61:
# TrustedUI rework
# TrustedUI rework
# Keyboard management rework
# Keyboard management rework
# FxaAccount review
# DownloadManager review
# CardsView rework


== Stage.3 - Do experiments ==
=== Stage.3 - Do experiments ===
# We could start trying to load everything inside iframe as Vivien's lovely-proposal because we had the similar interfaces for modules now.
# We could start trying to load everything inside iframe as Vivien's lovely-proposal because we had the similar interfaces for modules now.
# We could introduce module loader solution in this stage. I personally isn't the fan of any of them so I don't insist on this item is must-have.
# We could introduce module loader solution in this stage. I personally isn't the fan of any of them so I don't insist on this item is must-have.
# Work out a clear proposal for system app for different kind of target devices.
# Do whatever you want - system should be stable enough now!
# Do whatever you want - system should be stable enough now!
== FAQ ==
=== How to run jsdoc locally? ===
<pre>
npm install
grunt docs
</pre>
and jsdoc will be generated to 'docs' folder
=== Stage 1 example ===
<pre>
'use strict';
(function(exports) {
  /**
  * DESCRIPTION-OF-THIS-MODULE.
  * @class Module
  */
  function Module() {
  }
  Module.prototype = {
    /**
    * DESCRIPTION-OF-IMPORTANT-PUBLIC-API
    * @memberof Module.prototype
    */
    show: function(data) {
      /**
        * DESCRIPTION-OF-THE-EVENT.
        * @event Module#i-am-displayed
        */
      this.publish('i-am-displayed');
    },
    /**
    * DESCRIPTION-OF-WHAT-START-DO
    * @memberof Module.prototype
    */
    start: function() {
      if (this._started) {
        throw 'Module XXX have already started.';
      }
      this._started = true;
      window.addEventListener('someevent', this);
    },
    /**
    * DESCRIPTION-OF-WHAT-STOP-DO
    * @memberof Module.prototype
    */
    stop: function() {
      if (!this._started) {
        throw 'Module XXX have not started.';
      }
      this._started = false;
      window.removeEventListener('someevent', this);
    },
    /**
    * DESCRIPTION-OF-EVENT-HANDLER
    * @memberof Module.prototype
    */
    handleEvent: function(evt) {
    },
    /**
    * DESCRIPTION-OF-IMPORTANT-PUBLIC-ATTRIBUTE
    * @memberof Module.prototype
    */
    state: 'begin'
  };
  exports.Module = Module;
}(window));
</pre>
[[File:jsdoc-sample.png|300px|thumb|left|Output with default theme]]

Latest revision as of 13:34, 22 February 2014

Links

  1. [META] http://bugzil.la/system-app-v2
  2. [JSDOC] http://alivedise.github.io/gaia-system-jsdoc

Target

The main purposes/targets are:

  1. Minimize the memory usage of the system app
  2. More maintainable and testable
  3. Easier for a new contributor to jump in
  4. Scalable on multiple targets (TV, phone, tablet, ...)

Stages

Stage.1 - Painless instantiation

Everything that has states need to be an instance, even if we only need one in the app. Rewrite all modules to be instantiable and rewrite unit tests, as well as JSDOC.

See Stage 1 example for detail.

There are already bugs (87 bugs, excluding downloadmananger and fxaccounts for now. Take as you like!) of this stage for every js under the system app. See meta bug.

Initialization

We should not change where we initialize the instance of the module in this stage. We do this in Stage 1 to ensure we don't don't need to resolve the launching sequence puzzle for now. If the module your are dealing with simply start itself, feel free to add


  /**
   * Start ourselves
   * XXX: To be moved.
   */
  window.foo = new Foo();
  window.foo.start();

at the bottom of the file. If the module is initialized elsewhere, e.g. bootstrap.js, you can still safely do that there.

Note

  • You are required to resolve jshint errors in this stage and remove the file from blacklist.
  • You are required to have unit tests in this stage.
  • If you register any event listener in start(), remember to remove them in stop(). Otherwise, our unit tests will get confused because we run all unit tests in the same iframe and module dependencies will mess things up. For the self-initialized script, do call the stop() method on the "global" instance in the test setup().

Stage.2 - Architecture love

Find out loading sequence and dependency relationships

1. File bugs to track all dependency resolving.

Do architecture review and rework case by case

  1. Find the unnecessary module coupling and remove it.
  2. Split a single "heavy-loading" module into different modules with its specific responsibility
    1. For instance, split window manager into 3 pieces: manager, factory, and classes.
  3. Move the static DOM elements into its responsible module and let the module render its own UI with whatever template engine.
  4. (optional) Use event emitter to replace DOM elements. (But we need to find out 'home' event replacement.)
  5. Find out patterns and figure out if we could group them.
    1. For example many modules are depending on a specific settings to be ON/OFF. Maybe we could lazy load them in a SettingsOberver.

Some candidate bugs

  1. Clean widget-like cost control
  2. Clean rocketbar
  3. Manage hardware dependent modules together by feature detection
  4. Split lockscreen
  5. TrustedUI rework
  6. Keyboard management rework
  7. FxaAccount review
  8. DownloadManager review
  9. CardsView rework

Stage.3 - Do experiments

  1. We could start trying to load everything inside iframe as Vivien's lovely-proposal because we had the similar interfaces for modules now.
  2. We could introduce module loader solution in this stage. I personally isn't the fan of any of them so I don't insist on this item is must-have.
  3. Work out a clear proposal for system app for different kind of target devices.
  4. Do whatever you want - system should be stable enough now!

FAQ

How to run jsdoc locally?

npm install
grunt docs

and jsdoc will be generated to 'docs' folder

Stage 1 example

'use strict';

(function(exports) {

  /**
   * DESCRIPTION-OF-THIS-MODULE.
   * @class Module
   */
  function Module() {
  }

  Module.prototype = {

    /**
     * DESCRIPTION-OF-IMPORTANT-PUBLIC-API
     * @memberof Module.prototype
     */
    show: function(data) {
      /**
        * DESCRIPTION-OF-THE-EVENT.
        * @event Module#i-am-displayed
        */
       this.publish('i-am-displayed');
    },

    /**
     * DESCRIPTION-OF-WHAT-START-DO
     * @memberof Module.prototype
     */
    start: function() {
      if (this._started) {
        throw 'Module XXX have already started.';
      }
      this._started = true;
      window.addEventListener('someevent', this);
    },

    /**
     * DESCRIPTION-OF-WHAT-STOP-DO
     * @memberof Module.prototype
     */
    stop: function() {
      if (!this._started) {
        throw 'Module XXX have not started.';
      }
      this._started = false;
      window.removeEventListener('someevent', this);
    },

    /**
     * DESCRIPTION-OF-EVENT-HANDLER
     * @memberof Module.prototype
     */
    handleEvent: function(evt) {
    },

    /**
     * DESCRIPTION-OF-IMPORTANT-PUBLIC-ATTRIBUTE
     * @memberof Module.prototype
     */
    state: 'begin'
  };

  exports.Module = Module;

}(window));
Output with default theme