前言

很长时间没有在博客更新自己的笔记,原因是近期入职了一家公司开始实习,一时间太多的新事物新思想让我无从下手,今天在系统迭代完成期间抽时间记录一下自己近期所学。
在近期实习开发过程中,体会到了在校学习开发和真正企业级开发过程中的一些不同点。主要的不同点在于对编码规范的理解。和之前自己的认知不同,所谓的编码规范不仅仅局限于代码的格式以及各种变量常量的使用细则。写这篇笔记主要的目的就是记录一下目前应该去注意和改进的规范问题。

不得不重视的“小问题”

https://github.com/alibaba/p3c
在开发过程中,对代码的规范扫描主要依托于阿里巴巴的java开发规约IDE插件。在初次完成自己功能模块后,我的代码报了三十多个规范提醒。。。
其中主要问题主要体现在下面几个方面:

命名规范

在第一次使用公司框架的代码生成器时,我在传入表明参数的时候没有忽略表名的前缀,大概就像这样:t_user_name,在没有忽略t前缀的情况下生成的各层命名都为TUserName***。这样的类名不仅对于开发过程中的理解不利,而且对应生成的方法和形参都会携带t前缀,导致不符合规范。
阿里的规范提到:

类名使用 UpperCamelCase 风格,但以下情形例外:DO / BO / DTO / VO / AO / PO / UID 等。
方法名、参数名、成员变量、局部变量都统一使用 lowerCamelCase 风格,必须遵从驼峰形式。

封装规范

在校的小型项目开发中,大多不涉及复杂的表字段关联和一些返回类的封装。即便部分参数会按对象封装,也没有一个统一的规范。在企业级开发中,最常用的就是对应表的VO封装类,它区别于必须与表字段一一对应的实体类,VO进行封装后可以返回加多样的参数形式以便于调用。在这个过程中也加深了我对于java面向对象编程的理解。

常量规范

在我的代码第一次审核的时候,师傅给我指出了魔法值的问题。在校开发的过程中一些参数的取值范围,状态值的设置等等都是直接使用一些凭空出现的常量值,比如下面的错误示范:

if(num<0 || num>100){
	System.out.println("参数范围不合法");
}

//another case
userVO.setstatus(1);

像上面这样凭空出现的常量被称为魔法值,它不利于代码可读性。在开发过程中,一般会建立专门的constant用来存放一些常量。其优势主要在于两个方面:
1.命名方便,便于理解。阿里巴巴规约中对于常量有如下描述:

不允许任何魔法值(即未经预先定义的常量)直接出现在代码中
在常量与变量的命名时,表示类型的名词放在词尾,以提升辨识度。
正例:startTime / workQueue / nameList / TERMINATED_THREAD_COUNT

像这样的常量命名极大的便利了代码的理解。

2.可加注释,方便维护。在constant中我们可以在一些常量声明时添加一些注释便于之后项目的维护。

注释规范

在初期入职时,读代码是不可避免的一个过程。一份拥有完整注释的代码不仅有助于快速理解其用途,还可以在第一时间确定所需的参数和返回值的一些信息。这对于快速熟悉接口非常重要。在阿里的规约扫描中,我的代码大多没有对方法参数以及返回值进行相应说明。这也是导致我的警告高达三十余个的主要原因之一。由于方法和类注释大多都有框架的生成,而方法中的行注释又比较常用,所以在这里就不详细说明了,需要可以回顾一下阿里的java开发手册。

无法忽略的“大问题”

在上一个模块,还有两个规范问题我没有提到,因为我认为那是我了解最少,落实最差的问题。而且这两个问题还在企业开发中有举足轻重的地位。所以我选择单独记录

日志规范

在学习java开发的过程中,几乎没有一些网课对于日志的重要性有一个比较系统的 阐述,导致在进入公司前日志只是一个被我用来测试当前对象取值的工具。相对于它“监控”工程的功能,我的用法更像是把磨盘拿来砸核桃。
近期正值本次迭代完成,需要在测试服务器进行部署并测试各自的功能模块是否正常。最直观的感受就是当出现问题时无从下手。最常见的就是当某个方法运行报错可能只能根据服务器打印的一些错误堆栈进行排查,这个过程极其痛苦。因为并不能知道出问题的是业务逻辑缺陷还是某个参数的问题。更无法排查到底是哪个环节运行出了错。但是如果在日志和切面都比较完善的条件下,能够轻而易举的在日志中看到某某方法的运行以及传入传出参数。甚至可以在方法运行的过程中对中间步骤的关键参数进行打印,这就极大的细化了排查问题的过程。

然而,问题不仅于此。在对一些方法进行打印日志时,我的格式规范不合格。在刚刚被指出日志问题的时候,我对日志的理解仅限于打印一些方法执行的输出语句:

//No
log.info("用户插入成功");

//Yes
log.info("用户【{}】插入成功",user.getName);

就像上面的示例,如果在打印日志时输出一些必要的参数,可以很直观的看到所需要的参数是否正常的传到了这里,这才是一个日志应该起到的作用。
这里放一些阿里关于日志的规范要求:
image.png

异常规范

相对于日志的打印,异常处理可以说更是开发过程中的重中之重。在校期间的开发中,RUNTIMEERROR更多的是利用IDEA的自动补全直接trycatch后打印栈。基本没有对异常有过比较完整的处理。或者一些认为不影响功能跑通的异常比如空指针,会直接一层层的抛出去不做任何处理,这样的处理方式很明显是不合规的。即便经过这些操作后程序可以跑得起来,其健壮性和可读性都会相当差。一旦出现了不合法参数等的小问题可能立刻就会服务器异常,并且还要自己一点点的去摸排问题。
我所负责的钉钉用户同步功能调用了阿里的SDK包,其中包含一些已经封装好的异常信息。当我抛出那些异常后,原本的打印栈就变得没有任何意义。而如果我在catch住异常后通过log.error打印异常信息,就能得到封装好的异常信息,我还可以在其中打印参数日志,甚至可以进行封装返回一个可供前端展示的报错信息。这样的处理就很符合一个web程序在日常使用中和调试中的运行模式。
这里同样放上一些关于异常的阿里规约:
image.png

仍需补充

至于NPE(NullPointException)问题,我认为是一个在开发过程中相当常见的问题,对它的认识和处理之后会单独用一个篇幅来进行整理归纳。

结语

自四月六日入职开始实习至今已有大半个月,这些日子里我自认为对于编码的学习和认知都有了一个不小的进步,真正把自己的所思所学应用于实际的感觉或许就是学习编程带给我的乐趣。最后还要诚挚的感谢在工作之余兼顾指导我的领路人。

Q.E.D.


二八笙歌云幕下,三千世界雪花中