代码规范、API设计等规范
一份整理好了的规范文档,node后端开发用到
"规范是个好东西..." - 鲁迅
以下规范仅作为参考
1、代码规范
命名
- 尽量保证命名更加语义化
文件命名采用下划线命名法
// good
service_center.js
// bad
serviceCenter.js
类 & 构造函数命名
- 类命名采用 Pascal命名法,大写字母开头,各个单词首字母大写
class Person {
constructor(name) {
this.name = name;
}
}
const person = new Person('小明');
方法名
- 方法命名采用 Camel命名法,小写字母开头,各个单词首字母大写
前缀应当是动词
命名建议:可使用常见动词约定等。
// good
function getName() {
...
return this.name;
}
function isExist() {
...
return true;
}
变量命名
- 采用 Camel命名法,小写字母开头,各个单词首字母大写
特有大写缩写词汇保持大写如:SQL, URL等
变量名字不宜过长,可适当采用缩减英文元音字母来缩短长度
前缀应当是名词(方法名前缀为动词,以此区分变量和方法)
// good
let maxLength = 10;
// bad
let setLength = 10;
常量命名
- 必须采用 全大写命名,且单词以_分割
const MAX_COUNT = 10;
const SQL = 'SELECT * from bas_table';
注释规范
- 行内注释:行内注释以两个斜线开始,以行尾结束。双斜线与代码以及注释文字之间都都保留一个空格。
function addNumber() {
return 3 + 2; // 5
}
- 单行注释:单独一行,单行注释以两个斜线开始,以行尾结束。
function addNumber(a, b) {
return a + b;
}
// 调用求和方法
addNumber(2, 3);
- 方法注释:函数(方法)注释也是多行注释的一种,但是包含了特殊的注释要求。
/**
- 方法描述
- @param {type} 参数值 参数说明
- @param {type} 参数值 参数说明
/
示例:
/* - @param {number} a 参数a
- @param {Number} b 参数b
*/
funtion addNumber(a, b) {
return a + b;
}
格式规范
- JS格式规范要严格遵循 Eslint,要求在 husky 钩子中增加Eslint规则校验,校验不通过,代码提交失败。
其他规范
- 变量声明
- 对所有的变量优先使用const,可变的变量使用let,不允许使用var
// good
const a = 1;
const b = 2;
// good
let count = 1;
if (true) {
count += 1;
}
- Strings
- 字符串使用单引号 ‘’
生成字符串时,使用模板字符串代替字符串连接
// bad
function sayHi(name) {
return 'How are you, ' + name + '?';
}
// good
function sayHi(name) {
return `How are you, ${name}?`;
}
- 对象
- 使用字面值创建对象
// good
const obj = {};
// bad
const obj = new Object();
对象方法的简写
// bad
const atom = {
value: 1,
addValue: function (value) {
return atom.value + value;
},
};
// good
const atom = {
value: 1,
addValue(value) {
return atom.value + value;
},
};
对象属性值的简写
const lukeSkywalker = 'Hello World';
// bad
const obj = {
lukeSkywalker: lukeSkywalker
};
// good
const obj = {
lukeSkywalker
};
- 数组
- 使用字面值创建数组
// bad
const arr = new Array();
// good
const arr = [];
- 使用拓展运算符 … 复制数组
// bad
const len = arr.length;
const arrCopy = [];
let i;
for (i = 0; i < len; i++) {
arrCopy[i] = arr[i];
}
// good
const arrCopy = [...arr];
- 解构
- 使用解构存取和使用多属性对象
// bad
function getFullName(user) {
const firstName = user.firstName;
const lastName = user.lastName;
return `${firstName} ${lastName}`;
}
// good
function getFullName(user) {
const { firstName, lastName } = user;
return `${firstName} ${lastName}`;
}
// best
function getFullName({ firstName, lastName }) {
return `${firstName} ${lastName}`;
}
- 函数
- 尽可能使用箭头函数
不允许在一个非函数代码块(if、while 等)中声明一个函数
使用函数声明代替函数表达式因为函数声明是可命名的,所以他们在调用栈中更容易被识别。此外,函数声明会把整个函数提升(hoisted),而函数表达式只会把函数的引用变量名提升。这条规则使得箭头函数可以取代函数表达式。
// bad
const foo = function () {
};
// good
function foo() {
}
- 别保存 this 的引用。使用箭头函数或 Function#bind。
// bad
function foo() {
const that = this;
return function() {
console.log(that);
};
}
// good
function foo() {
return () => {
console.log(this);
};
}
语法原则
- 统一使用Node.js支持的 ES6 及以上版本的新特性写法
- 尽量使用常用常规的方法去实现一个功能,避免使用各种奇技淫巧
- 能用原生语法或原生函数实现的功能尽量不要借助 lodash 等额外的库来实现
- 统一使用 Promise + async/await 取代 callback, 解决回调地狱
- require() 引入的模块和库按代码长度排序,且库和自定义模块分开,库引用在前,自定义模块在后
- 对象定义统一用 {} 定义,而不是 new Object()
- 使用字面值创建数组,数组定义统一用 [],而不是 new Array()
- 向数组添加元素时使用 push 替代直接赋值
- 使用拓展运算符 ... 复制数组
- 使用 map、reduce、filter 时如果函数简单应省略 return
- 给注释增加 FIXME 或 TODO 的前缀,帮助其他开发者快速了解这是一个需要复查的问题,或是给需要实现的功能提供一个解决方式。
命名规范:
- 函数名/变量名:
方式: 小驼峰
good: testFunction/testVar
bad: test_function/test_var - 全局常量:
方式: 大写下划线分隔
good: TEST_CONST
bad: test_const - 文件名:
方式: 小写下划线分隔
good: test_file.js
bad: test-file.js - 类名:
方式: 小写下划线分隔
good: TestClass
bad: testClass
2、api设计
路由规范(URI)
- URI必须全部使用小写
good: /api/v1/uic/check/login
bad: /api/v1/uic/checkLogin
- 如需连接多个单词则必须使用 下划线
good:/api/v1/dubhe/task_run_history
bad: /api/v1/dubhe/task-run-history
- 版本号格式(必须是 v + 整数)
good:/api/v2/dubhe/tasks
bad: /api/v1.1/dubhe/tasks
HTTP Method
- 能抽象成资源的CURD则使用标准的HTTP Method来区分,URI中尽量不使用动词(特殊情况除外[1])
- GET 读取资源(必须保证接口的幂等性)
- POST 新增资源
- PUT 更新资源
- DELETE 删除资源
- 资源的描述尽量采用复数形式
good: GET /api/v1/dubhe/tasks
bad: GET /api/v1/dubhe/task_list
- 对于不方便直接抽象为资源的操作,例如 启动一个任务 可采用如下动词的方式
POST /api/v1/dubhe/start/task/:taskId
- 参数传递主要使用如下三种方式(文件上传除外)
- 路由参数(Route Param)
- URL查询参数(Query String)
- JSON参数(Request Body)
- 单个资源的操作推荐使用动态路由参数(Route Param)
good:GET /api/v1/uic/users/:userId
bad: GET /api/v1/uic/users?userId=1234
- 参数命名方式统一采用驼峰式
good:
POST /api/v1/uic/users
body:
{
"userId": 1,
"userName": "用户名",
"tenantId": 1,
"tenantName": "租户名"
}
◦
bad:
POST /api/v1/uic/users
body:
{
"user_id": 1,
"user_name": "用户名",
"tenant_id": 1,
"tenant_name": "租户名"
}
接口返回值格式
默认统一格式为 application/json (文件下载除外)
返回体json数据中包含如下4个字段:
success : 描述接口返回成功还是失败,取值 true or false
code: 接口返回的错误码,错误码的规范由各个业务系统自行约束
推荐使用英文大写枚举值,如: ERROR_UNAUTH ERROR_INVALID_PARAM ERROR_NO_PERMISSION
message: 接口返回错误时的描述信息,如: param transform failed, userId should be a number.
content: 接口返回成功时的数据内容, json格式
示例:
成功:
{
"success": true,
"code": "",
"message": "",
"content": {
"id": 1,
"name": 2,
"email": "12345@sina.cn"
}
}
注:content的内容及格式由接口实现者给出
失败:
{
"success": false,
"code": "ERROR_NO_PERMISSION",
"message": "you have no permission",
"content": ""
}
◦
- 查询接口分页返回场景
- 查询参数(querystring):?currentPage=1&pageSize=10
{
"success": true,
"code": "",
"message": "",
"content": {
"count": 20, // 数据总条数
"currentPage": 1, // 当前页码
"pageSize": 10, // 每页的数据条数
"data":[
]
}
}
注:data中的内容及格式由接口实现者给出
标杆API设计样例
- 名称:查询功能点列表
- 方法:GET
- 路径:/api/v1/uic/functions
- 成功返回接口示例:
{
"success": true,
"code": 0,
"message": null,
"content": [
{
"functionId": 6530,
"functionName": "登录权限",
"functionCode": "dsp_page",
"description": null,
"type": "1",
"productId": 102,
"groupId": null,
"groupName": null,
"enabled": 1,
"invalid": "N",
"createTime": "2018-03-21T03:13:06.000Z",
"modifyTime": "2018-03-21T03:13:06.000Z"
},
{
"functionId": 6528,
"functionName": "用户页面-管理",
"functionCode": "user_page",
"description": null,
"type": "1",
"productId": 85,
"groupId": null,
"groupName": null,
"enabled": 1,
"invalid": "N",
"createTime": "2018-03-13T13:35:11.000Z",
"modifyTime": "2018-03-13T13:35:11.000Z"
}
]
}
3、版本号规范
此规范约束的是package.json中的version以及git仓库中打tag的规范。
- 版本号格式:
标准的版本号必须采用 X.Y.Z 的格式,其中 X、Y、Z 为非负的整数,且禁止在数字前方加前导零。X 是主版本号、Y 是次版本号、 Z 为修订号。每个元素必须以数值来递增。例如:1.9.0 -> 1.10.0 -> 1.11.0
- 版本号修改规则:
- 主版本号:当你做了不兼容的API修改的情况需要增加
- 次版本号:当你做了向下兼容的功能性新增需要增加
- 修订号 :当你做了向下兼容的问题修正需要增加
基本规范 - 主版本号为零(0.y.z)的软件处于开发初始阶段,一切都可能随时被改变。这样的公共 API 不应该被视为稳定版。
- 1.0.0 的版本号用于标识稳定 API 的发布。这一版本之后,所有的版本号更新都基于公共 API 的修改内容
- 带版本号的软件发行后,禁止改变该版本软件的内容。任何修改都必须以新版本发行。
修订号 Z(x.y.Z | x > 0)必须在只做了向下兼容的 bug 修复时才递增。 - bug 修复的定义是,修改程序内部行为,使其输出正确的结果
次版本号 Y(x.Y.z | x > 0)必须在有向下兼容的新功能出现时递增。 - 在任何公共 API 的功能被标记为弃用时也必须递增。也可以在内部程序有大量功能更新或改进时递增。其中可能包括修订号的改变。每当次版本号递增时,修订号必须置零。
主版本号 X(X.y.z | X > 0)必须在有任何不向下兼容的修改被加入公共 API 时递增。其中可能包括次版本号及修订号的改变。 - 每当主版本号递增时,次版本号和修订号必须置零
修改版本号的MR里需要描述此次版本更新和上一版本的区别内容
FQ:
Q:万一不小心发布了不兼容的更新,但只更改了次版本号,该如何补救?
A:一旦发现自己破坏了语义化版本控制的规范,就要修正这个问题,并发行一个新的次版本号来更正这个问题,并且恢复向下兼容。即使是这种情况,也不能去修改已发行的版本。可以的话,将有问题的版本号记录到文档中,告诉使用者问题所在,让他们能够意识到这是有问题的版本。
Q:如何判断发布 1.0.0 版本的时机?
A:当你的软件被用于正式环境,它应该已经达到了 1.0.0 版。如果你已经有个稳定的 API 被使用者依赖,也应是 1.0.0 版。如果你有很多向下兼容的问题要考虑,也应该算是 1.0.0 版了。
Q:对于公共 API,若即使是最小但不向下兼容的改变都需要产生新的主版本号,岂不是很快就达到 42.0.0 版?
A:这是开发者的责任感和前瞻性的问题。不兼容的改变不应该轻易被加入到有许多依赖代码的软件中。升级所付出的代价必须是有意义的。要递增主版本号来发行不兼容的版本,意味着你已经为这些改变所带来的影响慎重考虑过,并且评估了所涉及的成本/效益比。
操作
项目每周迭代情况下,每次发布时增加次版本号,如果发布失败重新修改后发布则增加修订号。
package.js
{
"version": "1.0.0"
}
Makefile
tag:
@cat package.json | xargs -0 node -p 'JSON.parse(process.argv[1]).version' | xargs git tag
@git push origin --tags
提交版本号:
使用make命令
$make tag
或
// 删除版本号
git tag -d 1.0.0
// 添加版本号
git tag 1.0.0
// 推送到git服务器
git push origin --tags
4、eslint配置规则
{
// 开启了Node.js 和 Mocha 两个环境,会自动识别其中的全局变量
"env": {
"node": true,
"mocha": true
},
"plugins": [],
"parserOptions": {
// 使用 ES2017 的语法
"ecmaVersion": 8,
"sourceType": "script",
"ecmaFeatures": {
}
},
"rules": {
// 强制驼峰法命名变量
"camelcase": ["error"],
// 不允许在条件判断语句中使用赋值语句
"no-cond-assign": ["error"],
// 禁用行尾空格
"no-trailing-spaces": ["error"],
// 不允许在代码里写 console.xxx 语句
"no-console": ["error"],
// 不允许使用 var 声明变量
"no-var": ["error"],
// 不能直接 return 赋值语句
"no-return-assign": ["error"],
// 不允许给函数参数重新赋值
"no-param-reassign": ["error"],
// 不允许注释跟代码在同一行
"no-inline-comments": ["error"],
// 逗号前面不允许有空格,逗号后面必须有空格
"comma-spacing": ["error", {"before": false, "after": true}],
// 强制始终使用分号结尾
"semi": ["error", "always"],
// 强制始终使用大括号,就算代码块中只有一条语句
"curly": ["error", "all"],
// 强制使用 === 和 !==
"eqeqeq": ["error", "always"],
// 大括号的风格,前面一个在行末,后面一个在行首
"brace-style": ["error"],
// 缩进格式为2个空格,switch语句的case子句也是缩进2个空格
"indent": ["error", 2, {"SwitchCase": 1}],
// 一行代码的最大长度,tab计算为2个空格,忽略注释部分
"max-len": ["error", 180, 2, {"ignoreComments": true}],
// 禁止出现未被使用过的变量
"no-unused-vars": ["error"],
// 可以使用的地方强制使用箭头函数
"prefer-arrow-callback": ["error"],
// 强制统一使用单引号
"quotes": ["error", "single"],
// 强制在关键字前后使用空格
"keyword-spacing": ["error"],
// 冒号前面不允许有空格,冒号后面强制需要一个空格
"key-spacing": ["error"],
// 分号前不允许有空格,分号后强制需要空格
"semi-spacing": ["error", {"before": false, "after": true}],
// json 对象大括号前后不允许有空格
"object-curly-spacing": ["error", "never"],
// 操作符前后必须有空格
"space-infix-ops": ["error"],
// (左)大括号前强制空格
"space-before-blocks": ["error"]
},
"globals": {
}
}
代码规范、API设计等规范的更多相关文章
- RESTful API设计原则与规范
RESTful API设计原则与规范 一.背景与基础概念 2 二.RESTful API应遵循的原则 3 1.协议(Protocol) 3 2.域名(ROOT URL) 3 3.版本(Versioni ...
- .NET代码设计简单规范
以下转载于:http://www.it28.cn/ASPNET/825095.html 下面这个规范是我为朋友写的几点建议,写的很范,作为BLOG,愿与大家一起分享.只给出部分设计规范样例,关于.NE ...
- API 接口开发规范
整体规范建议采用RESTful 方式来实施. 协议 API与用户的通信协议,总是使用HTTPs协议,确保交互数据的传输安全. 域名 应该尽量将API部署在专用域名之下.https://api.exam ...
- Atitit usrQBF2312 命名空间pkg 以及 api命名 spec规范
Atitit usrQBF2312 命名空间pkg 以及 api命名 spec规范 简化英文1 常用类库sdk的命名单词统计表1 简化时间规则1 Namsspace nam spec,参照java . ...
- Web UI 网站用户界面设计命名规范
Web UI 网站用户界面设计命名规范 WEB UI设计命名规范,也就是网站用户界面设计(网页设计)命名规范. 这套规范并非单纯的CSS.html或JavaScript命名规范,它涉及了很多使用Pho ...
- (2.15)Mysql之SQL基础——开发设计最佳规范
(2.15)Mysql之SQL基础——开发设计最佳规范 关键字:mysql三大范式,mysql sql开发规范 分析: show profile.mysqllsla.mysqldrmpslow.exp ...
- vscode保存代码,自动按照eslint规范格式化代码设置
# vscode保存代码,自动按照eslint规范格式化代码设置 编辑器代码风格一致,是前端代码规范的一部分.同一个项目,或者同一个小组,保持代码风格一致很必要.就拿vue项目来说,之前做的几个项目, ...
- Web UI 设计(网页设计)命名规范
Web UI 设计命名规范 一.网站设计及基本框架结构: 1. Container“container“ 就是将页面中的所有元素包在一起的部分,这部分还可以命名为: “wrapper“, “wr ...
- MySQL(9)— 规范数据库设计
九.规范数据库设计 9-1.为什么要设计? 当数据库比较复杂时,我们就需要设计了! 糟糕的数据库设计: 数据冗余,浪费大量存储空间 使用物理外键,大量的增删改操作麻烦,异常 查询效率低下 良好的数据库 ...
随机推荐
- 解决只能通过localhost访问Elasticsearch的问题
解决只能通过localhost访问Elasticsearch的问题 在默认情况下Elasticsearch是无法通过外网访问的 需要绑定地址,原因如下: 具体方法为: vim /opt/es/ ...
- DNS域名解析服务的介绍
1.1什么是域名? 域名(英语:Domain Name),简称域名.网域,是由一串用点分隔的名字组成的Internet上某一台计算机或计算机组的名称,用于在数据传输时标识计算机的电子方位(有时也指地理 ...
- 字符串的排列(剑指offer-27)
题目描述 输入一个字符串,按字典序打印出该字符串中字符的所有排列.例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba. 输入描述: 输 ...
- #pragma comment(linker,"/SECTION:shared,RWS")
Windows在一个Win32程序的地址空间周围筑了一道墙.通常,一个程序的地址空间中的数据是私有的,对别的程序而言是不可见的.但是执行多个执行实体表示了程序的所有执行实体之间共享数据是毫无问题的.当 ...
- java 面向对象(十三):面向对象的特征二:继承性 (二) 方法的重写
1.什么是方法的重写(override 或 overwrite)?子类继承父类以后,可以对父类中同名同参数的方法,进行覆盖操作. 2. 应用:重写以后,当创建子类对象以后,通过子类对象调用子父类中的同 ...
- 数据可视化之DAX篇(十八)收藏 | DAX代码格式指南
https://zhuanlan.zhihu.com/p/64422599 为什么要进行格式化? DAX 是一种函数式语言,正如我们已经学习的或者看到的,DAX 代码中总有一些函数带有几个参数,而参数 ...
- CRM【第三篇】: crm业务
1. 项目背景 crm系统是某某教育公司正在使用的项目,系统主要为 销售部.运营部.教质部门提供管理平台,随着公司规模的扩展,对公司员工的业务信息量化以及信息化建设越来越重要. crm系统为不同角色的 ...
- 数字孪生,数据驱动下的北京 CBD 智能楼宇三维可视化系统
前言 楼宇作为建筑基础设施的主体,为人们提供着重要的生存空间.随着物联网.人工智能概念的兴起以及智慧城市如火如荼的开展,智能楼宇的重要性越发突显. 随着城市现代化建设的发展,建筑的智能化,特别是公用建 ...
- SQL语句 查询最新记录
要求:SQL语句按ID以最新时间查询最新的一条记录 方法1: select * from (select *, ROW_NUMBER() over(partition by id order by u ...
- 题解 洛谷 P4632 【[APIO2018] New Home 新家】
首先考虑可以用二分答案来解决询问,可以二分一个长度\(len\),若在区间\([x-len,x+len]\)内包含了所有\(k\)种的商店,那么这个\(len\)就是合法的,可以通过二分来求其最小值. ...