这是我参与「第三届青训营 -后端场」笔记创作活动的第6篇笔记。
《从需求到上线全流程》课程由王晨老师讲授,根据王老师讲解的课程内容,我总结梳理出了如下笔记内容。
见微知著——课程重点一览
步步为营——知识点详细剖析
为什么要有流程
先从网上流传的一个梗讲起:有个老板想做一个百度一样的网站,什么都想好了,就差一个程序员了。
对于有过开发经验的人来说,大家都知道一个简单的小程序确实是从想法到实现只需一个程序员。但是随着团队规模和问题复杂度的上升,一个人搞定一切就不可能了。
那么为什么需要有流程这样一个概念呢?
对于个人开发者来说,是并不需要流程的,整个软件的开发进度由他一个人来掌控即可,也就不存在流程这样一个概念。
当超过一个人而形成团队时,整个团队需要进行协作来完成共同的目标,为了能够让团队成员齐头并进,那么就有必要制定一系列的规则来进行约束,这些规则说明了每个团队中各个成员在每个时期需要完成的任务,这些规则也就是所谓的“流程”。
随着团队规模的上升,全新的问题也会随之出现,一套完善的流程也就显得更为重要。
团队规模和流程的关系
当形成团队时就需要有流程来加以约束,随着团队规模的上升,流程也就需要更加的完善。对于复杂的项目和规模庞大的团队来说,如果没有流程的约束,那么整个系统开发的全过程将会“惨不忍睹”:
- 需求阶段:每个人都有自己的想法,甚至有些还是馊主意,没有流程的约束,团队将无法进行决策。
- 开发阶段:项目庞大需要多人多端协作,每个人都有各自的计划与安排,没有流程的约束,团队人员将无法进行合作
- 测试阶段:产物怎样交付、测试如何展开、Bug怎么修复,如果没有流程的约束,这些工作将无法有序开展
- 发布阶段:怎样确保发布过程平稳丝滑,版本流量如何控制,如果没有流程的约束,整个系统管理将变得十分混乱
- 运维阶段:线上问题如何应急响应,如何处理用户反馈,如何解决线上问题,如果没有流程的约束,运维工作也将无法开展
传统的瀑布模型
为了保障团队能够有序地完成任务,软件开发界早已形成了许多“流程”规范。首先介绍一下最为传统的瀑布模型。
瀑布模型是最传统,也是最直观的流程模型。它是对工作流程的最直观表达,定义了标准的研发阶段,并把整个软件开发按照各个阶段排成一条线,只有当前一个阶段完成之后才会进入到下一个阶段。瀑布模型以流程为本,以文档进行驱动,是一个理想化的模型。
瀑布模型在一些非常重视流程的公司中大规模地使用,但其缺点也十分明显:流程上低效,工作上不灵活。
敏捷开发
在追求高效的现代生活中,瀑布模型的缺点实在是太明显了。因此,大多数互联网公司开始逐渐将流程倾向于敏捷化。这里的敏捷所指的更多是一种思想,最早可以追溯到2001年的敏捷宣言。敏捷宣言的内容如下:
“我们一直在实践中探寻更好的软件开发方法,身体力行的同时也帮助他人。由此我们建立了如下价值观:
- 个体和互动高于流程和工具
- 工作的软件高于详尽的文档
- 客户合作高于合同谈判
- 相应变化高于遵循计划
也就是说,尽管右项有其价值,我们更重视左项的价值”。
所谓的敏捷开发简单来说就是以更小的团队进行更快速的迭代开发。因为团队的规模小,因此团队成员可以围绕一个具体的目标开展工作,团队内部的合作也更加紧密。敏捷开发所强调的更多是以人为本,小规模的团队也更加便于与用户进行直接沟通。它是一种更加现代的流程模型。
SAFe简介
SAFe是The Scaled Agile Framework的缩写,它是一套管理框架。这套框架是为企业中实施敏捷开发提供的一套方法论。如果说敏捷开发是一个团队内部的协作方式,那么SAFe就是在企业中,多个敏捷团队之间的配合的一个指导。这套框架所关注的更多的是精益的产品开发、敏捷的软件开发以及系统思考等等。
如果将现代的敏捷开发Scrum比作一个特种部队的话,与之相关的一些概念往往可以进行如下的对比:
- 敏捷教练Scrum Master:好比一个小分队的队长
- 产品负责人Product Owner:好比负责联络指挥部和发布任务的人
- 敏捷团队Scrum Team:整个特种部队
- 敏捷发布火车Aglie Realease Train:更加敏捷的开发流程
我们团队的流程
在字节内部有着如下的一个开发流程:
每轮迭代会持续两周的时间,团队划分成两个scrum,因此站会由两个scrum交替进行。
从时间表上可以看到许多专有名词和会议名称,下面进行一波解释:
-
人员&名词解释:
- RD:研发
- PM:产品经理
- PRD:需求文档
- UED:用户体验设计
- QA:测试
- Scrum1:敏捷团队1
- P0 / P1:优先级0 / 优先级1
- Backlog:规划列表
-
会议解释:
-
待办事项整理会议(Backlog Grooming Meeting):产品负责人描述下个迭代希望实现的用户故事,PM提出需求列表
-
迭代计划会议(Sprint Planning Meeting):选择迭代的任务和估算工作量
-
每日站会(Standup Meeting):
- 昨天你做了什么
- 你今天将要做什么
- 你有需要帮助的地方吗
-
评审会(Review Meeting):小组向产品负责人展示迭代工作结果
-
反思会(Retrospective Meeting):在每个迭代后召开简短的反思会,总结哪些事情做得好,哪些事情做得不好
-
有哪些流程
下面我们可以来具体地看一下整个软件开发的过程中的流程,我们将正式地按照需求、开发、测试、发布和运维这几个阶段来展开介绍。
需求阶段
首先是需求阶段,它是整个软件开发工作的起点。
在需求阶段所要做的事情就是去明确需求,不要浪费时间讨论不应该存在的问题上。对于不该存在的需求,就应该尽早砍掉,避免浪费时间去进行无意义的讨论。然而,砍需求并不是一件容易的事,需要我们站在用户的角度去评估需求,进而再决定是否要砍掉需求。
对需求进行评估可以采用一种MVP(Minimum Viable Product,最小化可行产品)的思想开展。这种思想要求我们站在用户的角度去思考,并且积极地收集用户的反馈,进行快速迭代。
另一种需求评估的方法被称为四象限法,该方法将需求划分为:“重要但不紧急”、“重要且紧急”、“不重要不紧急”和“紧急但不重要”四个类别。
在任务繁多的情况下,可以按照这个坐标把任务按照重要性和紧急程度进行分类。对于既重要又紧急的任务就应该先做,对于不重要不紧急的任务可以最后做。对于重要但不紧急的任务要优先于紧急但不重要的任务,因为重要但不紧急的任务最终会变为既重要又紧急的任务。
四象限法的理论原则是先判断事情的重要性,再去判断事情的紧急程度。
对于一个高效的工作场景应该是大多数时间在处理重要但不紧急的事情,如果每天都在处理既重要又紧急的任务时,这样的工作场景是不健康的。
开发阶段
当需求确定下来之后,下一步就是进入开发阶段了。开发阶段不仅仅只有写代码那么简单,除了实现需求,还有很多方面需要考虑。
云原生下的开发
目前大家正处于一个时代的变革中,云原生的发展深刻地改变着后端开发的工作。
在云原生下的开发中,与传统开发的一个最大的区别在于部署的形式有所不同。
对于传统的虚拟机上的服务开发来说,它是在物理机或是更底层上虚拟出来多个虚拟主机,然后在每个虚拟主机中安装软件和依赖。这样就需要有专门的运维人员去负责维护和交付虚拟机,并且保证每个虚拟机中都要安装相应的依赖环境。
而开发云原生的后端程序更多地是在使用容器。容器是从操作系统中虚拟出来的,所有的容器都共享主机的系统。通过cgroup,namespace和union mount实现容器之间的隔离,因此在部署的时候,应用和依赖的系统是整体打包成一个镜像的。这样,后端开发将不再依赖运维人员创建程序的运行时环境。
此外,云原生也让开发环境逐渐云化,借助容器技术,新入职的员工可以借助云原生的IDE直接上手开发,不必再纠结本地环境的繁琐配置问题。
团队的分支策略
下面介绍一下影响开发的最大因素,即团队的分支策略。不同的分支策略往往影响着团队的开发流程,为了能够让团队成员能够更好地进行协作开发,需要定义出一些分支策略:
- 多个团队成员之间各自用什么分支来进行开发?
- 修改之间有冲突如何解决?
- 出了问题的代码如何回退到之前的版本?
在实际的工作中,一个项目的分支会变得非常复杂。因此,在团队中一定要统一分支的规则。要确保团队中的每个人都清楚每个分支是做什么的,并且对于git的知识也要重点掌握。
代码规范,自测和文档
在开发阶段,代码规范,自测和文档也是十分重要的。一个经验丰富的开发和一个新人所写的代码,往往最大的差别不是功能的实现,而在于代码的风格和规范。这里可以给到一些常用原则:
- 养成良好的注释习惯
- 拒绝魔法数字和魔法字符串
- 重复逻辑可抽象成公共方法,不要copy代码
- 正确使用IDE重构功能,防止修改错误
此外,开发阶段还要进行自测和文档编写,在开发过程中,随时进行一些静态代码扫描,也能显著提高代码质量。
遵守开发的规范就像大家随手捡起手边的垃圾,是一个对团队有益的好习惯。
测试阶段
开发阶段占据日常工作的比例大概只有30%,其余的大量时间其实是在进行测试。
测试应该伴随着开发的整个过程,每写一段代码都要想办法测试这段代码。一个常见的误区是:测试用于保证代码质量。然而,代码的质量通过测试是测不出来的,而且BUG也不是因为没有进行测试才产生的。因此,对编写的代码进行测试是一个对自己代码负责的好习惯。
测试可以划分成一个传统的测试金字塔模型:越底层的测试粒度越细,就需要越多的数量去覆盖所有的场景,越顶层的测试越能用少量的case覆盖大多数场景。
在软件开发中,还有另外一个常识:越早发现的缺陷解决成本越低。由于85%的缺陷是在开发阶段引入的,而如果要在上线之后修复它们,花费的成本可能是一开始就解决它们的数百倍。因此,需要我们进行充分的单元测试,从而尽早地发现bug。
日常的开发应用可以简化为下图中模型:
由客户端发送请求到网关,网关再请求后端服务器。对于后端的服务可能会有不同的版本,因而在测试中会存在一个虚拟环境的概念。我们可以用特定的设备通过某些设置,让它请求到对应的后端服务器,从而达到测试对应的后端服务的目的。这样一个从客户端到服务端的一整套体系被称为一个环境。
在实际工作中,一般至少会需要三套环境:
- 功能环境:用于开发和测试新开发功能的环境。该环境需要能够模拟线上的环境以支持开发和测试。各个环境间要能够实现隔离,不会影响其他功能的开发和测试。
- 集成环境:用于将不同的功能合并在一起进行测试。在该环境下会将不同的人开发的功能合并在一起,互相之间产生的影响可能会导致缺陷。该环境下会将迭代发布的所有功能合并在一起测试,目的是为了确保发布的所有功能之间的影响不产生缺陷。
- 回归环境:用于验证新功能对老功能没有影响,一般会借助自动化测试脚本来辅助测试。
发布阶段
经过了开发阶段,我们按照规范完成了需求,并且按照测试的标准在不同环境进行了各种测试。现在我们终于到了最重要的发布阶段。
软件系统的整体崩溃可以类比于空难,空难的发生遵循着这样一个规律:80%的事故发生在起飞和降落阶段。软件系统也是一样,其严重的崩溃场景往往是一些严重的线上事故。
发布过程
在发布的过程当中,如果出现了问题需要我们能够快速地进行定位。此外,根据团队中的角色不同,还需要做一些常规的检查:
- 发布负责人:要负责通知各个相关工作人员,观察各个服务的发布状态
- 变更服务的相关RD:要按照规范检查日志,监控,响应线上的告警
- 值班同学:要关注用户的反馈
发布模式
除了发布过程需要我们知道以外,我们还需要了解一些常见的发布模式。
蛮力发布
蛮力发布是最简单粗暴的发布模式,它直接使用新版本去覆盖老版本。
- 其优点在于操作简单,成本低。
- 其缺点在于发布过程中服务会中断,出了问题会影响全部的用户。
- 该模式比较适用于测试环境的部署,在小公司或非核心业务服务中也比较常见。
金丝雀发布
金丝雀发布是一种探测性的发布方式。由于金丝雀对瓦斯极其敏感,因此很早以前,矿工开矿下矿前,会先放一只金丝雀进去探测是否有有毒气体,看金丝雀是否能够活下来,金丝雀发布由此而得名。
- 其优点在于操作上相对简单,并且能够用少量用户来验证新版本的功能。
- 其缺点在于发布过程中也会出现服务中断,无法探测随用户量增大才会暴露的问题。
- 该模式同样比较适用于测试环境的部署,在小公司或非核心业务服务中比较常见。
滚动发布
另一种发布模式被称为滚动发布。在该发布模式下,每个实例都是通过金丝雀发布的方式逐步放大流量的,对用户的影响较小,体验较为平滑。
- 其优点在于发布过程当中用户体验不会中断,并且可以充分验证服务的功能。
- 其缺点在于操作流程较为复杂,对发布系统有着比较高的要求。另外,该发布模式的发布速度较慢,而且在新老版本不兼容的情况下无法使用。
- 适用于发布系统能力较强、自动化程度较高,可以平滑切换流量、自动进行发布滚动的设备上。
蓝绿发布
第四种发布模式被称为“蓝绿发布”,该模式会将服务分成蓝绿两组,先把蓝组流量摘掉然后升级,只用绿组提供服务,之后切换全部流量,只用蓝组提供服务,然后升级绿组服务,最终两组服务全部升级。
- 其优点在于发布速度快,操作流程相对简单。
- 其缺点在于需要有一半的机器能够承担所有流量的能力,一旦出了问题会影响到全部的用户。
- 适用于服务器资源丰富,新老版本不兼容且需要一次性升级到新版的场景下。
红黑发布
与蓝绿发布类似的另一类发布模式被称为“红黑发布”,该模式会在发布时动态扩容出一组新的服务,而不需要常备两组服务。
- 其优点在于发布速度快,操作流程相对简单。
- 其缺点在于对机器数量仍然有要求,需要能够扩容出一倍,并且一旦出了问题会影响到全部的用户。
- 适用于服务器资源丰富,新老版本不兼容且需要一次性升级到新版的场景下。
发布模式远不止上面提到的这几种,针对不同的应用场景需要选择不同的发布模式来进行发布:
- 对于没有强大发布系统和服务器资源不足的公司,一般使用蛮力发布或者金丝雀发布。
- 对于有强大发布工具和服务器资源充足的公司,一般使用滚动发布和蓝绿发布。
而在实际的工作当中,最常使用的还是滚动发布,发布的负责人需要关注滚动的粒度和时间,以及具体的执行进度。尽管滚动发布操作上比较麻烦,但该发布方式对用户的体验最为平滑。此外,针对一些特殊场景,蓝绿发布有时也会在用户低峰期时采用。
运维阶段
那么,是否当我们的软件上线后就结束了呢?其实并没有,在服务上线之后,我们还需要保证服务在线上的稳定,所以需要运维阶段来保证。
在上面我们把发布比作飞机的起飞与降落,同样的运维阶段也可以类比为平飞阶段,在平飞阶段也是有事故发生的可能的。
在事故发生之后,我们需要尽快做出如下几个动作的响应:
- 止损:尽快去让服务功能恢复
- 周知:要让服务的上下游感知到出了问题
- 定位和修复:当上面两个动作完成之后,才是定位与修复阶段。这里在流程上不能颠倒。
流程怎样优化
下面我们需要讨论的一个问题就是如何对上述的流程进行优化,让我们的流程变得更好。
怎样让生活更美好
在之前我们讨论的流程中存在着很多繁琐的规范和操作,这些操作无疑会使我们的服务质量有所提升。而另一方面,这些又会导致我们的工作效率下降,因此如何平衡我们的软件质量和工作效率是一个值得思考的问题。
- 在重视质量的团队中,效率往往比较低
- 在重视效率的团队中,事故往往比较多
然而,我们的时代又变了。随着技术的发展,我们可以实现让质量和效率同时得到提高。我们可以把质量保障规范融入流程,将流程自动化。从需求到上线全流程自动化,我们就同时提高了质量和效率。
DevOps
那么如何实现需求到上线的全流程自动化呢?那就需要用到DevOps理念。
所谓的DevOps,就是由左侧的Dev和右侧的Ops组成:从需求开始,写代码,编译,测试,发布,部署,运维,监控形成了一个闭环。于是我们就可以进行持续集成(CI)和持续交付(CD)。
全流程自动化
在DevOps的基础之上,我们还可以进行进一步的优化,也就引出了一个效率竖井的概念。我们可以看到,从需求到交付的过程中,我们真正产生价值的开发、测试等动作占比是很低的,大量的时间可能是在等待和传递上。此外,人与人之间的沟通也是很慢的。因此,在这一方面还可以进行进一步的优化。
于是,我们可以更进一步地,将价值流作为全流程的指标,尽可能地将流程自动化,同时减少无价值的等待。
-
通过效能平台串联各个阶段:
- 需求发起研发流程的自动化
- 写代码,测试环境部署的自动化
- 自动化测试触发和报告分析
- 发布过程可观测融入流程
-
减少无价值的等待:
- 分析整个流程的耗时,计算真正产生价值的时间
- 不断优化流程,让有价值的流程时间占比上升
后端开发的一周
最后,我们用第一视角来感受一下后端开发的一周是如何度过的。
周一
一般大家在周一会处理上一周遗留的事项。这一天的主要内容主要在PM和UED那里,因为他们要准备第二天要讨论的需求列表。
周二
项目的迭代一般在周二开始,这一天最重要的事情就是需求规划会议(Grooming 会议)。这个会议上会打开需求管理平台的页面,由PO和PM阐述各个需求的价值,Scrum Master和架构师会确认需求中包含的技术任务。最终,会议会定下需求任务列表,并做好任务的分配。
周三
周三主要是为了第二天的发布做一些测试和修复缺陷之类的准备。对于之前开发的需求要提交敏捷发布火车的车票准备上车,对其他人的代码进行一下Code Review。测试人员还有可能在回归测试的时候发现一些需要你来修复的缺陷。
周四
周四一般会有一次日常的发布。如果发布的过程中监控出现了异常,需要马上终止发布进行止损,然后再定位问题。如果发现是自己的代码有问题,就需要回滚代码或进行修复。
周五
周五一般是要对下个迭代的需求进行评估,经过讨论(Planning 会议),按照优先级对需求按照开发和上线时间进行排期。
小试牛刀——课后实践
作业描述
- 敏捷宣言是什么?
- Grooming meeting 的作用是什么?
- 我们为什么需要进行集成测试?
- 遇到线上问题,我们要做的四个关键动作是什么?
- DevOps 包含了哪些流程?
实践成果
- 敏捷宣言是什么?
答:敏捷宣言如下:
“我们一直在实践中探寻更好的软件开发方法,身体力行的同时也帮助他人。由此我们建立了如下价值观:
个体和互动高于流程和工具;
工作的软件高于详尽的文档;
客户合作高于合同谈判;
相应变化高于遵循计划。
也就是说,尽管右项有其价值,我们更重视左项的价值”。
- Grooming meeting 的作用是什么?
答:Grooming meeting是需求规划会议,会上由产品负责人描述下一个迭代希望实现的用户故事,并由PM提出需求列表。
Grooming meeting的作用主要在于通过协商讨论各项需求的价值,从而明确下个迭代要做的具体需求条目,以及确认这些需求的分工情况。
- 我们为什么需要进行集成测试?
答:集成测试是将不同的功能合并在一起进行测试。
由于不同的人开发不同的功能,而不同的功能之间又互相产生着影响。当把这些功能合并在一起之后,就难免会产生缺陷。因此,需要及早地进行测试,将缺陷尽早地进行解决。
另外,将迭代发布的所有功能合并在一起进行测试也能够确保发布的所有功能中间的影响不产生缺陷。因此,需要进行集成测试来保证软件的质量。
- 遇到线上问题,我们要做的四个关键动作是什么?
答:线上问题发生时,我们要做的四个关键动作是:止损、周知、定位和修复。
止损:我们应该尽快去让服务恢复功能。
周知:当问题发生时,应该让服务的上下游能够感知到问题的存在。
定位:当止损和周知做完之后,下一步就是定位问题的产生位置及原因。
修复:最后,定位了问题,及时进行修复处理。
- DevOps 包含了哪些流程?
答:DevOps包含了:计划(plan)、编码(code)、编译(build)、测试(test)、发布(release)、部署(deploy)、运行(operate)和监控(monitor)八个阶段。
温故知新——总结与感悟
王晨老师的这门课是一门轻松愉快的一门课,老师用幽默的语言为我们讲述了从需求到上线的整个流程。
王老师从流程的意义讲起,介绍了流程的发展过程。之后,详细地介绍了每个流程需要做哪些工作,并且也描绘了每个流程的发展过程。之后,讲述了目前流程的一个自动化的趋势。最后,通过第一视角,带领我们了解了王老师一周的工作情况。
整门课程轻松愉快地度过,王老师的精彩分享也给我们留下了深刻的印象。