最好的 Go 框架就是不用框架?
撰寫本文時,我已經(jīng)領(lǐng)導(dǎo) Go 團(tuán)隊好多年了。我從初學(xué)者那里聽到的最常見的問題是:我應(yīng)該使用什么框架?
在使用 Go 的過程中最糟糕的事情之一就是遵循其它編程語言的方法。其它語言已經(jīng)建立了“默認(rèn)”框架:Java 的默認(rèn)框架是 Spring,Python 的默認(rèn)框架是 Django 和 Flask,Ruby 的默認(rèn)框架是 Rails,C# 的默認(rèn)框架是 ASP.NET,Node 的默認(rèn)框架是 Express,PHP 的默認(rèn)框架是 Symfony 和 Laravel。而 Go 不同:沒有默認(rèn)框架。
更有趣的是,許多人建議你根本不應(yīng)該(在 Go 中)使用框架。他們瘋了嗎?
Go 框架是存在的,但沒有一個 Go 框架提供項其它語言框架那樣的功能集。這點短期內(nèi)不會改變。你可能認(rèn)為這是因為 Go 生態(tài)系統(tǒng)比較“年輕”。但是還有一個更重要的因素。Go 是圍繞 Unix 哲學(xué)構(gòu)建的:
一個程序只做一件事并把它做好。
程序間協(xié)同工作。
編寫程序來處理文本流,因為這是一個通用接口。
這個理念來自 B 編程語言(C 語言的前身)的設(shè)計者肯·湯普森(Ken Thompson),他也是 Go 語言的設(shè)計者。
在實踐中,Unix 哲學(xué)傾向于構(gòu)建小而美的軟件,而不是大而全的軟件。你可以在你的終端中看到這些例子。例如:cat example.txt | sort | uniq 。cat 從文件中讀取文本,sort 對行進(jìn)行排序,uniq 刪除重復(fù)行。所有命令都是獨立的且只做一件事。這直接來自 Unix 哲學(xué)。得益于這樣的設(shè)計,你可以獨立開發(fā)比較小的自治命令。
在 Go 中,Unix 哲學(xué)在標(biāo)準(zhǔn)庫中隨處可見。最好的例子是應(yīng)用最廣泛的接口:io.Reader 和io.Writer 。最好的庫都遵循這種哲學(xué)。
框架的設(shè)計違背這種哲學(xué)理念。通常,它們試圖在一個框架內(nèi)涵蓋所有可能的用例。它們不是為了與其它工具一起使用而設(shè)計的,而且通常無法復(fù)用。這意味著不可能將開發(fā)成果轉(zhuǎn)移到其它不兼容的框架。如果框架的采用率很低(或者就是死了),那所有的努力都白費了。
每個技術(shù)決策都有權(quán)衡,你的選擇要對你和你的項目更有意義。
當(dāng)你在從事一個短期項目(比如用時不到一周且用完即扔的概念驗證項目)時,有些方案是有意義的。在這種情況下,最關(guān)鍵的因素是你能多快地完成它。但是如果你在從事一個持續(xù)很長時間的項目,并且你要與多人一起協(xié)作,那么這個決定的影響是巨大的。
對于大多數(shù)項目,最重要的參數(shù)是:
你能以多快的速度啟動項目
從長遠(yuǎn)來看,你能以多快的速度開發(fā)項目
對于未來的變化,項目的靈活度(這與前兩點緊密相關(guān))。
讓我們開始評估我們的決定。
框架最大的好處之一就是節(jié)省時間。運行一個命令就可以得到一個功能齊全的項目??蚣芡ǔL峁┮粋€固定結(jié)構(gòu)的項目,而且如果你不知道如何做,它會有很大幫助。但與大多數(shù)其他技術(shù)決策一樣,它不是沒有代價的。
隨著時間的推移,當(dāng)項目增長時,你會很快觸及框架在約定和限制方面的墻壁??蚣茏髡叩男枨蟾愕男枨罂赡苡兴煌???蚣軇?chuàng)建者采取的決策可能適用于簡單的 CRUD 應(yīng)用程序,但無法處理更復(fù)雜的場景。如果繼續(xù)使用,很容易就為了克服一個框架限制而迅速失去在項目啟動上節(jié)省的所有時間。隨著時間的推移,這可能會導(dǎo)致團(tuán)隊遇到很多挫折。
幾年前,我在一家使用 Go 框架(我會略過框架名稱)的初創(chuàng)公司工作。這家公司正在成長并創(chuàng)建新的服務(wù)。隨著時間的推移,當(dāng)我們想要支持的復(fù)雜用例越多時,我們就感到越痛苦。這個框架也是嚴(yán)重 Bugs 的來源。不幸的是,擺脫這個框架并不容易。
有一次,一些框架組件變得無法維護(hù),與生態(tài)系統(tǒng)的其它部分不可兼容。我們被迫擺脫這個框架,而這個框架已經(jīng)與整個系統(tǒng)緊密耦合。將其從數(shù)十個服務(wù)中移除是一個不小的任務(wù),這需要一個跨團(tuán)隊的計劃、需要多人數(shù)月的時間和努力,才能擺脫這個框架。即使這個項目最后成功了,我也不認(rèn)為整個事情是成功的。如果有人更早做出不同的決定,所有花費的時間可以被利用得更好。整個項目都不是必要的。許多公司對開發(fā)團(tuán)隊缺乏信任也就并不令人奇怪了。
這是一個很好的例子,表明了一個小小的決定會在數(shù)年后變成一個代價高昂的需要“救援”的項目。

