阅读更多

2顶
0踩

企业架构

转载新闻 Quora是如何维持高质量代码的

2015-07-31 16:22 by 副主编 mengyidan1988 评论(1) 有5002人浏览
一个高质量的代码库可以加快长期开发的速度,因为它会使得迭代、协作和维护更加容易。在Quora,我们十分重视代码库的质量。



除了会取得收益之外,要维护高质量的代码,会带来一大笔间接费用,还会牺牲实际开发周期。很多人发现,实际产生的收益很难抵消这一间接费用,这时人们会面临两个选择:要么以低质量代码提升开发速度,要么维护高质量代码而牺牲开发速度。而对于初创公司来说,他们希望开发速度能快一些,所以就不得不使用低质量的代码。

我们开发了一系列工具和流程,这样就可以在维护高质量代码库的同时,提升开发的速度。在这篇文章中,我们将会介绍关于保证代码质量的一些方法,以及一些平衡这两方面的具体案例。

维护高质量代码的目标

维护高质量代码主要的好处在于能够长期推动开发速度,这也是我们所关注的重点。通过编写清晰代码而产生的短期成本,就可以换来长期的收益。

记住这一点,然后下面是四点基本原则,我们发现对代码质量非常有帮助:

Quara的代码质量基本原则

1. 代码的阅读和理解都要很容易——现在的情况是更多的时间用在了代码的阅读上,而不是代码的编写上。实际上,应该把阅读的时间减少,即便这样意味着需要花费更多的时间来写代码。

2. 代码的不同部分需要有不同的质量标准——不同的代码行需要有不同的使用时间、范围、被破坏的风险、被破坏后造成的成本及其修复的成本,等等。总体来讲,这些对长期迭代速度的影响不同,所以执行一个统一的质量标准是不合理的。

3. 代码质量的间接费用是可以缩减的——维护高质量成本的间接费用一般是可以节省的,这可以通过使用自动化、更好的工具、更好的流程和培训更优质的开发人员来实现。

4. 代码库一致性很重要——保持整个代码库的一致性是十分有价值的,即便这意味着有一部分代码不能是最优的。一个不一致的代码库是很难阅读和理解的(见第一点),也很难编写,很难通过自动化工具进行优化。

下面,我来介绍几个我们将这几点原则用于实际开发的例子。

提交后code review

我们代码库的代码变更需要从六个维度进行评估——正确性、隐私、性能、架构、复用性和风格。读代码是code review的关键部分,所以说,code review在提升代码可读性方面起着至关重要的作用。



但是有一点不好的是,code review同样会减缓开发速度。比如说,提交前code review在行业中目前是比较常见的,其中代码必须在推送之前就进行审查和修改。这样的话,即使是每一轮审查只需要2天的时间,这样重复2-3轮,也会耽误开发人员一周的时间,这是严重的时间浪费。

在Quora,我们主要做的是提交后code review。也就是说,代码首先进入生产阶段,然后再找人进行code review。为了让你对这一工作的规模有个认识,举个例子,昨天我们48个人总共推送了187次代码。提交后review是很好的办法,因为它解放了开发人员,可以去做其他的工作。code review人员也可以更好的管理自己的时间,可以在他们方便的时候做代码审查,而不是非得匆忙的完成这一工作,以便不影响其他人的工作。过程合理的话,预计代码审查一周内可以完成,而实际上大部分情况下,一到两天就可以完成。之所以说一周的时间,也是经过仔细考虑的,因为一周足够长,可以允许审查人员灵活安排,而一周的时间又有点短,因为它需要将不好结果的影响最小化,比如说有人读了代码之后将不好的代码在整个代码库中进行传播。实际还有这样一层原因,很多的开发人员都是按周进行个人工作安排的。

我们之所以可以做提交后code review,是因为我们相信我们的每一位开发人员,我们选择的都是最优秀的人才,并且我们在他们的代码质量培训/工具方面投入了大量资金。这也督促我们对代码进行更好的测试,而好的测试能帮助检测代码的准确性,甚至在任何code review工作开始之前就可以检测。对此,我们采用的是Phabricator,一个稳健的、高配置的审查工具。我们对它做了几点改进,这样就能与我们的提交后code review工作流更好的配合。比如说,我们构建了一个命令行工具,可以将代码推向生产阶段,并提出代码审查请求。有了该工具,Phabricator的diff就可以继续工作,而无需去修复那些commits。

所有这些说明,对于不同类型的代码问题,我们有不同的代码审查标准。如果说我们事先发现了某一个潜在错误,问题比较大,可能会带来很大影响,那么我们会转而执行提交前审查,而不是平常的提交后审查。这方面的几个例子:

1.涉及用户隐私和匿名的代码。

