代碼規範、API設計等規範


"規範是個好東西..." - 魯迅
如下規範僅做爲參考node


一、代碼規範

命名git

  • 儘可能保證命名更加語義化

文件命名採用下劃線命名法json

// good
service_center.js
// bad
serviceCenter.js

類 & 構造函數命名api

  • 類命名採用 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';

註釋規範app

  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;
    }

格式規範curl

  • JS格式規範要嚴格遵循 Eslint,要求在 husky 鉤子中增長Eslint規則校驗,校驗不經過,代碼提交失敗。

其餘規範async

  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

二、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"
        }
    ]
}

三、版本號規範

此規範約束的是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

四、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": {
  }
}
相關文章
相關標籤/搜索