《代码之丑》学习总结

一、13类典型坏味道

01 | 缺乏业务含义的命名:如何精准命名?

  • 不精准的命名:主要体现在命名过于宽泛,不能精准描述,这是很多代码在命名上存在的严重问题,也是代码难以理解的根源所在,所以命名要能够准确的描述出这段代码在做的事情
  • 技术术语命名:在实际的代码中,技术名词的出现,往往就代表着它缺少了一个应有的模型。在一个技术类的项目中,这些技术术语其实就是它的业务语言。但对于业务项目,这个说法就必须重新审视了。

总结:好的命名,是体现业务含义的命名。在我看来命名做到不言自喻就可,让后来者看到你的命名就大致知道这段代码的大致详情即可。

02 | 乱用英语:站在中国人的视角来看英文命名

  • 违反语法规则的命名:常见的命名规则是:类名是一个名词,表示一个对象,而方法名则是一个动词,或者是动宾短语,表示一个动作。
  • 不准确的英语词汇:最好的解决方案还是建立起一个业务词汇表,千万不要臆想(可以在开发前,专门开会制定业务词汇表,这样大家均用同一套词汇,更利于开发。用集体智慧,而非个体智慧。)
  • 英语单词的拼写错误:常见问题,可能是粗心大意,一般开发工具会提示,但是还是会出现。

总结:编写符合英语语法规则的代码。在我看来该坏味道其实就是自身细心程度和团队开发的整体性问题,集大家之想,必将降低问题的出现

03 | 重复代码:简单需求到处修改,怎么办?

  • 复制粘贴的代码:不要使用复制粘贴。真正应该做的是,先提取出函数,然后,在需要的地方调用这个函数。复制粘贴的代码是一颗随时可能爆炸的炸弹。
  • 结构重复的代码:一旦出现重复的结构,就提取公共方法,避免代码的冗余。
  • if 和 else 代码块中的语句高度类似:只要你看到 if 语句出现,而且 if 和 else 的代码块长得又比较像,多半就是出现了这个坏味道

总结:不要重复自己,不要复制粘贴。

04 | 长函数:为什么你总是不可避免地写出长函数?

  • 以性能为借口:性能优化不应该是写代码的第一考量。
  • 把代码平铺直叙地摊在那里:关注点越多越好,粒度越小越好。
    • 把多个业务处理流程放在一个函数里实现;
    • 把不同层面的细节放到一个函数里实现。
  • 只是每次增加了一点点:任何代码都经不起这种无意识的累积,每个人都没做错,但最终的结果很糟糕。

总结:把函数写短,越短越好。

05 | 大类:如何避免写出难以理解的大类?

如果一个类里面的内容太多,它就会超过一个人的理解范畴,顾此失彼就在所难免了。、

主要是将大类拆分成小类。我们需要认识到,模块拆分,本质上是帮助人们降低理解成本的一种方式。

  • 职责不单一:把不同的职责拆分开来,我们需要对不同内容的变动原因进行分析,而支撑我们来做这种分析的就是单一职责原则。
  • 字段未分组

总结:把类写小,越小越好

06 | 长参数列表:如何处理不同类型的长参数?

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

参数列表中经常会出现标记参数,这是参数列表变长的另一个重要原因。对于这种标记参数,一种解决方案就是根据这些标记参数,将函数拆分成多个函数。

总结:减小参数列表,越小越好

07 | 滥用控制语句:出现控制结构,多半是错误的提示

  • 嵌套的代码
  • else 语句:一种典型的重构手法:以卫语句取代嵌套的条件表达式,不要使用 else 关键字
  • 重复的 switch:以多态取代条件表达式
  • 循环语句

总结:循环和选择语句,可能都是坏味道

08 | 缺乏封装:如何应对火车代码和基本类型偏执问题?

  • 过长的消息链,或者叫火车残骸

例如:

String name = book.getAuthor().getName();

解决这种代码的重构手法叫隐藏委托关系(Hide Delegate),说得更直白一些就是,把这种调用封装起来(要想摆脱初级程序员的水平,就要先从少暴露细节开始)

  • 基本类型偏执:这种引入一个模型封装基本类型的重构手法,叫做以对象取代基本类型(Replace Primitive with Object)。

总结:构建模型,封装散落的代码。

09 | 可变的数据:不要让你的代码“失控”

  • 满天飞的 Setter:相比于读数据,修改是一个更危险的操作。缺乏封装再加上不可控的变化,在我个人心目中,setter 几乎是排名第一的坏味道

    • 消除 setter ,有一种专门的重构手法,叫做移除设值函数(Remove Setting Method)。总而言之,setter 是完全没有必要存在的。
  • 可变的数据

    • 所有的字段只在构造函数中初始化;
    • 所有的方法都是纯函数;
    • 如果需要有改变,返回一个新的对象,而不是修改已有字段。
      总结:可变数据最直白的体现就是各种 setter。setter 一方面破坏了封装,另一方面它会带来不可控的修改,给代码增添许多问题。解决它的一种方式就是移除设值函数(Remove Setting Method),将变化限制在一定的范围之内。限制可变的数据。

10 | 变量声明与赋值分离:普通的变量声明,怎么也有坏味道?

  • 变量的初始化:一个变量的初始化是分成了声明和赋值两个部分,而我这里要说的就是,变量初始化最好一次性完成。尽可能使用不变的量,在能够使用 final 的地方尽量使用 final,限制变量的赋值
  • 集合初始化:传统的集合初始化方式是命令式的,而今天我们完全可以用声明式的方式进行集合的初始化,让初始化的过程一次性完成。使用java9的集合新特性

11 | 依赖混乱:你可能还没发现问题,代码就已经无法挽救了

  • 缺少防腐层:会让请求对象传导到业务代码中,造成了业务与外部接口的耦合,也就是业务依赖了一个外部通信协议。一般来说,业务的稳定性要比外部接口高,这种反向的依赖就会让业务一直无法稳定下来,继而在日后带来更多的问题。解决方案自然就是引入一个防腐层,将业务和接口隔离开来。
  • 业务代码中出现具体的实现类:实际上是违反了依赖倒置原则。因为违反了依赖倒置原则,业务代码也就不可避免地受到具体实现的影响,也就造成了业务代码的不稳定。识别一段代码是否属于业务,我们不妨问一下,看把它换成其它的东西,是否影响业务。解决这种坏味道就是引入一个模型,将业务与具体的实现隔离开来。
    总结:代码应该向着稳定的方向依赖。

12 | 不一致的代码:为什么你的代码总被吐槽难懂?

  • 命名中的不一致:表示类似含义的代码应该有一致的名字
  • 方案中的不一致
  • 代码中的不一致

13 | 落后的代码风格:使用“新”的语言特性和程序库升级你的代码

  • Optional的使用:Optional 的引入可以减少由于程序员的忽略而引发对空对象的问题。团队内部可以约定,所有可能返回空对象的地方,都要返回 Optional,以此降低犯错的几率。
    参考:https://blog.csdn.net/qq_46728644/article/details/125486253
  • 函数式编程:是一个影响代码整体风格的重要编程范式

总结:不断学习“新”的代码风格,不断改善自己的代码。

学习自:https://time.geekbang.org/column/intro/100068401 如有侵权请及时联系

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值