【前端】重构,有品位的代码 01——走上重构之道

写在前面

正如你所知道的,在进行项目开发过程中代码不断进行更迭堆砌,整个项目的体积和重量也愈发庞大,而代码质量愈发下降。代码堆砌造成的致命后果就是变得逻辑混乱、难以维护,可读性下降,这也造成了理解成本和沟通成本增加,此时想要重构简直是珠穆朗玛峰上种树般难。

而造成重构难度大,弊病积重难返的原因主要有:

  • 只顾着编程,却忽略了程序设计
  • 缺乏代码质量监督,项目从严谨的工程堕落成随意性行为
  • 出于成本考虑,在原代码基础上进行持续开发
  • 缺乏代码review习惯,不能做到时时回顾重整代码

古有云“时时勤拂拭,勿使惹尘埃”,就是告诫你我要时时刻刻打扫尘土,不要让它染上灰尘。同样的,对于我们写过的就代码亦是如此,好的代码能够让人赏心悦目,而坏味道的代码却让人难以下咽。有幸淘到Martin Fowler写的《重构──改善既有代码的设计》,如获至宝,现在就开始跟着笔者开启重构之路吧。

何谓重构

在《重构》书籍中,作者对重构的定义是:

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

在笔者理解,重构就是对既有代码进行有效的设计

“结构调整”和重构:结构调整泛指的是对既有代码进行各种形式的重新组织或清理,而重构特指的是对特定类结构进行调整。

重构和性能优化:

  • 相同点:两者均需要修改代码,且均不会改变程序整体功能。
  • 差异点:重构是使得既有代码“便于理解,便于修改”,无关乎运行性能。而性能优化注重的是如何使得程序运行更快,但是可能代码难以理解和维护。

正所谓”鱼和熊掌不可兼得“,理解阅读和运行性能有时也正是如此。

为何重构

在项目开发中,会不会有这样的分裂行为,把自己的时间分配给了添加新功能和重构,在添加新功能时发觉自己的代码没有条理、晦涩难懂,在进行代码重构时发现自己的代码没有添加新功能,不能刷kpi。

  • 重构改进软件的设计:重构是宏观的项目代码进行调整,而非短期的行为。经常性的重构有助于代码维持该有的形态。

  • 重构使得软件更易理解:未进行重构的代码可能机器阅读很明白,人类阅读却比较吃力,而重构后使得机器和人类都能简单易懂。

  • 重构有助于找到BUG:在进行代码重构时,需要对代码结构进行深入理解,能够书写出更加健壮的代码。

  • 重构提高编程速度:重构能够使得代码在后续添加新功能时事半功倍,节约阅读代码的时间成本。

何时重构

  • 预备性重构:让添加新功能更加容易:重构的最佳时机是在添加新功能前,将更新数据的逻辑和查询逻辑分开,会更容易避免造成错误的逻辑纠缠。

  • 帮助理解的重构:使代码更易理解:在研读代码时,重构会引领我们获得更高层面的理解,能够深入理解代码的深层逻辑。如同站在窗前看远方风景,拂去灰尘能够使得我们看得更远更清晰。

  • 捡垃圾式重构:在已经理解代码在做什么,但是发现其做的不够好,逻辑混乱复杂,此时就需要注意取舍,是想要将代码垃圾铲除,还是继续保持业务开发。其实,可以将易于重构的优先处理,积重难返的就后续慢慢处理。

其实预备性重构、帮助理解的重构和捡垃圾式重构等都是见机行事的,没有计划安排具体时间进行专门重构,而是在开发过程中发现问题顺便进行重构。但是,如果团队在过去的开发过程中忽略了代码重构,那么就会需要计划一段专门的时间对项目代码进行重构,其实工程浩大,花费的时间也更长。

