本报记者 张明 2025年1月15日
在软件开发领域,“Bug修得干净”通常是对程序员工作的高度肯定。然而,近日某互联网公司却发生了一件令人哭笑不得的事——一名程序员因将一个隐藏Bug修复得太过彻底,导致测试组成员在回归测试时,误以为该模块的现状就是原始设计,从而未对相关功能进行任何质疑,险些让另一个潜在问题“蒙混过关”。
“我改完代码,测试组说‘没问题’”
事件的主角是该公司的后端开发工程师李彦。据李彦介绍,他所负责的“用户积分引擎”模块存在一个历史遗留问题:积分累积规则中有一个边界条件处理错误,导致在特定场景下用户积分会出现小数点后两位的偏差。这个Bug已经存在近两个版本,虽然影响范围极小,但每次测试都会因为“不稳定”而被标记为低优先级。
“我实在受不了了,花了整整一天时间,从底层逻辑到数据结构翻了个底朝天,终于定位到了问题。”李彦回忆道。他没有简单修补边界条件,而是对涉及积分计算的核心函数进行了重构,并将所有相关单元测试覆盖率提升到95%以上。修复完成后,他自己模拟了上百种入参组合,确认无误后才提交了代码。
按照流程,测试组需要对本次迭代的“积分引擎”模块进行回归测试。测试工程师张薇负责这部分工作。她在执行测试用例时发现:以往那些“偶尔会冒出来”的积分异常统统消失了,所有数值计算精确无误,甚至之前在极限压力测试中偶尔出现的性能抖动也不复存在。
“我当时的第一反应是:这个模块是不是之前就已经完美了?只是我们测试环境数据有问题?”张薇在事后复盘时坦言。她以为李彦做的只是无关紧要的“代码优化”,而模块的功能表现本来就是“笔直且稳定”的。于是,她在测试报告中对“积分引擎”模块的评价写下了“功能正常,与需求文档一致”的结论。
一场会议揭开的误会
真正让事件浮出水面的是一次产品需求评审会。会上,产品经理提出了一项针对积分规则的新改动,并引用了原有的需求文档。李彦当场指出:“那个边界条件我修过了,现在行为与文档描述不完全一致,但更符合业务直觉。”此话一出,全场安静。
张薇脸色微变:“等等,你修了Bug?我以为那部分功能本来就是那样运行的。” 测试组长立刻调出两周前的测试记录,发现张薇确实没有标记任何缺陷或异常。而李彦提交的代码变更记录显示,他修改了32个文件,删除了142行冗余代码,新增了89行逻辑。
测试组长刘栋哭笑不得:“小李,你修Bug是好事,但你得在代码注释和提测备注里写清楚啊。我们把‘修复后’当成了‘原始状态’,这要是后面有个依赖这个旧Bug逻辑的模块上线,系统就得崩。”
工程师的“完美主义”与测试的“惯性思维”
此事在内部技术分享会上被当作经典案例讨论。有资深工程师指出,这暴露了开发与测试之间信息同步的典型痛点:开发人员倾向于“默默把事做到极致”,认为自己修复了Bug、提升了代码质量,测试组自然能通过行为变化发现差异;而测试人员在迭代频繁、需求变更多的环境下,容易形成“惯性思维”——如果前一个版本有已知Bug,本版本如果Bug消失,他们第一时间不会认为是开发修复了,反而可能怀疑自己的测试环境出了问题,或者需求本身发生了变化。
“我承认我犯了一个傲慢的错误——我以为好的代码自己会说话。”李彦在复盘笔记中写道,“但其实代码不会说话,文档和沟通才会。我应该主动在提测邮件里标注‘此处有重大Bug修复,测试用例需关注边界场景’。”
行业反思:如何避免“修复性沉默”
业内专家指出,这种“修复性沉默”现象并不罕见。许多经验丰富的程序员在修复Bug时,往往会顺手重构代码,让整个模块“脱胎换骨”。然而,如果这种改变没有被清晰地传达给测试团队,就可能引发上述尴尬。更严重的是,如果测试组基于“新状态”去验证后续需求,而后续需求却与旧逻辑兼容,问题会演变成上线事故。
目前,该公司技术部已修订了提测规范:所有涉及功能逻辑变更的Bug修复,必须在提测单中勾选“影响范围”并附上修改说明;测试组则针对回归测试增加了一项“历史缺陷回归确认”环节——即针对上一个版本中已知的、本次却未复现的缺陷,需与开发确认是否已经被主动修复。
李彦最后对记者表示,这次事件让他明白了一个道理:“代码可以写得完美无瑕,但团队协作不能‘完美地沉默’。” 而测试组的张薇则自嘲道:“以后看到完美得不像话的功能,我一定先问一句:这玩意儿原来就这样,还是被‘神之手’摸过了?”
截至发稿,该公司“积分引擎”模块在新规则下运行稳定,而这段“最干净的Bug修复”故事,已经成为了公司内部技术文化墙上的一则幽默警示。