Rails 信條(重譯)

最近在 Ruby China 看到 @huacnlee 分享的 The Rails Doctrine - 中文翻譯,拜讀之下受益匪淺。
唯一遺憾是原譯文不大符合我的閱讀習(xí)慣,因此就有了這篇譯文的誕生。希望與我有相似閱讀習(xí)慣的小伙伴們會喜歡。:smile:
本翻譯參考了 DHH 的原文 The Rails Doctrine 和 @huacnlee 的譯文,在這里對兩位表示由衷的感謝!
譯文中如有不當(dāng)之處,歡迎指正。

Rails 信條

Ruby on Rails 能夠現(xiàn)象般地崛起并取得如此卓越的成就,很大程度上應(yīng)歸功于其對新技術(shù)的運(yùn)用及切入的時機(jī)。但技術(shù)優(yōu)勢一般會隨著時間推移而逐漸削弱,而好的時機(jī)也并不總會長久相伴。Rails 為何能始終保持與時俱進(jìn),并不斷擴(kuò)大其影響力和社區(qū)呢?這里有必要給大眾一個合理的解釋。我認(rèn)為最主要的原因就是其一直堅(jiān)守的那些飽受爭議的信條。

這些信條在過去的十年中也在不斷地演進(jìn),但最重要的依舊還是那些最基礎(chǔ)的信條。我不會自詡是這些信條的原創(chuàng)者。畢竟,Rails 取得的最大的成就就是:圍繞諸多離經(jīng)叛道的思想(主要是關(guān)于程序設(shè)計(jì)和程序員本質(zhì)),融合并培養(yǎng)了一個如此強(qiáng)大的社群。

閑話到此,以下就是 Rails 中最重要的9個信條,請用心領(lǐng)悟:

  1. 盡力討程序員歡心
  2. 約定優(yōu)于配置
  3. 主廚推薦
  4. 多元化
  5. 推崇優(yōu)美的代碼
  6. 提供開發(fā)利器
  7. 面向綜合應(yīng)用
  8. 演進(jìn)優(yōu)于穩(wěn)定
  9. 兼收并蓄

盡力討程序員歡心

沒有 Ruby 就不會有 Rails,因此,第一信條必然是來自于創(chuàng)造 Ruby 的核心理念。

Ruby 最初的理念確實(shí)將“程序員的開心”放在最首要的位置,也就是將它放在許多曾經(jīng)驅(qū)動程序設(shè)計(jì)語言和生態(tài)圈前進(jìn)的真理之前。

當(dāng) Python 推崇“完成一件事情,有且最好只有一種方式”,Ruby 卻沉醉于表達(dá)方式的豐富多彩和優(yōu)雅精妙。當(dāng)Java因其保護(hù)程序員自身的特性而備受推崇,Ruby 卻在歡迎工具里就附上了自盡的繩子。當(dāng) Smalltalk 專注于消息傳遞的純粹性,Ruby 卻近乎貪婪地增加關(guān)鍵字和構(gòu)造器。

Ruby 如此與眾不同是因?yàn)樗浅W鹬厥挛锏亩鄻有?。而這些多樣性中的絕大部分恰是為了滿足程序員開心而服務(wù)的。這種追求不僅引起了 Ruby 與其他編程語言環(huán)境的爭論,也開啟了主流文化對“究竟什么是程序員,以及他們應(yīng)該如何工作的”的認(rèn)知。

Ruby 不僅了解程序員的編程感受,而且還會盡量滿足甚至改善他們的編程感受。無論這些感受是不當(dāng)?shù)?、異想天開的或是令人愉悅的。Matz 跨越了復(fù)雜度如此驚人的實(shí)現(xiàn)門檻,才讓機(jī)器最終面帶微笑以取悅它的人類伙伴。Ruby 充滿了視覺假象,那些表面上看上去如此簡潔、清晰和優(yōu)美的代碼,其背后的實(shí)現(xiàn)卻如雜技般錯綜復(fù)雜。當(dāng)然這些選擇并不是沒有代價的(不信的話,可以問問 JRuby 那些嘗試對 Ruby 做逆向工程的人),這也恰恰是這些選擇如此值得稱贊的原因。

正是這種從另一個角度致敬程序設(shè)計(jì)和程序員的方式,使我深深的愛上了 Ruby。這不僅僅因?yàn)樗暮唵我子煤统錆M美學(xué)的設(shè)計(jì),也不是任何一項(xiàng)單一的技術(shù)成就,而是一種愿景,一種反文化。Ruby 就是程序設(shè)計(jì)領(lǐng)域中與現(xiàn)有專業(yè)程序設(shè)計(jì)模式相左,而又符合人類思維習(xí)慣的缺失部分。

我曾經(jīng)說過,發(fā)現(xiàn) Ruby 就像是找到了完全適合我大腦思維習(xí)慣的魔術(shù)手套。比我曾經(jīng)夢想過的任何手套都要來得合用。它甚至成為了我從“寫程序只是因?yàn)槲倚枰绦颉钡健皩懗绦蚴且驗(yàn)槲覑凵狭诉@種思維的運(yùn)用和表達(dá)方式”的轉(zhuǎn)折點(diǎn)。就像是找到了“流動之泉”(流動指的是著作 Flow:The Psychology of Optimal Experince 中描述的一種意識狀態(tài),處在這種狀態(tài)中的人通常非常愉悅,富有創(chuàng)造力,并且完全沉醉其中),并能隨意進(jìn)入其中。熟悉 Csikszentmihalyi(上述著作的作者)著作的人都應(yīng)該知道,這種影響力簡直是有過之而無不及。

