目录
以降低认知负载为前提:为什么遗留系统这么难搞?
怎样理解认知负载?
遗留系统中的认知负载
以降低认知负载为前提
总结
如何降低认知负载:活的文档能救命
什么是活文档
如何用活文档挖掘业务知识
为遗留代码添加注解
实例化需求最好的工件就是活文档
用依赖分析工具展示系统知识
总结
以假设驱动为指引:如何评价遗留系统的现代化成果?
脱离业务的技术改进都是耍流氓
什么是假设驱动?
在遗留系统中应用假设驱动开发
明确目标和度量指标
小结
以增量演进为手段:为什么历时一年的改造到头来是一场空?
什么是增量演进?
代码的增量演进
架构的增量演进
小结
本文地址:《遗留系统现代化》读书笔记(原则篇)_陆业聪的博客-CSDN博客
认知负载(Cognitive Load)是指从事一件工作所要使用的脑力劳动的总和。简单来说,就是你可以用认知负载衡量你牺牲了多少脑细胞。
我们要完成一项工作,就要在内在认知负载一定的前提下,尽量减少外在认知负载,增加相关认知负载。
遗留系统最大的认知负载其实是无处可寻的业务知识。因为它们是以“质量很差的代码”这种形式向人呈现出来的,因此有着非常高的外在认知负载。
下图是事件风暴的发明者 Alberto Brandolini 在讲述知识的分布时用到的图,有些知识只有曾经工作在它上面的某一个人知道,有些知识得去问 Bob,而有些知识就像一个谜。
遗留系统的第二大认知负载,是同样难以获取的系统知识。这里的系统知识是指系统的具体实现细节,包括模块的划分、架构的取舍,以及每一个技术决策的原因。这些知识也同样很难有文档可以一窥究竟,更遗憾的是,连代码都无法体现出每一个细节。
以降低外在认知负载为前提的意思就是,我们进行遗留系统现代化时,所做的任何举措都应该是能够降低外在认知负载的。其实不止是遗留系统现代化,我们所有的工作都应该尽量去降低外在认知负载,从而简化工作本身。降低认知负载这一原则不光能作为方向指引,落到微观操作层,同样能帮助你科学预判改造过程中的每个决策。
你只需要判断一下,当前这个事物、活动、决策所增加的认知负载是否更有利于我们完成当前和以后的工作。如果有利(比如学习更多的业务知识),就增加这种认知负载;如果不利(比如读一篇晦涩难懂的需求文档),就减少这种认知负载。
活文档(living document),顾名思义,就是指活着的文档,也就是在持续编辑和更新的文档,有时候也叫长青文档或动态文档。
可以通过在代码中加入活文档的方式,来降低认知负载。通过在代码中添加注解,分析代码生成各种可视化的图表。
所谓实例化需求,实际上指的是以现实中的例子来描述需求,而不是抽象的描述。我们在开发时,可以将这种需求转换为测试,这种以实例化方式描述的测试,也是一种活文档。它们不但很好地展示了业务知识,而且是随代码更新的。
我们可以通过依赖分析工具,建立一张遗留系统的地图,这样就可以快速知道一个业务是由哪些模块组成的。对于存储过程或函数,我们也可以找到执行它们的点,获得存储过程或函数的名称,然后再根据名称找到对应的 SQL 文件,再做类似的分析。对于复杂的入口方法,你可能会得到一幅相当大的列表或脑图,它虽然能列出全部内容,但读起来仍然很费劲。这时候我们有两个办法。一是重构复杂的入口方法,抽取出若干小的方法,再以小方法为入口点做分析。二是修改分析工具,直接分析存储过程或函数。如果存储过程或函数过大,也可以进一步拆分。
遗留系统里充满了知识,但通常是加密的,而且我们已经丢失了秘钥。没有测试,我们就无法对遗留系统的预期行为做出清晰的定义。没有一致的结构,我们就必须猜测它是如何设计的、为什么这么设计以及应该如何演进。没有谨慎的命名,我们就必须猜测和推断变量、方法和类的含义,以及每段代码负责的任务。
技术要为业务服务。业务不需要的话,技术升级没有任何意义。
假设驱动实际上是一种科学的研究方法,在面对一个问题时,我们先要分析问题,然后试着提出一种阐述或者假设,去解释我们的发现。接着就到了实验环节,如果实验结果满足假设,就证明我们的理论是正确的。
如果以假设驱动的方式进行开发,我可以在某个方向上快速验证,如果假设不成立,就立即止损,不再追加投资。这样整个过程就显得十分精益了。
我们可以将假设驱动开发引入到遗留系统现代化中来,将那些以“As…I want…So that…”或“Given…When…Then…”编写的故事卡和验收条件,改为下面这种形式:
我们相信 < 某个功能 >
将 < 产生某种结果 >
当 < 我们看到某种可度量的信号 > 时,我们就有信心沿着这个方向继续下去
如果只注重产出,我们就会更关注团队都完成了哪些技术改进,考核维度是工作量。这样能快速完成的工作优先级会更高,改进带来的业务价值反而被忽视;但如果注重成效,我们更关注改进如何服务于业务,考核维度变成某项改进,在多大程度上能提高用户效率,并在上线后关注相关指标的变化。
在以假设驱动的方式推动遗留系统现代化时,首要工作就是确定目标。以下图为例,我们通常可以制定这样四个维度的目标。
1. 业务敏捷:系统快速响应市场变化和新兴机会的能力,比如一个需求从提出到上线的时间;
2. 运营效率:系统提升价值流效率的能力,比如一个业务从开始办理到办理完成的时间;
3. 客户洞见:系统理解和解释客户数据、行为和反馈的能力,比如前面提到的,客户对于商品视频和直播等特性的敏感程度,我们应该如何去解释;
4. 系统韧性与弹性:云时代对于系统的基本要求。
需要主要的点:
在应用假设驱动开发时,你首先要根据自己的项目制定一些目标,然后再根据目标建立度量体系。这样,所有的技术改进都可以围绕这些指标展开了。
在建立度量指标时要尽量避免绝对的数值,而要尽量用数据的比值。比值更能体现数据的相对性,比绝对的数值更能减少误差。
最后,要记得把数据可视化出来。
演进式架构的定义:支持跨多个维度的引导性增量变更的架构。
其中,多维度是指技术、数据、安全、运维等不同的看待架构的视角;引导性是指在适应度函数的引导下,向着正确的方向演进架构;而增量变更是指以小步快跑的方式,细粒度地构建和部署软件,同时在一定程度上允许新旧两种实现并行运行。
增量演进是指,以增量的方式,不断向明确的目标前进的过程。
在代码现代化方面,我们的主要目标包括三类:修补测试、代码重构、代码分层。
以代码重构为例,向你演示如何实现增量演进。
绞杀植物模式
为什么历时很久的遗留系统改造会以失败而告终呢?一是因为直到最后一刻才上线,失去了持续验证的机会;二是上线后发现有问题,只能硬着头皮热修复,或者整体回滚,缺乏细粒度的回退机制。
而增量演进原则可以有效解决这个问题。它一方面鼓励我们持续交付改造的功能或新的实现,不断在生产环境验证;另一方面拥有细粒度的开关,也使得回退变得十分灵活,一旦发现问题,我们只需要关闭引起问题的那个开关即可。