2009-12-22

用 GWT 寫個「生命遊戲」吧!

原文寫於 Java 版(ptt.cc)

以 GWT 教學系列來說,應該先講環境建制之類 blahblah
不過還是跳過那些繁文縟節,先講比較實在的部份
如果這樣子寫 JavaScript 的方式沒辦法引起興趣
還是會想要用 jQuery 之類的方法來寫程式
那開發環境安裝起來再快(例如 XAMPP [大笑]),也沒啥意義 :P
------------

寫一個 JavaScript 版的生命遊戲(Game of life)
要花多久? 有多難呢?

嗯? Java 版不是說好不提 JavaScript 嗎?
好好好,那拿出以前交作業的 Java 程式吧! [咦?]

首先包個「細胞」class
狀態只有兩種,要嘛活著要嘛死掉
不過得多個變數預知下一代會生會死
public class Cell{
  private boolean now;
  private boolean next;
  public Cell(){}

  public Cell(boolean alive) {now = alive;}

  public boolean isAlive(){return now;}

  public void setNextAlive(boolean alive){
   this.next = alive;
  }

  public void nextTurn() {now = next;}
 }
然後再來包個「世界」的 class
裡頭有一堆細胞,所以用個二維陣列來表示
至於 width, 跟 height 這兩個 field 純粹只是為了懶惰好看 [逃]
public class World{
  private int width;
  private int height;
  private Cell[][] cell;

  public World(int w, int h){
   width = w;
   height = h;

   cell = new Cell[w][h];
   for(int i=0; i<2; i++){
    tmpW = w+i;
    if( tmpW<0 || tmpW==width){
     continue;
    }
    for(int j=-1; j<2; j++){
     tmpH = h+j;
     if( tmpH<0 || tmpH==height){
      continue;
     }
     if(tmpH==h && tmpW==w){
      continue;
     }
     if(getCell(tmpW, tmpH).isAlive()){
      sum++;
     }
    }
   }

   switch(sum){
   case 0: case 1: case 4: case 5:
   case 6: case 7: case 8:
    getCell(w, h).setNextAlive(false);
    break;
   case 3:
    getCell(w, h).setNextAlive(true);
    break;
   }
  }

  public Cell getCell(int w, int h){
   return cell[w][h];
  }
 }
好了,物件都包好了,那麼現在該來解決畫面了
這次不用 Swing、也不用 SWT,試試傳說中的 GWT [奸笑]

「監視器」本身是個 panel,至於 vertical 在幹麼就跳過。
監視器要監看生命遊戲的世界,還要有一個棋盤來顯示狀況
所以 field 大概就是這樣啦~
public class Monitor extends VerticalPanel{
    private World world;
    private Grid board;
    private int width = 10, height = 10;
}
constructor 要把「世界」跟「棋盤」正式建立起來
「棋盤」要放在「監視器」上頭,還要有個按鈕讓人家可以點下一步
所以...
public Monitor(){
  world = new World(width, height);

  board = new Grid(width, height);
  this.add(board);

  Button next = new Button("下一世代");
  //點下一步要幹些什麼好事?
  next.addClickHandler(new ClickHandler(){
    @Override
    public void onClick(ClickEvent event) {
     nextTurn();
    }
  });
  this.add(next);

  //重新整理畫面
  refresh();
 }
這邊先跑出來兩個新的 method
nextTurn() 沒啥好講的,就是要 world 過個年,然後重新整理畫面
public void nextTurn(){
  world.nextTurn();
  refresh();
 }
至於 refresh(),我打算讓活著的細胞用「X」來表示
死掉的細胞的空空白白的什麼都沒有(其實是全形空白)
private void refresh() {
  for (int i = 0; i < width; i++) {
   for (int j = 0; j < height; j++) {
    if (world.getCell(i, j).isAlive()) {
     board.setText(i, j, "X");
    } else {
     board.setText(i, j, " ");
    }
   }
  }
 }
剩下的就是找到啟動的地方
在 GWT 裡頭是 EntryPoint 這個家族的 class 然後這樣寫:
public class Enter implements EntryPoint {
  public void onModuleLoad() {
   RootPanel.get().add(new Monitor());
  }
 }
好啦~ 恭喜你,只剩下 compile 以及找個網頁空間放 .js 檔
JavaScript 版的生命遊戲就... 寫 完 啦... \囧/

輕不輕鬆? 開不開心? [扭扭]
以前的 Java 程式碼可以直接拿來用...


阿? 什麼?
GWT 的開發環境要怎麼安裝?
程式碼要放在哪個目錄下?
怎麼指定 EntryPoint?
ㄜ... 請參照課本第 43 頁就可以了,好! 下課! [逃]

2009-12-11

GWT 2.0 介紹

原文網址:http://googlewebtoolkit.blogspot.com/2009/12/introducing-google-web-toolkit-20-now.html

今晚稍早,令人興奮的 Campfire One 結束了,在這個聚會上,我們宣佈 GWT 2.0 正式發佈。除了 GWT SDK 與 Google Eclipse Plugin 的重大改進外,GWT 2.0 包含了給 Chrome 使用的全新效率分析工具,名為 Speed Tracer。

Speed Tracer 介紹
我們已經在前幾個禮拜中提到過,現在真的可以用啦。Speed Tracer 是在 Chrome 上頭的強力效能分析工具,前所未有地讓你切入到「任何」的 web application(不再只是用 GWT 寫的)。想知道為甚麼你的 web application 感覺這麼遲鈍嗎?Speed Tracer 可以幫你找到答案。

看 Speed Tracer 運作是十分有趣的,下面是一個快速介紹的影片:


更快的開發速度、更快的 application
這裡是另外一個快速導覽的影片,展示 GWT 2.0 當中一些很酷的功能:


現在,讓我們更進一步看看 GWT SDK 跟 Google Eclipse Plugin 多了哪些新東西:

