Slides da apresentação sobre DI com o Unity no .Net Architects

02/06/2009 17:34

Segue a apresentação sobre injeção de dependência com Unity que fiz no décimo encontro do .Net Architects.

 

Quem quiser, pode assistir a gravação do encontro que foi transmitido via Live Meeting no link a seguir:

https://www323.livemeeting.com/cc/usergroups/view?id=BH8CBN

Arquitetura, .Net Architects, Palestras , ,



Inscrições abertas para o .NET Architects Day 2009

30/05/2009 22:12

O site para as inscrições do .NET Architects Day 2009 está disponível no seguinte endereço:

http://www2.dotnetarchitects.net/dnawww2/registroDNAD2009/

O processo de inscrição é rápido e simples! Para mais informações do evento, incluindo a grade de palestras e a localização, vejam no link a seguir:

http://www.dotnetarchitects.net/dnad2009

.Net Architects, Arquitetura, Eventos , , , ,



.NET Architects Day 2009

24/05/2009 00:01

 

Convido a todos os interessados em arquitetura de software a participarem do primeiro evento do grupo .NET Architects.

Qual a idéia do evento:

  • Temas apresentados por membros ativos do grupo e MVP's;
  • Apresentações focadas na experiência dos palestrantes, e não somente na tecnologia;
  • Interação com a comunidade;
  • Sorteio de brindes (DVDs VSTS, Livros, Camisetas, entre outros);
  • Temas focados em arquitetura de soluções;
  • Oportunidade de interagir com outros arquitetos de software e interessados no assunto.

Temas a serem apresentados:

Informações completas sobre o evento você encontra aqui. Espero por você lá!

.Net Architects, Arquitetura, Eventos , , , ,



EntLib (parte 7) – Configurando InterceptionExtension no Unity

17/05/2009 23:45

No meu último post da série sobre a Enterprise Library expliquei como podemos utilizar a extensão de biblioteca InterceptionExtension do Unity para aplicar interceptação na chamada da interface ILogger aplicando uma característica AOP no container. O exemplo levava em consideração que a definição fosse realizada em tempo de execução. Veremos agora como podemos modificar o exemplo anterior colocando todas as definições no arquivo de configuração da aplicação.

Dentro do arquivo de configuração, adicione dentro da sessão typeAliases os tipos descritos abaixo:

<typeAliases>
 
    ...

    <typeAlias 
        alias="GUIDAttribute" 
        type="Reverb.Handlers.GUIDAttribute, Reverb.InterceptionSample" />
    <typeAlias 
        alias="GUIDHandler" 
        type="Reverb.Handlers.GUIDHandler, Reverb.InterceptionSample" />
    <typeAlias 
        alias="interface" 
        type="Microsoft.Practices.Unity.InterceptionExtension.InterfaceInterceptor, Microsoft.Practices.Unity.Interception, Version=1.2.0.0" />
</typeAliases>

Em seguida adicione um novo container dentro da sessão Containers, conforme descrito abaixo:

<container name="InterfaceInterceptionContainer">
    <extensions>
        <add type="Microsoft.Practices.Unity.InterceptionExtension.Interception, Microsoft.Practices.Unity.Interception" />
    </extensions>
    <extensionConfig>
        <add name="interception"
            type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationElement, Microsoft.Practices.Unity.Interception.Configuration">
            <interceptors>
                <interceptor type="interface">                                
                    <key type="ILogger"/>
                </interceptor>                            
            </interceptors>
        </add>
    </extensionConfig>
    <types>
        <type type="ILogger" mapTo="ConsoleLogger" />
    </types>
</container>

Por fim o construtor da classe Servico deve ser alterado da seguinte forma:

public Servico()
{
    container = new UnityContainer(); 
    section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
    
    section.Containers["InterfaceInterceptionContainer"].Configure(container);            
    
    logger = container.Resolve<ILogger>();
}

Repare que modificamos o código anterior retirando toda a configuração para ser usada em tempo de execução e colocando em seu lugar a linha 6 que diz qual configuração utilizaremos para adicionarmos a extensão de interceptação do Unity. Assim, é possível conferir maior facilidade para alterações nas definições de interceptação, sem a necessidade de recompilar toda a aplicação (a menos, é claro, que você adicione um novo handler).

Até o próximo post da série.

