仓库源文

.. Kenneth Lee 版权所有 2018-2020

:Authors: Kenneth Lee :Version: 1.0

接口的封装层次问题


接口不但体现在功能上,也体现在其他属性上(比如性能),所以接口上的可见还是不可 见,对于很多人来说,是不清楚的。本文厘清一下这个问题。

接口是一方给另一方提供服务,我们把提供方称为provider,使用方称为consumer。比如 我们有这么一个接口:::

    ouput=provider.service(input)

这是这个接口的功能,把input这个数据转换成output这个数据,这个数据可以是内存中的 数据,可以是设备IO空间寄存器中的值,可以是函数的入口参数,也可以是一个文件。 provider和consumer可以是硬件,也可以是软件。但接口的名,主要还是两个:input和 output(当然,如果你非要算,service本身也是)

当然,其实这背后还隐藏了不少其他名的,比如服务是否具有原子性(多个请求能否被自 动排序),(多个不同的请求能否同时执行),连续性(处理发生异常的时候,如何保证 数据的自洽),等等。

但这个不是我们这个讨论的重点,我们暂时认为那些概念被埋藏在input和output的外延中 了。

provider怎么处理这个service,这是provider内部被封装的细节,很多工程师认为,这是 “内部现实”,和接口无关。

但考虑一个问题,这个地方在支持某个业务的时候,我们发现这个接口成了我们的性能瓶 颈,深入分析我们发现,comsumer提供的input是150个数据为分块提供给provider的,而 provider内部呢,是按100个数据为单位进行整体处理的,这样一组合,本来可以更高效的 流程平白速度降低了。

可能其实comsumer并不在乎这个数据多大,你说好100个数据为单位处理,给你100也不是 不行,但你把100封装起来,这就帮不了你了。

问题是,如果把100暴露出来,provider以后就不好升级了,如果以后处理能力变化了,最 优的处理单元是200怎么办?provider有很多选择,一种是暴露一个handle_block的概念, 要求comsumer aware这个概念。第二种选择是引入流的概念(这同时会引入会话的概念) ,要求comsumer允许数据在provider内部“残存”,以便provider自己合并流。所以,一旦 竞争压力上来,你认为不会暴露的接口,“自然”会暴露。竞争压力是一只无形的手,它最 终决定接口的形态,接口不是被设计出来的,它是自然生成的。

接口发展的过程,就好像一个七绕八绕的胶皮水管,一开始都是软软的,有的地方弯,有 的地方直,但只要冲水,什么地方会直起来,这是“本身”存在的。

所以,我们设计接口,不能局限在“什么接口是好接口”这个问题上,而应该看到数据流本 身的特性是什么,基于这个来控制熵增,没有这个认识,就开始设计复杂的接口形态的, 最终只会成为发展的负担。