Day951.认知负载 -遗留系统现代化实战

news2024/11/17 1:51:49

认知负载

Hi,我是阿昌,今天学习记录的是关于认知负载的内容。


一、怎样理解认知负载?

作为开发人员,不管是不是工作在遗留系统上,一定面临过来自业务方或项目经理的灵魂拷问:

为什么这个需求这么简单,不过是多一项在下拉菜单,却开发这么长时间,要做绝对不超过半天!

言语中透露出一丝对于你工作能力的质疑,或是上班摸鱼的揣度。然而实际情况真的如此吗?恨不得翻出代码逐行展示给他看。

来来来,以为只是下拉框多了一项,实际上前后端都要加上;后端还要改五个服务,有两个本地从未部署;搭环境调服务就用了一天,改代码修 bug 又是两天半;别问为什么修了两天 bug,因为实际上服务要改六个;已经连续加班三个晚上,要觉得你行下次你上……玩笑归玩笑,但类似的 battle 相信每个同学都经历过。

在面对这样的质疑时,内心肯定是很委屈的。但是是否思考过这里面的真正原因?可能会说,是架构不合理,新增一个下拉项要改五六个服务;是 DevOps 工具不好用或根本没有,在本地部署新服务搭环境要很长时间;是系统知识严重缺失,不知道要改哪些地方以至于漏掉了一个服务……虽然这些问题确实增加了工作难度,但是对于项目上的老人不是这样啊,他们改起来仍然游刃有余,没部署过的服务也能轻松调通。你可能会辩驳,这是系统太复杂,对新人不友好,而老人都已经熟悉了。是的,没错,说对了。但这里面有个更专业的术语,叫做认知负载。

认知负载(Cognitive Load)是认知心理学家 John Sweller 在上世纪 80 年代所创建的理论,是指从事一件工作所要使用的脑力劳动的总和。简单来说,就是可以用认知负载衡量牺牲了多少脑细胞。

认知负载一共分为三种类型,内在认知负载、外在认知负载和相关认知负载。

对于它们的定义和对比,汇总了一张表。

在这里插入图片描述

从表中可以看到:

  • 内在认知负载是掌握一门技能所必须要付出的努力,虽然不同的技能难度不同,但只要选择了一个,它的大小就固定了,掌握得不够必然就无法胜任工作。

  • 外在认知负载是信息的呈现方式,是着重要降低的,信息的呈现自然应该越简单越好。

  • 相关认知负载是在构建概念时要了解的知识,是要尽可能增加的,因为这些知识越多越有利于工作。

也就是说,要完成一项工作,就要在内在认知负载一定的前提下,尽量减少外在认知负载,增加相关认知负载。

以软件开发为例,要完成这项工作,就要在掌握开发技能的前提下,尽量简化与开发需求本身无关的细节,而去了解尽可能多的业务知识。看到这里,就能充分理解为啥架构不合理、DevOps 工具不好用以及系统知识匮乏,都会导致改个“芝麻大”的需求都要加班加点,没错,罪魁祸首就是外在认知负载。

结合前面的例子,逐一分析:一个小需求都要改很多地方,说明模块划分时,可能一起发生变化的部分没有内聚在一起,而是分离到了不同模块和层级,架构向开发者呈现系统的方式过于复杂,增加了外在认知负载;DevOps 工具不好用,意味着工具向开发者呈现的部署任务方式太复杂;同理,没人能把一个需求要改哪些地方都说清楚,说明系统知识早已藏身代码深处,不陪葬一把头发深入研究代码,别想拿到这些知识。而项目里的“老人们”早已经消化掉了这些外在认知负载。

相信他们在刚加入项目时,也一定经历过你的这些崩溃时刻。还有一点就是,有些时候一些知识或实践,看上去在当下增加了外在认知负载,但实际上长远来看,是可以大大降低外在认知负载的。

比如测试驱动开发,一开始上手的时候,绝大多数开发人员可能都不会写代码了,软件开发的外在认知负载一下子大了很多。但如果把它当做一项技能(也就是内在认知负载)去不断学习、刻意练习的话,熟能生巧之后,就会大大降低写代码的整体认知负载,而且还提升了软件的质量(因为有很多自动化测试),降低了业务知识获取的难度(测试可以看成是有效的文档)。


