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