如何规范多人协作开发

2,852 阅读21分钟

为什么要规范多人协作开发?

如果将开发比喻成开车,单人开发就像一辆车行驶在荒野公路上,没有限速、没有红绿灯、没有各种规则限制, 可以自由的疾速飞驰,可以顺畅的到达目的地。而多人协作开发,就像N辆车行驶在城市的交通线路上, 各自有不同的出发点和目的地(就像开发者各有不同的开发任务),且都想快速的到达目的地(完成开发任务)。 假如没有一套完善的交通规则(红绿灯、交通法律法规等各类规章制度),各个十字路口就会拥堵不堪,交通事故也会频发不断,最后大家都很难顺利的到达目的地(难于顺利的完成开发任务)。

一套完善的多人协作开发规范,就如同城市的交通线路上拥有一套完善的交通规则一样重要。虽然规则限制了部分车辆的高速飞驰, 却能保障大部分车辆可以顺利到达目的地。

制定多人协作开发规范 ,是为了提高团队的整体开发效率。

影响开发效率的因素有很多,比如:

  1. 开发文档:需求分析、原型图、设计稿等开发文档的欠缺或者粗糙,会导致产品、设计和开发人员对需求的理解不一致,容易造成返工;
  2. 项目开发模式:需要根据项目的特点和类型采用合适的开发模式,瀑布开发模式、增量开发模式、敏捷开发模式等;
  3. 技术框架/架构:模块化、组件化,还是原始jQuery的DOM操作模式;
  4. 代码规范:统一的代码规范,能提高代码的可理解性、可维护性,便于团队间相互code review等;
  5. 开发流程规范:分支如何管理、如何制定git提交规范等;
  6. 其他因素:IDE、脚手架、UI框架、代码版本管理系统(svn\git) 等,好的开发工具,能带来事半功倍的效果。

不管是单人开发还是多人协作开发,要提高开发效率,以下都是必要条件:

  1. 齐全、完善的开发文档;
  2. 一个合适的项目开发模式;
  3. 一个优秀的技术架构;
  4. 一套功能完备的开发工具;

而一套完善的代码规范和开发流程规范却是影响多人协作开发效率的关键因素。
对比多人协作和单人协作的差别:
image

单人开发的效率通常比多人协作开发要高,但开发周期往往比较长。要想让产品快速的占领市场,就得开启多人协作开发模式,尽可能的缩短开发周期。而怎么让“1 + 1 尽可能等于 2”,保证有效的人力资源投入,则需要思考如何制定一套完善的多人协作开发规范了。

如何规范多人协作开发?

协作开发过程中容易遇到的问题
image

笔者结合个人项目开发和团队协作开发经验,要避免以上协作开发类问题,提高多人协作开发效率,可从以下五个方面逐步制定一套合适的多人协作开发规范:
image

下面我们依次从这五个方面,详细介绍如何构建一套多人协作开发规范。

一、任务管理

在任务管理中,主要考虑如何将需求转化成清晰有序的开发任务,并对开发任务进行有效的管理。

任务管理的主要目标:
1、对需求进行分解,将大任务分解成小任务,让多人并行开发,并尽可能避免代码重复和冲突;
2、创建任务/issues,列举任务详细,用于后续验证和跟踪对应的功能代码;
3、对任务进行分类,用于区分新功能开发、BUG修复等任务类型;
4、排优先级,明确各阶段任务,保证重要紧急的任务优先开发;
5、划分团队成员职责,制定的任务分配&领取机制,形成任务看板,关注项目开发进度。

任务管理的关键路径:
① 任务分解 —> ② 建任务/issues —> ③ 任务标签管理 —> ④ 排优先级 —> ⑤ 分配&领取 —> ⑥ 任务看板

1.1、任务分解
任务管理是协作开发中最重要的环节,任务分解又是任务管理中最重要的一步。任务分解的好坏,直接影响到多人协作开发能否有效的进行。
通常我们可以按业务、按阶段、按功能模块、按页面对项目进行拆分。
例如一个电商项目, 按业务拆分,我们可以拆分出商城、超市、生鲜、直播电商、拼团、社交电商等较大的业务模块:
image

按阶段分,即按主次功能分阶段开发,可以先后拆解出购买流程、会员模块、导购模块、营销模块等:
image

按功能模块分,可以拆分出导购模块、购物车模块、结算模块、订单模块、会员模块、营销模块等:
image

