穿梭在银河的火箭队——β冲刺代码规范
| 这个作业属于哪个课程 | 2022年福大-软件工程;软件工程实践-W班 |
|---|---|
| 这个作业要求在哪里 | 团队作业——beta冲刺+事后诸葛亮 |
| 这个作业的目标 | 代码规范 |
| 其它参考文献 | 无 |
目录
- 1.1 前端代码规范
- 1.1.1 代码风格
- 1.1.2 语言特性
- 1.1.3 浏览器环境
- 1.2 后端代码规范
- 1.2.1 编程规约
- 1.2.1.1 命名风格
- 1.2.1.2 常量定义
- 1.2.1.3 代码格式
- 1.2.1.4 OOP规约
- 1.2.1.5 控制语句
- 1.2.1.6 注释规约
- 1.2.1.7 其它
- 1.2.2 异常处理
- 1.2.3 单元测试
- 1.2.4 MySQL数据库
- 1.2.4.1 建表规约
- 1.2.4.2 索引规约
- 1.2.4.3 SQL语句
- 1.2.4.4 ORM映射
1.1 前端代码规范
1.1.1 代码风格
文件
- JavaScript 文件使用无
BOM的UTF-8编码。 - 在文件结尾处,保留一个空行。
- JavaScript 文件使用无
结构
- 缩进
- 使用
4个空格做为一个缩进层级,不允许使用2个空格 或tab字符。 switch下的case和default必须增加一个缩进层级。
- 使用
- 空格
- 二元运算符两侧必须有一个空格,一元运算符与操作对象之间不允许有空格。
- 用作代码块起始的左花括号
{前必须有一个空格。 if / else / for / while / function / switch / do / try / catch / finally关键字后,必须有一个空格。- 在对象创建时,属性中的
:之后必须有空格,:之前不允许有空格。 - 函数声明、具名函数表达式、函数调用中,函数名和
(之间不允许有空格。 ,和;前不允许有空格。如果不位于行尾,,和;后必须跟一个空格。- 在函数调用、函数声明、括号表达式、属性访问、
if / for / while / switch / catch等语句中,()和[]内紧贴括号部分不允许有空格。 - 单行声明的数组与对象,如果包含元素,
{}和[]内紧贴括号部分不允许包含空格. - 行尾不得有多余的空格。
- 换行
- 每个独立语句结束后必须换行。
- 每行不得超过
120个字符。 - 运算符处换行时,运算符必须在新行的行首。
- 在函数声明、函数表达式、函数调用、对象创建、数组创建、
for语句等场景中,不允许在,或;前换行。 - 不同行为或逻辑的语句集,使用空行隔开,更易阅读。
- 在语句的行长度超过
120时,根据逻辑条件合理缩进。 - 对于
if...else...、try...catch...finally等语句,推荐使用在}号后添加一个换行 的风格,使代码层次结构更清晰,阅读性更好。
- 语句
- 不得省略语句结束的分号。
- 在
if / else / for / do / while语句中,即使只有一行,也不得省略块{...}。 - 函数定义结束不允许添加分号。
IIFE必须在函数表达式外添加(,非IIFE不得在函数表达式外添加(。
- 缩进
命名
变量使用Camel命名法。常量使用全部字母大写,单词间下划线分隔的命名方式。函数使用Camel命名法。- 函数的
参数使用Camel命名法。 类使用Pascal命名法。- 类的
方法/属性使用Camel命名法。 枚举变量使用Pascal命名法,枚举的属性使用全部字母大写,单词间下划线分隔的命名方式。命名空间使用Camel命名法。- 由多个单词组成的缩写词,在命名中,根据当前命名法和出现的位置,所有字母的大小写与首字母的大小写保持一致。
类名使用名词。函数名使用动宾短语。boolean类型的变量使用is或has开头。Promise对象用动宾短语的进行时表达。
注释
单行注释
必须独占一行。
//后跟一个空格,缩进与下一行被注释说明的代码一致。多行注释
避免使用
/*...*/这样的多行注释。有多行注释内容时,使用多个单行注释。文档化注释
为了便于代码阅读和自文档化,以下内容必须包含以
/**...*/形式的块注释中。文档注释前必须空一行。
自文档化的文档说明 what,而不是 how。
类型定义
- 类型定义都是以
{开始, 以}结束。 - 对于基本类型 {string}, {number}, {boolean},首字母必须小写。
- 类型定义都是以
文件注释
- 文件顶部必须包含文件注释,用
@file标识文件说明。 - 文件注释中可以用
@author标识开发者信息。
- 文件顶部必须包含文件注释,用
命名空间注释
命名空间使用
@namespace标识。
类注释
- 使用
@class标记类或构造函数。 - 使用
@extends标记类的继承信息。 - 使用包装方式扩展类成员时, 必须通过
@lends进行重新指向。 - 类的属性或方法等成员信息不是
public的,应使用@protected或@private标识可访问性。
- 使用
函数/方法注释
- 函数/方法注释必须包含函数说明,有参数和返回值时必须使用注释标识。
- 参数和返回值注释必须包含类型信息,且不允许省略参数的说明。
- 当函数是内部函数,外部不可访问时,可以使用
@inner标识。 - 对 Object 中各项的描述, 必须使用
@param标识。 - 重写父类方法时, 应当添加
@override标识。如果重写的形参个数、类型、顺序和返回值类型均未发生变化,可省略@param、@return,仅用@override标识,否则仍应作完整注释。
事件注释
- 必须使用
@event标识事件,事件参数的标识与方法描述的参数标识相同。 - 在会广播事件的函数前使用
@fires标识广播的事件,在广播事件代码前使用@event标识事件。 - 对于事件对象的注释,使用
@param标识,生成文档时可读性更好。
- 必须使用
常量注释
常量必须使用
@const标记,并包含说明和类型信息。复杂类型注释
对于类型未定义的复杂结构的注释,可以使用
@typedef标识来定义。AMD 模块注释
- AMD 模块使用
@module或@exports标识。 - 对于已使用
@module标识为 AMD模块 的引用,在namepaths中必须增加module:作前缀。 - 对于类定义的模块,可以使用
@alias标识构建函数。 - 多模块定义时,可以使用
@exports标识各个模块。 - 对于 exports 为 Object 的模块,可以使用
@namespace标识。 - 对于 exports 为类名的模块,使用
@class和@exports标识。
- AMD 模块使用
1.1.2 语言特性
变量
- 变量、函数在使用前必须先定义。
- 每个
var只能声明一个变量。 - 变量必须
即用即声明,不得在函数或其它形式的代码块起始位置统一声明所有变量。
条件
- 在 Equality Expression 中使用类型严格的
===。仅当判断null或undefined时,允许使用== null。 - 尽可能使用简洁的表达式。
- 按执行频率排列分支的顺序。
- 如果函数或全局中的
else块后没有任何语句,可以删除else。
- 在 Equality Expression 中使用类型严格的
循环
- 不要在循环体中包含函数表达式,事先将函数提取到循环体外。
- 对循环内多次使用的不变值,在循环外用变量缓存。
类型
类型检测
类型检测优先使用
typeof。对象类型检测使用instanceof。null或undefined的检测使用== null。类型转换
- 转换成
string时,使用+ ''。 - 转换成
number时,通常使用+。 string转换成number,要转换的字符串结尾包含非数字并期望忽略时,使用parseInt。- 使用
parseInt时,必须指定进制。 - 转换成
boolean时,使用!!。 number去除小数点,使用Math.floor/Math.round/Math.ceil,不使用parseInt。
- 转换成
字符串
- 字符串开头和结束使用单引号
'。 - 使用
数组或+拼接字符串。 - 使用字符串拼接的方式生成HTML,需要根据语境进行合理的转义。
- 复杂的数据到视图字符串的转换过程,选用一种模板引擎。
- 字符串开头和结束使用单引号
对象
- 使用对象字面量
{}创建新Object。 - 对象创建时,如果一个对象的所有
属性均可以不添加引号,建议所有属性不添加引号。 - 对象创建时,如果任何一个
属性需要添加引号,则所有属性建议添加'。 - 不允许修改和扩展任何原生对象和宿主对象的原型。
- 属性访问时,尽量使用
.。 for in遍历对象时, 使用hasOwnProperty过滤掉原型中的属性。
- 使用对象字面量
数组
- 使用数组字面量
[]创建新数组,除非想要创建的是指定长度的数组。 - 不因为性能的原因自己实现数组排序功能,尽量使用数组的
sort方法。 - 清空数组使用
.length = 0。
- 使用数组字面量
函数
函数长度
一个函数的长度控制在
50行以内。参数设计
- 一个函数的参数控制在
6个以内。 - 通过
options参数传递非数据输入型参数。
- 一个函数的参数控制在
闭包
- 在适当的时候将闭包内大对象置为
null。 - 使用
IIFE避免Lift 效应。
- 在适当的时候将闭包内大对象置为
空函数
- 空函数不使用
new Function()的形式。 - 对于性能有高要求的场合,建议存在一个空函数的常量,供多处使用共享。
- 空函数不使用
9.面向对象
- 类的继承方案,实现时需要修正
constructor。 - 属性在构造函数中声明,方法在原型中声明。
- 自定义事件的
事件名必须全小写。 - 自定义事件只能有一个
event参数。如果事件需要传递较多信息,应仔细设计事件对象。 - 设计自定义事件时,应考虑禁止默认行为。
动态特性
eval
- 避免使用直接
eval函数。 - 尽量避免使用
eval函数。
- 避免使用直接
动态执行代码。
使用
new Function执行动态代码。with
尽量不要使用
with。对象属性
避免修改外部传入的对象。
1.1.3 浏览器环境
模块化
AMD
- 使用
AMD作为模块定义。 - 模块
id必须符合标准。
- 使用
define
- 定义模块时不要指明
id和dependencies。 - 使用
return来返回模块定义。
- 定义模块时不要指明
require
全局运行环境中,
require必须以async require形式调用。
DOM
元素获取
- 对于单个元素,尽可能使用
document.getElementById获取,避免使用document.all。 - 对于多个元素的集合,尽可能使用
context.getElementsByTagName获取。其中context可以为document或其他元素。指定tagName参数为*可以获得所有子元素。 - 遍历元素集合时,尽量缓存集合长度。如需多次操作同一集合,则应将集合转为数组。
- 对于单个元素,尽可能使用
样式获取
获取元素实际样式信息时,应使用
getComputedStyle或currentStyle。样式设置
- 尽可能通过为元素添加预定义的 className 来改变元素样式,避免直接操作 style 设置。
- 通过 style 对象设置元素样式时,对于带单位非 0 值的属性,不允许省略单位。
DOM 操作
- 操作
DOM时,尽量减少页面reflow。 - 尽量减少
DOM操作。
- 操作
DOM 事件
- 优先使用
addEventListener / attachEvent绑定事件,避免直接在 HTML 属性中或 DOM 的expando属性绑定事件处理。 - 使用
addEventListener时第三个参数使用false。 - 在没有事件自动管理的框架支持下,应持有监听器函数的引用,在适当时候(元素释放、页面卸载等)移除添加的监听器。
- 优先使用
1.2 后端代码规范
1.2.1 编程规约
1.2.1.1 命名风格
- 代码中的命名均不能以下划线或美元符号开始,也不能以下划线或美元符号结束。
- 代码中的命名严禁使用拼音与英文混合的方式,更不允许直接使用中文的方式。
- 类名使用 UpperCamelCase 风格,必须遵从驼峰形式,但以下情形例外:DO / BO / DTO / VO / AO
- 方法名、参数名、成员变量、局部变量都统一使用 lowerCamelCase 风格,必须遵从驼峰形式。
例:localValue / getHttpMessage() / inputUserId
- 常量命名全部大写,单词间用下划线隔开,力求语义表达完整清楚,不要嫌名字长。
- 抽象类命名使用 Abstract 或 Base 开头;异常类命名使用 Exception 结尾;测试类命名以它要测试的类的名称开始,以 Test 结尾。
- 中括号是数组类型的一部分,数组定义如下:String[] args;
- POJO 类中布尔类型的变量,都不要加 is,否则部分框架解析会引起序列化错误。
- 包名统一使用小写,点分隔符之间有且仅有一个自然语义的英语单词。包名统一使用单数形式,但是类名如果有复数含义,类名可以使用复数形式。
- 杜绝完全不规范的缩写,避免望文不知义。
- 为了达到代码自解释的目标,任何自定义编程元素在命名时,使用尽量完整的单词组合来表达其意。
- 如果模块、接口、类、方法使用了设计模式,在命名时体现出具体模式。
- 接口类中的方法和属性不要加任何修饰符号(public 也不要加),保持代码的简洁性,并加上有效的 Javadoc 注释。尽量不要在接口里定义变量,如果一定要定义变量,肯定是 与接口方法相关,并且是整个应用的基础常量。
- 接口和实现类的命名
对于 Service 和 DAO 类,基于 SOA 的理念,暴露出来的服务一定是接口,内部的实现类用 Impl 的后缀与接口区别。
例:CacheServiceImpl 实现 CacheService 接口。
如果是形容能力的接口名称,取对应的形容词做接口名(通常是–able 的形式)。
例:AbstractTranslator 实现 Translatable。
- 枚举类名建议带上 Enum 后缀,枚举成员名称需要全大写,单词间用下划线隔开。
- 各层命名规约:
- Service/DAO 层方法命名规约
- 获取单个对象的方法用 get 做前缀。
- 获取多个对象的方法用 list 做前缀。
- 获取统计值的方法用 count 做前缀。
- 插入的方法用 save/insert 做前缀。
- 删除的方法用 remove/delete 做前缀。
- 修改的方法用 update 做前缀。
- 领域模型命名规约
- 数据对象:xxxDO,xxx 即为数据表名。
- 数据传输对象:xxxDTO,xxx 为业务领域相关的名称。
- 展示对象:xxxVO,xxx 一般为网页名称。
- POJO 是 DO/DTO/BO/VO 的统称,禁止命名成 xxxPOJO。
- Service/DAO 层方法命名规约
1.2.1.2 常量定义
- 不允许任何魔法值(即未经定义的常量)直接出现在代码中。
- long或者Long初始赋值时,使用大写的L,不能是小写的l,小写容易跟数字1混 淆,造成误解。
- 不要使用一个常量类维护所有常量,按常量功能进行归类,分开维护。
- 常量的复用层次有五层:跨应用共享常量、应用内共享常量、子工程内共享常量、包 内共享常量、类内共享常量。
- 跨应用共享常量:放置在二方库中,通常是client.jar中的constant目录下。
- 应用内共享常量:放置在一方库中,通常是modules中的constant目录下。
- 子工程内部共享常量:即在当前子工程的constant目录下。
- 包内共享常量:即在当前包下单独的constant目录下。
- 类内共享常量:直接在类内部private static final定义。
- 如果变量值仅在一个范围内变化,且带有名称之外的延伸属性,定义为枚举类。下面 正例中的数字就是延伸信息,表示星期几。
例:public Enum { M0NDAY(1), TUESDAY(2), WEDNESDAY©), THURSDAY(4), FRIDAY(5), SATURDAY(6), SUNDAY(7);}
1.2.1.3 代码格式
- 大括号的使用约定。如果是大括号内为空,则简洁地写成{}即可,不需要换行;如果 是非空代码块则:
- 左大括号前不换行。
- 左大括号后换行。
- 右大括号前换行。
- 右大括号后还有else等代码则不换行;表示终止的右大括号后必须换行。
- 左小括号和字符之间不出现空格;同样,右小括号和字符之间也不出现空格。
- if/for/while/switch/do等保留字与括号之间都必须加空格。
- 任何二目、三目运算符的左右两边都需要加一个空格。 说明:运算符包括赋值运算符=、逻辑运算符&&、加减乘除符号等。
- 采用4个空格缩进,禁止使用tab字符。
说明:如果使用tab缩进,必须设置1个tab为4个空格。IDEA设置tab为4个空格时, 请勿勾选 Use tab character;而在 eclipse 中,必须勾选 insert spaces for tabs
例:(涉及1-5点)
public static void main(String[] args) {
//缩进4个空格
String say = "hello";
//运算符的左右必须有一个空格
int flag = 0;
//关键词if与括号之间必须有一个空格,括号内的f与左括号,0与右括号不需要空格
if (flag == 0) (
System.out.println(say);
)
//左大括号前加空格且不换行;左大括号后换行
if (flag == 1) (
System.out.println("world");
//右大括号前换行,右大括号后有else,不用换行
) else ( System.out.println("ok");
//在右大括号后直接结束,则必须换行
)
)
- 单行字符数限制不超过120个,超出需要换行
- 方法参数在定义和传入时,多个参数逗号后边必须加空格。
- IDE的text file encoding设置为UTF-8
- 方法体内的执行语句组、变量的定义语句组、不同的业务逻辑之间或者不同的语义之间插入一个空行。相同业务逻辑和语义之间不需要插入空行。
1.2.1.4 OOP规约
- 避免通过一个类的对象引用访问此类的静态变量或静态方法,无谓增加编译器解析成本,直接用类名来访问即可。
- 外部正在调用或者二方库依赖的接口,不允许修改方法签名,避免对接口调用方产生影响。
- 当一个类有多个构造方法,或者多个同名方法,这些方法应该按顺序放置在一起, 便于阅读。
- 类内方法定义顺序依次是:公有方法或保护方法 > 私有方法> getter/setter方法。
- final可以声明类、成员变量、方法、以及本地变量,下列情况使用final关键字:
- 不允许被继承的类,如:String类。
- 不允许修改引用的域对象,如:POJO类的域变量。
- 不允许被重写的方法,如:POJO类的setter方法。
- 不允许运行过程中重新赋值的局部变量。
- 避免上下文重复使用一个变量,使用final描述可以强制重新定义一个变量,方便更好 地进行重构。
- 慎用Object的clone方法来拷贝对象。
- 类成员与方法访问控制从严:
- 如果不允许外部直接通过new来创建对象,那么构造方法必须是private。
- 工具类不允许有public或default构造方法。
- 类非static成员变量并且与子类共享,必须是protected。
- 类非static成员变量并且仅在本类使用,必须是private。
- 类static成员变量如果仅在本类使用,必须是private。
- 若是static成员变量,必须考虑是否为final。
- 类成员方法只供类内部调用,必须是private。
- 类成员方法只对继承类公开,那么限制为protectedo
1.2.1.5 控制语句
- 在一个switch块内,每个case要么通过break/return等来终止,要么注释说明程 序将继续执行到哪一个case为止;在一个switch块内,都必须包含一个default语句并且 放在最后,即使它什么代码也没有。
- 在if/else/for/while/do语句中必须使用大括号。即使只有一行代码,避免采用单行的编码方式:if (condition) statements;
- 表达异常的分支时,少用if-else方式
- 除常用方法(如getXxx/isXxx)等外,不要在条件判断中执行其它复杂的语句,将复 杂逻辑判断的结果赋值给一个有意义的布尔变量名,以提高可读性。
- 循环体中的语句要考量性能,以下操作尽量移至循环体外处理,如定义对象、变量、 获取数据库连接,进行不必要的try-catch操作(这个try-catch是否可以移至循环体外)。
- 接口入参保护,这种场景常见的是用于做批量操作的接口。
- 下列情形,需要进行参数校验:
- 调用频次低的方法。
- 执行时间开销很大的方法。此情形中,参数校验时间几乎可以忽略不计,但如果因为参 数错误导致中间执行回退,或者错误,那得不偿失。
- 需要极高稳定性和可用性的方法。
- 对外提供的开放接口,不管是RPC/API/HTTP接口。
- 敏感权限入口。
- 下列情形,不需要进行参数校验:
- 极有可能被循环调用的方法。但在方法说明里必须注明外部参数检查要求。
- 底层调用频度比较高的方法。毕竟是像纯净水过滤的最后一道,参数错误不太可能到底 层才会暴露问题。一般DAO层与Service层都在同一个应用中,部署在同一台服务器中,所 以DAO的参数校验,可以省略。
- 被声明成private只会被自己代码所调用的方法,如果能够确定调用方法的代码传入参 数已经做过检查或者肯定不会有问题,此时可以不校验参数。
1.2.1.6 注释规约
- 类、类属性、类方法的注释必须使用Javadoc规范,不得使用 // xxx方式。
- 所有的抽象方法(包括接口中的方法)必须要用Javadoc注释、除了返回值、参数、 异常说明外,还必须指出该方法做什么事情,实现什么功能。
- 所有的类都必须添加创建者和创建日期。
- 方法内部单行注释,在被注释语句上方另起一行,使用//注释。方法内部多行注释使用/* */注释,注意与代码对齐。
- 所有的枚举类型字段必须要有注释,说明每个数据项的用途。
- 与其“半吊子”英文来注释,不如用中文注释把问题说清楚。专有名词与关键字保持 英文原文即可。
- 代码修改的同时,注释也要进行相应的修改,尤其是参数、返回值、异常、核心逻辑 等的修改。
- 谨慎注释掉代码。在上方详细说明,而不是简单地注释掉。如果无用,则删除。 说明:代码被注释掉有两种可能性:1)后续会恢复此段代码逻辑。2)永久不用。前者如果没 有备注信息,难以知晓注释动机。后者建议直接删掉(代码仓库保存了历史代码)。
- 对于注释的要求:
- 能够准确反应设计思想和代码逻辑;
- 能够描述业务含 义,使别的程序员能够迅速了解到代码背后的信息。
- 好的命名、代码结构是自解释的,注释力求精简准确、表达到位。避免出现注释的 一个极端:过多过滥的注释,代码的逻辑一旦修改,修改注释是相当大的负担。
- 特殊注释标记,请注明标记人与标记时间。注意及时处理这些标记,通过标记扫描, 经常清理此类标记。线上故障有时候就是来源于这些标记处的代码。
待办事宜(TODO):(标记人,标记时间,[预计处理时间])
表示需要实现,但目前还未实现的功能。这实际上是一个Javadoc的标签,目前的Javadoc 还没有实现,但已经被广泛使用。只能应用于类,接口和方法(因为它是一个Javadoc标签)。
错误,不能工作(FIXME):(标记人,标记时间,[预计处理时间])
1.2.1.7 其它
- 在使用正则表达式时,利用好其预编译功能,可以有效加快正则匹配速度。
- velocity调用POJO类的属性时,建议直接使用属性名取值即可,模板引擎会自动按 规范调用POJO的getXxx(),如果是boolean基本数据类型变量(boolean命名不需要加is 前缀),会自动调用isXxx()方法。
- 后台输送给页面的变量必须加$!{var}—中间的感叹号。 说明:如果var = null或者不存在,那么${var}会直接显示在页面上。
- 注意Math . random()这个方法返回是double类型,注意取值的范围0<x<1 (能够 取到零值,注意除零异常),如果想获取整数类型的随机数,不要将x放大10的若干倍然后 取整,直接使用Random对象的nextInt或者nextLong方法。
- 获取当前毫秒数 System.currentTimeMillis();而不是 new Date() .getTime(); 说明:如果想获取更加精确的纳秒级时间值,使用System.nanoTime()的方式。在JDK8中, 针对统计时间等场景,推荐使用Instant类。
- 不要在视图模板中加入任何复杂的逻辑。
- 任何数据结构的构造或初始化,都应指定大小,避免数据结构无限增长吃光内存。
- 及时清理不再使用的代码段或配置信息。
1.2.2 异常处理
- Java类库中定义的一类RuntimeException可以通过预先检查进行规避,而不应该 通过 catch 来处理。
- 对大段代码进行try-catch,这是不负责任的表现。catch时请分清稳定代码和非稳 定代码,稳定代码指的是无论如何不会出错的代码。对于非稳定代码的catch尽可能进行区分 异常类型,再做对应的异常处理。
- 捕获异常是为了处理它,不要捕获了却什么都不处理而抛弃之,如果不想处理它,请 将该异常抛给它的调用者。最外层的业务使用者,必须处理异常,将其转化为用户可以理解的 内容。
- 有try块放到了事务代码中,catch异常后,如果需要回滚事务,一定要注意手动回 滚事务。
- finally块必须对资源对象、流对象进行关闭,有异常也要做try-catch。
- 不能在finally块中使用return,finally块中的return返回后方法结束执行,不 会再执行try块中的return语句。
- 捕获异常与抛异常,必须是完全匹配,或者捕获异常是抛异常的父类。 说明:如果预期对方抛的是绣球,实际接到的是铅球,就会产生意外情况。
- 方法的返回值可以为null,不强制返回空集合,或者空对象等,必须添加注释充分 说明什么情况下会返回null值。调用方需要进行null判断防止NPE问题。
- 防止NPE,是程序员的基本修养,注意NPE产生的场景:
- 返回类型为基本数据类型,return包装数据类型的对象时,自动拆箱有可能产生NPE。
- 数据库的查询结果可能为null。
- 集合里的元素即使isNotEmpty,取出的数据元素也可能为null。
- 远程调用返回对象时,一律要求进行空指针判断,防止NPE。
- 对于Session中获取的数据,建议NPE检查,避免空指针。
- 级联调用obj.getA().getB().getC(); 一连串调用,易产生NPE。
- 定义时区分unchecked / checked异常,避免直接抛出new RuntimeException(), 更不允许抛出Exception或者Throwable,应使用有业务含义的自定义异常。推荐业界已定义 过的自定义异常,如:DAOException / ServiceException 等。
- 避免出现重复的代码。
1.2.3 单元测试
- 好的单元测试必须遵守AIR原则。
- A: Automatic (自动化)
- I: Independent (独立性)
- R: Repeatable (可重复)
- 单元测试应该是全自动执行的,并且非交互式的。测试框架通常是定期执行的,执行 过程必须完全自动化才有意义。输出结果需要人工检查的测试不是一个好的单元测试。单元测 试中不准使用System.out来进行人肉验证,必须使用assert来验证。
- 保持单元测试的独立性。为了保证单元测试稳定可靠且便于维护,单元测试用例之间 决不能互相调用,也不能依赖执行的先后次序。
- 单元测试是可以重复执行的,不能受到外界环境的影响。
- 对于单元测试,要保证测试粒度足够小,有助于精确定位问题。单测粒度至多是类级 另U, 一般是方法级别。
- 核心业务、核心应用、核心模块的增量代码确保单元测试通过。
- 单元测试代码必须写在如下工程目录:src/test/java,不允许写在业务代码目录下。 说明:源码构建时会跳过此目录,而单元测试框架默认是扫描此目录。
- 单元测试的基本目标:语句覆盖率达到70%;核心模块的语句覆盖率和分支覆盖率都 要达到100%
- 编写单元测试代码遵守BCDE原则,以保证被测试模块的交付质量。
- B: Border,边界值测试,包括循环边界、特殊取值、特殊时间点、数据顺序等。
- C: Correct,正确的输入,并得到预期的结果。
- D: Design,与设计文档相结合,来编写单元测试。
- E: Error,强制错误信息输入(如:非法数据、异常流程、非业务允许输入等),并得 到预期的结果。
- 对于数据库相关的查询,更新,删除等操作,不能假设数据库里的数据是存在的, 或者直接操作数据库把数据插入进去,请使用程序插入或者导入数据的方式来准备数据。
- 和数据库相关的单元测试,可以设定自动回滚机制,不给数据库造成脏数据。或者 对单元测试产生的数据有明确的前后缀标识。
- 对于不可测的代码建议做必要的重构,使代码变得可测,避免为了达到测试要求而 书写不规范测试代码。
- 在设计评审阶段,开发人员需要和测试人员一起确定单元测试范围,单元测试最好 覆盖所有测试用例(UC)。
- 单元测试作为一种质量保障手段,不建议项目发布后补充单元测试用例,建议在项 目提测前完成单元测试。
- 为了更方便地进行单元测试,业务代码应避免以下情况:
- 构造方法中做的事情过多。
- 存在过多的全局变量和静态方法。
- 存在过多的外部依赖。
- 存在过多的条件语句。
1.2.4 MySQL数据库
1.2.4.1 建表规约
- 表达是与否概念的字段,必须使用is_xxx的方式命名,数据类型是unsigned tinyint (1表示是,0表示否)。
- 表名、字段名必须使用小写字母或数字,禁止出现数字开头,禁止两个下划线中间只 出现数字。数据库字段名的修改代价很大,因为无法进行预发布,所以字段名称需要慎重考虑。
- 表名不使用复数名词。
- 禁用保留字,如desc、range、match、delayed等,请参考MySQL官方保留字。
- 主键索引名为pk_字段名;唯一索引名为uk_字段名;普通索引名则为idx_字段名。 说明:pk_ 即 primary key; uk_ 即 unique key; idx_ 即 index 的简称。
- 小数类型为decimal,禁止使用float和double。
- 如果存储的字符串长度几乎相等,使用char定长字符串类型。
- varchar是可变长字符串,不预先分配存储空间,长度不要超过5000,如果存储长 度大于此值,定义字段类型为text,独立出来一张表,用主键来对应,避免影响其它字段索 引效率。
- 表必备三字段:id, gmt_create, gmt_modified。
- 表的命名最好是加上“业务名称_表的作用”。
- 库名与应用名称尽量一致。
- 如果修改字段含义或对字段表示的状态追加时,需要及时更新字段注释。
- 字段允许适当冗余,以提高查询性能,但必须考虑数据一致。冗余字段应遵循:
- 不是频繁修改的字段。
- 不是varchar超长字段,更不能是text字段。
- 单表行数超过500万行或者单表容量超过2GB,才推荐进行分库分表。
- 合适的字符存储长度,不但节约数据库表空间、节约索引存储,更重要的是提升检 索速度。
1.2.4.2 索引规约
- 业务上具有唯一特性的字段,即使是多个字段的组合,也必须建成唯一索引。
- 超过三个表禁止join。需要join的字段,数据类型必须绝对一致;多表关联查询时, 保证被关联的字段需要有索引。
- 在varchar字段上建立索引时,必须指定索引长度,没必要对全字段建立索引,根据 实际文本区分度决定索引长度即可。
- 页面搜索严禁左模糊或者全模糊,如果需要请走搜索引擎来解决。
- 如果有order by的场景,请注意利用索引的有序性。order by最后的字段是组合 索引的一部分,并且放在索引组合顺序的最后,避免出现file_sort的情况,影响查询性能。
- 利用覆盖索引来进行查询操作,避免回表。
- 利用延迟关联或者子查询优化超多分页场景。
- SQL性能优化的目标:至少要达到range级别,要求是ref级别,如果可以是consts 最好。
- 建组合索引的时候,区分度最高的在最左边。
- 防止因字段类型不同造成的隐式转换,导致索引失效。
- 创建索引时避免有如下极端误解:
- 宁滥勿缺。认为一个查询就需要建一个索引。
- 宁缺勿滥。认为索引会消耗空间、严重拖慢更新和新增速度。
- 抵制惟一索引。认为业务的惟一性一律需要在应用层通过“先查后插”方式解决。
1.2.4.3 SQL语句
不要使用count(列名)或count(常量)来替代count(),count()是SQL92定义的 标准统计行数的语法,跟数据库无关,跟NULL和非NULL无关。
count(distinct col)计算该列除NULL之外的不重复行数,注意count(distinct col1, col2)如果其中一列全为NULL,那么即使另一列有不同的值,也返回为0。
当某一列的值全是NULL时,count(col)的返回结果为0,但sum(col)的返回结果为 NULL,因此使用sum()时需注意NPE问题。
使用ISNULL()来判断是否为NULL值。
在代码中写分页查询逻辑时,若count为0应直接返回,避免执行后面的分页语句。
不得使用外键与级联,一切外键概念必须在应用层解决。
禁止使用存储过程,存储过程难以调试和扩展,更没有移植性。
数据订正时,删除和修改记录时,要先select,避免出现误删除,确认无误才能执 行更新语句。
in操作能避免则避免,若实在避免不了,需要仔细评估in后边的集合元素数量,控 制在1。。。个之内。
如果有全球化需要,所有的字符存储与表示,均以utf-8编码,注意字符统计函数 的区别。
如果需要存储表情,那么选择utfmb4来进行存储,注意它与utf-8编码的区别。
TRUNCATE TABLE比DELETE速度快,且使用的系统和事务日志资源少,但TRUNCATE 无事务且不触发trigger,有可能造成事故,故不建议在开发代码中使用此语句。
1.2.4.4 ORM映射
在表查询中,一律不要使用星号作为查询的字段列表,需要哪些字段必须明确写明。
POJO类的布尔属性不能加is,而数据库字段必须加is_,要求在resultMap中进行 字段与属性之间的映射。
不要用resultclass当返回参数,即使所有类属性名与数据库字段一一对应,也需 要定义;反过来,每一个表也必然有一个与之对应。
sql.xml配置参数使用:#{},#param#不要使用${}此种方式容易出现SQL注入。
iBATIS 自带的 queryForList(String statementName, int start, int size)不推 荐使用。
不允许直接拿HashMap与Hashtable作为查询结果集的输出。
更新数据表记录时,必须同时更新记录对应的gmt_modified字段值为当前时间。
不要写一个大而全的数据更新接口。传入为POJO类,不管是不是自己的目标更新字 段,都进行叩date table set c1=value1,c2=value2, c3=value3;这是不对的。执行 SQL 时,不要更新无改动的字段,一是易出错;二是效率低;三是增加binlog存储。
@Transactional事务不要滥用。事务会影响数据库的QPS,另外使用事务的地方需 要考虑各方面的回滚方案,包括缓存回滚、搜索引擎回滚、消息补偿、统计修正等。
<isEqual>中的compareValue是与属性值对比的常量,一般是数字,表示相等时带 上此条件;<isNotEmpty>表示不为空且不为null时执行;<isNotNull>表示不为null值时 执行。
相关推荐
mongodb-linux-x86_64-ubuntu2004-8.0.13.tgz
mongodb-linux-x86_64-ubuntu2004-8.0.13
chromedriver-linux64-159.0.8135.0(Canary).zip
chromedriver-linux64-159.0.8135.0(Canary).zip
三相四桥臂电压不对称跌落补偿动态电压恢复器DVR(Simulink仿真实现)
内容概要:本文围绕三相四桥臂动态电压恢复器(DVR)在电压不对称跌落情况下的补偿能力展开,重点介绍了基于Simulink平台构建的仿真模型,用于研究和验证DVR对电网电压不平衡的动态补偿性能。系统采用三相四桥臂逆变器结构,利用其独立的中性线控制能力有效处理零序分量,结合多准PR(Proportional Resonant)控制策略实现对正负序电压分量的精确跟踪与快速响应,从而提升在不平衡负载或电网故障条件下DVR的补偿精度与系统稳定性。文中提供了完整的仿真模型及相关参考文献,涵盖控制算法设计、系统建模与参数整定等关键技术环节,适用于复杂电能质量问题的研究与教学演示。; 适合人群:电气工程、电力电子与电力系统相关专业的研究生、科研人员及从事电能质量治理的技术工程师;具备一定的电路理论、自动控制原理和Simulink仿真基础者更佳。; 使用场景及目标:①研究动态电压恢复器在三相电压不对称跌落工况下的补偿机制与控制策略;②掌握三相四桥臂逆变器在不平衡条件下的建模与控制方法;③深入理解多准PR控制器在正负序分离控制中的应用,提升对电能质量调节装置的设计与仿真能力; 阅读建议:建议结合提供的参考文献与说明文档,逐步搭建并调试Simulink仿真模型,重点关注控制器参数设计与系统动态响应特性,通过设置不同类型的电压跌落场景(如单相跌落、两相短路等)来验证控制策略的有效性与鲁棒性。
【MIMO无线编码】在瑞利衰落信道中比较2x2和4x4的BPSK调制系统(Matlab代码实现)
内容概要:本文通过Matlab代码实现,在瑞利衰落信道环境下对2x2和4x4 MIMO系统采用BPSK调制的性能进行仿真与比较,重点分析不同天线配置下的误码率(BER)表现,旨在探讨MIMO系统中天线数量增加对无线通信可靠性和传输性能的影响。研究涵盖了信道建模、信号调制解调、接收端检测算法等关键环节,并通过蒙特卡洛仿真获得统计结果,直观展示了MIMO技术在对抗多径衰落方面的优势。; 适合人群:具备通信原理基础知识和Matlab编程能力的高校学生、科研人员及从事无线通信系统设计的工程技术人员。; 使用场景及目标:①理解MIMO系统在瑞利衰落信道中的工作原理与性能评估方法;②掌握BPSK调制解调及典型MIMO检测技术的Matlab实现;③通过仿真对比不同规模MIMO系统的性能差异,为系统设计提供参考依据。; 阅读建议:建议读者结合Matlab代码逐段运行并观察仿真结果,深入理解各模块功能,同时可尝试修改参数(如信噪比范围、仿真次数、天线数目)以探究其对系统性能的影响,从而加深对MIMO无线编码技术的认知。
44-基于STC89C52粮库远程无线监测系统设计(设计说明书+全套资料).rar
项目44-基于STC89C52粮库远程无线监测系统设计 资料包括Proteus仿真+Keil程序+Altium Designer原理图+软件安装包+参考设计说明书+答辩PPT+设计流程图,保证资料完整性! 功能: (1)本设计以STC89C52单片机为控制核心,实现对粮库远程无线监测系统的稳定控制与高效管理。 (2)采用DHT11传感器检测温湿度,精准感知粮库内环境参数,为粮食储存状态监测提供关键数据。 (3)配备LCD1602显示屏实时显示温湿度信息,方便管理人员直观了解粮库环境,及时做出决策。 (4)设有无线模块实现远程数据传输,可远程监控粮库状态,提升管理效率,降低人工巡检成本。 (5)利用蜂鸣器与LED灯作为报警装置,当温湿度超出阈值时及时报警,资料助力学生掌握设计。