2.涉及核心的抽象类(abstraction),因为很多其他的代码都可能依赖于它。

3.涉及基础设施的某些部分,其有些错误可能会导致宕机的风险。

当然这还取决于开发人员如何决策——如果他们想要对某些代码进行提交前审查,从而从中获取更多想法,这也是可以的,而不用非得采用平常的提交后code review,只不过这种情况比较少见。
code review任务分派

为了做好code review,每一个变更都应该由有着相关经验的人员来审查。如果这些code review人员能负责“维护”这些他们审查过的代码的话那就更好了,这样他们可以获得一定物质报酬,进而形成长期的交易关系。

我们之前实施了一个简单的系统,其模块和目录层级代码的“所有权”只需要在文件开头赋予一个元标签(meta tag)就可以指定了。比如:
__reviewer__ = 'vanessa, kornel'

如果某commit要对文件做一些修改,其reviewer就会根据文件(或结构树【ancestor tree】),进行分析,并自动作为reviewer添加到commit中。我们针对code review任务的分派或者说路由选择还有一些其他的规则,比如说,如果没有reviewer的话,一个数据科学家可自动作为一个reviewer添加到启动A/B测试的commit中。实际上我们已经搭建了一些工具,可以让我们更容易的制定更多这类自定义的“路由”规则。举个例子,如果我们想做,那就很容易就能增加一个规则,可以将某一个新任务所有的commits都路由指派给相应的人员。

这样的一个智能系统,将所有的commits都分配给合适的人员进行代码审查,能有效减轻开发人员的负担,否则他们还需要四处寻找合适的审查人员,还要确保大部分的审查人员否能认真审查每条commit。

测试

测试对我们的开发流程来说是非常重要的一步,我们写了很多的单元测试、功能测试和UI测试代码,覆盖很大的测试范围。而一个综合性测试可以让开发人员并行工作,工作进行的更快,而不用担心会破坏现有功能。我们投入了大量时间来制定测试框架(建立在nosetests之上),使其容易使用、可快速应用,从而降低编写测试代码的间接费用。

我们还开发了几项工具,可以实现测试的自动化。我们之前发布了一篇关于“持续集成系统”的文章,描述了一个中心服务器,可以在部署任何新代码之前运行所有测试。该测试服务器可以并行运行,这样的话运行所有的测试只需要不到5分钟的时间。这样的快速运转可以激励人们经常性的编写和执行测试程序。我们有一个叫做“test-local”的工具,只能识别和执行代码工作副本的测试变更相关的测试文件。为了能做的更好,我们的测试还需要进行模块化(这能进一步帮我们在测试失败的时候进行快速调试)。为了确保好的测试代码能得到期望的性能,我们维护了一个共享文档,描述了编写测试代码相关的最佳实践。这些指导方针在代码审查过程中会被严格执行。



同code review一样,我们对不同类型的变更也有不同的测试标准,对测试范围有更高的要求,尤其是变更成本很高的情况。

所有这些系统使得我们能够从写测试代码的过程中获取最大收益,可以以很小的间接费用节省很多的开发周期。

代码质量指南

我们非常热衷于共享代码质量标准的指南,它可以帮我们做很多事情:

① 作为新开发人员培训的很好的工具。

② 与整个团队分享每个人的智慧和最佳实践。

③ 降低开发和代码审查过程的间接费用。比如说,我们讨论一次就可以得出一些有价值的结论的话,那么再在每次code review时讨论代码行应该是80个字符串还是100个字符串就完全没有意义了。



除了针对不同语言的语法风格指南,我们还有一些针对抽象事务的指导,比如如何写一个好的测试用例,或者如何做出更好的模块架构,从而提高工作效率。这些指南不是一成不变的,是随着我们对不同的过程有了更深的理解而不断发展的。我们还有很多重构的工具(一些开源工具比如codemod,还有一些内部开发的工具),以备我们改变指南的时候需要重新“修改”所有的历史代码。

旧代码的清理

一个快速发展的团队会尝试很多不同的工具,当然其中不乏有一些可以用而有一些不可用。到最后,任何一家快速发展的公司,随着时间的推移其代码库都会开发很多多余的东西,而这些可能永远都不会再用,放在那里只会使很多东西变得混乱。清理这些废弃代码可以使得代码库更健康的运行,还能提升开发的速度。



我们会定期组织“清理周”,对这些多余代码进行清理。在清理周内,某一些团队或者有时会发动整个公司专门来清理旧代码。这种定期的清理模式可以降低在“正常工作”和“清理工作”之间来回转换的成本,还能使得清理工作更加社交化,更加有乐趣。

