读代码整洁之路及实施重构总结

简介: ### 前言 在开发代码的时候,经常觉得代码有一种坏味道,有一种迫切重构的想法,但是再一次的仔细阅读代码,却发现为了实现业务需求,代码就应该是现有这种模式的写法。之前也有在网上看一些代码重构的文章,但是直到看完《代码整洁之路》这本书,才算是有了一些明确代码重构的方法和思路。在这次对生产代码的一些重构实践中,对文章中提到并亲身体会过的部分小点,有了一些认识和体会,记录如下。参考博客中的第一篇,

前言

在开发代码的时候,经常觉得代码有一种坏味道,有一种迫切重构的想法,但是再一次的仔细阅读代码,却发现为了实现业务需求,代码就应该是现有这种模式的写法。之前也有在网上看一些代码重构的文章,但是直到看完《代码整洁之路》这本书,才算是有了一些明确代码重构的方法和思路。在这次对生产代码的一些重构实践中,对文章中提到并亲身体会过的部分小点,有了一些认识和体会,记录如下。
参考博客中的第一篇,重构十六字心法是下述小点的前提:旧的不变,新的创建,一步切换,旧的再见;

过长的函数及过长的函数参数列表

过长的函数参数列表导致的函数一定是会过长的,因为会存在参数的校验和参数的进一步加工处理,这些是可以将参数进行封装到数据结构以后提前进行处理的,同时也能大大减少函数调用长度,让阅读者更加清楚的聚焦函数内部逻辑处理。
过长的函数处理体是很难让人一下理清处理逻辑,它需要开发者一行一行的阅读完整个函数才能有大概的了解,它代表着函数内部的代码抽象层级不统一,这个时候需要我们对其进行分治,将一些聚合在一起的逻辑封装为一个函数,这样子我们一个大函数里面只有几个子函数调用,通过子函数名我们就能知道这个函数的大概处理逻辑。

过长的判断条件

当我们在if 判断条件中,使用 || &&连接的判断语句超过两个,我觉得就可以被认定为过长的判断条件。这种写法在代码阅读的时候,要求阅读者能够记住判断条件中使用的变量代表中的意义,有一定的记忆成本。另外这种过长的判断条件,还是有很大一部分的重复使用的情况,此时将它封装为一个单独函数,并起名一个有意义的名字,方便后续的阅读和维护。

变量的有效命名

变量的有效命名和函数的有效命名是一样的,一个可以望文生义的名字可以节省维护代码很大一部分时间,书中对此点进行了反复的强调。一个有意义的名字不是立即取出来的,当我们发现有更适合的命名时,一定要毫不犹豫的更改掉。

函数中的输出参数

类似于如下代码,函数在处理的时候,直接从params获取参数处理后并将结果put到Map中去。

void process(Map<String, Object> params);

在我们的生产代码中有很多这种的函数处理,当我去阅读的时候,给我带来很大的认知困扰。这种函数会某个代码片段中被调用一下,并没有返回结果,这个行为是非常容易迷惑人的,因为参数被自然的看做是函数的输入。如果该函数没有返回结果,对于这种的代码,我认为是可以随意调整的,但是随后又会存在一个函数依赖此函数的处理结果,而这些函数的命名或者参数中并没有体现出依赖关系,很容易出现严重的BUG。
我们应该极力避免输出参数的使用,即使是简单的将输入参数作为结果返回也比返回Void好很多。

函数名和函数实际行为的匹配,避免副作用

正如变量的有效命名所说,函数名必须有意义,但是函数行为也必须和函数名匹配,不能导致其它的副作用。check、is等这些开头的函数不应该对对象的状态进行更改。

垃圾的代码上增加注释

很多时候,我会在晦涩难懂的代码上增加注释以增强自己的理解,但往往下一次阅读的时候还是没有办法一目了然,仍然需要一行行从头阅读才能大概了解其意思。更加困难的一个事情,如果这个代码实现具备一定的业务背景,在交接的时候并没有提及的话,后来者很难阅读出其意图,更加别提去维护了。
如果代码实现的不好,不要增加注释了,重构它吧。

循规蹈矩的JavaDoc注释

如果是仅仅为了避免ide的提示,给函数增加上了循规蹈矩的Java doc注释,那还是干掉它吧。多余的注释只会分散开发者的注意力,另外不正确注释比不好的代码实现更加容易让人误解。没有注释的情况下,开发者使用的时候会查看实现,但是有注释的情况下,很可能会以注释内容为准,从而导致错误的行为。

统一变量命名概念

标识同一个概念意义的变量,命名一定要尽量统一。比如说分页的页码标识,pageNo、currentPage、pageNumber等混用情况。如果是其它更加复杂带有业务属性的变量,同一个概念使用不同的变量标识会带来更加严重的认知困难。

尽量避免返回null值

Java中的NullPointException是我们在编程希望极力避免掉的,因此我们在调用某个可能返回null的函数时,我们都需要增加判断条件,当返回值不为null才进行进一步的处理,所有函数调用初都不可避免的带上了这个判断条件处理,影响代码的阅读。
从另外一个角度来说,当函数提供者实现时,发现有调用方获取一个不存在的值,返回null也是一种可以理解的行为,在我的实现中就经常出现该类代码。之前我一直没有思考过不返回null,直接抛异常的处理方式,但这次去回看某些函数实现,正确的行为就应该是当结果为null时,抛出业务异常。
这一重构点我目前觉得大部分场景都难以避免,但是在后续实现业务逻辑的时候,遇上返回null的场景,一定要思考下抛出异常的处理逻辑,这种实现能够确保函数调用方一定能够拿到有值的结果,从而避免的重复、无味的非空判断。

