代碼規范、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": {
  }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM