|
|
Olá pessoal!
No post anterior vimos alguns conceitos de Event-Driven Architecture e como seria sua arquitetura de referência. Neste veremos as possíveis realizações de tal arquitetura de referência e também iremos conferir alguns princípios que devem ser levados em consideração ao se fazer o design deste tipo de arquitetura.
Vamos começar então pelas possíveis utilizações de uma Event-Driven Architecture. No livro Event Processing: Designing IT Systems for Agile Companies são relacionadas três principais cenários: Disseminação de Informação, Conhecimento de Situação e Integração de Aplicações. Cada possível utilização demanda uma forma distinta de implementação da arquitetura de referência vista. Vejamos cada uma delas a seguir.

Disseminação de Informação
Quando o objetivo é apenas disseminar informações, visando manter consistência de dados entre diferentes aplicações, normalmente não há necessidade de utilização de um intermediário, de forma que apenas canais sejam suficientes. Isso por que para disseminar uma informação, em geral, não é necessário modificar o dado da origem antes que ele chegue ao seu destino.
Sob o ponto de vista físico, um canal pode ser, por exemplo, um servidor de mensagens, que recebe a denominação de Message Oriented Middleware (MOM). Um MOM funciona como um hub, onde mensagens são retransmitidas de um computador ou componente de software para outro. Os produtos Microsoft Message Queue, IBM MQ Series e similares de outros fornecedores são exemplos de produtos que seguem o conceito de middleware orientado a mensageria (MOM).
Exemplos de implementação com este objetivo incluem feeds RSS, e feeds de dados financeiros em mercados de capital aberto. Neste último caso o padrão publish-and-subscribe se encaixa perfeitamente, de forma que um produtor de informação possa fazer uma publicação apenas uma vez e uma cópia da informação possa ser entregue a milhares de consumidores. Veja como seria a arquitetura descrita no diagrama ao lado (direito).
Conhecimento de Situação
Já quando o objetivo é proporcionar conhecimento de situação, usualmente eventos de diferentes fontes são coletados, analisados para que então uma nova notificação seja gerada para um ou mais consumidores. Este cenário caracteriza o que é conhecido como processamento de eventos complexos (Complex Event Processing – CEP). Uma arquitetura que endereça este tipo de necessidade normalmente é composta de múltiplos cansais e ao menos um intermediário do tipo gerador de eventos (descrito no post anterior).

Sob o ponto de vista físico, intermediários de alto nível podem ser, por exemplo, um Enterprise Service Bus (ESB), um broker de integração, um motor de orquestração de processos, um agente de processamento de eventos complexos, uma aplicação customizada que faça o papel de uma das anteriores, ou uma combinação delas. Veja no diagrama ao lado (esquerdo), como se daria a realização de tal arquitetura, considerando o emprego de um Enterprise Service Bus como intermediário.
Integração de Aplicações
Quando o assunto é integração de aplicações, é sempre interessante considerar abordagens que proporcionem o mínimo de acoplamento entre as aplicações envolvidas. Uma arquitetura orientada a eventos proporciona tal desacoplamento através do emprego dos canais e intermediários vistos até então, que permitem que produtores sejam alterados sem que necessariamente consumidores sejam afetados, e vice-versa.
Agora que já entendemos as principais utilizações de uma arquitetura orientada a eventos, vamos aos princípios que você não pode deixar de lembrar ao estabelecer tal arquitetura.
Princípios de uma Arquitetura Orientada a Eventos
- Reporta Eventos Correntes (Reports Current Events): Uma notificação sempre deve reportar uma ocorrência discreta uma vez que ela tenha ocorrido. Por exemplo, quando um leitor RFID detecta a presença de um tag RFID, ele envia uma mensagem de notificação que reporta tal evento. É importante considerar que não necessariamente é preciso transmitir notificações de forma independente, como por exemplo, uma requisição a um canal realizado como um web service para cada notificação gerada. É sempre importante avaliar o trade-off entre a latência na produção e atualização da informação contra o overhead do envio de cada ocorrência de forma independente. Em algumas situações você pode querer abrir mão da atualização da informação “just-in-time” por uma maior otimização da utilização de recursos de rede / banda, agrupando um conjunto de eventos para envio de uma só vez.
- Envia Notificações (Pushes Notification): As notificações devem ser enviadas do produtor ao consumidor e não o contrário. O produtor deve decidir quando enviar a notificação, uma vez que ele sabe do evento antes do consumidor. É importante notar, porém, que a implementação física deste conceito pode variar. Um produtor sempre enviará o evento a um canal (fará um push do evento no canal). Já o canal poderá fazer um push da notificação ao consumidor ou o consumidor poderá fazer um poll no canal, em uma freqüência de tempo determinada pelo consumidor.
- Responde imediatamente (Responds Immediately): O consumidor sempre deve fazer algo imediatamente após o reconhecimento do evento. Esse “fazer algo” pode significar avaliar e descartar o evento, caso este não seja aplicável ao seu domínio, ou ainda fazer cálculos, descartar a mensagem e salvar o objeto de evento para utilizações futuras, quando outras notificações chegarem, possibilitando fazer correlações entre os eventos recebidos, desta forma caracterizando um CEP (Complex Event Processing).
- Comunica-se apenas em uma direção (Communicates On-Way): As notificações em uma arquitetura orientada a eventos seguem o estilo “fire-and-forget”, onde o produtor envia a notificação e logo em seguida fica livre para fazer outro trabalho, sem ter que aguardar o processamento / endereçamento de tal notificação pelo seu consumidor. Ou seja, o produtor envia uma notificação, porém, não aguarda uma resposta do consumidor. Neste contexto, geralmente surgem preocupações quanto à integridade da informação, no sentido de garantir que a informação chegue ao destinatário corretamente. Tal preocupação, porém, pode ser delegada ao canal onde a mensagem é colocada pelo provedor, de forma que o provedor apenas se responsabilize por garantir que a informação tenha chegado ao canal corretamente (este retorna um acknowledge informando o recebimento) e que tal canal implemente um mecanismo de garantia de entrega conhecido como reliable delivery ou guaranteed delivery.
- É livre de comandos (Is free of commands): Uma notificação é um reporte que informa a ocorrência de um evento. Ela não deve prescrever a ação que o consumidor do evento deve tomar. Tal princípio tem como objetivo garantir o acoplamento mínimo entre provedor e consumidor de eventos, já que se o provedor prescrevesse o que o consumidor deveria fazer com a informação, ele seria impactado diretamente por mudanças em requisitos ou regras de negócios que afetem tais ações no provedor. No nível físico, um produtor de eventos apenas se comunica com o canal, de forma a emitir comandos como “abra o canal”, “envie a mensagem”, “feche o canal”, enquanto que o consumidor usa comandos semelhantes, como por exemplo, “leia o canal (poll)”, ou “abra / obtenha a mensagem” e “feche o canal”. Note que tais comandos acoplam provedor e consumidor de mensagens ao canal apenas, mas não um ao outro diretamente.
E assim ficamos por aqui. Até a próxima!
Olá pessoal!
Neste post veremos um conteúdo bastante interessante. Se você busca um estilo arquitetural que proporcione benefícios para sua organização como execução de processos de negócio em menor tempo, agilidade em resposta às mudanças e disponibilidade de informação para tomada de decisão, então você deveria dar uma olhada em “Event Driven Architecture”.
Neste artigo entenderemos o conceito de eventos e eventos de negócios, veremos porque uma arquitetura orientada a eventos é importante e como tal arquitetura se realiza de forma lógica. Já na parte 2 desta série, veremos como a arquitetura lógica vista aqui se realiza fisicamente (quais são os produtos envolvidos) e alguns princípios que devem ser considerados ao se estabelecer tal arquitetura.
O conteúdo deste post foi baseado no livro Event Processing: Designing IT Systems for Agile Companies, de K. Chandy e W. Schulte. O livro traz tópicos como Padrões de Processamento de Eventos em Negócios, Arquitetura de Processamento de Eventos, O Papel de Processamento de Eventos em SOA, dentre diversos outros. Eu recomendo!
Vamos começar então pelo começo. O que é um evento? Um evento é qualquer coisa que acontece. Já um evento de negócio é um evento que é significante para a execução de atividades da sua organização, seja ela de qualquer ramo. Exemplos de eventos de negócios incluem o recebimento de um pedido de um cliente, a realização de um pagamento bancário, a alteração de um endereço de um cliente, a detecção de sinais de um atentado de fraude, a alteração do status de entrega de um pedido, etc.
Uma organização é dita como orientada a eventos quando ela responde diretamente a eventos, de forma que os eventos funcionem como estímulos, acionando determinadas ações. Considere como exemplo uma organização que percebe que a demanda pelo seu produto aumenta em uma determinada região (evento) e então aumenta sua produção e distribuição de tal produto em tal região (resposta).
A essa altura você deve estar se perguntando: E por que ser orientado a eventos é importante? Segundo o livro Event Processing: Designing IT Systems for Agile Companies, cenários de mercado atuais levam a adoção de estratégias de gerenciamento que por sua vez introduzem requisitos para a área de TI que são melhor endereçados através de uma arquitetura orientada a eventos. Considere o esquema representado na figura a seguir.

