《重构(第二版)》阅读笔记(一)

前言

这是一本通用的书籍,当中的示例使用 JavaScript 编写,对于前端程序员挺友好的

对于重构的学习,其实有一个过程,如同没有见过健康代码的人,根本想不到代码原来可以这么写🎉

何为重构

在代码完成之后,不修改原有逻辑的情况之下,进行提纯,让代码总体阅读性更好,如

  • 子类的共同方法,放置至父类上
  • 提取公用函数
  • 去除多余参数

以抬杠思想来说,我难道不能在编写代码的时候,就将其逻辑思路分明,从而无需费这二遍手

那当然是最佳表现,但可惜的是,所有的开局设计,都会在编写时逐渐分离崩盘,几乎做不到与设计之初所想的那样,重构的思想则是,先写再改,放开手直接干,当然这也不是说让你瞎搞,然后靠重构起死回生

为什么要重构

那么是不是说,对其结构“不甚清晰”的评价只是美学意义上的判断,只是对所谓丑陋代码的反感呢?毕竟编译器也不会在乎代码好不好看。但是,当我们需要修改系统时,就涉及了人,而人在乎这些。

对于多数代码,我们只停留在了能跑就行,这也是最基本的,满足最低需求。而改动则表示了很多的可能,可能导致无法运行,变得更糟,或许会变得更好,但让人感受不着,甚至说从表面上看,代码逻辑被拆的更加复杂

我再强调一次,是需求的变化使重构变得必要。如果一段代码能正常工作,并且不会再被修改,那么完全可以不去重构它。能改进之当然很好,但若没人需要去理解它,它就不会真正妨碍什么。如果确实有人需要理解它的工作原理,并且觉得理解起来很费劲,那你就需要改进一下代码了。

重构是一种优化手段,并非是必须的。当然,其中描述的某人,也可能是你自己,现在回看一些自己亲手写的代码,你真的能分辨出它的效果是什么吗?在这里起到了什么作用?

我体验过,感觉好极了🤣甚至不敢相信这是自己写的

重构需要注意什么

进行一次重构之后,最好进行一波测试,与重构前对比,是否出现了意料之外的结果,慢慢的小步前进

可以配合 git,每次成功的重构,进行一波存档

命名

对于一个函数,名称要能体现出函数的作用,参数名也是如此。最好的效果就是,一看函数名,就知道什么效果,通过传入不同的参数,又会造成什么影响

作者有一条风格,对于作为函数返回值的变量,统一使用 result 进行命名

因为重构过程一直在提取,修改变量名、给新函数取名的操作很多很多,命名这条还是很重要的,虽然我们更多时候是起名困难症,或者说一个词被使用掉了之后,就没词了

好看的代码有必要吗

傻瓜都能写出计算机可以理解的代码。唯有能写出人类容易理解的代码的,才是优秀的程序员。

虽然这方面一直被当成段子,一个将代码写的谁都能看懂的程序员,让人觉得谁都能接你的班,写出只有自己可以看懂的代码,便是无可替代👏

变量与参数

减少申明一堆傻乎乎的临时变量,绝大多数情况下,都是没有必要的,表达其意义的方式有很多

//bar
function template() {
  const btn = `<button>按钮<button/>`
  return btn
}

//good
function getBtn() {
  return `<button>按钮<button/>`
}

需要通过其他参数计算得到的值,可以将其转换为一个函数,然后分布式计算,调用一次函数就好,纯函数的执行效率是不错的,比传参的效率要高也不要意外,通过函数名来表达其执行的结果

临时变量

什么样的变量会是一个典型的代表呢?

function fn(index) {
  const arr = [1,3,5]
  return arr[index]
}

恩对,就是这样,一个一成不变的变量,写成闭包都可以,当然也可以这样

const numFor = index => [1, 3, 5][index] 

分离不相关的逻辑

一个示例

for (let perf of invoice.performances) {  
  volumeCredits += volumeCreditsFor(perf)  
  
  result += ` ${playFor(perf).name}: ${usd(amountFor(perf))} (${perf.audience} seats)\n`  
  totalAmount += amountFor(perf)  
}

作者将其修改为了

for (let perf of invoice.performances) {
  // print line for this order
  result += ` ${playFor(perf).name}: ${usd(amountFor(perf))} (${perf.audience} seats)\n`;
  totalAmount += amountFor(perf);
}
for (let perf of invoice.performances) {
  volumeCredits += volumeCreditsFor(perf);
}

这倒是不咋理解,毕竟从表面上,这循环是重复的,这方面我还是不太乐意接受的,或许换成 forEach() 看起来会好一些,而且在上面的那两个也没有关联,还分三个不成,变量相应的移动还可以

好吧,看书只看一半也是害人,后续就将变量与循环逻辑给完全抽出函数块了,直接给最终结果就完了,这种移动的利处在于让人观察到可抽离之处,让其从这个函数中消失

重构造成的性能问题

大多数情况下可以忽略它。如果重构引入了性能损耗,先完成重构,再做性能优化

这一点得到了承认,当出现性能倒退时,给出的反应是,不理睬,继续完成重构,再根据状况,挽回性能,也就是说,付出一些性能的代价,是可以接受的

reduce() 的使用

当中给我的一点启发,对于 Array.reduce() 什么时候传入第二参数,也就是初始化统计数

如果数组长成这样,那么作为一个统计总和的方法来说,不传递也没有问题

[1, 2, 3]

若是数组状态的都是对象,则不能如此使用,需要先占个位置

[{ value: 1 }, { value: 2 }, { value: 3}]
[
  { value: 1 }, 
  { value: 2 }, 
  { value: 3 }
].reduce((count, current) => count + current.value, 0)

编程时,需要遵循营地法则:保证你离开时的代码库一定比来时更健康。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值