让问题永不重现 » 代码简洁性
代码简洁性
让问题永不重现
2013年11月19日 by Max Kanat-Alexander
在代码库中解决问题时,症状消失并不意味着工作完成。只有当问题彻底消失且永不复现时,才算真正完成。
当问题不再有任何可见症状时,很容易停止解决工作。你已经修复了bug,没人抱怨,而且似乎还有其他紧迫问题。那么为什么要继续处理它呢?现在不是挺好的吗?
不对。请记住,在软件领域我们最关心的是未来。软件公司陷入代码库无法管理境地的原因,正是没有真正彻底地解决问题。
这也解释了为什么某些组织无法将混乱的代码库恢复到良好状态。他们看到代码中的一个问题,处理到没人抱怨就停止,然后转向处理下一个表面症状。他们没有建立确保问题永不复现的框架,没有追踪问题根源并彻底消除。因此他们的代码库永远无法真正"健康"。
这种未能完全处理问题的模式非常普遍。结果,许多开发者认为大型软件项目不可能保持良好设计——他们说:“所有软件最终都必须被抛弃重写。”
这是不正确的。我的职业生涯大部分时间都在从头设计可持续的代码库,或将糟糕的代码库重构为良好状态。无论代码库多糟糕,你都能解决其问题。但你必须理解软件设计,需要足够的人力资源,并且必须处理问题直到它们永不复现。
一般来说,判断问题解决程度的良好准则是:问题解决到不再需要任何人关注它的程度。
绝对意义上实现这一点是不可能的——你无法预测整个未来等等——但这更多是哲学上的反对而非实际障碍。在大多数实际情况下,你可以有效解决问题到当前无人需要关注,且没有明显理由将来需要关注的程度。
示例
假设你有一个网页,为网站写了一个"点击计数器"来跟踪访问人数。你发现点击计数器有个bug——它统计的访问量是实际值的1.5倍。你有几种解决方式:
忽略问题 理由可能是你的网站不太受欢迎,点击计数器说谎无关紧要。而且它让网站看起来更成功,可能对你有帮助。 这是糟糕解决方案的原因在于,未来有很多场景可能再次出现问题——特别是网站变得非常成功时。例如,主流新闻出版物发布你的点击数据——但数据是假的。这导致丑闻,用户失去信任(毕竟你知道问题却没解决),网站再次变得不受欢迎。很容易想象这个问题会以其他方式困扰你。
快速hack解决方案 显示点击量时直接除以1.5,数字就准确了。但你没有调查根本原因,结果发现它在早上8:00到11:00期间统计了3倍点击量。后来你的流量模式改变,计数器再次完全错误。你可能一段时间都注意不到,因为hack方案会让调试更困难。
调查并解决根本原因 你发现它在8:00到11:00统计了3倍点击量。你发现这是因为Web服务器在那段时间从磁盘删除许多旧文件,这以某种方式干扰了点击计数器。 此时你又有机会hack解决方案——你可以直接禁用删除过程或减少运行频率。但这没有真正追踪根本原因。你想知道的是:“为什么机器上运行其他东西会导致计数错误?” 进一步调查,你发现如果中断程序然后重启,它会重新计数最后一次访问。删除过程占用了机器太多资源,导致8:00到11:00期间每次访问都会中断计数器两次。所以那段时间每次访问都被计数三次。但实际上,根据机器负载情况,这个bug可能添加无限(或至少不可预测)的计数。 你重新设计计数器,使其即使被中断也能可靠计数,问题消失了。
显然,列表中正确的选择是调查并解决根本原因。这使问题消失,大多数开发者会认为工作完成了。但如果你真想确保问题不再需要人工关注,还有更多工作要做。
首先,有人可能修改点击计数器代码,将来将其恢复为损坏状态。显然正确的解决方案是添加自动化测试,确保点击计数器即使被中断也能正确运行。然后确保测试持续运行并在失败时提醒开发者。现在完成了吗?
不。即使到这一步,还有一些未来风险需要处理。
下一个问题是编写的测试必须易于维护。如果测试难以维护——开发者修改代码时测试经常变化,测试代码本身晦涩难懂,代码变更时容易返回假阳性等等——那么测试很可能将来会损坏或被人禁用。然后问题可能再次需要人工关注。所以你必须确保编写了可维护的测试,如果不可维护就重构测试。这可能引导你进入测试框架或被测试系统的另一条调查路径,找出使测试代码更简单的重构方法。
之后你还要关注持续集成系统(测试运行器)——它可靠吗?会以导致测试需要人工关注的方式失败吗?这可能是另一条调查路径。
所有这些调查路径可能发现其他问题,然后需要追踪其根源,这可能发现更多需要追踪的问题,依此类推。你可能发现,只需从几个症状开始,坚定追踪根本原因,就能发现(并可能解决)代码库所有主要问题。
有人真的这样做吗?是的。起初可能看起来很困难,但随着你解决越来越多这些根本问题,事情确实开始变得更容易,你能越来越快地推进,问题越来越少。
深入兔子洞
除此之外,如果你真想冒险,还可以问一个问题:为什么开发者一开始就写出有bug的代码?为什么bug可能存在?是开发者教育的问题吗?是他们的流程问题吗?他们应该边写代码边写测试吗?系统中有某些设计问题导致难以修改吗?编程语言太复杂吗?他们使用的库写得不好吗?操作系统行为不正常吗?文档不清晰吗?
得到答案后,你可以问那个问题的根本原因是什么,并持续追问直到满意。但要小心:这可能带你进入兔子洞,到达改变你对软件开发整体看法的地方。事实上,理论上这个系统是无限的,最终会解决整个软件行业的根本问题。你想走多远取决于你自己。