Rails 基本主義

David Heinemeier Hansson
翻譯 Juanito Fatas, wildjcrt

Ruby on Rails 驚人的活躍主要是因為本身採用了新穎的技術和對的時間點。但技術優勢隨時間推移而削弱;好景不長久。但 Rails 為什麼不僅能繼續與時俱進,影響並帶領社群繼續前進?需要更進一步的解釋。我提議以下這篇內容,是我們的基本主義,也是飽受爭議的基本主義。

這篇基本主義,在過去十年裡不斷演化,是最主要的支柱,同時也是最基本的支柱。我不自詡自己是這些想法的原創者。Rails 的主要成就是統整與培養出,一個圍繞在廣泛程式設計本質思想與程式設計師本身的族群。

廢話不多說,以下是由我所認為,Rails 最重要的 9 個基本主義是:

  1. 程式設計師的快樂優先
  2. 約定優於配置
  3. 主廚精選
  4. 多元範式
  5. 讚揚優美
  6. 提供實用工具
  7. 重視整合系統
  8. 進步比穩定更重要
  9. 包容並重

程式設計師的快樂優先

Ruby 造就了 Rails,所以第一條主義便是從創造 Ruby 的核心理念所提煉出來。

Ruby 早期的異端邪說就是把程式設計師的幸福擺在第一位。遠把追求幸福放在驅使程式語言與生態圈前進的競爭考量之上。

Python 可能對「用一種方法,最好只有一種方法來完成一件事」感到自豪,Ruby 則喜愛自身表現力與巧妙。Java 是保護程式設計師的強力擁簇者,Ruby 則在歡迎工具裡就附上可自盡的繩索。Smalltalk 鑽研消息傳遞的純粹性,Ruby 則積累關鍵字和臃腫的語法構造。

Ruby 與眾不同的原因是看重的事情不一樣。這些考量,都是為了滿足追求程式設計師的幸福。追求導致了與其它程式設計環境的辯論,也打開了主流文化對究竟什麼是程式設計師,以及該如何應對程式設計師的認知。

Ruby 不僅認可也適應與提昇了程式設計師的感受。這究竟是不適當、還是奇思呢,抑或是喜悅。Matz 跨越了驚人複雜的實作門檻,讓機器面有喜色充滿人性。Ruby 滿是視覺上的錯覺,在我們看起來 Ruby 很簡單,很清晰,也很優美,背後其實是雜技般的錯綜複雜。這些選擇不是沒有代價(問問 JRuby 那些試著要逆向工程 Ruby 的人看看!),這也是為什麼,這是很值得讚揚的一件事。

這是對程式設計另一種願景的致敬,也決定了我對 Ruby 的愛戀。這不只是簡單易用,不僅是美學的元素,也不是單一的技術成就。而是一種願景,是反文化。Ruby 是一個不適應呆板專業程式設計的人,而是專屬於愛好之士的樂土。

我過去談過,發現 Ruby 像是找到完全適合我的魔法手套。比我想像中的任何手套都來得合用。這是我從「寫程式只是因為我需要程式」到「寫程式是因為熱於其中的心智表達與練習」的一次轉換。是找到無我之境,且能夠隨意開啟的入口。對於任何熟悉 Csikszentmihalyi 的作品的人來說,我真的一點也不誇張。

當我說 Ruby 改變了我,我真的不誇張,Ruby 決定了我人生的努力目標。如此深刻的啟示。Ruby 感染了我,呼喚我對 Matz 的產物做出宣教的工作。傳播這深刻的語言與恩賜。

我想你們現在大概都感到疑惑的搖搖頭。我不怪你們。要我還處於「程式設計只不過是工具」的階段,要有人跟我說上面這樣的經歷,我也會搖頭。但接著我可能會對這宗教般的語言發笑。但說實在的,這也是最真誠的理由,即便這可能使某些人,甚至是多數的人感到不愉快。

無論如何,究竟這對 Rails 意味著什麼?這個理念為什麼持續引導 Rails 演進?要回答這個問題,我想用另一個啟發性的理念來說明,一個早期常用來描述 Ruby 的理念:最小驚訝原則(The Principle of Least Surprise)。Ruby 應該要如你預期般的運行。可以用下面這個對比於 Python 的例子來解釋:

$ irb
irb(main):001:0> exit
$ irb
irb(main):001:0> quit