二、遗留系统中的认知负载

那么遗留系统中的外在认知负载都有哪些呢?

遗留系统的特点,代码质量差、架构不合理、测试不充分、DevOps 水平低,其实都会导致外在认知负载增加。

不过,遗留系统最大的认知负载其实是无处可寻的业务知识。遗留系统中的蕴含着丰富的业务资产,但由于种种原因,导致这个资产并不那么容易获得。

遗留系统在构建的时候,往往会有成百上千页的需求、设计文档,这些的确能准确描述当时的系统状态。然而随着时间的更迭、需求的演化,当前的系统已经和构建时不可同日而语,且不同阶段的文档往往无法很好地保留下来,这就造成了业务知识的缺失。

即使所有文档都保存完好,也很难有人能完完整整地阅读下来。而且,也没有人能保证系统的实现和文档的描述是完全吻合的。

可能会问,不是还有人吗?去问问需求人员或者业务分析人员啊。遗憾的是,对于时间不太长的遗留系统,也许还能找到人,但稍长一点的,可能人影都找不到了。

有的离职了,有的升职了,有的可能是第三方供应商开发的,现在已经不合作了。即使有些知识可以在开发人员之间口口相传下来,但是也是严重失真的,没人能确保它的正确性。

下图是事件风暴的发明者 Alberto Brandolini 在讲述知识的分布时用到的图,想它也同样适合描述知识传递过程。

结合图片可以看到,有些知识只有曾经工作在它上面的某一个人知道,有些知识得去问 Bob,而有些知识就像一个谜。

在这里插入图片描述

如果系统中包含自动化测试,尤其是那种描述一个端到端业务的自动化测试,某种意义上是可以被看作有效文档的。

但对于遗留系统来说,这样的测试太罕见了,不提也罢。

很明显,想通过历史文档、咨询相关者,以及自动化测试等手段理清业务,都不靠谱。

其实,要想捋清一个遗留系统的业务,唯一有效的方式就是“扒代码”。

把代码掰开揉碎了仔细阅读,弄清楚每一行的意图,直到搞清楚这一块代码所要表达的业务逻辑。

但这种方法同时又是非常低效的,因为遗留系统的代码质量往往惨不忍睹,想靠人工的方式来梳理代码理清业务,是几乎不可能完成的任务。

经过这一番描述,应该弄清楚了遗留系统中业务知识难以获取的原因。

因为它们是以“质量很差的代码”这种形式向人呈现出来的,因此有着非常高的外在认知负载。


这里可能会有疑问,前面不是还说业务知识是相关认知负载,需要增加吗?

这里为什么又说业务知识是遗留系统最大的认知负载,需要降低呢?

其实这里说的,隐藏在遗留系统隐秘角落的业务知识,是指它们呈现的方式不友好,提高了外在认知负载,而这恰恰是需要降低的。


遗留系统的第二大认知负载,是同样难以获取的系统知识。这里的系统知识是指系统的具体实现细节,包括模块的划分、架构的取舍,以及每一个技术决策的原因。

这些知识也同样很难有文档可以一窥究竟,更遗憾的是,连代码都无法体现出每一个细节。治理的一段代码,有一行用 Thread.sleep(5000) 等待了 5 秒钟。

问遍团队的每一个人,都不知道这行代码的用意,于是就当做无用代码删掉了。

没想到几天之后系统崩溃了,原来这行代码的前面几百行,有一处调用链很深的代码触发了一个后台任务,等待 5 秒钟的目的就是等这个后台任务跑完,然后后面的代码就可以用这个后台任务所生成的数据了。

删掉这行等待代码,后续的代码就失败了。糟糕的代码各有各的糟糕之处。但这段代码的问题并不在于它有多糟糕,而是在于没有人知道它为什么糟糕。

这种代码存在于系统之中,就带来了非常高的外在认知负载。

