25 May 2014

去年約 7 月的時候,我開始使用 Dart 開發,時至今日已經快一年了。這段時間 Dart 也從 0.7 版前進到 1.4。看起來是很活躍的在更新,不過 Chrome 還是沒有整合進 Dart VM 的跡象 (canary channel 也還沒有),我覺得拖太久了。

這近一年的時間,除了 Cubie Messanger Desktop 版之外,我們也採用 Dart 開發了其他 web app。這些 web app 都是後台性質,即不是給終端消費者使用,而是僅限公司內部人員,功能上也不是很複雜的 app:

  • Cubie Messanger Desktop: Dart + Chrome API
  • Web Project A: Dart
  • Web Project B, C, D: Dart + AngularDart

合計大概有五個專案左右,有的只純用 Dart,而新進的專案則都是採用 AngularDart 了。

AngularDart 我們在年初時開始採用,最大的吸引點是 two-way binding,還有它的 dependency 管理。

不過我後悔了

太早導入 AngularDart

我們太早導入 AngularDart 了。一開始用起來的確是很爽,相比我們其他的純 Dart 專案,導入 framework 的確讓程式結構井然有序,也去除掉很多重覆的贅碼。但這半年來它都處於 pre-alpha 的階段,每個月更新一次,就代表要改寫,每一次改寫都要花一整天,這改寫通常伴隨著許多骯髒的 workaround。如果只有一個專案採用那其實還可以接受的。但專案越來越多就都變負債了,成本實在太大。

如果有人準備研究或是導入 AngularDart ,那剎個車吧,我會說明年才是開始評估的時機,現階段不宜採用。

編譯出的 js 執行期錯誤

AngularDart 除了不斷大改版之外,它還常常出現 編譯出的 js 執行期錯誤。每個 Dart app 都需要經過 dart2js 編譯產生 js 檔,才能佈署上線,給其他瀏覽器使用。我這裡提的 js 執行期錯誤就是指 dart2js 產生的 js 有問題。出這種錯很難 debug 因為 js 都被混肴過了。而且就算查到了為什麼,通常你也無法獨立解決,你只能回報給上游,這一等又是一個禮拜到一個月。

Dart mirror 是毒藥

這個問題其實不是 AngularDart 獨有的,只是它特別的嚴重,嚴重到你一定會踩到,避免不了。根本的原因在於 AngularDart 大量使用了 Dart mirror 的功能。 mirror 用 Java 的術語來說就是 reflection,可以用來寫 meta programming,framework 很需要這類的機制。但是 dart2js 會做刪除 js 碼和更改 js 變數名稱,所以 mirror 反射出的變數名稱很容易就壞掉了。因此 AngularDart 做法就是保護那些會被 mirror 的變數,不讓它們被 dart2js 混肴,但 AngularDart 的團隊常常搞砸這件事,東壞一個西壞一個的。也許真的是 AngularDart 還在 pre-alpha 造成的吧。不過我對他們的信心不斷下降中。

你只要開始採用 Dart 生態系的函式庫,那些用戶貢獻的,你常常會採到類似的 mirror 地雷。所以現在我學乖了,任何運用 mirror 的函式庫一概不採用。也許一年後再看看狀況有沒有改善吧,現階段能不用就不用。

缺乏成熟的 UI 元件庫

Dart 1.0 已經過了快半年了,不過我還是沒看到有什麼好的 UI 元件庫,儘管 Polymer-Dart 和 AngularDart 都提供了建置元件庫的基礎。這事情雖然有逐漸的再改進,但品質還是太差,因為 Polymer 和 AngularDart 兩者都還在 alpha 等級,在上面蓋 UI 元件庫當然也是零零落落。我原先以為 Dart 1.0 後的時期會好很多,但其實我還是沒看到曙光,Dart UI 現今還是在黑暗期。

Chrome 35 Shadow DOM 悲劇

