DevOps落地笔记-08|技术债务:勤借勤还,再借不难

news2024/11/26 2:24:27

上一讲主要介绍了如何有效管理第三方组件的实际案例,目的是让你意识到依赖组件的质量也会影响到软件的质量。前面几个课时谈论的主要内容都是跟软件质量相关,通过各种方式方法提高软件交付的质量。这时就会遇到一个问题,软件质量固然重要,但工作中我们不可能把软件质量做到完美无缺才上线。软件质量不是免费的,更好的质量需要付出更多的成本和时间。那么如何平衡软件的开发速度和软件质量的关系,这就是今天要介绍的内容——技术债务。在软件开发的过程中,技术债务是不可避免的,有技术债务也是正常的。那么,如何合理、有效的管理技术债务,让软件实现健康地发展呢?

什么是技术债务

相信很多软件开发人员都阅读或修改过他人写的代码,特别是企业里遗留下来的老代码。如果要修改其中的一个 Bug,或者在这些系统之上增加新的功能,那将非常痛苦。我听到很多次:“改他人的代码,还不如我自己写一个。”有时候并不是说大家喜欢重复造轮子,而是因为目前这个“轮子”年久失修,已经不具备重复使用的可能性。

目前大多数企业由于交付期限的压力,都存在这样的问题:

& 文档没有写或者根本与当前版本不同步;

& 架构设计也只是满足当时的需求;

& 代码中留下了很多待优化的代码片段;

& 遗留代码缺乏文档和单元测试,无人能改,无人敢改。

上面提到的这些问题你应该都能理解,这些问题大多是技术债务没有有效处理导致的结果。那么,什么是技术债务?技术债务的概念是由敏捷先驱 Ward Cunningham(沃德·柯宁汉)在 1992 年提出的,是指那些现在选择不做,但如果一直不做,就会影响未来软件发展的事情。 下面两个例子可以帮助我们理解。

& 过时的架构设计:支撑 1 万人的架构和支撑 1 千万人的架构肯定是不一样的。在最初用户量不大时,采用单体架构满足业务需求是没问题的,但随着用户量的增长,系统架构不做升级,就会影响到业务的发展。

& 需要重构的代码:在单体架构时,为了加快数据的加载速度,会在内存中将预先加载的数据缓存起来。但当采用分布式系统架构后,这段代码逻辑就要进行相应的重构,采用像 Redis 这种分布式缓存方案,否则就会出现数据不一致的情况。

要注意的是,未实现的功能需求不属于技术债务。

因此,技术债务是在短期内不会产生影响,但从长期来看,经常背负技术债务的团队会面临潜在的严重问题,甚至会危及软件的可持续性。每个技术债务,无论多么小,偿还的成本都会随着时间的推移而不断增加,还会导致额外的技术债务。

技术债务是如何产生的

生命周期

在介绍技术债务产生的原因之前,我们先了解一下技术债务的生命周期,掌握技术债务从产生到消亡的整个过程。如下图所示。技术债务经历了四个阶段:

1.产生阶段, 由于各种原因产生了技术债务,此时并未意识到技术债务的存在。

2.意识阶段, 开发人员意识到技术债务的存在,但并未影响到软件的正常发展。在此之前一直享受技术债务带来的红利。

3.临界点阶段, 技术债务已经阻碍软件的正常发展了,出现负债的情况。

4.补救阶段, 采取措施,偿还技术债务,恢复到正常开发流程。
在这里插入图片描述
产生的原因

从上图可以看出,技术债务的产生是源头。要想有效管理技术债务,首先就要了解技术债务产生的原因。下面介绍一下在许多团队中技术债务产生的常见原因,有利于团队能够清楚地认识技术债务,并选择正确的规避方法。这些原因主要与业务、上下文改变、开发流程和团队有关,如下图所示。
在这里插入图片描述
第一个原因与业务有关。

在企业里,业务目标、需求、具备的资源以及能够承担的风险都会影响软件产品。业务问题导致技术问题,进而产生技术债务。

& 时间和成本压力

