目录结构设计原则:模块化、版本隔离、平台分离、依赖清晰、用户友好
说实话,我见过太多 SDK 项目死在目录结构上。不是代码写得不好,而是开发者打开压缩包就懵了——文件散落一地,不知道从哪开始看。我自己早期也踩过这个坑,一个 SDK 塞了十几个文件夹,连我自己三个月后都找不到头绪。
后来我总结出五条原则。每次设计目录结构前,我都会拿这五条过一遍。今天咱们一条一条拆开聊。
模块化:每个功能块独立成包
模块化说白了就是「高内聚、低耦合」。每个模块只做一件事,并且做好。我习惯把 SDK 拆成这么几块:
- 核心层(core)——基础数据结构、公共工具函数、错误码定义
- 功能层(features)——具体业务能力,比如登录、支付、推送
- 接口层(api)——对外暴露的公共 API,用户直接调用的入口
- 内部实现(internal)——不对外暴露的实现细节,比如网络请求、数据库操作
举个例子。我做过一个支付 SDK,一开始把签名逻辑、网络请求、UI 弹窗全塞在一个文件夹里。后来要支持新支付渠道,改一个地方崩三个功能。重构后按模块拆分,每个渠道独立文件夹,改支付完全不影响支付宝。这才算真正解耦。
payment/ 而不是 doPayment/。用户找起来更直观。
版本隔离:别让旧版本污染新项目
版本隔离这件事,我吃过一次大亏。有一次发布 SDK 时,不小心把旧版本的动态库留在包里,用户集成后链接了旧版本,跑出来一堆诡异崩溃。查了两天才发现是版本冲突。
现在我的做法很简单:每个大版本独立目录,版本号写在文件夹名里。
sdk/
├── v1.0.0/
│ ├── lib/
│ ├── include/
│ └── docs/
├── v2.0.0/
│ ├── lib/
│ ├── include/
│ └── docs/
└── v3.0.0/
├── lib/
├── include/
└── docs/
用户想用哪个版本,直接复制对应目录就行。不会出现「我明明升级了怎么还是旧代码」的尴尬。
latest 或 current 这种软链接。很多用户会直接引用这个路径,一旦你更新了链接指向,他们的构建就不可复现了。
平台分离:不同平台各走各的路
SDK 经常要支持多个平台——Android、iOS、Windows、macOS、Linux。如果混在一起,用户找文件就像大海捞针。
我建议按平台分顶层目录:
sdk/
├── android/
│ ├── libs/
│ └── src/
├── ios/
│ ├── Frameworks/
│ └── Sources/
├── windows/
│ ├── bin/
│ └── lib/
└── linux/
├── lib/
└── include/
每个平台目录内部再按模块组织。这样用户一眼就知道「我是 iOS 开发者,只看 ios/ 文件夹就行」。
我记得有一次,一个用户反馈说「你们的 Windows 版 SDK 怎么有 .dylib 文件?」我一看,原来是平台目录没分开,iOS 的库混进了 Windows 包里。从那以后,平台分离就成了我的铁律。
依赖清晰:让用户一眼看懂需要什么
依赖管理是 SDK 发布中最容易被忽视的环节。用户拿到 SDK,第一件事就是看「我还需要装什么?」
我习惯在 SDK 根目录放一个 dependencies/ 文件夹,里面按模块列出所有外部依赖:
dependencies/
├── core/
│ ├── openssl-1.1.1/
│ └── zlib-1.2.11/
├── payment/
│ ├── libcurl-7.79.1/
│ └── jsoncpp-1.9.5/
└── push/
├── protobuf-3.19.0/
└── libwebsockets-4.3.0/
同时,每个模块目录下放一个 DEPENDENCIES.md 文件,写明依赖的版本、用途、以及可选的替代方案。
用户友好:从用户视角出发
最后这条最容易被忽略。你想想看,用户第一次打开你的 SDK 压缩包,他最先想找什么?
- 快速开始文档
- 示例代码
- API 参考
- 库文件
- 头文件
所以根目录应该长这样:
sdk/
├── README.md # 一句话介绍 + 快速链接
├── GETTING_STARTED.md # 5 分钟集成指南
├── examples/ # 可直接运行的示例项目
├── docs/ # 完整文档
├── api/ # 公共头文件
├── lib/ # 编译好的库文件
└── CHANGELOG.md # 版本更新记录
我见过最离谱的 SDK,根目录放了 30 多个文件夹,连个 README 都没有。用户得一个个点开猜用途。这不是技术问题,是态度问题。
嗯,这里要注意:示例代码一定要能直接跑起来。我见过太多 SDK 的示例代码缺依赖、缺配置、甚至缺文件。用户跑不通示例,第一反应就是「这 SDK 有问题」。
五条原则的关系图
下面这张图是我自己画的结构,帮你理清五条原则之间的层级关系:
一个完整的目录结构示例
最后,我把五条原则整合成一个完整的 SDK 目录结构。你可以直接拿来当模板:
my-sdk/
├── README.md
├── GETTING_STARTED.md
├── CHANGELOG.md
├── LICENSE
│
├── v1.0.0/
│ ├── android/
│ │ ├── libs/
│ │ ├── src/
│ │ └── build.gradle
│ ├── ios/
│ │ ├── Frameworks/
│ │ └── Sources/
│ └── docs/
│ ├── api-reference/
│ └── migration-guide/
│
├── v2.0.0/
│ ├── android/
│ ├── ios/
│ └── docs/
│
├── examples/
│ ├── android/
│ ├── ios/
│ └── web/
│
├── dependencies/
│ ├── core/
│ └── features/
│
└── tools/
├── code-generator/
└── dependency-checker/
这个结构我用了好几年,团队新成员上手很快,用户反馈也很好。说白了,目录结构设计不是炫技,是替用户省时间。你替用户省了时间,用户就会信任你的 SDK。