团队开发流程规范

2023-04-05 三
By xiayf

本文原是针对实际工作中团队的情况编写的一份流程规范说明,隐去敏感信息之后存放于此。

开发流程规范 是一种团队文化,也是服务和业务稳定性的基本保障线。

一、文档

共识:“谋定而后动”

团队的开发工作主要来自3个方面:工程优化(平响优化、性能优化、稳定性/可用性优化等)、算法业务需求、产品业务需求。

  • (强制)每一项开发工作实际编码之前,都需要梳理一份文档,放在 开发文档 目录下
  • (建议)文档命名规则如示例 “w1-20220721-xxx需求”、“w1-20220721-xxx优化”,“w1” 是文档的按序编号。
  • (建议)每一项工作,上线/推全后,部署相关信息、工程指标变化、业务指标变化、资源成本变化、遗留待优化的非关键问题等相关信息也应补充到文档中。
  • (建议)如果走实验流程,也在在文档中加上“实验推进板块”,记录实验推进情况,遇到的问题等,特别是对于多场景实验推进的情况。

1.1 工程优化 文档

  • 背景/现状描述/问题分析
  • 优化方案/设计方案
  • 预期收益
  • 分工排期

1.2 算法业务需求文档

  • 明确算法负责人,链接上算法侧相关文档(要求算法同学提供) - 文档中包含 背景、预期收益、算法逻辑/模型等要点信息
  • 明确工程方案,对于复杂的算法业务需求,应该给出设计概要
  • 预估资源成本
  • 明确项目优先级 和 排期 / Deadline
  • 对于高优紧急需求,尽可能预先明确进度风险点

1.3 产品业务需求文档

  • 明确产品负责人,链接上产品侧相关文档(要求产品同学提供) - 文档中包含 背景、预期收益、产品规则等要点信息
  • 明确工程方案,对于复杂的产品业务需求,应该给出设计概要
  • 预估资源成本
  • 明确项目优先级 和 排期 / Deadline
  • 对于高优紧急需求,尽可能预先明确进度风险点

1.4 所有文档

(强制)必须包含: - 测试用例设计和全面完整的测试报告/diff 报告 - 包含对应各个代码库变更的 MR 链接、发布版本的 tag 链接

二、编码

2.1 统一代码规范

共识:新代码统一新风格,老代码风格维持不变。

2.1.1 C++

---
BasedOnStyle: Google
---
Language: Cpp
IndentWidth: 4
ColumnLimit: 120
DerivePointerAlignment: false
PointerAlignment: Left
SortIncludes: CaseSensitive
Standard: Auto
AccessModifierOffset: -4
SpacesBeforeTrailingComments: 2
AllowShortBlocksOnASingleLine: Never
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Empty
AlignTrailingComments: true
BinPackParameters: false
AllowAllParametersOfDeclarationOnNextLine: false

2.1.2 Java

2.1.3 Python

2.2 代码分支管理

共识:一个代码库一个主分支;所有开发分支在测试/实验验证之后都需要合入主分支

(强制)基本的 git 工作流:

  • 每项开发工作,都从主分支签出一个(公共)开发分支
  • 如果是多人协作的开发工作,则基于新签出的公共开发分支,每个人各自签出个人的开发分支,进行独立开发
  • 个人开发自测完成后,合入公共开发分支,进行集成测试联调
  • 如果走实验流程,则使用(公共)开发分支的 sandbox 镜像部署实验集群
  • 实验推全反转下线后,(公共)开发分支合入主分支,并基于主分支上的正式 tag 镜像发布基准集群

(建议)分支命名规范:

  • (公共)开发分支:
    • 常规需求开发分支:feature/[目标服务名]-[文档 ID]
    • 紧急需求开发分支:urgent/[目标服务名]-[文档 ID]
    • 紧急修复开发分支:hotfix/[目标服务名]-[文档 ID]
  • 个人开发分支:在(公共)开发分支后带上个人 ID,示例:feature/[目标服务名]-[文档 ID]-[个人 ID]
  • 对紧急需求和紧急修复开发分支,可以先创建一个文档,拿到文档 ID,内容可能来不及写得非常完善,但之后应该进行补充完善
  • 不符合规范的开发分支,不能推送到远程代码库(不能对团队其他人可见),通过 git hook 来强行限制

(建议)所有(公共)开发分支、(需要代码评审的)个人开发分支,都应该创建对应的 MR,邀请其他人进行代码评审时,提供对应的 MR

