我们不能否认在很多的软件开发过程中,并没有遵循先“充分”设计,后“认真”开发的思路,也同样没有“敏捷开发”的思路,没有重构,没有改进,唯一的特征就是把“面条”下锅,并在捞出来的时候梳理一下而已。代码质量很难保证,但这是普遍现状,不可否认。既然已成事实并且你也没有太大的计划去改进你的方案,因为事实上你更认同你现在的做法,主要是可操作性可能更好,你不会因为某项理论的支持而去使用××方法论,更不会拿你的一箩筐的项目来做实验,那么好吧,就在一些细节上稍作改进以殊途同归吧。
通过在补写详细设计文档时混合代码审查以加快项目进度的方案
背景
-
- 早期赶进度,详细设计文档还没写,代码都已经接近尾声了。
- 开发人员并未参与项目的全程,包括需求到设计,对设计意图以及代码意图(包括一些旧版本的代码)以及整个项目的结构不是很了解。
- 开发人员水平参差不齐,对代码的优化以及代码潜在的问题了解不透彻。
- 这是一个从旧代码转换成新代码的迁移过程,迁移过程通常还可能是异构的,伴随着代码风格的转变以及设计思路的转变以及一些需求变更和重新设计。
前提
在进行该方案之前,必须根据现有代码情况对潜在进行分析,并明确以下几点,包括:
-
-
代码规范,在项目早期所定制的代码规范不能够覆盖现有的代码体系,针对现有的代码规范进行修订,并在该计划施行之前进行推广并获得广泛认同。明确定义每一种错误方式的正确实现以及它们的改动级别,包括必须改动/不必改动/在小成本的前提下建议改动等。
-
程序员心理,在团队中传达一种思想,这个计划不是对他们既往工作的否定,仅仅只是一种更佳有效的工作方式,目的旨在改善代码质量,并帮助他们在修正BUG前将所有潜在问题一网打尽。关于代码BUG的问题则应该在测试阶段完成,而不是在该方案中。
-
方案目的
-
-
是什么?
-
[是]补写详细设计,因为项目本身需要通过文档来将代码资产化,并且利用文档来削减人员流动,项目迁移等的总体成本。
-
[是]精化详细设计,假设原来我们的目的旨在让详细设计文档满足页数上的要求,通过该方案,文档的质量将有质的飞跃。
-
[是]代码审查,因为补文档的前提是已经有了代码,那既然要对代码做理解,那不如顺便做一下代码审查。
-
[是]提高程序员素质,阅读他人的代码,不论是在拓展思路还是在理解需求上都会有很大的提高。
-
-
不是什么?
-
[ 不是]BUG管理的一部分,我们 必须只希望通过该方案完成详细设计,并顺带进行代码审查,目的必须不在记录程序员的BUG,否则将会大大影响团队成员信心,影响后续工作的进行。
-
-
项目时间
假设原来的设想是:先补写详细设计文档,后进行代码审查或者说是代码自我检查。并且原先的做法是“自我检查”而不是“他人审阅”。这样的做法无疑是对下面的方案的一种抽象:
-
-
if(c > 'a' && c <'z') c = c + 'A' - 'a';
-
if(c == 'a') c = 'A'; else if(c == 'b') c = 'B'; else ...
-
至于方案1和方案2孰优孰劣,相信很容易区分。
质量问题根源
-
-
对需求的不理解以及误解,这里包括对整个项目总体框架的不理解,程序员从微观的代码视角逐渐转化为对整体有充分认识后,才能在有“原则”的情况下对代码正确性作出总体保证,这本应该在项目前期完成,但假设我们的成员在项目初期还未正确理解的前提下,现在必须得有正确的认识了。
-
对旧代码的误解以及开小差,甚至是旧代码原先就潜在的问题,我们当然不能保证旧代码就是正确的,甚至从绝大多数人的心理来讲,更愿意是“问题不是我造成的,而是旧代码造成的”。误解别人的设计意图这显然是再自然不过的,我们不应怪罪程序员的一时疏忽,特别是在两种异构代码之间切换上,更应该包容这样的错误,但现在我们必须将这些臭虫一一发现并抓做典型。
-
团队沟通的不顺畅,大型的团队必然存在不同程度的沟通问题,谁都不愿意每小时都被人烦,谁也都不愿意一点小事就去烦别人,这不仅是对自身理解力的一种亵渎,也是对他人耐心的一种挑战,既然这是人类心理潜在的毛病,那就让该方案来帮助弥补好了。
-
项目成员的水平参差不齐,一段代码可以有N种写法,但只有一种是效率最高的,也只有一种是漏洞最少的,但是却有很多种都是臭虫,抓出来,戴高帽,然后灭掉。当然这里的典型必须是匿名的,这基于后续“如何避免降低开发人员信心”一节的原理,就事论事就可以了,我们不希望问下面这样的问题:“是谁带了这样的坏头?”。这个做法的最佳实践应该是在代码开展之前有个基础的方案和假设,在代码进行中不断地迭代这种做法,最无奈的实践就是在代码审查中来改,但这都是必须的。
-
如何解决引入的这些问题
这一节提出一些我认为正确的具体的解决方案,但不一定适合于每个项目,可以根据自己的项目酌情修改。
-
-
不使用BUG管理工具,虽然BUG管理工具有跟踪管理的功能,但我们应该始终避免这种错误被跟踪。因为假设这个方案最早是由“谁开发谁负责”的思路来完成的,那么这种错误根本就无法跟踪,没有人会向组织报告自己是多么地愚蠢和粗心大意,这些BUG早就在被你审查之前涂改掉了。好吧,那就让我们满足他们的心理要求,远离BUG管理。
-
错位检查,当一个项目小组的成员的数量大于3个的时候,错位检查无疑是最好的,这将暗示这项工作是一个“给别人找茬”以及“被别人找茬”的工作项而已。谁都无法避免“被别人找到茬”的灾难,这是一项复杂的心理工程,被熟人找出错误是很丢人的事。但人们还有一种心理,应该大家都有经验,就是,你不会去嫉妒比尔盖茨的财富,但是很在意你同学朋友的财富,哪怕他们每个月仅在收入上比你可观500元。所以你会发现程序员们比原来更乐意找到别人的错误,而项目本身自然是这项计划的最大受益者。当然根据业务数量的不一致,错位不一定代表A必须是检查B,B必须检查C,A的目标是任意与他所熟知的范围息息相关但又只是小组的另一个成员,而不是另一个项目的某个成员。这将代码规范限定在一个项目内,而不是在若干项目内。这也利于代码风格的统一。因为不同的项目可能本身在构建的时候就不一致,现在做统一无疑等于重做。
-
指出并修正错误,我的建议是首先对不同的代码进行理解,并进行检查,对一些通用的错误,进行修改,并直接在代码中写下修改理由,要求简洁明了,对于被修改掉的代码,不建议在源代码上直接修改,而是将其复制在相同位置,并对源代码进行注释,并保留。对于无法简单修改的错误,也应当记录错误思路,并进行后续核准。
-
私下通知,这里的私下通知不是面对面地口述,也不是手把手地修改,更不是打个电话给对方,并在对方正在午餐或休假的时候说明。请将你所检查的部分,以及必要的简述分点拽写在邮件中,并发给对方,并抄送给小组组长,如果团队仍然希望统一跟踪所有的这些BUG,可以建立一个专用的邮箱,并在抄送给小组组长的同时抄送到该邮箱,仅此而已,不需要复杂到非得建立一个专用的BUG管理来记录这些错误,这会让人觉得懊恼。所有的代码构建都应该受限于源代码控制的版本跟踪下,以利于随时进行恢复。抄送组长的目的是对一些经典问题进行记录并向上汇报,并及时迭代出更全面的代码规范,并对存在问题的修改进行指明,但这可以不作为工作项的一部分。邮件标题格式建议“[2009-07-18]代码审查/详细设计(01)”,避免使用“回复:/RE:”等,这样做的目的旨在于简单地通过标题进行排序,别无他意。
-
每日复核,对既有代码进行的修改被提交到版本控制中,必须在每日工作结束前预留几个小时给源码主人,一次辩护的机会。代码原作者检查被提交的错误构建,并进行代码复查,对认同的代码审查结果,删除旧有被注释的代码,修改旧有代码注释,这通常可以从修改者的注释中快速提取。这样的注释相比原来的注释,增加了更多的避免错误的思考,使注释在自我诠释方面更具优势。
-
详细文档完善,从时间上,修改者对代码的审查是最近的,从要求上,我们希望代码者的任何修改都是建立在完全理解该需求以及该代码的前提下,因此详细代码应该由代码审查人员来编写,而不是代码原作者,因为代码原作者编写代码的时间离当前时间已经相去甚远。
-
如何避免降低开发人员信心
大部分的程序员都不愿意别人发现自己的错误,这个欲望远比他们期望编写出完美的程序还要强烈。他们更愿意自己偷偷将代码扼杀在摇篮里,而不是被他人揭发。如何避免大量的问题被揭发?最好的做法是在项目开始的时候就告诉他们会有互相审查,这样他们会自发地认真起来。但是现在的情况是:我们应该去替他们消除被人揭发后的悔恨以及愤怒。但这本身就与这种审查制度相悖。我们甚至希望将改动的部分直接记录在代码被改动的部分,成为版本变更的一部分。但这么做明显就留下了案底。那我们就就事论事好了,去掉修改代码中原作者的信息。改动本身记录修改者的自信和聪明,而隐藏掉原作者的粗心,这同样利于信心提升。
为什么不用测试来解决
测试是的基础是来源于对需求的正确认识,并对正确的目标有明确的认识,而该方案的前提在于对需求的误解以及对程序员在阅读代码时候开小差的一种弥补,而不是程序员在编写代码时候开小差的修正,编写代码时候开小差的行为可以通过增加测试来修正,但对需求等的理解偏差则是测试无法覆盖的。因此你也可以根据自己的团队,要求在代码审查的时候同时修正现有测试代码,或者添加测试代码。
原理
将代码质量控制在投放生产环境前,远比将代码投放生产后再进行修改要容易,包括测试在内的许多软件工程实践都在阐释这个问题的严重性。尽早发现代码无疑是更有益的。
注解
本文档标注为“暗红色”的字体仅适用于从旧项目源代码迁移至新项目源代码的过程,非特殊说明的可泛用于普通软件工程。
我非常希望有人能够在增强程序员信心方面提供更多经验和思路。因为不论如何都是在揭疤。