新的 development mode 跟 draft compile 加快「編輯」與「重新整理」的速度

  • GWT 2.0 引進了「development mode」這個 debug 的新方法,大幅改進了「編輯」→「重新整理」的週期。這可以讓你在自己選擇的 browser 上頭 debug,不再是用 GWT 指定的 browser。development mode 需要名為「GWT Developer Plugin」的 browser plugin,掛上這個 plugin 的 browser 就會跟你的 Java project 建立起 debug bridge。先撇開技術細節,這種 debug 的方法真的感覺不賴。
  • development mode 把 debug 過程直接轉移到 browser 上,這讓你可以使用每個 browser 特有的 development tool、必且能和 GWT 的工具結合在一起。是的,你現在可以在 Firefox 上頭抓 Java 程式碼的錯誤,同時使用像 Firebug 這種超強工具來看 DOM 結構、測試 CSS。
  • 新的 Google Eclipse Plugin 優化了啟動、控制 development mode 的支援,包含了一個新的(Eclipse 中的)view ,可以直接看到 development mode 的 log 訊息。不在 Eclipse 裡頭啟動,而是利用 Swing 寫成的使用者介面(包含其他 IDE)來手工啟動 development mode 也是可以的。
  • development mode 也支援同時在多個 browser 作 debug。這表示你可以在同一個 debug 階段連接一個以上的 browser。這個接口相當有用,可以讓 development mode 的 session 持續運作一長段時間,卻讓你只需要簡單地 refresh browser 就可以看到 Java 程式碼改變的結果。這可以讓你快速地確認 project 可以在多數主要的 browser 正常運作,而不用重新啟動 Java debugger。
  • 還有還有,development mode 可以跨網路運作啦。這有什麼厲害的咧?因為你可以輕鬆地在你 coding 以外的平台上對 browser 作測試。舉例來說,假設你在 Linux 上頭的 IDE 寫程式,你可以在同一個 debug session 透過網路用 Windows 上的 IE 或 Chrome、OS X 上的 Safari 或 Firefox 執行你的 application,還可以 debug。重點是你可以在任何你喜歡的平台上頭開發,然後在每一個使用者可能使用的 browser/OS 組合上頭測試。
  • 雖然 development mode 會大幅度地減少 compile 的必要,但如果你還是常常需要 compile 成 JavaScript,你可以使用 GWT compiler 的新 flag「draftCompile」,這會省略最佳化的過程而加快 compile 的速度。你必須清楚瞭解,用這個方法產生的 JavaScript 不應該 deploy 出去,但是它在非成品輸出的不斷 build 階段,是節省時間的好東西。
用 UiBinder 來描繪 UI
  • GWT 2.0 引進一個建立 UI 新方法「UiBinder」,可以大幅提昇產能。UiBinder 的機制讓 UI 的外觀可以輕易地跟 application 的邏輯分離。在一個 UiBinder 的 XML template(*.ui.xml) 檔案裡頭宣告 HTML 跟 widget 就可以建構你的 UI 畫面。至於 application 的邏輯就放在相關的 .java 檔裡頭。
  • UiBinder 讓網頁設計師更容易直接切入開發流程中。舉例來說,開發人員可以複製貼上網頁設計師提供的 HTML mock。我們也看到,網頁設計師會喜歡直接修改 UiBinder XML template 然後在 development mode 當中快速的測試 UI 設計結果。用可互動的 widget 來設計,一定會比被動地用 HTML mock 來的有趣的多。
  • 這並不是說,你在用 UiBinder 時只能用內建的 widget。結合你自己的 widget 到 UiBinder template 跟使用任何 built-in widget 一樣。(譯註:感謝 tkcn 協助指正)
  • UiBinder 也可以協助預防微小的 bug,像是 ID 打錯,因為在 compile 的時候會交叉比對驗證 .ui.xml.java
  • Google Eclipse Plugin 現在提供 UiBinder 方面的建置精靈、code completion、red squiggly(譯註:spell check?)以及 refactoring,讓你用 UiBinder 更有效率。
Layout Panel 讓你有完美的視覺效果
  • 精準地弄出你想要的 look and fell 的 UI,向來是 HTML 跟 CSS 的一個棘手問題。在 GWT 2.0 之前,連 GWT 的 widget 也無法完整 abstract 出來,這導致某些 layout 很難做出來。不過,GWT 2.0 引入了「Layout Panel」機制,讓你可以精確地做出你想要的 layout。GWT SDK 裡頭那個 Mail 的範例已經改成這個方法,你可以從這裡看出它怎麼運作的。
  • Layout Panel 在標準的 CSS 上建立一個可預料、constraint-base 的 layout system。因為它跟 CSS 並存而不是不理會 CSS,Layout Panel 持續如預期顯示你需要載入的自訂 CSS。又因為 CSS-base 的 layout 實質上是由 browser 的 rendering engine 處理的,因此並不需要任何 JavaScript。所以,layout 非常快速而且流暢,你可以在調整 browser 視窗大小的時候感受特別深刻。
  • 正如你所預期的,Layout Panel 用 UiBinder 來操作特別順。只要幾行 XML,你就可以弄出非常精緻複雜的 layout,包括 animated transition、splitter...... 等等。
改進 Compiler
  • GWT 2.0 一個很關鍵的新功能是「developer-guided code splitting」。舉個簡單的比喻:你該不會希望在 YouTube 看影片的時候,是整部片下載完才能看吧?你會希望影片馬上開始,其他的部份繼續下載—web application 也是同樣道理。啟動 web application 不應該讓你感覺像是在「安裝」東西,而是當你按下 hyperlink 的時候就馬上開始。Code splitting 是非常有力的工具讓你實現這個想法。
  • 這聽起來很複雜,但是實際上 code splitting 相當簡單。只要找到你的 project 當中想要切出一些程式碼的點,然後用 GWT.runAsync() 這個新的神奇 method 來建立一個 split point。藉由胡亂增加 split point,你可以輕鬆且安全地切割你的 application,以確保一開始下載的部份是啟動程式的最低所需。Compiler 會安排其他的程式碼片段在稍後才下載。不像手動分割 JavaScript 檔,GWT compiler 把繁雜的工作都包好啦,會確保所有相依的部份會自動按照正確順序下載。GWT SDK 當中的 Showcase 範例已經更新成使用 code splitting,你可以去看看成效。
  • 除了 code splitting,compiler 還做了一些重要的改進,來增強產出 JavaScript 的能力。每個 GWT 版本釋出時,我們會改善 compiler 的最佳化技術,讓 JavaScript 更小也更快。當你已經有一堆 GWT project,這就很棒啦,因為你可以很簡單的升級、重新 compile 然後—嘿嘿,你的 application 就會啟動的更快、跑的更順。GWT 2.0 包含了一些強力效果的最佳化作法,我們也看到產出的 JavaScript 縮小了 3~20%。
