mcpField
C
common-hexagonal-architecture

common-hexagonal-architecture

github.com/xip-online-applications开发046 次安装14 周前更新
代码仓库

关于 common-hexagonal-architecture

为服务和模块设计、重构提供六边形架构指导,通过端口与适配器隔离领域逻辑和基础设施。适用于需要可测试核心、明确依赖边界及外部集成的开发者。

主要功能

  1. 01划分驱动端口与被驱动端口
  2. 02将业务逻辑保留在应用核心
  3. 03通过适配器连接基础设施
  4. 04使用依赖注入组装组件
  5. 05按核心与适配器设计测试
  6. 06检查并维护架构边界

适用场景

  1. 01设计新服务或重构模块架构
  2. 02在无基础设施依赖时测试业务逻辑
  3. 03接入数据库、API 或消息队列
  4. 04检查并清理分层代码的依赖边界

安装

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

$npx skills add https://github.com/xip-online-applications/skills --skill common-hexagonal-architecture

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

详细介绍

通用六边形架构

在单个服务边界内应用六边形架构(也称为端口与适配器),使领域逻辑独立于框架、数据库、消息系统和 UI。

适用场景

在以下情况下使用此技能:

  • 设计或重构服务或模块的内部架构
  • 确保领域/业务逻辑无需依赖基础设施即可测试
  • 引入新的外部集成(数据库、API、队列、文件系统)
  • 审查代码,确认基础设施相关问题不会渗入核心
  • 将分层代码库或「大泥球」代码库重构为边界更清晰的架构

核心概念

六边形(应用核心)

六边形包含所有业务逻辑和领域规则。它对外部世界一无所知——不涉及 HTTP、SQL 或文件 I/O。它仅通过端口进行通信。

端口

端口是一种接口(契约),定义应用核心如何与外部世界交互。

端口类型方向用途
驱动端口(主要端口)入站定义外部世界可在核心上调用的用例。
被驱动端口(次要端口)出站定义核心需要外部系统提供的内容。
  • 驱动端口由应用核心(用例/应用服务)实现。
  • 被驱动端口由基础设施层中的适配器实现。
适配器

适配器负责在外部世界与端口之间转换。

适配器类型连接到示例
驱动适配器(主要适配器)驱动端口REST 控制器、命令行处理程序、gRPC 服务端、消息使用者
被驱动适配器(次要适配器)被驱动端口SQL 仓储、HTTP 客户端、SMTP 邮件发送器、文件存储
依赖规则

依赖关系始终向内指向——适配器依赖端口,端口位于核心中,而核心不依赖任何外部内容。

[Driving Adapter] --> [Driving Port (interface)]
                            |
                    [Application Core]
                            |
                  [Driven Port (interface)] <-- [Driven Adapter]

说明

  1. 将驱动端口定义为用例接口。

    • 每个用例或紧密相关的一组用例对应一个接口。
    • 使用领域动作命名:PlaceOrder、RegisterUser、GenerateReport。
    • 只接受和返回领域对象或简单的 DTO,不要使用框架特定类型。
  2. 在应用服务中实现驱动端口。

    • 应用服务位于六边形内部。
    • 它们编排领域对象并调用被驱动端口。
    • 它们不包含基础设施逻辑(不执行 SQL、不发起 HTTP 调用、不进行文件 I/O)。
  3. 将被驱动端口定义为仓储/网关接口。

    • 每种外部依赖概念对应一个接口:OrderRepository、PaymentGateway、NotificationSender。
    • 方法签名应聚焦于领域需求,而非技术实现(例如,使用 findByCustomerId(id),而不是 executeQuery(sql))。
    • 被驱动端口接口与领域一起位于应用核心中。
  4. 在基础设施中实现被驱动适配器。

    • 每个被驱动适配器只实现一个被驱动端口接口。
    • 包含所有特定于技术的代码(ORM 调用、HTTP 客户端、SDK 用法)。
    • 可以替换而不触及核心(例如,从 PostgreSQL 切换到 DynamoDB)。
  5. 在边界处实现驱动适配器。

    • 驱动适配器接收外部输入(HTTP 请求、CLI 参数、队列消息)。
    • 它将输入转换为对驱动端口的调用。
    • 它将端口的响应转换回外部响应(JSON、退出代码、确认消息)。
    • 驱动适配器不得包含业务逻辑,只能进行映射和委派。
  6. 通过注入连接依赖项。

    • 使用构造函数注入(或组合根/DI 容器)将被驱动适配器实例传入应用服务。
    • 组合根是唯一了解具体适配器实现的地方。
    • 在测试中,通过相同的端口注入伪造/模拟/内存适配器。
  7. 文件夹/模块结构。 组织服务,使其结构清晰地体现六边形:

    src/
      <service-or-module>/
        core/
          domain/
            model/             # Entities, value objects, aggregates
            event/             # Domain events
            service/           # Domain services (pure logic)
          port/
            in/               # Driving port interfaces (use cases)
            out/              # Driven port interfaces (repositories, gateways)
          application/
            service/          # Application services implementing driving ports
            dto/              # Input/output DTOs for ports
        adapter/
          in/
            web/             # REST/GraphQL controllers
            cli/             # CLI command handlers
            messaging/       # Message/event consumers
          out/
            persistence/     # Database repositories
            http/            # External API clients
            messaging/       # Event publishers, queue producers
            filesystem/      # File storage adapters
        config/              # Composition root, DI wiring, framework bootstrap
    
  8. 采用与六边形架构相匹配的测试策略。

    • 单元测试:使用内存/伪造的被驱动适配器测试领域模型和应用服务。不进行真实 I/O。
    • 集成测试:使用真实基础设施(数据库、通过 testcontainers 或沙盒接入的外部 API)测试被驱动适配器。
    • 验收测试:端到端调用驱动端口(或驱动适配器),使用真实或接近真实的适配器验证完整用例。
    • 大多数测试都应针对核心进行单元测试——运行快速、结果确定,且不模拟内部实现。
  9. 守住边界。

    • 核心绝不能导入 adapter/ 包。
    • 适配器只能导入 core/port/(以及用于类型的 core/domain/model/)。
    • 通过模块边界强制执行这些规则(lint 规则、包可见性、ArchUnit/Deptrac/dependency-cruiser 等架构测试)。
  10. 验证架构。

    • 能否通过为所有被驱动端口注入伪造实现来测试任意用例?如果不能,就说明有依赖泄漏。
    • 能否在不更改核心的情况下替换被驱动适配器(例如,将 Postgres 替换为内存存储)?如果不能,说明端口耦合过紧。
    • 驱动适配器是否包含条件业务逻辑?如果是,就将其移入核心,并通过驱动端口调用。
    • 组合根是否是唯一引用具体适配器类的文件?如果不是,说明连接逻辑已泄漏。

评论

支持 Markdown