Enterprise Library, Arquitetura , ,



EntLib (parte 6) – Interceptação de chamada de interface com o Unity

10/05/2009 23:36

Dentro do desenvolvimento de software chamamos de “cross-cutting concerns” tudo aquilo que faz parte do nosso código provendo funcionalidades comuns entre diversas classes (entre camadas lógicas, por exemplo). Exemplificando, poderíamos dizer que itens como segurança, log, instrumentação de código, são preocupações que atravessam nossas classes, daí dizermos “cross-cutting concerns” ou preocupações transversais.

O Unity Application Block, além de resolver problemas de alto acoplamento também pode ajudar imprimindo um certo nível de AOP (Aspect-oriented programming, ou programação orientada a aspectos) em suas aplicações através de uma extensão da biblioteca chamada InterceptorExtension.

Vamos pegar o mesmo exemplo utilizado no meu post anterior da série, e modifica-lo para vermos como podemos usar uma interceptação para a interface ILogger. Tomaremos o resultado final da classe Servico e faremos a alteração no seu construtor, indicada nas linhas 20 a 28. Basicamente, dizemos ao container que toda vez que o mapeamento da interface ILogger for para a classe concreta ConsoleLogger interceptaremos as chamadas para essa interface (InterfaceInterceptor), aplicando alguma nova característica. Repare que na linha 4 adicionamos o namespace que contém a extensão de interceptação do Unity.

using System.Configuration;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
using Microsoft.Practices.Unity.InterceptionExtension;

using Reverb.Loggers;

namespace Reverb.InterceptionSample
{
    public class Servico
    {
        private IUnityContainer container;
        private UnityConfigurationSection section;
        private ILogger logger;

        public Servico()
        {
            container = new UnityContainer();
            
            /* *******************************************
             * Adicionando o tratamento de interceptação
             * para a interface ILogger.
             *********************************************/
            container.AddNewExtension<Interception>();
            container.RegisterType<ILogger, ConsoleLogger>()
                .Configure<Interception>()
                .SetInterceptorFor<ILogger>(new InterfaceInterceptor());
            //*********************************************

            section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
            section.Containers.Default.Configure(container);
            logger = container.Resolve<ILogger>();
        }

        public void Iniciar()
        {   
            logger.Log("Iniciando servico...", System.Diagnostics.TraceEventType.Information);

            // Código de inicialização do serviço...

            logger.Log("Servico iniciado.", System.Diagnostics.TraceEventType.Information);
        }

        public void Parar()
        {
            logger.Log("Parando servico...", System.Diagnostics.TraceEventType.Information);

            // Código de parada do serviço...

            logger.Log("Servico Parado.", System.Diagnostics.TraceEventType.Information);
        }
    }
}

Adicionaremos uma nova classe que manipulará a chamada interceptada pelo Unity adicionando um GUID para cada evento, exatamente como o código a seguir:

using System;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.InterceptionExtension;

namespace Reverb.Handlers
{
    public class GUIDAttribute : HandlerAttribute
    {
        public override ICallHandler CreateHandler(IUnityContainer container)
        {
            return new GUIDHandler();
        }
    }

    public class GUIDHandler : ICallHandler
    {
        public int Order { get; set; }

        public IMethodReturn Invoke(
            IMethodInvocation input, 
            GetNextHandlerDelegate getNext)
        {
            System.Guid guid = System.Guid.NewGuid();
            Console.WriteLine();
            Console.WriteLine("ID: {0}", guid.ToString());
            return getNext()(input, getNext);
        }
    }
}

Por fim, decoraremos a interface ILogger com o atributo criado no código anterior:

using System.Diagnostics;
using Reverb.Handlers;

namespace Reverb.Loggers
{
    [GUID]
    public interface ILogger
    {
        void Log(string message, TraceEventType eventType);
    }
}

Desta forma, toda vez que chamarmos a interface ILogger para resolução da classe concreta ConsoleLogger, o Unity interceptará essa chamada utilizando o manipulador GUIDHandler para criar um GUID e adiciona-lo na mensagem de retorno. Como usei um projeto do tipo Console Application o resultado da chamada é ilustrado na imagem abaixo:

ConsoleInterception

Fantástico não?

Enterprise Library, Arquitetura , ,



EntLib (parte 5) – Unity Application Block