用 ClientBundle 來最佳化 resource
  • GWT 1.4 有 ImageBundle 這個 resource-bunding 功能,ClientBundle 繼承這個 pattern 並且延伸出去。只要宣告一個簡單的 interface,就可以在 compile 階段把 resource 直接嵌入到最終的 JavaScript 還附帶最佳化。舉例來說,bunding 圖片可以讓你省去一堆 HTTP 溝通過程。ClientBundle 支援更多樣的 resource 種類,包含圖片、文字、甚至 CSS。
  • CSS?沒~錯!CssResource 是一個新的 framework 讓你可以有效管理 style。It supports a new extended CSS syntax for defining sprites, named constants, scopes, conditional selectors, and more. t also aggressively optimizes your CSS by stripping comments and whitespace and by obfuscating class names.(譯註:CSS 不熟,實在不知道怎麼翻 Orz)
  • ClientBundle 是可以擴充的。你可以創造自己的 resource 種類,然後 hook 進 ClientBundle framework,使得你找得到你要用的 resource 卻又能保持 interface 一致與簡潔。
(痞子:最後兩段「Special Thanks」跟「Getting Start」就懶得翻了 [茶])

2009-12-03

GWT:這是什麼?幹什麼的?

就像看電影會先看預告片、買 A 片會先看封面
學 GWT 之前,先知道 GWT 是什麼? 能做什麼?
再來決定要不要學,這十分重要

生命中有這麼多美好的事情(例如 H-Game [誤])
不知道為了什麼而學(無趣的)新技術
實在是浪費時間虛擲生命

所以,GWT 是什麼呢?

他是 Java 界的救星
他是 JavaScript 界的剋星
更是網頁開發界的啤兒綠茶... \囧/


好好好,我言歸正傳就是了... [被毆飛]

〔GWT 是什麼?〕
是 Java、也是 JavaScript [扭]

GWT 全名是 Google Web Toolkit
望文生義,是用在網頁上頭的工具組

以軟體開發的角度,GWT 的核心是一個 Java compiler
處理 Java 程式碼,但輸出的不是 byte code
而是在 browser 上頭執行的 JavaScript

因此,為了方便開發時的測試與除錯
GWT 有 hosted mode,包括一個 JSP container 跟 browser
在 hosted mode 下,可以在 runtime 獲得一些錯誤訊息與資訊
這些訊息是由 GWT 提供,會比較好讀、貼近程式碼
(如果你想倚賴 browser 或 FireBug 來 debug,忘了他們吧! XD)
也能點出一些 GWT 才會有的錯誤
例如在 client 端的程式用了 java.util.Hashtable


以軟體架構的角度,GWT 的程式碼
分為 client 端以及可有可無的 server 端

client 端的基礎是 JSNI(JavaScript Native Interface)
Java 無法涵蓋 JavaScript 的部份
尤其是 browser 層級的操作
可以用 JSNI 的寫法包成 Java 可呼叫的 method

GWT 提供基本開發需要的 class 與相關機制
例如 UI componet、event handling、Http wrapper、JSON parser...
已經把 JSNI 包的差不多了
也許你寫完一個 project 都還看不到 JSNI 的影子

server 端的部份,主要是 GWT RPC
RPC 原文是 Remote Procedure Call
簡單地說,這讓你可以幾乎毫無感覺地使用遠端的 method/object
這裡的「遠端」當然是指 web server

GWT RPC 把 HTTP 的傳輸過程包起來
要傳遞的資料,封裝跟 parser 的手續也包起來
不管是在寫 client 端還是 server 端
都不用煩惱這些繁文縟節(而且,都是用 Java 寫!)
Java Compiler 還幫你作 type checking

真是太棒了阿... 這麼好的東西我以後用不到怎麼辦 <囧>

等等... 前頭不是說:server 端是可有可無的嗎?

是的,用 GWT RPC 有一個前提,server 必須是 JSP container
如果你是用 PHP 或是其他語言
又或著你想使用 JSON、XML 的方式來傳遞資料
那麼,GWT RPC 是可以完全不去理會的

〔GWT 能做什麼?〕
client 端? server 端? 傻傻的不用分清楚!

純粹以 JavaScript 的角度來說
JavaScript 能做到的「效果」(不是語言特性 XD)
都能以 Java code 寫出來
在某些情況,(大多是沒有 library 幫你包好 囧>)
才可能需要寫 JSNI 來做到底層控制

以網頁開發的觀點
GWT 能讓你以傳統 application 的思維來面對網頁程式

以 browser 的角度來看,GWT 用 JavaScript 操作 DOM
來產生 & 控制所有的畫面
(再囉唆一次,寫的時候還是用 Java XD)
因此當畫面改變時,頁面不用切換,變數也就不用傳遞
所以,你不用思考 JavaScript 變數要怎麼傳到下一個畫面
也就不用煩惱到底要塞 session 還是跟著 URL 帶著走

如果你用 GWT RPC,那更徹底
除了 callback 的寫法比較怪了點
其餘的部份,你很難分辨是在寫 Java application 還是在寫網頁
object 內容的維持、與 server 的同步也不再是瑣事 or 難事

對於會寫 Java Application 的人而言
要跨進 web 開發的領域
不用把思路切換成一頁一頁的方式、
不用學一堆新技術新語言、
不太需要知道哪些是 server/client 處理
甚至感覺不到 stateless
以開發的角度,這不是很美妙的一件事情嗎?

註:這裡不討論安全性的議題
(迷之聲:因為有人不會 [指])


〔GWT 不能做什麼?〕
不能讓你寫 JavaScript... [誤]

JavaScript 作不到的事情,GWT 也作不到
雖然這根本就像在說廢話 XD
但是當你在撰寫 client 端的程式時
得時時刻刻想起這句話
不然,寫到忘我的時候
很順手的就想讀個 File、連個 DB
Eclipse 這類的 IDE 也不會出現 compile 錯誤
(在 GWT compile 時還是會炸出錯誤訊息)


我研究 GWT 還不是很透徹、其他 JavaScript 的技術也沒在碰
所以 GWT 這個架構不能做什麼? 我實在回答不出來 [毆飛]

這邊只能提出一個「可能性」
就是 GWT 要整合其他 JavaScript 的技術
也許很困難 or 不可能?
之前要嘗試用 jQuery 將 GWT 生出來的 TextArea
裝上彩色模擬 scroll bar 就屢戰屢敗 Orz
(這跟當時懵然無知也很有關係 [炸])
換個角度想,用 GWT 是一定可以做出同樣效果
只是目前可能還沒有人寫 or release 出來

