К основному содержанию
скилл Claude Code CX Codex Cursor GitHub Copilot

hexagonal-architecture — скилл для Claude Code: обзор и установка

Помогает изолировать доменные правила от фреймворков, баз данных и очередей в сервисах на TypeScript, Java, Kotlin и Go. Пригодится при распутывании бизнес-логики и I/O.

Установить в Claude Code · Через Skills CLI (Vercel) Все способы и платформы ↓
npx skills add affaan-m/ECC --skill hexagonal-architecture -a claude-code
Открыть на GitHub

Что делает hexagonal-architecture

Скилл выстраивает структуру приложения по принципу портов и адаптеров (Hexagonal Architecture). Зависимости направлены строго внутрь. Входящие порты описывают команды и запросы, а исходящие фиксируют контракты для репозиториев или очередей. Вся логика координируется в чистых юзкейсах без привязки к Express или ORM.

Внутри заложен пошаговый процесс: выделение портов, реализация сценариев и сквозная связка зависимостей в composition root. Скилл также задаёт правила тестирования — юнит-тесты с фейковыми портами и интеграционные проверки адаптеров с реальной базой данных.

Ставить этот скилл стоит при распутывании сервисов, где доменные правила срослись с внешними библиотеками или HTTP-контроллерами.

Какие задачи решает

  • отделить доменную модель и бизнес-правила от библиотек, ORM и HTTP-транспорта
  • спроектировать входящие и исходящие порты для запуска сценария из очереди или CLI
  • заменить базу данных или сторонний API без переписывания прикладной логики
  • настроить изолированное юнит-тестирование юзкейсов через подмену портов

Примеры запросов агенту

  • Помоги отрефакторить этот сервис заказов на Express под гексагональную архитектуру.
  • Выдели входящие и исходящие порты для сценария регистрации пользователя на TypeScript.
  • Спроектируй структуру каталогов и composition root для нового модуля платежей.

Как установить hexagonal-architecture

1Через Skills CLI (Vercel)

npx skills add affaan-m/ECC --skill hexagonal-architecture -a claude-code

2Вручную: положить файлы

~/.claude/skills/hexagonal-architecture/SKILL.md

Папка скилла целиком; для одного проекта — .claude/skills/hexagonal-architecture/

Из того же набора146

Весь набор →
video-editing affaan-m Скилл выстраивает пайплайн монтажа реального видео через ИИ. Помогает нарезать сырые записи через FFmpeg, собрать титры в Remotion и добавить озвучку в ElevenLabs. Claude Code CX Codex Cursor +1 6 500установок docker-patterns affaan-m Скилл с проверенными шаблонами Dockerfile и Docker Compose: локальная разработка, сети, тома, безопасность контейнеров. Claude Code CX Codex Cursor +1 6 300установок frontend-patterns affaan-m Скилл подсказывает паттерны для React и Next.js: компоненты, состояние, загрузка данных и производительность. Нужен при разработке и ревью интерфейса. Claude Code CX Codex Cursor +1 5 900установок backend-patterns affaan-m Скилл с паттернами бэкенда для Node.js, Express и Next.js API routes: слои, кэш, транзакции, обработка ошибок. Claude Code CX Codex Cursor +1 5 900установок coding-standards affaan-m Базовые правила кода для проектов: проверяет именование, запрещает мутации объектов и следит за простыми конструкциями. Пригодится на ревью и рефакторинге. Claude Code CX Codex Cursor +1 5 600установок api-design affaan-m Скилл задаёт правила проектирования REST API: именование эндпоинтов, выбор статус-кодов, пагинацию и формат ошибок. Помогает при создании и ревью серверных контрактов. Claude Code CX Codex Cursor +1 5 500установок rust-testing affaan-m Скилл для написания тестов на Rust: юнит-тесты, интеграционные, async, property-based, моки и покрытие. Пригодится, когда ведёшь проект по TDD. Claude Code CX Codex Cursor +1 5 500установок laravel-security affaan-m Скилл помогает проверять безопасность Laravel-приложений: аутентификацию, Eloquent, CSRF, XSS, API и настройки production. Пригодится для ревью и деплоя. Claude Code CX Codex Cursor +1 5 400установок

Похожие

