提交代码是个技术活

在这里我记录了我所在的团队通常是如何提交代码(以Git为例),以及这种做法背后的价值观。

7步提交法

我的团队以非常严肃的态度对待代码提交这件事。我们把提交分为七个步骤,以此如下,

git st

通过这个命令查看这次commit涉及到了哪些文件,产品代码、测试、配置、数据库脚本等等。如果发现存在有预期不符合的文件,应该检查是不是由于一些误操作导致的,及时修改。比如,“我只是给Account增加了一个新的属性,为什么OrderService文件会提示我modified了?哦,原来是我在Debug时在里面加了条log,这个应该去掉”。

当确保了所有被修改的文件都符合预期后,执行下面的命令,

git diff

这个命令会看到每个文件具体修改的内容。此时要检查每个修改,比如“这个方法是我刚刚加上去的、这个变量是我刚刚重命名的、这个循环体被重构掉了用一个新函数取代了……哦?这个为什么被改了?是IDE自动化重构给我改错了,得调整回来。”这个时候去review你的代码很容易发现错误,因为你刚刚编写完,对里面的逻辑还很清晰。

当认为自己的代码都没有问题,这时执行下面的命令,

git ci

这个命令会被你working space的修改提交到local repo中,这时为后续把它push到centre repo中的必要步骤。

这步成功后,立刻执行下面的步骤,

git pull –reb

这个命令会把centre repo上的commit拉回到本地,并与本地的修改进行合并。这一步需要记住的要点就是:一定要和第三步git ci同步执行!这个命令结束后,你其实完成了一次和其他人的代码的持续集成后动。当团队中的每个人都能频繁地提交代码后,代码就能在每个人的机器上频繁地集成——持续集成。这样即可以最大限度地避免冲突,也可以及时把你的知识(代码)分享给其他人,避免造成浪费。

虽然可能性很低,但这步仍然会遇到合并冲突,相信我,此时解决冲突是成本最低的时候。当顺利把centre repo的代码同步并合并到本地后,接下来要运行测试,

run test

这步和下一步都不是git的命令了。当你合并了其他人的代码后,需要检查这些代码是不是正确的。你必须具备这个能力:通过一个简单的命令来运行一个测试集,以验证当前代码的可用性。这个步骤涉及很多自动化测试的方法和策略,不在这里讨论了。

当我们确认当前代码是可用的,接下来就可以把它push到centre repo里,但是在这之前先要:

check CI

每个团队应该有一个CI服务器来监控项目的运行状态。在你要把代码push到centre repo之前,必须确保CI服务器处于正常状态(通常以绿色表示)。如果CI是正好处于正常状态,接下来就可以完成最后一步:

git push

好,到此为止你的修改终于可以被其他人“享用”了。如果此时坐在你旁边的同事刚好执行了git ci,那么你的修改马上就会被他看到,如果(很不幸地)有什么错误,(很幸运地)你会在很短的时间里收到反馈。

当然,在继续下一个功能的开发之前,你有责任确保你的提交可以通过CI上面所有的验证。

实践和价值观

这个7步提交法收到的最多反馈就是“影响生产效率”,然而有意思的是,它的初衷却是要“提高生产效率”。之所以很多人误会它,是因为人们没有理解它背后的价值观和实践。

小步前进

如我前面所说,这些7步提交总是被认为太繁琐,所以降低了生产效率。诚然,像审查代码、处理合并冲突、运行测试,这些都要花时间,但是这些时间的开销是你无路如何也避免不了的,无非上先做后做的区别。这些事情如何提前做,就会让你痛苦,也就产生了削弱生产率的错觉。

当然,让7步提交法不会成为扼杀生产力的最核心的原因,可不是心理学的暗示,而是采用小步前进的开发方法。小步前进的方式在很多敏捷、精益的理论里都有提及。它也是支撑7步提交法的第一个实践。

我见过有一周提交一次代码的团队,他们提交时要花上难以预期的时间进行集成,这个时间有时是开发时间的几倍。然而我的团队的每个人会把提交频率控制在15-60分钟,这样,配合7步提交,可以保证你在每个小的时间片里开发的功能是正确的、有价值的,而且,由于时间控制在很短的范围里,所以7步提交时也不会花费很长的时间,而取得的好处是惊人的——几乎不需要集成的投入了。

任务划分

然而在提倡“小步前进”的工作方法时,同样会遇到很多阻力,最常听到的就是“我这件事情没法小步前进,必须一次都做完啊!”不是吹牛的说,每次我和说这种话的人坐下来一起工作一会儿,总是能发现机会把他手头“没法小步前进”的工作拆分成更加细粒度的小任务,接下来这个人就会抱怨别人提交的频率太低了:-)

iamge 顺手拍的一张同事的Task卡片

所以,要想小步前进,首先要学会如何把复杂的事情化繁为简、化整为零。这又是很大的一个主题,可以写很多东西来说明它,不过目前只能先简单地介绍一下。很多人问我,任务划分到多细的粒度才合适,我的答案是,“越细越好,直到你觉得不能再细了为止”。再补充一句,一个任务的底线是不给别人添乱,上限是能提供价值。举个例子,如果你可以每写一行代码就向CI提交一次,而且在这个过程中你即没有影响别人的工作也在不断地为产品增加功能,那你绝对是大师了!

持续集成(CI)

在我介绍7步提交法的第四步(git pull –reb)时,提到了一点,就是那一步不是关于你自己的,而是关于你也别人的,在七步中,第四步建立了你的代码和其他人代码的联系。同时,我也暗示了一点,就是只有你一人“独善其身”是不够的,因为如果其他人的提交频率很低,你在第四步的时候依然会遇到合并的问题。

所以,为了让每个人都能“敏捷”起来,我们需要持续集成,将每个人的提交活动、提交代码的质量可视化出来,同时,CI服务器团队的协调工具,每个人要根据CI状态来确定自己是否能够提交代码,正像第七步所述的那样。

快速反馈

最后,我掌握了划分任务的技巧、小步前进地工作;因为持续集成,我所在的团队中的每个人也都这样工作着。

追求这种工作方式源自于我们对“快速反馈”的渴求。我希望不断得到反馈,告诉我编写的每一行代码是不是符合我理解的需求、能和其他人的代码集成到一起运行,PO也希望尽快得到反馈告诉他交付团队的产品是不是他所要的样子、是不是能解决用户眼前的问题。在把想法转化为产品的过程中,编码并提交是产生价值第一步,后续这个价值链还要延续很久。那么要想让整个价值链可以延绵不断地输出价值,就要给每一步加速。

而7步提交法是一面镜子,它反映了创造价值的第一步是不是迅速。当你质疑7步提交法的时候,我要首先质疑的你价值链是不是够流畅。