代码重构该怎么办呢

简介: 《系统设计》系列

前段时间重读了《重构:改善代码既有设计》open in new window,收货颇多。于是,简单写了一篇文章来聊聊我对重构的看法

image.png

何谓重构?

学习重构必看的一本神书《重构:改善代码既有设计》从两个角度给出了重构的定义:

  • 重构(名词):对软件内部结构的一种调整,目的是在不改变软件可观察行为的前提下,提高其可理解性,降低其修改成本。
  • 重构(动词):使用一系列重构手法,在不改变软件可观察行为的前提下,调整其结构。

用更贴近工程师的语言来说: 重构就是利用设计模式(如组合模式、策略模式、责任链模式)、软件设计原则(如 SOLID 原则、YAGNI 原则、KISS 原则)和重构手段(如封装、继承、构建测试体系)来让代码更容易理解,更易于修改。

软件设计原则指导着我们组织和规范代码,同时,重构也是为了能够尽量设计出尽量满足软件设计原则的软件

正确重构的核心在于 步子一定要小,每一步的重构都不会影响软件的正常运行,可以随时停止重构

常见的设计模式如下

image.png

更全面的设计模式总结,可以看 java-design-patterns 这个开源项目。

常见的软件设计原则如下

9.png

更全面的设计原则总结,可以看 java-design-patternsopen in new windowhacker-laws-zh 这两个开源项目

为什么要重构?

在上面介绍重构定义的时候,我从比较抽象的角度介绍了重构的好处:重构的主要目的主要是提升代码&架构的灵活性/可扩展性以及复用性。

如果对应到一个真实的项目,重构具体能为我们带来什么好处呢?

  1. 让代码更容易理解 : 通过添加注释、命名规范、逻辑优化等手段可以让我们的代码更容易被理解;
  2. 避免代码腐化 :通过重构干掉坏味道代码;
  3. 加深对代码的理解 :重构代码的过程会加深你对某部分代码的理解;
  4. 发现潜在 bug :是这样的,很多潜在的 bug ,都是我们在重构的过程中发现的;
  5. ......

看了上面介绍的关于重构带来的好处之后,你会发现重构的最终目标是 提高软件开发速度和质量 。

重构并不会减慢软件开发速度,相反,如果代码质量和软件设计较差,当我们想要添加新功能的话,开发速度会越来越慢。到了最后,甚至都有想要重写整个系统的冲动


《重构:改善代码既有设计》这本书中这样说

重构的唯一目的就是让我们开发更快,用更少的工作量创造更大的价值。

何时进行重构?

重构在是开发过程中随时可以进行的,见机行事即可,并不需要单独分配一两天的时间专门用来重构

提交代码之前

《重构:改善代码既有设计》这本书介绍了一个 营地法则 的概念:

编程时,需要遵循营地法则:保证你离开时的代码库一定比来时更健康。

这个概念表达的核心思想其实很简单:在你提交代码的之前,花一会时间想一想,我这次的提交是让项目代码变得更健康了,还是更腐化了,或者说没什么变化?

项目团队的每一个人只有保证自己的提交没有让项目代码变得更腐化,项目代码才会朝着健康的方向发展。

当我们离开营地(项目代码)的时候,请不要留下垃圾(代码花味道)!尽量确保营地变得更干净了!

开发一个新功能之后&之前

在开发一个新功能之后,我们应该回过头看看是不是有可以改进的地方。在添加一个新功能之前,我们可以思考一下自己是否可以重构代码以让新功能的开发更容易。

一个新功能的开发不应该仅仅只有功能验证通过那么简单,我们还应该尽量保证代码质量。

有一个两顶帽子的比喻:在我开发新功能之前,我发现重构可以让新功能的开发更容易,于是我戴上了重构的帽子。重构之后,我换回原来的帽子,继续开发新能功能。新功能开发完成之后,我又发现自己的代码难以理解,于是我又戴上了重构帽子。比较好的开发状态就是就是这样在重构和开发新功能之间来回切换

image.png

Code Review 之后

Code Review 可以非常有效提高代码的整体质量,它会帮助我们发现代码中的坏味道以及可能存在问题的地方。并且, Code Review 可以帮助项目团队其他程序员理解你负责的业务模块,有效避免人员方面的单点风险。

经历一次 Code Review ,你的代码可能会收到很多改进建议。

捡垃圾式重构

当我们发现坏味道代码(垃圾)的时候,如果我们不想停下手头自己正在做的工作,但又不想放着垃圾不管,我们可以这样做:

  • 如果这个垃圾很容易重构的话,我们可以立即重构它。
  • 如果这个垃圾不太容易重构的话,我们可以先记录下来,当完成当下的任务再回来重构它

阅读理解代码的时候

搞开发的小伙伴应该非常有体会:我们经常需要阅读项目团队中其他人写的代码,也经常需要阅读自己过去写的代码。阅读代码的时候,通常要比我们写代码的时间还要多很多。

我们在阅读理解代码的时候,如果发现一些坏味道的话,我们就可以对其进行重构。

就比如说你在阅读张三写的某段代码的时候,你发现这段代码逻辑过于复杂难以理解,你有更好的写法,那你就可以对张三的这段代码逻辑进行重构

重构有哪些注意事项?

单元测试是重构的保护网

单元测试可以为重构提供信心,降低重构的成本。我们要像重视生产代码那样,重视单元测试。

另外,多提一句:持续集成也要依赖单元测试,当持续集成服务自动构建新代码之后,会自动运行单元测试来发现代码错误。

