Clean Code读后总结——前进者的基石

前言

作为一个程序员,再职业生涯中会写很多很多万行代码。感觉学习写代码的过程很像学习写作的过程,写大型软件就是在写一本长篇小说,那么如何定义好的代码,感觉就像是问说怎么写出好的文章。
那么什么是好的代码呢?对于产品人员来说,好的代码是只要能运行,不出现bug的就是好的代码,也就是所谓的说文以载道,诗以言志,至于辞藻是否华丽,不是最重要的。
但是别忘了,写代码的时间可能发现在那一刻,但是我们后面阅读自己代码的却经常进行,如果结构混乱,词不达意那么就往往会发生写到最后发现前面的情节都不慎了之了。
所以,写出好的代码的一个目的在于如何减少代码维护的成本,理解代码是其中之一。
另外,我们要知道没有人能够在跨度周期在几个月,甚至一年的时间内知道自己软件最后会具体怎么一个呈现。业务都是不尽相同的,根据排列组合我们没有办法一开始就穷尽所有的变化,所以我们总是会在原有代码的基础上不断修修改改,正如很多小说一样,一气呵成总是发生在极少数天才那里,即使是如红楼梦一样的惊世之作,也是批阅十载。
所以,总的来说,好的代码的原则也就是两点,一个是容易阅读,一个是容易修改。

相关内容

有意义的命名

程序代码里面除了一些约定熟成的关键字,大部分的英文字符都是被变量、函数、参数、类等构成的,而这些都是我们自己所赋予的。所以,容易阅读是命名最关注的东西,常见的一些tips如下:

  • 不要使用误导性的词语来进行命名,例如list,;,o等。
  • 在对同类型数据进行区分的时候,不要使用数字来进行。
  • 可搜索也是命名关注的点,无论是变量名还是文件名,包名等
  • 对于强类型语言来说,当前的编译环境来说(不用运行就能检测出类型错误),类型编码已经淘汰。
  • 成员前缀也是不必要的,因为都是看有意义的字段。
  • 类名和对象名应该是短语,而不应该是动词。如Customer等
  • 方法名应该是动词或动词短语。如postPayment。
  • 对于程序中经常出现的概念,取一个一以贯之的词,例如xx控制器,可以一直用controller,或者一直用manager。

函数

函数是对于程序逻辑的第一层封装,因此,同样也遵循易读,易修改原则,常见的一些tips如下:

  • 函数长度不宜过长,主要是容易阅读,同时函数越短,功能越集中,名字也更好取,更容易抽象,长而有描述性的名字比短名称好
  • 函数只做一件事,这是出于高内聚低耦合的考虑,同时也让代码更易修改,一处的改动不会影响到其他部分
  • 自顶向下阅读代码,这是处于易读的考虑,因此在对函数进行编写的时候,可以从上到下依次编写对应的抽象,再紧接着对应的实现。
  • 对于多态情况下的switch使用,对于对象不同行为的实现方式根据对象种类的不同会有n种 switch语句和对应的分支,同时违反了单一职责原则(多个修改的理由),以及开闭原则(添加和修改没办法解耦)。解决方法可以利用工厂模式,也就是对不同对象的行为定义一个统一的接口或者抽象类,将switch分支封装在工厂类下。
  • 函数参数一般是0-2最好,一个是处于理解成本的考虑,还有一个最重要的原因是多参数对于测试代码组合带来的复杂度。
    • 单参数:一般单参数有几种情况,一个是判断参数的问题,一个是将参数进行转换为另一种类型,还有就是事件。但是,对于一种传入bool的标识参数来说,这意味着在true和false的情况下都对应着不同的处理逻辑,也就是函数不只是做一件事,这是应该进行拆分为两个函数分开处理。
    • 双参数:双参数主要是注意两个参数的相对顺序,以及是否可以将两个参数转换为一个参数(成员)等
    • 参数列表:当函数需要两个及以上的参数类型,且这些组合经常出现的话,就意味着这写参数可以被封装为类了,这意味着对这组参数的封装。而对于可变参数类型,如果超过三个,那么和直接传递list类型的单个参数也没有分别,所以一般是1-3
    • 命名:对于单参数,直接采用动名词形式就好,对于双参数类型,可以在命名时记录参数的相对顺序。
    • 输出参数:在oop出现前,存在着向函数中传递参数的时候,也就是 方法名(参数),但是在oop后,可以直接利用this来代替输出参数,也就是利用 对象.防方法()的形式。
    • 在异常处理的时候,直接返回错误码会造成更深的嵌套结构,直接 try-catch返回异常就好,同时为了避免异常处理与正常流程混在一起,可以把try-catch的代码块主体抽离出来,另外形成函数。

对象与数据结构

  • 数据抽象: 不愿意暴露具体操作数据实现的逻辑可以利用函数进行一次封装。
  • 过程式代码(数据结构代码)和面向对象代码的不同在于过程式代码可以在不修改原有代码的基础上新增方法,而面向对象更适用于新类型的添加。
  • 数据传送对象:DTO,只有公告变量,没有函数的类。通常用于与数据库通信的部门。

  • 类的抽象也应该符合单一职责,也就是只有一个修改的理由。理想的状态是多个短小的类互相协同而不是少数巨大的类。
  • 类的内聚一方面体现在内部方法对于内部变量操作的程度,操作的变量越多,说明变量越黏聚在类上,这将得到许多短小的类。
  • 隔离依赖主要在于怎么对容易变更的部分进行抽象,提供接口等等。

系统

  • 将系统的构造与使用分开,否则如果在程序中有许多种类似的情况,根据全局设置策略就会缺乏模块组织性,通常也会有很多重复代码。
  • 一个方法是将全部的构造过程搬迁在main函数中进行处理 ,mian函数创建系统需要的对象,再传递给应用程序,只管使用。
  • 对于大型软件的编写来说,一开始就将所有的组件和系统构造得很好是很难的,我们应该只去实现今天的用户故事,在后续再不断地扩展系统,实现新的用户故事,这也是迭代和重构。

迭进

这一部分其实主要就是说一点,在代码和模块越来越多的时候也,不断重构。

代码的坏味道

  • 注释
    • 不恰当的信息:无用的,重复的
    • 废弃的注释:过时的注释意味着代码的跌进后注释并没有怎么改变
    • 注释掉的代码
  • 环境
    • 多步实现的构建 : 单个命令进行系统的签出
    • 需要多步才能做到的测试:应该能够使用单个指令就可以运行全部的单元测试
  • 函数
    • 过多的参数:参数0-3差不多
    • 输出参数:如果函数要修改什么变量的状态,直接修改它所在的对象的状态就好了
    • 布尔值参数:这使用函数不止做了一件事
  • 一般性问题
    • 不正确的边界行为:在开发的时候,不要只写出能工作的函数,也要考虑或证明代码在所有的边界情形下都能真正工作。
    • 重复:重复的代码可能会是一个子程序或者一个类,出现在概念上重复的代码意味着抽象的遗漏。
    • 在错误的抽象层级上的代码:在继承关系中,注意将较低层级概念放在派生类中,较高层级概念放在基类中。比如说只与细节实现有关的常量,变量或者工具函数不应该在基类中出现。软件设计要求分离不同层级的概念,放在不同的容器中,这些容器有时是基类或派生类,有时是源文件模块或组件,不管如何,底层级概念不能和高层级概念混在一起。
    • 基类依赖派生类:主要在有限状态机的实现中会出现这样的问题。
    • 位置错误的权责:例如很多变量应该放在哪里的问题,根据最小惊异原则,变量应该放在读者期望它在的地方,或者看函数名称。
    • 不恰当的静态方法:静态方法不应该在单个实体上操作,而更多作为一个工具函数的作用不与特定对象绑定,另外对于一些需要多态实现的方法,也应该使用非静态函数。
    • 函数名称应该表达其行为
    • 用多态替代if/else或者switch/case:在使用switch之前,先考虑使用多态。或者在case语句中,创建多态对象,避免对于多个方法选择上使用多个switch的情况。
    • 封装条件:将关于条件判断的表达式进行封装会更容易理解
    • 避免否定性条件:使用肯定性条件会更好
    • 函数应该只做一件事:函数不应该只做一件事,应该转换为多个更小的函数
    • 掩盖时序耦合:这种情况下,使用有参返回也可以。
    • 在较高层级上放置可配置数据

