TICA 2019 京东数科研发效率和质量提升实践

阿里QA导读:快速迭代是互联网公司的典型特征之一,这也要求技术团队能够做到快速交付,然而快速交付就意味着要牺牲一定的质量吗?研发过程中,是什么样的痛点、需求阻碍了效能的提升?京东数科熊志男老师,在TICA 2019为我们介绍了“以质量为前提的效能提升”,以及京东数科的研发效能平台,是如何在实践落地过程中,通过一点点的经验积累和不断改善,最终像一颗大树一样长起来的。

我是熊志男,来自于京东数科, 是研发效能团队的一名开发工程师,我今天跟大家分享的是研发效能团队为公司上千研发提供工具和技术支持过程中的一些心得体会和经验教训,希望能和大家一块探讨一下。


关于研发效能提升我有一些个人的想法和思考:站在不同的视角看研发效能,对效能的理解是不一样的。比如说作为管理者和作为一线的开发工程师,关注点都是不一样的。

一、不同视角的研发效能

我们作为研发效能团队,会面对两种不同的用户:首先是公司内部的研发管理者,另外一类就是一线研发工程师。我们需要满足他们不同的需求,在这个过程中就会遇到冲突或者是矛盾。我们曾经做过一个小调研,目的是为了收集一下大家在使用效能工具平台时候有什么痛点、是否是编译构建太慢不好用、上线流程太多、卡点太多不方便或者是代码扫描执行太慢。不过最终收集上来的结果其实还有一些挺意外的不一样的观点,有的研发说我最迫切的提升效能的需求是希望给我一个最高配的Mac笔记本电脑,这是不是有点想的不一样?他说你看我现在的电脑做编译需要几分钟,执行打包也很慢,比如说本地的代码检查,打开一个IDE都特别慢,非常浪费时间、非常痛苦。后来我们找到这位同学和他沟通说给你加一个内存或者是给你一个高配的台式机,应该就可以了吧。然后他说不行,他说我就是觉得Mac用的爽,要的是一种感觉。

转过头来思考下,我们开发研发效能平台的目的就是说让想能够把日常的手工的操作解放出来;对于一线的研发工程师来说他希望减少束缚,不要有太多的卡点,比如我要申请一个机器要过很多层审批。另外他们还希望能够为日常研发工作提供一些赋能,比如一些自动化编译构建、自动化单元测试和自动化打包发布等等这些能力。其实站在研发者的角度来说这是很切合实际的需求。


那如果我们切换一下视角。作为老板的视角,有可能会更加注重度量,度量代码的提交数量、代码扫描出来的违规数量、单元测试写的数量,最好能够对应到个人,到底是哪个人写的代码多、哪个人写的质量好,要做到这样。可能还希望能够设一些合理的卡点,比如说我在合并代码的时候必须要经过代码检查,在提测的时候必须单次覆盖率达到一定的要求才能提交,上线的时候也要发邮件通过我的审批,要不然不能随便上线。而站在管理者的视角,为什么会有这样想法?其实我们团队内部也在回顾这件事情,就总结了一下:其实作为管理者,他希望团队能够规模化的作战,才能够更大发挥出我们的效果,达到1+1>2的效果,而不是说纯粹靠个人,个人能力高、个人能力强那就强,写出的代码就好,个人能力差就不行。


回到我现在所在的公司京东数科,以一个金融科技服务为主的公司,它在实际研发中有哪些质量和安全方面的要求和诉求?也就是说在研发管理层面有哪些诉求呢?

首先,现在有些人说一些互联网公司为了追求快速的迭代,要快速的交付,恨不得每天上线。他说你们这么快,肯定是以牺牲了一些质量为代价的,这个观念肯定是不对的。就是说如果你没有以质量为前提的交付和研发效能的提升,肯定是不对的。


我们公司作为提供金融类的产品,它肯定要求有比较严的合规审计,它需要有代码的严格管理,就是分支管理,比如说代码不同分支要有不同的权限、哪些人要有哪些权限,比如说我对这个代码都做过一系列的操作,比如我创建了几个分支,然后对谁赋予相关权限,这些操作日志都要记录下来。还要实现从原码到上线的一致性,就是上线的部分必须保证测过的。


