代码整洁之道——读书小结

代码整洁之道第——命名

第二章:命名

  1. 名副其实:通过名字可以读出变量的含义,如int daysSinceCreation
  2. 避免误导:特殊意义的词不能用,accountList也不要用(误导其是一个List,如果真的是一个List也无需这样,java是强对象的,所以不需要类型编码),不如accounts
  3. 有意义的区分:a1和a2就是无意义的区分,destination和source就是有意义的区分。
  4. 可读性好:不要使用自造词,如genymdhms、modificationTimestamp就是属于自造词。
  5. 使用可搜索的名称:单词字符名称如(a、e、i)仅用于短方法中的本地变量;其他变量、常量的命名长名称好于短名称,便于搜索。
  6. 避免使用编码:①不需要类型编码,错误示范:PhoneNumber phoneString,不如PhoneNumber string;②前缀无意义,成员变量_name或m_name不如直接用name;③接口实现,正确示范:UserService接口的实现UseServiceImp
  7. 避免思维映射:不应让变量名映射成读者脑中其他的含义
  8. 类名:类名和对象名应该是名字或名字短语,不能是动词,如Customer、AddressParser等,指代具体的事物,避免使用Data、Processor等。
  9. 方法名:动词或动词短语。如deletePage、save。
  10. 不要用俚语俗语,要言到意到。
  11. 每个概念对应一个词:如get和retrieve、controller和manager不要一起用(一个概念对应两个词了)
  12. 别用双关语:如insert比add更精确。
  13. 尽管用CS专业领域词汇,如thread processor
  14. 无法使用CS专业领域词汇,可以使用所涉及领域词汇(比如电商领域)。
    1. 添加有意义的语句 VS 不要添加没用的语境:一个类的几个成员变量,共同出现在了一个方法中,此时局部变量的命名可以加上类名前缀;但是在一个类中,成员变量的命名,没有必要加上类名前缀。

第三章:函数

  1. 短小:首要原则是短小,20行封顶最佳,函数的缩进层级(if while)不应该多余一层或两层。
  2. 只做一件事,做不到时,拆分新函数。
  3. 每个函数在一个抽象层级,比如Controller Service Dao就属于不同的层级,各层级的函数应该负责本层的业务,不能跨多级。
  4. switch语句:如果出现一次还能忍受,否则就用多态。
  5. 使用描述性函数名:长而具有描述性的名称,比短而费解的名称好,比注释好
  6. 函数参数:最理想的参数数量为0,其次是1,再次是2,尽量避免三个及以上参数;多参数导致测试组合几何倍增多。
    ①一元函数:参数有两个作用: 操作该参数(如 add(object)) 和 将参数转化为什么东西再输出(如 append(string))。
    ②标识参数:即向函数传入boolean值参数,极其不可取!可以将原函数一分为二。
    ③二元函数:尽量用一些机制将其转化为一元函数
    ④三元参数:尽量不写三元函数
    ⑤参数对象:参数有两个、三个或以上,说明应该考虑封装为类了。
    ⑥可变参数函数:可变参数函数有可能相当于一元函数、二元函数、三元函数。
    ⑦动词与名词:正确范例:assertExpectedEqualsActual(expected, actual)。函数名是动词,可以跟上名词对象,参数是名词。
  7. 无副作用:只做一下事,就是函数名字对应的事,如果不对应就可能会带来副作用; 避免把输入参数对象作为函数返回值,这样可以改造成void的无参函数。
  8. 分隔指令与询问:函数要么做什么事情,要么回答(查询、得到)什么事,二者不可得兼,如果都干,则将其拆分为两个函数。但是对于某些数据库的操作函数,就是二者都干的,比如insert,插入成功返回true,插入失败返回false。
  9. 使用异常代替返回错误码:将try代码块 catch代码块抽取成方法;错误处理的函数只做一件事,即try是函数的第一个词,catch finally后面不应再有内容;错误代码类是依赖磁铁,造成很其他类都要引入和使用,耦合严重,错误码修改使用它的地方都要重新修改编译,推荐使用异常代替错误码,新的异常可以从异常类派生出来。
  10. 重复代码时万恶之源
  11. 一个函数只有一个入口,但是可以有多个出口。

第四章:注解

  1. 注解不能美化代码,用代码函数命名阐明意图
  2. 好注释 VS 坏注释:
    ①没有规范每个函数都要有javadoc 和每个变量都要有注释
    ②注释掉的代码删掉即可。
    ③不要在代码中注释关于本地的信息,因为代码会部署到服务器

第五章:格式

  1. 格式的目的在于沟通,和修改维护的可读性
  2. 垂直距离:①研究了一些开源类库源码,表明类文件的长度大多数小于200,短文件比长文件更易于理解 ②不要把关系密切的概念放到不同的文件中,这也是避免使用protected变量的理由之一,③关联越密切,应该靠的越近,④调用者函数放在被调用者的上面。
  3. 风格要统一,保持团队规定风格。

第六章:对象和数据结构

  1. 数据抽象:私有成员;对外暴露越少越好
  2. 数据结构和对象:对象隐藏数据,暴露操作数据的函数;(面向过程代码)数据结构暴露数据,不提供函数
  3. The Law of Demeter:类C的方法f只应该调用一下对象的方法①C,类内的方法,②f创建的对象(局部对象)的方法,③作为参数传给f的对象,④C的实体变量持有的对象(类成员变量)
    火车失事代码(如下),应拆分。

