Buscar

Padrões de Arquitetura de Software

Prévia do material em texto

Arquitetura em camadas 
O padrão de arquitetura mais comum é o padrão de arquitetura em camadas, também conhecido como padrão de arquitetura de n camadas.
Este padrão é o padrão utilizado na maioria das aplicações Java EE e portanto, é amplamente conhecido pela maioria dos arquitetos, projetistas e desenvolvedores.
O padrão de arquitetura em camadas está de acordo com as estruturas tradicionais de comunicação e organização de TI encontradas na maioria das empresas, tornando-se uma escolha natural para a maioria dos esforços de desenvolvimento de aplicativos de negócios.
Descrição do Padrão
Os componentes dentro do padrão de arquitetura em camadas são organizados em camadas horizontais, cada camada desempenhando uma função específica dentro do aplicativo (por exemplo, lógica de apresentação ou lógica de negócios). Embora o padrão de arquitetura em camadas não especifique o número e os tipos de camadas que devem existir no padrão, a maioria das arquiteturas em camadas consiste em quatro camadas padrão: apresentação, negócios, persistência e banco de dados.
Em alguns casos, a camada de negócios e a camada de persistência são combinadas em uma única camada de negócios, principalmente quando a lógica de persistência (por exemplo, SQL ou HSQL) é incorporada nos componentes da camada de negócios. Assim, aplicativos menores podem ter apenas três camadas, enquanto aplicativos de negócios maiores e mais complexos podem conter cinco ou mais camadas.
Cada camada do padrão de arquitetura em camadas tem um papel específico e responsabilidade dentro do aplicativo. Por exemplo, uma camada de apresentação seria responsável por manipular toda a interface de usuário e a lógica de comunicação do navegador, enquanto uma camada de negócios seria responsável pela execução de regras de negócios específicas associadas à solicitação. Cada camada da arquitetura forma uma abstração em torno do trabalho que precisa ser feito para satisfazer uma solicitação de negócios específica. Por exemplo, a camada de apresentação não precisa saber ou se preocupar sobre como obter dados do cliente; ela só precisa exibir essas informações em uma tela em formato específico. Da mesma forma, a camada de negócios não precisa se preocupar sobre como formatar os dados do cliente para exibição em uma tela ou até mesmo de onde os dados do cliente estão vindo; ela só precisa obter os dados da camada de persistência, executar lógica de negócios em relação aos dados (por exemplo, calcular valores ou agregar dados) e passar essas informações para a camada de apresentação.
Uma das características poderosas do padrão de arquitetura em camadas é a separação de interesses entre os componentes. Componentes dentro de uma camada específica lidam apenas com a lógica que pertence a essa camada. Por exemplo, os componentes na camada de apresentação lidam apenas com a lógica de apresentação, enquanto os componentes que residem na camada de negócios lidam apenas com a lógica de negócios. Esse tipo de classificação de componente facilita a criação de funções e modelos de responsabilidade eficazes em sua arquitetura e também facilita o desenvolvimento, teste, controle e manutenção de aplicativos usando esse padrão de arquitetura devido a interfaces de componentes bem definidas e escopo de componente limitado.
Conceitos Chave
Observe na Figura 1-2 que cada uma das camadas na arquitetura está marcada como sendo fechada. Este é um conceito muito importante no padrão de arquitetura em camadas. Uma camada fechada significa que, conforme uma solicitação é movida de uma camada para outra, ela deve passar pela camada logo abaixo dela para chegar à próxima camada abaixo daquela. Por exemplo, uma solicitação originada da camada de apresentação deve primeiro passar pela camada de negócios e depois pela camada de persistência antes de finalmente atingir a camada do banco de dados.
Então, por que não permitir o acesso direto da camada de apresentação à camada de persistência ou à camada do banco de dados? Afinal, o acesso direto ao banco de dados a partir da camada de apresentação é muito mais rápido do que passar por um monte de camadas desnecessárias apenas para recuperar ou salvar informações do banco de dados. A resposta a essa pergunta está em um conceito-chave conhecido como camadas de isolamento.
As camadas do conceito de isolamento significam que as mudanças feitas em uma camada da arquitetura geralmente não afetam os componentes em outras camadas: a mudança é isolada para os componentes dentro dessa camada, e possivelmente outra camada associada (como uma persistência camada contendo SQL). Se você permitir que a camada de apresentação acesse diretamente a camada de persistência, as alterações feitas no SQL na camada de persistência afetariam a camada de negócios e a apresentação camada, produzindo assim uma aplicação muito fortemente acoplada com muitas interdependências entre os componentes. Esse tipo de a arquitetura torna-se muito difícil e cara de mudar.
O conceito das camadas de isolamento também significa que cada camada é independente das outras camadas, tendo assim pouco ou nenhum conhecimento do funcionamento interno de outras camadas na arquitetura. Para entender o poder e a importância deste conceito, considere uma grande refatoração para alterar a estrutura de apresentação de um sistema. Assumindo que os contratos (por exemplo, modelo) usado entre a camada de apresentação e o negócio camada permanecem as mesmas, a camada de negócios não é afetada pela refatoração e permanece completamente independente do tipo de interface do usuário estrutura usada pela camada de apresentação.
Enquanto as camadas fechadas facilitam as camadas de isolamento e, portanto, ajudam isolar a mudança dentro da arquitetura, há momentos em que faz sentido para certas camadas estarem abertas. Por exemplo, suponha que você queira para adicionar uma camada de serviços compartilhados a uma arquitetura contendo componentes de serviço acessados ​​por componentes dentro da camada de negócio (por exemplo, classes de utilitário de dados e string ou auditoria e registro em classes de log). Criar uma camada de serviços geralmente é uma boa ideia neste caso porque arquitetonicamente restringe o acesso aos serviços compartilhados na camada de negócios (e não a camada de apresentação). Sem uma camada separada, não há nada arquitetonicamente que restrinja a camada de apresentação de acessar esses serviços comuns, tornando difícil governar esta restrição de acesso. Neste exemplo, a nova camada de serviços provavelmente residiria abaixo da camada de negócios para indicar que os componentes nesta camada de serviços não são acessíveis a partir da camada de apresentação. No entanto, isso apresenta um problema em que a camada de negócios é agora obrigada a passar pela camada de serviços para chegar à camada de persistência, o que não faz muito sentido. Este é um antigo problema com a arquitetura em camadas, e é resolvido criando camadas abertas dentro da arquitetura. 
Conforme ilustrado na Figura 1-3, a camada de serviços, neste caso, está marcada como aberto, significa que as solicitações podem ignorar essa camada aberta e vá diretamente para a camada abaixo dela. No exemplo a seguir, uma vez que a camada de serviços está aberta, a camada de negócios agora está autorizada a contorná-la e ir diretamente para a camada de persistência, o que faz todo o sentido.
Alavancar o conceito de camadas abertas e fechadas ajuda a definir relação entre camadas de arquitetura e fluxos de solicitação e também fornece aos designers e desenvolvedores as informações necessárias para entender as várias restrições de acesso de camada dentro da arquitetura. Falha em documentar ou comunicar corretamente quais camadas da arquitetura é aberta e fechada (e por que) geralmente resulta em arquiteturas fortemente acopladas e frágeis que são muito difíceis de testar, manter e implantar.
Exemplo do padrão
Para ilustrar como a arquitetura em camadas funciona, considere uma solicitação de um usuário corporativopara recuperar informações do cliente para um determinado indivíduo, conforme ilustrado na Figura 1-4. As setas pretas mostram a solicitação que flui para o banco de dados para recuperar o cliente dados, e as setas vermelhas mostram a resposta fluindo de volta para a tela para exibir os dados. Neste exemplo, as informações do cliente consistem em dados do cliente e dados do pedido (pedidos feitos pelo cliente).
A tela do cliente é responsável por aceitar a solicitação e exibir as informações do cliente. Não sabe de onde os dados são, como são recuperados ou quantas tabelas de banco de dados devem ser consultas para obter os dados. Uma vez que a tela do cliente recebe uma solicitação para obter informações do cliente para um indivíduo em particular, ele então encaminha essa solicitação para o módulo de delegação do cliente. Este módulo é responsável por saber quais módulos na camada de negócios processam esse pedido e também como chegar a esse módulo e que dados são necessários (o contrato). O objeto do cliente na camada de negócios é responsável por agregar todas as informações necessárias para a solicitação de negócio (neste caso para obter informações do cliente). Este módulo chama o módulo DAO (data access object) do cliente na camada de persistência para obter dados do cliente e também o DAO do módulo pedido para obter informações sobre o pedido. Esses módulos, por sua vez, executam Instruções SQL para recuperar os dados correspondentes e repassá-los até o objeto do cliente na camada de negócios. Uma vez que o objeto cliente recebe os dados, agrega os dados e passa essas informações de volta para o cliente delegado, que passa então dados para a tela do cliente a ser apresentada ao usuário.
Considerações
O padrão de arquitetura em camadas é um padrão sólido de propósito geral, tornando-o um bom ponto de partida para a maioria das aplicações, particularmente quando você não tem certeza de qual padrão de arquitetura é mais adequado para sua aplicação. No entanto, há algumas coisas a considerar do ponto de vista da arquitetura ao escolher esse padrão. A primeira coisa a observar é o que é conhecido como a arquitetura antipadrão de sumidouro (“architecture sinkhole anti-pattern”). Esse antipadrão descreve a situação em que solicitações fluem através de múltiplas camadas da arquitetura como simples processamento de passagem com pouca ou nenhuma lógica executada dentro cada camada. Por exemplo, suponha que a camada de apresentação responda a uma solicitação do usuário para recuperar dados do cliente. A camada de apresentação passa a solicitação para a camada de negócios, que simplesmente passa o pedido para a camada de persistência, que então faz um simples SQL chamada para a camada de banco de dados para recuperar os dados do cliente. Os dados em seguida, passam por todo o caminho de volta até a pilha sem processamento adicional ou lógica para agregar, calcular ou transformar os dados.
Cada arquitetura em camadas terá pelo menos alguns cenários que caem no antipadrão do sumidouro da arquitetura. A chave, no entanto, é analisar a porcentagem de solicitações que se enquadram nessa categoria. O Regra 80-20 é geralmente uma boa prática a seguir para determinar se você está ou não utilizando o antipadrão de sumidouro de arquitetura. Isto é típico ter cerca de 20% dos pedidos como passagem com simples processamento e 80 por cento dos pedidos com alguma lógica de negócios associada à solicitação. No entanto, se você achar que essa relação é revertida e a maioria dos seus pedidos é simples passagem sem processamento, você pode querer considerar algumas das camadas de arquitetura abertas, tendo em mente que será mais difícil para controlar a mudança devido à falta de isolamento da camada.
Arquitetura orientada a eventos
O padrão de arquitetura orientado a eventos é um popular padrão de arquitetura assíncrona usado para produzir aplicações altamente escalonáveis. Também é altamente adaptável e pode ser usado para pequenas aplicações, bem como grandes e complexas. A arquitetura orientada a eventos é composta por componentes de processamento de eventos de propósito único altamente desacoplados que recebem e processam eventos de maneira assíncrona. 
O padrão de arquitetura orientada a eventos consiste em duas topologias principais, o mediator e o broker. A topologia do mediador é comumente usada quando você precisa orquestrar várias etapas dentro de um evento por meio de um mediador central, enquanto a topologia do intermediário é usada quando você deseja encadear eventos juntos sem o uso de um mediador central. Como as características de arquitetura e as estratégias de implementação diferem entre essas duas topologias, é importante entender cada uma delas para saber qual é a mais adequada para sua situação específica.
Topologia de Mediator
A topologia de mediador é útil para eventos que possuem várias etapas e exigem algum nível de orquestração para processar o evento. Por exemplo, um único evento para colocar uma negociação de ações pode exigir que você primeiro valide a negociação, verifique a conformidade dessa negociação de ações com várias regras de conformidade, atribua a negociação a um corretor, calcule a comissão e finalmente coloque a negociação com esse corretor.
Todas essas etapas exigiriam algum nível de orquestração para determinar a ordem das etapas e quais podem ser feitas em série e em paralelo.
Existem quatro tipos principais de componentes de arquitetura na topologia do mediador: filas de eventos, um mediador de eventos, canais de eventos e processadores de eventos. O fluxo de eventos começa com um cliente enviando um evento para uma fila de eventos, que é usada para transportar o evento para o mediador de eventos. O mediador de eventos recebe o evento inicial e orquestra esse evento enviando eventos assíncronos adicionais aos canais de eventos para executar cada etapa do processo. Os processadores de eventos, que ouvem nos canais de eventos, recebem o evento do mediador do evento e executam uma lógica de negócios específica para processar o evento. A Figura 2-1 ilustra a topologia geral do mediador do padrão de arquitetura orientada a eventos.
É comum ter de uma dúzia a várias centenas de filas de eventos em uma arquitetura orientada a eventos. O padrão não especifica a implementação do componente da fila de eventos; pode ser uma fila de mensagens, um ponto de extremidade de serviço da web ou qualquer combinação deles.
Existem dois tipos de eventos nesse padrão: um evento inicial e um evento de processamento. O evento inicial é o evento original recebido pelo mediador, enquanto os eventos de processamento são aqueles que são gerados pelo mediador e recebidos pelos componentes de processamento de eventos.
O componente mediador de eventos é responsável por orquestrar as etapas contidas no evento inicial. Para cada etapa no evento inicial, o mediador de evento envia um evento de processamento específico para um canal de evento, que é então recebido e processado pelo processador de evento. É importante observar que o mediador de eventos não realiza a lógica de negócios necessária para processar o evento inicial, em vez disso, ele conhece as etapas necessárias para processar o evento inicial.
Os canais de eventos são usados pelo mediador de eventos para passar de forma assíncrona eventos de processamento específicos relacionados a cada etapa no evento inicial para os processadores de eventos. Os canais de eventos podem ser filas de mensagens ou tópicos de mensagens, embora os tópicos de mensagens sejam mais amplamente usados com a topologia do mediador para que os eventos de processamento possam ser processados por vários processadores de eventos (cada um executando uma tarefa diferente com base no evento de processamento recebido).
Os componentes do processador de eventos contêm a lógica de negócios do aplicativo necessária para processar o evento de processamento. Processadores de eventos são componentes de arquitetura autônomos, independentes e altamente desacoplados queexecutam uma tarefa específica no aplicativo ou no sistema. Embora a granularidade do componente do processador de eventos possa variar de granularidade fina (por exemplo, calcular imposto sobre vendas em um pedido) para grosseira (por exemplo, processar uma reivindicação de seguro), é importante ter em mente que, em geral, cada componente processador de evento deve executar uma única tarefa de negócios e não depender de outros processadores de eventos para concluir sua tarefa específica.
O mediador de eventos pode ser implementado de várias maneiras. Como arquiteto, você deve entender cada uma dessas opções de implementação para garantir que a solução escolhida para o mediador de evento corresponda às suas necessidades e requisitos.
A implementação mais simples e mais comum do mediador de eventos é por meio de hubs de integração de software livre, como o Spring Integration, o Apache Camel ou o Mule ESB. Os fluxos de eventos nesses hubs de integração de código-fonte aberto são geralmente implementados por meio do código Java ou de uma linguagem DSL (domínio específico). Para uma mediação e orquestração mais sofisticadas, você pode usar o BPEL (linguagem de execução de processos de negócios) acoplado a um mecanismo BPEL, como o Apache ODE de software livre. BPEL é uma linguagem padrão XML que descreve os dados e as etapas necessárias para processar um evento inicial. Para aplicativos muito grandes que exigem orquestração muito mais sofisticada (incluindo etapas que envolvem interações humanas), você pode implementar o mediador de eventos usando um gerenciador de processos de negócios (BPM), como o jBPM.
Entender suas necessidades e combiná-las à implementação correta do mediador de eventos é essencial para o sucesso de qualquer arquitetura orientada a eventos usando essa topologia. Usar um hub de integração de software livre para fazer uma orquestração de gerenciamento de processos de negócios muito complexa é uma receita para falhas, assim como a implementação de uma solução de BPM para executar uma lógica de roteamento simples.
Para ilustrar como a topologia do mediador funciona, suponha que você esteja segurado por uma companhia de seguros e decida se mudar. Nesse caso, o evento inicial pode ser chamado de algo como evento de realocação. As etapas envolvidas no processamento de um evento de realocação estão contidas no mediador de eventos, conforme mostrado na Figura 2-2. Para cada etapa inicial do evento, o mediador de evento cria um evento de processamento (por exemplo, alterar endereço, recálculo, etc.), envia esse evento de processamento para o canal de evento e aguarda o processamento do evento pelo processador de eventos correspondente (por exemplo, processo do cliente, processo de cotação, etc.). Esse processo continua até que todas as etapas do evento inicial tenham sido processadas. A barra única sobre as etapas de recálculo de cotação e atualização de declarações no mediador de evento indica que essas etapas podem ser executadas ao mesmo tempo.
Topologia de Broker
A topologia do intermediário difere da topologia do mediador, na medida em que não existe um mediador de evento central; em vez disso, o fluxo de mensagens é distribuído pelos componentes do processador de eventos de maneira semelhante a uma cadeia por meio de um intermediário de mensagens simples (por exemplo, ActiveMQ, HornetQ, etc.). Essa topologia é útil quando você tem um fluxo de processamento de eventos relativamente simples e não deseja (ou precisa) orquestração de evento central. Existem dois tipos principais de componentes de arquitetura na topologia do broker: um componente do broker e um componente do processador de eventos. O componente do broker pode ser centralizado ou federado e contém todos os canais de eventos que são usados no fluxo de eventos.
Os canais de eventos contidos no componente do broker podem ser filas de mensagens, tópicos de mensagens ou uma combinação de ambos.
Esta topologia é ilustrada na Figura 2-3. Como você pode ver no diagrama, não há nenhum componente mediador de evento central controlando e orquestrando o evento inicial; em vez disso, cada componente do processador de eventos é responsável por processar um evento e publicar um novo evento, indicando a ação que acabou de executar. Por exemplo, um processador de eventos que equilibre uma carteira de ações pode receber um evento inicial denominado desdobramento de ações. Com base nesse evento inicial, o processador de eventos pode fazer algum rebalanceamento de portfólio e, em seguida, publicar um novo evento no broker chamado portfólio de rebalanceamento, que seria então capturado por um processador de evento diferente. Observe que pode haver momentos em que um evento é publicado por um processador de eventos, mas não detectado por outro processador de eventos. Isso é comum quando você está desenvolvendo um aplicativo ou fornecendo funcionalidades e extensões futuras.
Para ilustrar como a topologia do corretor funciona, usamos o mesmo exemplo da topologia do mediador. Como não há mediador de evento central para receber o evento inicial na topologia do agente, o componente de processamento do cliente recebe o evento diretamente, altera o endereço do cliente e envia um evento dizendo que alterou o endereço de um cliente. Neste exemplo, há dois processadores de eventos que estão interessados ​​no evento de mudança de endereço: o processo de cotação e o processo de solicitações. O componente do processador de cotações recalcula as novas taxas de auto-seguro com base na alteração de endereço e publica um evento no restante do sistema, indicando o que ele fez. O componente de processamento de declarações, por outro lado, recebe o mesmo evento de endereço de alteração, mas, nesse caso, atualiza uma solicitação de seguro pendente e publica um evento no sistema como um evento de reivindicação de atualização. Esses novos eventos são então selecionados por outros componentes do processador de eventos e a cadeia de eventos continua pelo sistema até que não haja mais eventos publicados para esse evento inicial específico.
Como você pode ver na Figura 2-4, a topologia do agente é toda sobre o encadeamento de eventos para executar uma função de negócios. A melhor maneira de entender a topologia do corretor é pensar nisso como uma corrida de revezamento. Em uma corrida de revezamento, os corredores seguram um bastão e correm por uma certa distância, em seguida, entregam o bastão para o próximo corredor, e assim por diante, até que o último corredor cruze a linha de chegada. Em corridas de revezamento, uma vez que um corredor entrega o bastão, ela termina a corrida. Isso também é verdade com a topologia do agente: uma vez que um processador de evento transfere o evento, ele não está mais envolvido com o processamento desse evento específico.
Considerações
O padrão de arquitetura orientado a eventos é um padrão relativamente complexo de implementar, principalmente devido à natureza distribuída assíncrona. Ao implementar esse padrão, você deve abordar vários problemas de arquitetura distribuída, como a disponibilidade remota do processo, a falta de capacidade de resposta e a lógica de reconexão do intermediário no caso de uma falha do intermediário ou mediador.
Uma consideração a ser levada em conta ao escolher esse padrão de arquitetura é a falta de transações atômicas para um único processo de negócios. Como os componentes do processador de eventos são altamente desacoplados e distribuídos, é muito difícil manter uma unidade de trabalho transacional entre eles. Por esse motivo, ao projetar seu aplicativo usando esse padrão, você deve pensar continuamente em quais eventos podem ou não ser executados de forma independente e planejar a granularidade de seus processadores de eventos de acordo. Se você achar que precisa dividir uma única unidade de trabalho nos processadores de eventos, ou seja, se estiver usando processadores separados para algo que deveria ser uma transação indivisa, esse provavelmente não é o padrão certo para seu aplicativo.Talvez um dos aspectos mais difíceis do padrão de arquitetura orientada a eventos seja a criação, manutenção e controle dos contratos de componentes do processador de eventos. Cada evento geralmente tem um contrato específico associado a ele (por exemplo, os valores de dados e o formato de dados sendo transmitidos para o processador de eventos). É de vital importância ao usar esse padrão para estabelecer um formato de dados padrão (por exemplo, XML, JSON, Objeto Java, etc.) e estabelecer uma política de versão de contrato desde o início.
Arquitetura Microkernel
O padrão de arquitetura microkernel (por vezes referido como o padrão de arquitetura de plug-in) é um padrão natural para implementar aplicações baseadas em produto. Um aplicativo baseado em produto é aquele que é empacotado e disponibilizado para download em versões como um típico produto de terceiros. No entanto, muitas empresas também desenvolvem e liberar seus aplicativos de negócios internos, como produtos de software, completo com versões, notas de lançamento e recursos conectáveis. Estes também são um ajuste natural para esse padrão. A arquitetura microkernel padrão permite que você adicione recursos de aplicativos adicionais como plug-ins ao aplicativo principal, fornecendo extensibilidade, bem como separação de recursos e isolamento.
Descrição do Padrão
O padrão de arquitetura microkernel consiste em dois tipos de componentes de arquitetura: um sistema central e módulos de plug-in. A lógica de aplicação é dividida entre módulos de plug-in independentes e o sistema básico de núcleo, fornecendo extensibilidade, flexibilidade e isolamento de recursos de aplicativos e lógica de processamento personalizada. A figura 3-1 ilustra o padrão básico da arquitetura microkernel.
O sistema central do padrão de arquitetura microkernel tradicionalmente contém apenas a funcionalidade mínima necessária para tornar o sistema operacional. Muitos sistemas operacionais implementam o padrão de arquitetura de microkernel, daí a origem do nome desse padrão. A partir de uma perspectiva de aplicativo de negócios, o sistema central é geralmente definido como a lógica geral de negócios que possui código customizado para casos especiais, regras especiais ou processamento condicional complexo.
Os módulos de plug-in são componentes autônomos e independentes que contêm processamento especializado, recursos adicionais e código customizado destinado a aprimorar ou estender o sistema principal para produzir recursos de negócios adicionais. Geralmente, os módulos de plug-in devem ser independentes de outros módulos de plug-in, mas você certamente pode criar plug-ins que exijam que outros plug-ins estejam presentes. De qualquer forma, é importante manter a comunicação entre os plug-ins ao mínimo para evitar problemas de dependência.
O sistema central precisa saber quais módulos de plug-in estão disponíveis e como chegar até eles. Uma maneira comum de implementar isso é através de algum tipo de registro de plug-in. Esse registro contém informações sobre cada módulo de plug-in, incluindo detalhes como nome, contrato de dados e protocolo de acesso remoto (dependendo de como o plug-in está conectado ao sistema principal). Por exemplo, um plug-in para software fiscal que sinaliza itens de auditoria fiscal de alto risco pode ter uma entrada de registro que contém o nome do serviço (AuditChecker), o contrato de dados (dados de entrada e saída) e o formato do contrato (XML). Ele também pode conter um WSDL (Web Services Definition Language) se o plug-in for acessado por meio do SOAP.
Os módulos plug-in podem ser conectados ao sistema principal por várias maneiras, incluindo OSGi (iniciativa de gateway de serviço aberto), sistema de mensagens, serviços da Web ou até mesmo vinculação ponto a ponto direta (por exemplo, instanciação de objetos). O tipo de conexão usado depende do tipo de aplicativo que você está criando (aplicativo para pequenos produtos ou grandes empresas) e suas necessidades específicas (por exemplo, implantação única ou implantação distribuída). O próprio padrão de arquitetura não especifica nenhum desses detalhes de implementação, apenas que os módulos de plug-in devem permanecer independentes um do outro.
Os contratos entre os módulos de plug-in e o sistema principal podem variar de contratos padrão a personalizados. Os contratos personalizados são normalmente encontrados em situações em que os componentes de plug-in são desenvolvidos por terceiros, onde você não tem controle sobre o contrato usado pelo plug-in. Nesses casos, é comum criar um adaptador entre o contato do plug-in e seu contrato padrão, para que o sistema principal não precise de código especializado para cada plug-in. Ao criar contratos padrão (geralmente implementados por meio de XML), é importante lembrar de criar uma estratégia de controle de versão desde o início.
Exemplo do padrão
Talvez o melhor exemplo da arquitetura microkernel seja o Eclipse IDE. O download do produto básico do Eclipse fornece pouco mais que um editor sofisticado. No entanto, quando você começa a adicionar plug-ins, ele se torna um produto altamente personalizável e útil. Os navegadores de Internet são outro exemplo comum de produtos que usam a arquitetura microkernel: os visualizadores e outros plug-ins adicionam recursos adicionais que não são encontrados no navegador básico (ou seja, no sistema principal).
Considerações
Uma grande coisa sobre o padrão de arquitetura de microkernel é que ele pode ser incorporado ou usado como parte de outro padrão de arquitetura. Por exemplo, se esse padrão resolver um problema específico que você tem com uma área volátil específica do aplicativo, talvez você não consiga implementar a arquitetura inteira usando esse padrão. Nesse caso, você pode incorporar o padrão de arquitetura de microsserviços em outro padrão que estiver usando (por exemplo, arquitetura em camadas). Da mesma forma, os componentes do processador de eventos descritos na seção anterior sobre arquitetura orientada a eventos podem ser implementados usando o padrão de arquitetura de microsserviços.
O padrão de arquitetura de microsserviços fornece grande suporte para design evolucionário e desenvolvimento incremental. Você pode primeiro produzir um sistema de núcleo sólido e, à medida que o aplicativo evoluir de forma incremental, adicione recursos e funcionalidades sem precisar fazer alterações significativas no sistema principal.
Para aplicativos baseados em produto, o padrão de arquitetura microkernel sempre deve ser sua primeira escolha como uma arquitetura inicial, especialmente para os produtos em que você liberará recursos adicionais ao longo do tempo e desejará controlar quais usuários obterão quais recursos. Se, com o tempo, você descobrir que o padrão não atende a todos os seus requisitos, é possível refatorar seu aplicativo para outro padrão de arquitetura mais adequado aos seus requisitos específicos.
Padrão de arquitetura de microsserviços
O padrão de arquitetura de microsserviços está rapidamente ganhando espaço na indústria como uma alternativa viável para aplicações monolíticas e arquiteturas orientadas a serviços. Como esse padrão de arquitetura ainda está em evolução, há muita confusão na indústria sobre o que é esse padrão e como ele é implementado. Esta seção do relatório fornecerá os principais conceitos e conhecimentos fundamentais necessários para entender os benefícios (e as compensações) desse importante padrão de arquitetura e se é o padrão certo para sua aplicação.
Descrição do Padrão
Independentemente da topologia ou do estilo de implementação escolhido, há vários conceitos básicos comuns que se aplicam ao padrão geral de arquitetura. O primeiro desses conceitos é a noção de unidades implantadas separadamente. Conforme ilustrado na Figura 4-1, cada componente da arquitetura de microsserviços é implantado como uma unidade separada, permitindo uma implantação mais fácil por meio de um pipeline de entrega eficiente e simplificado, maior escalabilidade e um alto grau dedesacoplamento de aplicativos e componentes em seu aplicativo.
Talvez o conceito mais importante para entender esse padrão seja a noção de um componente de serviço. Em vez de pensar em serviços em uma arquitetura de microsserviços, é melhor pensar nos componentes de serviço, que podem variar em granularidade de um único módulo para uma grande parte do aplicativo. Os componentes de serviço contêm um ou mais módulos que representam uma função de finalidade única ou uma parte independente de um aplicativo de negócios grande. Projetar o nível correto de granularidade do componente de serviço é um dos maiores desafios em uma arquitetura de microsserviços.
Outro conceito-chave dentro do padrão de arquitetura de microsserviços é que é uma arquitetura distribuída, significando que todos os componentes dentro da arquitetura são totalmente desacoplados uns dos outros e acessados através de algum tipo de protocolo de acesso remoto (por exemplo, REST, SOAP, etc.). A natureza distribuída desse padrão de arquitetura é como ele atinge algumas de suas características superiores de escalabilidade e implantação.
Uma das coisas interessantes sobre a arquitetura de microsserviços é que ela evoluiu a partir de problemas associados a outros padrões comuns de arquitetura, em vez de ser criada como uma solução aguardando a ocorrência de um problema. O estilo de arquitetura de microservices evoluiu naturalmente de duas fontes principais: aplicações monolíticas desenvolvidas usando o padrão de arquitetura em camadas e aplicativos distribuídos desenvolvidos através do padrão de arquitetura orientada a serviços.
O caminho evolutivo de aplicativos monolíticos para um estilo de arquitetura de microsserviços foi solicitado principalmente através do desenvolvimento de entrega contínua, a noção de um pipeline de implantação contínua do desenvolvimento à produção, que agiliza a implantação de aplicativos. Aplicativos monolíticos normalmente consistem em componentes fortemente acoplados que fazem parte de uma única unidade implantável, tornando difícil e difícil alterar, testar e implantar o aplicativo (daí a ascensão dos ciclos comuns de "implantação mensal" normalmente encontrados na maioria das grandes lojas de TI). Esses fatores geralmente levam a aplicativos frágeis que quebram toda vez que algo novo é implantado. O padrão de arquitetura de microsserviços aborda esses problemas separando o aplicativo em várias unidades implementáveis (componentes de serviço) que podem ser desenvolvidas, testadas e implementadas individualmente, independentemente de outros componentes de serviço.
O outro caminho evolutivo que leva ao padrão de arquitetura de microsserviços é de problemas encontrados com aplicativos que implementam o SOA (padrão de arquitetura orientada a serviços). Embora o padrão SOA seja muito poderoso e ofereça níveis incomparáveis de abstração, conectividade heterogênea, orquestração de serviços e a promessa de alinhar metas de negócios a recursos de TI, é complexo, difícil de entender e implementar e geralmente é um exagero para a maioria das aplicações. O estilo de arquitetura de microsserviços aborda essa complexidade simplificando a noção de um serviço, eliminando as necessidades de orquestração e simplificando a conectividade e o acesso aos componentes de serviço.
Topologias do padrão
Embora existam literalmente dezenas de maneiras de implementar um padrão de arquitetura de microsserviços, três topologias principais destacam-se como as mais comuns e populares: a topologia baseada em REST da API, a topologia baseada em REST do aplicativo e a topologia centralizada de mensagens.
A topologia baseada em API REST é útil para sites que expõem serviços individuais pequenos e autônomos por meio de algum tipo de API (interface de programação de aplicativos). Essa topologia, ilustrada na Figura 4-2, consiste em componentes de serviço muito refinados (daí os microsserviços de nomes) que contêm um ou dois módulos que executam funções de negócios específicas, independentemente do restante dos serviços. Nessa topologia, esses componentes de serviço detalhados são normalmente acessados usando uma interface baseada em REST implementada por meio de uma camada de API baseada na Web implantada separadamente. Exemplos dessa topologia incluem alguns dos serviços Web RESTful baseados em nuvem de uso único comuns encontrados pelo Yahoo, Google e Amazon.
A topologia baseada em REST do aplicativo difere da abordagem baseada em REST da API em que as solicitações do cliente são recebidas por meio de telas de aplicativo de negócios tradicionais baseadas na web ou fat-client em vez de por meio de uma camada de API simples. Conforme ilustrado na Figura 4-3, a camada da interface com o usuário do aplicativo é implantada como um aplicativo da Web separado que acessa remotamente componentes de serviços implantados separadamente (funcionalidade de negócios) por meio de interfaces simples baseadas em REST. Os componentes de serviço nesta topologia diferem daqueles na topologia baseada em API-REST em que esses componentes de serviço tendem a ser maiores, mais granulares e representam uma pequena parte do aplicativo de negócios geral, em vez de serviços únicos e refinados. Essa topologia é comum para aplicativos comerciais de pequeno a médio porte que possuem um grau de complexidade relativamente baixo.
Outra abordagem comum dentro do padrão de arquitetura de microsserviços é a topologia de mensagem centralizada. Essa topologia (ilustrada na Figura 4-4) é semelhante à topologia baseada em REST do aplicativo anterior, exceto que, em vez de usar REST para acesso remoto, essa topologia usa um intermediário de mensagens centralizado leve (por exemplo, ActiveMQ, HornetQ etc.). É de vital importância observar essa topologia para não confundi-la com o padrão de arquitetura orientada a serviços ou considerá-la “SOA-Lite.” O intermediário de mensagem leve encontrado nesta topologia não executa nenhuma orquestração, transformação ou roteamento complexo; , é apenas um transporte leve para acessar componentes de serviços remotos.
A topologia centralizada de mensagens é normalmente encontrada em aplicativos de negócios maiores ou aplicativos que exigem controle mais sofisticado sobre a camada de transporte entre a interface do usuário e os componentes de serviço. Os benefícios dessa topologia sobre a topologia baseada em REST simples discutida anteriormente são mecanismos avançados de enfileiramento, mensagens assíncronas, monitoramento, tratamento de erros e melhor balanceamento de carga e escalabilidade gerais. O ponto único de falha e problemas de afunilamento arquitetural geralmente associados a um broker centralizado são tratados por meio de clustering de agente e federação do broker (dividindo uma única instância do broker em várias instâncias do broker para dividir a carga de transferência da mensagem com base nas áreas funcionais do sistema).
Evitar dependências e orquestração
Um dos principais desafios do padrão de arquitetura de microsserviços é determinar o nível correto de granularidade para os componentes de serviço. Se os componentes de serviço forem muito granulados, talvez você não perceba os benefícios que vêm com esse padrão de arquitetura (implantação, escalabilidade, capacidade de teste e acoplamento flexível). No entanto, os componentes de serviço muito detalhados levarão aos requisitos de orquestração de serviços, o que transformará rapidamente a arquitetura de microsserviços enxutos em uma arquitetura orientada a serviços pesada, completa com toda a complexidade, confusão, despesa e cotão normalmente encontrados no SOA. aplicativos baseados em Se você achar que precisa orquestrar seus componentes de serviço na interface do usuário ou na camada de API do aplicativo, é provável que seus componentes de serviço sejam muito granulares. Da mesma forma, se você achar que precisa realizar a comunicação entre serviços entre os componentes de serviço para processar uma única solicitação, é provável que seus componentes de serviço sejammuito refinados ou não sejam particionados corretamente do ponto de vista de funcionalidade comercial. A comunicação entre serviços, que pode forçar acoplamentos indesejados entre componentes, pode ser manipulada em vez disso por meio de um banco de dados compartilhado. Por exemplo, se um componente de serviço que entrega pedidos da Internet precisar de informações do cliente, ele poderá ir ao banco de dados para recuperar os dados necessários, em vez de invocar a funcionalidade no componente de atendimento ao cliente.
O banco de dados compartilhado pode lidar com as necessidades de informação, mas e a funcionalidade compartilhada? Se um componente de serviço precisar de funcionalidade contida em outro componente de serviço ou comum a todos os componentes de serviço, às vezes você pode copiar a funcionalidade compartilhada entre os componentes de serviço (violando assim o princípio DRY: não se repita). Essa é uma prática bastante comum na maioria dos aplicativos de negócios que implementam o padrão de arquitetura de microsserviços, trocando a redundância de repetir pequenas partes da lógica de negócios para manter os componentes de serviço independentes e separar sua implementação. Classes de utilidade pequenas podem se enquadrar nessa categoria de código repetido. Se você achar que, independentemente do nível de granularidade do componente de serviço, ainda não é possível evitar a orquestração do componente de serviço, isso é um bom sinal de que esse pode não ser o padrão de arquitetura correto para seu aplicativo. Devido à natureza distribuída desse padrão, é muito difícil manter uma única unidade de trabalho transacional entre (e entre) componentes de serviço. Tal prática exigiria algum tipo de estrutura de compensação de transações para reverter transações, o que adiciona complexidade significativa a esse padrão de arquitetura relativamente simples e elegante.
Considerações
O padrão de arquitetura de microsserviços resolve muitos dos problemas comuns encontrados em aplicativos monolíticos, bem como em arquiteturas orientadas a serviços. Como os principais componentes do aplicativo são divididos em unidades menores, implantadas separadamente, os aplicativos construídos usando o padrão de arquitetura de microsserviços são geralmente mais robustos, oferecem melhor escalabilidade e podem suportar mais facilmente a entrega contínua.
Outra vantagem desse padrão é que ele oferece a capacidade de realizar implantações de produção em tempo real, reduzindo significativamente a necessidade de implantações tradicionais de produção “big bang” mensais ou de fim de semana. Como a mudança geralmente é isolada para componentes de serviço específicos, somente os componentes de serviço que precisam ser alterados são implantados. Se você tiver apenas uma única instância de um componente de serviço, poderá escrever um código especializado no aplicativo de interface do usuário para detectar uma implantação ativa e redirecionar os usuários para uma página de erro ou uma página de espera. Como alternativa, você pode alternar várias instâncias de um componente de serviço para dentro e para fora durante uma implantação em tempo real, permitindo disponibilidade contínua durante os ciclos de implementação (algo que é muito difícil de fazer com o padrão de arquitetura em camadas).
Uma consideração final a ser considerada é que, como o padrão de arquitetura de microsserviços é uma arquitetura distribuída, ele compartilha alguns dos mesmos problemas complexos encontrados no padrão de arquitetura orientada a eventos, incluindo criação, manutenção e governo de contrato, disponibilidade remota do sistema e autenticação e autorização de acesso remoto.
Resumo de Análise dos Padrões
A Figura A-1 resume a pontuação da análise de padrões para cada um dos padrões de arquitetura descritos neste relatório. Este resumo ajudará você a determinar qual padrão pode ser melhor para sua situação. Por exemplo, se sua principal preocupação de arquitetura for a escalabilidade, você poderá examinar esse gráfico e ver que o padrão orientado por eventos, o padrão de microsserviços e o padrão baseado em espaço provavelmente são boas escolhas de padrões de arquitetura. Da mesma forma, se você escolher o padrão de arquitetura em camadas para seu aplicativo, poderá consultar o gráfico para ver se a implantação, o desempenho e a escalabilidade podem ser áreas de risco em sua arquitetura.

Continue navegando