2007 年 4 月 24 日
Ruby on Rails 開發(fā)和 Java? 開發(fā)有著本質(zhì)的不同。在跨越邊界 系列的最后一期中,Bruce Tate 將概述使用 Rails 從頭開發(fā)一個(gè)復(fù)雜、可伸縮的 Web 站點(diǎn)時(shí)所發(fā)現(xiàn)的二者的主要差異。
Rails 開發(fā)人員常常把 Java 開發(fā)人員看作是沉悶而勞碌的老古董。而 Java 崇拜者則常常認(rèn)為 Ruby on Rails 只是一個(gè)玩具,根本不能用于任何嚴(yán)肅的軟件開發(fā)。作為一名對這兩種技術(shù)都有著廣泛使用經(jīng)驗(yàn)的顧問,我認(rèn)為真實(shí)的情形介于這兩種觀點(diǎn)之間。由于跨越邊界 系列文章即將結(jié)束,因此我打算對它們再作一次比較。本文并非考察某種特殊的技術(shù)或語言,而是主要介紹我當(dāng)前正在從事的項(xiàng)目,并將它與我以前從事的 Java 項(xiàng)目進(jìn)行比較。另外,我建議您閱讀“跨越邊界”系列的前幾期文章,對相關(guān)主題作更深入的了解。這種直接的說明可讓您在二者之間權(quán)衡利弊,并可能使您在數(shù)據(jù)庫 Web 應(yīng)用程序 green-field 的開發(fā)中通過使用 Rails 獲益。
業(yè)務(wù)問題
 |