开发团队通常因为项目交付的时间、项目预算问题,而优先处理用户需要的功能。业务人员和客户也只关心如何更快的向用户交付新功能,抢占市场先机。因此,开发团队没有太多时间设计具有低耦合、高内聚、可扩展的服务层,而需要继续在现有的系统中添加这些功能。虽然短期内能暂时满足项目需求,但此时技术债务已经产生。

& 业务目标不匹配

开发团体的设计方案和技术选型不是为了实现业务目标,而是其他方面的原因。比如,企业需要快速开发一个 App。但技术人员考虑到性能因素,采用了原生的 Android 和 iOS 语言开发。由于对语言的掌握有限,导致系统设计差,用户体验不好,最终导致大量返工。

& 需求不足

当需求不明确,就会产生技术债务,特别是对软件的非功能性需求,没有明确的要求(如安全性、性能、可扩展性等)情况下。

第二个原因与上下文改变有关

技术债务是一个与时间有关的概念。即便是在当初做决策时未产生任何技术债务的设计,随着时间的推移也会过时,需要重新设计。这种重新设计是由业务、技术的变化,或者自然进化造成的技术债务的结果。

& 业务上下文变化

系统的所有决策在当初都是合理的,可突如其来的外部事件改变了现有的业务目标。比如企业被收购,收购后系统需要进行融合等。

& 技术变化

软件、硬件和中间件技术的更新迭代,导致现有系统债务重重。比如:十年前使用 JDK5 开发的应用系统,在今天的技术形态下只能推翻重来了。

& 自然进化

系统在演化的过程中会发生变化,如修复问题、增加新功能。这种变化本身也会削弱一个系统,这是自然进化的结果。就跟人类身体的零部件随时年龄慢慢老化一样,如果做过手术,更会元气大伤。

第三个原因与开发流程有关

我们通常将没有按照软件工程实践和开发规范完成的事项也归类为技术债务。这类技术债务要分析哪些是没有遵循流程规范,哪些是流程规范本身不合理导致的。再根据分析结果进行相应的处理。

& 无效的文档

文档,一直都是软件开发过程中的痛。开发人员对编写文档的抵触一直都是存在的。事实上,关键性文档的缺失或过时增加了系统产生技术债务的风险,比如架构设计文档、测试用例文档等。最初的设计人员在交付压力下,并未有效纪录架构设计的细节、约束和遗留的问题,后续的开发人员会犹豫是否要更改他们不确定的代码。

& 测试自动化不足

随着系统功能不断增加,开发人员会着重关注当前开发的新功能是否可用,而对已有功能的关注就相应减少了。这时就需要有一套自动化测试工具,能够对已有的功能进行测试。这样就可以校验当前的变更是否对已有功能产生影响。

& 流程不匹配

为了保障研发过程顺利开展,所有的软件研发团队都有自己的研发流程。团队成员如果偏离该流程,就有可能导致技术债务,比如代码评审,分支策略,导致版本分支混乱。

第四个原因与团队相关。

影响系统发展的一个关键的、经常被忽略的因素是人。需求是人提出的,架构是人设计的,代码是人编写的,系统是人使用的。有很多现实的例子表明,团队成员的业务和技术水平对于技术债务的产生至关重要。

& 经验不足

一般情况下,团队中经验较少的队员在编码时更容易产生技术债务。比如缺乏模块化设计、代码复杂度的理解。由于企业内部对员工级别的限制和团队梯队的合理性,每个团队中都会有一些初级开发人员,因此,对初级开发人员的工作结果审核和技能培训是至关重要的。

& 分布式团队

沟通问题可能会导致对设计决策理解不一致。分布式团队经常会面临着沟通协调的问题。比如广州的团队进行架构设计,北京的团队负责代码实现,在进行任务沟通时,将会是一个很大的挑战。

& 非专属团队

团队成员横跨多个项目,特别是经验丰富的开发人员。多任务并行不仅需要在多个任务间进行切换,而且往往团队和个人会将注意力集中在最紧迫的项目上,而忽略对其他项目的关注。不能高效、专注地完成任务,不可避免的会产生技术债务。

管理技术债务的原则和实践

介绍完技术债务产生的原因,下面就要介绍如何有效地管理技术债务。**管理技术债务不是一项一次性活动,它是软件开发过程中的一部分。**下面按照避免产生、提前发现和尽快修复的顺序和原则介绍如何有效管理技术债务。

