【深入浅出系列】之代码可读性

深入浅出,系列,代码,可读性 · 浏览次数 : 296

小编点评

## 可读性分析: **1. 可读性一句话:** “如果不存在目录则创建”、“获取文件名”这类注释有何意义?有可能这是coder当时的方案思路,但这里真的需要吗? **2. 代码无注释:** 是否影响阅读?其实我做的只是把先前的代码重新归类,分别放到了三个方法中,核心实现还是原本的代码,没有改动,现在阅读起来是不是顺畅了许多? **3. 逻辑清晰,抽象合理:** “方法抽象的边界是什么?哪些因素应该考虑进行方法抽象?”这些问题可以帮助我们更深入地理解抽象的概念,以及如何进行合理的抽象。 **4. 关键注释:** “注释是代码主体不是注释,而且这样也会带来隐性的工作量问题:代码修改,注释也必须修改。”这句话提醒我们,代码的注释应该准确易懂,并尽量避免多余的描述。 **5. 代码可读性是相对的:** 作者从多个角度探讨了代码可读性,并指出代码可读性是一个比较宽泛的问题,也是一个老生常谈的问题。随着编码经验积累,在不同职业阶段,我们对可读性也会有不同的理解和认识。

正文

这是“深入浅出系列”文章的第一篇,主要记录和分享程序设计的一些思想和方法论,如果读者觉得所有受用,还请“一键三连”,这是对我最大的鼓励。

一、老生常谈,到底啥是可读性

一句话:见名知其义。有人说好的代码必然有清晰完整的注释,我不否认;也有人说代码即注释,是代码简洁之道的最高境界,我也不否认。但我都不完全接受,如果照搬前者,有人会在每个方法、每个循环、每个判断都添加大量注释,对于一个表达不严谨的coder来说,代码与汉字可能词不达意;而且,一旦代码逻辑发生变化,注释改不改?对于后者,英语水平可能也就是个半吊子,动词名词不区分,真能做到代码即注释的有多少人?

二、骂归骂,总归要硬着头皮干

先来举个简单例子:

public StepExitEnum doExecute(StepContext stepContext) throws Exception {
    String targetFilePath = this.getOriginFilePath(stepContext.getJobContext());//获取目标路径
    File targetDir = new File(targetFilePath);
    if (!targetDir.exists()) {
        targetDir.mkdirs();//如果不存在目录则创建
    }

    String encryptedFilePath = this.getEncryptedFilePath(stepContext.getJobContext());//获取加密文件路径
    String fileName = this.getFileName(stepContext);//获取文件名
    File[] encryptedFiles = new File(encryptedFilePath).listFiles(this.buildFilenameFilter(fileName));//过滤文件

    FileEncryptor dencryptor = this.buildFileEncryptor(stepContext);//创建FileEncryptor
    Stream.of(encryptedFiles)
            .forEach(encryptFile -> {
                File targetFile = new File(targetFilePath, encryptFile.getName());
                dencryptor.invoke(encryptFile, targetFile);//解密文件
            });

    return StepExitEnum.CONTINUING;
}

这种代码很常见,耐着性子其实也容易看懂:创建目录->读取加密文件->解密文件,就当前来说其实满足了业务需求也就可以了,但不够优雅,从长期来讲,这会产生bad smell,首先,“如果不存在目录则创建”、“获取文件名”这类注释有何意义?有可能这是coder当时的方案思路,但这里真的需要吗?它确确实实影响我的注意力了,但我没有获取到任何有价值信息;其次,若想要理解doExecute这个方法的目的,必须通读代码,而我只是想知道它做了什么事;最后,这个方法如果某一行出问题了,那么影响范围是整个业务流程。

如果后期需要改动,大部分人可能会增加条件判断,或是在后面继续追加代码实现,最后会导致越来越难以阅读,这其实也就是“能运行就不要动它”这个梗的根源了,因为没人能读明白它到底做了什么,但又不得不改,同时可能伴随着“口吐芬芳”。

三、意识先行,从一行做起

那么到底该如何做呢?下面是我的一个例子:

public StepExitEnum doExecute(StepContext stepContext) throws Exception {
    initTempFilePath(stepContext);
    File[] encryptedFiles = findEncryptedFiles(stepContext);
    dencryptFiles(encryptedFiles, stepContext);
    return StepExitEnum.CONTINUING;
}

先不论具体实现细节,是不是一眼看过之后就了解doExecute做了什么事?这个方法的确没有任何注释,是否影响阅读?其实我做的只是把先前的代码重新归类,分别放到了三个方法中,核心实现还是原本的代码,没有改动,现在阅读起来是不是顺畅了许多?

通读代码后我发现其实只做了三件事:创建目录、读取加密文件、解密文件,这是最核心的三个步骤,把它抽象出来,独立为方法,既表达了逻辑功能,也清晰阅读,还可以缩小影响范围,今后哪里有问题改哪里,不需要再通读代码了。

四、回到主题,再说可读性

(1)抽象,合理的业务逻辑抽象

“一个方法只应该做一件事”,想必很多人听过类似的表述,听起来简单做起来难,怎么定义“只做一件事”?这件事的边界是什么?这就依赖coder对业务逻辑、对功能实现的深入理解和合理抽象,这才能清晰的区分出各个功能的边界,或者说是如何定义这件“事”。

没有基于业务的合理抽象,硬生生地写了几个方法,你会发现这几个方法“藕断丝连”,一个方法的参数变化总会影响到另一个方法,很难将一个方法单拎出来应用在其他场景,一处改,处处改,这时候就要考虑,方法抽象的是否合理?

合理的抽象,从功能角色、职责划分上就很清晰,有了这个基础,才能清晰的编写业务逻辑代码,而不是堆砌各种条件判断和循环,同时带着两条斜杠和注释,这是可读性的基础。

(2)各司其职,职责单一

一个方法只做一件事,扩展到一个类也如此,职责单一,归根结底还得基于合理的抽象,所以,它其实是抽象的一种具体体现,二者总是相辅相成。

(3)命名规范

这也是老生常谈了,但真正做到的coder其实不多,类名、方法、变量的命名规则其实很有讲究,但这不是本文的主题,不多赘述,类名用名词,方法名用动词,因为类表述的是做什么事,而方法名表述的是如何做,规范的命名和正确的词法,这是编码的基础功底,这会有助于他人阅读代码,当然也是为什么我们读spring源码会感觉顺畅,而读同事写的业务代码却很蹩脚的原因,我们太过于强调spring的IOC了,却忽略了最基础的东西。

(4)关键注释

注释不能少,但也不应该每个方法、每个判断、每个循环到处都是///*,毕竟代码是主体不是注释,而且这样还会带来隐性的工作量问题:代码修改,注释也必须修改。所以好的注释不是多,是关键。例如java.util.HashMap类的注释上会告诉你线程安全问题:

Note that this implementation is not synchronized.

这是很关键的信息,所以注释要给出关键性的、使用上注意的事项,不在于多。

代码可读性其实是一个比较宽泛的问题,也是一个老生常谈的问题,随着编码经验积累,在不同职业阶段,我们对可读性都会有不同的理解和认识,本文从我自己的角度和经验,讨论了一些比较浅的理解,如何写出易读、易懂的优秀代码,可能是我们coder永远追寻的目标之一,即使它没有终点。

作者:京东科技 张宇

来源:京东云开发者社区 转载请注明来源

与【深入浅出系列】之代码可读性相似的内容:

【深入浅出系列】之代码可读性

代码可读性其实是一个比较宽泛的问题,也是一个老生常谈的问题,随着编码经验积累,在不同职业阶段,我们对可读性都会有不同的理解和认识,本文从我自己的角度和经验,讨论了一些比较浅的理解,如何写出易读、易懂的优秀代码,可能是我们coder永远追寻的目标之一,即使它没有终点。

智能化生产应用搭建的实战案例

摘要:本文主要为大家介绍使用华为云数字工厂平台,快速搭建一个智能化生产管理应用的实战案例。 本文分享自华为云社区《数字工厂深入浅出系列(一):智能化生产应用搭建的实战案例》,作者: 云起MAE。 华为云数字工厂平台,专门面向中小型制造企业的生产制造数字化场景设计,端到端整合了构建生产制造数字化应用所

结合实例,解读华为云数字工厂信息模型配置器

摘要:结合一个实际的“生产执行管理”场景涉及的相关业务数据对象,系统介绍了华为云数字工厂平台的“信息模型”配置器的使用方法,实现对相关业务对象的数据建模。 本文分享自华为云社区《数字工厂深入浅出系列(二):信息模型配置器的使用方法介绍》,作者: 云起MAE 。 华为云数字工厂平台,采用业内先进的元数

实例解读华为云数字工厂平台的逻辑模型编排器

摘要: 本期结合一个“生产执行管理”案例场景涉及的相关业务活动流程,系统地介绍了华为云数字工厂平台的逻辑模型编排器的使用方法。 本文分享自华为云社区《数字工厂深入浅出系列(三):逻辑模型编排器的使用方法介绍》,作者:云起MAE 。 华为云数字工厂平台的制造应用构建引擎(Manufacturing A

建设数字工厂:生产物料齐套检查的实现方法

摘要: 本期介绍如何在华为云数字工厂平台上,通过扩展配置生产工单的信息模型和逻辑流程模型,实现在生产工单下发前,轻松透视生产物料齐套状况。 本文分享自华为云社区《数字工厂深入浅出系列(四):生产物料齐套检查的实现方法》,作者:云起MAE 。 随着市场个性化需求不断发展,多品种小批量生产加工模式已经形

建设数字工厂:华为云数字工厂平台接入第三方网关设备数据

摘要:本期介绍工业自动化产线设备由第三方数采网关(软件)采集数据后,如何快速接入到华为云数字工厂平台,实现生产自动化控制层与数字工厂应用层的数据集成和实时交互。 本文分享自华为云社区《数字工厂深入浅出系列(五):接入第三方网关设备数据》,作者: 云起MAE。 华为云数字工厂平台内置工业IoT数据引擎

构建数字工厂丨数据分析与图表视图模型的配置用法

摘要:本期结合示例,详细介绍华为云数字工厂平台的数据分析模型和数据图表视图模型的配置用法。 本文分享自华为云社区《数字工厂深入浅出系列(六):数据分析与图表视图模型的配置用法》,作者:云起MAE 。 华为云数字工厂平台基于“数据与业务一体化”理念,提供统一的制造全域数据平台底座,内置轻量级制造数据分

从原理到实战,详解XXE攻击

本文分享自华为云社区《【安全攻防】深入浅出实战系列专题-XXE攻击》,作者: MDKing。 1 基本概念 XML基础:XML 指可扩展标记语言(Extensible Markup Language),是一种与HTML类似的纯文本的标记语言,设计宗旨是为了传输数据,而非显示数据。是W3C的推荐标准。

深入浅出RPC服务 | 不同层的网络协议

本系列文章从RPC产生的历史背景开始讲解,涉及RPC核心原理、RPC实现、JSF的实现等,通过图文类比的方式剖析它的内部世界,让大家对RPC的设计思想有一个宏观的认识。

[转帖]如何优化Java垃圾回收机制简单讨论?

https://www.cnblogs.com/lizexiong/p/15594187.html 本文是成为Java GC专家系列文章的第三篇。在第一篇《成为JavaGC专家Part I — 深入浅出Java垃圾回收机制》中我们学习了不同GC算法的执行过程,GC是如何工作的,什么是新生代和老年代,