通用订单搜索的API设计得失录
先把 Joshua Bloch 大神的 API PDF 放在这里膜拜下:“How to Design a Good API and Why it Matters.pdf”
总述###
在设计和实现通用订单搜索API的过程中,收获了一点关于API设计的得与失。总结下,希望能给后面的工作带来有益的帮助。
什么是好的API ?
简洁、清晰、易懂、易使用。 语义行为与选项分离。
- Easy to learn
- Easy to use, even without documentation
- Hard to misuse
- Easy to read and maintain code that uses it
- Sufficiently powerful to satisfy requirements
- Easy to extend
- Appropriate to audience
得:
从交易订单搜索能力化角度思考API,充分考虑了组合性,做到足够灵活,同时兼顾可读性。能够在较少改动和发布 trade-manage 的基础上,实现多样化的需求。
失:
在过于注重灵活性功能的情况下,有一些地方做的不够好,给使用方带来很多困扰。
本文主要讨论其得与失,希望能够给后来者带来有益的启发。
好的地方###
能力化####
强调从能力的角度而不是业务场景角度来思考API设计,考虑足够灵活性。 比如
定义交易订单搜索能力需要的参数,而不是依赖页面传过来的参数。通过定义的参数来组合搜索能力。
虽然搜索页面只需要传一个订单类型,但是后台允许传多个订单类型,为后续扩展性留下空间。
实现清晰####
基于自身定义的订单搜索参数,后台实现也非常简洁,而不需要做各种参数的解析和适配。对于搜索能力的稳定性和减少BUG的发生,是非常有益的。
一体两面,总有正面和反面的地方。由于通用订单搜索API 特别强调基础层的能力化和稳定性,在基础层与业务层之间缺乏一道友好的适配层,给业务方使用也带来了不少曲折。
详细的文档####
其实通用订单搜索API 的文档也做了不少工作。 接口入参 ,代码示例, 搜索入参的分类,包括代码里 java doc 其实也写得很清楚。 为什么业务方还来咨询呢? 一个原因,确实 API 设计有失当之处(考虑了最主要的PC列表页面搜索场景),对于业务方的简单需求(比如按照下单人ID)显得过于复杂了; 另一个原因,我认为开发人员对于陌生事物还是缺乏必要的耐心。当然我其实也有这个毛病。 如果说文档没有,代码里 java doc API 也缺失,过来咨询是没问题的,但是文档 ,javadoc 注释写的很明白了,花2分钟稍微扫一下,能够学到更多东西,就不会为了一个小需求来咨询了。
但是文档确实也有写的不够的地方。
比如返回的错误信息,文档没有写明。于是联调的时候,业务方遇到“非法的调用源”,一脸懵逼。需要有一些错误提示文档 ; 比如业务方遇到其他的错误,也不知道是什么原因,只能找我们来查。
比如没有突出常用的需要的东西。往往业务方内部依赖订单搜索列表的时候,基于应用场景,可能更多依赖于 订单状态,订单类型,粉丝ID,下单人ID,维权状态, 这些可以单独抽离一个更 brief 的订单搜索接口,并辅以文档,也许就不会遭遇不知道用哪个参数的问题了。 换句话说, 原来过于依赖能力化的角度思考接口,缺失的一块是, 基于应用场景的角度来思考接口。
不好的地方###
盲增参数####
先说下背景。当时是因为老搜索接口不太灵活,且参数与前端页面耦合比较紧,因此决定设计一个新的通用订单搜索接口,以提供更加灵活的搜索能力。
第一个失,就是不加思索地把老搜索接口里的参数全部拷贝过来。 比如说 毫无卵用的 订单标记,被废弃还让业务方传错的 pageSize, pageNo 。
经验: 由于新接口上线和接入通常有一个过程,其实不必要立即支持所有可能的搜索请求,而是先支持最常用的部分,然后根据情况扩展能力。 API 参数通常是越严格越少更好,公开了就收不回来了。
设计新接口入参时,可以参考老接口入参,但一定要慎之又慎,只取必需的,严格把控每个参数的必要性。
参数一定要仅仅针对接口服务而言,不要为了图方便把所有入参都混杂到一个类里,导致API语义不清,给业务方使用带来困惑。
继承滥用####
第二个失,过于追求复用代码和语义分离,继承层次比较深。
追求代码复用是好习惯,但不能过度。尤其 API 设计,应该以“清晰易使用”为重。 如下是个反例:
经验: 继承一般是为了实现不同的语义分离,比如基础通用参数与业务参数, 但强烈建议最多两层,继承层次绝不要超过两层。
public class PaginationParam extends BaseParam { }
public class GeneralOrderSearchParam extends PaginationParam {
protected String index = "trade_es_index";
/**
* 订单查询对象
*/
protected OrderSearchParam orderSearchParam;
// ...
}
public class OrderSearchParam extends BaseParam { }
使用体验不佳####
第三个失,没有充分考虑业务方的使用体验。
层次感不强
所有的搜索参数都平铺到一个 OrderSearchParam 的字段里,没有层次感, 业务方往往只要根据一个字段搜索,却要在繁多的搜索字段里搜索。
构造入参不方便
缺乏方便的构造搜索入参的方法,业务方需要写很无聊的 set , set , set 来构造搜索入参,代码会比较难看。 可以考虑使用 Builder 模式来构造常用参数。这个方法也可以解决 层次感不强 的问题。
经验: 应该对搜索字段进行区分对待,重点突出, 可以将最常用的搜索字段聚合成一个子搜索对象,有关联语义的搜索字段聚合成一个子搜索对象。 让业务方能够快速找到所需要的。通过提供易懂的 API 示例,也可以帮助业务方更好地使用 API。
常用搜索重复构建
由于设计参数时,参数取值过于原子化,强调灵活性与可组合性,需要业务方根据搜索场景自行组装参数,当多个业务方来对接某个常用搜索场景时,每个业务方都需要写相同的代码。
if (someCond) {
setOrderTypeDesc(Arrays.asList(xEnum.name(),yEnum.name(),zEnum.name()))
}
如果后续设计有变更,每个业务方都必须修改一遍。因此,更好的做法是,若组合语义占了常用80%的情形,那么应该清晰定义这些组合语义,内部做映射消化掉,而不是委托给外部。
参数混杂####
为了图方便,直接在原来的参数里加字段,而不是创造新的参数对象,导致原有的参数对象混杂不同的功能,给业务方使用带来困惑。
比如原来有个实时详情接口的入参 OrderQueryOptions , 非实时详情接口,多了个 withDeliveryInfo 可选参数,虽然放在原来的参数对象会省不少事,可是会让接口语义不清。对应实时接口来说,它根本不需要这个参数;对于非实时接口,又混杂了实时接口的入参。 两边都不讨好。
经验: 严格对接口入参进行控制,与接口服务无关的参数不允许加入。实现细节相关的东西不加入API,不公开。
暴漏内部细节的扩展方式####
为了具有更好的可扩展能力,减少发布,设计了一个入参 extendKeywords 。当要搜索的字段不在给定搜索入参时,可以直接指定 ES 里对应的字段及操作符来搜索。 虽然灵活了些,却将业务方与底层实现紧紧绑在一起。如果以后要改用其他的搜索引擎,这种就是非常难以摆脱的困扰了。对于API设计与实现来说,都是不好的决策。
小结###
API 是服务提供的接口抽象。 一旦公开,收回来会非常困难而且费力。因此,设计API 要精思细虑,严格把关每个入参字段、继承层次不要超过两次、充分考虑使用者体验、避免参数混杂、避免暴漏实现细节等问题。
API 好书推荐:《软件框架设计的艺术》,英文书名是:《 Practical API Design: Confessions of a Java Framework Architect 》
通用订单搜索的API设计得失录的更多相关文章
- Web API 设计摘要
近期读了一本微电子书 Brian Mulloy 所著<Web API Design>感觉颇多收获,特对其内容做了个整理摘要以便回想其观点精华以指导日常工作中的设计思路. 本文主要讲述 We ...
- API设计原则
译序 Qt的设计水准在业界很有口碑,一致.易于掌握和强大的API是Qt最著名的优点之一.此文既是Qt官网上的API设计指导准则,也是Qt在API设计上的实践总结.虽然Qt用的是C++,但其中设计原则和 ...
- (转)RESTful API 设计最佳实践
原文:http://www.oschina.net/translate/best-practices-for-a-pragmatic-restful-api 数据模型已经稳定,接下来你可能需要为web ...
- 一篇文章帮你梳理清楚API设计时需要考虑的几个关键点
本文作者是Enchant的架构师,他最近研究了Netflix.SoundCloud.谷歌.亚马逊.Spotify等公司的微服务实践,并根据自己的理解总结出了一套适用于现代Web和云技术的微服务实战经验 ...
- RESTful API 设计最佳实践
背景 目前互联网上充斥着大量的关于RESTful API(为了方便,以后API和RESTful API 一个意思)如何设计的文章,然而却没有一个"万能"的设计标准:如何鉴权?API ...
- 我所理解的RESTful Web API [设计篇]
<我所理解的RESTful Web API [Web标准篇]>Web服务已经成为了异质系统之间的互联与集成的主要手段,在过去一段不短的时间里,Web服务几乎清一水地采用SOAP来构建.构建 ...
- (转)Java API设计清单
转自: 伯乐在线 Java API设计清单 英文原文 TheAmiableAPI 在设计Java API的时候总是有很多不同的规范和考量.与任何复杂的事物一样,这项工作往往就是在考验我们思考的缜密程度 ...
- 来自HeroKu的HTTP API 设计指南(中文版)
原文转自:http://get.jobdeer.com/343.get 来自HeroKu的HTTP API 设计指南(中文版) 翻译 by @Easy 简介 本指南中文翻译者为 @Easy ,他是国内 ...
- 移动App的REST API设计实践
原文:http://www.jianshu.com/p/23cccb3a90b1 通讯协议 一些只是对服务器数据进行CRUD操作的App,通常采用HTTP协议,为了安全也可以采用HTTPS协议.IM软 ...
随机推荐
- Houdini技术体系 基础管线(四) :Houdini驱动的UE4植被系统 上篇
背景 之前在<Houdini技术体系 过程化地形系统(一):Far Cry5的植被系统分析>一文中已经对AAA游戏中过程化植被的需求有了一定的定义,后续工作就是如何用Houdini开发功能 ...
- maven报 Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.0:compile(defalut-compile) on project 项目名称:No such compile 'javac'
这个问题纠结了一天,在另外一个电脑是正常的,但是从服务器下载下来到另外一个电脑的时候却出现了如下图问题 看到javac大家都会想到是编译出现问题,而本地的配置如下图所示: 看着配置都是一致的,会是哪里 ...
- BCP文件导入SQLServer数据库遇到的问题
1. BCP文件插入sql server数据库,未指定数据库字段类型情况下,需要每个字段单独指定字段长度 2.文件中的存储值得类型 3.设置最大的类型
- cdh 安装调研
解决:No module named site http://blog.csdn.net/amgang/article/details/7030642 因为安装greenplum导致yum报如下错误: ...
- Qt编写高仿苹果MAC电脑输入法(支持触摸滑动选词)
最近有个朋友找我定制一个输入法,需要高仿一个苹果MAC电脑的输入法,MAC操作系统的审美无疑是相当棒的,于是乎直接拿以前的输入法高仿了一个,由于之前有做过输入法这块的开发,而且改进了四年,各种需求都遇 ...
- nodejs & npm & gulp 安装和配置
熟悉 Hellolily的过程中,了解了这个. 环境: ubuntu 14.04 LTS 64bit 源码安装方式: 下载最新源码:如果被和谐请自行想办法. 解压并编译安装: cd node-xxx ...
- C++ Msi函数判断应用是否已经安装
#include <Windows.h> #include <Msi.h> #pragma comment(lib, "Msi.lib") bool Che ...
- python2.7.X 升级至Python3.6.X
安装Python3 项目是在py3环境下进行编码的,正好yczhang默认的py版本是2,我们还需要安装py3才能让程序run起来,在此之前,需要安装开发工具包,因为要编译安装Python [root ...
- Druid连接池(一)
介绍 Druid首先是一个数据库连接池,但它不仅仅是一个数据库连接池,它还包含一个ProxyDriver,一系列内置的JDBC组件库,一个SQL Parser. 支持的数据库 Druid支持所有JDB ...
- 怎么访问不在网站目录下文件(iis虚拟目录设置)
很多时候,上传的文件多了,架设服务器当初设定的主目录所在盘空间往往就不够了,怎么办?这就需要设置虚拟目录.虚拟目录就是将其他目录以映射的方式虚拟到该FTP服务器的主目录下,这样,一个FTP服务器的主目 ...