Skip to content
lianshaoshuai edited this page Aug 13, 2017 · 1 revision

后端开发规范

名称解释

  • 小驼峰: 即除了第一个单词的首字母不大写外,其余单词的首字母都大写,词与词之间没有任何符号
  • 大驼峰: 即所有单词首字母大写,词与词之间没有任何符号

目录相关

  1. 公共目录说明
  • /configs 放置开发环境下的配置文档
  • /deployment 放置部署文件
  • /publicRes 放置几乎所有服务都会用到的 css,js,img
  • /sharedApp 放置常量定义和校验规则(一个项目一个文件夹,一般不向 global 文件中添加)
  • /swagger_files 放置 swagger 的 yaml
  • /templates 放置模板文件,里面包含一下上线部署文件
  1. 目录命名说明
  • 后台服务项目的命名规则是:svcXxx,如 svcInside
  • 前端项目的命名规则是:webXxx,如 webInside
  1. 后台服务项目目录说明
  • /api 具体的接口实现文件,命名规则:fgXxxService(为前端提供服务);bgXxxService(为后端提供服务)
  • /app 缓存,数据库,定时器,配置初始化
  • /cache 缓存具体方法实现文件
  • /config swagger 默认配置
  • /logic 公用逻辑
  • /interfaceClients 引用的服务客户端
  • /specs 测试
  1. 前端项目目录说明
  • /app 项目配置
  • /bin 项目启动配置
  • /interfaceClients 引用的服务客户端
  • /public js,css,img(按照功能模块划分文件目录)
  • /routes 路由层(按照功能模块划分文件目录)
  • /views 页面模板(按照功能模块划分文件目录)

原则

  1. 非特殊情况下,禁止在循环中执行 IO 操作(访问 Redis 、访问 Mysql)
  2. 优化循环减少循环次数
  3. 程序在进行取数时,需要什么数据取什么数据,不得取用不到的数据

代码格式

  1. 遵循 EsLint 规范
  2. 代码中不得有多余空格
  3. 对于逻辑块之间需要换一行
  4. 文档不得出现错别字,尤其是文件名、方法名、变量名及注释
  5. require 分为三部分:系统和第三方、自定义 define 、其他引用,每个部分换一行
// good
const knex = require('knex');

const testTypeDefine = require('../../testTypeDefine');

const db = require('../app/db');

// bad 
const knex = require('knex')
const testDefine = require('../../testDefine');
const db = require(../app/db);
  1. 字符串统一用英文单引号
// good
const name = 'langlib'

// bad
const name = "langlib";
  1. 长字符串处理,超过 80 个字符的字符串应该使用字符串连接换行
// good
const errorMessage = 'This is a super long error that ' +
'was thrown because of Batman.' +
'When you stop to think about ' +
'how Batman had anything to do ' +
'with this, you would get nowhere ' +
'fast.';

// bad
const errorMessage = 'This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.';

// bad
const errorMessage = 'This is a super long error that \
was thrown because of Batman. \
When you stop to think about \
how Batman had anything to do \
with this, you would get nowhere \
fast.';

命名规范

常量命名

  1. 对于依赖逻辑的常用参数需在 define 中定义常量
  2. define 中的常量采用大驼峰定义
  3. require 常量及需要实例化的类时,使用大驼峰进行别名定义

变量命名

  1. 为引用使用 const 关键字,而不是 var 定义
// good 
const  langbo =[1,2];

// bad
var  langbo =[1,2];
  1. 必须修改的引用实用 let 关键字,代替实用 var
// good 
let count = 1;
if (true) {
	count += 1;
}

// bad
var count = 1;
if (true) {
	count += 1;
}
  1. 命名采用小驼峰命名
// good
const userName = '';
// bad
const UserName = '';
const username = '';
  1. 数组、集合命名需要使用复数形式表达
// good 
const users = [];
// bad
const userArr = []
  1. 变量名在同一个域内不得产生二义性
// good
const teacherUserID = '';
const studentUserID ='' 

// bad
const userID = '';
const studentUserID ='';

// bad
const UnitFinishCount = 60;
const NewUnitFinishCount = 10;
  1. 从数据库直接查询的结果和直接操作 redis 的返回集合统一添加 dbcache 前缀
// good
const dbUnitStatus = await db.user('WB_ListStatus').select('XXX');
const cacheQuestStatus = await redis.hmget(`${redisWrapper.keys.dyn.info}${userID}#${testType}`, sysQuestTmpIDs);

方法命名

  1. 采用小驼峰命名
// good
getUserInfo: async()=>{ ... },

// bad
GetUserInfo: async()=>{ ... },
// bad
getuserinfo: async()=>{ ... }
  1. 函数命名采用动宾结构
// good 
getUserInfo: async()=>{ ... },
	