怎样才能算单元测试呢? 网上的定义很多,很抽象,很容易把人给看迷糊了。我觉得对于单元测试的定义主要取决于你的项目,一个函数甚至是一个类都可以看作是一个单元。就比如说我们写了一个计算个人股票收益率的方法,我们为了验证它的正确性专门为它写了一个单元测试。再比如说我们代码有一个类专门负责数据脱敏,我们为了验证脱敏是否符合预期专门为这个类写了一个单元测试

单元测试也是需要重构或者修改的。 《代码整洁之道:敏捷软件开发手册》open in new window这本书这样写到

测试代码需要随着生产代码的演进而修改,如果测试不能保持整洁,只会越来越难修改

不要为了重构而重构

重构一定是要为项目带来价值的! 某些情况下我们不应该进行重构:

  • 学习了某个设计模式/工程实践之后,不顾项目实际情况,刻意使用在项目上(避免货物崇拜编程);
  • 项目进展比较急的时候,重构项目调用的某个 API 的底层代码(重构之后对项目调用这个 API 并没有带来什么价值);
  • 重写比重构更容易更省事;
  • ......

遵循方法

《重构:改善代码既有设计》这本书中列举除了代码常见的一些坏味道(比如重复代码、过长函数)和重构手段(如提炼函数、提炼变量、提炼类)。我们应该花时间去学习这些重构相关的理论知识,并在代码中去实践这些重构理论。

如何练习重构?

除了可以在重构项目代码的过程中练习精进重构之外,你还可以有下面这些手段:

  • 重构实战练习:通过几个小案例一步一步带你学习重构!
  • 设计模式+重构学习网站 :免费在线学习代码重构、 设计模式、 SOLID 原则 (单一职责、 开闭原则、 里氏替换、 接口隔离以及依赖反转) 。
相关文章
|
12月前
|
存储 安全 算法
C#一分钟浅谈:数据加密与解密技术
【10月更文挑战第3天】在数字化时代,信息安全至关重要。数据加密作为保障信息不被未授权访问的有效手段,通过特定算法将明文转换为密文,确保即使数据被截获也难以解读。本文从基础概念入手,介绍C#中实现数据加密的方法,涵盖对称加密(如AES、DES)与非对称加密(如RSA),并通过具体示例代码演示如何使用`System.Security.Cryptography.Aes`类完成AES加密和解密过程。此外,还强调了密钥管理及安全策略的重要性。
214 4
|
存储 缓存 前端开发
两种异步日志方案的介绍
两种异步日志方案的介绍
341 0
|
监控 Cloud Native 数据挖掘
飞天发布时刻|阿里云可观测全速演进
5 月 22 日 10:00,阿里云飞天发布时刻,阿里云应用实时监控服务 ARMS 宣布全面升级。这次发布不仅标志着阿里云技术实力的演进,更是对企业需求深刻洞察后的创新实践。
1265 121
|
移动开发 JavaScript 小程序
uView Collapse 折叠面板
uView Collapse 折叠面板
251 0
|
设计模式 安全 Java
老系统重构系列--如何用一套流程接入所有业务线
**摘要:** 本文介绍了老系统改造的过程,作者提出,ToB业务的挑战在于需要支持多种差异化的业务需求,而模板模式在处理这种需求时可能会导致继承关系复杂和粒度过粗。为了解决这些问题,文章提出了以下步骤: 1. **梳理流程差异点**:识别不同业务流程的差异,以便确定扩展点。 2. **领域模型梳理**:区分核心域和支撑域,确保核心域的稳定性。 3. **二次抽象隔离层**:创建隔离层,避免核心域因新业务接入而变得不稳定。 4. **基于SPI的扩展体系建设**:选择了COLA-SPI实现扩展点,允许业务域定义接口并实现差异化的流程逻辑。
398 0
|
机器学习/深度学习 数据采集 算法
Python实现PCA降维和KNN人脸识别模型(PCA和KNeighborsClassifier算法)项目实战
Python实现PCA降维和KNN人脸识别模型(PCA和KNeighborsClassifier算法)项目实战
|
存储 分布式计算 监控
基于IoTDB 平台的学习和研究
Apache IoTDB是专为物联网设计的高性能时序数据库,适用于大规模数据存储、高速数据摄入和复杂分析。其特点是轻量级架构、高性能、丰富的功能集,并与Hadoop、Spark和Flink集成,支持边缘计算和云端部署。关键功能包括最新点查询、灵活部署、数据压缩和安全机制。此外,IoTDB在工业物联网场景中有广泛应用,如设备监控和智慧城市。该数据库易于使用,支持SQL-like查询,并提供与Spring Boot的整合示例。
1038 3
|
Ubuntu Linux 开发工具
Linux下多窗口分屏式终端--Terminator
Linux下多窗口分屏式终端--Terminator
1455 0
Linux下多窗口分屏式终端--Terminator
|
机器学习/深度学习 人工智能 自然语言处理
AI初探:人工智能的定义、历史与未来展望
【7月更文第15天】在科技飞速发展的今天,人工智能(Artificial Intelligence, AI)已经成为推动社会进步的关键力量,渗透到我们生活的方方面面,从智能家居到自动驾驶汽车,从精准医疗到智能金融,无不展现出其深远的影响。本文旨在为读者揭开人工智能的神秘面纱,从基本概念出发,回顾其发展历程,并探索未来的无限可能。
1747 2
|
缓存 JavaScript 前端开发
Vue3的魔法:深度解析Computed和Watch原理
【4月更文挑战第18天】
739 1