Communitygithub.com

六角架構 (Hexagonal Architecture)

設計、實作與重構 Ports & Adapters 系統,確保清晰的領域邊界、依賴反轉原則,以及可測試的用例編排,適用於 TypeScript、Java、Kotlin 與 Go 服務。適合在導入或重構為 Ports and Adapters 架構,或者當領域邏輯與 I/O 糾結在一起時使用。

六角架構 (Hexagonal Architecture) 是什麼?

六角架構(Ports and Adapters)的核心目標是將業務邏輯與框架、傳輸層及持久化細節徹底分離。此技能提供了一套結構化指南,協助開發者在 TypeScript、Java、Kotlin 與 Go 等主流語言中,設計、實作與重構出這種架構。它定義了清晰的邊界與依賴方向:外層的配接器(Adapters)透過抽象的連接埠(Ports)與內層的應用邏輯溝通,確保領域層不受任何外部技術的污染。 此技能包含了漸進式重構的遷移手冊,避免大規模重寫,並提供測試策略來驗證各個邊界的正確性。透過建立明確的組合根來集中管理依賴注入,能顯著提升系統的可維護性、可測試性,以及更換基礎設施(如資料庫、API)的靈活性。它適用於各種開發平台與語言生態,並提供對應的模組佈局與程式碼範例。 使用此技能時,開發者可以遵循六大步驟:建模用例邊界、定義輸出連接埠、實作純編排的用例、在邊緣建構配接器、集中於組合根進行注入,以及按邊界進行測試。此外,它也明確指出應避免的反模式,例如領域實體匯入 ORM 模型,或用例直接讀取 HTTP 請求物件。

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

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

六角架構 (Hexagonal Architecture) 是做什麼的?

六角架構(Ports and Adapters)讓業務邏輯不受框架、傳輸層與持久化細節的影響。核心應用取決於抽象連接埠(Ports),而配接器(Adapters)則在邊緣實作這些連接埠。

使用時機

  • 建立需要長期可維護性與可測試性的新功能。
  • 重構層次化或框架依賴過重的程式碼,其中領域邏輯與 I/O 關注點混雜在一起。
  • 為同一個用例支援多種介面(如 HTTP、CLI、佇列工作者、排程任務)。
  • 在無需改寫業務規則的情況下,更換基礎設施(資料庫、外部 API、訊息匯流排)。

當請求涉及邊界、領域驅動設計、重構緊耦合服務,或將應用邏輯與特定函式庫解耦時,請使用此技能。

核心概念

  • 領域模型 (Domain model):業務規則與實體/值物件。不匯入任何框架。
  • 用例(應用層) (Use cases (application layer)):編排領域行為與工作流程步驟。
  • 輸入連接埠 (Inbound ports):描述應用程式能做什麼的合約(命令/查詢/用例介面)。
  • 輸出連接埠 (Outbound ports):應用程式所需依賴項的合約(儲存庫、閘道器、事件發布器、時鐘、UUID 等)。
  • 配接器 (Adapters):連接埠的基礎設施與傳送實作(HTTP 控制器、資料庫儲存庫、佇列消費者、SDK 包裝器)。
  • 組合根 (Composition root):將具體配接器繫結到用例的單一注入位置。

輸出連接埠介面通常位於應用層(或僅當抽象確實屬於領域層級時才放在領域層),而基礎設施配接器則實作它們。

依賴方向始終向內:

  • 配接器 -> 應用/領域層
  • 應用層 -> 連接埠介面(輸入/輸出合約)
  • 領域層 -> 領域層專屬抽象(無框架或基礎設施依賴)
  • 領域層 -> 不對外依賴任何東西

運作方式

步驟 1:建模用例邊界

定義一個具有明確輸入與輸出 DTO 的用例。將傳輸細節(如 Express req、GraphQL context、工作負載包裝器)保留在此邊界之外。

步驟 2:先定義輸出連接埠

將每個副作用識別為一個連接埠:

  • 持久化 (UserRepositoryPort)
  • 外部呼叫 (BillingGatewayPort)
  • 橫切關注點 (LoggerPort、ClockPort)

連接埠應建模能力,而非技術。

步驟 3:以純編排實作用例

用例類別/函數透過建構子/引數接收連接埠。它驗證應用層級的不變量、協調領域規則,並回傳純資料結構。

步驟 4:在邊緣建構配接器

  • 輸入配接器將協定輸入轉換為用例輸入。
  • 輸出配接器將應用合約映射到具體 API/ORM/查詢建構器。
  • 映射邏輯保留在配接器中,而非進入用例內部。

