It's all about
connecting the dots

约束团队代码风格,提高代码质量

一、为何要进行代码风格检测

在一个项目团队中,每个成员都是独特的,大家都有自己的个性,这些个性在代码的书写上也有一定的体现。你会发现有些人喜欢在语句末尾加冒号,有些人不喜欢加冒号,还有一些人则是随机地加冒号或者不加冒号。在代码缩进的时候,你会发现有些人喜欢用空格,有些人喜欢用tab,即使是在空格的场景下,也经常能看到两种,一种是两个空格,一种是四个空格。在大部分情况下这种书写基本上都是属于纯个人喜好的问题,如果大家各自写各自的项目,那其实关系倒不是很大,反正就算是有坑也是自己给自己挖的。但是当你需要去维护一个团队的代码的时候,你就会发现大家各自按自己的喜好去写代码,带来的问题是非常大的,所以必须要借助eslint等lint工具或者我们自己写的一些脚本来进行代码的约束。代码风格错乱带来的问题至少有:

1.1、代码可读性下降

就我个人而言,我认为代码的可维护性,或者说,可读性,要比性能重要得多。多人开发的项目是一种工程化的产物,跟单人开发的项目是不一样的。

在单人项目中,我们可以很容易地做好代码的抽象。因为我们对我们自己的代码是很熟悉的,你知道什么时候可以把某个方法抽象出来,什么时候可以先不用去管他(过早的优化是没有意义的)。比如说你写第一个页面的时候需要写一个轮播图,但是因为这是第一个页面,所以不存在复用的情况,你可能直接就写了。过了几天,当你开始写了第二个,第三个,第四个,到第八个页面的时候,你发现,咦,这个地方好像跟前面第一个页面的东西差不多。然后你可能就决定把这一块轮播给抽象出来,然后在两个页面里直接去调用你抽象出来的方法/组件。我自己以前在公司维护过一个前端只有我一个人的项目,并且维护了相当长的一段时间,大概有两年左右。那个时候我用的就是这种策略,并且这种策略是主动的、自然而然的运用出来的。因为在你预期未来较长的一段时间内只有你一个人来维护这份代码,并且项目的需求迭代有一定周期规律的情况下,你除了做完常规功能需求之外,你还会希望让自己以后维护修改起来能方便一些,所以自然而然就会去做这些封装了。

在多人项目中,假设某一个文件,甲和乙都要去修改。开发者甲改了第一行和第三行代码并且使用的是两个空格缩进,开发者乙改了第二行和第四行代码并且使用的是四个空格缩进。这看起来好像没有什么问题。但是当我们将他们的代码合并到一起后,问题就来了。不妨先看下下面的代码:

if (a === '1') {
if (b === '2') {
     if (e === '6') {
    if (x === '7') return
    // code
     if (d === '5') {
        // code
} if (y === 7) {
    return 8
}}
            if (c === '3') {
 // code
   if (d === '5') {
        // code
    }}}
}

你以为这种代码是怎么写出来的?我觉得单人开发的项目中是很难出现这样的代码的,因为这对开发者的代码书写和阅读水平,带来了非常大的挑战,我认为没有一定“水平”的人是没法一个人完成这样子的代码的。当然上面这个例子是我故意夸张了一下子。实际上,类似的代码场景是非常多的,只是通常来说不会像上面这么高密度地集中在一起。下面这种代码就非常常见:

const RouteComponent = (
    <Route path="a" component=ComponentA>
    <Route path="b" component=ComponentB />
    <Route path="c" component=ComponentC />
    </Route>
)

在上面的例子中,是不是看起来好像ComponentA、ComponentB、ComponentC对应的Route都是同级的?但其实ComponentA对应的Route是包在另外两个Route的外面的,并非同级关系。

最后,需要强调一下,代码的可读性下降不单单是代码可读性下降就完事了,如果是这样的话谁还会在乎这个代码的可读性呢?可读性差的代码:

  • 非常容易产生bug;
  • 非常容易导致后续开发者不得不写很多脏代码,进而恶性循环,导致这一处代码越来越难维护;
  • 每次要修改此处代码时,前期需要花费较长的时间来阅读代码,否则无从下手。

1.2、不必要的性能浪费

比如你在代码中书写了下面这样的语句,其中objectA是一个对象:

console.log(objectA)

这里我们要说的不是兼容问题,而是性能问题。上面这种写法会导致objectA不被GC回收,长期占着茅坑不拉屎。

1.3、隐匿性较强的bug

有些人可能比较喜欢书写下面这样的代码,可大部分人在几百行的代码中扫读下面这种代码时,下意思会认为if条件语句里只是要单纯的返回一个truthy或falsy的值,并不会注意到这里存在赋值的动作。

if (a = 5) {
    // some code
}

这样就很容易因为代码的“歧义”导致出现bug。而且事实上,现实中我碰到类似场景的时候,最后几乎总是能发现,其实开发者自己一开始就是打算在这里进行全等判断而不是赋值的,也就是说一开始写成这样的时候就已经是bug了。如果我们通过代码检测工具约定不允许在if条件判断语句中使用赋值语句的话,上述这种bug就不会被带入产线环境了,因为执行代码检测的时候直接就报错了。

事实上,上面这种在if条件语句里进行赋值操作的场景还是非常常见的,但那是常见于编译产物代码中,不应该在团队维护的代码源码中出现这种写法。

二、如何添加代码风格检测

一般我们用vue或者react的脚手架cli工具创建好项目后,package.json的scripts字段下估计这时候已经有两个命令分别对应本地开发和构建正式产物了,假定这两个命令分别是:

  • npm run dev:本地开发(一般对应process.env.NODE_ENV => development);
  • npm run build:构建正式产物(一般对应process.env.NODE_ENV => production);

代码风格检测(以eslint为例)的逻辑,建议是npm run dev里要有,这样本地开发时可以直接在终端看到较及时的提示信息,然后最好用eslint-friendly-formatter这个包来处理下eslint的输出,处理后你就可以在终端(用iterm2)里通过点击报错提示里的文件路径直接跳到对应的文件上,不用手动去找文件了。

但是npm run build里不太建议加代码风格检测的东西。我的建议是新增两个命令:

  • npm run lint:进行代码风格检测(其他一些我们自己加的检测脚本,比如校验大家创建的文件的命名是否符合团队要求等)
  • npm run lint:fix:在eslint检测的时候开启自动修复功能。这块尤其是当你从其他项目copy了一段代码过来修改时非常实用。

之所以npm run build里不建议加这块逻辑而是单独拆出来。一方面是因为有很多场景下我们需要单独执行这块命令,比如我们本地提交代码前可以在本地的git hook里触发对应的检测(相关实现可以在npm仓库里搜【husky】这个库),或者也可以在gitlab上加这块的检测。另一方面当项目变大npm run build很慢时我们可以避免编译了很久最后发现是代码风格上有问题导致的时间浪费

有些团队里这块是通过在开发工具上配置来实现的,建议还是要有对应的命令来进行相对强制一些的校验。

小技巧,如果要强制在npm run build前自动执行npm run lint,除了修改npm run build的命令在前面加`npm run lint && …`也可以直接在package.json的scripts下新建一个字段”prebuild”,通过这种pre/post前缀,可以实现在当你执行某个命令时自动会在其前后执行对应的pre/post命令。比如你想在安装依赖之前执行某个脚本,你可以添加一个preinstall字段。

赞(1) 打赏
转载需注明来源并给出来源页链接:峰间的云 » 约束团队代码风格,提高代码质量

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