Isis 是 Task Tracer GUI 的名字。
它會從特定的 log 格式產生如上的圖示:以 event type 來顯示 task 被執行的順序。

Thread Scheduler

為了測試這個工具,我另外做了簡易版的 Thread Scheduler 去模擬以下情境:

  • 模擬系統開機後會建立數個不同的 Thread,各自有名字:'UI', 'worker', 'BT', 'NFC', 'Telephony', 'Main', 'IO'
  • 事先亂數產生一些由任意數量 Task 組成的任務
  • 單一 Task 會屬於某個特定 Thread
  • 單一 Task 在產生時的執行時間已經決定了
  • 單一 Thread 同時間只能執行一個 Task,其他的請求會進入 pool 內等待正在忙碌的 Task 完成。

用 Javascript 來模擬這些事情並不難:

  • 設計 Task 類別
  • 設計 Thread 類別
  • 設計 Mission 類別用以產生並記錄一連串的 Task
  • 使用 Factory Pattern 創造 Thread
  • 使用 Manager Pattern 管理 Thread
  • 定義數個 Mission
  • Thread 用 setTimeout 來管理 Task
  • Task 用 Date.now() 來記錄狀態改變的時間

在寫這個的時候讓我想起作業系統課寫過的 Page Allocator,
如果再加入 Memory 狀態的話搞不好還可以順便模擬 Context Switch。

時光機器

回到正題,我的目標是想要很快的產生出一整組完整的測試資料,
但是 setTimeout 很明顯會無法達成這件事。

想到的解決方式是利用 sinonjs 的 fake timer 來 hack setTimeout 以及 Date

  var TimeMachine = {
    init: function() {
      this.start = Date.now();
    },
    startSimulation: function(done) {
      var clock = sinon.useFakeTimers(0, 'setTimeout', 'clearTimeout',
                                      'setInterval', 'clearInterval', 'Date');
      for (var i = 0; i < randomCount(10) + 1; i++) {
        var mission = new Mission();
      }

      clock.tick(1000000000);

      clock.restore();
      if (typeof(done) == 'function') {
        setTimeout(done);
      }
    },
    now: function() {
      return (Date.now());
    }
  };

時光機器果然一下子就讓需要等 1000000000ms 的程序結果出現了。

我沒有仔細看裡面的實作,不過我想是我的話:

  1. 替換 window.setTimeout 變成一個自己的函示,並在內部紀錄所有 callback。
  2. 替換 window.Date 變成自己的物件
  3. 實作 tick:用迴圈去更新 Date.now() 並且在該呼叫 callback 的時候呼叫。

Happy New Year!
At the very first day of 2014,
several things I'd love to tackle in this year:

FirefoxOS projects

  1. System App Modualization
  2. Gaia Audio Channel Service
  3. Window Management v.next
  4. Hardware Button Events
  5. Password Manager
  6. Task Tracer

Side projects

  • Map Generator - I'd like to have a map generator: Seas, Lands, Lakes, Mountains, Roads. And finally Tribes, Cities and Nations.

Technology revolution

  • Try to write blog post every day.
  • Try to help somebody has difficulties on Web.
  • Be positive!

請叫我重構控

基於個人興趣,最近(其實,就是今天... XD)在重構 Cleopatra (Mozilla Profiling GUI) 的時候碰到一個小問題:

window.postMessage 有辦法在接收端有辦法用 handleEvent 的介面來改寫嗎?
畢竟接收也是透過 window.addEventListener 來收訊息。

