设计模式学习笔记 - 规范与重构 - 1.什么情况下要重构?重构什么?又该如何重构?

简述

“重构” 这个词大家都不陌生,但是 “听得多做得少”,真正进行过代码重构的人少之又少。

  • 一方面,重构代码对一个工程师能力的要求,要比单纯写代码高的多。重构需要你能洞察出代码存在的坏味道或设计上的不足,并且合理、熟练地利用设计思想、原则、模式、编程规范等理论知识解决这些问题。
  • 另一方面,很多人对为什么要重构、重构什么、什么时候重构、又该如何重构等相关问题理解不深,对重构没有系统性、全面的认识,面对一堆烂代码,没有重构技巧的指导,只能想到哪里改哪里,并不能全面的改善代码质量。

本节先学习,重构的目的、对象、时机和方法。


重构的目的:为什么要重构(why)

软件设计大师 Martin Fowler 是这样定义重构的:“重构是一种对软件内部结构的改善,目的是在不改变软件的可见行为的情况下,使其更易理解,修改成本更低。”

这个定义中有一个值得强调的点:“重构不改变外部的可见行为”。我们可以理解为,在保持功能不变的情况下,利用设计思想、原则、模式、编程规范等理论来优化代码,修改设计上的不足,提高代码质量。

简单了解重构的定义之后,我们看下为什么要进行重构?

  • 首先,重构是保证代码质量的一个极其有效的手段,不至于让代码腐化到无可救药的地步。项目在演进,代码不停地在堆砌。如果没有人为代码的质量负责任,代码总是会往越来越混乱的方向演进。当混乱到一定程度之后,量变引起质变,项目的维护成功已经搞过重新开发一套新代码的成本,想要再去重构,已经没有人能做到了。
  • 其次,优秀的代码或架构不是一开始就能完全设计好的。我们无法 100% 预见未来的需求,也没有足够经理、时间、资源为遥远的未来买单,所以,随着系统的演进,重构代码也是不可避免的。
  • 最后,重构是避免过度设计的有效手段。在我们维护代码的过程中,真正遇到问题的时候,再对代码进行重构,能有效避免前期投入太多时间做过度设计,做到有的放矢。

此外,重构对一个对工程师本身技术的成长也有重要的意义

从重构的定义来看,重构实际上是对我们学习经典的设计思想、设计原则、设计模式、编程规范的一种运用。重构可以让这些理论知识,应用实践的一个很好的场景,能够锻炼我们熟练使用这些理论知识的能力。此外,平时对其业务逻辑,你可能觉得没啥成长,而将一个烂代码重构成一个比较好的代码,会让进很有成就感。

重构能力也是衡量一个工程师代码能力的有效手段。所谓 “初级工程师在维护代码,高级工程师在设计代码,资深工程师在重构代码”。

当然,这里的初级、高级、资深只是一个相对概念,并不是一个确定的职级。

重构的对象:到底重构什么(what)?

根据重构的规模,我们可以笼统地分为大规模高层次重构(大型重构)和小规模低层次的重构(小型重构)。

  • 大型重构指的是对顶层代码设计的重构,包括:系统、模块、代码结构、类与类之间的关系的重构重构的手段有:分层、模块化、解耦、抽象可复用组件等等。这类重构的工具就是我们学习过的那些设计思想、原则和模式。这类重构涉及的代码改动会比较多,影响面会比较大,所以难度也较大,耗时会较长,引入 Bug 的风险也相对比较大。
  • 小型重构指的是对代码细节的重构,主要是针对类、函数、变量等代码级别的重构,比如规范命名、规范注释、消除超大类或函数、提取重复代码等等。小型重构更多的是利用“编码规范”(后面会讲)。这类重构要需要修改的地方比较集中,比较简单,可操作性较强,耗时会比较短,引入 bug 的风险相对来说也会比较小。只要熟练掌握各种编码规范,就可以做到得心应手。

重构的时机:什么时候重构(when)?

什么时候重构呢?

是等代码烂到一定程度之后才去重构吗?
当然不是。因为代码真的烂到 开发效率低,招了很多人天天加班,出活却不多,线上 bug 频发,领导发飙,中层束手无策,工程师抱怨不断,查找 BUG 困难 的时候,基本上重构也无法解决问题了。

