重点章节
第二章:有意义的命名
建议
-
不要写A,B,C变量名
-
避免误导的单词,给出具有实际意义的单词
-
有意义的区分
- 反例:nameString
-
不要用拼音
-
方便搜索的命名
-
避免编码问题
- utf_开头等
应用
-
一个概念一个单词,或者使用相近的单词,比如serialDate
-
少用双关的句子
- add可以表示多种可能的含义,可以是添加,可以是追加.....
-
一个有意义的语境
- 方法名和内容贴合
-
不需要无用的方法和内容,方法应该出现在该出现的位置
第三章:函数
重点
- 时刻保持参数的数量控制
- 函数要返回期望的内容,运行期望的行为
- 避免副作用的方法
- 取个好名是好方法的关键步骤
简介
- 介绍如何写出更加简单并且令人夸赞的好方法
- 函数式封装的第一个步骤,时刻练习如何写出好的函数
建议
-
switch语句结合抽象工厂,避免少用很多switch分支
-
函数名词长并且见文知意,可以很好的把握意思,如果短小并且易懂就是好名字
-
函数参数尽量控制在2个以内。函数的结果要尽量放到返回值,比如 obj transform(obj)
-
询问和命令要分开,不能在if进行数据处理的同时返回信息
-
函数不应该有副作用:比如函数不应该出现某些情况下的错误信息
-
少使用嵌套复杂的代码
- 方法内容越少越好
- if内容一行最佳
- 函数只做一件事情
应用
-
方法超过3个以上的时候,思考是否需要抽取到一个单独对象,当达到四个以上的时候,为每一个参数介绍作用(希望永远不要这样做)
-
工具类建议学习框架的工具类,比如CollectionUtils,BeanUtils等
-
不要返回NULL,容易造成空指针异常
-
自顶向下读代码 #重点
-
什么是自顶向下
- 从一个T0的头部到另一个T0的头部
- 容纳设置与分析步骤,先容纳设置步骤
- 纳入测试页面内容,纳入分析步骤
-
简单理解
- 设置执行步骤,提取主干方法
- 设置步骤(伪代码),再实现分支
- 用搜索代替上下关系
-
-
-
如何判断方法只做一件事
- 是否能再抽取一个方法
- 是否是对诠释的重新实现
-
正例
- checkEmptyAndNull()
- doSomething(Object obj)
反例
- return obj == null? null:new Object
- method(param1, param2, param3, param4, param5)
第四章:写出一个好注释
重点
- 写出好代码才是关键,先写出好简洁代码,再考虑写好注释
- 最好的状态是代码本身就能诠释注释
- 努力写出简单易懂的好注释
- 好注释不仅可以让阅读者理解,还可以让阅读者学到新知识
简介
- 写一个注释容易,但是写好一个注释不容易
- 程序员因为各种“借口”懒得写注释
- 如果你的代码足够具备表达力,就不需要注释,否则请加上你的注释
建议
- 阐述性注释保证注释的正确性,谨慎编写
- 警告性注释可以是说明禁止那样做,但是更好的方式是警告为什么要那样做
- 如果代码很难被解释,需要依赖注释解答,那代码就不是好代码,请确保编写好理解的代码,那么就不需要注释
- 注释不要喃喃而语,不要写意义不明的注释或者对当时自己有意义的注释
- 不要过于详细的注释,比如为每一个变量介绍他是干嘛用的
- 不要编写HTML标签注释,特别是复杂的HTML标签
- 定期删除TODO注释
应用
-
- 定期回顾自己写过的代码,对于注释进行回顾或者补充
-
- 注释要“有始有终”,要么全写,要么全不写
-
- 时常思考注释是否真的有必要,谨慎对待每一行注释
-
- 注释按照某种原则,可以让阅读者更好的理解
-
- 勇敢的删除注释掉的代码,版本控制工具会帮忙“找回”
正例
- 外国人的汇率换算和国人思路相反,比如人民币兑换美元,应该查找美元兑换人民币的汇率
- SimpleDateFormat 线程是不安全的,不能使用静态或者单例构建,这里必须每次实例化
- 5!代表 12345.....
反例
- 一行代码一行注释
- 为了赶工一行注释也不写
- 注释罗里吧嗦或者做一些奇怪的标记
- 把阅读者当初刚入行的新手,把注释写满
第五章:格式
建议
- 方法不应该超过120行,80行最佳
- 一个文件代码不要超过500行
- 遵循编程习惯,把变量声明在正确的位置
- 代码宽度在120个字符左右(不要依赖带鱼屏)
- 向报纸学习,学习如何简化头部和进行良好的排版
第七章:异常处理
重点
-
异常处理的一些技巧
- 用单独的方法进行try/catch
- 从大的异常到细化异常
-
不要返回NULL值
-
异常需要作为单一职责看待,而不是和方法捆绑
简介
- 异常处理是一种权责,不要和业务混淆
- 异常处理的基本手段和一些原则介绍
建议
- 用异常代替繁多的if else判断,是一种好习惯
- 异常就是一件事,所以异常最好单独为一个函数,同时catch的内容不应该做其他事情
- 不要用try包裹一大段代码,同时异常处理应该尽可能细节化
- 异常处理应该是单独的方法,可以使用内部方法抛出异常
- 如果不知道如何处理异常,就需要及时抛出异常通知调用者可能存在异常
应用
- 异常最好在一个方法的开头就定义好
- 将可能出现异常的部分和永远不会出现异常的部分分离
正例
- 异常用单独的方法进行封装
- 可以处理的异常,进行日志记录和提示打印
- 及时在方法声明有可能的异常信息
反例
- 几百行代码使用一个try/catch
- 捕获异常,不进行处理,同时不做日志记录
第九章:单元测试
重点
-
测试单元:一个测试一个断言,测试单元尽可能简短
-
FIRST原则
-
F:快速
- 测试可以快速进行
-
I:独立
- 测试之间相互独立
-
R:可重复
- 测试在任何环境都可以通过
-
S:自足验证
- 存在布尔值输出,可以验证自己的结果
-
T:及时
- 测试要及时进行编写
-
简介
-
学习使用TDD测试驱动开发的形式
-
单元测试是非常重要并且必要的
- 测试的好处
- 整洁的测试
-
TDD的三大定律
- 编写不能通过的测试代码之前,不编写生产代码
- 只编写刚好无法通过的单元测试
- 只编写刚好足以通过测试的生产代码
第十章:类
重点
- 少量的大类并不一定比大量小类好管理
- 用尽可能少的类和方法完成目的
- 类不应该有太多的权责和干扰
简介
-
关键内容在于类的权责拆分
- 当失去内聚的时候就想办法拆分
- 生活抽象:你是要一个装任何东西的百宝箱还是一个布满各种方格的工具箱
第十七章:味道和启发 #重点
重点
- 总结全书的一些要点
- 回顾全书的重点内容
简介
- 非常重要的一个章节,用一个章节概括了全书的一些重要内容
- 可以从最后一章确定全书要阅读的部分
注释
-
不恰当的注释信息
- 表达意义模糊不清
-
糟糕的代码
- 注释无法解释的代码
-
冗余的注释
- 对一段内容反复说明
-
糟糕的注释
- 画蛇添足
- 花了时间但是没有思考
-
注释掉的代码如何处理
- 不知道是否需要删除的代码
- 放心删除被注释的代码
环境
- 使用单步操作构建一整个系统
- 评估多少步可以完成测试
函数
- 杜绝过多的参数
- 注意输出参数 - 返回值
一般性问题 #重点
-
一个源文件不应该有很多种语言,比如JAVA doc的HTML代码
-
函数应该事先期待的行为并且返回期待的结果
- 最小惊异原则
-
不正确的边界行为
-
忽视安全机制
- 序列化的SerialId问题
-
尽可能的的消除重复,才能写出更好的代码 #重点
-
使用抽象概念定义更加高级的抽象模型
- 较低的概念在子类,较高级的概念在父类 #重点
-
基类依赖派生类
- 基类概念可以不依赖于低层级的派生类概念
-
接口的信息应该尽可能的精简,否则将会有复杂的实现 #重点
- 如果类存在过多的信息,应该思考如何分解
-
死代码问题
- 一般性永远不会执行的代码在现代可能永远不会排查
- 预防逻辑上永远不会执行的代码
-
垂直分隔
-
前后保持一致
- 最小惊异原则
-
移除混淆视听的代码
-
伪耦合:在合理位置放置合适内容
-
特性依恋问题
- 一个类的对象不应到依赖一个不相干的类,依赖应该保持在一个类内部
- PS:个人不是很同意问题
-
算子参数
- 警惕因为选择值的不同导致不同结果的方法 (Boolean参数)
-
代码具备强烈的表达含义
-
正确的函数名与正确的位置
-
确保静态方法没有多态的行为
-
良好的解释性变量可以使程序易读
-
良好的函数名应该见名知意
-
确保对于自己做的事情有全方位考虑而不是正常的运行
-
逻辑依赖改为物理依赖 #重点
-
尽可能避免直接使用类内部常量,而是方法当中进行保护
-
举例
- page-size = 35 改为 geMaxSize()
-
-
多态的选择分支
-
单个switch原则
- 支持一次类型判定同时case内容必须为多态
-
-
使用变量代替魔法值,尽可能少用魔法值
-
确保代码足够精确,在不同的情况下出现期望的行为
-
在IF里面尽可能少用“双重否定” #重点
-
函数永远只做一件事情 - 单一职责的原则
-
传递浏览信息
- A->B,B->C,A不能知道C的信息
-
如果派生类多次用到同一个配置,应该将配置放到最高层
JAVA部分
- 避免过长导入清单,Java.util.* 问题
- 用静态导入代替常量的继承
- 用枚举替代PSF常量(public static final)
名称
-
描述性名称
-
名称符合抽象概念
-
无歧义名称
-
标准命名法
- 驼峰命名
- 首字母大写
-
名称具备副作用解释
- exists
- null
附录:并发编程补充
影响线程运行的因素(性能)
IO密集型
- 套接字
- 连接数据库
- 内存交换
处理器
- 正则运算
- 垃圾回收
- 算法
如何测试线程
- 增加线程代码
- 通过测试的代码不一定正确
分析服务端代码权责
- 套接字连接
- 客户端处理
- 线程策略
- 服务器关闭
心得和总结
-
边看边思考,边看边实践。实践最重要
-
代码不是一步到位的,代码永远都没有最优解,根据自己的能力要不断摸索更优解。刻意练习
-
不想看书的一些建议点
-
单一职责
- 代码是否真的只做了一件事,是否在自己骗自己
- 验证是否只做一件事的万金油法则:加需求
- 方法是否是“全包干”
-
不要重复自己
- "CV"编程会让水平停留在"CV"
- 现代的编辑器可以减少很多思考
-
什么是简洁
- 没有注释,读代码就像在读业务逻辑
- 没有过时的注释,也没有错误的注释,更没有没用的注释
- 用最少的代码做最大的事情,代码复用度高
- 没有重复,单一职责
-
迭进
- 学会拆分职责和剥离职责
- 思考何为面向对象
- 不断的改进,写出更简洁的代码
-
批判精神
- 敢于重构代码,对于自己编写的代码发出挑战
- 接受批评,才会不断进步
- 运行所有测试
- 不可重复
- 表达程序员意图
- 尽可能减少类和方法
-
对象与数据结构
-
得墨忒耳定律
- 模块不应该了解对象内部的情形
-
对象和数据结构的二分定律
- 过程式代码便于不改动既有结构上加入新函数。面向对象在不改动既有函数情况下增加新类
- 过程式代码难以加入新的数据结构,面向对象代码难以加入新的函数
-
-