架构重构实践心得

一、前言

大多数的技术研发都对重构有所了解,而每个研发又都有自己的理解。从代码重构到架构重构,我参与了携程大型全链路重构项目,积累了一点经验心得,在此抛砖引玉和大家分享。

二、重构的定义

重构是指在不改变外部行为的情况下,改进其内部结构的软件系统更改过程。

三、重构的原因

3.1 组织架构调整

目前携程大部分业务场景都使用了微服务架构,要求服务应该封装单一的责任或单一的能力,以形成松散耦合的服务架构。

根据著名的康威定律,保证一个团队可以独立工作、快速交付变更、尽可能消除团队之间协作和协调的费力度。

所以当组织架构因为业务发展需要做相应调整时,决定了服务的架构也会需要相应的重构。

3.2 提升研发效能

重构遗留代码的目的,通常是使系统其更易于维护,减少维护系统所需的工作量,释放出研发资源处理更高价值的任务。

即使是在项目成功落地之后,仍然需要持续的系统迭代,支持新的业务需求。迭代过程引入新的缺陷也是难以避免的。

即使是最好的团队也可能会提交不成熟的代码,这往往会导致代码复杂性让系统变得难以维护,长期以往系统会越来越难以维护,影响研发效能。越来越长的开发周期,导致业务需求发布被推迟。

重构可以减少构建周期时间,改善需求交付时间。

图片

3.3 偿还技术债

技术债是很多研发团队为了追求交互的速度,倾向于选择更简单但不太可靠的方案所付出的代价。短期内为了更快地交付做出的妥协都会在未来带来更多的工作量。

重构有助于消除开发人员积累的技术债务的数量。

3.4 应用现代化

遗留代码可能无法利用现代 DevOps 集成来加速 CI/CD。

遗留代码需要改造成无状态服务,这样可以适配云上的弹性伸缩,优化成本。

四、重构的影响面

从重构的影响面可以分为最高层次的架构重构和最低层次的代码重构。

代码重构是在修改代码后不会改变对外的行为,主要目的是提高整个软件的质量。一个重构通常是一个小任务,但是多个重构应用于代码可以显著提高其质量。

架构重构主要是将现有代码重新组织成新的层级,改变代码在逻辑层次中的组织方式。

4.1 架构重构和代码重构的比较 

代码重构通常在一个开发团队内部达成一致,影响的范围容易控制和验证,风险较低。

架构重构必须要多个团队甚至是技术委员会达成一致,影响范围大,风险和成本较高。通常在做架构重构前尝试用可量化的指标来确定投入产出比,决策是否值得重构。

此外架构重构相比代码重构难度更高,对研发的专业知识要求也会更高,项目组里至少需要有一个熟悉链路上所有服务的资深研发,负责重构决策(特别是服务和服务边界处)。

五、重构计划

图片

在开始重构编码之前,对现有系统深入分析,评估哪些部分应该被重构以及重构的优先级,有助于列出重构计划。

全链路上的大规模重构往往都是长期项目,初期制定的计划也肯定会有变化调整,特别是重构过程中会有新的业务需求进入,需要调整优先级,所以计划要分成不同的阶段性里程碑目标。

六、业务研发团队沟通

重构期间需要和负责业务需求的研发团队同步协调计划,优先对新需求部分重构,避免新功能完成后立即又成为重构任务。

例如,重构后的版本在下周就会发布运行,有些业务需求计划可以直接在新版本上实现,这样既避免了业务研发被技术债务困扰,也减少了重构项目组的工作量。

七、分层设计

分层设计即定义服务之间、模块之间的边界,是完成重构的关键,让代码之间的依赖关系变得更清晰,减少耦合性。

根据关注点分离原则,把现有的功能分类,将对应的代码移动到合适的层级和该层级对应的模块。

前提是需要理解每个类的功能是什么,当面对实现多个功能的类,必须要拆分成多个只服务于一个目的的类。

单一职责的类更具备可测试性,依赖更少的外部功能,减少测试用例里 Mock 的工作量。单一职责的类也更容易被复用,更容易维护。

大型重构项目会有许多工作要做,分层后的设计就像地图,避免研发迷失方向。

八、灰度

图片

在分阶段重构的过程中,引入抽象层(例如面向接口编程),同一个接口有新老两套实现。抽象层的引入允许显示系统里新老版本多个实现的共存。

这种看似额外的临时兼容工作,可以带来以下好处:

  • 我们在编写测试用例代码的时候,也尽量面向接口验证,这样在旧代码验证通过的案例能够运行在重构后的新代码上。

  • 使用特性开关控制新老版本实现的切换,可以在不破坏原有的功能且对调用方透明的前提下逐步灰度在线上版本进行重大更改,最后新版本实现稳定后,删除老代码的实现。这种方式也能减少研发在重构时候的心智负担。

  • 特性开关的引入也能够实现快速回退,控制因为新实现带来的破坏范围。但验证不能完全依赖线上业务流量(对业务有损),下文会提到重构版本在发布前的改善质量的方法。

