2012年3月30日

快測試升級 ExtJS 4.1 RC1 吧!

若專案已經升級至 ExtJS 4.0.7 的朋友,可以開始進行 4.1 的測試了。目前 ExtJS 4.1 已經進入 RC1(Release Candidate),也就是即將正式發佈前的最後幾個測試版。

What to Expect in Ext JS 4.1
http://www.sencha.com/blog/what-to-expect-in-ext-js-4-1/
http://blog.csdn.net/tianxiaode/article/details/6683215 (簡體中文)

Ext JS 4.1 Update
http://www.sencha.com/blog/ext-js-4-1-update/

Ext JS 4.1 Performance Preview
http://www.sencha.com/blog/ext-js-4-1-developer-preview/
http://blog.csdn.net/tianxiaode/article/details/6903580 (簡體中文)

ExtJS 4.1 最值得關注的地方在於它對性能的優化;雖然只要改用 Google Chrome 或新版的 Firefox,速度就能得到很的改善,但只要 IE6-7-8 還活著的一天,網站開發者的頭痛問題就難以得醫治。雖然 4.0.x 比起更早的版本,已經在速度方面獲得改善,但 ExtJS 4.1 將會更進一步提昇性能,特別是在 IE 瀏覽器上,以下的圖表可以說明目前的測試結果(ExtJS 4.1 v.s. 4.0.7)。


這使  ExtJS 打造的應用程式,可以用更短的時間完成載入,即使是侏羅紀時代的 IE6 恐龍瀏覽器,也有顯著的效能改善。

除了速度的改善,伴隨 ExtJS 4.1 而來的還有全新 Neptune 佈景主題。

目前 ExtJS 4 除了內建的兩套佈景外,幾乎無法找到其他可用的佈景主題,相較之下早期的版本就有較多佈景可替換。

但 ExtJS 4.x 在佈景的部份其實相當先進,它加入 SASS & Compass 的支援,讓視覺設計師更容易客製佈景

但問題來了,ExtJS 4.x 預設的 Classic 佈景,是模仿視窗外觀所設計,如果以這種佈景為基礎,其實調整外觀的幅度會受到限制,除非砍掉重練。這一點只要看看過去早期版本的佈景,就會知道各佈景之間的差異有多麼少數。

新的 Neptune 佈景主題可以在 Kitchensink 範例看到:
http://dev.sencha.com/deploy/ext-4.1-pr1/examples/kitchensink/index.html


有了 Neptune 終於讓 ExtJS 看起來比較像 Web App,而不再是仿視窗的外觀設計。

所以,在升級 ExtJS 4.1 之後,外觀就可以改以 Neptune 為基礎,並交由視覺設計師以 CSS3 / SASS / Compass 客製出更獨特的風格,光是字體的調整就比過去更有彈性(ExtJS 官方也開始使用 font-face / woff 字型),減少像 Classic 佈景調整後變得支離破碎的情形。

但是從 ExtJS 4.0.7 升級到 4.1,過程是否能 "無痛" 呢?以目前初步測試的結果發現,並沒有發現太大的問題,但需要再細部調整的小問題仍是不少。趁著正式發行前還有一段時間可以慢慢研究,趕快準備好升級吧!

Blitz 雲端網站壓力測試服務(Load Test)blitz.io

Blitz  網站負載測試雲端服務(blitz.io)

Blitz 是針對網站「壓力測試(Load Test)」需求打造的雲端服務,可以協助開發者評估及改善網站的效能。

Blitz
http://blitz.io/


Blitz 依照需求分級收費,但註冊之後可以得到免費的額度,免費方案可以模擬 250 使用者在一分鐘內對網站進行存取。如果要模擬 1000 位以上使用者(目前最高可達5萬)、一小時以上的測試,就必須以信用卡付費。

Blitz 可以用 Google 或 Facebook 帳號登入,接下來就可以開始 Play!

為了測試 Blitz 的功能,我使用 Cloud Foundry 建立一個 Ruby Sinatra 的 Web App,網址是「http://loadtest.cloudfoundry.com/」。開始使用 Blitz 需要先將網址輸入,它會驗證這組網址是否正常回應。


看到 *** MS 的回應及 HTTP/1.1 200OK,表示 Blitz 存取這組網址沒問題,但此時還沒有進行壓力測試,需要點一下「-p 1-250:60 http://loadtest.cloudfoundry.com」這行指令,加上 -p 1-250:60 代表進行最高 250 位使用者的測試,期間為 60 秒。


雖然點選指令以後就會開始執行測試,但第一次測試會回應失敗,因為 Blitz 必須防止壓力測試被濫用,否則壞心人士只要拿 Blitz 就可以惡意攻擊別人的網站。所以需要增加一些網站的設定,證明這個網站是接受 Blitz 進行測試。

