1. 以下全部条款源于·<Clean Code Robert.C.Martin>Chapter 17,这里对其进行文字层面的加工,简化,便于以后能短时浏览
2. 出于1.的原因,部分条款不解释为什么,就这么做
3. 少数和我的编程哲学或者代码美学有悖的条款没有保留
4. 事无绝对,编程不需要权威,如果有一个令人令己信服的理由去违反条款请放手去做
5. 向前辈致敬
注释
C1:不恰当的信息
注释只应该描述和代码有关的技术性信息,作者、修改记录、修改时间等信息应该保存在源码控制系统。
C2:废弃的注释
过时、无关、不正确的注释就是废弃的注释,最好尽快更新或者删除。废弃的注释会远离它们曾经描述的代码。
C3:冗余注释
代码能充分self-explaining,那么注释就是多余的,例如:i++; //increment i
C4:糟糕的注释
如果要写注释就要确保字斟句酌写出最好的注释,别瞎扯别画蛇添足,保持简洁。
C5:注释掉的代码
删除它。
环境
E1:需要多步才能实现构建
构建系统应该是单步的小操作,不应该一点一点从源码控制系统签出。
E2:需要多步才能做到的测试
使用单个指令就应该能运行全部单元测试。
函数
F1:过多参数
函数参数尽量<=3。
F2:输出参数
别这么做,考虑修改他所在对象的状态(输出参数指传入参数,函数对它进行操作,然后后续操作使用这个参数)
F4:死函数
永不被调用的函数应该删除
一般性问题
G1:一个源文件存在多种语言
尽量减少源文件中其他编程语言的数量和范围
G2:明显的行为违背实现
函数或类应该实现其它程序员有理由期待的行为。(即[The principle of leastastonishment]( https://en.wikipedia.org/wiki/Principle_of_least_astonishment))。
G3:不正确的边界行为
多考虑边界条件,编写相关测试。
G4:忽略安全
切勿关闭失败测试欺骗自己稍后处理。关注warnings。
G5: 重复
最重要的条款之一。尽量消灭重复代码就是要做的一切。
G6:在错误的抽象层次上的代码
所有低层次抽象概念放在派生类,所有较高层次抽象概念放在基类。例如
interface Stack{
publicvoid push(Object object);
publicObject pop();
publicdouble percentFull();
}
其中percentFull()表示低层次的、具体的抽象概念应该放到子类。
G7:基类依赖于派生类
基类应该对派生类一无所知。
G8:模块信息过多
设计低劣的模块包含广泛,冗杂的接口。
G9:删除不执行的代码
G10:垂直分隔
变量和函数应该在靠近使用的地方定义,定义和使用的垂直分隔不应该过长。
G11:前后不一致
选择一个编程约定就一直遵守它。
G13:人为耦合
不互相依赖的东西不该耦合,本质上说的就是把代码放到正确的位置。
G16:晦涩的意图
不要使用匈牙利标记法和魔术数遮蔽作者意图。代码要尽可能具有表达力。
G19:使用解释性变量
让程序过程清晰最有力的方法之一就是将计算过程打散成有意义的单词命名的变量放置中间值
G20:函数名应该表达其行为
G21:理解算法
在完成某个函数前确认自己理解了它的工作原理。同时还需要确认当前解决方案是正确的。
G22:将逻辑依赖改为物理依赖
依赖者模块不应对被依赖者模块有假定。
G23:用多态替代IF/ELSE或SWITCH/CASE
G24:遵循标准约定
每个团队都应该遵循基于通用行业规范的一套编码标准。
G25:用命名常量代替魔术数
G26:准确
期望某个查询第一次匹配就是唯一匹配可能过于天真。
用浮点数表示货币近乎犯罪。
因为不想并发更新就避免使用Lock/Transaction是明显的偷懒行为。
代码中的含糊和不准确要么是意见不同的结果,要么是源于懒惰。
G27:结构甚于约定
G28:封装条件
if(shouldBeDeleted(timer))优于if((timer.hasExpired()) && !(timer.isRecurrent()))
G29:避免否定性条件
if(shouldCompact())优于if(!shouldNotCompact())
G30:函数只应该做一件事情
G31:掩蔽时序性耦合
public class MoogDriver{
public void dive(){
saturateGradient();
reticulateSplines();
diveForMoog();
}
}
三个函数次序很重要,但是代码没有强制这种次序,更好的方法是
public class MoogDriver{
publicvoid dive(){
Gradient gradient = saturateGradient();
List<Splines>splines = reticulateSplines(gradient);
diveForMoog(splines,MoogDrive.EXPAND);
}
}
G33:封装边界条件
把处理边界条件的代码集中到一处。
G35:在较高层次的函数防止可配置数据
这里的高层次有别于抽象上的高层次(抽象的高层次是不具体、广泛的概念如Animal,而Kangaroo则是具体、明确的低层次)。这里指的是在函数调用链的上游放置可配置数据。如在main函数中解析args。
G36:避免传递性浏览
让直接协作者提供全部功能,而不是m.getB().getC().doSomething();让协作者的协作者提供
Java
J1:通过使用通配符避免过长的导入清单
J2:不要继承常量
不要把常量藏在基层链的顶端然后一步步继承来获取它,直接使用static import
J3:用enum代替public static final int
名称
N1:采用描述性名称
N2:名称应该与抽象层次相符
不要取沟通实现的名称,取名的时候应该假设不存在具体的子类实现。
N3:尽可能使用标准命名法
如果用工厂模式就加Factory,装饰模式加Decorator,都是干这行的都懂。
N4:无歧义的名称
N5:为较大作用范围选用较长名称
N6:避免编码
不要使用匈牙利命名法那些前缀为名称编码。
N7:名称应该说明副作用
测试
T1:测试不足
让测试覆盖太阳下的每个角落
T2:使用覆盖率工具
T3:别略过小测试
T4:被忽略的测试就是对不确定事物的疑问
如果因为需求不明而不能确定某个行为细节,可以用注释掉的测试或者@Ignore标记的测试表达对于需求的疑问。
T5:测试边界条件
T6:全面测试相近的缺陷
如果在一个函数发现一个缺陷,最好全面测试那个函数
T8:测试应该快速