这些高认知负载的系统知识,会导致需求开发走向“魔改”。

所谓“魔改”,就是魔幻般地修改,这种情况下,没人能说清楚一个新需求应该改哪里,更没法保证改了这些,是否就覆盖了全部要改的内容。

至此,已经知道了遗留系统之所以这么“难搞”,就是因为过高的外在认知负载。人们在遗留系统上工作的时候,所付出的脑力劳动比正常系统要多得多,因此只要能大致测试通过,就会凑合着上线,而没有精力去偿还欠下的债务、改善外在认知负载。如此恶性循环,导致遗留系统的外在认知负载越来越高,修改起来越来越难。

进行遗留系统的整治,其实就是要尽力降低遗留系统的外在认知负载。外在认知负载降低了,开发起来容易了,痛点自然就解决了。


三、以降低认知负载为前提

以降低外在认知负载为前提的意思就是,进行遗留系统现代化时,所做的任何举措都应该是能够降低外在认知负载的。

遗留系统的四化建设的“四化建设”——代码现代化、架构现代化、DevOps 现代化和团队结构现代化,会发现这四大方向其实都有利于降低团队外在认知负载。

  • 对代码进行重构、改善代码的可读性,可以降低阅读代码的难度,实际上就是降低代码的认知负载;
  • 对单体架构进行拆分,分解成多个小的、更加内聚的微服务,每个服务可以独立部署和演进,实际上就是在降低业务和系统的认知负载;
  • 优化持续集成流水线,让开发人员提交代码之后就不必随时关注后续的步骤,轻装上阵;
  • 对团队结构进行优化,让每个团队只关注少量大小适中的业务模块,以降低认知负载。

没错,降低认知负载这一原则不光能作为方向指引,落到微观操作层,同样能帮助科学预判改造过程中的每个决策。

比如在进行微服务拆分时,是应该先对代码进行模块化分解,再进而拆分出独立的服务,还是应该直接拆分出服务,再对耦合的部分进行解耦呢?代码分层改造时,是应该改造成分层架构,还是六边形架构或整洁架构呢?优化分支策略时,是应该基于主干开发,还是应该使用特性分支呢?前端应该改造成 React 还是 Vue?改造过程如何回退?

在遗留系统现代化的过程中,如果以常规的技术视角去看待上述问题,可能很多类似的技术决策都很难找到具有说服力的依据,最后只好拍拍脑袋,随便决定一个,或者看架构师自己的喜好。

实际上只要掌握了“降低外在认知负载”这个原则,就可以把技术性的问题轻松转换成人的问题,然后去分析看看,到底哪个选项更有利于降低团队的认知负载,更容易被团队所接受,更容易实现。

很多时候,遗留系统的现代化项目以失败告终,或举步维艰,都是因为很多决定和举措非但不能降低认知负载,反倒增加了认知负载。

以高认知负载的方案去解决高认知负载的问题,最终必将导致项目做不下去,人也疲惫不堪。

其实不止是遗留系统现代化,所有的工作都应该尽量去降低外在认知负载,从而简化工作本身。

比如敏捷开发方法就是一套很好的可以降低外在认知负载的方法。几个月甚至几年的交付周期,所承载的内容会让人不堪重负;而只有两周的迭代,则能让人轻装上阵。一份动辄几百页的需求文档,会让人不知所措;而只有一两页的故事卡,则能让人更轻松地聚焦于眼前的工作。

领域驱动开发(DDD)也是行之有效的降低外在认知负载的方法论。形成统一语言、拆分限界上下文,都是为了使沟通更加容易、工作更加聚焦。还有目前大厂比较流行的研发工程效能,其本质说白了也是为了降低外在认知负载。

从这个角度出发,灵活应用这个原则,以前很多悬而未决的疑难杂症,很多靠“视情况而定”、“具体问题具体分析”等“托词”搪塞过去的问题,是不是一下子就豁然开朗了?


四、总结

认知负载的三个分类:内在认知负载、外在认知负载和相关认知负载。