2.3 Commit 规范

约定式提交 (conventionalcommits.org)

(建议)参考 Apache 顶级项目的实践(如 apache/arrow),commit log 的“描述”部分先带上文档链接。

2.4 MR 与代码评审

共识:质量把关、经验传承

从团队和长远来看,Code Review 的重要性再怎么强调都不为过。

  • (强制)每个开发分支的工作在开实验或者合入主分支之前,都需要邀请至少 3 名资深同学进行 Code Review
  • (强制)评审员在确认没有意见或者所有优化意见都已得到合理解决后对 MR 进行点赞 👍
  • (强制)开发分支/MR 需要攒 3 个以上的点赞才能开实验流量或者合入主分支
  • (强制)对于基于分支开实验流量的分支代码,也必须经 code review 后,基于分支进行打实验 tag,并基于实验 tag 进行线上发布。
  • (建议)适当约束分支合入权限,仅资深同学(具体名单?)才能将开发分支/MR 合入主分支
变更应该组织成1个或多个补丁/MR,视变更大小而定,组织方式遵循以下规范指南:
- MR 应该小一点
- MR 应该都可以独立编译并且是正确的(所有测试用例都通过)。不需要你验证这一点,但是需要在代码中放入一种标记来反映 MR 是否违反了这条规则。例如:在 fix 一个问题之前,先引入一个回归测试用例用例。
- MR 应该自包含(高内聚),并且只做一件事情。
- 每个 MR 都应该包含一份描述性的提交日志(commit log)。
- MR 的描述信息不应该假设代码评审人是一个专家。它应该包含足够的上下文信息,确保即使一个普通的小白也能理解。
- MR 的描述信息应该自包含,也不要引用无法保持关联的讨论信息(“如每日沟通达成的一致结论”)。
- MR 应该包含变更的动机(背景)。不能简单地说一句“让 X 完成 Y”,而应该仔细解释为什么要这么做。 

另附:Google Engineering Practices Documentation

2.5 CI 约束

因当前一个代码库支持产出不同服务的二进制程序和 Docker 镜像,为加速 CI,使用了条件编译,根据不同条件触发不同 CI 流水线。

  • 根据分支名的目标服务名对应触发不同 CI 流水线(all 则触发所有的 CI 流水线)
  • MR 合入 master 分支时,必须触发所有 CI 流水线。

基于 .gitlab-ci.yml 配置强行约束。

2.6 版本 Tag 规范

  • 正式tag
    • 只能在 master 分支上打 tag,tag 命名规范为 v主版本号.次版本号.修订号,基于 语义化版本
    • tag 内容必须包含必要的描述性信息,声明此次变更的内容,包含相关的 MR、文档链接
    • hotfix 版本 tag,应该以 fix 之前的 tag 为前缀,加上“-hotfix” 后缀,示例:v10.0.1-hotfix;如果对同一个 tag 的代码发生了不只一次 hotfix,则继续补充上秒级的时间戳作为后缀
  • 实验tag
    • 在分支上打tag进行线上实验开量,tag命名规范:exp.文档编号.迭代版本号,示例:exp.w88.0

2.7 监控打点和日志

共识:以尽可能小的性能开销最大化系统的可观测性

  • (建议)多使用 ROC 打点,借助多维数据分析,方便问题定位分析
  • (强制)注意日志级别(DEBUG、INFO、ERROR、FATAL)的语义
    • 不要使用非 DEBUG 级别来输出 DEBUG 日志
    • 注意 FATAL 的实际影响
    • 不同环境使用不同的日志级别,生产环境不要输出 DEBUG 日志,https://github.com/google/glog#setting-flags
    • (建议)使用 glog vlog 来进一步控制不同环境/场景下的日志量,https://github.com/google/glog#verbose-logging
  • (强制)不要默默地失败
    • ERROR/WARNING 日志
    • Event 打点
  • (建议)使用 Event 打点充分表现输入量、输入类型、输出量、变化趋势
    • 请求 QPS、增量消息 TPS、不同类型增量消息的 TPS、。。。
    • 基准数据的统计计数
    • 请求来源:客户端类型粒度、客户端 ip 粒度、场景维度、媒体维度、。。。
    • trigger 数、各类过滤器数目统计
    • 检索结果数量、截断后/实际返回给客户端的结果数量
    • 各类过滤器的过滤量
  • (建议)使用 Transaction 表现耗时分布 - 整体耗时多少、时间都花在哪些环节(包括 RPC 框架内的等待时延):Tt = T1 + T2 + ...
  • (建议)使用 Metric 表现跨节点/集群/场景的业务指标变化趋势
  • (建议)性能考虑,打点接口调用次数应小于等于请求 QPS、消息 TPS

