在之前《应对变化》[1]中提到模块之间合的策略:缩小依赖范围,API是两个模块间唯一的联结点
怎么才是一个好的API设计呢?最近项目中正好碰到一件关于一个API引起的相爱相恨的事件
数据来源于外部系统,外部系统通过回调把数据传输过来,内部系统通过系统A进行接受,接受完之后,转发给系统B
接受回调api大概是:
systemA.callback(long userId,Object data);
整体两个参数,一个userId表示这个数据是谁的、一个data表示数据本身
对于系统B来讲,他的业务要求,这数据必须要知道用户名字,必须在数据上打标签,所以跟系统A商量,要不你把username也随便转给我吧
系统A一想,那也是两秒的事,因为本身在接受数据时也得对userId校验,取个username也不麻烦,不废话了,你要就给你
因此系统B接受数据api设计成:
systemB.receive(long userId,String username,Object data);
一切都是行云流水,大家都很happy,如期发布上线
爱情总是在转角处遇到,上线完,QA同学一顿操作,却发现系统B没有如期显示出数据,系统B觉得是系统A没传来数据;咋办呢?心虚的系统A只能查查日志
log:systemB return error,username is empty
原来原来是因为这个用户的username是空,系统B拒绝接受了,怎么username会为空呢?username怎么能为空呢?
找到用户系统,用户系统解释了,一个用户在注册时并不一定有username,有username,email,usercode三个值中的任何一个值就可以了
这时该怎么办呢?相爱相杀时刻到了
系统B:要不你把这三个值都传给我?
系统A:我还得再改下代码,测试后发版本,要不你自己从用户系统取吧
系统B:传一个可以,怎么三个就不可以了,不都一样吗?
系统A:太麻烦了,你自己取了,想怎么控制就怎么控制
系统B:你是不爱我了
系统A:你怎么就不理解我呢
温习一下一个好的API设计要求:
缩小依赖范围,就是要精简API;API要稳定得站在需求角度,而不是how角度
1.API包含尽可能小的知识。因为任何一项知识的变化都会导致双方变化2.API也要高内聚,不应强迫API的客户依赖不需要的东西3.站在what角度;而不是how,怎么技术实现的角度
上面示例的问题就在系统B接受数据api:
systemB.receive(long userId,String username,Object data);
关照上面的要求:
问题一:API中包含的知识有重复:userid,username
问题二:客户端也就是systemA并不需要username,但被强迫要知晓并要按规则赋值
问题三:站在设术实现角度,api中增加参数username,而不是需求角度
总结
示例虽小,日常工作中常常碰到这类问题,如果这个例子上线成功,每个人都觉得这是一次成功的交付,但回头复盘,发现了很多理论缺乏,惯性思维使然造成的不合理,难维护,难扩展的设计
由此看出,日常的CRUD并不是没有技术含量,而是我们有没有深刻认知
References
[1]
《应对变化》: http://www.zhuxingsheng.com/blog/coping-with-change.html