《Clean Code》阅读笔记
Chapter 2 命名
- 命名要表现意图
- 避免歧义和误导,增强区分
- 命名可读性:便于发音,增强印象,便于交流
- 命名可查性:增强区分,便于搜索
- 类和对象的命名:名词或名词短语
- 方法的命名:动词或动词短语
- 使用仅表述单一概念的词,如 get,避免多概念的词,如 fetch
- 使用行业术语及业务术语
Chapter 3 方法
- 尺寸:越小越好,不应超过20行
- if、else、while 等 statement 不应超过一行
- 单一责任
- 单一抽象层级
- 无参最优,一参数次之,二参数最次,不应超过3参数,否则应引入参数结构或对象
- 避免将参数作为输出
Chapter 4 注释
- 尽量少用注释,避免过时的注释
- 如果能用良好的命名来表现意图,就不用注释
- 如果能用代码来表现意图,就不用注释
- 良好的注释:
- 提供补充信息
- 解释意图
- 警告
- TODO 注释
- 强调注释
Chapter 5 格式
- 垂直格式:
- 单个类文件,不超过100行/150行/200行
- 使用空行分隔方法
- 自顶向下的方法依赖分布
- 水平格式
- 单行不超过80字符/100字符/120字符,屏幕能够全部显示
- 保持缩进
- 使用空格,运算符左右使用空格等
- 显式地突出空循环,避免省略地写为一行
- 优先遵循团队规定的格式
- 垂直格式:
Chapter 6 对象和数据结构
- 数据结构和对象的对立性:
- 数据结构以 public 暴露内部属性,不提供访问方法
- 对象以 private 隐藏内部属性,提供访问方法
- 数据结构易于增加新方法,同时不影响已有结构。对象反之,易于增加新类,同时不影响已有方法。
- 数据结构不便于增加新数据结构,因为需要改变每个已有方法。对象反之,不便于增加新方法,因为需要改变每个已有类。
- Law of demeter:最少知识原则,一个对象应对其他对象有尽量少的了解。类C的 f 方法,应只调用这些方法:
- 类C的方法
- f 创造的对象的方法
- 传递给 f 的参数对象的方法
- 类C的成员实例变量的方法
- 数据结构和对象的对立性:
Chapter 7 错误处理
- 使用 exception, 避免使用返回的错误码
- 逐层 throw exception,在最顶层 catch,即定义一个错误传递流
- 将 try/catch 抽取出来作为独立函数
- 在需要时定义新的 exception 类
- 不要返回 null,定义一个 Null 类
- 不要传递 null
Chapter 8 边界
- 在自己的代码和第三方代码的边界处,使用自己编写的代码适配(适配器),避免将第三方代码直接嵌入自己的代码
- 测试第三方代码
Chapter 9 单元测试
- TDD
- 测试代码和生产代码同样重要,但测试代码不一定需要遵循同样的效率和资源限制
- 保持测试代码的clean,避免过时和冗余等
- BUILD-OPERATE-CHECK 的测试模板
- given/when/then 的测试方法命名建议
- 模板方法模式可能有所帮助
- 每个测试方法,仅测试一个概念
- F-I-R-S-T原则
- Fast,测试效率要高
- Independent:每个测试应当独立
- Repeatable:在不同环境下均可运行
- Self-Validating:应拥有一个boolean的输出,自身直接输出测试是否通过
- Timely:每个测试应 just before 写在生产代码之前
Chapter 10 类
- 类成员顺序如下,自顶向下
- public static constants
- private static constants
- private instance variables
- public functions
- 被 public function 调用的 private functions 紧跟在该 public function 之后,满足自顶向下的阅读顺序
- 尺寸:类尽可能小,不同于用物理行数衡量方法的尺寸,应该用 responsibilities 衡量类的尺寸。类应保持单一责任。
- 类应该保持单一责任(SRP),而类名应该描述这一责任。
- 类名不应超过25个单词,同时避免 if、and、or、but等代表多责任的词,同时少用大范围的含糊的词,如super,manager等。
- 尽可能提高类的内聚度:尽量使类中的每个成员变量被类方法使用
- 将大类分隔为很多小类,优化组织性,提高内聚。但也会造成类数量的激增。
- 依赖倒置原则(DIP),类依赖于抽象,而不是具体实现。降低耦合。
- 将类中会变化的部分抽象出来,让客户代码依赖于抽象,而不是具体实现。
- 类成员顺序如下,自顶向下
Chapter 11 系统
- 将系统构造部分,与使用部分解耦
- 将构造和初始化部分,全部放在main函数中,再在main函数中,将构造完毕的对象,以参数形式传递给具体使用它们的函数。这是一个方法。
- 工厂方法可能有所帮助。
- 依赖注入(DI)和控制反转(IoC)机制可能有所帮助。
- (这一章没怎么看懂)
Chapter 12 迭进
- Kent Beck 认为的“Simple Design”的四条规则。重要性由上而下递减。
- 运行所有测试
- 无重复(良好重构)
- 表现编程者意图
- 良好命名
- 保持类和方法尽可能小
- 遵循公有标准和共同语言,如通用规范、设计模式等
- 良好的单元测试
- 最小化类和方法的数量
- 经过去重、重构等操作之后,类和方法的数量可能激增。因此在此基础上,尽量减少它们的数量。
- Kent Beck 认为的“Simple Design”的四条规则。重要性由上而下递减。
Chapter 13 并发
- 复杂且不成熟,跳过。
Chapter 14 坏味道和启示
注释 Comments
- C1 不适宜的注释:修改历史、作者、最近修改日志等,都不适宜出现在注释中。注释应该仅保留技术和业务相关的要点。
- C2 过时的注释
- C3 冗余的注释:注释是代码的重复,没有提供额外信息
- C4 写的很烂的注释:认真措辞,不要随意
- C5 注释起来的代码:没人知道它的重要性和意义,其他人根本无法轻易地改动它。如果可以,直接删除它
环境 Environment
- E1 构筑环境需要不只一步:做到一键 build 你的项目环境。
- E2 单元测试需要不只一步:做到一键 test 你的项目的所有单元测试。
方法 Functions
- F1 太多参数:无参最佳,1参次之,2参再次,3参再次,多余三个参数,则考虑引入参数结构或对象。
- F2 输出参数:避免改变参数,然后将它作为结果输出。
- F3 Flag参数:避免使用Flag参数,这意味着这个方法将做不只一件事。
- F4 Dead方法:无人问津的方法,直接删除它。
通用 General
- G1 单个源码文件中,出现多种编程语言:解耦、分离他们。
- G2 明示的行为没有被实现:应该遵循“最低惊异原则”,任何明示而被期待的行为,都应该被正确实现。否则,代码阅读者将会对更多的代码失去信任。
- G3 边界处的行为都要被准确实现:任何边界条件、角落case、巧合case、异常case的行为,都需要被准确实现。否则,代码阅读者将会对更多的代码失去信任。
- G4 覆盖安全机制:避免覆盖你使用的框架提供的安全代码机制,如警告等,不要轻易重载、覆盖、取消它们。
- G5 重复:不仅包括明显重复的代码,还包括重复的设计等。善用模板方法和策略等设计模式。
- G6 错误/混乱抽象分层:不同抽象层级的隔离应该明确,一个方法应该仅在同一抽象层级上操作。
- G7 基础类依赖于它们的衍生类:不要让抽象上层依赖于抽象下层,抽象上层应该对抽象下层一无所知。也有例外:比如上层严格控制了下层衍生物的数量等。
- G8 单个方法/类/模块负责通过多责任:约束尺寸,约束责任,约束信息。
- G9 Dead Code:避免永远不会执行的代码,直接删除它。
- G10 垂直分隔:局部变量和方法需要被定义在他们的使用者附近。private function应该被定义在just below他们的首次调用者处。保持自顶向下的阅读顺序。
- G11 不一致性:相似的行为应该保持相似一直的结构和命名,保持“最低惊异原则”。
- G12 杂物:无用的变量,无用的方法,无信息的注释,都应该被尽早删除。
- G13 人为耦合:解耦那些不必要的、不小心造成的耦合关系。
- G14 位置不当:类中的方法应该尽量只使用此类中的变量和其他方法,如果某方法更多地使用其他类中的变量和方法,那么它可能需要挪动位置了。
- G15 传递boolean参数:不要将boolean值作为方法参数,这意味着该方法负责不只一件事。
- G16 含混的意图:代码自身要意图明确。
- G17 位置不当:一些变量和方法应该正确地放置在它们最被期待的地方。“最低惊异原则”
- G18 不适当的static:某些方法适合static,有些不适合,正确处理它们。
- G19 变量意图不明:使用有解释力和变现力的变量,如合适命名等,增强可读性。
- G20 方法意图不明:使用有变现力的方法名,增强可读性。
- G21 对算法理解不明
- G22
- G23 建议使用多态来代替if/else和switch/case,当后者重复超过1次时,考虑使用多态替换他们。工厂模式可能有所帮助。
- G24 建议遵循标准惯例
- G25 建议使用 Named Constants 代替魔数:魔数自身的变现力低,使用具名常量增强表现力。
- G26 建议当你首次完成系统时,对细节的完成尽可能详细,不要偷懒。
- G27 良好结构和惯例之间的取舍,前者优先
- G28 建议封装条件:将if/else和switch/case处的条件式,用独立而良好命名的方法重新表述,使条件处永远只有一行,并且让那个独立的方法的名字,替你解释此处条件是什么。
- G29 避免否定条件:首先使用肯定条件。
- G30 方法只做一件事
- G31 隐藏临时耦合
- G32 别随意
- G33 封装边界条件:将边界条件集中、封装,不要让他们散落各处
- G34 方法只活动在同一层抽象上
- G35 让配置信息和数据,保持在高层抽象上,不要定义在底层抽象上,通过参数逐层传递它们。
- G36 避免多级传递:遵守Law of Demeter
Java
- J1 包引入:如果引入了一个package中的超过两个成员,那么直接引入整个包。
- J2 不要继承常量:不要将常量声明在基类或接口中,然后继承它们。将常量声明在子类中。
- J3 使用枚举代替一系列常量。
命名 Naming
- N1 选择有描述力、表现力的名字
- N2 在命名时体现不同抽象层级
- N3 如果可能,采用某些标准惯例下的命名
- N4 明确命名,避免含混用词
- N5 相关域越大,其命名可以越长
- N6 避免编码:??
- N7 不要将方法不会去做的事,体现在其命名上
测试 Tests
- T1 不充分的测试
- T2 使用IDE提供的测试覆盖工具
- T3 不要跳过那么低级的、显而易见的trivial测试
- T4
- T5 细心测试边界条件
- T6 当你发现bug时,正儿八经地测试它
- T7 测试失败pattern
- T8
- T9 测试需要快速
《Clean Code》阅读笔记的更多相关文章
- 阅读《RobHess的SIFT源码分析:综述》笔记
今天总算是机缘巧合的找到了照样一篇纲要性质的文章. 如是能早一些找到就好了.不过“在你认为为时已晚的时候,其实还为时未晚”倒是也能聊以自慰,不过不能经常这样迷惑自己,毕竟我需要开始跑了! 就照着这个大 ...
- RobHess的SIFT源码分析:imgfeatures.h和imgfeatures.c文件
SIFT源码分析系列文章的索引在这里:RobHess的SIFT源码分析:综述 imgfeatures.h中有SIFT特征点结构struct feature的定义,除此之外还有一些特征点的导入导出以及特 ...
- RobHess的SIFT源码分析:综述
最初的目的是想做全景图像拼接,一开始找了OpenCV中自带的全景拼接的样例,用的是Stitcher类,可以很方便的实现全景拼接,而且效果很好,但是不利于做深入研究. 使用OpenCV中自带的Stitc ...
- 阅读《RobHess的SIFT源码分析:综述》笔记2
今天开始磕代码部分. part1: 1. sift特征提取. img1_Feat = cvCloneImage(img1);//复制图1,深拷贝,用来画特征点 img2_Feat = cvCloneI ...
- element-ui button组件 radio组件源码分析整理笔记(一)
Button组件 button.vue <template> <button class="el-button" @click="handleClick ...
- element-ui 组件源码分析整理笔记目录
element-ui button组件 radio组件源码分析整理笔记(一) element-ui switch组件源码分析整理笔记(二) element-ui inputNumber.Card .B ...
- element-ui Carousel 走马灯源码分析整理笔记(十一)
Carousel 走马灯源码分析整理笔记,这篇写的不详细,后面有空补充 main.vue <template> <!--走马灯的最外层包裹div--> <div clas ...
- STL源码分析读书笔记--第二章--空间配置器(allocator)
声明:侯捷先生的STL源码剖析第二章个人感觉讲得蛮乱的,而且跟第三章有关,建议看完第三章再看第二章,网上有人上传了一篇读书笔记,觉得这个读书笔记的内容和编排还不错,我的这篇总结基本就延续了该读书笔记的 ...
- element-ui MessageBox组件源码分析整理笔记(十二)
MessageBox组件源码,有添加部分注释 main.vue <template> <transition name="msgbox-fade"> < ...
- element-ui switch组件源码分析整理笔记(二)
源码如下: <template> <div class="el-switch" :class="{ 'is-disabled': switchDisab ...
随机推荐
- ui component 是一个前端 mvc 开发框架
- python之进程,线程,协程简单理解
进程:资源单位,由操作系统控制调度.正在执行的一个程序或者过程,进程之间不共享资源,进程间通讯手段:管道,队列,信号量等.多用于计算密集型场景,如金融计算 线程:是cpu的最小执行单位,由操作系统控制 ...
- UML作业第一次:UML用例图绘制
UML第一次作业 一. 用例图:用例图(usecase diagram)是UML用于描述软件功能的图形.用例图包括用例.参与者及其关系,用例图也可以包括注释和约束.程序员要画时序图啥的用其他的比较麻烦 ...
- Xamarin 自定义 ToolbarItem 溢出菜单实现(Popover/Popup) 弹出下拉效果
使用 Rg.Plugins.Popup 插件 1. 新建 PopupMenu.xaml <?xml version="1.0" encoding="utf-8& ...
- 1、写在开头的话——Tinking in Java 绪论之我见
新兵道歉!版式不懂,技术若有错误,请指正,或发我邮箱1300431700@qq.com 不胜感激! 本文力图通过文章总结的形式,阐述自己的观点,迫使自己思考书中精髓,即使跟技术无关! 正文开始! “上 ...
- codeforces-3
C Game"23" #include<iostream> using namespace std; int main() { long long n,m; long ...
- Vue系列之 => webpack的url loader
安装: npm i url-loader file-loader -D //url-loader内部依赖file-loader webpack.config.js const path = requ ...
- linux软AP--hostapd+dhcpd
linux软AP--hostapd+dhcpd 2018年05月08日 ⁄ 综合 ⁄ 共 4908字 ⁄ 字号 小 中 大 ⁄ 评论关闭 随着手机.笔记本等无线设备的增多,公司里的家用三个无线路由器已 ...
- 高校表白APP-冲刺第二天
今天进行了第二次会议. 一.任务: 昨日任务完成基本登录注册修改页面布局. 今日任务完成登录界面的基本框架. 明日任务登录修改注册跳转,解决真机运行闪退. 二.遇到的困难: 登录界面按钮布局位置,输入 ...
- 遗传算法(Genetic Algorithm, GA)及MATLAB实现
遗传算法概述: • 遗传算法(Genetic Algorithm,GA)是一种进化算法,其基本原理是仿效生物界中的“物竞天择.适者生存”的演化法则,它最初由美国Michigan大学的J. Hollan ...