相當幸運地,Blitz 預設提供的驗證程式碼,就是 Ruby Sinatra 專用。非 Sinatra 的使用者,只需要以 mu................. 這組驗證碼當做檔案名稱,建立一個包含數字驗證碼的文字檔,放在網站的根目錄下方。以這個例子來說,只要讓 http://loadtest.cloudfoundry.com/mu-2f5eccb1-0338f64d-6d88faad-74d6c823 能夠回傳數字 42 就是可以通過驗證。

get '/mu-2f5eccb1-0338f64d-6d88faad-74d6c823' do
    '42'
end

改完程式碼發佈後,再用 Blitz 進行測試;當測試開始進行,Blitz 可以將即時結果以超炫麗的 HTML5 圖表繪製出來。



以這個測試結果來說,網站很順利通過模擬 250 位使用者的壓力測試,測試是從 1 位使用者開始一直增加到 250 位結束,而回應時間都維持在穩定的 250ms 左右;當然,這個結果是可以預期的,因為 Cloud Foundry 是雲端 PaaS 服務,如果連 250 人都撐不住,那就太不可思議了。

最後 Blitz 會產生報表,可以列印出來。


在價格的部份,若要達到一般高負載網站常用的標竿「C10K」測試,每小時收費為  $39 USD,大約是 1200 元台幣。

若不透過 Blitz 的服務,而想要達到相同等級的測試,一般來說單靠開發者自己的電腦及頻寬可能不夠。常見的解決方案也是採用雲端的方式,例如利用 Script 建立 Amazon EC2 虛擬機器,自動建立測試需要的軟體環境及佈署測試端軟體,在利用多部虛擬機器及 Amazon 充沛的頻寬進行壓力測試;但這樣算下來,也需要花費不少虛擬主機租賃費用及開發測試程式的工時,除非經常需要進行壓力測試,否則只有在少數時候才進行網站調校所需的測試,也許使用 Blitz 之類的雲端服務會是相對划算的選擇。

Amazon S3 及 CloudFront Web Hosting 設定說明

Amazon S3(Simple Storage Service)是雲端儲存服務,它除了可以當做網站上傳檔案、影音媒體的空間外,本身也相當適合靜態網站(Static Web Sites)使用。例如以 Jekyll 或 Dreamweaver 產生的靜態網站,放在 S3 就能以「用多少付多少」的價格架站。

第一次使用需要先註冊、填寫信用卡資料,http://aws.amazon.com/console/
使用個人帳號登入 AWS(Amazon Web Services) Console(線上管理工具)
除了 S3 也能使用其他 AWS 服務,如 EC2、CloudFront
選擇 S3 服務
建立新的 S3 Bucket,名稱可以輸入自己購買的網域名稱(自定域名),已台灣來說目前速度最佳的機房位置是東京。
使用 Upload 或 s3cmd 將檔案上傳至 Bucket
打開「Properties」、點選左邊列表的 Bucket,即可設定屬性。將 Website 的功能 Enabled 打勾,並設定 Index/Error 網頁名稱。記住底下的 Endpoint 網址。這裡要注意網址必須是 .....s3-website-ap..... 才是支援 Website 功能的 S3 網址。
雖然上述的 Endpoint 網址即可用來瀏覽網站,但是預設的 S3 網址很長一點也不美觀,因此可以到網域註冊商提供的設定工具,利用 CNAME 指向 Endpoint 的網址,例如 s3(.yourname.com) -> s3.yourname.com.s3-website-ap-northeast-1.amazonaws.com,每一家域名註冊商提供的介面都不太一樣,但 CNAME 設定是一定能找到的基本功能。
接下來是 CloudFront 的設定,啟用後可以加速瀏覽速度、降低傳輸費用。

切換到 CloudFront 介面,使用 Create Distribution 增加一組設定,使用 S3 Bucket 作為檔案來源。

 設定 CNAME,也就是自定網域名稱,例如 cdn.yourname.com
建立 Distribution 後,可以取得 CloudFront 產生的 Domain Name,例如 drtesgfshfg.cloudfront.net,記住這組網域名稱。
再到網域名稱的設定增加一組 CNAME,指向 CloudFront 提供的 Domain Name。
接下來就能用自訂域名瀏覽發佈後的網站,例如 s3.yourname.com(直接存取 S3)或 cdn.yourname.com(透過 CloudFront 存取 S3);需要注意的是,CloudFront 有快取機制,因此 S3 資料更新後,可能需要24小時才能夠過 CloudFront 取得更新,因此需要經常變動的資料,並不建議使用 CloudFront。

Crunch time on the Enterprise Desktop,Ubuntu 與 Windows 比一比


Windows 7 已經是絕大多數新購電腦預置的作業系統,也是舊版 Windows 使用者升級的主流選擇;但相信還有數量非常多的舊電腦,還在企業中使用,執行著舊版的 Windows XP,如果要升級成 Windows 7,可能面臨硬體需要升級或必須重新購置的窘況,需要付出龐大的成本。

