Páginas

sexta-feira, 3 de maio de 2013

Trocando configurações padrão do Live TIM

Hoje trocamos aqui em casa a Internet para o Live TIM.

A primeira coisa que fiz foi trocar as senhas, pois por padrão a rede wireless se chama LIVE TIM, com senha 12345678. Não estou muito a fim de compartilhar minha conexão com outras pessoas.

Para fazer isso, conectei na página de administração do modem (ZXDSL 931WII), cujo endereço (pelo menos para mim) foi http://192.168.1.1/. O usuário e senha padrões são admin / admin. Este também é bom trocar (no menu, Administration > User Management).

O nome da rede troquei no menu Network > WLAN > SSID Settings (campo SSID Name). Já a senha da rede foi trocada em Network > WLAN > Security (campo WPA Password).

Aproveitei e fiz um teste de velocidade em http://www.speedtest.net/. Ping de 11 ms, download de 37,65 MB, upload de 19,85 MB. Mas vamos ver como a TIM vai se comportar em relação a estabilidade do serviço (espero que não seja igual a qualidade da telefonia móvel).


[]'s

sábado, 15 de dezembro de 2012

Versão 1.0.1 do NHilo!

Hoje o post é para falar que está disponível a primeira versão estável da biblioteca NHilo (http://nhilo.codeplex.com/), componente para se gerar chaves primárias utilizando o algoritmo hilo do NHibernate!

As mudanças que ocorreram entre a versão beta e esta são:

  • Inclusão de providers para trabalhar com MySQL e Oracle.
  • Criação de um método de extensão para retornar um valor inteiro de 32-bits ao invés de um inteiro de 64-bits.
  • Mudanças de algumas classes para o namespace raiz.
  • Correção de alguns bugs referentes ao schema de configuração.
Por enquanto é só. A biblioteca pode ser baixada tanto nosite do Codeplex quanto pelo Nuget (www.nuget.org).

[]'s

sábado, 24 de novembro de 2012

Usando o padrão Decorator (GoF)

O padrão Decorator, do livro Design Patterns: Elements of Reusable Object-Oriented Software, é útil quando precisamos adicionar um comportamento em uma classe já existente. Vamos demonstrar isso através de um exemplo de uma classe de acesso ao banco de dados onde será adicionado o uso de cache.

Primeiro temos  nossa classe que acessará o "banco de dados". Na verdade, a nossa base nada mais é que um array em memória. Optei por fazer assim para manter a simplicidade do exemplo e focarmos no que realmente é importante. Além disso, a busca demora propositadamente 3 segundos para simularmos todo o trabalho de se acessar um recurso externo à aplicação como um banco de dados.

// RepositorioConfiguracaoImpl.cs
using System.Collections.Generic;
using System.Threading;

namespace ExemploDecorator
{
    public class RepositorioConfiguracaoImpl : IRepositorioConfiguracao
    {
        private readonly Dictionary<string, string> _configuracoes = new Dictionary<string, string>()
        {
            {"REGISTROS_POR_GRID", "50"},
            {"TEMPO_SESSAO", "20"},
            {"TIMEOUT_CONEXAO_DB", "30"}
        };

        public string ObterConfiguracao(string chave)
        {
            Thread.Sleep(3000);
            return _configuracoes[chave];
        }
    }
}

Vejam que esta classe implementa uma interface, um contrato que dita quais são os métodos e suas assinaturas obrigatórias. Este é um ponto muito importante do Decorator e não pode ser esquecido.

// IRepositorioConfiguracao.cs

namespace ExemploDecorator
{
    public interface IRepositorioConfiguracao
    {
        string ObterConfiguracao(string chave);
    }
}

Agora vamos pensar. Como seria o uso dessa classe que recupera configurações para o seu cliente? Em primeiro lugar, o seu cliente deve trabalhar referenciando a interface, e não a classe concreta. Este é outro ponto importante para minimizar o impacto de se incluir uma lógica de cache nesse nosso exemplo. Vamos ver o código que consome esse repositório.

// Program.cs
using System;
using System.Diagnostics;
using Ninject;

namespace ExemploDecorator
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Iniciando testes...\n");
            var kernel = new StandardKernel(new ModuloInjecaoDependencia());
            IRepositorioConfiguracao repositorio = kernel.Get<IRepositorioConfiguracao>();

            MostrarConfiguracao("TIMEOUT_CONEXAO_DB", repositorio);
            MostrarConfiguracao("TIMEOUT_CONEXAO_DB", repositorio);
            MostrarConfiguracao("REGISTROS_POR_GRID", repositorio);
            MostrarConfiguracao("REGISTROS_POR_GRID", repositorio);
            MostrarConfiguracao("REGISTROS_POR_GRID", repositorio);

            Console.WriteLine("FIM");
        }

        private static void MostrarConfiguracao(string chave, IRepositorioConfiguracao repositorio)
        {
            Console.WriteLine("Obtendo configuração para '{0}'...", chave);
            var cronometro = Stopwatch.StartNew();
            Console.WriteLine("Configuração = '{0}'.", repositorio.ObterConfiguracao(chave));
            cronometro.Stop();
            Console.WriteLine("Tempo da chamada : {0} ms. \n", cronometro.ElapsedMilliseconds);
        }
    }
}