跟 jQuery 比起來,base on GWT 的 UI component(包含 3rd party)
的確是很量少虛弱又天生難看(靠自己的化妝技術彌補)
但這只能算是暫時的缺點,不能算是「作不到的事情」


〔為甚麼要用 GWT〕
因為這是一種 Rock'n Roll 的 style!

如果你喜歡一個 project 同時有好多技術
如果你喜歡自己掌握 HTTP/HTML/JavaScript 的所有細節

或著,你討厭 Swing 那類的 UI code
又甚至,你壓根討厭 Java 的一切

那麼,千萬、千萬不要碰 GWT

反過來說,如果你跟我差不多笨(好可憐阿 [炸])
對 Java 死心塌地,寫起來如吃飯睡覺一般自然
那麼,GWT 會是一個契機、一個救贖、一個捷徑

好了,接下來就要開始進入正題了......

2009-11-18

GWT:序章—用? 不用? Java 的錯?

我注意到 GWT 是今年年初的事情
如果再不碰 AJAX 的技術,就準備骨灰罈把自己裝進去吧![炸]

同時進了一家小工作室,於是跌跌撞撞
把開發環境從 PHP(CodeIgniter)+jQuery
先用 GWT 換掉 jQuery 以及畫面輸出,完成了兩個案子
最後是用純 GWT 完成了一個案子... 然後離職了 lol

雖然都沒用什麼高深的技術、案子也都不大
但也勉強能算是實做過
因此,我一直對 GWT 在台灣(或華文世界?)討論 & 資源很少
甚至連掀起一陣熱潮都沒有(例如像 Ruby,至少出了一堆中文書)
總覺得哪裡怪怪的

如果以 ptt.cc 當樣區
是說,除了 jQuery 之外,其他 AJAX/JavaScript的技術
Ext、YUI、dojo、DWR... 也沒看到什麼討論
Java 版上頭也幾乎是基礎的 J2SE 問題涵蓋了 80% 以上的討論
JSP 的問題也幾乎都「只是」JSP 的問題
zk, JSF 還有一堆東西,幾乎都不見蹤影

這會不會是 ptt.cc 的一種趨勢,除了西瓜效應之外
也停滯不前,或說對新技術的不在意 or 不敏感?
亦或是高手們覺得孤掌難鳴曲高和寡,問/講了也是白問/講?

ㄜ... 扯遠了...

最近沒有工作,加上這兩篇的 combo 連擊 XD

→《Is GWT the future of web development?
翻譯:《GWT 是網頁開發的未來嗎?

→《Lost in Translation or Why GWT Isn't the Future of Web Development
翻譯:《轉換不完全—為甚麼 GWT 不會是網頁開發的未來呢?
以下簡稱《Isn't Future》

讓我興起想要寫 GWT 推廣文系列的念頭
(迷之聲:系列? 誰知道你能撐幾篇... [毆])

在以傳統教學方式介紹 GWT 之前
先針對反對 GWT 的論點作一些思考
畢竟,知道敵人(?)怎麼想,是很重要的....
(雖然我覺得《Isn't Future》寫的實在... Lost in Words? lol)

OK! Let's start...


*   *   *


〔Java 是快過時的東西嗎?〕
GWT 是以 Java 語法作為開發語言
我們在寫 GWT 時,絕大多數是在寫 Java
只有在需要直接操作 JavaScript 時
才需要藉由 JSNI 來寫一些 JavaScript

《Isn't Future》強調 script 才是未來的主流
type safety 沒有也沒差
dynamic typing 可以少掉很多麻煩
JavaScript、Ruby、PHP 等等語言也寫出很多軟體、也沒有炸掉
在開發階段可以少些時間在等待

(這篇文章看到後來,比較像是在詰譙 Java Orz)

我的程度無法討論 or 比較這些東西誰優誰劣
或著說,我的程度只能寫 Java
因為 Eclipse 這種等級的 IDE 可以幫我處理很多雜事
code assist 也好、open declaration 也好(撇開 OO 的部份)
至少我年初用 PDT 跟很久之前用 RDT
都沒有堪用有效的工具(據說是很難有?)

當然,script 語言如果封裝的好、能夠產生良好的 API doc
那麼這些東西或許就沒差? 充其量就是腦袋要記得多一些東西?

但是,如果回歸商人的角度去想
為甚麼 Google 在選擇 GWT、Android 的開發語言
是用 Java 而不是用 Python?(即使是 App Engine 後來也?)
或是,理論上更多人會用的 C/C++?

話說回頭,「潮流」這回事情實在令人費解
很久以前的 Basic 系列都不用定義變數型態
後來 VB 可以不用定義、也可以強制定義、到後來就都要了
現在有人說,script 才是未來的主流
這中間的思維轉折,到底是怎麼一回事呢?

〔為甚麼我要學 JavaScript?〕
假設你會機械語言 [笑]
你會用機械語言當作軟體開發的語言嗎?

《Isn't Future》的答案是:
你應該要用機械語言;而不是用高階語言撰寫,再透過工具轉換成機械語言
中心思想是 Joel 的文章《The Law of Leaky Abstractions》
試圖論述一件事情:Java 不可能完整地轉成 JavaScript
這又可以拆成兩個部份來討論
一個是實作的能力、一個是語言本身的能力

關於「實做的能力」,《Isn't Future》沒有明確地說些什麼
我想,如果 Google Wave (GMail?)是用 GWT 做出來
這部份大概也沒什麼好質疑的
理論上 JavaScript 能作的事情,GWT 都(可以)有對應的功能
(還有 JSNI 這個大絕招嘛... [炸])

更進一步說,如果你用 GWT(剛好又會 Java 跟 Swing 基本概念 :P)
你將可以擺脫傳統寫網頁程式的困擾:要會一堆東西
(X)HTML、JavaScript、DOM、AJAX...
最後還來個該死的瀏覽器差異
也不用為了要處理上頭那一堆東西,再去學一個像 jQuery 的東西
(jQuery 的程式碼看起來像另一種語言 XD)
你就是在寫 Java,只不過出來的畫面是在 browser 上

當然,我認同文中說「好的程式設計師應該能很快的學會新東西」
但是,開發階段最痛苦的是那些藏在細節中的妖魔鬼怪
這跟學習能力好壞與否無關
唯有對該技術的深入瞭解才能稍微減輕 or 減少這種痛苦
我這種笨蛋,沒辦法掌握太多(各自獨立)的技術

《Isn't Future》大多數是在闡述很多 JavaScript 的語言特性
在 Java 當中是沒有的,而且有些根本作不出來。

問題是:為甚麼? (盧廣仲:Rock!! [炸])

如果功能都做得到,那麼語言特性真的有那麼重要嗎?
我們真的需要在 object 上頭隨意加掛 attribute 跟 method 嗎?
我們真的需要寫 first class function 嗎?

如果不是沒有也無損功能實做(最多囉唆點 :P)
那麼 Java 不能做出 JavaScript 的語言特性,又如何?
現在大多數的語言也沒有 goto 或是 jump 啊?

嗯... 還好我不會機械語言 :)

