Refresh Clean Code

2021年11月21日 阅读数:12
这篇文章主要向大家介绍Refresh Clean Code,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

这是一本被前辈称赞, 另外一个马丁的知名著做, 被赋予学习如何写出漂亮代码的教皇级手册, 最近(再)浏览, 有诸多感觉.算法

总结一下就是若是你是新手, 可能看优秀的open source学习更好; 若是你是老手, 可能他说的东西要么你会以为太啰嗦, 要么你会以为例子太细节, 太教条, 没法触类旁通.设计模式

不过一些General的要点思想我摘录了出来, 有些还包括我的的观点, 记录在此, 以备查阅.数据结构

  • 勒布朗(LeBlanc)法则, Later equals never
  • 代码若是烂了就会愈来愈烂, 所谓破窗原理, 之前总是也提过叫代码腐化
  • 命名
    • 命名应该合理, 成员变量不用加前缀, 靠高亮就很好
    • 接口加前缀I也不太好, 不如实现加Imp
    • 方法命名最好使用动词或动词短语
    • 多使用计算机领域的词汇
    • 有时候命名在语境里才有意义, 有时候变量命名也不须要重复语境
  • 函数
    • 函数短小一些比较易懂, 20行内最佳
    • if/else/while代码块封装函数, 只有一行最好 (有点激进?)
    • 一个函数只干一件事情
    • 复杂的switch试图用多态取代, 而后封装在抽象工厂里
    • 同一类型函数命名风格应该一致, 使用描述性的语句描述比难懂的短词更好
    • 一元函数最广泛, 标识函数(参数为boolean)的不如分红两个函数, 二元函数尽量转换成一元函数
    • 参数太多可能须要封装类了
    • 好名字的函数通常是动词, 或者动词+关键字
    • 函数通常要么作事, 要么回答事, 不可兼得 (其实也不必定, 好比不少返回boolean状态的函数)
    • 推荐使用异常代替错误代码
    • 最好将try/catch单独抽入一个函数 (如Android代码会对RemoteService调用进行相似封装, 吃掉exception)
    • 使用枚举表示错误码会让改动变得繁琐 (从新导入或者编译部署), 你们都依赖这个枚举, 应该用异常与继承取代
    • 不要重复, 偶尔能够考虑AOP这类的方法解决
  • 注释
    • 注释少要比注释多有用, 注释多说明代码糟糕 (其实分状况吧)
    • 有目的性的注释仍是有用的, 好比阐述, 放大, 警告, 按期维护的TODO等
    • 若是代码不用, 不要注释掉, 直接删掉
  • 格式
    • 横向, 竖向对齐, 间隔, 缩进等. 其实目前formater已经很强大了, 养成良好的format习惯, 渐渐的写出来的代码就会像直接format后同样
  • 对象与数据结构
    • 面向过程与面向对象对立, 前者容易加函数, 不容易加对象, 后者容易加对象, 而不容易加函数
    • 理想状况下, Law of Demeter认为, 类不该该操做对象内部的东西, 如不该该操做函数返回对象的方法. 目的只是为了下降复杂度, 认为这样将私有变量公开化, 增长了重构的难度, 如添加新函数, 方法等, 将数据结构与对象逻辑耦合在一块儿.
    • 针对于上面的问题, 原则应该是对象暴露行为, 隐藏数据, 数据结构暴露数据
  • 错误处理
    • Java特点的受控异常(Checked Exception), 必须得被catch, 对受控异常的修改会引发上层全部调用方法的改动, 尽可能不要使用, 其余语言只有RuntimeException
    • 能够包装第三方逻辑, 封装本身的异常类, 简化为只catch一种异常
    • 简化使用也能够将异常处理彻底封装进去, 返回特例便可
    • 轻易不要返回null, 传入null
    • 代码的坚固与干净不冲突, 因此添加一些check, throw相应的Exception也合理
  • 边界
    • 所谓边界就是本身能够控制到的程序与第三方的边界, 一般须要经过封装的办法来划清边界, 限制那些没法控制的第三方, 如直接Wrapper或者Adapter模式等
  • 单元测试
    • 测试须要整洁, 须要跟随代码一块儿更新, 测试的最大用途是保证你后续的修改有信心
    • 测试的整洁主要讲的是可读性, 即分为三个环节, build->operate->check, 能够把繁杂的准备封装起来
    • 测试API是渐渐重构演进过来的, 也不多是起初就设计出来
    • 有人建议每一个测试一个assert, 可是这样会有不少重复的代码, 不过能够利用Template Method来解决. 不过也不必定必须一个, 作到最小化就能够了
    • 整洁还有五条规则, Fast, Independent, Repeatable, Self-Validation, Timely
    • 这里讲到TDD的好处, 主要是帮助你覆盖更多的测试, 若是写完再测, 发现测不了, 就不写了.
    • 类应该短小, 权责应该足够单一, 内聚性应该高
    • 若是指望抽走一部分逻辑, 最好连相关函数参数也抽走
    • 简化类的过程应该小步, 每一步都运行测试一下
    • 类的精简是为了更好的体现开闭原则, 总体结构为修改而设计
    • 类应依赖于接口, 不依赖实现, 能够隔离修改, 符合依赖倒置原则, 相似策略模式
  • 系统
    • 构造与使用分开, 经过依赖注入等
    • 经过AOP, Proxy的方式, 无侵入性的插入逻辑
    • 系统若是充分模块化, 领域之间相互直接松耦合, 最为理想, 就能够经过测试来驱动
    • DSL的使用能够平衡领域与技术
  • 迭代
    • 代码是在不断迭代中进步的, 好比经过抽函数, 运用设计模式等
  • 并发
    • 应该尽量分离并发代码与其余代码
    • 尽量让线程之间独立, 不要有共享
    • 线程模型有典型的生产者与消费者, 读者与做者, 宴席哲学家模型, 分别用来讲明互斥, 读写, 竞争死锁等特例
    • 锁定代码块应该尽量小
    • 线程最好可插拔, 遵循单一权责, 分离线程与其余代码,  测试先保证除线程以外的逻辑
    • 最后一张经过实例来介绍并发代码如何重构的比较清晰
  • 逐步改进
    • 这片使用了一个例子, 先采用蛮干进行重构发现愈来愈难, 后来采用逐步的办法, 还写的很细节,  可是比较Tricky的地方是, 这里提出的每步改动都经过测试来印证, 而后保证测试经过, 或者补充一个测试, 让代码经过, 可是所谓TDD部分只有思想, 老代码既然写的很差, 测试是如何出来的, 如何作到Cover全的. 若是假设在一个有比较好测试覆盖的基础上重构, 我感受即使蛮力也不会太差...
  • JUnit
    • 比较神奇的一章, 感受更像是用一个算法类的重构来讲明如何把代码改简单, 可是开头先介绍了100%覆盖的Junit测试长什么样子... 感受做者是想说之前的人作的还不错, 都用JUnit给覆盖全了, 仍是能够重构的更漂亮的, 因此感受标题不太好
  • 重构SerialDate
    • 跟上一个对比, 这个测试覆盖不全, 因此在补测试的过程当中进行重构, 还发现了缺陷, 又最终把代码改清晰了. 不过一样因为太过细节, 一些重构理论也很教条, 若是想经过看别人重构的例子来学习若是写简洁的代码, 不如直接看优秀的代码是怎么写的
  • 味道
    • 里面类比了不少Bad Smell, 一样是很细节, 好比太多, 太死, 太复杂, 重复, 不一致, 耦合, 测试不足等, 提供的Tips大多的中心思想就是抽, 封装, 单一职责, 命名清晰
    • 提到使用*来避免过长import, 不过这个与如今流行的lint检测违背, 能够由于之前都是手动, 通配符简单吧.
    • 不要经过继承来使用常量, 还提到不要用静态常量, 用枚举, 这个也与当前的思想有出入, 如今常常将Java的enum太冗余, 没必要要时能够用常量
上一篇: 聊聊clean code
下一篇: pthread clean up