毫不夸張的說,Ruby 改變了我,并為我設(shè)定了人生努力的方向。這種啟示是如此深刻,以致于讓我對布道這個 Matz 的作品充滿了使命感,也就是去傳播這個意義深遠(yuǎn)的作品和它的優(yōu)點(diǎn)。

讀到這里,我可以想象你們中絕大部份的人都會難以置信地?fù)u搖頭。我不怪你們。當(dāng)我對程序設(shè)計(jì)的認(rèn)識還處在“程序設(shè)計(jì)只不過是個工具”的階段時,如果有人跟我描述上述經(jīng)歷,我也會搖頭的。并且,我還可能嘲笑這種過分夸張近似于宗教語言般的描述。但這確實(shí)是我的真實(shí)想法,也是我的肺腑之言,即便這也許會讓某些人或絕大部分人感到不適。

無論如何,這對Rails來說究竟意味著什么,以及這個理念是如何指引 Rails 持續(xù)演進(jìn)的呢?要回答這個問題,我想先來看看另一條早期經(jīng)常被用來描述Ruby的原則是非常具有啟發(fā)性的:最小驚奇原則。即 Ruby 應(yīng)該如你預(yù)期般運(yùn)行。通過以下與 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 則會迂腐的指導(dǎo)程序員如何正確完成操作,即便它已經(jīng)明確地知道程序員想要干什么(因?yàn)樗o出了錯誤信息嘛)。這就是一個非常清晰而又短小的解釋最小驚奇原則的例子。

最小驚奇原則最終在 Ruby 社區(qū)失寵的原因是:這條原則本身是非常主觀的。最小驚奇原則,驚奇誰呢?顯然是 Matz,以及那些和 Matz 具有相似思維方式的人。但是,隨著Ruby社區(qū)的逐漸壯大,和Matz思維方式相左的人數(shù)比例也越來越多,這也成為了郵件列表里那些毫無意義的爭論之源。因此,這條原則最終淡出了人們的視線,以避免“甲男是否對乙物是否驚奇”的爭論無處不在。

但這跟 Rails 又有什么關(guān)系呢?其實(shí),Rails 最初就是基于一個與最小驚奇(Matz)原則相似的原則設(shè)計(jì)的。這個原則就是DHH的 璀璨微笑原則 ,簡單來說就是:接口設(shè)計(jì)的最大考量是如何讓我盡可能地開懷大笑。當(dāng)我把這條原則寫出來的時候,連我自己都覺得這聽起來有些滑稽和自戀。

然而,正是由于這種最初的深度自戀才造就了 Ruby 或 Rails 這樣的作品,并且這兩個項(xiàng)目都是從單個作者的思想中迸發(fā)出來的。當(dāng)然,這樣說有將我自己的創(chuàng)作動機(jī)強(qiáng)加到 Matz 身上之嫌,因此我將聲明縮小到我所知道的范圍:我創(chuàng)作 Rails 純粹是為了我自己。第一條也是最首要的原則就是為了能讓我微笑。盡管 Rails 有各種各樣的功能,但這些功能的最終目的都是為了能讓我更好的享受人生,是為了幫助我改善為網(wǎng)絡(luò)信息系統(tǒng)需求所爭論不休的日常生活。

就像 Matz 一樣,有時我也會做出一些愚蠢的決定來實(shí)現(xiàn)我自己的理念。其中的一個例子就是 Inflector,一個恰可以完成類到表映射的類(包含規(guī)則和不規(guī)則的情況),譬如 Person 類對應(yīng)到 People 表、Analysis 對應(yīng)到 Analyses,Comment 對應(yīng)到 Comments。這種行為現(xiàn)在已成了 Rails 中毋庸置疑的一部分,但當(dāng)我們還在宣揚(yáng)該原則及其重要性的早期,爭議的怒火曾經(jīng)肆意蔓延。

另外一個例子是“為了減少了些許實(shí)現(xiàn)的工作量,卻幾乎觸發(fā)了大量程序員的恐慌”,如:Array#second#fifth(以及額外增加 #forty_two)。這些訪問器別名曾嚴(yán)重冒犯了一位非常直言不諱的支持者,他認(rèn)為這些過度設(shè)計(jì)(以及額外的那個 #forty_two 都快接近文明的終點(diǎn)了。這是一個關(guān)于42的梗,請自行搜索答案,:smile: )完全可以改寫成 Array#[1]Array#[2](和 Array[41])。

但是,時至今日上述兩個決定依然能令我開懷。我非常享受可以在測試用例或終端里輸入 people.third。這并不符合邏輯,也不高效,甚至有些病態(tài)。
但卻能使我持續(xù)開懷,并由此充滿信念并豐富我的人生,繼而證明在服務(wù)了 Rails 12年之后依然參與其中是完全正確的選擇。