// ModuloInjecaoDependencia.cs
using Ninject.Modules;

namespace ExemploDecorator
{
    public class ModuloInjecaoDependencia : NinjectModule
    {
        public override void Load()
        {
            Bind<IRepositorioConfiguracao>().To<RepositorioConfiguracaoImpl>();
        }
    }
}

Nosso programa está usando o Ninject para poder resolver a interface IRepositorioConfiguracao para RepositorioConfiguracaoImpl. Como não é objetivo deste post, deixo para vocês lerem a respeito deste ótimo framework para injeção de dependência. Outro detalhe que eu gostaria de comentar sobre este ponto é que eu poderia utilizar simplesmente uma classe factory para resolver a dependência, isolando os detalhes de como se cria a instância de IRepositorioConfiguracao do seu cliente. Escolhi o Ninject por pura vontade.

Executando este código, temos o seguinte resultado, onde cada chamada ao repositório leva em torno de 3 segundos.



Bom, se o cliente está trabalhando com a interface, então podemos trocar o uso da classe RepositorioConfiguracaoImpl por qualquer classe que implemente o contrato IRepositorioConfiguracao, correto? É aqui que vamos usar o Decorator. Vamos criar uma classe que implemente IRepositorioConfiguracao e que contenha, internamente, uma campo do tipo IRepositorioConfiguracao. Essa primeira classe, que chamaremos de RepositorioConfiguracaoComCache, irá receber uma instância de  RepositorioConfiguracaoImpl no seu construtor, que será armazenada internamente. Em toda a chamada do método ObterConfiguracao de RepositorioConfiguracaoComCache, ela irá fazer a lógica de controle de cache e, se necessário, redirecionar a chamada para o ObterConfiguracao de RepositorioConfiguracaoImpl para efetivamente recuperar o valor da configuração no "banco de dados" (ou seja, se a informação está no cache, usa o dado do cache; caso contrário, vai ao banco, pega o dado, atualiza o cache e retorna a informação).

// RepositorioConfiguracaoComCache.cs
using System.Runtime.Caching;

namespace ExemploDecorator
{
    public class RepositorioConfiguracaoComCache : IRepositorioConfiguracao
    {
        private ObjectCache _cache = MemoryCache.Default;
        private IRepositorioConfiguracao _repositorio;

        public RepositorioConfiguracaoComCache(IRepositorioConfiguracao repositorio)
        {
            _repositorio = repositorio;
        }

        public string ObterConfiguracao(string chave)
        {
            if (!_cache.Contains(chave))
            {
                string valor = _repositorio.ObterConfiguracao(chave);
                _cache.Add(chave, valor, null);
            }
            return (string)_cache[chave];
        }
    }
}

Obs. Estamos usando a classe ObjectCache, disponível a partir do .NET 4.0. Se você está criando este exemplo junto da leitura deste post, e criou um projeto do tipo ConsoleApplication, lembre-se de mudar a propriedade "Target framework" do seu projeto de ".NET Framework 4.0 Client profile" para ".NET Framework 4.0".

Para que o cliente passe a utilizar a nova classe RepositorioConfiguracaoComCache, basta alterar a configuração do Ninject no módulo que criamos.

// ModuloInjecaoDependencia.cs
using Ninject.Modules;

namespace ExemploDecorator
{
    public class ModuloInjecaoDependencia : NinjectModule
    {
        public override void Load()
        {
            Bind<IRepositorioConfiguracao>().ToMethod((ctx) => new RepositorioConfiguracaoComCache(new RepositorioConfiguracaoImpl()));
        }
    }
}

Com isso, ao executarmos novamente a aplicação, temos o acesso ao repositório feito com cache (primeiro acesso mais demorado, mas os demais rápidos)!


Bem útil, se bem aplicado, não acham?

Um último comentário. Esta não é a única maneira de se implementar esse tipo de funcionalidade. Existe um paradigma de programação chamado AOP (Aspect Oriented Programming) que trata da inclusão de comportamento adicional em classes já existentes, principalmente se o comportamento não for uma regra de negócio mas sim algo relacionado a log, segurança, etc. Sobre AOP, há alguns anos eu participei de um podcast sobre o assunto http://podcast.dotnetarchitects.net/2010/05/podcast-13programacao-orientada-a-aspecto/. Vale a pena conferir pois a técnica também é bem útil e em alguns casos mais fácil de implementar que o Decorator (principalmente para sistemas construídos sem levar em conta o uso correto da Orientação a Objetos).

[]'s

