CH02_重构的原则(什么是重构、为什么重构、何时重构)

什么是重构

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

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

重构的关键在于运用大量微小且保持软件行为的步骤,一步步达成大规模的修改。每个单独的重构要么很小,要么由若干小步骤组合而成。

可观察行为:整体而言,经过重构之后的代码所做的事应该与重构之前大致一样。

重构与性能优化有很多相似之处:两者都需要修改代码,并且两者都不会改变程序的整体功能。两者的差别在于其目的:重构是为了让代码“更容易理解,更易于修改”。这可能使程序运行得更快,也可能使程序运行得更慢。在性能优化时,只关心让程序运行得更快,最终得到的代码有可能更难理解和维护。

两顶帽子

这是一个比喻,使用重构技术开发软件时,我把自己的时间分配给两种截然不同的行为:添加新功能和重构。添加新功能时,我们不应该修改既有代码,只管添加新功能。重构时我们就不饿能添加功能,只管调整代码的结构。

实际开发过程中,我们可能需要经常变换帽子。如果把程序结构改一下,功能的添加会容易得多;新功能添加好了以后发现代码难以理解,则继续重构。

为何重构

我们之所以重构,因为它能让我们更快——添加功能更快,修复bug更快。

重构改进软件的设计

没有重构,程序的内部设计(架构)会逐渐腐败变质。当人们只为短期目的而修改代码时,他们经常没有完全理解架构的整体设计,于是代码逐渐失去了自己的结构。程序员越来越难通过阅读源码来理解原来的设计。

经常性的重构有助于代码维持自己该有的形态。

重构使软件更容易理解

写让计算机理解的代码很容易,只要能编译通过并运行;但写出让别人能理解的代码则需要下点功夫了。所以我们写代码要考虑以后那个修改的人,而且那个人很可能是哦我们自己。

开始进行重构前,代码可以正常运行,但结构不够理想。在重构上花一点点时间,就可以让代码更好地表达自己的意图。

重构帮助找到Bug

对代码进行重构,就可以深入理解代码的所作所为,并立即把新的理解反映在代码当中。搞清楚程序结构的同时,也验证了所做的一些假设, 更容易将Bug找出来。重构能够帮助我们更有效地写出健壮的代码。

重构提高编程速度

设计耐久性假说:通过投入精力改善内部设计,我们增加了软件的耐久性,从而可以更长时间地保持开发的快速。

在这里插入图片描述

行业的陈规认为:良好的设计必须在开始编程之前完成,因为一旦开始编写代码,设计就只会逐渐腐败。重构改变了这个图景。现在我们可以改善已有代码的设计,因此我们可以先做一个设计,然后不断改善它,哪怕程序本身的功能也在不断发生着变化。由于预先做出良好的设计非常困难,想要既体面又快速地开发功能,重构必不可少。

何时重构

三次法则

  • 第一次做某件事时只管去做
  • 第二次做类似的事会产生反感,但无论如何还是可以去做
  • 第三次再做类似的事,你就应该重构。

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

重构的最佳时机就在添加新功能之前。例如有个函数提供了我们需要的大部分功能,只是有几个变量跟我们需要的冲突,通常我们的做法使把这个函数复制过来,修改几个值。这样做会导致重复代码(将来有可能需要修改两处)。使用函数参数化(310)进行重构后,只需要调用这个函数,传入需要的参数。

修复bug时的情况也是一样。在寻找问题根因时,可能会发现:如果把3段一模一样且都会导致错误的代码合并到一处,问题修复起来会容易得多。

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

重构带来的帮助不仅发生在将来——常常是立竿见影。先在一些小细节上使用重构来帮助理解,给一两个变量改名,让它们更清楚地表达意图,以方便理解,或是将一个长函数拆成几个小函数。当代码变得更清晰一些时就会看见之前看不见的设计问题。

捡垃圾式重构

帮助理解的重构还有一个变体:已经理解代码在做什么,但发现它做得不好,例如逻辑不必要地迂回复杂,或者两个函数几乎完全相同,可以用一个参数化的函数取而代之。有两种处理方式:如果垃圾很容易重构,马上重构它;如果重构需要花一些精力,记录下来,完成当下的任务再回来重构它。

有计划的重构

一般项目计划上没有专门留给重构的时间,绝大多数重构都在做其他事的过程中自然发生。如果团队过去忽视了重构,那么常常会需要专门花一些时间来优化代码库,以便更容易添加新功能。

长久以来,人们认为编写软件是一个累加的过程:要添加新功能,我们就应该增加新代码。但优秀的程序员知道,添加新功能最快的方法往往是先修改现有的代码,使新功能容易被加入。所以,软件永远不应该被视为“完成”。每当需要新能力时,软件就应该做出相应的改变。越是在已有代码中,这样的改变就越显重要。

何时不应该重构

如果有一块凌乱的代码,但并不需要修改它,那么就不需要重构它。如果丑陋的代码能被隐藏在一个API之下,暂时容忍它继续保持丑陋。只有当需要理解其工作原理时,对其进行重构才有价值。

