如何保障前端项目的代码质量
Posted 前端那些事儿
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何保障前端项目的代码质量相关的知识,希望对你有一定的参考价值。
对于中大型前端项目,项目规范与代码质量尤为重要。当功能需求变更或需要重构时,随心所欲的(糟糕的)代码可能带来比重新开发还麻烦的问题。
1 前端项目代码中的常见问题
1.1 凌乱的书写风格,阅读体验差
这个问题不用作过多阐述,想必接手过他人代码的同学,多少都有些体会。简单来说,太过随意的代码会让强迫症患者难以容忍,难以阅读理解的代码有时甚至不如推倒重来。
1.2 低质量的编码,bug 不断
什么样的代码是低质量或高质量的?好的代码可能会让你如读小说一般被吸引,糟糕的代码会让你看一眼就不想继续、甚至看半天而不知所云。
有人可能认为初级程序员才会有这种问题,其实不然,一些工作经验两三年的同学写的代码依然如此。对于一些个人自学意识不够积极、没有团队规范性指引的同学,很容易习惯成“学习半年、然后重复三年无长进”的情况。
拿出来你可能不太愿意相信,下面这些例子即来源于真实项目。你能尽可能地找出其中存在的各种问题吗?
图1
图2
图3
图4
图5
图6
图7
以上只是截取的一些很简短的列子,那么涉及大块复杂逻辑的地方会是怎样的,试试发挥一下你的想象力。
1.3 功能不分离,逻辑糅合,难以阅读和理解
这种问题其实是非常普遍的。一个函数几百行、一个文件数千行、一个类几十个方法、方法参数定义随意、没有任何注释、方法与变量命名无明确的语义、数据修改与变更穿插在各种方法中等等。 这样的编码方式,你要去理解它的逻辑往往真的很难,一般只能一块块一行行的去做阅读理解(可能还会开启边看边骂娘模式)。
这主要原因在于开发者个人的基础知识能力、编码经验和意识等的不足。
其实针对这种情况,常见的开源的编码规范都会有所提及。我的建议是这些同学应该好好温习一下面向对象编程、函数式编程、数据结构、常见设计模式,看一看各种开源的编码规范并尝试去真正的理解它们。当你回顾一个月前的代码时,发现可以改进或重构使得编码逻辑更为简洁清晰,说明你是在成长与进步的。
经常看到各种社区中都会有同学问这类问题:新项目正在选型,Vue.js、React、Angular 三大框架哪个合适?其实团队开发成员对这些都比较有经验,哪种都可以;如果团队成员前端开发经验大都不是太丰富或人员不够稳定,选择 Vue.js 最适合,为什么?因为它更简单简洁,容易上手。Vue.js 通过 prop、data、computed、method、watch 等各种钩子,一定程度上限定了编码方式与风格,使得初级开发者写出来的代码也不会太难看,这也是它越来越受社区推崇的原因之一。
2 保障前端项目编码质量的方法
如何保障前端项目的编码质量呢?依我看来可以从这几个角度考虑:制定编码规范、开发工作流 lint 风格强制检查、定期 Code Review、单元测试。
2.1 制定项目编码规范
团队协作项目中,编码规范尤为重要。对于初级程序员,因经验欠缺,编码规范的要求可以避免许多低级问题的产生;对于多人团队来说,风格一致的编码约定,在协作开发、代码移交等时,可以在很大程度上降低风险和成本。
那么编码规范应当如何制定?
没有最好的风格,只有团队认同的一致性约定。一般来说可以由团队负责人牵头制定,成员提意见补充,最后落地成团队规范并严格执行。业界有很多优秀前端团队开源的规范可供参考。如:
参考 Angular 编码风格指南 | 中文
参考 Airbnb javascript Style Guide | 中文参考
参考 Code Guide by @imweb
参考 fex-team/styleguide
参考 es6-code-style-guide
参考 idiomatic.js - 书写具备一致风格、通俗易懂 JavaScript 的原则
参考 JSDoc 中文文档
参考 es6 编程风格
参考 Vue.js 风格指南
参考 Vue.js 组件编码规范
学习编码规范约定是有必要的,但你能在看完后并真正的理解它们吗?
2.2 在开发工作流中配置 lint 风格检查与修正
在开发工作流中引入工具辅助,可以强制性地实现编码书写和提交过程中的 lint 校验。可以怎么做?条条大道通罗马,下面以当前流行的 Git Hook 方案举例供参考。
2.2.1 开发编辑器及 lint 工具配置
我们在项目中配置 TSLint
插件以校验 typeScript
;配置 styleLint
插件以校验 CSS/LESS。
我们约定团队开发均采用 vscode
编辑器,并至少安装以下插件辅助开发:
TSLint
stylelint
Document This
EditorConfig for VS Code
Prettier - Code formatter
Debugger for Chrome
2.2.2 添加 .editorconfig 文件
由于不同开发者可能使用的编辑器不同,但各种编辑器基本都支持 .editorconfig, 故每个项目都应当包含 .editorconfig
,用来统一配置编辑器的换行、缩进存储格式。
配置参考:
# http://editorconfig.orgroot = true[*]
indent_style = space # 输入的 tab 都用空格代替indent_size = 2 # 一个 tab 用 2 个空格代替# end_of_line = lf # 换行符使用 unix 的换行符 \ncharset = utf-8 # 字符编码 utf-8trim_trailing_whitespace = true # 去掉每行末尾的空格insert_final_newline = true # 每个文件末尾都加一个空行[*.md]
trim_trailing_whitespace = false # .md 文件不去掉每行末尾的空格复制代码
2.2.3 配置 Git Hook 强制执行编码风格检测与修正
借助 Git Hook
,可以在提交代码时执行风格检测与修正,当存在无法通过的内容时,提交会被 block,从而实现编码规范的强制性执行。
可以利用以下几个工具来实现这个流程:
husky
它会安装一系列 git hook 到项目的.git/hook
目录中,这些钩子可以检测package.json
中的scripts
脚本命令配置,并在代码提交时执行它(我们这里利用pre-commit
钩子)lint-staged
可以取得所有被提交的文件并依次执行配置好的任务命令styleLint/TSLint/ESlint
各种 lint 校验工具,可以配置到lint-staged
的任务中prettier
配置到lint-staged
的任务中,可以实现修正可自动格式化的编码风格
package.json
中的相关配置信息参考:
{ "scripts": { "precommit": "lint-staged",
}, "lint-staged": { "*.ts": [ "tslint --fix", "prettier --parser typescript --single-quote --print-width 120 --write", "git add"
], "*.less": [ "stylelint --fix", "prettier --parser less --print-width 120 --write", "git add"
]
}, "devDependencies": { "husky": "^0.14.3", "prettier": "^1.13.5", "prettier-stylelint": "^0.4.2", "stylelint-config-standard": "^18.2.0", "stylelint": "^9.4.0", "stylelint-config-prettier": "^4.0.0"
}
}复制代码
.prettierrc
配置文件参考:
{ "singleQuote": true, "trailingComma": "es5", "printWidth": 120, "overrides": [
{ "files": ".prettierrc", "options": { "parser": "json" }
}
]
}复制代码
.stylelintrc
配置配置参考:
{
"extends": [
"stylelint-config-prettier",
"stylelint-config-standard",
"./node_modules/prettier-stylelint/config.js"
],
"rules": {
// 定义一些适合团队约定的规则
}
}复制代码
通过以上配置,当代码提交时,会在 pre-commit
阶段执行 .git/hook/precommit
钩子,该钩子会查找并执行 scrpits
中的 precommit
命令,于是 lint-staged
定义的任务会被逐个执行。这套方案也是当前比较流行的做法,在很多开源项目中都有所应用。
拓展阅读:
用 husky 和 lint-staged 构建超溜的代码检查工作流
怎样提升代码质量
重构 - 代码优化技巧
2.3 执行 Code Review
编码规范与 lint 检查只能让大家的编码风格保持一致性,却无法避免低质量输出的问题。而这种问题对团队和产品来说往往却是致命的。
低质量的代码不仅仅只是会制造各种低级 bug,让测试同学测到没脾气,对产品来说,可能很小的需求改动却需要代码有巨大的变动,导致产品迭代周期被潜在地延长。另外,当大家的精力总是聚焦于需求开发和 bug 修复时,产品设计的细节就顾不了那么多了(别跟我说什么精益求精,赶时间解决完 bug 就烧香拜佛了),这对产品体验来说也是很要命的。
什么样的代码是好的,什么样的代码是不好的?这来源于知识的学习运用和开发经验的日积月累。低质量的编码说到底还是经验不同、水平存在差异。对于个人来说要通过不断的学习积累自我提升,对于团队来说进行 Code Review 评审是有必要的。
那么 Code Review 应当如何进行?
Code Review 的形式可以多种多样。如 GitHub 上许多流行项目采用 PR(Pull Request) 工作流的方式,一个 PR 至少经过三人次 review 通过才能合入,这能从流程上较好地保障项目代码质量。在有的开发团队或企业,会引入 gerrit 这种代码审核平台,过程与此大致相似。但对许多快速迭代的业务产品开发团队来说,这种需要多人评审通过的模式都不太适合:人力有限、时间紧迫、顾不了那么多了,于是即使 gerrit 也流于形式,编码质量只能落到开发人员个人的肩膀上。
相比较而言,定期进行小组讨论形式,问题的提出可以得到快速反馈和总结,这会让大家更有动力一些。
一般来说团队内有新人入职,基本的 Code Review 是有必要的,这时候编码规范与风格是 review 的重点。当大家对常见的基本问题都有了比较一致且明确的认识后,探讨交流学习则会逐渐成为 Code Review 的主要内容。
对于内部交流氛围浓厚的团队,可以鼓励成员之间互相审阅提交的编码。对大多数团队来说,可以这么来做:主要负责人以抽查浏览的形式快速审阅成员提交的代码,发现有问题的地方提出并打回改进(问题较多的同学的代码应重点关注);团队定期(可以是每周)以例会讨论的形式,对一周提交的代码进行抽样和总结式评审,学习好的编码方式、探讨不好的编码的理由,甚至进而沉淀出适合团队的编码约定。
另外注意一点,Review 过程的操作方式和表达用语非常重要,应当是轻松的沟通交流学习的方式,不要把 Code Review 执行成了批判会。
拓展阅读:
Code Review 都是怎么做的?遇到过哪些问题?
【译】如何用人类的方式进行 Code Review
2.4 编写单元测试
前端项目写单元测试,对很多人来说是不愿意的,因为编写过程太过复杂。但基本的单元测试是可以写的,公共方法和组件的修改可能会为某些调用模块制造潜在的 BUG,良好的单元测试可以在出现问题时快速反馈出来。
我们当前对项目单元测试的基本要求是这样的:
公共方法、服务类必须写单元测试
公共组件应当书写单元测试,应尽可能覆盖到各种功能点
业务组件可以书写简单的测试
注意测试代码质量,应当反复通过测试覆盖率评估和改进测试代码
Vue.js/React/Angular 三大框架都有完善的单元测试实现体系,在项目中引入单元测试的成本并不高,高的是测试代码编写的过程。在某些情况下我认为这种“高成本”是值得的。另外需注意,单元测试的执行一定要与 CI 集成,才能真正发挥它实时性反馈问题的作用。
2.5 其他
2.5.1 使用静态检查语言 TypeScript / Flow
JavaScript 是一种语法简单使用灵活的弱数据类型语言,而正是这种过于灵活的特性,使得开发者能够任性地书写,但任性是需要成本和代价的。
有时会看到一些后端同学会说,前端看上去也没那么难嘛,我只学了一天就开始上手撸代码了。他们或许说的没错,但是有经验的前端同学去看一下他们此时产出的代码,往往都会表示不忍直视。许多前端开发的同学并非计算机相关专业出身,没有太多相关的基础理论知识作为背景,刚开始干活时在代码输出上“随心所欲任意妄为”的情况更为普遍。
TypeScript 和 Flow 近两年来越来越火热,几乎当前流行的前端开源产品都在转向使用它们,这足以体现它们存在的重要价值。静态检查语言在编码阶段即可检测并提示出潜在的类型引用风险,可以在很大程度上避免许多因粗心、误用带来的逻辑 bug。良好的类型定义会使得项目模块逻辑结构更为清晰可控。借助编辑器强大的类型提示功能,代码编写甚至无需看详细文档即可快速了解用法。特别是中大型的复杂项目,选用它们绝对是利大于弊。
TypeScript TypeScript Github
Flow Flow Github
2.5.2 构建页面埋点统计平台
对于产品质量而言,监控体系是非常重要的一部分。对于前端而言,可以通过设计网站埋点统计平台来收集页面信息,如脚本报错、页面性能卡顿等问题,基于统计信息回溯分析问题根源,进而进行问题修复和代码改进。当然统计数据的作用绝不止这些,这里不作过多的扩展讲述。
以上是关于如何保障前端项目的代码质量的主要内容,如果未能解决你的问题,请参考以下文章