什么是规范?
规范,名词意义上:即明文规定或约定俗成的标准,如:道德规范、技术规范等。 动词意义上:是指按照既定标准、规范的要求进行操作,使某一行为或活动达到或超越规定的标准,如:规范管理、规范操作.
为什么需要规范?
- 降低新成员融入团队的成本, 同时也一定程度避免挖坑
- 提高开发效率、团队协作效率, 降低沟通成本
- 实现高度统一的代码风格,方便review, 另外一方面可以提高项目的可维护性
- 规范是实现自动化的基础
- 规范是一个团队知识沉淀的直接输出
规范包含哪些内容?
前端协作规范并不单单指‘编码规范’,这个规范涉及到前端开发活动的方方面面,例如代码库的管理、前后端协作、代码规范、兼容性规范;
不仅仅是前端团队内部需要协作,一个完整的软件生命周期内,我们需要和产品/设计、后端(或者原生客户端团队)、测试进行协作, 我们需要覆盖这些内容.
1 工作流规范
1.1 开发
1.1.1 版本规范
项目的版本号应该根据某些规则进行迭代, 这里推荐使用语义化版本规范, 通过这个规范,用户可以了解版本变更的影响范围。 规则如下:
- 主版本号:当你做了不兼容的 API 修改,
- 次版本号:当你做了向下兼容的功能性新增,
- 修订号:当你做了向下兼容的问题修正。
1.1.2 版本控制系统规范
大部分团队都使用git作为版本库,管理好代码也是一种学问。尤其是涉及多人并发协作、需要管理多个软件版本的情况下,定义良好的版本库管理规范,可以让大型项目更有组织性,也可以提高成员协作效率.
比较流行的git分支模型/工作流是git-flow, 但是大部分团队会根据自己的情况制定自己的git工作流规范
Git 有很多工作流方法论,这些工作流的选择可能依赖于项目的规模、项目的类型以及团队成员的结构.
比如一个简单的个人项目可能不需要复杂的分支划分,我们的变更都是直接提交到 master 分支;
再比如开源项目,除了核心团队成员,其他贡献者是没有提交的权限的,而且我们也需要一定的手段来验证和讨论贡献的代码是否合理。 所以对于开源项目 fork 工作流更为适合.
了解常见的工作流有利于组织或创建适合自己团队的工作流, 提交团队协作的效率:
1.1.3 提交信息规范
组织好的提交信息, 可以提高项目的整体质量. 至少具有下面这些优点:
- 格式统一的提交信息有助于自动化生成CHANGELOG
- 版本库不只是存放代码的仓库, 它记录项目的开发日志, 它应该要清晰表达这次提交的做了什么. 这些记录应该可以帮助后来者快速地学习和回顾代码, 也应该方便其他协作者review你的代码
- 规范化提交信息可以促进提交者提交有意义的、粒度合适的'提交'. 提交者要想好要怎么描述这个提交,这样被动促进了他们去把控提交的粒度
1.2 构建规范
对于团队、或者需要维护多个项目场景,统一的构建工具链很重要, 这套工具应该强调"约定大于配置",让开发者更专注于业务的开发。例如,vue-cli3
更新有很多亮点,非常适合作为团队构建工具链的基础:
- 首先这类工具是推崇'约定大于配置'。即按照他们的规范,可以实现开箱即用,快速开发业务. 在团队协作中这点很重要,我们不推荐团队成员去关心又臭又长的webpack构建配置
vue-cli3
抽离了cli service层
,可以独立更新工具链。也就是说项目的构建脚本和配置在一个独立的service项目中维护,而不是像以前一样在每个项目目录下都有webpack配置和依赖. 这样做的好处是独立地、简单地升级整个构建链- 灵活的插件机制。对于团队的定制化构建应该封装到插件中,这样也可以实现独立的更新。
我们可以选择第三方CLI, 当然也定制自己的构建链,按照上面说的这个构建链应该有以下特点:
- 强约定,体现团队的规范。首先它应该避免团队成员去关心或更改构建的配置细节,暴露最小化的配置接口。 另外构建工具不仅仅是构建,通常它还会集成代码检查、测试等功能。
- 方便升级。尤其是团队需要维护多个项目场景, 这一点很有意义
1.3 发布工作流规范
发布工作流指的是将‘软件成品’对外发布(如测试或生产)的一套流程, 将这套流程规范化后,可以实现自动化.
举个例子, 一个典型的发布工作流如下:
- 代码变更
- 提交代码变更到远程版本库
- 程序通过CI测试(例如Travis变绿)
- 提升package.json中的版本
- 生成CHANGELOG
- 提交package.json和CHANGELOG.md文件
- 打上Tag
- 推送
1.4 持续集成
将整套开发工作流确定下来之后, 就可以使用持续集成服务
来自动化执行整个流程。比如一个典型的CI流程:
持续集成是什么,有什么意义呢?
我们需要持续集成
拆成两个词分别来理解, 什么是持续
? 什么是集成
?
持续(Continuous), 可以理解为'频繁'或者‘连续性’. 不管是持续集成还是敏捷开发思维、看板,都认为‘持续’是它们的基础。
举一个通俗的例子,比如代码检查,‘持续的’的代码检查就是代码一变动(如保存,或者IDE实时检查、或者提交到版本库时)就马上检查代码,而‘非持续’的代码检查就是在完成所有编码后,再进行检查。对比两者可以发现,持续性的代码检查可以尽早地发现错误,而且错误也比较容易理解和处理,反之非持续性的代码检查,可能会发现一堆的错误,失之毫厘谬以千里,错误相互牵连,最终会变得难以收拾。
‘持续’的概念,可以用于软件开发的方方面面,本质上就是把传统瀑布式的软件开发流程打碎,形成一个个更小的开发闭环,持续地输出产品,同时产品也持续地给上游反馈和纠正。
那什么是‘集成’呢?狭义的集成可以简单认为是‘集成测试’吧. 集成测试可以对代码静态测试、单元测试、通过单元测试后可以进行集成测试,在应用组成一个整体后在模拟环境中跑E2E测试等等。也就是说,在这里进行一系列的自动化测试来验证软件系统。
广义的持续集成服务,不仅仅是测试,它还衍生出很多概念,例如持续交付、持续部署,如下图
OK, 总结一下为什么持续集成的好处:
- 尽早发现错误,快速试错。越早发现错误,处理错误的成本越低
- 自动化工作流,减少人工干预。人类比机器容易犯错, 而且机器擅长做重复的事情
对于持续集成规范一般会定义这些内容:
- 执行的环境. 比如容器、Node版本、操作系统等等
- 触发的条件。比如定时触发、在哪个分支触发、会触发什么任务等等
- 执行的任务
- 划分持续集成的阶段. 比如
- 检查:包括单元测试和代码lint. 所有push到版本库的代码都会跑这个阶段. 一般可以在提交title中包含[ci skip]来跳过这个阶段
- 构建: 对前端项目进行构建. 只有打上版本tag的提交或release分支会跑构建任务
- 发布: 将前端的构建结果进行交付/发布. 只有打上版本tag的提交或者release分支在构建成功后会跑发布任务
- 定义持续集成脚本模板
2 技术栈规范
很少有人能精通Vue、React和AngularJS这三个框架的,更别说是一个团队。
三大框架跟编程语言一样都有自己的设计哲学,这跟库是不一样, 一个库的替换成本很低;而框架的背后是一个架构、一个生态。每个框架背后牵涉着开发思维、生态系统、配套工具、最佳实践、性能调优。要精通和熟练一个框架需要付出的成本是很高。
所以说团队的开发效率是基于稳定且熟练的技术栈的。稳定的技术栈规范有利于团队协作和沟通; 另外如果团队精通这个技术栈,当出现问题或者需要深入调优, 会相对轻松。
前端技术栈规范主要包含下面这些类型:
- 编程语言 - Typescript或Javascript
- UI框架及其配套生态, 以及备选方案。其背后的生态非常庞大:
- UI框架
- 路由
- 状态管理
- 组件库
- 国际化
- 动画
- 服务端渲染
- 脚手架、CLI工具
- 组件测试
- 样式. 包含了命名规范、预处理器、方法论等等
- 动画引擎
- QA. 包含了测试、Lint、格式化工具、监控
- 项目构建工具流. 例如webpack、vue-cli
- 包管理器。npm、yarn
- 项目管理工具
- 时间处理。例如Moment.js
- 模板引擎
- 开发工具
- 工具库
- 开发/调试工具
2.1 技术选型
怎么进行选型呢?举个例子, 先确定备选项, 你现在要选Vue还是选React(一个可能引起论战的主题)?
-
选择你最熟悉的技术。团队如果熟悉该技术,则可以很好地控制使用过程中的风险,方便对程序进行调优。所以成员熟悉、或至少Leader熟悉程度,是技术选型的一个打分项。
-
选择拥有强大生态和社区支撑的开源技术。有强大的生态和社区意味着,很多东西你不需要重复去造轮子,或者遇到问题可以很快解决,有更多的选择。
-
选择成长期的技术。<谈谈技术选型的注意事项>里面有一句话:'选择一个技术的最低标准是,技术的生命周期必须显著长于项目的生命周期'
我们选择的技术应该是向前发展的、面向未来的, 这是选型的基本原则。所以我们一般不会去选择那些'过气'的技术,比如
AngularJS
(1.x)、Backbone
. 因为现在有更好的选择,不必过于保守。 -
API的稳定性。API不稳定会导致社区的割裂,也会导致项目升级成本变高、或者无法升级, 最终成为技术债。
-
业务考虑 就是‘学会从业务端开始思考’. 意思就是选型需要充分地理解业务,理解用户需求,当下需要解决的首要问题,以及可能的风险有哪些,再将目标进行分解,进行具体的技术选型、模型设计、架构设计.
扩展:
2.2 迎接新技术
当然,对于团队而言也要鼓励学习新的技术、淘汰旧的技术栈。因为一般而言新的技术或解决方案,是为了更高的生产力而诞生的。当团队容纳一个新的技术选型需要考虑以下几点:
- 学习成本。考虑团队成员的接纳能力。如果成本小于收获的利益,在团队里面推行估计阻力会比较大
- 收益。是否能够解决当前的某些痛点
- 考虑风险。一般我们不能将一个实验阶段的技术使用的生产环境中
就团队而言,每个成员都有自己感兴趣的方向和领域,所以我们可以分工合作,探索各自的领域,再将成果分享出来,如果靠谱的话则可以在实验项目中先试验一下,最后才推广到其他项目.
3 浏览器兼容规范
前端团队应该根据针对应用所面对的用户情况、应用类型、开发成本、浏览器市场统计数据等因素,来制定自己的浏览器兼容规范,并写入应用使用手册中.
有了浏览器兼容规范,前端开发和兼容性测试就有理有据,避免争议; 同时它也是前端团队的一种对外声明,除非特殊要求,不符合浏览器兼容规范的浏览器,前端开发人员可以选择忽略。
4 项目组织规范
项目组织规范定义了如何组织一个前端项目, 例如项目的命名、项目的文件结构、版本号规范等等。尤其对于开源项目,规范化的项目组织就更重要了。
4.1 通用的项目组织规范
一个典型的项目组织规范如下:
-
README.md: 项目说明, 这个是最重要。你必须在这里提供关于项目的关键信息或者相关信息的入口. 一般包含下列信息:
- 简要描述、项目主要特性
- 运行环境/依赖、安装和构建、测试指南
- 简单示例代码
- 文档或文档入口, 其他版本或相关资源入口
- 联系方式、讨论群
- 许可、贡献/开发指南
-
CHANGELOG.md: 放置每个版本的变动内容, 通常要描述每个版本变更的内容。方便使用者确定应该使用哪个版本. 关于CHANGELOG的规范可以参考keep a changelog
-
package.json: 前端项目必须. 描述当前的版本、可用的命令、包名、依赖、环境约束、项目配置等信息.
-
.gitignore: 忽略不必要的文件,避免将自动生成的文件提交到版本库
-
.gitattributes: git配置,有一些跨平台差异的行为可能需要在这里配置一下,如换行规则
-
docs/: 项目的细化文档, 可选.
-
examples/: 项目的示例代码,可选.
-
build: 项目工具类脚本放置在这里,非必须。如果使用统一构建工具,则没有这个目录
-
dist/: 项目构建结果输出目录
-
src/: 源代码目录
-
tests/: 单元测试目录.
-
tests: 全局的测试目录,通常放应用的集成测试或E2E测试等用例
-
.env*: 项目中我们通常会使用
环境变量
来影响应用在不同运行环境下的行为. 可以通过dotEnv来从文件中读取环境变量. 通常有三个文件:.env
通用的环境变量.env.development
开发环境的环境变量.env.production
生成环境的环境变量
对于开源项目通常还包括这些目录:
- LICENSE: 说明项目许可
- .github: 开源贡献规范和指南
- CONTRIBUTING: 贡献指南, 这里一般会说明贡献的规范、以及项目的基本组织、架构等信息
- CODE_OF_CONDUCT: 行为准则
- COMMIT_CONVENTION: 提交信息规范,上文已经提及
- ISSUE_TEMPLATE: Issue的模板,github可以自动识别这个模板
- PULL_REQUEST_TEMPLATE: PR模板
任意一个优秀的开源项目都是你的老师,例如React、Vue...
4.3 脚手架和项目模板
在将项目结构规范确定下来后,可以创建自己的脚手架工具或者项目模板,用于快速初始化一个项目或代码模板。
5 编码规范
网络上大部分‘前端规范’指的都是编码规范, 这是一种‘狭义’的前端规范.
统一的编码规范对团队项目的长远维护不无裨益. 一致性的代码规范可以增强团队开发协作效率、提高代码质量、减少遗留系统维护的负担。
最直接的好处就是避免写出糟糕的代码, 糟糕的代码与新手和老手关系不大,糟糕的代码随着项目的迭代会变得难以控制。
现代的Lint工具已经非常先进,几乎可以约束各种编码行为. 比如约束一个文件的长度、函数的复杂度、命名规范、注释规范、接口黑名单、检查简单的逻辑错误...
每一个程序员心目中对‘好代码’都有自己的主见,统一的编码规范可以像秦始皇统一战国一样,避免不必要的论战和争议。
其实与其自己建立前端编码规范,推荐选择社区沉淀下来的规范. 这方面的资源非常多, 推荐下面这些资源:
5.1 Javascript
- Lint工具
- 规范
- JavaScript Standard Style - 🔥 零配置的、‘标准’的Javascript编码规范. 底层基于Eslint。目前不支持Typescript
- Airbnb JavaScript Style Guide - Airbnb的编码规范,业界标杆
- 类型检查. 暂时将它们归类到这里,因为它们同属于‘静态测试’
- Typescript - 🔥 Javascript语言的超集,这是一门‘新’的语言,而不是简单的类型检查器. 不过它也支持原生Javascript的类型检查
- Flow - Facebook出品的类型检查器,语法和Typescript类似. 个人推荐使用Typescript
5.2 HTML
- Lint工具
- 规范
5.3 CSS
- Lint工具
- stylelint - 🔥 通用的CSS编码检查工具,支持最新的CSS语法、CSS-in-js、以及其他类CSS语法(如SCSS、Less). 它也有预定义配置,推荐使用
- 规范
- 方法论
关于CSS可以学习Bootstrap这些传统UI框架,他们的代码组织性非常好, 值得学习
5.4 代码格式化
- Prettier - 🔥 关于代码格式化的所有东西都交给它吧!
基本上,所有代码格式相关的工作都可以交给Prettier来做,在这个基础上再使用Eslint覆盖语义相关的检查
6 UI设计规范
这是一个容易被忽略的规范类型。没有所谓的设计规范,就导致设计出来的产品都是东借西凑,前后不统一,多个应用之间的组件不能复用。这搞得我们不得不浪费时间,写很多定制化样式和组件
简单总结一下UI设计规范的意义:
- 提供团队协作效率(产品和开发)
- 提高组件的复用率. 统一的组件规范可以让组件更好管理
- 保持产品迭代过程中品牌一致性
建立一个定义良好的设计规范需要UI设计和开发
的紧密配合,有时候也可以由我们前端来推动。
比如很多开源的UI框架,一开始都是开发者YY出来的,并没有设计参与,后来组件库慢慢沉淀成型,UI设计师才介入规范一下。
如果你们团队不打算制定自己的UI设计规范,则推荐使用现成的开源组件库:
这些开源组件库都经过良好的设计和沉淀, 而且配套了完善的设计原则、最佳实践和设计资源文件(Sketch 和 Axure),可以帮助业务快速设计出高质量的产品原型
7 前后端协作规范
前端是Web的一个细分领域,往往不能脱离后端而存在。所以和后端协作的时间是最长的.
7.1 协作流程规范
前后端团队经过长期的合作,一般可以总结出一条对于双方开发效率最优的协作流程. 将这个落实为规范,后面的团队成员都遵循这个步调进行协作。
- 需求分析。参与者一般有前后端、测试、以及产品. 由产品主持,对需求进行宣贯,接受开发和测试的反馈,确保大家对需求有一致的认知
- 前后端开发讨论。讨论应用的一些开发设计,沟通技术点、难点、以及分工问题.
- 设计接口文档。可以由前后端一起设计;或者由后端设计、前端确认是否符合要求
- 并行开发。前后端并行开发,在这个阶段,前端可以先实现静态页面; 或者根据接口文档对接口进行Mock, 来模拟对接后端接口
- 在联调之前,要求后端做好接口测试
- 真实环境联调。前端将接口请求代理到后端服务,进行真实环境联调。
7.2 接口规范
首先应该确定下来的是接口规范。其实使用哪种接口标准是其次,重要的是统一,且要满足前后端的开发效率要求.
不建议后端去定义自己的接口标准,而应该去选择一些通用的、有标准定义接口形式, 例如:
-
RESTful: RESTful是目前使用最为广泛的API设计规范, 基于HTTP本身的机制来实现.
因为是使用最广泛的API形式,所以社区上有很多工具来对RESTful接口进行文档化、测试和模拟.
接口设计需要注意的点:
- 明确区分是正常还是异常,当出现异常时应该返回
错误对象
响应,而不是在正常的响应体中返回错误代码. 另外要规范化的错误码, HTTP响应码就是一个不错的学习对象 - 明确数据类型。
- 明确空值的意义。比如在做更新操作是,空值是表示重置,还是忽略更新?
- 响应避免冗余的嵌套。
- 接口版本化,保持向下兼容。就像我们上文的‘语义化版本规范’说的,对于后端来说,API就是公共的接口. 公共暴露的接口应该有一个版本号,来说明当前描述的接口做了什么变动,是否向下兼容。
7.3 接口文档规范
后端通过接口文档向前端暴露接口相关的信息。通常需要包含这些信息:
- 版本号
- 文档描述
- 服务的入口. 例如基本路径
- 测试服务器. 可选
- 简单使用示例
- 安全和认证
- 具体接口定义
- 方法名称或者URL
- 方法描述
- 请求参数及其描述,必须说明类型(数据类型、是否可选等)
- 响应参数及其描述, 必须说明类型(数据类型、是否可选等)
- 可能的异常情况、错误代码、以及描述
- 请求示例,可选
7.4 接口测试与模拟
为了做到高效率的前后端并行开发,接口的测试与模拟是必要的。
- 前端要求后端在联调之前,需要测试验证好自己的接口是否可以正常工作。
- 另外前端需要在后端接口未准备好之前,通过接口模拟的方式,来编写业务逻辑代码。
8 培训/知识管理/技术沉淀
一个团队的知识管理是非常重要的. 要问一个刚入行的新手加入团队希望得到什么?很多人的回答是'学习', 希望自己的技术可以更加精进。
8.1 培训
如果团队有规范的新成员培训手册,可以节省很多培训的时间,避免每次重复口述一样的内容。培训手册包含以下内容:
-
产品架构与组织架构.
-
工作范围: 团队成员的职责范围
-
建立资源索引: 开发需要设计到的资源,比如各种文档地址、研发系统入口(例如gitlab、bug跟踪系统、文件共享、发布平台、开发/测试环境、监控系统)、协作规范等等。将这些资源整理好可以减少不必要的沟通成本
-
规范: 即本文的主体'前端协作规范'。有规范可循,可以让成员以较快的速度入手开发、同时也减少培训成本投入。
8.2 营造技术氛围
-
鼓励成员写技术博客,或者建立自己的团队专栏. 写一篇好的文章不容易
-
鼓励参与开源项目
-
建立面试题库 组织一起解一些面试题或算法题,加深对知识点的理解
-
定期的专题分享. 鼓励团队成员定期进行专题学习和研究,编写技术博客,并将学习的成果分享给其他成员. 这是一种抱团取暖的学习方式,旨在帮助团队成员一起学习和成长。
比如开发老手可以分享自己的经验,研究更深层次的技术;新手则可以研究某些开发技巧、新技术,例如CSS Grid,svg动画等等。
专题怎么来?
- 专题请求. 可以请求其他成员完成专题,比如比较深的知识,可以要求团队比较有经验的进行学习分享
- 学习总结.
- 项目回顾
- 难点攻克
- 项目规范
- 工具使用
-
落实和完善开发规范. 规范本身就是团队知识沉淀的一种直接输出
-
图书分享. 和离散的文章或教程相比,图书的知识会比较系统,另外很多经典的图书是要静下来好好欣赏的。
-
鼓励重构和持续优化代码
-
抽象一套基础库或框架,减少重复工作, 提高工作效率. 不加班先从提高工作效率开始