代码的整洁之道阅读笔记
代码的整洁之道阅读笔记
第一章
整洁的目的是为了提高团队合作的效率以及缕清自己的编码思路、
第二章
作者强调注意命名,代码中的每一变量名,函数名,等等需要命名的场合,都需要注意: 首先要名副其实,直接通过命名知晓本意,其次做好区分,避免误导,要使用可搜索的名称(唯一性),这样能省去后面忘记时需要直接的理解代码的困难。
尽可能的使用IDE的环境去解决成员变量问题而不是将这个交给名称; 不要将所谓的联想法带到命名里去,要使用直达本意的词语; 类名使用名称去命名,而方法(函数)使用动词或者使用动词短语去命名; 尽量使用计算机科学的术语去命名;
这些方法要贯彻是需要较大的英语单词功底以及文化功底,不过可以从基础做起,比如直达本意。
第三章
函数本身要满足以下要求:
- 短小
- 只做一件事
- 函数内部只有一个层级
- 使用具有描述性的名称命名函数
- 参数最好只有一个或者没有,最多不超过三个
- 函数要么做某事,要么回答某事 函数内部处理的错误码尽可能的使用异常代替,并且处理异常本身属于一件事情。
这些的做法当然不是边做边想,而是将代码初步实现之后,在对其内部进行修正与改进,当然,以后熟练了之后可以一步到位,最后,作者提到,写代码就是讲故事。
第四章
无需注释的代码就可以理解的代码就是好代码,作者强调,将写注释的时间放到优化代码身上,不要在糟糕的代码上面花时间写注释,而是把它放到优化代码身上。 但是好的注释也是对代码的理解有十足的提升,还有减少编码之外的麻烦。 什么是好注释?有以下类型:
- 法律信息
- 提供准确描述的信息
- 对函数操作之中或之后的意图
- 解释一些标准库里面的代码
- 警告信息
- TODO
- 放大一些抽象(双重意思)的处理
- API的返回(这一点就是需要强调) 坏注释类型:
- 喃喃自语
- 多余的注释
- 有误导性的注释
- 代码的注释规矩坚决的执行
- 日志型的注释
- 废话
- 位置标记
- 括号后面的提醒
- 署名(交给IDE)
- 注释掉的代码(不过这个东西如果真有用应该用文档记下来)
- HTML的注释
- 不属于该上下文所执行的注释
- 信息过多
- 不明显的联系
- 函数名称
总结,坏注释几乎可以归纳为这几个特点:
- 与执行代码无关的。
- 废话
- 废物 所以能不写注释就不要写注释(但是这不是不写注释的理由)
第五章
代码的可读性影响整个程序的开发生命周期,除非这是一次性的垃圾玩意或者是一时兴起的玩具,所以对于阅读最有影响的是代码的格式以及代码风格。
- 纵向格式 首先是单个文件的代码行数,一个文件的代码行数尽可能的控制在200-500行的区间,因为短文件可以令人更便于理解。 整体的代码形式应该是逐级向下,逐步具象,最顶层的,对应的是最抽象的层级,也就是类似于报纸的阅读方式。然后利用好空格进行分割,增加可读性,对应的同样类型的应该要将其靠近到一起,关系密切的代码也要放在一起,所以这里作者强调了尽可能的不要使用protect变量。 在使用逻辑和类型逻辑冲突时,优先类型逻辑,但是仅适用于变量。 概念相关的函数也要放到一起,优先,哪怕他们之间没有互相调用。 摆放顺序按调用顺序摆放。
- 横向格式 每行字符不超过120个字符,并利用好空格将相关性弱的信息隔开。 缩进是个非常好的习惯,但是不要在是用两个空格和一个退格键还是用四个空格上面浪费时间(python就不存在这个问题)。还有一点是,短小的代码也要缩进,利于查看。
最后一点就是团队规则,团队规则对这个可能有出入,但是针对性调整就好了,在你无法以一己之力调整团队本身时,不应该强行要求团队服从你的要求。当然如果这团队规则几乎是不合理的话,那可以针对性的进行调整并保持自己的习惯于风格。
第六章
文章前一部分体现了接口的作用,接口就是抽象对象的体现,而实现接口就是对抽象对象具象化,在具象化的过程中,需要实现很多个细节,所以,先使用接口对整个执行流程抽象解释,后面在逐步具象化。这样即理清了思路并且更好的复用该对象。但这也对抽象程度的把握要有十足的信心(抽象与具象之间边界判定),否则容易产生一个无用的接口。
接着,文章介绍了得墨忒耳律,该定律强调模块不应该了解所操作的对象的内部情形。对应的反例有:
- 链式调用
- 数据结构与对象混合
- 不隐藏内部结构 最后,作者认为,最精炼的数据结构是仅仅只有公共变量,不存在函数,对应函数应交给其他类实现。
基于现状来说,链式调用几乎是无可避免,但是可以使用变量去改变编写形式。其他两条件,均可以在实践中运用。
第七章
作者在第三章表明,异常本身属于一件事情,并且使用异常本身而不是返回错误码,作者在这一章对此展开了说明,不引入错误码是因为引入会导致逻辑错乱,抛出异常的形式在查看代码时直接忽略,排除干扰项。
使用异常时要保证以下几点:
- 使用未检测异常(就是在预期之中的异常不做try-catch处理)
- 抛出异常时给出异常的环境说明
- 单独对调用者创建一个异常类 对于特殊情况来说,并且这个特殊情况是业务范围之内,那么就不适合用异常去处理而是使用特殊类去处理。 如果函数返回的是null,不要直接返回或传递,直接包装成异常进行处理。
第八章
作者认为要学会使用第三方的代码库去解决问题,在这一点上,有一个前提就是熟悉辨别第三方库,因为不是所有的第三方库都是可用的,有可能有些第三方库写的比你写的还烂,而且第三方库需要增加学习的时间成本和维护的成本(因为有些库用着用着他就不更新了,出事了还不知道往哪擦屁股),不过作者对于学习第三方库给出来一个方法:使用单元测试去尝试第三方库的功能。他有以下好处:
- 错误直接显示在你的面前
- 不妨碍正常的使用环境
- 可以疯狂的折腾而不怕犯错 如果遇到黑盒程序(不知晓原理和接口的第三方库),可对其套壳,前提是已知晓其执行边界(有什么,作用范围等)
第九章
作者在这一介绍了TDD模式,即测试驱动开发,它的要求是在编写生产代码之前,先编写单元测试代码,并且有以下定律:
- 在编写不能通过单元测试之前不能编写生产代码
- 只可编写刚好无法通过的单元测试,不能编译也算
- 只可编写刚好足以通过当前失败测试的生产代码
这个模式对于程序员的编码熟练度和对业务的分析能力有着极高的要求,而且产生的代码量是生产代码的三倍甚至有多,会极大产生大量的工作量,所以该模式我认为只有核心代码需要做这一块的工作,其余的不需要。
测试代码本身也是需要和生产代码一样整洁。可以使用适用于测试的语言以及框架来减轻工作量。在测试本身,可以适当的使用一些思维映射,使用与开发代码不一样的标准,来减轻理解的压力。最后作者强调,一个测试一个断言一个概念。
在结尾出,作者给出来一个短语:FIRST,分别是:
- 快速(fast)
- 独立(Independent)
- 可重复(Repeatable)
- 自我验证(Self-Validating,即自己内部判断而不是取决于外部的日志等错误输出功能)
- 及时(Timely,要编写就立马编写)
第十章
书中首先强调,一个类对应一种权责,就是一个类只处理一件事情。并且只有少数实体变量(已经被实例化的变量),即所谓的高内聚。 在类的创建下,要以准备修改的方式去构造一个类,构造本身就是为了修改和拓展,所以基类本身需要足够的抽象。并且要对未来需求变动时做出隔离。
第十一章
书中从构造开始,构造和使用本身需要做一些分离,建立一个构造流,把构造全过程分解成一个个小任务,然后和业务代码分离开。可通过依赖注入这一点进行优化。 在构造使用代码时,需要有意识的预留扩容的空间。面向过程编程(AOP)对于这个有着新的解决方案。
第十二章
首先,作者给出来程序设计的几项规则:
- 运行所有测试
- 不可重复
- 表达意图
- 尽可能减少类和方法的数量 第一个规则有一个前提就是所有在程序内的功能应有测试,然后是运行所有测试且通过,否则不允许部署。 第二到第四个运行的方法是重构,即当代码符合一下条件时:
- 越来越繁重
- 重复性较多
- 意图表达能力下降时 就要考虑重构设计,重构设计的目的就是为了消除或延缓以上要素,而不是为了重构而重构。整个设计他是属于一个动态矛盾的。
第十三章
本章是对并发编程过程进行针对性的优化 首先并发编程要对过程进行防御使用一下几点:
- SRP单一权责
- 限制数据作用域(加锁)
- 尽可能使用数据副本(不要使用共享数据)
- 线程尽可能独立 作者用JAVA举例了三个模型:
- 生产者——消费者
- 读者——作者
- 哲学家的宴会 以上三个需要针对性的学习算法和设计模式。 最后在这些前提下保证同步区间较小,和尽早考虑线程关闭问题。 在测试线程时,作者给了几条建议:
- 出现不可意料的失败首先查看线程went
- 让那些非线程代码可正常工作
- 线程可热插拔且能自由调整
- 测试运行在多处理器和不同平台
- 故意出错查看是否达预期(诱导)
第十四章
作者在这一章详尽的描述了他对Args类的重构和迭代改进,体现出代码在不及时重构下,会以极其恐怖的方式野蛮发展,所以,得出结论,要对代码时刻保持整洁与简单。
第十五章、第十六章
这两章是作者对于以上所有规则一个亲身实践,由此可总结一下特点:
- 构造时,要先可以让其工作且能做对(满足需求)
- 删除废话
- 遵循以上规定 作者给出来的重构例子确实细致,但是按我的想法,我更愿意从实践的角度去了解其本身的过程,而不是书本。
第十七章
这一章几乎是这个笔记的翻版,以后可以将这一章与这篇笔记结合一起看。
体会
这本书的作者对于TDD模式有着深刻的了解,并且似乎与这个标准作为参考写的这一片的文章,但是在实际生产中,TDD是会给生产效率基于沉重的打击(市场业务的紧迫性与优化之间的冲突),所以在实际运用时,切勿生搬硬套,根据实际需求做调整。 这本书给予的思路还是挺好的,首先,对于抽象与具象的把控,作者倾向于宁可抽象点也不要具象化,对应的理解就交给命名去解决。而且对应的每个过程中设计的相应粒度要足够小,也就是把每个功能做成一个小积木,使用小积木去构建大积木,只有粒度足够小,才可以在拓展是有更高的自由度和更少的工作量。其次,作者并非是让读者一步到位去执行这些规则,而是先把功能所实现了之后,才去花时间去重构,当然,还是那句话,要注意现实的时间和提升自己的编码经验,才能在规定时间内完成任务。最后,作者强调做这些重构的工作时要尽早,不然代码是会腐烂的。 在保持整洁的同时,把控好时间,因为一切以结果为基础。