29 September 2013

Back to the web with Dart

我已經不記得上次全程開發 web 是什麼時候了,大概是 web 2.0 終結的那時候吧,離開 web 後,開發的都是遊戲 (Flash),mobile (iOS/Android),以及佔掉最多時間的 server side。雖然每天都會看到有人提 HTML5、SASS、ember.js、AngularJS 這些最新銳的 web 前端技術,但終究跟日常開發的產品方向差太遠,而且這些技術是環繞在我最討厭的語言 - Javascript 上,所以一直興趣缺缺,與這些技術脫勾甚久。

不過事情總是會有轉變的時候,下班沒程式可寫我就會開始發慌發愁,所以又開始找 pet 專案來開發。來試試看移植 Cubie Messenger 到桌機好了,就算不能成為產品,自己私底下也能用的很爽。(給不知道 Cubie Messenger 的讀者們,Cubie 是類似 whatsapp 和 line 的 mobile app,是我們公司的主力產品)

選擇平台

桌機版嘛,第一個面臨的就是技術平台的選擇,我自己的電腦是 Ubuntu,公司的電腦一半以上是 Mac,而廣大的用戶群都是 Windows。所以不能跨平台的通通沒的選了。Java Swing、C#、Flash、原生 C/C++ 在我腦中閃過了一遍,他們不是老舊,就是未來沒前途,我還是想找比較有趣,新的平台來開發。那麼現在在 Hacker News 最潮的 Golang 如何呢?我很想玩玩看... 不過... 基本上它現階段還是偏後台,沒什麼前端的技術,如果你在 Google 搜尋上打 golang,Google 的第一個建議就是 golang gui,換句話說這是所有開發者共同的疑問,至於搜尋的結果,別提了。

想來想去,似乎只剩 web 了,現在 web 可以做 messenger 啦,Google Hangout/Facebook Messenager 都是 web 版,平台能力的限制比以前小很多。但我又不想寫 Javascript,於是往 Javascript compiler 方向找吧。Compile 成 Javascript 的程式語言有很多選擇,我最後選了 Dart。我關注它很久了 -- 因為 Google 是其後盾、因為它的開發 IDE 就是我最熟悉的 Eclipse、因為它是唯一比 Javascript 更快的 web、因為 AngularDart 已經開始開發、因為 DartVM 是 V8 團隊開發的、因為 Dart 經過兩年的開發已經趨近成熟...

然後我就用下班時間開發了近一個月,完成了初版 Cubie 桌機版,我想這初版完成了多少功能也不大重要,它已經可以正常每天使用就是,我的 pet 專案的目的算達到了一半。另一半就是新平台的學習心得了,Dart 真槍實彈開發起來,是怎麼樣的光景?

