Communitygithub.com

Hexagonale Architektur

Entwerfe, implementiere und refaktoriere Ports & Adapters Systeme mit klaren Domänengrenzen, Abhängigkeitsinversion und testbarer Use-Case-Orchestrierung für TypeScript-, Java-, Kotlin- und Go-Dienste. Verwende dieses Skill, wenn du Ports & Adapters einführst oder darauf umstellst, oder wenn die Geschäftslogik mit I/O vermischt ist.

Was ist Hexagonale Architektur?

Dieser Skill befähigt KI-Agenten (wie Claude Code, Cursor, Codex) dazu, hexagonale Architektur (Ports & Adapters) in verschiedenen Programmiersprachen zu entwerfen, implementieren und umzugestalten. Er stellt sicher, dass die Geschäftslogik von Frameworks, Transportprotokollen und Persistenzdetails isoliert bleibt, indem er sich auf klare Grenzen, Abhängigkeitsinversion und testbare Use-Case-Orchestrierung konzentriert. Der Skill unterstützt TypeScript, Java, Kotlin und Go und enthält eine strukturierte Schritt-für-Schritt-Anleitung zur Modellierung von Use Cases, zur Definition von Ports und Adaptern, zur Implementierung reiner Orchestrierung in der Anwendungsschicht, zur Konstruktion von Adaptern an den Grenzen und zur Verdrahtung des gesamten Systems in einer einzigen Kompositionswurzel. Er bietet auch eine Migrationsanleitung für die Umstellung bestehender Systeme, einschließlich einer Strangulation-Methode und spezifischer Teststrategien für jede architektonische Grenze, um wartbare, testbare und anpassungsfähige Systeme zu erhalten.

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

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

Was macht Hexagonale Architektur?

Hexagonale Architektur (Ports und Adapter) hält die Geschäftslogik unabhängig von Frameworks, Transport- und Persistenzdetails. Die Kernanwendung hängt von abstrakten Ports ab, und Adapter implementieren diese Ports an den Rändern.

Wann verwenden

  • Neue Funktionen entwickeln, bei denen langfristige Wartbarkeit und Testbarkeit wichtig sind.
  • Refaktorisieren von stark geschichtetem oder framework-lastigem Code, in dem die Domänenlogik mit I/O-Belangen vermischt ist.
  • Unterstützen mehrerer Schnittstellen für denselben Anwendungsfall (HTTP, CLI, Queue-Worker, Cron-Jobs).
  • Austauschen von Infrastruktur (Datenbank, externe APIs, Message Bus), ohne die Geschäftsregeln neu zu schreiben.

Verwende dieses Skill, wenn die Anfrage Grenzen, domänenzentriertes Design, Refaktorisieren von eng gekoppelten Diensten oder das Entkoppeln der Anwendungslogik von bestimmten Bibliotheken betrifft.

Kernkonzepte

  • Domänenmodell: Geschäftsregeln und Entitäten/Wertobjekte. Keine Framework-Importe.
  • Use Cases (Anwendungsschicht): Orchestrieren von Domänenverhalten und Arbeitsschritten.
  • Eingehende Ports: Verträge, die beschreiben, was die Anwendung tun kann (Befehle/Anfragen/Use-Case-Schnittstellen).
  • Ausgehende Ports: Verträge für Abhängigkeiten, die die Anwendung benötigt (Repositories, Gateways, Event-Publisher, Uhr, UUID usw.).
  • Adapter: Infrastruktur- und Bereitstellungsimplementierungen von Ports (HTTP-Controller, DB-Repositories, Queue-Consumer, SDK-Wrapper).
  • Kompositionswurzel: Einzige Verdrahtungsstelle, an der konkrete Adapter an Use Cases gebunden werden.

Ausgehende Port-Schnittstellen leben normalerweise in der Anwendungsschicht (oder nur in der Domäne, wenn die Abstraktion wirklich auf Domänenebene ist), während Infrastrukturadapter sie implementieren.

Die Abhängigkeitsrichtung ist immer nach innen gerichtet:

  • Adapter -> Anwendung/Domäne
  • Anwendung -> Port-Schnittstellen (eingehende/ausgehende Verträge)
  • Domäne -> domänenexklusive Abstraktionen (keine Framework- oder Infrastrukturabhängigkeiten)
  • Domäne -> nichts von außen

Wie es funktioniert

Schritt 1: Eine Use-Case-Grenze modellieren

Definiere einen einzelnen Use Case mit einem klaren Eingabe- und Ausgabe-DTO. Halte Transportdetails (Express req, GraphQL context, Job-Payload-Wrapper) außerhalb dieser Grenze.

