写点什么

与其硬啃“屎山”代码,不如用这六步有条不紊实现代码重构

  • 2022-04-28
  • 本文字数:2851 字

    阅读完需:约 9 分钟

与其硬啃“屎山”代码,不如用这六步有条不紊实现代码重构

对大规模系统进行重构,如果一个人对着又臭又长的代码硬刚,即使花了大量的时间进行手工验证,最后仍然会有很多问题,特别是一些深路径及特殊场景下的问题。其实,大规模的系统级别重构时是有方法的。我们采访了 Thoughtworks 数字化转型与运营 资深咨询师黄俊彬(QCon+案例研习社讲师),请他来分享 MV*模式重构演进的方法和经验。

 

InfoQ:请问,开发人员什么时候需要进行代码重构呢?

 

黄俊彬:重构的范围很广,基于实际对代码的调整的工作量及影响范围,可以细分为表中 3 种类型:


类型

修改范围

示例

小型重构

对单个类内部的重构优化

重命名、提取变量、提取函数等

中型重构

对多个类间的重构优化

提取接口、超类、委托等

大型重构

针对系统组件架构重构优化

单体应用组件化等


由于不同类型的重构影响及工作量不同,重构时机也不同:

 

  • 小型重构,建议任何阶段及时重构,同时借助 IDE 提供的自动化重构,保证安全。

  • 中型重构,建议在添加新功能或者修复 Bug 时集中设计及修改,需做好测试。

  • 大型重构,特别针对大型的遗留系统改造,建议立专项,结合业务的迭代需求,将大型的重构进行拆分,在不同的研发迭代中进行。


InfoQ:您在 QCon+分享了 MV* 模式重构演进,请问在重构的过程中,有什么通用的流程吗?


黄俊彬:在 MV*模式重构演进分享中,我将重构分为了 3 个维度 6 个步骤,如下图所示:



对于遗留系统来说,通常最常见的问题就是需求的上下文存在断层,所以第一步需要尽可能地分析了解原有的业务需求。


第二步是需要仔细去分析原有的代码设计,分析原有代码的设计及存在的坏味道,作为重构后的改进项及有优化点。


第三步,补充守护测试。在开始进行重构时先补充中大型的自动化测试将主要的业务场景进行覆盖,每当小步进行安全重构时都能运行测试进行快速的反馈,更好地减少修改代码导致的风险。


第四步是进行简单设计,结合未来架构的设计模式,设计关键的接口及数据模型,作为重构的输入。在这一步通常先结合未来的架构设计划分出主要的分层,例如 MVP 模式会有 Model、View 及 Presenter 层。接下来需要重新梳理领域模型,重新划分出合适的模型。最后需要定义出层之间关键的接口,例如 MVP 中 View 及 Presenter 之间交互及会调的接口。


第五步,进行小步安全重构。在重构的过程中尽可能运用前面重构基础中介绍的安全重构手法,减少人工修改,并且在过程中尽可能做到小步提交及借助测试进行频繁验证,逐步将代码修改为设计的架构模式。


第六步,集成验收测试。重构后的代码需要保证编译通过、所有的自动化测试运行通过及进行集成的验证。


InfoQ:您认为在重构过程中,如何更好提高效率及安全性?


黄俊彬:重构如果在没有好的保障机制下,很容易引起新的问题。这里有 4 种在重构过程中常用的技术实践,可以更安全及高效地对代码进行重构。


第一是结对进行重构,通过实时 Review 保障正确性。


例如在对某大型的通讯类系统进行重构时,我与客户的架构师一起结对进行重构。因为客户的架构师熟悉业务及原有代码的上下文,在结对进行重构时的一些上下文能实时进行确认,能更有效地保障重构的安全性。


第二是尽可能自动化,借助 IDE 的安全重构进行优化,避免手工修改代码的风险。


