程序员都了解一个事实: 代码的质量常常随着代码量的增加而下降。在某些极端情况下 - 例如赶工交付,老架构支撑不起新功能等 - 这种下降甚至非常剧烈。造成这种现象有很多原因,其中一个简单的因素,就是每一次的checkin,并不纯粹是添砖加瓦的贡献,还掺入了灰尘,污垢,甚至严重的破坏。这些负面行为,有些是无意识的,例如刚入门的程序员不知道正确的使用某些API。有些,则是有意识却“故意”做出的。以下对话(经常发生在程序员大脑中)并不罕见:
“这个方法加在这个类有点别扭,好像破坏了职责,但是好像也没别的地方可放。创建一个新的类又好像小题大做,要不先放这里吧,以后再考虑移出来”
“这几个bug的优先级都挺高的,我先全部改完,这样tester可以帮忙重测,单元测试晚点再加吧”
“我要实现的方法其实和已有的那个方法几乎一模一样,但是要重用它,还得先做一个重构。算了,感觉这个方法将来也不太可能改变,这次就拷贝出来改几行做一个新方法,不动原来的那个了”
还有很多类似这样的妥协,大多数程序员可能都这么干过。妥协并不绝对的错误,毕竟用户从来不关心单元测试覆盖率。问题在于做出妥协时,对负面行为的代价的估计是否准确。如果简单认为这种代价是孤立的和线性的,恐怕就大错特错了,因为下面的这类对话(同样,还是经常发生于程序员的自言自语)一样常见:
“我要实现的方法放在这个类好像不合适,但是之前已经有人加过类似的一个方法,我再加一个也没啥吧。顶多以后再把这些方法集中移出来好了”
“这个类已经有这么多方法了,居然一个单元测试都没写,我新加的这个方法要写测试吗?写的话要不要先把其他方法的测试补上了?算了我也不写了,反正之前那家伙也没写,要怪也得先怪他”
“我靠,这两个方法居然就差这一行,也不重构合并一下,你们不做我也不做。两个都不是我要的,我也拷贝出一个改几行,先用着再说”
这种“有意识”的错误行为的传染与累积,可以用“破窗效应”来解释。