自己动手写 SDK 的经验技巧分享

大家好,我是鱼皮。

最近因为工作需要,自己动手写了一些项目的通用 SDK。在编写的过程中,我阅读和参考了不少公司中其他大佬写的 SDK,也总结了一些开发 SDK 的经验和技巧,给大家分享下~

在此之前,必须先给大家解释一下啥是 SDK。

啥是 SDK ?

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

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

使用 SDK 有什么好处呢?

举个例子,假设公司有很多系统都需要实现文件上传功能。之前看过我文章的朋友应该知道,一个优秀的文件上传功能并不好做,要考虑很多点,比如分块、断点续传、秒传、文件存储、文件管理等。

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

显然,我们不需要给每个系统都去开发文件上传,而是只需要有一个团队舍身而出,编写一套 通用的 文件上传 SDK,然后让需要实现同样功能的系统引用就行了,这样就 大大减少了工作量、提高了开发效率

有点前人造车,后人享乐的意思~

编写 SDK 又称 造轮子 ,好的轮子不仅能够帮助团队省时省力,还能够减少一些项目在相同功能上的差异。就不要说同一个功能,小王写的要运行 1 秒,小李写的要运行 1 小时!

而假设每个系统都去开发同样的功能,那就是 重复造轮子 ,在大多数情况下,不是明智之举。

理解了啥是 SDK 后,来看看如何写出优秀的 SDK 吧~

手写 SDK 经验总结

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

易用性

如今,现成的轮子实在太多了!如何让你的轮子脱颖而出呢?那就要先提升 SDK 的易用性。

我自己在技术选型时,就会倾向于优先选择简单易用的 SDK,最好是几行代码就能轻松使用,而不是必须要我读完老长一份文档,再写个几十行代码才能生效。

就和产品说明书一样,太复杂直接把人劝退。

我们可以通过以下几点提高易用性:

统一调用

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

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

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

那大家觉得哪种更易用呢?

集中配置

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

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

# 服务器配置
server:
port: 8081
# 数据库配置
db:
ip: 10.0.0.1

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

良好命名

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

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

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

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

可理解性

有时,用户可能不满足于简单地使用你的 SDK,而是希望阅读你的 SDK 源码来进一步了解,用的才更放心。

因此,除了易用外,还要让你的 SDK 便于理解,不能金玉其外败絮其中。

这个就和编码习惯有很大的关系了,无论是写 SDK 也好,还是做项目也罢,都要做到以下几点:

结构清晰

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

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

统一风格

统一风格的目标很简单:让项目看起来是同一个人写出来的。

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

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

编写注释

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

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

说明文档

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

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

可扩展性

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

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

轻量依赖

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

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

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

自定义实现

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

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

// 按照 '-' 切分
date = DateUtils.parse('2021-01-18')

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

怎么实现呢?

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

// 按照 '-' 切分
parseRule = ':'
date = DateUtils.parse('2021-01-18', parseRule)

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

// 自定义解析器
interface MyParser extends Parser {
// 需要用户自己实现
void doParse();
}
// 指定解析器
date = DateUtils.parse('2021-01-18', MyParser.class);

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

高效稳定

其实,开发 SDK,尤其是在大厂开发 SDK,是个很 “坑” 的工作,我相信做过的朋友会感同身受。

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

我们需要注意以下几点:

1. 测试

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

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

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

2. 兼容性

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

举个例子,SDK 0.1 版本时,函数的定义是这样的:

boolean isValid(String str)

结果突然在 0.2 版本时改成了:

String checkValid(StringBuilder str)

这样就会导致用户升级时一脸懵逼,怎么报了一堆找不到函数呢?

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

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

3. 暴露异常

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

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


以上就是本期分享,建议学编程的同学多自己动手写 SDK,并且按照本文的总结去优化它,对提升编程能力真的很有帮助!

最近整理了我原创的 140 篇编程经验和技术文章,欢迎大家阅读,一起成长!️

指路:https://t.1yb.co/ARnD

我是鱼皮,最后求个 点赞 ,这将是我持续创作的最大动力,谢谢

最新文章

  1. Redis简单案例(三) 连续登陆活动的简单实现
  2. 从CLR角度来看值类型与引用类型
  3. Flv 视频格式(转)
  4. 近期刷题的c语言总结。
  5. python复习。知识点小记
  6. HDU 5617 DP
  7. HDU2874 LCA Tarjan
  8. Django框架的安装
  9. LayaAir引擎开发HTML5最简单教程(面向JS开发者)
  10. DButils实现数据库表下划线转bean中驼峰格式
  11. Oracle回收站的清理方法
  12. Qt532的QString输出各种编码的16进制数组(测试代码)
  13. 之前的一些Oracle的经验总结
  14. ViewPager实现Recycle机制和响应notifyDataSetChanged
  15. angular学习笔记(三十)-指令(2)-restrice,replace,template
  16. java命令启动jar包
  17. 935. Knight Dialer
  18. Mybatis-plus之RowBounds实现分页查询
  19. UVA 814 The Letter Carrier's Rounds(JAVA基础map)
  20. Android中的“再按一次返回键退出程序”实现 (转) 按返回键退出程序时进行提醒

热门文章

  1. root密码找回
  2. SQL语句(六)分页查询和联合查询
  3. 管理员权限的窗口,收不到WM_COPYDATA
  4. Mybatis源码解析2—— 实例搭建
  5. MyBatis学习02(配置解析)
  6. Java课程设计 ssm电影售票选座管理系统 电影网站的网页设计与制作mysql
  7. 【Java】jeesite使用学习
  8. 【笔记】二分类算法解决多分类问题之OvO与OvR
  9. LNMP 方式部署 zabbix 5.0
  10. VMware上安装的Ubuntu不显示全屏解决方法