2010-02-19

I Have a Dream:資訊領域翻譯專版開版理念

原文寫於 ptt.cc 的 Sub_CS 版 2010.02.15

很俗爛的開場白,不過
這個想法掛在 CompScience 的進組畫面很久了
也就借用這老套的標題吧...... [茶]

我有一個夢... 希望能有一個屬於 Computer Science 的翻譯版

這個版會介於 Computer Science 跟英文翻譯這兩個專業領域之間
以 Computer Science 專業為主,英文翻譯專業為輔
內容主要是討論資工、資科領域所遇到的英文問題

是的,英文問題。

英文已經統一電腦的世界了
ASCII 是英文字、導致主流的 program language 也都是英文
即使是非英語系的人們,開發出來的軟體
可能不見得有母語的 doc,但是一定會有英文的 doc

我們在閱讀的時候,困難點未必是自身的英文程度
(ㄜ... 當然,我是很困擾啦,畢竟高中四年英文從來沒及格過 XD)
而是被那些脫離一般用法的詞彙或句型所混淆

舉例來說,當初學者第一次看到 Object-Oriented 的文章
可能會很想死,例如:
A real instance of a class is called an "object"  [1]

instance 是啥? class 又是啥?
萬一英文不太好的人,可能還會順便懷疑
real 是不是「實數」? call 是不是「呼叫」?
明明想搞懂一個名詞,結果跑出來更多名詞
明明每個字都認得(都查得出來),但是放在一起就完全不懂
(我不知道母語是英文或是英文很好的人會不會有這種困擾)

這只是剛開始,如果在資訊領域待久了
另一個麻煩的來源,是很多不同領域會用相同的名詞,但是意思根本不一樣
就假設有一篇教 JSP programmer 如何處理 CSS 相關議題的好了
class 是... 啥? filter 又是... 啥? [2]

如果剛好這篇文章又扯到 Java 中的 class 跟 JSP 的 filter
沒有標示清楚,豈不叫人發狂?


除了面對英文會煩惱,很多時候,
我們面對(廣義的)中文會更煩惱
一個類別的實例稱為物件

或是簡體版的
一個類的實例稱為對象

說真的... 這 到 底 是 什 麼 鬼.... <囧>
徹底的中文翻譯,反而會造成我們哪天要去閱讀原典(?)的極度障礙
那麼... 該翻? 不該翻? that's a question......


最後,是比較敏感的話題,簡體中文

等等,我不想挑起什麼政治問題、誰優誰劣... blahblah
我只想陳述事實:
我用繁體中文、ptt.cc (主要)用繁體中文

當然,繁體簡體,畢竟同是中文
現在用機器作繁簡轉換,似乎可以得到不錯的結果(至少比英翻中好得多)
問題是,如果我們寫文章都(還是)用繁體
為甚麼我們要看從簡體轉換過來第二手(甚至第三手)的資料?

往更源頭、也更嚴肅的方向想:
難道我們已經開始倚賴簡體中文的資料了嗎?

「語言」的使用趨勢,是西瓜效應的經典範例
如果能提供一個園地,讓被英文 or 技術名詞所苦的人能夠交流
在遇到翻譯障礙時,有一個補給後援
是不是能讓繁體中文的西瓜長得大一些?
至少我們不會想仰賴簡體中文,而有讀原文的勇氣

啊? 那為什麼寫這篇? 直接申請開版就好啦?
這說來有些話長...
一是近來開的版,似乎生意都不怎麼興隆 XD
二是自己身兼小組長,總不能自己申請自己審,又不想勞駕群組長
三是自己智寡德薄,手上幾個版也沒有管得很好
加上英文實在很差、資訊領域也讀的不太像樣......

所以,在新年許個願望
希望有勇者能夠嚴謹而盡責地實現

以上...... [遠目]

備註:


  1. 這句不是我掰的,是來自於這個網站 http://searchsoa.techtarget.com/sDefinition/0,,sid26_gci212681,00.html
  2. class 跟 filter 在 JSP 跟 CSS 都是專有名詞。而且實際意思幾乎完全沒有雷同之處(尤其是 filter)

2010-02-18

Buzz?Buts?Bugs? Bums?