09/05/2009 22:53

Aproveitando o embalo do meu post dessa semana sobre o padrão de injeção de dependência, vamos ver o bloco da Enterprise Library responsável por prover essa funcionalidade, chamado Unity Application Block. Criado inicialmente como um projeto separado no CodePlex foi incorporado a Enterprise Library na versão 4.0.

No exemplo de código abaixo a classe Servico utiliza a classe TraceSourceLogger para registrar os passos executados na inicialização e paralização, ou seja, a classe Servico conhece e depende da classe concreta TraceSourceLogger.

public class Servico
{
    private TraceSourceLogger logger;

    public Servico()
    {
        logger = new TraceSourceLogger("Agent");
    }

    public void Iniciar()
    {
        logger.Log("Iniciando serviço...", System.Diagnostics.TraceEventType.Information);

        // Código de inicialização do serviço...

        logger.Log("Serviço iniciado.", System.Diagnostics.TraceEventType.Information);
    }

    public void Parar()
    {
        logger.Log("Parando serviço...", System.Diagnostics.TraceEventType.Information);

        // Código de parada do serviço...

        logger.Log("Serviço parado.", System.Diagnostics.TraceEventType.Information);
    }
}

O problema aqui é que qualquer alteração na forma de realizar o log da operação implicaria em alterações na classe Servico. Por exemplo, se quiséssemos substituir a classe TraceSourceLogger por outra que realizasse a operação gravando no Event Viewer teríamos que realizar a alteração na classe Servico, inclusive recompilando o projeto.

Uma boa prática aqui é fazer com que ao invés de instanciarmos diretamente a classe concreta o fizéssemos através de uma interface, conforme ilustrado no diagrama a seguir:

ClassDiagram1

Em seguida utilizamos o Unity para resolver as chamadas às classes concretas da seguinte forma. Primeiro adicionamos no arquivo de configuração do projeto as configurações abaixo:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
        <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" />
    </configSections>
    <unity>
        <typeAliases>
            <typeAlias
              alias="ILogger"
              type="Reverb.Loggers.ILogger, Reverb.DI" />
            <typeAlias
              alias="ConsoleLogger"
              type="Reverb.Loggers.ConsoleLogger, Reverb.DI" />
            <typeAlias
              alias="TraceSourceLogger"
              type="Reverb.Loggers.TraceSourceLogger, Reverb.DI" />
            <typeAlias
                alias="EventViewerLogger"
                type="Reverb.Loggers.EventViewerLogger, Reverb.DI" />
        </typeAliases>
        <containers>
            <container>
                <types>
                    <type type="ILogger" mapTo="TraceSourceLogger" />
                </types>
            </container>
        </containers>
    </unity>
</configuration>

No arquivo acima indicamos quais os tipos desejados e como o container deve resolver a implementação concreta para a interface ILogger. Depois, alteraríamos a classe Servico conforme exemplo a seguir:

public class Servico
{
    private IUnityContainer container;
    private UnityConfigurationSection section;
    private ILogger logger;

    public Servico()
    {
        container = new UnityContainer();
        section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
        section.Containers.Default.Configure(container);
        logger = container.Resolve<ILogger>();
    }

    public void Iniciar()
    {   
        logger.Log("Iniciando servico...", System.Diagnostics.TraceEventType.Information);

        // Código de inicialização do serviço...

        logger.Log("Servico iniciado.", System.Diagnostics.TraceEventType.Information);
    }

    public void Parar()
    {
        logger.Log("Parando servico...", System.Diagnostics.TraceEventType.Information);

        // Código de parada do serviço...

        logger.Log("Servico Parado.", System.Diagnostics.TraceEventType.Information);
    }
}

Note que no código acima não definimos em momento algum qual seria a implementação da classe concreta que realiza a operação de log, pois isso fica a cargo do container do Unity que resolverá essa dependência de acordo com o que definimos no arquivo de configuração da classe.

Se quiséssemos agora alterar a implementação de classe concreta que resolveria o log bastaria modificar no arquivo de configuração, como no exemplo a seguir:

<containers>
    <container>
        <types>
            <type type="ILogger" mapTo="ConsoleLogger" />
        </types>
    </container>
</containers>

Bem fácil, não? Na revista .net Magazine edição 62 terá um artigo meu sobre Injeção de Dependência com o Unity Application Block, colocarei mais informações aqui na próxima semana, aguardem!

