当前位置: 首页 > news >正文

可评审代码之道

如何组织改动的一些建议.

这篇文档是纯建议性的.Phabricator(一个源码审查工具)可以与很多源码控制策略一起使用,这篇文档中的建议产生的差异不会影响到把Phabricator作为代码审查和源码管理的使用.


概览

这篇文档描述了一个在Facebook和Phabricator中被成功的应用结构化改动的策略.大体上:
  • 每次提交应该尽可能的小,但不能再小了
  • 一次提交要小到是一个紧密结合的想法:不要让提交小到只有看到其他提交时才有意义.
  • 想法和提交应该是一一对应的:每次提交只实现一个想法而且各个想法应该用其各自的提交来实现.
  • 通过把大问题分解成小问题的方式来把大提交改成小提交,然后一次解决一个小问题.
  • 填写有合理的提交记录信息

众多的小提交

小巧简单的提交要比庞大复杂的提交要好的多.它们更易于理解,易于测试和易于评审.理解,测试和评审一个改动的复杂度比它的大小增加更快:每个改动做一件事的10个20行的改动通常比一个2000行做十件事的改动更容易理解.把一个做很多事情的大改动拆分成每个改动只做一件事的多个小的改动可以在完成同样目标的情况下降低整体的复杂度.

每次提交只做一件事.通常情况下,这意味着你应该在开发时应该把不同的改动分解成不同的提交.例如,如果你正在开发一个功能点同时遇到一个先前存在的Bug,应该暂存你的改动;签出一个干净的HEAD,用一个改动修复Bug;然后再把新功能代码衍合到修改Bug代码之上,这样就有了二个改动,每个都有一个原因("添加X新功能","修复Y Bug"), 而不是用一个改动带二个原因("添加X新功能和修复Y Bug").


(使用Git你可以在本地新功能分支上很容易的做,用命令git rebase, git rebase -i和git stash,或者使用git merge.使用Mercurial,可以使用书签和队列扩展.如果是SVN,虽然没有很多内置工具,但是可以使用多个工作复本.)

即使像整顿风格问题也最好要分解:因为它们要实现的是不同的目标.因为评审一个300行的"把tabs转成空格"加上一个30行的"实现Z功能点"要远比一个330行的"实现Z功能点和把tabs转成空格容易评审的多.


类似的,把相关的但复杂的改动分解成小巧且简单的部分.有一个夸张的比喻:如果你要建造一个新房子,不要用一个5000行的改动一下子把整个房子都盖好了.分成更小的更简单更容易理解的步骤:从地基开始,然后是框架等等.如果你决定用铁锹来挖地基和用硬纸板搭框架,如果决定是埋藏在5000行的内部设计和庭院设计, 那么它也会既容易迷失也难改正.每次仅做一点, 提供更大的问题能被理解的足够的环境. 但是每一步除必须外不做过多的事情, 以便能它让们独立存在.
一次改动的最小尺度是一个能独立工作的最小子问题的实现且要表达一个整个想法,不能是半个想法.你可随机选择行的方式来把一个1000行的改动机械的分成 10个100行的改动,但是没有一个是有意义的,这样做仅会增加整体的复杂度.正真正的目的是每一次改动有最小的复杂度,行数仅是一个经常与复杂度相关的代表而已.
我们通常会廷用Phabricator的做法.Phabricator的平均改动是35行.
到寻找关于评审大改动的信息

填写有意义的提交记录

关于这个话题Internet上有很多资源.所有的资源几乎都在表述同一个事情;这里也不例外.
唯一最重要的就是:提交记录信息应该 解释为何做这样的修改
Differential(Phabricator的一个工具)尝试去鼓励构建合理的提交记录,但仅能在结构上而不是内容上实施.
从结构上讲,提交信息可能是:
  • 标题,用一行简短描述改动
  • 概述,在细节上描述改动
  • 也许还有其他的.

内容远比结构重要.特别地,概述应该解释你为何做此修改并且为何选用那样的实现方式.改动本身通常能很好的解释改动的内容.例如,这明显是一个糟糕的提交记录信息:

fix a bug
但是这个也好不了哪去:

Allow dots in usernames

Change the regexps so usernames can have dots in them.

这个比没有强点,但是仅说些能从diff中得到的信息.相反,你应该提供修改的上下文并且解释为什么如此修改,以及为什么这是正确的做法:

Allow dots in usernames to support Google and LDAP auth

To prevent nonsense, usernames are currently restricted to A-Z0-9. Now that
we have Google and LDAP auth, a couple of installs want to allow "." too
since they have schemes like "abraham.lincoln@mycompany.com" (see Tnnn). There
are no technical reasons not to do this, so I opened up the regexps a bit.