Dart 實戰經驗

  • 我沒有打算帶你認識 Dart,如果你完全不曉得它是什麼,請上 Dart 官網
  • Dart 目前是 0.7 版,我這個月來一直追它的變化,它真的就是還剩 30% 左右還沒完工。不過,它的 VM 已經是達到產品等級的穩定了,我們自己用完全沒有當過,也沒有踩到 bug,所以就算 0.7 版上線也是完全 ok 的。
  • 現在要佈署 Dart 程式,要先用 dart2js 先 compile 成 Javascript 才行。這個 compiler 產生的 Javascript 檔仍然很巨大,如果你用到 Dart 的 mirror (reflection),會爆增幾百 kb 或 1M 以上。
    Cubie 桌機版 app dependent library/runtime
    Dart source code size 400 KB 4MB
    compiled.js size (minimized) 3.4 MB
    zip .js size 700 KB
    Cubie 桌機版與需要的 library source code 大約是 4.4 MB,合併 compiled .js 檔 minimize 後是 3.4 MB,壓縮後約 700KB。會變這麼大是因為 Dart runtime 本來就很大,然後 Cubie 也有用到一些 mirror。這對一般 web app 很傷,但是對 Cubie 到是沒差 (容後說明)
  • dart2js compiled .js 的速度我很滿意。我開發時用 DartVM 跑,每天正常使用則是 .js 版跑在 Chrome V8 上。完全沒有任何變慢的感覺。而且也沒有遇到 bug。.js 版反而比 Dart 版還少問題 (render 上的),因此我認為已經達到產品等級,可以上線。
  • Dart 語言本身,我第一天就學會了,已經進入正常開發速度,第二天的程式已經開始跟 Cubie server 來回 talk。語言非常好學,現在的文件也很齊全,建議先把 Dart 網站上的 Tutorial 看一遍,然後 Articles 部份挑幾篇入門的看一看就可以輕鬆入門。接下來的幾週把網站上的文章都讀完就很夠了。導入這個新語言到公司的成本很低。而且瞬間擺脫那充滿妖術的 Javascript 語言。
  • Dart 有沒有難入門的部份?有,第一個是它的 library 的概念。它的 library,雖然叫 library, 但其實很像 Java 的 package,然後 Dart 的 package 又是另一個意思,對我這個 Java 背景的人,一開始很困擾就是。Dart project 的 layout 要重新學習熟悉,不過這不大影響開發的速度啦。
  • Dart 第二個門檻是它的 API 到處是 Future。如果你常用 jQuery 的 Defered,那你就沒什麼門檻了,那阻力會小一點。如果你沒用過,那要花點時間學習如何正確的運用 Future。運用 Future based 的API 大家都會,但寫的有沒有 Dart '味' 就要一番工夫 了 。要訣是如果你開始用到 completer,那你大概走偏了。運用的好是不會寫 completer 的。要開始會用 if/for/while 很簡單吧?但要把它們運用的好,讓程式好讀不容易出錯,也是要學習和經驗。Dart Future 就是這樣。
  • Dart Stream 是萬能瑞式刀,一開始我只是當它是 Listener 照著用而已,但隨著一個月的開發,我漸漸發現它可以扮演很多角色,它可以是 Listener、也是 Buffer、也是 Throttler、也是 Transformer、一個單一的元件概念,可以套在各式各樣的運用上,真是另人讚嘆,我開始想把 Dart Stream 移植到別的平台啦。一開始 Dart 並沒有 Stream 的概念,大概過了一年後才重新架構出 Stream,然後整個 API 大翻新,自此之後 Iterable/Future/Stream 成為 Dart API 的三大支柱。Dart 再次驗證 -- 好的 API 必經過琢磨與焠鍊。
  • Dart 程式碼的長度約介於 python 和 Javascript 之間,在簡短與易懂間取得不錯的平衡 (過分短的語言通常不好讀,尤其是你一個月回頭來看時)。Dart 特有的 optional type,讓你想偷懶時可以通通去掉 type;想要穩固的源碼時就好好加上 type 的檢查;這是它一開始設計的宗旨。我剛開始開發 Cubie 桌機版時,由於是 prototype,所以沒管 type 就一股腦的寫,但接下來花很多時間除錯,bug 都是 type 相關的。開發到後期我就學乖了,老老實實的加回 type。因此雖然有這個偷懶功能,但我建議用 Dart 開發還是走穩固路線,寫小工具時偷個懶無妨。
  • Dart 語言及核心 API 並不多,我開發時大部份的時間反而都在學習 HTML5。web 跟我五、六年前接觸時完全不一樣了,indexed_db, secure web socket, file system, audio, canvas, css animation.... 這些原本只有 native app 才做的到的現在 web 都有了,這也讓 Cubie 桌機版的開發簡單許多。學習上我大部份都是讀 http://www.html5rocks.com 網站和 mozilla 上的 API 文件,這些文件雖然是用 Javascript 當做範例,但轉成 Dart 一點都不費力。Dart 裡的 HTML5 API 跟 Javascript 幾乎一模一樣,但通通用三大支柱修整過,API 的運用和命名規則都很一致,這點很不錯。說到這我就要順便抱怨一下 indexed_db ,它實在是很弱,只是個 key value store (比較接近 document store),根本不夠用嘛。key value store 這 *退化* 的概念是有用的,但那是為了 server side scalability。client side 又何必退步呢?之前有個 web_sql,那很棒,但 html 組織後來放棄了 web_sql,理由是世界上只有 sqlite 一種實作。某種程度上這也是我很討厭標準化的原因 -- 為了遷就多個實作,放棄好的技術、去選爛的。搞到後來大家都只有爛貨可以用,連個 order by 都沒有。
  • Dart 現階段最大缺點 -- 沒有成熟 UI 元件庫,, 這也是為什麼說 Dart 還有 30% 沒有完工。原本 Dart 在四月左右就有 Web-UI 這元件庫可以用了,可以讓你客製 html tag,運用 template,支援 model driven view。但他們後來直接放棄這個成果,轉向 http://www.polymer-project.org ,Polymer 也提供我前面提到的那些功能,但這次是 web 標準直接支援,不是靠程式自己硬刻。Dart 會這樣選擇也無可厚非,它是個新生平台,不用像 js 一樣要一直牽就舊的技術,有新的 web 發展方向它就會直接擁抱。也因為這個大轉變,使得現在開發 Dart 正好是黑暗期。你可以選 Web-UI,但那已經 deprecated,你可以選 polymer.dart ,但 bug 還很多。在這個黑暗期間,Cubie 桌機版的開發則是完全靠 DOM 來刻,DOM API 惡名昭彰很久了,後來 jQuery 的出現總算拯救了世人。Dart 的 DOM API 當然是模仿 jQuery,不會再犯同樣的錯誤,所以開發起來還算 ok,只是少了 model driven view 這類的功能,所以你會多寫一些重覆的程式碼。polymer.dart 現在處於全力開發的階段,我想過再一兩個月黑暗期就會結束了。我打算到時再慢慢將 Polymer 導回 Cubie 桌機版。
  • Dart 語言規格和核心 API 大多數已經穩定了,但每一兩個禮拜都有一次小 API break,你不見得會踩到就是。Dart Editor 也像 Chrome 瀏覽器一樣,每週自動更新,帶來新功能或是 break change。如果現階段要使用 Dart 開發,建議每週要逛一次 mailing list,或是直接看 Dart announcement。雖然說會有 break,但大多數都很小,如果踩到了,最多花個半小時左右就移植完成,沒什麼大不了。
  • Dart 可以直接呼叫 Javascript ,所以有舊程式要沿用的話是可行的,但我開發中比較沒遇到類似的問題,所以沒有經驗可以分享。在 web 上多少還是會碰到 Javascript 啦,但 Dart 有很多 library 都幫你包好了,大部份的情況都可用 Dart 來寫。
  • Dart Editor ! 一個完整的 IDE 完成最後一張拼圖。光是可以 auto completion 和 refactor 我就買帳了。他雖然是基於 Eclipse ,但不像開發 Android 時這麼肥重,這是個好的開始。我開發的這個月期間,可感受到它越來越穩定,希望這可以繼續保持。我一直認為要成為真正主流的語言平台,就是要瞄準那些朝九晚五的開發者,那些 Visual Basic 的用戶,才比較有機會,而他們很需要 IDE。我想這也是 Dart 從發表一開始就有 Dart Editor 的原因。我吃這一套!
  • Dart 還有其他技術,像是 snapshot、mirror、isolate 等等,我沒有實際的經驗所以不提了。