$ python
>>> exit
Use exit() or Ctrl-D (i.e. EOF) to exit

Ruby 可以用 exitquit,來回應程式設計師的需求,也就是想離開互動終端。另一方面 Python,迂腐地告訴程式設計師如何做該做的事,即便 Python 已經知道程式設計師想幹嘛(卻只顯示錯誤訊息)。這個非常清晰短小的例子說明了最小驚訝原則。

最小驚訝原則最終在 Ruby 社群失寵的原因非常直觀。最小驚訝原則,驚訝誰?那當然是 Matz 了,以及跟 Matz 對同樣事物感到驚訝的人。Ruby 社群成長茁壯的同時,人們對不同的事情感到驚訝,跟 Matz 成長過程中感到驚訝的事情不一樣,這主要咎因於失敗的郵件論壇。為了要避免更多甲男對乙物是否感到吃驚的爭論沒完沒了,所以這個理念從此退居幕後。

再一次,這跟 Rails 到底有什麼關係?嗯,Rails 就是按照相似的理念,盡量不驚訝(Matz)而設計,以及(DHH 的)燦爛微笑理念,這理念就是:框架的 API,設計時著重考量,如何可以讓人用起來會心一笑。我寫下此句時,即便是我自己,也覺得這第一次聽起來肯定非常的滑稽與自戀。

但創造出像是 Ruby 或 Rails 這樣的成果,本身就是深度自戀的努力成果。Ruby 與 Rails 都是誕生於單一創造者。但也許我只是在這把我的動機投射在 Matz 身上,所以讓我縮小我宣言的範疇:我發明 Rails 只是為了我自己。從最初開始就是為了讓我自己微笑。Rails 的許多工具,很多方面來看,他們的用途都是為了讓我更加享受人生。充實每天為需求所爭論不休的生活,以及用來打造 Web 資訊系統。

和 Matz 一樣,我有時候為了實現我的理念,也會做出一些蠢事。一個例子便是 Inflector,一個可以對英文做不規則轉換的類別,譬如 Person 類對應到 People 表、Analysis 對應到 Analyses,Comment 對應到 Comments 等。這現在已經是 Rails 不可切割的元素,但早期爭議的怒火延燒到今日,傷口到現在還在癒合,由此可見其重要性。

另一個例子只用了些許程式碼實現,卻幾乎引發了驚愕的程度。Array#second#fifth(以及挑釁意味的 #forty_two)。這些別名的存取器,非常嚴重的冒犯了常發表意見的支持者,說:這簡直太超過了(幾乎是程式設計文明時代的結束),這不就寫作 Array#[1]Array#[2](以及 Array[41])就好了嘛。

但時至今日,主要的抉擇還是,讓我自己開心。我喜歡在終端或測試裡撰寫 people.third。不,這不合理,也不高效。可能我有病吧,但這仍讓我發自內心的微笑,滿足了這個理念,也豐富了我的人生,幫我在過了 12 年之後,仍繼續參與 Rails。

不像優化效能有明確的指標,優化幸福很難量測。這使得優化幸福變成了不科學的無謂努力,某些人要不是徹底失望,可能就是覺得這並不怎麼重要。程式設計師被教導要爭執並征服實際的東西,也就是可以明確指出,為什麼甲比乙好的東西。

但追求幸福,是很難從微觀的角度來量測,但從宏觀的角度來看便很清楚。許多人留在 Ruby on Rails 社群便是這個原因。他們自豪於更好,更圓滿的工作生活。而正是因為這些感情因素,勝利是很清楚的。

總結,追求幸福可能是形成 Ruby on Rails 的關鍵要素。而這,會跟著 Rails 一直走下去。

約定優於配置

早期 Rails 的生產力座右銘是:「你不是獨一無二的,大家都一樣」。只要放下了自負的個人喜好,便可以跳過無謂的世俗決定,而只在最重要的地方下更快的決定。

真的有人在乎資料庫主鍵的名稱嗎?用 idpostIDposts_idpid,真的有差別嗎?這真的值得反覆討論嗎?不!

Rails 部分使命就是,幫開發者在為 Web 打造資訊系統,日漸複雜龐大的決策叢林中披荊斬棘。有幾千個無謂的決策只需要做一次,而若是別人幫你做這些決定,那就更好了。

