本文作者:开课吧效瑞
图文编辑:开三金
各位小伙伴们,大家呼声超高的下篇来喽,赶快来跟着效瑞老师学习吧~~
错过了【上篇】的小伙伴们可以直接点击下方蓝色文字,就可以复习上节课学过的知识咯☟☟
如何写好代码--教你重构的正确姿势(上篇)
本节课我们将要详细给大家讲解重构代码的“独家秘笈”,满满的编码干货,赶快拿小本本记起来吧!
提取字符串常量
目前为止,我们应该能发现一个特别明显的重复:表示“单位”的字符串在多处。
这里就是很明显的“重复代码”
要强调一下。
测试代码和生产代码一样重要。
测试越脏,代码就会变得越脏 最终将会丢失测试,代码开始腐坏。
所以测试代码也在我们的重构范围之内
那我们开始吧~
记住重构的重点是要小步骤
我决定先把 “yard”、“inch”、“f” 修改成常量
以下是提取步骤。
先创建常量:
// index.js
const YARD = "yard";
跑下测试:
yarn test
这里要特别说明一下,可能有的同学会有疑惑这里的操作这么小,有必要还跑测试吗?
有必要~
如果我们保证每一个步骤都是没有问题的话,那么我们就可以做到不需要调试代码。
当发现修改完之后测试跑不通的时候,立马回退代码。
因为我们的每一个步骤都足够的小,并且也能保证回撤后一定是能跑通测试的。
利用全局搜索:
使用 shift + command + f 打开搜索栏;
在搜索栏输入 'yard';
在替换栏输入 YARD;
☟vscode 开发☟
可以看到红圈部分提示可以替换所有(指的是 index.js )文件。
我们点击,替换 index.js 所有的 ‘yard’。
通过 IDE 来修改要比我们手工一个一个的修改要安全的多。
还有一个点,我们必须熟练使用快捷键。
快捷键的使用能帮助我们提高效率。
跑下测试:
yarn test
是的,我们修改完了之后继续跑下测试,保证每一个步骤都是安全的。
同样的,我们利用上面的步骤把剩下的 "inch" 和 'f' 也都重构掉,最终我们的代码应该是这样的:
这时候我们已经把生产代码里面的重复的字符串都修改成常量了.
接下来我们用相同的重构手法去处理测试文件 index.test.js
在我们开始重构的时候应该就能发现第一个问题:
我们之前声明的常量是在 index.js 内的,这里我们需要复用这些常量
所以我们创建 consts.js 文件来统一声明常量。
// consts.js
export const YARD = "yard";
export const F = "f";
export const INCH = "inch"
接着去修改 index.js 文件
+ import { YARD, F, INCH } from "./c-onsts";
- const YARD = "yard";
- const F = "f";
- const INCH = "inch"
跑下测试:
yarn test
ok 测试通过!我们继续去处理 index.test.js 吧。
// index.test.js
+ import { YARD, F, INCH } from "./c-onsts";
重构后的 index.test.js:
至此,我们已经把生产代码和测试代码内的重复字符串全部替换为常量了。
这里应该可以初步体会到重构了吧。
我们通过每一个安全的小步骤来一点点的重构完。
如果你只能记住一句话,那就是小范围修改代码,完事立马运行测试!
修改命名
可以发现 "f" 这个命名是没有明确的含义的。
有意义的命名是可读代码的重要前提。因为有了我们之前的铺垫,这次重构会非常的简单。
●打开 consts.js 文件;
●选中 F 然后按下 F2 全局重命名快捷键;
●着时候在弹出的输入框输入新的名称 FOOT;
// consts.js
+ const FOOT = "f"
- const F = "f"
跑下测试:
yarn test
ok 没有问题。
着时候我们发现所有的文件里面的 F 都变成了 FOOT。
接着我们把 'f' 也修改一下:
- const FOOT = "f"
+ const FOOT = "foot"
跑下测试:
yarn test
利用好快捷键,可以让我们的重构效率高的起飞!
如何提炼话术
1.提炼isUnit
让我们在聚焦到 parseTo() 函数上:
if (this.unit === YARD) {
if (u === FOOT) {
……
}else if(u === INCH){
……
}
会发现这里判断是否为某个单位的时候用了大量的 if 语句,缺乏表达力。
我们通过重构来让代码更易读。
通过之前的添加测试我们已经很清楚了,一共有 3 个不同的单位可以互相转换。
所以先增加判断是否为具体某个单位的函数:
// index.js
isYard(unit){
return unit === YARD;
}
通过函数名我们一眼就能看出这是检测是否为 yard 的处理。
跑下测试:
yarn test
接着我们替换第一个 if 语句:
- if (this.unit === YARD) {
+ if (this.isYard(this.unit))
if (u === FOOT) {
……
}else if(u === INCH){
……
}
跑下测试:
yarn test
同样的,我们把剩下所以的 if 语句都替换掉,千万要记得,每进行一步都要跑下测试哟。
看下我们重构后的代码吧:
有没有感受到我们的代码在一点点的变好,而且很重要的点就是你可以随时停下来。
因为你的代码是一直在可运行的状态。
所以有的小伙伴说我需要2天重构代码。真不好意思,你那不叫重构,叫重写 - -#
2.提炼计算函数
我们现在应该很明确的知道 parseTo 函数是同时处理了 3 种单位的转换。
在《代码整洁之道》函数一章里面提到,好的函数应该是尽可能小的,一个函数只做一件事。
所以这里我们要把每一个单位转换的逻辑都提炼到对应的函数内。
我们先创建新的函数:
接着跑下测试:
yarn test
继续 把之前的逻辑替换为调用新的函数:
跑下测试:
yarn test
测试又失败了:
通过测试给我们的反馈,可以意识到问题应该是出在返回的并非是 length 对象。
因为我们的步骤很小,所以我们能很快的把问题锁定在新加的函数 parseYard() 上。
仔细看一下逻辑,发现如果 2 个 if 都没有匹配的话,那么就会返回 undefined 。
而通过我们的测试提示,如果没有对应的转换单位应该返回当前单位。
所以这里我们应该返回当前的 length 对象。
跑下测试:
yarn test
通过啦~
现在我们应该可以进一步的体会到小步骤和安全网的好处了吧。
如果测试失败那么我们能很快的定位到问题。
看,我们根本不需要调试代码。
同样的, 把剩余的逻辑也都重构完。
最终的代码如下:
重构到现在代码的可读性已经很好啦。
如果这里后续要增加更多的单位转换的话,那么可以通过重构扩展为多态来解决。
三次法则:
第一次做某件事时只管去做;
第二次做类似的事会产生反感,但无论如何还是可以去做;
第三次再做类似的事,你就应该重构。
正如老话说的:事不过三,三则重构!
我认为重构可以很好的平衡设计过度,我们只要遵循三次法则。
因为我们有足够的测试,当代码开始散发出坏味道的时候,我们及时的去重构即可。
这样既避免了设计过度,也避免了代码腐烂。
我通过一个实际的项目展示了如何进行重构。
首先我们先构建安全网。
然后通过识别坏味道+小步骤+频繁的运行测试+ide 来快速安全的进行重构。
我们可以随时停下来,因为我们的代码是一直可工作的。
希望这篇文章能让你对"重构怎么做"有一点感觉。
这个示例告诉我们最重要的一点就是重构的节奏。
小步子,并且保证每一步都处于编译通过和测试通过的可工作状态。
开展高效有序的重构,关键的心得是:
小的步子可以更快前进,请保持代码永远处于可工作状态,小步修改积累起来也能大大改善系统的设计。
当然,这个实例仍有值得改进的地方。
但现在测试仍能全部通过,代码相比初见时已经有了巨大的改善,所以我已经很满足了。
☟快扫码关注我吧☟
点击【图片】,查看【往期干货】
刨根问底之——什么是编码?
用three.js玩转高数可视化
从0到1,Vue大牛的前端搭建——异常监控系统(下篇)
你“在看”我吗?