`
sunnylocus
  • 浏览: 869658 次
  • 性别: Icon_minigender_1
  • 来自: 美国图森
社区版块
存档分类
最新评论

人在江湖:如何用代码保护自己

    博客分类:
  • Java
阅读更多

  现在上一点规模的系统,特别是金融行业的系统,业务规则复杂,一般是将系统分割成较小的子模块,每个人开发一个或几个模块,模块开发完成后做成一个jar包,供其它的模块调用,待所有模块开发完成后再集成在一起。对于充值系统而言则更为复杂,除了要将系统分解成子模块外,还要与众多外围系统交互,如收单服务商、充值中心、银行等。程序员就是其中一个或几个模块的开发者。

 

本文的讨论的要点是:在系统出现问题时,如何有理有据的保护好自己。

 

     对于软件开发者来说,我们在公司里一般处于弱势群体,每当系统出现问题造成事故的时候,运营人员一般都会将矛头指向研发人员。他们这么做一般是将责任撇清,以防引火上身。当出现事故给公司造成了实际损失,那么公司老板肯定会介入进来,总有人要背这个黑锅的,这个责任会从上级一级一级的压下来,直到推到某个模块具体编码的程序员身上,这时候我们开发者唯一进行反击的武器就是日志,如果日志没有清楚的记录什么时间调用了什么代码,什么时间调用的代码出现异常,异常的原因是什么等详细信息,那么负责编码的程序员也将是一头雾水莫口难辩,屎盆子全都扣到你头上,最后的结果就是背了黑锅走人。

 

     这种情况在我上一家公司已经发生了很多次,在入职的那段时间里Team leader经常提醒我们,编码一定要小心小心再小心,千万不要出错,出事故了我要挨老板的骂,你们有人就得被辞退。在部门svn服务器的文件夹里有专门存放事故的总结报告,一个事故,一个word文档。差不多有11个文档,直接造成经济损失的A级事故也有3个左右,这几个同仁被辞退的时候心情肯定是极其郁闷。前段时间得到上一家公司同事的消息,公司有个技术大牛写的程序和另外一家公司的系统进行业务交互,结果充值报文被人给修改了,金额被修改成了200万,结果这个大牛写的代码不严谨,没有考虑周全,收到响应报文时没有做金额校验就做了转账操作,听说这一下公司就损失了200万,老板娘在公司发飙,把笔记本重重的摔在他办公桌上。最后也是被辞退,无论技术多么牛的人还是小心些好,常言道:小心驶得万年船。

 

 

现在我用做过的一个充值系统的交互图来说明我的观点,如何调用黑洞代码(所谓黑洞代码就是说你将要调用的这个法,对你而言就是一个黑盒子,你不知道这个方法做了哪些操作,你不知道它会出现什么错误)

 

如图:

 

这是一个银联卡充值系统,这个系统的功能是:只要你将可以能够在网上进行支付的银行卡(哪个银行的都可以)和自己的手机号绑定,就可以随时用手机拨打自动语音充值电话给自己的手机号或着他人的手机号充值,这个系统的参与者有IVR语音服务商、收单服务商、电信充值中心。整个系统可划分为IVR语音模块、收单模块、电信指令交互模块、报文加解密模块、支付模块。

 

模块开发明细表:

 

模块名称 开发者 调用模块编号 序号
IVR语音交互模块 张三 2 1
收单模块 李四 5、3 2
电信指令交互模块 王五 4 3
报文加解密模块 那六   4
支付模块 小七   5

 

系统上线时非常的不稳定,充值失败率很高,平均每五笔就有一笔充值失败。问题定位在2和3这两个模块上,两位开发者各就执一词,争的面红耳赤。我们看看李四的代码,李四的代码去调用了王五的代码。

 

李四的代码截图:

 

 

 

用红色框圈起来的代码是王五的代码,王五的代码打成jar包供李四去调用,李四将王五的业务实现用Spring注入进来,然后直接去调用doCharge方法,并将结果返回,看起来没有问题。只不过只是表面看起来没有问题。

 

打问号的代码你敢大胆的这样用吗?

 

风险一:

 

doCharge方法对李四来说就是一个黑洞代码,不知道这个方法作了哪些操作,会不会有错误发生,因为doCharge方法未声明该方法可能要抛出的异常,李四以为这个doCharge方法是安全的,所以没有加try{}catch()代码捕获异常。什么事都怕万一,万一这个doCharge出现了异常怎么办?

 

风险二:

如果doCharge方法因为某种原因产生了死锁,那么你的调用结程死在里面了,永远不返回调用结果,这种情况怎么办?

 

 

风险一的应对措施:

  对于要调用的关键方法,无论它有没有声明要抛出的异常,我们都要对它保持怀疑的态度,加try{}catch捕获,并将捕获到异常,记录日志后,包装下继续抛给上层调用者。让上层调用者知道出错了,异常抛出了你就尽到了通知的义务,系统出问题与你没有关系,不然出了问题问你:你为什么不捕获异常?为什么不抛异常?虽然有很多种理由可以向质问者解释,但还是多一事不如少一事,别偷懒加个try{}catch()捕获可能出现的异常。

 

风险二的应对措施:

 

打个比喻:你是猎人,你要在山洞里抓一只狼崽出来,但是你不确定这个山洞里有什么危险,聪明的猎人会放猎狗进去抓狼崽,如果猎狗进去一段时间没有出来,说明里面有危险,猎人再想其它办法。如果猎人自己进去是有风险的,谁知道这个洞里面是狼还是虎。这个比喻想说的是,如果你要调用一个你认为不太安全的方法,不要用主线程调用(猎人),创建一个调用线程(一只猎狗)去调用,这样做的好处是能够监控调用是否成功,还可以设置调用的超时时间。

 

用这个比喻我们创建一个猎狗工具类,调用黑洞方法时,自动生成调用线程,如果调用时间超时,抛出TimeoutException

采用猎狗模式修改后的代码:

 

 

事后终于找到了bug了,问题出在王五的电信指令交互模块上,发送给电信的报文长度必须符合协议,否则电信那端收到非法包后会将Socket连接断开,协议规定充值金额必须是4位数字,不足4位的,左补0,比如说客户要充值10,补全的就是0010

充值100,就是0100.如果客户充值少于10元,要在左侧补3个0,这个bug出现在王五在处理个位充值时,少补了一个0,结果是客户充值2位数金额的话费就成功,一充值个位数的话费Socket连接就断开,李四的调用线程一直堵塞在这里。

 

如果一开始李四采用猎狗模式的话,出现问题一看日志便知道问题出在哪里,有理有据的指出问题所在,也不用背这个黑锅了。

 

上面的代码适合Jdk1.5以上使用,如果想在jdk1.4使用,请自己改造下。

 

 

PS:应网友要求,贴出猎狗的测试代码,请大家对比

 

普通调用:

 

 

猎狗调用:

 

 

 

 

 

 

 

 

 

67
10
分享到:
评论
51 楼 Java_Caven 2017-01-26  
很少回帖的我 今天也回个,说的很好,分析的很透彻,有种茅塞顿开的感觉
50 楼 dayzhang1987 2016-09-18  
  惭愧,码了几年的代码只想到try catch那层,若是超时这种,一般只会想到用http请求,楼主这种确实是好方法
49 楼 ka520 2015-12-08  
说实话,我基本上看贴不回,你是例外,受益良多,阁下的技术我也佩服得紧,JAVA那些类你是在那里看到的,求指点!
48 楼 fengzhongzhixin 2013-05-23  
当然,对于博主的技术水平,在下还是相当敬佩的!
47 楼 fengzhongzhixin 2013-05-23  
我感觉在这种公司里干是浪费生命,写个代码还得小心翼翼的,太没有乐趣了,况且也挣不了几个钱,还不如去做生意,有钱就做大的,没钱就卖煎饼,都比在这种公司里受这个鸟气要好。
46 楼 qkjava 2012-10-10  
浅显易懂 务实 比较系统
45 楼 sunnylocus 2011-10-26  
今天去你的博客逛了逛,原来各咱们在同一家公司共事过。
tedeyang 写道
惊叹的代码!更惊叹的是思路

对程序员是自利,对系统却是无谓的性能消耗。
有多少个并发调用就要启双倍的线程,虽然是缓存的,但是线程要消耗1M heap和325k的native 。

可见一个要创造一个高度互信的社会是多么重要。国内的很多问题都来源于由上到下的信用缺失

今天去你的博客逛了逛,原来咱们在同一家公司共事过,缘分。
44 楼 锅巴49 2011-10-24  
受教了,谢谢
43 楼 raiha 2011-10-17  
我认为直接让王五去电信营业厅帮别人交话费最靠谱
42 楼 yingwu1206 2011-10-17  
看博文和评论都让我洗了洗脑,好文!
41 楼 laozhao 2011-10-17  
经典。清晰,受益匪浅!
40 楼 cpszy 2011-10-17  
mark!
39 楼 singleTon 2011-10-17  
很清晰的思路!学习了1
38 楼 sunnylocus 2011-10-17  
请输入用户名 写道
很清晰 很精辟 很喜欢

谢谢!共勉
37 楼 请输入用户名 2011-10-17  
很清晰 很精辟 很喜欢
36 楼 kilowen 2011-10-16  
学习了 ,谢谢了
35 楼 charles751 2011-10-16  
代码质量不错,考虑也很周全,但好像测试力度不够。
34 楼 BruceXX 2011-10-15  
对于你这种Callable线程池来说, 一种业务何尝不需要做一个池化隔离,PS:LZ是支付宝的兄弟吧?
33 楼 pmh905001 2011-10-14  
这种出了事情就知道往下推卸责任的公司,没有呆在里面浪费清楚。
32 楼 sunnylocus 2011-10-14  
cj2008am 写道
顶一个。。。。。。。。。。

谢谢

相关推荐

Global site tag (gtag.js) - Google Analytics