No esquema apresentado, os cenários de mercado (identificado na figura como “Pressões de Negócios”) são o aumento no número de concorrentes, globalização, consolidação de mercados (para redução de custos / aumento de competitividade), melhora em serviços ao consumidor, questões regulamentares e agilidade nos negócios. Tais questões levam a adoção de estratégias de negócios em específico, como por exemplo, Agile enterprise e Adaptive enterprise (temas bastante difundidos em negócios atualmente), que por sua vez se traduzem em demandas sistêmicas ou requisitos para TI, que incluem orientação a tempo (timeliness), agilidade (agility) e disponibilidade de informação (information availability). Vejamos mais detalhes sobre cada um destes requisitos a seguir.
Orientação a tempo (Timeliness)
Pode ser entendido como a identificação da oportunidade de execução de um processo de negócio end-to-end em um tempo menor. Considere o exemplo onde uma seguradora que atualmente atende 90% dos seus sinistros em 25 dias úteis, passa a atender os mesmos 90% em 9 dias úteis. O benefício de tal redução de tempo se realiza através do aumento na satisfação do cliente, levando a maior lucratividade.
Agilidade (Agility)
Uma empresa ágil pode ajustar rapidamente seu comportamento em resposta a mudanças ambientais ou internas, como por exemplo, mudanças em demandas de clientes, ações da concorrência, questões regulatórias, tendências econômicas, etc. A principio, o conceito de agilidade pode ser confundido com o de “Orientação a tempo”, porém, agilidade se refere à capacidade da organização de mudar suas ações em resposta a tais eventos, ao invés de apenas fazer as coisas mais rapidamente. Considere o cenário em que ocorre uma mudança na situação econômica de um país e a demanda para a indústria automobilística que antes era por SUVs passa a ser por carros de pequeno porte e econômicos. Uma vez identificada tal mudança, organizações devem agir rapidamente mudando seus processos e infraestruturas internas de fabricação para atender ao novo cenário.
Disponibilidade de Informação (Information Availability)
Dentro da disciplina de gerenciamento da informação, o conceito de disponibilidade de informação, no contexto de processamento de eventos, pode ser dividido em três partes: Consistência de dados (Data consistency), Disseminação de informações (Information dissemination) e Consciência de situação (Situation awareness).
O objetivo de iniciativas de consistência de dados é manter diversas unidades de negócios e seus respectivos sistemas e bancos de dados de forma a ter uma visão única sobre os fatos. Já a disseminação de informações é uma necessidade básica tanto para os negócios como para a vida. Informações podem identificar a chagada de um pedido em uma organização ou antecipar situações anormais, como por exemplo, a chegada de uma tempestade. A consciência de situação implica em ter um entendimento atualizado sobre o que está acontecendo na organização de forma a viabilizar tomadas de decisões bem embasadas. Este conceito vai além da disseminação de informações, dado que ele implica em ter algo ou alguém interpretando e sintetizando diversas fontes de informações de forma a desenvolver uma visão consolidada do que está acontecendo.
Orientação a tempo, agilidade e disponibilidade de informação não podem ser endereçados simplesmente pelo aumento na velocidade da execução de processos de negócios seja, por exemplo, pelo aumento no número de pessoas/hora que atuam em tal processo ou ainda pela atuação mais inteligente de tais pessoas com o suporte das aplicações existentes da forma como são. A adoção destes conceitos requerem mudanças arquiteturais em processos de negócios e nos sistemas que os suportam. Vejamos então a seguir o que seria uma arquitetura de referência para “Event-Driven Architecture”.
Arquitetura de referência de uma “Event-Driven Architecture”
Um arquitetura orientada a eventos é consistida de uma rede de processamento de eventos. Uma rede de processamento de eventos, por sua vez, é consistida de aplicações ou componentes de aplicações que processam objetos de eventos.
Uma arquitetura de referência define um template para o design de um sistema de um dado domínio. Ela descreve o vocabulário, componentes e o relacionamento entre os componentes dentro e fora do sistema. Na arquitetura de referência que veremos a seguir não entraremos em detalhes de implementação (como por exemplo, os produtos utilizados), mas ao invés, veremos os conceitos envolvidos de forma mais abstrata. Confira tal modelo no diagrama a seguir e posteriormente a descrição de cada componente envolvido.

