一个编程指南还有这么多道道儿?
作者:互联网
目录
1、为什么需要编程指南(WHY)
开发人员往往只关注程序的功能是否正确,而忽视质量的其它属性。至于编程指南(或者编程规范),很多程序员更是觉得没有必要遵循:我不遵守这些指南,程序不是执行的也很好吗?
实际上,代码不仅仅是被机器执行的,还是给人看的。不遵循指南的代码,可读性差,不利于理解,因此不利于维护。而软件维护成本通常占整个生命周期成本的40%~80%。
反对编程指南的人还可能会提出如下的一些理由:
1)引入编程指南会浪费时间:每个人都有自己的习惯,尤其在编程格式方面。为了符合指南,花费大量的时间修改代码格式等,太浪费时间。
刚开始的时候会带来这样的感觉,但长期来看,无论从团队协作还是长期收益来看,遵循指南是非常有益的。可以类比一下交通规则:从个体上看,许多交通规则是非常烦人的,浪费时间。但从群体角度看,这些交通规则不仅可以提升总体效率,还可以避免交通事故,保障人身安全。许多交通规则,都是在初期引起人们的反感,但较长一段时间之后,才体会到了它的好处。
2)编程是艺术创造,不能约束太多:前半句可是算法的上帝Donald Knuth讲的。
编程过程具有双重性:微观上的艺术性,与宏观上的工程性,期间不仅需要有创新,还需要有约束。尤其当软件逐步成为人类文明的载体时,宏观上的工程需求更加重要。个性再明显的程序员,也需要逐步适应。Python发明人加入谷歌后,也曾经因为代码可读性不足被拒绝将代码合入代码库。
3)编程指南本身有意义,但实施太困难:要让企业中所有的开发人员都完全掌握编程指南,是一件困难的事情。尤其是企业里的人员通常处于变动状态,总有编程新手持续加入。这给指南的实施带来了非常大的困难。
近年来,随着代码分析技术的不断进步,通过代码检查工具自动发现违反编程指南的代码,进而推动编程指南的落实,正在成为一个大趋势。许多公司的实施效果非常显著,大大提升了代码的质量。
正因为编程指南如此重要,一些大型公司纷纷颁布了编程方面的系列指南。不仅如此,一些行业组织也制定了行业特有的指南。例如:MISRA C是由汽车产业软件可靠性协会(MISRA:Motor Industry Software Reliability Association)提出的C语言开发标准指南,以增进嵌入式系统的安全性及可移植性。只有符合MISRA 指南的软件才可以在汽车领域进行应用。MISRA C一开始主要是针对汽车产业,后来许多其他行业也逐渐开始使用MISRA C,包括航空、电信、国防、医疗设备、铁路等领域中都已有厂商使用MISRA C。
2、编程指南关注什么(WHAT)2.1 编程指南内容分类
编程指南主要可以分为两大类:风格类与编程实践类。
风格类指南包括标识符的命名、格式以及注释风格等。此类指南引导开发团队使用统一的代码风格进行开发。一致的编码习惯与风格,会使代码更容易阅读、理解,也更容易维护。需要注意的是,对于开源项目,如果在代码风格类指南上有冲突,原则上遵从开源项目原本的代码风格要求。
• 命名类条款要求标识符的命名要清晰、明了,含义明确容易理解,软件项目内部应具有统一的命名风格。例如驼峰风格的命名是近年来多数企业推荐的命名方式。符合阅读习惯的命名将明显提高代码可读性,统一的命名风格更加有利于代码的理解和维护。
• 格式类条款建议在同一个项目中使用统一的排版格式风格,以便所有人都能够轻松的阅读和理解代码,增强代码的可维护性。例如使用空格进行缩进,每次缩进4个空格。
• 注释类条款建议在需要的时候,对逻辑较为复杂或者易于让读者产生困惑的代码,辅以注释加以说明。注释是为了帮助阅读者理解代码,所以要从阅读者的角度出发按需注释。例如“代码注释置于对应代码的上方或右边”。注释内容要简洁、明了、无歧义,信息全面而不冗余。注释跟代码一样重要,修改代码时也要保证其相关注释的一致性。只改代码,不改注释是一种不文明行为,破坏了代码与注释的一致性,让阅读者迷惑、费解,甚至误解。
编程实践类指南包含编程语言特性相关的条款,比如数据类型、常量与变量的使用,表达式、语句,函数设计与使用,资源管理以及错误处理等。这类编程实践有些具有一定的时效性,比如语言的新特性。对于趋于成熟的语言新特性,编程指南会引导开发人员从使用旧特性的编程方式向使用新特性转变,对于这类场景给出最佳实践作为参考,其中引导、建议的成分居多。但是,随着时间的推移,新特性的使用也可能逐步转变成更加严格的要求条款。编程实践类指南中,健壮性与安全性尤其受到人们的关注。
• 健壮类条款侧重于提升软件产品本身的质量属性,比如健壮性、可维护性、运行性能等。这类指南通过在语言本身的语法之外添加额外的合理限制,来避免语言本身或者开发人员无意疏漏导致的意外错误。比如“”确保枚举常量映射到唯一值”这一条款,虽然编程语言本身可能允许一个枚举中的项具有重复的值,但是这违反了人们对于枚举的自然期望,而且往往意味着不良的设计,进而导致一些不易发现的错误。
• 安全类条款侧重于软件的安全性,主要通过列举可能导致安全隐患的危险场景,结合导致安全风险的示例,要求开发人员避免使用不安全的方式编写代码。比如“禁止外部可控数据作为进程启动函数的参数”这一条款,举例说明了将外部可控输入数据直接传递给进程启动函数,导致程序产生注入漏洞。随后给出了如何避免此类风险的多种可行方案,引导开发人员正确进行安全编码。
2.2 编程指南应用分类
针对不同的场景,每一条编程指南条款的目标、范围以及适用性都略有不同。总体上来说,编程指南把所有的指南条款分为原则类和规则类两个类别。
原则类条款通常是对适用于某个较典型的开发场景或语言特性中的一类指南条款的概括,或者是对于不存在明确的标准的场景,给出指导性建议。比如“标识符命名应符合阅读习惯”这样的原则,是否符合阅读习惯是比较主观,但是尽量让标识符命名有意义,符合自然语言使用习惯可以极大地提高代码的可读性和可维护性。
规则类条款是需要遵从或参考的比较具体的优秀实践,这类条款通常都具有可以量化的评估手段,方便开发人员参照执行。规则类条款又可以细分为两个级别:要求、建议。
• 要求:表示开发团队原则上应该遵从,违反要求类条款往往会导致软件产品的潜在质量、安全以及可移植性等问题。比如“定义宏时,要使用完备的括号”这条要求条款,如条款所言“宏展开时只做文本替换,在编译时再求值。文本替换后,宏包含的语句跟调用点代码合并。合并后的表达式因为操作符的优先级和结合律,可能会导致计算结果跟期望的不同”。违反此条款往往意味着程序的正确性无法保证。
• 建议:代码风格类多属于这类条款,除此之外通常表示条款属于最佳实践,有助于进一步降低风险或优化代码。建议类条款作为优秀的实践经验的总结,通常是被广为接受的,但也并非就是唯一的正确选择,开发团队可结合具体实际情况考虑是否采纳。比如“行宽不超过120个字符”这条建议条款,从最早的行宽80到现在的120,具体的行宽要求也是顺应着开发人员的显示器或编辑器的可显示能力的变化而调整的。具体采用行宽80、120还是其他合理的值都是可以的,具体要看开发团队的实际情况。
3、如何落地编程指南(HOW)最理想的情况,是所有的开发人员都通过学习,掌握了编程指南的内容,然后编写出的代码都符合指南。但上述场景终归只是个理想。因为开发人员很难完全掌握内容繁杂的编程指南,尤其对于新手,经常会忘记部分指南的内容。这导致他们编写的代码里面不可避免的存在或多或少的违反编程指南的内容。
对于这些违反编程指南的代码,代码检视是发现它们的重要手段。可以说,审核代码是否符合编程指南,是代码检视的核心内容之一。开展代码检视的人员,通常是经验丰富的开发人员,对于指南内容的掌握也更加深入。
对于代码检视人员,其实他们也很难掌握指南的全部。尤其是对于资源泄漏等复杂的场景,人工检查效率很低。这时候,自动检查工具就可以发挥较大的作用了。当然,部分指南的内容过于笼统,还是需要人工检视人员。例如,类似“标识符命名应符合阅读习惯”这样的内容,目前工具识别的准确率还不够高,主要需要依赖检视人员来发现。
3.1 检查工具
基于现有的代码分析技术,研发人员综合运用语法树、数据流分析、控制流分析、指针分析、符号执行、约束求解等技术,开发出了许多代码检查工具,以自动地发现违反编程指南等规则的缺陷代码。华为公司在长期的代码检查实践过程中,结合研发侧对编程指南落地的诉求,研发了自己的代码检查系统CodeCheck,并在检查引擎的选择、研发上积累了大量的经验和教训。
3.2 检查流程
代码检查工具是否能融洽地集成到开发人员的工作流程中,往往会成为代码检查工具落地的门槛。华为倡导根据开发人员在编码、入库、持续集成阶段对检查速度与能力的要求不同,在不同阶段配置不同的检查规则,以较好地兼顾开发人员对检查时间与检查能力的要求。
• IDE:编码阶段是最早的缺陷检查时机,可以利用IDE插件实现检查功能。但由于一些缺陷的检查(例如资源泄露)需要对代码进行全量分析才能准确发现,而且耗时很多,因此这个阶段不用对所有的规则进行检查。
• 门禁:在门禁上做检查是最重要的时机。一方面,很难保证所有的开发人员都自觉地在编码阶段进行检查;另一方面,代码一旦通过了门禁,进入了代码库,就成为公司资产的一部分,并可能被大量地复制。这个阶段的检查,也可以被称为“检视机器人”,可以帮助 Committer 发现一些共性的问题,分担Committer的一些低级工作。由于程序员对代码合入时间比较敏感,因此,非常耗时的检查规则也不适合在这里部署。另外,在门禁阶段,便于进行增量式检查,即只检查新写的代码。
• CI:CI(持续集成)由于频率低一些,有些甚至可以放在晚上等非工作时间,因此对代码检查时间的容忍度相对高一些,适合部署所有的检查规则,并对代码进行全量检查。
3.3 检查报告
面对不同的目标受众,检查报告内容的角度也是同等重要的!例如普通开发人员需要尽可能多的缺陷详细信息;管理人员专注于问题概览,关注目前的产品是否可以发布,关于整体的问题分布;安全人员专注于代码里漏洞等。
检查报告里面通常列出针对某个项目发现的问题信息。例如:总共发现了多少个问题。这些问题中,致命的有多少,严重的有多少,一般的有多少,提示性的有多少,以及问题最多的TOP检查规则,等等。点击相关的链接,可以进一步查看更为具体的问题信息。
针对检查报告里面的列出的缺陷内容,通常情况下,开发人员需要逐条修复,然后再次提交审核。
对于部分检查结果,开发人员可能不采取修复动作,而是对其进行屏蔽。屏蔽的主要原因包括:1)检查报告中可能存在误报;2)部分代码不适合修改;3)提示性的问题;4)开源代码;等等
• 误报:软件分析技术面临的核心挑战之一是精确性与代码规模不可兼得。例如,为了在有限的时间内返回检查结果,许多工具不进行路径敏感等深度的分析。这将导致结果中包含一些漏报与误报。因此开发人员发现某条报告中列出的检查结果是误报时,可以对其进行屏蔽。
• 不适合修改的代码:多数是为了避免执行效率的降低,对于不严重的问题,可以不做修改。
开发人员基于代码检查系统提供的“申请屏蔽”入口,可以在系统中记录下屏蔽信息,下次系统就不再报出这个问题了,以减少对开发人员的干扰。对于开发人员提交的申请屏蔽信息,通常需要有专门的人员进行审核,以保障屏蔽的合理性。
标签:指南,道道儿,检查,代码,编程,开发人员,条款 来源: https://blog.51cto.com/u_15214399/2824785