Friday, June 29, 2012

Padrões EAA (Enterprise Application Architecture)



 O que significa EAA?

Enterprise Application Architecture é uma das técnicas mais comuns de desenvolvimento, onde as partes complexas da aplicação são desmembradas em camadas.

Apresenta como principais benefícios: isolamento, independência, reutilização de Código, desacoplamento  e fácil entendimento (código limpo e sucinto).

Os padrões EAA são muito comuns em softwares que envolvam grande volume de dados, acesso concorrente e integração com outros sistemas.
Exemplos:  Payroll, Supply Chain Management, ERP, etc...

As três camadas principais e mais encontradas nesses tipos de sistema são:
                Apresentação: Controla a interação entre o usuário e o software
                Domínio: Controla as regras de negócio do sistema.
                Fonte de Dados: Controla as comunicações com o banco de dados.




 Exemplos de Padrões EAA:

a)       Domain Logic

·         Transaction Script:
Organiza a lógica de negócios através de procedimentos onde cada procedimento trata de um request único da apresentação.
Por exemplo, se a precisamos matricular um aluno em uma determinada turma, a lógica para verificar quantidade de vagas na turma, requisitos do aluno, horários conflitantes com outras matérias do aluno e etc.. deve, estar compreendidas na mesma transação MatricularAluno(aluno, turma)

·         Table Module:
               Uma única instância que lida com a lógica de negócios para todas as linhas em uma tabela ou exibição de banco. Permite o empacotamento de dados e  a sua utilização deve se dar quando se deseja manipular dados tabulares usando um RecordSet.

·         Domain Model:
Um modelo do domínio que incorpora tanto o comportamento quanto os dados e contém os objetos que modelam a área de negócio.
Um modelo de domínio bem pensado serve como uma representação clara da estrutura conceitual do domínio do problema e, portanto, é imprescindível para garantir que todos os interessados estejam alinhados com escopo e significado.

b)       Service Layer

Camada de serviços que estabelece um conjunto de operações disponíveis e coordena a resposta da aplicação em cada operação.

O benefício da camada de serviço é que define um conjunto comum de operações, disponível para muitos tipos de clientes e coordena a resposta da aplicação em cada operação.
Na Arquitetura Orientada a Serviços (SOA), a camada de serviço é a terceira camada em um modelo de cinco camadas de abstração.

O modelo consiste em Object Layer, Component Layer, Service Layer, Process Layer e Enterprise Layer. [3] A camada de serviço pode ser considerada como uma ponte entre as camadas superior e inferior.



c)        Repository

Media as camadas de domínio e mapeamento de dados usando uma interface de coleção, para acessar objetos de domínio. Utilizado para atingir um ou mais dos seguintes objetivos:

·         Maximizar a quantidade de código que pode ser testada com  automação e isolar a camada de dados para suportar o teste de unidade.
·         Você pode acessar a fonte de dados de diversas localidades e deseja aplicar gerenciados centralmente, regras de acesso consistente e lógica.
·         Implementar e centralizar uma estratégia de cache para a fonte de dados.
·         Melhorar a manutenção do código e a legibilidade, separando a lógica de negócios a partir de dados ou lógica de acesso ao serviço.
·         Usar entidades empresariais que são fortemente tipadas para que você possa identificar os problemas em tempo de compilação em vez de em tempo de execução.
·         Associar um comportamento com os dados relacionados. Por exemplo, você deseja calcular campos ou impor relações complicadas ou de regras de negócios entre os elementos de dados dentro de uma entidade.
·         Você deseja aplicar um modelo de domínio para simplificar a lógica de negócios complexos.




d)       Active Record

Um objeto que envolve uma linha de tabela ou view, encapsula o acesso a banco de dados e adiciona lógica de domínio sobre esses dados.

A interface de um certo objeto deve incluir funções como por exemplo Inserir(Insert), Atualizar(Update), Apagar(Delete) e propriedades que correspondam de certa forma diretamente às colunas do banco de dados associado.

Uma instância de um objeto é amarrada a um único registo na tabela.  A classe de embrulho implementa os métodos de acesso(setter e getter) ou propriedades para cada coluna na tabela ou visão.
Este padrão é comumente utilizado por ferramentas de persistência de objetos e em mapeamento objeto-relacional. Geralmente as relações de chave estrangeira serão expostas como uma instância do objeto do tipo apropriado por meio de uma propriedade.