Até o próximo post.

Enterprise Library, Arquitetura , ,



O exemplo da Injeção de Dependência na tomada de decisão de um arquiteto

06/05/2009 23:57

Parte do trabalho de um arquiteto de software consiste em empregar da melhor forma possível técnicas e boas práticas para construir uma aplicação levando em consideração variáveis como:

- tecnologias disponíveis;
- interesses de negócio;
- durabilidade da aplicação;
- custo;
- expectativa do usuário;
- skill da equipe técnica;
- entre outras.

Trocando em miúdos, uma decisão errada impacta significativamente na consonância entre essas variáveis. Vamos pegar como exemplo um problema conhecido por quem desenvolve software chamado alto acoplamento.

(Aqui em abro um grande parêntesis. O termo acoplamento às vezes é confundido com coesão, contudo são dois conceitos diferentes. Uma classe pode ser coesa e altamente acoplada com outras classes, como também pode acontecer de ser desacoplada de outras classes e possuir baixa coesão. Coesão está relacionado ao Princípio da Responsabilidade Única (PRU), ou seja, se uma classe possui mais do que um motivo para ser alterada, possivelmente ela está fazendo mais do que devia. Já o acoplamento refere-se ao quanto que uma classe depende de outra classe, assim sendo, o ideal seria termos sempre alta coesão e baixo acoplamento.)

Dentre as técnicas mais utilizadas para resolver o problema do alto acoplamento a injeção de  dependência (DI, dependency injection) ressurgiu com grande destaque, em parte graças a crescente prática de testes unitários e desenvolvimento baseado em testes (TDD). Martin Fowler certamente foi um dos grandes responsáveis pela popularização do termo injeção de dependência, considerado-o um tipo de IoC (Inversion of Control). Apesar de não ser nova, diversas bibliotecas de DI, conhecidas como lightweight container, facilitam a utilização desta técnica que, somada ao motivos do seu reaparecimento citados no início desse parágrafo, destacam-na com uma das “modas do momento”.

Um bom arquiteto, na minha opinião, deve tomar suas decisões levando em consideração as variáveis citadas no primeiro parágrafo, elencando uma série de questões pertinentes, e com base nelas procurando as respostas mais sensatas para a sua realidade. Pensando no tema injeção de dependência:

  • A aplicação de DI pode representar um risco elevado levando em consideração o skill da equipe?
  • A empresa tem como cultura a prática de testes (TDD ou qualquer outra técnica)?
  • Se a aplicação não tem previsão de vida longa vale a pena aplicar DI?


E o caminho inverso também deve ser ponderado:

  • Eu consigo aumentar o skill da minha equipe aplicando uma nova técnica?
  • Eu consigo mostrar os benefícios de praticarmos TDD já que DI nos propicia isso mais facilmente?
  • Eu consigo comprovar que os custos com manutenção serão menores se empregarmos melhores técnicas agora, ainda que isso onere um pouco mais o projeto?


Respondidas as questões, imbuído de tranqüilidade e principalmente harmonizando as variáveis em jogo o arquiteto pode partir para a tomada de decisão com mais assertividade. Deste modo, retomando a frase “o ideal seria termos sempre alta coesão e baixo acoplamento, cabe ao arquiteto entender o quanto desse objetivo deve ser alcançado com o uso de DI.

Lembrem que a acepção da palavra “ideal” não deixa dúvidas:

ideal
adj.
1. Que só existe na idéia.
2. Que reúne toda a perfeição imaginável.
3. Conjunto imaginário de perfeições que não podem ter realização completa.

zen

Arquitetura, Reverberando , ,



Resultados da priorização do product backlog da Enterprise Library 5

19/04/2009 13:30

Foi postado há 4 dias no blog do Grigori Melkin os resultados da priorização do product backlog da EntLib 5 realizada com a ajuda da comunidade. Através do feedback das pessoas que contribuiram a equipe responsável pelo EntLib constatou que o foco para a próxima versão deve ser direcionado na melhoria da experiência de uso, simplicidade e aprendizado.

Estou preparando um material sobre o Unity Application Block, falarei aqui no Reverb sobre esse e outros blocos da Enterprise Library em breve, aguardem.

Enterprise Library, Arquitetura ,