Loading...
Loading...
Compare original and translation side by side
Orchestration Layer (Actions) Service Layer (Shared Mechanics)
├── owns business rules ├── owns reusable operations
├── owns state transitions ├── owns provider/SDK interactions
├── owns auth/ownership checks ├── owns command execution details
├── owns failure classification ├── owns health checks / readiness
├── owns retries / user-facing errors └── returns structured results
└── calls service functions编排层(Actions) 服务层(共享机制)
├── 负责业务规则 ├── 负责可复用操作
├── 负责状态转换 ├── 负责与提供商/SDK交互
├── 负责权限/归属校验 ├── 负责命令执行细节
├── 负责故障分类 ├── 负责健康检查/就绪状态
├── 负责重试/面向用户的错误处理 └── 返回结构化结果
└── 调用服务函数| Design Principle | Do | Don't |
|---|---|---|
| API shape | Composable capability blocks | One giant "do everything" method |
| Inputs/outputs | Explicit params, structured returns | Hidden global state, reaching into DB |
| Migration | Extract one block, replace one caller, verify, then migrate rest | Refactor everything at once |
| Domain logic | Keep auth, policy, error classification in actions | Let service mutate domain state directly |
| Extraction trigger | Logic repeated across 2+ callers | Logic used once (over-abstraction) |
| 设计原则 | 建议 | 禁忌 |
|---|---|---|
| API形态 | 采用可组合的能力模块 | 不要设计一个“包办一切”的巨型方法 |
| 输入/输出 | 使用明确参数、结构化返回 | 不要依赖隐藏全局状态、直接访问数据库 |
| 迁移方式 | 先提取一个模块,替换一个调用方,验证后再迁移剩余部分 | 不要一次性重构所有内容 |
| 领域逻辑 | 将权限、策略、错误分类保留在Actions中 | 不要让服务直接修改领域状态 |
| 提取触发条件 | 逻辑被2个及以上调用方重复使用 | 不要提取仅被使用一次的逻辑(过度抽象) |
// Good: composable, each caller chooses what to use
createManagedSandbox(...)
prepareRepo(...)
detectPackageManager(...)
installDependencies(...)
runBuildCommand(...)
startSandboxRuntime(...){ ready, previewUrl, proxyPort }// Good: composable, each caller chooses what to use
createManagedSandbox(...)
prepareRepo(...)
detectPackageManager(...)
installDependencies(...)
runBuildCommand(...)
startSandboxRuntime(...){ ready, previewUrl, proxyPort }| Anti-Pattern | Problem |
|---|---|
| God service | One huge function hides all control flow |
| Leaky service | Service mutates database tables directly |
| Inconsistent API | Each function uses different argument styles and error semantics |
| Over-abstraction | Extracting logic used by only one caller |
| 反模式 | 问题 |
|---|---|
| 上帝服务 | 单个巨型函数隐藏了所有控制流 |
| 泄漏服务 | 服务直接修改数据库表 |
| 不一致API | 每个函数使用不同的参数风格和错误语义 |
| 过度抽象 | 提取仅被一个调用方使用的逻辑 |
// emailService.ts — shared mechanics
export async function sendWelcomeEmail(params: { to: string; name: string }) {
const html = `<h1>Welcome ${params.name}</h1>`;
await emailProvider.send(params.to, "Welcome", html);
}
// userSignup.ts — orchestration (owns WHEN to send)
if (user.marketingOptIn) {
await sendWelcomeEmail({ to: user.email, name: user.name });
}
// adminInvite.ts — orchestration (different business rule, same mechanic)
await sendWelcomeEmail({ to: invitee.email, name: invitee.name });// emailService.ts — 共享机制
export async function sendWelcomeEmail(params: { to: string; name: string }) {
const html = `<h1>Welcome ${params.name}</h1>`;
await emailProvider.send(params.to, "Welcome", html);
}
// userSignup.ts — 编排层(负责决定发送时机)
if (user.marketingOptIn) {
await sendWelcomeEmail({ to: user.email, name: user.name });
}
// adminInvite.ts — 编排层(不同业务规则,相同操作机制)
await sendWelcomeEmail({ to: invitee.email, name: invitee.name });New feature? → Write in action first → See repeated ops? → Extract to service
→ No repetition? → Keep in action新增功能?→ 先在动作层编写 → 发现重复操作?→ 提取到服务层
→ 无重复?→ 保留在动作层