clean code
代码整洁之道
clean code:
能够实现功能,重复代码少,抽象合理有层次,代码表达力高,易于维护/修改/扩展
chapter 2 命名
统一的命名规范
清晰、有意义的名字
chapter 3 函数
短小,只做一件事
每个函数一个抽象层级
使用描述性的名称
函数参数数量尽可能的少
无副作用
使用异常替代返回错误码
别重复自己
chapter 4 注释
尽量用代码来阐述
好的注释:提供有效的信息 比如法律信息,意图的说明,警示/强调,todo
chapter 5 格式
团队统一的格式
变量声明尽量靠近其使用位置
相关函数互相靠近
chapter 6 对象和数据结构
对象把数据结构隐藏在抽象之后,暴露操作数据的函数
数据结构暴露数据,不提供有意义的函数
面向过程式代码便于在不改动数据结构的前提下添加新函数,面向对象的代码便于在不改动既有函数的前提下添加新类。
添加新的数据类型,使用面向对象的方式更方便,不影响其他的对象。
添加新的行为,使用面向过程的方式更方便,不印象其他的行为。
chapter 7 错误处理
使用异常而非返回错误码
使用unchecked error
给出详细的error message
依据调用者的需要定义异常类,打包/封装第三方异常信息抛出自己的异常
不要返回/传递null值
checked error
unchecked error
Exception分为一般的Exception和RuntimeException两类。
RuntimeException(Unchecked)继承Exception(Checked)接口。
继承RuntimeException的异常为unchecked exception。不需要声明抛出异常。
RuntimeException及其子类,如:OutOfMemoryError, UndeclaredThrowableException, IllegalArgumentException, IllegalMonitorStateException, NullPointerException, IllegalStateException, IndexOutOfBoundsException等。
继承Exception的异常为checked exception。必须显式声明抛出异常。
chapter 8 边界
使用第三方代码,可以将其打包/封装
给第三方代码写测试,确保其行为不会随版本更新而改变
使用不存在的代码。控制反转(DI),实现接口,解耦系统。
chapter 9 单元测试
TDD
保持测试的整洁性/可读性
面向特定领域的测试语言
每个测试一个断言
F.I.R.S.T 快速(fast) 独立(independent),可重复(repeatable),自足验证(self-validating),及时(timely)
chapter 10 类
短小 单一权责原则(SRP, Single Responsibility Principle),即类或模块应有且只有一条加以修改的理由。
内聚 类应该只有少量实体变量,类中的每个方法都应该操作该类的一个或多个变量
适当抽象,隔离修改,为后续修改留出空间
工厂模式(Factory Pattern), 在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
屏蔽实现,易于扩展。
chapter 11 系统
分解main
将系统的构造和使用分开 将构造过程搬迁至main模块中,系统的其他部分,假设所有对象都已正确构造和设置。
工厂
使用抽象工厂模式让应用自行控制何时创建对象,但实现构造的细节应该隔离在domain(领域设计)之外
依赖注入(DI,Dependency Injection)和控制反转(IoC, Iversion of Control)
对象不负责依赖的实例化,将`构造`权责从对象中拿出来,转移到另一个专注于此的对象。(比如spring)
AOP
切面编程,将横跨多个模块的功能/模块进行提取封装。
Java代理(基于接口,动态代理),CGLIB(基于类继承,动态代理),AspectJ(字节码,编译时)
大概可工作的最简单方案
chapter 12 迭进
能通过所有测试
没有重复代码
体现全部设计意图
包括尽量少的实体和方法
chapter 13 并发编程
单一职权
限制数据作用域
避免共享数据
线程尽可能独立
保持同步区域微小
测试线程代码
CAS (Compare and Swap)
死锁,线程互相等待其他线程持有的资源,导致程序不能正常运行。
死锁的4个条件:
互斥
上锁及等待
循环等待
无抢先机制
解决死锁:
不互斥
不上锁及等待(问题:线程饥饿,活锁等)
不循环等待
满足抢先机制
附:
多数JVM中解释器(Interpreter)和编译器(Compiler)并存
Java程序最初是通过解释器(Interpreter)进行解释执行的,当虚拟机发现某个方法或代码块的运行特别频繁时,就会把这些代码认定为“热点代码”。为了提高热点代码的执行效率,在运行时,虚拟机将会把这些代码编译成与本地平台相关的机器码,并进行各种层次的优化,完成这个任务的编译器称为即时编译器(Just In Time Compiler,下文统称JIT编译器)
当程序需要迅速启动和执行的时候,解释器可以首先发挥作用,省去编译的时间,立即执行。在程序运行后,随着时间的推移,编译器逐渐发挥作用,把越来越多的代码编译成本地代码之后,可以获取更高的执行效率。当程序运行环境中内存资源限制较大(如部分嵌入式系统中),可以使用解释器执行节约内存,反之可以使用编译执行来提升效率。此外,如果编译后出现“罕见陷阱”,可以通过逆优化退回到解释执行。