技术开发 频道

重视代码质量 不能等到“亡羊补牢”

IT168 专稿

    代码质量是一种特殊的质量。它经常在理论中被提起,而往往在实践中被忽视。长期来看它的作用很重要,但最后期限临近时,它又变得可有可无。它没有在日程表里直接体现,却影响着整个计划的执行。它有着语法上的、运行时稳定性方面的,以及更广泛的、关于设计的各种定义。那么,代码质量到底是什么?为什么它那么重要呢?

软件质量≠代码质量

    虽然软件与其背后的代码有着明显的关系,但两者还是有微妙的不同。软件是交付给用户,并由用户体验的产品;代码则是对于软件正规且详细的描述。当然,代码中的错误会导致软件上的缺陷,但是代码质量仍然要比KLOC(每千行代码)Bug密度或软件的外观重要得多。

    软件的质量,或者称之为感知质量(perceived quality),取决于软件所实现的功能、该功能的易用性、可能出现的缺陷、用户体验到的软件效果和软件执行效率等因素。代码的感知质量可以采用同样的方式来评估,包括代码实现了什么功能?代码在易用性方面有哪些表现?它本身是方便而有效的吗?代码正确吗?代码的资源利用方式正确或效率高吗?

提高代码的“可居住性”

    在《架构在敏捷开发中的作用》一文中曾经提到,拙劣的架构会增加变化的困难和成本,从而对变化有抵制效果。这种抵制明显地体现在代码上面。软件结构不仅是一个口号或框架;它是代码的特征,并最终由代码将这一特征表现出来。代码与结构不会(也不能)背道而驰,但是实际的代码与预期的结构却会(并且经常)背道而驰。

    Richard Gabriel在《软件模式》中指出,正如我们可以从建筑的结构图中看出建筑的居住环境和工作环境,我们也可以从软件结构中看到代码的环境。

    “可居住性”(habitability)是源代码的特征,它使程序员、编码员、Bug修正人员和其他与代码有关的人员能够明白代码的构建方式和目的,并能轻松自如地对其进行修改。可居住性指某个地方的居住舒适程度,比如家。这也是我们在软件方面的希望——让开发人员感觉像在家里一样,可以自由地处理各类代码,并且能够轻松记住其位置。

    开发人员的大量时间都“居住”并“工作”在代码中,因此提高代码的“可居住性”非常重要。当然,这并不意味着要在源代码中铺满地毯并装满各种各样的小饰品,比如过多的注释或者过于繁琐的逻辑。但确实应该有一些共通的安排和模式。如果没有这样的安排和清晰度,代码就会变得脆弱、混乱、难以理解与不一致,并且要么是过分的简单要么是没有理由的复杂(或者两者的结合)。这不仅会造成项目全局与局部两方面的损失,还会导致开发速度的降低,并因此提高开发成本。

破窗理论 防微杜渐

    代码质量可以反映出创建代码的过程与开发团队的修养。如果没有正确的态度和各方面的支持——包括技术、管理、社会——代码库可能就会慢慢衰退。延迟这种衰退的办法首先是要不断地处理各种小问题,以避免引发更大的问题。如果大问题是从中等问题中产生,而中等问题又是由小问题产生,那么我们可以从源代码上就杜绝问题的出现。这种保证代码质量的方法在《编程实战丛书》(Pragmatic Programmers)中被大力推广,并被称为“不要忍耐破窗户”(一幢建筑中如果开始有破窗户,就代表将有越来越多破窗户的倾向,即意指防微杜渐)。

    根据破窗理论进行的重构是一种有着战略意义的技术。重构并不只是对“改编代码”换了一种说法,虽然确实有些开发人员降低了它的价值并以这种含义来使用它。Martin Fowler为重构提供了以下更准确的、字典式的定义:

    重构(名词):在不改变软件的可见行为方式的情况下,为使软件结构更容易理解、更方便修改而对软件的内部结构做的改动。

    重构(动词):在不改变软件的可见行为方式的情况下,通过对软件进行一系列的重构来改变软件结构。

    为使这个定义不致过于广泛,需要说明其中提到的“可见行为”指的是功能方面,而不是操作方面。功能行为包含代码运行时的交互与最后产生的结果,而操作行为是指代码运行的特性,如性能、内存使用等。一次重构可能会影响到操作行为,但不能影响到功能行为。
 
修补破窗 关注代码质量

    与破窗理论形成对照的则是那句常被误用的老生常谈:“亡羊补牢,未为晚也”。理论上这句俗语听起来好像很正确,但实际上却是自欺欺人的借口。在这里,“破”到底指的是什么呢?“补”又涉及到哪些或者不涉及哪些呢?

    在破窗户的比喻中,“破”是指环境质量方面的问题。但是,在说“亡羊补牢”时,“破”就局限为一种功能行为了。换句话说,如果羊圈没有破洞,就不需要修补啦?如果代码没有错误,也不需要修改啦?很可能羊圈早就已经松动,轻轻一碰即可出现问题。而“修补”又包含哪些内容呢?如果已知代码有问题并且是许多缺陷的共同根源,那么通过一个接一个地修补代码错误根本不能解决本质问题,因为这已不是技术问题,而是组织问题了。非要等到问题彻底暴露才进行修补的这种狭隘态度,带来的是大量不协调的局部修补,这不仅不能解决问题,甚至还会使问题恶化。

    那么对于代码的其它改动呢?那些杂乱的代码,包括大量的重复代码、大量多余的注释掉的代码、冗长的编写逻辑、数不清的特殊用例等,都是在改动的时候占用时间、资源的无底洞。如果这种代码正在运行,虽然可以认为其实现了所需的功能,也极可能是正处于一种脆弱的状态,一种不稳定的平衡,一个不起眼的改动可能就将其彻底破坏。从某种意义上说,这种代码已经坏掉,改动只是起到将其破损之处暴露出来的作用而已。
 
    如果我们采用谨慎行事的保守主义做法,认为“事不关已,高高挂起”,那么很有可能造成“亡羊补牢,为时晚矣”。这样不做出任何改动的维持,也意味着要放弃新功能。

    没有任何的重构选项可以通过简单地点击来修正大量拙劣代码的质量问题,以把它们从最差代码转化成优质文化遗产。要跳出这个坑来,首先要停止继续往下挖坑。

    如果你希望能够随时做出非常好的决定,避免遇到需要解决这些难题的情况,那么很明显结论只有一个,那就是从一开始就关注代码质量,避免出现问题。这也是本文最后的教训。当然,你可以直到遇到交通堵塞的时候再考虑另一条路,但这时候就太晚了——你所有的精力都已经放到如何逃离这片堵车区上面。因此,你最好从一开始就一边小心驾驶,一边注意收听关于前方路线状况的报道。

0
相关文章