Go mod 七宗罪,你知道几宗?

开发 开发工具
Go list,Go test,Go build,所有命令都会去拉取依赖,有些库是用被墙的服务做了重定向,只是执行一下 go test,然后就被卡一年是家常便饭。

 [[384341]]

本文转载自微信公众号「码农桃花源」,作者曹春晖。转载本文请联系码农桃花源公众号。    

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/

 

责任编辑:武晓燕 来源: 码农桃花源
相关推荐

2023-05-08 10:54:39

IT管理CIO

2011-02-21 09:04:25

2018-02-05 23:14:35

光纤网络光纤施工

2014-01-13 09:35:13

创业企业

2013-01-17 17:14:52

Objective-C

2015-09-15 13:22:08

数据分析七宗罪

2013-05-10 10:49:53

2010-08-18 10:05:27

IE7IE6

2017-08-02 16:24:04

2017-01-09 15:25:49

物联网策略设计

2011-02-23 10:51:36

Chrome

2015-09-06 11:25:57

七宗罪失败案例

2012-04-04 22:15:19

移动游戏

2014-07-14 17:29:06

运营商定制手机

2015-07-16 09:14:50

数据中心数据中心效率

2023-10-17 20:28:13

软件开发代码

2021-03-03 14:08:48

自动化高管IT投资

2019-04-15 09:00:00

SQLOracle数据库

2016-12-08 13:12:36

数据中心绿色认证

2012-09-07 14:41:26

点赞
收藏

51CTO技术栈公众号