Ruby on Rails(也叫做 Rails)是一個針對支持數據庫的 Internet 應用程序的 Ruby 框架。我現在 已經將 Rails 用於兩個不同的應用程序並涉及了另外兩個關聯的程序。為了即將完成的新書 Java to Ruby(參見 參考資料),我已經采訪了很多 Rails 開發人員(那些在該框架上既成功也失敗過的人)、 框架的創始人和 Rails 書籍的旗艦之作 Agile Web Development with Rails(參見 Resources)的主要 作者。我開始理解為什麼 Ruby on Rails 架構如此成功。
炒作和懷疑論
在 Java 社區關於 Rails 的爭論已經相當激烈並且在將來一段時間沒有停止的跡象。Rails 的支持者 稱贊它的驚人的效率,與 Java 開發相比效率大約是 10:1。作為 Java 程序員,您下意識的反應是不相 信任何宣傳過高的效率,因為您可能以前聽到過這些,然而實際讓您很失望。Java 提倡者日益堅持 Ruby on Rails 是一個玩具,不能伸縮,會生成壞的代碼,並且只能開發簡單的應用程序。但是隨著對 Rails 的贊揚不斷出現(通常來自可信的來源),一項更加謹慎的任務是理解 Rails 能做好什麼事情,並把它 的思想帶回到 Java 平台。在本文中,將探究為 Rails 帶來巨大效率的核心特性(即秘笈)。
Rails 基本原理
Ruby on Rails 框架不是大家所想的典型的應用程序開發框架。Rails 的創始人 David Heinemeier Hansson 通常把該框架稱為固執己見的軟件,並且他喜歡打破長期存在的約定。David 做出了非常有哲理 性的決策並在整個框架中嚴格遵循這些決策。遍布於 Rails 內的核心觀點有:
無縫集成:Rails 聰明地利用了 Ruby 語言的最好特性。它擴展了 Ruby,但您很難說出 Ruby 在哪裡 結束,Rails 從哪裡開始。您也可以看到 Active Record(Rails 的持久引擎)和模型-視圖-控制器 (MVC)框架之間進行了很好的集成。例如,您可以編寫三行代碼,創建一個表,然後立即為該模型生成 用戶界面。
約定優於配置:為保持良好的靈活性,Java 框架保持了大量普遍的配置文件。Rails 不采用這種策略 。它為方法、類、表和列采用普通的項目目錄結構和簡單普通的命名約定,以推斷哪些已配置在 Java 應 用程序中。結果是,Rails 應用程序只需要對應 Java 應用程序的一小部分配置代碼,一般是十分之一或 更多。
低重復:不要重復自己(Don't Repeat Yourself,DRY)是 Rails 社區的一個常見術語。Rails 框架 委員會使用通常看起來像是 Ruby 語言的擴展的方法來把重復的任務抽象出來。正如您在本系列的 第三 篇文章 中看到的,Rails 的元編程策略使每行代碼都執行更多的任務。
即時反饋:使用 Rails,對於您所做的大多數工作都會給出即時反饋。編寫一行代碼並保存後,在加 載下一個 Web 頁面時將激活您所做的更改。更新了您的數據庫以後,遷移可以向您即時顯示更改。
專注於某個領域
反對其宣稱的過高生產率的爭論通常類似於這樣:如果獲得了一把好的錘子,就很難找到另外一把生 產率達到兩倍的錘子,更不用說把生產率提高 5 到 10 倍了,因為錘子已經發展演變幾千年了。但是把 Ruby on Rails 與各種通用目的的 Java 框架相比較的人是不得要領的。通過從根本上改變工具的本質可 以在某些方面提高 10 倍的生產率。現在專業的制造者使用釘子槍能夠在用錘子釘入一顆釘子的時間內釘 入很多釘子。像釘子槍一樣,Rails 也是有專門用途的。它是一個專門編寫來用於單個領域的框架:新的 支持數據庫的 Web 應用程序。
我猜想現今構建的應用程序有一半是支持數據庫且基於 Web 的應用程序。所以 Rails 是明確針對某 領域的產品,但是這個領域很大也很重要。專攻此領域使 Rails 具有巨大的優勢,引起巨大轟動。通過 專注於此領域的項目,Rails 的設計者可以選擇一些其他框架不能或者不應該采用的捷徑。這種專門化往 往為簡單性而失去靈活性。
新的支持數據庫的應用程序建議打包方法優於映射方法。正如您在本系列的 第一篇文章 中看到的, Rails 工具采用數據模型中的約定。Rails 應用程序需要 Java 應用程序中創建的一小部分模型代碼。如 果特別為 Rails 應用程序創建模式,此原則能工作得很好。如果試圖把遺留的模式塞入 Rails 中,將變 得不太平滑。
基於 Web 的應用程序允許一組相似的優化。當您知道一個應用程序是基於 Web 的,您就能知道應用 程序的大體結構和可能需要的主要組件。因為 Rails 關注的是基於 Web 的應用程序,所以在 Rails 中 增強了以下功能:
模型-視圖-控制器:Rails 的 MVC 框架(稱為 Action Pack)為基於 Web 的訪問進行了定制並且實 現了著名的被稱為 Model 2(參見 參考資料)的設計策略。Rails 版本已經優化了控制器和視圖之間的 集成(該集成能夠使配置文件最小化)並且自動使控制器實例變量可供視圖使用。
項目目錄結構:所有 Rails 應用程序都具有相同的項目結構,其中的目錄用於存儲應用程序代碼、數 據庫配置、公共的靜態文件,以及用於管理 Web 服務器和進行基於 Web 的功能測試的腳本。
架構:通過提供用於生成應用程序組件(這些組件都符合普通架構目標,比如頁面級和片段級緩存; 兩層設計;用於測試、開發和生產的環境)的開箱即用腳本,Rails 框架簡化了架構。
工具:Rails 工具專門用於 Web。日志支持、breakpointer、剖析器(profiler)和測試框架都針對 基於 Web 的應用程序進行了修剪並針對兩層操作而被啟用。
但是釘子槍永遠不會取代錘子,我們卻愚蠢地希望能完全取代。錘子總能做一些釘子槍不能做的事情 。Rails 將永遠不會成為用於企業集成、對象關系映射或全堆棧 Web 服務的工具。您可以對 Rails 所做 的最好期望是,它是能很好滿足它所針對領域的專門工具。
開發人員實踐
當您開始透過表面深入研究下去時,您開始了解 Rails 開發人員實踐是如此的完全不同。快速的反饋 周期、每次的交互控制和約定優於配置,這些都增強了在 Java 框架中不常用的那些方面的開發人員實踐 。
反饋周期
影響開發人員生產率的最重要因素之一是總體反饋周期。反饋周期是從改變代碼到在屏幕上看到執行 應用程序的結果所用的時間。在 Rails 中,能夠在編碼時得到即時的反饋。當您對 Ruby 代碼做出更改 時,該功能十分顯著。可以立即加載一個浏覽器頁面來查看更改以後的結果。因為在開發期間不需要編譯 或部署,我傾向於在重新加載浏覽器或執行測試用例之前只對編程做微小的更改。幾乎每個開始使用 Rails 的 Java 開發人員都以較小的程序塊進行編碼。
您可能認為對開發人員實踐友好的快速反饋周期不支持生產環境。畢竟,頻繁地重新加載類能夠獲得 快速反饋周期,但是會使生產應用程序變得很慢。但是 Rails 通過為部署和開發提供不同的環境,避免 了這個問題。在開發環境中以應用程序的性能為代價強制頻繁地重新加載類,而生產環境則把類的重新加 載減少到最低限度,以開發人員的快速反饋周期為代價,為最終用戶提供快速的體驗。
交互性
Ruby 的交互式體驗也有助於 Rails。您可能認為在沒有完整的 IDE 的情況下調試 Rails 應用程序將 是一個痛苦的過程。實際卻不是這樣。Rails 提供兩種簡化調試的功能。其中之一是 breakpointer,它 允許您向源代碼添加 breakpoint 關鍵字。
為理解 breakpointer 的運行過程,可創建一個簡單的 Rails 應用程序,生成一個控制器,啟動服務 器,並啟動 breakpointer。確保您有權使用 breakpointer 窗口,因為當 Ruby 遇到斷點時您將使用它 。使用 Windows 時,命令序列如下:
>rails sample
>cd sample
>ruby script/generate controller samples
>start ruby script\server
>start ruby script\breakpointer
如果在 UNIX® 或 Mac OS X 中運行,請確保服務器在一個單獨的進程中啟動。
把以下代 碼鍵入或粘貼到 app/controllers/samples_controller.rb 文件中:
class SamplesController < ApplicationController
def index
breakpoint
@session[:message] = "hi, mom"
render_text "Showing index"
end
def show
render_text @session[:message]
end
end
通過加載頁面 localhost:3000/samples 和 localhost:3000/samples/show 來測試 代碼。
當 Rails 執行到斷點時,應用程序暫停。breakpointer 窗口用具有控制器當前狀態的環 境打開一個 Ruby 解釋器。然後可以執行 Ruby 命令來查詢會話的狀態、執行方法和查詢變量:
> puts @session[:message]
-> hi, mom
這種密切聯系並沒有 給您一個完整的調試器,但是您確實能獲得 Java 調試器不能為您帶來的功能,包括訪問完整的解釋器和 能夠執行應用程序的方法。
能夠簡化調試的第二個功能是 Active Record 控制台。在本系列的 第一篇文章中,您已經看到 Rails 也附帶一個腳本,能夠讓您在交互式 Ruby 解釋器窗口處理持久對象 。我經常想讓我的 Java 應用程序具有這種功能。您可以編寫一個持久模型,通過該模型更改數據庫,然 後運行一些數據庫查詢來看一下它們對系統的影響。要是能夠在類似的設置中查詢 Hibernate 對象就太 好了。
約定優於配置
約定優於配置也會使新的 Rails 開發人員能夠立即上手,因為控制器和模型代碼特別簡潔。您在 第 一篇文章中 看到,依靠 Rails 環境,可以從一些非常瘦的類獲得相當高級的行為 —— 通過采用 Rails 命名約定和由 Rails 推斷應用程序的連接點而不是直接配置它們。回顧一下,具有很多屬性且與部門 (department)具有一對多關系的 Person 對象可能類似於下面這樣:
class Person < Active Record::Base
belongs_to :department
end
不需要任何配置,因為 Rails 根據命名約定推斷表 (people) 的名稱、對象標識符和主鍵 (id) 的名 稱、相關的表 (departments) 的名稱、外鍵 (department_id) 的名稱、外部類 (department.rb) 的名 稱。無論對於編寫、閱讀還是維護來說,代碼都保持簡單、輕巧和非常賞心悅目。目的直接而清楚。
Java 開發人員能學到什麼?
我不推薦用 Java 語言構建一個更好的 Rails。相反,Java 開發人員應該從 Rails 框架學習一些教 訓,並試圖構建或增強 Java 框架以完成下面的任務:
允許熱部署,這將縮短開發反饋周期或支持允許熱部署的框架。在 Java 端此優先權應該比現在高得 多。
使用較少的 XML 和更多的約定。約定與配置並不是井水不犯河水,因為可以使用約定來指定明確的默 認值,使用配置來覆蓋約定。像 Rails 那樣使用這種方法,您可以兩全其美:具有較少重復的簡潔代碼 而不會失去靈活性。
為了在調試過程中浏覽 Java 類,合並更多的腳本語言,包括 BeanShell(參見 參考資料)。
為任務選用正確的工具。不必僅僅因為需要持久性就借助於 Hibernate 或僅僅因為需要 Web 應用程 序就借助於 Struts。
通過合並其他編程語言的最好特性,您可以不必重復 Rails,但肯定可以改善 Java 體驗。