約定優於配置,將我們從各種小的決定中解放出來,也提供一個繁茂的草原,讓我們蘊育更深層的抽象。如果我們可以仰賴 Person 類別對應到 people 資料表,我們可以用同樣的詞形變化,來從 has_many :people 推論出,類別是 Person。優良約定的力量是廣泛使用能獲得許多好處。

除了專家的生產力提昇了以外,約定也降低了新手的門檻。Rails 裡有非常多的約定,新手不用知道,但卻能從中獲益。不需要了解,每一件事情為什麼是這樣,也可以打造出偉大的應用。

但框架要是只是厚重的教科書就不可能了,新的應用好比一張白紙。單單是要理解從那開始,如何起步,就需要花費巨大的努力。一半的時間都花在糾結,究竟該拉那條線才是正確的。

同樣的道理也可以套用在,當你了解了所有部件是如何一起工作時。當每一個改變的下一步非常明確時,我們可以快速的遊走在應用相似或與其它應用相同的部件之間。一個包含了所有東西的地方,所有東西都在一個地方。即便是最有能的人,也可以從約束中解放出來。

世間萬物,有好有壞,約定的力量不是沒有危險。當 Rails 這麼簡單就可以做這麼多事情的時候,很容易就會這麼想,應用的每個部分,都可以用一個預先準備的模版來解決。

但多數值得做的應用,總有某種程度上獨一無二的部分。可能是 5% 或是 1%,但總是有。

最困難的部份就是,何時要打破約定。什麼時候才要偏離正軌? 我主張多數的衝動其實都沒什麼不同的,也沒好好認真想過,而偏離 Rails 的代價被低估了,但其實也有代價的,不需要你一一深刻審視。

主廚精選

在餐廳不知道什麼好吃該怎麼點菜?若你交給主廚挑選,可能可以在了解何為「好」之前,就吃上一頓好料。這就是 Omakase。無須成為美食專家或亂點菜碰運氣,就可以吃到好東西的方法。

對程式設計來說,這個實踐的好處是,技術棧交給別人幫你組合,跟我們從約定優於配置所得出的論點相似,但更上一樓。「約定優於配置」考量如何用好單一的工具,而 Omakase 則考量該用什麼框架,以及框架之間該如何合作。

有這麼一說,程式設計的優良傳統便是把可用的工具交給使用者自己去選擇,授與(還是負擔?)程式設計師決策權。

你一定聽過這句話,也暗自點頭贊同:「用最好的工具來解決問題」。這聽起來很基本,但能夠選擇「最好的工具」需要明確的定義出什麼是「最好」。這其實比想像中要難許多。

這個問題跟在餐廳要吃什麼類似。像是挑選八道菜的每一道,選擇每一個函式庫或框架,這不是獨立的決定。選菜需要根據今晚的狀況來考慮,挑選函式庫則要考量整個系統。

所以 Rails 我們根據大局考量,把選擇減少到一套好的工具,讓每個程式設計師可以從中挑選:一套為了大家好的工具。好處如下:

  1. 分散風險:當大家都用預設的方式來使用 Rails,我們有共同的體驗。這共同基礎讓我們可以更容易教導和幫助新人。有討論的共同基礎。就好比大家昨天晚上七點都看過某個節目,所以明天大家有共同的話題可以談論。進而培養出更強凝聚力的社群。
  2. 大家熟練使用相同的基礎工具:身為一個全棧的框架,Rails 有很多可以移動的部件,這些部件如何一起工作?如何獨立工作?兩者同樣重要。多數軟體開發的痛苦不是來自於獨立的部件,而是部件之間的互動。當我們用同樣的方式來使用這些部件,相同的配置便可得出相同的錯誤,則大家受的苦便減少了。
  3. 有必要時也可以換掉:Rails 是主廚精選的技術棧,某些子框架或函式庫你仍保有選擇權。只是你不一定要換掉,這些決策可以之後再做,在你開發出一個明確的,需要不一樣的個人化應用時再來考慮吧。

因為多數使用 Rails,有經驗的程式設計師,不是都討厭菜單上的每一道(討厭的話就不會繼續使用 Rails 了)。他們努力挑選想要的替代方案,而其它則享受跟大家一樣的工具。

多元範式

大家對中央集權的概念有很強烈的情感,而根據最終得出的理性結論,來當作架構基礎。這個紀律存在某種純粹性,這也是為什麼程式設計師會被中央集權所吸引。

Rails 不是這樣。Rails 不是一件剪裁完美的衣服。Rails 是一件棉被。一個用很多概念,甚至是範式所組成的棉被。這些概念和範式看起來可能有抵觸、自相矛盾或互相矛盾。但這不是我們要做的事。這不是更優越的點子就勝出的總冠軍賽,不是一定要選出一個贏家。

看看在 Rails MVC 裡用來打造 View 的模版。默認情況下,這些 Helper 允許我們從 View 抽取出程式碼,抽出來不過是一堆函數!這些函數甚至存在同一個命名空間之下。噢,驚訝了嗎?感到恐懼嗎?正像是 PHP 那樣呢!

但我主張 PHP 在單一函數之間,鮮少需要互動這點上是對的,就像 View 有著許多抽象一樣。根據這個目的,單一命名空間,一堆方法,這不只是個合理的決定,而是很棒的決定。

這不代表我們不會偶爾想要用 Object-Oriented 的方式來打造 View。Presenter 的概念,把彼此之間獨立的方法,和要呈現的資料包在一起;這可能是方法混在一起最好的解藥。但這很少見,不是常見的場景。

相比之下,我們通常把 MVC 的 Model,看成是 Object-Oriented 精華的主要堡壘。選擇正確的名稱,增加一致性,減少耦合,這是建模好玩的地方。這跟 View 是很不一樣的一層,所以我們採用了不同的做法。

但即便我們不採納單一範式的教條。Rails 的 concerns,Ruby mixin 的特例,通常用來擴充 Model。這跟 Active Record 的模式合作無間,透過給予每個方法有直接存取與儲存正在交互的資料的權力。

即使 Active Record 框架的根本侵犯了某些純粹主義者。我們把跟資料庫打交道的邏輯和商業邏輯混合了在一起。合併了邊界!沒錯,因為這才是做出 Web 應用的實際方法,Web 應用通常就需要跟資料庫打交道,也需要儲存某些商業邏輯的狀態。

有如此理想的彈性,正是為什麼 Rails 可以解決許多不同的問題。多數單一的流派解決單一的問題很厲害,但超出舒適圈就變得非常尷尬死板。要應用許多交錯的範式,我們旁敲側擊,在後面把關。最終整合出來的框架更強大,也比單一範式能做更多事。

現在,這種和許多程式設計流派結合的多重關係,是概念上的負擔。僅了解 Object-Oriented 程式設計不足以把 Rails 用好。還需要有過程式和函數式的經驗。

這也可以應用到許多 Rails 的子語言。我們不試著剝奪你學習的機會,比如你可以在 View 用任何 JavaScript,或某用 SQL 來做複雜的查詢。這些都是可以的。

降低學習曲線的方法,真的只是想辦法更容易上手,在了解框架的每一個方面之前,做一些有實際價值的東西。這也是框架為什麼要儘快示範 Hello World。告訴你桌子已經準備好了,前菜也上了。

這其中的思想就是,盡早給出有實際價值的東西,我們鼓勵 Rails 的實踐家快速學習。接受學習的過程是一種喜悅,而不是障礙。

讚揚優美

我們寫程式,不只是要讓計算機或其他人理解,而是要沐浴在優美的夕陽餘暉裡。看起來漂亮的程式碼,本身就有價值,要盡力追尋。但這不代表優美的程式碼,就該勝於一切的考量,而是要把優美納入優先考量。

優美的程式碼是什麼?在 Ruby,通常交會於 Ruby 本身的慣用式和自定的 DSL 威力之間。這是一條模糊的分界線,但非常值得一試。

以下是一個取自 Active Record 的簡單範例:

class Project < ApplicationRecord
  belongs_to :account
  has_many :participants, class_name: 'Person'
  validates_presence_of :name
end

這看起來像是 DSL,但這只是一個類別定義,其中有三句類別方法呼叫,方法呼叫接受符號及選項參數。沒什麼特別的,但這很漂亮。這也很簡單。只消幾行宣告,便賦予了我們碩大的能力與彈性。