Chrome Packaged App

Cubie 桌機版是用 web 技術開發,但它佈署時是選擇 Chrome Packaged App (以下簡稱 Chrome App),現在 Chrome App 還不多,所以大概沒什麼人知道,簡單說就是它可以讓 Chrome extension 之類的產品,變成桌上一個獨立的 app,點擊直接開啟,不用透過瀏覽器,細節我就不說了,自己看吧 - About Chrome Apps 。會選擇佈署成 Chrome App 有幾個原因:

  • messenger 的使用習慣通常是開個小視窗掛在桌面的邊邊,而不是很大一頁的瀏覽器分頁
  • 一旦做成網頁,就會有開多個分頁的問題,開個兩個分頁然後都同時登入 Cubie server,這同步的技術做起來會死人的。
  • Cubie 有一些多媒體和加密的東西要額外處理,雖然初版的開發暫時不會處理這一塊,但未來很難說,Chrome App 有提供 web 以外的 API 可以直接存取 OS 資源,也可以透過 NaCl 直接寫 native code。有額外擴充的彈性是個賣點。

說說心得吧:開發 Chrome App 時,很像是開發 mobile 的產品,而不是 web app。一般 web 所有的資源都是從遠端 server 來的。但 Chrome App 則是一開始就包在下載的 zip 檔裡,一切都要以離線可使用為出發點 (mobile app 就是這樣,即使沒網路,你也要讓用戶可以瀏覽些東西,不能白白的一片)。前面有提到 Cubie 桌機版程式 compile 成 .js 後,就變好幾 MB,如果是遠端的網頁這是個問題,但包成 Chrome App 就沒差,因為用戶早就下載好存在本機端了。