我个人比较反对,平时不注重代码质量,堆砌烂代码,实在维护不了了就大刀阔斧地重构、甚至重写的行为。有时候项目代码太多了,重构很难做的彻底,最后又搞出一个四不像,这就更麻烦了。所以,寄希望于代码烂到一定程度之后,集中重构解决所有问题是不现实的,我们必修探索一条可持续、可演进的方式。

所以,提倡持续重构。平时没有事情的时候,你可以看看项目中有哪些写得不够好的、可以优化的代码,主动去重构以下。或者,在修改、添加某个功能代码的时候,你也可以顺手把不符合编码规范、不好的设计重构一下。总之,就像把单元测试、CodeReview 作为开发的一部分,我们如果能把持续重构也作为开发的一部分,成为一种开发习惯,对项目、对自己都会很有好处。

尽管重构能力很重要,但持续重构意识更重要。要正确看待代码质量和重构这件事情。技术在更新、需求在变化、人员在变动,代码质量总会在下降,代码总会存在不完美,重构就会持续进行。时刻具有重构意识,才能避免开发前期过度设计,避免代码维护的过程中质量下降。而那些看到别人代码有点瑕疵就一段乱骂,或者花尽心思去构思一个完美设计的人,往往都是因为没有树立正确的代码质量观,没有持续重构意识。

重构的方法:又该如何重构(how)?

前面讲过,按照重构的规模,重构可以分为大型重构和小型重构。对于这两种不同的重构规模,我们要区别对待。

对于大型重构来说,因为涉及模块、代码比较多,此时如果项目代码质量又比较差,耦合严重,往往会牵一发而动全身,本来觉得一天就能完成的重构,你会发现越改越多、越改越乱,没一两个礼拜都搞不定。而新的业务开发又与重构相冲突,最后只能半途而废,revert 掉所有的改动,很失落地又去堆砌烂代码了。

在进行大型重构时,我们要提前做好完善的重构计划,有条不紊地分阶段来进行。每个阶段完成一小部分代码的重构,然后提交、测试、运行,发现没有问题之后,再继续进行下一阶段的重构,保证代码仓库中的代码一直处于可运行、逻辑正确的状态。每个阶段,我们都要控制好重构影响的代码范围,考虑好如何兼容老的代码逻辑,必要的时候还需要写一些兼容过度代码。只有这样,我们才能让每一阶段的重构都不至于耗时太长(最好一天能完成),不至于与新的功能开发相冲突。

大规模高层次的重构一定是有组织、有计划,并且非常谨慎的,需要有经验、熟悉业务的资深同事来主导

小规模低层次的重构,因为影响范围小,改动耗时短,所以,只要你愿意并且有时间,随时可以去做

实际上,除了人工去发现低层次的质量问题,我们还可以借助很多成熟的静态代码分析工具(比如 CheckStyle、FindBugs、PMD),来自动发现代码中的问题,然后针对性地进行重构优化。

对于重构这件事情,资深的工程师、项目 Leader 要负起责任来,没事就重构一下代码,时刻保证代码质量处在一个良好的状态。否则,一旦出现 “破窗效应”,一个人往里堆了一些烂代码,之后就会有更多的人往里堆更烂的代码。毕竟,往项目里堆砌烂代码的成本太低了。不过,保持代码质量最好的方法还是打造一种好的技术氛围,以此来驱动大家主动去关注代码质量,持续重构代码。

总结

1.重构的目的:为什么重构(why)?

  • 对项目而言,重构可以保持代码质量持续处于一个可控的状态,不至于腐化到无可救药的地步。
  • 对于个人而言,重构非常锻炼一个人的代码能力,并且是一件非常有成就感的事情。它是我们学习的经典设计思想、设计原则、设计模式、编程规范等理论知识的练兵场。

2.重构的对象:到底重构什么(what)?

按照重构的规模,可以分为大型重构和小型重构。

  • 大型重构:大规模高层次重构,包括代码分层、模块化、解耦、梳理类之间的交互关系、抽象复用组件等等。这部分工作用的更多的是比较抽象、比较顶层的设计思想、原则、模式。
  • 小型重构:小规模低层次重构,包括规范命名、注释、修正函数参数过多、消除超大类、提取重复代码等等编程细节问题,主要是针对类、函数级别的重构。小规模低层次的重构更多的是利用编码规范这一理论知识。

