他写完代码我不用拉分支就能验收

不用再搭环境的轻松

老张第一次因为"搭环境"崩溃,是在一个周五下午。

那天,阿行辅助团队的一个工程师修了一个 bug——一个关于订单审批流程的偶发错误。代码已经提交,review 也过了。老张作为 TL,要做最后的验收:亲眼看看这个 bug 是不是真的修好了。

他打开终端,开始搭环境。

第一步,把分支拉到本地。git fetch、git checkout,等了几秒。

第二步,装依赖。他本地的依赖是半个月前的,pnpm install 跑了五分钟,中间还报了个 peer dependency 警告,他犹豫了一下要不要处理,最后决定忽略。

第三步,启动本地数据库。数据库起来了,但 migration 没跑——因为这个分支的改动包含一个新的 migration。他跑了一遍 migration,又遇到一个报错:本地数据库的某个表结构和代码预期不一致。他花了一刻钟才弄清楚,是一个月前的一个 migration 他本地没执行过。

第四步,造测试数据。他想复现那个 bug,但阿行用的那批测试数据在他本地根本没有。他得自己造——而且他甚至不太确定,到底要用什么样的数据才能触发那个 bug。

第五步,配环境变量。某个环境变量配错了,服务起不来。他翻了一圈配置文档才找对值。

两个小时后,老张终于把环境跑起来了。他点了几个按钮,确认 bug 确实修好了。

然后他关掉电脑,瘫在椅子上,有一种说不出的疲惫。

这两个小时里,没有一分钟是在"验收"

老张后来回忆这件事,最让他难受的不是"花了两小时"——虽然这确实很浪费时间。最让他难受的是一个他不愿承认的事实:

这两个小时里,他做的每一件事,没有一件是"验收"。

拉代码、装依赖、跑 migration、造数据、配环境变量——这些事和"这个 bug 修没修好"毫无关系。它们是纯粹的体力活,是"把环境跑起来"必须付出的代价。而真正的验收——"点几个按钮看看对不对"——只花了五分钟。

老张算了一笔账:如果每次验收都要两小时搭环境,而他一周要验收好几次……光搭环境就要吃掉他一整天。一整天里,他做的全是机械操作,没有一件事用到他作为 TL 的判断力。

而且更隐蔽的问题是:为了少搭几次环境,团队会不自觉地减少验收次数。 "算了,代码 review 过了,应该没问题,就不跑环境验了。"——这种心态会悄悄蔓延。于是验收变成了走过场,质量保障出现了裂缝。

老张意识到,这不是"效率低"的问题,是一个协作结构的问题。

一个被所有人忽视的问题

老张把这件事想了几天,慢慢看清了一个之前被所有人忽视的问题。

传统的开发流程里,所有关键的"工作状态"都留在开发者的电脑上——当前代码、本地数据库、配置文件、测试数据、"怎么复现这个 bug"的个人经验。这些状态是私有的、本地的、不可共享的。

这意味着什么?意味着当阿行说"我修好了"的时候,老张接手的不是一个"可以直接验收的现场",而是一段文字说明——"我在分支 X 上修了 Y,本地测试通过了"。老张要验证这段话,只能从头搭一遍环境。

阿行完成了他的工作,但他完成的本质是"代码 + 文字说明",不是一个"人可以直接接手的工作现场"。

老张把这个问题总结成三个"断点":

断点一:代码 review 和功能验收脱节。 代码能在 diff 里看到,但"跑起来是什么效果"藏在某个人的本地环境里。老张要么信阿行的描述,要么自己搭环境。

断点二:阿行完成 ≠ 人可以验收。 阿行说"修好了",但老张接手的第一件事不是"判断修没修好",而是"先花两小时搭环境"。判断被环境搭建挤掉了。

断点三:工作状态无法交接。 老张搭好的环境,换一个人来验收还得重新搭。所有状态都是一次性的、不可复用的。

老张意识到,只要这个现状不改变,无论阿行多强、review 多智能、自动化多严密——人接手的那一刻,永远要重新搭一遍环境。这是协作效率的真正天花板。

老张的"搬家"

老张想出来的办法,他管它叫"搬家"——把工作现场从"个人电脑"搬到"所有人都能进的地方"。

他设了两个共享的东西:

第一个,代码合并请求(MR)。 所有的代码变更、提交历史、review 记录,都放在 MR 上。它是"代码层面"的共享现场——任何人都能看,不依赖任何一台个人电脑。

第二个,验收环境。 这是老张这次"搬家"的核心。他让阿行在需要人工验收的 MR 上,自动创建一个运行着当前代码的独立环境——使用脱敏的测试数据、临时创建的数据库 schema、受权限控制的访问入口。不是每个 MR 都建——只有需要远程验收的才触发,合并后自动销毁。

