《clean code》中对一些代码中坏味道(bad smell)的总结,在编写代码的过程中应该多注意不要出现列表中的问题,使代码具有更高的可读性。
欢迎大家来我的个人博客玩耍~
https://xuchang-x.github.io/
转载请注明出处:https://blog.youkuaiyun.com/weixin_37587973/article/details/110137123
环境
- 需要多步才能做到的环境
- 构建系统应该可以用单个命令运行,其本身应该是单步的小操作,但不应该依赖一系列指令或环境依赖脚本,不应该到处寻找额外的jar、xml等。
- 需要多步才能做到的测试
- 测试应该可以快速运行
JAVA
- 不要继承常量,而应该使用静态导入。在某个接口中放置了常量,在深层级继承类中使用会很困惑这些常量的来源。
- 减少常量的使用,更多的使用枚举类。
函数
- 过多的参数
- 输出参数违反直觉,与函数命名不符
- 标识函数,通过布尔值在函数中做多个功能,这类函数违反单一权责原则
- 死函数(永远不会被调用的函数)
名称
- 采用描述性名称
- 名称应与抽象层级相符
- 尽可能使用标准命名法。如采用装饰器模式,就该以Decorator结尾
- 使用没有歧义的名称
- 为较大作用范围选用较长的名称。如for循环中
for(i)
,如果循环体中逻辑复杂,应该选用有意义的命名 - 避免编码。不应在名称中包括类型或作用范围信息。
- 名称应说明带来的副作用。也就是应该准确的描述其实现的所有功能。
注释
- 不恰当的信息,如作者、修改历史等信息
- 废弃的注释
- 冗余注释,用解释一段可以充分自我解释的代码,那么注释就是多余的
- 糟糕的注释,注释应该足够简洁,甄字酌句。
- 注释掉的代码
一般性问题
- 一个源文件中存在多种语言。如java中包括XML、HTML、YAML等。
- 理应被实现的行为未被实现。如将日期翻译成该日期的枚举类,我们希望Monday可以翻译,也希望缩写可以翻译,同时还希望忽略大小写。如果以上的功能没能实现,用户就需要阅读代码细节而不是依靠对函数名的直觉。
- 不正确的边界行为。不要依赖直觉,未各种边界条件编写测试,确定函数确实符合预期。
- 忽视安全。不要关闭测试然后告诉自己过后处理。
- 重复。DRY原则(Don’t Repeat Yourself,别重复自己)。
- 在错误的抽象层级上的代码,如细节实现有关的常量、变量或工具函数不应在基类中出现。这个原则对源文件、组件和模块也适用,不同层级对概念应该分离到不同的容器中。
- 基类依赖与派生类。基类概念不应该依赖较底层派生类的概念。
- 信息过多。一个类中的方法越少越好,一个函数知道的变量越少越好。
- 死代码(不执行的代码)。
- 垂直分隔。 变量和函数应该在靠近被使用的地方定义。
- 前后不一致。
- 混淆视听。比如没有用的变量、从不调用的函数、没有用的注释和一切应该移除的代码。
- 人为耦合。不相互依赖的东西不该耦合,一般人为耦合的根源是将变量、常量或函数不恰当地放在临时方便的位置。
- 特性依赖。类的方法应该只对其所属类的变量和函数感兴趣感兴趣,不应该访问其他类中的变量和函数。
- 选择算子参数。不要在函数中使用标识位(布尔、枚举、整数等等)。
- 晦涩的意图。代码应该尽可能具有表达力。
- 位置错误的权责。仔细考虑代码应该放在哪里,深入思考类、函数和变量的命名,避免误解。
- 不恰当的静态方法。通常应倾向于选用非静态方法,如果拿不准应该使用哪一种,那么就选用非静态方法。
- 使用解释性变量。让程序可读的最有力的方式之一就是将计算过程打散,并通过有意义的单词命名中间值。
- 函数名称应该表达其行为。如果必须通过查看实现或文档才能知道函数是做什么的,那就应该换个更好的函数名。
- 理解算法。在实现某个函数前应该深入理解它工作的方式,通过全部测试只是最低要求,应该用优雅的方式实现,而不是if-else的堆砌。
- 把逻辑依赖改为物理依赖。如果某个模块依赖另一个模块,那就应该通过调用该模块方法的方式查询相关信息,而不是直接调用该模块中的某些数据结构。
- 用多态替代If/Else和Switch/Case
- 遵循标准约定。如团队中的标准。
- 用命名常量替代魔术数(难以理解的符号)。
- 准确。比如第一次匹配不等于唯一匹配、浮点数不能直接用在货币计算上、某些行为应该使用事务等等,编写代码应该在恰当的位置使用准确的方式。
- 结构强于约定。比如用到良好命名的Switch/Case要若愚拥有抽象方法的基类。没人强迫每次一同样的方式实现Switch/Case,但实现类中必须实现基类中的方法。
- 封装条件。如布尔条件难以理解,应该把解释了条件意图的函数抽离出来。
- 避免否定性条件。尽可能将条件表达式表示为肯定形式。
- 函数只该做一件事
- 掩蔽时序耦合。需要按序调用的函数应该让调用次序显而易见,每个函数都传出下一个函数所需的结果,这样一来就没理由不按顺序调用了。
- 别随意。代码的组织和构建(如方法应该放在哪个类中)需要理由,不要随意堆砌。
- 封装边界条件。边界条件难以追踪,把边界条件的代码集中到一处,不要散落在代码中。
- 函数应该只在一个抽象层级上。函数中的语句应该在同一抽象层级上,不要混淆层级。
- 在较高层级放置可配置数据
- 避免传递浏览。模块应该只了解其直接协作者,而不是整个系统的游览图。
测试
- 避免测试不足
- 使用覆盖率工具
- 不要略过小测试
- 被忽略的测试就是对不确定事务的疑问
- 全面测试边界条件
- 全面测试相近的缺陷。缺陷趋向于扎堆,在某个函数中发现一个缺陷时,最好全面测试那个函数。
- 测试应该快速
最后再次期待大家来我的个人博客玩耍呀~
https://xuchang-x.github.io/