一个怪异的接口
-- 为了因糟糕接口而加班,而吐槽。
项目的需求,考虑在原来某功能函数的接口层实现过滤逻辑:
b2. 第二次函数调用,未读取上次请求的结果(可能处理逻辑没来得及返回),也不添加此次的获取请求。
最后,经多方面讨论以上的“糟糕设计”虽然可完成基本的过滤功能,但有一点它是完成不了的。区分出不同接口调用者。示例:
接口声明如下:
# 故事背景
故事发生于2012-05-05,2012-05-12。
接口声明如下:
Long RequestGetInfo (TaskID taskId, Param param, Info info);
输入:
taskId,一个任务id标识针对某任务的请求。
param,一系列的参数描述具体的请求,其中包含一属性session id区分不同调用者(详见后续部分)。
输出:
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。
就这样,没了,足够简单的逻辑吧。在保证结果正确的前提下,其逻辑又清晰明了。
# 吐槽牢骚
谁该做的事,而谁不该做的事,需要分得清楚,然后就各做各的的吧。简单即美!
没有评论:
发表评论