Mostrando postagens com marcador conceito. Mostrar todas as postagens
Mostrando postagens com marcador conceito. Mostrar todas as postagens

domingo, 2 de fevereiro de 2014

Composite Pattern: Um exemplo prático e usável

O padrão de projeto Composto -- conhecido como Composite Pattern -- é um padrão em que um cliente lida com um outro objeto o tratando como apenas um. E este único objeto geralmente possui uma coleção de objetos de um mesmo tipo.

É mais fácil demonstrar um exemplo prático do que explicar a teoria deste padrão. Vamos supor um cenário (que eu mesmo já enfrentei algumas vezes) para lidar com tratamento de erros de um sistema.

Imagine que queremos logar todos os erros de um sistema num arquivo de texto e, dependendo da criticidade do erro, enviar um email ao administrador do sistema. Com este cenário, conseguimos extrair 2 objetos (logar em texto e enviar email) que possuem um denominador em comum:

LidarComUmErro

Com o padrão Composite, conseguimos que os clientes de um componente lidem com uma coleção como se estivessem lidando com apenas um objeto. Dessa forma, poderíamos criar dois tipos de objetos que compartilham uma ideia parecida (LidarComUmErro):


public class LogArquivoTexto
{
 public void LogarErro(object erro)
 {
  // lógica para salvar os detalhes do erro em um arquivo de texto
 }
}


public class NotificadorDeErroCritico
{
 public void NotificarErroCritico(object erro)
 {
  // lógica para enviar a notificação de erro crítico por email
 }
}


Se usarmos a beleza da abstração, conseguiríamos uma interface como a seguir:

public interface GerenciadorDeErros
{
 void GerenciarErro(object erro);
}

Nós abstraimos a ideia geral dos componentes que logam um erro num arquivo e enviam um email sobre um erro, correto?

Com algumas modificações, conseguiríamos que os dois componentes realizassem a interface de GerenciadorDeErros:


public class LogArquivoTexto
 : GerenciadorDeErros
{
 public void GerenciarErro(object erro)
 {
  LogarErro(erro);
 }
 
 public void LogarErro(object erro)
 {
  // lógica para salvar os detalhes do erro em um arquivo de texto
 }
}


public class NotificadorDeErroCritico
 : GerenciadorDeErros
{
 public void GerenciarErro(object erro)
 {
  LogarErro(erro);
 }
 
 public void NotificarErroCritico(object erro)
 {
  // lógica para enviar a notificação de erro crítico por email
 }
}


O que temos até agora  é a base para usarmos o padrão Composite. Precisamos de um cara que nos permita trabalhar com nossos dois componentes como se fossem um só:


public class GerenciadorDeErrosDoMeuSistema
 : GerenciadorDeErros
{
 public void GerenciarErro(object erro)
 {
  // O que fazemos agora?!?
 }
}

Sem mais delongas, a implementação que nos permitiria trabalhar com uma coleção parecendo que é apenas um objeto seria como a seguir:


public class GerenciadorDeErrosDoMeuSistema
 : GerenciadorDeErros
{
 private IList<GerenciadorDeErros> _gerenciadoresDeErros;
 
 public GerenciadorDeErrosDoMeuSistema()
 {
  _gerenciadoresDeErros = new List<GerenciadorDeErros>();
  _gerenciadoresDeErros.Add(new LogArquivoTexto());
  _gerenciadoresDeErros.Add(new NotificadorDeErroCritico());
 }
 
 public void GerenciarErro(object erro)
 {
  foreach(GerenciadorDeErros gerenciadorDeErro in _gerenciadoresDeErros)
  {
   gerenciadorDeErro.GerenciarErro(erro);
  }
 }
}


E este objeto seria usado mais ou menos como a ideia seguinte:

try
{
 ...
}
catch(Exception ex)
{
 GerenciadorDeErros gerenciadorDeErros = AlgumaFormaParaObterOGerenciadorDeErros();//
 gerenciadorDeErros.GerenciarErro(ex);
}

Pronto!

Espero ter passado de forma clara um exemplo prático e usável deste padrão.

quarta-feira, 29 de maio de 2013

HTML, CSS, Javascript - "Baixo Acoplamento e Alta Coesão" (Sim, Por Aqui Também!)

Por causa do Colabre, eu retomei muitas questões de desenvolvimento com HTML, CSS, Javascript -- todos esses assuntos relacionados a front end. E esse post foi inspirado por uma reescrita pesada nas telas. O que gostaria de dizer é:

Evite definir as mesmas classes de elementos HTML que têm propósitos de estilo e Javascript!

Por exemplo, uma classe link-especial de um elemento <a href="/exemplo" class="link-especial">Meu Link Especial</a> não deveria ser usada para deixar esse elemento vermelho, com uma borda preta em baixo e azul em cima e fazer com que elementos dessa classe, sempre que clicados, enviem uma requisição ajax para registrar um log.


.link-especial
{
 border-top: 1px solid blue;
 border-bottom: 1px solid black;
 color: red;
}

(Ok. Eu sei que esse estilo é horrível.)

E

$(".link-especial").click(function(){
 // enviar requisição ajax para registrar log...
});

