訂閱

上次更新

April 25, 2015 12:00 AM

所有時間皆為協調世界時(UTC)。

Powered By

Planet

摩茲星球 | MozTW Planet

這邊是工作人員碎碎念的地方,您可獲得最新出爐的資訊以及最不成形的想法 :P

April 21, 2015

BobChao

Google Tag Manager 新版學習札記

先前稍微玩了一下 Google Tag Manager 但一直沒有正式放到網站上(主要是... 沒有人有時間再去研究,還有一堆 GA 調整的票掛在那邊沒時間做啊啊啊啊),但因為某顆布丁說要有光就有了光,於是我這星期又重新把沈寂數個月的「研究轉換到 GTM」那張票挖出來。

快速分享一些東西,或許能幫上跟我狀況 / 程度差不多的人。

這篇文:

  • 不是教學,是快速概覽:我是站在「如果是我的話,看了以後可以省一些摸索時間」來寫的,而介面選項在哪裡什麼的,自己摸吧 XD
  • 不是去技術文:GTM 本身雖然沒有限制是開發人員才能使用,但會不會 JavaScript 影響規劃時能用的把戲,我直接以小會一點 js 的角度來看

那就開始囉!

改名

如果你用過舊版的,有些名詞換了,個人認為是更好懂:

  • Rules 改稱為 Trigger
  • Macro 改稱 Variable

改名這種事情,其實對初學者來說超級重要的,因為在求助時,找到的文件可能都還是舊版。

概念

基本流程如下

  1. 新增 Container,就是... 意義上可以歸類的一組東西
  2. 請開發人員將 Container 產生的 GTM 程式碼放上網站。理想上無論你以後怎麼改設定,這就是少數幾次真的會動到網站程式碼的時候了。
  3. 在 Container 中可以新增各種 Tag,可以想為「要做的事」
  4. 每個 Tag 可以藉由多種 Trigger「觸發」
  5. 另外 Trigger 跟 Tag 中可以藉由各種 Variable 來設定雜七雜八的東西
  6. 設定完畢後,可以用 Preview / Debug 來測試
  7. 測試沒問題就發佈,相關設定就會直接套用到網站上
  8. 若以後有要改什麼,就從 Step 3 再走一遍,而開發人員理想上不用更動什麼程式碼

舉例:「使用者在進入這一頁點選『喝我喝我』按鈕後,就告訴 GA 這人在進來多久以後才按這個鈕」,這句話裡:

  • Tag 是「就告訴 GA 這人在進來多久以後才按這個鈕」
    • 其中「進來多久」很可能是 Variable
  • Trigger 是使用者「點選『喝我喝我』按鈕」

Tag 與 Trigger

Tag 的設定不盡相同。簡單的狀況:以設定「讀入此頁時,就在 GA 中記上一筆 pageview」這樣的事情來說,只要新增一個 GA 的 Tag、選擇 Pageview、並且設定在 All page 觸發就結束了。

但複雜的話就很複雜:一樣以 GA 為例,你有「一大堆」的欄位可以指定要傳送怎樣的資訊給 GA,舉凡 UserID、Enhanced eCommerce data 等等都可以(也必須)在這裡設定。這部分有必要搭配相關的開發文件來查閱該怎麼傳。

每個 Tag 都可以指定讓很多種 Trigger 觸發,這裡會是聯集,也就是說如果你設定了 3 個 Trigger,那只要符合 3 個中的任一種情形,都會觸發此 Tag。若想用「交集」,也就是要符合所有條件才會動,那設定上得自己兜成一個 Trigger(單一 Trigger 內的各條件是交集),或者另外新增 Exception。

舉例:我們希望在使用者登入的情況下(這裡有個 Variable 可以得知使用者是否登入),點擊某頁 A 上的某個連結 B 會觸發 Tag。有兩類設定方式:

  1. 在一個 Trigger 裡,設定在 A 頁啟用 Link Click 追蹤,並僅在使用者已登入點擊 B 連結時觸發
  2. 或者,也可以設定某個 Trigger 是在 A 頁啟用 Link Click 追蹤,並僅在點擊 B 連結時觸發。此時該 Tag 還要記得另外新增一個若使用者未登入則不觸發此 Tag 的 Exception

兩種方式主要看規劃,講簡潔好維護當然是 1,但或許某些時候還是會想用 2。

Exception 其實也是一種 Trigger,你可以想成「如果符合這個 Trigger 的條件,我就不觸發」。正所謂敵不動我不動,敵一動我亂動(此句意味不明。)

當然一個 Trigger 也可以觸發兩個以上的 Tag。

Variable

記得先進 Variable 把一些預設的 Built-In Variables 開起來,例如我開了 Page 跟 Click 的大部分。

這些做啥用?例如 Click Element 可以作為 Trigger 的條件,讓你做到「如果點選了 DIV.triggerme 底下的 A 元素,就觸發這個 Tag」,以此類推。

Variable 有許多類型,我覺得比較有用的東西例如:

  • Constant: 常數(固定值),例如 GAID 會用在很多 Tag 上,先拉出來做常數設定好。一個重點是在這邊設定好以後就會變成各欄位的下拉選單。
  • Custom JavaScript: 大概是變化最多最厲害的一種,可以用 JavaScript 抓/拼出各種想要的值交給 GTM。
    • 一行看熱鬧: function(){ return {{Click Element}}.getElementsByClassName("text")[0].getAttribute("data-event-label"); }
    • 其中 {{Click Element}} 是 Variable 的引用方式
    • GTM 高人 Zorro 曾指點,其實 GTM 內建 jQuery,所以不見得要像我那樣用原生 DOM API 抓東西。但... 我就習慣了... 然後沒有公開說支援的東西我也會擔心不告而別壞光光 :/
  • Data Layer Variable: 網頁上送來的 Data Layer 資訊要從這裡轉成變數給其他人用
  • Lookup Table: 如果你會 JavaScript 的話差不多就是 Switch ... Case 的精簡版,需求簡單又懶得寫程式時是蠻方便

Preview / Debug

