Learn to be defensive


作为开发者,我们必须要学会defensive programming,尤其是对要求高可靠性和无人职守的企业级应用中,需要特别留意我们的设计和编码,必须尽可能做到足够defensive。

什么是defensive programming?举个大家都看过的例子:

String str = ...
if ("".equals(str)) {}

在这里我们不写str.equals("")而是反过来,就是为了防止出现不必要的NPE – NullPointerException。

运行期异常是最最需要特别关照的一种非正常状况,除了像上面这类要求我们采用相对较好的编码习惯之外,为了减少运行期异常的发生,通常也需要使用try-catch代码块来把我们相对脆弱,或者需要格外保护的逻辑包起来,对于外部传进来的参数,一定要assert它们的合法性,即assert它们是否能够安全的被后面的逻辑所使用。

通常意义上,defensive programming主要cover的是避免不必要的运行期异常发生。我们可以更进一步,更广义的运用defensive programming的核心思想:在企业应用中,除了运行期异常,对于有些看似严重的极端的错误,如网络超时,连接丢失,数据库提交失败等情况,需要我们具体问题具体分析,并非所有checked exception都一定需要我们去一一catch然后处理。更多的时候,尤其当开发无人职守的后台程序,我们可以采取重试、报告、修改外部数据等方式处理,能够自行解决的,就不要动不动就报错,或等待用户确认,不能自行解决的,则要及时报告并停止运行,避免更大的错误发生。

举个相对具体的例子,两个异构的系统,通过一个中间层的消息平台相互发送消息,通信协议采用最基本的socket方式,这三个系统随时都可能出现宕机或链接中断的情况。为了保证数据的完整性,我们拿其中一个需要发送和接收消息的系统来细说:

一个可能的实现方式是:该系统所有要发送的消息保存到数据库,给它一个初始状态;另一个独立进程从数据库按照时间先后拿出消息,更新拿出的这条消息的状态为处理中,并尝试发送消息;成功后根据需要,更新消息状态为成功发送或者直接删除,如果遇到失败或异常,消息恢复为初始状态,线程sleep一段时间,然后再次尝试,多次尝试或者尝试跨度超过一定时间范围,则停止处理,向管理员汇报(通过邮件、短信等途径)。对于接收到的消息,同样是先存入数据库,然后再由后续的进程用类似的方式取出并处理。如果程序崩溃,可以自动重新启动(应用或整个服务器)。这样不管哪一段通信线路出现故障或阻塞,或者宕机,系统都可以一步一个脚印,确保任务主动而自动的执行,并且忠实记录下有价值的状态信息,出现问题时管理员可以很直观的看到在哪个环节出现故障,从而快速找到问题关键并有效解决。

Defensive programming可以让我们的应用更健壮,在保证数据正确性、完整性的前提下,面对困难也能更加独立自主。和defensive programming相关的话题我想大家如果感兴趣,可以展开更多更深入的探讨,这里只是给大家做个介绍性的铺垫,能抛砖引玉当然更好。


你可能感兴趣的:(Learn to be defensive)