Implementações do conceito podem ser encontradas em vários Frameworks para diversos ambientes de programação. Por exemplo, se um banco de dados possui a tabela produtos e o padrão de projeto Active Record é implementado na classe Produto, o pseudo-código:

produto = new Produto()
produto.nome = "Produto exemplo"
produto.valor = 123.45
produto.save()

Irá criar um novo registro na table produtos com os valores fornecidos sendo grosseiramente equivalente ao comando SQL:

INSERT INTO produtos (nome, valor) VALUES ('Produto exemplo', 123.45);



e)       Unity of Work

Um dos padrões de design mais comuns em EAA, este padrão "mantém uma lista de objetos afetados por uma transação e coordena a escrita de alterações e a resolução dos problemas de concorrência.".

Este padrão aparece em quase todos os frameworks de persistência mais comuns no mercado de hoje. Por exemplo: a interface ITransaction em NHibernate, a classe DataContext no LINQ to SQL, e a classe ObjectContext no Entity Framework.

Se você fosse construir o seu próprio Unity of Work, seria provavelmente algo parecido com esta interface:
public interface IUnitOfWork {
  void MarkDirty(object entity);
  void MarkNew(object entity);
  void MarkDeleted(object entity);
  void Commit();
  void Rollback();
Sua classe deve conter métodos para marcar entidades como alteradas, novas ou excluídas e para confirmar ou reverter todas as mudanças.
De certa forma, você pode pensar no Unit of Work como um lugar para despejar todo o código de manipulação de transação.
As responsabilidades da Unidade de Trabalho são:
Gerenciar as transações.
Ordenar as inserções de banco de dados, exclusões e atualizações.
Impedir duplicação de atualizações.


MVC 3 Razor - Multi Idiomas

Muitas vezes nos encontramos em uma situação aonde o sistema que desenvolvemos será utilizado por usuários ao redor do mundo todo, de culturas diferentes. O requisito "suportar N idiomas" é muito comum para aplicações web.

Estes dias estive pesquisando maneiras alternativas para criar uma aplicação multi idiomas.
A primeira idéia que vem é utilizar os recursos de Culture, Global Resources e Local Resources do .NET Framewrok.

Existe muito material disponível na web sobre como utilizar os arquivos .resx para gerar texto dinâmicamente de acordo com a cultura do usuário. Para saber como utilizá-los, primeiro precisamos entender o conceito de Cultura do .NET.


Cultura nada mais é do que a combinação do idioma que é falado referente a sua localização geográfica. Isso inclui a forma de exibir as datas e valores monetários. Exemplos de cultura:

pt-BR – Português falado no Brasil

en-US – Inglês falado nos Estados Unidos


Os  Global Resources e Local Resources  são arquivos .resx que irão armazenar o texto a ser exibido para cada cultura. O que diferencia um do outro é a estrutura de diretórios.


Global Resources: São as informações do seu site como um todo, como por exemplo, o título da página.

Local Resources: Se referem ao conteúdo específico de uma página do site.

No ASP.NET MVC suas Views irão utilizar os recursos locais, porém, seus Controllers terão acesso apenas aos recursos globais.


Utilizando Recursos Globais

O primeiro passo é criar o diretório dos recursos globais, devemos lembrar que os recursos acessados pelas views (local resources) não estarão incluídos nesse diretório. Clique com o botão direto na raiz do seu projeto ASP.NET MVC, acesse Add ASP.NET Folder e em seguida escolha App_GlobalResources.



Dentro do diretório criado vamos adicionar um arquivo de recurso chamado Layouts.resx e preencher os textos a serem exibidos. Repare que cada texto ("Value") deve estar associado a uma chave("Name").


Agora, em nosso Controller vamos criar um método para obter o texto definido no arquivo Layouts.resx de acordo com o idioma e cultura utilizado.


Obs: Substituir "titulo" pelo parâmetro "key".

Se você prefere não ter que adicionar este método a todos os seus controles crie um classe base e faça com que seus controles herdem as propriedades desta classe. Como mostra a figura abaixo, aonde o controller de Usuarios faz referência ao controle base.



Até o momento foi criado apenas um arquivo global de recursos, que  é o recurso padrão do sistema.
Agora vamos criar um novo arquivo no mesmo diretório com o nome “Layouts.en-US.resx”.
Este arquivo possui no nome uma string de cultura("en-Us"), para indicar que ele será responsável pela tradução para o inglês americano.


Utilizando Recursos Locais


Os textos gerados pelos controllers já estão sendo traduzidos, mas para as Views, os arquivos de recursos globais não podem ser utilizados.
Para implementar a tradução em uma View , precisamos usar os Recursos Locais.
Clique com o botão direto no diretório da View, selecione Add ASP.NET Folder e em seguida escolha App_LocalResources.
Atenção, você deve criar um arquivo de recurso com o mesmo nome da View que irá utilizá-lo(no exemplo temos o arquivo Index.chtml no grupo de views, o arquivo de resource deve se cahamar Index.resx). Adicione a string de cultura para obter outras linguagens, assim como foi feito com os recursos globais.

A figura abaixo demonstra um exemplo:






Para recuperar o texto do arquivo de resources dentro da nossa view de uma maneira limpa, vamos criar uma classe Extension.cs e referênciá-la no web.config do nosso projeto, para que todas as páginas sejam capazes de interpretar a chamada do método LocalResources (responsável por retornar o texto na cultura correta). Segue abaixo a figura com um exemplo:




Agora para recuperar o texto dentro da view basta adicionar o código @this.LocalResources("chave") como mostra a imagem abaixo.



Um dos maiores problemas desse tipo de abordagem é o reaproveitamento dos arquivos .resx.

Caso haja outra camada de apresentação, será necessário criar novos recursos globais e locais. As própias views não conseguem compartilhar recursos entre si, gerando uma infinidade de arquivos .resx para cada controller.

Pensando nisso, criei uma nova camada no projeto, que será responsável por traduzir os textos de uma maneira diferente.

A intenção dessa nova bordagem é ter um único arquivo .xml que conterá todos os textos a serem exibidos no site, centralizando os textos para serem utilizados por N-camadas do sistema.
A classe Controller.cs fica responsável por carregar na cache a tabela de textos de acordo com o idioma selecionado para o usuário. Temos também a classe HttpCache responsável por encapsular o acesso aos objetos da cache e as operações de leitura e gravação. A estrutura do projeto e do arquivo XML que armazena as linguagens estão na imagem abaixo:



Dentro do nosso controlador temos o método responsável por retornar o texto para a camada de apresentação.


Temos também o mpetodo responsável por carregar a tabela com base no arquivo xml, de acordo com a cultura solicitada.


Tendo criada nossa nova camada de tradução. Agora basta adiciona-la como referência no nosso projeto MVC para podermos utilizar tanto nos Controllers, Models e Views. Podemos também adicionar a referência em outras camadas.

Para usarmos em um controller ou model precisamos apenas adicionar o código: Traducao.Controller.Texto(id);

Para usarmos nas Views em razor, adicionamos o código: @Traducao.Controller.Texto(id)

O exemplo acima demonstra uma situação aonde é possível alterar o idioma da aplicação inteira em tempo de execução, através do arquivo web.config. O exemplo pode ser facilmente modificado para modificar o idioma de acordo com as preferências do usuário.
O maior problema nesta abordagem aparece quando pensamos nas Data Anottations dos nossos modelos.
As validações geradas automaticamente pelos modelos são compiladas e não podem ser dinâmicas.

Por exemplo:

namespace IntcomProjectManager.Models.Facades
{
    public class Usuarios: DataAccessLayer.Usuarios
    {
        [Required(ErrorMessage = "*")] //Não pode ser dinâmica referenciando Traducao.Controller.Texto
        public  string Nome { get; set; }
        [Required(ErrorMessage = "*")]
        public  string Email { get; set; }
        [Required(ErrorMessage = "*")]
        public  string Cpf { get; set; }
        [Required(ErrorMessage = "*")]
        public  string Senha { get; set; }
    }

Para acabar com este problema andei pesquisando na internet e achei um excelente post do Jonas Gauffin (http://blog.gauffin.org/2011/09/easy-model-and-validation-localization-in-asp-net-mvc3/) ele disponibilizou uma interface para ser implementada que permite que usemos arquivos XML, bancos de dados ou arquivos de resources para gerar Data Annotations com localização de uma maneira limpa e eficiente.