[inBuilder x UBML]关于开发规范,一些可能要说的点(一)
开发规范(Development Standards)是软件开发过程中至关重要的指导性文件,它定义了团队在编码、设计、测试、部署等环节的统一规则。对于这个词而言,很多人可能只会将其与代码规范划为等号,简单的理解为代码风格一致,正确缩进,正确注释等内容,但其作用不仅限于代码风格的一致性,还涉及项目管理、质量保障、团队协作等多个维度。在做项目时如果没法做到开发规范,人员之间的相互对接就会出现困难,导致项目人月成本上升,成果交付困难。低代码虽然在使用上涉及的代码不是很多,如果只是短期简单投入使用,开发规范确实不是特别重要,但在开发新模块,版本维护等方面,开发规范依然是需要着重注意的点。
UBML开源社区官网内有20多个仓库,涉及社区、文档、项目代码等方面。其中每一个区域的提交,维护等方面都涉及到规范,本篇文章主要谈谈这个开源社区的一些规范,顺便进行宣传与启发——如何良好的规定规范。
1.代码方面
1.1前端代码规范
1.1.1 适用对象
适用对象为研发部门的设计人员、开发人员、测试人员、项目管理人员
1.1.2 适用范围
适用于采用Angular + TypeScript技术开发的前端应用、以及基于inBuilder开发平台开发的Web应用。
Angular Style Guide:https://angular.io/guide/styleguide
ECMA-262, Edition 5:http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf,http://www.ecma-international.org/publications
1.1.3 代码书写规范
1.1.3.1 注释风格
推荐使用JSDoc注释风格。JSDoc Toolkit是一个把Java Script代码注释格式化成文档的工具。开发者只需按JSDoc的规范写好注释就可以很方便导出文档。JSDoc Toolkit是google 推荐的 JSDoc生成工具。
1.1.3.1.1 文件注释
文件注释用于告诉不熟悉这段代码的开发者这个文件中包含哪些内容。应该提供文件的概述、作者、依赖关系和兼容性信息。 如下:
/**
- 
@fileoverview 处理Text Area 的工具类。 
- 
@author chenshj@inspur.com 
*/
1.1.3.1.2 变量注释
代码中的变量要有必要的注释,用来说明变量的类型以及变量的意义。
标记变量类型:
@type Type
@type {Type}
如:
/**
- 
消息ID。 
- 
@type 
*/
var messageId = messageId;
标记私有变量:
@private
如:
/**
- 
日志监听对象。 
- 
@type Array. 
- 
@private 
*/
this.handlers_ = [];
定义枚举值:
@enum {Type}
如:
/**
- 
状态值枚举。 
- 
@enum 
*/
project.TriState = {
TRUE: 1,
FALSE: -1,
MAYBE: 0
};
定义常量:
@const
如:
/**
- 
最喜欢的啤酒。 
- 
@const 
- 
@type 
*/
mynamespace.MY_BEER = ‘stout’;
1.1.3.1.3 类注释
每个类的定义都要附带一份注释,描述类的功能和用法。也需要说明构造方法的参数,如果该类继承自其它类,应该使用 @extends 标记。如果该类是对接口的实现,应该使用 @implements 标记。
标记构造函数:
@constructor
如:
/**
- 
矩形区域。 
- 
@constructor 
*/
Function Rect() {
…
}
标记类继承:
@extends Type
@extends {Type}
如:
/**
- 
空节点列表 
- 
@constructor 
- 
@extends BasicNodeList 
*/
Function EmptyNodeList () {
…
};
标记实现接口:
@implements Type
@implements {Type}
如:
/**
- 
图形接口。 
- 
@interface 
*/
function Shape() {};
Shape.prototype.draw = function() {};
/**
- 
@constructor 
- 
@implements 
*/
function Square() {};
Square.prototype.draw = function() {
…
};
1.1.3.1.4 方法与函数的注释
方法与函数的注释应提供参数的说明,使用完整的句子,并用第三人称来书写方法说明。
变量注释:
@param {Type} 变量名 描述
如:
/**
- 
查询项目信息 
- 
@param {number} 分组ID 
- 
@param {string|number|null} 项目名称或者ID,传入null值查询全部项目。 
*/
function query (groupNum, term) {
// …
};
方法返回值:
@return {Type} 描述
如:
/**
- @return {string} 最后一个项目的ID。
*/
function getLastId () {
// …
return id;
};
标记保护方法:
@protected
如:
/**
- 
设置组件的根元素。 
- 
@param {Element} 组件根元素 
- 
@protected 
*/
function setElementInternal (element) {
// …
};
1.1.3.2 注释规范
代码注释需要包含以下内容:
版权和著作权的信息。
文件注释中应该写明该文件的基本信息,如:这段代码的功能摘要,如何使用,与哪些东西相关。
类,函数,变量要有必要的注释。
1.1.3.2.1 单行注释与多行注释
单行注释,即形式为“//”的注释。单行注释用于方法内的代码注释。如对局部变量声明的注释或代码行、代码段的注释。单行注释可单独一行,如果仅仅针对一句注释,且不影响换行,可放于代码行后部;也可以用于临时屏蔽不用的代码行,在开发完毕后应及时清理。行内代码的注释应该使用单行注释。
多行注释,即形式为“/* */”的注释。行内代码注释不要使用多行注释。
1.1.3.2.2 缩进
如果在@param,@return, @supported, @this或@deprecated中断行,需要像在代码中一样,使用4个空格作为一个缩进层次。
不要在@fileoverview标记中进行缩进。虽然不建议,但也可对说明文字进行适当的排版对齐。不过,这样带来一些负面影响,就是当你每次修改变量名时,都得重新排版说明文字以保持和变量名对齐。
1.1.3.3 书写风格
包括分号(遗漏分号有时会出现很奇怪的结果,所以确保语句以分号结束)、大括号(分号会被隐式插入到代码中,开发者务必在同一行上插入大括号)、数组和对象初始化(如果初始值不是很长,就保持写在单行上;初始值占用多行时,缩进2个空格;不要为了让代码好看些而手工对齐)函数参数(尽量让函数参数在同一行上,否则每个参数独占一行,并以4个空格缩进,或者与括号对齐,以提高可读性,尽可能不要让每行超过80个字符)、传递匿名参数(如果参数中有匿名函数,函数体从调用该函数的左边开始缩进2个空格,而不是从 function 这个关键字开始,可以让匿名函数更加易读)、多行字符串(尽量不要写多行字符串)、块内函数声明(尽量不要在块内声明一个函数,因为不属于ECMAScript规范,防止出现实现相互不兼容)
1.1.4 命名规范
1.1.4.1 大小写规则
使用下面的三种标识符约定:
1.Pascal 大小写规则:将标识符的首字母和后面连接的每个单词的首字母都大写。可以对三字符或更多字符的标识符使用 Pascal 大小写。如:BackColor。
2.Camel 大小写规则:标识符的首字母小写,而每个后面连接的单词的首字母都大写。如:backColor
3.大写规则:标识符中的所有字母都大写,单词之间用下划线分隔。如:EFAULA_LANGUAGE。
标识符	大小写规则	示例
命名空间	Pascal	System.Drawing
类	Pascal	AppDomain
常量	大写	SECONDS_IN_A_MINUTE
枚举	Pascal	LoginState
属性	Camel	backColor
方法	Camel	parseFloat
方法参数	Camel	typeName
局部变量	Camel	var index = 0;
1.1.4.2 命名空间
除非是枚举类型,否则不要访问别名变量的属性。
/* @enum {string} /
some.long.namespace.Fruit = {
APPLE: ‘a’,
BANANA: ‘b’
};
myapp.main = function() {
var Fruit = some.long.namespace.Fruit;
switch (fruit) {
case Fruit.APPLE:
…
case Fruit.BANANA:
…
}
};
myapp.main = function() {
var MyClass = some.long.namespace.MyClass;
MyClass.staticHelper(null);
};
不要在全局范围内创建别名,而仅在函数块作用域中使用。
1.1.4.3 文件名
文件名应该使用小写字符,以避免在有些系统平台上不识别大小写的命名方式。文件名以.js结尾,不要包含除“-”和“”外的标点符号(使用“ –” 优于“ ”)。
1.1.4.4 命名空间规范
Java Script 不支持包和命名空间。
不容易发现和调试全局命名的冲突,多个系统集成时还可能因为命名冲突导致很严重的问题。为了提高 JavaScript 代码复用率,我们遵循下面的约定以避免冲突。
在全局作用域上,使用一个唯一的,与工程/库相关的名字作为前缀标识。比如,你的工程是 “Project GSP Aries UI”,那么命名空间前缀可取为gsp.*。
var gsp= {};
gsp.aries= function() {
…
};
不要对命名空间创建别名。
myapp.main = function() {
var namespace = some.long.namespace;
namespace.MyClass.staticHelper(new namespace.MyClass());
};
1.1.4.5 类命名规范
使用名词或名词短语命名类;使用 Pascal 大小写规则;少用缩写。
1.1.4.6 常量字段命名规范
常量的形式如: NAMES_LIKE_THIS, 即使用大写字符, 并用下划线分隔。
你也可用 @const 标记来指明它是一个常量;但请永远不要使用 const 关键词;对于基本类型的常量, 只需转换命名;对于非基本类型, 使用 @const 标记来告诉编译器它是常量。
1.1.4.7 属性命名规范
使用名词或名词短语命名属性。
使用描述性名称,且名称应含义清晰,不要使用描述其类型的名称。
使用 Pascal 大小写规则。
考虑用与属性的基础类型相同的名称创建属性。例如,如果声明名为 Color 的属性,则属性的类型同样应该是 。
1.1.4.8 方法命名规范
使用动词或动词短语命名方法;使用camel大小写规则。
1.1.4.9 方法参数命名规范
对方法参数名称使用Camel大小写规则;使用描述性名称,且名称应含义清晰,不要使用描述其类型的名称。
1.1.4.10 局部变量命名规范
声明变量必须加上 var 关键字。当你没有写 var,变量就会暴露在全局上下文中,这样很可能会和现有变量冲突。另外,如果没有加上,很难明确该变量的作用域是什么, 变量也很可能像在局部作用域中,很轻易地泄漏到 Document 或者 Window 中,所以务必用 var 去声明变量。
1.1.5 基本代码开发规范
包含变量(使用前必须通过 var 定义,不通过 var 定义变量将导致变量污染全局环境;必须即用即声明,不得在函数或其它形式的代码块起始位置统一声明所有变量;应该根据编程中的意图,缩小变量出现的距离空间)、条件(在等于判断中使用类型严格的===以避免等于判断中隐式的类型转换,仅当判断 null 或 undefined 时,允许使用 == null;且尽可能使用简洁的表达式;按执行频率排列分支的顺序;对于相同变量或表达式的多值条件,用 switch 代替 if)、循环(不要在循环体中包含函数表达式,事先将函数提取到循环体外;对循环内多次使用的不变值,在循环外用变量缓存;对有序集合进行遍历时,缓存 length以提升部分浏览器程序性能;对有序集合进行顺序无关的遍历时,使用逆序遍历来节省变量,以优化代码)、类型(类型检测优先使用 typeof。对象类型检测使用 instanceof。null 或 undefined 的检测使用 == null)、类型转换(转换成 string 时,使用 + ‘’;转换成 number 时,通常使用 +;string 转换成 number,要转换的字符串结尾包含非数字并期望忽略时,使用 parseInt;使用 parseInt 时,必须指定进制。如果十进制数包含前导0,那么最好采用基数10,防止意外得到八进制的值;转换成 boolean 时,使用 !!;number 去除小数点,使用 Math.floor / Math.round / Math.ceil,不使用 parseInt)、字符串(字符串开头和结束使用单引号;使用数组或 + 拼接字符串;静态字符串建议使用 + 拼接;在现代浏览器下,使用 + 拼接字符串,性能较数组的方式要高;如需要兼顾老旧浏览器,应尽量使用数组拼接字符串;复杂的数据到视图字符串的转换过程,推荐选用模板引擎)、浮点计算(在运算前把参加运算的浮点数先升次到整数,等运算完后再进行降次)、对象(使用对象字面量 {} 创建新 Object;对象创建时,如果一个对象的所有属性均可以不添加引号,则所有属性不得添加引号,反之则所有属性必须添加单引号;如果属性不符合 Identifier 和 Number Literal 的形式,就需要以 String Literal 的形式提供;不允许修改和扩展任何原生对象和宿主对象的原型;属性访问时,尽量使用 .,若属性名符合 Identifier 的要求,就可以通过 . 来访问,否则就只能通过 [expr] 方式访问。)、数组(使用数组字面量 [] 创建新数组,除非想要创建的是指定长度的数组;遍历数组不使用 for in,因为可能存在数字以外的属性;不因为性能的原因自己实现数组排序功能,尽量使用数组的 sort 方法;需要稳定的排序算法,达到严格一致的排序结果;清空数组使用 .length = 0)、函数(一个函数的长度控制在 50 行以内;一个清晰易懂的函数应该完成单一的逻辑单元;复杂的操作应进一步抽取,通过函数的调用来体现流程,特定算法等不可分割的逻辑允许例外;一个函数的参数控制在 6 个以内。除去不定长参数以外,函数具备不同逻辑意义的参数建议控制在 6 个以内,过多参数会导致维护难度增大)
 
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号