避免产生技术债务

团队成员的综合能力和丰富经验可以识别技术债务以及避免产生技术债务。因此,从团队成员来说,避免产生技术债务的方法是:

& 让具有丰富经验和能力的人参加到项目中;

& 让具有丰富经验和能力的人把控项目的进度和质量;

& 建立系统化的业务知识和技能的培训,提升团队的整体实力。

提前发现技术债务

大多数情况下,技术债务都是无意产生的。如果要想尽早发现这些技术债务并不是一件容易的事。目前有大量的免费、开源的工具可以帮助识别代码中的技术债务。

& 单元测试框架

单元测试是开发人员自己编写测试,以验证代码中单个代码单元的正确性。如果单元测试失败,团队成员能够立即发现并修复导致失败的代码。单元测试还可以检验当前变更是否对已有功能有影响。目前,每一种编程语言都有对应的单元测试框架 xUnit。比如 Java 语言的 JUnit,Python 语言的 PyUnit 和 C++ 语言的 CppUnit 等等。

& 静态代码分析

静态代码分析工具可以识别代码的编码规范、漏洞和缺陷,以及重复代码等问题。这些工具可以方便地与流水线进行集成,自动化的执行扫描和生成检查报告。下图是 SonarQube 执行代码检查的结果,可以非常清晰的了解当前代码的内部质量和技术债务情况,点击上面的数字,能够看到产生该问题的具体代码片段,对于解决问题非常有帮助。
在这里插入图片描述
& 持续集成

传统软件开发中,一般要到每个功能完成后才会进行集成,此时会有各种各样的问题,如果该问题影响范围较大,甚至将设计方案推翻重来,那付出的代价将会是巨大的。持续集成是一种不同于传统开发的方法,团队每天至少集成一次或者每次提交到代码库时,自动执行集成和验证的过程。通过频繁的集成尽早发现集成中遇到的问题,降低最终集成时的风险。

尽快偿还技术债务

当我们通过代码扫描工具或者在开发过程中发现技术债务后,就要考虑尽快偿还技术债务。根据技术债务的难易、大小、缓急采取不同的偿还策略。

& 立即偿还技术债务

对于能当时处理的就立即偿还掉。这种方法可能是最有效的方法,但也是实施起来难度最大的方法。团队习惯于对当前正在处理的功能进行编码,而是把技术债务留到以后去改进,即便是“以后”永远也不会到来…无论如何,尽快偿还是解决技术债务和使软件更具有可维护性的最有效方法。

& 标记技术债务

当发现技术债务的代码时,如果不能立即处理,就先记录一下,然后在后面的某个时间点进行处理。之前的做法是添加 TODO 或 FIXME 这样的注释作为临时占位符,标记这里是存在技术债务的。但随着时间的推移,这些注释不但效果不好,也不会阻止有问题的代码提交到代码库。更有效的做法是在发现技术债务的代码中添加运行时异常,这样就可以使代码运行时处于中断的状态,阻止有问题的代码提交到代码库。

可以看下面的例子,在代码中灵活配置门限的阈值。代码片段如下:

try {
            File thresholdConfig = new File("c:/threshold.config");
            FileInputStream fis = new FileInputStream(thresholdConfig);
            Properties infoProperties = new Properties();
            infoProperties.load(fis);
            String thresholdVal = infoProperties.getProperty("threshold");
            System.out.println(thresholdVal);
        } catch (IOException e) {
            e.printStackTrace();
        }```

这段代码的问题是以硬编码的方式从本地加载配置文件。开发人员也了解这样写是不对的,因为他只是想调试一下代码逻辑的正确性,并且不希望分散目前的注意力。那么可以将运行时异常添加到验证成功代码的后面,这样既能验证代码逻辑的正确性又不会遗忘此处的技术债务。如下所示:

try {
File thresholdConfig = new File(“c:/threshold.config”);
FileInputStream fis = new FileInputStream(thresholdConfig);
Properties infoProperties = new Properties();
infoProperties.load(fis);
String thresholdVal = infoProperties.getProperty(“threshold”);
System.out.println(thresholdVal);
throw new RuntimeException(“不要以硬编码的方式加载配置文件”);
} catch (IOException e) {
e.printStackTrace();
}


运行的结果如下图所示:
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/cb6cb49fad4d4644adae2ed09972a85a.png)
&  **对技术债务进行排期**

当发现技术债务较大,并不能在短时间内解决时,就需要将技术债务添加到产品列表(Product Backlog)中,产品经理将技术债务和需求一起排列优先级,共享团队的资源和时间,并和需求一样进行跟踪和验收,保证技术债务确实被偿还。

**总结**

本课时开篇以如何平衡软件开发进度和软件质量之间的关系引出技术债务。并提出在软件开发过程中,技术债务是不可避免的,需要有效的管理和控制技术债务的蔓延,才能保证软件的健康发展。

接下来系统化地介绍了什么是技术债务,什么不是技术债务,分析了技术债务产生的原因。根据技术债务的生命周期曲线图,技术债务产生后,在一段时间内会对当前业务有积极作用,只是随着时间的推移,慢慢会成为阻碍企业发展的绊脚石。因此,在管理技术债务部分,先是在产生之前能避免则避免,不能避免的可以借助工具提前发现,对于发现的技术债务尽可能早的偿还掉。有句俗话:“勤借勤还,再借不难”,言简意赅地表明了管理技术债务的策略。针对如何管理技术债务,你是否有其他的方法,欢迎在评论区分享自己的方法。

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

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

相关文章

c++设计模式之观察者模式(发布-订阅模式)

介绍 观察者模式主要关注于对象的一对多关系,其中多个对象都依赖于一个对象,当该对象的状态发生改变时,其余对象都能接收到相应的通知。 如,现在有 一个数据对象三个画图对象,分别wield曲线图、柱状图、饼状图三个对象…

基于SSM+MySQL的的新闻发布系统设计与实现

目录 项目简介 项目技术栈 项目运行环境 项目截图 代码截取 源码获取 项目简介 新闻发布系统是一款基于Servletjspjdbc的网站应用程序,旨在提供一个全面且高效的新闻发布平台。该系统主要包括后台管理和前台新闻展示两个平台,涵盖了新闻稿件的撰写…

为什么SSL会握手失败?SSL握手失败原因及解决方案

随着网络安全技术的发展,SSL证书作为网站数据安全的第一道防线,被越来越多的企业选择。SSL证书使用的是SSL协议,而SSL握手是SSL协议当中最重要的一部分。当部署SSL证书时,如果服务器和客户端之间无法建立安全连接,就会…

蓝桥杯刷题 #1 最小化战斗力差距

知识点:for 循环和简单排序 收录原因:对题目理解有误,逻辑出现错误,解题思路不清晰 n int(input()) w list(map(int,input().split())) def sort_min(n,s):s.sort()l []for i in range(1,len(s)):result s[i] - s[i-1]l.app…

Ps:自动混合图层

Ps菜单:编辑/自动混合图层 Edit/Auto-Blend Layers 自动混合图层 Auto-Blend Layers命令可以自动地混合多个图层,特别适合于制作全景图、焦点堆叠、曝光合成或任何需要平滑融合多个图像的场景。 自动混合图层命令仅适用于 RGB 或灰度图像,不适…

react中使用useEffcet抛出错误“超出最大更新深度”

目录 【项目中部分代码】: 【说明】: 【抛出错误】:“超出最大更新深度” 【造成原因】: 【例如:】 【解决】: 【项目中部分代码】: // 类组件中:一进页面就拿到要notiveType的…

(亲测)开发API接口调用管理系统网站源码2024全新接口平台多用户管理系统 api接口调用教程

2024全新开发API接口调用管理系统网站源码 附教程 用layui框架写的 个人感觉很简洁 方便使用和二次开发 搭建说明: 测试环境:Nginx PHP7.0 MySQL5.6 导入数据库 数据库配置文件修改路径:/includes/config.php 后台登录地址:http…

OpenCV学习记录——平滑处理

文章目录 前言一、图像噪声二、图像平滑处理三、完整应用代码 前言 当我们用树莓派进行opencv图像处理时,摄像头所获取的图像质量通常会有所下降,此时,需要多种手段来优化图像的质量,提高图像识别的准度。今天所记录的是当图片经过…

C++模板:非类型模板参数、特化以及分离编译

一、非类型模板参数 模板参数分类类型形参与非类型形参。 类型形参即:出现在模板参数列表中,跟在class或者typename之类的参数类型名称。 非类型形参,就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成…

Open CASCADE学习|曲面上一点的曲率及切平面

曲率(Curvature)是一个几何学的概念,用于描述一个物体的形状在某一点上的弯曲程度。在我们日常生活中,曲率与我们的生活息息相关,如道路的弯道、建筑物的拱形结构、自然界的山脉等等。了解曲率的概念和计算方法&#x…

基于QPSO-LSTM的短期风电负荷MATLAB预测程序

微❤关注“电气仔推送”获得资料(专享优惠) 参考文献 基于QPSO-LSTM的短期风电负荷预测模型——谭才兴(完全复现) 程序简介 传统的LSTM神经网络超参数和拓扑结构通常是基于经验和试验确定,但这种方法容易受到人为因…

有趣的css - 动态的毛玻璃背景

页面效果 此效果主要使用 backdrop-filter 属性,以及配合 animation 属性来实现毛玻璃模糊和一些动效。 此效果可适用于登录窗口,网站背景或者一些卡片列表中,使网页更具科技感和空间感。 核心代码部分,简要说明了写法思路&#x…

linux使用iptables禁用ip

iptables是什么? iptables 是一个强大的开源软件,它是 Linux 系统内核中 netfilter 包过滤框架的一部分,用来实现防火墙功能。iptables 提供了一种灵活的方式来控制和管理进出以及通过 Linux 计算机的网络流量。 前提 我在云服务器上用doc…

一些大语言模型(LLM)相关的开源项目

一些大语言模型(LLM)相关的开源项目 更多文章访问: https://www.cyisme.top 因为站内限制问题,有些图片无法显示,导致阅读体验较差,可以访问原文:《一些大语言模型(LLM)相关的开源项…

【云原生kubernetes系列】---亲和与反亲和

1、亲和和反亲和 node的亲和性和反亲和性pod的亲和性和反亲和性 1.1node的亲和和反亲和 1.1.1ndoeSelector(node标签亲和) #查看node的标签 rootk8s-master1:~# kubectl get nodes --show-labels #给node节点添加标签 rootk8s-master1:~# kubectl la…

Git 怎么设置用户的权限

在团队协作的软件开发中,对于版本控制系统Git来说,确保代码与数据的安全性至关重要。为了实现这一目标,Git提供了灵活且可定制的用户权限管理机制。下面将简单的探讨一下Git如何设置用户的权限,以及如何保护代码和数据。 用户身份…

3D应用开发平台HOOPS Platforms优化制造流程和数字化转型

Tech Soft 3D公司的HOOPS Platform (包括HOOPS Native Platform 和HOOPS Web Platform),是一种用于开发顶级3D软件的集成技术。具有高性能3D图形,准确,快速的CAD数据转换,3D数据发布以及与流行的建模内核的…

CTF-WEB进阶与学习

PHP弱类型 在进行比较的时候,会先判断两种字符串的类型是否相等,再比较 在进行比较的时候,会先将字符串类型转化成相同,再比较 如果比较一个数字和字符串或者比较涉及到数字内容的字符串,则字符串会被转换成数值 并且…

并查集(高阶数据结构)

目录 一、并查集的原理 二、并查集的实现 2.1 并查集的初始化 2.2 查找元素所在的集合 2.3 判断两个元素是否在同一个集合 2.4 合并两个元素所在的集合 2.5 获取并查集中集合的个数 2.6 并查集的路径压缩 2.7 元素的编号问题 三、并查集题目 3.1 省份的数量 3.2 等…

pytorch调用多个gpu训练,手动分配gpu以及指定gpu训练模型的流程以及示例

torch.device("cuda" if torch.cuda.is_available() else "cpu") 当使用上面的这个命令时,PyTorch 会检查系统是否有可用的 CUDA 支持的 GPU。如果有,它将选择默认的 GPU(通常是第一块,即 “cuda:0”&#xf…