代码库有些部分会比其他部分相对更好清理一些。同样地,清理代码库的不同部分会对开发速度产生不同的影响。为了能更好的利用好旧代码清理的时间,我们在考虑成本的基础上优化了相关模块,来进行清理工作,以及衡量清理工作对未来开发速度的影响。

Linting

我们很可能会低估在某一实例中不遵循上述代码质量指南(比如说docstring的格式或代码行长度)所造成的成本,但事实上成本的确是增加了。同时,要记住各种各样的规则并应用,也是一件很烦的事情,尤其是规则还在不断增加。最终造成的结果就是,很多人都选择不再遵循这些指导方针。

我们开发了一个内部的linter,叫做qlint,可以相应减轻一些上述困扰。qlint是一个很智能的linter,可以读懂文本结构以及AST,是基于flake8和pylint的。它旨在使得未来增加自定义的lint规则变得更容易。比如说,我们其中一个做法是Python中任何一个“私有”变量都需要进行突出强调,所以我们在qlint中新增了一个规则,那就是可以检测出这类私有变量中任何不合理的地方。

我们还将qlint与很多系统集成起来,提供无缝的开发环境,这样人们就不必亲自盯着lint错误。对于新手来说,qlint是一个与我们常用的文本编辑器——Vim,Emacs和Sublime——充分集成的工具,可以在规则被破坏的情况下提供可视的反馈(红色标记)。它还与我们的推送流程集成在了一起,任何人在进行code推送的时候都可以运行qlint(以互动的方式)。而实际上,如果某项规则被commit打破,它有可能就会影响到部署工作。我们还将我们的风格指南与qlint集成起来,这样对每一个lint错误,qlint都可以给出一个超链接,指向相关风格指导的相应规则。我们的Phabricator也可以用qlint。通过这种方式,所有被qlint找到的错误都被明显的标记出来,这样他们的代码审查工作就变得相当容易了。



所有这些都帮我们实现了以很小的成本就能提升代码的一致性和质量。

结论

就像文章中所说的那样, Quora对代码的重视程度是很高的。我们讲求务实主义,搭建了很多好的系统、工具和流程,能帮我们增强并维护长期开发的生产效率。今天我们努力维持一个良好的平衡,我们的团队也在不断成长和发展,所以我们相信,未来我们还将生产更多的工具和系统。

如果你想帮我们搭建这样的系统,或者想成为我们强大开发团队的一份子,帮助我们以这样一种务实的、深刻的方式提升代码质量,那么欢迎加入我们

本文转自:http://www.jointforce.com/
原文链接:Moving Fast With High Code Quality
译者:杰微刊—程慧
  • 大小: 48.1 KB
  • 大小: 26.3 KB
  • 大小: 106 KB
  • 大小: 38.1 KB
  • 大小: 38.1 KB
  • 大小: 37.2 KB
