让所有代码都经过检查

提纲

  • 让缺陷在最短路径闭环
  • CodeCC工具平台大揭秘
  • 告警修复和价值收益
  • 后续展望和愿景

前言

今天谈论 DevOps 这个话题,所以要先来看下代码检查在DevOps中的位置。下面这张图来自于乔梁老师《持续交付》那本书,一个简单的部署流水线示意图,简化表示了软件开发从代码提交、编译构建、代码检查到各种测试最后发布到用户手中的一个自动化过程。

从左到右随着活动的进展,我们对版本的信心度越来越大,从右到左看我们希望每一个阶段都能有更快的速度将问题向开发者反馈。

从这张图可以看出提交阶段是整个部署流水线的入口。提交阶段主要包含的活动有:编译代码,运行单元测试,执行代码检查,创建二进制包等。

提交阶段的首要目标是在那些有问题的构建代码在引起麻烦之前,就把他们拒之于门外,因为当缺陷还比较容易修复时,尽快得到反馈是非常重要的,这时候引入错误的人对上下文印象还比较深,而找到错误原因的方法也比较简单,如果时间隔得越多,这个活动就越困难。本文后面的所有内容,都是围绕提交阶段的代码检查活动来开展。

让缺陷在最短路径闭环

【曾经那个黑色的四月】

做项目最怕的就是出质量事故,2012年某开发组4月份出了两个大事:

  • 4月11号升级版本时大量用户登录失败,遭到了合作方投诉……
  • 4月28日某项目新开2个服务器后出现大量崩溃……

第二个事故处理完成,leader及时写了一封说明邮件,问题的根本和直接原因是程序中写内存没有做数组边界判断,导致访问越界。之后开发团队一起做了一次质量回溯,一轮原因头脑风暴下来,真相慢慢浮出水面。

后来就在组内成立了质量改进小组,重点进行代码质量改进,当时其中一个重要改进措施是用静态代码检查工具Pclint扫描代码,要求是在转测前Pclint扫描结果清零,这也是后续在更大范围做代码质量提升活动的萌芽。

【缺陷的发现成本和修复成本】

下图来自于《代码大全》中的行业经典数据分析,第一张图行表示引入缺陷的时间,列表示检测到缺陷的时间,可以看到检测到缺陷的时间越靠后,修复缺陷的平均成本越高。但是比较尴尬的是,这种情况还比较多的出现,绝大部分缺陷在修复成本比较低的时候被引入,大部分缺陷在成本比较高的时候被发现和修复。

第二张图指示在软件开发过程中有各种检错措施(各种质量保证活动),个人桌面代码检查是其中一个方法,从经典数据来看还是一个效果不错的方法,典型检出率能达到40%,文章后面也会有相关实践数据和大家分享。

【工具检查代码曾经面临的问题】

从前面描述可以看出,代码质量问题曾经带给我们很多麻烦,代码检查活动也确实有很多好处,它客观全面,一致性好,成本低,更加严格。但是其实要真的把有效的代码检查工具运用到开发活动中,也不是一件容易的事情。

  • 首先我们要去寻找合适的工具,有商用,有开源的,各种各样评价不一,要开发同学投入人力一一去选择。
  • 其次要研究使用方法去试用,怎样才能用上,是不是这个工具真的能够达到我们的要求?
  • 再就是这个工具易用吗?查看代码方便吗?邮件报告方便吗?如何去改造成我们想要的样子?
  • 最后就是一个开发团队经过辛苦探索用上了,其他开发团队能分享使用吗?

以上每一个环节,都能让这个事情停止。

【CodeCC诞生了】

看到了代码质量的重要性,看到了工具检查代码的价值,为了帮助开发同学们解决以上问题,CodeCC诞生了,第一个版本在2016年10月24号发布,它是一个开放的代码检查平台,集成了多维度代码检查工具,为开发团队提供代码检查解决方案及服务。

CodeCC工具和平台大揭秘

代码检查工具这部分我们主要围绕两个方面来做重点建设。一是有效性,能不能检查出很猛的,比较深层次的问题,CodeCC主打的商用代码检查工具Coverity是行业公认的比较厉害的能够发现比较深层次问题的静态代码检查工具。二是多样性,就是能不能支持多种语言,多种质量维度的代码检查。

