《代码整洁之道》读书笔记

来源:互联网 发布:大盘指数算法 编辑:程序博客网 时间:2024/05/18 00:53
* 整洁代码的意义?
可读性,可维护性。
* 如何写出整洁代码?
1.只做一件事
2.不重复
3.有表达力
* 整洁代码的态度要求,要遵守的军规?
专业 和责任。让营地比你来时更干净,拒绝破窗效应。
* 写出整洁代码的具体做法?
有意义的命名(表达力,可读性)
函数只做一件事,每个函数一个抽象层级,短小不重复。
注释是代码缺乏表达力时的弥补措施,好的代码自我注释。
格式要统一,有层次,易理解。
类,权责对应,内聚,只做一件事。得墨忒耳定律:模块不应该了解所操作的类的内部情况。
对象方便增加子类,数据结构方便增加新操作方法。
错误处理应该独立于主逻辑之外。
迭代、 逐步改进、重构。



下面是章节概要内容:
  • 代码整洁之道
    • 我加的前言
      • 本书需要着重琢磨书中的案例才能深刻理解其原则,否则就如同是一本泛泛而谈的书。
      • 简单原则
        • 保持代码的整洁与可维护有一条很简单的规则:
          • 10:包内的类不超过10个  
          • 50:方法的代码行数不超过50
          • 500:类的代码行数不超过500
        • 只做一件事
        • 有表达力
        • 不重复
    • 1整洁代码
      • 混乱的代价
        • 生产力的持续下降
      • 态度
        • 坚持整洁代码是一种专业的态度和责任
      • 意义
      • 什么是整洁代码
        • 整洁的代码只做好一件事
        • 直接简单如同优美的散文,从不隐藏设计者的意图,充满了干净利落的抽象和直截了当的控制语句
        • Dave Thomas
          • 便于其他开发人员阅读和增补
          • 有单元测试和验收测试
          • 有意义的命名
          • 一种而非多种做一件的途径
          • 尽量少的依赖
          • 明确和尽量少的api
          • 代码通过其字面表达含义
        • Ron
          • 通过所有测试
          • 没有重复代码
          • 体现系统的全部设计理念
          • 包括尽量少的实体
          • 减少重复代码、提高表达力、提早构建简单抽象。
      • 我们是作者
        • 其他程序员会阅读我们的代码,所以要写的易懂些。
      • 童子军军规
        • 让营地比你来时更干净
          • 不论代码现状如何糟糕,都要进行改善,而不是任其腐烂。
          • 不论代码现状如何良好,都不增加任何小的糟糕代码进行腐化。
        • 拒绝破窗效应
    • 2有意义的命名
      • 这个一个严肃的问题
      • 规则
        • 名副其实
          • 魔术数
        • 避免误导
        • 做有意义的区分
        • 使用读得出来的名称
        • 使用可搜索的名称
        • 避免使用编码
          • 避免使用各种前缀
            • 接口I避免使用
              • 干扰和废话
        • 避免思维映射
          • 不要用自己才懂的标记
          • 明确是王道
        • 类名应该是名词或名词短语。类名不应当是动词。
        • 方法名应当是动词或动词短语。
        • 别扮可爱
        • 每个概念对应一个词
          • 不要既有controller,又有manager
        • 别用双关语
        • 使用解决方案领域名称
        • 使用源自所设计问题领域的名称
        • 添加有意义的语境
        • 不要添加没有意义的语境
    • 3函数
      • 如何写好函数
        • 短小
        • 短小
          • 行列不应该长于一个屏幕
            • 20行最佳
        • 只做一件事
        • 每个函数一个抽象层级
          • 不要让实现细节和基础概念混杂
          • 向下规则
            • 自顶向下读代码
        • switch语句
          • 根据代价判断是否使用多态来代替switch语句
        • 使用描述性的名称
          • 别怕长名称
          • 命名方式要一脉相承
        • 函数参数
          • 尽量避免3个以上的参数
          • 避免向参数传入布尔值
            • 意外着函数要做不止一件事
          • 函数名字和参数尽量形成动词/名称的结构
          • 无副作用
            • 避免时序耦合、顺序耦合
        • 避免使用输出函数
          • 使用更改对象的状态来替代
        • 函数要么是做什么事,要么是回答什么事,两者不可兼得
        • 指令与询问分隔开
        • 使用异常替代返回错误码
          • 错误码违反了指令与询问分隔开的原则
          • 抽离try/catch代码块
          • 错误处理就是一件事
            • try开头,catch/finally代码后面不该有其他内容
        • 别重复自己
          • pmd
        • 结构化编程
          • 每个代码块只有一个入口一个出口
        • 如何写出这样的函数
          • 在单元测试通过的基础上不断重构打磨
    • 4注释
      • 别给糟糕的代码加注释--重新写吧
      • 用代码来阐述
      • 好注释
        • 想办法不去写注释
        • 法律信息
          • 使用链接
        • 提供信息的注释
        • 对意图的解释
        • 阐述
        • 警示
        • TODO注释
          • 要经常清理
        • 公共API的JavaDoc
      • 坏注释
        • 喃喃自语
        • 多余
        • 误导
        • 循规蹈矩的注释
        • 日志式注释
        • 废话
        • 能用函数名和变量名时就不要用注释
        • 位置标记
        • 括号后面的注释
          • 将函数写的短小就不需要这种注释了
        • 归属与署名
        • 注释掉的代码
        • html注释
        • 非本地信息
        • 信息过多
        • 不明显的联系
        • 函数头注释
        • 非公共代码的JavaDoc
    • 5格式
      • 团队公用一套管理代码格式的简单规则
        • checkstyle
      • 格式的目的
        • 代码风格和可读性将会影响到可维护性和扩展性
      • 垂直格式
        • 使用大多数为200行,最长500行的单个文件是可以构建出优秀的系统的
        • 向报纸学习
          • 有层次,细节逐层展开
        • 概念间垂直方向上的区隔
          • 空白行分割,在每个函数之间有利于阅读
        • 垂直方向的靠近
        • 垂直距离
          • 关系密切的放在一起,避免用户阅读时跳来跳去
            • 变量声明
              • 靠近使用位置
              • 本地变量应该在函数的顶部
              • 循环中的控制变量应该总是在循环语句中声明
            • 实体变量
              • 类的顶部
            • 相关函数
              • 调用关系的尽量在一起,并且调用者在被调用者上面。
            • 概念相关
              • 执行相似任务的函数放在一起
        • 垂直顺序
          • 自上而下展示函数调用顺序
      • 横向格式
        • 一行代码应该有多宽?
          • 上限120个字符
        • 水平方向的区隔与靠近
          • 格式化工具自动完成
        • 水平对齐
          • 没什么用
        • 缩进
          • 按层级缩进,有助于快速了解文件结构
        • 空范围
          • 空函数也要有括号和缩进
      • 团队规则
        • 使用统一的风格以减少复杂度
    • 6对象和数据结构
      • 数据抽象
        • 隐藏实现
          • 用户无需了解数据的实现就能操作数据本体
      • 数据、对象的反对称性
        • 对象和数据结构的差异
          • 对象把数据隐藏于抽象之后,曝露操作数据的函数
          • 数据结构曝露其数据,没有提供有意义的函数
        • 对象与数据之间的二分原理
          • 面向对象代码
            • 便于在不改动既有函数的前提下添加新类
            • 难以添加新函数,因为必须修改所有类
          • 过程式代码
            • 使用数据结构的代码
            • 便于在不改动既有数据结构的前提下添加新函数
            • 难以添加新数据结构,因为必须修改所有函数
        • 根据系统是需要添加新函数还是新数据类型选择合适的代码
      • 得墨忒耳定律
        • The Law of Demeter
        • 模块不应了解它所操作的类的内部情形
          • 对象不应通过存取器暴露其内部结构
        • 类C的方法f只应该调用以下对象的方法
          • C
          • 由f创建的对象
          • 作为参数传递给f的对象
          • 由C的实体变量持有的对象
        • 方法不应调用由任何函数返回的对象的方法
          • 只跟朋友谈话,不与陌生人谈话。
        • 火车失事
          • 传递链
          • 违背了得墨忒尔定律,应该避免
        • 混杂
          • 一半是对象,一半是数据结构
            • 一种混乱的设计,导致难以修改。应当避免。
        • 隐藏结构
      • 数据传送对象
        • DTO
          • Data Transfer Object
          • 最精简的数据结构
            • 只有公共变量、没有函数的类
          • 在DTO中塞进业务处理方法是不智的行为,因为它导致了数据结构和对象的混杂体
      • 小结
        • 对象
          • 曝露行为
          • 隐藏数据
          • 便于新增数据类型而无需修改既有行为
          • 难以在既有对象中添加行为
        • 数据结构
          • 曝露数据
          • 没有明显的行为
          • 便于向既有数据结构添加新行为
          • 难以向既有函数添加新数据结构
    • 7错误处理
      • 使用异常而非返回码
      • 先写try-catch-finally语句
      • 使用不可控异常
        • 可控异常会导致从底层到每个调用该函数的函数都要捕获异常,违反了开闭原则破坏了封装
      • 给出异常发生的环境说明
      • 依调用者需要定义异常类
      • 定义常规流程
      • 别返回null值
        • 空对象代替null
      • 别传递null值
        • 禁止传入null值
      • 小结
        • 将错误处理隔离看待,独立于主要逻辑之外
    • 8边界
      • 使用第三方代码时需要适当封装,不要要让边界细节传递到自己的系统中
      • 使用第三方代码时要对其编写测试检测和加强自己的理解程度
        • 学习性测试
      • 示例:学习log4j
      • 学习性测试的好处
        • 边界测试能及时发现版本更新后的不兼容
      • 使用尚不存在的代码
        • 编写我们想得到的接口
      • 整洁的边界
        • 边界上的代码需要清晰的分割和定义了期望的测试
        • 不要让我们的代码过多地了解第三方代码中的特定信息
        • 使用少数的几处引用隔离和管理第三方边界
    • 9单元测试
      • TDD三定律
        • 在编写不能通过的单元测试前,不可编写生产代码
        • 只可编写刚好无法通过的单元测试,不能编译也算不通过
        • 只可编写刚好足以通过当前失败测试的生产代码
      • 保持测试整洁
        • 测试代码和生产代码一样重要
          • 坐视测试代码腐坏,那么生产代码也会跟着腐坏
        • 测试带来一切好处
      • 整洁的测试
        • 可读性
        • 面向特定领域的测试语言
          • 测试api
        • 双重标准
        • 每个测试一个断言
        • 每个测试一个概念
      • F.I.R.S.T
        • 整洁测试的5条规则
        • 快速Fast
        • 独立Independent
        • 可重复Repeatable
        • 自足验证Self-Validating
          • 测试应该有布尔值输出,不要依赖于其他手段
        • 及时Timely
    • 10类
      • 类的组织
        • java约定
          • 一组变量列表开头
            • 公有静态常量量在上面
            • 私有静态变量
            • 私有实体变量
          • 公共函数跟在变量列表之后
            • 被公共函数调用的私有函数紧跟在该公有函数后面
        • 封装
      • 类应该短小
        • 类名应当描述其权责
        • 单一权责原则
          • SRP
          • 避免上帝类
            • 维护了太多功能,职责较多的类
            • 较难修改
          • 类应当只有一条修改的理由
          • 大量短小的类胜过少数臃肿的类
        • 内聚
          • 类应该只有少量实体变量
            • 每个方法都应该操作一个或多个这种变量
        • 保持内聚性就会得到很多短小的类
          • 当类丧失了内聚性就拆分它
          • SRP
      • 为了修改而组织
        • OCP
          • 类应当对扩展开放,对修改封闭。
        • 在理想系统中,我们通过扩展系统而非修改现有代码来添加特性
        • 当出现了只与类的一小部分有关的私有方法时,意味着类存在改进空间
        • 隔离修改
          • 具体类中包含了太多的细节,细节改变将带来风险
            • 可以借助接口和抽象类来隔离细节的影响
              • 解耦
          • DIP
            • 类应该依赖于抽象而非细节
            • 依赖倒置原则
    • 11系统
      • 如何建造一个城市
        • 一些人负责全局,一些人负责细节
        • 将系统的构造和使用分开
          • 分解main
            • 将构造过程搬迁到main或者main模块中
            • 工厂
            • 依赖注入
        • 扩容
          • 关注面切分,增量迭代
          • 横贯式关注面
            • AOP aspect
        • Java代理
          • 适用于简单的情况
          • 原理
            • 代理对象使用Java反射API将一般方法调用映射到被代理的实现类中对应的方法
          • 缺点
            • 代码量
            • 复杂度
        • 纯Java AOP框架
          • Spring AOP
          • 框架以对用户透明的方式处理Java代理或字节代码库。
            • 用户只需要配置文件或调用API
            • 框架声明驱动依赖注入容器实例化对象,并按需将对象连接起来
        • AspectJ的方面
        • 测试驱动系统架构
          • 这种架构能测试驱动
            • 最佳的系统架构由模块化的关注面领域组成,每个关注面均用纯Java(或其他语言)对象实现。
            • 不同的领域之间用最不具有侵害性的方面或类方面工具整合起来
        • 优化决策
        • 明智使用添加了可论证价值的标准
        • 系统需要领域特定语言
          • DSL
        • 小结
          • 保持敏捷性,避免侵害性的框架
          • 所有的抽象层级上,意图都应该清晰可辨
            • 编写POJO并无损地组合其他关注面
          • 尽量使用大概可工作的最简单方案,避免脱离实际的过度设计
    • 12迭代
      • 通过迭代设计达到整洁目的
      • 简单设计四原则
        • 运行所有测试
          • 紧耦合的代码难以编写测试
          • 测试编写越多,越促使系统符合OO设计原则
        • 不可重复
          • 重复意味着额外的工作和风险
        • 表达了程序员的意图
          • 别人读不懂就无法良好的维护
        • 尽可能的减少类和方法的数量
          • 最不重要的一条
        • 以上四条重要性依次降低
    • 13并发编程
      • 对象是过程的抽象,线程是调度的抽象
      • 为什么要并发
        • 并发是一种解耦策略
          • 将目的和时机分解开
        • 明显改进应用程序的吞吐量和结构
        • 改进系统响应时间
        • 大量数据的并行处理
      • 挑战
        • 与编译器、jvm内存原型有关,要获得正确的结果并不容易
      • 并发防御原则
        • 单一权责原则
          • 分离并发相关代码和其他代码
        • 限制数据作用域
          • 使用synchronized关键字在代码中保护一块使用共享对象的临界区
          • 严格限制对可能被共享的数据的访问
        • 使用数据复本
          • 可以避免锁定
        • 线程应该尽可能独立
          • 尝试将数据分解到可被独立线程操作的独立子集。
      • 了解Java库
        • java5编写线程代码时,要注意
          • 使用类库提供的线程安全群集
          • 使用executor框架执行无关任务
          • 尽可能的使用非锁定方案
          • 有几个类并不是线程安全的
        • 建议检读可用的类,掌握java.util.concurrent、java.util.concurrent.atomic和java.util.concurrent.locks
      • 了解执行模型
        • 基础定义
          • 限定资源
            • 固定
          • 互斥
          • 线程饥饿
          • 死锁
          • 活锁
        • 并发大多是这三种模型的变种
          • 生产者消费者模型
            • 限定资源
          • 读者作者模型
            • 线程饥饿
          • 宴席哲学家模型
            • 竞争性系统
      • 警惕同步方法之间的依赖
        • 建议:避免使用一个共享对象的多个方法。
        • 这种情况下有3种写对代码的手段
          • 基于客户端的锁定
            • 客户端代码调用前锁定服务器,并确保锁的范围覆盖了最后一个方法
          • 基于服务端的锁定
            • 在服务端内创建锁定服务端的方法,调用所有方法然后解锁。
          • 适配服务器
            • 创建执行锁定的中间层。
      • 保持同步区域微小
      • 很难编写正确的关闭代码
        • 尽早考虑关闭问题
      • 测试线程代码
        • 建议:编写有潜力暴露问题的测试,在不同的编程配置、系统配置和负载条件下频繁运行。如果失败,跟踪错误。
        • 建议
          • 将伪失败看作可能的线程问题
            • 不要归因于偶发事件
          • 先使非线程代码可工作
          • 编写可插拔的线程代码
            • 单线程与多个线程在执行时不同的情况
            • 线程代码与实物或测试替身互动
            • 用运行快速、缓慢和有变动的测试替身执行
            • 将测试配置为能运行一定数量的迭代
          • 编写(线程数量等)可调整的线程代码
          • 运行多于处理器数量的线程
          • 在不同平台上运行
          • 装置试错代码
          • 硬编码
            • 手工插入wait、sleep、yield、priority等进行测试
          • 自动化
    • 14逐步改进
      • 一个逐步改进的案例
        • 本章需要结合代码体会
      • 实现
      • 草稿
      • 暂停
      • 渐进
        • 大量的最小规模改动
        • TDD
          • 每次改动必须保证系统能像以前一样工作
      • 小结
        • 清理清理糟糕代码的代价高昂,最好的解决之道就是保持代码持续整洁简单。
    • 15JUnit内幕
      • 对JUnit的ComparisonCompactor模块的重构示例
      • 本章需要结合代码体会
    • 16重构SerialDate类
    • 17味道与启发
      • “代码味道”
        • 注释
          • 不恰当的信息
          • 废弃的注释
          • 冗余注释
          • 糟糕的注释
          • 注释掉的代码
        • 环境
          • 需多步才能实现的构建
          • 需多步才能做到的测试
        • 函数
          • 过多的参数
          • 输出参数
          • 标识参数
          • 死函数
        • 一般性问题
          • 一个源中存在多种语言
          • 明显的行为未被实现
            • 对函数直觉的期望未能满足将导致读者不得不阅读代码细节
          • 不正确的边界行为
            • 追索每种边界条件,并编写测试
          • 忽视安全
          • 重复
            • DRY别重复自己
          • 在错误的抽象层级上的代码
          • 基类依赖于派生类
          • 信息过多
          • 死代码
          • 垂直分割
            • 垂直距离要短
          • 前后不一致
          • 混淆视听
            • 没用的变量,从不调用的函数,无用的代码删掉
          • 人为耦合
          • 特性依恋
          • 算子参数
          • 晦涩的意图
          • 位置错误的权责
          • 不恰当的静态方法
          • 使用解释性变量
          • 函数名称应该表达其行为
          • 理解算法
          • 把逻辑依赖改为物理依赖
          • 使用多态代替if/else
          • 遵循标准约定
          • 用命名常量代替魔术数
          • 准确
          • 结构胜于约定
          • 封装条件
          • 避免否定性条件
          • 函数只做一件事
          • 掩蔽时序耦合
          • 别随意
          • 封装边界条件
          • 函数应该只在一个抽象层级上
          • 在较高层级放置可配置数据
          • 避免传递浏览
        • java
          • 使用通配符避免过长的清单
          • 不要继承常量
          • 常量vs枚举
        • 名称
          • 采用描述性名称
          • 名称应与抽象层级相符
          • 尽可能使用标准命名法
          • 无歧义的名称
          • 为较大范围选用校长名称
          • 避免编码
          • 名称应该说明副作用
        • 测试
          • 测试不足
          • 使用覆盖率工具
          • 别略过小测试
          • 被忽略的测试就是不确定的疑问
          • 测试边界条件
          • 测试失败的模式有启发性
          • 测试应该快速
        • 小结
          • 这份启发与味道的清单并不完备,重要的是它给出了一套价值体系,那才是目标。
          • 专业性和技艺来自驱动规则的价值观  
        • 下载地址:http://download.csdn.net/download/shy_snow/9993995
原创粉丝点击