代码的坏味道

代码的坏味道

这篇文章根据马丁福乐的重构一书, 来做了一点自己的总结.

1 神秘的命名 Mysterious Name

无论是在动态语言还是静态语言, 见名知意, 明确地命名是极为重要的;

尤其是变量名要准确, 辨识度高.

在开发中中遇到过这样的代码 (下面是伪代码)

@user = UserCommon.find....
user = SubMobileUser.find ...

都是user, 但是代表的不是同一个类的实例对象;

使用时非常容易混淆.

2 重复代码 Duplicated Code

代码设计中一大原则就是 不要重复你自己. Don’t Repeat Yourself!

有类似的逻辑, 或者仅仅有细微的差别.
可以通过传入参数, 改变调用顺序等方式, 把类似的逻辑提炼函数, 统一地调用.
而不是, 混在一起, 有重复的逻辑.

def check
end

def update_r
	check
	....
end

def create_r
	check
	....
end

3 过长的函数 Long Function

过长的函数. Rails 中规定一个函数不能超过10+ 行.
一个函数, 如果超过20行, 那么这个函数往往就会涉及到比较复杂的处理;
而复杂的处理, 往往是可以拆分的, 也是需要拆分的;

小方法, 它会更易于组合, 理解. 当然, 方法的命名尤其重要, 见名知意.
而且, UT做起来也方便!

这个可以通过 rubocop等工具来强制方法不能超过多少行.

4 过长的参数列表 Long Parameter List

一个方法, 往往有几个参数. 但是, 最好不要超过三个.
一旦参数过多, 往往会造成很大的心智负担, 去追踪参数的来源和类型.

那么, 如何减少参数呢?

用查询替代参数, 如果参数a , 可以通过参数b 的查询得到, 那么就没有必要传入参数a
多个参数对象化, 看看能不能把相关联的参数处理成一个对象
子类对象, 数组存储. 如果要处理多个有相同方法的对象, 可以放到一个数组中循环处理.

5 全局数据 Global Data

全局数据是非常危险的!
因为, 我们不知道哪里会去修改它. 很难去定位到问题出现在哪里.

我们要尽可能地减少使用全局变量. 如果一定要使用, 那么也要读写分离.

对于更改全局变量的方法进行封装. 统一调用.

如果是不可修改的全局变量, 危险性稍小. 但是, 也要尽可能地避免

6 可变数据 Mutable Data

变量的作用域越大, 越容易出现问题.

变量是可以更改的, 可能不知道哪里改变了它.
这里和 5 差不多. 只不过, 这里强调的是局部的变量, 对象.

Vuex 是一个全局的state 管理工具. 一般情况下, 要尽可能地少用Vuex.

它往往意味着, 修改位置的不确定. 影响范围较大.

Vuex的文档中也推荐将修改的方法单独写到一个方法里. 然后调用修改的方法.

让state读写分离.

写ruby 方法, 也应该是这样的. 查询, 修改应该放到不同的方法中去.

7 发散式的变化 Divergent Change 待完善

当一个模块因为不同的原因需要在不同的方向上修改, 发散式的变化就要出现了.

每次只关心一个上下文

这一块, 我还不太清晰, 现在就不妄言了.

8 散弹式修改 Shotgun Surgery

如果一个需求, 需要在多个类中做出修改, 哪怕是很小的修改, 那也是不应该出现的;
因为, 人是容易遗漏的, 一次性要修改多个地方, 往往就会造成难以测试的问题.

此时, 要把变化的地方组合成到一个模块中, 或者抽取成类. 把本不该分散的逻辑放到一个地方.
统一调用, 这样可以仅仅修改一处. 降低了人为失误的概率.

9 依恋情结 Feature Envy

模块化的目的就是区分代码, 最大化的内部交互, 最小化的跨区域交互.
如果说, 在一个模块中函数和另外一个模块中的函数交流要超过自己模块中的函数.

那么, 就出现了依恋情结.
在开发过程中, 总会出现一个model里去调用其它几个model中的方法.

那么, 这种情况怎么处理呢?
把多个操作, 放到操作次数最多的那个model里面.

或者, 写到一个中间层里面, 去调用中间层的方法.

10 数据泥团 Data Clumps
我们总能看到, 相同的三四个数据项: 两个类中有相同的字段,许多函数签名有相同的参数.

这些总是绑在一起的数据参数, 应该有它们自己待在的地方.

把出现相同数据项的地方, 封装到一个类中, 调用这个类的对象去处理.

然后, 再尝试把函数迁移到这个类中.

11 基本类型偏执 Primitive Obsession

这一点, 我是深有体会.
在开发中中, 有很多的流程, 完全没有利用面向对象. 基本上和面向过程的写法一样.
一大串代码直接写下来, 很多逻辑看起来恶心. 另外, 还有极大可能造成重复的逻辑.

