编程规范

Java后端开发规范

Git分支管理规范

1. 分支说明及操作

  • master 分支

    • 主分支,永远处于稳定状态,对应当前线上版本
    • 以 tag 标记一个版本,因此在 master 分支上看到的每一个 tag 都应该对应一个线上版本
    • 不允许在该分支直接提交代码
  • develop 分支

    • 开发分支,包含了项目最新的功能和代码,所有开发都依赖 develop 分支进行
    • 小的改动可以直接在 develop 分支进行,改动较多时切出新的 feature 分支进行

    注: 更好的做法是 develop 分支作为开发的主分支,也不允许直接提交代码。小改动也应该以 feature 分支提 merge request 合并,目的是保证每个改动都经过了强制代码 review,降低代码风险。

  • feature 分支

    • 功能分支,开发新功能的分支
    • 开发新的功能或者改动较大的调整,从 develop 分支切换出 feature 分支,分支名称为 feature/xxx
    • 开发完成后合并回 develop 分支并且删除该 feature/xxx 分支
  • release 分支

    • 发布分支,新功能合并到 develop 分支,准备发布新版本时使用的分支
    • 当 develop 分支完成功能合并和部分 bug fix,准备发布新版本时,切出一个 release 分支,来做发布前的准备,分支名约定为release/xxx
    • 发布之前发现的 bug 就直接在这个分支上修复,确定准备发版本就合并到 master 分支,完成发布,同时合并到 develop 分支
  • hotfix 分支

    • 紧急修复线上 bug 分支
    • 当线上版本出现 bug 时,从 master 分支切出一个 hotfix/xxx 分支,完成 bug 修复,然后将 hotfix/xxx 合并到 master 和 develop 分支(如果此时存在 release 分支,则应该合并到 release 分支),合并完成后删除该 hotfix/xxx 分支

以上就是在项目中应该出现的分支以及每个分支功能的说明。
其中稳定长期存在的分支只有 master 和 develop 分支,别的分支在完成对应的使命之后都会合并到这两个分支然后被删除。简单总结如下:

  • master 分支: 线上稳定版本分支, 该分支代码与线上代码是完全一致的。
  • develop 分支: 开发分支,衍生出 feature 分支和 release 分支
  • release 分支: 发布分支,准备待发布版本的分支,存在多个,版本发布之后删除。该分支从 develop 分支创建,创建之后由测试人员发布到测试环境进行测试。
  • feature 分支: 功能分支,完成特定功能开发的分支,存在多个,功能合并之后删除
  • hotfix 分支: 紧急热修复分支,存在多个,紧急版本发布之后删除

2. 提交信息规范

提交信息规范部分参考 Angular.js commit messgae

git commit 格式 如下:

1
2
3
4
5
<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>

各个部分的说明如下:

  • type 类型,提交的类别

    • feat: 新功能
    • fix: 修复 bug
    • docs: 文档变动
    • style: 格式调整,对代码实际运行没有改动,例如添加空行、格式化等
    • refactor: bug 修复和添加新功能之外的代码改动
    • perf: 提升性能的改动
    • test: 添加或修正测试代码
    • chore: 构建过程或辅助工具和库(如文档生成)的更改
  • scope 修改范围

    主要是这次修改涉及到的部分,简单概括,例如 login、train-order

  • subject 修改的描述

    具体的修改描述信息

  • 范例

    1
    2
    3
    feat(detail): 详情页修改样式
    fix(login): 登录页面错误处理
    test(list): 列表页添加测试代码

补充规范

服务命名规范

采用英文小写方式

命名结构: 项目名-微服务名-服务类型(如pay-bill-web)

  1. 项目名: 立项的项目, 如crm、call等
  2. 微服务名: 表示微服务的核心业务或功能
  3. 服务类型说明:
  • Dubbo: service
  • SpringBoot: web

包名命名规范

命名 备注
cn.idea360 总体要求
cn.idea360.xxx.controller controller的package
cn.idea360.xxx.service service的package
cn.idea360.xxx.service.impl service接口实现的package
cn.idea360.xxx.dao dao的package
cn.idea360.xxx.dao.impl dao接口实现类的package
cn.idea360.xxx.entity 表实体的package
cn.idea360.xxx.vo api层实体的package
cn.idea360.xxx.dto 数据交换的package
cn.idea360.xxx.common utils、config等package
cn.idea360.xxx.api dubbo接口定义package
cn.idea360.xxx.provider dubbo服务提供package

方法名、参数名、成员变量、局部变量都统一使用lowerCamelCase风格, 必须遵从驼峰形式

Redis Key名设计规范

redis-key基于以下几个角度进行设计

  1. 可读性和可管理性(以业务名为前缀(防止key冲突),用冒号分隔,比如业务名:表名:id)
  2. 简洁性(保证语义的前提下,控制key的长度, 如cid用c, uid用u代替)
  3. 现在公司是saas业务, 和用户相关的数据最好包含cid和uid, 如不相关可不写
  4. 需要对key设置合理过期时间
  5. 命名必须全部小写字母、数字、英文点号(.)和英文半角冒号(:)组成,必须以英文字母开头

key完整示例:

应用名.服务名:c:{cid}:u:{uid}:{xxx}

应用名和服务名需要统一约定字母缩写

1
2
3
4
5
6
# 说明:
# crm.pay crm业务线支付服务(同一业务逻辑含义段的单词之间使用英文半角点号 (.)分割,用来表示一个完整的语义)
# c:1 公司id为1
# u:1 用户id为1
# 7 业务参数, 业务参数由开发根据实际业务设计, 建议多维度描述用-标识
crm.pay:c:1:u:1:7

