Communitygithub.com

ヘキサゴナルアーキテクチャ

ポートとアダプターからなるシステムを設計、実装、リファクタリングし、明確なドメイン境界、依存性逆転、テスト可能なユースケースオーケストレーションをTypeScript、Java、Kotlin、Goのサービスで実現します。ポートとアダプターを導入またはリファクタリングする場合、またはドメインロジックがI/Oと混在している場合に使用します。

ヘキサゴナルアーキテクチャ とは?

ヘキサゴナルアーキテクチャ(ポートとアダプター)スキルは、ビジネスロジックをフレームワーク、トランスポート、永続化の詳細から独立させます。コアとなるアプリケーションは抽象的なポートに依存し、アダプターがそのポートを境界で実装します。このスキルは、新機能開発、レイヤードアーキテクチャやフレームワークに依存したコードのリファクタリング、単一ユースケースへの複数インターフェース(HTTP、CLI、ワーカーなど)のサポート、インフラストラクチャ(データベース、外部API、メッセージバス)の交換をビジネスルールを書き換えずに行う際に特に役立ちます。TypeScript、Java、Kotlin、Goを公式にサポートし、依存関係の方向は常に内側(アダプター→アプリケーション/ドメイン)になります。ポートインターフェースはアプリケーション層に置き、アダプターはインフラストラクチャの詳細を実装します。ユースケースは純粋なオーケストレーションとして構築され、テストは境界ごとに行います(ユニットテスト、結合テスト、E2Eテスト)。移行はストラングラーパターンを用いてスライスごとに行い、一度に全書き換えは避けます。

対応~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/ECC/tree/main/skills/hexagonal-architecture

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

ヘキサゴナルアーキテクチャ は何をしますか?

ヘキサゴナルアーキテクチャ(ポートとアダプター)は、ビジネスロジックをフレームワーク、トランスポート、永続化の詳細から独立させます。コアとなるアプリケーションは抽象的なポートに依存し、アダプターがそのポートを境界で実装します。

使用するタイミング

  • 長期的な保守性とテスタビリティが重要な新機能を構築する場合。
  • ドメインロジックがI/Oの懸念と混在している、レイヤードまたはフレームワークに依存したコードをリファクタリングする場合。
  • 同じユースケースに対して複数のインターフェース(HTTP、CLI、キューワーカー、cronジョブ)をサポートする場合。
  • ビジネスルールを書き換えずにインフラストラクチャ(データベース、外部API、メッセージバス)を交換する場合。

このスキルは、境界、ドメイン中心設計、密結合されたサービスのリファクタリング、またはアプリケーションロジックを特定のライブラリから切り離すことに関するリクエストがある場合に使用してください。

コアコンセプト

  • ドメインモデル: ビジネスルールとエンティティ/値オブジェクト。フレームワークのインポートはありません。
  • ユースケース(アプリケーション層): ドメインの動作とワークフローステップをオーケストレーションします。
  • インバウンドポート: アプリケーションが何をできるかを記述する契約(コマンド/クエリ/ユースケースインターフェース)。
  • アウトバウンドポート: アプリケーションが必要とする依存関係のための契約(リポジトリ、ゲートウェイ、イベントパブリッシャー、クロック、UUIDなど)。
  • アダプター: ポートのインフラストラクチャおよび配信の実装(HTTPコントローラー、DBリポジトリ、キューコンシューマー、SDKラッパー)。
  • コンポジションルート: 具体的なアダプターがユースケースにバインドされる単一の配線場所。

アウトバウンドポートインターフェースは通常アプリケーション層に存在します(抽象化が真にドメインレベルの場合のみドメイン層に配置します)。一方、インフラストラクチャアダプターはそれらを実装します。

依存関係の方向は常に内側です:

  • アダプター -> アプリケーション/ドメイン
  • アプリケーション -> ポートインターフェース(インバウンド/アウトバウンド契約)
  • ドメイン -> ドメインのみの抽象化(フレームワークやインフラストラクチャの依存関係なし)
  • ドメイン -> 外部への依存関係なし

動作方法

ステップ 1: ユースケース境界をモデル化する

明確な入力DTOと出力DTOを持つ単一のユースケースを定義します。トランスポートの詳細(Expressのreq、GraphQLのcontext、ジョブペイロードラッパー)はこの境界の外側に保持します。

ステップ 2: まずアウトバウンドポートを定義する

すべての副作用をポートとして特定します:

  • 永続化 (UserRepositoryPort)
  • 外部呼び出し (BillingGatewayPort)
  • 横断的関心事 (LoggerPort、ClockPort)

ポートはテクノロジーではなく、機能をモデル化する必要があります。

ステップ 3: 純粋なオーケストレーションでユースケースを実装する