火车头事件,代码的封装

当A依赖B,B依赖C时,如果A实现的一个逻辑处理,实际依赖于C的处理,我们有时会让A使用B拿到C以后,然后A直接调用C进行处理,这种行为被作者称为火车头事件。A直接调用C的行为,打破了B的封装,让A直接感受到了B的内部逻辑。
正确的行为应该是B封装C的行为,A只会感知到B,A调用B后,由B再来调用C。这个场景在我的代码中经常出现,当A、B、C都是自己编写的情况下,这个打破封装的行为自己是完全意识不到的,需要我们回过头来审视自己的代码,重新思考代码的正确行为。

重构时的单测

程序员都对自己的代码非常自信,特别是大部分的业务逻辑都是简单的增删改查的情况下,我自己单测是写得比较少的。但是错误往往出现于细微之处,特别在大部分正确的情况下,细小处的错误行为是很难寻找的。书中作者在讲述重构样例时,花了很大一番功夫来描述单测。如何让单测能够覆盖函数的所有行为是对程序员的一个考验,写好单测是重构的先决条件,不然往往会让自己事倍功半。
一定要有单测,TDD!
一定要有单测,TDD!
一定要有单测,TDD!

避免重复

Do not repeat youself! 这个原则被大部分的重构指引提及,而现代的ide能够智能识别到重复代码,另外当你发现你自己写了似曾相似的处理代码,那么你也在重复自己了,这种时候就应该提醒自己回头审视自己的代码了,一定是我们的处理逻辑存在问题才会导致这种的重复。当发现重复时,多回头看看!


参考博客

https://www.zhihu.com/question/19574943
https://martinfowler.com/bliki/BranchByAbstraction.html
http://insights.thoughtworkers.org/principles-of-refactoring/
https://www.infoq.cn/article/clean-code-refactor
http://insights.thoughtworkers.org/service-split-and-architecture-evolution/

目录
相关文章
|
存储 运维 机器人
Nvidia和AMD显卡是如何制作的
Nvidia和AMD显卡是如何制作的
1089 0
|
4月前
|
存储 监控 Java
吃透线程池核心原理:从参数设计、拒绝策略到高并发场景终极选型
本文深入剖析Java线程池底层原理,涵盖核心架构、生命周期、7大参数设计逻辑、执行流程及4种拒绝策略;结合CPU/IO密集型等场景给出生产级配置方案,并提供自定义线程工厂、监控、失败任务持久化等完整实战代码,助你规避OOM、雪崩等高频风险。
469 1
|
4月前
|
存储 弹性计算 安全
2026年阿里云服务器2核8G可选实例规格、收费标准、适用场景及活动价格
阿里云2核8G配置服务器因性能均衡、成本适中,成为个人开发者、初创企业及中小型应用的优选。阿里云提供从经济型到企业级的多类实例,配合2026年最新活动政策,用户可灵活组合实现性能与成本的双重优化。文章详细解析了2核8G实例的规格、定价、典型应用场景及当前优惠,并给出不同场景下的选型指南与预算参考,助力用户技术选型与下单购买。
1212 3
|
7月前
|
JSON 安全 Java
SpringBoot.鉴权
本文介绍如何在Spring Boot项目中结合JWT与Spring Security实现安全鉴权。涵盖Token生成与验证、自定义认证流程、角色权限控制(RBAC),并通过过滤器实现登录拦截与请求认证,保障接口安全。
448 2
|
8月前
|
安全 C++
C++ 智能指针详解:从原理到实践
深入解析 C++ 智能指针的原理与用法,掌握 unique_ptr、shared_ptr、weak_ptr 的最佳实践
|
7月前
|
弹性计算 负载均衡 网络协议
。全球加速GA实战:为出海游戏业务降低延迟的架构方案
阿里云全球加速(GA)为出海游戏提供低延迟、高稳定网络方案,通过智能路由与全球70+地区边缘节点,优化TCP/UDP协议传输,解决跨境延迟高、公网不稳定难题。分层架构支持四层加速、智能调度与混合云部署,结合CDN与游戏盾,实现全球玩家流畅对战,助力打造无国界沉浸式体验。(239字)
|
编解码 人工智能 测试技术
CogView4:智谱开源中文文生图新标杆,中文海报+任意分辨率一键生成
CogView4 是智谱推出的开源文生图模型,支持中英双语输入和任意分辨率图像生成,特别优化了中文文字生成能力,适合广告、创意设计等场景。
913 1
CogView4:智谱开源中文文生图新标杆,中文海报+任意分辨率一键生成
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
701 1
|
网络协议 RDMA
GlusterFS支持哪些挂载选项?
【10月更文挑战第1天】GlusterFS支持哪些挂载选项?
367 1
|
弹性计算 运维 关系型数据库
云上Serverless高可用架构一键部署体验与测评
在数字化转型背景下,Serverless架构因其实现业务敏捷、降低成本及提升服务可靠性而备受青睐。本文以阿里云Serverless应用引擎(SAE)为核心,展示了一种高可用、低成本且易于扩展的解决方案。通过单地域双可用区部署,构建了具备自动伸缩与故障恢复能力的架构。借助阿里云的一键部署功能,大幅简化了搭建流程,实现了快速部署,并通过性能与成本分析验证了其优势。对比传统ECS,SAE在资源利用与运维效率上表现更佳,特别适合平均负载较低的应用场景。