〔其他〕 上頭沒涵蓋的零散論點,集合在這裡
→GWT 內建 widget 醜到爆
如果你在意自己長得不夠美
只要體質好、本錢夠,整形技術可以讓你煥然一新

只要在 gwt.xml 拿掉設定,widget 預設的 CSS 就會移除
還原成 browser 最原始會呈現的樣子
要自己加掛 CSS name 當然沒有問題,剩下來是美術人員煩惱的事情

反過來說,我還沒看過什麼正式的網站
不去修改元件的外觀(Google 自己的網站不算 XD)

愛美不是罪,但是本末倒置是一種錯誤。

→compile 速度爆慢
GWT compile 成 JavaScript 的時候,真的是打混摸魚的好時光
但是在「全部使用 GWT」的情況下
開發階段根本不需要 compile

client 的變動,在 hosted browser reload 之後
跟改 PHP/JSP 然後重新 reload 的速度差不多
(重點是 GWT 只有「一頁」,PHP/JSP 有好多頁)

server 端的變動,需要 restart server
這跟改 web.xml、servlet 的狀況是一樣的
(GWT RPC,server 端是一個 servlet)
跟 GWT 的 compiler 沒啥關係

只有在 server 端不是使用 GWT RPC
因為 cross-domain 的關係,必須先 compile 成 JavaScript
放到實際 web server 上頭才能測試
(當時有弄出用 form submit 來暫時代替的奧步,可省下一些時間 XD,不知道有沒有其他方法?)
GWT 2.0 會對此做出改進
但是對純 Java(GWT)開發環境而言,其實就還好...

〔結尾 & 開始〕
《Isn't Future》並沒有說服我
還是選擇站在 GWT 這邊的  \囧/

接下來,我會開始唬爛 GWT
盡量有系統地瞎掰出一些教學文章

如有謬誤之處,還請高手前輩們指點一二以正方家
如有疑問 or 建議,也歡迎版上討論 or 來信指教


就先這樣啦~ 囧>

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」的部份,中文翻譯是直接引用中文版的對應段落。

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

2009-11-06

GWT 是網頁開發的未來嗎?

原文網址:http://blog.balfes.net/?p=869

有非常多的人看過、玩過、或聽過 GMail 以及其他像 Google Wave 的應用程式。是否曾經納悶這些應用程式是怎麼做出來的?那你應該去看一下 Google Web Toolkit(GWT)。我從上個禮拜開始瘋狂地寫 GWT,我必須承認它非常有趣,應該會有很多支持它的理由。當你在開發 web 應用程式時,可以用到 Eclipse 這個 IDE 的所有好處,而且你寫的語言卻是 Java,你就會認同我了。最棒的是,你可以重頭到尾都在寫 Java,但是最後 compile 的結果卻是一個以 JavaScript 做出來美妙 web 2.0 應用程式。GWT 的 compiler 支援絕大多數 Java 語言的內容。

你可以看一下 GWT API Reference 導覽,實際感受一下 UI 可以好到什麼樣子。基礎的 widget library 也可以馬上讓你用用看;如果基礎的 widget 沒辦法滿足你,你也自己弄一些 custom widget。我覺得做的實在很棒的是 i18n 的技術(雖然我並沒有處理過很多 i18n 的東西)。講到 debug 那更是不得了,你現在可以輕鬆在 Eclipse 用正統的 debugger 來開發、debug 你的 JavaScript 應用程式。GWT Compiler 只產生一些 JavaScript 跟 HTML 檔,與其他公開的 resource(例如 CSS、圖檔)分開。在 deploy 時,你需要做的就是把這些東西放到你的 web server 上。

為甚麼 GWT 可以這麼酷咧?我想關鍵點在於它會吸引 Java 開發者,而且在轉成 JavaScript 的時候還會幫你作最佳化。你會得到一堆混淆過後的 JavaScript 檔案,且已經針對主要的 browser 作最佳化—這些常常是你得先知道怎麼作,然後常常還得自己手工處理的煩人事。你還可以把你做的東西掛進 GWT SDK 當中。為自己的產品及開發人員,建立自己的 service、UI 元件。還有還有,GWT 是 open source 的,你可以在 Apache 2.0 license 的規範下使用 & 修改它

我相信我們會聽到更多 GWT 的東東,我也希望聽到關於這個 Web 2.0 開發方式的不同意見。

========
原文下面還有一堆 comment,就懶得翻譯了 XD
作者後來又 po 了一篇補刀的文章,也可以順便看看

2009-10-12

「讓 AJAX 網頁可以被網路爬蟲讀取」的建議書

原文網址: http://googlewebmastercentral.blogspot.com/2009/10/proposal-for-making-ajax-crawlable.html

今天,我們很興奮地提出「讓以 AJAX 為基礎的網站可以被網路爬蟲讀取」的規格建議書。這將有益於網站管理者和使用者在製作豐富、互動的 AJAX 網站時,可以讓所有的搜尋引擎讀取到想要被搜尋到的部份。我們相信,這類的內容如果可以被網路爬蟲讀取以及被索引,將會讓網路有長足的進步。

當 AJAX 網站受到使用者歡迎的同時,搜尋引擎並無法讀取這些網站的內容。我們的最新調查顯示:有 70% 的網站在 form 或是其他地方使用了 JavaScript。當然,大部分的 JavaScript 並不是 AJAX,但是如果搜尋引擎可以處理、索引 AJAX 的內容,開發者就可以在他們的網站上做出更多豐富的內容,而搜尋引擎依然找得到。