ユースケースクラス/関数は、コンストラクタ/引数を介してポートを受け取ります。アプリケーションレベルの不変条件を検証し、ドメインルールを調整し、プレーンなデータ構造を返します。

ステップ 4: 境界にアダプターを構築する

  • インバウンドアダプターはプロトコル入力をユースケース入力に変換します。
  • アウトバウンドアダプターはアプリケーション契約を具体的なAPI/ORM/クエリビルダーにマッピングします。
  • マッピングはアダプター内に留まり、ユースケース内部には入りません。

ステップ 5: コンポジションルートですべてを配線する

アダプターをインスタンス化し、それらをユースケースに注入します。この配線を集中管理して、隠れたサービスロケーター動作を避けます。

ステップ 6: 境界ごとにテストする

  • フェイクポートを使用してユースケースを単体テストします。
  • 実際のインフラ依存関係を使用してアダプターを統合テストします。
  • インバウンドアダプターを通じてユーザー向けフローをE2Eテストします。

アーキテクチャ図

flowchart LR
  Client["クライアント (HTTP/CLI/ワーカー)"] --> InboundAdapter["インバウンドアダプター"]
  InboundAdapter -->|"呼び出し"| UseCase["ユースケース (アプリケーション層)"]
  UseCase -->|"使用"| OutboundPort["アウトバウンドポート (インターフェース)"]
  OutboundAdapter["アウトバウンドアダプター"] -->|"実装"| OutboundPort
  OutboundAdapter --> ExternalSystem["DB/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. 変更が頻繁に発生する1つの垂直スライス(単一のエンドポイント/ジョブ)を選択します。
  2. 明示的な入出力型を持つユースケース境界を抽出します。
  3. 既存のインフラストラクチャ呼び出しの周りにアウトバウンドポートを導入します。
  4. コントローラー/サービスからユースケースへオーケストレーションロジックを移動します。
  5. 古いアダプターはそのままにして、新しいユースケースに委譲するようにします。
  6. 新しい境界の周りにテストを追加します(単体テスト+アダプター統合テスト)。
  7. スライスごとに繰り返します。完全な書き換えは避けます。

既存システムのリファクタリング

  • ストラングラーアプローチ: 現在のエンドポイントを維持し、一度に1つのユースケースを新しいポート/アダプター経由でルーティングします。
  • ビッグバン書き換えはしない: 機能スライスごとに移行し、特性テストで動作を保護します。
  • まずファサード: 内部を置き換える前に、レガシーサービスをアウトバウンドポートの背後にラップします。
  • コンポジションの凍結: 新しい依存関係がドメイン/ユースケース層に漏れないように、早期に配線を集中管理します。
  • スライス選択ルール: 変更頻度が高く、影響範囲が狭いフローを優先します。
  • ロールバックパス: プロダクションでの動作が検証されるまで、移行したスライスごとに元に戻せるトグルまたはルートスイッチを保持します。

テストガイダンス(同じヘキサゴナル境界)

  • ドメインテスト: エンティティ/値オブジェクトを純粋なビジネスルールとしてテストします(モックなし、フレームワークのセットアップなし)。
  • ユースケース単体テスト: アウトバウンドポートのフェイク/スタブを使用してオーケストレーションをテストし、ビジネス成果とポートインタラクションをアサートします。
  • アウトバウンドアダプター契約テスト: ポートレベルで共有の契約スイートを定義し、各アダプター実装に対して実行します。
  • インバウンドアダプターテスト: プロトコルマッピング(HTTP/CLI/キューペイロードからユースケース入力、出力/エラーのプロトコルへのマッピング)を検証します。
  • アダプター統合テスト: シリアル化、スキーマ/クエリ動作、リトライ、タイムアウトについて実際のインフラ(DB/API/キュー)に対して実行します。
  • エンドツーエンドテスト: インバウンドアダプター -> ユースケース -> アウトバウンドアダプターを通じて、重要なユーザージャーニーをカバーします。
  • リファクタリングの安全性: 抽出前に特性テストを追加し、新しい境界の動作が安定して同等になるまで維持します。

ベストプラクティスチェックリスト

  • ドメイン層とユースケース層は内部型とポートのみをインポートします。
  • すべての外部依存関係はアウトバウンドポートによって表現されています。
  • 検証は境界(インバウンドアダプター + ユースケース不変条件)で行われます。
  • 不変の変換を使用します(共有状態を変更する代わりに、新しい値/エンティティを返します)。
  • エラーは境界を越えて変換されます(インフラエラー -> アプリケーション/ドメインエラー)。
  • コンポジションルートは明示的で監査が容易です。
  • ユースケースはポートに対するシンプルなインメモリフェイクでテスト可能です。
  • リファクタリングは動作を保持するテストから始まる1つの垂直スライスから開始します。
  • 言語/フレームワーク固有の詳細はアダプターに留まり、ドメインルールには決して入りません。

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.

関連スキル