Arquitetura Hexagonal

Arquitetura Hexagonal

Crie uma solução para funcionar sem uma interface gráfica de usuário e/ou um banco de dados, podendo então executar testes de regressão automatizados, trabalhar quando o banco de dados ficar indisponível e evoluir aplicativos sem nenhum envolvimento do usuário.

Intenção

Permitir que uma solução seja igualmente orientada por usuários, programas, testes automatizados ou scripts em lote, e que seja desenvolvido e testado isoladamente de seus dispositivos e bancos de dados de tempo de execução eventuais. À medida que os eventos chegam do mundo externo a uma porta, um adaptador específico de tecnologia o converte em uma chamada ou mensagem de procedimento utilizável e a transmite para o produto. O aplicativo ignora a natureza do dispositivo de entrada. Quando o aplicativo tem algo a enviar, ele o envia por uma porta para um adaptador, que cria os sinais apropriados necessários pela tecnologia de recebimento (humana ou automatizada). A solução tem uma interação de som semanticamente com os adaptadores em todos os lados dele, sem realmente saber a natureza das coisas do outro lado dos adaptadores.

Motivação

Um dos grandes problemas dos softwares ao longo dos anos tem sido a infiltração da lógica de negócios no código na camada de interface do usuário ou no banco de dados e a complexidade ocasionada pela mistura de ambos. O problema que isso causa é triplo: primeiro, o sistema não pode ser testado com suítes de testes automatizadas, porque parte da lógica que precisa ser testada depende de detalhes visuais que mudam constantemente, como tamanho de campo e colocação de botões; Pela mesma razão, torna-se impossível mudar de um uso do sistema conduzido pelo homem para um sistema de execução em testes em lote; Ainda pela mesma razão, torna-se difícil ou impossível permitir que o programa seja conduzido por outro programa quando isso se torna necessário.

A tentativa de resolver isso, repetida em muitas organizações, é criar uma camada adicional na arquitetura, com a promessa de que desta vez, real e verdadeiramente, nenhuma lógica de negócios será colocada na nova camada. No entanto, não tendo nenhum mecanismo para detectar quando ocorre uma violação dessa promessa, a organização descobre, alguns anos depois, que a nova camada está cheia de lógica de negócios e o antigo problema reapareceu.

Imagine agora que cada funcionalidade oferecida pelo aplicativo estava disponível por meio de uma API (interface programada do aplicativo) ou chamada de função. Nessa situação, o departamento de teste ou QA pode executar scripts de teste automatizados no aplicativo para detectar quando qualquer nova codificação quebra uma função que estava funcionando anteriormente. Os especialistas em negócios podem criar casos de teste automatizados, antes que os detalhes da GUI sejam finalizados, informando aos programadores quando eles realizaram o trabalho corretamente (e esses testes se tornam os executados pelo departamento de teste). O aplicativo pode ser implantado no modo “sem cabeça”, de modo que somente a API está disponível e outros programas podem fazer uso de sua funcionalidade – isso simplifica o design geral de conjuntos de aplicativos complexos e permite que aplicativos de serviços business-to-business usem uns aos outros sem intervenção humana na web. Por fim, os testes de regressão de função automatizada detectam qualquer violação da promessa de manter a lógica de negócios fora da camada de apresentação. A organização pode detectar e corrigir o vazamento de lógica.

Um problema semelhante interessante existe no que normalmente é considerado “o outro lado” do aplicativo, onde a lógica do aplicativo fica vinculada a um banco de dados externo ou outro serviço. Quando o servidor de banco de dados fica inativo ou sofre retrabalho ou substituição significativos, os programadores não podem trabalhar porque seu trabalho está vinculado à presença do banco de dados. Isso causa atrasos nos custos e, muitas vezes, sentimentos ruins entre as pessoas. Não é óbvio que os dois problemas estejam relacionados, mas existe uma simetria entre eles que se manifesta na natureza da solução.

Natura da Solução

Os problemas do lado do usuário e do lado do servidor, na verdade, são causados pelo mesmo erro no projeto e na programação – o entrelaçamento entre a lógica de negócios e a interação com entidades externas. A assimetria a explorar não é aquela entre os lados esquerdo e direito da aplicação, mas entre dentro e fora da aplicação. A regra a ser obedecida é que o código pertencente à parte interna não deve vazar para a parte externa.

