最近在修一个听起来很简单的bug,但是因为以前代码写的太差导致很难实现。要能实现的话,工作量非常大。
这个事情可以作为一个很好的反面教材。
背景
安装office补丁的时候,如果office正在运行,则不进行安装,等2小时候,如果office还在运行,则上报本次安装任务失败,失败原因是office正在运行。
当前的代码是有这个逻辑的,但是上报的是任务成功。所以和预期不太符合。需要修改。
我们的业务和通信是分成了2个进程,这是一个非常好得设计,因为通信进程做客户端非常重要,一旦通信进程挂了的话,想远程控制客户端就很难了。这2个进程
是用RPC来通信的。
直观修改方案
其实如果接口拆分很好的话,这个需求非常简单,只需要在业务进程那边找到这个场景的处理逻辑,然后把原来上报失败的地方,改成成功即可。但是看了代码之后,
发现没那么简单。
问题
首先,架构上是把业务和通信分开了,但是架不住码农瞎搞。
正常情况下,业务和通信进程的接口应该是:
- 补丁安装列表:包含补丁的名字,安装状态
- 补丁安装列表的长度(因为要进程间通信,需要知道列表中有多少个成员)
- 任务成功与否
看了现在的代码发现,以前的人为了偷懒,不传任务成功与否。只传了补丁安装列表和长度。那本次任务是成功还是失败怎么判断。
竟然是通过遍历补丁安装列表来间接推断的。
如果补丁安装列表的长度是负数,表示任务失败,如果补丁安装列表长度是0,表示这次任务成功,但是一个补丁也不装。
如果补丁安装列表长度大于0,遍历所有安装补丁的状态,有一个是失败,则说明这次任务是失败的。
天才啊!!!!
但是这样的话,上面提到的场景就没招了,没有补丁被安装===>补丁安装列表长度为0,但是需要上报为失败。
分析
这样的设计有下面几个问题:
- 通信进程不需要理解业务,但是他们把业务放到了通信进程,这会导致接口不稳定,业务一旦变化,就要改接口,接口兼容性很差。这次这个例子就是这样,
为了兼容这个场景,我要把接口全改了,但是那么多地方在调用老接口,改动造成的影响面肯定是很大的。 - 判断安装成功怎么能依赖补丁任务列表个数呢,这个-1是一个很不合理的判断。最好是写一个函数,专门负责判断安装任务是否成功,这样的话,后期改代码也很好改。
感悟
这些细节不可能在架构里面约定的,再好的架构也架不住码农瞎搞。