和性能優(yōu)化不一樣,開心優(yōu)化很難衡量。這使得開心優(yōu)化幾乎成了不科學(xué)的無謂之舉。即使有些人并未完全放棄,但也覺得這是無關(guān)緊要的事情。因?yàn)槌绦騿T一直被教導(dǎo)要執(zhí)著并攻克于可被衡量的事物,也就是那些可以明確指出A要比B好的事物。

盡管對開心的追求很難在微觀角度加以衡量,但從宏觀角度來看卻很清晰。Ruby on Rails 社區(qū)中的很多人明顯是因?yàn)檫@樣追求的才聚集于此的。他們因擁有更好的,更能帶來滿足感的職業(yè)生涯而驕傲。而這條原則正好處于這些情感的匯集之地,可想而知它的成功是必然的。

因此,我們可以得出以下結(jié)論:盡可能讓程序員開心可能是造就 Ruby on Rails 最關(guān)鍵的因素,它應(yīng)該陪伴 Rails 一直走下去。

約定優(yōu)于配置

一條 Rails 早期廣為流傳的箴言是這樣的:你并不是唯一美麗的雪花。如果能放棄那些毫無意義的個人喜好,你就可以跳出諸多無謂選擇的牢籠,在那些真正重要的領(lǐng)域快速前進(jìn)。

有誰會在乎你的數(shù)據(jù)庫主鍵采用什么格式嗎?選擇 id,postId,posts_id 或 pid 真的那么重要嗎?這真的值得反復(fù)討論才做出決定嗎?當(dāng)然不。

Rails 的部分使命就是,幫助那些創(chuàng)建網(wǎng)絡(luò)信息系統(tǒng)的開發(fā)者在日益龐大并一再出現(xiàn)的決策叢林中劈荊斬棘。其實(shí)這些成千上萬的的決策只需要做一次就夠了,如果有人能幫你做,那就再好不過了。

約定優(yōu)于配置,不僅可以讓我們避免許多無謂的思考,而且為更深層的抽象提供了肥沃的土壤。如果我們可以遵循 Person 類到 people 表的映射約定,那么我們也能用相同的約定來為 has_many :people 定義的關(guān)聯(lián)找到 Person 類。優(yōu)良約定的威力就在于:每個廣泛使用它們的領(lǐng)域都會受益頗豐。

不僅專家可以借此提升生產(chǎn)力,新手們的入門門檻也可以大大降低。Rails 中包含了如此之多的約定,以至于新手們即使都沒有察覺到它們的存在就可以從中獲益。就算不了解每件事情的底細(xì),也可能創(chuàng)建出偉大的應(yīng)用。

如果你的框架僅僅是一本厚厚的教科書,而你的新應(yīng)用只不過是一張白紙,你是不可能成功的。僅僅是找出從哪里以及如何開始就會花費(fèi)你大量的精力。估計(jì)項(xiàng)目開始的大半時間基本上就耗在尋找哪個才是正確的入口上了。

即使你已經(jīng)了解了所有組件是如何一起工作的,這種情況也不會有所好轉(zhuǎn)。但是,如果每次變動都有一個明確清晰的應(yīng)對話,我們就可以快速地略過應(yīng)用中的大部分工作。因?yàn)檫@些內(nèi)容和其它應(yīng)用中曾出現(xiàn)過的內(nèi)容是相同或類似。所謂各得其所,物盡其用就是這個樣子。從這種意義上來講,約束甚至讓那些最有能力的人獲得了解放。

當(dāng)然和其它事物一樣,約定的力量也并不是沒有風(fēng)險的。Rails 如此簡潔就可以完成如此多的事情,這很容易就讓人覺得應(yīng)用中的每個部分都可以由預(yù)定的模版來完成。但是大部分值得創(chuàng)建的應(yīng)用總會包含一些本身特有的元素,盡管它們可能只占 %5 或 1%,但總會有的。

因此,最難的部分是知道何時我們應(yīng)該打破約定。那么什么時候值得偏離正軌呢?我認(rèn)為,大多數(shù)想成為唯一美麗雪花的沖動都是不明智的,并且大大低估了脫離 Rails 的成本。但是僅打破該打破的那一小部分應(yīng)該是沒有問題的,當(dāng)然你的仔細(xì)斟酌每個細(xì)節(jié)。

主廚推薦

當(dāng)你不知道餐廳里的哪些菜好吃時,如何點(diǎn)餐呢?如果可以讓主廚幫你點(diǎn)的話,那么即使之前你并不知道哪些菜好吃,也可以吃上一頓美味大餐。這就是主廚推薦。一種無需成為美食專家或通過亂點(diǎn)一氣來碰運(yùn)氣就可以享受一頓美餐的方法。

對于程序設(shè)計(jì)來說,這條實(shí)踐帶來的好處就是讓別人幫你搭建技術(shù)棧。這與我們從約定優(yōu)于配置得出的觀點(diǎn)類似,只是層次更高。約定優(yōu)于配置著重于為何我們應(yīng)該使用單一的的框架,而主廚推薦考量的是多個框架如何協(xié)同工作。

這和保守的程序設(shè)計(jì)傳統(tǒng)大相庭徑。傳統(tǒng)做法是提供可用的工具讓程序員自行挑選,并賦予程序員自行決定的權(quán)利(其實(shí)這是一種負(fù)擔(dān))。

