API 工具链研发的理论基础 - 流派
在乌托邦世界的理想国里,有一家企业,他提供的服务被世界上许许多多的客户使用着。人们都希望,能够使用自己趁手的工具/编程语言,来享受该服务带来的便利。
小欧是一个初入职场的年轻工程师,他怀着对前路的憧憬和对未来的迷茫加入了它,希望能帮助这家企业打造出好用的工具产品,满足用户的期待。
企业对外公开了大量的 API,用户通过自己趁手的编程语言来编写程序,编排 API,创建自己的需要的产品实例。
我们的故事,从小欧面临的第一个问题开始说起:API 是如何定义的。
源流
为了弄清楚这个问题,小欧研究了乌托邦世界中几乎所有的 API 设计工具,总结出了它们的一些共同的构成。
首先是结构类信息,包括 API 的:
组织方式,如何划分命名空间,例如按照不同的产品将 API 的定义分开,甚至可以采用多级的命名空间划分,比如产品大类 - 产品小类等等
抽象粒度,比如我们如果以一次 API 调用作为一个整体来看待的话,那么这些 API 应该如何分布在命名空间中?是以资源,还是以服务的形式来组织?和网络协议相关的声明(比如 HTTP 动词),应该在哪个层级中被定义?
基本构成,包括 API 的请求、响应以及错误信息的定义
其次是特性类信息,一般指用于特种用途,主要由周边系统来消费的信息。例如,SDK 的包名、国际化(i18n)的文本、API 文档的告示等等。
通常情况下结构类信息统一在 API 管理平台中来维护。而特性类信息则通常用于周边的系统,可以在系统中进行标注,也可以从周边的系统中抽取过来。结构类信息与特性类信息呈正交关系,一类信息的缺失并不会对另一类信息产生影响。
最后是类型系统,即对于 API 的定义,如何标注可以使其描述请求的和响应的类型信息。类型系统的完备性直接决定了是否可以完成后续的制品(例如 SDK、工具产品)生成的工作,同时也对 API 的编写提供了一定的约束能力。
一个较为完备的类型系统应提供以下几种类型:
基本类型(Base/Primitive Type)
复合类型
数组类型(Array Type)
对象类型(Object/Record Type)
联合类型(Union/Sum Type)(可选)
编者按:关于类型系统的知识,这里就不过多介绍了,感兴趣的读者可以看附录中的参考文献。
作为一个经验丰富的工程师,小欧觉得,采用更为主流的技术,从软件工程的角度来说更加稳妥。
小欧决定稳一手,先找个开源方案用起来。
抉择
在调研的过程中,小欧发现,企业内部似乎已经存在了多种 API 主流方案的流派,选择之旅,似乎在一开始就夭折了。
因为面前有两头拦路虎:
描述能力:企业中有大量风格迥异的存量 API,无法放弃,单一开源工具的描述能力不足以覆盖这些企业定制化的情形,包括但不限于 RPC 风格的 HTTP API、自定义的错误码格式,以及对于类型系统的扩展需求(例如枚举值需要定义三要素、命名、值和描述信息)。
约束能力:开源工具需要满足绝大多数人的需求,所以在约束能力方面往往比较宽松,例如许多工具支持将字段类型声明为动态类型或联合类型,而一些企业可能需要更严格的约束。
那么如何既拥抱主流的方案,又能够解决企业遇到的难题呢?经过科学的软件工程训练的小欧,自然想到了 SOLID 原则中的里式替换原则(Liskov Substitution principle)。
我们完全可以派生出一个完全符合企业现状的 API 声明格式,并且在其它的方案上实现一个转换逻辑,只要保证新的格式在我们关注领域的描述能力是主流方案的超集,那么在这个领域我们就可以新旧两种方案并存。我们当我们需要新方案的描述能力时,就可以切换到新方案去编写。
我们的小欧一拍脑袋,“嗨,这不难嘛,我也能写!”。
小欧花了 5 分钟时间,写下了这样的 API:
编者按:文中示例仅供参考,实际生产中的用法因为需要兼顾一些工程细节,会显得更为复杂些
优雅清爽、足够简单,API 定义的问题真的就这样解决了吗?
此时的小欧所不知道的是,更大的难题正在向他悄悄袭来。
参考阅读
项目实践:
经典书籍:
《Types and Programming Languages》,Benjamin C. Pierce
课程讲义:
《编程语言的设计原理》,北大熊英飞老师开设的一门课程,其中涉及了类型系统的理论基础
版权声明: 本文为 InfoQ 作者【李宇飞】的原创文章。
原文链接:【http://xie.infoq.cn/article/ed7c786f1b0b82143beb38e12】。文章转载请联系作者。
评论