这是我参与「第三届青训营 -后端场」笔记创作活动的的第3篇笔记。
一、为什么要有流程
1.1 团队规模和流程的关系
为什么要有流程?
- 个人开发者是不需要流程的
- 超过一个人的团队就需要协作
- 随着团队规模上升,会出现全新的问题
复杂项目没有流程会有什么问题?
- 需求阶段:每个人都有自己的想法,团队决策需要有一个过程
- 开发阶段:多人、多端协作开发,每个人都有自己的安排,相互配合需要有一个流程
- 测试阶段:产物怎样交付,测试如何开展,BUG怎么样需要修都需要流程
- 发布阶段:怎样确保发布过程平稳丝滑,版本和流量如何控制,需要有规范
- 运维阶段:线上问题如何应急响应,处理用户反馈和线上问题需要有流程
1.2 传统的瀑布模型
按照我们最传统的也是最直觉的模型,把整个软件开发按照各个阶段拍成一条线,前一个阶段完成之后进行下一个阶段,这就是传统的瀑布模型。
优点:
- 工作流程直观表达
- 定义了标准的研发阶段
- 以流程为本,理想化模型
缺点:
- 流程非常的低效,到了一定时间就要做一定的事情,因此会有很多实践在等待前面的流程完成。
1.3 敏捷开发(Scrum)
- 以小团队快速迭代
- 团队成员之间的合作更加紧密
- 以人为本,和用户沟通
1.4 The Scaled Agile Framework(SAFe)简介
SAFe是一套管理框架,是为企业中实施敏捷开发提供一套方法论。如果说敏捷开发是一个团队内部的协作方式,那么SAFe就是在企业中,多个敏捷团队之间怎样配合。
- 精益产品开发
- 敏捷软件开发
- 系统思考
二、有哪些流程
2.1 需求阶段
不要浪费时间讨论不应该存在的问题。还要学会砍需求。
那么需求应该怎样评估?采用MVP思维方式。
MVP(minimun viable product,最小化可行产品)思想:
- 站在用户的角度思考
- 收集用户反馈,快速迭代
另外一个评估需求的方法,四象限法:
2.2 开发阶段
2.2.1 云原生的发展,深刻改变了后端开发的工作
云原生下的开发,一个最大的区别,就是部署的形式不同
传统的虚拟机
- 在物理主机中虚拟出多个虚拟机,每个虚拟机拥有自己的操作系统。
- 运维人员负责维护和交付虚拟机
- 每个虚拟机中都要安装相应的依赖环境
容器化
- 容器是在操作系统中虚拟出来的
- 通过cgroup,namespace和Union Mount等技术实现容器之间的相互隔离,同时容器只有很低的开销
- 应用和其依赖作为一个整体,打包成镜像交付
云原生带来的另一个改变就是微服务
单体架构
- 多个模块共同组成一个服务,服务体量较大
- 模块之间直接调用,不需要rpc通信
- 服务整体扩缩容量
- 多人开发一个代码仓库,需要充分集成测试
微服务架构
- 各个功能在不同的服务中
- 不同模块需要进行rpc通信
- 不同模块可以独立扩容
- 每个服务的代码仓库仅由少部分人维护
云原生让我们的开发环境逐渐云原生化
- 开发环境逐渐云原生化
- Faas、Paas等等技术,让开发逐渐从本地IDE向线上转变
- 从入职到电脑搭建完一套完整的开发环境需要很久,通过web ide等技术,环境未来将会开箱即用
2.2.2 团队的分支策略
我们日常工作中写代码都是基于主干的某个版本进行修改,修完之后再把代码合并回主干形成新的版本。这里就会有一些协作上的问题。
- 多个团队成员之间各用什么分支开发?
- 修改之间有冲突怎么办?
- 出了问题的代码如何回退到之前版本
为了应对这些问题:
- 有些团队会有一个专门的release分支,大家都把代码合并到release分支,然后测试,发布,之后再把release分支合并到master
- 有些团队会直接把开发的分支合并到master,然后再用某个master上的commit发布
只所以有各种各样的分支策略,就是我们在后续的测试和发布阶段要按照对应的分支和commit进行交付。
2.2.3 代码规范、自测和文档
代码规范
- 养成良好的的注释习惯,超过三个月的代码,自己都会忘了当时是在想什么
- 不要有魔法数字,魔法字符串。比如判断条件里判断某个变量等于2,2代表什么?可以用常量定义
- 重复的逻辑抽象成公共的方法,不要copy代码
- 正确使用IDE的重构功能,防止修改错误。不要手动去编辑或者全局替换
自测
- 单元测试
- 功能环境测试
- 测试数据构造
文档
- 大型改造需要有技术设计文档,方案评估
- 好的接口文档能更方便的和前端进行沟通
2.3 测试阶段
测试应该是伴随着开发的全部过程的,每写一段代码之后就要想办法测试这段代码。有的人可能以为测试负责保证代码的质量,但是这是一个很常见的误区。
左边这个图是传统的测试金字塔模型,他的意思是:越底层的测试粒度越细,就需要越多的数量去覆盖所有的场景,越顶层测试越能用少量的case覆盖大多数场景。
但是有一个软件开发的常识:越早发现的缺陷解决成本越低。因为85%的缺陷是在开发阶段引入的,如果上线之后修复他们,成本可能是一开始就解决他们的数百倍。所以我们还是要尽可能早的发现bug,进行充分的单元测试。
我们日常开发的应用,可以简化成图中的模型,由客户端发送请求到网关,网关请求到后端服务器
我们用特定的设备可以通过某些设置,让他请求到对应的后端服务器,从而达到测试对应的后端服务的目的。这样一个从客户端到服务端的一整套体系,称为一个环境。
在实际的工作中,我们一般需要三套环境:
功能环境:用于开发和测试新功能的
- 需要一个能模拟线上的环境进行开发和测试
- 环境和环境之间能够隔离,不影响其他功能的开发和测试
集成环境:是为了把不同的功能合并在一起测试
- 不同人开发的功能合并在一起测试,相互之间的影响可能产生缺陷
- 迭代发布的所有功能合并在一起测试,确保发布的所有功能之间的影响不产生缺陷
回归环境:是为了验证新的功能对老的功能有没有影响
- 确保新的功能不对老的功能产生影响
- 回归测试一般会借助于自动化测试脚本
具体要根据开发的应用采用的架构,这里只是一个最简化的模型。
2.4 发布阶段
2.4.1 发布过程中要做的事情
发布负责人
- 负责按照计划执行发布
- 需要通知各个相关人员发布进展
- 观察各个服务的发布状态,及时处理异常
变更服务的相关RD
- 按照上线checklist检查服务的日志,监控,响应上线过程中的告警
- 对于自己负责的改动,在小流量或者是预览环境进行功能验证
- 执行发布计划中的其他操作(如线上配置,数据处理等)
值班同学
- 发布过程中的监控和告警需要特别关注,如果有异常需要立即判断是否由变更引起
- 如果有变更引起的告警或者用户反馈,需要及时中止发布
2.4.2 发布模式 - 蛮力发布
简单粗暴,直接用新版本覆盖老版本。
优点:简单、成本低。
缺点:发布过程中服务会中断。出了问题会影响全部用户。
适用:测试环境部署,小公司或者非核心的业务服务。
2.4.3 发布模式 - 金丝雀发布
由于金丝雀对瓦斯极其敏感,因此以前矿工开矿下矿洞前,先放一只金丝雀进去探是否有有毒气体,看金丝雀能否活下来。金丝雀发布由此得名。
优点:相对简单,能够用少量用户验证新版本功能。
缺点:发布过程中服务会中断,发现不了随用户量增大才会暴漏的问题。
适用:测试环境部署。小公司或者非核心的业务服务。
2.4.4 发布模式 - 滚动发布
每个实例都通过金丝雀的方式逐步放大流量,对用户影响小,体验平滑。
优点:发布过程中用户体验不会断,可以充分验证服务功能。
缺点:流程较复杂,对发布系统有比较高的要求;发布速度较慢;新老版本不兼容的情况不能使用。
适用:发布系统能力较强,可以平滑切换流量;发布自动化程度高,可以自动滚动。
2.4.5 发布模式 - 蓝绿发布
把服务分成蓝绿两组,先把蓝组流量摘掉然后升级,只用绿组提供服务,之后切换全部流量,只用蓝组提供服务,然后升级绿组服务,最终两组全部升级。
优点:发布速度快,流程相对简单
缺点:需要有一半机器承担所有流量的能力;出问题会影响全部用户。
适用:服务器资源丰富;新老版本不能兼容的情况,需要一次性升级到新版
2.4.5 发布模式 - 红黑发布
和蓝绿发布类似,但是发布时会动态扩容出一组新的服务,而不需要常备两组服务。
优点:发布速度快;流程相对简单。
缺点:对机器数量仍有要求,需要能扩容一倍;出问题会影响全部用户。
适用:服务器资源丰富;新老版本不能兼容的情况,需要一次性升级到新版。
2.4.6 总结
其实发布的模式还不只这几种。实际工作中,我们的发布使用的是滚动发布,发布的负责人需要关注滚动的粒度和时间,以及具体执行的进度。因为这种方式对用户的体验最为平滑,同时公司也有强大的流量控制能力,能够平滑的切换流量能够支持滚动。
但是仍有一些场景需要使用蓝绿发布,可能有些公司发布需要在用户低峰期进行,所以在那些公司发布的时候,往往都是在夜深人静的时候。
- 没有强大发布系统和服务器资源不足的公司一般使用蛮力发布或者金丝雀发布。
- 有强大的发布工具和服务器资源丰富的公司一般使用滚动发布和蓝绿发布。
2.5 运维阶段
在服务器上线之后,我们还要保证服务在线上的稳定,所以要有运维阶段。
服务运行期间可能出现的问题:
- 用户量增加引起流量洪峰(12306抢票)
- 数据库表的数据量增长导致查询速度变慢
- 内存、进程泄露导致服务资源不足
- 光缆被挖断
三、总结与思考
经过本节课的学习,我了解到了软件开发从需求到上线的全流程。知道了完整的软件开发周期:
- 经过需求阶段我们讨论该作什么不该做什么
- 开发阶段我们按照规范去实现产品
- 测试阶段我们去验证产品,修改缺陷
- 发布阶段我们按照流程规范上线
- 运维阶段我们观察线上监控和日志
本次课程提高了我的专业素养。让我懂得了开发人员也要对自己的代码进行测试,从而保证代码的质量。