你肯定聽說過并贊同這句話:工欲善其事,必先利其器。聽起來就像是一種毋庸置疑的常識,但前提是你的有自信分辨出哪種工具才是最好的。其實(shí),這遠(yuǎn)比想象中的要難得多。

這和之前在餐廳吃飯時遇到的問題類似,選擇每個單一的庫或框架并不是獨(dú)立的工作,就像為一個包含八道菜的套餐挑選每道菜一樣。兩者的目標(biāo)都需要基于整個晚宴或系統(tǒng)統(tǒng)籌考慮。

因此,在 Rails 中我們決定舍棄小利:程序員在工具箱里挑選每件工具的權(quán)利,來換取更大的利益:一整套更好的工具箱。這個決定回報頗豐:

  1. 人多勢眾:當(dāng)大家都用默認(rèn)的方式使用 Rails 時,我們就擁有了共同的體驗(yàn)。教授和幫助他人就會變得容易的多,同時討論也有了共同的基礎(chǔ)。就好比我們都在昨晚7點(diǎn)看了相同的節(jié)目,第二天我們的討論就有了共同話題。這種共同的體驗(yàn)進(jìn)而促成了更有凝聚力的社區(qū)。

  2. 日益完善的基礎(chǔ)工具箱:Rails 作為一個全??蚣馨嗽S多活動組件,它們之間如何協(xié)同工作與它們單獨(dú)運(yùn)行具有相同的重要性。軟件工程的痛點(diǎn)大部分不是來自于組件內(nèi)部,而是組件之前的相互協(xié)作。當(dāng)我們都在一起努力工作修復(fù)這些大家都會碰到的痛點(diǎn)(因相同的的配置和使用方式而獲得一致的錯誤)時,這些痛點(diǎn)就會越來越少。

  3. 按需替換:盡管 Rails 是一個主廚推薦的技術(shù)棧,你仍然有機(jī)會替換掉其中的某些框架或類庫。只是不建議你這么做。當(dāng)你需要為某些特定的場景開發(fā)出一套清晰的個性化工具箱時,再來考慮這些決定吧。

即使那些最博學(xué)多才且經(jīng)驗(yàn)豐富的 Rails 程序員也不可能抵觸菜單上的每道菜(如果是的話,那他們就不會選擇繼續(xù)使用 Rails 了)。因此,他們會謹(jǐn)慎的挑選替代者,并和其他人一齊享受剩下的部分。

多元化

大家都對挑選并遵循單個核心理念來構(gòu)建自己的基礎(chǔ)架構(gòu)具有強(qiáng)烈的訴求。這個訴求如此純粹,以至于程序員都會自然而然地被它所吸引。

Rails 不遵循上述理念。它不是單件完美剪裁的衣服,它是一床棉被,是諸多不同理念和模式的組合體。如果將它們分開來一一對比的話,其中許多通??磥磉€是相互抵觸的。當(dāng)然,我們也不會這么去做。這又不是僅有一個贏家的超級理念錦標(biāo)賽。

來看看 Rails MVC 模式中用來創(chuàng)建 View 的模板。默認(rèn)情況下,所有從模板里抽取出來的 Helper 不過是一堆方法,甚至擁有同一個命名空間。是不是感到有點(diǎn)震驚和恐懼,這不就是 PHP 嘛!

但我認(rèn)為,PHP 處理這些方法的方式是正確的,因?yàn)樗鼈冎g很少相互調(diào)用,就像那些從 View 模板中抽取出來的方法一樣。以此為目的,使用單個命名空間來包含這些方法不僅是理性的選擇,而且是一個很棒的選擇。

我們偶爾也會想用更加面向?qū)ο蟮姆绞絹韯?chuàng)建 View。MVP 模式中的 Presenter 就是這樣一劑解決方法之間相互依賴的良藥。Presenter 中封裝了一系列相互獨(dú)立的方法和這些方法要處理的數(shù)據(jù)。但事實(shí)證明這種情況并不常見。

相較而言,我們將 MVC 中的 Model 看做面向?qū)ο笏枷氲木杷?。領(lǐng)域建模的樂趣就在于為對象挑選合適的名稱、提高一致性和降低耦合程度。這是和 View 層完全不同的場景,因此需要另辟蹊徑。

即便如此,我們也不會遵循單一理念的信條。Rails concern (定制過的 Ruby mixin) 經(jīng)常用來擴(kuò)展 Model。它可以和 Active Record 模式完美結(jié)合,讓那些混入的方法可以直接存取它們要處理的數(shù)據(jù)。

就算是 Active Record 模式最基本的理念也會冒犯某些純粹主義者。因?yàn)?,我們將與數(shù)據(jù)庫相關(guān)的操作和業(yè)務(wù)邏輯直接混合在了一起。毫無邊界的融合!沒錯,因?yàn)檫@是已經(jīng)證明的切實(shí)可行的方法,可用于構(gòu)建需要經(jīng)常訪問數(shù)據(jù)庫,以存取領(lǐng)域模型狀態(tài)的網(wǎng)絡(luò)應(yīng)用。

Rails 擁有如此理想的靈活性,使得它可以處理各式各樣的問題。而大多數(shù)單一模式僅在問題的某一領(lǐng)域運(yùn)轉(zhuǎn)良好,當(dāng)超出其范圍時就顯得力所不及了。但是,通過將多個模式疊加應(yīng)用,我們就可以做到全面地覆蓋。最終框架的健壯性和能力將遠(yuǎn)超任何單一模式所能達(dá)到的高度。