Produtores (Producers)
Um produtor de eventos é um componente de software responsável por detectar eventos no ambiente. Considere o seguinte exemplo: Um leitor RFID identifica uma mudança em seu ambiente como um evento de negócio, criando um objeto de evento e colocando-o em uma mensagem de notificação, emitindo-a através de um canal. O produtor, neste exemplo, é um software distribuído junto ao leitor RFID.
Canal (Channel)
Um canal pode ser entendido como um meio de transmissão de uma notificação de um componente da rede de processamento de eventos para o outro. Um canal pode receber mais de um tipo de notificação, como por exemplo, “Pedido Aprovado” e ao mesmo tempo, “Pedido Rejeitado”. Canais podem receber eventos de múltiplos produtores e torna-los disponíveis para apenas um consumidor, o que caracteriza uma abordagem denominada “fan-in”. O inverso também é possível, ou seja, a existência de apenas um produtor e eventos sendo disponibilizados por um canal para múltiplos consumidores, o que caracteriza uma abordagem denominada “fan-out”. Canais podem funcionar enviando mensagens, colocando objetos de eventos em um local compartilhado por produtores e consumidores ou ainda tendo o produtor chamando diretamente o consumidor.
Consumidor (Consumer)
Um consumidor é um agente da rede de processamento de eventos que recebe objetos de eventos. Dado o recebimento de um evento, um consumidor pode processar o evento localmente, pode acionar um serviço ou um processo de negócio, emitir uma mensagem, salvar o objeto para uso futuro (veja Complex Event Processing) ou ainda descartar o evento sem fazer nada com ele. Consumidores também são conhecidos como “event handlers”, “listeners” ou ainda “responders”.
Intermediário (Intermediary)
Redes de processamento de eventos podem ser intermediadas por canais apenas ou por canais e agentes de processamento de eventos.
Um canal é entendido como um intermediário de baixo nível, pois, suas funções são limitadas a tarefas relacionadas à comunicação apenas. Enquanto intermediário, um canal não modifica o conteúdo da mensagem recebida antes que ela seja entregue ao seu consumidor.
Já um intermediário, do tipo agente de processamentos de eventos, difere de um canal pelo fato de possibilitar a modificação do conteúdo da mensagem. Nestes casos, tais intermediários funcionam como consumidores e produtores de eventos, uma vez que eles recebem notificações, interpretam, processam e emitem novas notificações.
Existem duas categorias de agentes de processamentos: Roteadores de eventos e Geradores de eventos. Os roteadores se limitam a apenas ler objetos de eventos, filtrar, descartar aqueles que não são necessários para nenhum consumidor, e direcionar os eventos remanescentes para destinatários com base em seu conteúdo, caracterizando o que é conhecido como “content-based-routing”. Já os geradores de eventos fazem mais do que apenas retransmitir eventos. Eles podem receber e descartar eventos recebidos, gerando novos eventos com base nestes, que podem ser criados a partir de cálculos em cima dos eventos recebidos. Geradores de eventos intermediários podem:
- Copiar dados dos eventos base, alterar seu formato e reordená-los;
- Enriquecer eventos pelo acréscimo de dados relevantes, através da obtenção de dados adicionais a partir de base de dados ou outras fontes;
- Computar valores como totais, médias, mínimos e máximos a partir de múltiplos eventos;
- Realizar outros tipos de processamento de eventos complexos (complex event processing – CEP).
E assim ficamos por aqui! Não deixe de conferir o post seguinte, onde veremos algumas formas de realização física da arquitetura de referência apresentada e também alguns princípios da orientação a eventos. Até lá!
Olá pessoal!
Muito dificilmente você ainda não ouviu falar do livro Enterprise Integration Patterns, de Gregor Hohpe e Bobby Woolf, com prefácio e contribuição de Martin Fowler. Trata-se de excelente livro sobre integrações, mais especificamente sobre padrões de integrações corporativas, como o próprio título enuncia. O livro aborda padrões de integração amplamente vistos no mercado e explica porque a Mensageria (Messaging) é, dentre eles, o que melhor endereça diversos aspectos que devem ser levados em consideração ao estabelecer integrações confiáveis. Os autores ainda consideram que apesar desta ser uma abordagem amplamente indicada, ela é igualmente pouco conhecido ou aprofundado pelo mercado, e é justamente essa a motivação para que a maior parte do livro discorra sobre os diversos padrões relacionados à mensageria, como por exemplo: Guaranteed Delivery, Message Broker, Message Bus, Publish Subscribe Channel, Request-Reply e diversos outros.
Neste post veremos alguns dos tópicos abordados no livro. Começaremos pela motivação para a existência de integrações, passaremos pelos principais aspectos a considerar em integrações e posteriormente pelas principais abordagens de integração existentes – algumas delas estabelecidas por Martin Fowler. Por fim, veremos um comparativo entre as abordagens descritas. Comecemos então pela questão: Por que integrações são necessárias? A resposta é simples. Integrações são inevitáveis para prover uma experiência unificada e produtiva para funcionários da organização, parceiros e clientes.
Em um mundo ideal, pode se imaginar uma organização que tenha um sistema único e coeso, projetado desde o inicio para funcionar de forma unificada e coerente. Porém, a realidade que vemos é completamente diferente. Em uma empresa, mesmo que pequena, muito dificilmente existe apenas uma aplicação. E mesmo que se opte por desenvolver tal aplicação única, diversos seriam os desafios que acabariam por inviabilizar a estratégia.
E para se prover uma experiência unificada para funcionários, parceiros e clientes, devemos considerar que integrações podem ocorrer entre soluções estruturadas em plataformas distintas, separadas geograficamente dentro e fora do escopo da organização e que usam tecnologias distintas.
Neste contexto, o livro sugere que a escolha por uma abordagem de integração apropriada deva levar em consideração alguns aspectos. Vejamos:
- Formato de Dado: Para se integrarem, aplicações devem concordar em um formato de dado. Considerando que alterar todas as aplicações da organização para considerar um formato de dado único pode ser inviável, tradutores intermediários podem ser empregados. Outro assunto relacionado é como a evolução do formato do dado ao longo do tempo pode impactar as aplicações dependentes.
- Seleção de Tecnologia: Diferentes abordagens de integração requerem diferentes quantidades de licenças de software e hardware. Tais ferramentas podem ser caras, podem levar a dependência da organização com fornecedores específicos e ao aumento da curva de aprendizado dos desenvolvedores.
- Exposição de funcionalidades: Muitas abordagens de integrações permitem que aplicações compartilhem não apenas dado, mas também funcionalidades. Tal compartilhamento é interessante, pois gera um nível maior de abstração entre as aplicações envolvidas.
- Tempo para Atualização: Integrações devem ser estruturadas pensando na minimização do tempo de defasagem de dado. Idealmente, aplicações consumidoras de dado deveriam ser informadas assim que o dado estivesse pronto para consumo. Quanto mais tempo se leva para o compartilhamento do dado, maior a probabilidade de falta de sincronismo de dados.
- Processamento assíncrono: A chamada de funcionalidades remotas de forma síncrona pode ser algo custoso para a aplicação consumidora. A capacidade de realizar tarefas assíncronas traz diversas vantagens como, por exemplo, escalabilidade. Porém, tal solução tem design, desenvolvimento e depuração mais complexos.
- Confiabilidade: Conexões remotas não são apenas lentas, mas também são muito menos confiáveis do que a execução de procedimentos locais. Aplicações remotas podem não estar disponíveis ou a rede pode estar temporariamente indisponível. Comunicações assíncronas e confiáveis permitem que a aplicação origem realize outras tarefas, de forma confiante que a aplicação destino receberá a informação.
- Acoplamento entre aplicações: Aplicações integradas devem minimizar as dependências entre si, de forma que cada uma possa evoluir sem causar problemas para as demais. Integrações devem ser específicas o suficiente para cumprir seu papel, porém, genéricas o suficiente para garantir que mudanças não façam com que as aplicações dependentes parem.
- Intrusividade: Integrações devem causar o mínimo de impacto em códigos existentes e devem requerer pouca codificação.
- Esforço de desenvolvimento (*): Algumas soluções de integração podem endereçar bem os diversos fatores apresentados, porém, podem ser difíceis de se desenvolver, depurar e manter. Profissionais específicos podem ser necessários para monitorá-las e para gerenciar erros.
- Escalabilidade (*): Integrações devem causar o mínimo de impacto na performance dos sistemas envolvidos. Também devem ser projetadas para suportar aumento no volume de dados trafegados e ainda pensando-se nos impactos decorrentes de acréscimo no número de sistemas consumidores de uma determinada informação.
(*) Não constam no livro. Adicionados por mim por considera-los igualmente importantes com relação aos demais.
Segundo o livro Enterprise Integration Patterns, nenhuma abordagem de integração endereça todas estas características ao mesmo tempo de forma igualmente bem. Porém, determinadas abordagens de integração podem ser melhores do que outras em determinados cenários. Ainda segundo o livro, existem quatro principais categorias / estilos de integração. Vejamos a seguir:
File Transfer (Martin Fowler): As aplicações produzem arquivos de dados compartilhados para outras aplicações consumirem.

Remote Procedure Invocation (Martin Fowler): As aplicações expõem algumas das suas operações de forma que elas possam ser invocadas remotamente. Outras aplicações invocam tais operações para realizar determinadas tarefas ou para compartilhar dados.

Shared Database (Martin Fowler): As aplicações gravam dados que se deseja compartilhar em um banco de dados de comum acesso.

Messaging: As aplicações se conectam a um sistema comum de mensageria, de forma a compartilhar dados e a invocar operações através do uso de mensagens.

Cada uma dessas abordagens possuem vantagens e desvantagens. A ideia não é usar sempre a mesma, mas ao invés, aquela que melhor se adeque a um cenário em particular.
Conforme podemos observar na tabela comparativa a seguir, elaborada com base no conteúdo do livro, as abordagens File Transfer e Shared Database são as que apresentam os problemas considerados como os mais graves. Ambas não possibilitam a exposição de funcionalidades, o que permitiria um nível considerável de desacoplamento entre aplicações. A abordagem File Transfer apresenta ainda questões relacionadas ao tempo de