GTM 內建的除錯工具,啟用後在瀏覽網頁時下半部會分割視窗顯示,平常測試起來會比用瀏覽器內建的 developer console 方便非常多。主要功能是查閱各種狀態(網頁載入、DOM 完備、網頁讀完、各種點擊事件)下:

  • 到底哪些 Tag 被觸發了
    • 以及,送出了什麼資訊
    • 而如果沒被觸發又因為哪些條件沒滿足(這個非常好用)
  • 各自訂變數值

由於他會把各狀態當下的所有數值記錄下來,所以你也可以在十幾個事件之後才回頭查第三次 click 觸發了什麼東西。下圖代表在剛載入的時機點由於網頁 URL 不符規則,於是沒有觸發。

Preview 時的 GTM 設定只有你才看得到,或者你也可以分享給其他特定人。總之,即使在 production 上測試也是沒問題的。

其他筆記

  • 瀏覽器相容性:寫 Custom JavaScript 要注意瀏覽器相容性,畢竟這段 js 碼是真的會在瀏覽器上跑。
  • 由於 GTM 的設計,只要你會寫 JavaScript 就幾乎可以不靠開發人員調整網頁,就能自幹所有的變數(例如,自己爬最終訂單畫面來解析出訂單內容資料)。
    • 不過基礎 Metadata 我會仍然傾向商請網站開發人員送 Data Layer 過來,以免網頁結構有些許更動時讓 GTM 死在路邊。
  • 閱讀文件後我認為 GTM for iOS / Android App 實際作用倒沒有像網站上那麼大,開發人員仍然得自己送出幾乎所有的事件(App 沒有 DOM 可以抓啊...),差異點是:
    1. 有些設定過的 Data Layer 值可以直接重複使用
    2. 可以在軟體發佈以後才透過 GTM 改一些設定值

小結

網站分析師善用 GTM 的話可以省很多「等開發人員有空」的時間,有什麼要調整的東西時開發人員也比較不會覺得很煩。站在「網站企劃分析人員多少都得懂點網頁技術」的角度上,是蠻推薦每個人都可以學學。不過相較 GA 已經深入行銷人的領域、在用詞與操作上幾乎只要懂網路基本原理就可以用,GTM 就還是很技術人的工具。

當然,即使你完全不會寫 JavaScript,也還是可以用 GTM 快樂做些事情、不用等 RD 幫你處理,但會寫 JavaScript 的情況下,用起來根本不是同個級別的。無論如何,Google 提供不少範例,或可作為一個入口。

有打算下個月或下下個月在摩茲工寮弄個簡單的 GTM 分享,有興趣的下面留言一下吧。

by Po-chiang Chao (noreply@blogger.com) at April 21, 2015 02:14 AM

April 07, 2015

Othree

srcset

Responsive Image 大概定案成 srcset<picture> 都有了,src-N 已經消失,雖然我還蠻喜歡,不過總之最近發現 srcset 和我當初介紹時已經差蠻多,中文資源有找到 Zhusee 有另外一篇介紹,不過其實我去看現在的 spec 的時候發現,又有些修改了!最早 srcset 後面是用類似 media query 的設計,後來改成對圖片的 metadata,spec 裡面稱為 descriptor,分別有 width descriptor 用 w 和 density descriptor 用 x,而且限制 srcset 裡面只能用同一種 descriptor,例如全部用 x 或是全部用 w,所以:

  1. 不能在一張圖片裡面同時有 wx
  2. 全部都用 w 或是全部都用 x
  3. 不可有相同的數值,例如兩個 1x 或是兩個 760w
  4. Descriptor 可以算是該圖片的資訊

不過最新的 spec 裡面少了第二點的限制,所以會有一組 srceset 混和 width descriptor 和 density descriptor 的情形,然後怎麼挑選圖片的地方寫說:

In a user agent-specific manner, choose one image source from source set. Let this be selected source.

就是叫瀏覽器自己想辦法的意思,我就很好奇,如果我想設定一組規則,要分成四個組合:

  • 小螢幕低密度
  • 小螢幕高密度
  • 大螢幕低密度
  • 大螢幕高密度

的話,我要怎樣設定 srcset 才能達到目標,因為現在已經不是用 media query 來寫 srcset 了,不能直接寫這樣四組,所以我就去找了 Firefox 和 Chromium 的原始碼來看看他們怎麼做的,Firefox 的找沒多久就找到了,因為他們有 dxr 專案用來方便找程式碼,實際用過覺得真的好用,至於 Chromium 就找比較久了,後來是在 WebKit 裡面有找到,然後發現兩個瀏覽器的原理其實都一樣,要處理同時有 width descriptor 和 density descriptor 的狀況,基本上就是都轉成 density 然後來挑最適合的,作法大致如下,細節可能有誤:

  1. 先對圖片標籤排版,這邊可能會用到 sizes 屬性,不過 CSS 還是優先,然後會得到圖片在頁面上的寬度,稱為 computed width
  2. 對每張候選圖片計算 effective pixel density,算法是: 圖片寬度 / computed width,圖片寬度可以是 width descriptor 來的或是圖片的實際寬度,如果 descriptor 是 density descriptor 的話就不用計算,直接拿來用
  3. 比對 effective pixel density 和現在 device 螢幕的 density,取最接近的

其中第三步驟的比較,大概是考慮效能和記憶體問題,兩個瀏覽器都沒真的做很嚴謹,都是照順序跑過一遍而已,所以在寫 srcset 的時候建議也要照圖片的大小排,至於要大的先還是小的先,就看開發者希望是 density 略大的優先還是略小的優先了,所以如果我寫:

srcset="aaa.jpg 1x, bbb.jpg 1.4x, ccc.jpg 1.6x, ddd.jpg 2x"

然後我現在圖片需要 1.5x 的話,應該就會拿到 1.4x 的 bbb.jpg,而如果我偏好用 1.6x ccc.jpg 的話,就要改成:

srcset="ddd.jpg 2x, ccc.jpg 1.6x, bbb.jpg 1.4x, aaa.jpg 1x"