Buzz
前些日子,要進 GMail 的時候會跳一個「要不要加入 Buzz 功能」的畫面。Google 正式推出的東西,當然是會想要用用看的。於是,一個早上就栽進去了,除了跟也在摸 Buzz 的人哈拉打屁之外,比較多的時間是在 try 功能與設定......
好東西啊 (y)
很多東西說穿了,其實就是留言板,blog 是個人留言板、Plurk 是多了 timeline 展現方式的個人留言板。Plurk 跟傳統留言板的差別,只在於你知道誰有訂閱你的看板,如此而已。Buzz 大致也依循這個基礎,基本功能就是讓你可以 blahblah 一些有的沒的,然後別人可以在這個主題下回應 comment。如果 Buzz 就只有這樣,除了跟 GMail 整合在一起(有新 Buzz 會有信件通知、可以直接在信件當中增加 comment)、沒有字數限制之外,根本不會覺得它是好東西、也不會想要用(我只用 Plurk 就覺得夠浪費時間啦~ [慘笑])

重點在於整合。Buzz 有一個「connected sites」的設定,可以連接 Google 指定的網站,例如Google Reader、Blogspot(其他沒用過就跳過 XD)。在 Google Reader 對某個 item 設定「分享」,那麼這個 item 就會變成一個 buzz;同理,在 Blogspot 發表新文章時,文章內容也會自動變成一個 buzz。當然,可以直接在 Buzz 的介面看完整內容,也可以回應 comment。

我想,Buzz 的目標就是彙整使用者在 Google 系列產品所產生的資訊,並加以流通。

在 Blogspot 上寫了一篇文章,得手動(至少得自己按個按鈕)轉到 Plurk 上頭才能提醒朋友們去點開來看,Buzz 直接強迫你看 [大笑],還不用在視窗 or tab 之間切換。萬一某個 buzz 導致要私下單挑,轉戰 chat(GTalk)或是 email 的按鈕也都幫你傳便便,而且後續的動作不用在視窗 or tab 之間切換

Buzz 讓平常已經會停留很久的 GMail 變得更久——或著這麼說,如果你的朋友們都是 Google 愛用者(soon or later? :P),那 GMail 或許可以涵蓋所有的溝通需求,因為——還是那句老話——不用在視窗 or tab 之間切換(當然,我不否認,其實我比較喜歡用 Alt+Tab 切換視窗比較快,用滑鼠點來點去實在是很慢.... Orz)。

反過來說,Buzz 又加重了「專一帳號」 的力度。像我自己有兩個 Google 帳號,一個是 PsMonkey(本名?)、另一個是 PT2Club(工作用)。因為工作上的信件往來比較多,導致後來幾乎都用 PT2Club 這個帳號來用 Doc、Reader、譯者工具包、webmaster 等服務。那些也都還好,畢竟各自獨立。但是 Buzz 的出現,就讓我開始猶豫我到底要用哪一個帳號?聊天打屁事小,至少 blog 的文章要能夠自動張貼啊...... 後來解決方法是我的 blog 們現在都有兩個作者 XDXD。

Buts
雖然個人覺得實在是個好東西,不過網路上抨擊 Buzz 的也不少。主要攻擊點在於隱私權政策。這(據說)是因為一開始使用 Buzz 時,它會預設把很多資訊都公開:例如你的某些聯絡人(尤其是在 Google Reader 就有 follow 的)會自動加入成 follower→而 follower 的清單可以在 profile 上頭看到→profile 預設公開...... 如此之類的問題。隱私權的問題我始終...... 搞不太懂,就跳過 XD。

另外,也有這種聲音
忙碌的人不需要另一個社交網絡,他們需要的是一個方便的整合,我們已經做了。Hotmail 用戶自 2008 年起已享受到微軟與 Flickr、 facebook、Twitter 及另外 75 個伙伴合作所帶來的益處。
為此我還特地登入半個月才上去一次的 www.hotmail.com,奇怪... 就跟過去一年多的印象一樣——沒有啊?難道登入之後下面的「好友動向」就是上面說的東西?平常只會看到誰又改了暱稱或是換了照片啊?好吧,就算是好了,那我要怎麼增加新的資訊?至少 blog 的新文章要能掛進去吧?難道一定要跳到 Windows Live 的首頁? (中略數分鐘)還真的是在 Windows Live 的首頁找到了,叫做「新增網路活動」,這需要一點聯想才能從「好友動向」想到這來。而這幾個字有多麼顯眼呢?為了怕大家找不到,我用紅框圈起來了。
點進去則是洋洋灑灑、二字排開、完全沒有分類的項目。有趣的事情來了... M$ 自己提供的 blog service 在裡頭找不到,得在「個人檔案」裡頭的「好友動向」下面的「選項」才有辦法設定(字一樣小,還會跟另一個也叫「選項」的搞混)。因為那被歸類在「Windows Live」裡頭,跟「網路活動」是分開的...... 至於這玩意到底方不方便、好不好用,我就不知道了....... 因為才弄到這裡 我 就 快 抓 狂 啦... 沒有用 AJAX、排版又花又亂、功能提示不清... 啊啊啊啊... <囧>。M$ 的場面話說 2008 年就有這個功能,我很好奇到底有多少人真正在用?上頭有多少資訊在流通(尤其是撇開 MSN 暱稱與圖片 update 資訊)?

