2012年5月19日星期六

一个怪异的接口


一个怪异的接口
     -- 为了因糟糕接口而加班,而吐槽。
 



# 故事背景

     故事发生于2012-05-05,2012-05-12。


     接口声明如下:
      Long RequestGetInfo (TaskID taskId, Param param, Info info);
    输入:
       taskId,一个任务id标识针对某任务的请求。
       param,一系列的参数描述具体的请求,其中包含一属性session id区分不同调用者(详见后续部分)。
    输出:
       info,存放读取请求的结果。


     项目的需求,考虑在原来某功能函数的接口层实现过滤逻辑:
          过滤外界一样的调用者投递过来的一样(同参数)的请求。

# 规则描述

     为了能清楚的描述该逻辑,而不涉及过多具体细节,所以尽量以抽象形式描述,过滤规则两点如下:
     一、读取上次请求的结果,若处理逻辑已完成信息的返回则读取成功,否则失败。
     二、添加此次获取某信息的请求。

……

     以下描述两种不同的设计方案,”糟糕设计“与”良好设计“。

# 糟糕设计

     接口声明如下:
      Long RequestGetInfo (Param param, Info info);

     在原接口里修改,将过滤逻辑想办法增加进去。过滤逻辑有些复杂,需要完成的事情包括:
     a .  第一次函数调用,(一定)读取不到上次请求的结果,必须添加此次获取信息的请求。
     b1. 第二次函数调用,读取到上次请求的结果,但不添加此次的获取请求。

     b2. 第二次函数调用,未读取上次请求的结果(可能处理逻辑没来得及返回),也不添加此次的获取请求。
     下次函数调用,继续b1或b2步骤。
     c. 直到执行b1,后面的函数调用,则开始下面步骤,如下:
          c1 读取到上次结果,添加此次的获取请求。
          c2 未读取上次结果,不添加此次的获取请求。下次函数调用,继续步骤c。

     d. 补充一点,当外界调用(接口)者第一次调用时,接口层进去的业务层逻辑需分配之一个新的唯一session id给调用者。
          session id 用于区分不同(请求)调用者。需要由内部的业务层逻辑来负责完成分配session id该功能。

     最后,经多方面讨论以上的“糟糕设计”虽然可完成基本的过滤功能,但有一点它是完成不了的。区分出不同接口调用者。示例:
     callA     ---    RequestGetInfo (paramA, info)
     callB     ---    RequestGetInfo (paramB, info)
     callC     ---    RequestGetInfo (paramC, info)

     这样,当callA,callB,callC,都是首次过来请求,此时就RequestGetInfo 区分不出到底是谁调用,因为调用参数里不带有区分调用者身份的信息,参数paramA,paramB,paramC也完全可能是相同。该情况就很容易导致过滤逻辑出现错误。

     该接口现在不单纯是调用传递了,已经足够复杂了,虽然它处在接口层。而且还存在缺陷,可能导致结果错误。

# 良好设计

     接口声明如下:
      Long SubmitRequestGetInfo (Param param, Long resquetID);
      Long QueryRequestGetInfo ( Long resquetID, Info info);
      Long CreateSessionId (ID id);
     
     从几次“糟糕设计”的失败中,得出了一种可行方案,而且算是良好设计的方案。关键是,需要独立出该接口的不同部分,包括:
     a. 获取信息的请求 SubmitRequestGetInfo (...),接口层返回一个请求id给调用者;
     b. 调用者拿着请求id,读取上次请求的结果 QueryRequestGetInfo (...);
     c. 生成会话id以区分不同的会话请求 CreateSessionId (...)。

     这样做法改变了之前的思路,把过滤逻辑抛出去给调用者去关心了,而独立开以上三接口完全满足调用者使用需求,而且过滤逻辑看似‘淡淡’地消失了。调用者自己控制不重复请求的逻辑就很简单了,现在调用者需要逻辑描述如下:
     1. 请求获取信息之前,调用者需通过 CreateSessionId (...)得到一个会话id,以区分于其他调用者。
     2. 提交一个获取信息请求,返回一个请求ID。
     3. 用请求ID查询,信息结果是否返回。
          3.1 若结果返回,成功读取。则开始下一个获取信息,继续步骤2。
          3.2 若结果未返回,则等下次(定时)继续查询,继续步骤3。

     就这样,没了,足够简单的逻辑吧。在保证结果正确的前提下,其逻辑又清晰明了。

# 吐槽牢骚

     谁该做的事,而谁不该做的事,需要分得清楚,然后就各做各的的吧。简单即美!

     

没有评论:

发表评论