对几个软件开发传统观点的质疑和反驳

标签: 软件开发 传统 | 发表时间:2012-11-02 23:00 | 作者:
出处:http://www.iteye.com

下面这些观点都是程序员在教科书上、在编码规范里、在正统的软件工程流程里流传开来的,帮助了许多人在程序员启蒙期间养成了良好的习惯、原则。对许多人(包括曾经的我)来说,似乎是理所当然的。但是随着阅历的增长,视角在变化、看法也在变化,曾经的好恶现在都可能大翻身了。

为代码写足够的注释,让代码易于理解

“所有程序员都会写自己看得懂的代码,但只有优秀的程序员才写大家看得懂的代码。”这话没错,但是——

  1. 什么才是“大家看得懂”的定义?我有必要让我的C++代码对于一个月前才明白指针和引用区别的初学者简单易懂么?
  2. 更重要的是,要代码能够“看得懂”,主要是靠足够多的注释吗?

我觉得这两点都是扯淡。

关于第1点,造就了一些自我感觉过度良好的人,习惯性地把前人写的代码批得体无完肤。在他们眼中,这段代码巨烂,那段代码是屎,更有甚者,在评审别人代码的时候,一样说出这样的话来(请 参见这篇文章里的“一坨屎型评审”)。

反对我的人会说,软件公司做产品赚钱,它们希望你的代码让不熟悉项目的新员工快速阅读、上手。这确实是个矛盾。说白了,你写的代码要和一个团队的能力匹配。在一个鱼龙混杂的团队,甚至一个糟糕的团队,你写出的代码也许很难和大伙儿产生共鸣,他们希望你写最普通最易懂的代码,没有精巧的设计(我指的是,“ 某一些精巧的设计,恰恰是以降低代码的可维护性为代价的”),没有语言高级特性,看着只有顺序、循环、分支判断的基本代码。如果大家都是JavaEE的初学者,那么就从JSP+Servlet开始吧,这样你们才在一个圈子里,要不然,没有人能真正和你一起讨论设计和代码的问题。

所以许多上进的程序员,会希望在一个牛人的团队里工作。这就像足球运动员一样,因为足球是集体运动,一个足球运动员能达到的高度,是和他所在的团队息息相关的。在一个优秀的团队里,大家个性各有千秋,擅长领域不甚相同,但是都学习迅速,能力不差太远,大家阅读代码都能够很快理解和领会,而且讨论问题可以用一些程序员才明白的隐喻(比如有人说“我觉得这里应该用一个builder来实现”,大家都明白builder指的是什么),氛围和效率显而易见。

如果你恰好对当前需要用到的业务和技术特别熟悉,领先团队里其他人一大截怎么办?那你就该在做设计编码的时候先行一步,你是那个最该去做架构设计、写骨架代码的人,完成一个架子以后再来给大家讲解,并和大家讨论,改进现有的设计。也就是说,你要多做一些更重要的事,而不是和大家一起分析、一起讨论,甚至一人负责一个模块,最后的结果就是大家根本和你讨论不到一块儿去。

关于第2点,要代码“看得懂”,是设计出来的,而不是注释加出来的。这和产品质量一样,产品质量是设计出来的,而不是测试测出来的。注释的意义在于对当前代码自解释做不到的地方进行补充。

所以,你的代码要易于理解,首先要保持简洁和清晰,这既包括良好的设计,也包括良好的编码习惯,也就是说,代码是自解释的,其次才通过注释的补充,让代码更易懂。注意,我不是说注释不重要和不必要,而是说,注释应该完成它自己的功用,它远不能代替代码本身自我解释的价值。

举一个简单的例子,你可以这样写代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
  * 图表模型
  */
class Chart{
     /**
      * 图表长度
      */
     private int length;
     
     /**
      * 获取图表长度
      * @return 图表长度
      */
     public int getLength(){
         return this .length;
     }
 
     /**
      * 设置图表长度
      * @param length 图表长度
      */
     public void setLength( int length){
         this .length = length;
     }
}

好,那么你告诉我,这段代码和下面这段代码相比,你获取了什么更多的有用信息?

1
2
3
4
5
6
7
8
9
10
class Chart{
     private int length;
 
     public int getLength(){
         return this .length;
     }
     public void setLength( int length){
         this .length = length;
     }
}

我想你懂我的意思,两段代码,代码本身意思已经够明确了,再加上这些无聊的注释,只是浪费资源、浪费生命。很多编程语言,利用语法糖,连简单get、set方法都可以省了(比如Objective C),而加这种注释的做法却依然在反软件、反人类而行。也许你和我一样,曾经为了公司某些扯淡的规定,为了规避某些扯淡的代码静态检查工具(比如CheckStyle这样的,甚至自己开发这种无聊的检查工具)检查结果中的警告信息,加上了(包括IDE自动生成)这些毫无意义的注释,于是领导看了:“好,没有警告信息,代码质量好”。虽然至始都痛恨这样的做法,但我还是做了,至今后悔。最让人痛恨自己的事情就是不得不去做那些自己痛恨的事情。