後來發現這個挑選圖片的原則,其實在 WHATWG 的 HTML Spec 裡面有寫,不過是 non-normative 的段落,就是說這不是一定要遵守,只是建議,而且前面也有提到 spec 內是寫說挑選的原則是瀏覽器自己處理,而會這樣設計相信是為了像 mobile device 之類的裝置,網路速度如果比較慢,或是需要節省流量時,就可以挑選比較小的檔案,而不一定是挑出顯示上最好的那張圖片。

最後,其實 descriptor 除了 density 和 width 兩種之外,還有一種 height descriptor,不過目前只是保留可能性,spec 還沒定義要怎樣處理,其實還蠻能理解目前會以寬度為主的狀況,在 Matt Brubeck 的 Let's build a browser engine! 系列文章中的第六篇「Block layout」這篇文章有介紹到一般瀏覽器是怎樣排版畫 layout 的,而其處理的原則就是先從左上角開始把東西往右排,所以寬度一定先決定,然後才決定高度,相信這也是垂直置中搞這麼多年的原因吧。

April 07, 2015 04:53 PM

April 05, 2015

Othree

Loader

Loader 是 ECMAScript 定義要來處理 module import/export 等等事情的底層介面,ES6 的 module 我一直都很好奇,到底要怎麼去找 import 進來模組的原始碼,會好奇這點是因為如果是網頁環境,所有其它模組的原始碼一定是在遠端的 server 上,要拿到勢必是一個 request,然後還要等下載,總之就是非同步的流程,以前在 ES5 的話,要做非同步控制大概就是要做成 callback 的形式,所以會有像 AMD 那樣的設計出來,加上 module 名稱和檔案名稱可能又有差別,像是差個副檔名之類的,而 ES6 提供了原生的 import/export 語法來定義 module,所以我就很好奇它的底層要怎樣設計才能標準化。

Addy Osmani 有建立一個 Loader 的 polyfill 給 ES5 環境使用 Loader API,就叫做 ES6 Module Loader Polyfill,這個 polyfill 內部實做是照當初 ES6 draft 來寫的,其實還蠻複雜,不過把讀取一個 module 的事情拆分一下,可以分成以下幾個步驟:

  1. Normalize:根據給的名稱取得實際的 module name
  2. Locate:根據實際的 module name 取得 module 的位置
  3. Fetch:根據 module 位置去取得檔案內容
  4. Translate:如果有需要對檔案內容作任何修改,就在這裡處理
  5. Instaniate:最後是根據檔案內容(程式碼),判斷有哪些相依模組和知道如何初始化這個模組

以上幾個步驟是屬於 Loader 可自訂化的部分,到 instaniate 完成後,Loader 就繼續去讀其它相依的模組,相依模組都準備好之後,就可以使用模組的的程式碼,正式的把模組建立起來,ES spec 細部還定義了很多實做細節,像是非同步的操作都是用 Promise 來做流程控制,還有 Loader 也有個 module 的 registry 可以來保存已經讀好的模組,就不用一直重新建立,另外還有一些內部溝通的資料結構,像 instaniate 步驟要回傳一個物件,裡面有兩個屬性分別是 depsexecutedeps 是相依模組名稱的陣列, execute 則是該模組本身的初始化函數,參數的數量要剛好和相依模組數量一樣,回傳的則是 Module 物件等等。

其實目前的 ES6 spec draft 已經把 Loader 拿掉了,TC39 決定把他獨立出來,目前是 WHATWG 再接手繼續,不過目前的最新版本已經改很大了,看起來感覺有簡化不少,不過上面的五個步驟基本上還是存在,我一開始看到這五個步驟加上說可以自訂還沒什麼感覺,只是覺得奇怪為什麼細節沒寫,沒錯,這五個步驟在 spec draft 都只有介紹目的,不像其它的操作有詳細的寫出 method 內的流程,關鍵的地方就在於 JavaScript 已經不是單純只是在瀏覽器上跑的語言了,把這部分抽象化就是為了讓它可以同時在瀏覽器環境和單機環境下都可以實做,根據不同的 JS 環境去實做相對應的步驟細節,像是 fetch 在瀏覽器下就是真的用 fetch 去拉檔案,但是在 node 下就變成讀檔案,而在 ES6 Module Loader Polyfill 下,就有實做一組瀏覽器環境下的操作,不過這組操作的實做未來也不會真的進到瀏覽器內,最大的問題在於第五個步驟的 instaniate。

Instaniate 這個步驟是要實做 ES6 module 一個很關鍵的部分,關鍵之處在於要把 module 的 dependency 找出來,在 ES6 module 裡面,有一個限制是每個 module 都必須要獨立一個檔案,所以不能一個檔案定義兩個 module,然後假設瀏覽器已經支援 ES6 module 了,只要 parse 程式碼成 AST 找出裡面的 import 就可以把 dependency 列出來。不過現在是 polyfill,瀏覽器也還不支援 import,所以要實做 instaniate 自然需要能處理這個問題,ES6 Module Loader Polyfill 的作法是使用 transpiler,目前支援 TraceurBabel,把本來用 importexport 寫的模組轉成用類似的 AMD 模組定義的型式,而這邊用的型式是 systemjs 裡面提供的 System.register,這個方法本身並不是 ES spec 裡面定義的,比較像是為了處理這尷尬時間點所設計的替代方案。

本來我是想看看,是不是能夠只靠 Loader 就把 ES6 的 module 機制在現在的瀏覽器上建立起來,結果發現只靠 ES6 Module Loader Polyfill 是辦不到的,Loader API 並沒有定義模組的語法,如果用 ES6 的語法來定義模組還需要 transpiler 來從程式碼中分析出 module dependency,不過我不太想要把整包 transpiler 也放到 translate 裡面用,雖然可以自己寫一個什麼事情都不做的 translate function,但是要解決 dependency 的話還是會需要像 System.register 的幫助,總之到這邊,可以發現一個重點是,Loader 不管 module 定義的方法,雖然假想情境下是用 ES6 module 語法,每個檔案代表一個 module,然後用 importexport 來定義相依模組和提供的 method,不過其實 Loader 也是可以處理 AMD、CommonJS 甚至是 NodeJS 型式的模組定義,只是要有人去實做這部分的 translate 和 instantiate 的部分,而 SystemJS最新版(0.16)就是這樣一個專案,它號稱是 universal module loader,支援 AMD、CommonJS、NodeJS 和 ES6 的模組定義,然後在最新的版本,改成使用 ES6 Module Loader Polyfill 的機制來做 module 的讀取、相依性的判斷和模組初始化,雖然有些地方沒有真的照之前的 spec 來實做。

