• 手写SDK的秘诀


    什么是SDK?

    SDK(Software Development Kit)即 软件开发工具包 ,就是帮助我们开发出软件的工具集合,除了代码之外,一般还要搭配文档、示例等。

    一般 SDK 都是需要 引入 到项目中使用的。比如学 Java 的朋友最早接触的 JDK,就是用来开发 Java 软件的工具包,使用时需要编写 类似 import java.util.* 的语法来引入。此外,大部分的 SDK,都是需要通过人工或项目管理工具,将其文件下载到指定路径才能引入。

    使用SDK的好处?

    比如公司有许多系统都需要实现文件上传的功能

    文件上传设计:https://mp.weixin.qq.com/s/3QXe4MSObJTP43M2gXWSlA

    显然我们不需要给每个系统都去开发文件上传,而是只要有一个团队编写一套通用的文件上传SDK,然后让需要实现同样功能的系统去引入即可。可以大大提高开发效率。

    在这里插入图片描述

    因此,编写SDK也就是写一个功能、造一个轮子。好的轮子可以减少一些项目在相同功能上的差异,也可以省去每个系统都去开发同样功能的时间。至此,我们已经了解了什么是SDK,来看看如何写出优秀的SDK。

    手写SDK经验总结

    好的 SDK 应该具有简单易用、通俗易懂、便于扩展、高效稳定等特点。

    易用性

    在技术选型的时候一般选择简单易用的SDK,最好是几行代码就能轻松使用,而不是必须要读完很长的一份文档,再写个几十行代码才能生效。

    如何提高易用性?

    1、统一调用

    将复杂的功能进行封装,对外提供统一的调用入口,尽量屏蔽一些实现细节,减少用户调用的流程和对参数的理解成本。

    举个例子,下面是两种日期处理函数。用户不需要关心他们是如何实现的,只需要知道怎么用、传递哪些参数、得到哪些返回值就行了。

    // 第 1 种:需要 new 对象
    DateUtils dateUtils = new DateUtils();
    dateUtils.setDate('2021-08-31');
    Date date = dateUtils.parse();
    
    // 第 2 种:直接调用
    Date date = DateUtils.parse('2021-08-13');
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    显然是第二种更加方便快捷一些。

    2、集中配置

    将复杂的参数配置化,不需要让用户到处写参数,而是通过一个配置文件统一管理。

    Java主流开发框架Springboot就是典型的例子,假如用户想要改变内嵌服务器启动的端口、亦或者改变数据库连接的地址,不需要写代码,而是改一下配置文件即可:

    # 服务器配置
    server:
      port: 8081
    # 数据库配置
    db:
     ip: 10.0.0.1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    此外,这样也便于维护项目和实现多环境

    3、良好的命名

    给 SDK 的函数取名称时,尽量让它符合用户的习惯。

    比如具有解析功能的函数,可以叫 “parseXXX”;判断是否为空的函数,可以叫 “xx.isEmpty” 等。最好能做到让用户不看文档,只通过函数名称和参数,就知道你这个函数是做什么的。

    因此,想要写出好的 SDK,首先要多用、多参考别人的 SDK,养成习惯后你就会发现,大家起名儿都差不多。

    但也要注意一点,如果可以,尽量不要让你 SDK 中的类名(函数名)和别人的完全一致,否则可能给用户带来困扰:这么多同名的函数,我该用哪个呢?哪个是你开发的 SDK 呢?

    可理解性

    有的时候用户不满足于简单的使用你的SDK,而是希望阅读SDK源码来进一步理解,因此除了易用意外还需要让SDK便于理解,而这一点就和编码有很大的关系,需要做到以下几点:

    1、结构清晰

    把代码按照功能或类别进行整理,放到指定的目录下。常见的做法有分包、分层等,让人一眼就知道每个目录下的文件的作用。

    比如下面这个经典的 Java 项目结构,service 目录是编写业务逻辑的、constant 是存放常量的、utils 是存放工具类的等等,都很清晰:

    2、统一风格

    比如代码缩进都用 4 个空格、命名都用驼峰式等。尤其是功能相似的代码,一定要保持命名和用法的统一!比如解析文本的函数,不要一会叫 “parseXXX”、一会儿又叫 “jiexiXXX”

    但实际上,团队开发中,很难做到这点。因此才需要有一套通用的代码规范,大家都去遵守规范,才能让项目更好理解、更便于维护。

    在这里插入图片描述

    3、编写注释

    最好给 SDK 中的每个类和函数的 开头 都加上注释,这样用户在使用 SDK 时,甚至都不需要看文档,直接看代码注释就能知道它是干嘛的、怎么用。

    随便打开 Java SDK 或者网上知名 SDK 中的一个函数,一般都能看到这些注释,包括对函数功能的描述、参数含义、返回值含义等:

    在这里插入图片描述

    4、说明文档

    除了注释外,还要编写一个说明文档(用户手册),包括如何引入 SDK 、有哪些功能、应该怎么使用等等,甚至还可以补充一些关键的实现细节、以及常见的问题列表。

    这点也会极大地影响用户的选择。就我个人而言,没有文档的 SDK 我一般是不会选用的,万一出了事我找谁呢?

    可扩展性

    编写 SDK 的一大难点是:不仅要考虑到大部分通用的使用场景,还要满足小部分用户定制化的需求。

    因此,SDK 的可扩展性是很重要的,但怎么提升呢?

    轻量依赖

    一方面,我们可以尽量减少 SDK 本身对其他类库的依赖。

    举个例子,假如你要做一个很轻小的工具类,可能只有几十 KB,那就没有必要再引入一个几百 KB 的依赖库了,得不偿失!别人也不乐意用啊!

    轻量依赖不仅可以减少 SDK 的体积,更关键的是可以减少依赖冲突的可能性。我自己也曾经遇到过很多次这样的尴尬局面:引入一个工具类后,整个项目就跑不起来了!

    自定义实现

    为了提高SDK的通用性和灵活性,在设计SDK的时候,除了提供默认的实现外,建议提供一个通用的接口或者抽象类,让用户来集成,编写自己的实现方式。

    举个例子,假设我们要编写一个日期解析类,默认的解析规则是按照短横分割字符串:

    // 按照 '-' 切分
    date = DateUtils.parse('2023-10-24')
    
    • 1
    • 2

    如果只能做到这点,那这个 SDK 就很死板。因为用户可能想按照冒号或其他规则来解析。

    怎么实现呢?

    我们可以允许用户自己传入分割字符:

    // 按照 '-' 切分
    parseRule = ':'
    date = DateUtils.parse('2023-10-24', parseRule)
    
    • 1
    • 2
    • 3

    还可以让用户自己来控制解析的方式:

    // 自定义解析器
    interface MyParser extends Parser {
      // 需要用户自己实现
      void doParse();
    }
    // 指定解析器
    date = DateUtils.parse('2023-10-24', MyParser.class);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    这两种方式在 SDK 的设计中屡见不鲜,此外还可以让用户自行编写或指定配置文件,也能提高灵活性。

    高效稳定

    随着使用你 SDK 的用户越来越多,可能会发现各种各样莫名其妙的问题;而且 SDK 作为相对底层的依赖,对使用方的影响也是无法估量的。所以,不想经常加班改 Bug 的话,就要保证你 SDK 的稳定性。

    我们需要注意以下几点:

    1. 测试

    为了保证每个功能都是正常的,我们可以编写 单元测试(UT)来最大程度上地覆盖 SDK 的功能和代码。

    尤其是每次改动代码后、发布新版本之前,都要再完整地执行一遍测试,不要盲目自信。

    此外,还可以通过 压力测试 来估算 SDK 的执行效率,比如每秒最多同时执行 3 次、每次要执行 500 毫秒等。建议将这些信息补充到说明文档中,给用户一些预期。当然也可以尝试通过压测来优化 SDK 的性能。

    1. 兼容性

    重要的函数和接口尽量减少改动,尤其是函数名、入参和返回值!

    对于比较大的改动,可以新写一个函数,并且给老函数打上类似 @Deprecated 的注释,表示已过时,引导用户去用新的。

    此外,还可以在 版本号 上做做文章,小改动时只改变小版本号,比如 0.0.1 到 0.0.2;大改动时才改变大版本号,比如 1.0 到 2.0。这样可以给用户一个预期:这次改动很大,可能会存在不兼容。

    1. 暴露异常

    要让用户感知到 SDK 代码中可能抛出的异常,交给他们去进行相应的处理,防止出现一些意料之外的错误。

    此外,SDK 要合理地打印日志,尤其是异常日志,在出了问题时要让调用者知道是出了什么问题,便于排查。

    写在最后

    本文是我在学习如何开发一个合格的SDK后将笔记分享出来,如果大家对这系列感兴趣的话,后续将分享一篇开发企业微信机器人的SDK。
    今天也是2023.10.24,程序员节,祝各位节日快乐,天底下再也没有难改的bug。按时下班,好好休息!!💪

  • 相关阅读:
    P21 元组 列表 P22 列表 list P23 多维列表
    session认证
    【C语言】入门——结构体
    一文看懂推荐系统:物品冷启01:优化目标 & 评价指标
    RequestMappingHandlerMapping类的简介说明
    理解 React 18 中的 useId Hooks
    【校招VIP】前端操作系统之存储管理加密
    昊帆生物提交注册:预计2022年度收入约5亿元,朱勇为实控人
    [Spark、hadoop]Spark Streaming整合kafka实战
    hadoop_概念
  • 原文地址:https://blog.csdn.net/m0_60496161/article/details/134017755