下面这些观点都是程序员在教科书上、在编码规范里、在正统的软件工程流程里流传开来的,帮助了许多人在程序员启蒙期间养成了良好的习惯、原则。对许多人(包括曾经的我)来说,似乎是理所当然的。但是随着阅历的增长,视角在变化、看法也在变化,曾经的好恶现在都可能大翻身了。
为代码写足够的注释,让代码易于理解
“所有程序员都会写自己看得懂的代码,但只有优秀的程序员才写大家看得懂的代码。”这话没错,但是——
-
什么才是“大家看得懂”的定义?我有必要让我的C++代码对于一个月前才明白指针和引用区别的初学者简单易懂么?
- 更重要的是,要代码能够“看得懂”,主要是靠足够多的注释吗?
我觉得这两点都是扯淡。
关于第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博客在数日后将不再更新。
分享到:
相关推荐
质疑在批判性思维中扮演着重要角色,它要求我们对既有的信念和观点提出疑问,以此检验它们的合理性。合理的质疑不是无端的怀疑,而是基于逻辑和证据的挑战,目的是促进理解和知识的深化。在教育领域,培养学生的质疑...
软件危机是指随着软件复杂性的增加,出现交付延迟、错误频发、成本上升等问题,引发人们对大型软件可管理性的质疑。水波效应是指修改代码一处可能引发其他未预见问题的现象。黑箱检验是通过输入和输出验证软件正确性...
这篇文档是一个软件开发公司的员工提交的辞职申请书。在信中,员工表达了自己决定离职的遗憾,同时也分享了在公司工作的经历和个人感受。以下是对这个情境中涉及的一些关键知识点的详细说明: 1. **职业发展与自我...
很抱歉,根据您给出的信息,"论《月牙儿》对西方文明的质疑和反思.zip"这个文件似乎与IT行业专业领域并不直接相关,而是属于文学或者文化批评的范畴。标题和描述中提到的是对中国文学作品《月牙儿》对于西方文明的一...
他们开始质疑自己是否适合从事软件开发工作,这表明员工对个人兴趣、爱好和职业定位的深入思考。他们意识到,可能需要跳出当前环境,通过更多的尝试和挑战来找到更适合自己的位置。这种自我认知的过程虽然痛苦,但也...
1. **软件危机**:随着软件复杂性的增加,出现了交付延迟、错误频发等问题,引发了对软件开发能力的质疑。 2. **水波效应**:修改代码可能导致连锁反应,产生新的错误,强调了全面考虑修改影响的重要性。 3. **...
【描述】:本文主要探讨了在充水巷道探测过程中采用的一种名为SYT型物性探测仪的技术,并对其探测原理和传统电磁波理论提出了疑问。 【标签】:电磁波、通信技术、技术开发、参考文献、专业指导 【内容解析】: ...
总的来说,"数据库质疑脚本"是一个综合性的工具,旨在帮助数据库管理员和开发人员发现并解决数据库相关的各种问题,确保系统的稳定运行和数据的安全性。通过深入理解和应用这些知识,我们可以提升数据库的管理效率和...
方象软件数据库质疑修复工具的核心功能主要包括以下几个方面: 1. **错误检测**:该工具可以全面扫描数据库,找出潜在的错误,如记录丢失、字段值异常、索引损坏等。 2. **数据恢复**:对于因各种原因造成的数据...
通过对数据库质疑修复教程的分析,我们可以总结出以下几点重要的知识点: 1. 数据库质疑处理:在数据库质疑或者修复的处理过程中,须先将文中的数据库更改为真实的数据库名称。数据库质疑修复处理完成后,需执行第...
这份离职申请书体现了软件开发员在职业规划中的自我探索和对公司责任的承担,同时也反映出企业在人力资源管理中如何处理员工离职,以减少对公司运营的影响,并从中汲取经验,优化团队结构和工作流程。对于其他软件...
面对质疑,作为软件公司的总工程师,反驳的观点应该是:虽然错误难以在早期完全消除,但通过遵循软件工程的原则,可以在设计阶段尽可能减少错误。软件工程是一种工程化的、系统性的方法,结合了管理技术与最佳实践,...
首先,软件开发工具是一类为软件开发者在规划、分析、设计、测试、文档编写和管理等多个阶段提供帮助的软件。这些工具旨在提升开发质量和效率,涵盖范围广泛,包括CASE工具(计算机辅助软件工程)等。 CASE工具是...
以下是对几种常见的逻辑错误及其反驳策略的详细解析: 1. **自相矛盾逻辑**:当团队成员对论点的理解不一致时,可能会出现自相矛盾的现象。例如,不同的辩手对同一论点给出截然不同的解释。对此,辩手应统一观点并...
电子商务对传统会计概念和范畴的影响主要体现在以下几个方面: 1. 电子商务对会计计量的影响:电子商務使得会计计量方法发生了变化,传统会计计量方法基于纸质记账和手工操作,而电子商务使得会计计量方法扩展到...
4. 接受和提出质疑:科学精神不仅包括对他人观点的质疑,也包括愿意接受他人的质疑。我们应该鼓励开放的讨论和批评,以共同寻找真相。 5. 流行说法的质疑:一些常见的说法可能并不科学,例如,关于金鱼喂食、鲜花...
"这个论点忽略了软件开发中持续学习和适应新技术的需求。" 在快速变化的IT环境中,仅仅具备基础技能是远远不够的。 此外,我们应关注数据的来源和分类。"统计数据仅基于新入职开发者的反馈,没有区分不同经验级别的...
2. 苏轼推理过程的质疑:学生分析了苏轼对郦道元和李渤观点的质疑,认为苏轼的某些推理并不严密。例如,他以钟磬置水为例否定郦道元的观点,但学生认为这并不能充分证明水石相搏不能发出钟声。此外,苏轼根据个人...