以 2012 年來說,即使已經用了 3-5 年的舊電腦,處理器仍有 GHz 以上等級,記憶體通常也有 2GB 以上,應付企業常見的文書辦公需求其實已經很足夠;汰換電腦除了花錢也不環保。

如果不想為了 Windows 7 的硬體需求而升級電腦,停留在 Windows XP 也面臨軟體陸續停止支援的情況,例如 Internet Explorer 9 以上版本就開始不支援 XP,而 IE9 又是 IE 功能比較堪用的版本。儘管瀏覽器可用 Google Chrome、Firefox 替代,但是隨著時代演進,超過10年的老舊作業系統也會被許多新版應用程式放棄支援。

Canonical 是 Ubuntu Linux 的發行商,目前 Ubuntu 除了 Desktop 版本廣受電腦玩家、開發者的青睞,其 Server 版本也開始被許多企業用來取代 RedHat Enterprise Linux 及 CentOS;而 Business 應用也是 Canonical 瞄準的目標市場。

Crunch time on  the Enterprise Desktop 是 Canonical 針對 Ubuntu 及 Windows 進行比較的電子書,可以在以下的頁面取得。

Crunch time on  the Enterprise Desktop
https://pages.canonical.com/enterprise-desktop-ebook

勇於接受改變的企業,在這個時間點評估升級至 Ubuntu,其實是相當不錯的時機,可以賦予舊電腦新的生命,新購置的電腦也不必在付高額作業系統授權費用;新版的 Ubuntu 桌面很容易使用,使用者不必跨越太高的學習門檻,未來也可以持續更新 Ubuntu Linux 版本,而不會有「停止支援」的窘況。

雖然很多企業都有相同的疑慮,轉換到 Ubuntu 之後,原本的 Office、Outlook 怎麼辦?

其實這也是企業開始重新檢視軟體需求的最好時機,以雲端應用取代舊有的套裝軟體,可以帶來更強大的軟體功能,舊電腦可以繼續沿用至硬體壽命結束,新購置的電腦也可以考慮價格便宜的低階規格,同時也免去建置維護機房的麻煩。

例如,只要使用 Ubuntu Linux 桌面環境,加上 Google Chrome 或 Firefox 瀏覽器,採用 Cloud-based 應用軟體(如 Google Apps),就可以帶來開放自由、更有效率的新一代工作環境。

Google Apps for Business
http://www.google.com/apps/intl/zh-TW/business/index.html

當然有更多人會考慮到「使用者習慣」的問題,其實只要老闆、主管自己樂於接受改變,問題就不會太大,畢竟年輕一代的知識工作者,早已習慣這些新時代的改變;他們在公司可能被迫使用老舊不堪的郵件系統、辦公軟體,甚至被禁用 Facebook : ) 該是解放束縛的時候了...

2012年3月29日

Cloud Foundry 支持的 Java EE 開發框架整理

CloudFoundry.com
Cloud Foundry 是開放源碼的 PaaS 雲端解決方案,只要註冊帳號、不必等到死就能上雲端。

雖然 CloudFoundry 的 VCAP/VMC 主要是 Ruby 開發,但是因為 VMWare 併購 SpringSource,而 Spring 又是 Java EE 當前最盛行的  Framework,所以在 Cloud Foundry 上佈署 Java 開發的 Web App,算是相當不錯的選擇。

Spring(Java)
http://start.cloudfoundry.com/frameworks/java/spring/spring.html

支援 Spring 是一定要的,但個人認為用 Spring 開發 Java Web App 還是太過麻煩,例如要自己搞定 Spring MVC、Hibernate、SiteMesh...等 stack。

Lift(Scala)
http://blog.cloudfoundry.com/post/6109591023/cloud-foundry-now-supporting-scala

Scala 是 JVM Scripting Language,也是 Cloud Foundry 預設支援的語言之一,它讓 Java 程式設計師可以不必再忍受老舊語言的諸多缺陷,使用更現代的程式語言特色及風格;而 Lift 是以 Scala 建構的 Web Framework,兼具開發敏捷、安全性、易擴展與高性能。


Play(Scala/Java)
http://www.playframework.org/modules/cloudfoundry

Play! Framework 是同時支援 Scala 及傳統 Java 語言的開發框架,相容舊的 Java 語法也使轉換的門檻降低;透過 Modules 可以輕鬆將 Play 的 Web App 發佈到 Cloud Foundry,因此這是個相當不錯的選擇。

Grails(Groovy)
http://start.cloudfoundry.com/frameworks/java/spring/grails.html

Grails 是 SpringSource 的 Web Framework,因為採用了比 Java 更容易撰寫的 Groovy,並整合 Spring MVC、Hibernate、SiteMesh... 等優秀的開發框架,因此在國外是個相當受 Java 世界歡迎的框架。

