zoukankan      html  css  js  c++  java
  • 代码规范、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';

    注释规范

    1. 行内注释:行内注释以两个斜线开始,以行尾结束。双斜线与代码以及注释文字之间都都保留一个空格。
    function addNumber() {
    return 3 + 2; // 5
    }
    
    1. 单行注释:单独一行,单行注释以两个斜线开始,以行尾结束。
    function addNumber(a, b) {
    return a + b;
    }
    
    // 调用求和方法
    addNumber(2, 3);
    
    
    1. 方法注释:函数(方法)注释也是多行注释的一种,但是包含了特殊的注释要求。
      /**
    • 方法描述
    • @param {type} 参数值 参数说明
    • @param {type} 参数值 参数说明
      /
      示例:
      /
      *
    • @param {number} a 参数a
    • @param {Number} b 参数b
      */
      funtion addNumber(a, b) {
      return a + b;
      }

    格式规范

    • JS格式规范要严格遵循 Eslint,要求在 husky 钩子中增加Eslint规则校验,校验不通过,代码提交失败。

    其他规范

    1. 变量声明
    • 对所有的变量优先使用const,可变的变量使用let,不允许使用var
    // good
    const a = 1;
    const b = 2;
    
    // good
    let count = 1;
    if (true) {
        count += 1;
    }
    
    1. Strings
    • 字符串使用单引号 ‘’
      生成字符串时,使用模板字符串代替字符串连接
    // bad
    function sayHi(name) {
      return 'How are you, ' + name + '?';
    }
    
    // good
    function sayHi(name) {
      return `How are you, ${name}?`;
    }
    
    1. 对象
    • 使用字面值创建对象
    // 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
    };
    
    1. 数组
    • 使用字面值创建数组
    // 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];
    
    1. 解构
    • 使用解构存取和使用多属性对象
    // 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}`;
    }
    
    1. 函数
    • 尽可能使用箭头函数
      不允许在一个非函数代码块(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);
      };
    }
    

    语法原则

    1. 统一使用Node.js支持的 ES6 及以上版本的新特性写法
    2. 尽量使用常用常规的方法去实现一个功能,避免使用各种奇技淫巧
    3. 能用原生语法或原生函数实现的功能尽量不要借助 lodash 等额外的库来实现
    4. 统一使用 Promise + async/await 取代 callback, 解决回调地狱
    5. require() 引入的模块和库按代码长度排序,且库和自定义模块分开,库引用在前,自定义模块在后
    6. 对象定义统一用 {} 定义,而不是 new Object()
    7. 使用字面值创建数组,数组定义统一用 [],而不是 new Array()
    8. 向数组添加元素时使用 push 替代直接赋值
    9. 使用拓展运算符 ... 复制数组
    10. 使用 map、reduce、filter 时如果函数简单应省略 return
    11. 给注释增加 FIXME 或 TODO 的前缀,帮助其他开发者快速了解这是一个需要复查的问题,或是给需要实现的功能提供一个解决方式。

    命名规范:

    1. 函数名/变量名:
      方式: 小驼峰
      good: testFunction/testVar
      bad: test_function/test_var
    2. 全局常量:
      方式: 大写下划线分隔
      good: TEST_CONST
      bad: test_const
    3. 文件名:
      方式: 小写下划线分隔
      good: test_file.js
      bad: test-file.js
    4. 类名:
      方式: 小写下划线分隔
      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])
    1. GET 读取资源(必须保证接口的幂等性)
    2. POST 新增资源
    3. PUT 更新资源
    4. DELETE 删除资源
    • 资源的描述尽量采用复数形式
    good: GET /api/v1/dubhe/tasks
    bad: GET /api/v1/dubhe/task_list
    
    • 对于不方便直接抽象为资源的操作,例如 启动一个任务 可采用如下动词的方式
    POST /api/v1/dubhe/start/task/:taskId
    
    • 参数传递主要使用如下三种方式(文件上传除外)
    1. 路由参数(Route Param)
    2. URL查询参数(Query String)
    3. 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

    • 版本号修改规则:
    1. 主版本号:当你做了不兼容的API修改的情况需要增加
    2. 次版本号:当你做了向下兼容的功能性新增需要增加
    3. 修订号 :当你做了向下兼容的问题修正需要增加
      基本规范
    4. 主版本号为零(0.y.z)的软件处于开发初始阶段,一切都可能随时被改变。这样的公共 API 不应该被视为稳定版。
    5. 1.0.0 的版本号用于标识稳定 API 的发布。这一版本之后,所有的版本号更新都基于公共 API 的修改内容
    6. 带版本号的软件发行后,禁止改变该版本软件的内容。任何修改都必须以新版本发行。
      修订号 Z(x.y.Z | x > 0)必须在只做了向下兼容的 bug 修复时才递增。
    7. bug 修复的定义是,修改程序内部行为,使其输出正确的结果
      次版本号 Y(x.Y.z | x > 0)必须在有向下兼容的新功能出现时递增。
    8. 在任何公共 API 的功能被标记为弃用时也必须递增。也可以在内部程序有大量功能更新或改进时递增。其中可能包括修订号的改变。每当次版本号递增时,修订号必须置零。
      主版本号 X(X.y.z | X > 0)必须在有任何不向下兼容的修改被加入公共 API 时递增。其中可能包括次版本号及修订号的改变。
    9. 每当主版本号递增时,次版本号和修订号必须置零
      修改版本号的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": {
      }
    }
    
  • 相关阅读:
    Asp.net MVC3
    ASP.NET 路由实现页面静态化(附在线Demo和Source)
    ASP.NET MVC中Unobtrusive Ajax的妙用
    ASP.NET MVC Controller激活系统详解:IoC的应用[上篇]
    探讨大数据量处理
    提高ASP.NET性能与可伸缩性的几个个常用方法剖析
    Winform 应用
    C#利用QrCode.Net生成二维码
    MS SQL删除大数据
    由浅入深:自己动手开发模板引擎——置换型模板引擎1
  • 原文地址:https://www.cnblogs.com/mapleChain/p/11527902.html
Copyright © 2011-2022 走看看