总结

在编写大型软件的时候,我们常常对于过高的复杂度以及过高的理解成本而望而却步,这直接影响了我们代码跌进的速度和效率,软件开发是一个增量跌进的过程,因此,降低每一个环节的理解成本和减少每一个模块之间的耦合就是我们的终极目的,也是一个良好的编码习惯的养成。在这个基础上,去看看其他更美丽的风景吧。

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

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

相关文章

Helix QAC 2023.4 新版支持C++20语言,带来更多性能提升!

Helix QAC 2023.4 新增功能 Helix QAC 2023.4全面支持MISRA C:2023规则,涵盖100%的指南。此版本还加强了对C20语言的支持,改进了数据流分析性能,并在整个产品中增加了多项用户体验改进。 增强的C20支持 此版本新增了对以下语言特性的支持&a…

代码随想录算法训练营Day28|93.复原IP地址、78.子集、90.子集II

93.复原IP地址 题目链接&#xff1a;93.复原IP地址 文档链接&#xff1a;93.复原IP地址 视频链接&#xff1a;回溯算法如何分割字符串并判断是合法IP&#xff1f;| LeetCode&#xff1a;93.复原IP地址 C实现 class Solution { private:vector<string> result;bool isVal…

vscode设置python脚本运行参数

1 添加配置文件 点击到你要配置的python文件&#xff0c;然后右上角点击 运行 &#xff0c;再点击 添加配置 再点击 “Pyhton文件” 选项&#xff08;其实就是在选择 当前的python文件 进行配置&#xff09; 接着就生成了配置文件 lanunch.json 2 参数配置 再上面代码的基础上…

c++语言基础20-排队取奶茶(堆)

题目描述 假设有一家奶茶店&#xff0c;现在有一些人在排队等待取奶茶&#xff0c;同时也有人在取奶茶。 请你设计一个程序模拟这种情况下的奶茶队列管理。假设每个人取奶茶的时间非常短&#xff0c;可以忽略不计&#xff0c;只需要考虑队列中的操作。 队列操作说明&#xff1…

Guava:Cache强大的本地缓存框架

Guava Cache是一款非常优秀的本地缓存框架。 一、 经典配置 Guava Cache 的数据结构跟 JDK1.7 的 ConcurrentHashMap 类似&#xff0c;提供了基于时间、容量、引用三种回收策略&#xff0c;以及自动加载、访问统计等功能。 基本的配置 Testpublic void testLoadingCache() th…

6 - 数据备份与恢复|innobackupex

数据备份与恢复&#xff5c;innobackupex 数据备份与恢复数据备份相关概念物理备份与恢复逻辑备份&#xff08;推荐&#xff09;使用binlog日志文件实现对数据的时时备份‘使用日志 恢复数据 innobackupex 对数据做备份和恢复增量备份与恢复 数据备份与恢复 数据备份相关概念 …

EPICS scanparm记录和相关软件

概要 本文档描述EPICS scanparm记录&#xff0c;以及构建和使用它所需的相关EPICS软件。此版本的记录兼容EPICS 3.14.8.2&#xff0c;而不兼容任何EPICS 3.13.x版本。 scanparm记录存储了为了将它们写入到EPICS sscan记录的参数&#xff0c;并且项EPICS终端用户提供了一种装载…

Tomcat服务实例部署

目录 **Tomcat 由一系列的组件构成&#xff0c;其中核心的组件有三个&#xff1a;** 什么是 servlet&#xff1f; 什么是 JSP? Tomcat 功能组件结构&#xff1a; Container 结构分析&#xff1a; Tomcat 请求过程&#xff1a; ## Tomcat 服务部署 1.关闭防火墙&#xf…

golang学习-流程控制

if else 建议条件不用()包裹&#xff0c;if{}不能省略&#xff0c;{}中的{必须紧靠着条件 go语言中没有while循环&#xff0c;可以通过for 代替 age : 30if age > 18 {fmt.Println("我是大人")}//另一种写法if age : 99; age > 18 {fmt.Printf("年龄是%v&…