說真的,有時候不是「Google 就是好」、也不是「逢 M$ 必反」,而是無論以使用者經驗來給分、以技術面來評估、或是以行銷手段來衡量,孰好孰壞,一望便知。

Bugs
這幾天用下來,其實現階段的 bug——嚴格來講是功能缺失點——還頗嚴重。

最大條也最明顯的是「未讀」的數字始終不太對。常常有新的 buzz 但是數字卻沒出來,或是有出現數字但是點進去卻沒發現有沒讀過的 buzz。這實在是蠻令人生氣(失望)的一個缺點。如果我得要點進去 Buzz、肉眼掃描才能知道有沒有新東西要看......
那我幹麼還用 Buzz 啊啊啊啊....... [翻桌]
另外一個功能缺失點,是在單個 buzz 的 comment 太多時,系統會自動幫你隱藏中間的 comment,只留下第一個跟最後兩個。問題是,可能這個 buzz 最後五筆 comment 都沒看過,就還得全部顯示之後用肉眼掃描......
那我幹麼還用 Buzz 啊啊啊啊....... [翻桌]
至於「別人回覆 comment 會自動寄信到 mail 當中通知」,我覺得這設計的很粗糙且囉唆(弄好 Buzz 的未讀機制,或是開放 API 還比較實在),還好 GMail 本身有 filter 的功能。其他還有 connected site 在顯示 blog 名稱會錯亂、connected site 的來源種類很少、comment 似乎沒辦法擺圖、Insert Link 在刪除 link 之後不會再出現...... etc

總結來說,Buzz 目前是堪用而不太好用。以 Google 的以往的標準來說,實在是不及格(想當年 GMail 出來的時候,我簡直感動得要落淚啊...)。

這給了我一些想像的空間...

Bums
Google 在泛稱 social network 的部份,似乎沒有做的很成功。GTalk 出來太晚,文字訊息打不過 MSN 跟 Yahoo 即時通、聲音影像又搶不了 Skype(當然,micro blog 某種程度導致標準的 IM 沒落)。很早之前有 Orkut,但是好像沒有推起來,至少沒有變成 Facebook。Blogspot 顯示追蹤訂閱的功能應該沒有出來很久(不太確定)......... 如果上述沒有觀察錯誤,那也就是說,Google 手上幾乎沒有「人跟人之間關係」的資料...... 除了不能說的 GMail [奸笑](是說 email 也不太好 mining... 畢竟正常的 mail 都是一對一),還有不太有用的 Google Group 跟... Google Codes? [大笑]

social network 的 service 會徹底遵守西瓜效應。當你身邊的人都在噗來噗去的時候,即使你不趕流行、你身邊的人也會逼你用——不然我怎麼聯絡你啊? or 你一直 lag 我們在講什麼你都聽不懂。雖然使用者的需求是否滿足很重要(所以我壓根不會去用 Facebook),但是常常扮演關鍵的是「誰比較快」。畢竟網路上沒有春夏秋冬,只要種子沒有太差,早播種通常就是早收成。M$ 主管的說詞並沒有錯「忙碌的人不需要另一個社交網絡」,Twitter、Facebook(以很多 service)都有開放的 API 可以連,也就是說,有心要整合都不是問題。如果我已經用了這一個,那為甚麼我要去用另一個呢(一如我到現在還是很死忠 BBS [大笑])?