在安裝 Cloud Foundry Plugin(Grails 的擴充套件)之後,就可以輕鬆將 Web App 直接發佈到 Cloud Foundry,這也是相當簡便的一種方式。

由於 GORM(Grails 的 ORM、Model )是採用 Hibernate 作為底層,對 MongoDB 或 MySQL 等雲端 PaaS 常見的資料庫選項,都有內建(由 Hibernate 原生提供支援)或 Grails Plugins 可供安裝,對應用程式佈署及遷移需求通常都能找到合適的方案。

即使讀者還沒打算使用 Cloud Foundry 或 PaaS,也可以考慮早一點認識這些現代(Modern)的 Java EE 開發框架,雖然 Servlet、JSP、JSTL、EL... 是 Java EE 入門必要的基礎,但這些早期制定的技術規格,早已跟不上時代進步的潮流,如果想開發 Modern Web Application,那先選個  Modern Web Framework 也是必然的前提。而 Cloud Foundry 很快就支援這些 Framework,也代表著這些 Framework 有一定的成熟度、組態(套件相依管理)維護容易、可擴展性(Scalable)高、... 是相當值得參考的選項。

MongoHub 簡單易用的 MongoDB 圖形化管理工具(Mac限定)

MongoDB 是高性能的 NOSQL 資料庫解決方案,雖然使用 JavaScript 就能輕鬆維護管理 MongoDB,不過簡單易用的圖形化工具仍受到許多人期待。

想要瞭解 MongoDB 的朋友,可以下載這本我正在翻譯中的電子書「The Little MongoDB Book 中文版」。這本書的繁體中文翻譯已經得到原作者的許可,我們也秉持自由開放的精神,依循CC授權免費分享完整電子書內容,有興趣的朋友在閱讀時,不妨也給我們翻譯及內容上的建議。

最近我也打算開始介紹一些 MongoDB 的工具,讓更多中文使用者可以開始接觸這個超級好用的資料庫;Node.js Taiwan 發起人 Clonn 經營的友站熱血漢誌,也開始發佈一些 MongoDB 介紹,例如 phpmoadminrockmongo 等。相信藉由開發社群的分享,能讓新技術更快普及化,歡迎各路朋友加入研究討論 : )

這篇介紹是假設讀者已經裝好 MongoDB Server,基本上只要看 Little Book 的介紹就會清楚怎麼安裝,超級無敵簡單。但如果讀者覺得太簡單不想自己動手安裝,也可以選擇稍微麻煩一點的方式,就是到 MongoHQ 填寫註冊資料,就可以擁有免費的雲端 MongoDB 資料庫儲存服務(但是有限制容量)。

2012年3月26日

JUSTFONT 就是字

黑與白的饗宴」活動是由「JUSTFONT就是字」主辦,各位可以參考 Even Wu 分享的簡報

這邊就直接分享「重點」啦!請看一下以下的文字,你的電腦可能根本沒安裝這兩個字型,而且也不是用圖片畫出來的,但確實能在許多瀏覽器顯示字型變化的效果。

王漢宗特黑體
王漢宗仿宋標準

JUSTFONT 原理與 Google Web Font 相似,但 Google 到目前為止仍無法提供中文字型,因為中文字型必須收錄一萬五千個中文字,而不像英文只有26個字母的大小寫及標點符號,所以單一種字型就需要好幾MB的容量,造成瀏覽器必須讀取很久才能取得整個字型。

所以 JUSTFONT 實現了一個看來相當管用的創新作法,也就是將字型拆解,針對網頁內容實際用到的文字,只傳給瀏覽器縮減過的字型,這麼一來就不必下載完整的字型,所以能在很短的時間內讀取中文字型。

目前可以免費註冊 JUSTFONT,選用其中兩款字型,並安裝在自己的網誌或網站使用;目前可用的字型主要是以王漢宗系列為主,想要改變預設的中文字型、美化網站的朋友,趕快試試吧!

2012年3月25日

淺談 Grails Resources Plugin 網站靜態資源最佳化

Resources plugin 在 Grails 2.x 成為預設的套件,有許多其它來不及升級的 plugin,也因為啟用 Resources 的關係而導致 bug 出現,許多人建議乾脆把它關掉吧!這篇文章希望可以幫助開發者更多認識 Resources,善用它,而不要將它給關掉了 : )

Resources plugin 是用來處理網站的靜態資源,例如 *.js 及 *.css,由於 modern web design 在 front-end 用了愈來愈多 CSS/JavaScript,使得這些資源是否最佳化也會造成網站效能的影響。

在 Grails 1.3.x 需要自己安裝 resource plugin,這只需要一行指令:

grails install-plugin resources

在 BuildConfig 可以看到 plugins 區塊多了 resources 的宣告。

