mcpField
S
sdk-dx

sdk-dx

github.com/jonathimer开发87115 次安装34 周前更新
代码仓库

关于 sdk-dx

面向 SDK 设计者的开发者体验技能,提供 API 设计、错误处理、类型安全和 IDE 适配方面的指导。还涵盖版本管理、迁移指南及发布前检查。

主要功能

  1. 01简化常见用例并逐步呈现复杂度
  2. 02设计清晰且可操作的错误信息
  3. 03应用类型安全与 IDE 自动补全
  4. 04遵循语义化版本并规划弃用
  5. 05编写迁移指南与质量检查清单

适用场景

  1. 01设计易上手的 SDK API
  2. 02改进 SDK 的错误提示
  3. 03规划破坏性变更与版本升级
  4. 04检查 SDK 发布准备情况

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/jonathimer/devmarketing-skills --skill sdk-dx

安装后在 Claude Code 中输入/sdk-dx确认已加载。

附带文件README.md

详细介绍

SDK 设计与开发者体验

最好的 SDK 营销,就是让开发者忍不住谈论你的 SDK。当你的 SDK 让开发者觉得高效又能干时,他们就会成为你的拥护者。如果它让他们感到挫败,再多的营销也无济于事。

概述

SDK 开发者体验(DX)涵盖开发者使用你的库时的所有感受:

  • 发现:他们能多轻松地找到并安装它?
  • 学习:他们能多快理解如何使用它?
  • 使用:他们日常使用时的效率如何?
  • 调试:他们能多轻松地解决问题?
  • 升级:他们采用新版本时能有多省心?

出色的 SDK 开发者体验是一种竞争优势。开发者会选择让他们觉得自己很聪明的工具。

开始之前

查看 developer-audience-context 技能,了解:

  • 你的目标开发者使用哪些语言和框架?
  • 最常见的 IDE/编辑器配置是什么?
  • 他们对你的问题领域有多少经验?
  • 他们用过哪些竞品 SDK?喜欢或不喜欢哪些方面?

SDK 设计决策应基于对用户的深入了解。

API 设计原则

原则 1:针对常见场景进行优化

最常见的使用场景应只需最少的代码。

良好的设计:

# Common case: send a simple message
client.messages.send("Hello world", to="+1234567890")

# Full control when needed
client.messages.send(
    body="Hello world",
    to="+1234567890",
    from_="+0987654321",
    status_callback="https://...",
    media_urls=["https://..."]
)

糟糕的设计:

# Every call requires full configuration
message = Message(
    body="Hello world",
    to=PhoneNumber("+1234567890"),
    from_=PhoneNumber(config.get_default_from()),
    options=MessageOptions(
        status_callback=None,
        media_urls=[]
    )
)
client.messages.send(message)
原则 2:渐进式呈现

从简单开始,按需逐步展现复杂性。

// Level 1: Simplest possible usage
const result = await client.analyze("Hello world");

// Level 2: Common options
const result = await client.analyze("Hello world", {
  language: "en",
  features: ["sentiment", "entities"]
});

// Level 3: Full control
const result = await client.analyze("Hello world", {
  language: "en",
  features: ["sentiment", "entities"],
  model: "v2-large",
  timeout: 30000,
  retries: { max: 3, backoff: "exponential" }
});
原则 3:快速且明确地失败

尽早捕获错误,并提供可执行的提示。

良好:

# Validation at construction time
client = MyClient(api_key="")
# Raises immediately: ValueError: API key cannot be empty.
# Get your API key at https://dashboard.example.com/keys

# Clear error at runtime
client.users.get("invalid-id")
# Raises: NotFoundError: User 'invalid-id' not found.
# Use client.users.list() to see available users.

糟糕:

client = MyClient(api_key="")  # No validation
result = client.users.get("invalid-id")
# Returns: None (is this an error? empty result? who knows?)
# Or worse: raises generic Exception with stack trace
原则 4:合理的默认值

默认值应无需配置即可适用于大多数场景。

// This should just work without configuration
const client = new MyClient({ apiKey: process.env.MY_API_KEY });

// Sensible defaults:
// - Automatic retries with exponential backoff
// - Reasonable timeouts
// - JSON content type
// - Standard auth headers
// - Connection pooling

能引导用户的错误消息

错误消息就是文档。让它们发挥作用。