3.重构的时机:什么时候重构(when)?

我们一定要有持续重构意识,把重构作为开发必不可少的部分,融入到日常开发中,而不是等到代码出现很大问题的时候,再大刀阔斧地重构。

4.重构的方法:又该如何重构(how)?

  • 大规模高层次的重构难度比较大,需要组织、有计划地进行,分阶段地小步快跑,时刻让代码处于一个可运行的状态。
  • 而小规模低层次的重构,因为影响范围小,改动耗时短,所以,只要你愿意并且有时间,随时随地都可以去做。

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

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

相关文章

stable diffusion 零基础入门教程

一、前言 Midjourney 生成的图片很难精准的控制,随机性很高,需要大量的跑图,但Stable Diffusion可以根据模型较精准的控制。 SD 效果图展示: 二、Stable Diffusion 介绍 Stable Diffusion 是一款基于人工智能技术开发的绘画软件…

IM6ULL学习总结(四-七-1)输入系统应用编程

第7章 输入系统应用编程 7.1 什么是输入系统 ⚫ 先来了解什么是输入设备? 常见的输入设备有键盘、鼠标、遥控杆、书写板、触摸屏等等,用户通过这些输入设备与 Linux 系统进行数据交换。 ⚫ 什么是输入系统? 输入设备种类繁多,能否统一它们的…

ZJUBCA研报分享 | 《BTC/USDT周内效应研究》

ZJUBCA研报分享 引言 2023 年 11 月 — 2024 年初,浙大链协顺利举办为期 6 周的浙大链协加密创投训练营 (ZJUBCA Community Crypto VC Course)。在本次训练营中,我们组织了投研比赛,鼓励学员分析感兴趣的 Web3 前沿话题…

深度学习图像算法工程师--面试准备(2)

深度学习面试准备 深度学习图像算法工程师–面试准备(1) 深度学习图像算法工程师–面试准备(2) 文章目录 深度学习面试准备前言一、Batch Normalization(批归一化)1.1 具体步骤1.2 BN一般用在网络的哪个部分 二、Layer Normaliza…

【JavaEE初阶 -- 多线程】

认识线程(Thread)Thread类及常见方法 1.认识线程(Thread)1.1 线程1.2 进程和线程的关系和区别1.3 Java的线程和操作系统线程的关系1.4 创建线程 2. Thread类及常用的方法2.1 Thread的常见构造方法2.2 Thread的几个常见属性2.3 启动…

AI 赋能,第二大脑:一个开源的个人生产力助手 | 开源日报 No.195

QuivrHQ/quivr Stars: 28.3k License: Apache-2.0 quivr 是一个个人生产力助手,利用生成式人工智能技术作为第二大脑。 快速高效:设计迅捷高效,确保快速访问数据。安全可靠:您的数据由您掌控,始终安全。跨平台兼容性…

Unity3d C#实现文件(json、txt、xml等)加密、解密和加载(信息脱敏)功能实现(含源码工程)

前言 在Unity3d工程中经常有需要将一些文件放到本地项目中,诸如json、txt、csv和xml等文件需要放到StreamingAssets和Resources文件夹目录下,在程序发布后这些文件基本是对用户可见的状态,造成信息泄露,甚至有不法分子会利用这些…

Ajax+Axios+前后端分离+YApi+Vue-ElementUI组件+Vue路由+nginx【全详解】

目录 一.Ajax技术 二. Axios 三.前后台分离开发介绍 四. YAPI 五.前端工程化 六.vue工程的目录结构 七.Vue项目核心文件 八.Vue组件库ElementUI AboutView.vue最终代码 AboutView.vue最终代码 九.Vue路由 十.案例 十一.nginx介绍 一.Ajax技术 1.Ajax概述 Ajax: 全…

华为OD面试分享12(2024年)

背景:双非无经验转行,只会刷题,面的测试 12.31 机试 1. 给定一个字符串a(含有万能字符?),判断a字符串的字符能不能构成给定的其他字符串 2.给定一组数据heights,找出山峰的高度(还是数量?有点忘了) 3.是一道深搜题,给定一串密码数字,在矩阵里按照顺序找出这些密码…

离线数仓(五)【数据仓库建模】

