O que é Arquitetura de Software?
Antes de se aprofundar na Arquitetura Hexagonal, vamos esclarecer o que é Arquitetura de Software. Existem muitos especialistas famosos no mundo do software que criaram suas próprias definições sobre Arquitetura de Software.
Grady Booch, um grande colaborador da indústria de software que co-desenvolveu a linguagem de modelagem UML, referiu-se à arquitetura como:
“Arquitetura representa as decisões significativas que moldam um sistema, onde o significativo é medido com o custo da mudança”.
Ralph Johnson, um membro da Gang of Four, um dos autores de um dos mais influentes livros de ciência da computação: Design Patterns: Elements of Reusable Object-Oriented, explicou desta forma:
“Arquitetura é sobre as coisas importantes… seja lá o que for”.
Existem muito mais descrições e, até agora, parece que não temos um consenso sobre a definição de Arquitetura de Software entre os especialistas no espaço de software.
Os Pilares da Arquitetura de Software
Embora pareça impossível concordar com uma definição consolidada de arquitetura de software, podemos definitivamente falar sobre os principais ingredientes da Arquitetura de Software.
Neal Ford e Mark Richards, em seu brilhante livro Fundamentals of Software Architecture: An Engineering Approach, criaram quatro dimensões que compõem a arquitetura de software. Eu gosto de chamá-los de “Pilares da Arquitetura de Software”.
O que é Arquitetura Hexagonal?
A arquitetura hexagonal é um estilo arquitetural de propósito geral que visa criar software desacoplado. Como o próprio autor, Dr. Alistair Cockburn afirma:
“Ele permite que um aplicativo seja conduzido igualmente por usuários, programas, testes automatizados ou scripts em lote, e seja desenvolvido e testado isoladamente de seus eventuais dispositivos de tempo de execução e bancos de dados”.
Esse estilo de arquitetura também é conhecido como Portas e Adaptadores, e isso porque Portas e Adaptadores são as principais propriedades desse padrão. A ideia-chave é separar a lógica de negócios principal de preocupações externas, como bancos de dados, estruturas da Web, filas de mensagens e assim por diante, de forma que o aplicativo em si não dependa de nenhuma tecnologia específica. A regra geral é que nada entra e nada sai sem passar pelas portas.
A história da Arquitetura Hexagonal
A separação de regras de negócios de preocupações periféricas remonta ao início dos anos 90, especificamente no método orientado a casos de uso de Ivar Jacobson. Inicialmente, o padrão de Jacobson foi denominado EIC (Entity-Interface-Control). Resumidamente, o termo “limite” substituiu “interface” para evitar a confusão potencial com a terminologia da linguagem de programação orientada a objetos. Outros padrões semelhantes à Arquitetura Hexagonal são Onion Architecture de Jeffrey Palermo e Clean Architecture de Robert C. Martin.
Embora todos apresentem seus próprios conceitos, todos eles também usam o princípio de inversão de dependência, que afirma que módulos de alto nível (regras de negócios) não devem depender de módulos de baixo nível (módulos específicos de tecnologia); ambos devem depender de abstrações. As abstrações não devem depender de detalhes. Os detalhes devem depender das abstrações.
Esse princípio é proposto por Robert Martin, que descreve que, ao seguir esse princípio, as dependências do código-fonte podem ser invertidas e não serem restringidas para alinhar com o fluxo de controle. Com a capacidade de inverter as dependências do código-fonte, você obtém controle absoluto sobre a direção das dependências do código-fonte do sistema.
Portas
Podemos ver uma porta como um ponto de entrada independente de tecnologia, ela determina a interface que permitirá que atores estrangeiros se comuniquem com o aplicativo, independentemente de quem ou o que implementará essa interface. Assim como uma porta USB permite que vários tipos de dispositivos se comuniquem com um computador, desde que tenham um adaptador USB.
As portas também permitem que o Aplicativo se comunique com sistemas ou serviços externos, como bancos de dados, intermediários de mensagens, outros aplicativos, etc.
Dica profissional: uma Porta deve sempre ter dois itens vinculados a ela, sendo um deles sempre um teste.
Adaptadores
Um Adaptador iniciará a interação com a aplicação através de uma Porta, utilizando uma tecnologia específica, por exemplo, um controlador REST representaria um adaptador que permite que um cliente se comunique com a aplicação. Pode haver adaptadores para uma única porta o quanto forem necessários, sem que isso represente um risco para as portas ou para a própria aplicação.
Aplicação
A Aplicação é o core do sistema, ela contém os serviços de aplicação, os quais orquestram a funcionalidade ou os use cases. Ela também contém o Modelo de Domínio, o qual é a lógica de negócio integrada aos Agregados, Entidades e Objetos de Valor (Value Objects).
A Aplicação é representada por um hexágono, o qual recebe comandos ou queries das Portas, e envia requisições para outros atores externos, como banco de dados, via Porta também. Quando pareado com Design Orientado ao Domínio (Domain-Driven Design), a Aplicação ou Hexágono, contém ambos, a Aplicação e camadas de Domínio, deixando as camadas de Interface do Usuário e Infraestrutura de fora.
Lado Condutor x Lado Dirigido (Driving Side vs Driven Side)
Os atores condutores (ou primários) são os que iniciam a interação e são sempre representados no lado esquerdo. Por exemplo, um adaptador de acionamento pode ser um controlador que recebe a entrada (do usuário) e a passa para o aplicativo por meio de uma porta.
Atores dirigidos (ou secundários) são aqueles que são “induzidos ao comportamento” pela Aplicação. Por exemplo, um adaptador de banco de dados é chamado pelo aplicativo para que ele busque um determinado conjunto de dados da persistência.
Quando se trata de implementação, há alguns detalhes importantes que não devem ser esquecidos:
- As portas serão (na maioria das vezes, dependendo do idioma escolhido) representadas como interfaces no código.
- Os Driving Adapters usarão uma Porta e um Application Service irá implementar a Interface definida pela Porta, neste caso, tanto a interface da Porta quanto a implementação estão dentro do Hexágono.
- Os adaptadores conduzidos irão implementar a Porta e um Serviço de Aplicação irá utilizá-la, neste caso, a Porta está dentro do Hexágono, mas a implementação está no Adaptador, portanto fora do Hexágono.
Inversão de Dependência no Contexto da Arquitetura Hexagonal
O Princípio de Inversão de Dependência é um dos 5 princípios cunhados por (Tio) Bob Martin em seu Paper OO Design Quality Metrics e posteriormente em seu livro Agile Software Development Principles, Patterns and Practices, onde ele o define da seguinte forma:
- Módulos de alto nível não devem depender de módulos de baixo nível. Ambos devem depender de abstrações.
- As abstrações não devem depender de detalhes. Detalhes devem depender de abstrações.
Como mencionado anteriormente, os lados esquerdo e direito do hexágono contém 2 tipos diferentes de atores, Driving e Driven, onde existem portas e adaptadores.
Do lado do Condutor, o Adaptador depende da Porta, que é implementada pelo Serviço de Aplicação, portanto o Adaptador não sabe quem vai reagir às suas invocações, apenas sabe quais métodos estão garantidos para estar disponíveis, portanto depende de uma abstração.
No lado Dirigido (Driven), o Application Service é aquele que depende do Port, e o Adapter é aquele que implementa a Port's Interface, invertendo efetivamente a dependência já que o adaptador 'low-level' (ou seja, repositório de banco de dados) é forçado a implementar a abstração definida no núcleo do aplicativo, que é de 'nível superior'.
Conclusão
Existem muitas vantagens em usar a Arquitetura de Portas e Adaptadores, uma delas é poder isolar completamente a lógica de sua aplicação e a lógica de domínio de uma forma totalmente testável. Como não depende de fatores externos, testá-lo torna-se natural e o mocking de suas dependências é fácil.
Ele também permite que você projete todas as interfaces do seu sistema "por propósito" e não por tecnologia, evitando que você fique preso e facilitando a evolução da pilha de tecnologia da sua aplicação com o tempo. Se você precisar alterar a camada de persistência, vá em frente. Se você precisa permitir que seu aplicativo seja chamado por bots do Slack em vez de humanos, você conseguiu! Tudo o que você precisa fazer é implementar novos adaptadores e pronto.
A arquitetura hexagonal ou de portas e adaptadores não é a bala de prata para todas as aplicações. Envolve um certo nível de complexidade, que quando manuseado com cuidado, trará grandes benefícios ao seu sistema.
Quando adequadamente implementados e combinados com outras metodologias, como Domain-Driven Design, portas e adaptadores, podem garantir a estabilidade e extensibilidade de longo prazo de um aplicativo, agregando muito valor ao sistema e à empresa.
A Revelo Content Network acolhe todas as raças, etnias, nacionalidades, credos, gêneros, orientações, pontos de vista e ideologias, desde que promovam diversidade, equidade, inclusão e crescimento na carreira dos profissionais de tecnologia.