错误消息框架

每条错误消息都应回答:

  1. 发生了什么?
  2. 为什么会发生?
  3. 如何修复?
好与坏的错误消息

良好:

AuthenticationError: Invalid API key provided.

The API key 'sk_test_abc...' (test key) cannot be used for
production requests.

To fix this:
1. Go to https://dashboard.example.com/keys
2. Copy your production API key (starts with 'sk_live_')
3. Update your environment variable: MY_API_KEY=sk_live_...

Docs: https://docs.example.com/authentication

糟糕:

Error: 401 Unauthorized
区分错误类型

创建特定的错误类型,供开发者捕获:

from myapi.errors import (
    AuthenticationError,  # Invalid/missing credentials
    AuthorizationError,   # Valid creds, insufficient permissions
    ValidationError,      # Invalid input data
    NotFoundError,        # Resource doesn't exist
    RateLimitError,       # Too many requests
    ServerError,          # Our fault, retry might help
)

try:
    client.users.get(user_id)
except NotFoundError as e:
    # Handle missing user specifically
except AuthenticationError as e:
    # Handle auth issues specifically
except MyAPIError as e:
    # Catch-all for other API errors
在错误中包含上下文
// Bad: generic error
throw new Error("Invalid parameter");

// Good: contextual error
throw new ValidationError({
  message: "Invalid phone number format",
  field: "to",
  value: "+1abc",
  expected: "E.164 format (e.g., +14155551234)",
  docs: "https://docs.example.com/phone-numbers"
});

类型安全

类型安全是永不过时的文档。

TypeScript 最佳实践
// Define explicit types for all inputs and outputs
interface User {
  id: string;
  email: string;
  name: string;
  createdAt: Date;
  metadata?: Record<string, unknown>;
}

interface CreateUserInput {
  email: string;
  name: string;
  metadata?: Record<string, unknown>;
}

// Return types are explicit
async function createUser(input: CreateUserInput): Promise<User> {
  // ...
}

// Use discriminated unions for responses
type ApiResponse<T> =
  | { success: true; data: T }
  | { success: false; error: ApiError };
以自动补全为导向的设计

针对 IDE 自动补全进行设计:

// Good: autocomplete shows all options
client.messages.create({
  to: "+1...",     // IDE shows: (property) to: string
  body: "...",    // IDE shows: (property) body: string
  // User types 'me' and sees 'mediaUrls' autocomplete
});

// Bad: requires memorization
client.send("messages", { /* what goes here? */ });
枚举和字面量类型
// Good: constrained values with autocomplete
type MessageStatus = "queued" | "sending" | "sent" | "failed";

interface Message {
  status: MessageStatus;  // IDE shows valid values
}

// Bad: any string accepted
interface Message {
  status: string;  // No guidance, errors at runtime
}

IDE 集成

让发现变得轻松

合理组织 SDK,让 IDE 功能助力开发者:

// Namespace methods logically
client.users.get(id)
client.users.list()
client.users.create(data)
client.users.update(id, data)
client.users.delete(id)

// After typing 'client.users.' the IDE shows all user operations
随处提供 JSDoc/文档字符串
/**
 * Creates a new user in your organization.
 *
 * @param input - The user details
 * @param input.email - Must be a valid email address
 * @param input.name - Display name (max 100 characters)
 * @returns The created user with generated ID
 * @throws {ValidationError} If email format is invalid
 * @throws {ConflictError} If email already exists
 *
 * @example
 * const user = await client.users.create({
 *   email: "[email protected]",
 *   name: "Jane Developer"
 * });
 */
async createUser(input: CreateUserInput): Promise<User>
内联示例
def send_message(self, body: str, to: str, **kwargs) -> Message:
    """
    Send an SMS message.

    Args:
        body: The message content (max 1600 characters)
        to: Recipient phone number in E.164 format

    Returns:
        Message object with ID and status

    Example:
        >>> message = client.messages.send(
        ...     body="Hello from Python!",
        ...     to="+14155551234"
        ... )
        >>> print(message.status)
        'queued'
    """

版本策略

语义化版本控制

严格遵循 semver:

  • MAJOR:不兼容的变更(移除内容、更改签名)
  • MINOR:新功能(向后兼容)
  • PATCH:错误修复(向后兼容)
哪些情况属于不兼容变更