Talvez para você seja óbvio o motivo de não misturar classes do DOM com propósitos diferentes. Ou talvez nunca tenha tido problema com isso. De toda forma, evite para manter uma boa separação entre estilização e de outros aspectos.

No meu caso, por exemplo, estou mudando todo o Colabre para usar o framework Bootstrap. Se não tivesse separado bem as classes de estilo e as de uso com javascript, teria um trabalho enorme para remover os estilos não mais usados. Você pode usar um prefixo para as classes de uso com javascript -- js-link-logger, por exemplo.

Os princípios de "baixo acoplamento e alta coesão" muito conhecidos na orientação a objetos não são exclusivos ;)

terça-feira, 11 de dezembro de 2012

Introdução à Abordagens para Integrações entre Sistemas

Pretendo iniciar uma pequena série de posts sobre Arquitetura de Integrações com foco na abordagem da Arquitetura Orientada a Eventos, conhecida como EDA em inglês (Event Driven Architecture).

Pela minha experiência profissional (que é 95% Microsoft), notei que é uma arquitetura pouquíssimo conhecida. E é legal notar que quando a explico ou até mesmo monto algum protótipo dela, as pessoas gostam. Os projetos em que pude usá-la foram bem sucedidos, e a curva de aprendizado dos desenvolvedores que a implementaram foi pequena -- ela é uma arquitetura relativamente simples.

Se você não faz a menor ideia sobre o que estou falando, essa arquitetura tem tudo a ver com sistemas de mensageria ou message queuing systems (já ouviu falar sobre MSMQ - Microsoft Message Queuing?). Outros termos relacionados comumente usados são enfileiramento, filas, canais, etc.

Antes de mergulhar no assunto, gostaria de dar uma breve introdução aos tipos mais comuns de integração entre sistemas.

Transferência de Arquivos

Uma aplicação coloca um arquivo em determinado local (conhecido entre as aplicações participantes) para que outra aplicação use-o (leia, escreva). A transferência de arquivo promove um bom desacoplamento e é relativamente fácil entrar num acordo sobre um formato (geralmente em texto puro). Os problemas começam quando questões sobre quem e quando deve-se apagar o arquivo, por exemplo. Outra desavantagem é que essa arquitetura geralmente é usada apenas para processamento em lote. Seria difícil fazer uma integração do tipo requisição/resposta nesse formato (request/reply). Por exemplo: liste todos os usuários do departamento de marketing.


Banco de Dados Compartilhado

É difícil encontrar alguém que nunca tenha feito isso. Eu julgo que o pior é adaptar (ou até mesmo modelar) um schema para mais de uma aplicação. Um atributo em uma aplicação é do tipo numérico, mas no outro é um texto; os campos sempre sobram para alguém; etc. e por exemplo. Um ponto muito negativo nessa abordagem é o acoplamento temporal -- se o banco cai, o acesso é interrompido.


Chamada Remota de Procedimento (RPC)

Chique o nome, não? Honestamente, eu acho a pior de todas. O acoplamento é tremendo, mudanças nos contratos são caóticas e cria-se uma rede de dependências muito complexa. A performance é um fator muito crítico aqui também. Acredito que a palavra que melhor descreve essa abordagem é arcaica.


Web Services

Essa abordagem é a "É difícil encontrar alguém que nunca tenha feito isso - versão II". Eu acho que é um dos padrões mais usados hoje em dia para integração entre aplicações. É uma abordagem que já está bastante madura e tem uma interoperabilidade ótima, ou seja, qualquer linguagem de programação hoje tem suporte à troca de mensagens no formato SOAP (que é estruturado em XML). Contudo, eu acho que ela sofre da síndrome da confusão entre conceito e técnica quando o assunto é Barramento de Serviços. Já testemunhei muita gente falando que "esse é meu Barramento de Serviços" (ou Service Bus), quando na verdade era um monte de Web Services (ou até mesmo serviços WCF). Mas isso é um outro assunto e muito extenso porque entra governança, diretórios de serviços, etc.
Voltando às vantagens e desavantagens dessa abordagem. Web services sofrem um pouco das mesmas desavantagens de um banco de dados compartilhado -- acoplamento temporal. Se o serviço cai, ninguém usa. Outro ponto (com defensores e ofensores) é a sincronicidade: web services são síncronos por natureza. O tempo de resposta da sua aplicação consumindo um web service vai depender do tempo de resposta da aplicação a qual está fazendo a requisição.


Mensageria

É a minha abordagem preferida para a maioria dos cenários de integração entre sistemas. É relativamente fácil, promove um bom desacoplamento (principalmente temporal), é bastante tolerante à falhas, e é a menos dolorosa e mais barata (sem contar com as soluções comerciais que são caríssimas -- TIBCO, por exemplo) para escalar porque a escalamos horizontalmente muito facilmente (pretendo falar mais sobre isso em posts futuros). Ela tem também as vantagens e desavantagens da assincronicidade.



Aí está um resumo bem enxuto das abordagens mais conhecidas para integrações de sistemas.

Se você se interessou por esse assunto ou quer se aprofundar mais, eu recomendo fortemente o livro Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions (Gregor Hohpe e Bobby Woolf). Apesar de ser um livro de 2003, ainda é uma referência no assunto de integrações usando sistemas de mensagens com muitos exemplos em Java e C#.