如果以這點來看 Google Buzz,或許可以代表 Google 也急了、急到連平常應有的水準都沒有就推出來正式上線了。Wave 雖然複雜到不知道該怎麼用,算是失敗,至少它先進且(理論上)完整。Buzz,坦白說,對 Google 開始失望。

如果 Google 未來會崩壞,我會以 Buzz 作為一個轉折點。這也是為甚麼寫這篇的原因,紀錄有過這麼一件事。

2010-02-12

徹底瞭解 GWT Part 2:JavaScript 的 overlay type

原文:http://googlewebtoolkit.blogspot.com/2008/08/getting-to-really-know-gwt-part-2.html

技術校正、審閱:tkcn

假設你已經在 GWT module 當中,愉快地使用 JSNI 來呼叫某些手寫的 JavaScript。一切運作正常,但是 JSNI 只能在獨立的 method 下運作。某些整合性狀況需要你徹底地把 JavaScript 跟 Java 的 object 綁在一起——寫 DOM 跟 JSON 就是兩個好例子——所以我們十分需要可以從 Java 程式碼直接與 JavaScript object 互動的方法。換句話說,我們想要 JavaScript 的 object 看起來就像我們寫的 Java object。

GWT 1.5 引入了 JavaScript overlay type,這讓 GWT 程式整合各種 JavaScript object 變得容易許多。這個技術有很多好處,像是讓你能用 Java IDE 的 code completion 跟 refactoring 功能,即使你寫的是 untype 的 JavaScript object。

範例:簡單、有效率的 JSON
用一個範例來瞭解 overlay type 是最簡單的方法。假設我們要存取一組「customer」數據,底層是用 JSON object。在 JavaScript 中的資料結構可能像這樣:
void jsonData = [
  { "FirstName" : "Ps", "LastName" : "Monkey" },
  { "FirstName" : "痞子", "LastName" : "猴" },
  { "FirstName" : "Pt2", "LastName" : "Club" },
  { "FirstName" : "STO", "LastName" : "Orz" },
];

要把一個 Java type 加到上述的資料結構,要從建立一個 JavaScriptObject 的 subclass 開始,這在 GWT 表示是一個 JavaScript 的 object。接著增加一些 getter。
// An overlay type
class Customer extends JavaScriptObject {
  // Overlay types always have protected, zero-arg ctors
  protected Customer() { }    

  // Typically, methods on overlay types are JSNI
  public final native String getFirstName() /*-{ return this.FirstName; }-*/
  public final native String getLastName()  /*-{ return this.LastName;  }-*/
       
  // Note, though, that methods aren't required to be JSNI
  public final String getFullName() {
    return getFirstName() + " " + getLastName(); 
  }
}

如此一來,GWT 就會瞭解所有 Customer 的 instance 實際上是來自 GWT module 以外的 JavaScript object。這包含了很多意義。舉例來說,看到 getFirstName()getLastName() 裡頭的 this reference。它實質上是代表一個 JavaScript object,所以你操作這個 this 就像在 JavaScript 裡頭一樣。在這個例子中,我們可以直接存取 JSON 中那些我們已知的 field:this.FirstNamethis.LastName

那麼,你要如何才能真正得到一個被包裝成 Java type 的 JavaScript object 呢?你不能用 new Customer() 來建構它,因為重點是把一個既有的 JavaScript object 包裝成 Java type。因此,我們必須使用 JSNI 來得到這樣一個 object:
class MyModuleEntryPoint implements EntryPoint {
  public void onModuleLoad() {
    Customer c = getFirstCustomer();
    // Yay! Now I have a JS object that appears to be a Customer
    Window.alert("Hello, " + c.getFirstName());
  }

  // Use JSNI to grab the JSON object we care about
  // The JSON object gets its Java type implicitly 
  // based on the method's return type
  private native Customer getFirstCustomer() /*-{
    // Get a reference to the first customer in the JSON array from earlier
    return $wnd.jsonData[0];
  }-*/;
}

現在來搞清楚我們做了啥。我們拿到了一個 plain old JSON object(譯註:源自於 POJO)並且建立一個看起來很正常的 Java type,讓 GWT 程式碼中能夠使用它。於是你就有了 code completion、refactoring、compile 階段的檢查——這些寫 Java 時所擁有的好處。然而,你還是可以靈活地操作任何 JavaScript object,這使得存取 JSON service(使用 RequestBuilder)變得很輕而易舉。