而且版本在流程中都必须是可追溯的,比如说出现比较严重的线上问题肯定要追溯,线上是哪个版本,当时是经过谁测试、谁开发、谁合并代码,整个过程都需要追溯,从而来分析原则,可能还要定责。


安全性对金融类产品也是很重要的,网上以前也出现过安全事故,比如说账号被盗或者出现信息泄露,都是影响比较大的。因此会有比较高的安全合规的要求。


快速迭代肯定是一个必选项。即使你有这么多要求,还是需要快速地做出一个最小的MVP版本进行验证到底是否可行,然后再大规模推广。如果不能做到快速迭代,很可能会丢失市场机会。


再回过头来看研发过程中的痛点和需求。我们刚才说到研发有具体痛点,研发有哪些具体痛点?我们这些年跟一线研发打交道过程中逐渐积累了一些问题:

 

  1. 人工操作。比如最早是需要人工打包,人工打包就涉及到机器性能不一样、打包的速度不一样,如果是C++或者C语言类打包就更慢了,会很耽误时间;执行测试,其实我们有些研发可能还不太擅长写单元测试,需要人工写测试、调试,都是很费时间的;上线发布也是有这样的很痛的例子,在早期的时候上线发布也是靠运维人员来人工操作的,都是非常低效的。对于研发人员来说,如果每天都在做这样的工作,就可能没有时间做很多高技术含量的事情。

  2. 多人协同。比如一些依赖冲突的问题,依赖Jar包冲突等等,后面会讲到具体的案例。合并冲突也是如此,比如我要上线了,准备合代码,发现了冲突,需要解决很长时间。可读性差,我们经常会发现多团队之间合作,也会进行组织结构调整,原来做系统的团队可能做别的去了,他把这个团队交接B团队,B团队说我看不懂代码,我重新写,这都是活生生的例子。

  3. 代码质量。原来对于提升代码质量,也没有什么好的手段,只能人工看,每一个团队都有一个架构师或者技术带头人来把关,纯靠人。当然纯靠也能实现,但是不可复制,万一这个人离职了呢。

  4. 个人提效。比如提升一线研发工程师基本能力?可以利用一些好的工程实践,比如做好测试驱动开发,可以写很好的单元测试,这样就可以减少很多的调试时间。


   基于这些痛点,我说一下我们最开始怎么做,然后后面怎么逐渐做改善。

二、人工驱动的质量管控

我们团队早期有点像很多企业里面的配管团队,但职责又会多一点,就是有一部分配置管理和研发支持的工作,还有一部分质量管控的工作。具体的工作是怎么做的?

首先是配管要统一配置管理,谁要开分支、加权限、加角色,都找我们的人,我们给他加分支和角色。早期研发要加个权限,就找我们,需要改构建步骤,我们就给他改脚本,还有比如说改代码仓库地址,也需要我们支持,我们称之为保姆式支持,所有的事情是我们代替研发人员做的,不是他做的,而是我们来做的。其实他也可以做,但我们为什么要自己做?一方面是为了达到管控的需求,希望把这件事情集中化、方便管理。但我们又没有工具和平台,那时候只能靠人,这样能做好管控,但是团队的人会做的很累。当然也有很多积淀和成长,也还是挺有意思的一件事情。


我们团队当初还有一种双重角色的感觉。第一种是服务角色,要提供保姆式服务;另一方面我们又要负责质量管控,这时候研发又要求,说你的度量结果给我看看,比如我们统一有一个质量周报,会有每周的代码的违规数据,说为什么我那个会比较低,给我看看怎么提升;比如说我要加什么权限,你能否尽快帮我操作一些;还有一些合规审查的,你能否帮助我解决一下。这个时候,我们又像家长式管理,要把整个研发过程管控起来。

