重构·改善既有代码的设计.01

news/2024/9/17 13:40:17/
  1. 前言

近期在看Martin Fowler著作的《重构.改善既有代码的设计》这本书,这是一本经典著作。书本封面誉为软件开发的不朽经典。书中从一个简单的案例揭示了重构的过程以及最佳实践。同时给出了重构原则,何时重构,以及重构的手法。用来改善既有代码的设计,提升软件的可维护性。

这里会对本书持续进行阶段性总结,希望自己能够从中学习到精髓。

  1. 什么是重构

书中提到,所谓重构(refactoring)是这样一个过程:在不改变代码外在行为的前提下,对代码做出修改,以改进程序的内部结构。

通常一个系统的第一个版本会经过很大很精细的设计,且会遵循先设计后编码的开发流程。但是随着时间的流逝,人们会不断的修改代码。中间随着人员的流动,项目业务性质的变化......,如果按照原先设计所得系统,整体结构会逐渐衰弱,或者说渐渐偏离起初的设计。这样,编码工作就会从一开始的严谨逐渐堕落为胡砍乱劈的随性。

书中提到重构的2层含义:

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

当我们在重构软件时,经常会把时间分配给两种截然不同的行为:

  1. 添加新功能

  1. 重构

添加新功能时,你不应该修改既有的代码,只管添加新功能。编写测试,你可以衡量自己的工作进度。

重构时,你就不能再添加新功能,只管改进程序结构,此时不应该添加任何的测试,只在绝对必要时才修改测试。

但是往往我们在开发过程中,会发现要经常变换帽子。首先你会尝试添加新功能,然后意识到:如果把程序结构改一下,功能添加会容易很多。于是乎,你就换了一定帽子,做一会重构工作。等程序结构调整好后,你又换上原先的帽子继续添加新功能......但无论何时,你都应该清楚知道自己戴的是哪顶帽子。

  1. 为何重构

  1. 重构改进软件设计

当人们只为短期目的,或是在完全理解整体设计之前,就贸然修改代码,程序会逐渐失去自己的结构,程序员越来越难通过阅读源码而理解原来的设计。重构很像是在整理代码,你所做的就是让后所有的东西回到应处的位置上。

代码结构的流失是累积性的,越难看出代码所代表的设计意图,就越难保护其中的设计,于是该设计就腐败的越快。经常性的重构可以帮助代码维持自己该有的形态。

因此改进设计的一个重要方向就是:消除重复代码

  1. 重构使软件更容易理解

一般情况下,我们所编写的代码告诉计算机要做什么事,他的响应则是精确按照你的指示行动。但是除了计算机外,你的源码还有其他读者:几个月后可能会有另一位程序员尝试读懂你的代码并尝试做一些修改。

通常,当你努力的让程序正常运转的时候,很容易忘记第二位读者,但是未来出现的读者(开发者)才是最重要的。计算机多花了几个小时编译,又有什么关系呢?如果一个程序员花一周的时间修改代码,这才要命。有可能理解了你的代码之后,真正的修改只需一个小时。

所以我们应该改变一下开发节奏,对代码适当进行修改,让代码变得更容易理解。这种编程模式的核心就是“准确说出我所要的”。

  1. 重构帮助找到bug

对代码进行重构,可以深入理解代码的作为,并恰到好处的把新的理解反馈回去。搞清楚程序结构的同时,也清楚了自己所作的一些假设,于是想不把bug揪出来都很难。

  1. 重构提高编程速度

良好的设计是快速开发的根本,事实上,拥有良好的设计才可以做到快速开发。

如果没有好的设计,或者在起初阶段,你的进展会很迅速。但是缺乏设计(或恶劣的设计)很快会让你的速度慢下来。你会把时间花在调试上,无法添加新功能。修改时间越来越长,因为你必须花越来越多的时间去理解系统、寻找重复代码。各种打补丁,新特性需要更多的代码才能实现,一直恶性循环下去。

所以前面的一些都归结到这一点:重构帮助你更快速的开发程序

  1. 何时重构

  1. 三次法则

书中提到了Don Roberts提出的准则:

  • 第一次做某件事,只管去做;

  • 第二次做类似的事情会产生反感,但无论如何还是可以去做;

  • 第三次做类似的事,你就应该重构。

事不过三,三则重构
  1. 添加功能时重构

这里,重构的一个原动力是:代码的设计无法帮助我轻松和那个添加所需要的特性。然后对自己说:“如果用某种方式设计,添加特性会简单很多。”这么做的部分原因是为了让未来增加新特性时能够更轻松一些。

  1. 修补错误时重构

调试过程中运用重构,多半是为了让代码更具可读性。如果收到一份错误报告,这就是需要重构的信号,因为显然代码还不够清晰,至少没有清晰到让你能一眼看出bug。

  1. 复审代码时重构

极限编程[XP]中的“结对编程”形式,把代码复审的积极性发挥到了极致。一旦采用这种形式,所有正式开发任务都由2名开发者在同一台机器上进行,这样便在开发过程中形成随时进行的代码复审工作,而重构也被包含在开发过程中了。

  1. 何时不该重构

1、代码根本无法工作,或太糟糕。代码重构还不如重写来的简单;
2、在项目的最后期限,应该避免重构。

小结

到此,刚看完整本书的2个章节。重构和设计模式等诸多思想一样,是需要反复学习,反复实践的。重构的技术就是以微小的步伐修改程序。希望真正吸收这些之后,能够看到一个不一样的代码世界。借此,共勉~

1、如果发现自己需要为程序添加一个特性,而代码结构使得你无法很方便地达成目的,那么就需要重构那个程序了。使特性的添加比较容易进行,然后再添加特性。
2、代码块越小,代码的功能就越容易管理,代码的处理和移动也就越轻松。
3、代码应该表现自己的目的。任何一个人都能写出计算机可以理解的代码,唯有写出人类容易理解的代码,才是优秀程序员。

后续阶段性阅读该书后,会持续更新中......


http://www.ppmy.cn/news/30022.html

相关文章

【微信小程序】-- 案例 - 本地生活(二十)

💌 所属专栏:【微信小程序开发教程】 😀 作  者:我是夜阑的狗🐶 🚀 个人简介:一个正在努力学技术的CV工程师,专注基础和实战分享 ,欢迎咨询! &…

【springcloud 微服务】Spring Cloud Alibaba 整合Nacos实战

目录 一、前言 二、常用服务注册中心介绍 2.1 dubbo服务注册示意图 2.2 常用注册中心对比 三、nacos介绍 3.1 什么是nacos 3.2 nacos 特点 3.3 nacos生态链地图 四、nacos部署 4.1 下载安装包 4.2 修改脚本启动模式 4.3 启动nacos 服务 五、Spring Cloud Alibaba…

刷题记录:CF1285D Dr. Evil Underscores 区间异或使序列最大值最小