九、改善质量

9.1 静态检查

图片

静态检查工具 Sonar

  • 解决循环依赖

  • 解决 Cyclomatic Complexity 

  • 控制每个类的方法数

  • 控制每个方法的行数

  • 解决 warning(删除不使用的代码,也意味着减少重构的工作量)

9.2 自动化测试

自动化测试是重构最重要的基础,它能确保系统的行为不会因为重构而改变。

在重构开始优先保证测试的覆盖率,所以我们会在重构前优先使用集成测试来验证重构结果:

  • 集成测试相比单元测试覆盖率会更大,随着覆盖率越高,覆盖剩余的测试成本也会越大,例如一些异常边界场景,用单元测试覆盖的成本会更低。

  • 有些单元测试往往和老系统代码耦合,没有面向接口测试,或者是一些静态类的测试。重构代码意味着单元测试需要重写,在早期重构阶段优先用集成测试覆盖验证。

设计集成测试需要减少对其他系统(尤其是和外部第三方交互)的依赖,通过一些 Mock 工具提供稳定的测试数据,让测试结果更稳定可靠,比如使用缓存保证相同的请求能拿到相同的结果,这也能帮助后续新老版本的比对回归验证。

借助 CI 持续迭代,每一次变更提交会触发自动化测试回归验证,在早期开发阶段快速暴露问题。同时也鼓励研发多次提交变更,避免一次提交包含太多的功能点,减少测试不通过排查问题的复杂度。

9.3 链路比对

在整个链路上的服务完成一次里程碑后,会做链路上的端到端的自动化测试,比对新老系统结果,验证整条链路。

图片

a. 线上版本链路入口在收到业务真实请求后,会把请求和响应推送到消息队列里。

b. 比对工具 SmartDiff 订阅消息队列,复制请求重构后的版本链路入口,拿到结果后和线上版本结果比对

c. SmartDiff 把比对结果写入 ES 日志,研发分析日志排查比对差异原因,修复问题。

十、可观察性

图片

很多时候,软件架构容易被作为一个学术概念。即使是在一些成熟的研发团队,团队成员能够描述系统架构应该实现哪些重要的非业务功能需求(吞吐量、耗时、稳定性等等),但很难证明系统确实做到了这些。

尤其是系统经过长期多次迭代后,当前的架构实现是否还遵循原先的架构设计呢?如果无法验证,研发对架构也会失去信心。

所以我们需要对系统定义多个非功能性指标并将其可视化,线上持续地观察和确认是否和我们当初设计期望的指标一致。

比如读写缓存接口响应 P90 保持在 100ms 以内,假设后续为了提升缓存命中率,架构重构引入了多个缓存,P90 线 100ms 就可能会不达标。

指标可视化帮助我们快速发现新的设计带来的问题并做相应调整。这些非功能性指标就如同测试用例一样,快速发现问题、增强研发对架构重构的信心。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

改进的北方苍鹰算法优化VMD参数,最小包络熵、样本熵、信息熵、排列熵(适应度函数可自行选择,一键修改)包含MATLAB源代码...

今天给大家带来一期由改进的北方苍鹰算法(SCNGO)优化VMD的两个参数。 同样以西储大学数据集为例,选用105.mat中的X105_BA_time.mat数据中1000个数据点。没有数据的看这篇文章。西储大学轴承诊断数据处理,matlab免费代码获取 选取四种适应度函数进行优化&…

信息安全运维经验

1.备份系统 国外主流:veritas NetBackUp(NBU)、IBM(TSM) (191条消息) 【大数据-文摘笔记】Veritas NBU简介_weixin_30501857的博客-CSDN博客 虚拟机玩转 Veritas NetBackup(NBU)之服务端安装…

【云计算小知识】云环境是什么意思?有什么优点?

随着云计算的快速发展,了解云计算相关知识也是运维人员必备的。那你知道云环境是什么意思?有什么优点?云环境安全威胁有哪些?如何保证云环境的运维安全?这里我们就来简单聊聊。 云环境是什么意思? 云环境是…

水环境综合治理监测系统:筑牢城市水生态安全屏障

水是生命之源,是人类赖以生存的基础。然而,随着工业化、城市化的快速发展,水污染问题日益凸显,给居民的环境卫生以及用水安全带来了巨大的威胁。因此,加强水环境综合治理,保护水资源和维护生态平衡&#xf…

微信小程序导入微信地址