修改前
window.addEventListener("message", function messageFromAddon(msg) {
  // This is triggered by the profiler add-on.

  var o = JSON.parse(msg.data);
  switch (o.task) {
    case "importFromAddonStart":
      var totalReporter = enterProgressUI();
      gImportFromAddonSubreporters = totalReporter.addSubreporters({
        import: 10000,
        parsing: 1000
      });
      gImportFromAddonSubreporters.import.begin("Symbolicating...");
      break;
    case "importFromAddonProgress":
      gImportFromAddonSubreporters.import.setProgress(o.progress);
      if (o.action != null) {
          gImportFromAddonSubreporters.import.setAction(o.action);
      }
      break;
    case "importFromAddonFinish":
      importFromAddonFinish(o.rawProfile);
      break;
  }
});
修改後
var App = {
  init: function app_init() {
    window.addEventListener('message', this);
    window.addEventListener('click', this);
  },
  
  handleEvent: function app_handleEvent(evt) {
    switch (evt.type) {
        case 'message':
        this._handleMessage(evt.data);
        break;
      case 'click':
        break;
    }
  },
  
  _handleMessage: function app__handleMessage(data) {
    var o = JSON.parse(data);
    switch (o.task) {
      case "importFromAddonStart":
        var totalReporter = enterProgressUI();
        gImportFromAddonSubreporters = totalReporter.addSubreporters({
          import: 10000,
          parsing: 1000
        });
        gImportFromAddonSubreporters.import.begin("Symbolicating...");
        break;
      case "importFromAddonProgress":
        gImportFromAddonSubreporters.import.setProgress(o.progress);
        if (o.action != null) {
            gImportFromAddonSubreporters.import.setAction(o.action);
        }
        break;
      case "importFromAddonFinish":
        importFromAddonFinish(o.rawProfile);
        break;
    }
  }
};
App.init();

Make a guess?

答案是可以

因為 MessageEvent 是繼承自 Event
證明在此:http://jsfiddle.net/alivedise/Nqm6S/

Which one is better?

1.Closure

function Class(){
   this.foo = functoin(){

   }
}

2.Prototype

function Class() {}
Class.prototype.foo = function() {

}

My answer is #2

  1. All method/object under prototype is shared among all instances. Memory free.
  2. Prototype is faster than closure when instanciating http://stackoverflow.com/questions/3493252/javascript-prototype-operator-performance-saves-memory-but-is-it-faster/4041582#4041582
  3. Closure is good for having private members, but private means not white-test-able.

  1. If your property/method doesn't appear after running doc generation,
    that means you need to specify @memberOf in object literal


    /**
    
    
    • My module
    • @module moduleA /
    var moduleA = { /*
  2. Init process
  3. @memberOf module:moduleA */
  4. init: function() { } };
    But if you are using prototype, you don't need to do this; jsdoc would know the relationship.

  5. {@private|@access private} marked section would not appear in the document unless you do specify -p when running jsdoc.

  6. If your google closure linter is not happy when you do |git commit|, add a tag here:
    https://github.com/mozilla-b2g/gaia/blob/master/Makefile#L878

  7. Use conf.json to release you from typing a long command to generate the docs. Mine: https://gist.github.com/alivedise/7904430

  8. Since jsdoc supports markdown, there's nothing could prevent us from having an architecture diagram image in the doc instead of drawing with ASCII characters.
    Sample: http://alivedise.github.io/gaia-system-jsdoc/module-AppWindowManager.html#init
    (I'm using http://cacoo.com but open to know if there's any better solution for making diagrams/flowcharts.)

http://alivedise.github.io/gaia-system-jsdoc/AppWindow.html

Just one year ago, in the snowy city, Berlin, I orally described this idea to Vivien and initialed this project with the first file (window.js) - Window management system rework. What I didn't knew then was, this work took me the whole year to come to an end.

During this year, I failed and restarted the work many many many times. Countless conflicts, regressions, testing failures, old bugs, invisible traps and tears

Finally this day comes: suddenly, everything is set up. People come to help and/or support me for testing, documentation, reviewing. The future OS wide improvement plan is there awaiting the new system to exploit its full power.

Thanks everyone involved!

最近才知道 Array 裡面有三個看似相同其實不同的 iterator,這邊做個筆記:

Array.prototype.forEach(iterator, [scope])

無法用任何方式中斷直到循序跑完整個陣列

Array.prototype.every(iterator, [scope])

會循序執行 iterator 到 iterator function 回傳 false 為止

Array.prototype.some(iterator, [scope])

會循序執行 iteractor 到 iterator function 回傳 true 為止

iterator(element, index, array)

iterator的參數應該不需要解釋了 :P