Removendo qualquer assimetria esquerda-direita ou cima-baixo por um momento, vemos que o aplicativo se comunica através de portas para agências externas. A palavra “porta” deve evocar pensamentos de portas em um sistema operacional, onde qualquer dispositivo que adira aos protocolos de uma porta pode ser conectado a ele; e portas em dispositivos eletrônicos, onde, novamente, qualquer dispositivo que se encaixe nos protocolos mecânicos e elétricos pode ser conectado. O protocolo para uma porta é fornecido pelo propósito da conversa entre os dois dispositivos. O protocolo assume a forma de uma interface de programa de aplicativo (API).

Para cada dispositivo externo, existe um adaptador que converte a definição da API nos sinais necessários para esse dispositivo e vice-versa. Uma interface gráfica do usuário ou GUI é um exemplo de um adaptador que mapeia os movimentos de uma pessoa para a API da porta. Outros adaptadores que se encaixam na mesma porta são os suítes de teste automatizados, os arquivos em lote e qualquer outro código necessário para a comunicação entre aplicativos em toda a empresa ou na rede.

No outro lado, o aplicativo se comunica com uma entidade externa para obter dados. O protocolo é tipicamente um protocolo de banco de dados. Do ponto de vista do aplicativo, se o banco de dados for movido de um banco de dados SQL para um arquivo simples ou qualquer outro tipo de banco de dados, a conversação na API não deve ser alterada. Adaptadores adicionais para a mesma porta incluem um adaptador SQL, um adaptador de arquivo simples e, o mais importante, um adaptador para um banco de dados “simulado”, que fica na memória e não depende da presença do banco de dados real

Muitos aplicativos têm apenas duas portas: o diálogo do lado do usuário e o diálogo do lado do banco de dados. Isso lhes dá uma aparência assimétrica, o que faz parecer natural construir o aplicativo em uma arquitetura empilhada unidimensional, de três, quatro ou cinco camadas.

Existem dois problemas com esses desenhos. Primeiro e pior, as pessoas tendem a não levar a sério as “linhas” no desenho em camadas. Eles permitem que a lógica do aplicativo vaze pelos limites da camada, causando os problemas mencionados acima. Em segundo lugar, pode haver mais de duas portas para o aplicativo, para que a arquitetura não se encaixe no desenho de camada unidimensional.

A arquitetura hexagonal, ou portas e adaptadores, resolve esses problemas observando a simetria da situação: existe uma aplicação no interior comunicando-se sobre um certo número de portas com coisas do lado de fora. Os itens fora do aplicativo podem ser tratados simetricamente.

O hexágono destina-se a destacar visualmente:

  • a assimetria interior-exterior e a natureza similar dos portos, para fugir da imagem em camadas unidimensional e tudo o que evoca.
  • a presença de um número definido de portas diferentes – dois, três ou quatro (quatro é mais que eu encontrei até o momento).

O hexágono não é um hexágono porque o número seis é importante, mas permite que as pessoas que estão fazendo o desenho tenham espaço para inserir portas e adaptadores conforme necessário, não sendo restringidos por um desenho em camadas unidimensional. O termo arquitetura hexagonal vem desse efeito visual.

O termo “porta e adaptadores” retoma as finalidades das partes do desenho. Uma porta identifica uma conversa intencional. Normalmente haverá vários adaptadores para qualquer porta, para várias tecnologias que podem se conectar a essa porta. Normalmente, eles podem incluir uma secretária eletrônica, uma voz humana, um telefone de discagem por tom, uma interface gráfica humana, um equipamento de teste, um driver em lote, uma interface http, uma interface direta entre programas, um simulado (em -memória), um banco de dados real talvez bancos de dados diferentes para desenvolvimento, teste e uso real.

Nas Notas de Aplicação, a assimetria esquerda-direita será ativada novamente. No entanto, o objetivo principal desse padrão é focar na assimetria interna e externa, fingindo brevemente que todos os itens externos são idênticos do ponto de vista da aplicação.

Estrutura