一、数据结构

一、 数组 1.1 数组 定义 遍历 // 遍历数组 传递指针 func traverse() {var b [...]int{1, 2, 3} //长度为3 元素为 1 2 3var ptr &b //ptr是指向数组的指针fmt.Println(b[0], b[1]) // 打印数组的前 2 个元素fmt.Println(ptr[0], ptr[1]) // 通…

UDS统一诊断服务读取DTC信息0X19服务

概念 UDS(Unified Diagnostic Services)统一诊断服务中的0x19服务是用于读取诊断故障代码(DTC,Diagnostic Trouble Code)信息的服务。DTC是车辆故障诊断系统中的重要部分,当车辆发生故障时,相应的DTC会被存储在ECU(电子控制单元)的故障代码存储器中。 0x19服务包含了…

CMake入门教程【核心篇】导出项目库

概述 CMake是一个跨平台的自动化构建系统,它使用配置文件(CMakeLists.txt)来管理软件构建过程。如何使用CMake导出静态库(.a)和动态库(.so/.dll)。 #mermaid-svg-cnd9qfr6rFQgQRNR {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fil…

解读MyabtisPlus中的R类(通用响应包装类)

目录 前言1. 概念2. 源码解读3. Demo 前言 大部分R类可以自已手写一个适配的&#xff0c;但MybatisPlus中有专门的R类&#xff0c;于是就使用封装好的类即可 1. 概念 通用R类是一种用于处理API响应的通用响应包装类。 概念含义作用示例用途1.R类是一个泛型类&#xff0c;可…

C/C++汇编学习(六)——数据结构汇编实例:链表、树、图。

我们继续开展 目录 一、链表 1. C代码 2. 链表部分转为汇编并注释 二、树 1. C代码 2. 链表部分转为汇编并注释 3. 汇编伪代码 三、图 1. C代码 2. 汇编伪代码 四、总结 一、链表 1. C代码 #include <iostream>struct ListNode {int data;ListNode* next;…

vue 前端等比例压缩图片(再转换成文件后上传后端)

前端压缩图片总的来说还是转base64 然后等比例放小宽和高 这个是上次压缩图片的一个扩展 压缩完之后 再将base64 转成blob再转成文件然后再上传 一生要强的前端崽子&#xff08;后端不支持base64上传&#xff09; 自己改吧改吧 // 图片上传async changePic(e) {this.isshang…

【Docker】Docker基础

文章目录 安装使用帮助启动命令镜像命令容器命令 安装 # 卸载旧版本 sudo yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-engine # 设置存储库 sudo yum install -y yum-utils …

关于git使用的tips

前言 这里是一些git指令使用的tips&#xff0c;如果你作为初学者的话&#xff0c;我认为它将对你有所帮助。 常见指令 常见问题处理 1、使用git clone下载【huggingface.co】资源超时或无法请求问题 绝大多数情况是网络问题&#xff0c;首先如果是比较大的资源&#xff0c;你需…

数据库:如何取消mysql的密码

因为调试MySQL数据接口&#xff0c;总是需要输入密码很烦&#xff0c;所以决定取消mysql的root密码&#xff0c; 网上推荐的有两种方法&#xff1a; 1、mysql命令 SET PASSWORD FOR rootlocalhostPASSWORD(); 2、运行 mysqladmin 命令 mysqladmin -u root -p password …

C# 错误: 集合已修改,可能无法执行枚举操作

出错原因是使用了RemoveAt()函数移除了数据中的某一个数&#xff0c;导致数据发生了错位&#xff08;参考链接一&#xff09; 解决方案&#xff1a; 第一种解决方法&#xff1a;使用for循环 第二种解决方法&#xff1a;调用ToArray()方法&#xff0c;然后再进行foreach循环 …

vue设置height:100vh导致页面超出屏幕可以上下滑动

刚开始设置的height:100vh&#xff0c;就会出现如图的效果&#xff0c;会出现上下滚动 <template><view class"container">......</view> </template><style lang"scss">.container {height: 100vh;} </style> 解决方…