俗话说世界之大什么人都有,对于程序员也是一样,如果没有一个规范来制约,那么项目可能就会出现很多风格。
项目分层
应用一般包括以下几个逻辑层(xxx为应用名):
- xxx-portal:请求处理层,负责对外提供 http 和 rpc 接口,也可以把RPC单独抽出来作为一层。
- xxx-business:业务逻辑层,在这一层做的事情除了组装原子服务层的接口以外,还可以调用外部依赖的 rpc 服务,或者消费 MQ 消息。
- xxx-service:原子服务层,对dao层的方法进行组装。
- xxx-dao:数据访问层,提供增删改查在内的原子服务。
- xxx-sdk(可选):RPC 接口对外提供的 API 包。
项目之前的依赖约定:
- portal-sdk 对内只会被对应的 portal 层依赖
- business 只会被对应的 portal 层依赖
- service 可以被对应的 business 层依赖,也可以被对应的 portal/rpc 层依赖
- dao 只会被对应的 service 层依赖
以上涉及的依赖访问全部是基于接口依赖
命名规范
域名反过来.业务线.子业务线.产品名.逻辑层名
com.chaiguanxin.baseservice.uc.auth.business
POJO约定
- portal 传入对象统一以DTO结尾,传出对象统一以VO 结尾。
- rpc 传入或者传出的对象除了简单对象以外,统一定义为 DTO 对象,命名统一以 RequestDTO 或 ResponseDTO 结尾。
命名约定
- Service/DAO 层方法命名规范:
- 获取单个对象的方法用 get 作为前缀
- 获取多个对象的方法使用 list 作为前缀
- 获取统计值的方法使用 count 作为前缀
- 插入的方法用 save 作为前缀
- 删除的方法用 remove 作为前缀
- 修改的方法用 update 作为前缀
- 领域模型命名规范:
- 数据对象:xxxEntity,xxx为数据表名
- 数据传输对象:xxxDTO,xxx 为业务领域相关的名称
- 展示对象:xxxVO,xxx一般为网页名称
命名风格
- 命名不能使用下划线或者美元符号开头或者结尾
- 代码中的命名严禁使用拼音与英文混合的方式
- 类名使用 UpperCamelCase 风格,但 DO、BO、DTO、VO 等情形除外
- 方法名、参数名、成员变量、局部变量都统一使用 lowCamelCase 风格
- 常量命名全部大写,单词间用下划线隔开,力求语意表达完整清楚,不要嫌名字长
- 抽象类命名使用 Abstract 或 Base 开头,异常类命名使用 Exception 结尾,测试类命名以它要测试的类名开始,以 Test 结尾
- 包名统一使用小写,点分隔符之间有且只有一个自然语意的英语单词。包名统一使用单数形式,类名允许使用复数形式
- 尽量避免会引起歧义的缩写
- 如果模块、接口、类等使用了设计模式,应在命名时体现出具体模式
public class ConsumerFacadeFactory public class AccountFacadeProxy
- 对于 Service 和 DAO 类,基于 SOA 的理念,暴露出来的服务一定是接口,内部的实现类用 Impl 后缀与接口区别
CacheServiceImpl 实现 CacheService 接口
常量定义
- long 或者 Long 初始赋值时,使用大写的 L,不能用小写的 l,避免误读
- 如果变量值仅在一个范围内变化,则用 enum 类型来定义
代码风格
- 注释的双斜线与注释内容之间有且只有一个空格
- 关于换行
- 方法调用的点符号与下文一起换行
@Override public boolean xxx(String zz) { return xx.create(zzz, aaa) .aaa(aaa) .build() .aaa(token) .bbb() .ccc(); }
- 方法调用中的多个参数需要换行时,在逗号后进行
String.format("%s?aaa=%s&bbb=%s&ccc=%s", zzzz, aaa, bbb, ccc);
OOP约定
- 所有的覆写方法,必须加 @Override 注解
- Object 的 equals 方法容易抛出空指针异常,应使用常量或确定有值的对象来调用 equals
- 当序列化类新增属性时,不要修改 serialVersionUID 字段,避免反序列化失败
- 构造方法里面禁止加入任何业务逻辑,如果有初始化逻辑,请放入 init 方法中
集合约定
PECS原则:频繁往外读取内容的,适用 <? extends T>;频繁往里插入的,适用 <? supper T>
- 不要在 foreach 循环里进行元素的 remove/add 操作。remove 元素需使用 Iterator 方式。
并发约定
- 在并发修改同一记录时,为避免更新丢失,需要加锁。要么在应用层加锁,要么在缓存层加锁,要么在数据库使用乐观锁,使用 version 作为更新依据。如果每次访问冲突概率小于20%,推荐使用乐观锁,否则使用悲观锁。乐观锁的重试次数不得小于3次。
- 超过 3 层的 if-else 逻辑判断代码可以使用卫语句(短路的写法)、策略模式、状态模式等来实现。
注释规范
- 类、类属性、类方法的注释必须使用 Javadoc 规范,使用 /** 内容 */ 的格式,不得使用 // 方式
- 所有类的注释中都必须添加创建者和创建日期
- 方法内部的单行注释,在被注释的语句上方另起一行,使用 // 注释
- 在修改代码的同时,要对注释进行相应的修改
日志规范
- 日志输出语句中尽量使用占位符的形式,避免使用字符串拼接的形式
- 日志打印统一使用 @Slf4j 注解
安全规范
- 为了防止 SQL 注入,禁止字符串拼接 SQL 访问数据库
ORM映射
- 在表查询中,禁止使用 * 作为查询的字段列表,需要哪些字段必须明确写明
- mybatis 中的 xml 文件中参数使用 #{} 的写法,尽量避免使用 ${} 的写法
- 更新记录时,必须同时更新记录的最后修改时间字段
- mybatis 中的 xml 文件中的 SQL 语句关键字大写,其他都小写
数据库规范
- 表名、字段名必须使用小写字母,禁止出现数字开头,禁止两个下划线中间出现数字。
- 表名不使用复数名词
- 主键索引名为 pk_字段名,唯一索引名为 uk_字段名,普通索引名为 idx_字段名
- 每个表必备的三个字段:id、create_time、update_time
- 表名推荐使用以下规则 "所属系统名_业务名_表的作用"
- sql 语句中禁止使用左模糊或者全模糊查询
- 建组合索引的时候区分度最高的放在最左边
- 不得使用外键与级联,一切外键概念必须在应用层解决
- in 操作要控制在 1000 个以内
代码仓库规范
- 私服仓库中的jar包的三围定义规则
- groupId 格式: com.chaiguanxin.业务线.子业务线
- artifactId 格式:产品线名-模块名
- version 格式,起始版本号必须是 1.0.0 ,正式版本号不允许覆盖升级:
- 主版本号:产品方向改变,或者大规模 API 不兼容,或者架构不兼容升级
- 次版本号:每月迭代自增加一
- 修订号:如果月迭代发现线上 bug,修复上线的版本修订号自增加一
- 所有 pom 文件中的依赖声明放在
语句块中,所有版本放在 语句块中 - 仓库中 jar 包的提供者应该遵循精简可控原则,如果所提供的 jar 包依赖其它 jar 包,尽量是 provided 引入,让 jar 包的使用者依赖具体的版本号
单元测试规范
以下几个关键环节必须被单元测试覆盖:
- dao 层暴露给 service 层的每个方法
- service 层暴露给 business 或 portal 层的每个方法
- business 层暴露给 portal 层的每个方法
- portal 层暴露给外部调用的每个接口 ( 包括 HTTP 和 Dubbo 接口 )
各层单元测试的编写规范
- dao 层单元测试类需要继承 BaseDaoTest 类,测试类以被测试的类名开头、以 Test 结尾
- service、business 层单元测试类需要继承 BaseServiceTest 类,测试类以 ServiceTest、BusinessTest 结尾
- portal 层 HTTP 服务的单元测试类需要继承 BaseHttpTest 类,测试类以 ControllerTest 结尾
- portal 层 Dubbo 服务的单元测试类以 FacadeTest 结尾
- 单元测试中使用的断言统一使用 org.junit.Assert 类下面的静态方法
- 单元测试的结果必须用 assert 进行断言判断,禁止使用控制台输出的方式通过肉眼识别测试结果
本文为博主原创文章,未经博主允许不得转载。
更多内容请访问:IT源点
注意:本文归作者所有,未经作者允许,不得转载