atualização de dados, o que pode gerar falta de sincronismo e, por consequência, falta de confiança nos dados apresentados.
Já o Shared Database, porém, ao contrário do File Transfer, é bastante versátil quando se trata de sincronismo de informações, já que as aplicações compartilham um mesmo repositório de dados. Porém, tal abordagem pode não ser viável quando se adquire um pacote de mercado. Fornecedores de tais pacotes, em geral, se reservam o direito de evoluir a estrutura (schema) da sua base de dados em novas versões do seu produto. Outros problemas intrínsecos desta abordagem são o alto acoplamento gerado entre as aplicações que a adotam, uma vez que uma alteração em uma estrutura de dados pode afetar diversas aplicações de uma só vez, e escalabilidade, já que problemas de concorrência podem ocorrer à medida que o número de aplicações que atualizam com frequência uma mesma estrutura cresça. Bloqueios de registros podem fazer com que seleções de dados simples demorem mais do que o esperado. Atualizações massivas ou frequentes podem ainda causar impactos significativos na performance dos demais sistemas.
Apesar da abordagem Remote Procedure Invocation permitir exposição de funcionalidades, o que garante um bom nível de abstração entre as aplicações envolvidas, o acoplamento ainda é considerado como alto neste tipo de abordagem, uma vez que a indisponibilidade da aplicação provedore ou que mudança em formatos de dados impactem diretamente as aplicações consumidoras. A abordagem também é considerada como pouco escalável, de forma semelhante a abordagem Shared Database, considerando que diversos consumidores dependeriam de um único recurso, neste caso a aplicação provedora, e que o aumento no número de consumidores impactaria diretamente tal aplicação provedora.
O livro ainda sugere que dentre as abordagens apresentadas, a Mensageria (Messaging) é a que teria mais vantagens e o que endereçaria melhor os aspectos apresentados anteriormente. E tal sugestão parece ser válida. Note que a abordagem Messaging é a que tem, de fato, mais aspectos positivos nos critérios avaliados.
A abordagem Messaging não requer que aplicações envolvidas sejam modificadas para suportar formatos de dados específicos. Tradutores intermediários podem ser usados para tal (Message Translator). Também permite que funcionalidades sejam executadas quando do recebimento de mensagens (exposição de funcionalidades). Já com relação ao tempo de processamento, padrões de integração near real-time e real-time podem ser usados nesta abordagem. E padrões near real-time logo remetem a processamento assíncrono, que somado a padrões que permitem a garantia de entrega de mensagens (Guaranteed Delivery), vem a garantir maior confiabilidade da integração. Acoplamento e Intrusividade também são itens com mais aspectos positivos nesta abordagem, quando comparado com as demais. Pela fato de empregar um sistema intermediário entre provedor e consumidor de dado, um não é necessariamente diretamente afetado por modificações no outro. A abordagem ainda é considerada pouco intrusiva, já que o código da aplicação não precisa ser afetado pelo código da integração. E uma vez que haja tal separação e que abordagens assíncronas sejam usadas, a abordagem é considerada altamente escalável, já que o processamento de um grande volume de mensagens pode ocorrer no ritmo que a aplicação suporta e não no ritmo que as demais aplicações impõem.
Seus principais problemas não são tão relevantes quando comparados com os das demais abordagens. A seleção de tecnologia, por exemplo, é considerada como negativa para esta abordagem, dada a dependência tecnológica que se adquire com sistemas de mensageria específicos. O esforço de desenvolvimento também é maior quando comparado com as demais abordagens, dada a complexidade intrínseca do desenvolvimento assíncrono e a necessidade de aquisição de conhecimento especializado.
E assim ficamos por aqui. Até a próxima!
Olá pessoal!
Frequentemente sou questionado com relação a quando a utilização de um ESB (Enterprise Service Bus ou Barramento de Serviços Corporativo) é interessante em um dado cenário de integração ou não. Espero que este post ajude a esclarecer a esta dúvida, bem como a elucidar as principais funcionalidades que se pode tirar proveito quando se emprega uma ferramenta robusta como esta. Vamos lá!

Em geral, um Enterprise Service Bus está relacionado a estratégias de arquiteturas orientadas a serviço (SOA), com o objetivo de proporcionar a disponibilização de serviços em um local único e centralizado, alavancando reuso, diminuindo acoplamento entre consumidores e provedores de serviços, o que por sua vez reduz significativamente a dependência entre ambos, de forma que manutenções – que, diga-se de passagem, são inevitáveis – possam ser feitas de forma mais tranquila. Todos estes fatores apoiam na redução de custos, seja pela manutenção facilitada (ou com baixo impacto), seja pelo reuso proporcionado.
Uma arquitetura onde há integração entre aplicações através de serviços, que não conta com o emprego de um barramento de serviços, corre o risco de se tornar o que é conhecido como arquitetura espaguete (veja diagrama representando tal arquitetura à esquerda), onde consumidores de serviços dependem diretamente de provedores de serviços. O nome arquitetura espaguete vem da quantidade de “fios” (dependências) que as múltiplas conexões entre consumidores e provedores vêm a gerar. Neste tipo de arquitetura, uma alteração em um serviço pode afetar diversos consumidores de uma só vez, o que pode envolver não só custos com a adaptação de tais consumidores, como também toda uma coordenação quando da publicação da nova versão do serviço, para que seus dependentes não parem de funcionar.
Um barramento de serviços proporciona desacoplamento entre consumidores e provedores de serviços, já que os consumidores não conhecem diretamente quem está provendo o serviço. Alterações em tais provedores de serviços podem impactar diretamente o ESB, mas em geral são transparentes para os consumidores de serviços. Veja no diagrama à direita uma representação da mesma arquitetura apresentada anteriormente, com o emprego de um ESB.
Além deste fator de extrema importância, o livro Service Design Patterns de Robert Daigneau destaca três principais funções de um barramento de serviços: Roteamento de Mensagens, Tradução de Mensagens e Tradução de Protocolo. Vejam a seguir maiores detalhes sobre cada uma destas funções.
Roteamento de Mensagens
Como vimos anteriormente, ESBs são capazes de encaminhar requisições para serviços e enviar respostas de volta para clientes, com o objetivo de prover aos clientes uma forma de chamar serviços que minimiza a dependência entre ambos. Neste sentido, um ESB funciona como uma camada de indireção que permite que a inclusão, atualização, substituição e remoção de serviços aconteçam sem necessariamente impactar consumidores de serviços.
Para tal, em um ESB são criados o que é conhecido como Virtual Services (serviços virtuais), que se parecem com os serviços reais (contratos semelhantes ou exatamente iguais), mas que simplesmente provêm um endpoint (porta de entrada) para o recebimento e posterior endereçamento de mensagens. Uma vez que o serviço virtual seja acionado, o ESB pode direcionar a mensagem para o serviço apropriado, de acordo com regras definidas. A decisão pelo serviço a ser acionado pode ser tomada com base no conteúdo do pacote SOAP (como por exemplo a tag SOAPAction), ou de acordo com cabeçalhos que seguem a especificação WS-Addressing. Padrões de URI (abordagens REST, por exemplo), ou conteúdos da mensagem em si também podem ser considerados para este fim.
Tradução de Mensagens
Um ESB também pode ser usado para traduzir ou transformar mensagens enviadas por consumidores de serviços para um padrão específico esperado pelos provedores de serviço. São diversas as situações em que se pode desejar fazer tal tradução. Vejamos algumas.
A utilização do padrão Canonical Data Model frequentemente requer a tradução de mensagens entre consumidores e provedores de serviços. Em resumo, tal padrão tem como objetivo minimizar dependências entre aplicações que usam modelos de dados distintos para descrever o mesmo conjunto de entidades (cliente, fornecedor, produto, etc.). Para tal, o padrão prega que deve ser estabelecida uma forma única de descrever cada uma das entidades da companhia, e que tal forma seja utilizada quando aplicações distintas precisem conversar sobre as mesmas entidades. Neste contexto, um ESB pode ser utilizado para transformar mensagens recebidas no formato do modelo canônico estabelecido, para o padrão específico que a aplicação destino espera receber. Confira o cenário descrito no diagrama de sequencia a seguir.

