我第一次负责重大版本发布是v2.3.0,那天晚上通宵,不是因为代码写得很烂,而是因为发布前我花了两个小时改配置,六个小时等人审批,最后发现客服部门根本不知道新版首页改版了。凌晨三点,线上报错,我靠远程给数据库执行了一条修复SQL,花了42分钟才恢复。当时CTO站在我背后说了一句:发布不是技术活,是人性活。那时候我只觉得他在安慰我,后来才慢慢体会到,这句话比什么CI/CD都重要。
版本号这个东西,看着很理性,其实全是玄学。语义化版本说得很清楚,主版本号代表不向后兼容的修改,但现实里人们从来不会这么看。我待过一个项目,从2.9.0直接跳到了5.0.0,就因为产品经理觉得数字4不吉利。也有人喜欢在minor版本里偷偷改接口参数,然后说这是补充说明,不算破坏性变更。版本号本质上不是说逻辑,而是说故事——你在告诉使用你软件的人:“你放心,这个版本最多就是小打小闹”或者“你赶紧去修你的兼容层”。可是大多数团队根本就没想清楚自己要讲哪种故事,自然每次发版都像掷骰子。
我观察过两类极端的发布策略:一类是Chrome那种固定短周期,四星期就发一次,代码没做完也得塞进去藏在一个特性开关后面;另一类是很多传统企业软件,一年憋一个大版本,反正用户已经习惯了等待。有意思的是,短周期看似激进,但Chrome每次发布前都有数千个自动化测试在跑,还要配合灰度放量,实际上比那些定期发布更保守。亚马逊号称每天可以发布上千次,可他们的内部代码审查和权限控制严苛到你改一行注释都需要领导批准。激进发布从来就不是一种文化,而是高强度工程化之后的结果。想学到快速发布,先要让自己愿意接受“发布是一个随时可以重来的演练”这个事实。
我们在公司做自动化发布流水线的时候,曾经以为只要按钮一按,世界就清净了。第一个版本确实跑得顺利,5分钟完成了构建、测试、部署。但等我们真的按下那个一键发布,整个团队却花了整整两天讨论回滚策略。为什么?因为大家突然发现,所谓回滚不只是把代码切到上一个版本,还得想清楚数据库迁移怎么降级、缓存里的旧数据怎么处理、已经开始跑的用户请求要不要掐断。自动化工具帮我们把手脚捆住,但没有帮我们长出脑子。后来我们决定把版本号改成时间戳加流水号,每次发版前所有人都知道“今天上线的就是今天做出来的东西,错了就跑这条路”。这个改动让我觉得团队吵架次数少了很多,特别是没有人在群里问“现在跑的是哪个版本”了。作为一个相信直觉的人,我判断沟通成本至少降了三成,虽然这个数字没有精确统计。
我越来越觉得,每一次发布,其实都是在给用户发送一句“我们变了”。这句话传递得好,老用户会觉得你进步了;传递得不好,再大的新功能也会被骂。就像一个驾驶技术很好的人,最大的危险不是第一次启动,而是变道时没看后视镜。版本发布也是一样,它考验的从来不是你能不能把代码放上去,而是你有没有办法让上下游所有人对“什么时候变、变成什么样、变多长时间”达成一致。假如你问团队“这次发布出问题,谁第一个醒来看告警”,大家回答的是不同的人名,那不管换多少流程工具和容器编排,凌晨三点的会议室里,永远会有一群穿着睡衣的人在想这个版本到底是怎么混进来的。版本发布不是期末考,它更像是出门前照镜子,你可以浓妆艳抹,也可以直接素颜,但你至少得知道自己今天的脸长什么样。