clean code-代码整洁之道 阅读笔记(第十七章 终章)

news2024/9/30 2:43:43

大纲

第十七章 味道与启发

17.1 注释

C1:不恰当的信息

C2:废弃的注释

C3:冗余注释

C4:糟糕的注释

C5:注释掉的代码

17.2 环境

E1:需要多步才能实现的构建

E2:需要多步才能做到的测试

17.3 函数

F1:过多的参数

F2:输出参数

F3:标识参数

F4:死函数

17.4 一般性问题

G1:一个源文件中存在多种语言

G2:明显的行为未被实现

G3:不正确的边界行为

G4:忽视安全

G5:重复

G6:在错误的抽象层级上的代码

G7:基类依赖于派生类

G8:信息过多

G9:死代码

G10:垂直分隔

G11:前后不一致

G12:混淆视听

G13:人为耦合

G14:特性依恋

G15:选择算子参数

G16:晦涩的意图

G17:位置错误的权责

G18:不恰当的静态方法

G19:使用解释性变量

G20:函数名称应该表达其行为

G21:理解算法

G22:把逻辑依赖改为物理依赖

G23:用多态替代lf/Else或Switch/Case

G24:遵循标准约定

G25:用命名常量替代魔术数

G26:准确

G27:结构甚于约定

G28:封装条件

G29:避免否定性条件

G30:函数只该做一件事

G31:掩蔽时序耦合

G32:别随意

G33:封装边界条件

G34:函数应该只在一个抽象层级上

G35:在较高层级放置可配置数据

G36:避免传递浏览

17.5 Java

J1:通过使用通配符避免过长的导入清单

J2:不要继承常量

J3:常量vs.枚举

17.6 名称

N1:采用描述性名称

N2:名称应与抽象层级相符

N3:尽可能使用标准命名法

N4:无歧义的名称

N5:为较大作用范围选用较长名称

N6:避免编码

N7:名称应该说明副作用 

17.7 测试

T1:测试不足

T2:使用覆盖率工具

T3:别略过小测试

T4:被忽略的测试就是对不确定事物的疑问

T5:测试边界条件

T6:全面测试相近的缺陷

T7:测试失败的模式有启发性

T8:测试覆盖率的模式有启发性

T9:测试应该快速

17.8小结


第十七章 味道与启发

17.1 注释

C1:不恰当的信息

        注释只应该描述有关代码和设计的技术性信息。

C2:废弃的注释
C3:冗余注释
C4:糟糕的注释

        使用正确的语法和拼写。别闲扯,别画蛇添足,,保持简洁。

C5:注释掉的代码

        看到注释掉的代码,就删除它!别担心,源代码控制系统还会记得它。

17.2 环境

E1:需要多步才能实现的构建

        构建系统应该是单步的小操作。不应该从源代码控制系统中一小点一小点签出代码。不应该需要一系列神秘指令或环境依赖脚本来构建单个元素。不应该四处寻找额外的 JAR、XML文件和其他系统所需的杂物。你应当能够用单个命令签出系统,并用单个指令构建它。

E2:需要多步才能做到的测试

        你应当能够发出单个指令就可以运行全部单元测试。能够运行全部测试是如此基础和重要,应该快速、轻易和直截了当地做到。

17.3 函数

F1:过多的参数

        函数的参数量应该少。没参数最好,一个次之,两个、三个再次之。三个以上的参数非常值得质疑,应坚决避免。

F2:输出参数

        输出参数违反直觉。如果函数非要修改什么东西的状态不可,就修改它所在对象的状态。

F3:标识参数

        布尔值参数大声宣告函数做了不止一件事。它们令人迷惑,应该消灭掉。

F4:死函数

        永不被调用的方法应该丢弃。

17.4 一般性问题

G1:一个源文件中存在多种语言

        理想的源文件包括且只包括一种语言。现实上,我们可能会不得不使用多于一种语言但应该尽力减少源文件中额外语言的数量和范围。

G2:明显的行为未被实现

        遵循"最小惊异原则"(The Principle of Least Surprise),函数或类现其他程序员有理由期待的行为。例如,考虑一个将日期名称翻译为表示该日期的枚举的函数。

Day day = DayDate.StringToDay(String dayName);

        我们期望字符串 Monday 翻译为 Day.MONDAY。我们也期望常用缩写形式也能被翻译出来,我们还期待函数忽略大小写。
        如果明显的行为未被实现,读者和用户就不能再依靠他们对函数名称的直觉。他们不再信任原作者,不得不阅读代码细节。