另外一個之前不太清楚的問題也藉此搞清楚了,ES6 module 有限制一個檔案定義一個 module,而現在的 web application 常常為了效能問題,都把多個檔案合併成一個檔案,這時就不能用 ES6 module 了,當然也可以用像現在 SystemJS 的作法來處理,不過其實再過一兩年 HTTP/2 普及後,也不需要這樣搞了,會變成只需要 minimize,這部分倒是還可以接受。

ES6 裡面的 Loader 本身其實是一個 constructor,放在另外一個 ES6 提供的新東西 Reflect 下面,而用 Reflect.Loader 建立 Loader instance 時可以順便給他一些參數,像是前面提到的讀模組的五個步驟的實做,或是領域(realm),而 System 物件則是該 JS 環境下的預設的 Loader,理論上如果是瀏覽器環境,它就會知道怎樣去 fetch 遠端的程式碼回來,如果是 NodeJS 就會改用 file system 讀檔案,而且也知道要把模組放到那個 realm(理論上不同 frame 就是不同 realm),這樣大部分的使用都可以用 System 就好了,只有很少數的情形需要自己建立 Loader。其實上面說的 Loader API 不知道為什麼是移到 WHATWG 之後,幾乎是重新開始編寫,完整度欠佳,有些章節還是空的,另外也沒有定義 System 或是其它的新的替代方案,所以現在想要看看到底 Loader 內部怎麼做的話,要看舊版的 spec,可以去抓 2014 年 8 月的 ES6 draft rev 27 然後看看 CH 26, 15,對照 ES6 Module Loader Polyfill 的程式碼可能比好懂。

April 05, 2015 06:50 AM

March 30, 2015

timdream

Service Worker and the grand re-architecture proposal of Firefox OS Gaia

TL;DR: Service Worker, a new Web API, can be used as a mean to re-engineering client-side web applications, and a departure from the single-page web application paradigm. Detail of realizing that is being experimented on Gaia and proposed. In Gaia, particularly, “hosted packaged app” is served as a new iteration of security model work to make sure Service Workers work with Gaia.

Last week, I spent an entire week, in face-to-face meetings, going through the technical plans of re-architecture Gaia apps, the web applications that powers the front-end of Firefox OS, and the management plan on resourcing and deployment. Given the there were only a few of developers in the meeting and the public promise of “the new architecture”, I think it’s make sense to do a recap on what’s being proposed and what are the challenges already foreseen.

Using Service Worker

Before dive into the re-architecture plan, we need to explain what Service Worker is. From a boarder perspective, Service Worker can be understood as simply a browser feature/Web API that allow web developers to insert a JavaScript-implemented proxy between the server content and the actual page shown. It is the latest piece of sexy Web technologies that is heavily marketed by Google. The platform engineering team of Mozilla is devoting to ship it as well.

Many things previously not possible can be done with the worker proxy. For starter, it could replace AppCache while keeping the flexibility of managing cache in the hand of the app. The “flexibility” bits is the part where it gets interesting — theologically everything not touching the DOM can be moved into the worker — effectively re-creating the server-client architecture without a real remote HTTP server.

The Gaia Re-architecture Plan

Indeed, that’s what the proponent of the re-architecture is aiming for — my colleagues, mostly whom based in Paris, proposed such architecture as the 2015 iteration/departure of “traditional” single-page web application. What’s more, the intention is to create a framework where the backend, or “server” part of the code, to be individually contained in their own worker threads, with strong interface definitions to achieve maximum reusability of these components — much like Web APIs themselves, if I understand it correctly.

It does not, however, tie to a specific front-end framework. User of the proposed framework should be free to use any of the strategy she/he feel comfortable with — the UI can be as hardcore as entirely rendered in WebGL, or simply plain HTML/CSS/jQuery.

The plan is made public on a Wiki page, where I expect there will be changes as progress being made. This post intentionally does not cover many of the features the architecture promise to unlock, in favor of fresh contents (as opposed of copy-edit) so I recommend readers to check out the page.

Technical Challenges around using Service Workers

There are two major technical challenges: one is the possible performance (memory and cold-launch time) impact to fit this multi-thread framework and it’s binding middleware in to a phone, the other is the security model changes needed to make the framework usable in Gaia.

To speak about the backend, “server” side, the one key difference between real remote servers and workers is one lives in data centers with endless power supply, and the other depend on your phone battery. Remote servers can push constructed HTML as soon as possible, but for an local web app backed by workers, it might need to wait for the worker to spin up. For that the architecture might be depend on yet another out-of-spec feature of Service Worker, a cache that the worker thread have control of. The browser should render these pre-constructed HTML without waiting for the worker to launch.

Without considering the cache feature, and considering the memory usage, we kind of get to a point where we can only say for sure on performance, once there is a implementation to measure. The other solution the architecture proposed to workaround that on low-end phones would be to “merge back” the back-end code into one single thread, although I personally suspect the risk of timing issues, as essentially doing so would require the implementation to simulate multi-threading in one single thread. We would just have to wait for the real implementation.

The security model part is really tricky. Gaia currently exists as packaged zips shipped in the phone and updates with OTA images, pinning the Gecko version it ships along with. Packaging is one piece of sad workaround since Firefox OS v1.0 — the primary reasons of doing so are (1) we want to make sure proprietary APIs does not pollute the general Web and (2) we want a trusted 3rd-party (Mozilla) to involve in security decisions for users by check and sign contents.

The current Gecko implementation of Service Worker does not work with the classic packaged apps which serve from an app: URL. Incidentally, the app: URL something we feel not webby enough so we try to get rid off. The proposal of the week is called “hosted packaged apps”, which serve packages from the real, remote Web and allow references of content in the package directly with a special path syntax. We can’t get rid of packages yet because of the reasons stated above, but serving content from HTTP should allow us to use Service Worker from the trusted contents, i.e. Gaia.