目前,理論上來說維持眾多編程模式多元共存關(guān)系的代價是高昂的。想要用好 Rails,僅了解面向?qū)ο缶幊淌遣粔虻?,最好還能有面向過程編程和函數(shù)式編程的經(jīng)驗(yàn)。

上述原則也同樣適用于 Rails 中的其他子語言。 我們不會為你提供過多保護(hù),以便讓你不必學(xué)習(xí)那些必須掌握的知識。比如,在 View 中使用 JavaScript 或偶爾用 SQL 來構(gòu)建復(fù)雜查詢。至少這類保護(hù)不會以盡可能完善為目標(biāo)。

降低學(xué)習(xí)曲線的方式就是讓大家容易上手,在了解框架的每個細(xì)節(jié)之前,就可以做出一些有真正價值的東西。這也是為什么我們會有一個快速搭建 Hello World 方法的原因。萬事俱備就等你來嘗試了。

Rails 的思路是,通過讓從業(yè)者盡早地創(chuàng)建真正有價值的東西,來鼓勵他們快速成長。讓他們覺得學(xué)習(xí) Rails 是一種愉悅的過程,而不是一種障礙。

推崇優(yōu)美的代碼

寫代碼并不僅僅是為了讓計(jì)算機(jī)或其他程序員易于理解,而且還要享受那種沐浴在優(yōu)美代碼中的愉悅感。從美學(xué)角度來說,令人愉悅的代碼本身就很有價值,應(yīng)該值得我們花精力去追求。這并不意味著優(yōu)美的代碼應(yīng)該勝過其他考量,但至少應(yīng)該在優(yōu)先考量中占有一席之地。

那么什么才算優(yōu)美的代碼呢?在 Ruby 中,通常指的是 Ruby 固有語法和自定義 DSL 力量的交集。這是一條模糊的定義,但非常值得一試。

下面是一個取自 Active Record 的簡單例子:

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

它看起來和DSL非常相似,其實(shí)不過是一個類定義,加上三個帶 symbol 參數(shù)和選項(xiàng)的類方法調(diào)用。這里并沒有什么魔幻的東西,不過確實(shí)優(yōu)美而又簡潔。簡單幾行聲明就帶來了如此強(qiáng)大的洪荒之力。

這種優(yōu)美部分應(yīng)該歸功于之前提到過的那些原則,如約定優(yōu)于配置。 當(dāng)調(diào)用 belongs_to :account
時,我們假定 projects 表中存在一個名字為 account_id 的外鍵。當(dāng)必須為 partcipants 關(guān)聯(lián)指定 class_name 為 Person 時,我們只需定義 Person 類即可,并可以由此推斷出外鍵和其它相關(guān)設(shè)定。

下面是另一個取自數(shù)據(jù)庫遷移系統(tǒng)的例子:

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

這個例子體現(xiàn)了框架威力的精髓。這里程序員遵循某種約定定義了一個類,這個類繼承自 ActiveRecord::Migration 并實(shí)現(xiàn)了一個 change 方法。剩下的事情就可以交給框架去處理了,并且框架知道該調(diào)用這個change方法來處理。

這樣程序員只需要寫很少的代碼就可以很好地完成工作了。上述代碼不僅支持通過調(diào)用 rails db:migrate
為數(shù)據(jù)庫添加一張新表,同時也支持通過調(diào)用另外一個命令從數(shù)據(jù)庫中刪除這張表。這和工程師自己實(shí)現(xiàn)這些功能,并將它們整合為工作流的方式完全不同。

優(yōu)美的代碼有時看起來也會顯得晦澀難懂。但優(yōu)美的代碼不應(yīng)該是為了盡可能地短小精干,而應(yīng)該更加關(guān)注閱讀的流暢性。

以下兩條語句是等價的:

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

但它們在語境和側(cè)重點(diǎn)上存在細(xì)微的差異。第一條語句側(cè)重點(diǎn)在集合,因?yàn)樗侵髡Z。第二條語句中,主語明顯是 person。這兩條語句在長度上并沒有太大的差別,但是我認(rèn)為第二條要優(yōu)美的多,特別是當(dāng)它用在判斷條件是關(guān)于 person 的時候,這會讓我感到由衷的開心。

提供開發(fā)利器

Ruby 本身就包含了許多開發(fā)利器。不是碰巧,而是設(shè)計(jì)如此。其中最著名的應(yīng)屬 Monkey Patching: 一種可以修改現(xiàn)有類和方法的能力。

這個能力經(jīng)常被嘲諷為:太簡單了,即便是最普通的程序員也可以輕松掌握。以至于那些來自限制性較為嚴(yán)格語言陣營的人曾經(jīng)?;孟耄禾^信任程序員可以駕馭這項(xiàng)能力最終會毀了 Ruby 這門語言。

因?yàn)椋绻裁炊伎梢孕薷牡脑?,那還有什么可以阻止你重寫 String 的 capitalize 方法,讓 “something bold”.capitalize 返回 “Something Bold”,而不是 “Something bold” 呢?這在你自己本地的應(yīng)用中可能沒有什么問題,但所有那些依賴于原始實(shí)現(xiàn)的輔助代碼可能就要遭殃了。

