一、前言
最近朋友公司发生了一个非常严重的事情,在对接公司客户的充值接口时,一个BUG导致了3000万左右的资金入错帐!
当听说这个事情的时候,我第一反应可能是前端的充值按钮以及充值接口未做防重复提交的校验,导致用户出现多次点击同一笔充值记录的按钮或者直接通过调用该笔交易的充值接口进行充值出现了问题!
但实际的原因是我意想不到的!
二、过程
朋友说是因为他们公司的充值可以冲负数!(猜测的需求场景:用户充值多了,通过充值相应的负金额来校准)但后端的逻辑代码是把充值金额进行了绝对值转换再进行充值的。所以导致了这个BUG的发生!由于能操作充值的都是企业里财务大佬很小的一部分员工,使用并不频繁,难以发现一直没有发现这个问题,导致了错误金额的积累,最后达到了3000万的数量级!
首先这个功能实际并不复杂,业务流程如下:
1.充值人员进行一笔充值给某公司多少钱的申请记录提交到审核人员
2.审核人员确认无误后审核通过,钱就会打给对应的公司账户上
后面从朋友那得知了出现BUG的原因:之前主要测试该模块和开发该模块的人员都离职了,在离职交接的过程中对于类似如此细节上的问题出现了遗漏。在前几个月的版本迭代中,由于涉及充值模块的需求所以做了改动,又因为接手该项目的都是新人,就导致了这个BUG的发生!在测试的时候,新的测试同学做回归的时候也未想到有充值负数的情况(我相信绝大部分小伙伴跟我一样都想不到充值会有负数的情况)因此导致了此BUG的发生!
三、分析
这个锅应该由谁来背?
这个锅我认为是项目制度和项目流程的问题,应该由制定审计这些的负责人来背锅。
有的小伙伴可能会问:这个问题是BUG,也属于漏测,应该是测试、开发的问题呀,关其他人什么事?
但如果你仔细分析会发现:这更多的问题是在离职交接上出的问题。交接疏漏导致了接手的测试、开发不知道这个功能的逻辑,且后续迭代版本中也没人提出(充值可以为负数)这个功能点,等于没人知晓这个事情,自然就成为了隐藏的BUG!
如果测试提前知晓了这个功能,对于如此简单的功能还出现漏测是很荒唐的事情!
所以问题是相关负责人未制定规范的制度建立健硕的体系导致了遗漏!
那对于如此的情况我们应该如何避免呢?
这里要说到两个开发模式:敏捷开发和瀑布模型开发
瀑布模型的核心思想是按工序将问题化简,将功能的实现与设计分开,便于分工协作,即采用结构化的分析与设计方法将逻辑实现与物理实现分开。将软件生命周期划分为制定计划、需求分析、软件设计、程序编写、软件测试和运行维护等六个基本活动,并且规定了它们自上而下、相互衔接的固定次序,如同瀑布流水,逐级下落。
瀑布模型非常强调文档,前一个阶段的输出就是下一个阶段的输入,文档是个阶段衔接的唯一信息。所以很多开发人员好象是在开发文档,而不是开发软件,因为要到开发的后期,才可以看到软件的“模样”。
而且这样对于新员工来讲也能够清晰、快速的熟悉产品业务!正因为有了完备的文档,也就不会导致上面出现的新员工都不知道 (充值可以冲负数) 这样的功能。
但是!!!
瀑布模型有一个不可忽视的缺点,在国内不适应的原因也正是如此:开发周期太长!
往往按照瀑布模型进行开发花费的时间是敏捷开发模式的三倍之多!
如果使用瀑布模型开发在目前的国情下,等你9个月时间做出一个产品,黄花菜都凉了,你的用户已经被抢占的一无所有!
敏捷开发强调更快的交付价值;简单来说就是项目团队要且尽快的交付可以使用的产品给客户,让其能够更早的将产品投入市场,验证其是否满足市场需求,是否具有一定的商业价值。这是敏捷提倡的核心价值之一。敏捷开发更能够拥抱变化、更具有灵活性。
国内的大部分企业的开发模式都是敏捷开发,毕竟最为需要的就是先把产品做出来,抢占市场!后面再一步一步优化!另外的好处是,如果产品并不适合市场,还可以及时止损,不会像瀑布模型那样投入更多的人力、时间!这也是国内大部分企业选择敏捷开发模式的最主要的原因。
敏捷开发是以用户的需求为核心,采用迭代、循序渐进的方法进行软件开发。换言之,就是把一个大项目分为多个相互联系,但也可独立运行的小项目,并分别完成,在此过程中软件一直处于可使用状态。但是在快速迭代的过程中,很难保证清晰详尽的文档,因此导致需要花更多的时间熟悉业务产品,并且存在更大的遗漏风险,上述BUG的出现与其有着密不可分的原因。
总结下来,这两个模型简而言之就是:
敏捷开发:快!难维护!
瀑布模型:易维护!慢!贵!
我们又想开发快,又怕出现如此严重的BUG,甚至可能辛苦一整年的成果,一夜之间全都付之东流,那我们应该作何选择呢?
三、解决方案
其实我们可以将两种模式结合起来,采用瀑布+敏捷开发的模式。
把项目维度进行细分,减小瀑布模型的粒度;同时,采用敏捷开发的优秀实践方式,提高开发的沟通效率,提供项目的全景视图。
换而言之就是重要的功能模块就可以采用瀑布开发的模式来进行,类似于上述的支付;权重稍低的模块则可以选择敏捷开发进行。类似一些不影响使用、不太影响美观的界面问题,亦或是客户最关注的、风险不大的需求可以先做起来,再后续迭代中进一步优化调整。
另外,对于支付来说,我们应该保持一个原则:钱要在手!
往细了来说就是:
付款失败不要做重复支付
收款时要先去对比银行的余额增加了才算成功
如果因为网络波动等原因导致银行余额查询失败,但钱实际收到了,这个时候也应该标记为收款失败!
哪怕客户因此打电话来投诉,也不应该因此而将状态改为收款成功!
还有就是行业问题:类似于银行、军工行业他们的开发模式基本都是瀑布模型。
毕竟这个出现BUG直接损失就是资金或者生命了!
总的来说,在实际项目过程中,过于强调哪种开发模式是毫无意义的,重要的是能不能预防问题的发生,在问题发生之后能不能用最小的成本解决,这才是最有必要考虑的事情。
四、涉及资金交易的功能该如何测试
我们可以走六个方面来划分功能点:
1. 金额层面
正常金额的支付:最小、最大值、小数点支付;
非法金额(为0、负数、多小数点、非数字字符等)支付;
错误金额(小于最小值、大于最大值、格式错误、大于余额、每日限额、不允许货币等)的输入.
2. 交易流程
包括正常完成支付的流程,余额不足的支付流程、支付中断后继续支付的流程,支付中断后结束支付的流程,支付中断结束支付后再次支付的流程,付款后退款相关流程、单订单支付的流程,多订单合并支付的流程等;
3. 接口层面
直接通过接口传递非法、错误的数据的情况,短时间重复调用支付接口的情况。大压力负载下的支付情况等。
4. 兼容性
业务需求涉及的设备都需要扩展测试,例如可以通过网页支付,那就需要考虑PC端不同系统、不同浏览器版本、类型的浏览器、不同类型的手机Web浏览器的支付情况。
5. 账单记录
成功交易的、失败的、退款的、支付中的订单账单记录信息是否完备可追踪。
6. 优惠券
有优惠券抵扣时实际金额计算是否正确,发生退款计算是否正确、发生退款时,优惠券被废弃的处理情等。