当前位置: 首页 > news >正文

重构的原则

何为重构

重构,可以说既是一个名词又是一个动词。

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

从动词的意义上定义,重构就是使用一系列重构手法,在不改变软件可观察行为的前提下,调整起结构。

从上面的定义可以看到,重构的目的是让软件更易于理解和修改。但从外部来看,重构造成的修改对可观察的外部行为只造成很小的改变,甚至不造成改变。重构和性能优化一样,通常不会改变组件的行为,只是改变其内部结构,只是性能优化还会改变执行速度;但两者的出发点不同,性能优化有时候会让代码更加难以理解和修改,这也是为了提高性能不得不付出的代价。

为何重构

重构改进软件设计
代码结构的流失是累计性的,越是难以看出代码所代表的设计意图,就越是难保护其设计,于是设计就腐败的越快。如果没有重构,代码就会腐败变质,而经常性的重构可以帮助代码维持起该有的形态。

重构使软件更容易理解
软件是写给计算机读的,也是写给开发者读的,你需要让计算机知道你所要达到的意图,同样也需要让其他开发者知道软件的意图。事实上,有时候我们常常不需要记忆自己写过的代码,因为当我们需要了解软件的时候,只要打开形成它的代码,就应该对“想要干什么”和“能干什么”了如指掌了。

软件应该是“自描述”的。

随着代码的趋于简洁,你可以看到之前没有发现的一些设计意图,重构不仅仅是调整代码的细枝末节,还能帮助你对软件获得更高层次的理解。

重构帮助找到bug

对于bug而言,当程序比较简单的时候,通过阅读代码就可以发现里面是否有bug。但是随着程序的复杂,光看代码已经很难发现bug了。调试也许可以帮助你更好地发现bug,但是并不是所有程序都有良好的调试条件。面对复杂的代码,重构的过程可以让你深入理解代码的意图和细节,从而让你发现其中的bug。

重构提高开发效率

对于重构提高开发质量大家已经达成共识了,但是很多人忽略了重构也可以提高开发速度。

对于糟糕的软件,我们需要花大量的时间阅读代码去理解它的设计意图,同时需要耗费大量的精力寻找重复代码,给程序打上一个又一个的补丁。由于需要大量的时间调试代码,因此你很少有时间编写新的代码,开发效率也就大打折扣。

良好的设计是维持开发速度的根本。重构可以防止程序腐败变质,还可以提高软件的质量,是提高开发效率的根本。

何时重构

我们是不是应该抽出专门的几个星期时间来重构呢?事实上,重构不应该成为一个单独的任务,重构应该随时随地地进行。我们不要为了重构而重构,我们应该是为了做什么具体的事情而顺便进行重构。重构可以让你把应该做的事情做的更好。

三次法则

如果一件事需要做一两次,可以不着急重构;但是如果需要重复三次甚至以上的话,就该考虑着手去重构了。

事不过三,三次重构。

添加功能时重构

重构的直接原因是帮助我们理解代码的意图,当我们发现程序难以理解的时候,往往是重构代码的绝佳时机。

当我们发现添加新的功能不能良好的体现我们的设计意图的时候,也是重构的时机,重构可以让我们新增功能变得更加简单,也更能体现出设计意图。

修复错误的时候重构

如果你的程序出现了意想不到的bug,这正是你的代码需要重构的信号。因为你无法一眼看出程序中的bug。

修复错误的时候重构,正是为了帮助我们理解代码,从而更清晰地看到bug的所在。

评审代码时重构

在进行“Code Review”的时候,如果发现代码难以理解,这正是重构代码的良好契机。评审代码的时候一般会有一个评审者和一个原作者,在极限编程中叫做“结对编程”,在这种讨论的场景下,我们更容易跳出程序细节,从整体设计和可读性上审视代码。

何时不该重构

如果代码过于混乱,甚至根本没有办法正常运行,这个时候与其花大力气重构,倒不如重写来的快。

一个折中的方法是,将大的软件系统拆成多个子模块或子系统,然后分别对这些子模块或子系统进行重构或重写。

还有一个情况是当项目工期临近终点的时候,如果时间来不及重构应该优先保证项目进度。

我们常常把待重构的任务称为“技术债务”。类比现实生活中的债务,一个公司难免会有债务,而债务是要偿还的。当一个公司财务状况良好的时候,应该让自己的债务保持在一个健康的水平。但是当一个公司陷入泥潭,需要资金救急的时候,如果它手里有一笔钱,相比于还债,这笔钱更应该花在保证公司生存的事务上。

重构的难题