A Figura acima mostra um aplicativo com várias portas ativas e vários adaptadores para cada porta. As portas são o lado controlador de aplicativos e o lado de recuperação de dados. Esse desenho mostra que o aplicativo pode ser igualmente orientado por um conjunto de testes de regressão automatizado no nível do sistema, por um usuário humano, por um aplicativo http remoto ou por outro aplicativo local. No lado dos dados, o aplicativo pode ser configurado para ser executado desacoplado de bancos de dados externos usando uma substituição de banco de dados oracle ou mock na memória; ou pode ser executado no banco de dados de teste ou em tempo de execução. A especificação funcional da aplicação, talvez em casos de uso, é feita contra a interface do hexágono interno e não contra qualquer uma das tecnologias externas que podem ser usadas.

A figura acima mostra o mesmo aplicativo mapeado para um desenho arquitetônico de três camadas. Para simplificar o desenho, apenas dois adaptadores são mostrados para cada porta. Este desenho destina-se a mostrar como vários adaptadores se encaixam nas camadas superior e inferior e a sequência na qual os vários adaptadores são usados durante o desenvolvimento do sistema. As setas numeradas mostram a ordem em que uma equipe pode desenvolver e usar o aplicativo:

  1. Com um equipamento de teste conduzindo o aplicativo e usando o banco de dados mock (in-memory) substituindo o banco de dados real;
  2. Adicionando uma GUI ao aplicativo, ainda executando o banco de dados simulado;
  3. No teste de integração, com scripts de teste automatizados (por exemplo, do Cruise Control), direcionando o aplicativo para um banco de dados real contendo dados de teste;
  4. Em uso real, com uma pessoa usando o aplicativo para acessar um banco de dados ao vivo.

Assimetria Esquerda/Direita

O padrão de portas e adaptadores é deliberadamente escrito, fingindo que todas as portas são fundamentalmente semelhantes. Essa pretensão é útil no nível arquitetônico. Na implementação, os ports e adaptadores aparecem em dois tipos, que eu chamarei de primários e secundários, por razões óbvias de ser óbvio. Eles também podem ser chamados de adaptadores de acionamento e adaptadores acionados.

A camada de GUI pode ser usado nas portas do lado esquerdo e nas simulações à direita. Na arquitetura de três camadas, o GUI fica na camada superior e o mock fica na camada inferior. Mas podem ser considerados fisicamente no desenho da arquitetura como qualquer lado de adaptação.

Isso está relacionado à ideia de casos de uso de “atores primários” e “atores secundários”. Um ator primário é um ator que dirige o aplicativo (retira-o do estado inativo para executar uma de suas funções anunciadas). Um ator secundário é aquele que o aplicativo dirige, seja para obter respostas de ou simplesmente notificar. A distinção entre primário e secundário está em quem desencadeia ou está no comando da conversa.

O adaptador de teste natural para substituir um ator primário, uma vez que essa estrutura é projetada para ler um script e direcionar o aplicativo. O adaptador de teste natural para substituir um ator secundário, como um banco de dados, é uma simulação, já que foi projetado para responder a consultas ou registrar eventos do aplicativo.

Essas observações nos levam a seguir o desenho abaixo e desenhar as portas primárias e os adaptadores primários no lado esquerdo (ou superior) do hexágono e as portas secundárias e adaptadores secundários no lado direito (ou inferior) do hexágono.

A relação entre portas / adaptadores primários e secundários e suas respectivas implementações em GUI e mocks é útil ter em mente, mas deve ser usada como consequência do uso da arquitetura de portas e adaptadores, e não de curto-circuito. O benefício final de uma implementação de portas e adaptadores é a capacidade de executar o aplicativo em um modo totalmente isolado.

Caso de Uso e os Limites de Aplicação

É útil usar o padrão de arquitetura hexagonal para reforçar a maneira preferida de escrever casos de uso. Um erro comum é escrever casos de uso para conter conhecimento íntimo da tecnologia situada fora de cada porta. Esses casos de uso ganharam um nome justificadamente ruim na indústria por serem longos, difíceis de ler, chatos, quebradiços e caros de manter.

Compreendendo a arquitetura de portas e adaptadores, podemos ver que os casos de uso devem geralmente ser colocados no limite do aplicativo (o hexágono interno), para especificar as funções e eventos suportados pelo aplicativo, independentemente da tecnologia externa. Esses casos de uso são mais curtos, mais fáceis de ler, menos caros de manter e mais estáveis ao longo do tempo.

Quantas Portas?