下面是這份建議書希望達到的目標:

  • 當網站成長時,所需要的變動是最小的
  • 使用者跟搜尋引擎看到的是相同的內容(無須 cloaking)
  • 搜尋引擎可以直接讓使用者導向到 AJAX 的 URL(而不一個靜態複製網頁)
  • 網站擁有者有方法可以驗證他們的 AJAX 網站顯示正常,也因此網路爬蟲可以讀取所有的內容。

下面是我們初步建議書當中,搜尋引擎處理、索引 AJAX 內容的方式:

  • 把 stateful 的 AJAX 頁面的 URL fragment 稍作修改:
    無論何時,直接讀取 stateful 的 AJAX 頁面都會顯示一樣內容。這些頁面可以變成搜尋結果。我們想把像這樣的 URL「http://example.com/page?query#state」 加上一個 token 成這樣「http://example.com/page?query#[FRAGMENTTOKEN]state」以作識別。在檢視網路上的 URL 之後,我們建議使用驚嘆號「!」。在搜尋結果當中顯示的 URL 會像這樣「http://example.com/page?query#!state」。
  • 使用 headless 瀏覽器,讓你的 web server 有一個 HTML 的 snapshot。
    headless 瀏覽器用來讀取 AJAX 頁面,然後最終瀏覽器的結果產生 HTML。只有特別標記的 URL 才傳給 headless 瀏覽器處理。在 server 端作這件事情時,網站擁有者可以控制 HTML  的產生,也就可以輕鬆地驗證所有的 JavaScript 是否正常執行。HtmlUnit —open source、沒有 GUI 的 Java 程式—就是一個 headless 瀏覽器的例子。
  • 允許搜尋引擎的爬蟲去讀取有對 state 作 escape 的 URL
    URL fragment 並不會隨著 request 送到 server 去,所以需要稍微變動 URL 以讀取該頁面。同時,這也會讓 server 啟用 headless 瀏覽器去產生 HTML 而不是傳回有 JavaScript 的頁面。此外,既有的 URL—使用者看到的那些—則會用平常的方式處理,不會啟用 headless 瀏覽器。我們建議 escape state 資訊,然後把它加到 query parameter 當中,變成一個 token。用上頭的例子,URL 可能會長這樣:「http://example.com/page?query&[QUERYTOKEN]=state」。依照我們對現在網路上 URL 的分析結果,我們建議用「_escaped_fragment_」來作為 token。建議的 URL 會變成:「http://example.com/page?query&_escaped_fragment_=state」
  • 在搜尋結果當中,顯示原來的 URL
    為了改善使用者經驗,這會讓使用者直接連回 AJAX 頁面。搜尋結果當中顯示原始的 URL(如前面的例子:http://example.com/page?query#!state)就可以做到。搜尋引擎可以檢查被 Googlebot 索引的文字,是否跟使用者看到的一樣(或是子集)。



總結來說,如果一個 stateful 的 URL,例如:「http://example.com/dictionary.html#AJAX」,同時給使用者或網路爬蟲使用的 URL 會變成「http://example.com/dictionary.html#!AJAX」,而可以被爬蟲爬的 URL 會變成「http://example.com/dictionary.html?_escaped_fragment_=AJAX」,但使用者存取還是用「http://example.com/dictionary.html#!AJAX」

2009-10-07

GWT Animation 再探

在〈GWT Animation 初探〉當中,程式已經能讓畫面看起來有動畫的效果,「表面上」要怎麼使用 Animation 是沒有問題了;不過這樣子有些無趣,還是要殺進去 Animation 來瞭解這一切背後的內幕(?)。

起點當然是 Animation.run(),沒有呼叫這個 method,是不會有什麼反應的。run() 有兩個,run(int duration, double startTime) 的 duration 是 Animation 預計持續作用的時間;startTime 是預計執行的時間。為甚麼用 startTime 的 data type 是 double 呢?這點在 Animation 不算是有用到的 Duration.elapsedMillis() 可以找到答案:
Returns the same result as System#currentTimeMillis(), but as a double. Because emulated long math is significantly slower than doubles in web mode, this method is to be preferred.
因為在瀏覽器上頭,使用 double 處理起來比模擬 long 還要快得多(btw... 為甚麼 Animation 只用了 Duration.currentTimeMillis() 取得時間,而沒有用 Duration.elapsedMillis() 去計算時間差,這我一直想不透 XD)。另一個 run(int duration) 其實還是呼叫 run(int, double),只是自動以當下時間傳給 startTime。

回到 run(int, double) 的內容,關鍵點在於下面這段
if (animations == null) {
   animations = new ArrayList();  //point-A
   animationTimer = new Timer() {
    @Override
    public void run() {
     updateAnimations();
    }
   };
  }
  animations.add(this);
這邊要回頭看一下 Animation 的資料結構。講起來有點饒舌。大致上來說,Animation 有一些 static 的 field 跟 method,目的是統一處理系統當中所有的 Animation object(程式碼 point-A)。這裡也可以看到,其實 Animation 裡頭是用 Timer 來實做的。Timer 的細節得先跳過,這裡只要知道看到 animationTime.schedule(int delayMillis) 就表示隔了 delayMillis 個 ms 就會執行 updateAnimations() 的內容,而 updateAnimations() 會呼叫 update()。那麼,勢必有需要好好看一下 update() 的內容:
private boolean update(double curTime) {
  boolean finished = curTime >= startTime + duration;
  if (started && !finished) {
   // Animation is in progress.
   double progress = (curTime - startTime) / duration;
   onUpdate(interpolate(progress));
   return false;
  }
  if (!started && curTime >= startTime) {
   // Start the animation.
   started = true;
   onStart();
   // Intentional fall through to possibly end the animation.
  }
  if (finished) {
   // Animation is complete.
   onComplete();
   started = false;
   running = false;
   return true;
  }
  return false;
 }
裡頭依照不同的狀況,呼叫了 onUpdate(), onStart()onComplete()。嗯?為甚麼只有 onUpdate() 是 abstract 的呢?因為這兩個到最後還是去呼叫 onUpdate(),progress 的值給 0 表示剛開始、給 1 表示結束。接下來就是最詭異的部份啦,傳給 onUpdate() 的數值,居然還要經過 interpolate() 的計算,這又是為甚麼呢?根據 javadoc 的說法:
Interpolate the linear progress into a more natural easing function.
看個對照圖可能比較好懂:

在開始跟結束的部份比較緩和,或許這樣比較符合人類視覺觀點?總之,這是為甚麼 Animation 的 javadoc 會說「at a non-fixed frame rate」了。(順帶提一點,相同的 duration,呼叫 onUpdate() 的次數應該會一樣,但是 progress 值會有差異。這應該是 Timer 先天上無法很精準的缺陷?)

看到這邊,Animation 應該可以說沒有秘密了。剩下來就是如何運用的問題了...... [遠目]

2009-10-05

GWT Animation 初探

Animation 是 GWT 內的一個 class,名字取的很美妙,實際上是在做什麼的呢? GWT 的 showcase 給了一個示範,不過裡頭的程式碼實在有點古怪,姑且直接來看 1.6 版的 API doc 怎麼說。
An Animation is a continuous event that updates progressively over time at a non-fixed frame rate.
哈哈... 根本就是騙人的,哪來什麼動畫 [笑]。簡單地說「Animation 是一個會持續要求 update 動作的物件。而間隔的時間是不固定的。」阿?這什麼鬼?還是用程式碼來說明好了...

import com.google.gwt.animation.client.Animation;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.Label;

public class HelloAnimation extends AbsolutePanel{
 private Label hello = new Label("Hello Animation");
 private final int WIDTH = 800;
 private final int HEIGHT = 200;
 
 public HelloAnimation(){
  this.setPixelSize(WIDTH, HEIGHT);
  this.add(hello); //要先加上去,才有辦法移動
  Player player = new Player(this);
  player.run(5*1000); //point-A
 }
 
 public void playOneFrame(double progress){
  this.setWidgetPosition(hello, (int)(WIDTH*progress), HEIGHT/2);
 }
}

class Player extends Animation{
 HelloAnimation target;
 
 public Player(HelloAnimation t){
  target = t;
 }
 
 @Override
 protected void onUpdate(double progress) {
  target.playOneFrame(progress);
 }
}

只要 new 一個 HelloAnimation,然後加到 RootPanel 上頭去,就會看「Hello Animation」從畫面左邊跑到右邊。(至於最後「Hello Animation」突然換行的狀況,先跳過... XD)

裡頭兩個 class 分別負責兩件事情。HelloAnimation 負責畫面顯示的部份,直接 extends AbsolutePanel,搭配 AbsolutePanel.setWidgetPosition() 就可以很快速地設定 widget 的位置,這樣在上頭的東西「動」起來就相對方便。playOneFrame() 這個 method 就是在處理這件事情,至於 progress 這個參數的作用,就必須回到 Animation(也就是範例程式裡頭的 Player才能說明。

Player 這個 class 其實很簡單,extends Animation 之後,只有一個 method 必須實作,就是 onUpdate()。這個 method 就是 API 提到的效果,當 Player 起作用的時候,onUpdate() 就會持續地被呼叫、並且給予不同的參數 progress 值,值域介於 0~1 之間,會隨著時間會越來越大,乘上 100 就是完成度啦,因為實際負責「動」的物件是 HelloAnimation,所以在呼叫 HelloAnimation.playOneFrame() 時候就原封不動地傳進去。這個參數在製作像動畫這種東西時,就很方便,因為 Animation 幫你算好 progress,不用自己動手。像這個例子當中,「Hello Animation」要在指定的時間內橫越指定的寬度,但是在撰寫 playOneFrame() 時完全不用理會「指定的時間」有多長,只要把寬度乘上 progress 就解決了。現在動畫的長度是五秒鐘(程式碼 point-A),要改成兩倍慢 or 兩倍快,就只要在 player.run() 時給 10 秒 or 2.5 秒就可以了。

看到這裡,是不是覺得 GWT 設計的很好、使用起來很簡單呢? [奸笑]

至於 Animation 的細節,我們下次再談(初探嘛...)

2009-09-17

GWT 的 Debug Panel (3rd party lib) 介紹

原文網址:http://googlewebtoolkit.blogspot.com/2009/07/introducing-debug-panel-for-gwt.html

Debug Panel 最主要的用途,是提供開發人員在 debug client 端程式碼時,一些關於 application 的效能資料。用 GWT 建立的 web application,大部分在 client 端的環境運作,這是開發人員不太能控制或存取的。Debug Panel 提供開發人員一個工具,除去 client 環境的阻礙以便於診斷問題所在、調整或加強效能以助於 application 測試。

就像所有的 application,測試及品質保證(QA)對於 GWT application 也是很重要的。也因為 GWT application 是使用者介面,所以效能測試是非常重要的。但是,在 browser 上運作的 application,要測量它的效能不是件容易的事情。那些在 client 端才變動的部份(例如 RPC, DOM 的更新)、以及 GWT 讓你不再自己撰寫 JavaScript 的狀況下,要找出效能瓶頸就有點困難了。要自動化效能測試、以及取得 RPC 精確的反應時間,就更加困難。此刻就是 Debug Panel 登場的時候啦!這是一個外掛的 library,可以輕鬆地加到 GWT application 當中。它提供你效能面的數據、理解表面之下的運作,並且將這一切自動化!

下面是 Debug Panel 的真相:

Debug Panel 展示了調用 EchoService 的統計資料、以及起始時間。很明顯的,RPC 非常快就做完了。其中最慢的部份是在等待 server 的回應,花了 121ms;serialize request 跟 deserialize response 都花了 19ms;更新 server 回傳的資料到 UI 上頭花了 2ms。這些事你會想要看到的數據。

下面是 Debug Panel 的另一個真相:

這次有點不一樣,這個 application 在 Hosted 模式下運行時,在 RPC 的過程中炸了一個 exception。當你把 application 轉譯成 JavaScript 時,stack trace 很理所當然地會是 JavaScript 的 stack trace。exception panel 是 Debug Panel 裡頭的一個延伸。GWT 的開發者可以針對自己的需求,把客制化的 panel 加到 Debug Panel。Debug Panel 提供一個 framework,讓你可以用一個輕量級的元件加到你的 application 以顯示相關的 debug 資料,並且可以傳遞相關資料給 Debug Panel,還不太會影響到執行效率。

事實上,你可以在不改任何程式碼的情況下,把 Debug Panel 掛到一個已經存在的 application。這也表示在 compile JavaScript 時不用作啥改變。你可以讓 GWT application 在處理內部 IP 時讓 Debug Panel 起作用,其他狀況下則關掉。

試試看 Debug Panel 的線上範例、也看一下 source code,你就會發現使用起來有多簡單啦。到我們在 Google Code 的主頁也可以得到更多的資訊。

2009-09-15

CodeIgniter 1.7.2 更新紀錄


1.7.2

釋出日期:2009.09.11
SVN Revision:1737

Libraries

  • 新增 Cart Class
  • File Uploading Class 增加 $config['file_name'] 參數,可以變更上傳檔案的檔名。
  • 更改 user-agents 的清單順序,讓 Safari 可以更精準地被確定。

Database

  • escape() 裡頭用 is_* method 取代 gettype(),因為未來的 PHP 版本可能會改變這個 output 內容,因為未來的 PHP 版本可能會改變這個 output 內容
  • 更新所有 database driver,使 escape_str() 可以處理 array
  • DB driver 增加 reconnect(),可以在一長段 idle 之後用來試著保持連線或是重新建立連線。
  • 增加 escape_like_str():在使用 like 條件的時候可以對字串作 escape 處理
  • 用新的 like escape 處理機制,更新 Active Record 的部份。
  • 修改 MSSQL 的 driver,使用 mssql_get_last_message() 來取得錯誤訊息

Helper

  • Form helper 增加 form_multiselect()
  • 修改 Form helper 的 form_hidden(),可以處理多維度的 array
  • 修改 Form helper 的 form_prep(),keep track of prepped fields to avoid prep/mutation from subsequent calls which can occur when using Form Validation and form helper functions to output form fields.
  • 修改 Directory helper 的 directory_map(),可以顯示隱藏檔案、讀目錄出錯會回傳 FALSE
  • 讓 Smiley helper 可以在輸入多個 field 時正常運作、以及在最後游標位置插入表情符號的功能。

General

  • 相容於 PHP 5.3.0
  • 修改 show_error(),使之回傳 HTTP server 的 response code。
  • 修改 show_404(),會送出 404 的 status code、移除 error_404.php template 中與 non-CGI 相容的 header()
  • Common function 增加 is_php(),好作 PHP 版本的比對
  • 增加兩張 CodeIgniter 小抄(感謝 DesignFellow.com)

Bug Fix

  • 修正 user guide、example 裡頭各種 typo(#6743, #7214, #7516, #7287, #7852, #8224, #8324, #8349)。
  • 修正 Form Validation 當中,多個 callback 敘述不會運作的錯誤
  • doctype helper 的預設值總是缺少一個「1」
  • 修正 Language class 在找不到檔案室輸出錯誤的錯誤
  • 修正 Calendar class 當以短名輸出「May」的錯誤
  • 修正 ORIG_PATH_INFO 允許 URI 只有一個「/」
  • 修正 Oracle 跟 ODBC driver 發生的 fatal error(#6752)
  • 修正 xml_from_result() 會檢查一個不存在 method 的錯誤
  • 修正當送出多個 field 時,Database Forge add_column 與 modify_column 不會跑迴圈的錯誤
  • 修正 File Helper 改使用 DIRECTORY_SEPARATOR 這個常數而不是「/」
  • 當嘗試使用 sendmail 但是 server 卻把 PHP 的 popen() 關掉時,預防 PHP 發生錯誤
  • 修正當 PHP 的資料型態不符合 XML-RPC 型態時,會導致 XML-RPC 資料當中 PHP 發生錯誤的 bug
  • 修正 XML-RPC class 在 parse dateTime.iso8601 時的錯誤
  • xss_clean() 的字串替換改成大小寫有別
  • 修正 form_textarea() 在 form data 並沒有正確 prep 時的錯誤
  • Fixed a bug in form_prep() causing it to not preserve entities in the user's original input when called back into a form element
  • 修正 _protect_identifiers() 當 swap prefex($swap_pre)還沒有被偵測到的錯誤。
  • 修正當 400 status header 與「不允許的 URI 字元」一起送出時,無法與 CGI 環境整合的錯誤
  • Fixed a bug in the typography class where heading tags could have paragraph tags inserted when using auto_typography().

2009-09-10

ColorPicker (auroris) Bug Fix

技術提供:aries

「http://code.google.com/p/auroris/」這是一個 GWT 上的 3rd party library,負責提供還不錯的 color picker 元件。不過,在實際使用的時候,卻會有「某些時候」中間那條直立漸層色條出不來的 bug。經過一番血戰之後,終於抓到了... 設定顏色的時候少一個「#」

//ColorPicker.java 的片段
    public void onClick(Widget sender) {
        if (sender == rbHue) {
            // skip
        } else if (sender == rbSaturation) {
            if (colorMode != SliderMap.Saturation) {
                colorMode = SliderMap.Saturation;
                slidermap.setColorSelectMode(SliderMap.Saturation);
                sliderbar.setColorSelectMode(SliderBar.Saturation);
                slidermap.setOverlayColor("transparent");
                sliderbar.setLayerColor("#ffffff", SliderBar.BarC);
                sliderbar.setLayerOpacity(100, SliderBar.BarD);
            }

            slidermap.setOverlayOpacity(100 - saturation);
            /* ERROR
             * sliderbar.setLayerColor(tbHexColor.getText(), SliderBar.BarD);
             */
            sliderbar.setLayerColor("#" + tbHexColor.getText(), SliderBar.BarD);

            sliderbar.setSliderPosition(256 - (int) ((new Integer(saturation)
                    .floatValue() / 100) * 256));
            slidermap
                    .setSliderPosition(
                            (int) ((new Integer(hue).floatValue() / 360) * 256),
                            256 - (int) ((new Integer(brightness).floatValue() / 100) * 256));
        } else if (sender == rbBrightness) {
            // skip
        } else if (sender == rbRed) {
            // skip
        } else if (sender == rbGreen) {
            // skip
        } else if (sender == rbBlue) {
            // skip
        }

        if (colorMode == SliderMap.Red || colorMode == SliderMap.Green
                || colorMode == SliderMap.Blue) {
            // skip
        }
    }

其實造成「某些時候」才會出問題的原因不在這裡,而是 HTML 碼有沒有這個「
<DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">」。拿掉的話,錯誤也就不會發生,不過,不怎麼建議用這招就是了。

測試環境:
  • GWT 1.7
  • FireFox, Chrome(IE 不會出問題)