CodeCC目前共支持编译型语言和非编译性语言共11种。代码检查工具按照支持的质量维度来分主要有两大类,一类是能够检查出深层次代码缺陷类的工具,比如Coverity和Klocwork,还有一类是代码坏味道检查工具,比如各种编程规范,圈复杂度检查,重复代码检查等。

【这种问题都能扫出来!】

先从代码缺陷这个维度看,CodeCC能够帮助开发同学检查到哪些问题呢?

这里以三类告警为例介绍背后凉凉的问题,都是在开发过程中很容易犯的错误,比较严重,容易引发崩溃等等。同时从我们的修复数据观察这也是修复量排在前几位的告警。

第一类就是数组越界,规则名称是OVERRUN,前面两个质量事故都是这个问题造的祸。代码片段中标识了发生错误的代码行,因为没有对数组下标的边界做正确的判断,把entry后面的数据写坏了,这种数据写坏的问题甚至比宕机还严重。

第二类告警是空指针解引用,工具规则名称是FORWARD_NULL。这行代码将指针与Null进行比较意味着它可能为空,发生错误的代码行解引用了这个空指针,这是编程中十分常见的问题,会导致程序Core Dump。

第三类告警是资源泄露,规则名称是RESOURCE_LEAK,看错误代码片段,循环体内申请了文件资源,有break语句可能跳出循环,并导致该文件资源没有及时释放,因此造成了资源泄露问题。这个危害是“日积月累”的,慢慢侵蚀应用程序和系统中有限的资源,最终导致性能下降,甚至引发崩溃。

【代码整洁之道】

参考维基百科上的说明,代码坏味道通常不是bug,他们不是技术上的错误,并不一定能引起程序的功能问题。

Martin fowler《重构》第三章专门讲了22种代码坏味道,位于之首的是重复代码,过长的函数,过大的类,过长参数列等等都是代码坏味道,最后一个是过多的注释。

下图来自于代码整洁之道,漫画中用“每分钟骂人的次数”来衡量代码质量的好坏,这也是和实际情况比较符合的一个玩笑。

那CodeCC能够发现哪些代码坏味道呢?

第一类就是重复率检查工具能发现程序中的重复代码,CodeCC能发现不同文件/相同文件的代码重复情况并方便的进行查看和比对。

第二类是编程规范,CodeCC有各种语言的Lint类检查工具可以检查编程规范,比如下面例子中过长的代码行,过长的函数,头文件不规范,参数列表过长等等。

第三类就是复杂代码,CodeCC有圈复杂度检查工具可以检查代码的复杂性,下面这段代码示例圈复杂度达到了88,嵌套大量if,else,switch,后面还有17个case。

这里也想说明一下,前面我们说到的开发同学工具使用的探索成本,并没有消失,这里只是交给了CodeCC的工具团队,每一款工具上线前,我们都经历了非常严格的流程,从目标语言工具确定,到最后灰度上线,开展易用性调整,才正式发布到开发同学手中使用。

【平台的易用性】

平台的存在是为了方便工具的使用,更大程度发挥工具的价值,最初大家真的都有一些痛,比如:

CodeCC实现了以下平台特性,轻松解决以上问题。

  • 亮点一:自助接入 开发工具适配组件,最大化减少工具安装需要的服务器申请,环境配置修改等工作量,实现编译型工具0.5小时接入,非编译型工具分钟级接入。
  • 亮点二:扫描方式 可以根据需要自行平台配置实时触发扫描或定时扫描的方式,并且同时可以配置你想要的扫描结果报告方式。
  • 亮点三:告警展示 多个工具一个平台查看结果,无需跳转,直接点击查看告警代码;同时可以轻松实现单个告警忽略以及按照路径和规则进行告警屏蔽。
  • 亮点四:数据报表 清楚展示新增/修复/遗留告警,实时把握代码质量趋势变化。
  • 亮点五:规则配置 行业首创规则包定制方法,开发团队根据项目特点配置自己的规则组合,自行调整规则包。

……

以上所有,都让代码检查这件事情变得更加容易,这是促进开发团队使用代码检查工具在开发前端闭环代码缺陷的有利条件。

【平台的开放和合作】

