突破架构瓶颈:克服软件系统中的漂移和侵蚀

一种常见但不完美的比喻是将软件系统中的架构漂移和侵蚀与物理建筑的架构相比。虽然这个比喻很直观,但它存在一个根本性的误解,这也常常引发软件开发中的架构问题。

试想一下,一个设计良好的摩天大楼或房屋建成后,我们期望它基本保持不变,顶多因为偶尔的现代化或扩建而发生变化。

令人惊讶的是,如今许多工程师(甚至可能是无意识地)将同样的逻辑套用到软件架构上:认为一旦系统架构设计完成,如果设计得当,它就不需要进一步修改,直到需求变化和遗留代码迫使进行大规模重写。

这是一个关键的误解。与物理结构不同,软件本质上是动态的,不断变化,需要定期更新以保持活力。一旦软件停止演变,就会开始衰亡。

此外,这种比喻通常强调软件系统的结构和行为,但忽略了同样重要的决策、权衡和妥协,这些因素共同塑造了架构。理解架构决策背后的原因对于未来的修改以及管理和演变软件架构至关重要。

本文旨在加深你对架构技术债务的理解,并强调有效管理架构漂移和侵蚀的关键因素。

架构技术债务概述

“在软件密集型系统中,技术债务指的是那些在短期内权宜的设计或实现,这些构造设置了一个技术背景,使得未来的变更更为昂贵甚至不可能。技术债务是一种或有负债,其影响主要限于系统内部质量,特别是可维护性和可演化性。” ——Avgeriou等人,2016年

技术债务总结了软件开发中过去决策和捷径累积的后果,包括低质量代码、缺失的文档和严重耦合等问题。这些问题可能源自多种原因,如战略性权衡或需求的意外变化等。

尽管许多工程团队记录了他们管理技术债务的策略——如谷歌和 ThoughtWorks 的做法——但关于特定类型的技术债务,即架构技术债(ADT),讨论较少。

ADT 源于系统设计过程中的有意或无意决策,导致维护性降低、复杂性增加、性能下降和可扩展性受限等问题。由于软件架构定义了系统的关键属性和约束,ADT 对系统演变及组织实现目标的能力构成重大风险。

ADT 是不可避免的,特别是在目标是快速交付和后续迭代时,有时甚至是必要的。因此,团队必须识别 ADT 并实施有效管理策略,以防止架构退化——即逐渐变得过时、不可靠,无法适应不断变化的业务需求或技术进步。

首先,关键的是在 ADT 的广泛范围内区分两个独特的现象:系统架构漂移和系统架构侵蚀。

架构漂移与架构侵蚀

架构漂移指的是在系统中引入不在原始架构计划中的设计决策,但这些决策并不一定会违反基础架构原则。架构侵蚀是指引入的新设计直接与系统的预期架构相冲突,破坏了系统的指导原则。

以建筑架构为比喻,架构漂移就像是建造一栋地中海风格的房子,然后添加一个哥特式的塔楼和一个后现代的扩建。这虽然导致了风格混杂(可能并不美观),但不会破坏结构的完整性。

在软件工程中,一个系统可能以干净的架构开始,但由于架构漂移,最终演变成包含多种架构范式、不一致编码实践、冗余组件和依赖项的复杂结构。

深入探讨架构漂移  by Vladi Stevanovic

另一方面,架构侵蚀类似于进行改造时破坏了房屋的结构完整性。例如,为了创建开放式布局而拆除承重墙却没有适当的支撑,或者在没有考虑原始墙体承重能力的情况下加建一层楼。

在软件架构中,架构侵蚀引入了违反系统基础原则和预期设计模式的行为,使系统变得脆弱,最终导致劣质架构,未来出现问题。

这些违规行为可能表现为紧密耦合的模块、绕过安全协议、忽略性能约束,或在无状态系统中引入有状态组件等。

DALL-E 对架构侵蚀的诠释

应对架构技术债务的策略

架构技术债务积累过多会导致架构全面退化。团队通常会采取两种策略之一:不断调整代码以应对突发问题,或者进行大规模重构。不幸的是,这两种策略常常失败,甚至可能加剧现有的技术债务。

调整代码通常只是表面解决方案。如果团队缺乏对系统架构的全面了解或对问题根源的理解,他们只能被动应对,这难以解决根本问题。

另一方面,即使是有意的重构——无论是渐进式还是一次性重构——如果不解决导致债务的根本原因,仍可能失败,技术债务也会再次出现。

