API如何设计

在之前《应对变化》中提到模块之间合的策略:缩小依赖范围,API是两个模块间唯一的联结点

怎么才是一个好的API设计呢?最近项目中正好碰到一件关于一个API引起的相爱相恨的事件

数据来源于外部系统,外部系统通过回调把数据传输过来,内部系统通过系统A进行接受,接受完之后,转发给系统B

接受回调api大概是:

1
systemA.callback(long userId,Object data);

整体两个参数,一个userId表示这个数据是谁的、一个data表示数据本身

对于系统B来讲,他的业务要求,这数据必须要知道用户名字,必须在数据上打标签,所以跟系统A商量,要不你把username也随便转给我吧

系统A一想,那也是两秒的事,因为本身在接受数据时也得对userId校验,取个username也不麻烦,不废话了,你要就给你

因此系统B接受数据api设计成:

1
systemB.receive(long userId,String username,Object data);

一切都是行云流水,大家都很happy,如期发布上线

爱情总是在转角处遇到,上线完,QA同学一顿操作,却发现系统B没有如期显示出数据,系统B觉得是系统A没传来数据;咋办呢?心虚的系统A只能查查日志

1
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:

1
systemB.receive(long userId,String username,Object data);

关照上面的要求:

问题一:API中包含的知识有重复:userid,username

问题二:客户端也就是systemA并不需要username,但被强迫要知晓并要按规则赋值

问题三:站在设术实现角度,api中增加参数username,而不是需求角度

总结

示例虽小,日常工作中常常碰到这类问题,如果这个例子上线成功,每个人都觉得这是一次成功的交付,但回头复盘,发现了很多理论缺乏,惯性思维使然造成的不合理,难维护,难扩展的设计

由此看出,日常的CRUD并不是没有技术含量,而是我们有没有深刻认知

公众号:码农戏码
欢迎关注微信公众号『码农戏码』