以前听说过软件系统中有定时炸弹,今天我领教了代码中的地雷。
所谓地雷,它的特性是安装容易拆除难,下面段代码完全符合地雷的特性。
public static void GetAvail(SegmentType segment, out int avail) { if(segment.StartDate < DateTime.Now) segment.ClientTypes.ForEach(n=>n.MaxAvail = 0); //.... }
这是一个底层方法,依赖于它的代码较多,即它的扇出较大。
这个函数的本意是获取avail,但在获取avail的同时染指了segment实例,而这个行为并未通过函数的名称表现出来。这就意味着,只想通过该函数来获取avail的程序员得到了一个意外的结果,传入的segment实例被意外地修改了,而这个修改肯定不会在它的设计之中,所以接下来就可能会出现莫名其妙的逻辑错误--他踩上这颗地雷。
现在,我们发现了这个“地雷”要将其排除掉,是否可以直接将其删除呢?我只能说你可以试试,如果你胆子够大且不怕系统出现其他问题。
现在,我们不能保证不存在这样的上下文,即依赖于GetAvail中的那段所谓的“地雷”代码才能够正确执行。如果这样的上下文存在,那么贸然地删除这段代码的同时也将引爆这颗“地雷”。
而要排除这颗“地雷”,其惊险程度不亚于排除一颗真正的地雷,因为你不知道到底有多少上下文直接或间接地依赖于这个函数。你必须将这些依赖一个一个地列出来,然后逐一分析,然后做出正确的决定。这其中的险在于没有一个参照物可以帮你证明你已经将所有的依赖都分析完了。所以当产品发布时,你还得提心吊胆。
如何解决,地雷问题。我认为有两点可以有所帮助。
- 模块化,尽量将功能的范围限制在模块内,因此也限制了可能的错误的波及范围
- 将扇出较大的功能放在系统底层构架的范围内,而对系统底层构架的任何变动都要做严密的监视。
也希望听听大家对代码中的地雷的看法。