Day953.以假设驱动为指引 -遗留系统现代化实战

news2024/12/25 1:16:17

以假设驱动为指引

Hi,我是阿昌,今天学习记录的是关于以假设驱动为指引的内容。

很多人在做遗留系统现代化的时候呢,总觉得它是一个十分复杂的技术问题。

本来嘛,无论是代码的重构、架构的拆分,还是 DevOps 平台的搭建或技术栈的升级,无一不是技术活动。

一、脱离业务的技术改进都是耍流氓

十年前,曾经试图去主导一次技术改进,希望将一个遗留系统上的 JDK 从 1.4 升级到 5

可以想象一下,使用 Java 1.4 开发是一个什么样的情形,没有 stream、没有泛型,甚至没有枚举,实现一个简单的功能都需要好几行代码(当然现在的 Java 也没好到哪去……),在这样的项目上工作简直痛不欲生。

当时做了充分的调研,制定了详细的计划,以确保升级过程的平滑。然而这样一个看起来很“正常”的改进却被部门领导叫停了。他的理由是,系统刚刚上线不久,一两年内不会有很多的新需求,旧 JDK 导致的开发痛点并不明显。而业务方也没有明确提出,未来要提升开发效率以支撑更多的需求。所以,这样的改进,虽然看上去在技术上十分必要,但在业务上优先级却没那么高。这番话一语点醒梦中人。

在“怎么改”这件事儿上,当时的确做了不少功课,但偏偏“要不要改”这个关键问题脱离了业务,所以成了单方面的“技术自嗨”。

这种改进虽说从技术上看十分必要,但业务上优先级却没那么高。这个翻车案例告诉,技术要为业务服务

业务不需要的话,技术升级没有任何意义。

  • 做好了,业务方面也感知不到;
  • 做不好,很有可能导致项目失败,可谓费力不讨好。

那么,到底如何做,才能让技术更好地为业务服务呢?如果一个遗留系统平时用的人不多,需求也不多,一两个开发人员完全能够应付得来,这种情况还需要技术的更新换代吗?

其实对于这样的系统,最好的方案就是保持原样,根本不需要做什么升级和优化,因为它所带来的业务价值太小,投入产出比过低。

但面对使用人数众多、需求纷至沓来的遗留系统,想要让业务方充分感知到技术迭代带来的好处,又该怎么办呢?

这时候假设驱动的方法就派上用场了。先说说假设驱动是什么,又该怎样应用。


二、什么是假设驱动?

假设驱动实际上是一种科学的研究方法,在面对一个问题时,先要分析问题,然后试着提出一种阐述或者假设,去解释我们的发现。接着就到了实验环节,如果实验结果满足假设,就证明理论是正确的

假设驱动的思想在数学、物理、生物等科学领域都是十分常见的方法,比如哥德巴赫猜想、量子力学等,最初都是通过假设的方式提出来,并在后期通过实验加以证明或验证的。

实验是科学研究的基础,但并不是只有在实验室里才能做。

在软件开发领域,同样可以做实验,这就是假设驱动开发(Hypothesis-Driven Development,简称 HDD)。

《持续交付》的作者 Jez Humble 曾经说过:

“验证业务模式或产品理念的最低效的方法,是构建完整的产品以查看设想中的需求是否真实存在”。

在构建一个产品或功能之前,应该先扪心自问:“应该构建它吗?理由是什么?”然后开展最廉价、最快速的实验,通过用户研究,验证设想的功能是否会产生预想的业务成果。

在一个产品处于探索、复杂和不确定的阶段时,更需要的是假设,而不是传统的需求。

也就是说,假设一个功能上线之后会得到一个什么样的结果,然后等功能上线后,再去验证是否得到了这样的结果,从而得出结论和提取知识。

在这里插入图片描述

可以看到,以假设驱动的方式去构建产品,可以将用户的反馈纳入到开发过程中来,让每一个需求的效果都可以度量。

比如对于一个电子商城的 App,假设如果在商品的展示页面中加入视频功能,商品的销量就会增加 10%。

之后就开始开发视频功能,上线之后通过 A/B 测试做实验对比,看看是否加入了视频功能的商品,销量真的会增加 10%。

在这里插入图片描述
你可能会说,公司的商品展示页面也有视频功能,但就是按照普通需求去开发的,这跟假设驱动开发的方式有什么区别吗?其实区别是很明显的。一个需求总是要解决一个业务问题的,电商平台不会平白无故开发一个视频功能,背后要解决的问题,就是提升商品销量。但以普通需求的方式提出来,就不会特意做度量,等到上线后发现没达成这个目标,也就不了了之了。

回忆一下,所在的系统中,有多少费时费力开发完但却没人用的功能?它们中大多数都是因为没达成预想的假设。这是巨大的浪费。而如果以假设驱动的方式进行开发,可以在某个方向上快速验证,如果假设不成立,就立即止损,不再追加投资。

这样整个过程就显得十分精益了。还拿商品页的视频功能为例,可以先开发一个极其简单的版本快速上线,在对比发现真的对销量有提升效果后,再来逐步优化整个方案,比如延长视频时间、提高视频清晰度,甚至把直播带货时该商品的介绍剪辑下来,放到商品页等等。

这样不断迭代,每一步都通过假设驱动,并不断验证假设,得到能带来最多客户价值的方案。


三、在遗留系统中应用假设驱动开发

既然新功能开发上,可以借助假设驱动实现“多快好省”,那遗留系统现代化是不是同样适用呢?答案是肯定的。

在遗留系统现代化的过程中,接收到的任务,呈现形式往往也是需求或者故事卡,得到的也都是一个技术结果而不是业务结果。

比如重构某段代码来提升可读性,或者添加测试来提高某个模块的单元测试覆盖率。这样的技术任务是很难验收的,而且上线之后,业务方无法很容易地感知它所带来的价值。

这时可以将假设驱动开发引入到遗留系统现代化中来,将那些以“As…I want…So that…”或“Given…When…Then…”编写的故事卡和验收条件,改为下面这种形式:

我们相信 < 某个功能 >
将 < 产生某种结果 >
当 < 我们看到某种可度量的信号 > 时,我们就有信心沿着这个方向继续下去

举个例子来说就是:

我们相信,为 < 库存模块添加单元测试 >将 < 提升库存模块的内建质量 >当 < 我们看到库存模块新需求的 bug 数量连续三个月降低 > 时,我们就有信心沿着这个方向继续下去

如果只添加单元测试,而不拿出添加完测试后的数据,业务方就无法直观看到这样做的好处,这样的改进也很难获得他们认可。但如果拿着一份图表,向业务方展示连续三个月降低的 bug 数,他们一定会非常开心,并支持下一步计划。

在开发软件时,主张关注成效而非产出,在遗留系统现代化过程中,同样也应该关注成效,而不仅仅是做了哪些改进。

在上面的例子中,添加完测试后的测试数量和覆盖率就是产出,而 bug 数降低就是成效。

如果只注重产出,就会更关注团队都完成了哪些技术改进,考核维度是工作量。

这样能快速完成的工作优先级会更高,改进带来的业务价值反而被忽视;但如果注重成效,我们更关注改进如何服务于业务,考核维度变成某项改进,在多大程度上能提高用户效率,并在上线后关注相关指标的变化。

关注成效,不但可以激励去找出可以衡量业务价值的指标,也能帮助避免一些价值不大的技术改进。

还拿添加单元测试举例,如果只是为了产出,那我们关注的就是提高测试数量和测试覆盖率,当这样的度量指标,落到团队头上去真正执行时,他们就会想出一些匪夷所思的方式。

比如给 Java 类的 getter/setter 添加测试,那产出的测试数量是惊人的,但却对降低 bug 数量完全没有任何帮助,是毫无价值的。这就像如果用代码行数去评价开发人员的工作,就会多出很多无用代码一样。

说到这,明确了关注成效的必要性,下一步就是把“成效”转化成更明确的指标,这样才能更好地建立假设。


四、明确目标和度量指标

在以假设驱动的方式推动遗留系统现代化时,首要工作就是确定目标。

没有目标的工作会让我们变成无头苍蝇,到处乱撞。以下图为例,通常可以制定这样四个维度的目标。

在这里插入图片描述

  1. 业务敏捷:系统快速响应市场变化和新兴机会的能力,比如一个需求从提出到上线的时间;
  2. 运营效率:系统提升价值流效率的能力,比如一个业务从开始办理到办理完成的时间;
  3. 客户洞见:系统理解和解释客户数据、行为和反馈的能力,比如前面提到的,客户对于商品视频和直播等特性的敏感程度,我们应该如何去解释;
  4. 系统韧性与弹性:云时代对于系统的基本要求。

确定好目标,接下来就是制定各个目标的度量指标了。

软件度量是很多项目都欠缺的一环,缺少了度量,就没有办法对系统做出有效的评价。

以业务敏捷为例,可以进一步细化成 3 个维度、6 个指标。

然后再讨论出某项遗留系统现代化的举措实施之后,能带来怎样的数据变化。

等交付之后,再收集度量数据,并把数据可视化。