plugins {
    // ...
    compile ":resources:1.0.2"
}

Resources 是在編譯、建置階段處理靜態資源,因此並不會讓執行期速度變慢,雖然在 development 階段,它可能會多消耗一些處理效能,偶爾也會造成資源載入不正常。但是到 production 階段,它的效果通常都會帶來正面的幫助。

用 Grails 2.x 建立的網站專案,可以發現 grails-app/views/layout/home.gsp 已經使用 <g:layoutResources /> 的宣告。這是啟用 Resources plugin 的必要步驟,在 View 的 *.gsp 加上宣告,讓資源能在適當的位置載入。

「適當位置」包括在 </head> 以及 </body> 之前,例如:

<html>
   <head>
      <g:layoutTitle/>
      <r:layoutResources/>
   </head>
   <body>
      <g:layoutBody/>
      <r:layoutResources/>
   </body>
</html>

接下來,將所需要的資源以宣告方式加入 *.gsp,例如:


    <head>
        <!-- require modules -->
        <r:require modules="jquery"/>
        <r:layoutResources/>
    </head>


在 Grails 2.x 已經預設提供 jquery plugin,而新版的 jquery plugin 有針對 Resources plugin 提供適當設定,因此在 <r:require ... /> 可以直接加入 jqeury 的 modules 設定。

對於專案本身的資源,必須建立 grails-app/conf/ApplicationResources.groovy 設定檔,將相關的資源分類定義成 module。例如以下的範例,是我自行將 Compass 編譯產生的 .css 定義成 "compass" 這個 module。

