该笔记包含一下内容:
- 重复代码:简单需求到处修改,怎么办?
- 长函数:为什么你总是不可避免地写出长函数?
- 大类:如何避免写出难以理解的大类?
重复代码:简单需求到处修改,怎么办?
这节最直白的建议就是不要复制粘贴代码,真正应该做的是先提取出函数,然后在需要的地方调用这个函数
长函数:为什么你总是不可避免地写出长函数?
问题1: 多长的函数才算“长”?
对于函数长度的容忍度高,这是导致长函数产生的关键点,一个优秀的程序员面对代码库是要有不同尺度的观察能力,看设计时要能够高屋建瓴,看代码时能细致入微,随着对于长代码的容忍度降低,对代码细节的感知力就会逐渐提升,你才能看到那些原本所谓的细枝末节的地方隐藏的各种问题。
在具体工作中,越短越好是一个追求的目标,不过没有一个具体的数字就没有办法约束人的行为,因此这里参考资料中建议的一个函数程度长度标准是,对于Python、Ruby这样表达能力比较强的动态语言,大约是5行左右,对于Java这样表达能力若的静态类型语言是争取在10行左右解决问题,对于多数的程序员可以前期稍微放宽限制,以这个标准翻倍即20行即可。
问题2: 长函数的产生
限制函数的长度只是一种简单粗暴的解决方案,长函数本身是一个结果,我们来研究一下长函数是如何产生的?
以性能为理由
人们写长函数的历史由来以久,即使像C语言这样在今天看来已经是高性能的程序设计语言,在问世之初,也曾被人质疑性能不佳,尤其是函数调用,在经常写汇编的人看来,调用函数涉及入栈出栈的过程,显来不如直接执行来的快,这样的想法一直演变并流传至今,任何一门新的语言出现都会被同样的理由质疑,在很多人看来把函数写长是为了性能,不过这个观点至今都是站不住的,因为性能优化从来不应该是写代码的第一考量,一方面,一门有活力的语言是需要不断优化的,不论编译器还是运行时,性能都会越来越好;另一方面,代码的可维护性比性能要优先考虑,当性能不足以满足需求时,我们再需要找到焦点进行特定的优化。
平铺直叙
处理性能为由之外,最常见的把代码写长的原因就是平铺直叙的直述,把自己想到的全部罗列出来,这里就不列举了,简单说一下笔者上学的时候编码习惯,我会先构思一下整个函数的流程用注释的方式标注出几个阶段,接着想写作文一样把注释里的内容实现出来,这样我曾写出过一个2000+的代码文件,平铺直述的代码主要存在两个典型问题。
- 将多个业务处理流程放到同一个函数中实现
- 把不同层面的细节放到同一个函数中实现
处理平铺直述的一个直接的方式是提取函数,将大函数拆分成若干小函数,这里顺便提一下,长函数还存在一个命名问题,拆分为小函数内的变量命名通常会别大函数的命名要短一些,理解成本也会降低,因为变量都是在短小的上下文中,就不会出现很多的命名冲突。
平铺直述的代码关键就是没有吧不同的东西分离出来,用设计的眼光查看其实就是“分离关注点”没有做好,将不同层面的东西混在了一起。
一次加一点
有时候一段代码开始的时候并不长,但是新的需求慢慢的增加,代码会慢慢的变长例如:
1 | if (code == 400 || code == 401) { |
随着业务的需求增加,他慢慢的变成这个样子,
1 | if (code == 400 || code == 401 || code == 402 ) { |
极端一些,甚至是这样子1
2
3if (code == 400 || code == 401 || ...|| code == 100) {
// 做一些错误处理
}
这就是经典的“雪崩的时候没有一片雪花是无辜的”,其实每一个写代码的人都没有增加太多,仅仅是增加了一个判断条件而已,而任何代码都经不起这种无意识的积累,每个人都没有做错,但是最终的结果就是很糟糕,为了对抗这种逐渐糟糕迂腐的代码,我们需要知道“童子军军规”
让营地比你来的时候更干净
—–童子军军规
简言之,任何时刻我们对于代码的改动不应该是让原有的代码变得更糟糕,如果是就需要改进它
大类:如何避免写出难以理解的大类?
大类是指一打开就是一片无边无际的代码,产生大类的一种重要原因是长函数,一般来说一个大类只要有几个长函数就肯定是一眼看不到边,除此之外大类的另一种重要表现形式就是类中有特别多的字段以及函数,这一节主要侧重如何处理后者。
分模块的程序
我们来考虑一个极端,把代码都写到同一个文件里会怎么样?从结果来看这个程序的复杂度会远远超出一个人能掌握的认知范围,一个人理解问题的能力是有限的,没有人能同时面对所有的细节,人类面对复杂事物给出的解决方案是分而治之,我们看到各式各样的语言都是有自己的模块划分方案,从最初的按文件划分,到后来使用面向对象的方式进行划分,如果一个类的内容过多,那么顾此失彼也就在所难免了,解决大类的方案也随之而来,就是把大类拆解为若干个小类,出现大类很可能的几种原因如下:
职责不单一
字段未分组
所谓的将大类拆解成小类,本质上在做的工作是一个设计工作。我们分解的依据其实是单一职责这个重要的设计原则。很多人写代码写不好,其实是缺乏软件设计的功底,不能有效地把各种模型识别出来。所以,想要写好代码,还是要好好学学软件设计的。