在这里插入图片描述

对于其他维度的指标,这里举一些例子。

可以根据自己项目的实际情况,定制更适合的指标。

运营效率主要看某个业务条线的技术改进,会对该业务带来哪些效率提升。

比如银行贷款业务,从借贷申请到发放贷款的间隔时间,就是一个不错的指标;而对于保险公司的投保业务,可以选择从投保申请到核保完成的时间。

客户洞见,主要看技术改进能否帮助系统更好地理解客户行为。这一点乍听上去有点虚,来举个例子你就明白了。很多电商系统都有秒杀功能,在客户秒杀时会造成大量的并发请求,有时甚至会拖垮服务器。这种把客户秒杀行为与系统吞吐量做关联的能力,就是客户洞见。那么给系统“上云”,或者引入缓存,都是可以提升吞吐量的方案,最终服务于优化秒杀体验这个目的。可能觉得,这个例子这么简单,哪算得上什么“洞见”嘛!其实,所谓客户洞见,就是要求站在客户视角去理解客户。有些可能很好理解,有些却不是那么直观。比如以地图的形式显示订单的运送路线和状态,可以显著地降低客户的投诉率。这里面隐含的一个客户洞见就是,客户非常关注包裹的物流信息,而地图的形式比文字列表的形式更能让客户安心。

在这里插入图片描述

系统韧性和弹性的指标就很多了,比如平均恢复时间、平均故障时间等、每秒请求数、每秒事务数等。

在确定这些指标时,可以通过正推的方式(即某项技术改进可以改善哪些指标)推导指标,也可以通过逆推的方式来寻找解决方案(即想要改善某个指标,都可以通过哪些技术改进来实现)。

举个例子,希望优化 DevOps 平台,就可以用部署频率这个指标来评价优化的结果;希望减少线上 bug 数量,也可以逆推出提高测试覆盖率、加强代码评审、拆分模块以降低认知负载等质量内建的手段。

不同目标维度的指标可以是重合的,比如服务恢复时长,既可作为业务敏捷维度的指标,也可作为系统韧性与弹性的指标;

一项技术改进也可能带来多个指标的变化。在制定度量指标时,还要注意的一点是,要尽量使用相对的数据,避免使用绝对的数据。

比如一次交付周期内的 bug 数就是一个绝对的数字,它在有些情况下有意义,但在某些情况下可能就没有意义。

比如某个需求特别大,需要横跨几个交付周期,在前几个交付周期时不会上线,这时 bug 数自然就少。等最后一个交付周期上线时,可能一下子就会多出不少 bug。

通过这样绝对的数据,就不能推出“前几个交付周期质量高,最后一个交付周期质量差”的结论。把指标换成 bug 数和上线需求数的比值,就可以避免这种偏差。

实际上,bug 数与需求数的比值也并不十全十美的,因为 bug 的严重程度、修复难度都不相同,需求的大小、紧急程度和难易程度也不相同。这时可以用“行 bug 数”来代替“需求 bug 数”,但不同代码行的难度显然也是不同的,但扩大代码行的数量就可以拉平这种差别,比如“每千行代码的 bug 数”。

还可以将 bug 的特点和需求的特点作为权重,引入到整个评价体系中来。不过如果你的项目上还没有任何度量,我建议你先把简单的度量体系搭建起来,等想要更精准度量的时候,再引入具体系数也不迟。想要了解更多关于软件指标和度量的内容,推荐你看看《精益软件度量》这本书。

指标制定好之后,等各项改进任务以增量上线之后,就可以开始收集数据,持续度量了。需要牢记的是,一定要把度量结果用各种图表可视化出来。

  • 一方面,这可以向开发团队展示改造的成果以及给公司带来的价值,以前开发人员可能只知道在哪里添加了什么代码,但并不知道这几行代码给公司带来了什么样的价值。

  • 另一方面也把改造的过程向业务部门、运营部门、市场部门透明,让他们了解并支持我们的工作

有了可度量的指标,遗留系统的假设驱动开发就成为了可能。在开始一项改进任务时,首先要对相关指标的变化做一个假设,等改进任务的部分交付之后,再收集相应的指标数据,以验证假设。如果数据是朝着假设的方向变动的,就有理由继续投资后续的改进;如果数据变化不明显或是向相反的方向变化,就要停下来仔细研究一下原因了。

以假设驱动为指引的遗留系统现代化,就是说所做的所有现代化任务,都应该能够提升这些指标。

这些指标就像灯塔一样,引领着朝着正确的方向前行。

五、小结

以假设驱动为指引