最有效的方式是摒弃这些被动措施,转向整体的、主动的方法。在开发过程中整合持续的、前置的系统设计审查,使团队能够更持续地管理技术债务。例如,与其通过快速修复强行将新需求加到现有系统架构中,或不断替换遗留系统,不如采取更有效的方法,使系统设计始终包含新特性,然后无缝集成实际特性。

正如敏捷宣言的签署者之一、极限编程创始人 Kent Beck 所言:“对于每一个期望的变更,先让变更变得容易(警告:这可能很难),然后再进行容易的变更。”

架构恢复的可持续策略

许多团队误以为采用敏捷方法就能确保持续的系统设计审查,并防止架构技术债务的积累。然而,现实情况往往与这种期望存在差距。

敏捷团队注重频繁交付功能增量,可能无意中忽视了长期的架构完整性。快速交付模式还可能导致文档和设计不够清晰,使开发人员难以理解系统的整体架构及其组件的交互方式。这种疏忽会使系统维护和扩展越来越困难,最终导致技术债务的积累。

应对已累积的架构技术债务(ADT)并防止其进一步增加,需要采取以下关键步骤:

  1. 实施架构可观测性。首先,对现有架构进行彻底检查,了解应用程序在生产环境中的行为,并列出其最关键的问题。这一步对于评估系统设计的架构漂移程度至关重要。
  2. 现代化开发流程。架构漂移和侵蚀往往源于缺乏有效的流程,而不是缺乏技能。随着业务环境和软件需求的演变,缺乏系统化的方法来引入新变化以及处理团队成员的入职和离职,会使软件架构偏离其预期设计。制定系统设计、管理和文档的最佳实践,对于长期维护架构完整性至关重要。
最后的思考

在技术变革加速和竞争加剧的背景下,适应性是现代技术世界的关键。拥有一个积累了大量技术债务的复杂系统,就像是背负沉重的枷锁。在依赖关系和错误的迷宫中穿梭,使得适应变化的世界变得越来越困难,机会也因此流失。

从财务角度来看,修改负担沉重的架构债务系统的成本,总是高于那些经过深思熟虑的前期设计的系统。

虽然适量的技术债务是可管理的,并且可以通过战略性方法解决,但过度积累往往会导致系统瘫痪,带来重大挑战。

驾驭架构技术债务的复杂性,必须采取有意识且主动的策略。团队必须优先进行持续的架构评估,并整合强大的可观测性工具,以准确监控系统演变。此外,通过严格的设计、管理和文档实践来现代化开发流程,这对于维护系统的完整性和可扩展性至关重要。

管理技术债务的最有效方法是将软件变更和演化置于开发过程的核心。

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

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

相关文章

Linux下的信号使用总结

主要参考《【正点原子】I.MX6U嵌入式Linux C应用编程指南V1.4》信号篇 发送给进程的诸多信号中,大多数都是来自于内核。 信号本质上是 int 类型的数字编号,这就好比硬件中断所对应的中断号。内核针对每个信号,都给其定义了一个唯一的整数编号…

docker 容器设置中文环境

1.容器中安装和设置 1.1.进入容器查看已有语言包 locale -a 默认情况下: 1.2 安装中文语言环境 如果没有zh_CN.utf8就安装。 方式1: #直接安装中文语言包 apt-get install -y language-pack-zh-hans 方式2: #安装中文语言环境 apt-g…

线性和二次判别分析

线性判别分析 线性判别分析(Linear Discriminant Analysis,LDA)亦称 Fisher 判别分析。其基本思想是:将训练样本投影到低维超平面上,使得同类的样例尽可能近,不同类的样例尽可能远。在对新样本进行分类时&…

达梦数据库的系统视图v$lock

达梦数据库的系统视图v$lock 在达梦数据库(DM)中,V$LOCK 系统视图用于查看当前数据库中的锁定状态。该视图提供了关于所有锁定详细信息,例如锁的内存地址、所属事务 ID,锁类型和锁模式等。这对于数据库管理员进行锁定…

国产数据库 - 内核特性 - CloudberryDB中的Runtime Filter

国产数据库 - 内核特性 - CloudberryDB中的Runtime Filter 今年5月份GreenPlum官方将GitHub仓库代码全部删除,各个分支的issues和bugs讨论等信息全部清除,仅将master分支代码进行归档。对于国内应用GPDB的用户来说,这是一个挑战性事件&#x…

开发网页版加密访问文档

开发一个支持加密访问文档的网页版应用程序涉及多个步骤,包括用户认证、文档加密和解密、文件上传和下载,以及确保整个过程中的数据安全性。下面是一个详细的步骤指南: 步骤1:设置项目环境 首先,设置一个新的项目环境…

