mcpField
A
architecture-patterns

architecture-patterns

github.com/wshobson开发41.9k24.4k 次安装2 周前更新
代码仓库

关于 architecture-patterns

用于采用 Clean Architecture、Hexagonal Architecture 和领域驱动设计构建后端服务的技能,帮助团队划分层次、接口和测试边界,使业务逻辑与基础设施分离。

主要功能

  1. 01Clean Architecture 分层指导
  2. 02端口与适配器设计
  3. 03DDD 限界上下文
  4. 04领域建模模式
  5. 05内存适配器测试
  6. 06依赖边界问题排查

适用场景

  1. 01设计后端服务
  2. 02分离业务逻辑与 ORM 或 HTTP 代码
  3. 03定义服务限界上下文
  4. 04无需数据库测试用例

安装

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

$npx skills add https://github.com/wshobson/agents --skill architecture-patterns

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

附带文件references/advanced-patterns.mdreferences/details.md

详细介绍

架构模式

掌握经过验证的后端架构模式,包括整洁架构、六边形架构和领域驱动设计,以构建可维护、可测试且可扩展的系统。

输入: 一个需要架构设计的服务边界或模块。 产出: 具有清晰依赖规则、接口定义和测试边界的分层结构。

何时使用此技能

  • 从零开始设计新的后端服务或微服务
  • 重构业务逻辑与 ORM 模型或 HTTP 关注点纠缠在一起的单体应用
  • 在将系统拆分为服务之前建立限界上下文
  • 调试基础设施代码渗入领域层的依赖循环
  • 创建可测试的代码库,使用例测试无需运行中的数据库
  • 实现领域驱动设计的战术模式(聚合、值对象、领域事件)

核心概念

1. 整洁架构(Uncle Bob)

分层(依赖向内流动):

  • 实体:核心业务模型,不导入任何框架
  • 用例:应用业务规则,编排实体
  • 接口适配器:控制器、展示器、网关——在用例与外部格式之间转换
  • 框架与驱动:UI、数据库、外部服务——全部位于最外层环

关键原则:

  • 依赖只向内指向;内层对外层一无所知
  • 业务逻辑独立于框架、数据库和交付机制
  • 每个层边界都通过抽象接口跨越
  • 无需 UI、数据库或外部服务即可测试
2. 六边形架构(端口与适配器)

组件:

  • 领域核心:业务逻辑所在之处,不依赖框架
  • 端口:定义核心如何与外部世界交互的抽象接口(驱动端口与被驱动端口)
  • 适配器:端口的具体实现(PostgreSQL 适配器、Stripe 适配器、REST 适配器)

优势:

  • 无需触碰核心即可替换实现(例如,将 PostgreSQL 替换为 DynamoDB)
  • 在测试中使用内存适配器——无需 Docker
  • 技术决策推迟到边缘
3. 领域驱动设计(DDD)

战略模式:

  • 限界上下文:为某个子域隔离出一致的模型;避免在整个系统中共享单一模型
  • 上下文映射:定义上下文之间的关系(防腐层、共享内核、开放主机服务)
  • 通用语言:代码中的每个术语都与领域专家使用的术语一致

战术模式:

  • 实体:具有稳定标识、随时间变化的对象
  • 值对象:由其属性标识的不可变对象(Email、Money、Address)
  • 聚合:一致性边界;只有根可从外部访问
  • 仓储:持久化和重建聚合;抽象存储机制
  • 领域事件:捕获领域内发生的事件;用于跨聚合协调

详细模式与实例

详细的模式文档位于 references/details.md。当上述导航层级不够用时,请阅读该文件。

测试——内存适配器

正确应用整洁架构的标志是:每个用例都可以在普通单元测试中执行,无需真实数据库、无需 Docker、无需网络:

# tests/unit/test_create_user.py
import asyncio
from typing import Dict, Optional
from domain.entities.user import User
from domain.interfaces.user_repository import IUserRepository
from use_cases.create_user import CreateUserUseCase, CreateUserRequest


class InMemoryUserRepository(IUserRepository):
    def __init__(self):
        self._store: Dict[str, User] = {}

    async def find_by_id(self, user_id: str) -> Optional[User]:
        return self._store.get(user_id)

    async def find_by_email(self, email: str) -> Optional[User]:
        return next((u for u in self._store.values() if u.email == email), None)

    async def save(self, user: User) -> User:
        self._store[user.id] = user
        return user

    async def delete(self, user_id: str) -> bool:
        return self._store.pop(user_id, None) is not None


async def test_create_user_succeeds():
    repo = InMemoryUserRepository()
    use_case = CreateUserUseCase(user_repository=repo)

    response = await use_case.execute(CreateUserRequest(email="[email protected]", name="Alice"))

    assert response.success
    assert response.user.email == "[email protected]"
    assert response.user.id is not None


async def test_duplicate_email_rejected():
    repo = InMemoryUserRepository()
    use_case = CreateUserUseCase(user_repository=repo)

    await use_case.execute(CreateUserRequest(email="[email protected]", name="Alice"))
    response = await use_case.execute(CreateUserRequest(email="[email protected]", name="Alice2"))

    assert not response.success
    assert "already exists" in response.error

故障排查

用例测试需要运行中的数据库

业务逻辑已泄漏到基础设施层。将所有数据库调用移到 IRepository 接口之后,并在测试中注入内存实现(参见上文测试部分)。用例构造函数必须接受抽象端口,而非具体类。

层之间的循环导入

一个常见症状是在 use_cases 和 adapters 之间出现 ImportError: cannot import name X。当用例导入具体的适配器类而不是抽象端口时,就会发生这种情况。强制执行该规则:use_cases/ 只能从 domain/(实体和接口)导入。它绝不能从 adapters/ 或 infrastructure/ 导入。

框架装饰器出现在领域实体中

如果 SQLAlchemy Column() 或 Pydantic Field() 注解出现在领域实体上,那么该实体就不再是纯净的。在 adapters/repositories/ 中创建一个单独的 ORM 模型,并在仓储的 _to_entity() 方法中与领域实体相互映射。

所有逻辑最终都落在控制器中

当控制器超出 HTTP 解析和响应格式化的范围时,将逻辑提取到用例类中。控制器方法应该只做三件事:解析请求、调用用例、映射响应。

值对象过晚抛出错误

在 __post_init__(Python)或构造函数中验证不变量,这样根本无法构造无效的 Email 或 Money。这会在边界处暴露坏数据,而不是深入业务逻辑内部。

跨限界上下文的情境泄漏

如果 Order 上下文从 Identity 上下文导入 User 实体,则引入防腐层。Order 上下文应持有自己的轻量级 CustomerId 值对象,并且只通过显式接口调用 Identity 上下文。

高级模式

有关详细的 DDD 限界上下文映射、完整的多服务项目树、防腐层实现以及洋葱架构对比,请参见:

相关技能

  • microservices-patterns — 在将单体拆解为服务时应用这些架构模式
  • cqrs-implementation — 将整洁架构作为 CQRS 命令/查询分离的结构基础
  • saga-orchestration — Saga 需要定义良好的聚合边界,而 DDD 战术模式可提供这些边界
  • event-store-design — 聚合产生的领域事件直接馈入事件存储

评论

支持 Markdown