One thing to note about this mix is that a signed package means it is offline by default by it’s own right, and it’s updates must be signed as well. The Service Worker spec will be violated a bit in order to make them work well — it’s a detail currently being work out.

Technical Challenges on the proposed implementation

As already mentioned on the paragraph on Service Worker challenges, one worker might introduce performance issue, let along many workers. With each worker threads, it would imply memory usage as well. For that the proposal is for the framework to control the start up and shut down threads (i.e. part of the app) as necessary. But again, we will have to wait for the implementation and evaluate it.

The proposed framework asks for restriction of Web API access to “back-end” only, to decouple UI with the front-end as far as possible. However, having little Web APIs available in the worker threads will be a problem. The framework proposes to workaround it with a message routing bus and send the calls back to the UI thread, and asking Gecko to implement APIs to workers from time to time.

As an abstraction to platform worker threads and attempt to abstract platform/component changes, the architecture deserves special attention on classic abstraction problems: abstraction eventually leaks, and abstraction always comes with overhead, whether is runtime performance overhead, or human costs on learning the abstraction or debugging. I am not the expert; Joel is.

Technical Challenges on enabling Gaia

Arguably, Gaia is one of the topmost complex web projects in the industry. We inherit a strong Mozilla tradition on continuous integration. The architecture proposal call for a strong separation between front-end application codebase and the back-end application codebase — includes separate integration between two when build for different form factors. The integration plan, itself, is something worthy to rethink along to meet such requirement.

With hosted packaged apps, the architecture proposal unlocks the possibility to deploy Gaia from the Web, instead of always ships with the OTA image. How to match Gaia/Gecko version all the way to every Nightly builds is something to figure out too.

Conclusion

Given everything is in flux and the immense amount of work (as outlined above), it’s hard to achieve any of the end goals without prioritizing the internals and land/deploy them separately. From last week, it’s already concluded parts of security model changes will be blocking Service Worker usage in signed package — we’ll would need to identify the part and resolve it first. It’s also important to make sure the implementation does not suffer any performance issue before deploy the code and start the major work of revamping every app. We should be able to figure out a scaled-back version of the work and realizing that first.

If we could plan and manage the work properly, I remain optimistic on the technical outcome of the architecture proposal. I trust my colleagues, particularly whom make the architecture proposal, to make reasonable technical judgements. It’s been years since the introduction of single-page web application — it’s indeed worthy to rethink what’s possible if we depart from it.

The key here is trying not to do all the things at once, strength what working and amend what’s not, along the process of making the proposal into a usable implementation.

Edit: This post have since been modified to fix some of the grammar errors.

by timdream at March 30, 2015 10:39 PM

Othree

ECMAScript 6 Final Draft Approved

剛剛看到說 ECMAScript 2015(ES6) 定稿了,最後一版草稿是 RC4(還沒 release),接下來會是 ECMA 認證流程的樣子,不過繼續下一版的討論也不會中斷,順便要說一下他們最後 approve 的地方是在 H.R. Giger 博物館的酒吧,超酷的,這是畫異形那位大師的博物館。

March 30, 2015 10:34 AM

March 28, 2015

Othree

For the Entire Web

這陣子有兩件事情引起我的一些注意,覺得值得寫下,兩件事情我覺得其實本質上是同一件事情,先來看一下第一件事情,就是 Daniel Yoder 寫了篇文章 React Is A Terrible Idea,這篇文章在 React 當紅的時間出現,自然引起很多人的不滿,隨便在 Google 上搜尋就可以找到一堆回應,我自己對於 React 其實是沒特別感覺,沒有喜歡也沒有覺得它做錯什麼,真的要說的話大概還有點覺得它方向正確,我是認為 React 和 Angular 的 directive 都在把 component 的觀念引入前端工程師的視野之中,而這對於 Web Component 的發展應該會是有正面影響的。

再回到 Terriable Idea 這篇文章,作者對 React 的評論我其實不完全認同,最後面有提到用 Web Component 而不要用 React,這部分我覺得是作者誤會了 React 的角色,不過有些地方有人說 React 明明就可以和 Web Component 合作,還附上 ng-conf 的演講影片,我到覺得他們也完全沒搞清楚作者的重點在哪裡;提到 Flipboard 的 react-canvas 那部分算是我認為最能表現出作者想要講什麼的,作者想說的重點是現在的網路環境有限制、有問題,但是遇到時不要用一些旁門左道的方法來處理,因為這些問題終究會被解決,而問題被解決時,你之前所花的時間和資源就等於是完全浪費掉,與其要浪費在走旁門左道,還不如把這些時間和資源用在從正確的地方解決這個問題,而最後受惠的不只是自己,還有所有網際網路的開發者、使用者,這是從一個很高等生命體的角度來看事情,就如同這篇文章的標題:「For the Entire Web」,要你犧牲自己的部分利益去成就整體網際網路的利益,當然這是有些理想化,很多商業公司可能要短時間就有產品出來,不太可能所有的開發在遇到問題時都停下來等瀏覽器或是標準齊備,但是對於不少的大型企業,我就覺得他們確實應該要好好正確的回饋網路環境來解決這些問題,像是文中提到 Facebook,還有接下來要說的 Google,不過他說 Facebook 是為了和 Google 競爭才開發 React 之類的論點我就不予評論了,太多臆測~

