贡献者:星辰大海
有意义的命名
命名必须有意义
名称需要避免歧义
避免重复定义, 比如:product类与productinfo类并无区别
使用可拼写的单词,避免自定义缩写,如 timespan -> ts
使用方便搜索的名称
类名应当是名词或名词短语,如
方法名应该是动词或动词短语
使用约定俗成的命名,不要使用whack()替换kill(),尽管是同一个含义
尽量使用专业术语和领域与语言
函数
函数要简洁
函数单一职责,只做一件事
一个函数代表一个抽象层级
函数参数避免两个以上直接参数
分割指令与查询
使用异常代替错误码
尽量避免重复代码
不使用goto
先完成功能,再重构
注释
注释不能美化垃圾代码,尽量用代码名称介绍逻辑
注释用于警示
注释不要写与代码无关的事
注释需要精确
不是每个代码都需要注释
一个好名称胜过一段注释
格式
不同的公司有不同的编程风格,但不应该是的代码水平缩进和垂直缩进方差过大
对象和数据结构
面向过程和面向对象是对立统一的: 过程式代码方便添加函数而难以添加结构体而面向对象式代码方便添加结构体而难以添加函数
尽量避免四不像代码思想,如一半面向过程,一半面向对象。这种风格非常容易导致即不容易添加结构体又不容易拓展方法
错误处理
使用异常而不是返回错误码,如C语言中0是等价于false,所以可能在遇到出错误时return 0,而不是throw Exception,建议再使用统一异常处理返回异常返回处理后的异常信息给用户
可以将try-catch-finally语句视为一个事务
抛出异常需要具体,不应当以来语言本身的栈追踪
不返回null值,不传递null值
第三方代码
对于第三方代码可以对其功能进行业务封装,防止第三方库改动导致接口改动
单元测试
测试代码也是需要遵守严格的开发准则
测试分三步:构造-操作-检验
一个测试一个断言
一个测试一个概念
测试五特征:快速、独立、可重复、自足验证、及时
类
保证变量和工具函数的私有性---封装
努力保证单一职责
高内聚保证类的方法操作一个或多个成员
将大函数拆分成小函数是践行单一职责的好时机
践行面向对象23种设计模式,和其中6个原则
系统
将系统的构造与使用分开:将全部构造过程放置在main中,使用工厂方法构造对象,使用依赖注入和控制反转
使用面向切面编程,动态代理,使用AOP框架,AspectJ语言
使用测试驱动系统架构
不要先做大设计,要先有设计再实现
使用模块化管理和切面编程可以延迟决策的最后一刻,可以根据最新的信息优化业务逻辑
不要盲目使用新架构,使用已经验证过的可行架构
使用DDD编程思想将领域专家带入项目,使项目容易让人阅读
迭代进步
运行所有测试用例
不能重复
重构
表达程序员意图
尽量减少类和方法的数量
并发编程
并发编程的作用将目的和时机分离
会增加性能或代码复杂度
任何简单业务改为并发都是复杂的
并发编程的缺陷容易当作偶然事件而被忽略
并发防御编程:单一职责原则、限制数据作用域、避免共享数据、尽量让线程独立
了解执行模型:生产者-消费者模型、读者-作者模型、哲学家进餐模型
气味与启发
注释
不恰当的信息
废弃的注释
冗余的注释
糟糕的注释
注释掉的代码
环境
需要多个步骤才能实现构建
需要多步骤才能做到的测试
函数
过多的参数
输出参数
标识参数
无法到达的函数
一般性问题
一个源文件出现多种语言
明显行为未被发现,如Day day = DayDate.StringToDate(String dayName) 应该明白输入可能是Monday, MONDAY, monday等等参数
不正确的边界行为
忽略安全
重复
在错误的抽象层级的代码
基类依赖于派生类
信息过多
死代码
垂直分割
前后不一致
混淆视听
人为耦合
特性依赖
选择算子函数(使用多个函数,优于向单个函数传递代码来选择函数行为)
晦涩的意图
位置错误的权责
不恰当的静态方法
不使用解释性变量
函数名称应当要表达其行为
了解代码工作结果
把逻辑依赖改为物理依赖
使用多态代替if/else或switch/case
遵守标准约定
不需要将全部命名常量代替魔法值(部分魔法值具有自解释性)
不封装条件
避免否定条件
单一职责原则
掩蔽时序耦合
封装边界条件
函数应该只在一个抽象层级上
在较高层级放置可配置数据
避免传递浏览