随着业务规模扩大、团队组成变复杂,如何降低项目实施风险,降低软件复杂度变得尤为关键。 我从 Martin Flower、Joel Spolsky(软件随想录 作者) 等巨匠智慧中寻找解决复杂工程之道,其中 Code Review 是行之有效手段。 我认同 Code Review 价值也是忠实执行者。
加入蚂蚁以后,我在所接触项目中都大力推广 Code Review。 感谢团队信任和支持,目前 CR 协作进展顺利, 项目 CR 从最早不主动,到现在形成基于模块 Owner 制度 CR 和 Peer Review。 我也曾经在 3 个月内处理完成 700 多个 Pull Request,并在 PR 讨论中中都留下一些有价值讨论。 这里我将自己对 Code Review 一些理解记录下来。
这一篇先讲讲进入 Code Review 之前需要做准备工作。
评估团队成熟度
不管是在一个遗留系统上推广 Code Review,还是在一个新团队推广 Code Review, 起手式不是立马挽起袖子猛干,而是应当观察一下当前所处情况是否允许自己推动这个「艰巨」任务。 最需要观察的是团队成熟度。
我将团队成熟度粗略分为草台班子、成长型团队、成熟团队。 具体衡量指标可以有成员技术储备、团队成员信任度、团队负责人对工程管控力度。 相信集团内大部分团队处于成长型、成熟型团队。 但如果考虑到生态同学一起协作,或者临时因为紧急项目凑在一起,就比较容易成为「草台班子」。
如果还停留在草台班子,那就得先在团队内形成一定共识: 包括技术共识和合作模式的共识。 技术共识需要包括:技术栈共识、好代码定义、研发流程共识等。 合作模式共识需要包括:冲突解决机制、职责范围边界、决策机制等。 如果基本共识还没有形成就仓促进入 Code Review,那就容易将一件好事变成工程师战争。
并不是所有团队、项目都适合无差别引入 Code Review。这么几种情况建议暂缓 Code Review 推广:
- 老板和同事都不支持甚至反对
- 业务重要性低,或者团队都是特立独行高手
- 创新业务需要快速上线,这时候适合将这类任务分发给配合度高老团队,或者给高手单兵作战
当条件不满足时也不用气馁。先成为一个布道师吧,探索一下团队中有没有相似想法的人,了解一下他们担心点和诉求点。 相信只要条件允许,没有人会拒绝提高工程质量。
构建「好代码」共识
Code Review 核心产出物是代码,如何界定代码是好是坏就至关重要。 根据 Bjarne(「C++ Programming Language」作者)、Grady Booch(「面向对象分析与设计」作者)等人定义, 总结下来好代码有这么基本特征(via「Clean Code」):
- 正确
- 可测试
- 不重复
- 少且简单
- 可读
深思一下这些基本特征背后道理:代码是人类和机器沟通工具,好代码也要利于人类阅读和再次书写。 人比机器更犯错,机器算力在成倍增长,因此简单易维护重要度逐步增高。 这些朴素道理也正是语言从低级语言进化到高级语言驱动力, 也是近几年高级语言语言特性主打点(类型系统、格式系统、面向人类同步思想异步设计)。
但上面这几条原则太底层了,无法成为实践标准。 因此行业基于这些公理衍生了不少实践定理,我将其分为工程规约和设计范式两类。
工程规约包含语言风格规约和应用工程规约。 语言风格规约比较容易理解,开源世界提供了很多选择。硅谷大厂 Google / Facebook / Uber 等都有不少规约提供。 国内还有极具价值的「阿里巴巴 Java 开发手册」,我称之为 50331 ;) (PS:「阿里巴巴 Java 开发手册」不仅有语言风格规约、也有应用工程规约和一部分设计规约)。 这里罗列了一些常见面向语言的 Style Guide。
- Google Style Guides | styleguide
- 包含 C++ / Object-C / Java / Python / R / Shell / HTML CSS / JavaScript / AngularJS / Common Lisp / Vimscript
- alibaba/p3c: Alibaba Java Coding Guidelines pmd implements and IDE plugin
- Java
- airbnb/javascript: JavaScript Style Guide
- JavaScript
- uber-go/guide: The Uber Go Style Guide.
- Go
应用工程规约关注点则更为落地:包括依赖管理、配置管理、应用层次结构、对外服务暴露约束,数据建模,文档注释,测试管理, 甚至包含中间件使用规约。 这些规约逐步从「如何表达代码」延展到到「如何管理工程」。 这块发挥空间比较大,中大规模团队会有应用框架组这样团队。 基于应用框架对使用方式方法约束。针对具体业务使用也会给出针对性建议。 这些定理总结出来往往以轻量 Best Practice 和重量级应用框架对外输出。
这里举两个例子说明一下应用工程规约应该讲清楚哪些问题。 第一个例子 alibaba/COLA 这个项目来说,它约束了整体工程结构,并且明确的通过 Archetype 帮助(约束)用户行为。 第二个例子是 RoR / Django 这类 RoR 框架,他们使用约定大于配置方式,基于 ActiveRecord 这种模式约束了用户如何使用框架, 从 Model、Controller 到 Router,对立面则是 Spring MVC / Flask 这类框架,几乎只提供纯技术特性,不约束开发者行为。
除了阿里 Java 开发手册,这里提供三个应用工程规范供参考:
- alibaba/COLA: Clean Object-oriented & Layered Architecture
- SOFA 项目工程结构 - 蚂蚁金服金融科技 和 SOFA 微服务平台概述 - 蚂蚁金服金融科技
- realpython/python-guide: Python best practices guidebook, written for humans.
比工程规约更难定义的是设计范式,核心点是解决「如何做架构决策」。 设计范式决策过程在系统架构设计和系分设计阶段就应当完成了。 如果设计范式差异性导致代码在 Code Review 阶段出现意见不一。 要么是这个团队过于草台班子,要么是这个项目架构师/负责人在前期设计做的工作太少了。
当一个团队遵循相近设计范式,意味着他们达到了同一级别技术储 备,并形成了统一自顶向下设计打法。 在 Code Review 过程中,一些范式使用完全可以将 GoF23 / S.O.L.I.D. / DDD 这些术语概念拎出来。 相信 Commiter 和 Reviewer 可以基于业务场景快速达成一致。
方法论贴在墙上是无法解决开发中中遇到设计问题,在代码中真刀真枪干,Show me the fuck code。
Code Review 沟通协作机制
除了工程规约,还有一件事情往往会被忽略,如何解决冲突? 这个冲突不是指代码 Conflict,而是面对技术方案决策时候交流讨论。
文无第一武无第二,两个秀才在一起能吵到天翻地覆面红耳赤。 技术层面 Augue 容易陷入我说我有理你说你有理局面。这种情况如何解决? 没有一个好协作机制,会倒逼 Commiter 和 Reviewer 退缩,不能充分展开讨论。 这是我们不想看见。
很多时候技术决策就是在 40% 正确性 和 60% 正确性中间选择,看中长期收益和短期收益就可能导致结论不一样。 非黑既白反而不容易有争论。想要促进快速决策,一套冲突解决机制就不可缺少。 因此一定要在事前制定一套冲突解决机制。大部分冲突解决都可以使用这么一套逻辑:数据、逻辑、民主、独裁。 当需要进行某个技术或者产品决策时候,最优先方式是用数据来量化,证明自己观点。 当数据不充分时候,可以进行逻辑归纳推衍形成结论。 当形成逻辑不能服众众说纷纭时候,可以使用民主方式进行裁决。 当民主也无法生效,就需要 Owner / 一号位力排众议,进行独裁决策了。
CodeReview 有这么几种形式,同步离线、异步离线、同步在线。 处于同步形式 CodeReview 需要尽快处理掉 PR,这时候协作机制一定要干净利索,避免大家在 PR 反反复复来来回回讨论。 如果每个 PR 都要消耗数次来回沟通,我建议将 CR 形式升级到同步在线,拉个会议立刻将事情解决。
如果在一个实现方案上真无法决策,如果不涉及原则,那我建议使用搁置争议,使用
TODO @commiter what, how, when
方式先标记意见和处理时间,先行将工程开发往下推进。
一切准备好了,谢天谢地,终于可以进入 Code Review 阶段了。 我们下篇文章再来讲进入 Code Review 阶段的事情。
原文链接: 浅谈 Code Review 之事前准备 | Log4D
3a1ff193cee606bd1e2ea554a16353ee
欢迎关注我的微信公众号:窥豹