關(guān)于過氣網(wǎng)紅編程語言 Ruby,我們此前曾發(fā)過一篇文章去回顧其大受追捧的過往,并討論了它每況愈下的生存狀態(tài)。不過人氣并不能直接說明語言質(zhì)量差,一方面 Ruby on Rails(用 Ruby 寫的開源 Web 應(yīng)用程序框架)仍是實現(xiàn)原型設(shè)計演示的好方法,能幫助開發(fā)者在幾天之內(nèi)更穩(wěn)妥地構(gòu)建起最小可行性產(chǎn)品,另一方面,市場對于 Rails 和 Ruby 開發(fā)者還是存在剛性需求。
近期,GitLab 就發(fā)布了一篇文章闡述它們堅持使用 Ruby on Rails 的原因。全球有許多流行網(wǎng)站都是基于 Rails 構(gòu)建的,盡管今天 Rails 有日落西山之勢,但技術(shù)選型還得圖個“合適”。從 GitLab 的角度看,他們本身沒有復(fù)雜的運行體系,也不需要用微服務(wù),在這樣的情況下,Ruby on Rails 對他們而言反而是最佳選擇。
Ruby on Rails 勝在哪
2004 年 7 月,Rails 的創(chuàng)始人 David Heinemeier Hansson 從 37signals 公司的項目管理工具 Basecamp 分離出 Ruby on Rails,并且以開源方式發(fā)布。
David 曾在一個采訪中回顧他創(chuàng)造 Ruby on Rails 的心路歷程,其中最大的影響來自他使用 php 與 JAVA 的深度經(jīng)驗。一方面,他不喜歡 Java 那種冗長、僵化、導(dǎo)致 Java Web 框架既復(fù)雜又難以使用的設(shè)計方式,但他贊賞 Java 良好的結(jié)構(gòu)完整性。另一方面,他喜歡 PHP 易于上手的友好特性,但也發(fā)現(xiàn) PHP 過于混亂,難以提供順暢的項目開發(fā)軌道。
當(dāng)時的情況就是,必須在兩種都不夠好的方案中做選擇:要么是易于上手卻混亂不堪,要么是結(jié)構(gòu)良好卻難以使用。這種困境不禁讓人聯(lián)想起服務(wù)器級操作系統(tǒng)(例如穩(wěn)定卻難以使用的 Unix)和客戶端操作系統(tǒng)(例如簡便易懂卻經(jīng)常崩潰的 windows 和 macOS)間的經(jīng)典難題。
當(dāng)初人人都覺得現(xiàn)實就是這樣殘酷,只能陷入二選一的艱難抉擇。但后來 NeXT 在 Unix 的堅實基礎(chǔ)之上卻開發(fā)出一套漂亮、易用且流暢的 GUI。如今,“服務(wù)器級”Unix 不僅能夠運行起漂亮的 GUI 桌面,甚至還能搭載在大部分手機、智能手表當(dāng)中。
所以事實證明,易用性和穩(wěn)定性之間并不是非此即彼的關(guān)系。Web 框架中的易用性和混亂性也是如此——明明是兩條并行的車道,為啥非得糾纏在一起?
所以,David 看到的一個理想的平衡點是:既平易近人、又結(jié)構(gòu)良好的 Web 框架。憑借其扎實、支持元編程的 Samlltalk 特性,再加上良好的 Unix 集成效果,Ruby 證明了自己完全可以在配合 Rails 之后成為那個正確答案。
回到 GitLab 本身,當(dāng)聯(lián)合創(chuàng)始人 Dmitriy Zaporozhets 在決定開發(fā)自己的版本控制服務(wù)器軟件的時候,他其實也是 PHP 開發(fā)背景,但他沒有堅持自己熟悉的方法,而是選擇了 Rails。
對此,Sid Sijbrandij(GitLab 聯(lián)合創(chuàng)始人 &現(xiàn)任 CEO)表示了肯定:Dmitry 的判斷是有先見之明(或許也有偶然性),但不管怎么說,GitLab 也因此發(fā)展得不錯。這里的部分原因可歸功于 Rails 在良好架構(gòu)與平易近人之間找到了平衡。
“我們不需要微服務(wù)”
在 1971 年發(fā)表的文章《關(guān)于將系統(tǒng)分解為模塊時,所應(yīng)遵循的標準》中,David L. Parnas 將模塊化系統(tǒng)的優(yōu)勢總結(jié)如下:
- 有望“縮短開發(fā)時間,因為各獨立小組可以在每個模塊上工作,彼此之間幾乎不需要溝通。”
- 有望“對單一模塊做出重大變更或改進,且不影響其他模塊。”
- 有望每次只學(xué)習(xí)系統(tǒng)中的一個模塊。
Fred Brooks 在后來的《人月神話》中也強調(diào)了減少溝通需求的重要意義,認為額外的溝通開銷正是“在項目后期再增加人手,反而會進一步拖慢項目進度”的主要原因之一。
Sid Sijbrandij 認為,模塊化雖然受到高度追捧,但也往往神秘莫測。因此,設(shè)計師們只能從當(dāng)今世界上規(guī)模最大的軟件系統(tǒng)中汲取靈感——萬維網(wǎng)。考慮到萬維網(wǎng)的基本特性,它只能選擇模塊化構(gòu)建方式。
使用獨立的進程組織本地軟件系統(tǒng),再使用 REST 架構(gòu)風(fēng)格將各微服務(wù)組合起來,這樣確實有助于通過操作系統(tǒng)強制劃定模塊邊界。雖然這是種行之有效的嚴格模塊化實現(xiàn)方式,但對應(yīng)的成本也相當(dāng)沉重。
Sid Sijbrandij 進一步說道,目前分布式系統(tǒng)也面臨著類似的實現(xiàn)挑戰(zhàn)與高昂成本,人們遲遲找不到在分布式計算中保障性能與可靠性的有效方法。
“簡而言之,為了保證性能與可靠性,我們只能把原本以納秒為衡量單位、且永不失敗的函數(shù)調(diào)用,替換成以毫秒甚至秒為衡量單位、而且隨時可能失敗的網(wǎng)絡(luò)調(diào)用。而且我們經(jīng)常需要在幾乎沒有工具支持的情況下,跨多項服務(wù)開展跟蹤,于是故障診斷變得更加困難。只有相當(dāng)成熟的 DevOps 組織才能成功運行起微服務(wù)架構(gòu)。總之,請大家明確一點——我們不是谷歌,我們可能搞不定那么復(fù)雜的大規(guī)模運行體系。”
而且即使是真能管理起來,還有另一個問題要注意:**架構(gòu)本身的復(fù)雜度,是不是已經(jīng)超出了問題本身的原始復(fù)雜度。**微服務(wù)并不能降低復(fù)雜性,所以想象中的模塊化改進最終帶來的很可能只是一團永遠理不清頭緒的亂麻。
模塊化單體架構(gòu)
憑借著良好架構(gòu)加平易近人、再加高效操作,Rails 幫助 GitLab 開發(fā)出了模塊化單體架構(gòu)。模塊化單體與分布式架構(gòu)完全相反:它強調(diào)程序應(yīng)該具有良好的結(jié)構(gòu)、架構(gòu)以及更高的模塊化水平,其中每個進程都能穩(wěn)定運行且盡可能保持簡單。
Sid Sijbrandij 表示,雖然將 GitLab 構(gòu)建成單體最符合項目預(yù)期,但對于具體結(jié)構(gòu)取舍也絕不能太過教條。總之,架構(gòu)要為需求服務(wù),而非需求為架構(gòu)服務(wù)。
雖然 Rails 確實能幫助 GitLab 有效達成目標,但它也有一些缺點,特別是在性能方面。所幸的是,GitLab 大多數(shù)代碼庫中只有極小一部分需要重視性能。“所以我們用 Go 自己編寫了 gitaly 守護進程以處理實際 git 操作,并使用 PostgreSQL 處理非 repo 持久性數(shù)據(jù)。”Sid Sijbrandij 坦言道。
Sid Sijbrandij 表示,模塊化單體架構(gòu)把 GitLab 的“核心開放”(Open Core)商業(yè)模式從理論真正轉(zhuǎn)化為現(xiàn)實。盡管 Rails 本身并不能實現(xiàn)這一點,這是那些出色的貢獻者和工程師們完成的,但 Rails 還是為這些成功奠定了基礎(chǔ)。
開源運動的“圣經(jīng)”《大教堂與集市》里提到,為了發(fā)揮開源的真正優(yōu)勢,貢獻者必須能夠隨時訪問源代碼。另一方面,為了在接收各種貢獻的同時保持架構(gòu)完整性,就需要在開放組件和封閉組件之間劃開定清晰的分界線、保證代碼結(jié)構(gòu)良好。
如此一來,有些人可能會想問,GitLab 為什么不開發(fā)一套合適的插件接口呢?或者干脆建立基于微服務(wù)的服務(wù)接口?對于這類問題,Sid Sijbrandij 的回答是堅決的:沒必要。因為這些方法不僅會在部署和集成層面,顯著提升源代碼輕微改動的實現(xiàn)難度,同時也會帶來過于嚴格的架構(gòu)實施約束。“誰能預(yù)測出未來一切可能的擴展點?根本不可能,我們也壓根不打算給自己找這個麻煩。”
“憑借著這些無聊的模塊化單體,用戶及其他第三方開發(fā)商一樣能為核心產(chǎn)品做出貢獻、并幫助社區(qū)積累起巨大的影響力,同時保持著無與倫比的創(chuàng)新速度與可擴展性。”或許在 GitLab 看來,有時候,平平淡淡才是真。
參考鏈接:
https://about.gitlab.com/blog/2022/07/06/why-were-sticking-with-ruby-on-rails/
https://corecursive.com/045-david-heinemeier-hansson-software-contrarian/