Outro cenário é o caso de composição de serviços. Suponha que para realizar uma determinada tarefa seja necessário acionar dois serviços distintos. Com o objetivo de não impor a cada uma das aplicações consumidoras a responsabilidade de acionar os dois serviços na ordem correta, um ESB pode prover, através de um serviço virtual, uma interface única para a realização de tal tarefa. Os dados requeridos por ambos os serviços seriam unidos nesta interface, que uma vez acionada, disparará a transformação do conteúdo da mensagem recebida, separando os campos específicos que cada um dos dois serviços destino espera receber.
Tradução de protocolo
Considere o seguinte cenário fictício. Diversas aplicações em uma organização precisam se integrar com um pacote de mercado, como um ERP, por exemplo. Tal pacote de mercado provê interfaces para integração, porém por não ser dos melhores ERPs, tais interfaces são em um padrão específico apenas, como por exemplo, JMS. No nosso cenário, o padrão JMS não condiz com o padrão corporativo da organização, que prefere utilizar o protocolo HTTP, com mensagens no formato XML/SOAP. Para que todas as aplicações que precisam se integrar com o tal ERP não precisem se adaptar ao seu padrão, podemos utilizar o ESB como um tradutor de protocolo, responsável por intermediar a comunicação entre as aplicações consumidoras e o provedor de serviços, que no nosso caso é o ERP. Para isso, uma vez que as aplicações consumidoras chamem um serviço virtual criado no ESB, utilizando o padrão adotado na companhia (HTTP com XML sobre SOAP), haverá possivelmente a tradução da mensagem para o padrão esperado pelo ERP e certamente a tradução do protocolo, através da utilização de uma API JMS especifica que será responsável por encaminhar a mensagem para o ERP.
Desta forma, além de não acoplar as aplicações da companhia com um padrão que não é tido como corporativo, ou que muitas vezes pode não ser viável para determinadas tecnologias de aplicações consumidoras, numa eventual substituição do tal ERP, as aplicações que se integram com ele não necessariamente seriam impactadas.
Outras funções
Além das principais funções listadas, existem outras funções que ESBs robustos implementam. Vejamos abaixo um breve resumo sobre algumas delas.
Garantia de Entrega. Se um dado serviço está indisponível, o ESB pode persistir a mensagem em um repositório interno e tentar enviá-la novamente, usando o padrão Idempotent Retry Pattern, já descrito aqui em posts anteriores.
Funções genéricas como autenticação, autorização e logging, tirando dos provedores de serviços tais responsabilidades, além de garantir que determinadas politicas sejam aplicadas de forma consistente na companhia.
Comunicação com ferramentas de monitoramento de negócios (BAM, por exemplo). Uma vez que dados que servem como base para formação de KPIs (Key Process Indicators ou Indicadores Chave de Processos) passem pelo ESB, o mesmo pode direcioná-los para ferramentas que permitem agregar tais informações, de forma a disponibilizá-las em tempo real para visualização.
E assim ficamos por aqui! Até a próxima.
Olá pessoal,
No post anterior vimos as possíveis situações em que uma chamada a um web service pode falhar. Vimos também que uma possível solução seria utilizar estruturas de enfileiramento de mensagens (MSMQ, WebSphere MQ, por exemplo), e que porém, tais soluções não são indicadas para cenários em que a necessidade de entrega ou recebimento de mensagens ultrapasse o escopo da rede interna da organização.
Outro ponto a se considerar, é que tais abordagens caracterizam o que é conhecido com integração near real-time, onde o dado consumido ou provido chega ao seu destino não em tempo real, mais próximo disso. Existem situações em que requisitos estabelecerão que o dado deverá ser obtido ou entregue ao seu destino em tempo real, o que gera uma demanda por abordagens denominadas real-time. Web service é uma abordagem que permite a implementação de integrações real-time, porém, como visto anteriormente, como endereçar as possíveis falhas que podem ocorrer quando da sua utilização?
No livro Service Design Patterns, de Ian Robinson, o padrão Idempotent Retry promete endereçar tais falhas, sendo descrito da seguinte forma:
“Projete o cliente de forma que problemas comuns de conectividade sejam tratados. Quando um erro de conexão ocorrer, reconecte ao serviço e reenvie à requisição. Limite o número de vezes que tais tentativas sejam feitas. Inclua um identificador único em cada requisição de forma que o serviço possa identificar requisições duplicadas…“ [Minha tradução]

Nada é tão simples quanto parece. Ao implementar este padrão diversos aspectos devem ser considerados. Uma vez que o consumidor do serviço tenha positivamente identificado um erro temporário e recuperável de conexão, como os que vimos no artigo anterior, ele deve iniciar sua lógica de reconexão. Consumidores de serviço devem determinar quanto tempo aguardar antes de fazer uma nova tentativa. Tal tempo pode ser nenhum, ou seja, o serviço é chamado novamente logo após o erro, ou pode haver uma pausa, de forma a endereçar problemas temporários que podem ser recuperados automaticamente em poucos segundos. O tempo de espera pode ser o mesmo para todo tipo de erro ou pode ser diferenciado por tipo de erro. Também é importante que uma quantidade máxima de tentativas seja estabelecida, considerando situações de falhas crônicas, ou seja, falhas que não se resolverão sozinhas. Caso contrário, tentativas de entrega de um número de mensagens de forma indefinida poderá sobrecarregar tanto consumidores quanto o provedores do serviços.
O consumidor do serviço também deverá definir como implementar a espera. Uma possibilidade poderia ser chamar novamente o serviço em threads apartadas da principal, de forma a não causar bloqueios. Tal thread seria colocada em modo “sleep” por um certo tempo, após tentativas malsucedidas. Porém, se o intervalo entre as requisições for longo (algo acima de poucos minutos, ou horas), uma melhor abordagem seria persistir a informação necessária para chamada do serviço em uma fila ou um banco de dados, de forma que tal recurso seja lido com certa frequência por um processo que rode em background. Neste ponto é importante considerar que o cliente também poderá falhar entre uma tentativa de envio de outra, de forma que muito provavelmente haverá perdas caso as mensagens pendentes de envio não estejam persistidas para uma possível retomada de processamento.
Complicou? Note que até agora descrevemos apenas o que seria a parte “Retry” do “Idempotent Retry Pattern”. O que seria então a parte “Idempotent”? Segundo Ian, uma requisição idempotente (idempotent) é aquela que produz o mesmo resultado não importa quantas vezes o serviço for chamado. Um exemplo simples é um serviço que exclui informações. Este tipo de serviço é considerado como idempotente, pois, uma vez que se tenha excluído a informação destino, a informação sempre já estará excluída em chamadas subsequentes, de forma que o efeito esperado pela chamada do serviço será sempre o mesmo – a exclusão bem-sucedida. O problema de não implementar serviços de forma que eles sejam idempotentes, é que efeitos colaterais poderão acontecer se um consumidor assumir erroneamente que uma requisição pode ser reiniciada após a perda de uma conexão. O serviço pode ter processado a requisição anteriormente, mesmo tendo perdido a conexão com o seu consumidor.
Ainda segundo Ian, o serviço deve identificar requisições duplicadas e implementar lógicas apropriadas para garantir sua qualidade. Consumidores de serviços devem gerar ou adquirir identificadores únicos para mensagens, que devem ser utilizados pelo serviço para identificar se a mesma mensagem foi processada anteriormente ou não. Se o identificador é novo, a mensagem deve ser processada, caso contrário, um erro pode ser retornado.
Você confere no diagrama de sequencia ao lado uma representação alto nível do padrão Idempotent Retry Pattern, conforme descrito.
Um tópico a parte, porém, é a melhor forma de implementar este padrão, considerando que as lógicas necessárias não sejam repetidas em todas as requisições de serviços de uma ou mais aplicações consumidoras. Frameworks como o WCF (Windows Communication Foundation) da Microsoft, a WS extension WS-ReliableMessaging, bem como outros padrões de implementação para consumidores de serviços descritos no livro, endereçam bem esta questão. Porém, como dito, este é todo um tópico a parte! Neste ficamos por aqui.
Até a próxima!
Olá pessoal,
Nos dois posts anteriores vimos alguns padrões para requisição e reposta de serviços, como por exemplo, os padrões síncronos Request/Response e Asynchronous Response Handler e os padrões assíncronos Request/Acknowledge/Pool e Request/Acknowledge/Callback, que foram discutidos em detalhes. Em todos os padrões para requisição e resposta de serviços que vimos, podemos nos deparar com problemas de indisponibilidade, o que levará a uma falha que será percebida pela aplicação consumidora. Se tal falha não for tratada adequadamente, poderemos ter o nível de confiabilidade (reliability) da solução diminuído, além da possibilidade de termos impactos para o negócio.
Neste post veremos como endereçar esta questão através de um padrão para tratamento de falhas de disponibilidade de serviços, também descrito no livro Service Design Patterns, de Ian Robinson.
Infraestruturas em geral muito dificilmente estão disponíveis em 100% do tempo. Comumente encontramos níveis de disponibilidade estabelecidas por SLA’s de 99.9%, 99.8% e 98%, que implicam em 8,76, 17,52 e 175 horas de indisponibilidade por ano, respectivamente. Menos comuns, porém, são infraestruturas estruturadas para 99.99% ou 99.999%, que representam 52,56 e 5,25 minutos de indisponibilidade por ano, respectivamente. Diversos são os recursos envolvidos para se estabelecer uma infraestrutura de alta disponibilidade e o custo associado é proporcionalmente alto. Mesmo em infraestruturas de alta disponibilidade, como as que garantem 99.999%, ainda temos períodos de indisponibilidade acordados em contrato, que podem calhar no momento exato da chamada de um serviço hospedado em tal infraestrutura.
É preciso ainda considerar que mesmo serviços hospedados na nuvem estão sujeitos à impossibilidade de acesso, seja por uma indisponibilidade prevista em um SLA definido pelo próprio provedor da infraestrutura, ou por indisponibilidade de banda da organização consumidora, ou ainda do seu provedor de internet (ISP), por exemplo.
Neste contexto, como garantir que chamadas à web services (sejam síncronas ou assíncronas) sejam bem sucedidas, independentemente de indisponibilidades de infraestrutura (falhas de rede ou de servidores)? Veremos a seguir mais detalhes sobre as possíveis causas de falhas em requisições de serviços e posteriormente possíveis soluções.
Tipos de Falha
Toleráveis
Em determinadas situações, falhas em chamadas de serviços são toleráveis. Considere, por exemplo, um serviço de busca de restaurantes, acionado pela implementação de uma funcionalidade acessada diretamente pelo usuário. Caso a requisição a este serviço não seja bem-sucedida, o usuário poderá ser notificado, podendo, por sua vez, acionar a mesma funcionalidade novamente, até que uma eventual falha temporária seja corrigida e o resultado esperado seja retornado.
Falha no estabelecimento de conexão
Um consumidor de serviço pode não ser capaz de se conectar ao serviço seja por instabilidade de rede – redes possuem intrinsicamente características de baixa confiabilidade – ou indisponibilidade de servidor (aquele que hospeda o serviço, por exemplo). Tais problemas podem ser temporários – uma instabilidade retomada em poucos segundos – ou crônica – uma indisponibilidade de servidor mais séria, por exemplo, como danos à CPU ou ao disco, em uma infraestrutura não projetada para alta disponibilidade.
Perda de conexão
Um consumidor de serviço pode enviar uma requisição ao serviço com sucesso, porém, pode ter sua conexão perdida enquanto o serviço ainda está processando sua requisição. Se o consumidor do serviço considerar que houve uma falha e enviar a mesma requisição novamente, é possível que dados sejam duplicados no provedor do serviço, o que causaria inconsistências e diminuiria a confiabilidade da solução.
Sobrecarga de servidores
Servidores podem estar sobrecarregados de tempos em tempos, de forma que se tais eventos coincidirem com momentos em que os serviços hospedados por eles são requisitados, haverá a possibilidade de o servidor recusar o estabelecimento da conexão ou não ser capaz de processá-la.
Timeout
Seja por sobrecarga de servidores, ou por qualquer falha que faça com que o servidor destino demore mais para responder do que o normal, um timeout poderá ser lançado no consumidor do serviço. A configuração e um tempo condizente de timeout é de extrema importância, para que o consumidor do serviço não fique bloqueado indefinidamente em tais situações. É importante notar que quando um timeout é lançado no consumidor do serviço, não é possível estabelecer se a requisição foi processada com sucesso ou não pelo serviço, uma vez que o processamento pode ter sido bem-sucedido momentos após a perda da conexão.
Indisponibilidade de URI
Uma vez estabelecido o serviço em produção, tal problema é menos comum. Porém, existem cenários de implementação que podem potencializar situações como esta. Serviços que implementam o padrão REST, por exemplo, frequentemente retornam como resposta URI’s para outras funcionalidades / dados. Tais URI’s podem ou ser inválidas por um bug de implementação ou podem ainda não estar disponíveis no momento da sua requisição. Este último cenário é conhecido como “race condition”, onde o consumidor do serviço compete com o serviço em si. Se o cliente for mais rápido, então links providos na comunicação anterior podem ser inválidos. Porém, se o cliente aguardar ou tentar novamente, as mesmas URI’s serão válidas posteriormente.
Possíveis soluções
A utilização de um sistema de enfileiramento de mensagens, como Microsoft Message Queue ou WebSphere MQ, resolveria o problema, uma vez que tais sistemas implementam o que se chama de garantia de entrega. Com a garantia de entrega (ou guaranteed delivery), quando uma fila remota não está disponível ou acessível, as mensagens são guardadas em uma fila local até que a infraestrutura remota seja restabelecida. Uma vez que a infraestrutura de enfileiramento de mensagens remota esteja estabelecida novamente, as mensagens pendentes serão entregues, podendo ser consumidas pelo sistema destino.
O problema com esta abordagem é que ele requer um protocolo de comunicação específico e proprietário, o pode não ser viável ou acessível para qualquer sistema. Ou seja, a interoperabilidade provida por protocolos de comunicação estabelecidos sobre HTTP, como SOAP e REST, não é mantida em tal abordagem. Além disso, a exposição de sistemas de enfileiramento de mensagens diretamente através de um firewall corporativo para consumidores externos à organização pode implicar na necessidade de abertura de portas, o que junto com outras questões, podem implicar em riscos à segurança.
Como endereçar então falhas em requisições de web servies de forma adequada?
Este é tópico do próximo post, onde será detalhado o padrão Idempotent Retry Pattern.
Até lá!