按页面分,比如会员模块,可以拆解出会员页、积分页、预存款页、礼金券页、地址列表页、地址管理页等:
image

1.2、建任务/issues
完成任务分解后,需求转化成颗粒度较小的任务清单,我们可以借助gitlab或github自带的issues面板创建Issue来管理这些开发任务。创建任务时,列举任务明细,以task list形式展示当前任务需要完成的功能点。如此,我们便能得到一份清晰的开发任务清单,后续code review时也可以根据Issue的task list快速了解代码功能明细。
github中issue示例:
image

1.3、任务标签管理
有了开发任务清单之后,我们还需要将任务进行分类,用于区分新功能开发、bug修复和功能完善等任务类型。
通常可以设置如下任务标签:
feat:用于标记为功能开发类任务;
bug:用于标记为错误修复类任务;
fix:用于标记为历史功能完善类任务;
refactor:用于标记为历史功能重构类任务;
style:用于标记为样式重构类任务。

1.4、排优先级
设置任务标签后,我们还需要确定任务的优先级,输出一份功能点明确且带优先级的任务清单。
可参照 重要&紧急 > 紧急不重要 > 重要不紧急 > 不重要&不紧急 设置任务优先级:
image

1.5、分配&领取
任务分解是一个比较耗时的工作,项目负责人可以采用任务分配+领取并行的方式,快速进行任务分解: 项目负责人仅分解颗粒度较大的任务模块,然后分配给各开发成员,由开发成员再细分任务模块,建颗粒度更小的issue,开发前项目负责人过审一遍,确保issue的合理性。不管是分配模式还是领取模式,尽可能提前划分好各开发成员的职责范围。

1.6、任务看板
建立任务看板,以便随时了解当前进行的任务情况,也可以根据待完成和已完成的任务数量,预估当前项目的开发进度。
gitlab自带Issues Board功能:
image

维护任务看板:
1、开发时将对应任务设置为“开发中”状态;
2、任务完成开发且合并到主分支后,将任务设置成“完成”状态。

二、分支管理

在分支管理中,主要考虑如何充分利用Git(分布式版本控制系统) ,保证各开发成员在同一个项目代码中有序的进行开发工作。
分支管理的主要目标:
1、给各分支赋予固定的职责,明确分支职责;
2、主分支设置权限,避免主分支代码污染;
3、在功能分支进行开发,并避免多人同时在同一功能分支上,形成有序的开发分支线路;
4、功能分支需和对应任务建立关联,以便Code Review;
5、保障开发/测试/上线 可同步进行。

分支管理关键路径:
① 引进/借鉴 Git flow —> ② 建立分支 —> ③ 设置分支权限 —> ④ 分支维护

2.1、引进/借鉴 Git flow
Git flow 是最早诞生、并得到广泛采用的一种工作流程,它最主要的特点有两个:
1、存在两个长期分支,主分支master和开发分支develop,前者用于存放对外发布的版本,任何时候在这个分支拿到的都是稳定的发布版;后者用于日常开发,存放最新的开发版。
2、项目存在三种短期分支,功能分支(feature branch)、补丁分支(hotfix branch)和预发分支(release branch),一旦完成开发,它们就会被合并进develop或master,然后被删除。

Git flow工作流程图:
image

通过引进Git flow 工作流程,给各分支赋予固定的职责,创建独立的功能开发分支,实现多人并行开发模式。

