Driver FixRecommendedSound, Wi-Fi or graphics acting up? Check drivers firstFind missing or outdated drivers fast.Check DriversHalloween DealsAmazon USHalloween week deals: useful picks before month-endAmazon US: current deals, useful picks and tech finds.Check DealsSlow PC?RecommendedPC slow today? Run a repair scan before it gets worseResolve common Windows issues and optimize system performance.Scan Now×
Skip to content
World desk8 min

Arquitetura Hexagonal em Python do zero: um domínio que não sabe onde mora nem quem o chama

Arquitetura hexagonal (Ports and Adapters) faz o domínio depender de contratos, e não de banco, HTTP ou SDKs. Veja o passo a passo em Python, um exemplo mínimo e quando a abstração compensa.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Arquitetura hexagonal, também chamada de Ports and Adapters, organiza o código para que as regras de negócio e os casos de uso dependam de contratos que expressam o que eles precisam, enquanto banco de dados, HTTP, CLI, filas e APIs externas ficam nas bordas do sistema. Na prática, o domínio não sabe qual classe o persiste nem qual interface iniciou a operação. Isso não elimina a necessidade de um ponto em que os objetos concretos são montados e conectados: esse ponto existe, mas fica fora do núcleo.

O que significa “o domínio não sabe quem o chama”

Na documentação de orientação prescritiva da AWS, o núcleo da aplicação é descrito como o lugar das regras de negócio, e as portas são abstrações para a interação com o mundo exterior. Um adaptador faz a tradução entre uma tecnologia externa e o contrato da aplicação. Há dois sentidos de uso:

As an Amazon Associate I earn from qualifying purchases.

  • Adaptador primário (entrada): conduz uma solicitação para dentro do núcleo. Exemplos: uma rota HTTP, um comando de terminal ou um worker que consome uma fila.
  • Adaptador secundário (saída): atende a uma necessidade do núcleo para fora. Exemplos: persistência em banco, envio de e-mail ou chamada a um serviço de pagamento.

A mudança em relação a uma arquitetura em camadas tradicional está na direção da dependência. Em vez de a regra de negócio importar o ORM, o cliente de nuvem ou o framework web, o contrato pertence à necessidade do núcleo e a implementação concreta é que conhece esse contrato. Assim, trocar uma integração não exige alterar a regra que a utiliza, desde que o comportamento do contrato continue o mesmo.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A AWS formula a ideia de duas maneiras que valem ser citadas literalmente:

  • “Ports are technology-agnostic entry points into an application component.”
  • “A port can have multiple adapters without any risk to the port or to the application component.”

O formato hexagonal do diagrama é só uma convenção visual para representar várias fronteiras. Não há exatamente seis portas nem seis componentes. Para explicar a arquitetura a outra pessoa, use setas e nomes de contratos, não a geometria.

Roteiro para construir do zero em Python

  1. Descreva uma regra ou caso de uso concreto. Comece pela linguagem do problema: entidades, valores e as operações que o usuário precisa realizar. Não comece escolhendo FastAPI, um ORM ou uma estrutura de pastas.
  2. Mantenha as regras de domínio sem I/O. No núcleo, evite importar framework, cliente de banco, SDK ou leitura de variáveis de ambiente. O livro Architecture Patterns with Python enfatiza que o modelo de domínio não deve carregar dependências de infraestrutura.
  3. Identifique as dependências externas de cada caso de uso. Um repositório, um relógio ou um gateway de pagamento pode virar porta de saída, mas só se o caso de uso realmente precisar dele. Criar abstrações sem uma fronteira que as justifique é um erro comum.
  4. Declare um contrato pequeno. Em Python, uma porta costuma ser uma classe base abstrata (ABC) com métodos abstratos. O tutorial AWS declara as portas em um pacote domain/ports e faz o handler receber a dependência pelo tipo da porta. Outras formas de tipagem estrutural são possíveis, mas o material que serviu de base não compara mecanismos entre si.
  5. Implemente adaptadores para tecnologias específicas. No tutorial AWS, há um adaptador para DynamoDB e a entrada é feita por Lambda e API Gateway. Para aprender localmente, uma implementação em memória permite testar o caso de uso sem provisionar serviço algum.
  6. Conecte as implementações na composição. Na inicialização da aplicação, construa os adaptadores concretos e injete-os nos casos de uso e handlers. A borda conhece as implementações; o domínio recebe o que precisa e não procura nada por conta própria.
  7. Teste por fronteira. Teste o domínio e os casos de uso com dependências falsas. Teste cada adaptador separadamente contra o contrato da porta e acrescente testes de integração quando o comportamento do sistema externo for relevante para a regra.

Um exemplo mínimo: porta, caso de uso e adaptador em memória

O exemplo abaixo é ilustrativo e foi escrito apenas para mostrar a direção das dependências. Ele assume que a entidade Pedido, com um método confirmar() e um atributo id, está definida no domínio.

from abc import ABC, abstractmethod

class PedidoRepository(ABC):          # porta de saída
    @abstractmethod
    def salvar(self, pedido) -> None: ...

    @abstractmethod
    def buscar(self, pedido_id: str): ...

class ConfirmarPedido:                # caso de uso
    def __init__(self, pedidos: PedidoRepository):
        self._pedidos = pedidos

    def executar(self, pedido_id: str) -> None:
        pedido = self._pedidos.buscar(pedido_id)
        if pedido is None:
            raise ValueError("pedido não encontrado")
        pedido.confirmar()
        self._pedidos.salvar(pedido)

