Communitygithub.com

Arquitetura Hexagonal

Projetar, implementar e refatorar sistemas de Ports & Adapters com limites de domínio claros, inversão de dependência e orquestração de casos de uso testável em serviços TypeScript, Java, Kotlin e Go. Use ao introduzir ou refatorar para Ports and Adapters, ou quando a lógica de domínio se tornar emaranhada com E/S.

O que é Arquitetura Hexagonal?

Esta skill implementa a Arquitetura Hexagonal (Ports and Adapters) para manter a lógica de negócio independente de frameworks, transporte e detalhes de persistência. O núcleo da aplicação depende de portas abstratas, e os adaptadores concretizam essas portas nas bordas. É útil ao construir novos recursos onde manutenibilidade e testabilidade são importantes, refatorar código com forte acoplamento de framework ou substituir infraestrutura (banco de dados, APIs externas, barramento de mensagens) sem reescrever regras de negócio. A skill abrange conceitos fundamentais como modelo de domínio, portas de entrada e saída, adaptadores, e um roteiro de migração com abordagem estranguladora. Fornece exemplos em TypeScript, Java, Kotlin e Go, além de orientações detalhadas sobre testes (domínio, caso de uso, adaptador, integração e ponta a ponta) e antipadrões a evitar, garantindo que a lógica de domínio permaneça pura e as dependências sempre apontem para dentro.

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

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

O que Arquitetura Hexagonal faz?

A arquitetura hexagonal (Ports e Adapters) mantém a lógica de negócio independente de frameworks, transporte e detalhes de persistência. O aplicativo principal depende de portas abstratas, e os adaptadores implementam essas portas nas bordas.

Quando Usar

  • Construir novos recursos onde manutenibilidade e testabilidade a longo prazo são importantes.
  • Refatorar código em camadas ou com forte dependência de framework onde a lógica de domínio está misturada com preocupações de E/S.
  • Suportar múltiplas interfaces para o mesmo caso de uso (HTTP, CLI, workers de fila, cron jobs).
  • Substituir infraestrutura (banco de dados, APIs externas, barramento de mensagens) sem reescrever regras de negócio.

Use esta skill quando a solicitação envolver limites, design centrado em domínio, refatoração de serviços fortemente acoplados ou desacoplamento da lógica de aplicação de bibliotecas específicas.

Conceitos Principais

  • Modelo de domínio: Regras de negócio e entidades/objetos de valor. Sem importações de framework.
  • Casos de uso (camada de aplicação): Orquestrar comportamento de domínio e etapas do fluxo de trabalho.
  • Portas de entrada: Contratos que descrevem o que a aplicação pode fazer (interfaces de comandos/consultas/casos de uso).
  • Portas de saída: Contratos para dependências que a aplicação precisa (repositórios, gateways, publicadores de eventos, relógio, UUID, etc.).
  • Adaptadores: Implementações de infraestrutura e entrega das portas (controladores HTTP, repositórios de banco de dados, consumidores de fila, wrappers de SDK).
  • Raiz de composição: Único local de montagem onde adaptadores concretos são vinculados a casos de uso.

Interfaces de portas de saída geralmente residem na camada de aplicação (ou apenas no domínio quando a abstração é verdadeiramente de nível de domínio), enquanto adaptadores de infraestrutura as implementam.

A direção da dependência é sempre para dentro:

  • Adaptadores -> aplicação/domínio
  • Aplicação -> interfaces de porta (contratos de entrada/saída)
  • Domínio -> abstrações apenas do domínio (sem dependências de framework ou infraestrutura)
  • Domínio -> nada externo

Como Funciona

Passo 1: Modele um limite de caso de uso

Defina um único caso de uso com um DTO de entrada e saída claros. Mantenha detalhes de transporte (Express req, GraphQL context, wrappers de payload de job) fora deste limite.

Passo 2: Defina primeiro as portas de saída

Identifique cada efeito colateral como uma porta:

  • persistência (UserRepositoryPort)
  • chamadas externas (BillingGatewayPort)
  • transversais (LoggerPort, ClockPort)

As portas devem modelar capacidades, não tecnologias.

Passo 3: Implemente o caso de uso com orquestração pura

A classe/função de caso de uso recebe portas via construtor/argumentos. Ela valida invariantes de nível de aplicação, coordena regras de domínio e retorna estruturas de dados simples.

Passo 4: Construa adaptadores na borda

  • Adaptador de entrada converte entrada do protocolo em entrada do caso de uso.
  • Adaptador de saída mapeia contratos da aplicação para APIs/ORM/query builders concretos.
  • O mapeamento permanece nos adaptadores, não dentro dos casos de uso.

Passo 5: Conecte tudo em uma raiz de composição

Instancie adaptadores e injete-os nos casos de uso. Mantenha essa montagem centralizada para evitar comportamento oculto de localizador de serviços.