2.2、参考Git flow 工作流 建立分支

  • master 主分支:用于存放对外发布的版本,任何时候在这个分支拿到的,都是稳定的发布版;
  • dev 开发分支:用于合并开发完成的功能分支,存放最新的开发版代码;
  • feat 功能分支(feature branch):用于完成某个开发任务的分支,以feat#开头命名,建立和Issue关联的功能分支,比如* 创建用于完成任务3(issues#3)的功能分支,则命名为 feat#3;
  • release 预发分支(release branch):发布正式版本之前(即合并到master分支之前),需要有一个预发布的版本进行测试。预发布分支一般从develop分支上面分出来,预发布结束以后,必须合并进develop和master分支;
  • bug 补丁分支(hotfix branch):测试阶段,用于修复某个bug的分支,可以合进master、develop和release分支,比如建立用于修复bug133(bugs#133)的补丁分支,则命名为 bug#133;

2.3、设置分支权限
保护主要分支(主分支、开发分支),只允许项目主要负责人可以merge和push。确保项目开发人员提交的代码经过项目负责人Code Review后才能合并至主分支。

2.4、分支维护
临时性的功能分支需要及时删除,避免线上过多功能分支和补丁分支。
删除临时分支两个较好的时机:
1、功能分支请求合并至开发分支时,开发者选择合并后自动删除;
2、功能分支合并至开发分支后,由项目负责人验证通过后手动进行删除(同时会关闭对应的issue)。

三、代码规范

在代码规范中,主要考虑如何产出代码规范一致的高质量(可理解性、可维护性)项目代码。
代码规范的主要目标:建立统一的代码规范,提高代码的可理解性、可维护性。

3.1、制定代码规范
以前端项目为例,可以指定HTML、CSS&SCSS、JavaScript的代码规范,以及对各类文件命名进行约束:
image

比如对JavaScript的使用进行约束
1.缩进
使用soft tab(4个空格);
2.空行
变量声明后增加空行(当变量声明在代码块的最后一行时,则无需空行);
注释前增加空行(当注释在代码块的第一行时,则无需空行);
代码块后增加空行(在函数调用、数组、对象中则无需空行);
文件最后保留一个空行 ;
3.等等。

对目录和各类文件的命名规则进行规范:
1.目录命名
全部采用小写方式, 以下划线分隔。例:my_project_name;
有复数结构时,要采用复数命名法。例:scripts, styles, images, data_models
2.JS文件命名
参照目录命名规则。例:account_model.js
3.等等。

更多代码约束可参考airbnb style。

我们也可以直接使用市面上最流行的代码规范:airbnb style 或者 javascript standard style,不用可以从0到1的制定一套团队自己的代码规范,直接使用市面上现成的代码规范,还可以使用其配套的代码规范检查工具。

3.2、检查代码规范
指定代码规范后,可使用ESLint检验代码是否符合规范。
ESLint是一个可组装的JavaScript和JSX检查工具,在开发时,可以用于实时检查当前代码规范。
image

ESLint的使用方法
1、使用 npm 安装 ESLint:

# 先决条件:Node.js (>=6.14), npm version 3+
$ npm install eslint --save-dev

2、生成eslint配置文件:

$ ./node_modules/.bin/eslint --init

3、在任何文件或目录上运行ESLint:

$ ./node_modules/.bin/eslint yourfile.js

在ESLint中使用第三方的规则配置
ESLint的配置文件使用eslint-config-开头命名,比如airbnb style规范的eslint规则配置文件:eslint-config-airbnb-base。
使用时可省略eslint-config-,比如配置使用airbnb style规范:

// .eslintrc.js
module.exports = {
  root: true,
  parser: 'babel-eslint',
  env: {
    browser: true,
  },
  extends: 'airbnb-base',
  plugins: [
    'html'
  ],
  'rules': {
   // 存放自定义规则
  }
}

使用javascript standard的规范(eslint-config-standard)

// .eslintrc.js
module.exports = {
  root: true,
  parser: 'babel-eslint',
  env: {
    browser: true,
  },
  extends: 'standard',
  plugins: [
    'html'
  ],
  'rules': {
    // 存放自定义规则
  }
}

我们也可以配置使用自定义的代码规范(eslint-config-xxx)。

使用StyleLint检查css代码规范
ESLint主要用于检测js类型的代码规范,检测css代码规范可使用StyleLint, StyleLint的使用方法与ESLint类似,此处不做过多讲解,如有需要请自行查看官方使用说明文档(StyleLint)。

3.3、自动修正代码规范
可使用Prettier自动修正代码的基本格式。
Prettier的中文意思是“漂亮的、机灵的”,是当前比较流行的代码格式化工具,它能够解析代码,也可以使用你自己设定的规则来重新打印出格式规范的代码。使用说明文档请自行翻阅官方文档(Prettier)

四、Git提交规范

在Git提交规范中,主要考虑如何提供可读性更好的代码提交记录。
Git提交规范的目标:
1、提供可读性更好的代码提交记录,浏览项目历史记录时更容易理解;
2、可以过滤某些commit(比如文档改动),便于快速查找信息;
3、可以使用commit message来生成Change log。

4.1、Git提交规范
目前使用最广的Git提交规范是 AngularJS Git Commit Message 规范,其Git提交规范比较合理和系统化,并且有齐全的配套工具,我们可以参考或者直接拿来使用。

AngularJS Git Commit Message 规范:
Commit message 由Header、Body 和 Footer三个部分组成,其格式如下,

<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>

type 用于说明commit的类型,只允许使用下面9个标示:
build:影响构建系统或外部依赖项的更改(示例范围:gulp,broccoli,npm)
ci:对 CI 配置文件和脚本的更改(示例范围:Travis,Circle,BrowserStack,SauceLabs)
docs:文档只会更改
feat:一项新功能
fix:错误修复
perf:改进性能的代码更改
refactor:代码更改既不修复错误也不添加功能
style:不影响代码含义的更改(空格,格式,缺少分号等)
test:添加缺失测试或更正现有测试
scope 用于说明当前功能点作用于哪个页面或者哪个功能模块
subject 用于简短的描述当前commit,不超过50个字符
body 用于填写对本次 commit 的详细描述,可以分成多行
footer 不兼容变动声明,或者关闭 Issue

其中type、scope和subject是必填内容,而body和footer是非必填内容。前面我们在任务管理中创建了描述清晰的Issue列表,在分支管理中创建了和Issue关联的功能分支,所以我们可以将body和footer的内容放进对应的Issue描述中。

比如完成某项功能编码后,进行Git提交时,录入:

git commit -m “feat(某页):完成xx功能开发"

4.2、使用交互式Git提交工具
我们可以通过commit规范辅助工具(比如:Commitizen)进行交互式的Git Commit,让工具帮我们生成符合Git提交规范的提交记录。
Commitizen是一个编写合格的(符合AngularJS Git Commit Message 规范)Commit message 工具,使用方法简单,如有需要请自行查看官方使用说明文档(Commitizen)。

4.3、检查Git提交规范
有了Git提交规范之后,我们还需要有一个能检测git commit message是否符合当前Git提交规范的工具。
目前用于检查Git提交规范的工具有很多, 以commitlint + husky简单对其使用方法简单说明:
1、安装commitlint,并生成commitlint配置文件:

npm install --save-dev @commitlint/config-angular @commitlint/cli
echo "module.exports = {extends: ['@commitlint/config-angular']};" > commitlint.config.js

2、安装husky,在package.json中进行如下配置:

// package.json
{
 "husky": {
   "hooks": {
     "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
   }
 }
}

husky继承了Git下所有的钩子,在触发钩子的时候,husky可以阻止不合规范的commit。

五、开发流程规范

在开发流程规范中,主要考虑如何建立清晰、有序、无阻塞的开发流程。

开发流程规范的目标:
1、建立清晰、有序、无阻塞的开发流程;
2、开发流程零阻塞;
3、开发/测试/上线可持续进行。

5.1、开发工作流程
开发工作,从领取一个开发任务(Issue)开始,到完成功能开发且合并至开发分支为止。
开发工作流程图: image

当前开发工作流程说明:
① 领取任务后,从最新的开发分支上创建对应的功能分支(feat#xx);
② 完成功能开发后,上传本地开发代码前先进行同步操作;
③ 同步代码时,由开发人员自己在本地解决代码冲突;
④ 线上发起代码合并请求(Merge Requests),由项目负责人或者某业务模块负责人 Code Reivew;
⑤ Code Review:依照任务的功能点清单检查代码功能是否齐全,同时也可以将当前请求合并的功能分支代码拉取到本地进行预览和验证;
⑥ 合并分支:确保功能分支代码没有明显问题后即可通过合并请求;
⑦ 开发人员在完成功能开发并发起合并请求后,可立即领取新任务(下一个issue),创建新的功能分支,无需等待Code Review。

5.2、相关Git命令的使用说明
1、创建功能分支时,需要跟对应的Issue建立关联。
领取任务后,创建对应的功能分支时,功能分支的序号和任务的issue序号保持一致,比如:领取任务133(issues#133),则创建功能分支 feat#133:

git checkout dev # 进入开发分支
git checkout -b feat#133 #从开发分支创建新的功能分支

2、完成功能开发后,按照Git提交规范格式提交代码:

# 将当前工作区代码所有改动提交到git暂存区
git add -A
# 提交git暂存区的最新代码
git commit -m “feat(xxx页面): 完成xxx功能开发”

3、上传本地代码前,先进行代码同步操作(将线上最新开发分支的代码同步到当前功能分支上):

# Git fetch 将数据拉取到本地仓库 - 不会自动合度并问或修改当前的工作
git fetch

# 同步远端的开发分支代码
git rebase origin/dev

# 如果远端开发分支有更新,使用git rebase 进行代码同步
git push origin feat#133

5、同步代码时,发生代码冲突时,在本地解决冲突后进行git操作命令:

git rebase origin/dev
# 使用git rebase 同步代码时,如果远程dev分支有更新,且和本地代码有冲突,git 会提示相关代码冲突

# 解决代码冲突# 解决代码冲突后提交最新变动代码
git add -A
git commit -m “refactor(xx功能): 解决代码冲突”

# 继续 git rebase
Git rebase —-continue

# 最后上传本地代码
git push origin feat#133

# 如果此前push过feat#133分支的代码,则需要强制push(因为此时的feat#分支结构已变动,需要强制覆盖远端的feat#133 参见这里)
git push origin feat#133 —-force
# —force 可以简写成 -f

使用Git Rebase的目的:
上传本地代码前使用git rebase 同步代码,可保证每个功能分支的代码都是基于当前最新的dev分支开发的。

5.3、测试和上线工作流程
当各个功能开发完成,并依次合进dev分支后,就可以进行测试相关工作了。
测试的目的,是尽可能在项目(或者某功能模块)上线前发现潜在的问题,以便及时修复。

测试工作流程图:
image

各个功能开发完成后,依次合进dev分支,当现阶段所有bug修复完成并验证通过后,就可以进行上线操作了。

上线工作流程图:
image

在开发工作流程中,功能开发主要在独立的功能分支(feat#xx)上进行编码,完成后合并到dev分支。
在测试工作流程中,会额外创建预发分支(release-x)用于进行测试工作,bug的修复工作也是在独立的bug分支(bug#xx)上进行修复,完成修复工作后合并到预发分支(release-x)上。
最后在上线工作流程中,将测试完成的预发分支(release-x)合并至主分支(master),就可以对主分支的最新代码进行上线部署操作了。

开发、测试、上线工作流程总览:
image 如图所示,开发、测试、上线可以有序的并行工作,可在同一时间段完成不同阶段的需求任务。

如何推行多人协作开发规范

对开发人员的限制多:
1、需要按照统一的代码规范编写代码;
2、只能在功能分支和bug分支进行编码工作;
3、提交代码前需要先同步代码,并处理代码冲突;
4、需要按照规定的格式进行git commit;
5、代码需要经过Code Review才能合并到dev分支。
限制太多容易让开发人员产生抵触情绪,前期推行多人协作规范会比较艰难。可以适当放宽限制,逐步推行。

项目负责人的挑战
1、如何将复杂的大型需求任务分解成简单的小任务是一个有挑战的技术活;
2、如何快速Code Review,避免开发流程阻塞。
通过创建描述详细的Issue和可读性良好的Git提交记录来提高Code Review的效率,同时也可以新增业务模块负责人分担任务分解和Code Review相关工作。

任务管理中我们除了使用gitlab/github自带的Issues Board外,也可以考虑使用专业的任务管理工具来提高任务管理的质量和效率,比如:Tower、jira等。

按需调整,制定灵活的协作规范
世界上没有十全十美、适用任何场景的万能方案,协作开发规范也需要根据项目实际情况和开发人员数量进行适当的调整。
比如部门内的创新类项目,因为没有专业测试人员介入,可以采取开发人员交叉测试的方式。在分支管理中,也可以不用额外创建预发分支,自测发现的bug,可以按功能分支的开发方式进行修复,修复完成后直接合并至开发分支。

让 “ 1 + 1 大于 2 ”
本文提供的多人协作开发规范方法,主要考虑的是如何让多人协作开发效率 “1 + 1 尽可能的等于 2”,而如何让“ 1 + 1 大于 2 ”,则需要我们深入思考更多方面的因素,比如沉淀可复用UI组件、功能模块、优质的项目模板。只有在项目实战中不断的积累,才能持续性输出可复用的UI组件、功能模块、优质的项目模板等,如此才能不断的提高开发效率,实现“ 1 + 1 大于 2 ”!

参考清单

相关开源项目

AKFun 是一个基于 Webpack4.0 和 rollup 的前端多场景打包工具,支持多种技术栈:Vue技术栈、React技术栈、React&TS技术栈。可使用akfun体验文章中提到的eslint、stylelint、prettier和commitlint等相关工具的能力。
Github地址:AKFun