重读【代码整洁之道】
共 4435字,需浏览 9分钟
·
2021-10-01 13:05
一、前言
【代码整洁之道】很经典,但也有些过时,翻译上也有些啰嗦,但总体上是好书。通过对本书核心内容的摘抄,结合自己的经验,整理了一些精简的点,这样你就省的去啃那本400多页的书了。
软件质量 = 架构设计 + 项目管理 + 代码质量。
架构设计:像建筑师设计的一个宏伟建筑的设计图。
项目管理:专注于敏捷、快速的将产品推向市场。
代码质量:确保交付的产品稳定、持久的提供它的特性。
软件工程打造的数字化产品不同于传统的建筑、车辆等产品,他有极强的迭代、维护需求。代码是一个宏大产品的小细节,但东西方的很多寓言故事中都透露着,细节的重要性:
守小节者不亏大节
及时一针省九针
早起的鸟儿有虫吃
日事日毕
防病好过治病
还有扁鹊与蔡桓公的故事
关注细节深埋于人类壮丽的文化、智慧之下。但人性的弱点,往往让我们追求宏大的叙事,而忽视了细节的打磨。
插播一下,为什么大家最近经常谈内卷?为什么日本有工匠精神?
通过对比发达国家发展来看,经历了高速发展之后,低速发展阶段更注重质量的打磨,所以内卷不是毫无意义,而是低速发展时代的必经产物。
干净的代码,即在质量上较为可靠,也为后期维护、升级、扩展奠定了基础。
代码整洁之道提供了一条条规则,以提升代码质量。
认真对待每个命名,如同给孩子起名一样谨慎。
其他的还包括:命名、函数、注释、代码格式、对象、数据结构、错误处理、边界问题、单元测试、类、系统、并发编程等方面。
二、如何提高代码质量
有什么标准识别代码质量好坏?
WTF / min
通过两扇门后传出的脏话数量判断,右侧团队的代码质量应该很差。
写整洁代码很难,不是你掌握了原则和模式就可以写好。你得在上面花功夫,多实践,多看看别人如何绞尽脑汁做出决策,又是如何为错误付出代价的。琢磨某段代码好在什么地方、坏在什么地方。
写整洁代码,需要遵循大量的小技巧,写出有“代码感”的代码,“代码感”帮助程序员选出最好的方案。
没有“代码感”的程序员,看混乱是混乱,无处着手,走一步算一步;
有“代码感”的程序员,能从混乱中看到其他可能的变化;
怎么看待整洁代码?看看行业大牛怎么说
C++语言发明人Bjarne说:
代码逻辑应该直接了当,叫缺陷难以隐藏;尽量减少依赖关系,使之便于维护;通过某种分层战略约束错误处理代码。
Bjarne认为,整洁的代码读起来令人愉悦。
糟糕的代码想做的事太多,意图混乱、目标含混。
整洁的代码力求集中,每个函数、每个类、每个模块都专注于做一件事,而不会受到外围细节的干扰。
整洁代码注重表达力,小规模抽象
代码应该讲述事实,不引人猜测,应该更果断决绝。整洁的代码可读性更强,也便于其他人增补逻辑,有很好的易修改性。
没有测试的代码是不干净的。
代码块,越小越好。
有意义的命名,是体现表达力的一种方式,表达力还体现在方法是否想做的事情太多上。如果方法里面功能太多,那么需要抽取出来。
有意义的命名
略。。。
函数编码要求
第一原则:要短小。(20行最多)
不短小就不是函数了,那是类。
第二原则:只做一件事,且做好这件事。
函数中语句都要在同一个抽象层级上,函数如果杂糅不同抽象层级,往往让人迷惑。
长而具有描述性的名称,比短而令人费解的名称好。
第三原则:避免多参数,最理想是零个参数,其次是一个,再次是两个,尽量避免三个。
三个以上可能确实多了,可以通过重载方式实现。
bad case:向函数传入布尔值骇人听闻,里面让函数复杂起来,代表函数不只做一件事。
第四原则:try/catch代码块的处理,最好把代码块主体抽离出来,如下:
第五原则:不要重复自己。
第六原则:不要将null传递给方法,除非API要求。
单元测试
TDD要求,在编写生产代码之前,先编写单元测试。
类的原则
第一原则:类应该短小。
多小合适呢?对于函数我们可以要求代码行数,对于类来说,我们要求权责。
如果一个类里面有几十个函数,那它就是个bad class。5个方法不算多,这样类的权责也更可控。
第二原则:类名应该描述其权责。
一个类名是含糊的,它未来拥有的权责就会太多。比如Manager、Process、Super这种类名就太含糊。
遵照面向对象的“单一职能原则”,类模块有且只有一条加以修改的理由,是类权责的定义。
鉴别了类的权责,可以帮助我们做更好的类抽象。
类太多怎么办?用包组织起来。
第三原则:多个类之间,将类的构造与使用分开。
常量与枚举
enum可以拥有更多方法和字段,从而比常量提供更多的表达力和灵活性,所以在常量与枚举之间,如果需要更多的信息表达,推荐用枚举。
三、识别代码的坏味道
那如何识别系统中存在的坏味道呢?有个清单可以参考使用。
注释的坏味道
1)不恰当的信息:注释应只描述有关代码和设计的技术性信息。
2)废弃的注释:过时、无关、不正确的注释就是废弃的注释,废弃的注释应该及时被更新或删除。
3)冗余注释:注释应该谈及代码自身没提到的东西。
4)写值得写的注释:值得写、保持简洁。
5)注释掉的代码:被注释掉的代码,没人知道他的意义,看到注释掉的代码,就删除它。
函数的坏味道
1)过多的参数:函数的参数数量应该少,没参数最好,一个次之,两个、三个再次之。三个以上值得商榷,应该避免。
2)输出参数:参数用于输入而非输出,所以不要通过一个函数获取输入参数的变更,违反直觉。
3)布尔参数:如果参数是布尔值,这个函数就会不止做一件事,它令人迷惑,应该消灭。
4)死函数:不再被调用的函数应该丢弃,别害怕删除函数。
5)忽视安全:函数代码不要轻易挂了,必要的非空判断还是要有的。
6)重复:DRY原则,每次看到重复的代码,就代表了没有抽象,重构那些看起来一样的代码。
7)错误的抽象层次:代码可以简单的抽象成基类能力和细节能力,基类应该对细节(派生类)一无所知,这条规则适用于源文件、组件、模块与系统。良好的软件设计要求分离位于不同层级的概念。低层抽象概念和较高级抽象概念不应该混杂在一起。
8)信息过多:前面的很多原则体现了短、少的概念,如果一个类、函数信息过多,某种程度代表他是有问题的。设计良好的接口不提供许多需要依靠的函数,所以耦合度也较低。设计低劣的接口提供大量你必须调用的接口,耦合度也高。优秀的开发人员应该学会限制类或模块暴露的接口数量,类里面的方法越少越好,函数知道的变量越少越好,类拥有的实体变量越少越好。太多了说明你抽象的还不够。
9)垂直距离最短:变量和函数应该在靠近被使用的地方定义。本地变量应该正好定义在其首次被使用的位置上声明,确保定义与使用垂直距离最短,本地变量不应该放在其被使用之外的几百行以外声明。
10)人为耦合:不相互依赖的东西不应该耦合,两个没有直接相关的模块产生耦合的原因在于变量、常量、枚举、函数被临时放在了不正确的位置上,背后是偷懒行为。应该花时间研究在什么地方声明函数、常量、变量,不要随手放置。
11)依恋行为:类方法只应该对其所属类中的变量和函数感兴趣,不应该对其他类中的变量和函数产生依赖。
12)最小惊讶原则:代码应该放在读者自然而然期待他所在的地方,比如PI常量应该出现在声明三角函数的地方。
13)函数名称应表达其行为,如:
14)常量名代替魔术数。
15)封装条件,如:
16)避免否定性条件,如:
17)函数只做一件事:如果要做多件事,拆成更多的更小的函数,每个只做一件事。
18)调用顺序应该显而易见,如:
四、面向对象
行文至此,发现写好整洁代码,除了短、小、命名这些原则之外,面向对象原则同样非常重要。
面向对象是业务系统编码非常重要的思想,很多解决复杂业务问题的设计模式与设计思想都遵循面向对象思想,比如设计模式和领域驱动,你是不是都可以发现面向对象的影子呢?
五大基本原则(S.O.L.I.D)
1)单一职能原则SRP:一个类功能要单一,一个类负责一个职责,这个类被修改的原因是因为职责变化了;
2)开放封闭原则OCP:一个类要具有扩展性的开放,更改性的封闭,背后体现的是灵活性、重用性、可维护性,同样要求有很好的抽象能力,也就是面向接口编程,而不是面向实现编程,抽象是稳定的;
3)替换原则LSP:子类可以替换父类出现在父类能够出现的任何地方,这个原则是GOF倡导的面向接口编程,父类尽可能使用接口或抽象类实现,他非常好的价值在于,帮助我们看到继承关系的定义;
4)接口隔离原则ISP:使用专门的接口比简单单个接口要好很多,模块之间通过抽象接口进行通信,而不是通过类的强耦合;
5)依赖倒置原则DIP:高层模块不依赖底层模块,依托于很好的抽象能力,细节依赖具体;
五、最后
《代码整洁之道》聊的不只是代码,更多是程序员的职业素养。
程序员不应该仅仅满足于让代码能工作,还需要考虑到可读性、可扩展、可迭代。解决之道是保持代码持续的整洁与简单。
日常编码过程中不是简单的遵守这些实践,而是要思考下这样写有什么好处。