Chrome 35 版在這週更新了,大家大概沒什麼感覺吧,不過使用 Polymer-Dart 和 AngularDart 的人都哭了,因為這兩者都依賴 Shadow DOM 的功能。而 Shadow DOM 在 Chrome 35 版變成正式功能了,並且拿掉了 applyAuthorStyles 的 flag。這個 flag 是可以讓 shadow DOM 可以吃外面的 css,換句話說就是延用主網頁的 css。少了這個 flag,原先開發的元件都變裸體。怎麼辦?找 workaround 啊 (又是 workaround 啊),最笨的辦法就是替每個元件都加上主網頁的 css,夠蠢了吧。

我沒有打算提 shadow DOM 問題的細節,不過我想點出一個共犯結構:

  • Chrome 不斷的自動更新,推出新功能,也按照標準在走,這一次是 shadow DOM 的標準去除掉 applyAuthorStyles
  • Dart 平台是 Google 實驗的場地,即使 shadow DOM 還沒有正式成為標準,Polymer-Dart 和 AngularDart 已經率先採用。

這結構會有什麼問題?如果你是用 Dart 開發軟體的話,用戶端的程式因為 Chrome 強迫自動升級直接壞掉。通常你開發 web app 時,如果用到那些 vendor prefix 的功能,你大概會有所警覺。如果要相容性的話,就不選擇那些實驗性的功能了。不過在 Dart 平台上不是這麼回事,兩大元件庫都依賴超新的實驗功能 (shadow DOM),你無意中就用了,而他們也鼓勵大家用新東西。所以結果就是 Chrome 升級了你的 app 就爆了。(其實 Firefox 下也會爆,也不單單是 Google 的問題)

這代表什麼?這代表你的軟體的 release cycle 不能自行掌控:例如原本 A 軟體計畫在一年內完成轉移。現在變成要提前轉移了,而且是一夕變天。Dart 本身雖然已經到達 1.0 ,但是它的生態系除了不週全外,也走的太前衛,前衛到你無法控制進度。這樣的平台發展策略表面上對 Google 有利,但我想這只會嚇走開發者,最終放棄 Dart,對 Google 也沒好處。

Shadow DOM 只是單一事件,不過我想這還會不斷的再發生,因為這是結構的問題。這個悲劇給了我一個啟示:Dart 是 Google 實驗場,Dart 開發者是白老鼠。

Dart 1.5 drop IE 8/9 support

Dart 在上週發表了 1.4,接下來 (約二個月後) 就是 1.5 版。而 1.5 要放棄支援 IE 8/9 了,Dart 原本就放棄支援 IE7,再過幾個月連 IE9 以下都不支援了。雖然我本身是個 IE hater,不過 IE 8/9 還佔據整個 internet 15% 左右的流量,尤其是我們這些亞洲國家。這代表 Dart 平台正式脫離消費者市場,它現在只適合內部開發或是很炫的創業公司使用。Dart 拋棄舊東西不手軟。

小結

Dart 這個語言我很喜歡,寫起來也很爽。Dart VM 和它的原生 API 都做的不錯,現在也很穩定,如果只純寫 Dart 專案的話,其實不會遇到我上面列的那些問題的。但開發軟體只有語言穩定是不夠,生態系的穩定也很重要,AngularDart 也許明年就成熟了。但是 Dart 和 Chrome 的共生結構,如果未來仍然充斥著實驗性色彩,那麼遠離 Dart 似乎是唯一的路了。我個人比較希望 Dart/Chrome 平台要有 LTS (Long term support) 版本的概念,這樣新舊都能兼顧,不過 Google 似乎沒這種文化。

對尚未採用 Dart 的團隊,我的建議是明年再說吧。我們呢,已經兩隻腳踩進去了,暫時脫不了身,會繼續跟它拼,當 early adopter 雖然要付出不少代價,但有一天還是會開花結果吧。話說 Javascript 界好像也是挺慘的,每半年就有一個新的 framework,真是有一好沒兩好。


回響

可以用 Tag <I>、<B>,程式碼請用 <PRE>