在进行大型重构时,我们经常需要移动相关的代码及类到合适的位置。特别是当移动的类有关联到其他相关的类的时候,手工进行移动风险非常大,效率也非常低。


在这种场景下,我们可以借助 IDE 的 Move 或者 Moduriaze(Android Studio 带的功能)进行重构,像 Moduriaze 能够智能分析出移动的类及其关联的所有类与资源,一把进行自动化的移动,大大提高了安全性及效率。


第三是增加测试保护,借助自动化测试,在每次重构时频繁执行进行保障,及时反馈。


这里要特别说明的是,很多遗留的系统由于代码的腐化,存在大量的上万行的类及大几千的方法,比较难编写单元测试。在对遗留系统增加的自动化测试的策略上,通常会先覆盖中大型的接口测试或者 UI 测试,守护核心的业务逻辑。在重构完成后,再及时补充小型的单元测试。


第四是小步前进,让每笔提交尽可能小,方便进行问题定位及回滚。


InfoQ:如何更好去度量重构的结果呢?


黄俊彬在重构的过程中,一定要以终为始,思考清楚重构是为了解决什么样的问题,建立有效的度量反馈机制。例如希望将遗留代码重构成为新的架构模式,我们就必须度量重构后的代码是否符合新的架构设计模式,并且尽可能通过自动化的方式进行约束及统计。比如重构为了简化代码的复杂度,如过长的类及方法,我们就必须度量重构的代码复杂度,如圈复杂度、类及方法长度、重复率等。


实际上,通过度量反馈机制,可以让重构的价值更显性比如,中小型的重构可以通过观察代码的健康度相关的指标来显性重构的价值,如重构后代码的圈复杂度、平均函数行数、类行数等指标。大型的重构可以通过工程效率上的指标来显性重构的价值,如组件化后的编译速度的提升,组件化后发布的效率等。


InfoQ:代码重构有哪些常见阻碍因素呢?该如何解决呢?


黄俊彬:重构落地的阻碍因素,我认为主要受下面三个因素影响。


1. 重构带来的价值不够显性。重构后不会改变软件可观察行为,其价值不够显性,往往优先级都会排列在业务迭代之后。


2. 没有足够的重构时间窗口。在实际项目中不可能将业务停下来专门预留充足的时间窗口来进行重构,结合上面提到的重构时机,中小型的重构还是需要结合在日常的开发过程中,化整为零。


3. 缺少激励,风险高。如果组织中缺少这方面的文化及保障机制,重构往往让技术人员望而却步。一方面需要结合有效的度量指标来引导技术人员进行重构,另一方面也需要从组织上做好激励机制,鼓励将重构工作也作为技术故事排入迭代开发中来。


InfoQ:你印象最深的一次遗留系统重构实践是什么?为什么令你印象深刻?


黄俊彬:我印象最深的的一次遗留系统重构是给一个客户做一个超级 App 重构,这次重构主要是进行架构上的优化。让我印象比较深刻的点是因为这个应用规模比较大,代码在百万行级别,开发人员也达到 200+,全量编译构建达到 15 分钟以上。


在系统分析的过程中,我们发现业内像 Sonar 等工具更多是对现有的代码进行通用的代码坏味道扫描,对于遗留系统的大型重构通常需要将现有的系统重构为新的架构模式,所以必须以未来的架构进行输入去梳理出当前系统需要解除的耦合。


基于这个诉求我们自己开发了工具,以未来的架构作为输入,对代码进行扫描分析,梳理出依赖清单,然后基于依赖清单进行重构。


在这个案例中,最后一个业务组件解耦独立出来后,一次组件的构建调试只需要 1 分钟。


嘉宾介绍:黄俊彬,Thoughtworks 数字化转型与运营 资深咨询师,10 年软件开发、设计和架构经验。在移动开发领域的应⽤性能优化、自动化测试、架构设计及组件化等⽅向有丰富的经验。目前主要在智能硬件、通信、互联网、金融等领军企业提供敏捷转型、性能优化、系统架构改造、大型遗留系统重构等服务。