它们的特点以及和软件开发特别是遗留系统的关系总结一下:

  • 内在认知负载是指从事一项工作必须付出的努力,比如学习 Java 知识、前端知识等;
  • 外在认知负载是指知识呈现的形式,代码越糟糕、越难读,外在认知负载越高;
  • 相关认知负载 是指人们要学习一个知识所要付出的努力,在软件开发领域就特指业务知识。

在这里插入图片描述

其中,外在认知负载是最痛恨的,一定要尽可能地降低。

在做遗留系统现代化的时候,所有的决策在制定之前都要思考一下,是否有利于降低当前的外在认知负载。

可以说,将遗留系统的外在认知负载降到最低,遗留系统的现代化工作也就完成了。当前这个事物、活动、决策所增加的认知负载是否更有利于完成当前和以后的工作。

  • 如果有利(比如学习更多的业务知识),就增加这种认知负载;

  • 如果不利(比如读一篇晦涩难懂的需求文档),就减少这种认知负载。


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

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

相关文章

车载网络 - Autosar网络管理 - 跳转状态

四、Autosar网络管理跳转状态 网络模式对应报文状态 Autosar网络管理报文各个状态对应的网络管理报文和应用报文的发送和接收状态。 网络模式 网络管理报文 应用报文 收发类型 发送报文 接收报文 发送报文 接收报文 总线睡眠模式(BSM) No Yes No NA 准备总线睡眠模…

探索Whisper语音识别

问题一:python多版本切换 背景:有了anaconda环境 还有一个c盘的不知道什么东西 我准备下载一个python3.9.9 去官网 然后安装,安装之前一定要把原来的python卸载干净。 3.9.9安装不上,我用3.10 切换的话,就是去环境…

总结828

学习目标: 4月(复习完高数18讲内容,背诵21篇短文,熟词僻义300词基础词) 学习内容: 暴力英语:回环诵读之前的文章,背150个单词,背《冰与火之歌》-守夜人誓词 高等数学&…

《Effective C++》读书笔记(二):构造/析构/赋值运算(条款05~条款12)

目录 1. 条款05:了解C默默编写并调用哪些函数 2. 条款06:若不想使用编译器自动生成的函数,就该明确拒绝 3. 条款07:为多态基类virtual析构函数 4.条款08:别让异常逃离析构函数 5.条款09:绝不在构造和析…

Vue CLI 服务

使用命令 在一个 Vue CLI 项目中,vue/cli-service 安装了一个名为 vue-cli-service 的命令。你可以在 npm scripts 中以 vue-cli-service、或者从终端中以 ./node_modules/.bin/vue-cli-service 访问这个命令。 这是你使用默认 preset 的项目的 package.json&…

2023红明谷杯部分WP

0x00 签到 一直点就能得到flag 0x01 Dreamer 拿到题感觉有点儿懵 先下发靶机看一眼 梦想家CMS,好嘛,我直接一手查找官网 直接一手演示中心碰运气 哎嘿嘿,运气不错进去了,突然想起之前有位大佬写的关于Dreamer CMS的代码审…

【Linux网络设置】

目录 一、查看网络接口信息1.1、查看所有活动的网络接口信息1.2、查看指定网络接口信息 二、查看主机名称2.1、hostname命令2.2、永久设置主机名 三、查看路由表条目route命令 四、查看网络连接情况4.1、netstat命令4.2、ss命令 五、测试网络连接ping命令 6、跟踪数据包tracerr…

CorelDRAW2023最新版本配置及新功能介绍

从简单的线框到令人称叹的水平,使用CorelDRAW Graphics Suite 2023开始您的设计之旅:一套完整的专业图形设计应用程序,用于矢量插图、布局、照片编辑等。CorelDRAW平面设计软件通常也被叫做CDR,CDR广泛应用于排版印刷、矢量图形编…

关于电脑出厂时间查询工具的构思

在做一个单位的计算机盘点、管理的时候,很容易遇见需要知道电脑的采购时间,或者出厂时间。这个信息能够帮助管理人员决定电脑是否该按定期报废制度进行报废或更换。 目前为止,作者接触过的各类电脑,没有看到过哪台电脑有专门的一…