老张后来在和同行交流时发现,这个做法在业界已经有名字了——叫 Preview Environment(预览环境):每个 PR 自动创建一个临时的、隔离的运行环境,reviewer 直接点进去看效果。老张的方案和这个思路一致,只是他是让阿行帮他一步步搭起来的。

这个验收环境,不是老张自己电脑上的,也不是阿行自己电脑上的。它在云上,是一个脱离任何个人电脑的共享现场。

老张后来给团队定了一条规矩,这条规矩他反复强调:

阿行完成任务后,交付的不只是"代码写完了",而是一个人可以直接进去验收的现场——代码已经在跑,数据已经准备好,入口一点就能进。

这意味着,老张验收时不需要搭任何环境。他打开 MR 看代码,点链接进验收环境试功能。判断和环境搭建,终于解耦了。

但"环境准备好了"这件事,怎么证明?

老张很快发现一个新的坑。

阿行说"环境准备好了,你可以来验收了"。老张怎么知道这是真的?

最容易被误解的是:把"构建跑完了""部署完成了"等同于"环境准备好了"。老张一开始也这么以为——直到有一次,他点进验收环境,发现跑的代码版本和 MR 上的对不上。阿行部署的是上一个版本,这个 MR 的改动根本没进去。

老张那次验收了个寂寞。

从那以后,他定了一套严格的"准备好"标准。环境要算"准备好",必须同时满足:

最后一条最关键:代码、环境、数据、入口、验收预期,必须全部指向同一个版本。任何一环对不上,整个"准备好"状态就作废——因为你不知道你验收的,到底是不是你以为的那个版本。

老张说,这套标准看起来繁琐,但它的意义在于:把"准备好了"从一个模糊的主观判断,变成了一个机器能验证的客观清单。 阿行不能凭感觉说"好了",它必须让每一项都通过检查。

为什么这件事是整套协作的"地基"

老张后来把这套协作方式想透了之后,回过头看,发现"共享环境"这件事的地位很特殊。

前面几篇讲的所有东西——阿行接手工作、AI review 代码、三角结构管控——本质上都是在解决信息怎么流动的问题。

但信息最终要落到物理层面才能被验证。一段代码对不对,要跑起来才知道;一个修复有没有效,要在真实环境里复现才作数。而这些"跑起来、复现",全都需要一个真实运行的环境。

如果这个环境不存在,或者只存在于某个人的电脑里,那前面所有的信息层优化,都会在"最后一公里"失效。

老张说,共享环境就是把整套协作方式从"信息层"锚定到"物理层"的那根钉子。它保证了:无论信息怎么流转、无论阿行和人怎么异步协作,最终都有一个所有人都够得着、状态明确、可独立验证的现场。

没有它,协作就退化成了"阿行发一段文字,老张自己脑补现场"。

老张的验收,变了

老张现在的验收流程,和那个周五下午已经完全不同了。

他打开 MR,扫一眼代码。然后点 MR 上的"查看应用"按钮——直接进入阿行准备好的验收环境。环境里跑的就是这个 MR 的代码,测试数据已经备好,账号已经登录好。老张要做的,只有一件事:

判断这个功能跑起来的效果,符不符合业务预期。

没有了拉代码,没有了装依赖,没有了跑 migration,没有了造数据,没有了配环境变量。两个小时,压缩成了五分钟。

老张说,他现在验收的时候,脑子里只剩一个问题——"这玩意儿对不对"。而不是"我什么时候才能把这玩意儿跑起来看看它对不对"。

但他心里还压着最后一个、也是最容易被低估的问题。

环境准备好了,他点进去了,功能跑起来了。但是——"跑起来了"就等于"对"吗?

老张想起了另一次验收。那次,所有东西都准备好了,他点进去试了一遍,功能正常,绿灯。他放心地合入了。结果上线之后,才发现有一个边界场景——他验收时根本没测到。

那次让他意识到一个反直觉的事实:"完成了"和"正确了",是两件完全不同的事。 而大多数人都把它们混为一谈了。

怎么保证"跑通了"就是"对的"?怎么防止一次"看起来完成了"的验收,漏掉一个真实的回归?

这是第 6 篇的故事。

一句话结论

共享环境把工作现场从个人电脑搬到云端,让人验收时不用再花两小时搭环境——代码、运行环境、数据、入口全部备好,人只做最后的业务判断;严格的"准备好"标准保证跑的就是要验收的版本。

下一篇 →绿灯亮了,但老张想起了那次事故