We could mostly open this up more but I figured I'd wait until someone asks
before allowing "ke$ha", etc., because I personally find such names
distasteful and offensive.
这个信息不能从改动本身获取.并且对评审者以及事后试图理解改动的人来说也更有用.

一个简单的解释为什么的方法是参考促使你做改动的东西(如Bug,问题,版本等).
Differential也包含一个默认情况下必须的项:Test Plan.在Differential用户指南上有关于此荐的详细描述.可以在配置中把它置为可选或者禁掉,但是建议采用它.这条信息会对评审者特别有用.
在提交记录中还有一些有时感觉很强烈但又不是那么重要的东西:
  • 是否要以及在哪里换行
  • 标题的最大长度
  • 标题后是否应有句点
  • 用时态或语态,如"fix/add"还是"fixes/adds".
  • 提交记录中一些其他的与"为什么此改动会出现"不相干的东西
  • 虽然也许拼写和语法不是那么十分的火糟糕?

Phabricator关于此没有指南.如果喜欢也诚然可以为你的组织设立指南,但是将"为什么"放进提交记录是最重要的一部分.

原文:Writing Reviewable Code

相关文章:

  • JDK的动态代理
  • 实验一 Linux基本环境
  • 病毒原理实例
  • 利用jodconverter+openoffice+flexpaper实现的在线文档系统核心demo
  • 八数码编码(优化数据结构,优化算法)
  • mac 下 git svn 设置代理
  • 实时机票/火车票抓取系统整体架构
  • 我是伪程序员
  • asp.net实验一:hello world!
  • asp.net实验二:连接sql server 2008数据库
  • ASP.NET实验三:读取web.config连接数据库
  • 谷歌面试题(持续更新)
  • web前端实验一:利用Js捕获鼠标事件实现图片切换
  • web前端实验二:利用JS保护网页源代码
  • 五年专业编程的14个经验
  • [rust! #004] [译] Rust 的内置 Traits, 使用场景, 方式, 和原因
  • 2017-08-04 前端日报
  • co模块的前端实现
  • isset在php5.6-和php7.0+的一些差异
  • JS 面试题总结
  • Python3爬取英雄联盟英雄皮肤大图
  • Python中eval与exec的使用及区别
  • redis学习笔记(三):列表、集合、有序集合
  • socket.io+express实现聊天室的思考(三)
  • 看图轻松理解数据结构与算法系列(基于数组的栈)
  • 如何设计一个比特币钱包服务
  • 数据库写操作弃用“SELECT ... FOR UPDATE”解决方案
  • 无服务器化是企业 IT 架构的未来吗?
  • 一个普通的 5 年iOS开发者的自我总结,以及5年开发经历和感想!
  • 在electron中实现跨域请求,无需更改服务器端设置
  • ​​​​​​​GitLab 之 GitLab-Runner 安装,配置与问题汇总
  • # Java NIO(一)FileChannel
  • #!/usr/bin/python与#!/usr/bin/env python的区别
  • ()、[]、{}、(())、[[]]等各种括号的使用
  • (2021|NIPS,扩散,无条件分数估计,条件分数估计)无分类器引导扩散
  • (3)nginx 配置(nginx.conf)
  • (Matlab)遗传算法优化的BP神经网络实现回归预测
  • (NO.00004)iOS实现打砖块游戏(九):游戏中小球与反弹棒的碰撞
  • (八)Flask之app.route装饰器函数的参数
  • (八十八)VFL语言初步 - 实现布局
  • (第8天)保姆级 PL/SQL Developer 安装与配置
  • (分布式缓存)Redis持久化
  • (附源码)ssm航空客运订票系统 毕业设计 141612
  • (十六)串口UART
  • (未解决)jmeter报错之“请在微信客户端打开链接”
  • (一) storm的集群安装与配置
  • (一)appium-desktop定位元素原理
  • (幽默漫画)有个程序员老公,是怎样的体验?
  • (转)Android学习系列(31)--App自动化之使用Ant编译项目多渠道打包
  • **Java有哪些悲观锁的实现_乐观锁、悲观锁、Redis分布式锁和Zookeeper分布式锁的实现以及流程原理...
  • .[hudsonL@cock.li].mkp勒索病毒数据怎么处理|数据解密恢复
  • .apk文件,IIS不支持下载解决
  • .bat批处理(一):@echo off
  • .Net 代码性能 - (1)
  • .NET 中使用 Mutex 进行跨越进程边界的同步