class RepositorioEmMemoria(PedidoRepository):   # adaptador de saída
    def __init__(self):
        self._dados = {}

    def salvar(self, pedido) -> None:
        self._dados[pedido.id] = pedido

    def buscar(self, pedido_id: str):
        return self._dados.get(pedido_id)

Na composição, em um arquivo como bootstrap.py, a escolha da implementação acontece em uma única linha. Trocar a memória por um adaptador de banco muda só essa linha e o novo adaptador, nunca ConfirmarPedido:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
repositorio = RepositorioEmMemoria()
confirmar = ConfirmarPedido(repositorio)

Uma estrutura de pastas possível

Pastas são uma representação possível, não uma exigência do padrão. O critério é proteger a direção das dependências, de modo que nada em domain ou application importe algo de adapters.

src/
  app/
    domain/          # entidades e regras puras
    application/     # casos de uso e contratos (portas)
  adapters/
    inbound/         # HTTP, CLI, worker
    outbound/        # banco, API externa, filesystem
  bootstrap.py       # composição das implementações
tests/
  unit/
  integration/

O tutorial AWS usa uma divisão própria, com domain, ports, adapters e entrypoints, e um exemplo orientado a Lambda. Ele indica Python 3.7 ou posterior e lista dependências do próprio exemplo, como CDK v2, Poetry 1.1.13, pytest 7.1.1, Moto 3.1.9, Pydantic 1.9.0 e Boto3 1.22.4. Essas são versões de uma época específica e não devem ser tomadas como versões atuais nem como requisitos universais; confirme a compatibilidade antes de reproduzir o tutorial. O próprio guia informa que o exemplo foi testado em ambiente de prova de conceito e que exige revisão de segurança antes de qualquer implantação produtiva.

Como testar um domínio sem banco de dados

Esse é o benefício mais concreto da separação. A AWS afirma que, como a lógica da aplicação não depende de fatores externos, o teste fica simplificado e dependências se tornam mais fáceis de substituir por mocks. Na prática, a estratégia costuma ser esta:

  • Testes unitários do caso de uso: usam um repositório em memória ou um fake. Não há banco, rede nem variável de ambiente envolvidos, então rodam rapidamente e em qualquer máquina.
  • Testes de contrato do adaptador: executam a mesma bateria de testes contra cada implementação da porta, incluindo a em memória e a real. Isso garante que as implementações se comportem da mesma forma.
  • Testes de integração: entram quando o comportamento do sistema externo é parte da regra, como uma consulta com filtro específico ou uma transação. O tutorial AWS usa Moto para simular o DynamoDB nos testes do adaptador, o que dispensa uma conta real na nuvem para esse nível de teste.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Quando a arquitetura compensa e quando é excesso

A AWS considera o padrão especialmente adequado quando clientes diferentes compartilham a mesma lógica de domínio, quando há múltiplas entradas e saídas, ou quando a interface de usuário ou a tecnologia de persistência precisam mudar sem reescrever as regras. A mesma orientação ressalta que o código extra de adaptadores só se justifica quando essas variações existem ou são prováveis. Use a tabela abaixo como critério inicial.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Eixo Pergunta a fazer Sinal de que a abstração vale o custo
Entradas Quantas formas de iniciar a operação existem? Mais de uma entrada, como API e worker, usando o mesmo caso de uso
Saídas Quantos destinos o núcleo precisa alcançar? Banco, API externa ou fila com chance real de substituição
Volatilidade Algum sistema externo deve mudar com o tempo? Troca de fornecedor, de banco ou de protocolo prevista
Testes A regra só pode ser verificada com infraestrutura real? Regras complexas que se beneficiam de testes sem I/O
Custo Quanto código de composição e tradução a equipe vai manter? Custo aceitável frente aos ganhos de fronteira

Uma aplicação pequena, com uma única interface e persistência estável, pode começar com uma estrutura menor. Não crie uma interface para cada função. Crie uma porta quando houver uma dependência externa ou uma fronteira de substituição ou teste que de fato beneficie o sistema.

O custo tem características conhecidas. A AWS alerta para complexidade, manutenção e possível latência adicional causada pela camada extra. Um exemplo em Python também aponta a repetição de operações CRUD em cada porta e o crescimento do ponto de composição à medida que o sistema cresce. Esses efeitos aparecem com frequência em projetos médios e grandes, e merecem ser planejados desde o início.

Evidência e limites do que se pode afirmar

As fontes consultadas para este texto são de orientação e de exemplo, e não trazem medições públicas de produtividade, qualidade de código ou custo atribuídas ao padrão. Por isso, o argumento aqui é de design e de custo de mudança, não de ganho numérico. Os exemplos de tecnologia, como versões de bibliotecas e serviços em nuvem, descrevem um momento específico e devem ser revalidados antes de uso.

Leituras complementares

  • Guia de orientação prescritiva da AWS sobre arquitetura hexagonal, com introdução conceitual e comparação com a arquitetura em camadas.
  • Tutorial AWS de exemplo completo com Lambda, API Gateway e DynamoDB. Trate-o como estudo de caso específico, e não como arquitetura obrigatória para todo serviço Python.
  • Architecture Patterns with Python, uma leitura complementar sobre esses mesmos princípios aplicados a Python.

A ideia central é simples de enunciar e exige disciplina para aplicar: o domínio define o que precisa, a borda decide como isso é feito, e a composição é o único lugar onde essas escolhas se encontram.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
Crashes, No Sound, or Screen Glitches?Free driver scan
Windows Errors? Fix Them Before They SpreadFree repair scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.