Google工程实践:如何编写小型代码变更(CL)
引言
在软件开发过程中,代码审查是保证代码质量的重要环节。Google工程实践中特别强调"小型代码变更"(Change List,简称CL)的重要性。本文将深入探讨为什么小型CL如此重要,以及如何有效地编写和管理小型CL。
为什么小型CL如此重要?
1. 提升审查效率
- 快速审查:审查者更容易抽出5分钟多次审查小型CL,而不是一次性花30分钟审查大型变更
- 更彻底的审查:大型变更容易让审查者和作者感到沮丧,导致重要问题被忽视
2. 降低风险
- 减少bug引入:变更越小,越容易评估其影响和潜在问题
- 减少工作浪费:如果大型CL被拒绝,前期投入的工作就白费了
3. 工程实践优势
- 易于合并:减少合并冲突
- 设计更优:小型变更更容易优化设计和代码健康度
- 减少阻塞:可以并行开发其他功能
- 回滚简单:大型CL回滚时可能涉及多个中间变更
重要提示:审查者有权仅因CL过大而直接拒绝变更。与其事后拆分,不如一开始就编写小型CL。
什么是"小型"CL?
核心原则
小型CL应该是自包含的单一变更,这意味着:
- 最小化变更范围:通常只实现功能的某一部分而非整个功能
- 包含相关测试代码
- 上下文完整:审查者无需额外信息即可理解变更
- 系统保持稳定:变更后系统仍能正常工作
- 足够清晰:不能过小导致难以理解其意图
量化标准
虽然没有绝对标准,但通常:
- 100行左右:合理大小
- 1000行左右:通常过大
- 文件数量也影响感知大小:200行单文件变更可能可以接受,但分散在50个文件中通常过大
专家建议:从审查者角度思考。对你来说合适的变更大小,对缺乏上下文的审查者可能难以接受。如有疑问,宁可更小。
何时可以接受大型CL?
虽然不推荐,但在以下情况大型CL是可以接受的:
- 删除整个文件:审查工作量小
- 可信的自动重构工具生成:审查者只需确认变更意图
高效编写小型CL的策略
1. 并行工作流
不要等待一个CL审查完成才开始下一个。可以采用:
- 同时进行多个项目
- 安排即时可用的审查者
- 结对编程
- 合理拆分CL以保持工作连续性
2. 代码拆分策略
垂直堆叠
编写一个CL后立即基于它开发下一个CL。版本控制系统通常都支持这种方式。
按文件拆分
将需要不同审查者的文件分组为独立的CL。例如:
- 先提交协议缓冲区修改
- 再提交使用该协议的代码
- 通知相关审查者相互关联的CL
水平拆分
创建共享代码或存根,隔离技术栈各层变更。例如:
- 计算器应用可分为客户端、API、服务和数据模型层
- 使用共享协议定义抽象服务与数据模型层
- API存根隔离客户端与服务实现
垂直拆分
将功能拆分为独立的全栈实现路径。例如:
- 计算器的新运算符(乘法和除法)可作为独立功能并行开发
- 尽管可能有共享逻辑(如按钮样式),但核心功能独立
网格拆分
结合水平和垂直拆分,规划实现路径:
| 层级 | 乘法功能 | 除法功能 | |------|----------|----------| | 客户端 | 添加按钮 | 添加按钮 | | API | 添加端点 | 添加端点 | | 服务 | 实现转换 | 共享转换逻辑 | | 模型 | 添加协议定义 | 添加协议定义 |
3. 重构分离
重构应与功能变更或bug修复分开:
- 类重命名与类中bug修复应分属不同CL
- 小清理(如局部变量重命名)可包含在功能变更中
4. 测试代码管理
黄金法则:CL应包含相关测试代码。测试不被视为增加CL大小的负担。
测试策略:
- 新增/修改逻辑必须包含相应测试
- 纯重构应确保已有测试覆盖,否则添加新测试
- 独立测试修改可先单独提交:
- 为现有代码添加测试
- 重构测试代码(如引入辅助函数)
- 添加大型测试框架代码
特殊情况处理
构建完整性
多个相互依赖的CL需确保每次提交后系统仍能工作,避免破坏团队构建。
无法缩小的情况
极少情况下CL必须很大时:
- 尝试先用重构CL铺路
- 与团队讨论可能的拆分方案
- 提前获得审查者同意
- 加强测试和审查流程
结语
小型CL是Google工程实践中的核心原则之一。通过合理拆分和规划,开发者可以显著提升代码审查效率和质量,同时保持开发节奏。记住:当有疑问时,更小的变更几乎总是更好的选择。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考