在开发中, 做到一个排名的需求, 很多排名的条件都是硬写出来的.

这些条件的各个参数都有它们相同的地方, 它们都有平均数, 总数, 占比等类似的参数.

如果把它们写成一个个对象, 那么就会非常的好处理了

一个简单的数据, 但是有较为复杂的逻辑, 那么把它封装成类, 是一个好方式.

例如, 电话号码, 它有区号, 有分机号, 有国家编号等等. 如果只是把它当作一个字符串来处理

那么, 面对复杂的场景就会不好处理. 当然, 如果现阶段用不上, 也没有必要封装,
但是一旦有类似的需要, 那么一定要积极地把它变成一个类.

12 重复的switch Repeated Switch

switch 并不是不可使用, 而是, 我们不要有重复的switch.

同理, if else 也是这样, 不要写相同的逻辑判断, 应该把它们封装成方法.

另外, 多态替代 switch, 是一个很好的选择.

13 循环语句 Loops

循环语句可以使用管道符来替代. 例如: map, filter, each

14 累赘的元素 Lazy Element

不要为了封装而封装. 根据真实的需要, 去封装.
但是, 这一点难以甄别, 未来的变化.

15 夸夸其谈的通用性 Speculative Generality

我们在写代码的时候, 有时候会为未来, 来添加许多现阶段用不到的hook和一些特殊处理.
但是, 如果这些代码在整个系统中都没有体现, 那么, 就要考虑是否要移除它了;

我认为, 最好的代码就是没有一行代码是无用的. 没有用到的代码, 只会平添心智负担.

16 临时字段 Temporary Field

临时字段, 如果可以使用查询替代临时字段
但是, 代码中一定不要有没有用到的临时变量. 会让之后的人莫名奇妙.

当然, 现在的一些静态代码检查, 可以避免上述情况.
但是, 我们也要养成习惯, 删除一些无用的代码.

17 过长的消息链 Message Chain

消息链, 在ruby 代码中, 我经常看到.
最经典的例子就是, 在开发中一行代码写的老长.

一个方法接着一个方法地调用, 并不是说这样的形式不好.
而是, 这种代码理解起来有一些心智负担. 而且, 有修改的话, 会不灵活.
但是, 确实写起来比较爽. 最好还是可以提炼成一个函数, 而非一直调用方法链.

18 中间人 Middle Man

委托是一种常见的封装方式, 例如: 我想和主管开个会议, 我应该先去 一个记事本看看哪个时间段主管有空.
而没有必要直接去问主管.
那么, 这个行为就是 委托.

如果, 过度使用委托, 把很多方法都放到了中间人(例子中的 记事本), 那么就有必要做一些处理了.
如果, 委托的方法很少, 那可以直接内联到这个类中.
如果, 很多, 那么应该把这些行为和状态封装成对象.

19 内幕交易 Insider Trading

模块与模块之间的交流必不可少.
我们要尽可能地把这些交流, 放到明面上去.

这个坏味道, 我并没有实践上的看法.
还没处理过类似的问题.

20 过大的类 Large Class

如果想利用一个类做太多的事情, 那么必然会导致一个文件中代码太多.
而且, 往往会导致代码重复, 混乱最后导致困局.

在开发中中, employee.rb中那代码长得几乎没法看.
很多方法, 虽然rails 提倡fat model. 但这样代码逻辑还是比较混乱的.
例如一个用户的权限判断, 就可以单独拆成一个员工权限类, 来处理各种权限的控制.
要试着提炼类.

21 异曲同工的类 Alternative Classes with Different Interfaces

使用类的好处就是可以替换, 今天用这个类, 明天就可以用那个类.
当然, 这里前提是函数的签名一致. 在搬迁函数的过程中, 如果发现有相同的行为,

可以试着提炼成超类.
这里, 我也不太清楚. 没有遇到实际的例子.

对于相同的行为, 我想使用多态就好了. 那么, 应该是很少出现, 函数签名一致, 却不属于同一个类的把

22 纯数据类 Data Class

如果一个类中仅仅有字段相关的get, set函数.
那么, 你就要考虑是不是有建立这个类的必要性了.

是不是使用一个工厂方法替代会好一些

23 被拒绝的遗赠 Refused Bequest

这里谈到了接口, ruby中没有接口.
在java中有.继承体系中, 子类需要实现父类的接口.

如果, 不能需要考虑换一个继承体系.

24 注释 Comments

注释是一定要写的.
但是, 也可以试着减少注释. 尝试把注释的内容封装成要给方法.

那么, 注释的作用就没有那么大了, 甚至可以去掉.

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值