睡不著,看到軟體工程版有篇 F2E心情文,順手回了,也貼到這。
http://www.ptt.cc/bbs/Soft_Job/M.1384196333.A.E16.html


F2E 是什麼, 我相信今年 JSDC awoo 大大的演講可以給我們一個標竿

https://speakerdeck.com/josephj/f2e-the-keystone

※ 引述《tooto1985 ( )》之銘言:
: 就我所知的F2E,基本上還是得涉略一些美術及後端
: 我定義F2E為:能夠解決網頁設計師與程式設計師中間的溝通橋梁

個人沒有任何美術細胞,
我也相信公司內的 Art 會作好他們該作的事,
所以我不認為我需要僭越過去幫他們改圖,
這只是在浪費彼此時間而已。

當公司內沒有 Art 或者 Art 反應很慢,
UX 還生不出 spec 或者根本沒有 UX,
後端程式還沒寫好或者 API 根本還沒定,

F2E 可以做什麼?

  1. 用假圖/假資料作 prototype。
    既然是prototype,圖美不美不重要,只是需要[那個位置有一張圖]。
    文字類的假資料網路上甚至有產生器。
    ICON 類型的東西可以參考 awesome font http://fontawesome.io/
    圖片就...google 先吧

  2. 列出所有你需要的 backend API,寫下來,找後端討論。
    在自己程式內部先用集中管理的方式把需要跟後端要資料的部分寫在一個 lib
    裡面,一樣先用假資料回應,等後端建好再一併撤換掉。
    假如你是用 ajax 要資料的話,CanJS 有一個神奇的工具可以"攔截" ajax request
    同時餵給他你想給的資料 (在 client 端)
    http://javascriptmvc.com/docs/can.fixture.html

所以你的架構可以變成
app.js // 程式主體
api.js // API接口
fixture.js / /攔截AJAX給假資料

當後端上線時你直接把 fixture.js 拿掉就好了

  1. 拿 prototype 給 PM 或主管看,他們一定會有新的意見(so called UX...), 看時程決定下一步是繼續作新的 prototype 還是定案了。

以上尤其第三點可能是整個專案中最煩人的部分,
如果 PM 不夠力或者老闆很沒 sense 你的網站上線可能要改數十次...

除了快逃以外,
最好的就是在一遍又一遍的打掉重練中找到 pattern,
讓自己每次"重寫"都能進步

其實 UX 的 pattern 都差不多,
假設你第一版的網站有側邊欄,第二版也有只是改個花樣,
你能不能作到程式邏輯部分幾乎不用動純改 CSS/HTML DOM Structure 就跳躍到第二版?
甚至老闆又反悔想要弄回第一版,
你能不能寫出 theming 的功能可以無痛切來切去?
商業邏輯的部分你能不能固定下來,把常更動的 UI 邏輯另外切出來?
常常思考:我該怎麼節省下次改這段 code 的時間
常常去想:自己覺得好不好用,可以怎麼改,節省自己重工也節省老闆 review 的時間。

那長時間下來就會進步。
反覆琢磨,學到的東西是你自己的,
而訂不下來的 spec 只是浪費到老闆的時間而已,不要讓這種理由阻礙自己進步。

淺見

Bug

是你的 bug 就是你的,就算被搶走,被別人 comment 了五百次討論到翻掉,被送了 patch,被 r+,被解掉,總有一天會被 reopen 然後 assignee 自動掛回到你身上。

準備好在那之前擁有足夠的能量跟正確解答再次承接吧。

Now we have two disposition for web activity, they are "window" and "inline".
The difference of these two dispositions are:

  1. Life cycle

    inline

    System would closes/kills the activity once activity calls |activity.postError| or |activity.postResult|.

    window

    System won't close/kills the activity after it's finished its job.

  2. UI layout position

    inline

    On top of current active app or active activity.

    window

    Parallel to current active app or active activity.

  3. Chain behavior

    inline

    Strongly connected. When one activity of the activity chain is killed, all the remaining shall be killed except the caller.

    window

    Weakly connected. When one activity of the activity chain is killed, we just remove the reference of each other.