這幾條語句部分的美麗,來自於履行先前的理念,像是約定優於配置。當我們使用 belongs_to :account 時,我們假設 projects 表有一個叫做 account_id 的外鍵存在。當我們把 participants 的關聯類別,用 class_name 指定為 Person 時,我們只需要定義 Person 類別就可以了。從這條語句便可以推出外鍵以及其它需要的設定。

以下是取自資料庫 Migration 的另一個範例:

class CreateAccounts < ActiveRecord::Migration
  def change
    create_table :accounts do |t|
      t.integer :queenbee_id
      t.timestamps
    end
  end
end

這是框架威力的精華所在。程式設計師按照某種約定來宣告一個類別,像是繼承自 ActiveRecord::Migration 並實現 #change 方法,剩下的交給框架來處理,什麼該去那裡,該呼叫那個方法。

這讓程式設計師只要寫很少的程式碼。就 Migration 的例子來說,就這樣一個檔案加 rails db:migrate 就可以把資料庫升級、新增一張表;反過來也可以用另一條命令來移掉一張表。這跟程式設計師自己使用所有背後的函式庫,搞定所有細節很不一樣。

有時候優美的程式反而更玄乎。不是要追求寫得多短多短,或是有多厲害,更重要的是讀起來的節奏感:

以下兩條語句等價:

if people.include? person
...
if person.in? people

但執行流程與關注的地方有著微妙的不同。第一個語句,關注的是群體是否有特定的人。第二個語句則是人是否屬於群體。兩條語句都差不多長,但我主張第二條語句更美,能讓我在想出這條件式考量的是人的時候,更容易有種會心一笑的感覺。

提供實用工具

Ruby 本身就有許多實用的工具,不是碰巧,設計正是如此。最出名的就是 Monkey Patching:可以修改類別與方法的能力。

但這個能力很快被嘲諷說,一般的程式設計師掌握不了。而從限制性較嚴格的語言陣營人們認為,Ruby 這個功能盲目的信任程式設計師,Ruby 是註定是要失敗的。

什麼都可以改變的話,又怎麼能阻止你把 String#capitalize 從本來的 "something bold".capitalize 改成 "Something Bold" 而不是本來的 "Something bold" 呢?這在你自己的應用上可能沒問題,但這就把其它倚賴 String#capitalize 的函式庫都搞壞了。

有人說禁止使用才是答案。在 Ruby 裡,只要有好的理由,沒有什麼可以阻止你使用這個功能。我們透過約定、推廣、教育來宣導好的觀念,而不是禁止使用廚房的菜刀,一定要規定每個人只能用湯匙來切番茄。

但 Monkey Patching 的反面是能夠做出 2.days.ago(回傳兩天前到現在的日期)這樣的美技。你可能會覺得,噢,這交易真不划算。也就是你寧願不要 2.days.ago,也不想修改語言的核心類別,若你這麼想的話,那 Ruby 可能不適合你。

但有些人出自於安全性的考量,不得以只好放棄修改 Ruby 的核心類別。但反方面來說,語言活躍的原因,正是因為給程式設計師提供了激進不同的觀點:同時也相信可以放心的把工具交給程式設計師使用。

不只是相信,語言本身也用多種方法,來教導我們使用這些有用的工具。如此一來我們可以把整個產業向上提昇,透過假設多數的程式設計師都想更進步,大家都能使用好的工具,而不傷害到自己。這真是一個鼓舞人心的想法啊,但這有悖於大部分程式設計師對其他同僚的想法。

在決定實用工具的價值時,總得以大家為出發點來討論。我尚未聽到任何一個程式設計師說,「我無法相信這股力量,請把它拿走!」。常常聽到則是「我想其他的程式設計師會濫用這個」。但我從來就不喜歡這種家長式的作風。

這正是 Rails 要提供實用工具的原因。框架所提供的工具不僅和語言所提供的工具同樣實用,也很銳利。我們不為提供這些工具而感到抱歉。事實上,我們應該要慶祝我們有足夠的信心,來啟發下一代的程式設計師,有勇氣相信他們。

許多 Rails 的功能常常飽受這樣的爭議:「太過自由」。但我現在想到的一個例子是 Concern 這個功能。這是基於 Ruby 內建功能 Module 之上的一層,薄薄的語法糖。為了單一類別打造,可以用來封裝多個相關卻又可獨立理解的「關係」(也正是 Concern 名字的由來)。