获取用户收货地址。调起用户编辑收货地址原生界面,并在编辑完成后返回用户选择的地址。 1:原生微信小程序接口使用API:wx.chooseAddress(OBJECT) wx.chooseAddress({success (res) {console.log(res.userName)console.log(res.postalCode)c…

一篇文章搞定《APP的启动流程》

一篇文章搞定《APP的启动流程》 前言冷启动、温启动、热启动启动中的重要成员简介zygote进程InstrumentationSystemServer进程ActivityManagerServiceBinderActivityThread 启动的步骤详解一、点击桌面图标二、创建进程三、初始化APP进程四、APP进程与System_server的绑定五、初…

【软件架构】企业架构4A定义

文章目录 前言战略、BA、DA、AA、TA五者的关系1、业务架构(BA)2、数据架构(DA)3、应用架构(AA)4、技术架构(TA)总结 前言 业务架构是跨系统的业务架构蓝图,应用架构、数…

【Nodejs】nodejs内置模块(中)

1.路劲处理模块 path 1.1 模块概览 在nodejs中,path是个使用频率很高,但却让人又爱又恨的模块。部分因为文档说的不够清晰,部分因为接口的平台差异性。将path的接口按照用途归类,仔细琢磨琢磨,也就没那么费解了。 1.…

Python基于PyTorch实现卷积神经网络分类模型(CNN分类算法)项目实战

说明:这是一个机器学习实战项目(附带数据代码文档视频讲解),如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 卷积神经网络,简称为卷积网络,与普通神经网络的区别是它的卷积层内的神经元只覆…

FUNBOX_1靶场详解

FUNBOX_1靶场复盘 这个系列的靶场给出的干扰因素都挺多的,必须从中找到有用的线索才可以。 这个靶场你扫描到ip地址后打开网页会发现,ip自动转换成域名了,所以我们需要添加一条hosts解析才可以。 192.168.102.190 funbox.fritz.box从目录…

vue中预览静态pdf文件

方法 // pdf预览 viewFileCompare() { const pdfUrl "/static/wjbd.pdf"; window.open(pdfUrl); }, // 下载 downloadFile(){ var a document.createElement("a"); a.href "/static/wjbd.pdf"; a.…

自学网络安全(黑客),遇到问题怎么解决

自学网络安全很容易学着学着就迷茫了,找到源头问题,解决它就可以了,所以首先咱们聊聊,学习网络安全方向通常会有哪些问题,看到后面有惊喜哦 1、打基础时间太长 学基础花费很长时间,光语言都有几门&#xf…

专项练习-1数据结构-02字符串

1. 下面关于「串」的叙述中,哪一个是不正确的?( ) A 串是字符的有限序列 B 空串是由空格构成的串 C 模式匹配是串的一种重要运算 D 串既可以采用顺序存储,也可以采用链式存储 正确答案:B 官方解析&…

如何在3ds max中创建可用于真人场景的巨型机器人:第 1部分

推荐: NSDT场景编辑器助你快速搭建可二次开发的3D应用场景 1. 创建主体 步骤 1 打开 3ds Max。 打开 3ds Max 步骤 2 在左侧视口中,按键盘上的 Alt-B 键。它 打开视口配置窗口。 打开“锁定缩放/平移”和“匹配位图”选项。单击“文件”并转到参考 …

实验二十四、滞回比较器电压传输特性的测量

一、题目 滞回比较器电压传输特性的测量。 二、仿真电路 电路如图1所示。 为便于观察电压传输特性的变化,输入信号采用信号发生器产生的幅值为 10 V 10\,\textrm V 10V、频率为 20 Hz 20\,\textrm{Hz} 20Hz 的三角波电压。采用虚拟的运算放大电路,其…

从娱乐产品到效率工具,ARknovv首款AR眼镜回归“AR本质”

如果说2022年是AR的元年,2023年则有望成为消费级AR眼镜的新拐点。 今年AR眼镜行业发展明显加快,且不断有大厂入局:今年2月小米发布无线AR眼镜探索版;3月荣耀也推出了一款全新的观影眼镜;而苹果在6月发布的MR头显Visio…

[面试官,你坐好],今天我给你吹下卡顿监控

这是一篇面试总结稿,根据之前的面试过程以一种模拟面试的风格进行阐述。 面试官: 自我介绍下 诶?这面试官头发还比较多,应该不牛逼,心里踏实了不少。我: 面试官你好,我叫**,5年工作经验。曾经跟OPPO产品PK&…

甄云质量管理解决方案——插上数字“羽翼”,实现PPAP落地

导语 质量管理是供应链管理中非常重要的一环,通过制定和开展质量相关的活动,确保产品符合质量标准和一致性要求。质量管理水平的高低直接影响供应链的整体效率和最终效益,关乎企业形象和品牌声誉,已然是企业的生命线。 作为采购…

ES6:Object.assign方法详解

ES6:Object.assign方法详解 1、前言2、语法3、基本用法3.1 目标对象和源对象无重名属性3.2 目标对象和源对象有重名属性3.3 有多个源对象3.4 其他情况3.4.1 只有一个参数时,Object.assign会直接返回该参数3.4.2 如果该参数不是对象,则会先转成…

el-table 表头设置渐变色

<el-table :data"tableData" stripe><el-table-column prop"name" label"测试" align"left"></el-table-column><el-table-column prop"code" label"测试1" align"left"></…