zoukankan      html  css  js  c++  java
  • 通用订单搜索的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设计,考虑足够灵活性。 比如

    1. 定义交易订单搜索能力需要的参数,而不是依赖页面传过来的参数。通过定义的参数来组合搜索能力。

    2. 虽然搜索页面只需要传一个订单类型,但是后台允许传多个订单类型,为后续扩展性留下空间。

    实现清晰####

    基于自身定义的订单搜索参数,后台实现也非常简洁,而不需要做各种参数的解析和适配。对于搜索能力的稳定性和减少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 》


  • 相关阅读:
    百度mp3地址解密码
    VB 在EXE后附加信息
    截屏函数
    Base64和StrToByte
    The Android ION memory allocator, DMABUF is mentioned as well
    DDC EDID 介绍
    Memory management for graphic processors TTM的由来
    科普 写display driver的必看 How video card works [2D的四种主要操作]
    GEM vs TTM
    DMABUF 背景介绍文章 Sharing buffers between devices
  • 原文地址:https://www.cnblogs.com/lovesqcc/p/9902305.html
Copyright © 2011-2022 走看看