在讨论软件研发工程效率之前,需要明确工程效率的目标到底是什么。
一提到工程效率的目标,很多人的第一反应就是“要快”。
但,什么要快?是研发人员要更快地忙碌吗?如果价值因为不同部门之间传递时的等待,导致很晚才流动到用户手中,那么研发人员忙得再快,也是没有用的。
工程效率的目标
不管是工程效率的目标,还是敏捷、精益、DevOps的目标,如果放到软件开发的领域,那么目标都只有一个。
工程效率的目标,就是让用户能及时在生产环境,持续稳定地享受软件所提供的良好服务。
这个目标的定义,其实涉及了工程效率的四个维度。
工程效率的目标,就是让用户能及时(流速快)在生产环境,持续稳定地(稳态久)享受(价值准)软件所提供的良好服务(质量好)。
这四个维度,可以按照重要性进行排序:
- 稳态久
- 价值准
- 流速快
- 质量好
其中,稳态久,指后面3个维度“价值准”、“流速快”和“质量好”,都要能持续地保持,即能保持收益稳态。之所以排名第一,是因为其所涉及的“凶兆1:用线性思维解决复杂系统问题”,经常被大家忽视,导致开发团队难以保持后面3个维度的收益稳态。
流速快,指价值向用户流动的速度快,而不是指某个员工或某个部门完成工作的速度快。因为如果价值在两个部门间发生了等待,即使每个部门工作得再快,价值流向用户的速度还是变慢了。
13大凶兆
在通往工程效率目标的路上,潜伏着13大凶兆,阻碍工程效率的达成。
这13大凶兆,按工程效率的四维度,可分为4类。
1. 稳态久
凶兆1:用线性思维解决复杂系统问题。比如靠“加班和加人”加快进度。易事与愿违,老板易破财,员工易加班伤身,大凶。
无法保持长久“收益稳态”的首要原因,就是习惯用线性思维,来解决复杂系统问题。
为何软件开发过程本身,就是一个复杂系统?
我们身边有很多复杂系统的实例,比如全球气候、人脑和电网等等。
复杂系统具有以下特点:
- 内部组件相互作用
- 与环境之间的相互作用
- 相互作用的类别多种多样,比如合作、依赖、竞争……
- 组件及其相互之间的关系数量庞大,难以在一个人的大脑里完整建模
- 非线性,经常事与愿违,难以预测
想想在软件开发过程中,光涉及到的人员、设备、数据、过程、环境就多得不计其数,更别提它们之间的相互关系的数量了。
有人说能否将复杂系统,简化为线性的简单系统?这样就不必应对复杂系统了。
遗憾的是,这样做,短期可行,但长期不可行。
Frederick Brooks于1986年在论文No Silver Bullet中,将复杂性粗略地分为两类——偶然复杂性和本质复杂性。
软件开发的资源,总是有限的。所以妥协总是要做出的。一旦做出妥协,就会形成次优代码。而次优代码不断积攒,总会到达一个令人难以理解的状态。这样就出现了偶然复杂性。
我的客户田杰老师说,“偶然复杂性这个名称,会让大家觉得这个是偶然的,很少出现的。”所以,将这里的“偶然复杂性”更名为“妥协复杂性”会更揭示意图。因为这些复杂性,都是在资源受限时做出妥协所造成的。而资源受限,总是一直存在的。
软件的功能越丰富,复杂度越高,就增大了本质复杂性。W. Ross Ashby于1958年所发表的论文Requisite Variety and Its Implications for the Control of Complex Systems中解释了“必要多样性法则”。简而言之,对于能够完全控制系统B的系统A,必须至少与系统B一样复杂。
总之,只要资源有限,或不断增加新需求,那么偶然复杂性或本质复杂性就必然随着时间推移,不断增大。这样,就无法实现将复杂系统,简化为线性的简单系统。
应对复杂系统的方法有哪些?有下面两种。
第一,是可视化安全边界。
Jens Rasmussen于1997年在论文Risk Management in a Dynamic Society提出了“动态安全模型”。
可以想象,图中的小人腰上拴着3根橡皮筋,每一根都绑到相应的一个方块上。
因为人对于“经济性”和“工作量一般都有直觉,比如不会随意浪费,每天至少有几小时的睡眠和休息,所以这两根皮筋一般不会绷断。但由于“安全性”很少能被可视化出来,所以员工经常会在无意中把“安全性”这根橡皮筋绷断而不自知,导致系统在线上出现故障。
所以,应对复杂性,可以把安全边界可视化出来,让员工自觉地远离漏洞,减少故障的风险。
第二,是改善可逆性。
Trento大学经济学系主任Enrico Zaninotto教授于2002年在一次演讲中所提出的“复杂性的经济支柱模型”。
在复杂系统中,如果缺乏“可逆性”,即使能在“状态”、“关系”、“环境”上取得优势,那么所获得得收益也是暂时的。比如上个世纪福特的T型车,通过标准化零件,车身只有黑色,来减少”状态“。通过标准化工人在流水线上动作,简化人与流水线的”关系“。通过打赢了与ALAM美国特许汽车制造商协会的官司,创造了设计创新车型,不再支付高额许可费的”环境“,从而让汽车首次进入寻常百姓家。但面对之后丰田的能实现“可逆性”的精益制造,福特却败下阵来。
由于福特汽车生产线是全自动的,如果在生产中出现了有缺陷的零件,流水线是无法停下来的,只能等车下了流水线,再把新车拆开换零件。这种“可逆性”的缺失,导致福特汽车质量较差,成本较高。
而丰田汽车由于花不起钱建全自动的流水线,所以只好建半自动的。但恰恰是半自动的,就能让工人在生产过程中,随时停下流水线,更换刚刚发现的有缺陷的零件。这种改善“可逆性”的方法,让丰田汽车质量更好,成本更低。
总之,在应对复杂系统时,可以使用“可视化安全边界”,让人能对安全边界产生直觉反应,减少失误的机会。另外,失误在所难免,但如果做好了“改善可逆性”,那么就能快速和低成本地进行补救。
下面会从应对剩下12个凶兆的技术中,选取一些技术,来讨论它们如何能体现出“可视化安全边界”和“改善可逆性”。这能帮助我们更好地理解,一些熟知的技术,是如何能通过这两种方法,应对复杂系统的。
2. 价值准
凶兆2:不分析用户问题。领导经常以解决方案的形式提需求。易返工,老板易破财,员工易加班伤身,凶。
分析用户问题的技术有哪些?
- 电梯演讲
- 用户画像
- 用户目标
- 用户问题定义
- 快速启动
- 纸面原型
用户画像,通过描述用户痛点,可视化了安全边界。
分析用户问题的工具有何推荐?
- BeeArt
- Figma
- Invision
- Sketch
凶兆3:找不到业务和测试人员。开发人员经常找不到业务和测试人员,澄清需求文档上的疑问。易返工,老板易破财,员工易加班伤身,凶。
解决“找不到业务和测试人员”的技术有哪些?
- 全功能团队
- 故事梳理工作坊
- 用户故事验收条件
- 用户故事开卡
- 用户故事验卡
- 产品共识沉淀(用于为团队新成员传递知识)
- 领域驱动设计工作坊
- 迭代展示会
带有验收条件的用户故事,既通过验收条件可视化了边界,又通过用户故事本身都是需求纵向拆分的小批量,来改善可逆性。
3. 流速快
凶兆4:大需求。业务人员每次给的需求都很大,每个都需要几个月才能完成。阻碍财路,大凶。
拆分大需求的技术有哪些?
- 用户体验地图
- 用户故事地图
- 用户故事拆分
用户故事拆分,通过小粒度的需求纵向拆分,能加快价值流速,尽早获取用户反馈,改善了可逆性。
凶兆5:大批量上线。数量众多的新特性和缺陷修复,都集中在一起上线。发现缺陷难以定位,阻碍财路,因压力大,领导和员工精神易受刺激,都易加班伤身,大凶。
应对“大批量上线”的技术有哪些?
- 部署与发布分离
- 暗部署
- 特性开关
特性开关,通过调整开关来决定特性是否能够发布,来改善可逆性。
凶兆6:线上故障修复过程不规范且耗时长。线上故障抢修不走设计、开发、测试等规范过程,而是直接在生产环境改代码。易火上浇油,阻碍财路,老板易破财,影响领导仕途,员工易加班伤身,大凶。
应对“线上故障修复过程不规范且耗时长”的技术有哪些?
- 部署流水线
- 基础设施即代码
基础设施即代码,当抢修故障时,能通过代码从零开始构建整个健康状态的基础设施,从而改善可逆性。
凶兆7:长寿命Gitflow分支。代码向生产环境的测试晋级,靠分支合并晋级,而不是包晋级。阻碍财路,易发生代码合并遗漏,员工易加班伤身,大凶。
“从本质上讲,长寿命分支与将所有变更都不断集成到源代码库背道而驰。”——技术雷达2020年5月
应对“长寿命Gitflow分支”的技术有哪些?
- 主干式开发
- 持续集成
主干式开发,通过频繁小批地解决合并到主干上的代码提交的冲突,来可视化安全边界,并改善可逆性。
凶兆8:大批量代码提交。开发人员对每个用户故事,不做纵向拆分,不用特性开关,过几周才一次性提交大量代码。阻碍财路,易产生代码合并地狱,员工易加班伤身,大凶
应对“大批量代码提交”的技术有哪些?
- 任务拆分
- 特性开关
- 暗部署
- 单意图提交
- 7步提交法
7步提交法,既通过本地和流水线代码构建可视化安全边界,又通过失败提交回退改善了可逆性。
4. 质量好
凶兆9:线上故障频发。阻碍财路,老板易破财,影响领导仕途,员工易跳槽,大凶。
应对“线上故障频发”的技术
- 验尸报告
- 代码重构
- 自动化测试
- 持续集成
- Code Review
- 技术债管理
- 韧性工程
验尸报告,能通过记录线上事故的整个过程和所发现的漏洞,可视化安全边界。
凶兆10:烂代码。开发人员经常在进度的压力下图省事,复制粘贴代码,命名不揭示意图。易产生难以维护的烂代码,影响领导仕途,阻碍财路,且员工易加班伤身,大凶。
应对“烂代码”的技术有哪些?
- 重构
- 命名即过程
- 自动化测试
- 自动化单元测试
- 遗留系统单元测试
- 自动化组件测试
- 自动化契约测试
- 自动化接口测试
- 自动化用户界面测试
- 代码评审
- 技术债管理
应对“烂代码”的工具有何推荐?
- IntelliJ IDE
- SonarLint
- SonarQube
- JUnit
- Mockito
技术债管理,通过静态代码扫描工具,发现漏洞,可视化安全边界
凶兆11:流水线是摆设。没有搭建流水线,或者有流水线,但变红了没人搭理。易返工,老板易破财,员工易加班伤身,大凶。
快速发现代码集成问题的技术有哪些?
- 持续集成
- 持续集成证书
快速发现代码集成问题的工具有何推荐?
- GoCD
- LambdaCD
- Spinnaker
- Drone
- Jenkins(暂缓)
“Jenkins 2.0虽然引入了“流水线即代码”,但却继续使用插件对流水线进行建模。且未能将核心Jenkins产品更改为直接对流水线进行建模。 根据我们的经验,将部署流水线视作一等公民的构建工具才更好用。”——技术雷达2016年11月
凶兆12:Code Review没做好:开发人员很少做Code Review,要做也是等产品快上线前才集中做一次。易返工,易产生烂代码,影响领导仕途,阻碍财路,且员工易加班伤身,大凶。
做好Code Review的技术有哪些?
- 尽早、频繁、小批地做Code Review
- 频繁分享Code Review收益
尽早、频繁、小批的Code Review,既能发现代码漏洞,可视化安全边界,又能及时修复漏洞,改善可逆性。
凶兆13:单人开发。固定单个开发人员开发和维护某些模块,且不安排轮岗。易发生单点故障,领导精神易受刺激,无人能提反馈,代码难以改进,凶。
应对“单人开发”的技术有哪些?
- 频繁轮换搭档的结对编程
结对编程,既能通过随时提出编程反馈,实现可视化安全边界,又能通过修复代码缺陷,改善可逆性。
如何衡量工程效率?
衡量工程效率的指标,按工程效率的四维度,也可分为4类,共16个。
这16个指标,每个都属的维度,代表了这个指标所衡量的价值。
每个指标,都以“渐多”、“渐好”或“渐快”结尾,表示指标的绝对值没有意义,而与自己团队之前的指标相比,才有意义。
这16个指标,并不是一成不变的,需要根据团队的实际情况,进行取舍,或增加新指标。
1. 稳态久
- 可视化安全边界渐多
- 可逆性渐好
2. 价值准
- NPS渐高
- 分析出用户问题渐多
- 开发人员找到业务和测试人员速度渐快
3. 流速快
- 部署频率渐高
- 需求纵向拆分渐小
- 交货时长渐短
- 故障修复时长渐短
- 长寿命gitflow分支渐少
- 小批量代码合并渐多
4. 质量好
- 失效变更渐少
- 烂代码渐少
- 流水线修复渐快
- Code Review收益渐多
- 单人开发情况渐少
总结
工程效率的目标,就是让用户能及时在生产环境,持续稳定地享受软件所提供的良好服务。
在通往工程效率目标的道路上,按稳态久、价值准、流速快、质量好这4个维度分类,潜伏着13大凶兆。如果在团队开发工作中,看到了这些凶兆,就要警惕。
可以参考16个度量指标,来度量工程效率的变化趋势,以便达到工程效率的目标,并持续稳定地保持该目标的达成状态。