關(guān)于本系列
在 跨越邊界 系列文章中,作者 Bruce Tate 提出這樣一種觀點(diǎn),當(dāng)今的 Java 程序員們可以通過學(xué)習(xí)其他方法和語言更好地武裝自己。自從 Java 技術(shù)明顯成為所有開發(fā)項(xiàng)目最好的選擇以來,編程前景已經(jīng)發(fā)生了改變。其他框架影響著 Java 框架的構(gòu)建方式,從其他語言學(xué)到的概念也可以影響 Java 編程。您編寫的 Python(或 Ruby、Smalltalk 等語言)代碼可以改變編寫 Java 代碼的方式。 本系列介紹與 Java 開發(fā)完全不同的編程概念和技術(shù),但是這些概念和技術(shù)也可以直接應(yīng)用于 Java 開發(fā)。在某些情況下,需要集成這些技術(shù)來利用它們。在其他情況下,可以直接應(yīng)用概念。具體的工具并不重要,重要的是其他語言和框架可以影響 Java 社區(qū)中的開發(fā)人員、框架,甚至是基本方式。
|
|
不論是 Ruby on Rails 框架還是任何 Java 框架都不能解決所有問題。為了提高成功的幾率,需要長期、細(xì)致地考察業(yè)務(wù)問題,理解周圍的各種假定情況,以及了解您的團(tuán)隊(duì)。只有這樣才能選出正確的語言來進(jìn)行開發(fā)。
去年,Arvato Systems 聘請我?guī)ьI(lǐng)團(tuán)隊(duì)構(gòu)建 ChangingThePresent.org,它是一種新平臺(tái),用于將非贏利性團(tuán)體和捐贈(zèng)人組織在一起。與很多 Internet 公司一樣,我們向客戶展示了可購買的實(shí)際產(chǎn)品。與其他公司不同的是,這些 “產(chǎn)品” 指的是提供機(jī)會(huì),比如:一名癌癥研究員一小時(shí)服務(wù)收費(fèi) 50 美元、幫助盲人收費(fèi) 30 美元,或者保護(hù)一英畝雨林一個(gè)月收費(fèi) 20 美元。我們面臨兩大挑戰(zhàn):一份很緊湊的時(shí)間表和長期的復(fù)雜性。
開發(fā)工作從九月份開始,要求必須在十一月份之前建立起一個(gè)站點(diǎn),以便有機(jī)會(huì)趕上圣誕節(jié)期間的通信量高峰。(最終我們超出了十一月份這個(gè)期限兩星期。)在其他開發(fā)語言中,基于 Java 的解決方案可能要花費(fèi) 6 到 18 個(gè)月才能完成這一任務(wù)。因此生產(chǎn)力是一個(gè)很重要的考慮因素,這與 Java 部署思想相悖。
通過對競爭對手和項(xiàng)目的考察,我們了解到:我們希望能夠每天給站點(diǎn)帶來幾百萬次點(diǎn)擊的通信量。而我們需要每天有幾十萬次成功的點(diǎn)擊,因此可伸縮性也是一個(gè)考慮因素。這與 Java 部署思想相符。
最后,我們了解到:發(fā)布初始站點(diǎn)只是一個(gè)開始。我們只實(shí)現(xiàn)了總體規(guī)劃的百分之三。因此我們所選的技術(shù)需要根據(jù)復(fù)雜性和負(fù)載作出一些調(diào)整。我認(rèn)為 Ruby 語言在復(fù)雜性方面會(huì)更易于調(diào)整,因?yàn)樗峁┝藢Ω呒壵Z言和特性(如開放類)的支持,以及具有更少配置需求和更簡單、集成化編程模型的 Rails 框架。
雖然我們面臨著時(shí)間和可伸縮性方面的挑戰(zhàn),但是也擁有一些其他的有利因素。我們擁有一張完全空白的候選名單:可以選擇想要的任何技術(shù)、任何團(tuán)隊(duì)。可以定義項(xiàng)目、培訓(xùn)和全部的技術(shù)。我們可完全自由地作出選擇。
Java 語言是一種優(yōu)秀的通用語言。它總是應(yīng)用于新的技術(shù)領(lǐng)域,如嵌入式系統(tǒng)和移動(dòng)設(shè)備。Java 語言在廣泛關(guān)注的集成方面也表現(xiàn)優(yōu)秀。它具有高性能、流行并受到平臺(tái)的良好支持。但是正如您在本系列中所了解到的那樣,Java 語言并不是用于數(shù)據(jù)庫支持的 Web 應(yīng)用程序的 green-field 開發(fā)的最佳選擇(請參閱文章 “動(dòng)態(tài)類型語言中的 Web 開發(fā)策略”)。
相比之下,Ruby on Rails 框架則是新的。并沒有很多人使用 Rails 開發(fā)高通信流量的站點(diǎn),并且?guī)缀醪淮嬖谑裁词褂?Rails 多年開發(fā)項(xiàng)目的經(jīng)驗(yàn)。但它仍然是一種高生產(chǎn)力的數(shù)據(jù)庫支持的 Web 應(yīng)用程序開發(fā)的框架。最后,盡管我們對 Rails 缺乏開發(fā)長期項(xiàng)目的經(jīng)驗(yàn)和并未得到廣泛部署有所顧慮,但那份緊湊的時(shí)間表驅(qū)使我們選擇了 Ruby on Rails。
作出這個(gè)決定之后,我們發(fā)現(xiàn)招募項(xiàng)目人才非常容易。我們還發(fā)現(xiàn)早期的生產(chǎn)力優(yōu)勢非常顯著 —— 甚至比預(yù)期的還要好。我們確實(shí)遇到了一些早期的穩(wěn)定性問題,因此加強(qiáng)了測試工作的力度(請參閱文章 “在集成框架中進(jìn)行測試,第 1 部分” 和 “在集成框架中進(jìn)行測試,第 2 部分”)。此后穩(wěn)定性得到了極大的改進(jìn)。
原理
每個(gè)框架設(shè)計(jì)者都使用一組假定來構(gòu)造該框架的重寫原理。學(xué)習(xí)遵守該原理的約束可使您愉快地進(jìn)行編程,而挑戰(zhàn)這些約束則會(huì)使您的編程受挫。Rails 框架和 Java 框架擁有很多不同的原理。
Rails 是一種集成框架,需要使用高度利用 Ruby 語言的動(dòng)態(tài)本質(zhì)(請參閱 “Ruby on Rails 的秘笈是什么? ”)。Rails 開發(fā)人員強(qiáng)調(diào)框架的生產(chǎn)力特性而不是工具特性,并且常常將 Web 架構(gòu)看得非常簡單,在本系列的前幾篇文章中您已了解到這一點(diǎn)。Java 設(shè)計(jì)者通常必須分塊地組合開發(fā)環(huán)境,獨(dú)立地選擇持久性、Web 和集成層。他們通常嚴(yán)重地依賴工具來簡化核心任務(wù)。Web 架構(gòu)設(shè)計(jì)趨向于較為復(fù)雜。
完全集成
Java 框架往往是解決一個(gè)小問題(比如持久性或查看組織),而 Rails 則是一個(gè)集成環(huán)境。Rails 開發(fā)人員的優(yōu)勢在于不必解決與許多不同框架集成的問題。大多數(shù) Hibernate 開發(fā)人員陷入了過早關(guān)閉與 Java Web 框架之間的連接的陷阱。Rails 視圖框架是從頭構(gòu)建的,以便與 ActiveRecord 集成(Rails 持久性框架)。當(dāng)您考察用于 Web 服務(wù)、配置和插件的 Rails 框架時(shí)也會(huì)發(fā)現(xiàn)類似的經(jīng)驗(yàn)。Java 編程支持各種不同的框架,對于所有這些框架使用不同的集成策略。
Java 開發(fā)人員的優(yōu)勢在于選擇。如果您需要從頭構(gòu)建一個(gè)框架,則可能要考慮使用基于 SQL 的解決方案用于數(shù)據(jù)庫集成(如 iBATIS 或 Java 編程中基于 JDBC 的包裝框架之一)。反過來,如果要使用一種古老的模式進(jìn)行編程,則可能要使用對象關(guān)系映射框架(如 Hibernate)。相比之下,如果您使用 Rails,則擁有一個(gè)主要選擇:ActiveRecord。這意味著 Java 框架提供了更多的選擇,有時(shí)能提供更好的集成開發(fā)項(xiàng)目的解決方案。但是由于我們要開發(fā)一個(gè) green-field 項(xiàng)目,因此選擇算不上是一個(gè)問題。
一種動(dòng)態(tài)語言
Rails 原理的下一個(gè)主要部分是動(dòng)態(tài)編程語言(請參閱文章 “Java 模型以外的類型策略”)。Java 工具往往可以有效地使用 Java 類型模型提供的額外信息。工具可以識(shí)別錯(cuò)誤和有效地重構(gòu)代碼。Rails 還可有效地利用編程語言的優(yōu)點(diǎn)。Ruby 是一種構(gòu)建特定于域的語言(DSL)的理想語言(請參閱文章 “活動(dòng)記錄和 Java 編程中特定于域的語言”)。Rails 集中使用 DSL 來完成從構(gòu)建模型對象之間的關(guān)系到指定自定義組件(如狀態(tài)機(jī)器或可上傳的圖像)的所有工作。動(dòng)態(tài)語言常常更加簡潔,因此 Rails 項(xiàng)目比 Java 項(xiàng)目要簡練得多,可讓用戶更簡練地表達(dá)代碼和配置。在 ChangingThePresent.org 項(xiàng)目中,我們發(fā)現(xiàn)技術(shù)頂尖的程序員可達(dá)到更高的生產(chǎn)力,但是我們確實(shí)需要招募經(jīng)驗(yàn)更豐富的開發(fā)人員。我對這種妥協(xié)非常滿意。
傳統(tǒng)的 Java 程序員對 IDE 有著近乎虔誠的熱愛,造成這一現(xiàn)象有充分的理由。IDE 提供了語法的完整性檢查、修正了小錯(cuò)誤并提供了增量編譯以便更快地完成編碼、編譯、部署和測試這樣的周期。最近幾年來,開發(fā)環(huán)境開始更好地利用編譯循環(huán)和靜態(tài)類型提供的信息。IDE 現(xiàn)在編輯抽象語法樹(AST),而不是(或者同時(shí))編輯代碼的文本表示。這一策略允許使用強(qiáng)大的代碼重構(gòu)工具,而使用靜態(tài)類型語言的同樣方法來實(shí)現(xiàn)此功能則困難得多。
靜態(tài)類型確實(shí)能更好地使用工具,但是也存在缺點(diǎn)。強(qiáng)制使用靜態(tài)類型通常需要編譯器,而編譯步驟必然會(huì)降低生產(chǎn)力。使用 Rails,我可以更改一行代碼并重新加載瀏覽器,就可立即看到更改的結(jié)果。與 Java 開發(fā)人員相比,大多數(shù) Ruby 開發(fā)人員只使用一種很好的編輯器。TextMate 是最流行的 Ruby on Rails 編輯器,它提供了語法突出顯示、代碼完整性檢查,以及一些頻繁使用的結(jié)構(gòu)的良好的模板支持。而當(dāng)發(fā)現(xiàn)可將所有簡單的基于 Ruby 的腳本(用作基本的 Rails 工具包)放入編輯器中時(shí),您會(huì)更加喜出望外。與純粹的調(diào)試器不同的是,我可以使用斷點(diǎn)腳本,該腳本可停止特定的應(yīng)用程序,進(jìn)入一個(gè) Ruby 解釋程序,我可在其中調(diào)用方法、檢查變量的值,以及甚至在恢復(fù)執(zhí)行之間修改代碼。
簡單的架構(gòu)
傳統(tǒng)的 Web 端 Java 架構(gòu)包括:一個(gè)用于域?qū)ο蠛蛿?shù)據(jù)訪問對象的層、一個(gè)提供業(yè)務(wù)級 API 的外觀層、一個(gè)控制器層和一個(gè)視圖層。此架構(gòu)比典型的 “模型-視圖-控制器” 架構(gòu)(使用 Smalltalk 語言最早創(chuàng)建)稍微復(fù)雜一些。相比之下,Ruby on Rails 包括一個(gè)使用 ActiveRecord 設(shè)計(jì)模式的模型層、一個(gè)控制器層和一個(gè)視圖層。我們喜歡易于獲得的 Rails 方法。它更加簡練并且?guī)眍~外的復(fù)雜性和錯(cuò)誤的機(jī)會(huì)更小。
慣例優(yōu)先原則
Java 框架通常可以自由地使用 XML 配置,而 Rails 主要使用慣例來避免可能的配置。在程序員必須指定配置的位置,Rails 通常依賴 Ruby(常常以 DSL 形式)來提供配置。對于 green-field 開發(fā),我發(fā)現(xiàn)慣例優(yōu)先于配置是很有意義的。該策略為我省去了很多行代碼,更簡化了必須編寫的代碼。估計(jì)我們所需的配置只有傳統(tǒng) Java 應(yīng)用程序中所指定的十分之一。我們有時(shí)會(huì)損失一點(diǎn)靈活性,但這并不足以抵消使用此策略帶來的節(jié)省。
總而言之,Rails 框架的原理適合解決 ChangingThePresent.org 項(xiàng)目中的問題。集成的各種工具讓我可以利用框架實(shí)現(xiàn)更多的功能而無需自己進(jìn)行過多的集成?!皯T例優(yōu)先原則” 為我節(jié)省了配置站點(diǎn)的時(shí)間。動(dòng)態(tài)語言為經(jīng)驗(yàn)豐富的開發(fā)人員提供了更多的能力和靈活性,同時(shí)也使他們能夠利用更少的代碼表達(dá)更強(qiáng)大的思想。該框架適合于我們團(tuán)隊(duì)的能力和要解決的業(yè)務(wù)問題。
持久性
Java 和 Ruby 語言的最流行的持久性框架可以比任何其他特性更好地闡明 Java 和 Ruby 經(jīng)驗(yàn)之間的區(qū)別,Java 開發(fā)人員通常使用 Hibernate,它是一種對象關(guān)系映射框架。通過 Hibernate,您可獲取現(xiàn)有的模型和模式并使用注釋或 XML 表達(dá)二者之間的映射。Hibernate 類是簡單傳統(tǒng) Java 對象(POJO),它的每個(gè)對象派生自一個(gè)通用的基類。大多數(shù)配置是顯式的,使用注釋、XML 或二者的某種結(jié)合。
而 ActiveRecord 是一種包裝的框架,就是說每個(gè)類都是現(xiàn)有類的包裝器(請參閱文章 “研究活動(dòng)記錄”)。ActiveRecord 根據(jù)關(guān)聯(lián)表的內(nèi)容(如表中每列的一個(gè)屬性)自動(dòng)地向模型對象添加特性。所有的類都從一個(gè)通用的基類繼承。ActiveRecord 主要利用通用約定來推斷配置。例如:
- ActiveRecord 利用類名的復(fù)數(shù)形式來推出表名。
- 主鍵的名稱為
id 。
- 列表的排序順序由
position 字段決定。
對象關(guān)系映射是使用遺留模式(可能定義時(shí)沒有考慮對象模型)時(shí)的最佳解決方案。但是當(dāng)您能為應(yīng)用程序顯式地設(shè)計(jì)數(shù)據(jù)庫模式時(shí),您通常不需要映射框架了。我們將 ActiveRecord 看作我們的一個(gè)巨大優(yōu)點(diǎn)。我們可以包含關(guān)系數(shù)據(jù)庫,需要時(shí)轉(zhuǎn)入 SQL 并在適當(dāng)?shù)臅r(shí)候退出。
遷移
Rails 遷移使我們能夠用代碼表示模式的兩個(gè)版本之間的差別,和它們所包含的數(shù)據(jù)之間的差別(請參閱文章 “Rails 遷移”)。對每個(gè)遷移都進(jìn)行了命名和編號??稍谌魏螘r(shí)候恢復(fù)到任何版本。遷移有以下一些確切的優(yōu)點(diǎn):
- 產(chǎn)生錯(cuò)誤代碼時(shí)可恢復(fù)到一個(gè)舊版本的模式。
- 用代碼而不是 SQL 來表達(dá)模式,更便于我們使用。
- 在最大程度上與數(shù)據(jù)庫獨(dú)立。
但是遷移也有一些限制。如果兩個(gè)開發(fā)人員同時(shí)創(chuàng)建遷移,則編號會(huì)出現(xiàn)混亂,所以我們必須手動(dòng)處理。我們通過有效的通信來使這些問題最小化:團(tuán)隊(duì)成員構(gòu)建需使用遷移的新模型時(shí)發(fā)出通知。但是這個(gè)模型依賴于團(tuán)隊(duì)的開發(fā)人員較少或遷移進(jìn)展較慢的情況。
ActiveRecord 還有其他的限制,其中一些是故意作出的。Rails 的創(chuàng)建者認(rèn)為:數(shù)據(jù)庫的約束和組成應(yīng)歸入應(yīng)用程序而不是數(shù)據(jù)庫,這種思想帶來了一些副作用。ActiveRecord 使用視圖的情況不是很好:構(gòu)建過程(克隆模式、復(fù)制測試數(shù)據(jù)并運(yùn)行測試)并不能正確地進(jìn)行復(fù)制。ActiveRecord 在使用參考完整性約束的某些場合也會(huì)出現(xiàn)問題,因?yàn)槟承╊愋偷年P(guān)聯(lián)可能連接到多個(gè)數(shù)據(jù)庫表。跨越復(fù)雜模型進(jìn)行預(yù)先加載很復(fù)雜,通常在連接多行時(shí)需要使用 SQL。繼承也受到限制:使用 ActiveRecord 時(shí),我被迫使用單表繼承 映射策略,而該策略并不總是最佳選擇。(參見 參考資料)
所有的持久性策略都充滿了妥協(xié)。我認(rèn)為 ActiveRecord 實(shí)現(xiàn)了一組有效的妥協(xié),常常選擇了簡單性??偠灾?,ActiveRecord 和遷移是我們的積極推動(dòng)。我們可以快速地構(gòu)建解決方案,我們擁有足夠的 SQL 訪問權(quán)可在需要時(shí)改進(jìn)系統(tǒng)性能。但是當(dāng) ActiveRecord 并不總能應(yīng)對挑戰(zhàn)時(shí),最好將 Rails 應(yīng)用于使用老舊模式的項(xiàng)目。一些替代的持久性模型正在出現(xiàn),包括 RBatis,一種 iBATIS Java 框架的端口(參見 參考資料)。現(xiàn)在討論 RBatis 的有效性還為時(shí)過早。
結(jié)束語
對于我的團(tuán)隊(duì)和項(xiàng)目來說,Ruby on Rails 被證明相當(dāng)有效。我還不知道這個(gè)項(xiàng)目的最終規(guī)模如何,因?yàn)樽珜懕疚臅r(shí)該系統(tǒng)才運(yùn)行 3 個(gè)月?,F(xiàn)在只是開始增加通信量。但是我們對生產(chǎn)力卻很了解。我知道團(tuán)隊(duì)的預(yù)算比競爭公司(這些公司常常使用 Java 解決方案)的要低得多。我對我們的生產(chǎn)力也很有信心。
通過跨越邊界 系列,我向您介紹了 Java 領(lǐng)域以外的語言和解決方案。但程序員畢竟是技術(shù)人員。每個(gè)高明的技術(shù)人員的工具包中都應(yīng)包含適用于每個(gè)解決方案的廣泛的工具集。除工具外,本系列中介紹的觀點(diǎn)也為您展示了一些其他思路?,F(xiàn)在一些框架設(shè)計(jì)者甚至將 Seaside、Rails 中的技術(shù)甚至 JavaScript 應(yīng)用于 Java 框架中。找機(jī)會(huì)進(jìn)行同樣的應(yīng)用,繼續(xù) “跨越邊界”。
參考資料
學(xué)習(xí)
獲得產(chǎn)品和技術(shù)
討論
關(guān)于作者
 |
|
 |
Bruce Tate 是位父親、山地車手、皮艇手,住在德克薩斯州的奧斯汀。他是三本最暢銷 Java 圖書的作者,包括獲得 Jolt 獎(jiǎng)的 Better, Faster, Lighter Java。他最近推出了 From Java to Ruby 和 Rails: Up and Running。他在 IBM 工作了 13 年,而后創(chuàng)立了 RapidRed 顧問公司,在那里他專攻基于 Ruby 的輕量級開發(fā)策略和體系結(jié)構(gòu)及 Ruby on Rails 框架?,F(xiàn)在他是 WellGood LLC 的 CTO ,該公司致力于為非盈利組織和福利機(jī)構(gòu)開辟市場。
|
|