為一些 compiler 強者岔題一下。overlay type 另一個美妙的事情是你可以增加 Java 的 type,但是卻不用影響底層的 JavaScript object。注意到上面例子中,我們加入的 getFullName() 這個 method。它是純粹的 Java 程式碼(並不存在於底層的 JavaScript object),但卻是依照底層 JavaScript object 所寫的。也就是說,處理同一個 JavaScript object,以 Java 的角度會比用 JavaScript 功能豐富得多;而且不用動到底層的 JavaScript object——無論是 instance 或是 prototype

(接續上一段的題外話)在 overlay type 增加 method 這個很酷的怪招是可行的,因為 overlay type 的設計規則是不允許 polymorphic 呼叫,所有的 method 必須是 final 且/或 private。因此,compiler 是靜態地解讀每一個 overlay type 的 method,所以不需要在 runtime 的時候動態 dispatch。這是為甚麼我們不用拘泥在 object 的 function pointer;compiler 可以直接對 method 呼叫,就好像是 global function、獨立於 object 之外。很明顯的,直接呼叫 function 會比間接快得多。更棒的是,因為呼叫 overlay type 的 method 是靜態解讀的,這些動作會嘗試自動 inline;這在為了 script 語言的效率而奮戰時,是非常強大的火力支援。接下來我們會重新來一遍,展示給你看這個方法有多成功。

範例:lightweight collection

我們在上面的例子當中掩蓋了某些事情。getFirstCustomer() 這個 method 是非常不切實際的。你一定會希望存取全部的 customer 陣列。所以,我們需要一個 overlay type 來表示這個 JavaScript 陣列。幸運的是,這很簡單:
//泛型在 overlay type 裡頭也運作正常!
class JsArray<E extends JavaScriptObject> extends JavaScriptObject {
  protected JsArray() { }
  public final native int length() /*-{ return this.length; }-*/;
  public final native E get(int i) /*-{ return this[i];     }-*/;
}

現在我們可以寫出更有趣的程式了:
class MyModuleEntryPoint implements EntryPoint {
  public void onModuleLoad() {
    JsArray<Customer> cs = getCustomers();
    for (int i = 0, n = cs.length(); i < n; ++i) {
      Window.alert("Hello, " + cs.get(i).getFullName());
    }
  }

  // Return the whole JSON array, as is 
private final native JsArray<Customer> getCustomers() /*-{
    return $wnd.jsonData;
  }-*/;
}

這是一個很乾淨的程式碼,尤其是以建立靈活配置的角度來看。正如上頭提到的,compiler 可以作一些十分 fancy 的事情,讓它相當有效率。看一下 onModuleLoad() 這個 method 在沒有 obfuscate 的 compile 結果:
function $onModuleLoad(){
  var cs, i, n;
  cs = $wnd.jsonData;
  for (i = 0, n = cs.length; i < n; ++i) {
    $wnd.alert('Hello, ' + (cs[i].FirstName + ' ' + cs[i].LastName));
  }
}

這個最佳化真的是 xx 的好。即使是 getFullName() 這個 method 的 overhead 也沒了。事實上, 所有 Java method 的呼叫動作都不見了。當我們說:「GWT 給你可負擔的 abstraction」,這就是其中之一。不僅 inline 的程式碼執行速度明顯變快、我們不再需要定義 function 的內容、也因而得以將 script 簡短化(雖然持平而論,inline 的方式也很容易讓 script 量變多,所以我們小心地在速度與程式碼大小之間取得平衡)。現在回顧上頭原始的 Java 程式碼是十分有趣的,而試著推導 compiler 最佳化的步驟就展示到這邊。 不過,我們還是忍不住要 show 一下對應、obfuscate 過的程式碼:
function B(){var a,b,c;a=$wnd.jsonData;for(b=0,c=a.length;b<c;++b){  $wnd.alert(l+(a[b].FirstName+m+a[b].LastName))}}

注意在這個版本當中,唯一沒有 obfuscate 的是 JavaScript 當中的識別字,例如 FirstNameLastNamejsonData 等。這是為甚麼即使 GWT 努力讓大量 JavaScript 交互溝通的操作變得容易,但我們還是努力說服別人盡量用純 Java 來寫程式、而不是混著 JavaScript 寫。希望你聽到我們講這些之後,你會明白我們不是要打擊 JavaScript——只是我們不能對它們最佳化,這會讓我們很沮喪。