那么有什么解決方案嗎?答案是:沒有。在 Ruby 中,只要有好的理由沒有什么可以阻止你用利器來掃除障礙。我們會通過約定、勸說和教育來推行好的理念,而不是通過禁止使用廚房中的利器,并堅(jiān)持讓每個人使用勺子來切西紅柿。

由于 Monkey Patching 的負(fù)面效應(yīng)創(chuàng)造了諸如 2.days.ago(返回兩天前的日期)般的壯舉。你可能會覺得這是一樁虧本的買賣。也就是說寧可沒有 2.days.ago,你也不想修改語言的原始實(shí)現(xiàn)。如果這就是你的觀點(diǎn),那么也許 Ruby 并不適合你。

也許你從那些出于安全考慮而放棄自由的人口中聽說過:正是可以修改內(nèi)核類和方法的能力毀了 Ruby 這門語言。然而事實(shí)剛好相反,Ruby 的蓬勃發(fā)展正是由于它為程序員提供了全新的不同看法:完全可以相信程序員可以駕馭利器。

當(dāng)然僅相信是不夠的,還應(yīng)該教授他們使用這些利器的方法。如此一來還有利于提升整個行業(yè)水平,當(dāng)然前提是大多數(shù)程序員都想成為更好的程序員,并有能力在使用利器的同時避免割傷自己的手指。這真是一個夢寐以求的想法,也是一個有悖于許多程序員對其它程序員初衷(不相信其它程序員)的想法。

當(dāng)討論開發(fā)利器的重要性時,對象總是其它程序員。我從未聽過有程序員說:”我不確信自己可以駕馭這種能力,請讓我遠(yuǎn)離它!“ 經(jīng)常聽到的卻是 “我覺得其他程序員可能在濫用利器”。但這種專制的想法從未出現(xiàn)在我的腦海中。

正是這些開發(fā)利器將我們吸引到了 Rails 周圍。Rails 提供的利器盡管沒有 Ruby 提供的那么鋒利,但其中有些還是頗具威力的。我們不會因?yàn)樵诠ぞ呦淅锓胖昧诉@些利器而感到抱歉。事實(shí)上,我們對工程師們敢于嘗試的渴望持有足夠的信念,并為之自豪。

Rails 的許多功能一直因 “太過隨意” 而飽受爭議。當(dāng)下最流行的一個例子是:Concern。其實(shí)它就是在 Ruby 本身內(nèi)建的 Module 功能上添加了一層薄薄的語法糖,允許使用單個類來封裝多個相關(guān)又可以獨(dú)立理解的業(yè)務(wù)(也就是 Concern 這個名字的由來)。

Concern 功能備受指責(zé)的原因是,通過它程序員可以很容易將一些不相關(guān)的東西塞到對象中。說的沒錯,Concern 確實(shí)可以這樣使用。

一種謬論認(rèn)為,如果不提供類似于 Concern 的功能(即使是最溫和的用法也會導(dǎo)致設(shè)計(jì)思想的部分分離),就可以讓程序員處在通往幸福的康莊大道上。但是,如果你連讓對象保持整潔都做不到的話,談何可以寫出優(yōu)雅的代碼呢?

尚未學(xué)會如何使用利器的程序員就不可能做出甜美的糕點(diǎn)。注意這里的用詞:尚未。我相信每個人自己都會有一條成為 Ruby 和 Rails 稱職程序員的道路,即使這條道路并不完全順利。我說的稱職是指:有足夠的知識知道,何時以及如何根據(jù)不同的場景使用不同的工具,有時甚至危險的工具。

這不是在推脫幫助他們達(dá)成稱職程序員的責(zé)任。語言和框架應(yīng)該是有耐心的導(dǎo)師,愿意幫助和指導(dǎo)每個人成為專家。唯一可靠的道路就是不斷犯錯:錯誤地使用工具,些許血淚教訓(xùn)。沒有捷徑。

Ruby on Rails 是大廚以及那些想要成為大廚的人的廚房。也許剛開始你只是洗洗碗,但可以逐漸成長,最終可以運(yùn)營整個廚房。在這個過程中,別相信任何人告訴你的:你無法駕馭業(yè)內(nèi)最好的工具。

面向綜合應(yīng)用

Rails 可用于許多場景,但最初目的是創(chuàng)建一個整合系統(tǒng):Majestic Monolith!即一個可以解決所有問題的完整系統(tǒng)。這就意味著 Rails 需要考慮從前端需要即時更新的 JavasScript 到生產(chǎn)環(huán)境下數(shù)據(jù)庫如何進(jìn)行版本遷移的所有細(xì)節(jié)。

如上所述,這確實(shí)是一個非常寬廣的領(lǐng)域,但尚在我力所能及的范圍之內(nèi)。Rails 會專門尋找全棧工程師來創(chuàng)建這個整合系統(tǒng)。當(dāng)然,目的不是將那些專注于某個領(lǐng)域的專家排除在外,而是因?yàn)檎麄€全棧的團(tuán)隊(duì)可以更好的創(chuàng)建具有長遠(yuǎn)意義的事物。