CodeCC是一个开放的平台,已经通过API接口和公司各个持续集成的系统打通,为工具链提供代码检查能力。

以IEG蓝盾DevOps平台为例,CodeCC是蓝盾平台的一个服务,可以在流水线中以原子的方式让开发同学进行配置,同时设计的质量红线这个服务,可以在转测试/发布设置质量关卡配置拦截规则,举个例子,严重清零才能转测/发布,否则就停止流水线,同时还有人工审核或其他通知方式可供配置。

告警修复和价值体现

CodeCC具有工具的有效性和多样性,平台的易用性和开放性等特点。但其实,不管检查出多牛逼的告警,没有修复的话,所有的一切都是零。代码检查活动最终的价值体现在检查出来的告警被修掉了。这一部分重点是讲告警修复的方法以及修复之后给开发团队带来的收益。

【告警修复三部曲】

第一步是最难的,那就是历史告警清零。

关键人物:Leader 关键行为:梳理分配并制定计划 成功因素:决心

第一次扫描看到一堆告警的时候,大家都很发憷,很多开发同学都问我们到底要花多少时间把历史告警能够清零。那到底要花多少时间呢?

1、每天不超过半小时,共十多天!

“组长每天给组内每个小伙伴分配20多个告警,当天清空,每天耗时不超过半小时,坚持了十多天就把历史告警全部清空了,现在每天新增的告警很少,并且可以精确到人,所以每天早上基本就可以清空所有告警。”

2、2天580个。

“CodeCC上有各个告警代码片段和解释,按照对应的提示进行修改,我是两天集中处理,改到很晚修了580个告警,希望大家养成良好的编程习惯,提高代码的健壮性。”

历史告警不修复有什么问题呢?虱子多了不痒,债多了不愁,反正都有那么多了,再增加点何妨?因此,各位开发同学一定要重视历史告警清零。更何况,从那么多的经验来看,你和历史告警之间,只差了一个决心!

历史告警清零后,很重要就进入了第二步,日常新增告警持续清零。

关键人物:All 关键行为:每天关注并修复告警 成功因素:习惯

有些是在不想去动远古历史代码的,也可以直接进入第二步,那就是约定,新增告警清零,历史不增长。CodeCC平台数据报表和邮件报告都很清楚的对每日新增修复遗留告警进行指引并分配到代码提交人。我们这里继续看看两个项目组的实践心得。

第三步需要将代码检查这个活动固化进流程。

关键人物:Leader/QA 关键行为:制定规则固化进流程 成功因素:文化/IT自动化

主要包含两层含义:

1.团队约定形成代码质量标准,一起制定质量约定,将检查结果作为转测标准/发布标准,大家共同遵守。现在大多数团队的约定是转测/发布的时候告警清零。

2.将代码检查工具集成进流水线,自动化开展代码检查,设置质量关卡,拉响我们的质量红灯。参考上面蓝盾集成质量红线的实践。

【反馈是行动得以持续开展的动力】

告警修复习惯的养成需要动力,也需要压力。CodeCC利用层层修复数据度量报告作为反馈的重要手段,同时还持续开展质量文化宣传,让空气中弥漫着代码质量的味道。

主要目的是为了透明修复进展,表扬先进,同行压力,给大家一点成就感,把告警修复活动养成习惯。

1、日报:所有接入CodeCC的用户都可以自行定制报告,可以选择定时报告,也可以选择实时报告,报告中有新增/修复/遗留的告警信息,针对修复良好行为,还有即时自动识别发放的勋章奖励。

2、月报/双周报:月报/双周报重点展示各部门整体状态及趋势,表扬修复突出团队,形成同行压力。

【价值收益】

1、产品质量提升,崩溃率降低 以下来自某手游客户端的数据及修复的主要告警类型举例。

*REVERSE_INULL(空指针解引用)-游戏UI中使用某节点的指针是很常见的操作,由于很多UI是动态加载的,代码不规范容易造成Crash。

OVERRUN(越界访问)-数组越界常常导致外网一些莫名其妙的崩溃,CodeCC能很方便的定位到可能越界的地方,牌型算法中经常遇到的问题。