modules = {
    application {
        resource url: 'js/application.js'
    }


    compass {
        resource url: [dir: '/stylesheets', file: 'screen.css'],
            attrs: [media: 'screen, projection']
        resource url: [dir: '/stylesheets', file: 'print.css'],
            attrs: [media: 'print']
        resource url: [dir: '/stylesheets', file: 'ie.css'],
            attrs: [media: 'screen'],
            wrapper: { s -> "<!--[if IE]>$s<![endif]-->" }
        resource url: [dir: '/stylesheets', file: 'ie6.css'],
            attrs: [media: 'screen'],
            wrapper: { s -> "<!--[if lt IE 7]>$s<![endif]-->" }
    }

因此,若網站頁面需要用到 compass 模組,就只需要在某些 *.gsp 加上:


<r:require modules="jquery, compass"/>


這麼做有什麼好處呢?當網站用到的資源多到某個程度,利用 Resources plugin modules 定義進行集中分類、版本管理,就可以讓靜態資源更容易維護。

以下是 jquery-colorbox 及 codemirror 的資源定義,在 modules 宣告中可以混合 *.css 及 *.js,將歸屬於同一個類別的資源定義在一起(但資料夾可以分開,例如 /css 及 /js)。

    colorbox {
        resource url: [dir: '/css', file: 'colorbox.css'], attrs: [media: 'screen']
        resource url: [dir: '/js', file: 'jquery.colorbox-min.js']
    }


    codemirror {
        resource url: [dir: '/codemirror/lib', file: 'codemirror.css'],
            attrs: [media: 'screen']
        resource url: [dir: '/codemirror/lib', file: 'codemirror.js']
        resource url: [dir: '/codemirror/mode/rst', file: 'rst.js']
        resource url: [dir: '/js', file: 'jquery.codemirror.js']
        resource url: [dir: '/codemirror/lib/util', file: 'runmode.js']
    }

但是 Resources plugin 如果功能只是這樣,那它存在的必要性其實就不高,也不會變成 Grails 2.x 的預設功能。因為在 Grails 中,使用 taglib(自訂標籤)同樣可以輕鬆達到相同目的,例如利用 SimpleTag 自行定義 <res:jquery />、<res:codemirror /> 等標籤,用起來也不會比較麻煩。

所以,Resources plugin 對資源進行定義、管理,其實只是第一個步驟而已,我們可以(選擇性)加裝其它以 Resources plugin 為基礎建立的 Plugins,來達到資源自動最佳化的需求。

以下的 Plugin 安裝指令,應該從套件名稱就能猜到它們的用途。

# Compress resources using GZip/Deflate
grails install-plugin zipped-resources

# Cache resources in browsers
grails install-plugin cache-headers
grails install-plugin cached-resources

# Delivery resources using CDN
grails install-plugin cdn-resources

# Process less css
grails install-plugin lesscss-resources

# Pre-compress resources with YUI Compressor
grails install-plugin yui-minify-resources

zipped-resources 及 cached-resources 是 GrailsRocks 提供的 Plugins(開放源碼授權),只要安裝上去,就能立即得到靜態資源被壓縮、快取的效果。對於瀏覽器來說,差別只是存取 *.css 及 *.js 的檔案名稱被編碼過,其它並無副作用。

cdn-resources 可以和 zipped/cached 混搭使用,顧名思義就是透過 CDN(Content-Delivery-Network)來分散、加速瀏覽器對資源的存取,並減少網站伺服器的處理及頻寬負擔。它的原理相當簡單,開發者只要申請 Amazon CloudFront 或其他 CDN 服務,透過 CDN 來 mirror 網站的檔案,然後將 CDN URL 設定好,Grails 最後生成的 html 就會自動以 CDN URL 取代靜態資源原本的 URL。

使用 cdn-resources 需要以下的設定:

grails.resources.cdn.enabled = true
grails.resources.cdn.url = "http://cdn.your-web-name.com/"

因為有 enabled 選項可以自訂,所以建議只針對 production 開啟 cdn,至於 development 階段本來就沒有必要用 cdn,用了只會讓網站的開發、測試變得無法進行。

一般來說,使用 CDN 對於開發初期、內容不斷更新的網站,會帶來一些影響,因為大多 CDN 服務有 TTL(Time-To-Live)的限制,也就是內容可能已更新,但 CDN 伺服器仍然使用舊資料的快取來回應瀏覽器,造成網站發佈更新後的結果不一致、需要等候資源被更新(以 Amazon Cloud Front 來說,可能長達 24 小時)。

但 cdn-resources 與 zipped/cached-resources 搭配使用,理論上是能夠避免這種問題發生,因為 *.css / *.js 的檔案名稱會經過編碼,所以 JavaScript/CSS 靜態資源如果有更新,理論上就會產生新的檔案名稱,此時 CDN 服務就會重新讀取發佈的資料。當然,這在開發階段並不容易測試效果。

最後一個建議嘗試的套件是 yui-minify-resources,這個套件的使用方式也非常簡單,只要安裝好就會立即得到效果。它是利用 YUI Compressor 將 *.css/*.js 檔案進行壓縮處理,得到 *.min.css/*.min.js 最佳化的結果。

這裡也建議只將 yui-minify-resources 用於 production,如此一來,在 development 階段就能使用原始的 .css / .js 檔案以利除錯,而打包成 war 發佈之後又能自動化進行壓縮,可以同時兼顧 production 及 development 不同階段的需求。

回到文章一開始說到的「問題」,也就是許多舊的 Grails Plugins 並不支援 Resources plugin,主要原因是這些 plugin 附帶的靜態資源並沒有提供 resources 設定,造成在啟用 resources 時缺少檔案,瀏覽器讀不到(404 error)。

但是 2.x 遲早會成為 Grails 的主流版本,而 Resources plugin 帶來的利大於弊,所以這也是時候該淘汰那些不再繼續維護、更新的套件了;因為有了 Resources plugin,有一些 Grails plugin 僅有提供 3rd party js/css library 這種簡單功能,可以考慮自行打包 plugin 或藉由 resources modules 的宣告來達成。

Grails 是 VMWare / SpringSource 建立的開發框架,旨在提供 Java EE 開發者能利用 Groovy 程式語言、Rails 風格,簡化 Modern Web Application 的專案開發工作,既能延續利用現有的 Java Library,滿足企業級的開發需求,又能兼顧團隊對敏捷開發的追求。

如果您對 Grails 開發框架有興趣,歡迎加入我們的 Groovy Taiwan 社群。

2012年3月23日

使用 Groovy+AntBuilder 存取 SVN Repository

Groovy 的 AntBuilder 是相當好用的 DSL,它可以在程式中直接呼叫原本必須定義在 XML 的 Ant 工作,包括複製檔案及整個資料夾、寄送電子郵件、編譯 Java 程式、利用 FTP 傳送檔案、...等。如果需要進行的任務剛好有 Ant Task 可以用,那 Groovy + AntBuilder 就可以讓你少寫大量的 code。

例如,我最近需要用 Groovy 存取遠端的 SVN Repository,如果不考慮直接用 shell 執行 svn 指令(若這麼做就不夠 pure java 了),一般的作法是自行參考 SVNKIT 這個 library;但是,身為想要準時收工下班的開發人員,光是看到 SVNKIT 的 architecture diagram 頭就暈了。

所以我先找到 svnant 這個 SVN Ant Task,它可以用 Ant 的 build.xml 定義 svn 版本控制系統的操作。範例:

 <svn username="guest" password="">  
  <checkout url="http://subclipse.tigris.org/svn/subclipse/trunk/svnant/" revision="HEAD" destPath="svnant" />  
 </svn>  

不過,這畢竟是 XML 的寫法,不容易整合到程式裡面(如果要用 shell 去跑 ant 就等於多繞了一圈,不如直接跑 svn 指令)。

所以,我考慮用 Groovy + AntBuilder 來解決,測試之後相當順利。

@GrabConfig(systemClassLoader=true)
@GrabResolver(name='monkproject', root='http://www.monkproject.org/maven2/')
@Grab(group='org.tmatesoft.svnkit', module='svnkit', version='1.3.5')
@Grab(group='org.tmatesoft.svnkit', module='svnkit-javahl', version='1.3.5')
@Grab(group='org.monkproject', module='svnant', version='1.1.0-rc2')
@Grab(group='org.monkproject', module='svnClientAdapter', version='1.1.0-rc2')
def ant = new AntBuilder()
ant.typedef(resource: 'org/tigris/subversion/svnant/svnantlib.xml')
ant.svn(username: 'guest', password: 'password') {
    checkout(url: 'http://svn.apache.org/repos/asf/spamassassin/trunk', destPath: './test-svn')
}

這支程式用到了 svnant + svnClientAdapter + svnkit + svnkit-javahl 四個套件,所以前面的 @Grab 動作都是為了取得這些 .jar 套件檔案。其中 svnant + svnClientAdapter 好死不死 Grab 預設的 maven2 repository 並沒有提供,所以借來了 monkproject 這個專案的 maven2 網址暫時擋一下。

若把 @Grab 相關的 @Annotation 拿掉,其實真正的程式碼不過才 5 行而已,誰說 Java 程式一定要寫得落落長呢?趕快來玩 Groovy 吧... Groovy Taiwan 歡迎您!

Apache Buildr 支援 Java / Groovy / Scala 的自動化建置工具



過去不少次介紹 Gradle 這套專案建置工具,目前 Gradle 即將正式發行 1.0,不過在發行前的 milestone 階段停留很久。在等待  Gradle 1.0 的這段期間,我找了一下其它類似的工具。

Buildr 是 Apache 基金會推出的工具,它是以 Java 為基礎,但除了能夠建置 Java 專案外,它也支援 Scala、Groovy 等其它 JVM 語言。

Apache Buildr is a build system for Java-based applications, including support for Scala, Groovy and a growing number of JVM languages and tools. We wanted something that’s simple and intuitive to use, so we only need to tell it what to do, and it takes care of the rest. But also something we can easily extend for those one-off tasks, with a language that’s a joy to use. And of course, we wanted it to be fast, reliable and have outstanding dependency management.

安裝 Buildr 需要 RubyGems,這一點我認為相當有趣,通常 Java 的工具都會有「Pure Java」的設計,但 Buildr 光是在安裝這個步驟,就需要混搭 Ruby 才能完成。但我認為在開發階段,本來就必須整合各種好用的開發工具,例如 Ruby、Python、Perl 有好用的工具,就直接混搭使用,而不要重新再造輪子。可以放心的是,Buildr 最後建置出來的專案,肯定是 100% pure Java。

以 Mac OS X 為例,安裝 Buildr 只需要以下步驟:


  • sudo gem install rjb -v 1.3.3 --platform ruby
  • sudo gem update --system
  • export JAVA_HOME=/Library/Java/Home
  • sudo env JAVA_HOME=$JAVA_HOME gem install buildr
Linux 及 Windows 請安裝 Buildr http://buildr.apache.org/installing.html

由於 RubyGems 使 Buildr 支援多版本切換的設計,所以在執行 Buildr 時可以指定版本編號:

  • buildr _1.3.4_ clean
Buildr 的原始碼目錄結構和 Gradle 相同,都是放在 ./src/main,例如 Java 放在 ./src/main/java、Groovy 放在 ./src/main/groovy 而 Scala 則放在 ./src/main/scala。因此,在同一個專案中,同時使用 Buildr 及 Gradle 是有可能的(雖然不見得有理由需要這麼做)。

先來看幾個官方的範例。

首先,Buildr 的套件來源也是 Maven(Java Repository 世界幾年內可能都是以它為主了),repositories.remote 可以設定多個套件來源,也就是 Maven Repo 的 URL。這個範例可以看到 定義方式是用 define ... do ... end 指令。

repositories.remote << 'http://mirrors.ibiblio.org/maven2'

define 'killer-app' do
  project.version = '0.1.0'
  compile.with transitive('org.apache.wicket:wicket:jar:1.4-rc6')
  package :jar
end

上面的範例直到指定 Compile-time 的 dependencies 時才設定 Package,其 Package 的設定格式也和 Gradle 類似,使用 "群組:名稱:版本" 的定義。但遇到很多任務都要共用 package dependencies 時,就可以將 Package 在檔頭設定:


repositories.remote << 'http://mirrors.ibiblio.org/maven2'

WICKET = transitive('org.apache.wicket:wicket:jar:1.4-rc6')
SLF4J = 'org.slf4j:slf4j-jdk14:jar:1.5.8'

define 'killer-app' do
  project.version = '0.1.0'
  compile.with WICKET, SLF4J
  package :jar
end


接下來是 Buildr 讓我驚嘆的地方,它可以變魔術般地設定 ZIP URL,也就是說某些套件如果沒有被 Maven Repository 收錄,就可以直接找到官方的壓縮檔下載網址,作為相依套件的設定,而不必自行下載解壓縮 *.jar 到專案目錄下。例如:


DBPOOL = 'net.snaq:dbpool:jar:4.8.3'
download artifact(DBPOOL) => 'http://www.snaq.net/java/DBPool/DBPool_v4.8.3.zip'

define 'killer-app' do
  project.version '0.1.0'
  compile.with DBPool
  package :jar
end


在自動化測試的部份,Buildr 支援 JUnit4 及 TestNG,搭配 Scala 時則支援 Specs、ScalaTest,若搭配 Groovy 則支援 EasyB,這部份和 Gradle 的測試支援差不多,目錄結構也同樣是放在 ./src/test(./src/test/java、./src/test/groovy、./src/test/scala)。

Buildr 除了 test 及 compile 等常用的內建任務(Task),也可以自訂擴充新的任務,使用 task ... do ... end 語法,以下的範例定義了 run 任務,並宣告它依賴 compile 任務,所以執行 run 之前會先執行 compile,並用了 system 這個指令執行 java 程式。


define 'killer-app' do
  project.version = '0.1.0'
  package :jar

  task :run => :compile do
    system 'java -cp target/classes org.apache.killer.Main'
  end
end


建置程式必須儲存為「buildfile」或「Buildfile」,用「buildr killer-app:run」就能執行自訂的 run 任務。

雖然我暫時不會考慮在專案中加入 Buildr 的建置流程,但我覺得它仍是個值得學習參考的工具。無論如何,身為 Programmer,其實我們應該多認識每一種開發環境的自動化建置方式,例如:

  1. Makefile
  2. Ant、Maven、Gradle、Buildr
  3. Rakefile
  4. Jake (for JavaScript/Node.js)

我通常採用 Gradle 處理大部分的 Java 專案自動化建置流程,但很多時候還是搭配 Makefile,因為 Makefile 非常快、和 Shell Script 可以良好搭配,例如在執行 s3cmd 同步 S3 檔案時,直接用 Makefile 就明顯比 Gradle 執行 shell 指令的效果好得多。

使用 Java 以外的程式語言來建置 Java 專案,也許也是個值得考慮的方式,因為 Java 程式在第一次執行總是特別花費載入時間,對於每次寫完一段 code 就要跑 test 的情況來說,會耗費不少等待 Build System 載入的時間;雖然 Gradle 會提供 daemon 的模式,減少重複啟動,但至少現在還不是非常管用。

和 Java-based 的建置工具相比,Buildr 的啟動速度相當快;這種 Scripting 類型的工作,使用 Ruby/Python/Perl 本來就比較有效率。

所以,如果使用 Gradle 的開發者能熟悉 Makefile,就可以輕鬆將 Makefile+Gradle+Buildr+... 混搭,打造更敏捷的專案開發環境。

2012年3月17日

使用 Mustache 統一程式碼的字串樣板寫法

mustache /m'ʌst,æʃ/ n. 髭,胡子; 圖片來源 SMOSH.COM
String Template 在不同程式語言有不同做法:

舉例來說:
  • "Hello, ${who}" //Groovy
  • "Hello, #{who}" #Ruby
  • "Hello, %s" % who #Python
  • "Hello, $who" //PHP

但是有些語言並沒有類似的簡易方法,例如:
  • "Hello, " + who //JavaScript, etc...

這對於經常需要切換語言,或者同時需要使用多種語言的開發者來說,可能會造成一點小困擾。

如果想要追求統一的寫法,那就可以看看「Mustache」這個鬍子牌的解決方案。

Mustache 提供 RubyJavaScriptPythonErlangPHPPerlObjective-CJava.NETAndroidC++GoLuaoocActionScriptColdFusionScalaClojureFantomCoffeeScriptD, 以及 node.js 等不同版本實作。


Mustache 是鬍子的意思,所以在程式字串中要嵌入變數,就是用很像鬍子的符號 "{{" 起始與 "}}" 結尾。


Demo
 <h1>{{header}}</h1>  
 {{#bug}}  
 {{/bug}}  
 {{#items}}  
  {{#first}}  
   <li><strong>{{name}}</strong></li>  
  {{/first}}  
  {{#link}}  
   <li><a href="{{url}}">{{name}}</a></li>  
  {{/link}}  
 {{/items}}  
 {{#empty}}  
  <p>The list is empty.</p>  
 {{/empty}}  

Value Set in JSON
 {  
  "header": "Colors",  
  "items": [  
    {"name": "red", "first": true, "url": "#Red"},  
    {"name": "green", "link": true, "url": "#Green"},  
    {"name": "blue", "link": true, "url": "#Blue"}  
  ],  
  "empty": false  
 }  
lyhcode by lyhcode
歡迎轉載,請務必註明出處!