Communitygithub.com

六边形架构

设计、实现和重构端口与适配器系统,明确领域边界、依赖反转,并在 TypeScript、Java、Kotlin 和 Go 服务中实现可测试的用例编排。适用于引入或重构为端口与适配器架构,或当领域逻辑与 I/O 纠缠不清时。

六边形架构 是什么?

该技能提供了一套系统化的六边形架构(端口与适配器)实施指南。它指导开发者将业务逻辑与框架、传输和持久化细节解耦,核心应用依赖于抽象端口,适配器则在边缘实现这些端口。技能涵盖了何时使用此架构(例如,构建新功能、重构框架沉重的代码、支持多个接口)、核心概念(领域模型、用例、入站/出站端口和适配器、组合根)、以及从建模用例边界到测试的分步工作流。它提供了详细的项目结构建议、TypeScript 代码示例、多语言映射(TypeScript、Java、Kotlin、Go)以及一个迁移手册,用于逐步将现有系统重构为六边形架构,同时避免反模式。该技能适用于需要边界、领域驱动设计、解耦紧密耦合服务或将应用逻辑与特定库分离的任何场景。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/ECC/tree/main/skills/hexagonal-architecture

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

六边形架构 是做什么的?

六边形架构(端口与适配器)使业务逻辑独立于框架、传输和持久化细节。核心应用依赖于抽象端口,适配器在边缘实现这些端口。

何时使用

  • 构建对长期可维护性和可测试性至关重要的新功能。
  • 重构分层或框架沉重的代码,其中领域逻辑与 I/O 关注点混合。
  • 为同一用例支持多个接口(HTTP、CLI、队列工作者、定时任务)。
  • 替换基础设施(数据库、外部 API、消息总线)而无需重写业务规则。

当请求涉及边界、领域中心设计、重构紧密耦合的服务或将应用逻辑与特定库解耦时,使用此技能。

核心概念

  • 领域模型:业务规则和实体/值对象。无框架导入。
  • 用例(应用层):编排领域行为和工作流步骤。
  • 入站端口:描述应用程序能做什么的契约(命令/查询/用例接口)。
  • 出站端口:应用程序所需依赖项的契约(仓库、网关、事件发布器、时钟、UUID 等)。
  • 适配器:端口的基础设施和交付实现(HTTP 控制器、DB 仓库、队列消费者、SDK 包装器)。
  • 组合根:一个单一的接线位置,其中具体的适配器被绑定到用例。

出站端口接口通常位于应用层(只有当抽象确实是领域级别时才位于领域层),而基础设施适配器实现它们。

依赖方向始终向内:

  • 适配器 -> 应用/领域
  • 应用 -> 端口接口(入站/出站契约)
  • 领域 -> 仅领域抽象(无框架或基础设施依赖)
  • 领域 -> 无外部依赖

工作原理

步骤 1:建模用例边界

定义一个具有清晰输入和输出 DTO 的单一用例。将传输细节(Express req、GraphQL context、任务负载包装器)保留在此边界之外。

步骤 2:首先定义出站端口

将每个副作用标识为一个端口:

  • 持久化(UserRepositoryPort)
  • 外部调用(BillingGatewayPort)
  • 横切关注点(LoggerPort、ClockPort)

端口应建模能力,而非技术。

步骤 3:用纯编排实现用例

用例类/函数通过构造函数/参数接收端口。它验证应用级别的不变量,协调领域规则,并返回普通数据结构。

步骤 4:在边缘构建适配器

  • 入站适配器将协议输入转换为用例输入。
  • 出站适配器将应用契约映射到具体的 API/ORM/查询构建器。
  • 映射保持在适配器内,而不是在用例内部。

步骤 5:在组合根中连接所有内容

实例化适配器,然后将它们注入到用例中。保持此接线集中化,以避免隐藏的服务定位器行为。

步骤 6:按边界测试

  • 使用伪造端口进行用例单元测试。
  • 使用真实基础设施依赖进行适配器集成测试。
  • 通过入站适配器进行端到端测试用户面向的流程。

架构图

flowchart LR
  Client["客户端 (HTTP/CLI/工作者)"] --> InboundAdapter["入站适配器"]
  InboundAdapter -->|"调用"| UseCase["用例 (应用层)"]
  UseCase -->|"使用"| OutboundPort["出站端口 (接口)"]
  OutboundAdapter["出站适配器"] -->|"实现"| OutboundPort
  OutboundAdapter --> ExternalSystem["数据库/API/队列"]
  UseCase --> DomainModel["领域模型"]

建议的模块布局

使用以功能为先的组织结构,并带有明确的边界:

src/
  features/
    orders/
      domain/
        Order.ts
        OrderPolicy.ts
      application/
        ports/
          inbound/
            CreateOrder.ts
          outbound/
            OrderRepositoryPort.ts
            PaymentGatewayPort.ts
        use-cases/
          CreateOrderUseCase.ts
      adapters/
        inbound/
          http/
            createOrderRoute.ts
        outbound/
          postgres/
            PostgresOrderRepository.ts
          stripe/
            StripePaymentGateway.ts
      composition/
        ordersContainer.ts

TypeScript 示例

端口定义

export interface OrderRepositoryPort {
  save(order: Order): Promise<void>;
  findById(orderId: string): Promise<Order | null>;
}

export interface PaymentGatewayPort {
  authorize(input: { orderId: string; amountCents: number }): Promise<{ authorizationId: string }>;
}

用例

type CreateOrderInput = {
  orderId: string;
  amountCents: number;
};

type CreateOrderOutput = {
  orderId: string;
  authorizationId: string;
};

export class CreateOrderUseCase {
  constructor(
    private readonly orderRepository: OrderRepositoryPort,
    private readonly paymentGateway: PaymentGatewayPort
  ) {}

  async execute(input: CreateOrderInput): Promise<CreateOrderOutput> {
    const order = Order.create({ id: input.orderId, amountCents: input.amountCents });

    const auth = await this.paymentGateway.authorize({
      orderId: order.id,
      amountCents: order.amountCents,
    });

    // markAuthorized 返回一个新的 Order 实例;它不会就地修改。
    const authorizedOrder = order.markAuthorized(auth.authorizationId);
    await this.orderRepository.save(authorizedOrder);

    return {
      orderId: order.id,
      authorizationId: auth.authorizationId,
    };
  }
}

出站适配器

export class PostgresOrderRepository implements OrderRepositoryPort {
  constructor(private readonly db: SqlClient) {}

  async save(order: Order): Promise<void> {
    await this.db.query(
      "insert into orders (id, amount_cents, status, authorization_id) values ($1, $2, $3, $4)",
      [order.id, order.amountCents, order.status, order.authorizationId]
    );
  }

  async findById(orderId: string): Promise<Order | null> {
    const row = await this.db.oneOrNone("select * from orders where id = $1", [orderId]);
    return row ? Order.rehydrate(row) : null;
  }
}

组合根

export const buildCreateOrderUseCase = (deps: { db: SqlClient; stripe: StripeClient }) => {
  const orderRepository = new PostgresOrderRepository(deps.db);
  const paymentGateway = new StripePaymentGateway(deps.stripe);

  return new CreateOrderUseCase(orderRepository, paymentGateway);
};

多语言映射