可能有人會說,有沒有這些資源的投入應該差距也不大吧,最近就剛好有另外一件事情可以佐證,Dart for the Entire Web 這篇 Dart 官方的公告說到,Dart VM 將不會進入到 Chrome 裡面,也就是說要在瀏覽器上跑 Dart,將還是只有轉成 JavaScript 這個選項,這件事其實是蠻大的一件事,上一個在網頁裡面跑的另外一種語言是微軟的 VBScript,最大的問題不在於好不好寫,而是在於他被單一企業把持,不過後來結果大家也都知道,所以當 Google 推出 Dart 而且說以後 Chrome 會可以直接跑 Dart 的時候,我想大部分人都是都不看好的,甚至部分人是覺得 Google 怎麼做微軟做過的蠢事。而剛好在這個官方公告出來後幾天內,Brendan Eich 在 Hacker News 上回應一串討論回應的蠻激動的,這串本來是在說 ECMAScript 新版本有很多東西根本是從 Dart 來的,Brendan Eich 則是反駁說很多東西在 Dart 出來前就已經在討論有 Proposal 了,然後到後來寫了一篇幾乎都在抱怨 Dart,還提到 V8 team reset 的事情,從這邊看起來,似乎是因為新的 V8 team 不打算作 Dart VM 進去,才有了 Dart 那篇公告;而 Brendan Eich 抱怨的重點,其實就是前面那段提到的,Google 花了超多人力資源去搞 Dart,而不是來幫忙改進既有的 ECMAScript,而這確實有實際的影響,他舉了一個例子,就是大數(bignums)的支援,Dart 有支援,在 ES 這邊目前有一點可能性會在 ES7(2016) 中出來,但這東西其實從 2010 就已經開始有討論了,如果有人來將這些討論規格化,並實做起來,那大數應該在現在的 ES6(2015) 就有了。

最後再回到 Terriable Idea 這篇文章,我雖然不完全認同他對 React 的看法,但是我認為他的重點沒錯,如果他拿 Dart 出來講可能就不會引出這麼多砲火吧(可是可能也比較沒人注意),其實 react-canvas 我覺得也是很有趣的實驗,不過做成正式產品上線就是另外一回事了,最大的問題,他為了終會被解決的次要問題(畫面不流暢)完全放棄了親和力的問題,而 Flipboard 這種內容為主的產品性質是不該放棄親和力的。

March 28, 2015 05:25 AM

March 27, 2015

MozLinks-zh

新版 Firefox 設定頁網味十足

另外一個很棒的 Firefox 改變就要來了!

到目前為止,「Firefox 偏好設定」的長相一直是一堆累贅的視窗組成,幾乎沒可能在其中找到想要的設定。這是典型的軟體問題:隨著程式增加新功能,相關的設定直接加進原本的介面,讓已經很複雜的設定介面隨之膨脹,變得更加複雜。


這個亂七八糟的東西,就是現在的 Firefox 偏好設定介面

終於,新的契機來了!

Firefox UX 團隊興奮地向大家宣佈,全新的美麗設定頁面,已經成為 Nightly 版本的預設值,很快就會在釋出版中出現了。在這個新設計中,有一致的視覺元素、精進的資訊架構,所有的東西都在內頁中呈現,不需另開視窗。


新的 Firefox 設定頁

為什麼把設定放在內頁中,不另開視窗很重要呢?

  1. 跨裝置的一致性:使用內頁呈現,讓我們不再需要仰賴裝置繪製獨立的對話框與視窗。這對平板與手機來說格外重要,因為要在上面很難進行視窗管理。今後,Firefox 行動版的使用者在使用桌面版時,就會看到熟悉的介面,反之亦然。

  2. 跨系統的一致性:Windows、OSX 與 Linux 處理新視窗與對話框的方式都不一樣,這表示在不同的作業系統上,設定頁的使用體驗也不同。在 Firefox 內繪製設定頁,我們可以讓不同系統呈現一致的視覺體驗。

  3. 與網路的一致性:某方面來說,瀏覽器就是網路的門戶。如果表現得跟充滿對話框的傳統應用程式一樣,就太落伍了。用網頁做設定頁的優點,讓使用者不需在現有分頁之外另開視窗,而破壞體驗。

  4. 可擴充性:不被小小的浮動視窗限制,意謂我們可以創造更豐富的客製化體驗。附加元件管理員已在先前轉換成內容頁面,讓我們得以實驗更豐富的使用體驗。同樣的,請期待偏好設定畫面上更多的創新設計應用吧!

未看先回:是的,下一步就是在設定頁上增加搜尋功能。為了能讓你精確的召喚出想要的那個選項,而無須「學習」我們的介面,這是一定要的啦!

在此特別感謝資深視覺設計師 Michael Maslaney,它是變色龍專案的先鋒,制定此次改版的風格指南。另外感謝密西根州立大學的學生 Owen Carpenter、Joe Chan、Jon Rietveld 與 Devan Sayles,他們在 2012 年 5 月提出了獲獎內頁偏好設定設計初版

原文 / Firefox’s Redesigned Preferences Feel More like the Web | Mozilla UX
作者 / Jennifer Morrow
授權 / 創用 CC 姓名標示-相同方式分享-3.0
刊載日期 / 2014/5/23

φ Mika 翻譯 - Irvin 編輯

by Irvin Chen (noreply@blogger.com) at March 27, 2015 01:02 PM

March 20, 2015

MozLinks-zh

究竟…結果出爐了

數百萬人參與了「我們想要的網路」投票活動(一張票,一世情;感謝支持!),表達你們認為網路的未來最重要的是什麼事。

結果已經出爐…排在首位的是隱私保護—對我們而言這特別重要。事實上,這是我們的核心價值之一。

我們不只相信你擁有在線上保有隱私的權利,同時我們還捍衛它、並持續不斷在 Firefox 上打造創新的功能,幫助你保有線上生活的控制權。

關於 Firefox 如何保護你的隱私,立刻了解更多

原文 / The results are in
授權 / 創用 CC 姓名標示-相同方式分享-3.0
刊載日期 / 2014/7/17

φ Yingui Chen 翻譯 - Wildsky、Irvin 編輯

by Irvin Chen (noreply@blogger.com) at March 20, 2015 12:00 AM

March 17, 2015

MozLinks-zh

(大概是) 好事一椿… Metro 介面 Firefox 開發再度延宕

編按:本文刊載於 2014 年 3 月的 The Mozilla Magazine 中。MozLinks 正體中文版目前人力不足,積稿如山,在此誠徵有志成員加入編輯團隊

為 Window 8 作業系統特別開發的 Metro 介面 Mozilla Firefox,正式釋出的機會看起來微乎其微。Firefox 副總裁在 Mozilla Future Releases 部落格的一篇文章中說明原因。

