事件还原:
2000年,主人公就职富士通,用流行的商务处理语言Cobol为东京证券交易所开发股票交易系统。在涉及指令撤销的程序流程上留了个微不足道的bug,要特定条件才能触发,在多次验收、测试时这个bug都没暴露出来。
一个bug让程序员走上法庭
右侧流程图的主要逻辑是通过“交易品种数据库【会员号】【流水号】”和“下单数据库【会员号】【流水号】”是否相一致做判断,一致则判定“订单的一部分未商定,检索处理继续”,否则“订单商定完毕,检索处理终了(也就是不再受理撤销指令)”。且在备注框中注明,若“交易品种数据库【会员号】【流水号】”已清零,则直接进入分支3,即认定“交易商定达成,拒绝撤销指令”。然后,时间来到2005年12月8日,J-COM公司上市的日子。日本瑞穗证券公司的一名经纪人接到客户的委托,要求以61万日元(约合4.19万人民币)的价格卖出1股J-Com公司的股票。然而,这名交易员脑残手贱,把指令输成了以每股1日元的价格卖出61万股,且在系统弹出价格不合理的警告时置之不理,习惯性地点了“确定”。哎呀妈呀,这是要白送股票么?
幸好,幸好,系统有限价机制,新股上市首日开盘价格不设涨跌幅,开盘价格通过“集中竞价”方式确定。开盘价格确定后,根据该价格所对应的涨跌幅度限制,确定当日成交价格的最高和最低限价。如果某笔委托的价格超过当日最高或最低限价,系统便自动将其委托价格修正为最高或最低限价。
当瑞穗证券公司在上午9:27分开出每股1日元卖出61万股的大单时,市场立即以67.2万日元成交,开盘价即被确定为67.2万日元每股,该股当天的涨跌幅(±100,000日元)也随之确定。由于该笔卖单数量巨大(61万股诶!),首单成交后,未成交部分,在限价机制调整下,被系统默认登记为最低限价57.2万日元每股的卖单,并依次与随后陆续输入的买单成交。系统还是大幅修正了脑残手贱君的错误,没真让他用1日元这种无厘头的价格把J-COM给卖哭了。
其实,在手贱指令发出后2分钟,也就是上午9:29分,该脑残交易员的助理发现了这一问题。于是他们马上向东京证交所的计算机连续三次发出了撤单指令,但均被交易所主机拒绝。
上午 9:31,瑞穗证券公司证券交易部确认该指令不是由该部门发出的,而是由大宗交易部发出的。于是证券交易部一位高管再次试图通过交易所交易终端撤销该指令,但又被拒绝(已经是第4次被拒哦)。
上午9:35,瑞穗证券公司证券部确认此单系误操作,而且撤单申请被拒绝,请求东京证交所为其撤销此卖单。但东京证交所研究后认为,他们不能代瑞穗进行撤单,须由瑞穗自行解决这一问题(亚洲人的官僚气息是共通的,共通的!)。
与此同时,J-COM的股价一路跳水狂跌。散户们先是惊慌失措,各种抛售。然后反应快的竞争对手和大户猜到:“擦,肯定哪家券商手抖乌龙指了!”,迅速跟进疯狂抢购。随后,由于57万日元每股这种万年不遇的超低价,连日本大妈都火速跑步进场,各种抄底。脑残单开出的10分钟之内,47万股即被抢购一空。
为了止损,瑞穗反向买入J-COM股票,加入抢购大军。在各方疯抢情况下,J-COM的股票又被拉高到当天限价高位的77.2万日元。最后到当天交易结束,瑞穗一共损失了约270亿日元(约合18.5亿人民币)。
一个bug让程序员走上法庭 索赔金额达400亿日元
瑞惠证券误甩单事件流程(J-COM发行股票1.45万股)
9:27 瑞惠证券(误下单)
61万日元卖1股被下成1日元卖61万股?
(开盘)67.2万日元
急速下跌
9:30 (最低限价) 57.2万日元
9:37 (约有47万股买入单开出)
(瑞惠证券在回购?)
急速上升
9:43 (最高限价) 77.2万日元
15:00 (收盘) 77.2万日元这还不算完,J-COM的股票一共只发行了1.45万股,现在这61万股卖出去,拿什么交付?最后经过协商,瑞穗证券用每股91万日元的价格,现金清算了股民手上的9万多股。还好回购及时,把剩下的苦果都自己吞了。但即便这样,现金清算也使他们的损失扩大到400多亿日元。(以亿为单位,程序猿出身的小编表示:到底几个零,数不清啊……)
这么惨的损失,瑞惠整年的利润都报销了,全体员工翘首以盼的年终奖也挥一挥衣袖,让你摸不着踪影了。这么大的黑锅谁来背?瑞惠?东证?富士通?手捧传票心胆具颤的程序猿小哥?
瑞穗认为,事发后2分钟自己已提交撤销交易请求,但由于系统bug,4次撤销请求均被拒,直接导致损失大到难以承受的地步。之前的损失也就算了,撤销请求提交后造成的损失应该由东京证券来买单(你赔,你赔,你的系统你来赔!)
东证把社长鹤岛琢夫祭了出去,出了问题就要谢罪下台表态度,日本流行这个。但咱坚决不背这笔债,明明是系统承包商富士通的责任嘛。我的需求里写了要能撤单,你连拒人家4次明显没达到要求。
富士通更绝:自己脑残手贱怪我咯?
一个bug让程序员走上法庭
于是,2006年,瑞穗把东证和富士通告上了法庭。东京地方法院给出的判定是:这个系统的主要责任人是东证。富士通只是东证的系统供应商,属于连带责任人。无论是主要责任人还是连带责任人,如果被证明犯有重大过失,都应该做出赔偿。
至于什么样的bug算“重大过失”,法院给出了判断的标准:bug是不是很容易被检测出。
于是,控辩双方当庭撕代码。两边请来的资深程序猿专家吵成一团。你说“这么简单的bug,肉眼看都能看出来,测这么多遍还没测出,脑子秀逗了?”他说:“你觉得简单,那你现场重现给我看看?”
互撕结果:
东京地方法院判定:
程序bug不能算是重大过失,由这部分导致的损失无需赔偿。瑞穗电话联络东证后,东证未能履行中止异常交易的职责,属于重大过错方。但事件起因是由于瑞穗交易员的乌龙指,所以瑞穗也不能完全免责。电话联络时间点以后产生的损失,由东证承担70%,107亿日元。
没富士通啥事儿,更不关程序猿的事儿。程序猿小哥捧传票的手不抖了?小心肝儿落肚了?
先别急着安心。有了判例,“bug是不是很容易被检测出”这一标准便会被延续下去,成为此类诉讼的参照标杆。这次判决是bug非重大过失,那下次呢?
哪里有代码,哪里就有bug。苦逼程序猿小哥(或者程序媛小妹^_^)能保证自己的代码就不会遇上这种极品事件?
一个bug让程序员走上法庭 索赔金额达400亿日元
那么,在bug难免的情况下,要怎样规避程序猿、系统开发商、系统运营商、用户的风险呢?
首先,责权明晰。围绕系统开发、使用、维护过程中各个角色的责任与权力进行清晰的界定与描述,避免后续发生推诿现象。
其次,合规。系统开发商拿到客户的需求先别忙着成立项目组,划分任务模块,先到客户环境中尽职调研一番,把客户的业务逻辑搞清,编制出清晰明确的项目任务书。
程序猿应严格按照任务书给出的业务逻辑编写安全的代码,项目组遵从软件安全开发生命周期,反复测试、迭代,尽量掐灭bug出现的苗头。敏感事务、非常态事务请求提交前应进行有效的前端检查。系统运营商应尽职审查与合理部署,避免人为引入触发bug的特殊情况。
最后,完善事件响应和危机处理。防备掉电、断网、黑客攻击、敏感数据泄露、数据迁移失误、热备失效、数据库崩溃、激增交易量导致系统延迟等等突发状况。
程序猿虽然自称为‘猿’,本质上还是肉体凡胎,虽然在debug的路上披荆斩棘,身后留下的bug依然不计其数(参见微软大侠,每月打啊打啊打补丁,还是补不完^_^)。但是,虽然“bug恒久远,一颗永流传”,程序猿小哥小妹们也不必太过惊慌。一套系统的诞生、成长、运行、维护、使用,是很多人共同运作的结果,在系统研发运维的道路上你不是一个人,在立功受奖或者追责赔偿上当然也不会只揪着你一个小小的程序猿不放。bug难免,但可以尽力免,努力修,做到能做到的,一切水到渠成。
欢迎加群讨论技术,1群:677373950(满了,可以加,但通过不了),2群:656732739