本文原是针对实际工作中团队的情况编写的一份流程规范说明,隐去敏感信息之后存放于此。
开发流程规范 是一种团队文化,也是服务和业务稳定性的基本保障线。
一、文档
共识:“谋定而后动”
团队的开发工作主要来自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++
- Google C++ Style Guide、Google C++ 风格指南
- 代码规范/风格检查工具:cpplint
- Google 官方提供的工具,用于检测 C++ 代码是否符合 Google C++ Style Guide
- VS Code 插件:cpplint - Visual Studio Marketplace
- Vim 插件:vim-syntastic/syntastic: Syntax checking hacks for vim (github.com)
- Clion 插件:CLion-cpplint - CLion Plugin | Marketplace (jetbrains.com)
- 代码格式化工具:clang-format
- 项目根目录下放置 .clang-format 文件,编辑器/IDE 配置成编码时自动格式化或者保存时自动格式化:
- VS Code 插件:Clang-Format - Visual Studio Marketplace
- Vim 集成:https://clang.llvm.org/docs/ClangFormat.html#vim-integration
- Clion 集成:https://clang.llvm.org/docs/ClangFormat.html#clion-integration
---
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
- Google Java Style Guide
- IDE - Jetbrains IDEA
- 下载代码风格定义文件:intellij-java-google-style.xml
- 导入 IDEA
- 安装 Save Actions 插件
- 配置 Save Actions 插件
2.1.3 Python
- Python 3 + venv 虚拟环境
- Google Python Style Guide
- 代码规范/风格检查工具:pylint、https://google.github.io/styleguide/pyguide.html#21-lint
- 代码格式化工具:yapf
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 单元测试
- 明确单元测试与集成测试的区别,单元测试 - 维基百科,自由的百科全书 (wikipedia.org)
- 单元测试的作用:
- 验证某个逻辑的当前实验是否符合预期
- 更重要的是对以后的代码变更可能造成的非预期影响/破坏进行一定的防御
- GoogleTest,用好 Mocking
(强制)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 实验扩量或推全操作期间
- (强制)对实验集群负载情况保持关注
- (建议)对于推全操作,尽可能灰度推全,中间步骤留一定时间确认集群负载和流量变化是否符合预期
- (建议)先开反转,再进行推全,避免不必要的资源腾挪扩缩,也能一定程度上控制风险
六、规范落地
- (建议)规范流程支持工具和平台不断优化,尽可能减少规范流程造成的人力负担
- (建议)不断更新完善规范