代码的坏味道

神秘命名

整洁代码最重要的一环是好的名字,随便的命名会让人在阅读代码时不能第一时间明白你写这个代码的意图是什么,给理解代码造成困难。所以在编写代码时给函数、模块、变量和类命名时,要能清晰地表明自己的功能和用法。

重复代码

如果你在一个以上的地方看到相同的代码结构,说明你要设法将它们合二为一。如果重复的代码只是相似而不完全相同,则将相似的代码提炼出来。

过长函数

函数越长,就越难理解。如果分解为小函数的话,要让代码容易理解关键还是要有好的命名。
分解函数的原则:每当感觉需要写一段长注释来说明什么的时候,就把需要说明的东西写进一个独立的函数,并以其用途命名。

过长参数列表

  • 如果你正从现有的数据结构抽出很多数据项作为参数,那么还是把整个数据结构传过去。
  • 如果有几项参数总是同时出现,可以将其合并成一个对象作为参数传过去。
  • 如果有一个标记参数是用来区分执行函数哪一部分代码时,可以将函数拆分开来,这样就可以移除这个标记参数。
  • 如果多个函数有同样的几个参数,可以将函数放在一个类,然后将参数变成这个类的成员属性。

全局数据

全局数据容易造成不容易追查的bug,所以最好把全局数据一个用函数封装起来,然后只能通过函数调用访问全局变量。

可变数据

可变数据和全局数据的问题差不多,所以还是使用函数去访问与修改数据,使其更容易监控和演进。

发散式变化

发散式变化就是如果一个模块因为新增了某些变化便要去改变几个地方的代码。比如新增了数据库,便要去修改几个函数。好的代码应该在每次修改时只关注一个点,比如新增数据库就是数据库的逻辑,而不必修改到使用数据库的函数。

霰弹式变化

玩过枪战类游戏的应该知道霰弹枪,它一发子弹会分成多发子弹射出,造成大范围打击。用来比喻代码就是有一处变化了,便需要去大范围地修改分散在各处的代码。
霰弹式变化与发散式变化相似,不同的地方在于,发散式是更改一个类便需要更改一个类涉及的地方,霰弹式就是更改多个类涉及的多个地方。

依恋情结

当你判定某个函数应该归属于一个类时,但发现另外一个类和这个函数的数据交流很频繁,超过了这个函数的现任,这就是依恋情结的情况。
处理这种情况的原则就是:判断哪个模块拥有此函数使用的数据最多,便将这个函数和数据放在一起。

数据泥团

数据项总是成群结队地待在一起,我们常在很多地方看到相同的几项数据。这些绑在一起出现的数据应该拥有属于它们的对象。

基本类型偏执

大多数的编程环境都大量使用基本类型(如整数、浮点数、字符串等),我们基本不会去创建对自己问题有用的基本类型(如钱、坐标、范围等),而更愿意去使用if()去限定数据的范围。

重复的 switch

当你在不同的地方反复使用同样的 switch 逻辑(switch/case 或者连续的 if/else)时,一当想要增加一个选择分支,则必须修改所有的 switch。多态可以改正这种坏习惯。

循环语句

我们常用到循环,现在有了新的函数,例如 php 的 foreach(),java 的管道操作(如 filter 和 map),可以帮助我们更快地处理数据。

冗赘的元素

给代码增加结构(如类和函数)可以支持变化、促进复用。但可能最初在编写类或函数时觉得以后可能会变得更大、更复杂,结果却越变越小,最后剩一个函数,那么这时便要考虑将其归并到其他地方了。

夸夸其谈通用性

如果你总是觉得“总有一天需要做这事”,然后企图以各种各式各样的钩子和特殊情况来处理一些事情,那么坏代码就出现了,这样做往往造成系统更加难理解和维护。
应该遵循这样的原则:如果所有的装置都会被用到,那就值得那么做,如果用不到,就不值得。

临时字段

有时某个类的某个字段仅为某种特定情况而设,这样的代码不容易理解,因为你通常认为对象在所有时候都需要它的所有字段,在字段未被使用的情况下猜测当初设置它的目的,会让你很疑惑。
最好是将这个字段和与这个字段相关的代码集中在一块。

过长的消息链

如果你看到用户向一个对象请求另一个对象,然后再向后者请求另一个对象,接着继续请求另一个对象......这就是消息链。这意味着代码紧耦合,一旦对象间的关系发生变化,那么客户端就得做出相应的修改。
通常是将调用对象的代码用函数封装起来,这样客户端不需要知道对象间的关系,只需要知道调用这个函数就可以返回最终需要的对象。

中间人

前面消息链讲到的封装如果使用不恰当,可能会造成过度使用,这时应该移除中间人(封装的函数),直接与真正负责的对象打交道。

内幕交易

模块之间大量交换数据,增加模块间的耦合,应当尽量减少这种情况。

过大的类

如果单个类做太多事情,往往会出现很多字段与重复代码。最好是将相关的变量提到新类,或者提炼相同的代码到函数去。

异曲同工的类

当存在不同的类却在做同样的事时,可以通过搬移函数到其中一个类,逐渐消灭另一个类。

纯数据类

纯数据类是指除了拥有一些字段和访问这些字段的函数之外,便没有其他用处了。可以尝试找出这些函数被调用的地点,尽量将调用行为搬移到纯数据类来。

被拒绝的遗赠

子类应该继承超类的函数和数据,如果存在子类不想继承的,说明继承体系设计错误。这时可以新建一个兄弟类,将不需要的函数推给兄弟类,这样超类就只持有子类共享的东西。
子类不想继承超类的接口与不想实现超类的接口是两回事,既然不想继承,那就直接画清界限吧。

注释

如果你发现一段代码有着长长的注释时,说明这段代码难以理解,此时需要将代码搬移到新函数,并为它取个说明这段代码用途的名字。

讨论数量: 0

请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!