2、API设计原则:接口的稳定性与兼容性、命名规范与一致性、参数设计的最佳实践、返回值与错误码设计
好,咱们直接进入正题。API 设计这件事,说白了就是 SDK 的「门面」。用户第一眼看到的就是你的接口长什么样。接口设计得好,用户用得顺手,口碑自然就好。设计得烂,哪怕底层实现再牛,用户也会骂娘。
我这些年做 SDK,踩过不少坑,也重构过好几轮接口。今天就把我积累的一些原则和心得,掰开了揉碎了讲给你听。
2.1 接口的稳定性与兼容性
先聊聊稳定性。你想想看,用户基于你的 SDK 写了上千行代码,结果你发个新版本,接口名改了、参数类型变了、返回值结构也换了。用户什么感受?想杀人的心都有。
接口一旦发布,就不要轻易修改。 这是我给自己定的铁律。
那怎么保证兼容性呢?我总结了几个实操方法:
- 只增不减:新版本只加新接口,绝不删除旧接口。旧接口可以标记为
@Deprecated,但别直接删。 - 只扩不缩:给现有接口加参数时,用可选参数或默认值。别把必填参数改成选填,也别减少参数个数。
- 语义不变:接口的行为不能变。比如
getUserInfo()之前返回用户基本信息,新版本不能突然改成返回订单信息。
核心原则: 让用户升级 SDK 时,不需要改任何业务代码。这才是真正的兼容。
我记得有一次,我们团队为了追求「代码整洁」,把某个接口的返回类型从 List 改成了 Set。结果用户那边直接编译报错,因为他们的代码里用了 list.get(index)。那次事故之后,我们专门加了一条规范:返回类型的变更,必须走完整的废弃流程。
2.2 命名规范与一致性
命名这件事,看着简单,其实特别考验功力。好的命名,用户看一眼就知道怎么用。烂的命名,用户得翻半天文档。
我个人习惯遵循几个原则:
- 动词 + 名词:比如
startService()、stopService()、getConfig()。动词在前,名词在后,一目了然。 - 统一前缀:同一个模块的接口,用相同的前缀。比如支付模块都用
pay_开头:pay_order()、pay_refund()、pay_query()。 - 避免缩写:除非是行业通用缩写(比如
ID、URL),否则别自己造缩写。我见过有人用getUsrInf(),用户还得猜Usr是User还是Usher。
小技巧: 命名之前,先问问自己:「如果用户不看文档,能不能猜出这个接口是干嘛的?」如果答案是否定的,那就重新想个名字。
一致性也很重要。同一个 SDK 里,getXXX() 和 fetchXXX() 不能混用。要么都用 get,要么都用 fetch。我见过最离谱的,同一个类里既有 getData() 又有 retrieveInfo(),用户直接懵了。
2.3 参数设计的最佳实践
参数设计,是 API 设计里最容易出问题的地方。我见过太多「参数地狱」——一个接口十几个参数,调用的时候得对着文档一个一个填。
怎么避免?我分享几个经验:
- 参数越少越好:理想情况下,一个接口不超过 3 个参数。超过 3 个,考虑用配置对象。
- 必填参数放前面,选填参数放后面:这是约定俗成的规矩。用户调用时,必填参数一眼就能看到。
- 用枚举代替布尔值:
setMode(true)和setMode(Mode.ENCRYPTED),哪个更清晰?显然是后者。 - 提供合理的默认值:用户不传的参数,SDK 应该能自动用最合理的默认值。别让用户为了一个「超时时间」去翻文档。
// 不好的设计
void connect(String host, int port, boolean useSSL, int timeout, String proxy);
// 好的设计
void connect(String host, int port);
void connect(String host, int port, ConnectionConfig config);
// ConnectionConfig 提供默认值
class ConnectionConfig {
boolean useSSL = true;
int timeout = 30000;
String proxy = null;
}
注意: 参数类型尽量用基础类型或标准库类型。别用自定义类型做必填参数,除非那个类型本身就是业务实体。否则用户还得先构造一个对象才能调用你的接口,体验很差。
2.4 返回值与错误码设计
返回值设计得好,用户处理起来就轻松。设计得不好,用户得写一堆 if-else 来兜底。
我建议遵循「统一返回结构」的原则。不管接口成功还是失败,返回的数据结构都保持一致。比如:
{
"code": 0, // 0 表示成功,非 0 表示错误
"message": "success",
"data": { ... } // 业务数据
}
这样用户只需要判断 code 字段,就能知道接口是否成功。不用去猜返回的是 null 还是空对象。
错误码设计也有讲究:
- 错误码要有层次:比如
1001表示「参数错误」,1002表示「参数缺失」,1003表示「参数格式错误」。这样用户可以根据错误码的前两位,快速定位问题大类。 - 错误信息要友好:别只返回
ERROR或FAILED。要告诉用户具体哪里错了,比如参数 'timeout' 不能为负数。 - 预留扩展空间:错误码不要从 1 开始连续排,而是留一些间隔。比如用
1001、2001、3001,方便以后插入新的错误码。
避坑指南: 我曾经设计过一个错误码系统,把错误码和 HTTP 状态码绑在一起。结果后来发现,有些业务错误(比如「用户余额不足」)用 4xx 不合适,用 2xx 又不对。最后不得不重构整个错误码体系。所以,错误码应该独立于传输层协议,别跟 HTTP 状态码耦合。
另外,返回值里尽量别返回 null。如果某个字段可能为空,用 Optional 或者空对象代替。用户不用写一堆 if (xxx != null) 的防御代码。
知识体系总览
下面这张图,把 API 设计原则的核心逻辑串起来了。你可以对照着看,心里有个整体框架。
好了,API 设计原则这部分就聊到这儿。说白了,核心就一句话:站在用户的角度思考。你设计的每个接口、每个参数、每个错误码,最终都是给用户用的。多想想用户会怎么用、会怎么错、会怎么骂你,你的设计自然就会越来越好。
可可精品资料库