windows系统中安装目标检测平台detectron2

更多内容,欢迎访问老五笔记 detectron2是Facebook研发并开源的目标检测平台,包含了大量业内最具代表性的目标检测、图像分割、关键点检测算法等。Detectron2基于新版的Pytorch进行更新,包含了更大的灵活性与扩展性。​ 笔者将在本文中介绍如…

IS220UCSAH1A利用电子和空穴两种载流子导电的,所以叫做双极型电路

IS220UCSAH1A利用电子和空穴两种载流子导电的,所以叫做双极型电路 美国的通用电气公司(General Electric Company,以下简称 GE)想要称霸整个工业互联网,但却失败了。为什么呢? 多年来,GE 一直在…

关于CSDN文章内嵌视频自动播放问题

关于CSDN文章内嵌视频自动播放问题 1. 源由2. 分析3. 反馈4. 沟通5. 总结6. 附录-Firefox配置7. 附录-Microsoft Edge配置 1. 源由 这个问题是4月初发现的,主要现象就是页面上的视频一起自动播放了。 鉴于笔者有不少帖子都是文字、表格、图片、视频结合的。视频是…

机器学习:opencv案例——人脸检测

目录标题 实验数据实验原理实验步骤实验结果 实验数据 lena.jpg face3.jpg video.mp4 实验原理 (1)图片灰度转换 OpenCV 中有数百种关于在不同色彩空间之间转换的方法。 当前, 在计算机视觉中有三种常用的色彩空间: 灰度、 BG…

redis lpush rpop List消息队列实现

List 队列: 生产者存入消息: LPUSH queue2 msg1 LPUSH queue2 msg2 LPUSH queue2 msg3 消费者消费消息: RPOP queue2 RPOP queue2 RPOP queue2写个死循环消费: while true://没消息阻塞等待,3秒超时返回null,设置0时没消息一直浪…

JavaSE学习进阶day07_02 异常

第三章 异常 3.1 异常概念 异常,就是不正常的意思。在生活中:医生说,你的身体某个部位有异常,该部位和正常相比有点不同,该部位的功能将受影响.在程序中的意思就是: 异常 :指的是程序在执行过程中,出现的非正常的情况&#xff0…

Android---屏幕适配

为什么要适配 由于 Android 系统的开放性,任何用户、开发者、OEM 厂商、运营商都可以对 Android 进行定制,于是导致运行 Android 的设备多种多样,它们有着不同的屏幕尺寸和像素密度。尽管系统可以通过基本的缩放和调整大小功能使界面适应不同…

【LeetCode: 53. 最大子数组和 | 暴力递归=>记忆化搜索=>动态规划 | 分治法 】

🚀 算法题 🚀 🌲 算法刷题专栏 | 面试必备算法 | 面试高频算法 🍀 🌲 越难的东西,越要努力坚持,因为它具有很高的价值,算法就是这样✨ 🌲 作者简介:硕风和炜,…

抽象类,内部类,匿名类

java学习第十天 抽象类 1.用abstract关键字来修饰一个类时,这个类就叫抽象类 访问修饰符 abstract 类名 { } 2.用abstract关键字来修饰一个方法时,这个方法就是抽象方法访问修饰符abstract返回类型方法名(参数列表);//没有方法体 3.抽象类的价值更多作用是在于设计,是设计者…

ROS学习第十四节——参数服务器控制小乌龟

1.使用命令修改参数服务器 单独使用命令启动小乌龟节点,不是用lanuch文件,不启动键盘控制节点 rosrun turtlesim turtlesim_node 使用命令打印参数服务器参数列表 rosparam list 修改小乌龟节点的背景色 rosparam set /turtlesim/background_b 自定…

网络安全:一次艰难的 WAF 绕过

0x00:前言 做之前没想过有这么难 0x01:后缀绕过 首先看一下 waf 咋工作的,当数据包匹配到 waf 规则后,数据包就会被丢弃掉,就像这样 waf 是拦截后缀的,首先 fuzz 一波换行 失败 多个等于号 失败 单双引号…