Firefox 副總裁 Johnathan Nightingale 日前表示,已要求工程師和發行經理暫緩釋出 1.0 版的 Metro 介面 Firefox,因為「釋出可能會是個錯誤」。根據副總裁的說法,Firefox Metro 釋出預覽版僅有約 1000 個活躍測試者,但全球每日都有數百萬個活躍用戶使用 Firefox 的其他開發測試版本。這個現象讓 Mozilla 重新考量 Windows 8 與 8.1 的 Metro 介面版 Firefox 是否真有廣大的需求。

IE 作為 Windows 的預設瀏覽器,和 Google Chrome 一樣具備 Metro 模式。然而,在單一作業系統中同時推行兩種不同的使用介面,也引發各界爭議,據傳微軟已計畫在明年度的某個時刻,將開發主力轉移至「Windows 9」上。(編按:目前已公佈新版 Windows 將會是「Windows 10」,跳過「9」)

Mozilla 表示,雖然 Metro 介面版需求鮮少,但一旦正式釋出,還是得盡力修補錯誤及其他問題。由於用戶這麼少,我能想見為何繼續開發將會是吃力不討好的事情。無怪乎開發團隊決定終止,並著重在改進桌面版與 Android 版的 Firefox 上。

Google Chrome 的 Metro 模式則具有不同的目的:讓民眾熟悉 Chrome OS 以網路為核心的介面(雖然沒有網路的情況下也能使用)。這麼一來,民眾就能在購買 Chromebook 前先一探究竟。Google 透過 Windows 8 宣傳 Chromebook 使用體驗,所以即便需求量少,開發 Metro 介面還是有利於 Google。

Mozilla 的情況則不同,我賭 Metro 介面版的用戶會超少,而且除非 Mozilla 持續除錯、改善瀏覽器,不然難保還會招來一堆批評。趕緊對外說明 Mozilla 不感興趣的原因,然後塊陶是個更好的抉擇,Firefox 的副總裁就如此進行了。

至於程式碼就留給有興趣的開發者們傷腦筋吧。不論 Mozilla 未來會不會因為用戶增長而改變心意,至少目前看來,較合邏輯的結論是— Metro 介面的 Firefox 不會釋出了啦。

你同意 Mozilla 任務應當著重在可接觸到較多用戶的產品上嗎?

原文 / Mozilla Firefox for Windows 8 "Metro" gets delayed again; Probably for good - The Mozilla Magazine
作者 / A.I. Sajib
授權 / 創用 CC 姓名標示-相同方式分享-3.0

φ Cheng Yi Liu 翻譯 - Irvin 編輯

by Irvin Chen (noreply@blogger.com) at March 17, 2015 05:19 PM

February 14, 2015

Othree

CSP

CSP

Communicating Sequential Processes,簡稱 CSP,和 Content Security Policy 不一樣,是用來處理非同步執行序之間溝通的一個數學模型,我最早是在 Addy Osmani 的 JavaScript Application Architecture On The Road To 2015 這篇文章裡面看到的,花了蠻多時間試著去瞭解,最近終於覺得懂一點皮毛可以紀錄一下了。

CSP 其實不是新東西,是 C. A. R. Hoare 在 1978 年就發表的論文(PDF),1985 還出了整本書來介紹,而且全文 PDF 都有在網路上,可是這本書實在太理論了,看了一點點就看不下去,只好找其它資源,發現還真的蠻少的,但是確有找到一些近幾年的實做,像是 Go 的 routine 間用 channel 溝通,或是 Clojure 的 core.async,當然 Addy Osmani 那篇也有提到 JavaScript 的部分。

根據我目前淺薄的理解,CSP 就是用 channel 的非同步溝通機制,channel 怎麼用呢,顧名思義,就是一個傳遞訊息用的頻道,不過我覺得用管線可以更精確的描述它,而且這是一個單向的管線,一邊只能傳訊息進去,一邊只能拿訊息出來,可以達成非同步的溝通最主要在於拿訊息這邊,當你在其中一個 process 中說你要跟某個 channel 拿一個訊息出來時,如果那個 channel 裡面沒有東西,則這邊的 process 就會停下來等到那個 channel 有訊息出現,這個等待的機制不同語言有各自的方法實做。

先來看看 Go 的範例吧,因為實在是比 JavaScript 的直覺多了:

package main
import "fmt"

func main() {
    messages := make(chan string, 1)

    messages <- "ping"

    msg := <-messages
    fmt.Println(msg)
}

這段程式碼是基於 Go by Example 說明 channel 的範例,程式碼很好理解,messages := make(chan string, 1)這行用 make 產生一個 channel 指派給 messages 這個變數,messages <- "ping" 表示把 "ping" 這個字串丟進去 message 這個 channel 裡面,然後 msg := <-messages 表示從 message channel 裡面抓訊息出來,丟到 msg 這個變數,:= 是指派同時宣告變數的運算子,<- 則是用來描述操作中訊息傳遞方向用的運算子,當它是箭頭就很好理解,在 Go 裡面稱為 receive operator

在第一個例子當中,因為是先送資料進去 channel 才拿出來,所以還不太有感覺,接下來看第二個例子,一樣是 Go by Example 的,這段是 Channel Synchronization 的範例:

package main

import "fmt"
import "time"

func worker(done chan bool) {
    fmt.Print("working...")
    time.Sleep(time.Second)
    fmt.Println("done")

    done <- true
}

func main() {

    done := make(chan bool, 1)
    go worker(done)

    <-done
}

這個範例稍微複雜一點,done := make(chan bool, 1) 先產生一個 done channel,然後用 go worker(done) 產生一個 concurrent routine,跑的是 worker 這個 function,內容在 main 的上面,基本上就是 sleep 一下然後傳訊息回 done channel,然後 main 最後的 <-done 就是從 done channel 拿訊息出來,先不管平行出去的 routine,通常的程式跑到這行結束,整個程式就結束關閉了,不過,就是這個不過,正常情況下,有 <-channel 的話,該 routine 程式執行到這邊就會暫停下來,直到有從 channel 裡面拿到訊息才會繼續跑下去(或是裡面已經有訊息,直接拿到就繼續往下)。

Go 的 channel 還有一些細節可以參考 Golang channels tutorial 這篇文章,其實就是一個可以跨 routine 的傳遞資料的管道,資料可以一直傳,沒有限制數量,不過還有一些相關的細節,像是 sync channel,還有 channel 的 buffer 等等。