正是專注于提高個體程序員的開發(fā)能力,讓我們想要創(chuàng)建這樣一個整合系統(tǒng)。在整合系統(tǒng)里,我們可以拿掉很多不必要的抽象,減少各層之間的重復(fù)(就像服務(wù)端和客戶端共享的模版),最重要的是可以避免讓應(yīng)用成為分布式系統(tǒng)(在確實(shí)有必要之前)。

許多系統(tǒng)開發(fā)的復(fù)雜性來自于引入組件之間的新邊界,這些邊界限定了組件之間相互調(diào)用的方式。對象之間的本地調(diào)用要比遠(yuǎn)程微服務(wù)之間的調(diào)用簡單得多。那些冒險啟用分布式系統(tǒng)的人會發(fā)現(xiàn),這是一個充滿失敗調(diào)用、網(wǎng)絡(luò)延時和依賴更新周期的全新地獄。

有時候這種分布僅僅是簡單的需求。比如你為 web 應(yīng)用創(chuàng)建了一個 API 接口,以供其他人通過 HTTP 調(diào)用,那你就乖乖等著收拾爛攤子吧(盡管處理請求要比發(fā)送請求要容易的多。因?yàn)樵诎l(fā)送請求時,別人的錯誤也會導(dǎo)致你自己的錯誤)。但對你自己來說,這至少不是一次愉快的開發(fā)經(jīng)歷。

更糟的情況是,系統(tǒng)可能過早地被拆分成了服務(wù),甚至是更差的微服務(wù)。這通常來自于一個錯誤的認(rèn)知:如果你想要個現(xiàn)代網(wǎng)絡(luò)應(yīng)用的話,只需要簡單地多次的構(gòu)建系統(tǒng),一次在服務(wù)端,一次在基于 JavaScript MVC 的客戶端,以及每個移動端的本地應(yīng)用等。這不是基本規(guī)律,也完全沒有必要。

其實(shí)完全可以在多個 app 間共享整個應(yīng)用的大部分內(nèi)容。相同的 Controller 和 View 可以用于桌面 web 應(yīng)用,也可以內(nèi)嵌到手機(jī) app 的本地應(yīng)用中。也就是盡可能將開發(fā)集中在同一個整合系統(tǒng)中。

而且這樣做完全不必犧牲速度、用戶體驗(yàn)或其他任何誤導(dǎo)你過早拆分系統(tǒng)的因素。

這就是我們一直追尋的大一統(tǒng):可自行調(diào)配、適用于多平臺應(yīng)用開發(fā)、易于理解和使用的單個整合系統(tǒng)。

演進(jìn)優(yōu)于穩(wěn)定

當(dāng)一個系統(tǒng)存在已經(jīng)超過10年,如 Rails,一般都會自然僵化。每一處修改都有各種可能給他人帶來災(zāi)難,因?yàn)樗麄兛赡芤蕾囉谶^去的實(shí)現(xiàn)。而且,對這些人來說,他們的要求完全是合理的。

但如果我們太過遷就保守派的意見,我們將永遠(yuǎn)看不到事情的另一面。因此,我們必須偶爾打破陳規(guī),以改變事情演進(jìn)發(fā)展的方式。正是這種演進(jìn)方式才讓 Rails 得以存活,并可能在未來(數(shù))十年繼續(xù)蓬勃發(fā)展。

永遠(yuǎn)都是說起來容易做起來難,特別是當(dāng)你自己的應(yīng)用因 Rails 的重大版本升級(不向下兼容)而崩潰時。然而正是這些時刻,才讓我們謹(jǐn)記 演進(jìn)優(yōu)于穩(wěn)定 的價值所在,并為我們帶來修復(fù)崩潰應(yīng)用的力量,從而繼續(xù)保持與時俱進(jìn)。

這并不代表我們就可以不管三七二十一地給別人帶來不必要的或過份的傷害。Rails 2.x 到 3 的重大升級就是這樣一個艱難的決定,它所帶來的噩夢還依然徘徊在那些親身經(jīng)歷過的人的心頭,經(jīng)久不散。它讓許多人在 2.x 版本停留了很長一段時間,有些人甚至對此深惡痛絕到失去了理智。但,從大局來看這個決定還是值得肯定的。

