回想起来自己工作这么些年,也经历了不少团队,经历的项目更不算少了, 但是要说到代码规范, 问我我经历的这些代码规范是不是满意,我不得不如实回答:不是很满意。当然我自己的代码规范和风格也没有完全固化下来,近一年左右也开始关注到这个问题,为了让自己的代码风格能逐渐固化,我会专门用一个笔记来记录一些可能自己会纠结的写法,这样做了以后明显能感觉到自己代码风格的飘忽程度有所收敛。恰巧公司负责的项目也需要整理代码规范,正因如此我开始思考 如何制定可执行的代码规范 这个问题。
提到团队的代码规范,不止我经历过的,我和一些朋友也有聊过, 有微软那个级别的,也有 BAT 这种级别的,项目大的也有,小的亦很多。其中不乏规范的做的比较好的,有规范、有工具、还会有 Code Review 来保证。但是大公司规范和流程真的适合所有团队吗?我所看到的是大部分团队参照某某公司的规范和流程,定义了一个非常严格的标准,然而实际上并没有严格实施下去或者没有持续实施下去。最后都会甩锅给“历史包袱太重”、“开发人员太多太杂难以推广”这样的理由。
近半年到一年在代码规范这一块我主要思考如何在中小团队没有代码规范的基础上制定代码规范。根据自己的思考也正在组内逐步实践,从目前实践情况来看我是比较满意的,所以把自己观点写出来,希望能对跟我有同样困惑的人有些帮助。
所有的规范,包括但不限于代码规范,都会包含规范制定、规范推广执行、规范修正的过程。 其中规范的推广和执行通常是最难的(这就是为什么有很多流程文档,但是流程还是非常混乱的原因),而制定了什么样的规范直接决定了推广执行的难度,所以我们先从代码规范的制定说起。
大部分团队应该都是有 KPI 的,而且一般重要的事情都会被定成 KPI, 所以有些团队为了强调代码规范, 将其定为某些员工的 KPI,这样重视代码规范行为我是非常欣赏的,但是我不认同,因为我认为 代码规范不应该是一个文档, 代码规范应该是一种行为, 一种持续的行为,而 KPI 是要求可以量化有明确目标的。若把代码规范当作 KPI, 背了 KPI 的员工为了让 KPI 可量化, 通常情况会写出来一个代码规范文档,众所周知文档最可 量化的当然是页数,故最终可能会产出一个几十页的代码规范,它可能是结合了 Google、Facebook、Tencent 等等大公司的代码规范,几乎面面俱到,看起来就很高大上。
代码规范文档出来了,KPI 看起来也完成得不错,那然后呢?如果我们把代码规范理解为一种行为,那这文档就仅仅只是一个行为准则,它就像是一部法律,要求大家都要如何做,所以接下来更重点的工作应该是去让这些文档落地,让大家理解认可执行它。并且还需要有相应的监督机制、审查机制来保证大家确实按规范在写代码。但是后面这些,也就是整个代码规范实施最难的点,要量化又极其不易。能如何量化呢?量化推广程度?量化大家对各条代码规范的理解透彻程度?难道用考试来量化吗?这就是把代码规范设定成 KPI 的尴尬, 为了让 KPI 看起来丰满, 产出了一个丰满的规范, 而对于整个过程中最难的落地执行环节, 丰满的规范为其增加了阻力。
以前我对于代码规范的理解是也是越丰富越好,但是在近半年推广代码规范的过程中我开始青睐简单一些的代码规范,因为我相信大部分人会赞同:一个被 100% 彻底执行了的 40 分代码规范应该是好于一个被执行了 40% 的 100 分代码规范。
这个观点可能会更比较多人的看法不太一样, 因为很多人都认为规范应该前期就定下来,而且尽可能面面俱到,否则后面定规范容易背上历史包袱。前期就应该定规范的这个观点我比较认同,首先我们抛开你们团队已经有非常完善代码规范这种情况,因为如果是那样,你只需要按原有规范执行即可。
这里主要讨论新项目没有规范的情况下怎么做,我们可以复盘一下新项目开始阶段,通常情况新项目需求节奏都会非常快,基础框架、基础组件、大批量业务需求要开发,又因为是新项目,通常不会有特别多的人力投入,这种情况下,一个很严格冗长的代码规范,要求大家在拼命跑的过程中还要去理解执行你的规范,可能性大吗?所以这个时期的代码规范需要非常简单易于理解,要在所有人即使在赶需求,也能忍受的范围内制定规范。这个阶段最急迫的需求是用简单的代码规范让大家养成习惯,提升意识,宣告这个项目是有规范的。
我们拿前端项目来举例,首先应该先保证 JS 代码风格是对的,其次可能根据技术选型不同(例如 Angular,React),要遵循另外一批 Best Practice。按上述思路,我会在前期只要求大家 JS 代码格式规范就行了。因为把各种 Best Practice 一股脑的全丢进去容易绕晕大家。 如果你真的舍不得那些 Best Practice,我建议将其列为建议级别的,先不做必须,必须的条目尽可能精简。
上面一段提到代码规范应该循序渐进,但是简单的规范从何而来呢?之前看到过的一种做法是:团队内大家一起讨论,民主决定某一些规范的细节,因为这样可以出来一个适配这个团队的代码规范。
这听起来很美好,非常民主,大家很平等,但是回想一下以前这么做的结果是什么?我猜应该会有很多人又回忆起“大括号应不应该换行”、“else 是否应该换行”、“是否允许空两行”、“JS 结尾带不带分号”等等类似的争论吧,然而这些争论是有必要的吗?说白了,大部分争论找的理由都只是在为自己的代码习惯争取更多空间。这样的争论还只是“民主”引发问题的开始,更严重的是这会在所有开发人员心中形成一种“规范是可以商量和讨论的”心理暗示,这必对后续规范的执行成为阻碍,特别是一些本身就有争议的点,总会有人伺机反扑。
另外,“民主”的规范其实很难做到让所有人心理上平衡,例如可能会让 B 开发觉得自己在遵从 A 开发的习惯,即使这种感觉可能不是那么强烈,它也会变成规范执行的阻力。
正因为上述原因,我非常建议制定规范时“独裁”。我们的目标很清晰,就是要求代码写法一致,“独裁”的基础上可以选择一个第三方的标准,例如细的条目可以完全选择 Google 或者 Facebook 或者其他一些大公司的标准(当然可能还需要考虑我上面提到的循序渐进,做裁剪,但是规则细则不要再去讨论和挑战)。首先可以保证的是这些规范不会有太大的问题,跟着做不会犯大错;其次,“独裁”使用的规范来源于第三方,对团队内所有人公平;最后,这样的规范和行业更亲近。
我在我们的前端项目里面就选择了 StandardJS 的规范,StandardJS 的出现初衷也正是为了解决上述“民主”引发的问题。除此之外,还有一个好处是这些第三方规范的成熟不只是规范本身,它的配套工具会成熟很多,可以节省自己很多成本。
上面我们已经讨论了如何建立代码规范,主要强调了 代码规范不应只是一纸空文、代码规范要循序渐进、代码规范的制定需要“独裁”。这些都属于“立法”过程,接下来要讨论的必然是“执法”,代码规范的“执法”主要需要关注两点,一点是“违法”行为的判定,另一点是“违法”行为的责任追究,也就是代码规则检查以及发现不符合规范的代码应该由谁来负责。
代码规则检查通常直接使用现有成熟工具就好,例如前端开发常用的 ESLint,现在各种语言都有各自比较成熟的工具,我这里想强调的是几个检查代码的时机,一是写代码的时候,这是源头,配置一个好的 IDE 检查规则能从源头避免不规范的代码。二是提交时候,通常是设置 git/svn 的 hooks(PS: git 的 hooks 在 2.9.0 之前相当的难用,如果你用的版本低于 2.9.0,可以考虑升级并配置代码检查的钩子)。三是 CI 的时候,这是最后一关,可以保证合流以后的代码不出现规范的问题。只要在上面三个点严格执行了,不规范的代码几乎已经无处可藏。
“违法”行为判定尽可能通过工具来判定,那如果出现了库里面提交了不合规则的代码应该由谁去改呢?如果有 CI,那只需要增加提交构建,即可在 push 后的第一时间揪出违规者。如果没有 CI,我建议是先建立 CI,如果实在没有,那可以考虑最后提交代码负责制,最后提交代码的人可以去找这份代码是 merge 了谁的,追溯到上游把“锅”丢出去,最终找到违规者并要求改进(不限于代码的改进,更重要的是各种代码检查环境的配置)。这样的定义可以让所有开发知道遇到问题以后该如何走下一步,我认为是非常有必要的。
说到这里我猜必然有读者想到了 Code Review,实际上 Code Review 不应该是去关注代码风格的,所有到 Code Review 环节的代码必然是要过了代码风格检查的,Code Review 主要关注的是代码结构设计和代码逻辑,它是在代码规范上一层的东西。如果你的团队在使用 Code Review 来保证代码规范,那你们可能需要进一步完善自己的代码规范检查工具。
代码规范的好处大家都知道,但是任重道远。真正去推行代码规范的人,如果按我上面说的几点去做,可能会有各方面的压力,特别是上面提到的“独裁”和“执法”两点,但是从我自己的实践经验来看,想象中的压力小于实际,主要还是需要向同事们解释清楚各种做法的理由,得到理解和支持。为了避免前期的推行的压力过大,可以考虑裁剪规则(特别是在没有很好代码规范文化的团队内),因为提升团队人员意识和养成代码规范的习惯应该是最最首要的任务,这两点有了以后,再逐步的把要求提高,应该会容易得多。这个过程有困难,但是我坚定的认为这是值得的。
今日荐文
点击下方图片即可阅读
如果你想知道未来的架构如何发展,推荐一场汇聚国内外顶尖架构师的线下会议:ArchSummit 全球架构师峰会,从大数据框架到移动轻应用 ,从低延迟架构设计到人工智能落地,这里只谈最优秀的架构实践。大会将于 7 月 7 日深圳开幕,目前 9 折最后一周,点击“阅读原文”,看看对你有何启发?