请先通过 这个PPT 来了解极狐GitLab 代码仓库的管理模式和开发流程。
我们的工作周期和我们的产品版本发布节奏保持一致:每年五月份发布一个大版本(major release),每个月月底发布一个小版本(minor release),这也是 GitLab EE 的版本发布节奏(详见此处)。我们使用里程碑(Milestone)功能来记录和规划每个版本的开发时间和工作范围。每个月底我们都会在 GitLab EE 的月度版本(每月22号)发布后的一周内发布对应的极狐GitLab 版本,这一周的时间主要用来打包、测试和排查可能的问题。
日期 | 内容 |
---|---|
每月第一个周一 | Planning 会议: 1. PM(Product Manager)简要介绍所有需要在下个 milestone 中进行开发的新功能。 2. EM(Engineering Manager)和团队成员共同确定这些新功能的开发负责人,确定的依据之一是每位成员提前做好的工作量规划,也就是说,在每个 milestone 的中期每位成员需要提前预估自己在下个 milestone 的工作量,然后我们根据每位成员预计的工作负荷来确定谁能够在下个 milestone 中负责哪些新功能的开发。 |
Planning 会议之后下个 milestone 开始之前 | 功能需求讨论会议: Planning 会议中确定的各开发负责人针对自己在下个 milestone 所负责的功能单独安排会议和 PM、EM、QA、TW(technical writer)详细讨论具体的需求。具体的技术调研等到下个 milestone 正式开始之后再进行,以避免对当前 milestone 已安排项目的进度造成影响。 |
每月第三个周一 | Retrospective 会议(上午): 总结团队在这个 milestone 中做得好的地方以及待改进的问题。 Feature review 会议(下午): 各开发负责人通过 live demo 的方式向各相关部门(如:CTO office、customer success 和 pre-sales)演示自己在这个 milestone 中所完成的功能。 |
29号之前 | 极狐GitLab 新版本发布 |
对于每个需要完成的新功能,我们通过如下流程来对其进行整体的项目管理:
~"backend"
和 ~"frontend"
标签)以便分别对前后端工作进行管理。~"documentation"
标签),dev 需要在此 issue 中提供文档编写的大致思路。在创建 issue 时,请选择合适的 template 来规范 issue 中的描述信息,切勿创建仅有一个标题的空 issue。同样,在关闭 issue 或把 issue 移动到下一个 milestone 时,请务必描述清楚关闭/移动的原因,切勿不提供任何理由而直接关闭/移动 issue。
~"severity::"
标签来确定它的严重等级,然后 @ PM 来进行后续处理。~"priority::"
标签来确定这个 issue 的优先级,EM 把 issue 分配给负责修复的 dev。
Related to #<issue-id>
把 MR 和 issue 关联起来,不要使用 Closes #<issue-id>
,否则在 MR 被合并后 issue 会被自动关闭。我们所有的开发工作都是基于 极狐GitLab 代码仓库 的主分支 main-jh
来进行的,所以,main-jh
pipeline 的成功率非常重要,如果 main-jh
pipeline 处于失败状态,那所有 MR 的合并都会受到影响。
某些情况下,我们可能需要提交 upstream MR 来修复 main-jh
pipeline,这样的 MR 应该在 upstream repo 优先得到 review 和 merge。所以,我们和 GitLab Inc. 团队一起制定了紧急修复 main-jh
pipeline 的流程,详见 此处。
快速迭代是我们所推崇的软件开发策略,为了实现这一策略,在实际的项目开发中我们需要做到如下两点:
关于第1点,下图进行了非常形象的演示,核心思想是:对于任意一个项目,我们都不希望花很长时间来完成它且在此之前没有任何功能点能够交付测试。与之相对应的是,我们希望从每个独立可以交付测试的小功能点做起,逐步分阶段地完成整个项目的所有功能。前者会导致在项目的后期突然有大量的功能上线,这对测试和运维都可能带来较大的压力,且可能会出现大量集中的 bug 需要在短时间内修复,而后者能够使我们在项目进行的过程中,逐步测试、交付相关的功能,及时收集用户反馈,并有足够的时间修复发现的 bug,从而实现项目的平稳落地。
关于第2点,在提交 MR 来解决 issue 的过程中,我们需要将单个 MR 的粒度控制得足够细,切勿创建一个包含很多文件改动或同时处理多个 issue 的 MR,这样的 MR 会需要花比较长的时间进行 code review,从而有可能延误整个项目的进度。一般来说,有两种不同的做法可以将一个项目的开发工作切分为多个 MR 来完成:
我们推荐垂直切分的做法,通过这种做法创建出来的 MR 包含了完成一个功能所需的所有代码改动,这有助于 reviewer 在进行 code review 时快速了解整个功能的全貌。
关于快速迭代工作方式的更一步信息,详见此处。
Label 是我们对开发工作(如:issue 和 merge request)进行分类的重要方式。我们参考 GitLab Inc. 研发团队的做法主要使用如下 scoped label 对开发工作进行分类,这些 label 的详细信息在这里可以查看到。
~"type::bug"
: 已发布或上线的产品中所出现的缺陷。这种类型的 issue 需在 QA 验证过后才可以关闭,而下面其它类型的 issue 在相关的 merge request (MR) 合并后即可关闭。对于加了这个 label 的 issue,我们不强制要求必须再加上下面子 label 中的一个。
~"bug::performance"
: 性能问题。~"bug::availability"
: 和 SaaS 可用性相关的问题。~"bug::vulnerability"
: 安全漏洞。~"bug::mobile"
: 移动端的问题。~"bug::transient"
:偶发性问题。~"type::feature"
: 对于用户可见的新功能或对现有功能的改进。对于加了这个 label 的 issue,请务必再加上下面子 label 中的一个。
~"feature::addition"
: 为用户提供的全新功能。~"feature::enhancement"
: 为了提升用户体验而对现有功能进行的改进。~"feature::consolidation"
: 为了简化用户体验,将两个功能进行合并。~"feature::removal"
: 删除一个不再需要的功能。~"type::maintenance"
: 非用户可见的产品改进,如:解决之前的技术债。对于加了这个 label 的 issue,请务必再加上下面子 label 中的一个。
~"maintenance::refactor"
: 简化或重构现有的代码或文档。~"maintenance::dependency"
: 更新 GitLab 所需的依赖,如:Ruby gems、NPM packages、GitLab Workhorse、GitLab Shell、Gitaly 等。~"maintenance::usability"
: 针对产品易用性的通用改进。~"maintenance::test-gap"
: 测试覆盖率的改进。~"maintenance::pipelines"
: Pipeline 配置相关的工作。~"maintenance::workflow"
: 开发流程相关的工作,如:Danger、RuboCop、linters、issue templates 等。另外,无论是开发新功能还是修复 bug,我们都使用如下 label 来标识相关 issue 当前所处的状态。
Label | 含义 | 如何设置 |
---|---|---|
~"workflow::in confirmation" |
QA 正在确认此 issue 是否为一个 bug 以及它的严重等级 | 当一个 bug 类型的 issue 被创建出来时,Triage Ops 会自动把这个 issue 分配给一位 QA 并设置这个 label |
~"workflow::in dev" |
Dev 正在对此 issue 进行技术调研/方案设计/代码开发 | Dev 在刚接手一个新 issue 时设置这个 label |
~"workflow::in review" |
解决此 issue 的 MR 正在进行 code review | Dev 在创建了相关 MR 后为该 issue 设置这个 label |
~"workflow::in qa" |
QA 正在对此 issue 进行测试验证 | 当相关 MR 被 merge 后,dev 把负责测试的 QA 添加为该 issue 的共同 assignee,此时 Triage Ops 会自动设置这个 label |
~"workflow::blocked" |
此 issue 的开发/测试工作由于某种原因无法按计划继续进行了 | 根据实际情况,dev 和 QA 都可以设置这个 label,比如:dev 发现这个 issue 依赖的某个 upstream MR 一直没有进展,QA 发现测试这个 issue 所需的特殊测试环境不具备 |
除了上述 scoped label 之外,我们还会配合使用一些 facet label 来描述 issue 的相关背景信息:
~"upstream tracker"
: 默认情况下,我们在 https://jihulab.com/gitlab-cn 中建的 issue 都是仅针对极狐GitLab 的(如:极狐版GitLab 的专属功能或 bug),而对于我们发现的 GitLab CE/EE 的 bug 或需要在 GitLab CE/EE 完成的功能,在创建相关 issue 时需要加上 ~"upstream tracker"
用于标识这个 issue 仅用于追踪 upstream 的工作,而具体的 upstream 工作则需要在 upstream repo 中创建相应的 issue 来解决。~"SaaS"
和 ~"self-managed"
: 对于仅针对 SaaS (jihulab.com) 的 issue 和 MR,需要加上 ~"SaaS"
,对于仅针对 self-managed 的 issue 和 MR,需要加上 ~"self-managed"
,如果同时针对 SaaS 和 self-managed,则不需要加这两个标签。~"GitLab Free"
、~"GitLab Premium"
和 ~"GitLab Ultimate"
: 功能所属的 GitLab 版本,分别对应免费版、专业版和旗舰版。~"priority::1"
、~"priority::2"
、~"priority::3"
和 ~"priority::4"
: Issue 的优先级。~"frontend"
和 ~"backend"
: 分别用于标识前后端的工作。~"tech debt"
: 技术债。~"documentation"
: 文档相关的工作。~"research"
: 技术方案调查类的工作。~"product"
: 来自于 PM 的需求。~"customer"
: 客户反馈的需求或问题。每次进行极狐GitLab 新版本发布时,PM 都会根据当前 milestone 中已关闭的 issue 并结合 GitLab EE 对应新版本的 release post 内容,来编写极狐GitLab 新版本 release post 的内容,并最终由 Marketing 部门在极狐官网对外发布(详见此处)。一般来说,加了 ~"type::feature"
或 ~"type::bug"
标签的 issue 会作为 release post 中的内容。当一个 issue 的所有工作都全部完成后,负责人需及时关闭该 issue。如果用于解决某个 issue 的 MR 并没有合并到当前 release 的 stable 分支中(即:在 stable 分支从主分支创建出来之后,MR 才合并到主分支。关于 stable 分支的创建方式请参见 此处),那显然这个 issue 就无法作为当前 release 版本发布的一部分了,所以在这种情况下,负责人需要把这个 issue 移到下个 milestone 中作为下个 release 的内容。
我们使用 milestone 来规划我们每个版本的开发时间节点和工作范围,每个 milestone 都固定为一个月的时间:从当月的 18 号至下月的 17 号。每个 milestone 开始之前,会进行 planning 会议,从需求池(Backlog Pool)中挑选高优先级的需求或任务进入这个 milestone 里进行规划,然后进一步通过 weight 值来评估复杂度,最后通过工时统计功能(time tracking)来完成 capacity planning。
Issue 的优先级通过如下 label 分为4级:
优先级标签 | 描述 |
---|---|
~"priority::1" |
最高优先级的需求或 bug,需要在当前 milestone 里优先进行开发 |
~"priority::2" |
当前 Milestone 中计划完成的需求或 Bug,如遇到 capacity 不足的情况会酌情修改完成时间 |
~"priority::3" |
如果当前 milestone 的 capacity 有余量,会安排这类需求或 bug |
~"priority::4" |
短期不会计划实施的 nice-to-have 需求或 bug 修复 |
weight | 描述 |
---|---|
1: 极少 | 问题已充分理解,不需要额外调研,有明确的解决方案,只需要执行,不需要与其他团队或人员协调。 举例:文档更新、简单的回归,以及明确的只需少量代码就能修复的bug,或者是确切知道如何解决,但还没有找到时间的技术债务。 |
2: 少量 | 问题已充分理解,已有解决方案的雏形,但实现上,还需很少量的调研,不太可能有预期之外的问题,不需要与其他团队或人员协调。 举例:一些简单的功能开发,比如一个新的API端点来暴露现有的数据或功能;修复一些已经调研过的常规错误或性能问题。 |
3: 中等 | 需求已充分理解,已有解决方案的雏形,但实现上,还需适量的调研,可能有预期之外的问题,可能需要与其他团队或人员协调。 如果是 Bug 类型,问题还没理解清晰,还没有解决方案,需要花很多时间调研,一旦调研清楚,修复的过程是很简单直接的。 举例:一些常规的需求,涉及前段和后端的组件改动,或者大部分的 bug 和性能问题。 |
4: 大量 | 需求已充分理解,但有很多困难,虽然有解决方案的雏形,但实现上,需要大量的调研,会有很多预期之外的问题,需要与其他团队或人员协调。 如果是 Bug 类型,问题还没理解清晰,还没有解决方案,需要花很多时间调研,即便调研清楚,修复的过程也会比较麻烦。 举例:一些改动较大的需求,或者一些已知的 Bug 和性能问题,但是遇到无法重新或者一直没有解决。 |
5: 未知 | weight 为5的需求,不会被列入 milestone 的计划中,需要先做分解。 |
我们使用 issue 的 time tracking 功能来进行工作量预估和工时追踪,使用内部的 Capacity Planning表格来记录每个 Milestone 中每位团队成员的全部可用 capacity 和已计划的 issue 工作量预估。
GitLab 创建项目时可以用项目模板功能,这些项目模板是在 gitlab.com
中维护,我们将其镜像到了 jihulab.com
中。由于仓库镜像功能不支持组同步,当前是每个模板项目手动创建并配置的同步,因此我们有一个流程来检测和处理 Upstream 的项目模板变动:
jh/.gitlab/ci/project-template-check.gitlab-ci.yml
。gitlab-cn/project-templates
组的维护人。