Schritt 2: Zuerst ausgehende Ports definieren

Identifiziere jeden Seiteneffekt als Port:

  • Persistenz (UserRepositoryPort)
  • Externe Aufrufe (BillingGatewayPort)
  • Querschnittsfunktionen (LoggerPort, ClockPort)

Ports sollten Fähigkeiten modellieren, nicht Technologien.

Schritt 3: Den Use Case mit reiner Orchestrierung implementieren

Die Use-Case-Klasse/-Funktion erhält Ports über den Konstruktor/die Argumente. Sie validiert anwendungsbezogene Invarianten, koordiniert Domänenregeln und gibt einfache Datenstrukturen zurück.

Schritt 4: Adapter an den Rändern bauen

  • Eingehender Adapter: Konvertiert Protokolleingaben in Use-Case-Eingaben.
  • Ausgehender Adapter: Bildet Anwendungsverträge auf konkrete APIs/ORM/Query-Builder ab.
  • Das Mapping bleibt in Adaptern, nicht in Use Cases.

Schritt 5: Alles in einer Kompositionswurzel verdrahten

Instanziiere Adapter und injiziere sie in Use Cases. Halte diese Verdrahtung zentralisiert, um verstecktes Service-Locator-Verhalten zu vermeiden.

Schritt 6: Pro Grenze testen

  • Unit-Tests für Use Cases mit Fake-Ports.
  • Integrationstests für Adapter mit realen Infrastrukturabhängigkeiten.
  • E2E-Tests für benutzerseitige Abläufe durch eingehende Adapter.

Architekturdiagramm

flowchart LR
  Client["Client (HTTP/CLI/Worker)"] --> InboundAdapter["Eingehender Adapter"]
  InboundAdapter -->|"ruft auf"| UseCase["UseCase (Anwendungsschicht)"]
  UseCase -->|"verwendet"| OutboundPort["Ausgehender Port (Schnittstelle)"]
  OutboundAdapter["Ausgehender Adapter"] -->|"implementiert"| OutboundPort
  OutboundAdapter --> ExternalSystem["DB/API/Queue"]
  UseCase --> DomainModel["Domänenmodell"]

Vorgeschlagenes Modullayout

Verwende feature-first-Organisation mit expliziten Grenzen:

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-Beispiel

Port-Definitionen

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 }>;
}

Use Case

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 gibt eine neue Order-Instanz zurück; es mutiert nicht die vorhandene.
    const authorizedOrder = order.markAuthorized(auth.authorizationId);
    await this.orderRepository.save(authorizedOrder);

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

Ausgehender Adapter

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;
  }
}

Kompositionswurzel

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);
};

Sprachübergreifende Abbildung