然后分享下具体的趟过的坑。首先是从编译构建开始,我们目前要求所有上线的包不能用snapshot版本,因为这个版本问题遇到过很多的坑。我们在做构建过程中如果用快照包,会遇见各种各样的问题,有时候经常是调试半天很难找到原因,因为我们现在加载进来依赖一个A包,它里面原本提供了A方法,但是它又做了一个改动,然后发一个快照包到我们的私服,我们下载下来是最新的,最后引入和调用它的时候就会出现问题,因为它可能对A方法做了修改或者删除都有可能,使用方完全不知道。


还有开始比较依赖Jenkins工具,其实jenkins解决了很多问题。但早期的时候是我们使用jenkins来执行脚本,有个上千行的脚本,大家知道脚本还是不像java代码这样的好维护、易读性,经常会出现各种各样的问题。后来在我们没做工具改进的时候,我们也是把脚本重新梳了一下把结构图理顺了,遇到问题的时候定位好一些、方便一点,后来脚本完全替换掉了,加入自研的Pipeline,就会简单多了。


度量维度最开始关注缺陷数据。但是每个人提出粒度不一样,有的提缺陷粒度很粗,有的粒度很小。拿缺陷度量会产生各种各样的问题,还有就是维度单一。早期我们没有做代码质量平台改进的时候用了开源工具,但它也有一些问题,其中有个空指针扫描规则的误报率特别高。当然,后面也对规则做了一些改进。


我们就理了一下做这些研发效能从哪儿开始做?它有一个链条。比如我们按先后顺利来,从源头上,源头上是代码的分支管控,然后是编译构建,然后做测试环境,还有上线发布,这些必选流程。再加上可选流程,比如说代码扫描、单元测试,这是属于提升类。 

代码方面,我们这里分支策略一直也在改进,但目前大部分是采用上图的分支策略?确保Master和线上的分支是一致的,由平台托管了Master的权限,只有平台有Master权限,研发团队都是有自己开分支的权限。目的是为了不让大家随便往Master上提交代码,而且每次提测的时候都要拿过现在的代码和Master去对比一下,看看有没有新的代码没有合进来。另外提测的时候会打B-Tag,交给测试人员测。最后上线的时候,要上线发布的时候会打一个R-Tag,我们每个都是基于包上线的,而不是每次要发布的时候打包,这样就保证它的可追溯性。

我刚才讲到了很多坑,按顺序来说我们先做的代码分支的管控,然后是做编译构建的规则检查。编译构建的规则检查不是我们随随便便想做哪些的,这些都是历史上我们遇到的问题所积累下来的。刚才也提到了我们禁止用SNAOSHOT版本上线。


然后是Jar包黑名单,有一些依赖的开源组件存在安全风险,我们都会记录下来,然后每次扫一下你引入了一个有风险的包,我们就会把风险提前暴露出来。除了引入外部的风险,还可以查看有风险的组件包都被谁引用了。


还有依赖冲突检查、groupid规范和版本规范的要求和插件白名单。刚才说Jar包黑名单,而插件白名单是我们为了做出一定的规范,就是你必须在这些加一些插件,比如说你要发布一个Jar包出来给别人用,你必须要有文档,没有文档,别人不知道你是干什么用的。还有重复类检查,还有资源文件白名单,资源文件白名单已经为了控制编译打包中的不可控的问题,典型的资源文件白名单就是我打的这个包是给别人依赖的,里面有一个配置,我在业务线上也写了一个配置,很有可能这两个配置发生冲突。我用的过程中,我自己用的配置没有生效,但是依赖Jar包里的配置生效了,这是有问题的。所以就通过平台管控,不让随便加资源文件,以便来增加可控性。

三、质量和效能的平台化

现在大家都在做代码扫描,有的是纯粹的人工查看。常常需要花一些时间来Review一些低级错误,比如基本的空指针异常、判断逻辑错误和计算符号错误等等;其实可以通过工具来把低级错误过滤掉,这是很好的手段。


开始的时候,我们就是用开源工具,但会遇到问题。因为如果用开源工具,就会遇到开源规则和数据收集的问题,还有权限管理等问题。为了解决问题,所以我们才做的代码扫描平台,做代码扫描平台实现了代码度量的目的。 