注意,不要将重构错误理解为是为了弥补过去的错误或清理脏代码,当然这些情况是必须进行重构的。但是,对待漂亮的代码也需要进行重构,因为在编程时会有许多权衡取舍的情况,比如参数化的程度、用什么代码能够解耦,提升鲁棒性。此外,编写代码并不是简单的代码累加过程,而是在既有代码进行重构后进行添加新功能,能够事半功倍。

  • 长期重构:代码重构是个长期的宏观过程,不要为了短期目标而去破坏代码的逻辑。

  • 复审代码时重构:代码复审(code review)可以改善开发状况,有助于团队传播编程知识,帮助欠缺经验的开发者学习更多有益于团队的经验。而重构有助于复审别人的代码,使得复审工作得到更好的结果。

  • 何时不应该重构代码:意思就是,不是所有代码都需要重构,这个需要根据良好的判断力和丰富的经验进行处理,量力而行,尽力而为。

代码的坏味道

从字面意思理解,代码的坏味道就是冗余繁杂逻辑的代码如同裹脚布般又臭又长,那就进行舍弃和重构。

常见的坏味道的代码有很多,比如奇怪的命名方。初学者在进行编程学习时,经常将代码文件、变量、函数等起名各式各样,毫无章法,杂乱无章,不能起到见名思义的效果。所以好的名字是很关键,能够让人见名知意,通俗易懂。

下面进行总结,常见的坏味道的代码:

  • 奇怪的命名方式:不能做到见名知意
  • 代码重复冗余:代码的实现逻辑和执行流程相似或相同,此时可以进行抽取
  • 过长的函数
    • 函数方法中的语句不在同一个抽象层级
    • 逻辑混乱不堪,需要通过大量注释进行理解
    • 未实现面向对象编程
  • 过长的参数列表
  • 全局数据和可变数据
    • 全局数据:任何角落均可修改,不能探测,易出错误
    • 可变数据:数据修改经常导致出乎意料的结果和难以发现的BUG
  • 过大的类
    • 做的越多,越容易出错
    • 字段、实例变量和方法太多,容易造成代码重复、混乱不堪
    • 类的命名不足以描述所做的事情
  • 逻辑混乱
    • 发散式变化:某个模块经常因为不同的原因在不同的方向上发生变化
    • 霰弹式变化:每遇到某种变化,就必须对应的在多个类上中进行修改
  • 依恋情结:过分依赖于代码的模块化,导致逻辑复杂性高于模块内部交流
  • 纯数据类
    • 仅包含字段和访问(读写)这些字段的方法
    • 此类被称为数据容器,应保持最小可变性
  • 数据泥团和基本类型偏执
    • 数据泥团:两个类、方法签名中包含相同的字段或参数
    • 基本类型偏执:应该使用类但使用基本类型,比如表示数值与币种的Money类、起始值与结束值的Range类
  • 重复的switch:在新增一个选择分支时,必须找到所有的switch进行逐一更新
  • 不合理的继承体系
    • 继承打破了封装性,子类依赖其父类中特定功能的实现细节
    • 子类必须跟着其父类的更新而演变,除非父类是专门为了扩展而设计,并且有很好的文档说明
  • 过多的条件判断
  • 过长的参数列
  • 临时变量过多
  • 令人迷惑的暂时字段
    • 某个实例变量仅为某种特定情况而设置
    • 将实例变量与相应的方法提取到新的类中
  • 纯数据类
    • 仅包含字段和访问(读写)这些字段的方法
    • 此类被称为数据容器,应保持最小可变性
  • 注释过多:当需要使用过多注释,意味着这段代码需要进行重构

由上可知,坏代码普遍存在的问题是:难以复用、鲁棒性差、晦涩难懂、不易测试。

那么什么好代码呢?

代码的好坏是根据代码质量进行评估的,最重要的衡量指标是:可维护性、可阅读性和可扩展性。要写出高质量代码,我们就需要掌握一些更加细化、更加能落地的编程方法论,这就包含面向对象设计思想、设计原则、设计模式、编码规范、重构技巧等。

参考文章

《常见代码重构技巧》

《重构──改善既有代码的设计(第2版)》

写在最后

我是前端小菜鸡,感谢大家的阅读,我将继续和大家分享更多优秀的文章,此文参考了大量书籍和文章,如果有错误和纰漏,希望能给予指正。

更多最新文章敬请关注笔者CSDN账号和公众号前端万有引力。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值