前言
一般认为,代码复查、结对编程和静态分析如果能够严格执行,对提高代码的总体品质是有好处的。在快速、成功地执行无尽的、重复的任务时,人的能力是有限的,采用静态分析工具执行审查逐渐成为共识,它主要有以下优点:
1)工具运行成本低,只需要人工配置并执行一次,此后可自动执行,节省了很多人力
2)工具审查比人工审查更理性客观
利用工具进行自动化代码审查解决80%的问题,让人来处理另外20%的重要问题,自动化审查可以让人工复查变得更有效,代码底层已经通过扫描检查,人工复查可以关注那些自动化不能处理的方面,如代码是否满足需求,是否从长远来看易于维护等。
审查及其价值
测试是动态的,它执行软件,目的是测试功能。测试包括:单元测试、组件测试、系统测试等。
审查是基于一组预先定义的规则分析代码,由确定的标准指导。包括:编码的“语法”、标准架构分层遵守、重复代码等。
测试和审查是相似的,它们都不会修改代码,只是指出问题可能出现在哪里。
如果缺陷在进入代码后几个月才被发现,错失了时间,问题的上下文环境也记不清了。如果采用工具监控,缺陷可能在几分钟内就被发现和修复,无疑将在很大程度上改进代码质量。
而且,用写代码行数来度量开发工作者的生产效率是不客观的,有些代码测量指标包括了注释,且这种测量方式助长了复制粘贴之风。代码审查的引入可以为解决这一问题提供方法。
持续审查可以减少发现问题和修复问题之间的时间,确定系统中需要特别关注的部分。在CI系统中执行持续自动化审查,可以积极地预防缺陷,并确保一种可重复和一致的方式。
降低代码复杂度
圈复杂度值(CCN),是通过一个方法的执行路径数来衡量复杂性成为一个测量指标,通常是一个整数值。研究表面代码的路径和缺陷之间存在关系。CNN大于10的代码比其他同样规模的代码存在缺陷风险更大。
通过执行审查工具,通常会得到以下报告内容:
1)类、方法、非注释代码行及各种风格注释行数目
2)类中非注释代码行、方法、内部类和注释的数目
3)总体代码的非注释代码行数和圈复杂度
前文曾说,圈复杂度高通常表示缺陷风险高,得到表格后,检查是否存在对应的测试:
1)如果有测试,让测试数目与圈复杂度相等
2)如果没有相关测试,立刻编写一些测试,通过重构降低风险
降低圈复杂度最有效的方法是使用“提取方法技术”,将复杂度分解到更小、更可管理、更可测试的方法中去。
如果发现审查报告中显示CCN值一直在增长,可以采用以下方法:
1)提供足够数量的相关测试,减少风险
2)评估重构的可能性,减少长期维护的问题
可以在自动化构建的过程中执行这些审查,自动化确定代码中复杂度较高的部分,进行改善。
持续进行设计复查
当某对象与其他对象存在依赖关系,一个依赖关系发生变化,这个对象就可能出现问题,“传入耦合”和“传出耦合”有助于确定过度耦合情况。
不稳定性=传出耦合/(传出耦合+传入耦合)
值为0表示稳定,1为不稳定。
传入耦合高的对象会造成破坏,传出耦合高的配件则会受到破坏,为配件编写足够的测试,到达一定代码覆盖率有助于快速定位问题。监控时发现耦合有大量增加的趋势,可以采取下面措施:
1)根据发现的风险立即创建测试
2)评估耦合可能对脆弱性带来的长期影响
3)执行测试后,考虑通过重构令将来的修改更为方便
维持编码标准
编码标准有利于不同团队不同开发者对代码的共同理解。代码结构的标准化使不同人可以快速判断代码的行为,并进行需要的修改,在开发过程中响应更快,减少对必要人员或团队的依赖。
项目编码标准过多,包括条件语句中括号位置、命名惯例、设计惯例等,要求熟读并牢记这些标准对于开发者来说有很大压力,而且在工作过程中容易忘记,采用工具监督,可以在遇到对应问题的时候及时检查相应条例,及时修改。
CI过程中,代码分析工具可以在项目的版本控制库发生变更时就执行。在文件、结构或其他系统发生变更时分析全部代码,通过反馈机制及时通知到相关人员。通过持续地监控和审查代码,可以使团队保持遵守架构和编码指南,问题可以早发现、常发现,从而避免长期维护的问题。
减少重复代码
复制粘贴代码的现象总是存在的,而且通常问题是开发者根本没意识到自己正在做这种事,复制粘贴出现时的情况通常有:
1)数据库逻辑,包括存储过程和视图
2)编译的源代码
3)解释的源代码
4)构建脚本
5)数据和配置文件
可能导致以下问题:
1)增加维护成本、需要多次发现、报告、分析和修复缺陷
2)不确定是否存在其他缺陷
3)对额外编写的代码增加了测试成本
通过自动化审查工具,可以找出代码里重复的部分,得到代码的重复率,从而减少这些隐患。
判断代码覆盖率
判断代码覆盖率有不同的覆盖率测试方法。大多数方法只关注“行覆盖率”(语句覆盖率),其实这只能表明代码行被执行过,即:10行代码其中有7行在测试中得到执行,这个方法的行为覆盖率为70%
有些工具也提供“分支覆盖率”,尝试测量判断点的覆盖率。对于分支覆盖率报告来说,如果存在两个分支,测试过程中两个分支都执行到了,那么可以说这个方法的分支覆盖率为100%。
监控覆盖率报告可以帮助开发团队快速定位那些新写的、没有对应测试的代码。比如之前的覆盖率达70%,本周更新包的覆盖率变成60%,可以判断:
1)包的代码行数增加了,但新代码没有编写相应的测试(或新测试没有有效覆盖新代码)
2)有些测试用例被删除了
评估代码质量
1)覆盖率检查频次
代码覆盖率工具为了能生成报告,都会在源代码上稍作修改,成为“监听者”,需要消耗的时间稍长,可以把执行代码覆盖率的工具作为次级构建。
由于测试会分为不同阶段,单元、组件测试发生比较频繁,结合代码审查不太合适。可以在系统测试执行之后再执行另外一套测试,这时打开覆盖率检查开关,在下班后或夜晚执行。
2)覆盖率与性能
覆盖率测试过程会影响测试性能,建议不要同时执行性能测试、压力测试、负载测试。
实践自检
1)测试是定期、偶尔还是持续执行?是否有配合覆盖率检查?
2)是否在监控代码的复杂度?
3)是否运用工具持续进行自动化的设计复查?
4)是否监控代码的重复情况?
5)是否能判断当前代码覆盖率?如果根据数据反馈进行处理?
6)构建过程是否产生覆盖率报告?