// bad
get: async()=>{ ... },
  1. 箭头函数用括号包裹参数,即使是单个参数也不可以省略括号(省略括会降低了程序的可读性)
// good
[1, 2, 3].forEach((x) => { ... });

// bad
[1, 2, 3].forEach(x => x * x);

knex 使用规范

  1. 检查事务使用
  2. 代码需要符合 sql 结构表述(select {fieldName} from {tableName} where group by order by), first 视同 select 处理
  3. 不得在 where 条件中使用无法立即获知期成员列表的 object 类型,必须限定具体查询字段及条件
function query(params) {
// good
const dbUnitStatus = await db.user('WB_ListStatus')
			.select('ListID', 'RoutineIdx', 'F1', 'F2', 'F3', 'F4', 'F5', 'CompletedDate')
			.where('WordBookID', params.WordBookID)
			.orderBy('CompletedDate');
// bad
const dbUnitStatus = await db.user('WB_ListStatus')
.select('ListID', 'RoutineIdx', 'F1', 'F2', 'F3', 'F4', 'F5', 'CompletedDate')
.where(params);
}
  1. 非特殊情况 SQL 不得使用 *,只能返回需要的数据项
// good
const dbUnitStatus = await db.user('WB_ListStatus')
		.select('ListID', 'RoutineIdx', 'F1', 'F2', 'F3', 'F4', 'F5', 'CompletedDate')
// bad
const dbUnitStatus = await db.user('WB_ListStatus').select('*');
  1. 检查多表联合查询,使用链接方式是否正确及合理性
  2. 检查数据库的访问权限
  3. 检查 Order By 的必要性及排序方式
  4. db.getXXTableID 的返回值统一命名 newRowIDnewRowIDSeed(取过个的情况使用)
// good
const newRowID = await db.getUserTableID('SNS_UserServiceLog');
const newRowIDSeed = await db.getUserTableID('SNS_UserServiceLog','Id', 10);

// bad
const rowID = await db.getUserTableID('SNS_UserServiceLog');
  1. db.getXXTableID 不进事务

Swagger 使用规范

  1. swagger 接口返回值统一按下面格式进行返回
// good
	async (req, res) => {
	....
	res.json({ xxx });
	return;
	},
	async (req, res) => {
	....
	res.status(404).json({ Message:'xxxxx'});
	return;
	},
	
// bad
async (req, res) => {
	....
	return res.json({ xxx });
	},
async (req, res) => {
	....
	res.status(404).end();
	},
  1. swagger 客户端获取返回值统一用户 obj 属性获取
const user = (await membershipClient.apis.user.loginByCredential({
		userCredential: req.swagger.params.userCredential.value,
		password: req.swagger.params.password.value,
	})).obj;

常用方法定义

ES6 常用方法

  1. concat 数组合并
  const arr1 = ['a','b'];
  const arr2 = ['c','d'];
  const resultSubTestRating = arr1.concat(arr2);
  => ['a','b','c','d'];
  1. map
  2. Array.ForEach
  3. for ... of
  4. for ... in
  5. 解构
  6. Float.toFixed
  7. Object.values
  8. Object.keys
  9. Object.assign

lodash 模块使用

  1. _.isEmpty 判断是否为空
_.isEmpty({})=true;
_.isEmpty('')=true;
_.isEmpty([])=true;
_.isEmpty(undefined)=true;

// 注意
_.isEmpty(0)= true;
_.isEmpty(int32)= true;
  1. _.groupBy 对数据进行分组
const users = [{ Name:'张三',Sex: 1 },{ Name:'李四', Sex: 2 },{ Name:'王五', Sex:1 }];
_.groupBy(users, 'Sex'); =>
{
	1: [{ Name:'张三', Sex:1 }, { Name:'王五', Sex:1 }]
	2: [{ Name:'李四', Sex:2 }]
}
  1. _.orderBy 数组排序
const users = [{ Name: '张三', Score:2 },{ Name: '李四', Score:6 },{ Name: '王五', Score:5 }];
_.orderBy(users,'score');
	=> 
	[
	{ Name: '张三', Score: 2 },
	{ Name: '王五', Score: 5 },
	{ Name: '李四', Score: 6 }
	]
  1. _.pick 属性挑选
var object = { 'a': 1, 'b': '2', 'c': 3 };
_.pick(object, ['a', 'c']); => { 'a': 1, 'c': 3 }
  1. _.map
  2. _.each
  3. _.countBy

数据处理常用方法

  1. 数据合并方法, 一边处理成 Hash,一边处理成循环

eg: 10*10 二位数据和 一个长度为 10 的一维数组

循环方式: 1010 X 10 = 100 * 10 = 1000; Hash 方式:1010 + 10 = 100 + 10 = 110;