摻在一起作撒尿牛丸 
overlay type 是 GWT 1.5 的重要特性。這個技術讓直接與 JavaScript library 互相溝通變得相當容易。希望在讀完這篇文章之後,你可以想像如何以一組 Java type 直接導入任何 JavaScript library 到 GWT 裡頭,進而使用 Java IDE 來進行高效率的開發跟 debug,卻不會因為任何類型的 GWT overhead 而影響程式碼大小或執行速度。同時,overlay type 作為一個強大的 abstraction 工具,提供更優雅的低階 API,例如新的 GWT DOM package

2010-02-05

徹底瞭解 GWT Part 1:JSNI

原文:http://googlewebtoolkit.blogspot.com/2008/07/getting-to-really-know-gwt-part-1-jsni.html

技術校正、審閱:tkcn

[前面略過一段很口語、很難翻譯、但是不太重要的一段 XD]

徹底瞭解 GWT,第一步:JSNI
如果你是 GWT 新手,你可能覺得奇怪:到底有什麼好激動的?GWT 跟其他 framework 有什麼不同?GWT 是一個基礎技術、串起許多工具,而不只是特定 application 的 framework。因此,雖然 GWT「有」很多 library,覺得有用的話,要用多用少都可以。不喜歡 GWT 的 UI?你可以用 DOM 建立自己的 UI。不想用 RPC 而想要用 JSON?那也沒問題。事實上,要用 GWT 重頭開始打造自己的  framework 是絕對沒問題的,也能保留所有 GWT debug 跟 compile 方面的優點。

所以,用一個宏觀的角度來思考:為什麼你要考慮使用 GWT 來開發下一個大的 web application 呢?
  • 相較於傳統 server-centric 的方式,如果 AJAX 設計得好,因為本身的特性,在許多種類的 application 上會提供更好的使用經驗。你都已經在讀這個 blog 了,可能早就知道啦。
  • GWT compiler 產生的 JavaScript 碼通常會比你自己撰寫的程式碼還要小、還要快。
  • 用 GWT 開發可以讓你更有產能、而且產生的 JavaScript 也更加可靠。
  • You get the opportunity to say "Gwit" a lot.

我們擔心你是那種容易被一些主張或是行銷說詞給影響了,所以我們在接下來幾篇 blog 文章中,會看到 GWT 如何實現性能的提昇、以及如何讓 JavaScript 使用起來更容易。

在深入技術細節之前,還有一件事。我們有時會問兩個跟 GWT 本質有關的問題:
  1. 為什麼 GWT 以 Java 語言和工具為核心?
  2. 跟手寫的 JavaScript 比起來,GWT 是不是比較多限制、也比較 heavyweight?

先回答第一個問題,請瞭解我們的目標跟滿腔熱血,是為了徹底改善網頁使用者的使用者經驗,這表示 GWT 產生的 JavaScript 必須有最好的效能跟可靠度。為了做到這一點,我們自然想加入一堆程式碼的最佳化,並且盡可能的提早抓出 bug。這兩個目標都容易在 Java 的 static type、以及既有的 Java IDE 來達成。這是為什麼我們冷靜地選擇了 Java 技術作為 GWT 的核心。就是這樣—沒啥語言聖戰的梗。

再來回答第二個問題,有些開發人員在第一次聽到 GWT 時,會假設它是一個 abstraction 的「Walled Garden」,讓你永遠只能用 Java 寫程式而不讓你使用或是整合手寫的 JavaScript。這實在錯的很離譜......

GWT 中的 JavaScript Native Interface(JSNI)
你可以輕鬆地把手寫的 JavaScript 直接嵌入 GWT 程式碼當中。反正最後都會變成 JavaScript,那為甚麼不提供 GWT 的開發人員一個有用的方法,讓他們能夠混合這兩個東西?這方法就叫做 JSNI 啦。它的名字跟 JNI(Java Native Interface)很像,因為他們的基本想法也一樣:把一個 Java method 宣告成「native」然後用另一個語言來實做內容。在 JSNI 當中,就是用 JavaScript 來實做內容。

用 JavaScript 寫 Java Method
JSNI 在創造功能最底層的 abstraction 是非常有用的,它很自然地使用 JavaScript、而不是 Java 語法。例如 Regular Expression 在 JavaScript 是相當簡潔的,所以你可以透過 JSNI 在 GWT 程式碼當中直接使用它們。假設你想把某人的名字(Ps Monkey)轉過來,讓姓在後面、名字在前面(Monkey, Ps)(當然,這在 I18N 當中會是一場惡夢)。你可以建立一個很簡短的 JSNI method 來做到:
// Java method declaration...
native String flipName(String name) /*-{
  // ...implemented with JavaScript
  var re = /(\w+)\s(\w+)/;
  return name.replace(re, '$2, $1');
}-*/;
請注意,method 的內容整個被特殊標記「/*-」、「-*/」給包圍起來,變成一段 Java 的註解。

在 JSNI 中呼叫 Java method
你也可以反過來,在 JavaScript 呼叫一個 Java 的 method。假設我們修改上面的例子,改成這樣:
package org.example.foo;
public class Flipper {
  public native void flipName(String name) /*-{
    var re = /(\w+)\s(\w+)/;
    var s = name.replace(re, '$2, $1');
    this.@org.example.foo.Flipper::onFlip(Ljava/lang/String;)(s);
  }-*/;

  private void onFlip(String flippedName) {
    // do something useful with the flipped name
  }
}

用 JSNI 存取外部的 JavaScript 程式碼
當然,你可以在 GWT module 存取任何外部的 JavaScript 程式碼。舉例來說,如果你的 HTML 頁面看起來像這樣:
<html>
  <head>
    <SCRIPT>
    function sayHello(name) {
        alert("Hello from JavaScript, " + name);
    }
    </script>    
    <-- Include the GWT module called "Spiffy" -->
    <script src="org.example.yourcode.Spiffy.nocache.js"></script>
  </head>
...
在 Java 程式碼,您可以用 JSNI 去呼叫 JavaScript 的 sayHello() function:
// A Java method using JSNI
native void sayHelloInJava(String name) /*-{
  $wnd.sayHello(name); // $wnd is a JSNI synonym for 'window'
}-*/;
GWT compiler 把外部的 method 呼叫給內嵌進來,所以在 Java 當中呼叫 sayHelloInJava() 的效率並不會比直接在 JavaScript 當中呼叫來的差。

用 GWT 建立 JavaScript library
你甚至可以用 GWT 創造一個 JavaScript 可以呼叫的 library。這是一個非常棒的技巧:
package org.example.yourcode.format.client;
public class DateFormatterLib implements EntryPoint {

  // Expose the following method into JavaScript.
  private static String formatAsCurrency(double x) {
    return NumberFormat.getCurrencyFormat().format(x);
  }
  // Set up the JS-callable signature as a global JS function.
  private native void publish() /*-{
  $ wnd.formatAsCurrency =
    @org.example.yourcode.format.client.DateFormatterLib::formatAsCurrency(D);
}-*/;

  // Auto-publish the method into JS when the GWT module loads.
  public void onModuleLoad() {
    publish();
  }
}

接著,你可以在任何 HTML 或是 JavaScript library 當中存取這個 GWT 做出來的功能:
<html>
  <head>
  
    <-- Include the GWT module that publishes the JS API -->
    <script src="org.example.yourcode.FormatLib.nocache.js"></script>

    <-- Write some JS that uses that GWT code -->
    <SCRIPT>
    function doStuff() {
      alert(formatAsCurrency(1530281));
    }
    </script>
  </head>
...

Ray Cromwell(最有名的是 GWT Extreme!)在他的 GWT Exporter 淋漓盡致地採用了上述的 JavaScript 發佈技術。它用 GWT compile 期的 code 產生器來自動創造所有發佈出的程式碼。(「compile 階段的程式碼產生器」聽起來很酷吧?如果你也這樣覺得,那請期待這個系列的後續文章。)

摻在一起作撒尿牛丸
用 JSNI,你可以用你想要的方式,自由地混和手工撰寫的 JavaScript、外部的 JavaScript library、以及 Java 程式碼。這就是我們說 GWT 並不是一個 abstraction 的「walled garden」,因為你可以逐步地將 GWT 融入到既有的 web application 當中。更棒的是,你可以用你喜歡的 Java debugger 來 debug 所有 Java 程式碼。

想要了解更多的話,請看 GWT Developer Guide 的 JavaScript Native Interface。或著,讓 GWT compiler 的設計師 Scott Blum 解釋給你聽也不錯喔。