重构数据库
重构经常出问题的一个领域就是数据库。绝大多数程序都与它背后的数据库结构紧密耦合在一起,甚至还涉及到数据迁移,这都是数据结构如此难以重构的原因。

在非对象数据库中,解决这个问题的方法之一就是在对象模型和数据库模型之间插入一个分隔层。升级某个模型只需要修改分隔层即可,不需要改另一个模型。分割层会增加系统复杂度,但是可以也可以带来很大的灵活度。

重构接口

许多重构都需要修改接口,如果某个接口的调用者都在你的控制之下,那么修改接口就相对较为简单。

但是大多数情况下,你都需要维护新旧两个接口。

明天价值

程序的价值分为两个方面,即“今天能为你做什么”和“今后能为你做什么”。我们常常只关注前者,这就造成了程序“我今天能为你工作,明天我将完全无法胜任工作”的困境。

需要重构的代码往往都是难以修改的:

1、难以阅读。
2、逻辑重复。
3、添加新的行为需要修改已有代码。
4、带有复杂条件逻辑。

重构以后的代码需要达到的目标是:

1、容易阅读。
2、相同的逻辑只出现一次。
3、新的改动不会危及现有行为。
4、尽可能简单地表达条件逻辑。

性能提升

对于大多数程序而言,超过大半的时间都花费在一小半代码上。如果你要提高程序的性能,如果把时间花在那些不经常运行的代码上,对提高程序的整体性能影响不大。因此,重构要着重修改耗时最多的代码。

相关文章:

  • Restyle起来!
  • 【Unity3D日常BUG】Unity3D中出现“unsafe code 不安全的代码”的错误时的解决方法
  • Node中实现一个简易的图片验证码流程
  • java-Lambda表达式
  • Robotics System Toolbox中的机器人运动(7)--RRT规划避障路径
  • 和一个海归的博士聊人生
  • 移动端布局介绍——css像素/物理像素/设备像素比
  • redis简介及八种数据类型
  • GAN Step By Step -- Step1 GAN介绍
  • vue纯前端结合css动画实现模拟导航效果
  • 【数据增强】90°、180°和270°翻转图片(*4)
  • 【Hadoop---07】HDFS 读 / 写 数据流程(面试重点)
  • 【笔记】C#得到真正的屏幕大小
  • SSH远程端口转发
  • 微信支付配置信息如何获取
  • emacs初体验
  • HTTP--网络协议分层,http历史(二)
  • java8-模拟hadoop
  • Linux链接文件
  • 爬虫模拟登陆 SegmentFault
  • 前嗅ForeSpider教程:创建模板
  • Unity3D - 异步加载游戏场景与异步加载游戏资源进度条 ...
  • 通过调用文摘列表API获取文摘
  • # Maven错误Error executing Maven
  • $.type 怎么精确判断对象类型的 --(源码学习2)
  • ( 10 )MySQL中的外键
  • (06)Hive——正则表达式
  • (6)STL算法之转换
  • (带教程)商业版SEO关键词按天计费系统:关键词排名优化、代理服务、手机自适应及搭建教程
  • (二)springcloud实战之config配置中心
  • (三)mysql_MYSQL(三)
  • (学习日记)2024.04.04:UCOSIII第三十二节:计数信号量实验
  • (转)http-server应用
  • *_zh_CN.properties 国际化资源文件 struts 防乱码等
  • .md即markdown文件的基本常用编写语法
  • .Net FrameWork总结
  • .net 发送邮件
  • .net 获取url的方法
  • .NET中统一的存储过程调用方法(收藏)
  • .sh 的运行
  • @autowired注解作用_Spring Boot进阶教程——注解大全(建议收藏!)
  • [Android Studio] 开发Java 程序
  • [AndroidStudio]_[初级]_[修改虚拟设备镜像文件的存放位置]
  • [C#]C# winform部署yolov8目标检测的openvino模型
  • [C++] 如何使用Visual Studio 2022 + QT6创建桌面应用
  • [CVPR 2023:3D Gaussian Splatting:实时的神经场渲染]
  • [Grafana]ES数据源Alert告警发送
  • [hdu 4552] 怪盗基德的挑战书
  • [hive] posexplode函数
  • [INSTALL_FAILED_TEST_ONLY],Android开发出现应用未安装
  • [java] 23种设计模式之责任链模式
  • [LeetCode] 596:超过5名学生的课
  • [leetcode]Search a 2D Matrix @ Python
  • [MAT]使用MAT比較多个heap dump文件
  • [Python] 字典操作及方法总结