O que exatamente uma porta é e não é, em grande parte, é uma questão de gosto. Em um extremo, cada caso de uso poderia ter sua própria porta, produzindo centenas de portas para muitas operações. Alternativamente, pode-se imaginar a fusão de todas as portas primárias e todas as portas secundárias, de modo que haja apenas duas portas, um lado esquerdo e um lado direito. Nenhum extremo parece ótimo.

O sistema meteorológico descrito nos usos conhecidos padrões possui quatro portas naturais: o feed climático, o administrador, os assinantes notificados, o banco de dados do assinante. Um controlador de máquina de café possui quatro portas naturais: o usuário, o banco de dados contendo as receitas e os preços, os dispensadores e a caixa de moedas. Um sistema de medicação hospitalar pode ter três: um para o enfermeiro, um para o banco de dados de prescrição e outro para os dispensadores de medicamentos controlados pelo computador.

Não parece que haja algum dano específico na escolha do número “errado” de portas, de modo que isso continua sendo uma questão de intuição. Minha seleção tende a favorecer um pequeno número, dois, três ou quatro portas, conforme descrito acima e nos usos conhecidos.

A Figura 4 mostra um aplicativo com quatro portas e vários adaptadores em cada porta. Isso foi derivado de um aplicativo que ouviu alertas do serviço meteorológico nacional sobre terremotos, tornados, incêndios e inundações e notificou pessoas em seus telefones ou atendedores de chamadas telefônicas. Na época em que discutimos esse sistema, as interfaces do sistema foram identificadas e discutidas pela tecnologia, ligadas ao propósito. Havia uma interface para os dados do acionador que chegavam através de um feed, um para que os dados de notificação fossem enviados para as secretárias eletrônicas, uma interface administrativa implementada em uma GUI e uma interface de banco de dados para obter seus dados de assinante.

As pessoas estavam lutando porque precisavam adicionar uma interface http do serviço meteorológico, uma interface de e-mail para seus assinantes e tinham que encontrar uma maneira de agrupar e separar o crescente conjunto de aplicativos para diferentes preferências de compra do cliente. Eles temiam que estivessem encarando um pesadelo de manutenção e testes, pois precisavam implementar, testar e manter versões separadas para todas as combinações e permutações.

Sua mudança no design foi arquitetar as interfaces do sistema de propósito e não de tecnologia, e de ter as tecnologias substituíveis (por todos os lados) por adaptadores. Eles imediatamente conseguiram incluir o feed http e a notificação por e-mail (os novos adaptadores são mostrados no desenho com linhas tracejadas).

Ao tornar cada aplicativo executável no modo “sem cabeça” por meio de APIs, eles poderiam adicionar um adaptador de aplicativo para adicionar e separar o conjunto de aplicativos, conectando os sub-aplicativos sob demanda. Por fim, ao tornar cada executável do aplicativo completamente isolado, com os adaptadores de teste e simulação prontos, eles obtiveram a capacidade de testar seus aplicativos de regressão com scripts de teste automatizados independentes.

Separação do Desenvolvimento de GUI e Regra da Solução

O design da interface do usuário é instável, pois eles ainda não decidiram sobre uma tecnologia de direção ou uma metáfora. A arquitetura de serviços de back-end ainda não foi decidida e, de fato, provavelmente será alterada várias vezes nos próximos seis meses. No entanto, o projeto começou oficialmente e o tempo está passando. A equipe de aplicativos cria testes e simulações para isolar seus aplicativos e cria funcionalidades testáveis e demonstráveis para mostrar a seus usuários. Quando as decisões de serviços de interface de usuário e de back-end são finalmente atendidas, “deve ser simples” adicionar esses elementos ao aplicativo.

Objetos Mock

Um objeto mock é um objeto dublê usado para testar o comportamento de outros objetos. Primeiro, um objeto mock age como uma implementação falsa de uma interface ou classe que imita o comportamento externo de uma implementação verdadeira. Já um objeto simulado observa como outros objetos interagem com seus métodos e compara o comportamento real com as expectativas predefinidas. Quando ocorre uma discrepância, um objeto simulado pode interromper o teste e relatar a anomalia. Se a discrepância não puder ser notada durante o teste, um método de verificação chamado pelo testador garante que todas as expectativas foram atendidas ou falhas relatadas. ” – De http://MockObjects.com