build-mcp-app официальный Anthropic Помогает добавить к MCP-серверу интерактивные формы, списки и визуальные виджеты. Подойдёт, когда результата в виде текста или JSON недостаточно. Claude Code 6 458установок mcp-builder официальный anthropics Скилл проводит через создание MCP-сервера на TypeScript или Python: от изучения протокола до тестов и оценки качества. Claude Code Claude.ai 130 949установок google-agents-cli-adk-code официальный Google Скилл даёт примеры и справку по Agent Development Kit: агентам, инструментам, колбэкам, состоянию и графовым workflow. Нужен при написании кода. Claude Code CX Codex Cursor +1 511 400установок lark-im larksuite Скилл подключает Lark IM к агенту: он отправляет сообщения, ищет историю, управляет чатами и файлами. Подойдёт для задач вокруг командных коммуникаций. Claude Code CX Codex Cursor +1 472 300установок lark-event larksuite Слушает события Lark/Feishu и отдаёт их потоком NDJSON. Подходит для ботов, обработчиков сообщений и долгих подписчиков. Claude Code CX Codex Cursor +1 466 200установок caveman-discover JuliusBrussee Находит точки вызова LLM в репозитории и размечает их воркфлоу для Caveman Cloud, чтобы расходы на токены не сливались в одну общую кучу. Claude Code CX Codex Cursor +1 103 500установок migration JuliusBrussee Скилл задаёт правила безопасных миграций схем, данных и API с обязательным откатом. Пригодится при изменениях, где нельзя терять данные или ломать совместимость. Claude Code CX Codex Cursor +1 102 900установок

Вопросы о hexagonal-architecture

Как установить hexagonal-architecture в Claude Code?

Выполните команду npx skills add affaan-m/ECC --skill hexagonal-architecture -a claude-code. Агент получит инструкции по структурированию слоёв и изоляции портов.

Для каких языков программирования подходит этот скилл?

Он ориентирован на проекты на TypeScript, Java, Kotlin и Go. Правила разделения слоёв универсальны, меняются только синтаксис и способ сборки зависимостей.

Как скилл организует связь между слоями?

Зависимости идут строго внутрь: адаптеры реализуют контракты портов, а доменная модель не импортирует внешние пакеты. Конкретные адаптеры связываются с юзкейсами в единой точке — composition root.

Исходный текст

SKILL.md · MIT
---
name: hexagonal-architecture
description: Design, implement, and refactor Ports & Adapters systems with clear domain boundaries, dependency inversion, and testable use-case orchestration across TypeScript, Java, Kotlin, and Go services. Use when introducing or refactoring toward Ports and Adapters, or when domain logic has become entangled with I/O.
metadata:
  origin: ECC
---

# Hexagonal Architecture

Hexagonal architecture (Ports and Adapters) keeps business logic independent from frameworks, transport, and persistence details. The core app depends on abstract ports, and adapters implement those ports at the edges.

## When to Use

- Building new features where long-term maintainability and testability matter.
- Refactoring layered or framework-heavy code where domain logic is mixed with I/O concerns.
- Supporting multiple interfaces for the same use case (HTTP, CLI, queue workers, cron jobs).
- Replacing infrastructure (database, external APIs, message bus) without rewriting business rules.

Use this skill when the request involves boundaries, domain-centric design, refactoring tightly coupled services, or decoupling application logic from specific libraries.

## Core Concepts

- **Domain model**: Business rules and entities/value objects. No framework imports.
- **Use cases (application layer)**: Orchestrate domain behavior and workflow steps.
- **Inbound ports**: Contracts describing what the application can do (commands/queries/use-case interfaces).
- **Outbound ports**: Contracts for dependencies the application needs (repositories, gateways, event publishers, clock, UUID, etc.).
- **Adapters**: Infrastructure and delivery implementations of ports (HTTP controllers, DB repositories, queue consumers, SDK wrappers).
- **Composition root**: Single wiring location where concrete adapters are bound to use cases.

Outbound port interfaces usually live in the application layer (or in domain only when the abstraction is truly domain-level), while infrastructure adapters implement them.

Dependency direction is always inward:

- Adapters -> application/domain
- Application -> port interfaces (inbound/outbound contracts)
- Domain -> domain-only abstractions (no framework or infrastructure dependencies)
- Domain -> nothing external

## How It Works

### Step 1: Model a use case boundary

Define a single use case with a clear input and output DTO. Keep transport details (Express `req`, GraphQL `context`, job payload wrappers) outside this boundary.

### Step 2: Define outbound ports first

Identify every side effect as a port:

- persistence (`UserRepositoryPort`)
- external calls (`BillingGatewayPort`)
- cross-cutting (`LoggerPort`, `ClockPort`)

Ports should model capabilities, not technologies.

### Step 3: Implement the use case with pure orchestration

Use case class/function receives ports via constructor/arguments. It validates application-level invariants, coordinates domain rules, and returns plain data structures.

### Step 4: Build adapters at the edge

- Inbound adapter converts protocol input to use-case input.
- Outbound adapter maps app contracts to concrete APIs/ORM/query builders.
- Mapping stays in adapters, not inside use cases.

### Step 5: Wire everything in a composition root

Instantiate adapters, then inject them into use cases. Keep this wiring centralized to avoid hidden service-locator behavior.

### Step 6: Test per boundary

- Unit test use cases with fake ports.
- Integration test adapters with real infra dependencies.
- E2E test user-facing flows through inbound adapters.

## Architecture Diagram

```mermaid
flowchart LR
  Client["Client (HTTP/CLI/Worker)"] --> InboundAdapter["Inbound Adapter"]
  InboundAdapter -->|"calls"| UseCase["UseCase (Application Layer)"]
  UseCase -->|"uses"| OutboundPort["OutboundPort (Interface)"]
  OutboundAdapter["Outbound Adapter"] -->|"implements"| OutboundPort
  OutboundAdapter --> ExternalSystem["DB/API/Queue"]
  UseCase --> DomainModel["DomainModel"]
```

## Suggested Module Layout

Use feature-first organization with explicit boundaries:

```text
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 Example

### Port definitions

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

### Use case

```typescript
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 returns a new Order instance; it does not mutate in place.
    const authorizedOrder = order.markAuthorized(auth.authorizationId);
    await this.orderRepository.save(authorizedOrder);

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

### Outbound adapter

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

### Composition root

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

## Multi-Language Mapping

Use the same boundary rules across ecosystems; only syntax and wiring style change.

- **TypeScript/JavaScript**
  - Ports: `application/ports/*` as interfaces/types.
  - Use cases: classes/functions with constructor/argument injection.
  - Adapters: `adapters/inbound/*`, `adapters/outbound/*`.
  - Composition: explicit factory/container module (no hidden globals).
- **Java**
  - Packages: `domain`, `application.port.in`, `application.port.out`, `application.usecase`, `adapter.in`, `adapter.out`.
  - Ports: interfaces in `application.port.*`.
  - Use cases: plain classes (Spring `@Service` is optional, not required).
  - Composition: Spring config or manual wiring class; keep wiring out of domain/use-case classes.
- **Kotlin**
  - Modules/packages mirror the Java split (`domain`, `application.port`, `application.usecase`, `adapter`).
  - Ports: Kotlin interfaces.
  - Use cases: classes with constructor injection (Koin/Dagger/Spring/manual).
  - Composition: module definitions or dedicated composition functions; avoid service locator patterns.
- **Go**
  - Packages: `internal/<feature>/domain`, `application`, `ports`, `adapters/inbound`, `adapters/outbound`.
  - Ports: small interfaces owned by the consuming application package.
  - Use cases: structs with interface fields plus explicit `New...` constructors.
  - Composition: wire in `cmd/<app>/main.go` (or dedicated wiring package), keep constructors explicit.

## Anti-Patterns to Avoid

- Domain entities importing ORM models, web framework types, or SDK clients.
- Use cases reading directly from `req`, `res`, or queue metadata.
- Returning database rows directly from use cases without domain/application mapping.
- Letting adapters call each other directly instead of flowing through use-case ports.
- Spreading dependency wiring across many files with hidden global singletons.

## Migration Playbook

1. Pick one vertical slice (single endpoint/job) with frequent change pain.
2. Extract a use-case boundary with explicit input/output types.
3. Introduce outbound ports around existing infrastructure calls.
4. Move orchestration logic from controllers/services into the use case.
5. Keep old adapters, but make them delegate to the new use case.
6. Add tests around the new boundary (unit + adapter integration).
7. Repeat slice-by-slice; avoid full rewrites.

### Refactoring Existing Systems

- **Strangler approach**: keep current endpoints, route one use case at a time through new ports/adapters.
- **No big-bang rewrites**: migrate per feature slice and preserve behavior with characterization tests.
- **Facade first**: wrap legacy services behind outbound ports before replacing internals.
- **Composition freeze**: centralize wiring early so new dependencies do not leak into domain/use-case layers.
- **Slice selection rule**: prioritize high-churn, low-blast-radius flows first.
- **Rollback path**: keep a reversible toggle or route switch per migrated slice until production behavior is verified.

## Testing Guidance (Same Hexagonal Boundaries)

- **Domain tests**: test entities/value objects as pure business rules (no mocks, no framework setup).
- **Use-case unit tests**: test orchestration with fakes/stubs for outbound ports; assert business outcomes and port interactions.
- **Outbound adapter contract tests**: define shared contract suites at port level and run them against each adapter implementation.
- **Inbound adapter tests**: verify protocol mapping (HTTP/CLI/queue payload to use-case input and output/error mapping back to protocol).
- **Adapter integration tests**: run against real infrastructure (DB/API/queue) for serialization, schema/query behavior, retries, and timeouts.
- **End-to-end tests**: cover critical user journeys through inbound adapter -> use case -> outbound adapter.
- **Refactor safety**: add characterization tests before extraction; keep them until new boundary behavior is stable and equivalent.

## Best Practices Checklist

- Domain and use-case layers import only internal types and ports.
- Every external dependency is represented by an outbound port.
- Validation occurs at boundaries (inbound adapter + use-case invariants).
- Use immutable transformations (return new values/entities instead of mutating shared state).
- Errors are translated across boundaries (infra errors -> application/domain errors).
- Composition root is explicit and easy to audit.
- Use cases are testable with simple in-memory fakes for ports.
- Refactoring starts from one vertical slice with behavior-preserving tests.
- Language/framework specifics stay in adapters, never in domain rules.

© affaan-m · MIT · affaan-m/ECC

Смотрите также

Спонсоры проекта

Компании, которые помогают держать аналитику открытой