不要嫌麻烦和浪费时间,其实只要坚持下来,团队收益会非常大。
其实,写代码的时候,没有必要写太多的注释,因为好的方法名、变量名,就是最好的注释。以下就是总结的一些注释规范:
/**
?*?@author?didi
?*?@date?2023/04/22?5:20?PM
?*?@desc??实现类,用于demo展示
?*/
public?class?DidiClass?{
?
????/**
?????*?这它将两个价格整数相加并返回结果。
?????*?
?????*?@param?x?第一个整数
?????*?@param?y?第二个整数
?????*?@return?两个整数的和
?????*/
????public?int?sellTianLuo(int?x,?int?y)?{
????????return?x?+?y;
????}
}
日志是快速定位问题的好帮手,是撕逼和甩锅的利器!打印好日志非常重要。如果代码评审的时候,这些日志规范没遵守,就需要修改:
Java代码的命名应该清晰、简洁和易于理解。我们代码评审的时候,要注意是否有命名不规范,不清晰的代码。下面是一些命名规范的建议:
我们代码评审的时候,要注意参数是否都做了校验,如userId非空检查、金额范围检查、userName长度校验等等。一般我们在处理业务逻辑的时候,要遵循先检查、后处理的原则。
如果你的数据库字段userName设置为varchar(16),对方传了一个32位的字符串过来,你不校验参数,插入数据库直接异常了。
很多bug都是因为没做参数校验造成的,这是代码评审重点关注的
获取对象的属性时,都要判空处理。要不然很多时候会出现空指针异常。
if(object!=null){
??String?name?=?object.getName();
}
如果你要遍历列表,也需要判空
??if?(CollectionUtils.isNotEmpty(tianLuolist))?{
????????for?(TianLuo?temp?:?tianLuolist)?{
????????????//do?something
????????}
????}
良好的异常处理可以确保代码的可靠性和可维护性。因此,异常处理也是代码评审的一项重要规范。以下是一些异常处理的建议:
良好的代码格式,可以使代码更容易阅读和理解。下面是一些常见的代码格式化建议:
代码评审的时候,要重点关注是否考虑到了接口的兼容性.因为很多bug都是因为修改了对外旧接口,但是却不做兼容导致的。关键这个问题多数是比较严重的,可能直接导致系统发版失败的
所以,如果你的需求是在原来接口上修改,尤其这个接口是对外提供服务的话,一定要考虑接口兼容。举个例子吧,比如dubbo接口,原本是只接收A,B参数,现在你加了一个参数C,就可以考虑这样处理:
//老接口
void?oldService(A,B){
??//兼容新接口,传个null代替C
??newService(A,B,null);
}
//新接口,暂时不能删掉老接口,需要做兼容。
void?newService(A,B,C){
??...
}
代码评审的时候,要关注程序逻辑是否清晰。比如,你的一个注册接口,有参数校验、判断用户是否已经注册、插入用户记录、发送注册成功通知等功能。
如果你把所有所有功能代码塞到一个方法里面,程序逻辑就不清晰,主次不够分明,反例如下:
?public?Response?registerUser(String?userName,?String?password,?String?email)?{
????????if?(userName?==?null?||?StringUtils.isEmpty(userName))?{
??????????log.info("用户名不能为空!");
????????????throw?new?BizException();
????????}
????????if?(password?==?null?||?password.length()?<?6)?{
????????????log.info("密码长度不能少于6位!");
????????????throw?new?BizException();
????????}
????????if?(email?==?null?||?StringUtils.isEmpty(email)?||?!email.contains("@"))?{
????????????log.info("邮箱格式不正确!");
????????????throw?new?BizException();
????????}
????????Response?response?=?new?Response();
????????UserInfo?userInfo?=?userService.queryUserInfoByUsername();
????????if?(Objects.nonNull(userInfo))?{
????????????response.setCode(0);
????????????response.setMsg("注册成功");
????????????return?response;
????????}
????????UserInfo?addUserInfo?=?new?UserInfo();
????????addUserInfo.setUserName(userName);
????????addUserInfo.setPassword(password);
????????addUserInfo.setEmail(email);
????????userService.addUserInfo(addUserInfo);
????????MessageDo?messageDo?=?new?MessageDo();
????????messageDo.setUserName(userName);
????????messageDo.setEmail(email);
????????messageDo.setContent("注册成功");
????????messageService.sendMsg(messageDo);
????????response.setCode(0);
????????response.setMsg("注册成功");
????????return?response;
????}
其实,以上这块代码,主次不够分明的点:参数校验就占registerUser方法很大一部分。正例可以划分主次,抽一下小函数,如下:
????public?Response?registerUser(String?userName,?String?password,?String?email)?{
????????//检查参数
????????checkRegisterParam(userName,?password,?email);
????????//检查用户是否已经存在
????????if?(checkUserInfoExist(userName))?{
????????????Response?response?=?new?Response();
????????????response.setCode(0);
????????????response.setMsg("注册成功");
????????????return?response;
????????}
????????//插入用户
????????addUser(userName,?password,?email);
????????sendMsgOfRegister(userName,?email);
????????//构造注册成功报文
????????Response?response?=?new?Response();
????????response.setCode(0);
????????response.setMsg("注册成功");
????????return?response;
????}
????private?void?sendMsgOfRegister(String?userName,?String?email)?{
????????MessageDo?messageDo?=?new?MessageDo();
????????messageDo.setUserName(userName);
????????messageDo.setEmail(email);
????????messageDo.setContent("注册成功");
????????messageService.sendMsg(messageDo);
????}
????private?void?addUser(String?userName,?String?password,?String?email)?{
????????UserInfo?addUserInfo?=?new?UserInfo();
????????addUserInfo.setUserName(userName);
????????addUserInfo.setPassword(password);
????????addUserInfo.setEmail(email);
????????userService.addUserInfo(addUserInfo);
????}
????private?boolean?checkUserInfoExist(String?userName)?{
????????UserInfo?userInfo?=?userService.queryUserInfoByUsername();
????????if?(Objects.nonNull(userInfo))?{
????????????return?true;
????????}
????????return?false;
????}
????private?void?checkRegisterParam(String?userName,?String?password,?String?email)?{
????????if?(userName?==?null?||?StringUtils.isEmpty(userName))?{
????????????log.info("用户名不能为空!");
????????????throw?new?BizException();
????????}
????????if?(password?==?null?||?password.length()?<?6)?{
????????????log.info("密码长度不能少于6位!");
????????????throw?new?BizException();
????????}
????????if?(email?==?null?||?StringUtils.isEmpty(email)?||?!email.contains("@"))?{
????????????log.info("邮箱格式不正确!");
????????????throw?new?BizException();
????????}?
????}
代码评审,也非常有必要评审代码是否存在安全性问题。比如:
什么是幂等? 计算机科学中,幂等表示一次和多次请求某一个资源应该具有同样的副作用,或者说,多次请求所产生的影响与一次请求执行的影响效果相同。
代码评审的时候,要关注接口是否考虑幂等。比如开户接口,多次请求过来的时候,需要先查一下该客户是否已经开过户,如果已经开户成功,直接返回开户成功的报文。如果还没开户,就先开户,再返回开户成功的报文。这就是幂等处理。
一般情况有这几种幂等处理方案:
幂等要求有个唯一标记,比如数据库防重表的一个业务唯一键。同时强调多次请求和一次请求所产生影响是一样的。
代码评审的时候,如果用数据库、Redis、RocketMq等的中间件时,我们需要关注这些中间件的一些注意事项哈。
比如数据库:
关注数据库连接池参数设置、超时参数设置是否合理
避免循环调用数据库操作
如果不分页,查询SQL时,如果条数不明确,是否加了limit限制限制
数据库的返回是否判空处理
数据库慢SQL是否有监控
表结构更新是否做兼容,存量表数据是否涉及兼容问题考虑
索引添加是否合理
是否连表过多等等
比如Redis:
理解几个常见的代码坏味道,大家代码评审的时候,需要关注一些点:
远程调用是代码评审重点关注的一栏,比如: