阿里巴巴开发手册四
一、异常处理
1、【强制】Java 类库中定义的一类 RuntimeException 可以通过预先检查进行规避,而不应该 通过catch 来处理,比如:IndexOutOfBoundsException,NullPointerException等等。
2、【强制】异常不要用来做流程控制,条件控制,因为异常的处理效率比条件分支低。
3、【强制】对大段代码进行 try-catch,这是不负责任的表现。catch 时请分清稳定代码和非稳 定代码,稳定代码指的是无论如何不会出错的代码。对于非稳定代码的catch尽可能进行区分 异常类型,再做对应的异常处理。
4、【强制】捕获异常是为了处理它,不要捕获了却什么都不处理而抛弃之,如果不想处理它,请 将该异常抛给它的调用者。最外层的业务使用者,必须处理异常,将其转化为用户可以理解的 内容。
5、【强制】有 try 块放到了事务代码中,catch 异常后,如果需要回滚事务,一定要注意手动回 滚事务。
6、【强制】finally 块必须对资源对象、流对象进行关闭,有异常也要做 try-catch。
7、【强制】不能在 finally 块中使用 return,finally 块中的 return 返回后方法结束执行,不 会再执行 try 块中的 return 语句。
8、【强制】捕获异常与抛异常,必须是完全匹配,或者捕获异常是抛异常的父类。 ?> 如果预期对方抛的是绣球,实际接到的是铅球,就会产生意外情况。
9、【推荐】方法的返回值可以为 null,不强制返回空集合,或者空对象等,必须添加注释充分 说明什么情况下会返回 null 值。调用方需要进行 null 判断防止 NPE 问题。 ?> 本手册明确防止 NPE 是调用者的责任。即使被调用方法返回空集合或者空对象,对调用 者来说,也并非高枕无忧,必须考虑到远程调用失败、序列化失败、运行时异常等场景返回 null 的情况
10、【推荐】防止 NPE,是程序员的基本修养,注意 NPE 产生的场景:
11、【推荐】定义时区分unchecked/checked 异常,避免直接抛出newRuntimeException(), 更不允许抛出 Exception 或者 Throwable,应使用有业务含义的自定义异常。推荐业界已定义 过的自定义异常,如:DAOException / ServiceException 等。
12、【参考】在代码中使用“抛异常”还是“返回错误码”,对于公司外的 http/api 开放接口必须 使用“错误码”;而应用内部推荐异常抛出;跨应用间 RPC 调用优先考虑使用 Result 方式,封 装 isSuccess()方法、“错误码”、“错误简短信息”。
13、【参考】避免出现重复的代码(Don’t Repeat Yourself),即DRY原则。
二、日志规约
1、【强制】应用中不可直接使用日志系统(Log4j、Logback)中的 API,而应依赖使用日志框架SLF4J 中的 API,使用门面模式的日志框架,有利于维护和各个类的日志处理方式统一
2、【强制】日志文件推荐至少保存 15 天,因为有些异常具备以“周”为频次发生的特点。
3、【强制】应用中的扩展日志(如打点、临时监控、访问日志等)命名方式: appName_logType_logName.log。logType:日志类型,推荐分类有 stats/desc/monitor/visit 等;logName:日志 述。这种命名的好处:通过文件名就可知 道日志文件属于什么应用,什么类型,什么目的,也有利于归类查找。
4、【强制】对 trace/debug/info 级别的日志输出,必须使用条件输出形式或者使用占位符的方式。
5、【强制】避免重复打印日志,浪费磁盘空间,务必在 log4j.xml 中设置 additivity=false。
6、【强制】异常信息应该包括两类信息:案发现场信息和异常堆栈信息。如果不处理,那么通过 关键字 throws 往上抛出。
7、【荐】谨慎地记录日志。生产环境禁止输出 debug 日志;有选择地输出 info 日志;如果使 用 warn 来记录刚上线时的业务行为信息,一定要注意日志输出量的问题,避免把服务器磁盘 撑爆,并记得及时删除这些观察日志。
8、【参考】可以使用 warn 日志级别来记录用户输入参数错误的情况,避免用户投诉时,无所适 从。注意日志输出的级别,error 级别只记录系统逻辑出错、异常等重要的错误信息。如非必 要,请不要在此场景打出 error 级别。
三、单元测试
1、【强制】好的单元测试必须遵守 AIR 原则。
- A: Automatic(自动化)
- I: Independent(独立性)
- R: Repeatable(可重复)
2、【强制】单元测试应该是全自动执行的,并且非交互式的。测试框架通常是定期执行的,执行过程必须完全自动化才有意义。输出结果需要人工检查的测试不是一个好的单元测试。单元测 试中不准使用 System.out 来进行人肉验证,必须使用 assert 来验证。
3、【强制】保持单元测试的独立性。为了保证单元测试稳定可靠且便于维护,单元测试用例之间 决不能互相调用,也不能依赖执行的先后次序。
4、【强制】单元测试是可以重复执行的,不能受到外界环境的影响。
5、【强制】对于单元测试,要保证测试粒度足够小,有助于精确定位问题。单测粒度至多是类级 别,一般是方法级别。
6、【强制】核心业务、核心应用、核心模块的增量代码确保单元测试通过。 ?> 新增代码及时补充单元测试,如果新增代码影响了原有单元测试,请及时修正。
7、【强制】单元测试代码必须写在如下工程目录:src/test/java,不允许写在业务代码目录下。
8、【推荐】单元测试的基本目标:语句覆盖率达到 70%;核心模块的语句覆盖率和分支覆盖率都 要达到 100%
9、【推荐】编写单元测试代码遵守 BCDE 原则,以保证被测试模块的交付质量。
- B: Border,边界值测试,包括循环边界、特殊取值、特殊时间点、数据顺序等。
- C: Correct,正确的输入,并得到预期的结果。
- D: Design,与设计文档相结合,来编写单元测试。
- E: Error,强制错误信息输入(如:非法数据、异常流程、非业务允许输入等),并得 到预期的结果。
10、【推荐】对于数据库相关的查询,更新,删除等操作,不能假设数据库里的数据是存在的, 或者直接操作数据库把数据插入进去,请使用程序插入或者导入数据的方式来准备数据。
11、【推荐】和数据库相关的单元测试,可以设定自动回滚机制,不给数据库造成脏数据。或者 对单元测试产生的数据有明确的前后缀标识。
12、【推荐】对于不可测的代码建议做必要的重构,使代码变得可测,避免为了达到测试要求而 书写不规范测试代码。
13、【推荐】在设计评审阶段,开发人员需要和测试人员一起确定单元测试范围,单元测试最好 覆盖所有测试用例(UC)。
14、【推荐】单元测试作为一种质量保障手段,不建议项目发布后补充单元测试用例,建议在项 目 测前完成单元测试。
15、【参考】为了更方便地进行单元测试,业务代码应避免以下情况:
- 构造方法中做的事情过多。
- 存在过多的全局变量和静态方法。
- 存在过多的外部依赖。
- 存在过多的条件语句。
16、【参考】不要对单元测试存在如下误解:
- 那是测试同学干的事情。本文是开发手册,凡是本文内容都是与开发同学强相关的。
- 单元测试代码是多余的。汽车的整体功能与各单元部件的测试正常与否是强相关的。
- 单元测试代码不需要维护。一年半载后,那么单元测试几乎处于废弃状态。
- 单元测试与线上故障没有辩证关系。好的单元测试能够最大限度地规避线上故障。