Um modelo arquitetural…

Nos últimos tempos tenho recebido algumas perguntas de como modelo meus projetos, quais design patterns utilizo e como divido minha aplicação em camadas. Estas perguntas possuem apenas uma resposta: depende do caso.

Cada aplicação merece um modelo arquitetural diferente do outro. Cada aplicação exige diferentes design patterns. Cada aplicação funciona de um jeito. Nenhuma aplicação é igual a outra, assim como os dedos das mãos não são iguais.

Mas, como esta pergunta não possui uma resposta certa ou errada, gostaria de demonstrar um modelo arquitetural que me agrada bastante. Este modelo mescla alguns design patterns e alguns princípios de projetos orientados a objetos. A arquitetura da aplicação é a demonstrada abaixo.

architecture

Para fazer o download do exemplo clique no link ao lado: http://code.msdn.microsoft.com/Um-modelo-arquitetural-ef9a470e

Camadas e Padrões:

- A camada Model fica responsável por conter todas as entidades e interfaces relevantes para composição das camadas de dados e negócio.

- A camada Business contém as regras de negócio da aplicação e orquestra as chamadas entre as demais camadas da aplicação; indicando a ordem de execução e quais métodos devem ser executados.

- Service agrupa os serviços da aplicação, instanciando os componentes da camada Business para execução das regras da aplicação e expondo seus métodos para as camadas de apresentação.

- E a camada Data corresponde às rotinas de acesso a dados, abstraídas no pattern Data Access Layer (DAL). Esta camada deve isolar as tecnologias de acesso a dados das demais partes do sistema. A vantagem do uso desta camada é a facilidade de modificar a tecnologia armazenamento de dados sem impactar em todo o projeto. Isolar as dependências a serviços externos da aplicação é uma boa prática, pois torna a aplicação mais fácil de ser alterada quando necessário.

- Presentation corresponde à camada de apresentação da aplicação. Esta arquitetura permite que diferentes tipos de aplicações (Windows 8, ASP.Net, Windows Phone, Console, etc) façam uso dos recursos providos pelo serviço. Esta camada se comunica com o restante da aplicação através de chamadas aos métodos expostos pela camada de serviço.

- O padrão Factory fornece uma interface para a criação de objetos. Seu objetivo principal é compor objetos que as demais classes não precisam obter conhecimento sobre seu funcionamento. Neste exemplo, as classes de negócio dependem de uma classe Factory que será responsável por criar as instâncias dos objetos que a classe de negócio depende.

- De maneira adicional, para composição das instâncias das classes de regras de negócios, são utilizados recursos de injeção de dependências para tornar nossa solução ainda mais desacoplada, sem limitar seu funcionamento a uma única Factory. Este recurso é vantajoso, pois permite a mudança de todo o comportamento da aplicação apenas alterando um arquivo de configuração, indicando uma Factory diferente daquela que estava parametrizada inicialmente.

Injeção de Dependências

O uso do princípio da injeção de dependências é ideal quando precisamos manter o nível de acoplamento entre os módulos do sistema. Com o uso de injeção de dependências, as dependências entre os objetos não é definida programaticamente, de forma “chumbada” no código. As dependências são configuradas na estrutura da aplicação (geralmente em arquivos XML), para facilitar a manutenção da aplicação. Outro ponto chave para o uso de injeção de dependências é não programar para implementações e sim para interfaces; explorando o uso de polimorfismo e diminuindo o uso de interdependências.

Para o uso de injeção de dependências, fiz uso do Unity Application Block. Módulo da Enterprise Library, do projeto Microsoft Patterns & Praticies. Utilizei a versão 5 (http://www.microsoft.com/en-us/download/details.aspx?id=15104).

O arquivo de configuração da injeção de dependências ficou simples. Neste arquivo foi preciso adicionar as tags de configuração do Unity Application Block e registrar as dependências da aplicação, conforme listado abaixo:

<configuration>  
    <configSections>
      <section name="unity" 
         type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, 
               Microsoft.Practices.Unity.Configuration" />
    </configSections>
    <unity>
      <containers>
        <container>
          <types>
            <type type="Solution.Model.Factory.ISolutionFactory, Solution.Model" 
                            mapTo="Solution.MainFactory.Factory, Solution.MainFactory" />
            <type type="Solution.Model.Business.IUserController, Solution.Model" 
                            mapTo="Solution.Business.UserController, Solution.Business" />
          </types>
        </container>
      </containers>
    </unity>  
...

Para recuperar as instâncias registradas no arquivo de configuração é preciso:

- Capturar os dados registrados na seção do Unity Application Block

- Configurar o Container com as interfaces e suas respectivas dependências

- Utilizar o Container para resolver as dependências das classes

// Current container
var _container = new UnityContainer();

// Get Unity section.
UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");

// Configure Unity Application Block.
section.Configure(_container);

// Resolver current user controller
this._currentUserController = _container.Resolve<IUserController>();

Acesso a dados

Este exemplo utiliza o Entity Framework 5 com Code First.

Dentro do projeto de acesso a dados (Solution.Data) existe uma classe chamada DatabaseContext que herda de DbContext e faz o mapeamento das entidades.

Vale ressaltar que não foi configurada uma connection string, serão utilizadas as convenções padrões do Entity Framework para criação do banco de dados.

O projeto de acesso a dados, para este exemplo, é bastante simples. Apenas duas tabelas são mapeadas como forma de complementação da explicação deste exemplo de arquitetura. As entidades mapeadas são User e Log. User armazenará usuários fictícios e Log armazenará registros de log das ações executadas pela aplicação.

Camada de negócio

Um dos maiores esforços da construção da camada de negócios é reduzir suas dependências. Este camada foi construída sem depender de instâncias concretas de classes que dependam de recursos externos (i.e., bancos de dados, serviços, escrita em disco, etc) para evitar a dependência a recursos externos que possam comprometer a manutenabilidade da aplicação. Por exemplo, não queremos escrever uma aplicação inteira dependendo diretamente do namespace System.Data.ODBC e amanhã termos de mudar tudo para NHibernate. Este tipo de alteração é muito custosa, e se sua aplicação não tiver real controle sobre suas dependências é bastante provável que esta modificação demore (custe, canse, stresse) mais do que um ambiente cujas dependências estão todas controladas e resumidas em um bloco da aplicação.

Conclusão

A arquitetura de sua aplicação pode ditar o modo como seu projeto será conduzido e como será mantido. Arquiteturas de uma única camada são funcionais, mas não o melhor dos mundos, pois geram classes canivetes – aquelas classes que fazem de tudo: gravam, avisam, compõem, renderizam e dão trabalho.

Uma arquitetura bem definida (de acordo com as características da aplicação) podem salvar tempo e recursos. Princípios como injeção de dependências, reusabilidade, separação de responsabilidades, entre outros, agregam muito valor ao seu projeto.

Com este post gostaria de apresentar aquilo que acredito ser “uma arquitetura dinâmica e bem organizada”. Nem todos os projetos precisam de todos estes recursos, mas a maioria precisa ser dinâmico, organizado, manutenível, simples, clara e objetiva.

Comentários Adicionais

Depois de publicar o post estava pensando em algumas melhorias nessa arquitetura, algo como:

- Adicionar uma classe Agent entre a camada de apresentação e o consumo do serviço. Essa classe Agent funcionaria como um proxy, intermediando as chamadas para o serviço. As vantagens do uso desta classe são: reunir em uma única classe todas as chamadas ao serviço e implementar recursos de cache.

Obrigado.

Por
MSc. Fernando Henrique Inocêncio Borba Ferreira
Microsoft Most Valuable Professional – Visual C#

Sobre estes anúncios

15 Responses to Um modelo arquitetural…

  1. Eduardo Pires disse:

    Ótimo artigo, bem explicado!
    Baixei o código, muito bacana…
    Abraços!

  2. Itamar Nunes disse:

    Show de bola!

  3. Yan Justino disse:

    Fernado, este é um excelente artigo. Parabéns! Gosto muito deste tipo de abordagem arquitetural. Não sou muito fã do Unity como DI, mas tudo está muito bem explanado. Isso mostra o quanto você é Fera…

    • Grande Yan!!!!!
      Como vc esta?

      Fico feliz que tenha gostado!
      O que vc usa para injeção de dependências?

      Outro dia recomendei seu projeto de record set para uma amiga :)

      Ainda precisa de ajuda nele?

      []s!

      • Yan Justino disse:

        Grande Fernando, hoje tenho usado o Ninject como container DI. Obrigado pela recomendação. Sim. resolvi aquele probleminha. Tenho até que atualizar o projeto no Github. Tenho acompanhado o blog e tenho achado muito bom e tenho recomendado também aos amigos. Abração!

      • Yan, vlw pelas recomendações. Fico mto contente.
        Atualize o GitHub! Qro ver como esta seu projeto!
        []s meu amigo!

      • Qual o endereço novo do seu blog?

      • Yan Justino disse:

        yanjustino.com

  4. Nelson Junior disse:

    Opa, Fernando… tranquilo?

    Eu tenho uma dúvida na parte de validações. Creio que o melhor local de fazer validações de negócio seria na classe concreta do Controller (Solution.Business.UserController), certo?
    Porém qual seria a melhor maneira de transportar essas validações pra camada de UI (seja ela qual for… Web, WPF, Forms) ?

    Aproveitando. Belo exemplo de arquitetura. Achei muito interessante sua abordagem.
    Tenho visto exemplos de arquitetura em que a complexidade é absurda, sendo que a complexidade ela faria parte de um amadurecimento.

    Você não focou em um domínio gigante, cheio de Classes Generic Types, Eventos e Delegates.

    Parabéns pelo artigo, Fernando. :-)

    • Olá Nelson!
      Obrigado pelos comentários. Procurei deixar a arquitetura simples, pois acredito que o simples atende e funciona mto bem. Para ser bom não precisa ser complexo, precisa apenas atender de forma elegante os requisitos.

      Com relação as validações na camada de serviço: geralmente eu utilizo uma classe de contexto de retorno para serviços WCF. Essa classe é composta por 3 propriedades: ExecutouComSucesso, Mensagem e Dados. ExecutouComSucesso é um booleano que indica se tudo ocorreu bem, ou se algum erro foi disparado. Mensagem é uma mensagem de texto que descreve algum possível que ocorreu (como validação). E Dados, é a coleção ou estrutura de dados que deve ser retornada.

      Assim, fica fácil identificar se ocorreu algum erro, quais os dados retornados, e o que ocorreu de errado.

      Obrigado por postar.

      []s!

  5. Eae Fe, blz mano?!
    Cara, achei muito legal este exemplo. Vc reuniu diversos padrões e boas práticas em uma solution só.

    Um aprimoramento que eu sugeriria seria a inclusão de um bloco que englobe os crosscutting concerns – camadas transversais nesta arquitetura. De repente é assunto para um novo post :-)

    Abs!

    • Oi Le!
      Que bom ve-lo por aqui! E obrigado pelo comentário!
      Sim, acredito que é um excelente tema para um novo post. Vou estudar o assunto mais a fundo e farei algo para isso :)

      []s!

  6. Pingback: Hangout pattern MVP - reunião do Simples-e | MayogaX Dev Blog

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s

Seguir

Obtenha todo post novo entregue na sua caixa de entrada.

Junte-se a 69 outros seguidores

%d blogueiros gostam disto: