2009-11-17

轉換不完全—為甚麼 GWT 不會是網頁開發的未來呢?

原文網址:http://www.cforcoding.com/2009/10/lost-in-translation-or-why-gwt-isnt.html

最近我看到「GWT 是網頁開發的未來嗎?」這篇文章,裡頭假設 GWT(Google Web Toolkit)會是未來的趨勢,因為它引入了 type safety、會吸引既有的 Java 程式設計師,也提供一些 widget。

Google 最近有很多 widget 都是用 GWT,尤其是 Google Wave。對抗 Google 或是 Lars Rasmussen 這檔子事情,我當然會猶豫啦,但是我卻是抱持這種立場 \囧/。

Type Safety 跟 Static Typing
在 90 年代,type safety 跟 static typeing 的主宰地位幾乎沒被挑戰過,首先是 C 然後是 C++ 跟 Java(我知道還有這之前還有 Pascal、Algol-68 以及一卡車的語言)。Perl 是留鬍子、自信的系統管理者的名片。


相較於不夠力的硬體(當然是以今天的標準),越來越複雜的軟體以及效能問題,促使這種潮流。變數不用定義或是可變型態的想法,就像世界末日。

在 JavaScript、PHP、Python、Perl、Ruby 以及過去十年的其他語言(還有一些遠早於這些的語言)已經清楚地證明了,鬆散、動態的型態並不是世界末日。

吸引 Java 程式設計師
這裡論上聽起來不賴,但是我提出另一個觀點:如果你寫德語教科書的時候,你會用德文寫?還是先用英文寫然後再用個工具轉成德文?

任何人研究或是懂得第二語言都知道「有些事就是不能翻譯」。程式語言也一樣。JavaScript 有一堆內容是 Java 沒有的:first class functionclosureextendsion methods、意思差很多的「this」、anonymous object、dynamic typing 等等。

當你在寫「cross-compiler」會遇到的問題:
  1. 最終產出的弱點與侷限性,會包含兩個語言的弱點(用數學的講法就是「A 聯集 B」,A、B 分別是兩種語言)
  2. 最終產出的優點,會是兩個語言共同的優點(「A 交集 B」)
  3. 慣用語不同
  4. Abstractions are leaky(中文:抽象滲漏法則),Jeff Atwood 稱之為「所有的 Abstraction 都是失敗的 Abstraction
這也是 ORM(例如 Hibernate)的根本性問題:Object-relational impedance mismatch。常常你花了半天的時間去調整正確 property、annotation、XML、VM 參數的組合,只是為了產生一個 query,但是兩行 SQL 就可以解決了。

另一個 GWT 的問題是:它誤導那些只會寫 Java 的程式設計師,讓他們以為可以不用學 JavaScript。

我的立場可以總結如下:GWT 把 JavaScript 當成一個需要解決的 Bug

Widget 與成熟度
我曾經用 GWT 寫程式。widget 的選擇性實在讓人感到悲傷。GWT 標準的 widget 看起來十分嚇人、甚至可以說是糟糕透了。是有一些第三方的選擇,但是 ExtGWT 是一個非糟糕的 library、SmartGWT 看起來是一個比較好的選擇(實際上是一個社群的成果,而不是某個根本不懂 Java 泛型的人做的 GPL/commercial 授權的大雜燴)。除此之外,也沒有太多選擇。

JavaScript 有許多選擇:YUIExtJS(跟 ExtGWT 完全沒關係)、DojojQuery UISmartClient 等等。不只選擇更多、而且也更成熟。

最重要的是開發速度
GWT 需要花上幾分鐘在組建(build)跟佈署(deploy)。因為某些因素,你無法「hot-deploy」class 跟 JSP。對於 PHP 跟 JavaScript 的開發者而言,組建跟部屬通常只是替換儲存的檔案,然後要 browser 重新 reload。

GWT 的 compile 過程是很粗暴的,所以在 1.6+ 跟 2.0 版對這部份做了重大的改進。draft compile、平行處理 compile 過程、optimized vs unoptimized Javascript、選擇輸出的 browser,這些在開發階段會有些幫助,但是每個部份卻又會增加 compile 的時間。

雖然只有在更改 service interface 才需要 compile 。純粹 client 端的改變可以在 hosted browser(GWT 2.0+ 可以在實際 browser)重新 reload 之後測試。技術上來說,在不改變 interface 的情況下,Server 端的改變應該不需要使 GWT 重新 compile,但是實做上卻可能是個問題(無論是用 Ant 或是 Maven)

為甚麼很長的 compile 時間會是個問題?

或是看看〈The Joel Test: 12 Steps to Better Code〉(中文:〈約耳測試:邁向高品質的12個步驟〉)的說法:
我們都知道知識工作者進入「狀況」(flow,也被稱作in the zone)時工作效果最佳,這時候他們會完全與環境脫離,全心專注在工作上。他們忘記時間並透過絕對專注產出極佳成果。他們所有豐富的產出也都是在這個時候完成的。作家,程式人員,科學家,甚至籃球球員都會告訴你進入「狀況」的情形。
問題是要進入「狀況」不是那麼容易。如果你有試著計時,平均大概要15分鐘才能開始全速工作。有時如果你累了或是那一天已經有很多創造性的成果,會根本無法進入「狀況」,然後看看網頁玩玩俄羅斯方塊打混過完一天。
還有一個問題就是很容易脫離「狀況」。噪音、電話、同事的中斷(特別是這一點)都會讓你脫離「狀況」。假設有個同事問了一個問題讓你中斷了1分鐘,實際上卻會讓你完全脫離「狀況」,得再等半個小時才能回復生產力,結果你的整體產能都出問題了。如果你身在一個喧鬧的BULLPEN環境中(像那些一窩蜂(caffeinated)網路公司最愛營造的典型),行銷部門在程式人員旁對著電話大喊,你的產能就像一直被中斷的知識工作者一樣顛簸,永遠無法進入「狀況」。
即使是一分鐘的 compile 也會讓你脫離「狀況」。即使像 Jeff Atwood 這種毫無道理卻死命堅持厭惡 PHP 的人,也有如看到曙光、自命為「徹底的 Scripter」。

不是每個應用程式都像 GMail
我認為 Web 應用程式某些部份跟 GMail 一樣。它的特色是(幾乎)只有一頁、常常模仿一般應用程式。傳統的網頁需要使用越來越多的 JavaScript,但是 HTML 頁面間仍然需要倚賴標準的 HTTP 傳輸。

GWT 是一個針對 Web 應用程式的技術。載入的時間很久(因為 JavaScript 動輒超過 1MB),但是這沒啥關係,因為在整個過程當中,你只載入一個頁面一次而已。在載入時間這點,傳統網頁是更常見的,對 GWT 而言不是問題。

即使你把討論範圍縮小至 Web 應用程式,在我的經驗當中,就算最大的 Web 應用程式還是可以用 JavaScript library 來管理。

現在的程式碼的規模都很巨大,我也許可以瞭解 GWT—至少算是 type check—的價值。不過,我寧願用 JavaScript 處理 dynamic loading 而不是用 GWT 2.0+ code splitting。相較之下,YUI 3 dymanic loading 有精練 JavaScript 語法以及 first class function。

Layers 與 Value Objects
Java 程式設計師喜歡 layer 不是什麼秘密。你才弄了一個 Presentation Layer、Controller Layer、Repository Layer 接著有人又建議你需要有 Database Abstraction Layer、Service Layer、Web Service Layer 以及 Messageing Layer。

當然,你在這些 layer 之間傳遞資料時,無法使用某些 value object,所以你便寫了一堆照本宣科的東西:
public class TranslationUtils {
 public static CustomerVO translate(Customer customer) {
  CustomerVO ret = new CustomerVO();
  ret.setName(customer.getName());
  ret.setDateOfBirth(customer.getDateOfBirth());
  //...
  return ret;
 }
}
或是你使用一些 reflection(甚至是 XML)的 property 複製機制。顯然的,類似的事情被認為是一個好的作法(至少是普遍的作法)。理所當然會出現的問題是, interface 會用到的 class 是有相依關係的。

更多的 Java 程式設計師有一個偏好,擔心從來沒有發生事情:抽換 layer 或是分別在不同的地方實做。

我堅信這些程式碼是害蟲。這種東西越少越好。因此,我認為透過可以依需要動態變更的方式傳遞 object,比寫一堆死板複製 property 來的好;因為單純跟單調的事情是容易出錯的,偏偏自動化工具沒辦法(至少無法完全)處理這些細微差異。

在 JavaScript,你可以直接對 class(所有 instance 或是你覺得適合的 instance)掛上 property 跟 method。Java 沒有支援這個功能,就讓 GWT 出現一個問題:你怎麼用你的 presentation object?像 ExtGWT 的 library 就乾脆把所有東西(包含 JSON)經過一些轉換之後都變成 Map(那還有 type safety 嗎?)

關於語言特性
管理者跟員工常常太重視你(應徵程式設計師)使用的語言及 framework。好的程式設計師可以馬上學會新的東西,程式語言也是同樣的道理。基礎的控制結構在一般的操作是相同的(至少在兩個語法與功能相近的語言上)。

語言特性就比較難。很多寫 Java、C++ 或 C# 的人,當他們用像 PHP 之類的語言時,會試著重新作一些在他們「母語」裡頭的行為。這幾乎總是會出錯。

OOP 是最常誤用的語言特性。PHP 不是 OO(比較好的描述方法是「object capable」);另一個是討厭全域變數。在 PHP 裡頭沒有多少東西是 global,而HTTP request 大多數時候是純粹是 procedural。就像 Joel 在〈How Microsoft Lost the API War〉(中文:〈微軟如何輸掉 API 戰爭〉)所說:
我們很多人都認為1990年代最大的戰爭就是程序化程式設計與物件導向程式設計間的戰爭,而且我們認為物件導向程式設計能讓程式師的生產力大幅提升,我當時也是其中之一,而有些人到現在也還是這麼認為。不過結果我們錯了,物件導向程式師設計是很方便的好東西,不過並不能像它承諾地大幅提升生產力。真正讓程式師大幅提升生產力的,其實是那些會替你自動管理記憶體的程式語言。
重點是 Java 跟 JavaScript 分別有非常不同的特性。設計良好的 JavaScript 程式跟設計良好的 Java 程式所作的事情是相當不一樣的,所以在把 Java 轉換到 JavaScript 時,會失去一些東西,因為語言特性是沒辦法自動轉換的。

結論
Script 會是未來的趨勢。一堆的組建跟部屬步驟,無論是以行業趨勢或是最佳產能的角度,都已經是過時了。這樣的趨勢已經發展許多年了。

一次性 compile 的語言(像 C/C++,Java 跟 C# 是 compile 成一個中介的格式所以不算)佔了軟體開發的大多數,包含我們現在使用的網頁 browser、OS、Database、Web Server、VM 等等。現在他們被「semi-compile」管理平台(主要是 Java 跟 .Net)取代。這些語言會有適合它們的領域,但是會被以 script 為基礎的語言所取代。

GWT 用電報這方法,試圖找出最好的方法來實做大規模、高效率的全球訊息交換系統,但是其他人已經改用 Email 了。

========
譯註:大多數電腦領域的名詞都不翻譯,build 跟 deploy 則是為了中文語意而亂翻 XD。原文引用「Joel on Software」的部份,中文翻譯是直接引用中文版的對應段落。

說實在的... 這篇看起來筆調很輕鬆活潑
但是我寧願翻譯學術論文... 實在翻譯的好痛苦阿阿阿阿 <囧>