文章目录
背景
早上产品又来找我说改需求,需要支持一个已存在的规则校验。
由于之前不是我开发的,所以我去看了代码逻辑,发现好像和产品说的规则不一致。又上开发环境验证了下,也是不支持该规则的——系统提示校验不过,不能进行该操作。
但产品说现场测试环境可以,还给我演示了下,居然真的可以。
先是怀疑两个环境代码不一致,遂取了该环境的jar反编译看代码,但没发现问题。那问题出在哪里了呢?
代码走查
我们系统对业务规则按钮统一的校验逻辑 简略伪代码 如下:
// 校验并返回错误信息,校验通过则返回null
public String checkBussines(Param param) {
if (!doSomeCheck1) {
// 校验失败 则返回一个错误提示
return MessageSource.getText("CHECK_1_FAIL_CODE");
}
if (!doSomeCheck2) {
// 校验失败 则返回一个错误提示
return MessageSource.getText("CHECK_1_FAIL_CODE");
}
......
// 都校验过 则返回null 前端业务按钮就会亮化
return null;
}
其中错误提示为了满足国际化的要求,是配置在资源文件中的,上面的MessageSource.getText()
就是通过错误码和语言环境设置获取对应的资源文件。
上面的代码,乍看没有什么问题。但是如果MessageSource.getText()
方法如果返回null,那前端不就认为校验通过,要亮化按钮了吗?
那什么时候会返回null?看了MessageSource的实现,发现从资源文件获取不到code对应的message时,就默认返回null。
另外提一嘴,日常我们开发仅维护中文资源文件,交付团队会根据中文资源文件翻译对应语言的资源文件。
现象与原因
回到最初的现象本身,相同数据,相同代码,现场环境是校验通过的,我们开发环境校验不通过。那么问题就出在环境差异,现场环境是英语,开发环境是中文。
可能现场翻译资源文件缺失部分错误码?于是向现场要了下现场环境的资源文件。对比了下,发现缺失了相当一部分,包括产品所说业务规则的错误码。
没错,现场运维兄弟少翻译了一部分错误码导致了这个bug。
NULL到底代表什么
虽然这是个缺失翻译导致的问题。但是作为开发,我们得反思下checkBussines
方法用null来代表校验通过是否是合适的?MessageSource.getText()
方法获取不到错误码翻译时是否应该返回null?而不是抛出异常来提示错误码缺失?
换句话说,对于一种否定意义,我们到底能否返回null?查询不到的数据,我们应该返回null还是一个空对象或者异常?
- 个人建议业务上用明确的空对象来进行返回,而不是意义不明的null。
- 对于一些简单查询逻辑,可以用null来表示空。或者用空集合。
- 返回null来表示某种意义时需要保证null不会出现二义性,就比如上面的checkBussines用返回null(不返回错误提示信息)来表示校验通过,但是可能出现获取不到错误提示信息就返回null的情况,这时候的null就不是校验通过了。null此时意义就不明确了。
在阿里JAVA代码规范中是这样规定的:
推荐:方法的返回值可以为 null,不强制返回空集合,或者空对象等,必须添加注释充分说明什么情 况下会返回 null 值。
说明:本规约明确防止 NPE 是调用者的责任。即使被调用方法返回空集合或者空对象,对调用者来说,也并非高枕无忧,必须考虑到远程调用失败,运行时异常等场景返回 null 的情况。