【读书笔记】《重构_改善既有代码的设计》重构的方法论

2024-01-14 20:20

本文主要是介绍【读书笔记】《重构_改善既有代码的设计》重构的方法论,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

重构的方法论

标题:【读书笔记】【读书笔记】《重构_改善既有代码的设计》重构的方法论

时间:2024.01.14

作者:耿鬼不会笑

重构是什么?

什么是重构:

“重构”这个词既可以用作名词也可以用作动词。

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

重构(动词):使用一系列重构手法,在不改变软件可观察行为的前提下, 调整其结构。

重构 != 性能优化:

重构与性能优化有很多相似之处:两者都需要修改代码,并且两者都不会改变程序的整体功能。

两者的差别在于其目的:重构是为了让代码“更容易理解, 更易于修改”。这可能使程序运行得更快,也可能使程序运行得更慢。在性能优化时,我只关心让程序运行得更快,最终得到的代码有可能更难理解和维护。

重构应该永远是一种经济驱动的决定:

重构是一种经济适用行为,而非道德使然,如果它不能让我们更快更好的开发,那么它是毫无意义。

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

重构的意义:

重构对个体程序员的意义是提高ROI。

  1. 更快速的定位问题,节省调试时间。
  2. 最小化变更风险,提高代码质量,减少修复事故的时间。
  3. 得到程序员同行的认可,更好的发展机会。

重构对整个研发团队的意义是战斗力的提升。

image-20240111200628498

重构的原则

  1. 重构的目标: 提高迭代效率
  2. 获得同行认可的方法: 每一次提交代码,都应该使代码变得更好,先重构,再开发
  3. 增量式重构 = 自动化测试+持续集成+TDD驱动重构。

什么时候需要重构?

三次法则:

Don Roberts给了我一条准则:第一次做某件事时只管去做;第二次做类似的事会产生反感,但无论如何还是可以去做;第三次再做类似的事,你就应该重构。 正如老话说的:事不过三,三则重构。

预备性重构:让添加新功能更容易

重构的最佳时机就在添加新功能之前。在动手添加新功能之前,我会看看现有的代码库,此时经常会发现:如果对代码结构做一点微调,我的工作会容易得 多。

帮助理解的重构:使代码更易懂

我需要先理解代码在做什么,然后才能着手修改。这段代码可能是我写的, 也可能是别人写的。一旦我需要思考“这段代码到底在做什么”,我就会自问:能 不能重构这段代码,令其一目了然?当你接手一个异常难读的项目时, 说服项目组将重构作为一项需求任务来做。

捡垃圾式重构

帮助理解的重构还有一个变体:我已经理解代码在做什么,但发现它做得不好,例如逻辑不必要地迂回复杂,或者两个函数几乎完全相同,可以用一个参数化的函数取而代之。如果重构需要花一些精力,甚至会阻塞当前的任务,那么只需要将这块需要重构的代码记录下来,每次经过这段代码时都把它变好一点点,积少成多,垃圾总会被处理干净。每次 commit 代码时: 每一次经你之手提交的代码都应该比之前更加干净。

有计划的重构和见机行事的重构

见机行事的重构:我并不专门安排一段时间来重构,而是在添加功能或修复bug的同时顺便重构。例如:预备性重构、帮助理解的重构、捡垃圾式重构

有计划的重构:如果团队过去忽视了重构,那么常常会需要专门花一些时间来优化代码库,以便更容易添加新功能。 在重构上花一个星期的时间,会在未来几个月里发挥价值。当迭代效率低于预期时,将重构当作一个项任务专门来做,必要的时候停下来迭代需求。

长期重构

如果一些大型的重构可能要花上几个星期,例如要替换一个正在使用的库,或者将整块代码抽取到一个组件中并共享给另一支团队使用,再或者要处理一大堆混乱的依赖关系,等等。 这样的情况下,可以让整个团队达成共识,在未来几周时间里逐步解决这个问题,这经常是一个有效的策略。每当有人靠近“重构区”的代码,就把它朝想要改进的方向推动一点。这个策略的好处在于,重构不会破坏代码——每次小改动之后,整个系统仍然照常工作。

复审代码时重构

在给别人code review时嗅出坏味道,可以适当的提出重构的建议。

何时不应该重构

如果我看见一块凌乱的代码,但并不需要修改它,那么我就不需要重构它。 如果丑陋的代码能被隐藏在一个API之下,我就可以容忍它继续保持丑陋。只有 当我需要理解其工作原理时,对其进行重构才有价值。 另一种情况是,如果重写比重构还容易,就别重构了。

重构的手段

参考:重构:改善既有代码的设计

一种自底向上的演进方法

