关于 architecture-patterns
面向开发者的架构参考 Skill,介绍软件系统的组织方式及其取舍。涵盖多种架构模式、选择依据与常见陷阱。
主要功能
- 01单体与模块化单体指南
- 02微服务与无服务器模式
- 03事件驱动设计模式
- 04整洁架构与六边形架构
- 05DDD 与系统迁移模式
适用场景
- 01为新应用选择架构
- 02规划服务边界与部署方式
- 03逐步迁移遗留系统
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ miles990/ claude-software-skills --skill architecture-patterns安装后在 Claude Code 中输入/architecture-patterns确认已加载。
详细介绍
架构模式
概述
架构模式为构建软件系统提供经过验证的解决方案。选择合适的架构对于可扩展性、可维护性和团队效率至关重要。
模式
单体架构
描述:包含所有应用功能的单个可部署单元。
主要特点:
- 部署和开发简单
- 共享数据库和内存
- 调试直接明了
适用场景:
- MVP 和初创公司
- 小型团队(< 10 名开发者)
- 简单的领域逻辑
最佳实践:
src/
├── modules/ # Feature-based organization
│ ├── users/
│ ├── orders/
│ └── products/
├── shared/ # Cross-cutting concerns
└── infrastructure/ # External services
微服务架构
描述:由可独立部署的服务组成的分布式系统。
主要特点:
- 独立部署和扩展
- 各服务可采用不同技术
- 故障隔离
适用场景:
- 需要自主性的大型团队
- 边界明确的复杂领域
- 对高可扩展性的需求
主要组件:
| 组件 | 用途 | 工具 |
|---|---|---|
| API Gateway | 入口点、路由 | Kong, AWS API Gateway |
| Service Discovery | 服务注册 | Consul, Kubernetes DNS |
| Config Management | 集中式配置 | Spring Cloud Config, Consul |
| Circuit Breaker | 容错 | Resilience4j, Hystrix |
最佳实践:
- 围绕业务能力进行设计
- 分散数据管理
- 针对故障进行设计
- 自动化部署
事件驱动架构
描述:通过事件进行通信的系统。
主要模式:
| 模式 | 描述 | 适用场景 |
|---|---|---|
| Event Sourcing | 将状态存储为事件 | 审计跟踪、时间查询 |
| CQRS | 分离读写模型 | 读操作负载较高的场景 |
| Saga | 分布式事务 | 跨服务工作流 |
事件溯源示例:
// Events are the source of truth
interface OrderEvent {
id: string;
type: 'OrderCreated' | 'ItemAdded' | 'OrderShipped';
timestamp: Date;
payload: unknown;
}
// Rebuild state from events
function rebuildOrder(events: OrderEvent[]): Order {
return events.reduce((order, event) => {
switch (event.type) {
case 'OrderCreated': return { ...event.payload };
case 'ItemAdded': return { ...order, items: [...order.items, event.payload] };
case 'OrderShipped': return { ...order, status: 'shipped' };
}
}, {} as Order);
}
无服务器架构
描述:由云端管理执行,无需管理服务器。
主要特点:
- 按执行次数计费
- 自动缩容至零
- 降低运维开销
注意事项:
| 方面 | 影响 |
|---|---|
| 冷启动 | 首次调用延迟为 100ms-2s |
| 超时 | 通常最长执行时间为 15-30 min |
| 状态 | 必须使用外部存储 |
| 供应商锁定 | 平台专属功能 |
最佳实践:
- 保持函数小巧且职责明确
- 尽量减少依赖
- 对数据库使用连接池
- 实现适当的错误处理
整洁架构
描述:以领域为中心、依赖关系反转的架构。
分层结构:
┌──────────────────────────────────────┐
│ Frameworks & Drivers │ ← External (DB, Web, UI)
├──────────────────────────────────────┤
│ Interface Adapters │ ← Controllers, Gateways
├──────────────────────────────────────┤
│ Application Business │ ← Use Cases
├──────────────────────────────────────┤
│ Enterprise Business │ ← Entities, Domain Rules
└──────────────────────────────────────┘
依赖规则:依赖关系指向内层。内层不应了解任何外层的信息。
领域驱动设计(DDD)
描述:与业务领域相契合的架构。
战略模式:
| 模式 | 用途 |
|---|---|
| Bounded Context | 明确领域边界 |
| Context Map | 上下文之间的关系 |
| Ubiquitous Language | 共享词汇 |
战术模式:
| 模式 | 用途 |
|---|---|
| Entity | 具有标识的对象 |
| Value Object | 不可变的描述对象 |
| Aggregate | 一致性边界 |
| Repository | 类似集合的持久化机制 |
| Domain Event | 已发生的事情 |
决策指南
START
│
├─ Team size < 10? ──────────────────→ Monolith
│
├─ Need independent deployments? ────→ Microservices
│
├─ Audit trail required? ────────────→ Event Sourcing
│
├─ Variable/unpredictable load? ─────→ Serverless
│
├─ Complex business logic? ──────────→ Clean Architecture + DDD
│
└─ Default ──────────────────────────→ Modular Monolith
常见陷阱
1. 过早采用微服务
问题:简单应用一开始就采用微服务 解决方案:从单体架构开始,边界明确后再拆分服务
2. 分布式单体
问题:必须一起部署的微服务 解决方案:确保服务真正独立,并具有明确的 API 契约
3. 忽略数据边界
问题:多个服务共享数据库 解决方案:每个服务负责自己的数据,并使用事件进行同步
六边形架构(端口与适配器)
描述:通过端口(接口)和适配器(实现)将应用程序核心与外部关注点隔离。
结构:
┌─────────────────────────────────────────────────────────────┐
│ Driving Adapters │
│ (REST API, CLI, GraphQL, Message Consumer) │
└──────────────────────────┬──────────────────────────────────┘
│
┌──────────────────────────▼──────────────────────────────────┐
│ Input Ports │
│ (Use Case Interfaces) │
├─────────────────────────────────────────────────────────────┤
│ │
│ APPLICATION CORE │
│ (Domain Logic, Entities) │
│ │
├─────────────────────────────────────────────────────────────┤
│ Output Ports │
│ (Repository, Gateway Interfaces) │
└──────────────────────────┬──────────────────────────────────┘
│
┌──────────────────────────▼──────────────────────────────────┐
│ Driven Adapters │
│ (Database, External APIs, Message Publisher) │
└─────────────────────────────────────────────────────────────┘
TypeScript 示例:
// Port (Interface)
interface OrderRepository {
save(order: Order): Promise<void>;
findById(id: string): Promise<Order | null>;
}
// Adapter (Implementation)
class PostgresOrderRepository implements OrderRepository {
constructor(private db: Database) {}
async save(order: Order): Promise<void> {
await this.db.query('INSERT INTO orders...', [order]);
}
async findById(id: string): Promise<Order | null> {
const row = await this.db.query('SELECT * FROM orders WHERE id = $1', [id]);
return row ? this.toDomain(row) : null;
}
}
// Use Case (Application Core)
class CreateOrderUseCase {
constructor(private orderRepo: OrderRepository) {} // Depends on Port, not Adapter
async execute(input: CreateOrderInput): Promise<Order> {
const order = new Order(input);
await this.orderRepo.save(order);
return order;
}
}
优点:
- 易于替换实现(数据库、外部服务)
- 易于测试(模拟端口)
- 领域逻辑与框架无关
模块化单体
描述:具有严格模块边界的单体,为将来可能拆分为微服务做好准备。
主要特性:
- 模块通过定义好的接口进行通信
- 每个模块拥有自己的数据
- 可作为单个单元部署,也可拆分
结构:
src/
├── modules/
│ ├── users/
│ │ ├── api/ # Public API of module
│ │ │ └── UserService.ts
│ │ ├── internal/ # Private implementation
│ │ │ ├── UserRepository.ts
│ │ │ └── UserEntity.ts
│ │ └── index.ts # Only exports public API
│ ├── orders/
│ │ ├── api/
│ │ │ └── OrderService.ts
│ │ ├── internal/
│ │ └── index.ts
│ └── shared/ # Cross-cutting utilities
├── infrastructure/
│ ├── database/
│ ├── messaging/
│ └── http/
└── main.ts
模块通信规则:
// ✅ Good: Use public API
import { UserService } from '@modules/users';
const user = await userService.getById(id);
// ❌ Bad: Direct access to internal
import { UserRepository } from '@modules/users/internal/UserRepository';
实施:
// eslint rules or ts-paths to prevent internal imports
{
"rules": {
"no-restricted-imports": ["error", {
"patterns": ["@modules/*/internal/*"]
}]
}
}
绞杀者无花果模式
描述:通过将流量路由到新实现,逐步替换旧系统。
迁移流程:
Phase 1: Facade
┌─────────┐ ┌─────────┐ ┌─────────────┐
│ Client │────→│ Facade │────→│ Legacy │
└─────────┘ └─────────┘ │ System │
└─────────────┘
Phase 2: Partial Migration
┌─────────┐ ┌─────────┐ ┌─────────────┐
│ Client │────→│ Facade │──┬─→│ Legacy │
└─────────┘ └─────────┘ │ └─────────────┘
│ ┌─────────────┐
└─→│ New System │
└─────────────┘
Phase 3: Complete Migration
┌─────────┐ ┌─────────┐ ┌─────────────┐
│ Client │────→│ Facade │────→│ New System │
└─────────┘ └─────────┘ └─────────────┘
实现:
class PaymentFacade {
constructor(
private legacyPayment: LegacyPaymentService,
private newPayment: NewPaymentService,
private featureFlags: FeatureFlags
) {}
async processPayment(payment: Payment): Promise<Result> {
// Gradually migrate traffic
if (this.featureFlags.isEnabled('new-payment-system', payment.userId)) {
return this.newPayment.process(payment);
}
return this.legacyPayment.process(payment);
}
}
前端专用后端(BFF)
描述:为每种前端类型(Web、移动端等)提供专用后端。
结构:
┌─────────────┐
│ Web Client │
└──────┬──────┘
│
┌──────▼──────┐
│ Web BFF │
└──────┬──────┘
│
┌───────────────────┼───────────────────┐
│ │ │
┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐
│ User Service│ │Order Service│ │Product Svc │
└─────────────┘ └─────────────┘ └─────────────┘
│ │ │
└───────────────────┼───────────────────┘
│
┌──────▼──────┐
│ Mobile BFF │
└──────┬──────┘
│
┌──────▼──────┐
│Mobile Client│
└─────────────┘
优点:
- 为每个客户端优化负载
- 支持客户端专属身份验证
- 每种前端可独立部署
- 减少过度获取数据
适用场景:
| 场景 | 建议 |
|---|---|
| 只有一种客户端类型 | 不使用 BFF |
| Web 和移动端的需求相同 | 使用单个 API 网关 |
| 不同平台的用户体验不同 | 使用独立的 BFF |
| 每种前端由多个团队负责 | 使用专用 BFF |
架构模式对比
| 模式 | 复杂度 | 可扩展性 | 团队规模 | 最适合 |
|---|---|---|---|---|
| 单体 | 低 | 垂直 | 小型(2-10 人) | MVP、简单应用 |
| 模块化单体 | 中 | 垂直 | 中型(5-20 人) | 不断发展的应用 |
| 微服务 | 高 | 水平 | 大型(20 人以上) | 复杂领域 |
| 无服务器 | 中 | 自动 | 任意 | 事件驱动、负载变化 |
| 事件驱动 | 高 | 水平 | 中大型 | 异步工作流 |
架构决策记录(ADR)模板
选择架构时,请记录决策:
# ADR-001: Choose Modular Monolith
## Status
Accepted
## Context
- Team of 8 developers
- MVP deadline in 3 months
- Uncertain about domain boundaries
- Limited DevOps resources
## Decision
Adopt Modular Monolith with strict boundaries
## Consequences
### Positive
- Faster initial development
- Simpler deployment
- Can extract services later
### Negative
- Single point of failure
- Scaling limited to vertical
- Need discipline for module boundaries
## Alternatives Considered
1. Microservices - Too complex for team size
2. Traditional Monolith - No path to scale
演进路径
┌─────────────────────────────────────────────────────────────────┐
│ Architecture Evolution │
│ │
│ Monolith ──→ Modular Monolith ──→ Microservices │
│ │ │ │ │
│ │ │ ▼ │
│ │ │ Event-Driven / CQRS │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ [Simple] [Growing] [Complex/Scale] │
│ │
│ Tip: Don't skip steps. Each stage teaches domain boundaries. │
└─────────────────────────────────────────────────────────────────┘
应避免的反模式
1. 一团乱麻
症状:没有清晰的结构,所有内容都相互依赖 解决方法:引入模块边界,应用整洁架构原则
2. 万能锤
症状:每个项目都使用相同的架构 解决方法:评估需求,使用决策指南
3. 意外复杂性
症状:架构比领域需求更复杂 解决方法:从简单开始,仅在需要时增加复杂性
4. 履历驱动开发
症状:选择技术是为了学习,而非解决问题 解决方法:让架构与团队技能和项目需求相匹配
5. 厂商锁定
症状:核心逻辑与云服务提供商紧密耦合 解决方法:使用六边形架构,将厂商特定代码抽象化
各模式的性能考量
| 模式 | 延迟 | 吞吐量 | 冷启动 |
|---|---|---|---|
| 单体 | 低 | 高 | 不适用 |
| 微服务 | 中(网络) | 高(分布式) | 不适用 |
| 无服务器 | 不定 | 自动扩缩 | 100ms-2s |
| 事件驱动 | 较高(异步) | 非常高 | 视情况而定 |
各模式的测试策略
单体
Unit Tests → Integration Tests → E2E Tests
70% 20% 10%
微服务
Unit Tests → Contract Tests → Integration → E2E
60% 20% 15% 5%
// Contract Test Example (Pact)
const provider = new Pact({ consumer: 'OrderService', provider: 'UserService' });
await provider.addInteraction({
state: 'user exists',
uponReceiving: 'get user request',
withRequest: { method: 'GET', path: '/users/123' },
willRespondWith: { status: 200, body: { id: '123', name: 'John' } }
});
事件驱动
- 独立测试事件生产者和消费者
- 使用事件架构验证
- 测试 Saga/工作流编排
相关技能
- [[api-design]] - 用于服务通信的 API 设计
- [[system-design]] - 大规模系统考量
- [[devops-cicd]] - 各模式的部署策略
- [[data-design]] - 各架构的数据库模式