在不同生态系统中使用相同的边界规则;只有语法和接线风格发生变化。

  • TypeScript/JavaScript
    • 端口:application/ports/* 作为接口/类型。
    • 用例:带有构造函数/参数注入的类/函数。
    • 适配器:adapters/inbound/*、adapters/outbound/*。
    • 组合:显式工厂/容器模块(无隐藏全局变量)。
  • Java
    • 包:domain、application.port.in、application.port.out、application.usecase、adapter.in、adapter.out。
    • 端口:application.port.* 中的接口。
    • 用例:普通类(Spring @Service 是可选的,非必需)。
    • 组合:Spring 配置或手动接线类;将接线保持在领域/用例类之外。
  • Kotlin
    • 模块/包镜像 Java 的拆分(domain、application.port、application.usecase、adapter)。
    • 端口:Kotlin 接口。
    • 用例:带有构造函数注入的类(Koin/Dagger/Spring/手动)。
    • 组合:模块定义或专用组合函数;避免服务定位器模式。
  • Go
    • 包:internal/<feature>/domain、application、ports、adapters/inbound、adapters/outbound。
    • 端口:由消费应用包拥有的小接口。
    • 用例:带有接口字段和显式 New... 构造函数的结构体。
    • 组合:在 cmd/<app>/main.go(或专用接线包)中接线,保持构造函数显式。

应避免的反模式

  • 领域实体导入 ORM 模型、Web 框架类型或 SDK 客户端。
  • 用例直接从 req、res 或队列元数据中读取。
  • 从用例直接返回数据库行,而不进行领域/应用映射。
  • 让适配器直接相互调用,而不是通过用例端口流转。
  • 将依赖接线分散到许多文件中,使用隐藏的全局单例。

迁移手册

  1. 选择一个垂直切片(单一端点/作业),其变更痛苦频繁。
  2. 使用明确的输入/输出类型提取一个用例边界。
  3. 围绕现有基础设施调用引入出站端口。
  4. 将编排逻辑从控制器/服务移动到用例中。
  5. 保留旧适配器,但让它们委托给新的用例。
  6. 在新边界周围添加测试(单元测试 + 适配器集成测试)。
  7. 逐个切片重复;避免完全重写。

重构现有系统

  • 绞杀者模式:保留当前端点,一次将一个用例通过新的端口/适配器路由。
  • 没有大爆炸式重写:按功能切片迁移,并使用特征化测试保留行为。
  • 外观优先:在替换内部实现之前,将遗留服务包装在出站端口后面。
  • 组合冻结:早期集中接线,以便新依赖不会泄漏到领域/用例层。
  • 切片选择规则:优先考虑高变动、低影响范围的流程。
  • 回滚路径:在每个迁移的切片上保留一个可逆的切换或路由开关,直到生产行为得到验证。

测试指南(相同的六边形边界)

  • 领域测试:将实体/值对象作为纯业务规则进行测试(无模拟,无框架设置)。
  • 用例单元测试:使用出站端口的伪造/存根测试编排;断言业务成果和端口交互。
  • 出站适配器契约测试:在端口级别定义共享契约套件,并针对每个适配器实现运行它们。
  • 入站适配器测试:验证协议映射(HTTP/CLI/队列有效载荷到用例输入以及输出/错误映射回协议)。
  • 适配器集成测试:针对真实基础设施(数据库/API/队列)运行,以测试序列化、模式/查询行为、重试和超时。
  • 端到端测试:通过入站适配器 -> 用例 -> 出站适配器覆盖关键用户旅程。
  • 重构安全性:在提取之前添加特征化测试;保留它们直到新的边界行为稳定且等效。

最佳实践检查清单

  • 领域和用例层仅导入内部类型和端口。
  • 每个外部依赖都由一个出站端口表示。
  • 验证发生在边界(入站适配器 + 用例不变量)。
  • 使用不可变转换(返回新值/实体,而不是修改共享状态)。
  • 错误在边界之间转换(基础设施错误 -> 应用/领域错误)。
  • 组合根是显式的且易于审计。
  • 用例可以通过端口简单的内存伪造进行测试。
  • 重构从一个垂直切片开始,使用行为保留测试。
  • 语言/框架细节留在适配器中,永远不在领域规则中。

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/content-engine

Create platform-native content systems for X, LinkedIn, TikTok, YouTube, newsletters, and repurposed multi-platform campaigns. Use when the user wants social posts, threads, scripts, content calendars, or one source asset adapted cleanly across platforms.

affaan-m/ECC

Multi-platform content distribution across X, LinkedIn, Threads, and Bluesky. Adapts content per platform using content-engine patterns. Never posts identical content cross-platform. Use when the user wants to distribute content across social platforms.

affaan-m/fal-ai-media

Unified media generation via fal.ai MCP — image, video, and audio. Covers text-to-image (Nano Banana), text/image-to-video (Seedance, Kling, Veo 3), text-to-speech (CSM-1B), and video-to-audio (ThinkSound). Use when the user wants to generate images, videos, or audio with AI.

affaan-m/manim-video

日本語翻訳:このファイルは manim-video 用の日本語翻訳が必要です

affaan-m/remotion-video-creation

Remotion のベストプラクティス - React で動画を作成する。3D、アニメーション、音声、字幕、チャート、トランジションなどをカバーするドメイン固有の29のルール。

affaan-m/video-editing

AI-assisted video editing workflows for cutting, structuring, and augmenting real footage. Covers the full pipeline from raw capture through FFmpeg, Remotion, ElevenLabs, fal.ai, and final polish in Descript or CapCut. Use when the user wants to edit video, cut footage, create vlogs, or build video content.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

agent-self-evaluation

Use after completing any non-trivial task. The agent self-rates its output on 5 axes — accuracy, completeness, clarity, actionability, conciseness — with concrete evidence per criterion. Produces a structured 1-5 scorecard with specific improvement suggestions.

agent-sort

Build an evidence-backed ECC install plan for a specific repo by sorting skills, commands, rules, hooks, and extras into DAILY vs LIBRARY buckets using parallel repo-aware review passes. Use when ECC should be trimmed to what a project actually needs instead of loading the full bundle.

ai-first-engineering

Engineering operating model for teams where AI agents generate a large share of implementation output. Use when setting team process, review gates, or ownership rules for a codebase largely written by agents.

ai-regression-testing

Regression testing strategies for AI-assisted development. Sandbox-mode API testing without database dependencies, automated bug-check workflows, and patterns to catch AI blind spots where the same model writes and reviews code. Use when adding regression coverage to AI-assisted code, or when the same model both wrote and reviewed a change.

android-clean-architecture

Clean Architecture patterns for Android and Kotlin Multiplatform projects — module structure, dependency rules, UseCases, Repositories, and data layer patterns. Use when structuring modules, layers, or data flow in an Android or KMP project.

angular-developer

Generates Angular code and provides architectural guidance. Trigger when creating projects, components, or services, or for best practices on reactivity (signals, linkedSignal, resource), forms, dependency injection, routing, SSR, accessibility (ARIA), animations, styling (component styles, Tailwind CSS), testing, or CLI tooling.

相关技能