活动推荐:今年 7 月,ArchSummit全球架构师峰会将落地深圳站。官网现已上线研发效率提升、可观测性技术落地探索、出海业务架构、单云架构到多云架构转型、微服务架构落地实践、架构师能力模型、开源和自研选型思考、云原生前沿技术、IoT 系统架构设计、金融领域数字化转型等十余个热门专题,扫描下方二维码即可查看精彩内容。


现在购票可享 8 折特惠,单人购票立减 1760 元,团队购票优惠更多。购票请扫码或咨询:18514549229(微信同电话)



2022-04-28 14:553524

评论

发布
暂无评论
发现更多内容

开发利器——C语言必备实用第三方库

码哥比特

c c++ Linux 后端 框架

给hugo博客添加评论功能

远鹏

Hugo 静态博客 utterances

【STM32】TIM---基本定时器

AXYZdong

硬件 stm32 2月春节不断更

诊所数字化:诊所老板为什么拒绝预约制?

boshi

数字化转型 医院 七日更

C语言第三方库Melon开箱即用之词法分析器使用

码哥比特

c c++ Linux 后端 框架

日记 2021年2月17日(周三)

Changing Lin

2月春节不断更

今日笔记

Nydia

这是我的第一次JavaScript初级技巧

我是哪吒

JavaScript 学习 程序员 大前端 2月春节不断更

C语言实用第三方库Melon开箱即用之多线程模型

码哥比特

c c++ Linux 后端 框架

EternalWallet为您提供快速、便捷、低价的国际汇款服务

Geek_c610c0

【活动回顾】4步2小时,搭建爆火的语音聊天室

ZEGO即构

ElasticSearch.03 - 基本原理

insight

elasticsearch 2月春节不断更

gradle中的增量构建

程序那些事

maven Gradle 程序那些事 构建工具

第四章作业-编写一个用例文档

秦挺

写公号大半年,看看我都收获了些啥

架构精进之路

技术 总结 微信公众号 成长笔记

揭秘登上2021春晚舞台的黑科技-XR技术

架构精进之路

黑科技 vr 春晚 XR MR

第一次异地过年有感

石君

思考 情感

翻译:《实用的Python编程》01_05_Lists

codists

人工智能 后端 python 爬虫 列表 数据结构与算法

微信红包封面,2021年为啥突然火了?

架构精进之路

春节 微信红包封面 商业洞察

1.开篇(听说你还在艰难的啃react源码)

全栈潇晨

React React Hooks react源码

2.react心智模型(来来来,让大脑有react思维吧)

全栈潇晨

React React Hooks react源码

程序员成长第五篇:如何选择城市工作?

石云升

程序员 2月春节不断更 选择城市

数据量大读写缓慢如何优化(5)【读缓存】

我爱娃哈哈😍

redis 缓存 架构设计实战 缓存设计

1480. 一维数组的动态和

小马哥

算法 七日更

13. 如果自己写的 Python 程序出错了,怎么办?

梦想橡皮擦

python 爬虫 2月春节不断更

【STM32】PWM 输出 (标准库)

AXYZdong

硬件 stm32 2月春节不断更

消息队列Kafka:入门基础

正向成长

kafka

【LeetCode】数组拆分Java题解

Albert

算法 LeetCode 2月春节不断更

春节快过腻了?不妨关心下太空探索

脑极体

LeetCode题解:62. 不同路径,动态规划,JavaScript,详细注释

Lee Chen

算法 大前端 LeetCode

深度讲解背包问题:面试中每五道动态规划就有一道是背包模型 ...

宫水三叶的刷题日记

深度思考 面试 LeetCode 动态规划 数据结构与算法

与其硬啃“屎山”代码,不如用这六步有条不紊实现代码重构_文化 & 方法_李慧文_InfoQ精选文章