4

百度开发者中心的个人空间

 2 years ago
source link: https://my.oschina.net/u/4299156/blog/5140140
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

背景
去年底团队接手负责 30 多个面向 ToB 的平台系统,系统多,需求紧,人力缺口一直存在,主要问题体现在:

  1. 前后端部署耦合:前后端资源部署在同一 Web 容器,后端上线会带着前 端,同样前端也会带着后端;
  2. 研发流程不规范:各平台缺少统一的规范,比如分支规范,部署规范,联调规范等;
  3. 研发质量保证:缺少基本的质量保证手段,比如前端单元测试,前后端接口变更流程等;

通过技术手段提高研发效率一直是我们追求的目标。今年通过对业界和公司内部爱番番团队的相关技术调研,决定对现有研发流程进行改进规范,通过 CI/CD 能力建议,提高研发效率和降低运维成本(感谢爱番番团队的 CI/CD 工作!)

今天主要从以下方面来说明 CI/CD 针对 ToB 场景的最佳实践,除了说明做了 What 外,更重要希望能从价值收益上说明 How 和 Why。(注:ToC 与 ToB 各方面差异较大)

什么是CI/CD

简单理解:Continuous Integration/Continuous Deployment

深入理解:基于新兴的 DevOps 文化,以管道的形式,通过自动化构建、测试和部署,缩小开发团队和操作团队之间的差距,以到达快速稳定的交付目的。

  1. Devops
    DevOps 是 Development 和 Operations 的组合,是一种思想、一组最佳实践、以及一种文化,用于促进应用开发、应用运维和质量保障(QA)部门之间的沟通、协作与整合。以期打破传统开发和运营之间的壁垒和鸿沟。

  2. CI
    CI 即 Continuous Integration 的缩写,开发人员将会频繁地向主干提交代码,这些新提交的代码在最终合并到主干前,需要经过编译和自动化测试流进行验证;

  3. CD
    CD 可对应多个英文名称,持续交付 Continuous Delivery 和持续部署 Continuous Deployment;

  • Continuous Delivery
    完成 CI 中构建及单元测试和集成测试的自动化流程后,持续交付可自动将已验证的代码发布到存储库。为了实现高效的持续交付流程,务必要确 CI 已内置于开发管道。
    持续交付的目标是拥有一个可随时部署到生产环境的代码库。

  • Continuous Deployment 对于一个成熟的 CI/CD 管道(Pipeline)来说,最后的阶段是持续部署。作为持续交付 —— 自动将生产就绪型构建版本发布到代码存储库 —— 的延伸,持续部署可以自动将应用发布到生产环境。

涵盖范围
涵盖软件开发全生命周期,作用于各个阶段

基本原则

  • CI 流水线需要很快
  • 独立环境中构建和运行
  • 预发布环境和生产环境等价

CI/CD 实施的基本前提条件是根据团队的技术能力现状,制定符合团队实际情况的研发流程规范。

技术全景图

研发流程规范

  • 分支开发,主干测试,RB 上线
  • 历史分支保留,确保随时上线发布
  • 未测试代码不带到线上
  • 定期检测同步代码机制,尽量避免冲突
  • 各项检查能力 CI 上落地,保障高质量交付

分支管理规范

  • 代码版本分支是自动化构建的基础,开发团队必须遵守
  • feature 非必需分支,各团队根据实际开发协同场景的复杂度,酌情使用
  • 分支命名规范包含上线日期的做法,仅适合 ToB 场景

Pipeline 规范

  • 编译:使用公司统一的集群编译
  • 安全扫描:啄木鸟、猫头鹰
  • 静态代码扫描:包含代码规范和潜在的 Bug
  • 端测试:自动化,稳定性

云端部署(BOS/CDN)

部署设计

方案一与方案二的区别是 index.html 放在 BOS 还是 RD 服务器?
优先推荐方案一:

  • 与后端解耦更彻底,html 的更新可由前端来控制
  • 前端版本号管理放在 html 里,不用更新 version.js,部署更简单

方案一里有些后端可能无法配置转发;

备注:最优方案是由 BFE 配置转发规则至 BOS,不用经 RD 集群,但目前 BFE 无法直接转发至 BOS。

版本说明
前端静态资源版本一般分两种方式管理:
Hash 版本号:基于文件内容的 MD5 值,取部分长度或全部长度,做为文件的版本号,每个文件都有不同的版本号,适合于增量发布,节约存储空间。例如:index.abcd12.js,manifest.123456.js 等

时间戳版本号:以当前构建时间点为准,生成时间文件夹,构建结构部署在时间文件夹下。适合于全量发布。

目前选用时间戳版本号,考虑有如下:

Hash 版本,适合容器化部署,比如 Docker、Jarvis,每次包括所有资源文件;Bos 如果使用 Hash,文件夹下同名资源会有很多,显得较乱。

部署目录结构实例

performance
|---- 202101281200
|     |---- css
|     |---- js
|           |----index.js
|---- 202101291200
|     |---- css
|     |---- js
|           |----index.js
version.js
index.html

index.html 和 version.js 承担版本号维护,每次上线时更新版本号。

现状
前端中是大部分是无测试的,国外的一项调查显示,有 43% 的 developer 没有做过任何前端相关测试,两个主要原因:

  1. 前端属于 GUI 编程,浏览器很多,要在这么多浏览器上做几轮测试,其实是成本很高,很昂贵;
  2. 某些类型的产品当中,很多时候 UI 界面迭代的更快,测试跟不上迭代;

以上两点导致前端测试不受重视,很多开发可能工作好几年年仍未写过测试。

我们为什么要做单测
ToB 业务 与 ToC 相比:

  1. 业务会相对稳定:UI 页面稳定变化少
  2. 稳定性要求极高:需要频繁的进行回归测试,服务的是付费用户
  3. 持续升级迭代:迭代周期相对较长