quinta-feira, 27 de setembro de 2012

NHiLo - Gerador de chaves primárias (substitutas)

Hoje subi pela primeira vez um pacote Nuget para o seu repositório oficial. Trata-se de um pequeno componente de código aberto que eu fiz para permitir a geração de chaves primárias para registros sem a dependência do banco de dados para isso. Leia-se: NÃO PRECISAR MAIS DE COLUNAS DE AUTO-NUMERAÇÃO COMO IDENTITY.

O uso de colunas do tipo identity são uma das poucas coisas que eu torço o nariz sem antes saber o motivo porque foi escolhido essa abordagem para chaves substitutas. Não gosto porque esse tipo de campo dificulta se precisarmos manter bases sincronizadas, pois o ID da coluna pode ser diferente em cada uma delas.

Este componente é uma implementação isolada do algoritmo HiLo, famoso no NHibernate. Não é nada novo no mundo do desenvolvimento (e todo o crédito para os desenvolvedores do Hibernate/NHibernate), mas que não encontrei uso disponível fora desse framework de ORM. Inclusive esse foi o motivo de eu criá-lo: poder usar o HiLo em uma situação que eu não posso trabalhar com ferramentas de ORM por restrições do cliente :-( .

Ele trabalha separando uma faixa de chaves primárias que podem ser definidas pela própria aplicação. Isso quer dizer que qualquer dado é gerenciado totalmente pela aplicação, o repositório não é responsável por definir nada. Funciona assim: digamos que nossas faixas de chaves disponíveis variam de 100 em 100 registros. Grava-se numa tabela de controle o valor 1. Então a aplicação vai usando as chaves disponíveis, sempre incrementando 1 (veja que isso é feito sem interferência do repositório, chave 1, 2, 3 e assim por diante). Quando a aplicação chegar na última faixa disponível, vamos novamente para a tabela de controle e gravamos 2 (faixa de 101 até 200). Se durante o uso da aplicação outra instância da mesma necessitar de uma faixa de dados, sem problemas, ela vai nessa tabela e grava 3. A primeira instância continua usando a faixa 2, e quando necessitar de uma faixa nova, ela receberá a 4.

Bom, alguns podem argumentar que ainda assim há a dependência com o repositório, pois é nele que são armazenados os dados de controle. Sim, existe essa dependência, entretanto quem efetivamente define o valor de uma nova chave disponível não é o repositório, mas sim a aplicação.

Apesar de existir um momento em que há uma ida ao banco de dados, ela ocorre esporadicamente, e na maioria das vezes a geração da nova chave é uma operação rápida, sem ônus no desempenho da aplicação. Veja por exemplo o gráfico abaixo, que peguei de um teste que fiz. Os "picos" ocorrem de 100 em 100, exatamente no momento em que se busca um novo valor de faixa. O valor deles gira em torno de 2 milissegundos...

Gráfico mostrando poucos picos de "demora" na geração das chaves

O código de exemplo é bem simples. Basicamente criamos um factory (HiLoGeneratorFactory) e obtemos o gerador de chaves para determinada entidade.

[TestMethod]
    public void ShouldReturnAValidKey()
    {
    // Arrange
    var factory = new HiLoGeneratorFactory();
    // Act
    var generator = factory.GetKeyGenerator("dummy4");
    var key1 = generator.GetKey();
    var key2 = generator.GetKey();
    // Assert
    Assert.IsTrue(key1 > 0);
    Assert.IsTrue(key2 > 0);
}


Não é necessária nenhuma configuração adicional para o projeto funcionar, basta o arquivo config da aplicação possuir pelo menos uma string de conexão (faz sentido, pois precisamos acessar o banco de dados de alguma forma). NHiLo irá considerar sempre a última string de conexão para seu uso. Existe a possibilidade de configurar algumas coisas, como se quisermos escolher outra string de conexão ou mesmo o tamanho da faixa, mas isto vou deixar para outro post.

Além disso, foi testado apenas o uso do NHiLo no SQL Server e no SQL Server CE (a definição do tipo do repositório varia com o provider da string de conexão). A implementação para MySQL está pronta mas eu não testei, e a para Oracle ainda não começou a ser feita.


Bom, quem quiser testar a versão que está disponível no Nuget é só procurar por NHiLo, lembrando que é um pacote de pré-release (versão beta).

Tela mostrando o Nuget com o NHiLo disponibilizado.


Além disso, os fontes desse projeto estão hospedados no Codeplex, quem quiser olhar como foi feito ou mesmo contribuir é só entrar em contato comigo!


Abraços e até a próxima!

sexta-feira, 21 de setembro de 2012

Por que tá dando erro?


Hoje um colega de trabalho me mandou o seguinte código, trecho de um teste de unidade.

var objeto = null;
Assert.IsNull(objeto.atributo);

O questionamento era "por que tá dando erro?".

Que coisa, né? Tá dando erro...

[]'s