名称目的场景做法
提炼变量让表达式更加可读当存在难以阅读的表达式时(逻辑&计算)划分子表达式使用有意义的名称命名子表达式
提炼函数将意图与实现分离有大量重复的逻辑段时如果需要浏览一段代码才能理解其在做什么时识别变量依赖给函数命名确定函数体的存放位置构造参数,在目标位置进行调用编译,测试
封装类型高内聚,低耦合大量重复的,相同/相似变量被同时传递存在大量参数与逻辑无需关心。从函数的变量和行为上发现相关性从高度相关的函数中抽象出一个概念将概念具像化为一种类型/对象为其设计合理的名称以及生命周期
模块化逻辑划分,代码复用当一些类需要频繁配合完成一个独立的功能时关注点分离,抽象出模块/类库模块内部类相互紧密协作模块外部通过接口相互调用模块之间保持单一方向进行依赖
封装阶段 pipeline保持单一原则一段函数中处理存在处理多种事情时多个if/else代码杂糅在一起时逻辑分支膨胀&循环冗余抽象出多个任务阶段,并对阶段命名将阶段和处理的参数对象进行分离利用接口/多态特性替换if/else模式
委托模式分离变化与不变的逻辑被调用方会频繁变更时封装接口,通过依赖倒置隔离下游变更
服务化/多进程资源隔离(机器&人力)当某一个接口需要大量的状态与资源时为了提高运行时的稳定性时注册一个新的git仓库迁移代码,搭建CICD流程
配置化提高研发效率,减少重复需求当存在反复的大量的重复的需求时业务需求频繁,疲于应付需求抽象通用业务模型
领域化微服务的划分,拆分核心领域当具有一组完整业务交付价值的功能需要复用时提供完整的架构方案设计对外接口,提供SDK完善接入流程
中台化研发效能复用当公司多个业务具有相同功能时在系统化的基础上进行多租户化权限/资源管理
平台化自动化业务流程当业务需求模式清晰,需要边界明确时当研发成本成为最大成本时当要规模化获客接入时抽象自动化流程pipeline将研发介入的流程配置化将配置通过平台调度自动化权限/资源/计量/计费/数分
产品/开源化向公司外部提供产品服务榨取研发资源的剩余价值产品复杂度过高,超出内部研发能力技术资源不能创造更大价值时市场需求明确,规模化获客与续约不成问题时用户增长逻辑明确时提供对外open api 提供产品化的角色/权限/资源管理能力恰到好处的处理客户/用户使用问题

参考资料

GitHub - xianweics/refator-code: 重构 - 改善既有代码的设计

重构:改善既有代码的设计

这篇关于【读书笔记】《重构_改善既有代码的设计》重构的方法论的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/606405

相关文章

Java集合之Iterator迭代器实现代码解析

《Java集合之Iterator迭代器实现代码解析》迭代器Iterator是Java集合框架中的一个核心接口,位于java.util包下,它定义了一种标准的元素访问机制,为各种集合类型提供了一种统一的... 目录一、什么是Iterator二、Iterator的核心方法三、基本使用示例四、Iterator的工

Java 线程池+分布式实现代码

《Java线程池+分布式实现代码》在Java开发中,池通过预先创建并管理一定数量的资源,避免频繁创建和销毁资源带来的性能开销,从而提高系统效率,:本文主要介绍Java线程池+分布式实现代码,需要... 目录1. 线程池1.1 自定义线程池实现1.1.1 线程池核心1.1.2 代码示例1.2 总结流程2. J

JS纯前端实现浏览器语音播报、朗读功能的完整代码

《JS纯前端实现浏览器语音播报、朗读功能的完整代码》在现代互联网的发展中,语音技术正逐渐成为改变用户体验的重要一环,下面:本文主要介绍JS纯前端实现浏览器语音播报、朗读功能的相关资料,文中通过代码... 目录一、朗读单条文本:① 语音自选参数,按钮控制语音:② 效果图:二、朗读多条文本:① 语音有默认值:②

Vue实现路由守卫的示例代码

《Vue实现路由守卫的示例代码》Vue路由守卫是控制页面导航的钩子函数,主要用于鉴权、数据预加载等场景,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着... 目录一、概念二、类型三、实战一、概念路由守卫(Navigation Guards)本质上就是 在路

uni-app小程序项目中实现前端图片压缩实现方式(附详细代码)

《uni-app小程序项目中实现前端图片压缩实现方式(附详细代码)》在uni-app开发中,文件上传和图片处理是很常见的需求,但也经常会遇到各种问题,下面:本文主要介绍uni-app小程序项目中实... 目录方式一:使用<canvas>实现图片压缩(推荐,兼容性好)示例代码(小程序平台):方式二:使用uni

JAVA实现Token自动续期机制的示例代码

《JAVA实现Token自动续期机制的示例代码》本文主要介绍了JAVA实现Token自动续期机制的示例代码,通过动态调整会话生命周期平衡安全性与用户体验,解决固定有效期Token带来的风险与不便,感兴... 目录1. 固定有效期Token的内在局限性2. 自动续期机制:兼顾安全与体验的解决方案3. 总结PS

C#中通过Response.Headers设置自定义参数的代码示例

《C#中通过Response.Headers设置自定义参数的代码示例》:本文主要介绍C#中通过Response.Headers设置自定义响应头的方法,涵盖基础添加、安全校验、生产实践及调试技巧,强... 目录一、基础设置方法1. 直接添加自定义头2. 批量设置模式二、高级配置技巧1. 安全校验机制2. 类型

Python屏幕抓取和录制的详细代码示例

《Python屏幕抓取和录制的详细代码示例》随着现代计算机性能的提高和网络速度的加快,越来越多的用户需要对他们的屏幕进行录制,:本文主要介绍Python屏幕抓取和录制的相关资料,需要的朋友可以参考... 目录一、常用 python 屏幕抓取库二、pyautogui 截屏示例三、mss 高性能截图四、Pill

使用MapStruct实现Java对象映射的示例代码

《使用MapStruct实现Java对象映射的示例代码》本文主要介绍了使用MapStruct实现Java对象映射的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,... 目录一、什么是 MapStruct?二、实战演练:三步集成 MapStruct第一步:添加 Mave

Java抽象类Abstract Class示例代码详解

《Java抽象类AbstractClass示例代码详解》Java中的抽象类(AbstractClass)是面向对象编程中的重要概念,它通过abstract关键字声明,用于定义一组相关类的公共行为和属... 目录一、抽象类的定义1. 语法格式2. 核心特征二、抽象类的核心用途1. 定义公共接口2. 提供默认实