不会飞的章鱼

熟能生巧,勤能补拙;念念不忘,必有回响。

代码之丑

坏味道

缺乏业务含义的命名

错误命名

  • 宽泛的命名
  • 用技术术语命名

命名遵循的原则

  • 描述意图,而非细节
  • 面向接口编程,接口是稳定的,实现是易变的
  • 命名中出现技术名词,往往是它缺少了一个模型
  • 使用业务语言

乱用英语

英语使用不当

  • 违反语法规则
  • 不准确的英语词汇
  • 英语单词拼写错误

解决方法

  • 制定代码规范
  • 建立团队词汇表
  • 经常性进行代码评审

重复代码

重复的代码

  • 复制粘贴的代码
  • 结构重复的代码
  • if 和 else 代码块中的语句高度类似

消灭重复代码的原则

  • 每一处知识都必须有单一、明确、权威地表述

长函数

长函数的产生

  • 以性能为由
  • 平铺直叙写代码
  • 一次增加一点点代码

消灭长函数的原则

  • 定义好函数长度的标准
  • 做好“分离关注点”

重构手法

  • 提取函数

大类

产生大类的原因

  • 职责不单一
  • 字段未分组

软件设计的原则

  • 单一职责原则

极致的追求

  • 每个类不超过2个字段

长参数

消除长参数

  • 参数数量多导致的长参数
    变化频率相同,则封装成一个类;
    变化频率不同:静态不变的,可以成为软件结构的一部分;多个变化频率的,可以封装成几个类。

  • 标记参数导致的长参数
    根据标记参数,将函数拆分成多个函数。

重构的手法

  • 将参数列表封装成对象
  • 移除标记参数

滥用控制语句

呈现形态

  • 嵌套的代码
  • else语句
  • 重复的switch
  • 循环语句

编程原则

  • 函数至多有一层缩进
  • 不要使用else关键字

重构的手法

  • 以卫语句取代嵌套的条件表达式
  • 多态取代条件表达式

缺乏封装

呈现形态

  • 火车残骸/过长的消息链
  • 基本类型偏执

编程规则

  • 遵循迪米特法则
  • 封装所有的基本类型和字符串
  • 使用一流的集合

重构的手法

  • 隐藏委托关系
  • 以对象取代基本类型

可变的数据

呈现形态

  • 暴露的细节
  • 可变的数据
  • 全局数据

编程规则

  • 限制变化
  • 尽可能编写不变类
  • 区分类的性质,实体对象要限制数据变化,而值对象就要设计成不变类

重构的手法

  • 移除设置函数

变量的声明与赋值分离

编程规则

  • 变量要一次性完成初始化

应对策略

  • 在声明前面加上final,用不变性的限制约束代码
  • 用声明式的方式进行集合的初始化

依赖混乱

呈现形态

  • 缺少防腐层,业务与外部接口耦合
  • 业务代码中出现具体实现类

应对策略

  • 引入防腐层,将业务与内部接口隔离
  • 引入模型,将业务与具体实现隔离

编程规则

  • 高层模块不应依赖于低层模块,二者应依赖于抽象。抽象不应依赖于细节,细节应依赖于抽象。

不一致的代码

呈现形态

  • 命名中的不一致
  • 方案中的不一致
  • 代码中的不一致

应对策略

  • 团队统一编码方案
  • 提取函数,将不同层次的内容放入不同函数中

落后的代码风格

具体案例

  • Java8引入的Optional
  • 函数式编程

核心要点

  • 引入Optional可以减少由于程序员的忽略而引发对空对象的问题
  • 懂得最基本的几个操作:map、filter和reduce,就可以把大部分集合操作转成列表转换

编程规则

  • 声明式编程
  • 写短小的函数,不要在lambda中写过多代码

总结

  • 好的命名,是体现业务含义的命名
  • 编写符合英语语法规则的代码
  • 不要重复自己,不要复制粘贴
  • 把函数写短,越短越好
  • 把类写小,越小越好
  • 减小参数列表,越小越好
  • 循环和选择语句,可能都是坏味道
  • 构建模型,封装散落的代码
  • 限制可变的数据
  • 一次性完成变量的初始化
  • 代码应该向着稳定的方向依赖
  • 保持代码在各个层面上的一致性
  • 不断学习“新”的代码风格,不断改善自己的代码
------ 本文结束------
如果本篇文章对你有帮助,可以给作者加个鸡腿~(*^__^*),感谢鼓励与支持!