本文转载自微信公众号《码农的桃花源》,作者曹春晖。转载本文请联系码农桃花源公众号。gomod是rsc设计的Go版本管理工具。它借鉴了谷歌内部的版本管理方式,摒弃了开源社区版本管理的成功经验。借助MVS算法,它希望走一条不一样的路。然而,自发布以来,却给广大地鼠带来了种种困扰。本文只是简单列举了其中的一些罪行。谷歌并不总是世界的。当然,随着Go1.16的发布,部分罪证可能不再成立,读者可以自行辨别。Go命令的副作用Golist,Gotest,Gobuild,所有命令都会拉依赖,一些库被屏蔽服务重定向,执行gotest就可以了,然后卡一年是家常便饭。根据“Bydesign”,谷歌内部依赖库版本会尽量使用兼容的最新版本。对于墙内的我们来说,无论我执行什么Go命令,我都会卡住。逐渐开发去测试PTSD。解决方法:配置GOPROXY代理,虽然拉取依赖还是很慢。semver规范社区中有许多不符合semver规范的库。一些开源库在1.7.4~1.7.5中有一个突破性的变化。根据semver的定义,这不应该发生。gomod大大高估了开源社区的完整性。起初,我们认为这只是一个社区道德问题,直到我们遇到了gRPC。干得好,谷歌工程师。无法处理库删除leftpad悲剧重演。js社区使用集中式npm来管理依赖项。几年前,曾发生过因作者删库导致几乎所有互联网巨头的前端项目都无法搭建的悲剧。同时,js社区也对一位程序员如何破网[1],我们是否忘记了如何编程[2]提出了一些反思。npm仍然是一种集中式的版本管理方式。Go号称是分布式的,但是Go的大部分依赖库都存放在Github上。如果Github上原作者删库,也会导致大部分依赖用户无法构建。尽管看起来我们可以依靠go.mod和go.sum来实现可重现的构建,但实际情况是像k8s这样的项目仍然会对他们的repo的供应商产生巨大的依赖。笔者在dd离职时,还不小心删除了一个不应该依赖的个人库,给之前的同事造成了一定的困扰。Github发布/标签是不可接受的。在Github上发布了lib的release,或者给commit打了标签之后,我们仍然可以编辑这些标签和release:我们经常看到一些库的作者发布了一个release之后,他们把这个release删除了或者编辑了。对于用户来说,这将取决于一个已经“消失”的版本。如果不存储供应商,可重现的构建就成了笑话。goproxy的实现并不统一。不知道是不是因为goproxy没有规范。在使用不同的代理帮助我们加快下载依赖时,会出现各种错误。比如作者A开发的goproxy,当某个库不存在时,会返回404。作者B开发的goproxy,当某个库不存在时,会返回500。真的很混乱。goproxy本身的实现基本是懒下载,所以当我们想使用goproxy来测试新发布的库时,需要手动goget来触发。然而,大多数goproxy实现没有查询功能。goproxy服务什么时候内部同步,可以goget,或者goget过程中失败。它作为用户不可用。goget获取的lib版本在gobuild时被修改。goget时可以使用gogetlib@ver获取指定版本的依赖,但是在gobuild时可能会发现修改为其他版本(比如升级了)。),这是非常违反直觉的。我们想锁定一个特定的版本,只能使用replace。版本信息扩散由于gomod的设计,导入路径中包含了版本信息。当依赖库从v1升级到v2时,几乎可以肯定意味着我们代码中的大量导入路径需要修改。修改不兼容的api很累。go.summergeconflicts由于上述一系列问题,go.sum在多人维护的大型项目上经常发生变更,经常会出现冲突。对于集中式的版本管理系统,这个问题是完全不存在的。对于gomod来说,go.summerge本来就是纯append逻辑。但是这些冲突仍然在浪费我们的时间。[1]一个程序员如何破坏互联网:https://qz.com/646467/how-one-programmer-broke-the-internet-by-deleting-a-tiny-piece-of-code/[2]have我们忘记了如何编程:https://www.davidhaney.io/npm-left-pad-have-we-forgotten-how-to-program/