度量有哪几部分?比如说发布基线的质量趋势,比如说每次扫出来的缺陷是多少,它是增量还是下降的?这样就可以看出我的应用代码是逐渐在变好还是变坏,这是一个趋势。我可以看单个工程的健康值,其实现在有很多工具都有计算公式,比如说根据违规、复杂度、单测指标给你算出来一个健康值,这样就可以团队内部衡量对比或者我自己看一下,比如说有的人希望有一个排名。还有很重要的一点是把高风险的暴露出来了,有一些风险等级高的问题是零容忍的,不希望出现,可以把这种优先级展现出来。

目前代码扫描依赖两个工具:一个是开源的,一个是商业的,作为后台的代码扫描引擎,现在也在加入别的。我们用商业工具过来可以弥补缺陷,还能做两者的对比;规则中心:是为了满足各个团队的定制化需求,团队业务属性不同要求的规则不一样,而不同阶段用的规则也是不一样的;数据中心:为了实现代码工程级的度量和个人的度量,最后形成画像而反馈出来;配置中心:比如说我就想每次提测的时候不想进行代码扫描,你也可以说你把开关关掉就好了,就是提供更灵活的配置。通过这几大功能,现在就实现了比较完善的代码扫描平台来实现了。

这是一个代码扫描平台的界面,可以看到这里有几个步骤:比如说我创建、扫描代码、商业工具件的扫描、依赖包的扫描结果。能够清晰的看到高级缺陷、低级缺陷,最后还有一个评分,评分是根据工具提供的公式做了一些改进。

这是流水线的应用场景。开始的时候我们用统一的团队,所有的流程必须一致,你必须先编译打包,打完包再发布,这是统一的。但是具体到不同业务团队有更多的分支策略,需要给大家一定的灵活度。如果不能支持不同分支不同流水线的编排需求,比如要加哪个阶段进来、要减少哪个阶段,或者说某个步骤的开关,要实现这种功能的话,其实我们原来纯粹靠Jenkins的话已经不能很好支持了,所以我们自己开发了流水线功能,就是为了满足业务团队的定制化需求。而且为什么我要介绍这个?其实这对我们平台推广来说是很有里程碑的事情,因为有了自定义流水线,各个业务团队才能定制化,要不然他就说你无法支撑我的需求,比如你有一个统一的研发平台在跑,各个团队可能只用你来做打包、上线,我自己再搭一个Jenkins跑自己研发阶段的流线水。但如果我们平台支撑了灵活性流水线的定制,大家就说我不用Jenkins了,我用你的就可以了。

具体的就可能和Pipeline有点像,最上层是流水线,然后是阶段,阶段下面有Task,下面是任务。

实现了图形化拖拽,我们实现了这个功能,就能非常方便地创建流水线并进行编辑和配置。


还支持脚本在线、版本管理,还有worker的在线管理、统一支持配置、支持便宜性质等worker的自动扩缩容。

四、长出来的研发协同平台

这个平台不是一开始规划好的,是过程中我们根据研发的需求,解决一线研发工程师的痛点,再解决统一管控的作为管理者视角的事情,再解决自己作为支持团队在支持过程中的重复工作,提升我们支持的效率,最后形成了现在的研发协同平台。平台包含功能有敏捷协同,协同包含产品需求、迭代、具体的数据,交付阶段就是让流程自动化run起来,还有代码的托管以及最终的数据度量。


今天的分享主要是规则检查、代码扫描、分支策略和Pipeline,其他的可能没太多讲。不光工具是生长出来,其实我们团队也发生了一些转变,最早的时候类似于配管团队,大家都是做人工操作、统一配置和质量管理,而我们现在主要以JAVA开发为主,我们做工具和平台。当然还有一些人工操作,还有一个人专门处理人工的配置操作,现在大部分的工作全部让研发通过我们的协同平台来实现自主操作。

最后回归到,我认为研发效能和质量的提升就是这句话:寻常之处见功力,细微之处见真章。这个历程其实也是我们京东数科研发效能平部向JCI团队的转型实践。


最后,非常感谢大家,也感谢主办方,谢谢大家!