衡量項目的可維護(hù)性是一個有爭議的話題——很難比較兩個項目的可維護(hù)性。有些人說框架很棒,他們沒有感到使用框架的痛苦。對其他人來說,框架可能是長期以來最大的噩夢。有些項目比其他項目更具挑戰(zhàn)性,許多人認(rèn)為與框架較勁只是工作的一部分。這就是為什么很難客觀地衡量框架對項目可維護(hù)性的影響。
幸運的是,我們可以用一點科學(xué)知識來理解它。基于科學(xué)研究的《Accelerate:The Science of Lean Software and DevOps》一書,聚焦于找出表現(xiàn)最好和表現(xiàn)最差的團(tuán)隊的特點。對我們來說重要的是,良好性能的最重要的一個因素就是松耦合架構(gòu)。
我領(lǐng)導(dǎo)的團(tuán)隊經(jīng)常問我,“如何知道我們的架構(gòu)是松耦合的”,最簡單的方法之一是確保應(yīng)用程序的部件可以輕易替換或刪除。如果你的應(yīng)用程序的部件很難刪除,那么你的應(yīng)用程序就是緊耦合的。這樣的緊耦合會導(dǎo)致牽一發(fā)而動全身,引發(fā)多米諾效應(yīng)。
為什么松耦合架構(gòu)如此重要?需要承認(rèn),我們都是人,即使經(jīng)過了最好的調(diào)研,我們也會犯錯。當(dāng)你選擇了錯誤的庫或框架,應(yīng)該很容易替換而不需要重寫整個項目。如果我們想要節(jié)省時間,我們應(yīng)該考慮從長期來看有什么幫助,而不僅僅是在項目開始時。
請考慮一個場景,當(dāng)你想要完全刪除一個框架時,需要重寫大量代碼嗎?它可以在多個服務(wù)上獨立運行嗎?如果不行,那么你需要花些精力將框架和核心邏輯分開。但是,這會犧牲框架一開始時帶來的“省時”。
你可能會覺得,在沒有框架的情況下構(gòu)建服務(wù)需要很長時間,尤其是如果你之前使用其它編程語言。我理解這一點,幾年前當(dāng)我開始用 Go 寫程序時,我也有相同的感受。但是,不用框架并不意味著你自己需要構(gòu)建一切東西,有許多經(jīng)過驗證的庫會提供你需要的功能。
這意味著,你需要在調(diào)研上多花一點兒精力。如果你正在閱讀本文,那你就已經(jīng)在調(diào)研了!幾個小時的調(diào)研時間在整個項目的生命周期中幾乎不值一提。你這樣做所帶來的靈活性,很快會將你調(diào)研所花的時間“掙”回來。
如果你決定不使用框架,應(yīng)該怎么辦?一開始最大的障礙可能是如何構(gòu)建一個服務(wù)。最簡單的方法是一開始將所有東西放到一個文件中。你可以簡單地開始,推遲一些決定,然后隨著時間的推移演化你的項目。
如果有示例項目可以作為參考,那么這會很有幫助。你可以看看我在 GoRemoteFest – github.com/roblaszczak/goremotefest-livecoding 上的演講“讓我們用 Watermill 在 15 分鐘內(nèi)構(gòu)建一個事件驅(qū)動應(yīng)用程序”所用的項目。這個示例項目只需要兩個外部庫就可以運行了。
請隨意 copy 這個代碼庫并根據(jù)你的需要調(diào)整,我確信這個示例不會有你項目所需的全部的庫。我們發(fā)布了一篇文章介紹可以用來構(gòu)建 Go 服務(wù)的 Go 庫清單。這些庫我們已經(jīng)用了幾年了,還解釋了我們?yōu)槭裁词褂眠@些庫,以及如何識別類似的庫是好還是壞。
文章鏈接:
https://threedots.tech/post/list-of-recommended-libraries/
當(dāng)你的項目變得越來越復(fù)雜,而且你已經(jīng)知道了你的庫是如何協(xié)同工作的,那么你就可以開始重構(gòu)它了。最后,你可能不需要那些看起來很關(guān)鍵的框架功能。得益于此,你可以得到一個更簡單的項目并進(jìn)行更少的調(diào)研。
決定如何構(gòu)建服務(wù)不是你應(yīng)該走捷徑的地方。從長遠(yuǎn)來看,做出錯誤的決定會對你的時間產(chǎn)生非常負(fù)面的影響。它會對團(tuán)隊的速度產(chǎn)生負(fù)面影響,更重要的是會影響士氣。
在做出錯誤的決定后,你很快就會陷入沉沒成本謬論的陷阱。與其成為解決自己制造的問題的英雄,我們應(yīng)該避免制造這些問題。
Robert Laszczak 是 SlashID 的首席工程師、三點實驗室(Three Dots Labs)的聯(lián)合創(chuàng)始人、Watermill 庫的創(chuàng)建者。
原文鏈接:
The Best Go framework: no framework?(https://threedots.tech/post/best-go-framework/)
推薦閱讀
