代码规范¶
开发规范¶
一、命名要求¶
-
变量、函数和类的命名需要有具体的含义,对于非常长的变量,我们推荐用缩写的方式进行简化,进而提升可读性
-
变量、类一般以名词或动名词的单词组成;函数一般以动词或行为的词组组成
-
对于普通变量、函数需要以小驼峰风格命名;对于常量而言,需要以全大写、下划线风格命名;对于类而言,需要以大驼峰风格命名
二、注释要求¶
-
精简、清晰的注释对于代码维护有很大的帮助,我们推荐写有效的注释,但冗余、无效的注释并非我们期望的,它们提高代码的理解成本,因此注释精简也是非常重要的环节
-
错误、过时的注释是绝对不可取的,我们在提交代码的过程中,注释需要实时更新,即便是删除错位的注释而不是修改它们,也会比留下它们好
-
好的注释一般分为三部分内容:做什么、为什么、怎么做;我们也可以通过代码来相互解释,但精简、清晰是我们写注释的基本原则
三、函数要求¶
1.拒绝超大函数¶
不同的代码规范都会对超大函数(或者叫大函数)进行定义,而 Hango 给出的定义是:超过 50 行的函数我们称之为超大函数。超大函数一般是各种逻辑的堆叠,超大函数对于代码阅读有非常大地影响,对于此类函数后期的维护成本则是会更高,因此我们建议将大于 50 行的函数进行拆分,让函数内的逻辑更富有语义化。
2.优化圈复杂度¶
圈复杂度是一种代码复杂度的衡量标准,可以理解为函数用例所有的分支总数,如下运算符都会引入圈复杂度
- if 语句
- while 语句
- for 语句
- case 语句
- catch 语句
- and 和 or 布尔操作
- ? : 三元运算符
我们可以通过各类工具,例如 Sonar 、MetricsReload 等工具对函数进行圈复杂度的计算,圈复杂度影响函数的理解难度,我们对圈复杂度的要求: 15 <= 圈复杂度
圈复杂度 | 代码理解难度 | 测试难度 | 维护成本 |
---|---|---|---|
1 ~ 10 | 清晰 | 低 | 低 |
10 ~ 20 | 复杂 | 中 | 中 |
20 ~ 30 | 非常复杂 | 高 | 高 |
> 30 | 不可读 | 不可测 | 非常高 |
3.减少函数入参¶
函数入参的个数我们要求小于等于 5 个,过长参数列是典型的坏味道,因为数量越多的函数入参将会有更多松散的变量需要维护,函数的可用性需要依赖来自各处的变量,对于函数维护是不小的挑战
4.提炼重复代码¶
重复的代码在后期变更中将是噩梦,相同的代码散落各处,一个问题的修复将很难实现,我们需要把各处的相同代码进行同步修复,而这也并不能保证万无一失;因此我们需要尽可能地提炼函数和重复代码,降低后续代码修改难度
5.合理处理异常¶
对于可以预知的异常我们希望在代码中进行预处理,而非直接通过 try\catch 进行捕获处理,因为异常发生后程序将进行异常栈的采集和处理,这个过程是非常消耗性能的,举个典型的案例来说
Null Point Exception (NPE)
是开发过程中最常见的异常,我们需要通过判空来避免它,而不是通过 try\catch 来捕获他
四、代码格式¶
-
采用 4 个空格缩进,禁止使用 tab 字符
-
一行代码我们建议在 120 个字符以下,否则需要进行合理地换行
-
if/for/while/switch/do 等保留字与括号之间都必须加空格
-
任何二目、三目运算符的左右两边都需要加一个空格
-
左小括号和字符之间不出现空格;同样,右小括号和字符之间也不出现空格;而左大括号前需要空格
-
if/for/while 语句需要以 {} 包裹,即使只有 1 行内容
五、业务规约¶
1.数据bean相互转换¶
代码开发过程中,经常会遇到数据 bean A 需要转换为数据 bean B,该类操作,应放在对应 service 层实现,避免后续扩展时因需调用其他 service 函数填充某个字段时导致的扩展困难等问题。
2.业务远程短连接调用命名规范¶
对于业务模块中需要远程调用其他服务的场景,应在该业务的 package 中创建 remote package,并创建 XXXRemoteClient 类(xxx为业务名)用以实现远程调用相关代码
OpenAPI 规范¶
一、请求API规范¶
1.API 使用请求参数 Action 风格案例如下
GET /hango/v1/service/?Action=DescribeServices
2.查询统一用 GET 类型接口;修改接口(增、删、改)统一用 POST 类型接口
3.接口统一用动词风格
4.API 的请求 path 进行类型划分,以版本号作为的根 path,二级 path 以资源标识;版本序号:v1\v2\v3\v4 ...
以 Hango 最大概念拆分,例如当前查询服务的请求 path 为:GET /v1/service/?Action=DescribeServices&ServiceId=1
服务:/service
路由:/route
插件:/plugin
物理网关:/physicalGateway
虚拟网关:/virtualGateway
6.复数和单数查询接口归一,以过滤参数区分,用于精简各类命名的接口;案例如下
查询服务:/v1/service?Action=DescribeSerices&Offset=0&Limit=20
查询 serviceId 为 1 的服务:/v1/service?Action=DescribeSerices&ServiceId=1
二、请求参数规范¶
列表查询接口都需要提供分页和模糊功能,以请求参数 Pattern、 Offset 和 Limit 区分; Offset 默认值 0 , Limit 默认值 20
三、响应body¶
1.单一对象查询响应格式
{
"Code": "Success",
"Message": "处理成功",
"RequestId": "7e78958a-0d74-4a7b-be36-c303b2909580",
"Result": {
...
}
}
2.分页查询统一用如下格式进行返回(Total 代表总数、 Data 代表对象列表)
{
"Code": "Success",
"Message": "处理成功",
"RequestId": "7e78958a-0d74-4a7b-be36-c303b2909580",
"Total": 1,
"Result": [
{
...
}
]
}
3.修改接口,可以考虑传回数据
{
"Code": "Success",
"Message": "处理成功",
"RequestId": "7e78958a-0d74-4a7b-be36-c303b2909580",
...
}