綜合以上的兩個範例,可以歸納出來,要支援 CSP 有兩個必要條件,第一個是可以做得出 channel 物件的機制,可以放資料進去,可以拿資料出來,是先進先出機制,這部分其實不是問題,問題是第二個條件,程式碼要能跑一跑停下來等訊息然後又繼續跑下去,這可不是用 while (1) 可以處理的狀況,用 recursive function call 效能也不太好,以前的 JavaScript 是無法良好的達成第二個條件的,直到 ES6 的 async function 出現。

ES6 async function 之前有文章介紹過,這邊就不再說明,不過總之就是執行到 yield 後,這個 function call 就會先停下來,把值傳出,直到下次再次執行該 function 才會繼續往下執行,這樣停下來的機制,正好可以利用來作為 CSP 等訊息的機制,不過利用 yield 的話有一個限制,就是一定要在 async function 裡面才可以利用 channel,不像 Go 由於是建在語言裡面的,main thread 也可以跟 channel 溝通。

雖然說可以利用 async function 可以做出 CSP 的架構出來,不過要只用 async function 來寫出像 Go 那樣簡短的程式碼實在是很困難,中間還有很多機制需要補起來,所以就開始有 library 實做,目前最有名的是 js-csp,Facebook 最近的 React.js Conf 其中一場議程介紹 CSP 時也是用 js-csp 做範例,錄影在這,作為入門 CSP 我覺得是蠻不錯的一場演講:

js-csp 裡面其實做了很多事情,目前看起來像是參考 Go 來設計,例如這樣的 Go 程式碼

package main
import "fmt"
import "time"

type Ball struct{ hits int }

func player(name string, table chan *Ball) {
    for {
        ball := <-table
        ball.hits++
        fmt.Println(name, ball.hits)
        time.Sleep(100 * time.Millisecond)
        table <- ball
    }
}

func main() {
    table := make(chan *Ball)
    go player("ping", table)
    go player("pong", table)

    table <- new(Ball) // game on; toss the ball
    time.Sleep(1 * time.Second)
    <-table // game over; grab the ball
}

改成用 js-csp 寫的話就變成:

function* player(name, table) {
  while (true) {
    var ball = yield csp.take(table);
    if (ball === csp.CLOSED) {
      console.log(name + ": table's gone");
      return;
    }
    ball.hits += 1;
    console.log(name + " " + ball.hits);
    yield csp.timeout(100);
    yield csp.put(table, ball);
  }
}

csp.go(function* () {
  var table = csp.chan();

  csp.go(player, ["ping", table]);
  csp.go(player, ["pong", table]);

  yield csp.put(table, {hits: 0});
  yield csp.timeout(1000);
  table.close();
});

csp.chan 產生 channel,用 yield csp.take 代替從 channel 取訊息,用 yield csp.put 代替送訊息到 channel,然後最重要的是用 csp.go 來代替從 Go 裡面用 go 產生 routine 的操作,然後不說可能沒人注意到,js-csp 把 routine(process)、ticker 等比較底層的基礎建設都做起來了,也就是如此才能讓程式碼和 Go 的看起來這麼接近。

js-csp 基本上就是仿照 Go 的的語法來設計,只是常常需要 yield,語法還是不如 Go 來的簡潔,至於何種情境比較適合使用 CSP 呢,以 channel 的特性來說,目前看起來是常常會發生的 event 比較適合,像是常常被拿出來講的 mousemove 事件,另外就是有要分 thread 做平行運算的話也不錯,不過目前看起來是無法接上 WebWorker,主要是因為 postMessage 無法傳遞物件 instance 過去,而是會複製一份;另外因為 channel 可以關起來,所以要用來實做 Promise 也不是不行,不過就沒什麼必要如此搞就是。

講到做事件的處理,應該會有人注意到實做上的細節問題,就是要怎麼讓多個 process 去讀取同一個 channel 呢,一般而言,channel 的訊息是只能讀取一次的,就是說雖然你可以多個 process 等同一個 channel 的訊息,但是只會有一個 process 會真的拿到新的訊息,而實務上,一個事件綁了多個 handler 的情形非常常見,照 channel 的機制,應該是不能用下去的,不然就要自己管裡 handler,又多繞了一圈,事實上,CSP 模型是有一些運算可以用的,像要處理多個 handler 的問題,就可以用 mult,可以把一個 channel 轉成一對多,其它還有多對一的 share resource、Clojure 的 onto 等等,應該是想的到的情形都已經有數學模型或是不同語言的實做可以處理了,不過 js-csp 在這部分還在開發中,像是 mult 就還在 beta 階段,其實還不太能真的用,作者有說現在的介面可能會改,也因此還沒寫到文件裡面。

最後想要記錄一下 Clojure 所提出的 transducer,transducer 的目的是讓 reduce 的操作可以用 compose 來組合,什麼是 reduce 操作呢,其實包括像 map、filter 都可以算是,但是這些操作以前是無法用 function composition 來做組合的,直到有了 transducer,又加上 transducer 把處理資料的型別也 decouple 出去了,所以 channel message 也可以利用。有兩篇文章可以參考,第一篇文章是 CSP and transducers in JavaScript,這篇講得非常清楚,他是從無到有把 transducer 建構起來,我是第二次認真看這篇文章才理解的,另外一篇文章是 Transducers.js: A JavaScript Library for Transformation of Data,是 Transducer.js 的作者寫的,從不太一樣的角度來看 Transducer 這個設計,有機會再來分享詳細一點。

這篇文章其實也不算是介紹或教學 CSP on JavaScript,比較是記錄一些我花時間想辦法理解的問題,包括為什麼現在才有人用 JavaScript 實做 CSP,實際上怎麼實做,目前適用的地方,還有整理了對 transducer 的理解,如果單純是想理解 CSP,除了前面提到的文章之外,還有幾篇文章可以參考 ES6 Generators Deliver Go Style ConcurrencyTaming the Asynchronous Beast with CSP Channels in JavaScript

February 14, 2015 07:26 AM