Olá pessoal,
No post anterior vimos alguns padrões para modelos de processamento síncronos de web services. Vimos também os problemas decorrentes destes padrões, como por exemplo, o acoplamento temporal, que está relacionado à dependência que consumidores de serviços síncronos possuem com relação ao tempo de processamento do serviço, para que a operação seja bem sucedida. Problemas com estouro do tempo de resposta previsto (timeout) podem fazer com que mensagens sejam perdidas, diminuindo a confiabilidade da abordagem. Outros problemas relacionados também são, por exemplo, a dependência com relação à disponibilidade de todos os demais sistemas subjacentes ao serviço (sistemas gerenciadores de banco de dados, rede, servidores de aplicação, sistema de arquivos, etc.). Caso haja qualquer indisponibilidade em tais componentes, consumidores de serviços síncronos são diretamente afetados. Além disso, cargas acima do planejado em serviços que implementam o padrão Request/Response comprometem seu funcionamento e o da infraestrutura que o suporta, uma vez que todas as requisições são processadas assim que recebidas, dado o fato de que o número de requisições a serem processadas em paralelo é, em geral, comandado pelo cliente.
Para endereçar tais questões, no livro Service Design Patterns é sugerido à utilização de padrões assíncronos, e a utilização de message queues seria uma alternativa. Tal mecanismo permite que um cliente envie uma mensagem para uma fila remota em qualquer horário, independentemente do estado operacional do sistema destino. Usualmente, mensagens são salvas em filas locais até que as filas destino estejam disponíveis. Consumidores de mensagens podem proteger recursos dos sistemas remotos pela implementação de mecanismos de “throttling” (afunilamento – controle da taxa de processamento de mensagens), desta forma endereçando requisitos de escalabilidade e disponibilidade de forma mais eficiente do que o padrão síncrono Request/Response visto anteriormente.
Se por um lado a utilização de message queues resolve boa parte dos problemas, por outro, novos problemas podem ser introduzidos. O uso de mensageria, em geral, é aconselhado como uma abordagem interna à corporação, ou seja, não deveria ser exposto diretamente além do firewall corporativo, seja por questões de segurança, seja por acoplar consumidores externos às tecnologias específicas dos sistemas de mensageria.
Para endereçar tais questões, é sugerida então a utilização do padrão de web services Request/Acknowledge, no qual um web service recebe uma requisição, a encaminha para um processo em background (uma thread secundária, por exemplo) e então retorna uma mensagem ao consumidor (acknowledgment) contendo um identificador único para referência futura. Veja como isso funciona no diagrama de sequencia ao lado (direito).
Em diversas situações apenas o recebimento de um “acknowledgment” é suficiente para o consumidor saber que sua requisição foi armazenada para processamento posterior. Porém, em outras situações, um cliente pode precisar de uma resposta, seja, por exemplo, de um processo de longa duração iniciado pela requisição inicial. Imagine um cenário em que uma requisição é enviada contendo uma solicitação de compra. Um retorno (acknowledgment) é enviado para consumidor informando que a solicitação foi recebida e que será processada. Um acknowledgment contendo um ID único serve como um protocolo de recebimento, um recibo. Quando todos os processos de aprovação da compra (sejam automáticos ou manuais) forem finalizados, o que pode demorar horas ou dias, dependendo do processo da organização, o cliente deverá ser informado, para que possa tomar outras ações.
Existem três formas no qual o padrão Request/Acknowledge permite prover respostas assíncronas aos consumidores de serviços. Vejamos a seguir.
Request/Acknowledge/Poll
Neste padrão, uma vez que o cliente possui um acknowledge contendo um identificador único da sua requisição, ele fica constantemente consultando um outro serviço pelo resultado do seu processamento. Veja no diagrama de sequencia ao lado (esquerdo) a ilustração do fluxo deste padrão.
Os problemas decorrentes da utilização deste padrão estão relacionados ao intervalo de tempo em que o cliente efetua consultas pelo resultado final da operação. Se o intervalo de tempo for alto, então poderá haver um atraso entre o tempo em que o resultado final está pronto e o tempo em que ele é obtido. Se for baixo, então uma carga excessiva poderá ser colocada nos servidores envolvidos, além de aumentar trafego de rede.
Request/Acknowledge/Callback e Request/Acknowledge/Relay
No padrão Request/Acknowledge/Callback ao invés do cliente ficar constantemente buscando pelo resultado final da operação, ele é avisado através de um serviço que ele deve prover ou através do encaminhamento para outras partes interessadas. Esta última variação descreve o padrão Request/Acknowledge/Relay. A vantagem de tais abordagens com relação ao Request/Acknowledge/Poll está no tempo em que o cliente receberá a resposta e nos recursos consumidos para tal. Veja no diagrama de sequencia a mais abaixo (à direita) a ilustração do fluxo descrito.
Note que a forma pela qual o processador de requests pode saber para qual serviço ele deve retornar o resultado pode ser tanto através de um endereço provido no request inicial, pelo próprio cliente (veja, por exemplo, WS-Addressing), quanto através de configurações que relacionem o tipo de mensagem / processamento aos destinatários interessados (relay). Quando os destinatários de mensagens de callback são especificados pelo consumidor, cuidados especiais devem ser tomados para que eles não sejam alterados no meio do caminho. Segurança no nível de trans porte ou mesmo WS-Security podem ser usados para mitigar este risco.
Algumas considerações devem ser levadas em conta antes de optar por um dos padrões. Em geral, o padrão Request/Acknowledge/Poll é mais simples de se implementar e de se depurar do que o padrão Request/Acknowledge/Callback. O planejamento de capacity também é diferenciado dentre as abordagens. Se o callback for efetuado sempre para um destinatário apenas, então o número de mensagens de resposta deve ser semelhante ao que se teria no padrão Request/Response. Porém, se o número de destinatários for significante e se houver necessidade de transformar mensagens em formatos específicos para cada destinatário, então, os recursos de infraestrutura necessários devem ser maiores, o que pode implicar em investimentos mais significativos.
O padrão Request/Acknowledge/Callback pode não ser viável em cenários em que o cliente não pode ou não está disposto a prover um serviço para receber retornos, seja pela necessidade de abertura de porta para recebimento de trafego de dados, seja pela falta de recursos para prover infraestrutura necessária. Neste caso, a única alternativa possível para o recebimento de retornos seria o Request/Acknowledge/Poll.
Conclusão
Diante de tantos fatores a serem levados em consideração quando da escolha por um dos padrões mencionados, uma “Trade-off Analysis” pode lhe ser útil para ajudar em sua decisão, dado seu contexto de aplicação.
Neste post ficamos por aqui. Até o próximo!
Olá pessoal,

