Clean Code Notes

  1. 云栖社区>
  2. 博客>
  3. 正文

Clean Code Notes

忘我杨 2019-01-02 18:29:06 浏览213 评论0

摘要: 《代码整洁之道》笔记

一、有意义的命名及函数

  1. 类名:使用名词,方法名:动词
  2. 别用双关语:避免将同一单词用于不同目的。eg. add
  3. 使用解决方案领域名称。eg. JobQueue;如果不能使用程序员熟悉的术语来给手头的工作命名,就采用从所涉问题而来的名称。
  4. 函数应短小(每行150字符,不超过100行,20行封顶最佳)。
  5. 函数只做一件事,同设计模式一样,应尽量遵循单一权责原则及开闭原则。
  6. 每个函数中的语句,理应都要在同一抽象层级上。
  7. 沃德原则:如果每个例程都让你感到深合己意,那就是整洁代码(并且不要怕长名称方法名)
  8. 函数的参数:最理想的参数数量是零,其次是一,再次是二,尽量避免三。有足够特殊的理由才能用三个以上参数(阿里巴巴Java开发手册:相同参数类型,相同业务含义,才可以使用 Java 的可变参数,可变参数放在最后,尽量不用可变参数,避免使用 Object)
  9. 标识参数:丑陋不堪,render(Boolean isSuite)代表了该函数在标识为true会这样做,为false会那样做。应该一分为二——renderForSuite()和renderForSingleTest()
  10. 二元及三元函数:在当单个值的有序组成部分不确定时,多元函数并不是好的选择
  11. 参数对象:如果函数看来需要两个、三个或三个以上参数,就说明其中一些参数应该封装为类了。
    Circle makeCircle(double x,double y,double radius)
    Circle makeCircle(Point center,double radius)

后者优于前者

  1. 函数与参数:应是一种非常良好的动词/名词对形式
    write(name)
  2. 无副作用:在执行函数时,应不该造成其他部分的更改
  3. 分隔指令与询问:函数要么做什么事,要么回答什么事
  4. 使用异常代替返回错误代码,抽离Try/Catch代码块。Try/Catch代码块丑陋不堪,搞乱了代码结构,最好把其中内容单独写成一个函数。

二、注释

  1. 注释并不能美化糟糕的代码,最好用代码来阐述
  2. TODO 是一种程序员认为应该做,但由于某些原因目前还没做的工作,它可能是要提醒删除某个不必要的特性,或者要求他人注意某个问题等。
  3. 坏注释:
    喃喃自语、多余的注释、误导性注释、循规式注释、日志式注释、废话注释。(p55-p61)
  4. 不应当有的注释:位置标记、括号后面的注释、归属与署名、注释掉的代码、HTML注释、非本地信息、信息过多、不明显的联系(p62-p65)
  5. 非公共代码中的Javadoc

三、格式

  1. 垂直格式
    单个文件代码行数fitnese多在200行到500行之间

(作者认为尽量精简代码在单个文件中,并且文件之间代码行数最小与最大值差距不要过大)

  1. 向报纸学习(自上而下,内容逐次展开)。实际编程中注意很难注意这个
  2. 适当的换行

    1. 方法与方法之间
    2. 变量与方法之间
    3. import 与类之间
    4. import 系统类和导入包中的类或者自定义类之间
  3. 垂直距离

    1. 变量声明应尽可能靠近其使用位置
    2. 实体变量应放在类的顶部声明
    3. 相关函数应尽量放在一起,一个方法调用了该类中的另一个方法,应尽量放在一块
    4. 概念相关的代码应该放在一起,重载的方法也算
  4. 横向距离
    (一行代码所用字符 [阿里巴巴java开发手册中有定义],水品对齐,水平方向上的取个与靠近-不认同)

    1. 同一层级的代码应该缩进至同一个层级(Python中采用强制缩进)