第七章:错误处理

  1. 使用异常而不是返回码,好处如下:
    ①上次直接catch异常即可,不必知道下层返回的结果。
    ②通过对错误处理方法的包装抽取,实现错误处理与业务算法隔离
  2. try-catch-finally
  3. 使用不可控异常:checked exception的依赖链成本很高。
  4. 给出异常发生的环境申明:在异常中一并记录失败的操作、失败的类型、失败操作初衷
  5. 定义异常类:很多catch1 catch2…等,如果实现了定义之后,多态来抽象,就可以变成只有一个catch
  6. 定义常规流程:不要用catch异常来处理业务逻辑,可以使用特例模式,创建一个类用来处理特例,也是多态的一种用法,就不用判断异常了,比如NullObject。
  7. 别返回null:返回null值必然带来的工作是检查null增加工作量,如果返回null,不如抛出异常,或者返回特例对象(如Collections.emptyList)。
  8. 别传递null:除非API要求,否则禁止传null。

第八章:边界

  1. 使用第三方代码、学习测试第三方代码、使用尚不存在的代码(分离)

第九章:单元测试

  1. TDD:测试先行,在编写生产代码前,先编写测试单元。
  2. 保持测试整洁:测试代码和生产代码一样重要,同样要保持整洁
  3. 测试代码最重要的是可读性,测试代码和生产代码的标准不同,测试代码不必关心性能优化。
  4. 每个测试一个断言:单个测试断言数量最小化;每个测试只测一件事
  5. 快速、独立、可重复、自验证、及时五大原则:快速要求不能运行缓慢;独立要求每个测试不依赖;可重复要求测试应该在任何环境下重复通过;自验证要求测试自己告诉成功或失败;及时要求测试先行,如果在生产代码之后编写测试的话,会难以测试。

第十章:类

  1. 类约定:JAVA约定类先从变量列表开始,先出现公共静态常量,然后出现私有静态变量,然后是私有实体变量,非常少有公共变量。工具函数在其调用者后面。
  2. 类短小的原则:
    ①单一权责(SRP):有且只有一条修改类的理由,多个短小的类而不是少个巨大的类
    ②高内聚:最大的内聚指:每个变量都被每个函数操作;保持内聚性的结果通常会得到很多短小的类。
  3. 为了修改而隔离:通过继承体系,实现对扩展开放,对修改关闭,依赖抽象而不依赖细节。

第十一章:系统

  1. 系统的创建和使用分开,也是单一职责的思想
  2. AOP三种:springAOP JBossAOP AspectJ

第十二章:迭进

  1. 共性抽取,消除重复的进一步做法。如发现违反了SRP原则,则应该把抽取的方法移到其他类中。
  2. 函数和类的数量要少,一些教条主义:为每个类创建接口、字段和行为一定要切分到字段类和行为类中,抵制这些教条。
  3. 整洁之道按照重要性排序(降序):测试、消除重复、表达力、类和函数少。

第十三章:并发编程

  1. 分离并发相关的代码和其他代码
  2. 严格显示对共享数据的访问
  3. 使用数据副本,避免共享数据。使用对象副本应该考虑的是:对象创建成本以及垃圾回收开销
  4. 并发问题的三种模型:生产者消费者模型、读者作者模型(读者读共享资源,作者偶尔更新共享资源)、哲学家进餐模型(共享资源数少于占用资源的人数)
  5. 装置代码,Object.wait() Object.sleep() Object.yeild() Object.priority() 改变代码执行顺序,以测试多线程可能出的问题

第十四章:逐步改进

第十五章:JUnit内幕

第十六章:重构

先运行,在优化。

第十七章:味道与启发

1、通常基类对派生类应该一无所知,例外情况是:派生类数量严格固定时(有限状态机),可以在基类中最派生类进行switch。
2、变量和函数应该在靠近被使用的地方定义,距离越短越好。
3、特性依恋:类的方法只应该对当前所属类的变量和函数感兴趣,不应该垂青其他类中的变量和函数。有时特性依恋是必要的。
示例:calculateWeeklyPay方法依赖了HourlyEmployee对象的特性。

4、不要在函数参数中带 boolean参数、枚举类型、整数或其他用于选择分类的参数,如果需要这样的情形,说明可以将大函数拆分为小函数。
5、把逻辑依赖改为物流依赖
一个模块依赖于另一个模块,不需要对被依赖模块进行假定,则是物流依赖。否则对依赖模块进行假定,则是逻辑依赖。
逻辑依赖,不利于程序变成和向下扩展。
6、switch语句:对于给定的选择类型,不应有多于一个switch语句,必须创建多态对象,消除其多个case。
7、用命名常量代替魔数,某些常量具有自解释能力,因此不必用命名常量去隐藏。
8、结构优于约定:继承是结构、代码常量命名是约定
9、避免使用否定性条件
10、显示表现出时序耦合,必要的时序不应该被隐蔽。可以通过上一个函数的返回结果,给下一个函数调用,以此实现前后调用的时序关系。
11、封装边界条件,用一个变量表示边界,变量的名显示边界的意义。
12、函数应该只在一个抽象层级上。比如一个函数通过一个对象A构建一个String,就只需要构建A,然后调A的toString类似方法即可,而不需要知道A的toString的细节。
13、避免传递浏览,即不要写a.getB().getC().doSomething()的代码,导致A与B耦合,且A与C耦合。正确的做法:b = a.getB(),b.doSomething(),这样A只需要了解B即可,b.doSomething()可以调用b.getC c.doSomething()
14、如果使用了一个包里的两个或多个类,可以使用import package.*通配符,避免导入语句过长
15、不要继承常量

完结。

你可能感兴趣的:(编程,规范)