6.3 KiB
6.3 KiB
| name | description |
|---|---|
| design-an-interface | Backend Agent 使用此技能探索多種 API 介面設計方案。根據「Design It Twice」原則,產生多種截然不同的設計,比較後選擇最佳方案。觸發時機:API 設計階段(Stage 4),由 be-api-design 技能呼叫。 |
/design-an-interface — 介面設計探索
Backend Agent 使用此技能探索 API 介面設計方案。
基於 "A Philosophy of Software Design" 的 "Design It Twice" 原則:第一個想法通常不是最好的。產生多種截然不同的設計,然後比較選擇。
職責
- 針對模組需求,產生 2-3 種截然不同的介面設計方案
- 每種方案使用不同的設計約束
- 比較方案的優劣
- 協助選擇或合成最佳方案
輸入
- 模組描述(來自 PRD 的功能性需求)
- 使用者故事和操作場景
輸出
- 多種介面設計方案(含介面簽名、使用範例、優劣分析)
- 方案比較和建議
流程
收集需求
↓
產生 2-3 種設計方案(平行子代理)
↓
呈現各方案
↓
比較方案(介面簡潔性、通用性、實作效率、深度)
↓
合成最佳方案或選擇最適方案
步驟說明
1. 收集需求
在設計之前,先了解:
- 這個模組解決什麼問題?
- 誰是呼叫者?(其他模組、外部使用者、測試)
- 關鍵操作有哪些?
- 有什麼限制?(效能、相容性、現有模式)
- 什麼應該隱藏在內部?什麼應該暴露在外?
提問:「這個模組需要做什麼?誰會使用它?」
2. 產生設計方案(平行子代理)
同時產生 3+ 種截然不同的方案。每個方案必須遵循不同的約束:
方案 A:最小化方法數 — 目標 1-3 個方法
方案 B:最大化彈性 — 支援多種使用情境
方案 C:最佳化最常見操作
方案 D(可選):參考特定範式或框架的設計
每個方案需包含:
- 介面簽名(types / methods)
- 使用範例(呼叫者如何使用)
- 這個設計隱藏了什麼複雜度
- 這個方案的取捨
3. 呈現方案
逐一展示每個方案,包含:
- 介面簽名:types, methods, params
- 使用範例:呼叫者如何實際使用
- 隱藏的複雜度:小介面隱藏大量實作(好)vs 大介面薄實作(差)
讓使用者充分吸收每個方案後再進行比較。
4. 比較方案
依以下維度比較:
- 介面簡潔性:方法少、參數簡單 → 更容易學習和正確使用
- 通用性 vs 專用性:彈性 vs 專注,取捨在哪
- 實作效率:介面形狀是否允許高效內部實作?
- 深度:小介面隱藏大量複雜度(深模組,好)vs 大介面薄實作(淺模組,差)
- 正確使用的容易度 vs 誤用的容易度
用文字討論取捨,不要只用表格。強調方案分歧最大的地方。
5. 合成最佳方案
最佳設計往往結合多個方案的洞見。詢問:
- 「哪個方案最適合你的主要使用情境?」
- 「其他方案有沒有值得納入的元素?」
評估標準
來自 "A Philosophy of Software Design":
介面簡潔性:方法少、參數簡單 = 更容易學習和正確使用。
通用性:能否處理未來的使用情境而不需要修改。但要避免過度通用。
實作效率:介面形狀是否允許高效實作?還是迫使內部實作變得彆扭?
深度:小介面隱藏大量複雜度 = 深模組(好)。大介面薄實作 = 淺模組(避免)。
深模組(好):
┌─────────────────────┐
│ Small Interface │ ← 方法少,參數簡單
├─────────────────────┤
│ │
│ │
│ Deep Implementation│ ← 複雜邏輯隱藏在內部
│ │
│ │
└─────────────────────┘
淺模組(避免):
┌─────────────────────────────────┐
│ Large Interface │ ← 方法多,參數複雜
├─────────────────────────────────┤
│ Thin Implementation │ ← 只是穿隧
└─────────────────────────────────┘
反模式
- 不要讓子代理產生相似的設計 — 強制截然不同
- 不要跳過比較 — 價值在於對比
- 不要在此階段實作 — 這純粹是介面設計
- 不要基於實作工作量評價方案 — 只看介面品質
Golang 介面設計範例
// 方案 A: 最小化方法數
type UserRepository interface {
GetByID(ctx context.Context, id string) (*domain.User, error)
Save(ctx context.Context, user *domain.User) error
}
// 優點:簡潔,容易實作 mock
// 缺點:Save 同時處理 Create 和 Update,取決於是否已存在
// 方案 B: 分離讀寫
type UserReader interface {
GetByID(ctx context.Context, id string) (*domain.User, error)
List(ctx context.Context, page, limit int) ([]*domain.User, error)
}
type UserWriter interface {
Create(ctx context.Context, user *domain.User) error
Update(ctx context.Context, user *domain.User) error
Delete(ctx context.Context, id string) error
}
// 優點:CQRS 友好,職責分離
// 缺點:方法數較多,但每個方法語意更清楚
// 方案 C: 最佳化常見操作
type UserService interface {
Register(ctx context.Context, email, password, name string) (*domain.User, error)
Authenticate(ctx context.Context, email, password string) (*domain.User, error)
GetProfile(ctx context.Context, id string) (*domain.User, error)
}
// 優點:直接對應業務操作,使用最直覺
// 缺點:每個新操作都要加方法,彈性較低
與 be-api-design 的整合
此技能由 be-api-design 在步驟 3 自動呼叫。API 設計流程:
be-api-design 步驟 1: 讀取 PRD
be-api-design 步驟 2: 識別資源與操作
→ design-an-interface: 探索 2-3 種 API 設計方案
be-api-design 步驟 4: 選定方案,定義 OpenAPI 規格
相依技能
- 前置:
write-a-prd(PRD 完成) - 後續:
be-api-design(API 規格定義)