另外一點,Chrome App 不能寫 <img src="http://foo.com/pretty.png"> 這樣的語法,要顯示遠端的圖,你得用 ajax 自己抓圖檔下來,存在本機檔案系統,然後再餵給 tag,這個限制是因為安全性的考量 - CSP: Content Security Policy。這點讓開發 Chrome App 更像開發 mobile app 了,mobile 上原生也不支援直接顯示遠端的資源,除非你用別人包好的元件。CSP 的限制是我開發 Cubie 桌機版時最痛恨的事,我了解 Chrome App 是設計給離線使用,但 web 一出生就能自然地顯示遠端的圖片,所有功能和 API 都圍繞在這個前提下設計的,不能用的話就是斷了一隻手、一條腿。Google 有提供一些工具幫忙啦,但我希望未來 Google 能有更合適的解決方案,而不是砍了你的手再給你義肢這種做法。

選擇 Chrome 專屬,拋棄了另一大半的瀏覽器的用戶,是個很大缺點,但權衡優缺點後我還是選擇這個方向。即使用戶不用 Chrome 瀏覽器,他們大可在下載完 Cubie 桌機版後,不再開啟 Chrome 瀏覽器就是,反正使用起來跟一般桌面程式沒兩樣。最慘的是那種想在公司裡偷偷用 Cubie 桌機版的用戶,但電腦裡只有苦哈哈的 IE,卻不能自己安裝 Chrome。但即使 Cubie 桌機版是用原生 C++ 來開發,不綁 Chrome,這類用戶大概也不能安裝吧。如果我是公司的 MIS,員工自己裝 Chrome App 我反而比較放心,Chrome App 基本上是在 sandbox 裡跑,限制重重,要中毒搞怪很難。前面提到它也可以寫 native code,但如果用到 native,你上架時 Google 會額外審你的程式,是的,跟 Apple Store 一樣。

每個 App 的客群和使用時機都不同,Cubie 桌機版的決策僅供大家參考。

被 Google 綁死... ?

上面的段落裡,除了 Dart/Chrome 以外,出現最多的單字是啥?喔,是 Google ! 但這也代表 Dart 平台最致命的一點,選了這語言就是被 Google 綁死啦。Dart 基本上是全部 open source,但我也不想睜眼說瞎話,說 open source 就代表 Dart 可以有替代方案,可以脫離 Google 這類不切實際的幻想。選了 Dart 就是要被綁在 Google/Chrome 上,沒什麼好說的。如果是要替公司選個長期的解決方案,那你可能要再觀望個一兩年再看看要不要選 Dart。反正它也還沒1.0 你本來就不該選。

再來看 Google 對 Dart 有沒有長期的決心了。

Google 是大公司,本來嘛,大公司代表長期的保證,而且過去 Google 信譽良好,但現在大家知道 Google 砍服務不會手軟的,所以公司大小這準則沒屁用了。所以就要看該公司重不重視這項技術平台了,不要聽那些公司對外聲明說它們多在乎這技術,未來會 blahblah,那些都是屁話。這要自己判斷。我自己是這樣判斷啦:看看該技術是不是公司的命脈,財報上賺最多的那個業務就是。對 Microsoft 而言 Windows/Office 是它的命脈,對 Google 而言廣告/Web/Search 是它的命脈。例如 Google 在 Docs 雖然上花了很多資源,企圖強佔 Office 市場,但綁在這個平台開發產品卻很危險,不是核心業務一旦失敗就是政策大轉彎,或是直接砍了,同理如果 Microsoft 出了個 IE 的某某技術,你也是要避而遠之,對 MS 來說 web 最好死掉,大家都用 Windows 最好,你替它抬轎就是當炮灰。選擇這類階段性產品真的不是明智之舉。

那 Dart 在 Google 眼中是… ? 我想 Web/Chrome/Android 都是 Google 手上最火熱的產品,而 Dart 基本上就是它們未來的 web 核心技術,花了兩年開發,要再砍掉重練一次不太可能。Google 內部有沒有在用 Dart 呢? 有的,Dart 開發團隊是開放的,他們直接在 mailing list 討論 Dart 的進度和未來的方向,三不五時就會看到 Googler 透露 internal customer 想要 Dart 加上某某功能。Internal customer 指的當然是 Google 的其他部門啦,至於是什麼團隊就不曉得了,可能是 ads,可能是 gmail,或是 project x。吃自己的狗食是個好現象,最少 Google 會比你還在乎 Dart 成不成功。