单测带来的收益:

  • 减少 Bug:如今的项目大多都是多人分模块协同开发,当各个模块集成时再去发现问题,定位和沟通成本是非常高的,通过单元测试来保证各个模块的正确性,可以尽早的发现问题,而不是等到集成时再发现问题;
  • 放心重构:对于持续升级迭代的项目,代码不断的在变化和重构,通过单元测试,开发可以放心的修改重构代码,减少改代码时心理负担,提高重构的成功率;
  • 改进设计:越是良好设计的代码,一般越容易编写单元测试,多个小的方法的单测一般比大方法(成百上千行代码)的单测代码要简单、要稳定,所以在编写单测的过程中,如果发现单测代码非常难写,一般表明被测试的代码包含了太多的依赖或功能,需要反思代码的合理性,进而推进代码设计的优化,形成正向循环;

前端自动化测试分层

  • E2E 测试:是一种黑盒测试,测试的是应用的执行是否从头到尾都按设计完成。
    整个应用程序已在实际场景中进行了测试,其中包括测试组件之间的通信,例如数据库,网络,API 等,以及在各种浏览器中执行代码基本上测试一切。设置会花费很多时间,而且成本最高。

  • 集成测试:测试程序之间的交互,例如,UI 和 API 之间的通信。设置所需的时间较短,也不太昂贵。

  • 单元测试:是最小粒度的测试,因为它包括将代码的孤立部分作为单元进行测试。这些单元可以是方法,属性,某一个 UI 元素点击、输入这样的动作等形式。例如说我有一个函数,通过入参的不同,去覆盖逻辑的不同 if else 这样的分支,然后去确认函数的返回值是否与我们预期的一致,代码是否按预期执行,这就需要写断言,对于前两个测试类型来说,这是最快,最便宜的实现方式。

可以看到在金字塔中走的越高,建立我们的测试所花费的时间和成本(越耗时,失败时的信息越模糊,越难跟)就越多。这就是为什么许多项目倾向于专注于单元测试的原因,因为它们可以通过涵盖大多数场景,省时省力的去测试我们的代码。

测试框架选型

Jest 表现强劲,在满意度和使用度维度都有不错的表现:

  • 优秀的性能 :对测试用例并发测试,只执行发生改变的文件所对应的测试,测试速度快;
  • 集成度高 :零配置,默认提供所有的东西,比如 Mock(干掉 Sinon)、Test Runner(干掉 Karma)、Matcher(干掉 Chai)、Test Coverage(内置 istanbul);
  • 守护模式 :注重开发者体验,能够在编码的时候帮助我们快速获得测试结果的反馈;

前后端规约

现状问题
随着业务逻辑越来越复杂,前后端分工与协作难免会出现争议,表现在:

  • 存在一定的职责模糊地带,比如数据格式拼装、格式转换等工作,即可以由前端来完成,又可由后端来完成,需要多次沟通讨论,沟通成本高;
  • 前后端分离的模式下,前后端职责进行分工,导致开发沟通成本高,客户体验差(渲染速度慢,耗电高)等问题;

故制定此标准,意在明确前后端分工,减少沟通成本,减少开发维护成本,提升客户体验。

基本原则

  1. 后端按业务领域拆分接口,接口数据结构避免与 UI 展现耦合。前端应关注交互渲染逻辑,根据 UI 展现需要进行数据拼装和转换;
  2. 浏览器处理性能有限 (JS 单线程),移动端续航能力有限,为了保证流畅稳定的客户体验,在批量计算,排序,分页等大数据量计算时应放到后端完成,后端返回最终结果,而非中间结果;
  3. 前端网络环境复杂且不稳定 (2G/3G/4G/WIFI,进电梯等),应尽量减少前后端网络交互次数,单页面网络请求数量不建议大于 3 个;
  4. 在遇到对前端渲染速度要求极高,且后端接口数量及数据结构无法满足要求时,可做 BFF 层(Backend For Frontend)进行接口适配或者采用服务端渲染 (SSR) 技术完成;
  5. 接口遵循最简原则,屏蔽业务实现细节,避免无效字段,避免暴露过多的业务逻辑,避免冗余的多级嵌套格式出现;

其他具体的约定参考阿里的《Java 开发手册》里的前后端规约章节。

工程能力地图

工程能力地图的价值:

  • 规范研发和上线流程:需求、开发、准入、测试、部署与运行全流程的最佳实践指导;
  • 推荐工具链方案:全流程中推荐符合公司场景的最优工具;

YAPI平台

价值体现
无论是前端还是后端开发,都或多或少地被接口文档折磨过。前端经常抱怨后端给的接口文档与实际情况不一致。后端又觉得编写及维护接口文档会耗费不少精力,经常来不及更新,随着时间推移,版本迭代,接口文档往往很容易跟不上代码。
Swagger 提供了一套规范去定义接口及接口相关的信息,RD 只需要按照规范编写描述文件,就可以做到自动生成各种格式的接口文档,生成多种语言的客户端和服务端的代码,以及在线接口调试页面等等。

YAPI 对各角色同学都有价值:

  1. 后端同学实现「代码即文档」,简化接口文档维护;
  2. 前端同学实时的,全自动的,更加真实的 Mock 数据,完成自动化部署服务,及自动联调工具;
  3. QA 同学实现基于 Swagger 接口数据的契约测试,结合 ITP 平台,实现自动生成契约测试;
    对整体平台的价值,主要体现在稳定性:后端同学修改接口后,前端使用 Mock 数据,可及时发现接口变更,解决接口变更的流程沟通问题(沟通永远是最高的成本)。

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK