夜色中被灯光点亮的悬索桥,桥身横跨水面连接两岸

Go 的一个好设计,顺手带来的麻烦

Go 有个被大家夸的设计:导入路径就是代码的获取地址。你写 import "github.com/xxx/yyy",Go 自己就知道去哪儿拉代码,不需要中心化的包管理仓库,报 bug 也能顺着路径找到源头。代价是:你的代码被托管商绑定了。哪天从 GitHub 迁到 GitLab,所有引用过你库的项目都得改 import 路径——改的还不是自己的代码。

这不是理论问题,是真花过钱的

作者 Iain Cambridge 在 9 月 27 日的文章里举了一个真实案例:一家公司同时用着 GitLab、GitHub 和 Azure DevOps 三套托管。原因很实际——改代码位置的工作量太大,团队「没时间」,维持多平台并存反而更省事,结果是三份托管费一起付。他后来做的 Boneclone,就是为了在多平台之间同步骨架代码。

解法:用一个自己的域名当门牌

他的主张是:每个用 Go 做商业开发的团队,都该给内部库挂一个自定义域名,也就是 go.iain.rocks、go.uber.org、go.mongodb.org 这种做法。使用者看到的 import 路径永远是这个名字,名字背后指向哪里,由你自己决定:今天指 GitHub,明天指 GitLab,对方的安装命令一个字都不用改。

实现也不复杂。以他给的配置为例,nginx 上给 go.iain.rocks 开一个站点:如果请求参数里没有 go-get=1(说明是人在浏览器里看),就 301 跳转到 GitHub 页面;如果带了这个参数(说明是 Go 工具在探测),就返回站点根目录下的 index.html。这个 html 不需要展示内容,只要两行 meta:go-import 告诉 Go 工具「这个路径对应哪个 git 仓库」,go-source 给出代码浏览页的地址模板,方便工具生成跳转链接。他把自己在用的 nginx 配置和 index.html 都贴在文里,可以照抄。

对做企业数字化的实际启发

第一,域名是最便宜的抽象层。一个自定义域名,换来的是「换供应商不用通知任何人」。这套思路可以再推一步:附件地址、图片地址、接口地址,凡是会出现在客户资料或代码里的 URL,都值得先挂在自己的域名下再转发出去,而不是直接写供应商的地址。

第二,把「可迁移」写进交付标准。给客户的系统,如果内部地址都指向客户自己的域名、数据也在自己手里,后面的续费与合作才有底气。反过来,把关键地址直接绑在某个平台上,等于把议价权交出去。

第三,对小团队来说这条建议的成本收益比很直接:配置一次,之后每一次「要不要换」的讨论都不必再评估一次大改。锁定的代价往往不是钱,而是没人愿意碰的那次迁移。