Verwende dieselben Grenzregeln in allen Ökosystemen; nur Syntax und Verdrahtungsstil ändern sich.

  • TypeScript/JavaScript
    • Ports: application/ports/* als Schnittstellen/Typen.
    • Use Cases: Klassen/Funktionen mit Konstruktor-/Argumentinjektion.
    • Adapter: adapters/inbound/*, adapters/outbound/*.
    • Komposition: explizites Factory-/Container-Modul (keine versteckten Globals).
  • Java
    • Packages: domain, application.port.in, application.port.out, application.usecase, adapter.in, adapter.out.
    • Ports: Schnittstellen in application.port.*.
    • Use Cases: einfache Klassen (Spring @Service ist optional, nicht erforderlich).
    • Komposition: Spring-Konfiguration oder manuelle Verdrahtungsklasse; halte die Verdrahtung außerhalb von Domänen-/Use-Case-Klassen.
  • Kotlin
    • Module/Packages spiegeln die Java-Aufteilung wider (domain, application.port, application.usecase, adapter).
    • Ports: Kotlin-Schnittstellen.
    • Use Cases: Klassen mit Konstruktorinjektion (Koin/Dagger/Spring/manuell).
    • Komposition: Moduldefinitionen oder dedizierte Kompositionsfunktionen; vermeide Service-Locator-Muster.
  • Go
    • Packages: internal/<feature>/domain, application, ports, adapters/inbound, adapters/outbound.
    • Ports: kleine Schnittstellen, die dem verbrauchenden Anwendungspackage gehören.
    • Use Cases: Structs mit Schnittstellenfeldern und expliziten New...-Konstruktoren.
    • Komposition: Verdrahtung in cmd/<app>/main.go (oder dediziertes Verdrahtungspackage), halte Konstruktoren explizit.

Anti-Patterns vermeiden

  • Domänenentitäten importieren ORM-Modelle, Web-Framework-Typen oder SDK-Clients.
  • Use Cases lesen direkt von req, res oder Queue-Metadaten.
  • Rückgabe von Datenbankzeilen direkt aus Use Cases ohne Domänen-/Anwendungs-Mapping.
  • Adapter rufen sich gegenseitig direkt auf, anstatt durch Use-Case-Ports zu fließen.
  • Verteilung der Abhängigkeitsverdrahtung auf viele Dateien mit versteckten globalen Singletons.

Migrationshandbuch

  1. Wähle einen vertikalen Ausschnitt (einzelner Endpunkt/Job) mit häufigen Änderungsschmerzen.
  2. Extrahiere eine Use-Case-Grenze mit expliziten Ein-/Ausgabetypen.
  3. Führe ausgehende Ports um bestehende Infrastrukturaufrufe ein.
  4. Verschiebe Orchestrierungslogik von Controllern/Services in den Use Case.
  5. Behalte alte Adapter, aber lasse sie an den neuen Use Case delegieren.
  6. Füge Tests um die neue Grenze hinzu (Unit + Adapterintegration).
  7. Wiederhole ausschnittsweise; vermeide vollständige Neuschreibungen.

Refaktorisieren bestehender Systeme

  • Strangler-Ansatz: Behalte aktuelle Endpunkte bei, leite einen Use Case nach dem anderen durch neue Ports/Adapter.
  • Keine Big-Bang-Neuschreibungen: Migriere pro Feature-Ausschnitt und bewahre das Verhalten mit Charakterisierungstests.
  • Fassade zuerst: Umwickle Legacy-Services hinter ausgehenden Ports, bevor du Interna ersetzt.
  • Kompositionsstillstand: Zentralisiere die Verdrahtung frühzeitig, damit neue Abhängigkeiten nicht in die Domänen-/Use-Case-Schichten gelangen.
  • Ausschnittauswahl-Regel: Priorisiere zuerst Abläufe mit hoher Änderungsrate und geringem Schadensradius.
  • Rollback-Pfad: Behalte einen umkehrbaren Schalter oder Routenumschalter pro migriertem Ausschnitt bei, bis das Produktionsverhalten verifiziert ist.

Testleitfaden (gleiche hexagonale Grenzen)

  • Domänentests: Teste Entitäten/Wertobjekte als reine Geschäftsregeln (keine Mocks, kein Framework-Setup).
  • Use-Case-Unit-Tests: Teste Orchestrierung mit Fakes/Stubs für ausgehende Ports; bewerte Geschäftsergebnisse und Port-Interaktionen.
  • Ausgehende Adapter-Vertragstests: Definiere gemeinsame Vertragssuiten auf Port-Ebene und führe sie gegen jede Adapterimplementierung aus.
  • Eingehende Adapter-Tests: Überprüfe das Protokoll-Mapping (HTTP/CLI/Queue-Payload zu Use-Case-Eingabe und Ausgabe/Fehler-Mapping zurück zum Protokoll).
  • Adapter-Integrationstests: Führe gegen reale Infrastruktur (DB/API/Queue) für Serialisierung, Schema/Query-Verhalten, Wiederholungen und Timeouts aus.
  • Ende-zu-Ende-Tests: Decke kritische Benutzerreisen durch eingehenden Adapter -> Use Case -> ausgehenden Adapter ab.
  • Refaktorsicherheit: Füge Charakterisierungstests vor der Extraktion hinzu; behalte sie bei, bis das neue Grenzverhalten stabil und gleichwertig ist.

Checkliste für bewährte Praktiken

  • Domänen- und Use-Case-Schichten importieren nur interne Typen und Ports.
  • Jede externe Abhängigkeit wird durch einen ausgehenden Port repräsentiert.
  • Validierung erfolgt an Grenzen (eingehender Adapter + Use-Case-Invarianten).
  • Verwende unveränderliche Transformationen (gebe neue Werte/Entitäten zurück, anstatt gemeinsamen Zustand zu mutieren).
  • Fehler werden über Grenzen hinweg übersetzt (Infra-Fehler -> Anwendungs-/Domänenfehler).
  • Kompositionswurzel ist explizit und einfach zu prüfen.
  • Use Cases sind mit einfachen In-Memory-Fakes für Ports testbar.
  • Refaktorisierung beginnt mit einem vertikalen Ausschnitt und verhaltensbewahrenden Tests.
  • Sprach-/Framework-Spezifika bleiben in Adaptern, niemals in Domänenregeln.

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.

Verwandte Skills