Passo 6: Teste por limite

  • Teste unitário de casos de uso com portas simuladas (fakes).
  • Teste de integração de adaptadores com dependências de infraestrutura reais.
  • Teste ponta a ponta (E2E) de fluxos voltados ao usuário através de adaptadores de entrada.

Diagrama de Arquitetura

flowchart LR
  Client["Cliente (HTTP/CLI/Worker)"] --> InboundAdapter["Adaptador de Entrada"]
  InboundAdapter -->|"chama"| UseCase["CasoDeUso (Camada de Aplicação)"]
  UseCase -->|"usa"| OutboundPort["PortaDeSaída (Interface)"]
  OutboundAdapter["Adaptador de Saída"] -->|"implementa"| OutboundPort
  OutboundAdapter --> ExternalSystem["BD/API/Fila"]
  UseCase --> DomainModel["ModeloDeDomínio"]

Layout de Módulo Sugerido

Use organização por funcionalidade com limites explícitos:

src/
  features/
    pedidos/
      domain/
        Pedido.ts
        PoliticaDePedido.ts
      application/
        ports/
          inbound/
            CriarPedido.ts
          outbound/
            PortaRepositorioPedido.ts
            PortaGatewayPagamento.ts
        use-cases/
            CasoDeUsoCriarPedido.ts
      adapters/
        inbound/
          http/
            rotaCriarPedido.ts
        outbound/
          postgres/
            RepositorioPedidoPostgres.ts
          stripe/
            GatewayPagamentoStripe.ts
      composition/
        containerPedidos.ts

Exemplo em TypeScript

Definições de Porta

export interface PortaRepositorioPedido {
  salvar(pedido: Pedido): Promise<void>;
  encontrarPorId(id: string): Promise<Pedido | null>;
}

export interface PortaGatewayPagamento {
  autorizar(input: { idPedido: string; valorCentavos: number }): Promise<{ idAutorizacao: string }>;
}

Caso de Uso

type EntradaCriarPedido = {
  idPedido: string;
  valorCentavos: number;
};

type SaidaCriarPedido = {
  idPedido: string;
  idAutorizacao: string;
};

export class CasoDeUsoCriarPedido {
  constructor(
    private readonly repositorioPedido: PortaRepositorioPedido,
    private readonly gatewayPagamento: PortaGatewayPagamento
  ) {}

  async executar(input: EntradaCriarPedido): Promise<SaidaCriarPedido> {
    const pedido = Pedido.criar({ id: input.idPedido, valorCentavos: input.valorCentavos });

    const auth = await this.gatewayPagamento.autorizar({
      idPedido: pedido.id,
      valorCentavos: pedido.valorCentavos,
    });

    // marcarAutorizado retorna uma nova instância de Pedido; não modifica no local.
    const pedidoAutorizado = pedido.marcarAutorizado(auth.idAutorizacao);
    await this.repositorioPedido.salvar(pedidoAutorizado);

    return {
      idPedido: pedido.id,
      idAutorizacao: auth.idAutorizacao,
    };
  }
}

Adaptador de Saída

export class RepositorioPedidoPostgres implements PortaRepositorioPedido {
  constructor(private readonly db: SqlClient) {}

  async salvar(pedido: Pedido): Promise<void> {
    await this.db.query(
      "insert into pedidos (id, valor_centavos, status, id_autorizacao) values ($1, $2, $3, $4)",
      [pedido.id, pedido.valorCentavos, pedido.status, pedido.idAutorizacao]
    );
  }

  async encontrarPorId(idPedido: string): Promise<Pedido | null> {
    const linha = await this.db.oneOrNone("select * from pedidos where id = $1", [idPedido]);
    return linha ? Pedido.reidratar(linha) : null;
  }
}

Raiz de Composição

export const construirCasoDeUsoCriarPedido = (deps: { db: SqlClient; stripe: StripeClient }) => {
  const repositorioPedido = new RepositorioPedidoPostgres(deps.db);
  const gatewayPagamento = new GatewayPagamentoStripe(deps.stripe);

  return new CasoDeUsoCriarPedido(repositorioPedido, gatewayPagamento);
};

Mapeamento Multi-Linguagem