假设驱动开发是精益里的一个概念,不过迁移到遗留系统现代化中也完全适用。

Thoughtworks 的技术雷达中有一个条目就是假设驱动的遗留系统改造,讲的就是类似的技术。

假设驱动开发与传统的需求式开发不同,它先对要达成的目标做一个假设,这个目标其实才是我们真正要解决的问题。

然后根据假设制定解决方案,也就是平时开发时所面对的需求。

不同于传统需求式开发,并不是功能验收上线之后就算完成了,而是还要验证假设,看看所收集到的数据是否支持假设,从而帮助更好地演进产品。

不以假设驱动,遗留系统现代化的很多技术改进就会盲目开展,最后忘了初心,走错了方向。

在应用假设驱动开发时,首先要根据自己的项目制定一些目标,然后再根据目标建立度量体系。

这样,所有的技术改进都可以围绕这些指标展开了。

在建立度量指标时要尽量避免绝对的数值,而要尽量用数据的比值。

比值更能体现数据的相对性,比绝对的数值更能减少误差。

  • 要记得把数据可视化出来,可以打印出来贴在墙上,也可以用一个大显示器立在团队旁边。

  • 它们一方面可以激励团队成员,另一方面也是向业务方展示工作的成果,让他们相信,一个看上去很技术向的改进任务,也能给业务带来巨大的价值。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/454000.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2023年 团体程序设计天梯赛个人感悟及总结(附题解)——遗憾国三

今年也是第一次参加了天梯赛&#xff0c;在这里也写一下自己的一些赛前准备、比赛过程的一些问题&#xff0c;以及赛后的一些总结以及感悟叭&#xff01;首先赛前准备的话也不能说我准备的非常的充分吧&#xff0c;但是L2阶的题目我是真的刷的很猛很疯的呢&#xff0c;这样看来…

Python类的继承

一、类的继承 1、什么是继承 通过继承基类来得到基类的功能 所以我们把被继承的类称作父类或基类&#xff0c;继承者被称作子类 代码的重用 2、父&#xff08;基&#xff09;类与子类 子类拥有父类的所有属性和方法 父类不具备子类自有的属性和方法 3、继承的用法 定义…

vite+react+ts+mobx+antd+react-router-dom+sass+tailwindcss

写了Vue项目比较多了&#xff0c;最近想换一下react技术栈&#xff0c;锻炼自己的技术&#xff0c;废话不多说&#xff0c;开始创建项目吧&#xff0c;写这篇博客也只是记录我创建的过程&#xff0c;不通的版本难免有坑&#xff0c;欢迎一起分享讨论下! 1、npm create vite //…

【李老师云计算】Spark配置及Scala实现100个随机数找最大值

索引 前言1. Spark部署1.1 Spark下载1.2 解压Spark1.3 修改环境变量1.4 修改主机Spark配置文件1.4.1 slaves.template文件配置1.4.2 spark-env.sh.template文件配置 1.5 分享主机Spark到从机1.6 启动Spark集群(★重启后的操作)1.7 通过jps查看是否启动成功1.8 通过网页查看是否…

rk3568 适配摄像头 (mipi 单摄)

rk3568 适配摄像头 (mipi 单摄) MIPI CSI&#xff08;Mobile Industry Processor Interface Camera Serial Interface&#xff09;是一种用于移动设备的高速串行接口标准&#xff0c;用于连接图像传感器和图像处理器。MIPI CSI接口使用差分信号传输技术&#xff0c;将数据分为…

C/C++ 高精度(加减乘除)算法二进制优化

高级精度算法系列 第一章 简单实现 第二章 压位优化 第三章 二进制优化(本章) 文章目录 高级精度算法系列前言一、基本原理1、存储方式2、计算方式 二、关键实现1、整型转高精度数组&#xff08;二进制&#xff09;2、字符串转高精度数组&#xff08;二进制&#xff09;3、高精…

小程序进阶

1.1组件基础 自定义组件的结构与页面是一致的&#xff0c;即也包含有4个部分&#xff0c;分别为: .wxml 组件的布局结构 .js 组件的处理逻辑 .json 组件的配置文件 .wxstngs 组件的布局样式 1.1.1创建组件 通常将组件放到独立的目录components当中这个目录需要手动创建 …

Spring Boot的配置文件

目录 配置文件的作用 配置文件的格式 properties配置文件 格式 注释乱码问题 读取配置文件 properties的优缺点分析 YAML yml基本语法 yml配置的读取 注意事项:value的值加单双引号 配置对象 yml优点分析 properties和yml的区别 设置不同环境的配置文件 配置文件的…