设计文档要详细,细化到方法定义

持这个观点的大有人在。对于这个观点我并不是完全反对,如果你要说设计文档需要“详细到可以指导编码”我还能同意,但是我确实非常不喜欢详详细细的设计文档。肯定设计文档的价值这没有错,但是过于详细的设计文档撰写,往往容易造成纸上谈兵的窘境。

有人说设计文档太过粗略了做不好设计,事实上,文档只是呈现设计的其中一种形式而已,做得好设计的人,可以一边编码一边思考,可能辅助草稿纸上写写划划,就可以完成优秀的软件;不会做设计的人,设计文档写多少页都没用。这让我想起了今天和同事关于TDD的讨论,会做设计的人,不让他用TDD也能写好代码;不会做设计的人,TDD又有何用?所以让TDD成为设计的主要工具,那就是扯淡。

再一个,在设计文档中,不可能做完设计,不知你是否有这样的体会,设计文档思考得再缜密细致,等落到代码上的时候,还会和开始的思考有许多不同,至少有很多细小的不同。这是因为设计思考本身就是贯穿整个设计编码过程的,一人只做设计、另一人只写代码这样的理想模式是不可能达成的。

我了解一些对日外包公司,程序员拿到手的设计文档就是细化到方法定义了的,如果你有能力有志气,在中国最好就不要做外包,尤其是对日外包,这样的公司拒绝你的一切思考,就是在摧残人才。

另外一个原因,是针对一些阐明“设计文档可以传承业务和技术知识”观点的人,详细的设计文档并不能够传承什么业务和技术,原因很简单,详细的文档初始撰写成本高,维护的成本更高。我不相信程序员在修改了代码逻辑以后,会去经常保持设计文档的同步性。这不合理,只有代码才是保持最新的,其它一切都会过时。而相对简要或粗略的文档,稳定性就要强得多。

让项目组各个角色去评审代码设计

下面我要驳斥的这个观点来源于我的一些经历,也许并不能算是主流观点。

对于设计文档的评审,如果是设计原理、实现原理,正到了程序员才关心的层面上,如果不写代码的测试跑来一起讨论,这就成了浪费时间、制造矛盾的做法。我经历过这样的事情,觉得很幽默。专职测试人员的定位各有千秋,许多人经验丰富、无可替代,但是至少,我接触的测试人员中,他们几乎是不阅读代码的,也就是说,对于代码设计(注意,是代码设计,不是产品设计)的讨论,他们不该参与进来。

另外,不要说“我几年前也是写代码的”,毛爷爷都讲了,“不了解情况,就没有发言权”,如果你对当前的代码实现不了解,就不要来碍手碍脚地评审代码层面的设计了。

我也经历过这样的场景,每一个产品都要组织一些有经验的程序员,去给别的产品的代码挑刺儿。我的看法是,这很难挑出特别有价值的毛病来,原因也是一样的,你对别的产品业务不了解,那么要花大量精力去阅读代码,更要去熟悉业务,否则只能从代码层面上抠抠细节。

所以,谁来把关实现层面的设计和代码的质量最卓有成效呢?正是熟悉项目的程序员们,尤其是项目组骨干,或者一起参与设计、编码和测试的架构师(其实架构师还是一名优秀的程序员,我从来不认为“只懂业务的架构师”有什么资格去做软件架构)。

为代码设置量化的限制指标

统计指标是有价值的,但是如果设置这些量化指标给程序员套限,则是违背客观规律的行为。这一观点我有必要举例说明一下:

  • 测试代码覆盖率不得低于95%(比如工具EMMA);
  • 方法圈复杂度不能超过15(你也许知道圈复杂度的检查工具SourceMonitor);
  • 单个类的行数不能超过500,单个方法的行数不能超过200;
  • 任意两个类之间重复代码行数不能超过10行(你可能知道重复代码检测工具Simian);
  • ……

这些硬生生限制,都是反软件、反人类的。你可以说圈复杂度高的方法也许过于复杂,你可以说重复比率高的代码往往可以优化,但是这些都只是一个辅助的指标。这些工具都是用来帮助程序员改善他们的设计和代码质量的,如今它们却被用来做反程序员的事。

对于测试代码覆盖率的要求,而且有许许多多公司拿来作为代码质量衡量的重要指标,我认为更是骇人听闻。我写代码也做单元测试,但是会有选择地写UT用例,不会去追求测试覆盖率,而且测试再全面也不可能保证结果的绝对正确,好钢要用在刀刃上,时间的投入要换取划算的回报,而不是不计代价地补充测试用例。而且,在这里我要说的是,保证软件质量的方式有很多,测试验证的方式也有很多。即便覆盖率达到100%,也不能说明质量高到哪儿去,追求覆盖率始终太过功利。另外,有许多代码本身就没有多大被UT测试的价值,这也是不容忽视的。

优秀的程序员,应该难以容忍自己产出糟糕的代码,也许对代码有一点洁癖,对代码之美有不懈的追求。对这样的软件的使用动机,也应该来源于程序员,而相关数据的采集,最终一定要为程序员服务。