這些就是我們一直要做的艱難抉擇。Rails 是否會因?yàn)榻裉斓母淖兌谖磥砦迥陜?nèi)變的更好?Rails 是否會因?yàn)榻蛹{其他解決方案,如異步任務(wù)隊(duì)列或 WebSocket,而變的更好?如果答案是肯定的,那就啥都別說了,讓我們卷起袖子干活吧。

其實(shí)這項(xiàng)工作并不僅限于 Rails 本身,而應(yīng)該在廣大 Ruby 社區(qū)推行。Rails 應(yīng)該站在幫助 Ruby 進(jìn)步的前沿,推動廣大社區(qū)成員盡快使用最新版本。

就目前情況來看,我們做的還不錯。從我開始實(shí)踐這個信條開始,我們已經(jīng)經(jīng)歷 Ruby 1.6、1.7、1.8、1.9、2.0、2.1、2.1、2.2,直到目前最新的2.3。一路走來伴隨著許多重大的變遷,但 Rails 始終是 Ruby 的堅(jiān)強(qiáng)后盾,它幫助每個人盡快地適應(yīng)新版本的變遷。這是 Rails 作為Ruby 主要推廣者的部分權(quán)力和義務(wù)。

同樣,這一點(diǎn)也適用于工具鏈上的其它輔助工具。Bundler 曾經(jīng)是一個充滿爭議的理念,但是經(jīng)過 Rails 的不懈努力的推廣,它已經(jīng)成了可以和 Rails 相提并論的基石,并成為人們理所當(dāng)然的選擇。像 Asset Pipeline 和 Spring 這樣的連續(xù)處理指令組件其實(shí)也一樣。這三個組件全都經(jīng)歷過或正在經(jīng)歷演進(jìn)的痛苦,但是這些工具的長遠(yuǎn)意義促使我們一直推動他們前進(jìn)。

最終,進(jìn)步還是要取決于人以及他們想要做出改變的意愿。這就是為什么在 Rails Core 或 Rails Commiters 類似的小組中沒有終身職位一說。這兩個小組的成員都是那些為推動框架進(jìn)步而積極工作的人。有些人可能只會堅(jiān)持幾年,不管怎樣我們會永遠(yuǎn)感謝他們做出的貢獻(xiàn),但另外一些人可能會為之持續(xù)數(shù)十年。

因此,我們會一直歡迎和鼓勵新的成員加入社區(qū),這對我們來說至關(guān)重要。我們需要新的血液和理念來激蕩出更好的進(jìn)步。

兼收并蓄

Rails 因包含諸多富有爭議的理念而聞名。如果我們要求每個人無時無刻遵循所有的信條,那么 Rails 將會很快淪為孤芳自賞的小群體。所以我們絕不會這樣做。

我們需要不同的意見。我們需要不同的語法。我們需要多樣的思想和成員。在這個思想的大熔爐中,我們可以提煉出最好的精華部分給大家分享。在此過程中,許多人以代碼或深思熟慮的論點(diǎn)貢獻(xiàn)了他們的意見。

這篇信條其實(shí)描述的是一種理想狀態(tài),日常生活中的實(shí)際情況要微妙(也更有趣)的多。Rails 可以在同一個帳篷里容納下如此龐大的一個社區(qū),究其原因是 Rails 很少或者根本沒有試劍石(非一即二的考驗(yàn))。

RSpec(一個我經(jīng)常表達(dá)不滿的測試DSL框架)的持續(xù)成功就是一個完美的佐證。盡管我可以為此吐槽到口干舌燥:為什么我覺得這不是正確的測試方式。但依然不能妨礙它大獲成功。這點(diǎn)才是最為至關(guān)重要的。

Rails API 的出現(xiàn)同樣如此。盡管我個人是關(guān)注和傾力的重點(diǎn)是帶有 View 的整合系統(tǒng),但對那些想要做前后端分離的人來說,毫無疑問這是 Rails 可以改進(jìn)的地方。因此,我們應(yīng)該欣然接受 Rails API 成為 Rails 的第二使命,而且我相信它配得上如此重要的地位。

當(dāng)然,擁有同一個帳篷并不意味著需要迎合所有人的所有需求。它僅僅意味著歡迎所有人加入這個大家庭,并帶來他們自己的想法。我們不必犧牲我們的靈魂和價值觀來讓他們加入我們,我們只是知道如何將不同的想法混合在一起,來產(chǎn)生新的美妙思想。

當(dāng)然這樣一個帳篷不是唾手可得的,還需要很多工作來讓它受到大家的歡迎,特別是你的目標(biāo)不僅僅是吸引那些已經(jīng)在社區(qū)里的人。因此,降低入門門檻總是我們需要慎重考慮的工作首選。

你永遠(yuǎn)不會知道:修正文檔中拼寫錯誤的人是否最終可能會創(chuàng)作出下一項(xiàng)偉大功能。但是,你有機(jī)會向每個做出微不足道貢獻(xiàn)的人表示感激,從而激勵他們繼續(xù)努力工作。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 總結(jié)一下: 程序員的幸福最大化 約定優(yōu)于配置 主廚精選 多元化的設(shè)計(jì)模式 推崇優(yōu)美的代碼 提供實(shí)用工具 重視整合系...
    waynedeng閱讀 905評論 0 3
  • 一、異同對比選擇1、Python和ruby的相同點(diǎn): * 都強(qiáng)調(diào)語法簡單,都具有更一般的表達(dá)方式。python是縮...
    沃倫蓋茨閱讀 4,296評論 2 24
  • 第一次了解具象法則,是凈徹同學(xué)分享的一張圖片,當(dāng)時覺得好神奇,經(jīng)過凈徹的推薦,順利成為第九期的小伙伴。 在本周五天...
    goen8715閱讀 320評論 0 1
  • 生活中,我們常常有與別人意見不一致的時候,誠實(shí)的我們,通常都會很直接地表達(dá)自己的看法,表達(dá)與他的意見不一致,但這往...
    肖成燕閱讀 402評論 0 0
  • 一分鐘說教育,跟孩子做朋友! 面對“死亡”這個必須面對但誰都不愿意提及的話題,大人們應(yīng)該如何跟孩子溝通? ● 嬰幼...
    幸福親子會閱讀 1,313評論 0 2

友情鏈接更多精彩內(nèi)容