前言 今天开始正式数据仓库的内容了, 前面我们把生产数据 , 数据上传到 HDFS , Kafka 的通道都已经搭建完毕了, 数据也就正式进入数据仓库了, 解下来的数仓建模是重中之重 , 是将来吃饭的家伙 ! 以及 Hive SQL 必须熟练到像喝水一样 ! 第1章 数据仓库概述 1.1 数据仓库概念 数…

C语言:通讯录(纯代码)

目录 背景&#xff1a;VS2019编译器 创建文件&#xff1a; contact.h代码&#xff1a; test.c代码&#xff1a; contact.c代码&#xff1a; 背景&#xff1a;VS2019编译器 创建文件&#xff1a; contact.h代码&#xff1a; #pragma once#include <string.h> #includ…

FPGA的时钟资源

目录 简介 Clock Region详解 MRCC和SRCC的区别 BUFGs 时钟资源总结 简介 7系列FPGA的时钟结构图&#xff1a; Clock Region&#xff1a;时钟区域&#xff0c;下图中有6个时钟区域&#xff0c;用不同的颜色加以区分出来 Clock Backbone&#xff1a;从名字也能看出来&#x…

安卓 OpenGL ES 学习笔记

文章目录 OpenGL 学习笔记OpenGL 是什么&#xff1f;OpenGL ES是什么&#xff1f;怎么用&#xff1f;hello world如何实现动画效果 参考文章 OpenGL 学习笔记 OpenGL 是什么&#xff1f; OpenGL&#xff08;Open Graphics Library&#xff09;是一个跨平台的图形编程接口&…

Linux中more和less命令用法

Linux中more和less命令用法 一、more命令 more功能类似 cat &#xff0c;cat命令是整个文件的内容从上到下显示在屏幕上。 more会以一页一页的显示方便使用者逐页阅读&#xff0c;而最基本的指令就是按空白键&#xff08;space&#xff09;就往下一页显示&#xff0c;按 b 键…

Mint_21.3 drawing-area和goocanvas的FB笔记(七)

FreeBASIC gfx 基本 graphics 绘图 8、ScreenControl与屏幕窗口位置设置 FreeBASIC通过自建屏幕窗口摆脱了原来的屏幕模式限制&#xff0c;既然是窗口&#xff0c;在屏幕坐标中就有它的位置。ScreenControl GET_WINDOW_POS x, y 获取窗口左上角的x, y位置&#xff1b;ScreenC…

C++笔记之给枚举类型的变量赋值

C++笔记之给枚举类型的变量赋值 —— 杭州 2024-03-10 code review! 在C++中,你可以在结构体内部定义一个枚举类型,并在创建结构体变量时给枚举类型的变量赋值。下面是一个简单的例子展示了如何做到这一点: 代码 #include <iostream>// 定义结构体 struct MyStru…

如何在Windows系统使用固定tcp公网地址ssh远程Kali系统

文章目录 1. 启动kali ssh 服务2. kali 安装cpolar 内网穿透3. 配置kali ssh公网地址4. 远程连接5. 固定连接SSH公网地址6. SSH固定地址连接测试 简单几步通过[cpolar 内网穿透](cpolar官网-安全的内网穿透工具 | 无需公网ip | 远程访问 | 搭建网站)软件实现ssh 远程连接kali! …

proteus8.9 示波器放大

proteus8.9 示波器放大** 1. 打开放大&#xff1a;Windows徽标键 加号 2. 取消放大&#xff1a;Windows徽标键 ESC

在WSL2中安装多个Ubuntu教程

文章目录 前言一、前期准备1、WSL安装2、Docker安装 二、安装第二个Ubuntu系统1.切换为WSL22.获取Ubuntu16.04的tar文件从容器中导出tar 3. 将tar文件导入WSL4. 设置默认用户 总结 前言 适用于 Linux 的 Windows 子系统 (WSL) 是 Windows 的一项功能&#xff0c;可用于在 Wind…

Java中创建线程的多种方式。

在Java中&#xff0c;创建线程的方式有多种&#xff0c;包括继承Thread类、实现Runnable接口、使用Executor框架、使用Callable和Future等。 1. 继承Thread类 通过继承Thread类并重写run()方法来创建线程。 代码如下&#xff1a; public class MyThread extends Thread {Ov…