不兼容变更(需要提升主版本号):

  • 移除公开方法或属性
  • 更改方法签名
  • 更改返回类型
  • 更改默认行为
  • 不再支持某个语言/运行时版本

不属于不兼容变更(提升次版本号或修订号):

  • 添加新方法
  • 添加可选参数
  • 弃用(但不移除)功能
  • 修复导致不正确行为的错误
弃用流程
import warnings

def old_method(self):
    """
    .. deprecated:: 2.3.0
       Use :meth:`new_method` instead. Will be removed in 3.0.0.
    """
    warnings.warn(
        "old_method() is deprecated, use new_method() instead. "
        "See migration guide: https://docs.example.com/migrate-v3",
        DeprecationWarning,
        stacklevel=2
    )
    return self.new_method()

迁移指南

迁移指南结构
# Migrating from v2 to v3

## Overview
Version 3 introduces [major change] and removes [deprecated feature].
Migration typically takes [time estimate].

## Breaking Changes

### 1. Client Initialization
**Before (v2):**
```python
client = MyClient(key="...")

之后(v3):

client = MyClient(api_key="...")

原因:与其他 SDK 参数保持一致。

2. [下一个不兼容变更]

...

已移除的弃用功能

  • client.old_method() - 请改用 client.new_method()
  • LegacyClass - 请改用 ModernClass

新功能

  • [让迁移值得进行的功能]

需要帮助?

  • [迁移支持渠道]
  • [迁移问题答疑时段]

### Codemods and Automation

When possible, provide automated migration:

```bash
# Provide migration scripts
npx @myapi/migrate-v3

# Or codemods
npx jscodeshift -t @myapi/codemods/v2-to-v3 src/

让 SDK 符合语言习惯

语言惯用法

Python:使用 snake_case、上下文管理器和生成器

# Pythonic
with client.batch() as batch:
    for user in client.users.list():
        batch.add(user.send_notification("Hello"))

# Not Pythonic
users = client.getUsers()
batch = client.createBatch()
for i in range(len(users)):
    batch.addOperation(users[i].sendNotification("Hello"))
batch.execute()

JavaScript:使用 Promise、async/await 和解构

// Idiomatic JS
const { data, error } = await client.users.get(id);

// Not idiomatic
client.users.get(id, function(err, result) {
    if (err) { /* callback hell */ }
});

Go:使用错误返回、接口和通道

// Idiomatic Go
user, err := client.Users.Get(ctx, userID)
if err != nil {
    return fmt.Errorf("getting user: %w", err)
}

// Not idiomatic
user := client.Users.Get(userID)  // panics on error
匹配生态系统惯例
  • 使用开发者期望的包管理器(npm、pip、gem、go get)
  • 遵循该语言中热门库的命名惯例
  • 与热门框架集成(Express、Django、Rails)
  • 支持常见的测试模式

SDK 质量检查清单

发布前
  • 所有公共 API 都有文档
  • 所有公共 API 都有类型(语言支持时)
  • 错误消息包含解决步骤
  • 文档中的代码示例都会自动测试
  • 更新了包含所有变更的变更日志
  • 为不兼容变更提供迁移指南
  • 为已移除的功能提供弃用警告
打造出色的开发者体验
  • 可在 < 5 分钟内通过快速入门实现成功
  • IDE 自动补全适用于所有操作
  • 错误可按具体类型捕获
  • 重试逻辑可处理暂时性故障
  • 日志可配置且实用
  • 调试模式会显示请求/响应详情

工具

SDK 生成
  • OpenAPI Generator:根据 OpenAPI 规范生成 SDK
  • Swagger Codegen:另一种生成器
  • Speakeasy:现代 SDK 生成平台
  • Fern:类型安全的 SDK 生成
测试
  • VCR/Betamax:录制和重放 HTTP 交互
  • WireMock:模拟 HTTP 服务
  • Pact:契约测试
文档
  • TypeDoc:TypeScript 文档
  • Sphinx:Python 文档
  • GoDoc:Go 文档
  • YARD:Ruby 文档

相关技能

  • docs-as-marketing:展示 SDK 能力的文档
  • api-onboarding:用户首次使用 SDK 的体验
  • changelog-updates:有效传达 SDK 变更
  • developer-sandbox:无需安装即可试用 SDK
  • developer-audience-context:了解 SDK 用户

评论

支持 Markdown