函数调用,递归技巧之取反

递归指的是在解决问题的过程中,将问题分解为同类的子问题而解决问题的方法。在程序中通常体现为函数调用自身的方式。 比如是双方回合制对战的游戏进行结算,可以使用一个变量bool类型来完成一回合双方互相战斗并且攻击方同时会作为受攻击方的结算。在递归…

Vue跨标签页数据通信

跨标签页数据通信 在同一浏览器项目地址处于不同的标签页中,建立两个页面间的数据通信,即:B页面新增/修改数据;A页面表格自动更新数据 跨标签页通信常见方案: BroadCast Channel (广播频道) Service Worker LocalStorage Window.onstorage监听 Shared…

English note 1

It was right that I decided not to buy new course before. A few days ago, the after-sales staff of this software announced that all the courses of this software would be taken down. 之前决定不继续买新的课程是对的。几天前,这个软件的售后人员就宣布…

Zookeeper 三、Zookeeper基本使用

1.Zookeeper系统模型 1)Zookeeper数据模型之ZNode 在Zookeeper中,数据信息被保存在一个个数据节点上,这些节点被称为ZNode。ZNode是Zookeeper中最小数据单位,在ZNode下面又可以再挂ZNode,这样一层层下去就形成了一个…

Reactor模型:网络线程模型演进

一,阻塞IO线程池模型(BIO) 这是传统的网络编程方案所采用的线程模型。 即有一个主循环,socket.accept阻塞等待,当建立连接后,创建新的线程/从线程池中取一个,把该socket连接交由新线程全权处理。…

【机器参数】安装适合的nvidia驱动

背景:我现在nvidia-smi没有显示,我的目标是让nvidia-smi正常显示 参考: nchttps://www.cnblogs.com/carle-09/p/11504544.html 可能是驱动版本不对,所以我重新去nvidia官网下载了驱动。 Official Drivers | NVIDIA 得到了NVID…

discuz迪恩cul!教育课程培训网站模板

Discuz x3.2模板 迪恩cul!教育课程培训 GBK,程序包中内附详细的安装教程,下载后按照教程安装即可 discuz迪恩cul!教育课程培训网站模板

如何将本地的Django项目部署到阿里云服务器上?

场景:在本地的pycharm上已经写好了一个Django架构的网站,现在要把它放到公网上 一、阿里云服务器 选择云服务器ECS,新用户可以免费使用三个月 购买时选择预装宝塔面板 买好后,进入云服务器控制台 重置实例密码 远程连接至服务…

python-17-零基础自学python-

学习内容:《python编程:从入门到实践》第二版 知识点: 类、子类、继承、调用函数 练习内容: 练习9-6:冰激凌小店 冰激凌小店是一种特殊的餐馆。编写一个名为IceCreamStand的类,让它继承为完成练习9-1或…

宝塔计划任务调用node程序时,log4js日志保存本地位置会发生变化

接我上一篇文章的情况 超简单的nodejs使用log4js保存日志到本地(可直接复制使用)-CSDN博客 原本应当保存在node项目目录下的日志文件,如果使用宝塔的计划任务来定时执行的话,日志保存路径会发生变化到如下图的位置: 如…

六款顶级原型设计工具推荐,满足你所有需求!

即时设计作为一款专业原型工具,无论是从功能还是插件库配备情况来看,都是毫无疑问可以进行原型图设计的,而且,即时设计内设海量资源库,可以支持大家通过关键词进行搜索相关资源,并且在线编辑使用&#xff0…

瑜伽馆管理系统的设计

管理员账户功能包括:系统首页,个人中心,管理员管理,教练管理,用户管理,瑜伽管理,套餐管理,体测报告管理,基础数据管理 前台账户功能包括:系统首页&#xff0c…

51单片机STC89C52RC——8.1 8*8 LED点阵模块(点亮一个LED)

目录 目的/效果 一,STC单片机模块 二,8*8 LED点阵模块 2.1 电路图 2.1.1 8*8 点阵模块电路图 2.1.2 74HC595(串转并)模块 电路图 2.1.3 芯片引脚 2.2 引脚电平分析 2.3 74HC595 串转并模块 2.3.1 装弹(移位…

2024最新免费版轻量级Navicat Premium Lite 下载和安装教程

2024最新免费版轻量级Navicat Premium Lite 下载和安装教程 关于猫头虎 大家好,我是猫头虎,别名猫头虎博主,擅长的技术领域包括云原生、前端、后端、运维和AI。我的博客主要分享技术教程、bug解决思路、开发工具教程、前沿科技资讯、产品评…