對於 Concern 的指控是有了一組新的抽屜,讓程式設計師很容易把物件都塞進去。這說得沒錯,Concern 的用途就像這樣。

但謬論是不要提供像是 Concern 的功能,但只要是有點能力的人來使用 Concern,便可得出有說服力的概念分離,程式設計師可以從 Concern 獲得先天上架構的優勢。這麼說吧,如果你不能保持 Concern 的整潔,那你也不可能寫出單支優雅的程式。

尚未學會使用這些實用工具的程式設計師,嚐不到收穫的果實。這裡有一個重要的單字:「尚未」。我相信每個程式設計師,都有自己的一條道,最終將變成有能力的 Ruby 與 Rails 程式設計師。有能力我是指有足夠的知識,知道何時,以及該怎麼根據場景來使用不同的工具,有時甚至得使用危險的工具。

這不是要把幫助他們成為厲害開發者的責任卸下。框架與語言應該是有耐心的家教,願意指導幫助任何人,一步步成為大師。同時認可不斷犯錯是唯一的道路:錯用工具、一點教訓、汗水,有時候可能是淚水。想變強就是這樣,沒有捷徑。

Ruby on Rails 是大廚的廚房,是想變成大廚的試煉場。你可能從洗盤子起步,但可以一步步努力往上爬,爬到掌管廚房。別讓任何人告訴你,最好的工具不能放心的交給你使用,而是應該看作成長過程的一部分。

重視整合系統

Rails 可以在很多場景下使用,但最初是用來做整合系統的 Majestic Monolith!Majestic Monolith 即用一個系統來解決所有問題。這表示 Rails 從需要做即時刷新的前端 JavaScript,到資料庫如何在生產環境遷移一個版本,都要納入考量。

我們已經談過,這是多麼廣闊的眼界。但對於一人團隊來說,不過就是現實的考量而已。Rails 特別尋找通才來打造整個系統。目的不是要把專家束之高閣,而是讓通才和專家合力,打造出更具長遠價值的系統。

讓一個人可以做更多的事情,才想出了整合系統。而正是在整合系統裡,我們可以拿掉許多不必要的抽象,減少抽象層之間的重複(像是 Server 端與 Client 端可以共用模版),以及避免系統在非必要的情況下分離。

系統開發的複雜度多半是引入了系統部件之間的界限,比如限制甲部件該如何和乙部件互相調用。本地物件之間的方法呼叫,遠比 Microservices 之間的遠端程序呼叫要來得簡單。Microservices 是另一個存在失敗狀態、延遲問題、相依更新週期的新世界,等著讓想嘗試拆分服務的人去冒險。

有時候這種服務的拆分是必要的。若想建立讓大家可以透過 HTTP 使用的 API,好吧,那你就得毫無怨言的處理許多問題(雖然處理進來的請求比發出去請求要簡單——但要是你的服務掛了,別人就會收到錯誤的狀態了)。但這至少對你個人的開發體驗傷害有限。

更糟糕的是,當系統過早解耦,或是過早拆成小服務,比這更糟糕的是,拆成 Microservices。這是現代網路應用的錯誤認知,你只會反覆的重造系統:在 Server 端打造一次,在 JavaScript MVC Client 端又打造一次,在原生手機端又再來一次等等。這不是自然規律,你也不需要這樣。

若想在整個應用裡共享大部分的功能,這完全是可行的。桌上應用和 mobile app 可以用同樣的 Controller 跟 View。盡可能的把功能集中在 Majestic Monolith:整合系統。集中在一起完全不需要犧牲舉凡速度、使用者體驗、以及其他錯讓你以為要盡早拆分系統的因素。

這正是我們要追求的系統:包含所有功能,容易發佈,簡單理解的單一系統,整合系統。

進步比穩定更重要

當一個已經系統已經存在超過十年,比如 Rails,自然會慢慢僵化。每一處修改,都有百萬種理由可能會變成別人的困擾,或是有人仍需要舊的行為。這對他們來說都是合理的理由。

但若我們太仔細聽取保守派的意見,我們永遠不知道另一邊的聲音是什麼。我們需要勇敢的做出改變,打破陳規,事情才可以演化茁壯。正是這樣的演變,才讓 Rails 存活下來,並可能繼續繁榮發展(數)十年。

這些理論上都很簡單,實際做起來卻很困難。特別是你的應用因為升級大版本 Rails 時,有不相容的改變而壞掉了。正是此時,我們珍重「進步比穩定更重要」的價值,這個價值給我們力量來搞定升級,搞清楚為什麼並與時俱進。

但這不代表我們就可以加入不需要的功能,或是胡來把別人的應用搞壞了。Rails 2 升到 3 的升級惡夢,仍在經歷過的人身上陰魂不散。那真的是很艱難的決定。修改太大使得許多人停滯在 Rails 2.x 不前,有些人更是討厭至極。但從大局來看,仍是個值得的選擇。

這些是需要一直做出的權衡。做了這個改變之後,Rails 能夠在五年之內變更好嗎?Rails 可以採用某些問題的解決方案,比如背景工作或 WebSocket,這能讓 Rails 在今後變得更好嗎?是的話,那什麼也別說了,捲起袖子幹活吧。

這些工作不只有 Rails 需要,廣大的 Ruby 社群也需要。Rails 應該站在時代的前沿,透過帶領人們快速升級新版,來幫助 Ruby 演進。

這一點我們做的非常好。最早開始時,我們從 Ruby 1.6、1.7、1.8、1.9、2.0、2.1、2.2 一路升上 2.3。沿路歷經多次的大版本更新,但 Ruby 總是有 Rails 當後盾,並幫助每個人的程式跑的更快。這是身為最流行的 Ruby 專案 Rails 的特權,同時也是義務。

這點也可以延伸到工具鏈的輔助工具。Bundler 曾是一個爭議性的概念,但透過 Rails 的不懈努力,Bundler 成了未來的重要工具,今天理所當然已經是不可或缺的工具了。同樣也可以應用到 Asset Pipeline 跟 Spring(常駐的指令進程)。這三個一起出現,也仍然一起往前走,過程中可能造成了一些痛苦,但長遠下來,這些工具提供的價值正是為什麼我們要推廣他們的原因。

最終進步的是人,以及人們樂意做出改變。這也是為什麼,像 Rails CoreRails Committers 這樣的團隊裡沒有終身職位。這兩個團隊是給活躍致力於帶動框架進步的那群人。對某些人來說,可能就幾年,但我們永遠感激他們的付出奉獻,這些奉獻可能持續影響著我們幾十年。

而這也是為什麼對我們來說,有一個鼓舞社群新成員的友好環境非常重要。我們需要新血與新概念,才可以激盪出更好的進步。

包容並重

正是歸功於這麼多爭議性的概念才有 Rails。但若我們要求每個人完全遵從所有的主義,Rails 可能很快的就變成孤芳自賞的小族群,所以我們不這麼做!

我們需要反面意見。我們需要方言。我們需要多元的思想和群眾。正是在概念的熔爐裡,我們才能提煉出這之中最好的讓大家共享。許多人用程式碼或是深思熟慮的論證來提供意見。

當這篇基本主義描述著一種理想形式時,日常生活中的實際情況卻更微妙(和有趣)。Rails 可以包容尊重這樣龐大的社群,是因為我們幾乎不試驗任何的一份子。

RSpec,一個我不喜歡的測試 DSL。RSpec 的持續成功是最完美的證據。我可以說到臉紅氣喘,為什麼我不覺得它的方式是對的,但 RSpec 仍可以繁榮綻放。這才是重要的一點!

同樣的論點也適用在 Rails 作 API 的例子。雖然我個人關注也花心思的是帶有 View 的整合系統;但對於想要分離 Client 端與 Server 端的人來說,這當然是 Rails 可以發揮的地方。我們應該要擁抱這一點,就是 Rails 不只能做一件事,當然也可以做 API。

包容並重並不代表把所有東西加諸給所有人。這只是代表你歡迎人們帶自己的飲料來參加你的派對。我們要給別人加入我們的機會,卻又不能失了我們的靈魂與價值。因為我們可能從他們身上可以學到,如何調一兩杯新的飲料。

當然這要付出代價的。需要讓努力付出的貢獻受歡迎。特別是我們目標不僅是要吸引已經是社群的一份子。我們永遠都要認真考慮如何降低起步門檻。

你永遠不知道,改正文件錯誤拼寫的人,可能就是下個大功能的實作者。不論是多小的貢獻,都能笑著說感謝,那貢獻者就可以一直堅持下去。