今天只是把上面这些观点做了个整理,在和别人谈起这些的时候,其实我觉得我只是说了实话而已,我的观点一点都不偏激。我知道很可能你会有不同看法,这太好不过了,但是善意地提醒你,请一定仔细思考一下,不要被公司的精神和文化洗了脑,我们都是程序员,我们最清楚,或许也都经历过那些针对程序员、软件开发荒唐可笑、乃至不可思议的做法。

文章系本人原创,转载请注明作者和出处( http://www.raychase.net

注:本博客已经迁移到个人站点  http://www.raychase.net/ ,欢迎大家访问收藏,本ITEye博客在数日后将不再更新。



已有 4 人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



相关 [软件开发 传统] 推荐:

对几个软件开发传统观点的质疑和反驳

- - ITeye博客
下面这些观点都是程序员在教科书上、在编码规范里、在正统的软件工程流程里流传开来的,帮助了许多人在程序员启蒙期间养成了良好的习惯、原则. 对许多人(包括曾经的我)来说,似乎是理所当然的. 但是随着阅历的增长,视角在变化、看法也在变化,曾经的好恶现在都可能大翻身了. 为代码写足够的注释,让代码易于理解.

软件开发的核心

- - 博客园_知识库
  「我们一直这样做开发,时间做久了,便忘了当初的本意.   有关软件系统开发,我们谈些什么.   我们谈过程,编码规范、开发流程、同行评审、结对编程、持续集成,从瀑布到敏捷再到极限编程.   我们谈架构,企业级、J2EE、容器化、SOA(面向服务架构)、Microservices(微服务化).   我们谈规模,大容量、高并发、大数据.

软件开发的“三重门”

- - 酷壳 - CoolShell.cn
自从上次写了“ 程序员技术练级攻略” 以来,就觉得似乎还有很多东西没有谈到,但当时没有继续思考了. 而春节前有人问我,是做底层技术,还是做业务. 这问题让我思考了很多,不由自主地回顾了一 下我这十多年的软件开发经历,并顺着整理分类了一下自己解决过的若干问题,还发散想了很多,经过了一个春节假期的发酵,产生了下面这篇文章.

软件开发的人文关怀

- - 博客园_知识库
  几年前,我从温伯格的《技术领导之路》中学到一点:技术人员往往更喜欢和机器打交道,因为他们“认为”自己更适合和机器打交道;但是,优秀的技术人员必须(也必然)具备好的沟通能力. 所以,温伯格鼓励各位技术人员多加练习和其他人打交道的能力. 温伯格的这个观点我是非常赞成的,好的技术人员一定需要“勇敢”面对他人,不能被“自实现的预言”局限在机器的世界里.

软件吞噬软件开发

- - PingWest中文网
软件蚕食世界,自互联网特别是移动互联网连接线上线下服务后,已成为不可逆的趋势. 每一项实用的服务可以由小团队来完成. 以WhatsApp为例,这款被高调收购的IM应用,拥有4.5亿月活跃用户,70%的日活跃率,至今还保持每天新增用户1000万的速度. 但这些服务居然由32名工程师支撑下来了,所以有了业界八卦“每位员工价值20亿”的说法.

软件开发中的两种态度

- - 外刊IT评论网
一种态度认为,应该对程序员在软件开发中的行为进行约束( DirectingAttitude). 持这种态度的人认为大部分的程序员水平都不高(谣传说有50%的人低于平均水平),所以应该对他们所做的事情进行管教约束. 要防止他们做一些可能会给他们正在开发的系统带来危害的事情. 通常,这种态度体现在一些系统设计和工具中时,你会发现它们会试图阻止程序员去做某些事情,限制程序员的一些做法,以此避免他们陷入过于复杂的境况.

软件开发的人文关怀

- - 极客公园-GeekPark
我是极客公园黑板报认证值日生. [核心提示]软件可以没有活力,而软件开发却不能没有活力;程序可以像机器一样,程序员却不能像机器一样. 要改变这种状态,就应当增添更多的人文关怀,把开发人员当成活生生的人,而不是视为程序或者工具. 编辑注记:本文来自余晟的博客 乱象,印记. 作者从自己的经验出发,提出了一些给软件开发人员提供人文关怀的可行措施.

软件开发模型综述

- - CSDN博客推荐文章
                     软件开发模型概述. 最早出现的软件开发模型是1970年W·Royce提出的瀑布模型. 软件开发模型(Software Development Model)是指软件开发全部过程、活动和任务的结构框架. 软件开发包括需求、设计、编码和测试等阶段,有时也包括维护阶段.

防火长城内的软件开发

- - Solidot
对于软件开发者来说,防火长城不只是屏蔽网站过滤流量这么简单——它是痛苦之源,尤其是如果你想开发针对中国市场之外的软件或想利用广泛使用的服务和软件库的话. 上海聊天机器人创业公司Rikai Labs的创始人DC Collier认为,中国的软件开发者写代码的时候一只手是绑在背后的. 防火长城的屏蔽范围日益扩大,这意味着越来越多的服务被永久性或不定期的屏蔽.