Arquitetura Hexagonal em C++: código limpo sem dor

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Arquitetura Hexagonal em C++: como parar de temer mudanças e amar os testes

\n\n

Você já reescreveu um módulo de banco de dados e depois percebeu que precisava alterar metade da lógica de negócio? Ou tentou cobrir com testes unitários uma classe que arrasta três toneladas de dependências do mundo externo? Se sim — bem-vindo ao clube. Felizmente, temos uma ferramenta que resolve esses problemas de uma vez por todas: a arquitetura hexagonal (também conhecida como arquitetura Ports & Adapters).

\n\n

Neste artigo, vamos analisar como aplicar esse conceito poderoso em C++. Você verá não diagramas abstratos, mas código real que pode ser usado agora mesmo. E sim, faremos isso sem fanatismo — de modo que nem o projeto legado exploda e o novo código permaneça limpo.

\n\n

O que é arquitetura hexagonal (e qual a relação com o hexágono)?

\n\n

Imagine o núcleo da sua aplicação — é a lógica de negócio pura, que não conhece bancos de dados, REST API ou interface gráfica. Ao redor desse núcleo estão os portos (interfaces), e mais além, os adaptadores (implementações concretas). Visualmente, isso lembra um hexágono, daí o nome.

\n\n

A ideia central: as dependências apontam para dentro. O mundo externo depende do núcleo, e não o contrário. Isso permite trocar o banco de dados, o protocolo de comunicação ou a interface do usuário sem alterar a lógica de negócio. Parece um sonho? Vamos ver como implementar isso em C++.

\n\n

O problema clássico: alto acoplamento

\n\n

Assim é como geralmente se parece um código C++ típico:

\n\n
class OrderService {\npublic:\n    void createOrder(const OrderData& data) {\n        // Lógica de negócio\n        if (data.items.empty()) throw std::runtime_error("Pedido vazio");\n\n        // E aqui está o problema — dependência direta do banco de dados\n        Database db("localhost", 5432);\n        db.connect();\n        db.saveOrder(data);\n        db.disconnect();\n        \n        // E também do serviço de email\n        EmailSender sender("smtp.example.com");\n        sender.sendInvoice(data);\n    }\n};
\n\n

O que há de errado aqui? Tudo. Você não pode testar createOrder sem um banco de dados real e um servidor de email. Se amanhã decidir migrar de PostgreSQL para MongoDB — terá que reescrever OrderService. E se o serviço de email se tornar assíncrono via fila — novamente alterações na lógica de negócio.

\n\n

Resolvendo o problema com arquitetura hexagonal

\n\n

Passo 1: Definindo os portos (interfaces)

\n\n

Um porto é um contrato que define o que o núcleo precisa do mundo externo, mas não como é implementado.

\n\n
// port/OrderRepository.h\nclass OrderRepository {\npublic:\n    virtual ~OrderRepository() = default;\n    virtual void save(const Order& order) = 0;\n    virtual std::optional<Order> findById(const std::string& id) = 0;\n};\n\n// port/NotificationService.h\nclass NotificationService {\npublic:\n    virtual ~NotificationService() = default;\n    virtual void sendInvoice(const Order& order) = 0;\n};
\n\n

Observe: são classes abstratas puras. Sem dependências de frameworks, bibliotecas ou serviços externos. Apenas entidades de negócio.

\n\n

Passo 2: Escrevendo o núcleo (lógica de negócio)

\n\n

Agora nosso serviço depende apenas de interfaces, não de implementações concretas:

\n\n
// core/OrderService.h\nclass OrderService {\npublic:\n    OrderService(OrderRepository& repo, NotificationService& notifier)\n        : repository_(repo), notifier_(notifier) {}\n\n    void createOrder(const OrderData& data) {\n        // Validação — lógica de negócio pura\n        if (data.items.empty()) {\n            throw std::invalid_argument("O pedido não pode estar vazio");\n        }\n\n        Order order = Order::create(data);\n        repository_.save(order);\n        notifier_.sendInvoice(order);\n    }\n\nprivate:\n    OrderRepository& repository_;\n    NotificationServ                

Blogs

Book Recommendations