Go mod 七宗罪,你知道幾宗?
本文轉載自微信公眾號「碼農桃花源」,作者曹春暉。轉載本文請聯系碼農桃花源公眾號。
go mod 是 rsc 主導設計的 Go 版本管理工具,借鑒了 Google 內部的高大上版本管理方式,摒棄了開源社區的版本管理成功經驗,借助 MVS 算法,希望能夠走出一條不一樣的路,然而從發布以來給廣大 Gopher 帶來了各種各樣的麻煩。本文簡單列舉一部分罪狀,Google 的并不一定總是世界的。
當然,隨著 Go 1.16 的發布,其中有些罪證可能已經不成立了,讀者可以自行甄別。
Go 命令的副作用
Go list,Go test,Go build,所有命令都會去拉取依賴,有些庫是用被墻的服務做了重定向,只是執行一下 go test,然后就被卡一年是家常便飯。
按照 "By design" 的說法,Google 內部的依賴庫版本都會盡量使用能夠兼容的最新版本。對于墻內的我們來說,我不管執行什么 Go 命令怎么都卡。逐漸患上 go test PTSD。
解法:配置 GOPROXY 代理,雖然拉取依賴還是慢。
形同虛設的 semver 規范
社區里不遵守 semver 規范的庫很多,有的開源庫在 1.7.4 ~ 1.7.5 中進行了 breaking change,而按照 semver 的定義,這是不應該發生的。go mod 過度高估了開源社區的節操。
一開始,我們以為這只是社區的節操問題,直到我們碰到了 gRPC。
好樣的哦,Google 工程師。
無法應對刪庫
leftpad 悲劇重演
js 社區使用集中式的 npm 來管理依賴,在幾年前發生過一次因為作者刪庫,導致幾乎所有互聯網巨頭的前端項目全部 build 失敗的悲劇。同時 js 社區也進行了一些反思 how one programmer broke the internet[1],have we forgotten how to program[2]。
npm 好歹還是集中式的版本管理方式,Go 號稱分布式,但大多 Go 的依賴庫都是存在 Github 上,如果 Github 上的原作者刪除了該庫,那么也會導致大多數的依賴用戶 build 失敗。
即使看起來我們可以靠 go.mod 和 go.sum 來實現 reproducible build,實際的情況是,像 k8s 這樣的項目,依然會把龐大的依賴庫放在自己 repo 的 vendor 里。
在筆者從 dd 離職時,也曾經不小心刪除過一個認為應該沒有人再依賴的個人庫,當時給前同事們也造成了一些麻煩。
Github release/tag 水土不服
在 Github 上發布 lib 的 release,或者給某個 commit 打 tag 之后,我們依然可以對這些 tag 和 release 進行編輯:
我們經常看到,有些庫的作者在發布一個 release 之后,又刪除了這個 release,或對這個 release 進行了編輯。對于用戶來說,這樣就會依賴一個已經“消失”了的版本,在不存儲 vendor 的情況下,reproducible build 淪為笑談。
goproxy 的實現并不統一
不知道是否是因為 goproxy 并無規范,在使用不同的代理幫助我們加速下載依賴時,會出現各種不同的錯誤。
例如作者 A 開發的 goproxy,在某個庫不存在時,會返回 404。而作者 B 開發的 goproxy,在某個庫不存在時,會返回 500。著實令人困惑。
而 goproxy 本身的實現基本都是惰性下載,所以新發布的庫,我們要走 goproxy 來測試時,就需要手動 go get 觸發。而大多 goproxy 的實現并沒有查詢功能,goproxy 服務內部到底什么時候同步好了,可以 go get 了,還是 go get 的過程中發生失敗了。作為用戶是不可查的。
go get 到的 lib 版本在 go build 時被修改
在 go get 時,可以 go get lib@ver 來獲取指定版本的依賴,但是在 go build 時可能發現又被修改成了別的版本(比如被升級了),非常反直覺。
我們想要鎖定具體的版本,只能使用 replace。
版本信息擴散
由于 go mod 的設計,版本信息被包含在了 import 路徑中。當依賴庫從 v1 升級至 v2 時,幾乎一定意味著我們代碼中大量的 import 路徑需要修改。
修改不兼容的 api 就挺累的了。
go.sum 合并沖突
因為上面講到的一系列問題,go.sum 在多人維護的大項目上,經常會發生變動,也就經常會有沖突。對于中心化版本管理系統來說,這個問題根本就不存在。對于 go mod 來說,go.sum 合并本來是個純追加邏輯。
但這些沖突還是會浪費我們的時間。
[1]how one programmer broke the internet: https://qz.com/646467/how-one-programmer-broke-the-internet-by-deleting-a-tiny-piece-of-code/
[2]have we forgotten how to program: https://www.davidhaney.io/npm-left-pad-have-we-forgotten-how-to-program/