G3:不正确的边界行为

        没什么可以替代谨小慎微。每种边界条件、每种极端情形、每个个异常都代表了某种可能搞乱优雅而直白的算法的东西。别依赖直觉。追索每种边界条件,并编写测试。

G4:忽视安全

        忽视安全相当危险。手工控制serialVersionUID可能有必要,但总会有风险。关闭某些编译器警告(或者全部警告!)可能有助于构建成功,但也存在陷于无穷无尽的调试的风险。关闭失败测试、告诉自己过后再处理,这和假装刷信用卡不用还钱一样坏。

G5:重复

        本书提到的最重要的规则之一。

        每次看到重复代码,都代表遗漏了抽象。

        重复最明显的形态是你不断看到明显一样的代码,可以用单一方法来替代之。

        较隐蔽的形态是在不同模块中不断重复出现、检测同一组条件的switch/case或if/else链。可以用多态来替代之。

        更隐蔽的形态是采用类似算法但具体代码行不同的模块。这也是一种重复,可以使用模板方法模式或策略模式来修正。

G6:在错误的抽象层级上的代码

        创建分离较高层级一般性概念与较低层级细节概念的抽象模型。

        所有较低层级概念放在派生类中,所有较高层级概念放在基类中。

        要点是不能就错误放置的抽象模型撒谎。孤立抽象是软件开发者最难做到的事之一,而且一旦做错也没有快捷的修复手段。

G7:基类依赖于派生类

        通常来说,基类对派生类应该一无所知。

        有时,派生类数量严格固定,而基类中拥有在派生类之间选择的代码 。解决方法:把派生类和基类部署到不同的jar文件中。

G8:信息过多

        优秀的软件开发人员学会限制类或模块中暴露的接口数量。类中的方法越少越好。函数知道的变量越少越好。类拥有的实体变量越少越好。
        隐藏你的数据。隐藏你的工具函数。隐藏你的常量和你的临时变量。不要创建拥有大量方法或大量实体变量的类。不要为子类创建大量受保护变量和函数。尽力保持接口紧凑。通过限制信息来控制耦合度。

G9:死代码

        死代码就是不执行的代码。可以在检查不会发生的条件的if语句体中找到。可以在从不抛出异常的try语句的catch块中找到。可以在从不被调用的小工具方法中找到,也可以在永不会发生的switch/case条件中找到。
        死代码的问题是过不久它就会发出臭味。时间越久,味道就越酸臭。这是因为,在设计改变时,死代码不会随之更新。它还能通过编译,但并不会道循较新的约定或规则。它编写的时候,系统是另一番模样。如果你找到死代码,就体面地地埋葬它,将它从系统中删除掉。

G10:垂直分隔

        变量和函数应该在靠近被使用的地方定义。本地变量应该正好在其首次被使用的位置上面声明,垂直距离要短。本地变量不该在其被使用之处几百行以外声明。

        私有函数应该刚好在其首次被使用的位置下面定义。

G11:前后不一致

        小心选择约定,一旦选中,就小心持续遵循。

G12:混淆视听

        没有实现的默认构造器、没有用到的变量、从不调用的函数、没有信息量的注释等等,这些都是应该移除的废物。保持源文件整洁,良好地组织,不被搞乱。

G13:人为耦合

        一般来说,人为耦合是指两个没有直接目的之间的模块的耦合。其根源是将变量、常量或函数不恰当地放在临时方便的位置。这是种漫不经心的偷懒行为。花点时间研究应该在什么地方声明函数、常量和变量。不要为了力便随手放置,然后置之不理。

G14:特性依恋

        类的方法只应对其所属类中的变量和函数感兴趣,不该垂青其他类中的变量和函数。当方法通过某个其他对象的访问器和修改器来操作该对象内部数据,则它就依恋于该对象所属类的范围。它期望自己己在那个类里面,这样就能直接访问它操作的变量。

G15:选择算子参数

        算子可能是布尔类型、枚举元素、整数或任何一种用于选择函数行为的参数。使用多个函数,通常优于向单个函数传递某些代码来选择函数行为。

G16:晦涩的意图

        代码要尽可能具有表达力。联排表达式、匈牙利语标记法和魔术数都遮蔽了作者的意图。
例如,下面是overTimePay函数可能的一种表现形式:

public int m_otCalc(){
    return iThsWkd * iThsRte+ (int)Math.round(0.5 * iThsRte * Math.max(0, iThsWkd-400));
}


        它既短小又紧凑,但实际上不可捉摸。值得花时间将代码的意图呈现给读者。

G17:位置错误的权责

        代码应该放在读者自然而然期待它所在的地方。

G18:不恰当的静态方法

        通常应该倾向于选用非静态方法。如果有疑问,就是用非静态函数。如果的确需要静态函数,确保没机会打算让它有多态行为。

G19:使用解释性变量

        让程序可读的最有力方法之一,就是将计算过程打散成在用有意义的单词命名变量中放置中间值

        这事很难做过火。解释性变量多比少好。只要把计算过程打散成一系列良好命名的中间值,不透明的模块就会突然变得透明,这很值得注意。

G20:函数名称应该表达其行为

        如果你必须查看函数的实现(或文档)才知道它是做什么的,就该换个更好的函数名,或者重新安排功能代码,放到有较好名称的函数中。

G21:理解算法

        在你认为自己完成某个函数之前,确认自己理解了它是怎么工作的。通过全部测试还不够好。你必须知道解决方案是正确的。
        获得这种知识和理解的最好途径,往往是重构函数,得到某种整洁而足具表达力、清楚呈示如何工作的东西。

G22:把逻辑依赖改为物理依赖

        如果某个模块依赖于另一个模块,依赖就该是物理上的而不是逻辑再上的。依赖者模块不应对被依赖者模块有假定(换言之,逻辑依赖)。它应当明确地询问后者全部信息。

G23:用多态替代lf/Else或Switch/Case

        "单个switch"规则:对于给定的选择类型,不应有多于一个switch语句。在那个switch语句中的多个case,必须创建多态对象,取代系统中其他类似switch语句。

G24:遵循标准约定

        每个团队都应遵循基于通用行业规范的一套编码标准。编码标准维应指定诸如在何处声明实体变量,如何命名类,方法和变量,在何处放置括号等等。团队不应用文档描述这些约定,因为代码本身提供了范例。

G25:用命名常量替代魔术数
G26:准确

        在代码中做决定时,确认自己足够准确。明确自己为何要这么做,如果遇到异常情况如何处理。别懒得理会决定的准确性。如果你打算调用可能返回null的函数,确认自己检查了null值。如果查询你认为是数据库中唯一的记录,确保代码检查不存在其他记录。如果要处理货币数据,使用整数,并恰当地处理四舍五入。如果可能有并发更新,确认你实现了某种锁定机制。
        代码中的含糊和不准确要么是意见不同的结果,要么源于懒惰。无论原因是什么,都要消除。

G27:结构甚于约定

        坚守结构甚于约定的设计决策。命名约定很好,但却次于强制性的结构。

G28:封装条件

        如果没有if或while语句的上下文,布尔逻辑就难以理解。应该把解释了条件意图的函数抽离出来。

//例如:
if(shouldBeDeleted(timer))
//要好于
if(timer.hasExpired() && !timer.isRecurrent())
G29:避免否定性条件

        否定式要比肯定式难明白一些。所以,尽可能将条件表示为肯定形式。

G30:函数只该做一件事
G31:掩蔽时序耦合

        常常有必要使用时序耦合,但你不应该掩蔽它。排列函数参数,好让它们被调用的次序显而易见。

 =》

G32:别随意

        构建代码需要理由,而且理由应与代码结构相契合。如果结构显得太随意,其他人就会想修改它。如果结构自始至终保持一致,其他人就会使用它,并且遵循其约定。

G33:封装边界条件

        边界条件难以追踪。把处理边界条件的代码集中到一处,不要散落于代码中。

G34:函数应该只在一个抽象层级上

        函数中的语句应该在同一抽象层级上,该层级应该是函数名所示操作的下一层。

G35:在较高层级放置可配置数据

        如果你有个已知并该在较高抽象层级的默认常量或配置值,不要将它埋藏到较低层级的函数中。把它作为较高层级函数调用较低层级函数时的一个参数。

G36:避免传递浏览

        正确的做法是让直接协作者提供所需的全部服务。不必逛遍系统的对象全图,搜寻我们
要调用的方法。

17.5 Java

J1:通过使用通配符避免过长的导入清单
J2:不要继承常量
J3:常量vs.枚举

        别再用public static final int,而是使用枚举。

17.6 名称

N1:采用描述性名称
N2:名称应与抽象层级相符

        不要取沟通实现的名称;取反映类或函数抽象层级的名称。

N3:尽可能使用标准命名法
N4:无歧义的名称
N5:为较大作用范围选用较长名称
N6:避免编码

        不应在名称中包括类型或作用范围信息。

N7:名称应该说明副作用 

        名称应该说明函数、变量或类的一切信息。不要用名称掩蔽副作用。不要用简单的动词来描述做了不止一个简单动作的函数。

17.7 测试

T1:测试不足
T2:使用覆盖率工具
T3:别略过小测试
T4:被忽略的测试就是对不确定事物的疑问
T5:测试边界条件
T6:全面测试相近的缺陷
T7:测试失败的模式有启发性
T8:测试覆盖率的模式有启发性
T9:测试应该快速

17.8小结

        这份启发与味道的清单很难说已完备无缺。我不能确定这样一份清单会不会完备无缺。但或许完整性不该是目标,因为该清单确实给出了一套价值体系那套价值体系才该是目标,也是本书的主题所在。整洁代码并非遵循一套规则写就。学习一系列启发并不足以让你成为软件匠人。专业性和技艺来自于驱动规程的价值观。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1913459.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

极狐GitLab亮相世界人工智能大会,开启开源大模型赋能软件研发新时代

GitLab 是一个全球知名的一体化 DevOps 平台,很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab :https://gitlab.cn/install?channelcontent&utm_sourcecsdn 是 GitLab 在中国的发行版,专门为中国程序员服务。可以一键式部署…

IEC62056标准体系简介-3.IEC62056-62接口类(IC)

IEC62056-62接口类将IEC 62056-61对象标识系统中的数据项进行分类、归整,采用对象建模的方法构造了计量仪表通信的接口模型,规定了计量仪表的功能、数据显示和数据交换方式等,是COSEM核心组成部分。COSEM把计量仪表看成是公共事业部门商业过程…

包装器 std::function

使用前&#xff0c;包头文件&#xff1a;#include <functional> std::function 是 C标准库 中的一个通用函数包装器&#xff1b; 它可以储存、复制、调用任何可调用的对象&#xff0c;包括&#xff1a;函数指针、成员函数、绑定的成员函数、lambda表达式、仿函数等。 1…

Windows 网络重置及重置网络可能出现的问题( WIFI 没有了 / WLAN 图标消失)

netsh int ip reset 命令是用于重置 Windows 操作系统中的网络设置和配置的命令。 在网络故障排除、修复网络连接问题以及清除可能存在的网络配置冲突时非常有用。 命令详解&#xff1a; netsh: 用于配置各种网络设置 int: 用于管理网络接口 ip: 用于管理网络接口的 IP 配…

【C++】———— 多态

作者主页&#xff1a; 作者主页 本篇博客专栏&#xff1a;C 创作时间 &#xff1a;2024年7月8日 一、什么是多态 什么是多态呢&#xff1f;通俗的来讲&#xff0c;就是多种形态&#xff0c;具体点就是去完成某个行为&#xff0c;当不同的对象去完成时会产生不同的状态。 举…

AI推荐系统落地的实现与应用

目录 一、推荐系统的基础二、推荐系统的设计与实现三、推荐系统落地的挑战四、推荐系统的成功案例五、结语 AI推荐系统近年来在各个领域得到了广泛应用&#xff0c;从电子商务到娱乐&#xff0c;再到个性化学习平台。它们通过分析用户行为、偏好和历史数据&#xff0c;为用户提…

一举跃升!Cancer Discovery修正后IF30.6!

在科学出版界&#xff0c;影响因子&#xff08;IF&#xff09;被广泛认为是衡量期刊学术影响力的重要指标。每年6月&#xff0c;科睿唯安会发布期刊引证报告&#xff08;JCR&#xff09;&#xff0c;但这并不是最终结果。在10月份&#xff0c;JCR会进行统一的更新&#xff0c;包…

HTML+CSS+JS 实现3D风吹草动效果(B站视频)

效果&#xff1a; 代码&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>3D effect&…

一句话彻底搞懂Java的编译和执行过程

编译和运行可以在不同的计算机上实现。 编译阶段&#xff1a;由Javac编译器将 .Java 的源文件编译为 .class 的字节码文件&#xff1b; 运行阶段&#xff1a; jvm中Java编译器运行 .class 的字节码文件&#xff0c;运行过程中&#xff0c;类加载器从硬盘中找到该字节码文件并…