四、对象和数据结构

  1. 面向过程式代码与面向对象式代码(p89-p90)
    对于面向对象较难的事,对于过程式代码却较容易,反之亦然。
  2. 得墨忒耳律认为,类 C 的方法f只应该调用以下对象的方法:

    1. C
    2. 由 f 创建的对象
    3. 作为参数传递给 f 的对象
    4. 由 C 的实体变量持有的对象
      方法不应调用有任何函数返回的对象的方法,换言之,只跟朋友谈话,不与陌生人谈话。(实际生产环境用jfinal service 调 dao 是用的该实体类的静态内部对象,与ssm有不同)
  3. DTO(Data Transfer Objects) 里最好不要有业务规则代码。

五、错误处理

  1. 使用异常而非返回码
  2. 先写 try - catch - finally
  3. 某种意义上,try 代码块就像是事务,catch 代码块将程序维持在一中持续状态,无论 try 代码库中发生了什么均如此。
  4. 给出异常发生的环境说明。
  5. 别传递 null 值:可以用断言代替判空。 assert p1 != null: "p1 should not be null";

六、边界

  1. 学习 log4j
  2. 使用上尚不存在的代码:适配器模式(作者采用的)

七、类

  1. 类的组织:公共静态变量->私有静态变量->私有实体变量。很少出现公共实体变量
  2. 类应该短小:对于类,我们采用不同的衡量方法,计算权责。
  3. 单一权责原则:类或模块应有且只有一条加以修改的理由。
  4. 内聚:类应该只有少量实体变量,类中的每个方法都应该操作一个或多个这种变量。
  5. 文中举例说明了一个 Sql 类的重构。将一个 Sql 类中所有的 CRUD 方法抽象成一个 generate 方法,并由相应的 CRUD 类继承。(和现在 jfinal 的使用方法不一样,虽然违反了设计模式开闭原则。但我认为对中小型项目开发,反设计模式更为便捷)

八、系统

  1. 依赖注入(Dependency Injection DI),控制反转(Inversion of Control IOC):可以实现分离构造与使用,控制反转将第二权责从对象中拿出来,转义到另一个专注于此的对象中,从而遵循了单一权责原则。因为初始设置是一种全局问题,这种授权机制通常要么是 main 例程,要么是有特定的目的的容器(Spring 中采用 ConcurrentHashMap 作为该容器)。
  2. 扩容:为达到松耦合,采用 AOP 实现某些代码的行为修改。(最终的系统,系统内的模块达到高内聚低耦合的状态,并且易扩展)
  3. Java代理:详情 p148

九、并发编程

  1. 并发是一种解耦策略。它帮助我们把做什么(目的)和 何时(时机)做分解开。
  2. 常见的迷思与误解
  3. 并发总能改进性能?
    并发有时候能改进性能,单只在多个线程或处理器之间能分享大量等待时间的时候管用。事情没那么简单。(编排考生时,又开了一个线程,编排所有考生)
  4. 编写并发程序无需修改设计
    事实上,并发算法的设计有可能与单线程系统的设计极不相同。目的与时间的解耦往往对系统结构产生巨大影响。
  5. 采用Web 或 EJB 容器的时候,理解并发问题并不重要(实际开发中,面向servlet开发。。。)
  6. 并发防御原则
  7. 单一权责原则
    建议将并发相关代码与其他代码进行分离
  8. 限制数据作用域
    产生并发问题的原因,其实就是共享变量,在 JMM 中,共享变量存在于主存中,多个线程从主存中拷贝共享变量到当前线程中,在线程内部进行对变量的操作。 CPU 给每个线程分配时间片,当线程 A 将共享变量刷回主存中前,线程 B 可能得到了 CPU 分配的时间片,由于 A 线程未及时刷新共享变量至主存,B 线程取得的是未经过 A 线程修改的值,会造成数据与理想情况不一致。最经典的多线程入门,进行自增操作时,如果开了多线程进行该操作,结果永远是小于等于 期望值。例如 `java

int num=0;

    for(int i=0;i<100;i++){
      num++;
  }
 }  
【云栖快讯】一站式开发者服务,海量学习资源免费学  详情请点击

网友评论