我是百度工程效能部资深敏捷教练–金锐,也是百度 DevOps 解决方案的运营负责人。从今天开始,我将在 GitChat 通过一系列的文章,为大家分享百度在软件工程领域的思考和实践。今天我先从百度工程效能部对提升百度软件工程能力的实践和思考介绍开始:
工程是科学和数学的某种应用,通过这一应用,使自然界的物质和能源的特性能够通过各种结构、机器、产品、系统和过程,是以最短的时间和最少的人力、物力做出高效、可靠且对人类有用的东西。 --百度百科
上述定义摘自百度百科,从这里我们可以看到,广义的工程能力定义很宽泛,涵盖了软件,建筑,机械生产等多个行业。当我在讲百度的工程能力的时候,我更多提到的时百度的软件工程能力,下面是几年前公司内部一次会议上,公司领导层对软件工程能力与公司业务竞争力的阐述:
百度如何看待软件工程能力
百度是一家技术公司,研发工程能力的高低直接影响公司的持久创新力和公司在市场上的作为。只有不懈追求卓越的工程能力,才能够带来长期的核心竞争力,才能为每个用户、每个企业客户以及整个社会创造价值。
百度内部有多个业务形态各异,团队规模不同的产品线,下面一系列数据出自 2018 年工程效能部的数据统计:
从数据上可以看到,平均每个工程师每天要进行 3 次构建;执行 7 次以上的流水线;平均每个披萨团队,每天要进行一次服务的发布。而且在这些数据的背后,是 10000 多名有着强烈的自驱意识,勇于不断尝新的软件工程师。因此对于百度工程效能部来说,提升百度工程能力,是一件挑战巨大的系统性工程。
百度工程能力的发展历程,大致经历了三个阶段, 分别是:
在这个阶段,百度在软件工程领域要解决的首要问题是: 百度的软件研发管理对象是什么?对象之间的关系是什么?一个标准的,符合规范的研发流程是什么样的?
现在回顾起来,我们非常感谢那个时代工程效能部门的同事,为我们后续的管理奠定了坚实的基础,具体规范如下图:
从这张图上可以看到,我们当时定义了几个最基础的元素:
当时的一切软件研发工作,是围绕着模块级别发布进行的: 每一个项目在启动的时候,RD(开发工程师)会从当前模块基于线上的 3 位版本拉一条分支,建立一个新的 4 位版本;当开发完成后,RD 通过一个叫做"提测"的动作将构建产物传递给 QA(测试工程师), QA 在测试过程中发现的 BUG 会记录在当前的 4 位版本上,RD 修正后重新生成一个 4 位版本号再次交付 QA 直至最终测试完成,模块发布上线后,更新三位版本号,做为下一次拉取分支的基线。这样的流程也很好的支持了当时百度的主营业务–核心搜索。
时间前进到 2012 年,随时互联网思维的普及,更重要的是,移动互联网时代的到来,我们发现: 当时百度的软件研发效率跟不上市场竞争的需求了。2012 年 8 月,我们做过一个统计,当时百度单个模块的发布周期平均值是 21 天,而当时小米号称每周迭代。因此,当时我们要解决的首要问题是如何缩短模块的发布周期。
基于这个目标,我们引入的敏捷开发的概念,弱化项目的概念,强调产品的迭代。同时将原有的工具按照研发的不同阶段,拆分成三个独立的产品: 负责项目和产品管理的 icafe,负责代码和协同开发的 icode,负责持续交付的 ipipe,形成了目前研发工具链的雏形。我们也建立了百度的敏捷教练团队,引入了一批又一批业界优秀的软件工程人才,将敏捷开发的理念带入到产品线中。现在 DevOps 和敏捷圈中的各路英才,有相当一部分都曾经在百度工程效能部任职
经过 4 年的努力,截止 2016 年,我们将百度的模块发布周期从 21 天,缩短到不到 6 天的样子。敏捷开发已经成为百度的主流研发模式,95%的模块从 SVN 迁移到了更加适应互联网研发模式的 GIT 上,我们发布了百度内部的研发方法论专辑: 百度方法+。
反思这个阶段,我们发现:
同时,DevOps,云计算,AI 成为主流的技术,我们面临着更大的挑战:
前面铺垫了这么多的内容,终于进入到我们今天要讲述的内容主体: 当云成为主流 IT 架构,以模型训练为代表的 AI 开发兴起,DevOps 成为软件研发的主流思想时,百度工程效能部如何继续带动百度工程能力的提升。
关于整体提升的策略,我们可以用下面一张图来表示:
首先,我们来看一下人的方面,工程能力提升的根本还是人(工程师)本身的工程素养提升。即使我们有好的流程、方法和开发工具,如果开发者本身的能力和工程素养不够的话,工程效率也会非常低。
为了提升工程师的工程素养和工程能力,我们做了一些实践。例如招聘时,我们一定招优秀的工程师。新人入职之后,我们会为新同学提供工程师能力培养和文化建设的工作坊,这也我们一直在做的事情。工程师入职后,会有“码神训练营”,这个训练营除了介绍编码的规范及开发流程、工程实践之外,还会让大家在工具平台上实际操作,自主开发一个示例产品,促进大家在短时间内了解百度工程开发的流程和规范,建立工程规范意识。除此之外,公司内还有很多培养工程师文化的项目,比如 Hackathon ,还有 Good coder、Excellent Coder 认证等。
和 16 年以前最大的变化是,我们将数据也纳入了整体的提升策略中。
在 DevOps 的理念中,有一个非常重要的核心理念: 建立反馈闭环。我们认为在软件研发过程中,从 RD 每天的拉取分支–coding–提交代码,到模块测试–系统测试,最终到服务发布,产品更新。都应该建立不同的闭环,而在每个闭环中产生的数据,应该以最高的时效性反馈给研发/测试/运维人员。并且不断的引导用户去使用数据,信任数据,最终通过数据的驱动实现团队工程能力的不断提升。
而在以往,这些数据在生产出来之后便被束之高阁,只有在定期汇报的时候才被拿出来使用,为了改变这个现状,我们首先明确了百度软件研发的一系列闭环:
从上面的图中可以看到,在我们的治理思路中,整个软件研发的过程被划分成 4 个闭环:
在以上闭环中,我们认为下列数据是需要被相关人员关注并使用的:
这么多的数据,我们是如何将其一一呈现在整个研发团队的视野中的呢?这就离不开工具的贡献了: 我们在 17 年,自建了研发数据仓库,前面提到几大研发工具平台: icafe, icode, ipipe,之前是每个产品保存自己的数据,建了数据仓库之后,我们将数据以下面示意图的形式组织在一起,形成了从需求到发布的完整研发数据链:
另外,除了这些基础数据之外,有大量的测试结果,覆盖率数据是如何被记录下来的呢?这就得益于持续交付平台 ipipe 的插件式架构设计:
百度内部有几十个不同类型的测试,发布,环境管理工具。为了让百度内部的用户更好的使用这些插件,iPipe 平台改善了底层的架构设计,使这些工具可以通过简单的改造接入 iPipe。做为改造的一部分,这些工具需要通过统一的数据格式将自己生产的研发数据导入到研发数据仓库。这样,研发和测试人员只需要关心自己的日常工作,而数据很自然的就保留了下来。
接下来,数据是怎样应用的呢?首先最频繁的应用在流水线的执行结果中:
这是我在内部代码库提交的一次提交记录, 在图中看到我们配置了一条简单的流水线,只分为编译和测试两个阶段,现在展示的是编译阶段的所有 job。如图所示,用户可以非常直观的在流水线上看到每个 JOB 的执行结果。一旦有错误发生,iPipe 会通过邮件,即时通讯工具向用户推送消息。同时,在展示结果的同时,QA,RD 也能非常方便的观察每个阶段的执行时长,方便流水线的优化。
除了在流水线中应用,我们根据产品,团队,工程师的不同维度,将数据归纳整理:
这便是工程能力地图的主页面,如图所示: 工程能力地图以产品线(多个代码库)为维度,按照不同技术类型(Server, App, SDK)的代码库分类, 将产品线在整个研发过程中对管理,技术实践的采纳情况进行记录和评分,而所有的记录都来源于插件的数据录入。也可以说,页面上每一个色块中的实践,背后都对应着一个标准的实践工具。数据每天进行更新,而产品线的研发经理,测试经理,研发总监根据工程能力地图上数据的变化趋势即可了解自己团队工程能力的改进进展。在百度内部,大多数产品线在建立自己 DevOps 实施目标时,已经将地图上得分的提升做为重要参考。
交付周期散点图显示的是一个团度随着时间的推移,交付周期的变化趋势。怎样解读这张图表呢?横轴是时间轴,纵轴是交付周期(天为单位),图表上的每一个点都代表了一张需求卡片(统计粒度可自选)从建立到上线的确切时间流逝。从这张图上,我们可以解读到以下信息:
如图,这是展示在代码托管平台 iCode 上的某位内部工程师的研发活动数据,上半部分表示了该工程师的提交频次,每次的代码提交量;下半部分的数据说明了具体的量化信息。这个图表是和我们内部所提倡的工程师文化是密切相关的。什么是百度工程师在工程方面应该做的事情,那就是持续的提交代码,并且积极参与代码的评审工作。每次工程师在申请晋级的时候,技术委员会会直接查看该工程师的这个页面,并做为晋级的重要参考。我们经常说,是牛 X 的工程师就把个人页面亮出来。
为了解决前文提到的技术重复造轮子问题,提升技术的复用,我们也进行了百度内部的平台的建设和治理
平台建设包括平台复用和源码复用这两方面。在平台复用方面,我们梳理出公司内部的几百个平台,将这些平台划分成若干个类别,每个类别都成立一个 TOC 组织来负责规划这类平台未来的发展。发展的目标就是让这类平台可用性加强、复用度提高,让平台本身的能力增强,以便让每个业务方能够更快速地使用平台去搭建自己的业务,提高工程效能。
上面介绍平台复用会带来一个问题:如果多数平台逐渐收敛成少数平台后,许多需求都会涌向这些平台,会导致平台研发团队不能按时、高质量完成所有的需求,从而使研发效率下降。那么我们怎么在平台化的基础上去做更好的工程复用呢?
那就是源码复用。在代码管理平台(iCode)上,我们做了内部开源功能。在平台化治理的过程中,平台是否能够达标,有一个考察点是它能不能实现内部开源。如果一个平台的 API 已经对外开放,并且又做到了内部开源能够让其他团队贡献代码协作开发,我们才认为它是一个优秀的内部平台。
百度 C/C++模块开发采用跨模块依赖的形式,其中 97%为固定版本依赖(表现为 Depend on TAG 和 Depend on BRANCH:VERSION 两种形式,本文统一使用 Depend on TAG 表示)。固定版本依赖会导致严重的版本碎片化问题,两年前我们做过一个统计: 百度 top 200 的基础库,在用的大约 5000 多个版本。
版本碎片化问题背后,是严重的技术债务: 维护基础库的同学很难保证不同版本间代码的兼容性,业务方为规避版本不兼容的问题不愿意升级依赖模块版本,导致基础模块发布新版本后,三个月内只有十分之一不到的团队主动升级。如此一来,一方面在基础库维护上浪费了大量不必要的人力,另一方面,大量的业务线也没有办法享受基础库升级带来的好处。
参考 Google 的 Head 依赖模式,即所有的类库引用方,都直接引用类库的 head 标签。考虑到我们内部改造的成本和业务方的稳定性,我们决定推出 stable 模式–即每个类库维护一个 stable 标签,所有的引用方都来引用 stable 标签,基础库的维护团队将基础库的更新发布到 stable 标签上,这样保证了基础库的稳定性,也极大的收敛了基础库的版本数量,减轻了团队负担。
2019 年 5 月, 我们正式将百度内部的研发工具链对外输出,成为百度智能云的子产品,并命名为百度效率云。效率云包括内部的三大平台(iCafe, iCode, iPipe),并与智能云上的容器引擎,微服务平台一起,支持云原生 DevOps 的场景。目前产品处于免费试用阶段,欢迎大家试用
以上就是关于百度工程能力提升的介绍,欢迎大家提出建议和意见。对于云原生 DevOps,AI 服务开发感兴趣的同学,可以关注效率云官方公众号,我们会定期发布产品的最新动态:
再次感谢大家对百度技术的关注。