Neste post gostaria de trazer um assunto bastante recorrente em discussões relacionadas à integração, principalmente quando o meio escolhido para a tal é web service: quando que serviços devem ser síncronos ou assíncronos e quais as vantagens e desvantagens de ambas as abordagens. Além disso, discutiremos também, para o caso de serviços assíncronos, quais os padrões que podemos considerar para retornarmos um determinado resultado para o chamador do serviço, uma vez que o processamento tenha sido concluído. Padrões como Request/Response, Asynchronous Response Handler, Request/Acknowledge/Poll e Request/Acknowledge/Callback serão explicados, bem como o impacto da sua adoção na forma como os serviço são estruturados, o que incorre em esforço de desenvolvimento, timing de atualização e recuperação de informações, além de disponibilidade e escalabilidade do serviço provido. Neste primeira parte (parte 1) focarei em em padrões de serviços síncronos (padrão Request/Response e Asynchronous Response Handler) e no seguinte fecharei a comparação com os padrões de implementação de serviços assíncronos (Request/Acknowledge/Poll e Request/Acknowledge/Callback).
Todas estas questões e diversas outras, como padrões de APIs de serviços, padrões de interação client-service (que discutiremos em parte neste artigo), padrões para gerenciamento de requisição e resposta, padrões para implementação de serviços, padrões de infraestrutura de serviços e padrões de evolução de serviços, todos bastante relevantes e úteis em qualquer discussão que envolva web service como meio de integração, podem ser encontradas no livro Service Design Patterns de Robert Daigneau, que conta com prefácio de nada mais nada menos que Martin Fowler, além de Ian Robinson.

Padrão Request/Response
Um serviço que implementa o padrão Request/Response processa requisições assim que elas são recebidas, retornando resultados em uma mesma conexão de um cliente, de forma síncrona. Uma vez que o cliente submeta uma requisição, usualmente ele não continua com seu processamento até que uma resposta seja retornada. Na utilização deste padrão, frequentemente assume-se que o processamento será concluído em apenas alguns segundos. Dentre os padrões que serão abordados, o padrão Request/Response é mais simples de se implementar, depurar e testar, uma vez que funciona como uma chamada remota de uma operação, com parâmetros de entrada e resposta síncrona. Veja a exemplificação do padrão Request/Response no diagrama de sequencia ao lado.
O padrão Request/Response é indicado para casos em que uma resposta imediata seja necessária, como por exemplo, uma página web que proveja uma funcionalidade para consulta de abertura de vagas, cuja consulta das vagas disponíveis seja provida por um serviço.
Acoplamento temporal (temporal coupling)
A adoção do padrão Request/Response incorre em algumas implicações. Acoplamento temporal é uma delas. O acoplamento temporal remete à dependência do tempo de resposta que um serviço que implementa o padrão Request/Response implica para seu consumidor. No padrão Request/Response é assumido que o serviço sempre poderá processar uma requisição quando esta for recebida e que uma resposta será enviada assim que o processamento for encerrado. A implicação neste caso é que todos os sistemas dos quais o serviço depende (banco de dados, servidores de arquivos, etc.) sempre devem estar operacionais e sempre devem estar aptos a processar requisições imediatamente. Se tais sistemas estiverem indisponíveis, seja por uma falha ou por uma parada programada para manutenção, então as requisições dos clientes poderão ser rejeitadas.
Problemas relacionados ao tempo de resposta do serviço podem ainda acontecer mesmo quando todos os recursos dos quais o serviço dependem estão disponíveis. Uma vez que este padrão requer que requisições sejam processadas assim que recebidas, um grande volume de requisições pode comprometer a capacidade do sistema. Ao adotar tal padrão é preciso compreender a carga típica que o serviço deterá ter e projetar a capacidade de servidores, bancos de dados, rede, etc. de forma a endereçar tais cargas. Uma arquitetura tal deve ser projetada para que seja possível escalar horizontal ou verticalmente tais recursos, uma vez que as demandas de requisição aumentem ao longo do tempo. A adoção dos padrões assíncronos Request/Acknowledge/Poll e Request/Acknowledge/Callback, que serão vistos no próximo post, ajuda a mitigar esta necessidade, uma vez que transfere do cliente do serviço para o provedor do serviço o controle das requisições que serão processadas em paralelo.
O acoplamento temporal também traz implicações relacionadas ao tempo em que o consumidor do serviço aguardará por uma resposta antes que um timeout seja lançado. Nestes casos, uma vez que o processamento já tenha sido iniciado pelo serviço, a resposta não seria recebida pelo cliente, implicando em perda de sincronismo ou inconsistência de dados. As razões para que um serviço demore mais para responder do que o tempo planejado são inúmeras. Atividades que requeiram maior I/O, altos níveis de trafego de rede são exemplos comuns. Neste ponto, mais uma vez os padrões de serviços assíncronos são mais vantajosos.
Client-side Blocking / Asynchronous Response Handler
Por padrão, clientes de serviços que implementam o padrão Request/Response aguardam pela resposta do serviço invocado sem realizar outras operações no meio tempo. Esta característica é conhecida como “Client-side Blocking”, uma vez que o cliente fica bloqueado até que uma resposta do serviço chamado seja retornada. Para casos em que se deseje aproveitar o tempo de espera de um serviço processando outras atividades, pode-se utilizar o padrão denominado “Asynchronous Response Handler” em conjunto com o padrão Request/Response, o qual permite que o cliente efetue requisições para um serviço Request/Response, delegando o recebimento da resposta para um thread apartada da thread principal, de forma que outras atividades sejam executadas na thread principal logo após a requisição do serviço. Veja no diagrama de sequencia mais abaixo a ilustração desta implementação.
É importante destacar que este padrão também não garante que respostas não sejam perdidas, como já descrito anteriormente.

Por todos os motivos apresentados, podemos concluir que o padrão Request/Response deve ser usado apenas quando for possível garantir que o tempo médio de resposta do serviço seja relativamente baixo, e que o cliente será projetado para tolerar perda de respostas. No próximo post veremos como os padrões assíncronos ajudam a mitigar os riscos relacionados ao acoplamento temporal, à perda de sincronismo e inconsistência de dados, além de permitir que o cliente não fique bloqueado enquanto aguarda o resultado do processamento.
Neste post ficamos por aqui. Até o próximo!
Olá pessoal!
Quantas vezes nos deparamos com as frustrantes situações em que uma determinada solução tecnológica, aderente aos padrões corporativos e que melhor atende aos requisitos não-funcionais estabelecidos, não pode ser aplicada em um projeto, seja por não haver tempo hábil, por exemplo, levando a adoção de abordagens que nem sempre trazem bons resultados a longo prazo?
Neste post gostaria de compartilhar um trecho de um podcast publicado pelo Oracle Technology Network, em seu canal ArchBeat Pod Cast, onde Thomas Erl – best selling SOA author, explica como tais situações normalmente se originam. Segundo Thomas, existe o que ele chama de miopia na perspectiva considerada na avaliação dos resultados de projetos, onde acaba-se sendo considerado apenas prazo, orçamento e atendimento dos requisitos funcionais como critérios que definem se um projeto foi ou não bem-sucedido, deixando de lado a qualidade da arquitetura implantada, o que acaba resultando em defasagem tecnológica, projetos que geram silos de informação e aplicações que atendem apenas a um propósito, consequentemente aumentando o custo de propriedade do produto produzido pelo projeto. Confira abaixo.

“… the criteria organizations use to evaluate project team performance, I think there still a lot of tactical emphasis on determining what was and what was not a successful project and by that I mean did it come under budget, did it come on time, did it meet functional requirements and those tend to be focal points when projects are assessed and it is easy to lose sight of the importance of what you are designing and the long term implications of what you are building when you are focusing more on the timeline, the budget and meeting the functional requirements within the primitives of that budget and timeline. And it is easier to meet those goals as you are being assessed by bypassing proper technology architecture and just getting developers to build something that works as per the immediate functional requirements and if you as a project manager are not being assessed based on the quality of the technology architecture, its compatibility with the surrounding IT enterprise architecture, its compliance to predefined standards, then there is no means of assessing that or regulating that, then there is no motivation to really emphasize that or make that part of the project cycle, because it will just use up more time and resources and will go against the other points which you are being evaluated. So I think that assessment from a strategic perspective is also lacking in some IT environments and that is to their detriment in the long term, because it is not part of how they assess project, applications, delivery projects, then those projects do became very much silo based, single purpose and then, consequently, impact the subsequent governance and ownership burden that IT enterprise assumes and it is that shortsightedness that I think also leads to situations like that where IT architects are not given the level of responsibility that they should.”
A não mudança de tal cultura leva a geração de conflitos constantes entre os times de projetos e os times de arquitetura, pelos seus diferentes interesses. A convivência em projetos com tais conflitos acaba não sendo saudável para nenhum dos envolvidos, nem tão pouco para o próprio projeto. Decisões de design que deveriam ser facilmente tomadas precisam ser escaladas para a gestão, o que acaba gerando ainda mais desgaste – quando não há politicagem – atrasos e posterior pressa para implementar o design decidido.
E por esta razão, acredito que organizações hoje tenham chegado a um nível de maturidade onde já enxergam a necessidade e os benefícios da adoção das disciplinas de arquitetura, porém, ainda precisam evoluir para um próximo nível, onde estarão aptas a de fato empregar eficientemente tais áreas em seus projetos.
Olá pessoal!
Neste artigo gostaria de compartilhar um trecho do livro “The Clean Coder”, de Robert C. Martin (Uncle Bob), que trata de ética e conduta profissional para nós, profissionais de desenvolvimento de software. O trecho aborda dois tópicos de extrema relevância. O primeiro é sobre decisões políticas ou baseadas apenas em questões financeiras de curto prazo e o segundo é sobre a responsabilidade que um profissional de software responsável por decisões técnicas (seja um arquiteto de software ou qualquer outro papel correspondente) tem ao assumir tal papel.

Em um projeto, diferentes stakeholders demandam diferentes requisitos não-funcionais, muitas vezes conflitantes entre si. Gerentes de projetos, por exemplo, em geral priorizam o prazo estabelecido com as áreas de negócios (time-to-market). Áreas que manterão o sistema (que aplicação mudanças evolutivas / corretivas, por exemplo), demandam um sistema que seja modificável (modifiability). Um sistema projetado para ser modificável, em geral, leva mais tempo para ser construído. E esta aí o primeiro e mais comum conflito. A figura mais abaixo (extraída de materiais do Software Engineering Institute – SEI) representa este cenário.
Neste contexto, se por um lado um gestor tem a responsabilidade de não tomar decisões baseadas apenas em questões políticas e financeiras de curto prazo, um arquiteto de software tem o dever, a responsabilidade, de apontar de todas as formas possíveis, os possíveis riscos que uma determinada decisão de projeto (seja de design, por exemplo) pode apresentar.
A história descrita por Bob Martin fala de uma decisão política / financeira, tomada em um lançamento de uma nave aeroespacial, que não levou em consideração os riscos levantados pelos engenheiros responsáveis, culminando na perda de sete vidas. Veja a seguir.
At 11:39 AM EST on January 28, 1986, just 73.124 seconds after launch and at an altitude of 48,000 feet, the Space Shuttle Challenger was torn to smithereens by the failure of the right-hand solid rock booster (SRB). Seven brave astronauts, including high school teacher Christa McAuliffe, were lost. The expression on the face of McAuliffe’s mother as she watched the demise of her daughter nice miles overhead haunts me to this day.
The Challenger broke up because of hot exhaust gasses in the failing SRB leaked out from between the segments of its hull, splashing across the body of the external fuel tank.
… The engineers at Morton Thiokol who designed the SRB had known that there were problems with the O-rings [SRB component that was identified as the cause of the incident], and they had reported those problems to managers at Morton Thiokol and NASA seven years earlier.
… The engineers had designed a repair for the problem, but implementation of that repair had been long delayed.
… In short, the engineers knew that the risk was too high. The engineers acted on that knowledge. They wrote memos raising giant red flags. They strongly urged Thiokol and NASA managers not to launch. In an eleventh-hour meeting held just hours before the launch, those engineers presented their best data. They raged, and cajoled, and protested. But in the end, the managers ignored them.
… Despite all the protest and memos, and urgings of the engineers, the managers believed they knew better. They thought the engineers were overreacting. They didn’t trust the engineers’ data or their conclusions. They launched because they were under immense financial and political pressure. They hoped everything would be just fine.
These managers were not merely foolish, they were criminal. … They made a decision they had no right to make. They usurped the authority of people who actually knew: the engineers.
But what about the engineers? Certainly the engineers did what they were supposed to do. They informed their managers and fought hard for their position. They went through the appropriate channels and invoked all the right protocols. They did what they could, within the system – and still the managers overrode them.
E por fim, Bob Martin conclui: ”… As an engineer, you have a depth of knowledge about your systems and projects that no managers can possibly have. With that knowledge comes the responsibility to act.”
É claro que como arquitetos de software muito dificilmente estaremos envolvidos em decisões que poderão implicar em vida ou morte de pessoas. Porém, é certo que determinadas decisões mal tomadas implicarão, a médio/longo prazo, em custos de manutenção e de propriedade mais altos, tempos de entrega mais longos (time-to-market) e em requisitos não atendidos. Quando tais problemas perduram, toda uma área de TI passa a ser mais um custo necessário, ao invés de uma área estratégica para o crescimento da companhia.
|
|