【LLM之Agent】ReAct论文阅读笔记

研究背景 论文介绍了 “ReAct” 范式&#xff0c;该范式旨在融合推理和行动的功能&#xff0c;通过让大型语言模型&#xff08;LLMs&#xff09;生成既包括言语推理轨迹又包括行动序列的输出&#xff0c;解决多种语言推理和决策任务。这种方法允许模型在与外部环境&#xff08…

WPF引入多个控件库使用

目的 设计开发时有的控件库的一部分符合我们想要的UI样式&#xff0c;另一部分来自另一个控件库&#xff0c;想把两种库的样式做一个整合在同一个控件资源上。单纯通过引用的方式会导致原有样式被覆盖。这里通过设置全局样式的方式来实现。 1.安装控件库nuget包&#xff1a;H…

万界星空科技日化行业MES解决方案

日化行业MES&#xff08;制造执行系统&#xff09;解决方案是针对日化行业特点而设计的一套全面的生产管理系统&#xff0c;旨在提高生产效率、优化资源配置、加强质量控制&#xff0c;并推动企业的数字化转型。以下是对日化行业MES解决方案的详细阐述&#xff1a; 一、MES解决…

8.5结构体嵌套结构体

代码 #include <iostream> using namespace std; #include <string>//结构体嵌套结构体//定义学生结构体 struct student {string name;int age;int score; }; //定义老师结构体 struct teacher {int id;//教师编号string name;//教师姓名int age;//教师年龄struc…

iPhone数据恢复篇:iPhone 数据恢复软件有哪些

问题&#xff1a;iPhone 15 最好的免费恢复软件是什么&#xff1f;我一直在寻找一个恢复程序来恢复从iPhone中意外删除的照片&#xff0c;联系人和消息&#xff0c;但是我有很多选择。 谷歌一下&#xff0c;你会发现许多付费或免费的iPhone数据恢复工具&#xff0c;声称它们可…

目标检测基本标注工具-labelImg安装与使用

&#x1f349;一、安装 1.1 打开conda创建虚拟环境&#x1f388; conda create -n labelImg python3.8 -y 1.2 激活labelImg虚拟环境&#x1f388; activate labelImg1.3 安装labelImg&#x1f388; pip install -i https://pypi.tuna.tsinghua.edu.cn/simple lab…

0号事件何处来?

暑假开始&#xff0c;格蠹开始对NDB调试器的新一轮升级。研发团队里&#xff0c;有几位新的面孔&#xff0c;包括远程的志愿者&#xff0c;还有新来格蠹的实习生。 本地调试Linux应用是新增的一个较大功能。为了支持这个功能&#xff0c;我们特意把本来集成在ndstub模块中的Lin…

通过一个 AI 产品的落地,掌握产品经理工作全流程

对于任何一家互联网公司来说&#xff0c;用户流失都是我们必须要关注的一个问题。 这篇文章&#xff0c;我就通过我一个预测用户流失的项目&#xff0c;带你了解一个 AI 产品从筹备到上线的全流程。 从中&#xff0c;你可以体会到 AI 产品经理的完整工作流程是什么&#xff0…

Science|N型半导体水凝胶(柔性半导体器件/柔性健康监测/导电水凝胶/柔性电子)

2024年5月2日,北京大学雷霆(Ting Lei)课题组在《Science》上发布了一篇题为“N-type semiconducting hydrogel”的论文。论文内容如下: 一、 摘要 水凝胶是一类具有可调机械性能、多样生化功能和良好离子导电性的生物界面材料,但由于缺乏半导体特性,使得水凝胶在电子学中…

气膜体育馆的空气质量控制系统智能化管理—轻空间

随着科技的不断进步&#xff0c;气膜体育馆在全球范围内得到了广泛应用。一个重要的原因是其先进的空气质量控制系统&#xff0c;这不仅提高了场馆内部环境的舒适度&#xff0c;也保障了使用者的健康安全。轻空间将详细探讨气膜体育馆的空气质量控制系统是如何实现智能化管理的…

阅读笔记——《Fuzz4All: Universal Fuzzing with Large Language Models》

【参考文献】Xia C S, Paltenghi M, Le Tian J, et al. Fuzz4all: Universal fuzzing with large language models[C]//Proceedings of the IEEE/ACM 46th International Conference on Software Engineering. 2024: 1-13.【注】本文仅为作者个人学习笔记&#xff0c;如有冒犯&…