Explorando a Arquitetura Hexagonal em Java

Explorando a Arquitetura Hexagonal em Java

A Arquitetura Hexagonal, também conhecida como Arquitetura de Portas e Adaptadores (Ports and Adapters), é uma abordagem que promove a separação de responsabilidades e a flexibilidade em aplicações de software. Seu objetivo principal é desacoplar o núcleo de lógica de negócios das interfaces externas, como bancos de dados, APIs, interfaces de usuário ou sistemas de mensageria, permitindo que as partes externas sejam alteradas ou substituídas sem afetar a lógica de negócios central.

Neste artigo, vamos explorar como implementar essa arquitetura em Java, focando principalmente na simplicidade e eficiência dos Adaptadores Inbound e Outbound. Vamos discutir como esses componentes se relacionam e funcionam para criar uma aplicação mais flexível e fácil de testar.

Estrutura da Arquitetura Hexagonal

A arquitetura é dividida em três camadas principais:

  1. Camada de Domínio (Núcleo) — contém a lógica de negócios.
  2. Portas (Ports) — interfaces que definem como o domínio interage com o mundo exterior.
  3. Adaptadores (Adapters) — implementações das portas, que conectam o núcleo às interfaces externas (entradas e saídas).

Ingresso (Inbound) — Pontos de Entrada da Aplicação

A Camada de Ingresso é o ponto onde as requisições chegam à aplicação. Normalmente, em aplicações Java modernas, essas entradas podem ser controladores REST (@RestController), serviços gRPC, ou ouvintes de eventos (@KafkaListener). Nessa camada, o Adaptador Inbound é responsável por traduzir a requisição externa (como uma Request) em um objeto do domínio (DomainRequest) e, em seguida, passar o controle para a lógica de negócios por meio da InboundPort.

Por exemplo, em um sistema de gerenciamento de pedidos, você pode ter um controlador REST que lida com a criação de pedidos. Esse controlador injetaria um InboundAdapter para lidar com o mapeamento da Request para um objeto OrderRequest (representando o pedido no domínio) e, em seguida, chamaria o serviço apropriado.

InboundAdapter

O InboundAdapter é responsável por traduzir a solicitação recebida em algo que o sistema de domínio entende. Ele usa um mapeador (ou conversor) para mapear a Request em um DomainRequest, e então invoca o serviço de negócios por meio da InboundPort. Após a execução da lógica de negócios, o resultado (DomainResponse) é convertido de volta para a resposta apropriada (Response).

Exemplo de funcionamento de um InboundAdapter:

Imagine um controlador que lida com a criação de um pedido em um sistema de e-commerce. Quando o controlador REST recebe uma solicitação de criação de pedido, ele passa essa solicitação para o OrderInboundAdapter.

public class OrderInboundAdapter {
private final OrderService orderService; // Serviço de negócios via InboundPort
private final OrderMapper orderMapper; // Mapper para conversão

public OrderInboundAdapter(OrderService orderService, OrderMapper orderMapper) {
this.orderService = orderService;
this.orderMapper = orderMapper;
}

public OrderResponse createOrder(OrderRequest request) {
OrderDomainRequest domainRequest = orderMapper.toDomain(request); // Mapear para domínio
OrderDomainResponse domainResponse = orderService.createOrder(domainRequest); // Lógica de negócios
return orderMapper.toResponse(domainResponse); // Mapear de volta para resposta
}
}

InboundPort

A InboundPort é a interface que define as operações que podem ser realizadas pela lógica de negócios. Essa interface abstrai a implementação do serviço, permitindo que a lógica de negócios seja separada da camada de entrada.

public interface OrderService {
OrderDomainResponse createOrder(OrderDomainRequest request);
}

ServiceImpl

A implementação da InboundPort é feita pelo ServiceImpl, que contém a lógica de negócios da aplicação. Nesse exemplo, OrderServiceImpl implementa o serviço de pedidos, garantindo que todas as regras de negócio sejam seguidas.

public class OrderServiceImpl implements OrderService { @Override public OrderDomainResponse createOrder(OrderDomainRequest request) { // Implementação da lógica de negócios return new OrderDomainResponse("Pedido criado com sucesso"); }}

OutboundPort

A OutboundPort é o meio pelo qual a lógica de negócios interage com sistemas externos, como um banco de dados ou uma API externa. A OutboundPort define uma interface que a aplicação usará para acessar esses sistemas, garantindo que a lógica de negócios seja desacoplada das tecnologias externas.

Por exemplo, a OutboundPort pode ser usada para acessar um repositório de pedidos:

public interface OrderRepository {
void save(OrderEntity order);
}

OutboundAdapter

O OutboundAdapter implementa a OutboundPort, traduzindo o objeto de domínio em algo que o sistema externo entende, como uma entidade de banco de dados (OrderEntity) ou uma requisição de API externa.

public class OrderRepositoryAdapter implements OrderRepository {
@Override
public void save(OrderEntity order) {
// Persistir o pedido no banco de dados
}
}

Repositório

O Repositório é responsável por acessar dados do banco de dados, abstraindo os detalhes de implementação da camada de serviço.

Simplificando a Arquitetura

Uma das grandes vantagens da Arquitetura Hexagonal é que tanto os adaptadores Inbound quanto os Outbound seguem a mesma lógica de mapeamento e invocação de portas. Essa consistência torna o código mais fácil de entender e manter.

  1. Mapear a solicitação — ambos os adaptadores mapeiam a entrada para um objeto de domínio.
  2. Invocar a porta — os adaptadores chamam a porta apropriada (Inbound ou Outbound).
  3. Mapear a resposta — a resposta da porta é mapeada de volta para o formato externo.

Conclusão

A Arquitetura Hexagonal em Java proporciona uma separação clara de responsabilidades, facilitando a escalabilidade e manutenibilidade de sistemas complexos. Ao isolar a lógica de negócios em portas e adaptadores, você garante que sua aplicação seja altamente testável e possa evoluir de maneira mais flexível. A simplicidade e eficiência no gerenciamento dos adaptadores Inbound e Outbound são fundamentais para garantir que a aplicação permaneça organizada e de fácil manutenção.

Conteúdo Relacionado

O Rails 8 sempre foi um divisor de águas...
Os aplicativos da Web são uma pedra fundamental da...
Os desenvolvedores Java enfrentam uma variedade de erros relacionados...
Com várias décadas de experiência, adoro criar aplicativos corporativos...
A escalabilidade é um fator crítico quando se trata...
Ao trabalhar em um projeto de código aberto no...
A Inteligência Artificial (IA) tem se tornado cada vez...
A maioria das organizações enfrenta desafios ao se adaptar...
Quando nós, desenvolvedores, encontramos alguns bugs em nossos logs,...
A cibersegurança é um tópico cada vez mais importante...
A experiência do desenvolvedor (DX) é um tópico cada...
Ao relatar estatísticas resumidas para resultados de testes de...
Explorando as Engrenagens do Kernel Semântico Falei um pouco...
A arquitetura de software evoluiu drasticamente nas últimas décadas,...
Como você previne alucinações de grandes modelos de linguagem...
O conceito de "jardim digital" tem ganhado cada vez...
Voltar para o blog

Deixe um comentário

Os comentários precisam ser aprovados antes da publicação.