步驟 5:在組合根中注入所有元件

實例化配接器,然後將它們注入到用例中。保持此注入集中化,以避免隱藏的服務定位器行為。

步驟 6:按邊界進行測試

  • 使用虛擬連接埠對用例進行單元測試。
  • 使用真實基礎設施依賴項對配接器進行整合測試。
  • 透過輸入配接器對使用者面向流程進行端到端測試。

架構圖

flowchart LR
  Client["客戶端 (HTTP/CLI/Worker)"] --> 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 模型、網頁框架型別或 SDK 客戶端。
  • 用例直接從 req、res 或佇列後設資料中讀取。
  • 在未經過領域/應用層映射的情況下,直接從用例回傳資料庫行資料。
  • 讓配接器彼此直接呼叫,而不是透過用例連接埠流動。
  • 將依賴注入分散到許多檔案中,並使用隱藏的單例全域變數。

遷移手冊

  1. 選擇一個經常變更且痛苦的垂直切片(單一端點/工作)。
  2. 使用明確的輸入/輸出的型別提取出一個用例邊界。
  3. 圍繞現有的基礎設施呼叫導入輸出連接埠。
  4. 將編排邏輯從控制器/服務移動到用例中。
  5. 保留舊的配接器,但它們改為委託給新的用例。
  6. 圍繞新的邊界添加測試(單元測試 + 配接器整合測試)。
  7. 逐個切片重複此過程;避免全面改寫。

重構既有的系統

  • Strangler 方法:保持目前的端點,一次將一個用例透過新的連接埠/配接器路由。
  • 避免大規模改寫:按功能切片遷移,並使用特徵化測試保留行為。
  • 先建立外觀模式:在更換內部實作之前,先將舊版服務包裝在輸出連接埠之後。
  • 凍結組合根:及早集中管理注入,讓新的依賴項不會洩漏到領域/用例層。
  • 切片選擇規則:優先處理變更頻繁且影響範圍小的流程。
  • 復原路徑:為每個遷移的切片保留可逆的切換開關或路由切換,直到生產行為得到驗證。

測試指南(相同的六角邊界)

  • 領域測試:將實體/值物件作為純業務規則進行測試(無模擬、無框架設定)。
  • 用例單元測試:使用輸出連接埠的虛擬實作/樁件測試編排邏輯;斷言業務結果與連接埠互動。
  • 輸出配接器合約測試:在連接埠層級定義共享的合約套件,並針對每個配接器實作執行。
  • 輸入配接器測試:驗證協定映射(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/claude-api

Anthropic Claude API patterns for Python and TypeScript. Covers Messages API, streaming, tool use, vision, extended thinking, batches, prompt caching, and Claude Agent SDK. Use when building applications with the Claude API or Anthropic SDKs.

affaan-m/everything-claude-code

End-to-end marketing campaign planning and execution. Covers audience research, positioning, campaign angle definition, landing page copy, email sequences, social posts, ad copy, short-form video scripts, and content calendars. Use as the orchestration layer for multi-channel product launches. Use when planning or executing a multi-channel product launch, or producing landing page, email, social, or ad copy.

affaan-m/everything-claude-code

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/everything-claude-code-conventions

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/frontend-design

Create distinctive, production-grade frontend interfaces with high design quality. Use when the user asks to build web components, pages, or applications and the visual direction matters as much as the code quality.

affaan-m/gget

gget CLI and Python workflow for quick genomic database queries, sequence lookup, BLAST-style searches, enrichment checks, and reproducible bioinformatics evidence logs.

affaan-m/literature-review

Systematic literature-review workflow for academic, biomedical, technical, and scientific topics, including search planning, source screening, synthesis, citation checks, and evidence logging.

affaan-m/motion-ui

Production-ready UI motion system for React/Next.js. Use when implementing animations, transitions, or motion patterns.

affaan-m/project-guidelines-example

Example project-specific skill template based on a real production application.

affaan-m/pubmed-database

Direct PubMed and NCBI E-utilities search workflows for biomedical literature, MeSH queries, PMID lookup, citation retrieval, and API-backed literature monitoring.

affaan-m/scholar-evaluation

Structured scholarly-work evaluation for papers, proposals, literature reviews, methods sections, evidence quality, citation support, and research-writing feedback.

affaan-m/uspto-database

USPTO patent and trademark data workflow for official record lookup, PatentSearch queries, TSDR checks, assignment data, and reproducible IP research logs.

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.

相關技能