来自: jointforce
2
0
评论 共 1 条 请登录后发表评论
1 楼 wentao365 2015-08-03 07:57
Quora是一个问答SNS网站,由Facebook前雇员查理·切沃(Charlie Cheever)和亚当·安捷罗(Adam D' Angelo)于2009年6月创办。

发表评论

您还没有登录,请您登录后再发表评论

相关推荐

  • makefile进入子文件夹执行make

    写了一个文件夹比较多的程序,在写主Makefile的时候,需要进入子文件夹执行make,在这里记录下,自己运行成功的Makefile。SUBDIRS=directory1 directory2 directory3 RECURSIVE_MAKE= @for subdir in $

  • Linux系统编程-Makefile文件使用

    Linux中使用Makefile

  • 【makefile】初步学习

    makefile简单示例学习

  • Yacc介绍与使用

    概念 •什么是YACC? yacc(Yet Another Compiler Compiler),是Unix/Linux上一个用来生成编译器的编译器(编译器代码生成器). 使用巴克斯范式(BNF)定义语法,能处理上下文无关文法(context-free)。出现在每个产生式左边(left-hand side:lhs)的符号是非终端符号,出现在产生式右边(right-hand side:

  • 【Makefile基本知识】

    一个工程中的源文件不计其数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为 makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。Makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE。

  • Makefile学习-10 打印

    在makefile中打印可以使用echo或者info、warning、error打印 1- 目标内部打印---可选择echo 注意:echo必须在某个目标下面!否则报错 示例: all: @echo hello world 2- 任意位置打印--可选择info warning error echo打印有局限性,必须在目标下面。在任意位置加调试打印可使用下面方式 $(info "xxx") $(warning "xxx") $(error "xxx") 注意:对于erro

  • makefile 入门

    makefile 入门

  • make命令

    代码变成可执行文件,叫做编译(compile);先编译这个,还是先编译那个(即编译的安排),叫做构建(build)。Make是最常用的构建工具,诞生于1977年,主要用于C语言的项目。但是实际上 ,任何只要某个文件有变化,就要重新构建的项目,都可以用Make构建。 1、一个简单 makefile例子 Make这个词,英语的意思是"制作"。Make命令直接用了这个意思,就是要做出某个文件。比如,要做出文件a.txt,就可以通过以下步骤实现: 1)书写规则,...

  • #跟我一起写 Makefile# make的退出码&指定Makefile

    目录 make的退出码 指定Makefile 一般来说,最简单的就是直接在命令行下输入make命令,make命令会找当前目录的makefile来执行,一切都是自动的。但也有时你也许只想让make重编译某些文件,而不是整个工程,而又有的时候你有几套编译规则,你想在不同的时候使用不同的编译规则,等等。本章节就是讲述如何使用make命令的。 make的退出码 ...

  • makefile编写知识小结

    1、Makefile中的宏定义 -D 增加编译宏定义;-I增加头文件搜索路径; 示例:CFLAGS+=-D __CUSTOMER_CODE__, 则编译时,只编译__CUSTOMER_CODE__宏定义的代码 示例二: INCS = -I $(ENX) INCS += -I ./ \ -I include \ 指定头文件查找的目录。 2、ifeq else endif 条件编译,表示条件相等时执行某段代码 ifeq ...

  • makefile常用的命令总结及简单示例

    makefile常用指令

  • Makefile 保姆级使用教程

    Makefile 使用教程 设计思想 Makefile 菜鸟教程Makefile 规则 Makefile的使用介绍 make 命令的使用 即时变量、延时变量介绍和使用使用make命令编译多个文件假想目标 常用函数 1.$(foreach var,list,text) 2.$(wildcard pattern) 3.$(filter pattern...,text) 4.$(filter-out pattern...,text) 5.$(patsubstpattern,replacement,text)

  • Linux命令make -f,linux 之命令make

    在linux中,有一个重要的自动化编译命令—make,在源码文件的安装和开发大型项目的时候,都需要用到这个命令,例 安装程序和安装检测 make , make install make test例 卸载安装文件 make clean采用make 命令编译大型项目,可以使编译工作变的简单而有序,通过编写MakeFile 描述文件可以使整个项目中所有源文件之间的依赖关系一清二楚。如果没...

  • Makefile的使用

    Makefile的使用

  • linux指令firstword的用法

    $(firstword <text>) 名称:首单词函数——firstword 用法:取字符串<text>中的第一个单词 返回:返回字符串<text>的第一个单词 示例:$(firstword foo bar)返回值是“foo”。 示例: ABC := foo ba sda vdf $(firstword $(ABC))返回值是“foo”。 备注:这个函数可以用 wo...

  • makefile中使用shell 命令

    在makefile中要使用shell 命令必须加shell 例如$( shell pwd),不加的话是空值,例如下例中的M就是空值 这个你写法如下:直接通过make 命令就可以运行下面的makefile 附上源码:注意$(MAKE) 前面有一个tab键 ipmi_hisi_lpc_bt-objs := lpc_ipmi.o lpc_bt_sm.o obj-m

  • Linux复习篇(二)--makefile文件及make命令

    什么是makefile文件? 介绍一下make命令,make命令是GNU的工程化编译工具,它用于编译大量互相关联的源代码,使用它可以实现项目的工程化管理,提高开发效率。那么对于一个项目,该如何让它按照我们预想的规则去编译链接执行呢?这就要用到我们要学习的Makefile了。Makefile的作用就是在执行make命令的时候指定编译和链接的规则,包括源代码文件之间的链接关系、依赖关系等。它关系到整...

  • makefile的执行过程

    1.一次读取变量“MAKEFILES”定义的makefile文件列表 2.读取工作目录下的makefile文件(根据命令的查找顺序“GNUmakefile“, ”makefile“, ”Makefile“,首先找到哪个就读取哪个) 3.一次读取工作目录makefile文件中使用指示符“include“包含的文件 4.查找重建所有已读取的makefile文件的规则(如果存在一个目标是当前读取的某一个makefile文件,则执行此规则重建此makefile文件,完成以后从第一步开始重新执行) 5.初始化

  • Makefile常见“符号” 超全总结(绝对经典,这一篇就够了)

    可快速查找某几个符号具体含义,帮助你快速看懂自己的Makefile文件

  • Makefile简单的使用

    Makefile 就是一个文件,能体现出我们是否具备大型项目的开发能力Makefile中保存的就是整个项目的编译的规则,他可以根据文件的时间戳来判断哪些文件需要重新编译。make是一个可执行程序,是 /usr/bin/make是专门用来解析 Makefile 文件的如果系统中没有 make可以自己安装 sudo apt-get install make。

Global site tag (gtag.js) - Google Analytics