Use as mesmas regras de limite em todos os ecossistemas; apenas a sintaxe e o estilo de montagem mudam.

  • TypeScript/JavaScript
    • Portas: application/ports/* como interfaces/tipos.
    • Casos de uso: classes/funções com injeção via construtor/argumento.
    • Adaptadores: adapters/inbound/*, adapters/outbound/*.
    • Composição: módulo de fábrica/container explícito (sem globais ocultos).
  • Java
    • Pacotes: domain, application.port.in, application.port.out, application.usecase, adapter.in, adapter.out.
    • Portas: interfaces em application.port.*.
    • Casos de uso: classes simples (Spring @Service é opcional, não obrigatório).
    • Composição: configuração Spring ou classe de montagem manual; mantenha a montagem fora das classes de domínio/caso de uso.
  • Kotlin
    • Módulos/pacotes espelham a divisão Java (domain, application.port, application.usecase, adapter).
    • Portas: interfaces Kotlin.
    • Casos de uso: classes com injeção via construtor (Koin/Dagger/Spring/manual).
    • Composição: definições de módulo ou funções de composição dedicadas; evite padrões de localizador de serviços.
  • Go
    • Pacotes: internal/<funcionalidade>/domain, application, ports, adapters/inbound, adapters/outbound.
    • Portas: interfaces pequenas de propriedade do pacote de aplicação consumidor.
    • Casos de uso: structs com campos de interface e construtores explícitos New....
    • Composição: montagem em cmd/<app>/main.go (ou pacote de montagem dedicado), mantenha construtores explícitos.

Antipadrões a Evitar

  • Entidades de domínio importando modelos ORM, tipos de framework web ou clientes SDK.
  • Casos de uso lendo diretamente de req, res ou metadados de fila.
  • Retornar linhas de banco de dados diretamente dos casos de uso sem mapeamento de domínio/aplicação.
  • Deixar adaptadores chamarem uns aos outros diretamente em vez de fluir através de portas de caso de uso.
  • Espalhar a montagem de dependências por muitos arquivos com singletons globais ocultos.

Roteiro de Migração

  1. Escolha uma fatia vertical (único endpoint/job) com dor frequente de alteração.
  2. Extraia um limite de caso de uso com tipos de entrada/saída explícitos.
  3. Introduza portas de saída em torno de chamadas de infraestrutura existentes.
  4. Mova a lógica de orquestração de controladores/serviços para o caso de uso.
  5. Mantenha os adaptadores antigos, mas faça-os delegar para o novo caso de uso.
  6. Adicione testes em torno do novo limite (testes de unidade + integração de adaptador).
  7. Repita fatia por fatia; evite reescritas completas.

Refatoração de Sistemas Existentes

  • Abordagem estranguladora: mantenha os endpoints atuais, roteie um caso de uso por vez através de novas portas/adaptadores.
  • Sem reescritas de big-bang: migre por fatia de funcionalidade e preserve o comportamento com testes de caracterização.
  • Fachada primeiro: envolva serviços legados por trás de portas de saída antes de substituir os internos.
  • Congelamento de composição: centralize a montagem cedo para que novas dependências não vazem para as camadas de domínio/caso de uso.
  • Regra de seleção de fatia: priorize fluxos de alta rotatividade e baixo raio de impacto primeiro.
  • Caminho de reversão: mantenha um toggle reversível ou chave de rota por fatia migrada até que o comportamento em produção seja verificado.

Orientações de Teste (Mesmos Limites Hexagonais)

  • Testes de domínio: teste entidades/objetos de valor como regras de negócio puras (sem mocks, sem configuração de framework).
  • Testes de unidade de caso de uso: teste a orquestração com fakes/stubs para portas de saída; afirme resultados de negócio e interações com portas.
  • Testes de contrato de adaptador de saída: defina suítes de contrato compartilhadas no nível da porta e execute-as contra cada implementação de adaptador.
  • Testes de adaptador de entrada: verifique o mapeamento de protocolo (payload HTTP/CLI/fila para entrada do caso de uso e mapeamento de saída/erro de volta para o protocolo).
  • Testes de integração de adaptador: execute contra infraestrutura real (BD/API/fila) para serialização, comportamento de schema/consulta, retentativas e timeouts.
  • Testes ponta a ponta: cubra jornadas críticas do usuário através do adaptador de entrada -> caso de uso -> adaptador de saída.
  • Segurança para refatoração: adicione testes de caracterização antes da extração; mantenha-os até que o comportamento do novo limite esteja estável e equivalente.

Lista de Verificação de Melhores Práticas

  • Camadas de domínio e caso de uso importam apenas tipos internos e portas.
  • Toda dependência externa é representada por uma porta de saída.
  • Validação ocorre nos limites (adaptador de entrada + invariantes do caso de uso).
  • Use transformações imutáveis (retorne novos valores/entidades em vez de mutar estado compartilhado).
  • Erros são traduzidos entre limites (erros de infraestrutura -> erros de aplicação/domínio).
  • A raiz de composição é explícita e fácil de auditar.
  • Casos de uso são testáveis com fakes simples em memória para portas.
  • A refatoração começa a partir de uma fatia vertical com testes de preservação de comportamento.
  • Especificidades de linguagem/framework permanecem nos adaptadores, nunca nas regras de domínio.

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.

Habilidades Relacionadas