传送门:CF 题目描述: 有一个长度为 n(1≤n≤105)n\ (1\leq n\leq 10^5)n (1≤n≤105) 的整数序列 a1,⋯,an(0≤ai≤230−1)a_1,\cdots,a_n\ \ (0\leq a_i\leq 2^{30}-1)a1​,⋯,an​ (0≤ai​≤230−1),你需要找到一个非负整数 XXX 使得 max⁡(ai⊕X)\max(a_i\op…

【python】JSON数据类型与Python数据类型之间的转化

注:最后有面试挑战,看看自己掌握了吗 文章目录JSON格式文件JSON格式序列化与反序列化作用JSON常用数据结构键值对的集合值的有序列表JSON数据类型与Python数据类型之间的转化JSON格式和python的区别读写json文件dump 把python 写到json文件load 把json写…

C语言刷题(4)——“C”

各位CSDN的uu们你们好呀,今天小雅兰的内容又到了我们的复习啦,那么还是刷题噢,话不多说,让我们进入C语言的世界吧 BC55 简单计算器 BC56 线段图案 BC57 正方形图案 BC58 直角三角形图案 BC59 翻转直角三角形图案 BC60 带空格…

蚁群算法优化问题

%%%%%%%%%%%%蚁群算法解决 TSP 问题%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%初始化%%%%%%%%%%%%%%%%%%% clear all; %清除所有变量 close all; %清图 clc; %清屏 m 50; %蚂蚁个数 Alpha 1; %信息素重要程度参数 Beta 5; %启发式因子重要程度参数 Rho 0.1; %信息素蒸发系数 G 20…

嵌入式学习笔记——STM32硬件基础知识

STM32开发硬件知识前言STM32最小系统电源电路晶振电路复位电路BOOT选择电路调试接口电路其他电路本文重点本文参考博客链接前言 上一篇中我们重点是讲了一下怎么搭建开发环境以及怎么下载烧录的过程,这都是解决的电脑端的开发环境问题,还没有到实际的开…

【C++初阶】list的使用

大家好我是沐曦希💕 文章目录一、前言二、构造三、迭代器四、增删查改1.头插头删2.尾插尾删3.查找和插入4.删除五、其他成员函数1.排序和去重2.splice和remove3.resize一、前言 list本质是带头双向循环链表,本文只对list的一些常用接口进行说明&#xf…

用逻辑回归制作评分卡

目录 一.评分卡 二.导库,获取数据 三.探索数据与数据预处理 1.去除重复值 2.填补缺失值 3.描述性统计处理异常值 4.为什么不统一量纲,也不标准化数据分布 5.样本不均衡问题 6.分训练集和测试集 三.分箱 1.分多少个箱子才合适 2.分箱要达成什么…

真香,Grafana开源Loki日志系统取代ELK?

一、Loki是什么? Loki是由Grafana Labs开源的一个水平可扩展、高可用性,多租户的日志聚合系统的日志聚合系统。它的设计初衷是为了解决在大规模分布式系统中,处理海量日志的问题。Loki采用了分布式的架构,并且与Prometheus、Graf…

51单片机入门————数码管显示

我们在马路上看到的红绿灯,就是由数码管来实现的,就是其中可能加入了一些延时和转换数码管是通过控制138译码器与74HC245来控制数码管的亮灭与数字的显示电路原理图我们先讨论一个数码管数码管有共阳极和共阴极,我们现在使用的STC89C52是共阴…

Linux用户空间与内核空间通信(Netlink通信机制)

一,什么是Netlink通信机制 Netlink是linux提供的用于内核和用户态进程之间的通信方式。但是注意虽然Netlink主要用于用户空间和内核空间的通信,但是也能用于用户空间的两个进程通信。只是进程间通信有其他很多方式,一般不用Netlink。除非需要…

Cadence Allegro 导出Bill of Material Report (Condensed)详解

⏪《上一篇》   🏡《总目录》   ⏩《下一篇》 目录 1,概述2,Bill of Material Report (Condensed)作用3,Bill of Material Report (Condensed)示例4,Bill of Material Report (Condensed)导出方法4.1,方法14.2,方法2,

第十三届蓝桥杯

这里写目录标题一、刷题统计(ceil函数返回的是等值于某最小整数的浮点值,不强制转换回int就wa,没错就连和int整数相加都wa二、修剪灌木(主要应看清楚会调转方向三、统计子矩阵(前缀和滑动窗口⭐)四、[积木画…

十大经典排序算法【快速了解】

文章目录一、算法分类二、经典排序算法总览三、算法复杂度四、代码实现一、算法分类 十种常见排序算法可以分为两大类: 比较类排序: 通过比较来决定元素间的相对次序由于其时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排序。 非…

xgboost: 分割查找算法:贪婪算法、分桶算法

1、Basic Exact Greedy Algorithm 树学习的关键问题之一是找到最好的分割,如Eq(7)所示。 贪婪算法:分割查找算法枚举所有特征上的所有可能的分割。精确的贪婪算法如Alg. 1所示。为了高效地完成这一任务,算法必须首先根据特征值对数据进行排序&#xff…

配置本地 python GEE、geemap环境

1.安装anconda 百度搜索anconda清华镜像,从清华镜像中选择最新的anconda安装包,国内镜像网站下载速度较快,如果从国外官网下载速度相当慢,详细安装教程请参考: anconda安装教程https://blog.csdn.net/lwbCUMT/article…

MyBatis高频面试专题

一、介绍下MyBatis中的工作原理 1。介绍MyBatis的基本情况:ORM 2。原理: MyBatis框架的初始化操作处理SQL请求的流程 1.系统启动的时候会加载解析全局配置文件和对应映射文件。加载解析的相关信息存储在 Configuration 对象 Testpublic void test1(…

JavaScript(JS)

一、三种引入方式&#xff1a; 1、内部js 通过script标签嵌入到html里面 <script>alert(hello);</script> 2、外部js 写成一个单独的.js文件&#xff0c;让html引入进来 <script src"app.js"></script> 3、行内js 直接写到html内部 &…

SpringMVC文件上传、下载、国际化配置

Java知识点总结&#xff1a;想看的可以从这里进入 目录3.6、文件上传、下载3.6.1、文件上传3.6.2、文件下载3.7、国际化配置3.6、文件上传、下载 3.6.1、文件上传 form 表单想要具有文件上传功能&#xff0c;其必须满足以下 3 个条件。 form 表单的 method 属性必须设置为 p…