如果都沒有上面的考量的話,那大概就看開發者本身的需求和偏好了。對我來說,開發時可以像直接查平台的 source code 很重要,我並不在意該平台用什麼 licence,是不是成為標準,所以 JDK, Flash Flex, Dart 這類的平台我都可以接受,即使它們都被綁在某個公司上,但是像 Objective C Cocoa 這種沒 source 的我就很反感。而開發後的成品能不能跨 OS 也很重要,因為我自己是 Linux 的用戶,深切體會缺乏 app 的痛苦。我不在乎開發出的 app 只能在某個瀏覽器、某個 VM 跑,只要該平台可以跨 OS 即可,因此我會偏好 JVM, Flash Runtime, Chrome App 這類執行環境。而這點跟用戶的預期一樣,用戶只管能不能裝在自己的 PC/Mac,跑起來順不順,而不會在乎你用什麼執行環境。

Dart 的未來

我不是 Googler,也沒內線,所以下面都是我自己的觀察和解讀。歡迎 Googler 出來指正,我很樂意知道真正的答案 :)

Dart 預計今年底前會釋出 1.0,我想這應該不會跳票,畢竟已經開發兩年了,從 mailing list 觀察,看來他們已經不再收重大改變了,現在都是在收網。1.0 發表後屆時 Chrome 上就可以跑原生 Dart,不用再 compile 成 Javascript。除非你是個人想玩,像我一樣,不然你可以等到 1.0 後再關心還不遲,反正它上手很快。

Dart 的目標是什麼呢?Java 在 Google 內部是主要語言,但是發展卻被 Oracle 挾持,還被告過。以 Google 的資源,如果可以改良 Java,讓它更適合公司的目標絕對是做的到的 (事實上也做了,Android 用完全不同的 JVM),身為太陽系裡最多程式精英的公司怎麼可能在這種地方綁手綁腳呢?Google 如果不能擁有 Java,那就該找替代品,或是自己發展新的語言。所以近幾年來我們不斷看到 Google 釋出新的語言,但真正比較認真在做的只有 Golang 和 Dart,而不是僅僅個人的 20% 專案。這兩個語言都是由真正的語言專家領導,也投入了很多資源。Golang 目標是系統開發,Dart 目標則是應用開發。 Go/Dart 的組合正好取代C/C++/Java/Javascript 。Dart 的短期目標是取代 Javascript ,成為 web app 的主要開發語言,而且重心放在 Chrome 和 ChromeOS 的整合上。Google 希望在桌機上也能有一席之地,最好是開發者都能開發Chrome extension 或是 Chrome Packaged App。這些 app 在一般的桌機 OS 上都能跑,然後也能在 ChromeOS 執行,進而推廣它們的 OS。ChromeOS 現在只能上上網,編編簡單 Google Docs,但其實已經有 Chrome 版的 Dart Editor 在開發了 (用 Dart 寫的),如果發展順利,未來在 ChromeOS 也可以開發程式了,成為真正有用的 OS,而這些都圍繞在 Dart 上。Dart 下個目標是逐漸取代 Java 在 front-end server 的角色,但這要等短程目標達成後才比較有可能實現。至於 Dart 是否會登上 mobile 平台,我猜取決於 Android 和 ChromeOS 在什麼時間點會開始交集,這可能會很久。

Dart 在 Google 內可能會生龍活虎好一陣子,但要在外界成功還蠻難的。要那些 Javascript 熱血的開發者買帳、要讓 Mozilla 同意、要讓 Microsoft 低頭。Google 抱持著再開放的心胸也是白搭。對手才不會鳥你這些事咧。比較有效的策略是讓 DartVM 變得超快,快到 JVM 等級。同樣的 app 如果在 Chrome 裡跑超快,開始可以做 Javascript 做不到的運算,遠遠地甩開其他瀏覽器,那用戶自然就會轉移。用戶投了票,其他廠商和開發者才會跟進採用 Dart,或者是放棄老舊的 Javascript,重啟另一輪的瀏覽器大戰。神速 DartVM 有沒有可能呢?未來的事我不知道,但 DartVM 現在已經比 V8 快兩倍 了。

結語

經過五年的空窗,又回來摸 web 技術,我並沒有選夯到不行的 Javascript 生態系,反而擁抱 Dart,利用 HTML5 開發專屬於 Chrome 瀏覽器的 app,一整個就是 Google 套餐。雖然我很滿意這份套餐內容, 但被 Google 綁死風險相當高啊。 話說回來幾年前哪有這些技術呢?而現在我居然有這份新套餐可選了。這說明了 Google 花了不少心力改進 web,同時,也代表它侵略了更大的 web 版圖。未來兩年會如何呢?Chrome 會佔據市場 70% 嗎?DartVM 速度能追上 JVM 嗎?Android 和 ChromeOS 會如何合併?我很關心這些發展因為我已經先跳進來了,但也許某天你也會不得不掉進這個坑。


回響

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