Completamente multualizados de acordo com a agenda de objetos falsos, objetos simulados são usados ​​em todo o aplicativo, não apenas na interface externa. O impulso primário do movimento do objeto simulado é a conformidade com o protocolo especificado no indivíduo. classe e nível de objeto. Eu empresto a palavra “mock” como a melhor descrição curta de um substituto na memória para um ator secundário externo.

Inversão de Dependência

Princípio de Inversão de Dependência do SPRING Bob Martin (também chamado de Injeção de Dependência por Martin Fowler) afirma que “módulos de alto nível não devem depender de módulos de baixo nível. Ambos devem depender de abstrações. Abstrações não devem depender de detalhes, detalhes devem depender de abstrações.” O padrão de Injeção de Dependência de Martin Fowler fornece algumas implementações. É com IoC que se pode criar adaptadores de ator secundário intercambiáveis, sem fazer a solução depender de recursos externos.

Vamos aprender a implementar em Java?

Aguarde que estarei lançando 2 cursos sobre arquitetura hexagonal usando Java no Udemy.

“Ao SENHOR Deus pertencem o mundo e tudo o que nele existe; a terra e todos os seres vivos que nela vivem são dele.” Salmos 24:1

Anúncios

Arquitetura de Software

O que é arquitetura?

Arquitetura é um termo que admite múltiplas definições. Existem duas definições comumente encontradas:uma separação de alto nível do sistema em suas partes decisões que são difíceis de modificar. Assim, definiremos como: “Um conjunto de decisões de projeto que tem impacto em cada aspecto da construção e evolução de sistemas. Isso inclui como sistemas são estruturados em componentes e restrições sobre como tais componentes devem interagir.”

Qual o papel de um arquiteto de software?

Muitos acreditam se tratar de um desenvolvedor Sênior, contudo conhecimento técnico é só uma de suas habilidades. Um bom arquiteto de software deve:
1. Limitar as escolhas durante o desenvolvimento:

  • escolher um padrão de como desenvolver aplicações.
  • definir/criar um framework para ser utilizado na aplicação.

2. Indicar pontos potenciais de reutilização:

  • possuir uma visão abrangente do sistema e de seu contexto.
  • adotar um design de componentização.
  • ter conhecimento de outras aplicações na empresa.

Dentre suas atribuições, a necessidade de considerar  a aplicação por um ângulo de visão mais abrangente contempla:

  • Quebrar a complexidade do desenvolvimento de aplicações em pedaços menores e mais gerenciáveis.
  • Definir as funções de cada componente.
  • Definir as interações e dependências entre os componentes.
  • Comunicar esses pontos aos desenvolvedores.

Tipos de Arquitetura

  • Arquitetura Concreta – Também conhecida como Arquitetura Implementada. É a arquitetura que está representada no código fonte.
  • Arquitetura Planejada – Também conhecida como Arquitetura Documentada. É a arquitetura definida nos modelos e documentos arquiteturais do sistema, conforme definições do arquiteto.

Erosão Arquitetural

Apesar de sua inquestionável importância, a arquitetura documentada de um sistema – se disponível – geralmente não reflete a sua implementação atual. Isso indica que existem decisões implementadas no código fonte que violam a arquitetura planejada. A isso denomina-se desvio arquitetural. Desvios arquiteturais são comuns devido ao desconhecimento por parte dos desenvolvedores, requisitos conflitantes, dificuldades técnicas etc. Geralmente, não são capturados e resolvidos. Isso levanta ao fenômeno conhecido como erosão arquitetural.

Erosão arquitetural indica que o sistema está se degenerando. Isso faz com que os benefícios proporcionados por um bom projeto arquitetural sejam anulados: Manutenibilidade, Reusabilidade, Escalabilidade, Portabilidade etc

Recuperação Arquitetural

Consiste de um conjunto de métodos para extração de informações arquiteturais a partir de representações de baixo nível de um sistema desoftware, como o código fonte.

Conformação Arquitetural

Consiste no processo de verificar se uma representação de baixo nível de um sistema desoftware – como o código fonte ou algo similar – está emconformidade com sua arquitetura planejada.

Ricardo Terra e Marcos Tulio Valente – I Congresso Brasileiro de Software: Teoria e Prática 2010.