UNINIT(未初始化变量)-这种粗心大意导致的问题也很难查,经常由于未初始化产生的随机值而导致很多异常的产生,解决这类问题,除了提高自身代码素养外,CodeCC可以很精准的找出这类严重问题。*

2、对开发自测活动形成有力补充,提升开发阶段缺陷发现/修复率,提升开发效率,降低开发成本,让缺陷在最短路径闭环

3.帮助开发同学养成代码检查好习惯

原来:等测试同学告诉我哪里有错,不在意代码里面的坏味道……

现在:写完代码,上CodeCC看下,违反规范了吗?有没有写出复杂的函数?重复率变大没有?

后续展望和愿景

这两年,CodeCC为腾讯各个BG各个产品提供代码检查服务,作为持续交付流水线中的一个重要环节,我们将在以下重要维度继续发力!

工具:

持续行业新工具研究及应用;

支持工具规则自定义,满足不同项目/场景代码质量要求;

平台:

开发API站点,和DevOps工具链打通;

逐步开放平台能力,比如用户自行定制规则,接入工具等;

更加易用,有保障的安全/基础设施建设;

让所有代码都经过检查,大家一起努力!


参考书籍:

1. 《持续交付-发布可靠软件的系统方法》【英】Jez Humble David Farley 著 乔梁 译

2. 《代码大全》(第二版)【美】Steve McConnell 著

3. 《代码整洁之道》【美】Robert C.Martin 著 韩磊 译

原文发布于微信公众号 - DevOps时代(DevOpsTimes)

原文发表时间:2018-11-14

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Java架构师进阶

阿里优酷面试经历——学无止境

最近几周与阿里的面试官聊了聊,趁着我还有记忆先写下来。本人近5年工作的JAVA程序员,技术不精。大伙不必太过吐槽。哈哈。我曾两次时间投过简历。

15750
来自专栏java一日一条

程序员你为什么这么累?

大家一提到程序员,首先想到的是以下标签:苦逼,加班,熬夜通宵。但是,但凡工作了的同学都知道,其实大部分程序员做的事情都很简单,代码CRUD可以说毫无技术含量,就...

11440
来自专栏无原型不设计

Mockplus是如何节省你的原型时间的?

还在用老牌原型工具一点点绘制产品原型吗?还在为实现一个满意的交互而绞尽脑汁吗?还在为无法和用户高效沟通而发愁吗?朋友,现在是快速原型的时代了。时间不等人,当你...

28930
来自专栏杨建荣的学习笔记

数据库和开发行业中的IDE工具

在我从事DBA工作的这些年,经常会有网友会问我,数据库有什么好的工具可以使用,让我给推荐几个,数据库的工具还少吗,Oracle阵营: Toad(付费),S...

52480
来自专栏企鹅号快讯

C语言真的太强大了,C几乎无处不在!

今天存在的许多C项目都是在几十年前开始的。 UNIX操作系统的开发始于1969年,其代码在1972年被重写为C语言。C语言实际上是为了将UNIX内核代码从汇编语...

57570
来自专栏镁客网

微软Edge浏览器支持WebVR,小举动背后的“大阴谋”

13630
来自专栏数据科学与人工智能

【数据】常用API接口汇总

下面列举了100多个国内常用API接口,并按照 笔记、出行、词典、电商、地图、电影、即时通讯、开发者网站、快递查询、旅游、社交、视频、天气、团队协作、图片与图像...

7.4K110
来自专栏点滴积累

geotrellis使用初探

最近,单位领导要求我研究一下geotrellis(GITHUB地址:https://github.com/geotrellis/geotrellis,官网htt...

45280
来自专栏人工智能

微信机器人-Python学习日志(1)

一直以来,这个号发的都是《狼人杀小程序的开发日志》,体现产品的思路比较多,从纯技术的角度看其实并没有很精彩。这次,来讲讲我在其他方面的探索吧。 众所周知,微信公...

63680
来自专栏FreeBuf

价值3133.7美金的谷歌(Google)存储型XSS漏洞

在漏洞挖掘领域,不谈赏金和其它功利的东西,如果能发现谷歌公司的漏洞或进入其名人堂致谢榜,就已经非常不错的了。今天我要分享的这个漏洞,是迄今为止我上报漏洞中最简单...

15440

扫码关注云+社区

领取腾讯云代金券