日志使用规范

日志优先参考阿里巴巴日志规约

什么时候使用日志

  • 系统初始化:系统或者服务的启动参数。核心模块或者组件初始化过程中往往依赖一些关键配置,根据参数不同会提供不一样的服务。务必在这里记录 INFO 日志,打印出参数以及启动完成态服务表述。

  • 编程语言提示异常:如今各类主流的编程语言都包括异常机制,业务相关的流行框架有完整的异常模块。这类捕获的异常是系统告知开发人员需要加以关注的,是质量非常高的报错。应当适当记录日志,根据实际结合业务的情况使用 WARN 或者 ERROR 级别。

  • 业务流程预期不符:除开平台以及编程语言异常之外,项目代码中结果与期望不符时也是日志场景之一,简单来说所有流程分支都可以加入考虑。取决于开发人员判断能否容忍情形发生。常见的合适场景包括外部参数不正确,数据处理问题导致返回码不在合理范围内等等。

  • 系统核心角色,组件关键动作:系统中核心角色触发的业务动作是需要多加关注的,是衡量系统正常运行的重要指标,建议记录 INFO 级别日志,比如电商系统用户从登录到下单的整个流程;微服务各服务节点交互;核心数据表增删改;核心组件运行等等,如果日志频度高或者打印量特别大,可以提炼关键点 INFO 记录,其余酌情考虑 DEBUG 级别。

  • 第三方服务远程调用:微服务架构体系中有一个重要的点就是第三方永远不可信,对于第三方服务远程调用建议打印请求和响应的参数,方便在和各个终端定位问题,不会因为第三方服务日志的缺失变得手足无措。

日志规约补充

  1. 生产环境的服务需要集成ELK。kafka-topic必须以log-xxx命名, xxx为服务名
  2. 日志文件目录:/jesong/logs/xxx, xxx为项目名
  3. 日志文件命名:xxx.level.date.0.log, 其中xxx为项目名, level为日志等级, date为日志日期, 0为日志分割编号
  4. 日志需要做循环滚动删除配置
  5. 日志打印必须包含上下文
  6. 不允许记录日志后又抛出异常,因为这样会多次记录日志,只允许记录一次日志

异常处理规范

  1. 运行时异常需继承自统一异常 EasyliaoException, 异常通过全局异常统一返回
1
2
3
4
5
<dependency>
<groupId>cn.idea360</groupId>
<artifactId>idea360-core</artifactId>
<version>0.0.1</version>
</dependency>
  1. 异常的捕获用于容错处理。绝大部分场景,不允许捕获异常,不要乱加空判断。只有明显不需要关心的异常,如关闭资源的时候的io异常,可以捕获然后什么都不干,其他时候, 不允许捕获异常, 都抛出去到controller处理。空判断大部分时候不需要,你如果写了空判断,你就必须测试为空和不为空二种场景, 要么就不要写空判断。

强调, 有些空判断是要的,如:参数是用户输入的情况下。

事务使用规范

  1. 不得使用事务超时时间
  2. 只读接口不允许使用事务
  3. 严禁在事务中访问第三方/严禁在事务中使用分布式锁。因为只要进入了Transactional,哪怕没有任何SQL语句,都会占用数据库连接。所以,一旦在事务中访问第三方,第三方的故障可能会导致我方的数据库连接被大量占用。会产生灾难性的结果
  4. 事务粒度最小化

注释

类注释

类注释必须包含作者+日期+功能描述, 如

1
2
3
4
5
6
/**
* 支付账单
*
* @author xxx
* @date 2021-01-22
*/

方法注释

方法注释中必须包含功能描述+入参说明+返回说明, 如

1
2
3
4
5
6
/**
* 创建 CuratorFramework 对象并连接 Zookeeper
*
* @param zookeeperProperties zk配置文件
* @return CuratorFramework zk客户端
*/

对于多人修改同一方法, 注释中应该标明修改人, 修改日期, 修改说明

1
2
3
4
5
6
7
8
9
10
/**
* 创建 CuratorFramework 对象并连接 Zookeeper
*
* @param zookeeperProperties zk配置文件
* @return CuratorFramework zk客户端
*
* @author: xxx
* @date: 2021-01-22
* @modify: 将xxx修改为xxx
*/

SQL规范

1.使用InnoDB存储引擎

2. 字符集编码utf8mb4, 排序规则 默认采用不区分大小写的utf8mb4_general_ci, 表及字段必须添加COMMENT描述

3. 把字段定义为NOT NULL并且提供默认值

1
2
3
4
a. null的列使索引/索引统计/值比较都更加复杂,对MySQL来说更难优化。
b. null 这种类型MySQL内部需要进行特殊处理,增加数据库处理记录的复杂性,同等条件下,表中有较多空字段的时候,数据库的处理性能会降低很多。
c. null值需要更多的存储空,无论是表还是索引中每行中的null的列都需要额外的空间来标识。
d. 对null 的处理时候,只能采用is null或is not null,而不能采用=、in、<、<>、!=、not in这些操作符号。

4. 禁止使用小数存储金额等数据, 避免精度丢失

5. 数据量大的表必须建立索引

6. 禁止在更新十分频繁、区分度不高的属性上建立索引

1
2
a. 更新会变更B+树,更新频繁的字段建立索引会大大降低数据库性能
b. “性别”这种区分度不大的属性,建立索引是没有什么意义的,不能有效过滤数据,性能与全表扫描类似

7. 建立组合索引, 把区分度高的字段放在前面

8. 禁止在WHERE条件的属性上使用函数或者表达式

参考