Rob Pike的“抱怨”與Go的“解藥”:直面軟件膨脹的四大根源
今年年初,Go語(yǔ)言之父、UTF-8編碼的發(fā)明者Rob Pike的一篇題為"On Bloat"(關(guān)于膨脹)的演講幻燈片(在2024年下旬做的)在技術(shù)圈,尤其是在Hacker News(以下簡(jiǎn)稱HN)上,引發(fā)了相當(dāng)熱烈的討論。Pike作為業(yè)界泰斗,其對(duì)當(dāng)前軟件開(kāi)發(fā)中普遍存在的“膨脹”現(xiàn)象的犀利批評(píng),以及對(duì)依賴管理、軟件分層等問(wèn)題的深刻擔(dān)憂,無(wú)疑戳中了許多開(kāi)發(fā)者的痛點(diǎn)。
HN上的討論更是五花八門(mén),開(kāi)發(fā)者們紛紛從自身經(jīng)歷出發(fā),探討“膨脹”的定義、成因和后果。有人認(rèn)為膨脹是“層層疊加的間接性”導(dǎo)致簡(jiǎn)單修改寸步難行;有人認(rèn)為是“不必要的功能堆砌”;還有人歸咎于“失控的依賴樹(shù)”和“缺乏紀(jì)律的開(kāi)發(fā)文化”。
那么,Rob Pike究竟在“抱怨”什么?他指出的軟件膨脹根源有哪些?而作為我們Gopher,Go語(yǔ)言的設(shè)計(jì)哲學(xué)和工具鏈,能否為我們從純技術(shù)層面提供對(duì)抗膨脹的“解藥”呢?今天,我們就結(jié)合Pike的演講精髓和HN的熱議,深入聊聊軟件膨脹的四大根源,并從Go的視角嘗試尋找一下應(yīng)對(duì)之道。
“膨脹”的真相:遠(yuǎn)不止代碼大小和運(yùn)行速度
在深入探討根源之前,我們需要認(rèn)識(shí)到,“膨脹”并不止是字面意義上我們理解的最終編譯產(chǎn)物的大小或者應(yīng)用的運(yùn)行速度慢,Pike的觀點(diǎn)和HN討論中的“軟件膨脹”體現(xiàn)在多個(gè)維度:
- 復(fù)雜性失控: 過(guò)度的抽象層次、復(fù)雜的依賴關(guān)系、難以理解的代碼路徑,使得維護(hù)和迭代變得異常困難。
- 維護(hù)成本劇增: 添加新功能的長(zhǎng)期維護(hù)成本(包括理解、測(cè)試、修復(fù)Bug、處理兼容性)遠(yuǎn)超初次實(shí)現(xiàn)的成本,但往往被低估。
- 不可預(yù)測(cè)性與脆弱性: 龐大且快速變化的依賴樹(shù)使得我們幾乎無(wú)法完全理解和掌控軟件的實(shí)際構(gòu)成和行為,任何更新都可能引入未知風(fēng)險(xiǎn)。
下面我們具體看看Pike指出的“膨脹”幾個(gè)核心根源:
根源一:特性 (Features) —— “有用”不等于“值得”
圖片
Pike 指出,我們不斷地為產(chǎn)品添加特性,以使其“更好”。但所有特性都會(huì)增加復(fù)雜性和成本,而維護(hù)成本是最大的那部分,遠(yuǎn)超初次實(shí)現(xiàn)。他警示我們要注意“有用謬論” —— 并非所有“有用”的功能都值得我們付出長(zhǎng)期的維護(hù)代價(jià)。
HN討論也印證了這一點(diǎn):功能冗余、為了匹配競(jìng)品或滿足某個(gè)高層“拍腦袋”的想法而添加功能、甚至開(kāi)發(fā)者為了個(gè)人晉升而開(kāi)發(fā)復(fù)雜功能的現(xiàn)象屢見(jiàn)不鮮。
技術(shù)層面:Go的“解藥”在哪?
- 簡(jiǎn)潔哲學(xué): Go從設(shè)計(jì)之初就強(qiáng)調(diào)“少即是多”,鼓勵(lì)用簡(jiǎn)單的原語(yǔ)組合解決問(wèn)題,天然地抵制不必要的復(fù)雜性。
- 強(qiáng)大的標(biāo)準(zhǔn)庫(kù): Go 提供了功能豐富且高質(zhì)量的標(biāo)準(zhǔn)庫(kù),覆蓋了網(wǎng)絡(luò)、并發(fā)、加解密、I/O 等眾多領(lǐng)域,減少了對(duì)外部特性庫(kù)的依賴。很多時(shí)候,“自己動(dòng)手,豐衣足食”(使用標(biāo)準(zhǔn)庫(kù))比引入一個(gè)龐大的外部框架更符合Go的風(fēng)格。
- 關(guān)注工程效率: Go的設(shè)計(jì)目標(biāo)之一是提高軟件開(kāi)發(fā)(尤其是大型項(xiàng)目)的工程效率和可維護(hù)性,這促使Go社區(qū)更關(guān)注代碼的清晰度和長(zhǎng)期成本。
注:技術(shù)層面包括語(yǔ)言、工具以及設(shè)計(jì)思路和方法。
根源二:分層 (Layering) —— 在錯(cuò)誤的層級(jí)“打補(bǔ)丁”
圖片
Pike 認(rèn)為,現(xiàn)代軟件層層疊加(硬件 -> 內(nèi)核 -> 運(yùn)行時(shí) -> 框架 -> 應(yīng)用代碼),當(dāng)出現(xiàn)問(wèn)題時(shí),我們太容易在更高的層級(jí)通過(guò)包裝(wrap)來(lái)“修復(fù)”問(wèn)題,而不是深入底層真正解決它。這導(dǎo)致了層層疊疊的“創(chuàng)可貼”,增加了復(fù)雜性和維護(hù)難度。他列舉了ChromeOS文件App的例子,并強(qiáng)調(diào)要在正確的層級(jí)實(shí)現(xiàn)功能和修復(fù)。
在HN的討論中,有開(kāi)發(fā)者描述的修改按鈕顏色需要穿透17個(gè)文件和多個(gè)抽象層的例子,正是這種“錯(cuò)誤分層”或“過(guò)度抽象”的生動(dòng)體現(xiàn)。
技術(shù)層面:Go的“解藥”在哪?
- 小接口哲學(xué): Go 鼓勵(lì)定義小而專注的接口,這使得組件之間的依賴更清晰、更松耦合。當(dāng)問(wèn)題出現(xiàn)時(shí),更容易定位到具體的接口實(shí)現(xiàn)層去修復(fù),而不是在外部層層包裝。
- 組合優(yōu)于繼承: Go 通過(guò)組合(struct embedding)而非繼承來(lái)實(shí)現(xiàn)代碼復(fù)用,避免了深度繼承帶來(lái)的復(fù)雜性和脆弱性,使得在“正確層級(jí)”修改代碼更易操作。
- 顯式錯(cuò)誤處理: if err != nil 的模式強(qiáng)制開(kāi)發(fā)者在調(diào)用點(diǎn)處理錯(cuò)誤,使得問(wèn)題更難被“隱藏”到上層去統(tǒng)一“包裝”處理,鼓勵(lì)在錯(cuò)誤發(fā)生的源頭附近解決或添加上下文。
根源三:依賴 (Dependencies) —— 看不見(jiàn)的“冰山”
圖片
這是Pike演講中著墨最多、也最為憂慮的一點(diǎn)。他用數(shù)據(jù)(NPM 包平均依賴 115 個(gè)其他包,每天 1/4 的依賴解析發(fā)生變化)和實(shí)例(Kubernetes 的復(fù)雜依賴圖)強(qiáng)調(diào):
- 現(xiàn)代軟件依賴數(shù)量驚人且變化極快。
- 我們幾乎不可能完全理解自己項(xiàng)目的所有直接和間接依賴。
- 依賴中隱藏著巨大的維護(hù)成本、Bug 和安全風(fēng)險(xiǎn)。
- 簡(jiǎn)單的 npm update 或 audit 無(wú)法解決根本問(wèn)題。
他強(qiáng)烈建議要理解依賴的成本,嚴(yán)格、定期地審視依賴樹(shù),并推薦了 deps.dev 這樣的工具。
HN 社區(qū)對(duì)此深有同感,紛紛吐槽“為了一個(gè)函數(shù)引入整個(gè)庫(kù)”、“脆弱的傳遞性依賴”、“供應(yīng)鏈安全”等問(wèn)題,并呼喚更好的依賴分析工具。
技術(shù)層面:Go的“解藥”在哪?
- Go Modules: 相比 NPM 等包管理器,Go Modules 提供了相對(duì)更好的依賴管理機(jī)制,包括語(yǔ)義化版本控制、go.sum 校驗(yàn)和、最小版本選擇 (MVS) 等,提高了依賴的可預(yù)測(cè)性和安全性,但也要注意Go module并非完美。
- 強(qiáng)大的標(biāo)準(zhǔn)庫(kù): 這是 Go 對(duì)抗依賴泛濫的最有力武器。很多功能可以直接使用標(biāo)準(zhǔn)庫(kù),避免引入外部依賴。
- 社區(qū)文化: Go 社區(qū)相對(duì)而言更推崇穩(wěn)定性和較少的依賴。引入一個(gè)大型框架或過(guò)多的外部庫(kù)在 Go 社區(qū)通常需要更充分的理由。
- 工具支持: Go 提供了 go mod graph, go mod why 等命令,可以幫助開(kāi)發(fā)者理解依賴關(guān)系。結(jié)合 deps.dev,可以在一定程度上實(shí)踐 Pike 的建議。
根源四:開(kāi)源模式 (Open Source Development) —— “大門(mén)敞開(kāi)” vs “嚴(yán)格把關(guān)”
圖片
Pike 對(duì)比了兩種開(kāi)源開(kāi)發(fā)模式:
- “真正的開(kāi)源方式” (The true open source way): 接受一切貢獻(xiàn) (Accept everything that comes)。他認(rèn)為這是膨脹和 Bug 的巨大來(lái)源。
- 更好的方式: 設(shè)立嚴(yán)格的代碼質(zhì)量、標(biāo)準(zhǔn)、評(píng)審、測(cè)試、貢獻(xiàn)者審查等“門(mén)檻”,對(duì)允許合入的內(nèi)容有標(biāo)準(zhǔn)。這種方式維護(hù)成本低得多。
他暗示 Go 項(xiàng)目本身更傾向于后者,強(qiáng)調(diào)“先做好再提交”(make it good before checking it in)??赡芎芏郍opher也感受到了這一點(diǎn),Go項(xiàng)目本身對(duì)代碼質(zhì)量的review非常嚴(yán)格,這一定程度上也“延緩”了一些新特性進(jìn)入Go的時(shí)間點(diǎn)。
HN 的討論中也涉及了類似 "Bazaar vs Cathedral" 的模式對(duì)比,但觀點(diǎn)更加復(fù)雜,認(rèn)為現(xiàn)實(shí)中的項(xiàng)目往往處于兩者之間的某個(gè)位置,并且“完全不接受外部貢獻(xiàn)”也并非良策。
技術(shù)層面:Go的“解藥”在哪?
- Go 自身的開(kāi)發(fā)模式: Go 語(yǔ)言本身(由 Google 主導(dǎo))的開(kāi)發(fā)流程相對(duì)嚴(yán)謹(jǐn),對(duì)代碼質(zhì)量和向后兼容性有較高要求,可以看作是“嚴(yán)格把關(guān)”模式的體現(xiàn)。
- 標(biāo)準(zhǔn)庫(kù)的設(shè)計(jì): Go 標(biāo)準(zhǔn)庫(kù)的設(shè)計(jì)精良、接口穩(wěn)定,為開(kāi)發(fā)者提供了一個(gè)高質(zhì)量的基礎(chǔ)平臺(tái),減少了對(duì)外部“隨意貢獻(xiàn)”的依賴。
- 社區(qū)項(xiàng)目實(shí)踐: 觀察 Go 社區(qū)一些知名的開(kāi)源項(xiàng)目,其貢獻(xiàn)流程和代碼標(biāo)準(zhǔn)通常也比較嚴(yán)格。
反思與現(xiàn)實(shí):Go 也非萬(wàn)能,“警惕與紀(jì)律”仍是關(guān)鍵
雖然 Go 的設(shè)計(jì)哲學(xué)和工具鏈在對(duì)抗軟件膨脹方面提供了許多“天然優(yōu)勢(shì)”和“解藥”,但我們必須清醒地認(rèn)識(shí)到,Go 語(yǔ)言本身并不能完全免疫膨脹。
正如 Pike 在其“建議”(Advice) 中反復(fù)強(qiáng)調(diào)的,以及 HN 討論中部分開(kāi)發(fā)者指出的,最終軟件的質(zhì)量很大程度上取決于**開(kāi)發(fā)者和團(tuán)隊(duì)的“警惕與紀(jì)律” (vigilance and discipline)**:
- 我們是否真正理解并避免了增加不相稱成本的特性?
- 我們是否努力在正確的層級(jí)解決問(wèn)題?
- 我們是否審慎地評(píng)估和管理了每一個(gè)依賴?
- 我們是否堅(jiān)持了高標(biāo)準(zhǔn)的開(kāi)發(fā)和評(píng)審流程?
如果缺乏這些,即使使用 Go,項(xiàng)目同樣可能變得臃腫、復(fù)雜和難以維護(hù)。同時(shí),HN 討論也提醒我們,軟件膨脹背后還有更深層次的組織、文化和經(jīng)濟(jì)因素,這些往往超出了單純的技術(shù)和開(kāi)發(fā)者紀(jì)律所能解決的范疇。
小結(jié):擁抱 Go 的簡(jiǎn)潔,但需務(wù)實(shí)前行
Rob Pike 的“抱怨”為我們敲響了警鐘,Hacker News 的熱議則展現(xiàn)了軟件膨脹問(wèn)題的復(fù)雜性和普遍性。它確實(shí)是我們?cè)诠こ虒?shí)踐中需要持續(xù)對(duì)抗的“熵增”現(xiàn)象。
Go 語(yǔ)言以其簡(jiǎn)潔、顯式、組合的設(shè)計(jì)哲學(xué),以及強(qiáng)大的標(biāo)準(zhǔn)庫(kù)和相對(duì)穩(wěn)健的依賴管理,在技術(shù)層面上,為我們提供了對(duì)抗膨脹的有力武器。理解并擁抱這些 Go 的“基因”,無(wú)疑能在一定程度上幫助我們構(gòu)建更健康、更可持續(xù)的軟件系統(tǒng)。
當(dāng)然,Pike 的觀點(diǎn)也并非金科玉律。有批評(píng)者指出,他的視角可能帶有一定的“NIH(非我發(fā)明)傾向”,并且存在兩個(gè)關(guān)鍵的“盲點(diǎn)”:
- 忽視了“不使用依賴”同樣是巨大的技術(shù)債。 每一行自寫(xiě)的代碼都需要永遠(yuǎn)維護(hù)。
- 現(xiàn)實(shí)中的選擇往往不是“使用依賴 vs 自己實(shí)現(xiàn)”,而是“使用依賴 vs 根本不做這個(gè)功能”。 面對(duì)復(fù)雜的合規(guī)要求(如 ADA、GDPR)、第三方集成或 FIPS 認(rèn)證等,從零開(kāi)始構(gòu)建的成本(可能需要數(shù)百人年)往往讓“自己實(shí)現(xiàn)”變得不切實(shí)際。為了讓產(chǎn)品能夠及時(shí)上線并滿足用戶(哪怕是 Pike 本人可能也在使用的“緩慢”網(wǎng)站)的需求,引入依賴和一定的“膨脹”有時(shí)是必要且務(wù)實(shí)的選擇。
注:“NIH(非我發(fā)明)傾向”是一種心理現(xiàn)象,指的是人們對(duì)他人提出的想法或創(chuàng)新持有偏見(jiàn),通常因?yàn)檫@些想法不是自己發(fā)明的。這種傾向使得人們傾向于低估或拒絕其他人的創(chuàng)意,盡管這些創(chuàng)意可能是有價(jià)值的。
這種批評(píng)也提醒了我們,雖然 Pike 對(duì)簡(jiǎn)潔和紀(jì)律的呼吁值得我們高度重視,但在真實(shí)的商業(yè)環(huán)境和復(fù)雜的工程約束下,我們必須做出務(wù)實(shí)的權(quán)衡。純粹的技術(shù)理想有時(shí)需要向現(xiàn)實(shí)妥協(xié)。
最終,我們每一位 Gopher 都需要在理解 Go 簡(jiǎn)潔之道的同時(shí),保持批判性思維和務(wù)實(shí)態(tài)度。 在日常的每一個(gè)決策中,審慎地權(quán)衡簡(jiǎn)單與復(fù)雜、理想與現(xiàn)實(shí)、引入依賴與自主掌控,才能在這場(chǎng)與“膨脹”的持久戰(zhàn)中,找到最適合我們項(xiàng)目和團(tuán)隊(duì)的平衡點(diǎn),交付真正有價(jià)值且可持續(xù)的軟件。
你如何看待 Rob Pike 對(duì)軟件膨脹的觀點(diǎn)?你認(rèn)為他的批評(píng)切中要害,還是忽視了現(xiàn)實(shí)的復(fù)雜性?歡迎在評(píng)論區(qū)分享你的思考與實(shí)踐!
參考資料
[1] Rob Pike - On Bloat: https://docs.google.com/presentation/d/e/2PACX-1vSmIbSwh1_DXKEMU5YKgYpt5_b4yfOfpfEOKS5_cvtLdiHsX6zt-gNeisamRuCtDtCb2SbTafTI8V47/pub?slide=id.p
[2] HN:On Bloat: https://news.ycombinator.com/item?id=43045713
[3] Pike is wrong on bloat: https://blog.habets.se/2025/02/Pike-is-wrong-on-bloat.html
[4] On Bloat: https://commandcenter.blogspot.com/2025/02/on-bloat-these-are-slides-from-talk-i.html