“Então, ele me disse: A minha graça te basta, porque o poder se aperfeiçoa na fraqueza. De boa vontade, pois, mais me gloriarei nas fraquezas, para que sobre mim repouse o poder de Cristo”. 2 Coríntios 12:9

Gerenciando transações remotas com REST/Microservices

Uma das perguntas frequentes do nosso treinamento presencial Java EE REST com JAX-RS é como gerenciar as transações depois que você tem mais de 1 serviços REST e precisa fazer “roolback”. Na prática é impossível, pois cada chamada HTTP stateless, sendo uma transação isolada em um banco de dados separado. Umas das formas de fazer isso sem amarração proprietária ou de tecnologia especifica é uso do Try-Cancel/Confirm (TCC) pattern. Segue abaixo links para materiais sobre TCC:

“Quem ouve esses meus ensinamentos e vive de acordo com eles é como um homem sábio que construiu a sua casa na rocha.” Mateus 7:24

Antes de usar, aprenda o que é microservices

Todos os livros de microservices falam 2 coisas: microservices não é “bala de prata” e adicionam mais problemas que resolvem soluções. Maioria tem usado como “hype” e não como necessidade, caindo em buraco bem maior que estavam antes no monolítico. Sendo assim, antes de você querer usar, aprenda o que é e como se faz Esse ano saiu vários livros a respeito do assunto, não tendo mais desculpas. Segue abaixo a sequencia:

“O SENHOR Deus é bom. Em tempos difíceis, ele salva o seu povo e cuida dos que procuram a sua proteção.” Naum 1:7

Arquitetura de Aplicativos Open Source

Os arquitetos olham para milhares de edifícios durante o treinamento e estudam as críticas desses edifícios escritos por mestres. Em contraste, a maioria dos desenvolvedores de software só conhece um punhado de programas grandes – geralmente programas que eles mesmos escreveram – e nunca estudam os grandes programas da história. Como resultado, eles repetem os erros uns dos outros, em vez de se basearem nos sucessos uns dos outros.

Nosso objetivo é mudar isso. Nesses quatro livros, os autores de quatro dúzias de aplicativos de código aberto explicam como o software deles está estruturado e por quê. Quais são os principais componentes de cada programa? Como eles interagem? E o que seus construtores aprenderam durante seu desenvolvimento? Ao responder a essas perguntas, os colaboradores desses livros fornecem informações exclusivas sobre como eles pensam.

Se você é um desenvolvedor júnior e quer aprender como seus colegas mais experientes pensam, esses livros são o lugar para começar. Se você é um desenvolvedor intermediário ou sênior e deseja ver como seus colegas resolveram problemas difíceis de design, esses livros também podem ajudá-lo. Todos os quatros livros podem ser lidos grátis na web.

Gostaria de iniciar sua carreira em arquitetura de software em Java? Veja nosso curso de AQT M1 – Introdução a Arquitetura de Software com Java.

“Vocês vão me procurar e me achar, pois vão me procurar com todo o coração.” Jeremias 29:13

Parâmetros de Métodos Opcionais com Java

Com a ausência de parâmetros opcionais na linguagem Java como recurso nativo, muitas pessoas me perguntam qual é a melhor forma de se implementar essa estratégia. Segue ai dicas

1) Padrões e estratégias

Já existem vários patterns e abordagens para se implementar isso, fica a seu gosto escolher e decidir o melhor design para seu projeto. Segue abaixo dois links:

2) Outra opção paralela é fazer o uso de Optional<T>

Mesmo o recurso Optional<T> sendo direcionado para retorno de métodos [artigo], alguns não concordam com isso e acabam usando para parâmetros de entradas também.

“É como dizer que você não deve usar uma faca de pão para abrir um pacote em sua cozinha porque a faca de pão não foi feita para fazer isso”

Eu particularmente concordo totalmente com o artigo acima, e acho que design é pessoal e cada um deve aplicar da forma com que possa balancear propositalmente prós e contras dos resultados dessas opções.

Como vc bem pode ver, as opções estão na mesa, e vc fica livre para decidir qual é a melhor abordagem para seu projeto.

“O SENHOR Deus é bom. Em tempos difíceis, ele salva o seu povo e cuida dos que procuram a sua proteção.” Naum 1:7