另一种情况是,如果重写比重构还容易,就别重构了。

重构的挑战

延缓新功能开发

很多人认为,花在重构的时间是在拖慢新功能的开发进度。“重构会拖慢进度”这种看法仍然很普遍,这可能是导致人们没有充分重构的最大阻力所在。

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

有一种情况确实需要权衡取舍:有时会看到一个(大规模的)重构很有必要进行,而马上要添加的功能非常小,这时可以先把新功能加上,然后再做这次大规模重构。

测试

如果开发环境(开发工具)能很好的支持自动化重构,则可以信任这些重构;如果不能最好有完备的测试套件(测试环境、测试代码、单元测试等)。

遗留代码

遗留代码往往很复杂,可能也没有充足的测试,关键还是别人写的。如果不幸遇到,没有什么好办法:没测试就加测试、随时重构相关的代码(不建议尝试一鼓作气把复杂而混乱的遗留代码重构成漂亮的代码)。

重构、架构和YAGNI

YAGNI:“你不需要它(you are`t going to need it)”。YAGNI并不是“不做架构性思考”的意思,不过确实有人以这种欠考虑的方式做事。

重构对架构最大的影响在于,通过重构,我们能得到一个设计良好的代码库,使其能够优雅地应对不断变化的需求。“在编码之前先完成架构”这种做法最大的问题在于,它假设了软件的需求可以预先充分理解。但经验显示,这个假设很多时候甚至可以说大多数时候是不切实际的。只有真正使用了软件、看到了软件对工作的影响,人们才会想明白自己到底需要什么。

重构与软件开发过程

重构是否有效,与团队采用的其他软件开发实践紧密相关。

重构的第一块基石是自测试代码。

如果一支团队想要重构,那么每个团队成员都需要掌握重构技能,能在需要时开展重构,而不会干扰其他人的工作。

自测试代码、持续集成、重构三者之间有着很强的协同效应。

重构与性能

重构可能使软件运行更慢,但它也使软件的性能优化更容易。先写出可调优的软件,然后调优它以求获得足够的速度。

编写构造良好的程序,不对性能投以特别的关注,直至进入性能优化阶段——那通常是在开发后期。一旦进入该阶段,再遵循特定的流程来调优程序性能。

在性能优化阶段,首先应该用一个度量工具来监控程序的运行,让它告诉我程序中哪些地方大量消耗时间和空间。这样就可以找出性能热点所在的一小段代码。然后集中关注这些性能热点,并使用持续关注法中的优化手段来优化它们。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/100337.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ThinkPHP6.0+ 使用Redis 原始用法

composer 安装 predis/predis 依赖&#xff0c;或者安装php_redis.dll的扩展。 我这里选择的是predis/predis 依赖。 composer require predis/predis 进入config/cache.php 配置添加redis缓存支持 示例&#xff1a; <?php// -----------------------------------------…

【RabbitMQ】RabbitMQ整合SpringBoot案例

文章目录 1、前情提要【RabbitMQ】2、RabbitMQ-SpringBoot案例 -fanout模式2.1 实现架构总览2.2 具体实现2.2.1生产者2.2.1消费者 1、前情提要【RabbitMQ】 【RabbitMQ】消息队列-RabbitMQ篇章 RabbitMQ实现流程 2、RabbitMQ-SpringBoot案例 -fanout模式 2.1 实现架构总览…

Allegro如何设置Net Class在物理和间距规则中同步操作指导

Allegro如何设置Net Class在物理和间距规则中同步操作指导 在用Allegro设置规则的时候,设置net class是必要的操作,时常需要在物理和间距规则都设置好Class,如果物理和间距规则中都单独去设置的话比较费时间。如下图Net Class 下面介绍如何将物理和间距规则中的Class同步起来…

jsp 协同过滤 图书管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 协同过滤 图书管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境 为TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为My…

docker限制容器日志大小

文章目录 业务场景问题排查彻底解决 业务场景 我们公司做交通相关业务&#xff0c;我们部门主要负责信控服务&#xff0c;卖信号机的硬件产品和配套的信控平台 由于有部分小项目&#xff0c;可能只有几十个路口&#xff0c;客户预算有限&#xff0c;只给我们老旧的Windows ser…

Handler及相关的理论知识

前言 学安卓的都接触过Handler&#xff0c;许多老java项目中也有很多使用Handler进行网络通讯&#xff0c;或许现在我们都用kotlin&#xff0c;用协程&#xff0c;但咱也不能就把Handler忘了&#xff0c;本篇文章特此巩固Handler相关知识 是什么 Handler主要用于异步消息的处…

SCSS 学习笔记 和 vscode下载live sass compiler插件配置

1、下载livelive sass compiler插件并配置 // 在 已有代码 下面 添加下面 代码&#xff0c;一般刚刚下载打开最后一行是&#xff1a;// "liveSassCompile.settings.autoprefix": [],// 所以直接 把下面复制进去保存就行"liveSassCompile.settings.autoprefix&qu…

Ubuntu本地快速搭建web小游戏网站,并使用内网穿透将其发布到公网上

文章目录 前言1. 本地环境服务搭建2. 局域网测试访问3. 内网穿透3.1 ubuntu本地安装cpolar内网穿透3.2 创建隧道3.3 测试公网访问 4. 配置固定二级子域名4.1 保留一个二级子域名4.2 配置二级子域名4.3 测试访问公网固定二级子域名 前言 网&#xff1a;我们通常说的是互联网&am…

MySQL的基础操作

前言 对MySQL的一些基础操作做一下学习性的总结&#xff0c;基本上是照着视频写的。 MySQL的安装 MySQL的下载 MySQL :: Download MySQL Community Server (Archived Versions)https://downloads.mysql.com/archives/community/ 配置环境变量 下载之后直接解压&#xff0c…

IDEA启动报错【java.sql.SQLSyntaxErrorException: ORA-00904: “P“.“PRJ_NO“: 标识符无效】

IDEA报错如下&#xff1a; 2023-08-17 11:26:15.535 ERROR [egrant-biz,b48324d82fe23753,b48324d82fe23753,true] 24108 --- [ XNIO-1 task-1] c.i.c.l.c.RestExceptionController : 服务器异常org.springframework.jdbc.BadSqlGrammarException: ### Error queryin…

Vue前端封装一个任务条的组件进行使用

任务条 样式 代码 父组件 <articleSteps :tabs"tabs" :tabs-active-name"tabsActiveName" /><div class"drawer__footer"><el-button v-if"tabsActiveName 1 || tabsActiveName 2" click"backClick">…

【3Ds Max】可编辑多边形“边”层级的简单使用

目录 简介 示例 1. 编辑边 &#xff08;1&#xff09;插入顶点 &#xff08;2&#xff09;移除 &#xff08;3&#xff09;分割 &#xff08;4&#xff09;挤出 &#xff08;5&#xff09;切角 &#xff08;6&#xff09;焊接 &#xff08;7&#xff09;桥 &…

1.jvm和java体系结构

jvm简介 JVM&#xff1a;跨语言的平台 Java是目前应用最为广泛的软件开发平台之一。随着Java以及Java社区的不断壮大Java 也早已不再是简简单单的一门计算机语言了&#xff0c;它更是一个平台、一种文化、一个社区。 ● 作为一个平台&#xff0c;Java虚拟机扮演着举足轻重的…

前端(十三)——JavaScript 闭包的奥秘与高级用法探索

&#x1f636;博主&#xff1a;小猫娃来啦 &#x1f636;文章核心&#xff1a;深入理解 JavaScript 中的闭包 文章目录 不理解闭包&#xff1f;这玩意很难&#xff1f;闭包的定义与原理闭包是什么创建一个闭包 闭包的应用场景闭包与作用域闭包与作用域之间的关系全局作用域、函…

【CHI】(十三)链路层

本章介绍了链路层&#xff0c;链路层为节点之间的基于数据包的通信和跨链路的互连提供了一种简化的机制。它包含以下几部分&#xff1a; IntroductionLinkFlitChannelPortNode interface definitionsIncreasing inter-port bandwidthChannel interface signalsFlit packet defi…

视频汇聚/视频云存储/视频监控管理平台EasyCVR添加萤石云设备详细操作来啦!

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安…

juc概述和Lock接口

目录 一、什么是JUC 1、JUC概述 2、进程与线程 3、线程的状态 4、wait/sleep 的区别 5、并发与并行 6、管程 7、用户线程和守护线程 二、Lock接口 1、Synchronized 使用synchronized实现售票案例 使用synchronized实现增减变量操作 2、什么是 Lock 买票例子使用lo…

CST HFSS MATLAB参数方程定义曲面绘制

CST HFSS 函数定义曲面绘制 简介环境HFSSCSTMATLAB 简介 若在柱坐标系中半径r随z和phi都会变&#xff0c;无法使用一般的方法绘制&#xff0c;这时可以使用参数方程定义的曲面来绘制。举一个例子如下&#xff0c; r 100 0.5 ( c o s ( 0.2 ∗ p i ∗ z ) − 1 ) c o s ( φ …

定位服务器CPU爆满的具体原因

1、查询CPU消耗的进程 使用top命令查看系统的CPU和内存使用情况 CPU一列是线程占用百分比 2、具体查看某个占分比大的进程 以为PId:7355为例&#xff0c; 执行top -Hp 7355&#xff0c;线程按照CPU使用率排序。 3、将线程PID转化为16进制 执行printf %x 7391&#xff0c;将…

论文阅读 - Understanding Diffusion Models: A Unified Perspective

文章目录 1 概述2 背景知识2.1 直观的例子2.2 Evidence Lower Bound(ELBO)2.3 Variational Autoencoders(VAE)2.4 Hierachical Variational Autoencoders(HVAE) 3 Variational Diffusion Models(VDM)4 三个等价的解释4.1 预测图片4.2 预测噪声4.3 预测分数 5 Guidance5.1 Class…