Linux-搭建web服务器

综合练习&#xff1a;请给openlab搭建web网站 ​ 网站需求&#xff1a; ​ 1.基于域名[www.openlab.com](http://www.openlab.com)可以访问网站内容为 welcome to openlab!!! ​ 2.给该公司创建三个子界面分别显示学生信息&#xff0c;教学资料和缴费网站&#xff0c;基于[www.…

SpringCloud --- Ribbon负载均衡

一、负载均衡原理 SpringCloud底层其实是利用了一个名为Ribbon的组件&#xff0c;来实现负载均衡功能的。 那么我们发出的请求明明是http://userservice/user/1&#xff0c;怎么变成了http://localhost:8081的呢&#xff1f; 二、源码跟踪 为什么我们只输入了service名称就…

浅谈: 计算机—JVM—Java线程—池

计算机的基本组成 计算机的基本组成 计算机存储模型(CPU、寄存器、高速缓存、内存、外存) 现代计算机系统CPU和内存之间其实是有一个cache的层级结构的。比内存速度更快的存储介质(SRAM)&#xff0c;普通内存一般是DRAM&#xff0c;这种读写速度更快的介质充当CPU和内存之间的…

3 连续模块(二)

3.5 零极点增益模块 在控制系统设计和分析中&#xff0c;常用的函数包括 传递函数&#xff08;tf&#xff09;、零极点&#xff08;zpk&#xff09;和状态空间&#xff08;ss&#xff09;函数 传递函数&#xff08;tf&#xff09;&#xff1a;用于表示线性时不变系统的输入输出…

SQL Compliance Manager Crack

SQL Compliance Manager Crack 新的SQL CM云代理-扩展了当前SQL CM代理的功能&#xff0c;以支持EC2上Microsoft SQL服务器的远程审核。允许用户添加在共享网络位置上活动的SQL Server&#xff0c;以写入/读取数据并支持DBaaS SQL Server实例。云代理包含与当前SQL代理相同的行…

VS code 插件之中英文间自动添加空格

前言 不知道大家在开发过程中是不是会遇到写代码注释或者文本内容时中英文之间没有空格的情况&#xff0c;很多时候在写代码尤其是写注释的时候容易忘记加空格&#xff0c;但回过头来看又难以忍受&#xff0c;于是我就想着自己写一个 vscode 插件来解决这个问题&#xff0c;希…

跟我一起开启 linux 的学习吧

跟我学 CentOS 的安装 一、安装 VMware二、创建虚拟机三、安装 CentOS 7四、linux 的登录 一、安装 VMware VMware 计算机虚拟化软件 从官网 https://www.vmware.com/cn.html 下载并安装 这里就不再展示安装过程啦&#xff01; 有需要的可以 点击这里 →→→ VMware 下载安装过…

postgresql 源码结构分析

专栏内容&#xff1a;postgresql内核源码分析个人主页&#xff1a;我的主页座右铭&#xff1a;天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物&#xff0e; 目录 前言 源码下载 源码结构 核心代码目录 结尾 前言 本文对postgresql源码目…

进销存管理系统和ERP的工作原理和实现方式有何不同?

一、ERP是什么&#xff1f; ERP即企业资源规划&#xff08;Enterprise Resource Planning&#xff09;&#xff0c;是一种集成管理软件系统。它的目的是整合和规划各种企业资源和业务流程&#xff0c;包括财务、物流、采购、生产、销售等&#xff0c;以提高企业的管理效率和业…

Java -- IO流

IO流 主要用于读写数据 IO流按照流的方向可以分为以下两种&#xff1a; 输入流输出流 IO流按照操作文件类型可以分为以下两种&#xff1a; 字节流字符流 字节流可以操作所有类型的文件&#xff0c;而字符流只可以操作纯文本文件 #mermaid-svg-tfFZjSluOmEFUpyc {font-fam…

SVM-老师讲的真的很好!

支持向量机(Support Vector Machine) 如同逻辑回归一样,SVM是一个分类模型 目标 SVM解决分类模型的基本思路:什么是一个好的分类边界? SVM认为,好的分类决策边界应当是:类别边界的距离应当尽可能的远 目标函数 拉格朗日乘子法 那么我们的公式就可以写为

SIP协议之通话转接

一、介绍 在SIP协议应用中&#xff0c;有一个常用的功能叫通话转接&#xff0c;用于将接通后的通话转给第三方接听处理。 二、原理及流程 转接是通过SIP协议的一个扩展请求方法REFER实现的。呼叫转接由RFC5589(Session Initiation Protocol (SIP) Call Control - Transfer)定义…