版本号 | 更新说明 | 更新人 | 更新时间 |
---|---|---|---|
1.0 | 建立文档 | Reed | 2022-05-19 |
方法名、参数名、成员变量、局部变量都统一使用 lowerCamelCase 风格,必须遵从
驼峰形式。杜绝完全不规范的缩写,避免望文不知义。
反例:AbstractClass“缩写”命名成 AbsClass;condition“缩写”命名成 condi,此类随
意缩写严重降低了代码的可阅读性。
常量命名全部大写,单词间用下划线隔开,力求语义表达完整清楚,不要嫌名字长。
正例:MAX_STOCK_COUNT
反例:MAX_COUNT
全局变量尽量做到见名知意,并且必须增加注释说明;局部变量看情况而定
前后端代码目录结构是否保持对称?
命名规则是否与公司的规范保持一致?
文件名是否遵循项目组约定?
是否存在重名问题?
前端的变量、方法,使用以交易名称的组合,例如:modify_xxx;尽量避免方法名带数字,例如: xxx1
类名是否存在重名问题?(自己实现的类尽量不要和别人的类重名,尽管不在同一个包下。特别注意子类和父类重名的情况。)
包名统一使用小写
POJO 类中布尔类型的变量,都不要加 is,否则部分框架解析会引起序列化错误。
反例:定义为基本数据类型 Boolean isDeleted;的属性,它的方法也是 isDeleted(),部分
框架在反向解析的时候,“以为”对应的属性名称是 deleted,导致属性获取不到,进而抛出异
常。
项目分层
Action:接收前端请求、处理抛出异常、参数校验
Service:逻辑处理
Dao:和数据库交互
Adapter:和外部接口交互
类注释是否完整及正确?(用途、作者、版本、时间等信息)
注释是否较清晰且必要?
对于注释的要求:
复杂的分支流程是否已经被注释?复杂的逻辑代码是否有比较详细的注释说明。
函数是否已经有注释?文件,类(含接口,枚举等),成员变量,方法前需要有JAVADOC的注释、除了返回值、参数、异常说明外,还必须指出该方法做什么事情,实现什么功能。
方法内部单行注释,在被注释语句上方另起一行,使用//注释。方法内部多行注释
使用/* */注释,注意与代码对齐。
所有的枚举类型字段必须要有注释,说明每个数据项的用途。
谨慎注释掉代码。在上方详细说明,而不是简单地注释掉。如果无用,则删除。
说明:代码被注释掉有两种可能性:
后续会恢复此段代码逻辑。
永久不用。
前者如果没有备注信息,难以知晓注释动机。后者建议直接删掉(代码仓库保存了历史代码)。
代码修改的同时,注释也要进行相应的修改,尤其是参数、返回值、异常、核心逻辑
等的修改。修改时需要标注修改人、修改时间、修改内容
正例:// 修改内容 modify by Reed 20220519
所有的代码必须进行格式化,以保证样式整齐,便于查看
左小括号和字符之间不出现空格;同样,右小括号和字符之间也不出现空格
正例:if (a == b)
反例:if (空格 a == b 空格)
任何二目、三目运算符的左右两边都需要加一个空格。
正例:a ? b : c;
运算符的左右必须有一个空格 (说明:运算符包括赋值运算符=、逻辑运算符&&、加减乘除符号等)
int flag = 0;
注释的双斜线与注释内容之间有且仅有一个空格。
正例:// 注释内容,注意在//和注释内容之间有一个空格。
方法参数在定义和传入时,多个参数逗号后边必须加空格。
正例:method(“a”, “b”, “c”);
方法体内的执行语句组、变量的定义语句组、不同的业务逻辑之间或者不同的语义
之间插入一个空行。
在 if/else/for/while/do 语句中必须使用大括号。即使只有一行代码,避免采用
单行的编码方式:if (condition) statements;
正例:
if(){
} else if(){
}
常数变量是否声明为final?
成员变量、局部变量是否在使用前被赋值? 对象初始化为null的对象被调用前必须被重新赋值,如果赋值语句在try块中,调用操作必须在try块中。
对数组的访问是否是安全的?(合法的index取值为[0, MAX_SIZE-1])。
所有判断是否都使用了(常量==变量 或者 常量.equals(变量))的形式?常量放在比较符前可以有效降低比较符写成赋值语句 ,减少空指针异常。
正例:“test”.equals(object);
反例:object.equals(“test”);
对于流操作代码的异常捕获是否有finally操作以关闭流对象?
对浮点数值的相等判断是否是恰当的?严禁使用==直接判断浮点数值 。
是否对象比较都使用了equals?而不是使用==或!=操作。
所有的相同类型的包装类对象之间值的比较,全部使用 equals 方法比较。
说明:对于 Integer var = ? 在-128 至 127 范围内的赋值,Integer 对象是在IntegerCache.cache 产生,会复用已有对象,这个区间内的 Integer 值可以直接使用==进行判断,但是这个区间之外的所有数据,都会在堆上产生,并不会复用已有对象,这是一个大坑,推荐使用 equals 方法进行判断。
包装类做简单预算前是否保证非空?建议进行非空(null != xx)判断,防止发生空指针异常。
对参数的非空判断必须出现在方法调用之前,否则说明前面可能导致空指针或者后者判断是没有必要的,非空判断,默认由调用者提供。
非线程安全的对象是否被正确保证线程安全?
禁止使用class控制页面元素选择,必须要使用id进行唯一性选择
不要在 foreach 循环里进行元素的 remove/add 操作。remove 元素请使用 Iterator
方式,如果并发操作,需要对 Iterator 对象加锁。
// 正例:
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
String item = iterator.next();
if (删除元素的条件) {
iterator.remove();
}
}
循环体中的语句要考量性能,以下操作尽量移至循环体外处理,如定义对象、变量、
获取数据库连接,进行不必要的 try-catch 操作(这个 try-catch 是否可以移至循环体外)。
死循环控制,要有个阀值
if条件判断是否都采用”==”号,是否有写成赋值”=”号。
if条件判断表达式,判断值放在““”==”前面,如:if(“N03”==count)。
入口对象是否都被进行了判断不为空?
入口数据的合法范围是否都被进行了判断?
接口入参保护,这种场景常见的是用于做批量操作的接口。
说明:忽略参数校验可能导致:
是否对有异常抛出的方法都执行了try…catch保护?
是否函数的所有分支都有返回值?
int的返回值是否符合项目组约定?如成功为0000,其他均为失败。
是否对方法返回值对象做了null检查,该返回值定义时是否被初始化?
线程处理函数循环内部是否有异常捕获处理,防止线程抛出异常而退出?
方法对错误的处理是否是恰当的?
异常捕获后是否进行了日志记录或异常继续抛出?
导致结构模糊的连续赋值是否已经修改?如:(a= (b=d+c ))
所有的覆写方法,必须加@Override 注解。
说明:getObject()与 get0bject()的问题。一个是字母的 O,一个是数字的 0,加@Override
可以准确判断是否覆盖成功。另外,如果在抽象类中对方法签名进行修改,其实现类会马上编
译报错
打印信息是否都用日志管理?不要使用System.out.println打印信息。
是否正确使用了日志记录?关键代码日志打印级别正确及不缺失。
在输出对象类型时,必须写 toString 方法。使用 IDE 的中工具:source> generate toString
时,如果继承了另一个 POJO 类,注意在前面加一下 super.toString。
说明:在方法执行抛出异常时,可以直接调用 POJO 的 toString()方法打印其属性值,便于排
查问题
日志记录的Log,Logger对象是否定义为常量?用于记录日志的Log,Logger对象在类中定义必须是static final的,建议定义为private的,因为这类对象初始化比较耗时,不利系统运行。
应用中不可直接使用日志系统(Log4j、Logback)中的 API,而应依赖使用日志框架
SLF4J 中的 API,使用门面模式的日志框架,有利于维护和各个类的日志处理方式统一。
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static final Logger logger = LoggerFactory.getLogger(Abc.class);
对 trace/debug/info 级别的日志输出,必须使用条件输出形式或者使用占位符的方式。
说明:logger.debug("Processing trade with id: " + id + " and symbol: " + symbol);
如果日志级别是 warn,上述日志不会打印,但是会执行字符串拼接操作,如果 symbol 是对象,会执行 toString()方法,浪费了系统资源,执行了上述操作,最终日志却没有打印。
// 正例:(条件)
if (logger.isDebugEnabled()) {
logger.debug("Processing trade with id: " + id + " and symbol: " + symbol);
}
// 正例:(占位符)
logger.debug("Processing trade with id: {} and symbol : {} ", id, symbol);
避免重复打印日志,浪费磁盘空间,务必在 log4j.xml 中设置 additivity=false。
正例:
异常信息应该包括两类信息:案发现场信息和异常堆栈信息。如果不处理,那么通过
关键字 throws 往上抛出。
正例:logger.error(各类参数或者对象 toString + “_” + e.getMessage(), e);
谨慎地记录日志。
生产环境禁止输出 debug 日志;有选择地输出 info 日志;
如果使用 warn 来记录刚上线时的业务行为信息,一定要注意日志输出量的问题,避免把服务器磁盘
撑爆,并记得及时删除这些观察日志。
说明:大量地输出无效日志,不利于系统性能提升,也不利于快速定位错误点。记录日志时请
思考:这些日志真的有人看吗?看到这条日志你能做什么?能不能给问题排查带来好处?
使用 warn 日志级别来记录用户输入参数错误的情况,避免用户投诉时,无所适从。注意日志输出的级别,error 级别只记录系统逻辑出错、异常等重要的错误信息。如非必要,请不要在此场景打出 error 级别。
不允许任何魔法值(即未经定义的常量)直接出现在代码中。
反例:
String key = “Id#taobao_” + tradeId;
cache.put(key, value);
long 或者 Long 初始赋值时,使用大写的 L,不能是小写的 l,小写容易跟数字 1 混
淆,造成误解。
说明:Long a = 2l; 写的是数字的 21,还是 Long 型的 2?
java数组定义如下:String[] args
避免出现重复的代码(Don’t Repeat Yourself),即 DRY 原则。
说明:随意复制和粘贴代码,必然会导致代码的重复,在以后需要修改时,需要修改所有的副
本,容易遗漏。必要时抽取共性方法,或者抽象公共类,甚至是组件化。
正例:一个类中有多个 public 方法,都需要进行数行相同的参数校验操作,这个时候请抽取:
private boolean checkParam(DTO dto) {…}
待办事宜(TODO):( 标记人,标记时间,[预计处理时间])
表示需要实现,但目前还未实现的功能。
类成员与方法访问控制,如果仅在本类使用,必须是 private
UDE部门提供的样式文件不允许进行修改。若需要修改,项目组约定新建文件或者与公司的美工进行同步。
IDE 的 text file encoding 设置为 UTF-8,防止编码格式不一致导致的中文乱码。
在使用平台资源,譬如短信、邮件、电话、下单、支付,必须实现正确的防重放限制,
如数量限制、疲劳度控制、验证码校验,避免被滥刷、资损。
说明:如注册时发送验证码到手机,如果没有限制次数和频率,那么可以利用此功能骚扰到其
它用户,并造成短信平台资源浪费
用户请求传入的任何参数必须做有效性验证。
界面显示的敏感信息是否已经按要求进行脱敏。包括卡号、账号、证件号、金额、姓名等。
说明:查看个人手机号码会显示成:1589119,隐藏中间 4 位,防止隐私泄露。
金额显示是否进行格式化。金额格式化无错误。
ajax请求全部采用异步方法,防止页面卡死。
代码中是否使用Debug参数控制调试代码,在正常逻辑代码中是不存在调试代码?
客户输入的金额有校验机制。
上送交易的金额,没有经过中间处理,提交记账金额与客户输入金额一致
界面只要涉及提交数据到后台的按钮,有防重复提交机制且有效。如页面控制,重复流水号检查机制等。
涉及数据计算的代码确定计算结果无误?Js两数进行计算,类型不对可能导致结果错误。浮点数的精度丢失问题。
页面跳转或与后端请求按钮触发后是否显示遮罩,显示等待提示。