代码简洁之道:让问题永不重现

本文深入探讨了软件工程中彻底解决问题的哲学,通过点击计数器案例展示了从表面症状追踪到根本原因的方法论,强调了自动化测试和持续集成在确保问题永不重现中的关键作用。

让问题永不重现

作者:Max Kanat-Alexander
发布日期:2013年11月19日

在代码库中解决问题时,当症状停止并不意味着工作完成。只有当问题彻底消失且永不复现时,你的工作才算真正完成。

问题的本质

当问题不再有明显症状时就停止解决,这是非常容易犯的错误。你已经修复了bug,没有人抱怨,似乎还有其他紧迫问题。为什么还要继续处理它?现在不是挺好的吗?

不,请记住:在软件领域,我们最关心的是未来。软件公司陷入代码库难以管理境地的原因,正是因为没有真正彻底地解决问题。

这也解释了为什么某些组织无法将混乱的代码库恢复良好状态。他们看到代码中的一个问题,处理到没人抱怨就转向下一个症状。他们没有建立确保问题永不重现的框架,没有追踪问题的根源并彻底消除它。因此,他们的代码库永远无法真正"健康"。

彻底解决问题的指导原则

一个好的指导原则是:问题解决的程度应该达到不再需要任何人关注它

从绝对意义上实现这一点是不可能的——你无法预测整个未来——但这更多是哲学上的反对,而非实际障碍。在大多数实际情况下,你可以有效地解决问题,达到现在没人需要关注它,并且没有明显理由将来需要关注的程度。

案例研究:点击计数器bug

假设你有一个网页,写了一个跟踪访问量的"点击计数器"。你发现计数器存在bug——它统计的访问量是实际值的1.5倍。

方案一:忽略问题

理由可能是你的网站不太受欢迎,计数器是否准确无关紧要。而且它让你的网站看起来更成功,这可能对你有帮助。

这是个糟糕的解决方案,因为在许多未来场景中,这可能再次成为问题——特别是当你的网站变得非常成功时。

方案二:快速修复

在显示点击量时,直接除以1.5,数字就准确了。但你没有调查根本原因,结果发现问题是它在早上8:00到11:00期间统计了3倍的点击量。后来你的流量模式改变,计数器又完全错误了。

方案三:调查并解决根本原因

你发现它在8:00到11:00期间统计了3倍点击量。这是因为你的Web服务器在那段时间从磁盘删除许多旧文件,这以某种方式干扰了点击计数器。

进一步调查,你发现如果中断程序然后重新启动,它会重新统计最后一次访问。删除过程占用了机器太多资源,导致在8:00到11:00期间每个访问都会中断计数器两次。因此在那段时间,每个访问被统计了三次。

你重新设计计数器,使其在中断时也能可靠计数,问题就消失了。

确保问题永不重现

显然,正确的选择是调查根本原因并解决它。这使问题消失,大多数开发人员会认为工作到此结束。但如果你真的想确保问题不再需要人工关注,还有更多工作要做。

首先,有人可能会修改点击计数器的代码,在未来将其恢复为损坏状态。显然,正确的解决方案是添加自动化测试,确保点击计数器在中断时也能正确运行。然后你确保该测试持续运行,并在失败时提醒开发人员。

测试的可维护性

你编写的测试必须易于维护。如果测试难以维护——当开发人员更改代码时测试经常变化,测试代码本身难以理解,如果代码更改很容易返回误报等——那么测试很可能在未来被破坏或有人禁用它。然后问题可能再次需要人工关注。

持续集成系统

接下来要关注持续集成系统(测试运行器)——它可靠吗?它是否会以某种方式失败,导致你的测试需要人工关注?这可能是另一条调查路径。

所有这些调查路径可能会发现其他问题,然后必须追踪到它们的源头,这可能会发现更多需要追踪的问题,依此类推。你可能会发现,只需从几个症状开始,并非常坚定地追踪根本原因,就能发现(并可能解决)代码库的所有主要问题。

深入探索

如果你真的想冒险,还可以问一个问题:为什么开发人员一开始就编写了有bug的代码?为什么bug有可能存在?是开发人员的教育问题吗?是他们的流程问题吗?他们应该边写代码边写测试吗?系统中是否存在某些设计问题,使其难以修改?编程语言太复杂吗?他们使用的库写得不好吗?操作系统行为不正常吗?文档不清楚吗?

一旦得到答案,你可以问那个问题的根本原因是什么,并继续问这个问题,直到你满意为止。但要小心:这可能会带你进入兔子洞,到达一个改变你对软件开发整体看法的地方。

读者评论

Jeff Dickey:经过几年的TDD实践,我发现它迫使我一直这样思考(回归测试已成为遥远的记忆)。很棒的文章!喜欢点击计数器的例子!

Mike W.:很好的例子;很好地说明了观点。应该注意的是,这个例子并没有完全追踪到底。为什么点击计数器在中断和重启时会重新统计最后一次访问?

Max Kanat-Alexander回复:重新设计它甚至消除了这个问题。也就是说,你不必问这个问题,因为被质疑的对象已不存在。


本文探讨了软件工程中彻底解决问题的深度方法,强调了从表面症状追踪到系统根本原因的重要性,为构建可持续的软件系统提供了实用指导。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计