A Arquitetura Hexagonal, também conhecida como Ports and Adapters (Portas e Adaptadores), proposta por Alistair Cockburn, é um padrão de projeto de software que visa criar sistemas fracamente acoplados, onde a lógica de negócio (o “coração” da aplicação) é isolada de preocupações externas, como bancos de dados, interfaces de usuário (UI) ou APIs de terceiros.

O Conceito Fundamental Link para o cabeçalho

Em uma arquitetura tradicional em camadas, muitas vezes a lógica de negócio acaba “vazada” ou dependente de frameworks e tecnologias específicas. Na Arquitetura Hexagonal, invertemos essa dependência:

1. Core (Aplicação/Domínio): O centro do hexágono. Contém as regras de negócio e não conhece nada sobre o mundo externo.

2. Ports (Portas): Interfaces que definem como o mundo externo pode interagir com o seu sistema.

3. Adapters (Adaptadores): Implementações concretas que conectam o mundo externo (Web, CLI, SQL, Redis) às suas portas.

Organização de Pastas (Estrutura de Projeto) Link para o cabeçalho

Uma das maiores vantagens da arquitetura hexagonal é que ela sugere uma organização de diretórios que separa claramente o que é regra de negócio do que é detalhe técnico.

src/
├── Application/            # Casos de uso e lógica de orquestração
│   └── RegisterUser.php    # Atua como service
├── Domain/                 # O Coração: Entidades e Portas (Interfaces)
│   ├── Model/
│   │   └── User.php
│   └── Repository/
│       └── UserRepositoryInterface.php
└── Infrastructure/         # Adaptadores (Implementações técnicas)
    ├── Persistence/
    │   └── MySqlUserRepository.php
    └── Presentation/
        └── Http/
            └── UserController.php

Explicação dos diretórios: Link para o cabeçalho

  • Domain: ContĂ©m o que faz o seu sistema ser o que ele Ă©. NĂŁo deve ter referĂŞncias a bancos de dados, frameworks ou bibliotecas HTTP. É puro PHP.

  • Application: Onde orquestramos as regras de negĂłcio. Se o seu sistema tem um fluxo como “Validar dados -> Salvar no repositĂłrio -> Enviar e-mail de boas-vindas”, isso acontece aqui.

  • Infrastructure: Onde a mágica tĂ©cnica acontece. É aqui que vocĂŞ coloca o cĂłdigo que fala com o MySQL, Redis, APIs de terceiros (como Stripe ou AWS) ou o framework que vocĂŞ está usando (como Laravel ou Symfony).

Diagrama de Fluxo (Representação Conceitual) Link para o cabeçalho

Para visualizar melhor o fluxo, imagine a comunicação sempre entrando pelo “adaptador” e respeitando a “porta”:

graph TD
    A[Adaptador HTTP / CLI] -->|Chama| B(Porta: UserRepositoryInterface)
    B -->|Implementada por| C[Adaptador: MySqlUserRepository]
    D[Domain: UserService] -->|Depende de| B
    
    subgraph Core [Núcleo da Aplicação]
        D
        B
    end

Exemplo Prático em PHP Link para o cabeçalho

Vamos imaginar um sistema simples de Registro de Usuário.

1. O Core (Domínio) Link para o cabeçalho

O core define uma Porta (interface) para salvar o usuário. Ele não sabe se estamos usando MySQL, um arquivo de texto ou uma API externa.

// src/Domain/UserRepositoryInterface.php
interface UserRepositoryInterface {
    public function save(string $email): void;
}

// src/Domain/UserService.php
class UserService {
    public function __construct(private UserRepositoryInterface $repository) {}

    public function register(string $email): void {
        // Regra de negĂłcio simples
        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            throw new Exception("E-mail inválido");
        }
        $this->repository->save($email);
    }
}

2. O Adaptador (Infraestrutura) Link para o cabeçalho

Aqui criamos a implementação real que conversa com o banco de dados.

// src/Infrastructure/MySqlUserRepository.php
class MySqlUserRepository implements UserRepositoryInterface {
    public function save(string $email): void {
        echo "Salvando '$email' no banco de dados MySQL...\n";
    }
}

3. O Ponto de Entrada Link para o cabeçalho

Este é o adaptador que dispara a ação (ex: uma requisição HTTP ou comando CLI).

// public/index.php
$repository = new MySqlUserRepository();
$userService = new UserService($repository);

$userService->register("contato@exemplo.com");

Por que utilizar essa abordagem? Link para o cabeçalho

  • Testabilidade: VocĂŞ pode facilmente criar um InMemoryUserRepository para testes unitários, sem precisar de um banco de dados real.
  • Flexibilidade: Se amanhĂŁ vocĂŞ decidir trocar o MySQL pelo MongoDB, basta criar um novo Adaptador que implemente a UserRepositoryInterface. O UserService permanece intacto.
  • Isolamento: As mudanças na tecnologia (frameworks, drivers) nĂŁo impactam suas regras de negĂłcio.