开发手册
本指南为作者这几年养成的一些开发习惯和遵循的一些规范,主要为了规范自己的代码和向大家分享一下自己的习惯。
这些规则的存在是为了使代码库易于管理,同时提高自己的能力。
文章目录
目标
- 整洁
- 统一
- 易读
- 模块化
- 心情愉悦
好的代码应该整洁并使读者心情愉悦
原则
- 短小精悍 最多50行,建议30行以下
- KISS “kiss Simple and Stupid” 的缩写,意思是“保持简单和愚蠢”
- 六大原则
- 单一职责原则(Single Responsibility Principle, SRP)
- 一个类只负责一个功能领域中的相应职责
- 开闭原则(Open-Closed Principle, OCP)
- 对扩展开放,对修改关闭,在不修改原有内部代码的情况支持扩展
- 里氏代换原则(Liskov Substitution Principle, LSP)
- 依赖倒转原则(Dependency Inversion Principle, DIP)
- 依赖抽象而不是实现
- 接口隔离原则(Interface Segregation Principle, ISP
- 迪米特法则(Law of Demeter, LoD)(最少知识法则)
- 单一职责原则(Single Responsibility Principle, SRP)
规范
- 返回值不要使用Map
- 尽量减少魔法值,多使用枚举或常量
- 命名
- 禁止使用Oracle、MySQL、JavaScript、Java、Python、Go 关键字命名
- 使用英文,不能中英文混用,金融专业名词问卓阳
- Java 代码使用驼峰英文,常量大写下划线
- 枚举类加 Enum 后缀
- 查询方法 get 开头,不再使用 find / select
- 只能使用专业约定的缩写,不要制造缩写,不要嫌变量名长
- 例如 channelRequestNo 和 channelRN
- 不要在不同的类、表、项目中使用近义的英文,应该使用同一个
- 例如 status、verify_status
- DTO 数据传输对象
- DO 数据库实体对象
- 风格
- 缩进使用2个空格
- 单行长度不建议超过 120, 为了语义通顺,可以减少没必要的换行
- 方法参数尽量少于10个
- 方法有效代码行数不建议超过 50 行
- 过长的方法难以维护和理解
- 例外:
- 某些对象初始化导致方法过长
- 方法处理严重依赖上下文结果,比如计算逻辑
- 方法复杂度建议不超过 10
- 不同逻辑、不同语义代码之间插入一个空行
- 控制语句必须加括号,单行也不例外
- 注释必须使用 javadoc 规范,注意不加冒号
- @author 作者
- @param 参数名 参数用途
- @since 版本号/时间
- @see 关联类
- @return 返回值描述
- OOP
- 重写 toString()
- 过时方法加 Deprecated 注解
- 调用 equals 时注意空指针
- 调用其他方法也注意空指针
- 注意访问级别
- 集合处理
- 优先使用 ecm-utils 判空,虽然mybaits的返回值空集合,但也不要直接调用 size 判空
- 如果能预知容量,初始化时规定容量,防止扩容
- 注释
- 被注释掉的代码前一定要有原因
- 复杂逻辑最好在方法上写出实现思路
- 方法参数如果是枚举值,尽量写一下
日志和异常
- catch 就是为了处理异常,不能什么都不做,至少需要打日志
- 不要使用 e.printStackException 打印日志
- 使用 warn 记录参数错误问题,不要使用error
- 对于可重试且不是系统配置问题导致的错误,打印warn
- 系统配置错误、重试不能解决,打印error
- 打印 log 是 exception 对象,不用出现在占位符中
- 日志描述内容使用英文下划线,尽量不要使用空格,kibana 搜索有问题
- 框架日志看情况调整级别
- 关键流程,如进件、审核、还款流程多打关键日志
- 关键流程分支有日志
- 日志必须有效,可用于排查问题
单元测试
- 提高单元测试覆盖率
- 原则
- 独立
- 可重复
- 自动化
SQL
- 注意 Null 值判断
安全
- 四要素脱敏
- 用户只能访问自己的数据
- 用户账单
- 机构查询自己的账单
- 不要依赖前端校验
- SQL 注入
建议
- 过于垃圾代码和配置(过时,无法访问)直接删除
- 多用组合,少用继承
- 参数最小化,避免大而空
- 多用工具类,少写重复代码
- 时期计算使用 java8 新语法,或者 Joda-Time 工具类
- 不要重复自己 DRY
介绍
样式 (style) 是支配我们代码的惯例。
- Effective Java
- 编写高质量代码:改善Java程序的151个建议
指导原则
零值 Mutex 是有效的
零值 sync.Mutex
和 sync.RWMutex
是有效的。所以指向 mutex 的指针基本是不必要的。
枚举从 1 开始
在 Go 中引入枚举的标准方法是声明一个自定义类型和一个使用了 iota 的 const 组。由于变量的默认值为 0,因此通常应以非零值开头枚举。
使用 time 处理时间
时间处理很复杂。关于时间的错误假设通常包括以下几点。
- 一天有 24 小时
- 一小时有 60 分钟
- 一周有七天
- 一年 365 天
例如,1 表示在一个时间点上加上 24 小时并不总是产生一个新的日历日。
因此,在处理时间时始终使用 "time"
包,因为它有助于以更安全、更准确的方式处理这些不正确的假设。
错误类型
Java 中有多种声明异常 (Exception) 的选项:
返回错误时,请考虑以下因素以确定最佳选择:
- 这是一个不需要额外信息的简单错误吗?如果是这样,[
errors.New
] 足够了。 - 客户需要检测并处理此错误吗?如果是这样,则应使用自定义类型并实现该
Error()
方法。 - 您是否正在传播下游函数返回的错误?如果是这样,请查看本文后面有关错误包装
避免可变全局变量
使用选择依赖注入方式避免改变全局变量。
既适用于函数指针又适用于其他值类型
避免使用内置名称
根据上下文的不同,将这些标识符作为名称重复使用,
将在当前作用域(或任何嵌套作用域)中隐藏原始标识符,或者混淆代码。
在最好的情况下,编译器会报错;在最坏的情况下,这样的代码可能会引入潜在的、难以恢复的错误。
性能
性能方面的特定准则只适用于高频场景。
指定容器容量
尽可能指定容器容量,以便为容器预先分配内存。这将在添加元素时最小化后续分配(通过复制和调整容器大小)。
指定Map容量提示
在尽可能的情况下,请在初始化时提供 map 容量大小。
指定集合容量
在尽可能的情况下,请在初始化时提供集合容量大小。
规范
一致性
本文中概述的一些标准都是客观性的评估,是根据场景、上下文、或者主观性的判断;
但是最重要的是,保持一致.
一致性的代码更容易维护、是更合理的、需要更少的学习成本、并且随着新的约定出现或者出现错误后更容易迁移、更新、修复 bug
相反,在一个代码库中包含多个完全不同或冲突的代码风格会导致维护成本开销、不确定性和认知偏差。所有这些都会直接导致速度降低、代码审查痛苦、而且增加 bug 数量。
将这些标准应用于代码库时,建议在 package(或更大)级别进行更改,子包级别的应用程序通过将多个样式引入到同一代码中,违反了上述关注点。
相似的声明放在一组
仅将相关的声明放在一组。不要将不相关的声明放在一组。
import 分组
导入应该分为两组:
- 标准库
- 其他库
包名
当命名包时,请按下面规则选择一个名称:
- 全部小写。没有大写或下划线。
- 大多数使用命名导入的情况下,不需要重命名。
- 简短而简洁。请记住,在每个使用的地方都完整标识了该名称。
- 不用复数。例如
net/url
,而不是net/urls
。 - 不要用“common”,“util”,“shared”或“lib”。这些是不好的,信息量不足的名称。
减少嵌套
代码应通过尽可能先处理错误情况/特殊情况并尽早返回或继续循环来减少嵌套。减少嵌套多个级别的代码的代码量。
不必要的 else
如果在 if 的两个分支中都设置了变量,则可以将其替换为单个 if。
Bad
var a int
if b {
a = 100
} else {
a = 10
}
Good
a := 10
if b {
a = 100
}
本地变量声明
如果将变量明确设置为某个值,则应使用短变量声明形式 (:=
)。
缩小变量作用域
如果有可能,尽量缩小变量作用范围。除非它与 减少嵌套的规则冲突。
如果需要在 if 之外使用函数调用的结果,则不应尝试缩小范围。
避免参数语义不明确(Avoid Naked Parameters)
函数调用中的意义不明确的参数
可能会损害可读性。当参数名称的含义不明显时,请为参数添加 注释 (/* ... */
)
使用原始字符串字面值,避免转义
Go 支持使用 原始字符串字面值,也就是 " ` " 来表示原生字符串,在需要转义的场景下,我们应该尽量使用这种方案来替换。
可以跨越多行并包含引号。使用这些字符串可以避免更难阅读的手工转义的字符串。
字符串 string format
如果你在函数外声明Printf
-style 函数的格式字符串,请将其设置为const
常量。
编程模式
功能选项
功能选项是一种模式,您可以在其中声明一个不透明 Option 类型,该类型在某些内部结构中记录信息。您接受这些选项的可变编号,并根据内部结构上的选项记录的全部信息采取行动。
将此模式用于您需要扩展的构造函数和其他公共 API 中的可选参数,尤其是在这些功能上已经具有三个或更多参数的情况下。
Linting
推荐使用 checkstyle 来对代码就行扫描,checkstyle 具备很大的灵活性,可以同时配置和使用许多规范自定义规则来满足我们的基本需求,同时其支持自定义规则来满足特殊检查项。
在网上也有 sun 和 google 的代码规范的 checkstyle.xml,建议取其一作为基本规范,同时根据我们的个人能力、团队情况以及代码库情况来添加或者减少一些检查项。