2.8 最佳实践

  • (强制)尽早严格检测请求、数据、配置等输入的合法性
  • (建议)尽量不使用配置中心的配置监听
  • (建议)多了解使用基础库 - boost、abseil-cpp 等

三、测试

3.1 单元测试

(强制)CI 强制要求新增/变更代码的测试覆盖率。(基于 .gitlab-ci.yml 配置强行约束?)

3.2 集成测试

  • (强制)任何代码变更,都必须经过自测/集成测试
    • 任务可以正常跑起来,变更的逻辑已生效,产出的结果确认符合预期
    • 服务可以正常运行起来,变更的逻辑已生效,可以正常加载数据/索引,请求响应的结果确认符合预期
  • (建议)测试环境/工具
    • 独立的测试验证集群
    • 开发机环境下的 Docker 环境 + 代码库中的 Dockerfile
      • docker build -t image-name .
      • docker run -dp 8003:8003 image-name
    • 易用的脚本 - 一键启动+索引数据加载、易用的客户端工具、易用的数据校验工具

3.3 批量 Diff 测试

(强制)如果代码变更影响了索引或者检索逻辑,则应该进行充分的 diff:

  • 如果走实验,则部署新实验集群后开实验之前,进行 基准集群 VS. 实验集群 的请求结果 diff
  • 如果不走实验,则基于独立的测试验证集群,进行 生产集群 VS. 测试集群 的请求结果 diff
    • diff 完成后,即刻释放测试集群资源
  • 对于 diff 结果,不管最后的 diff 率有多小,只要有 diff,就需要确认 diff 来源/原因是否符合预期
  • diff 的不同请求数量必须达到 1000 以上
  • 统一使用易用且功能完善的 diff 工具
  • 生产集群发版或者实验集群开流量之前,在周知相关人员时,必须一并提供 diff 结果以及已确认 diff 来源符合预期

四、发布

  • (强制)流量高峰期不发版
  • (建议)周五晚上及周末不发版

4.1 发布之前

  • (强制)评估确认好本次发布前后服务集群负载是否会有变化,如果变更会影响集群负载上涨,则应提前扩容
  • (强制)在相关大群内进行通告,通告模板如下:
变更通知:
- 变更内容:xxxx
- 涉及集群和场景:xxx
- 操作人:xxx
- 相关文档(含需求背景、工程方案、代码 MR、diff / 测试报告等信息) 或 实验链接:xxx

4.2 发布期间

  • (强制)先灰度发布一行或者少量行,确认各项工程指标+业务指标无异常后,再全量发布
  • (强制)发布期间需要保持关注告警以及关键工程指标和业务指标

4.3 发布之后

(强制)发版完成后,确认各项工程指标/业务指标正常后,在相关大群内周知发版完成,确认各项指标平稳/符合预期

五、实验

5.1 实验开量之前

  • (强制)人工刷 demo,全链路验证
  • (强制)实验集群资源预估准备,包括评估链路中间环节资源负载变化
  • (强制)在相关大群内通告,通告信息:实验名、实验链接

5.2 实验期间

  • (强制)实验刚开量时,关注实时报表 10~30 分钟变化趋势:
  • (建议)每天及时查看实验平台上当前实验的天级实验报表,如果有较明显的负向指标,则应及时通告出来,与相关同学一起分析可能的原因

5.3 实验扩量或推全之前

  • (强制)实验集群资源预估准备,包括评估链路中间环节资源负载变化
  • (强制)与相关算法同学确认好实验时长与实验效果是否达到扩量要求
  • (强制)在相关大群内通告,通告信息:实验名、实验链接、流量从多少变化到多少

5.4 实验扩量或推全操作期间

  • (强制)对实验集群负载情况保持关注
  • (建议)对于推全操作,尽可能灰度推全,中间步骤留一定时间确认集群负载和流量变化是否符合预期
  • (建议)先开反转,再进行推全,避免不必要的资源腾挪扩缩,也能一定程度上控制风险

六、规范落地

  • (建议)规范流程支持工具和平台不断优化,尽可能减少规范流程造成的人力负担
  • (建议)不断更新完善规范