RPC接口将所有输入输出封装成类是合理设计吗

关于rpc接口的输入和输出,一直有一种观点是将输入和输出都包装成单个request和response类。本文,我们就分析一下这种方式是否是一个合理的设计。

先说输入, 这个我先说结论,当且仅当输入参数过多时,才应该做封装。其他情况下完全没有做封装的理由。

对于将输入参数包装成request类的理由,无非是下边这些

  • 修改接口参数时保持兼容性
  • 可以定义通用的抽象request类,方便做统一管理

首先,第一条完全就是个伪命题,第一次看到这种论断的时候,我也差一点被绕进去,但是仔细思考一下,就会发现这个完全不成立。

即便使用request体的形式,如果接口提供方增加了必传的字段,调用方仍然需要增加这个参数才能调用,那相比于直接传参数,没有解决任何问题。而这种问题实际上也是无法解决的,因为就不应该让这种情况出现。接口提供方有义务保证后续的修改是向前兼容的。而对于增加的是非必传字段这种情况,即便不包装request类,也可以通过适配器的形式实现新接口并兼容老接口,后续再找机会异步的将老接口下线。

第二条的话,确实存在一定意义。

  • 比如在抽象类里加一些统一的请求参数,这一点我认为做在框架里更合适,没有必要暴露在业务代码中
  • 再比如添加统一的参数校验,但是单纯为这种效果的话,我觉得用一个过于抽象的类是不合适的,而是应当一类相关的业务用一个抽象类,因为一类业务才会有这种需求。同时,即便不包装成request类,这类需求也没什么难做的,因为它的难度本身就不在输入结构不统一上。

而将输入参数包装成request类的最大问题就是会破坏代码的可读性,会造成语义不明确。本身类似 queryById(long id) 这么一个方法的语义是非常明确的,扫一眼接口定义就可以看清楚输入输出。但是强行封装之后,这个接口究竟要输入什么就不是那么明确了。同时,如果request中有三个参数,是否传入任意组合都能返回结果呢?这也是靠看接口看不明白的。而正常的用参数定义的话,可以使用适配器的形式定义一系列接口,接口调用方也更容易理解。

封装输入参数的唯一条件就是传入参数过多,这时候需要通过其他的方式,比如注释、文档,去约定接口的合法输入值和升级方案。

接下来说输出,将输出结果封装成一个response体,相对于封装输入参数,会合理一些,但也不能乱用。一般将输出结果封装的目的就是包一层返回状态码。

这一点实质上就是强迫调用方来了解接口的异常情况。我们知道,基本的设计原则中有一条叫「接口隔离原则」,其具体描述是 Clients should not be forced to depend upon interfaces that they do not use。对于这儿的情况要类似,如果调用方确实不关心请求成功或者失败的原因,那就不应该强迫调用方来了解这个。比如我就是要查个数,只存在查到或者查不到两种情况,并不想关心到底为什么没查到。

所以,在设计接口的时候,需要慎重的考虑接口的异常原因是否是一个应当提供出去的信息,在此基础上,才能说保障response合适或者不合适。

综上所述,盲目的一味去封装所有输入和输出参数,一定是不可取的。对于何时应该做封装,何时不应该,务必要做慎重的考虑。大家有什么想法的话,也可以跟我沟通。

原文地址:https://lichuanyang.top/posts/20888/