Android Jelly Bean no Nexus S

Meu Nexus S, após o upgrade para o Ice Cream Sandwich – ICS, ganhou funcionalidades, eye candy, e uma considerável lentidão. Lentidão esta que serviu de desculpa para a Samsung não atualizar os Galaxy S, que compartilham das mesmas especificações técnicas.

Nexus S

good old Nexus S

Então foi com muita ansiedade que vi a notícia de que o Jelly Bean OTA upgrade já estava rolando para o Nexus S pelo mundo, mas ainda não no Brasil.

Mas sempre há jeito. Fuçando pelo fórum XDA, vi ser possível atualizar o aparelho com o OTA upgrade, apesar de estar no Brasil. O truque é fazer o aparelho ser detectado como se fosse americano, que é uma das regiões onde  o upgrade está acontecendo.

Para isto fiz o seguinte – e não sei qual dos passos é realmente necessário:

  • trocar idioma para inglês;
  • colocar região/horário para o americano;
  • apagar o cache do Google Services Framework (Configurações > Aplicativos > Todos -> Google Services Framework: apagar cache);
  • remover o SIM card;
  • ligar, ir para as configurações > Sobre o Telefone > Atualizações do sistema.

E voilá! Atualização para o Jelly Bean disponível num download de 114MB.

Jelly Bean

Jujubim

Certifique-se de que a bateria está cheia ou de ficar na tomada, a atualização demora um pouco. Até o momento deu para perceber duas coisas: o Google Now é legal e o sistema ficou realmente, perceptivelmente, mais rápido. Finalmente. Fôlego para apagar o gadget lust sempre que surge um celular mais modernoso…

SonicWall NetExtender no Ubuntu 64

Bom, voltei ao Ubuntu, mas desta vez o 11.10 64bits. Fiquei feliz que o sistema está bem mais estável – até o momento – que o 11.04. Mas tem sempre algo que não funciona, que é o caso do cliente de VPN NetExtender da SonicWall.

Eu tinha feito funcionar no Debian 64, mas a mesma solução não coube aqui. O Ubuntu não tem uma variável de ambiente LD_LIBRARY_PATH. Como resolver então? Passando por cima do arquivo /etc/ ld.so.conf e definindo o caminho para as bibliotecas na mão:

sudo /lib/ld-linux.so.2 --library-path /lib32 ./netExtender -u username -d example.com vpn.example.com:4433

E é isso!

SonicWall NetExtender no Debian 64

Ao migrar do Ubuntu 11.04 – que estava dando muita dor de cabeça – para o Debian 64 tive alguns problemas para configurar o NetExtender (trocando dor de cabeça por diversão).

NetExtender

Baixei o programa e instalei o tarball. Ao executar o cliente gráfico, netExtenderGui, foi apresentado o erro:

There was a problem loading the NetExtender JNI library.
Please reinstall NetExtender, and make sure you have a
compatible version of Java installed. SonicWALL recommends
Sun Java 1.4 or higher.

Bom, estou com o Sun Java 1.6 e ele está configurado corretamente. Olhando no terminal, o erro é um pouco mais específico, mas não ajudou muito:

Could not load libNetExtender.so

Jogando a mensagem no Google encontrei um post com pessoas com o mesmo problema, que é a arquitetura usada: 64bits.

Sabendo qual o problema fica mais fácil resolver. No diretório /usr/lib32 crie dois arquivos simbólicos:

sudo ln -s libcrypto.so.0.9.8 libcrypto.so.6
sudo ln -s libssl.so.0.9.8 libssl.so.6

Se não existirem o libssl.so.0.9.8 e o libcrypto.so.0.9.8, instale o pacote ia32-libs.
Agora crie um script para configurar o LD_CONFIG_PATH:

#!/bin/sh
export LD_LIBRARY_PATH=/usr/lib32:$LD_LIBRARY_PATH
export COMMAND=/home/seiti/devel/netExtenderClient/netExtender
$COMMAND "$@"

Basta agora dar permissão de execução e correr pro abraço:

./netExtender.sh -u usuario -p 'senha' -d example.com vpn.example.com:1234

Asp.Net, Web Forms e Ninjas – Parte 1

Um padrão que facilita muito a montagem de um sistema orientado à objetos é o de Inversão de Controle e Injeção de Dependência – Inversion of Control / Dependency Injection, ou simplesmente IoC/DI. O padrão tira das mãos do programador o trabalho de instanciar objetos – que pode ficar bem complicado, restando apenas configurar a aplicação.

IoC/DI

Ninja!!!!

Ninja!!!!

Programando para a web, geralmente temos de aprender o ciclo de vida da aplicação web, quais os pontos de chamadas de páginas, controles, beans e etc. Quem tem o controle da aplicação é o servidor de aplicação – IIS/.NET, JBoss, WebSphere – e não o programador. Isto é um tipo de Inversão de Controle.

No caso da Injeção de Dependência, a Inversão de Controle se refere a quem cria os objetos. Quem deve criar os objetos é a própria aplicação. Por que isto? A criação de objetos pode ser complexa e cheia de dependências. Um exemplo: a criação de um objeto Samurai. Mas um Samurai obrigatoriamente precisa de uma Espada. Então você deve primeiro criar uma Espada, para depois criar o Samurai. Mas para criar uma Espada você precisa de uma Forja e um Ferreiro e assim por diante.

A solução é usar um contêiner – ou container – que faça este trabalho e crie estes objetos para nós. Ao programador resta elaborar e estabeler as regras para esta criação.

Um contêiner DI muito utilizado em Java é o Spring Framework. Em .Net temos vários, mas nenhum em amplo uso e aval da MS. Aqui vou falar de um que considero bem prático de usar e cuja configuração não é baseada em XML. O Ninject.

Ninjas!

Ok, criar objetos pode ser complicado e sujo, então contratemos ninjas para fazê-lo. O Ninject possui uma documentação bem simples de se acompanhar, mas vejamos aqui mesmo o básico.

Segue um código com comentários para exemplificar como o Ninject funciona:

class Samurai {
  readonly IWeapon _weapon;

  //O atributo 'Inject' faz com que o Ninject, ao instanciar um Samurai, instancie primeiro um IWeapon.
  //Este IWeapon é então passado para o Samurai como um parâmetro do construtor.
  [Inject]
  public Samurai(IWeapon weapon) {
    _weapon = weapon;
  }
  public void Attack(string target) {
    _weapon.Hit(target);
  }
}

class Espada implements IWeapon {
  public Metal Metal { get; private set; }
  public double Weight { get; private set; }
  public double Length { get; private set; }
  public string Name{ get; private set; }
  public Blacksmith Blacksmith { get; private set; }

  //Este 'Inject' é semelhante ao de cima, com a diferença do Ninject instanciar e atribuir um
  //DamageCalculator após a construção desta Espada.
  //Seria semelhante à um new Espada(...) { DamageCalculator = new DamageCalculator(...) }
  [Inject]
  public DamageCalculator Calculator { get; set; }

  [Inject]
  public Espada(Blacksmith blacksmith) {
    Metal = Metal.Iron;
    Weight = 1;
    Length = 2;
    Name = name;
    Blacksmith = blacksmith;
  }

  public Espada(Metal metal, double weight, double length, string name, Blacksmith blacksmith) {
    Metal = metal;
    Weight = weight;
    Length = length;
    Name = name;
    Blacksmith = blacksmith;
  }
  public void Hit(string target) {
     //código com o ataque, levando em conta as características da espada etc.
  }
}

//etc...

Acima vemos onde marcar nosso código de forma a instruir o Ninject onde agir. Mas como o Ninject sabe qual arma criar para o Samurai, se o Samurai recebe qualquer coisa que implemente IWeapon? Utilizando NinjectModule:

public class SamuraiModule : NinjectModule
{
    public override void Load()
    {
        //Sempre que o código pedir um Samurai, um Samurai será criado
        Bind<Samurai>().ToSelf();
        //Sempre que o código pedir um IWeapon, uma Espada será criada
        Bind<IWeapon>().To<Espada>();
        Bind<Blacksmith>().ToSelf();
    }
}

Basta agora configurar sua aplicação para ter um Ninject funcional sempre que necessário. Como escolhi, por vários motivos, criar meu projeto como um Asp.NET Web Forms (ao contrário do Asp.NET MVC), tive de alterar o Ninject para dar suporte. Sorte que alguém já havia feito isto.
Basta baixar o código fonte do Ninject, aplicar o patch e compilar.

Agora devemos alterar o Global.asax.cs para que ele estenda NinjectHttpApplication e instanciar um novo Ninject.IKernel sempre que a aplicação subir.
É o IKernel o responsável pelo tedioso e oneroso trabalho de instanciar seus objetos, suprindo-os dos elementos necessários para seu funcionamento.

public class Global : NinjectHttpApplication
{
    protected override void OnApplicationStarted()
    {
        base.OnApplicationStarted();
    }

    protected override Ninject.IKernel CreateKernel()
    {
        IKernel kernel = new StandardKernel(
            new List()
            {
                new SamuraiModule()
            }.ToArray()
        );

        return kernel;
    }
}

Nos próximos posts mostrarei como usar o Ninject e o NHibernate em uma aplicação Asp.NET Web Forms.

KISS, YAGNI e DRY

Hoje fui lembrado de algo importante, que…, hmm.., bem…, às vezes é esquecido: o desenvolvedor deve entregar software.

E acho que não sou só eu que devo ser lembrado disto, pois há até um site cujo propósito é lembrar isto (bom,  existe site para tudo, mas enfim…).

Como não poderia deixar de ser nesta área, existem alguns acrônimos e lemas que te auxiliam nesta tarefa tão importante, que é entregar um software de valor e respeito no prazo. KISS, YAGNI e DRY. Comecemos pelo mais simpático:

KISS – Keep It Simple, Stupid

Mantenha simples. A simplicidade facilita o entendimento. O que é simples é fácil de usar, de manipular. É fácil de explicar. Mas isto não quer dizer que a simplicidade como objetivo é algo simples. Complexo?

A simplicidade, a elegância são características que necessitam de experiência, de criatividade para serem alcançadas. Usando um  exemplo já surrado , o iPhone. Simples. Elegante. Lembra-se dos smartphones antes dele? Pois então. E o que fazer? Estudar, compreender, testar e inventar. E depois ver se sua mãe compreendeu seu invento.

YAGNI – You Ain’t Gonna Need It

Não implemente nada, a não ser que seja necessário para seu produto. Não produza o que não será usado. Senão será mais trabalho no momento de criar e no momento de dar manutenção.

Entra a questão: e o que realmente é necessário? Pergunta difícil. Se perguntar ao cliente o que é necessário, você terá de criar o Facebook.  A resposta requer experiência e análise fundamentada do problema em questão. Entra novamente um pouco de senso estético. Elegância. Descreva as features. Elimine todas quanto possível.  Tire qualquer uma em que restem dúvidas.  Depois de criar este conjunto mínimo, escolha uma feature para jogar fora. Aí, talvez, sobre uma lista contendo apenas o que é necessário.

Mas sejamos pragmáticos também. A aplicação de YAGNI deve levar em conta também o custo de implementação. Se é barato fazer agora e barato depois, deixe para depois. Se é barato agora, mas ficará caríssimo depois, faça agora. Este conhecimento, de novo, requer prática e experiência.

DRY – Don’t Repeat Yourself

Uma regra, uma especificidade (repita em voz alta, comendo paçoca Amor), um pedaço do conhecimento deve estar declarada, escrita, de forma clara, em um único ponto do sistema.

Pode ser fácil. Ou bem difícil. Depende do tamanho. Do tamanho do produto e da equipe.  É muito comum equipes grandes de desenvolvimento escreverem diversas soluções para o mesmo problema, sem um ter conhecimento da solução do outro.

Já ouvi que isso ocorre em alguns lugares entre equipes de departamentos distintos, que são muito “ciosos” de seu código…

O fato é que é preciso que o sistema seja claro o suficiente e que os desenvolvedores se comuniquem de maneira eficiente para a aplicação do DRY. Como fazer isso? Seria uma boa perguntar ao Fred Brooks.

Disk-sistema entregas rápidas

E o que isto tudo significa? Significa a prática da Programação Zen. O melhor código é o não-código. Executar isso difícil. Requer perseverança e auto-controle. Exerçamos a melhor qualidade de um programador. Mantenha o sistema limpo, enxuto, conciso. Não crie, não produza a mais. Menos features, menos código, menos trabalho, menos tempo gasto. Talvez até dê para cumprir aquele prazo….

NhLogo

Fluent NHibernate

O NHibernate é um port para .NET do Hibernate, um mapeador objeto relacional (ou ORM) com esteróides. Vamos ver como usá-lo para mapear e persistir nossos objetos no banco de dados.

O NHibernate é um grande auxílio para quem deseja implementar um sistema usando DDD (não, não é quando você liga para o programador que mora longe. É Domain Driven Design).

Me deixa dormir!

Me deixa dormir!

Quem já usou o Hibernate sabe que configurá-lo pode ser a porta de entrada para o primeiro dos nove círculos do inferno. Bom, não passei por isto, pois nunca havia usado diretamente o Hibernate. Se existe algo bom em chegar na festa por último no mundo do desenvolvimento, é de ter mais coisas prontas e mastigadinhas. Entra então o Fluent NHibernate.

Historinha para bovinos hibernarem

Primeiro o contexto. Enfrento um código legado (código legado == código sem testes, segundo Feathers) que usa o framework Castle ActiveRecord (Castle AR). Embora este framework facilite bastante a vida, poupando o pobre programador da tarefa de escrever muito código CRUD, ganhando uma tendinite, ele não se dá muito bem com o DDD, tornando mais trabalhoso que o necessário a separação das Entidades do sistema de persistência.

Outro problema é que, apesar do Castle AR fornecer uma camada de abstração sobre o Hibernate, é necessário que você saiba como o Hibernate funciona. Decidi então me livrar do Castle AR e usar apenas o Hibernate. E como não quero editar os arquivos XML do Hibernate eu mesmo (o Castle AR fazia este trabalho) decidi usar o Fluent NHibernate.

Programação, sistemas e zumbis

O Fluent NHibernate segue uma sintaxe fluente para realizar toda a configuração do Hibernate usando a própria linguagem de programação. No meu caso, C#.

Primeiro um esquema altamente complexo do sistema que servirá de exemplo:

Diagrama do sistema

Chamem o Chris Redfield!

Um RaccoonCity City possui inúmeros Zombies. O City tem uma data, Month, com mês e ano, de quando se iniciou a infecção de sua população. Zombie possui uma data, Month, de quando ele mesmo foi infectado. Por enquanto não podemos estimar estas datas com precisão de dias, por isso queremos apenas mês e ano.

O diagrama acima gerou as seguintes classes:

  • City é uma Entidade. E é uma Raíz de Agregado, ou Aggregate Root;
  • Zombie é um Objeto Valor, ou Value Object. Quer dizer que todos os zumbis são iguais, desde que tenham as mesmas propriedades: FormerName e Infected. Deixei um Id mesmo assim;
  • Month também é um Objeto Valor. Ele determina um mês e ano. Não estou interessado no dia.

Uma preocupação na modelagem foi quanto à lista Zombies. Para se adicionar um Zombie em um City é preciso usar o método AddZombie(). Assim tenho um lugar onde posso checar e validar o Zombie antes da adição.

Mas se eu exponho Zombies como um List<Zombie> nada impede o programador de fazer isso:

City raccoon = new City("Raccoon City", new Month(2010, 4));
raccoon.Zombies.Add(new Zombie("Zé Ninguém", new Month(2010, 7)));

ao invés de:

City raccoon = new City("Raccoon City", new Month(2010, 4));
raccoon.AddZombie(new Zombie("Zé Ninguém", new Month(2010, 7)));

Para resolver este problema eu guardo a lista como um List<Zombie> e exponho apenas um IEnumerable<Zombie>:

    public class City
    {
        public virtual int Id { get; private set; }

        public virtual string Name { get; private set; }

        public virtual Month InfectionStart { get; private set; }

        private readonly IList<Zombie> _zombies = new List<Zombie>();

        public virtual IEnumerable<Zombie> Zombies
        {
            get { return _zombies; }
        }

        protected City()
        {}

        public City(string name, Month startMonth)
        {
            Name = name;
            InfectionStart = startMonth;
        }

        public virtual void AddZombie(Zombie z)
        {
            _zombies.Add(z);
        }

    }

O IEnumerable apenas expõe método de consulta. Exatamente o que eu queria.

Vamos agora implementar a classe Zombie. Esta acaba sendo mais complicada, pois se trata de um VO (Value Object). É necessário realizar um override nos métodos Equals() e GetHashCode() para que o sistema possa comprar dois zumbis com as mesmas propriedades, mesmo que de instâncias diferentes, e devolver um resultado útil. E já podemos aproveitar para fazer override nos operadores == e !=, para que devolvam o mesmo resultado que o Equals():

    public class Zombie
    {
        public virtual int Id { get; private set;}
        public virtual string FormerName { get; set; }
        public virtual Month Infected { get; set; }

        public static bool operator ==(Zombie b1, Zombie b2)
        {
            return b1.FormerName == b2.FormerName && b1.Infected == b2.Infected;
        }

        public static bool operator !=(Zombie b1, Zombie b2)
        {
            return b1.FormerName != b2.FormerName || b1.Infected != b2.Infected;
        }

        public static bool operator >(Zombie b1, Zombie b2)
        {
            return b1.Infected > b2.Infected;
        }

        public static bool operator <(Zombie b1, Zombie b2)
        {
            return b1.Infected < b2.Infected;
        }

        public static bool operator >=(Zombie b1, Zombie b2)
        {
            return b1.Infected >= b2.Infected;
        }

        public static bool operator <=(Zombie b1, Zombie b2)
        {
            return b1.Infected <= b2.Infected;
        }

        public override bool Equals(object obj)
        {
            if (!(obj is Zombie))
                return false;

            return this == (Zombie)obj;
        }

        public override int GetHashCode()
        {
            return FormerName.GetHashCode() ^ Infected.GetHashCode();
        }
    }

Até aproveitei para implementar os operadores < e >, que dependem da data de infecção do safado.

E só resta a classe Month:

    public class Month: IComparable
    {
        private int Dia { get { return 1; } }
        public int Mes { get; private set; }
        public int Ano { get; private set; }

        protected Month()
        {}

        public Month(int ano, int mes)
        {
            if (!AnoValido(ano))
                throw new ArgumentOutOfRangeException(String.Format("Ano não cabível. Ano apresentado: {0}", ano));

             if (!MesValido(mes))
                throw new ArgumentOutOfRangeException(String.Format("Mês não cabível. Mês apresentado: {0}", mes));

            Ano = ano;
            Mes = mes;
        }

        private bool AnoValido(int ano)
        {
            // Valores válidos para o SQL Server.
            // Observe que dado o escopo do problema não faz sentido nada fora deste intevalo mesmo.
            if (1753 <= ano && ano <= 9999)
                return true;

            return false;
        }

        private bool MesValido(int mes)
        {
            if (1 <= mes && mes <= 12)
                return true;

            return false;
        }

        public DateTime AsDateTime()
        {
            return new DateTime(Ano, Mes, Dia);
        }

        public override string ToString()
        {
            return AsDateTime().ToString();
        }

        public static bool operator ==(Month d1, Month d2)
        {
            return d1.Ano == d2.Ano && d1.Mes == d2.Mes;
        }

        public static bool operator !=(Month d1, Month d2)
        {
            return d1.Ano != d2.Ano || d1.Mes != d2.Mes;
        }

        public static bool operator <=(Month d1, Month d2)
        {
            if (d1 == d2)
                return true;

            if (d1.Ano < d2.Ano)
                return true;

            if (d1.Ano > d2.Ano)
                return false;

            if (d1.Mes < d2.Mes)
                return true;

            return false;
        }

        public static bool operator >=(Month d1, Month d2)
        {
            if (d1 == d2)
                return true;

            if (d1.Ano > d2.Ano)
                return true;

            if (d1.Ano < d2.Ano)
                return false;

            if (d1.Mes > d2.Mes)
                return true;

            return false;
        }

        public static bool operator <(Month d1, Month d2)
        {
            if (d1 == d2)
                return false;

            if (d1.Ano < d2.Ano)
                return true;

            if (d1.Ano > d2.Ano)
                return false;

            if (d1.Mes < d2.Mes)
                return true;

            return false;
        }

        public static bool operator >(Month d1, Month d2)
        {
            if (d1 == d2)
                return false;

            if (d1.Ano > d2.Ano)
                return true;

            if (d1.Ano < d2.Ano)
                return false;

            if (d1.Mes > d2.Mes)
                return true;

            return false;
        }

        public override bool Equals(object obj)
        {
            if (!(obj is Month))
                return false;

            return this == (Month) obj;
        }

        public override int GetHashCode()
        {
            return Ano.GetHashCode() ^ Mes.GetHashCode();
        }

        public int CompareTo(object obj)
        {
            Month d = (Month)obj;

            if (this < d)
                return -1;
            else if (this > d)
                return 1;

            return 0;

        }
    }

Mesma história dos Zumbis: implementei Equals(), e GetHashCode() e os operadores. Asism posso escrever código do tipo:

Data d1 = new Data(2000, 1);
Data d2 = new Data(2000, 1);
if (d1 == d2)
    doSomething();
else if (d1 > d2)
    doSomethingElse();
else if (d1 < d2)
    doEtc();

Com as classes do modelo implementadas, posso adicionar validações, testes e tudo mais, sem me preocupar com a camada de persistência, tornando a criação de testes unitários um trabalho bem simples. Mas este post não é sobre DDD.

Persistência != Teimosia

Vamos mapear nossas estimadas classes, usando o Fluent NHibernate, para que possam ir para o banco de dados. Comecemos com a classe Zombie, mapeada pela classe ZombieMap:

public class ZombieMap: ClassMap<Zombie>
{
    public ZombieMap()
    {
        Id(x => x.Id);
        Map(x => x.FormerName);
        Map(x => x.Infected);
    }
}

Bem simples, não? Isto nos informa que a classe Zombie será mapeada para uma tabela Zombie, com campos FormerName (com tipo nvarchar(255)) e Infected (com tipo … hmmm, calma aí, veremos adiante).

Vamos ver a classe City:

public class CityMap: ClassMap<City>
{
    public  CityMap()
    {
        Id(x => x.Id);
        Map(x => x.Name);
        Map(x => x.InfectionStart);
        HasMany<Zombie>(x => x.Zombies)
            .Access.CamelCaseField(Prefix.Underscore)
            .Cascade.AllDeleteOrphan()
            .AsBag();
    }
}

Também bem simples. A diferença aqui fica por conta do HasMany<Zombie>, cujo significado é bem simples, um City possui muitos Zombies.

Algo não tão óbvio é o Access.CamelCaseField(Prefix.Underscore). Isto diz que a propriedade Zombies possui um campo que serve de suporte, com nome escrito no estilo camelCase (diferente de PascalCase) e iniciado por um underscore. Se trata do campo _zombies, que é Zombies escrito em camelCase e iniciado por underscore.

Cascade.AllDeleteOrphans() informa ao NHibernate para apagar os Zombies órfãos, quer dizer, que não possuem um City.

AsBag() é mais complicado. Primeiro é preciso entender que o NHibernate lida com vários tipos de coleções: Set, Bag, Map e List. Cada uma com características próprias. No caso optei por bag, mas poderia ter usado list (que é um bag indexado).

Bom, resta agora a classe Month. Decidi não guardar o month em uma tabela própria. Ela nada mais é que uma data, onde apenas mês e ano importam. Então é apropriado guardá-lo em um campo DATETIME no banco de dados.

Para isso acontecer configuramos o NHibernate para tratar o Month como um DATETIME na hora de persistir tanto o City quanto o Zombie (campos Infected), criando uma classe que implementa a interface IUserType:

public class MonthUserType: IUserType
{
    public new bool Equals(object x, object y)
    {
        if (ReferenceEquals(x, y)) return true;

        if (x == null || y == null) return false;

        return x.Equals(y);
    }

    public int GetHashCode(object x)
    {
        return x == null ? typeof(Month).GetHashCode() : x.GetHashCode();
    }

    //voltando do BD: passar de datetime para Month
    public object NullSafeGet(IDataReader rs, string[] names, object owner)
    {
        var date = NHibernateUtil.DateTime.NullSafeGet(rs, names[0]) as DateTime?;

        if (date == null) return null;

        return new Month(date.Value.Year, date.Value.Month);
    }

    //indo pro BD: passar de Month para datetime
    public void NullSafeSet(IDbCommand cmd, object value, int index)
    {
        DateTime? date = null;

        if (value != null)
            date = ((Month) value).AsDateTime();

        NHibernateUtil.DateTime.NullSafeSet(cmd, date, index);
    }

    public object DeepCopy(object value)
    {
        return value;
    }

    public object Replace(object original, object target, object owner)
    {
        return original;
    }

    public object Assemble(object cached, object owner)
    {
        return cached;
    }

    public object Disassemble(object value)
    {
        return value;
    }

    public SqlType[] SqlTypes
    {
        get { return new[] { NHibernateUtil.DateTime.SqlType }; }
    }

    public Type ReturnedType
    {
        get { return typeof (Month); }
    }

    public bool IsMutable
    {
        get { return false; }
    }
}

Esta classe vai tratar do trabalho de converter de Month para DATETIME e vice-versa. Para usar nosso MonthUserType é necessário configurar os mapeamentos das classes City e Zombie:

Map(x => x.Infected).CustomType(typeof(MonthUserType));

Mas eu não usei esta abordagem. Imagine que tenhamos mais que essas duas classes para alterar ou que eu deseje deixar a configuração mais limpa. Podemos deixar os mapeamentos já configurados do mesmo jeito, e informar o NHibernate a usar o MonthUserType usando Convenções (Conventions).

Basta implementar uma classe com a informação de que nossa convenção é usar MonthUserType para persistir objetos Month:

    public class MonthUserTypeConvention: UserTypeConvention<MonthUserType>
    {
    }

É assim mesmo, vazio. No caso nem foi necessário realizar nenhum override dos métodos Apply() ou Accept().

E pronto! Suas classes estão prontas para serem persistidas no banco de dados.

Infraestrutura

Bom, mas para se gravar os dados no banco é preciso ao menos saber como se conectar ao banco. Vamos facilitar nossa vida criando um método fábrica de objetos fábricas (ou algo assim):

    public static class FluentSessionFactory
    {
        public static ISessionFactory CreateFactory(string connectionString)
        {
            return Fluently.Configure()
              .Database(MsSqlConfiguration.MsSql2005.ConnectionString(connectionString))
              .Mappings(
                m => m.FluentMappings
                    .AddFromAssemblyOf<City>()
                    .Conventions.AddFromAssemblyOf<MonthUserTypeConvention>()
              )
              .ExposeConfiguration(BuildSchema)
              .BuildSessionFactory();
        }

        private static void BuildSchema(Configuration config)
        {
            SchemaExport schema = new SchemaExport(config);
            schema.Drop(false, true);
            schema.Create(false, true);
        }

    }

Note que meu banco é um Sql Server 2005. Acerte o código para teu banco de dados. E para usar:

ISessionFactory factory = FluentSessionFactory.CreateFactory(@"Database=test_db;Server=localhost\sqlexpress;user=theuser;pwd=thepassword;");
ISession session = factory.OpenSession();
/** cria objetos e manda para o bd usando Session.Save(objeto) **/
session.Close();

Mas tome cuidado. Note um schema.Drop() e um schema.Create() lá em cima. Eles jogam as tabelas do banco fora e depois recriam-nas. Bom para o ambiente de desenvolvimento. Ruim para ambiente de produção. Muito ruim.

1, 2, 3 Testando

Nada melhor que usar testes automatizados para verificar se está tudo funcionando. Quer dizer, comer camarão na praia tomando cerveja é melhor que isso, mas vamos lá.

O Fluent NHibernate conta com um método muito útil para verificar se os mapeamentos estão redondinhos. Se trata do PersistenceSpecification.VerifyTheMappings().

Veja como é simples:

[TestClass]
public class CityMapTest
{
    private static readonly string ConnString = @"Database=db_test;Server=localhost\sqlexpress;user=theuser;pwd=thepassword;";
    private static ISession Session;

    private TestContext testContextInstance;

    public TestContext TestContext
    {
        get
        {
            return testContextInstance;
        }
        set
        {
            testContextInstance = value;
        }
    }

    [ClassInitialize()]
    public static void MyClassInitialize(TestContext testContext)
    {
        ISessionFactory factory = FluentSessionFactory.CreateFactory(ConnString);
        Session = factory.OpenSession();
    }

    [ClassCleanup()]
    public static void MyClassCleanup()
    {
        Session.Close();
    }

    [TestMethod]
    public void CrudTest()
    {
        new PersistenceSpecification<City>(Session)
            .CheckProperty(x => x.Id, 1)
            .CheckProperty(x => x.Name, "Raccoon City")
            .CheckProperty(x => x.InfectionStart, new Month(1998, 8))
            .CheckList(
                x => x.Zombies,
                new []
                {
                    new Zombie { FormerName  =  "John Doe", Infected = new Month(1998, 7) },
                    new Zombie { FormerName  =  "José da Silva", Infected = new Month(1998, 6) }
                },
                (r, z) => r.AddZombie(z))
            .VerifyTheMappings();
    }
}

Ao executar o teste acima serão criadas as tabelas City e Zombie no banco de dados, que serão preenchidas com os dados fornecidos. Depois esses dados serão lidos e convetidos em objetos do sistema. Daí estes objetos serão comparados com os objetos originais. Se estiver tudo ok, o teste sinalizará verde. Se não, hora de corrigir bugs.

E é isso. Ah, para quem quiser o código do projeto…

Erro

Exceções do .Net

Uma lista de exceções úteis para utilizar em seu sistema, sem ter que criar sempre outra classe e escrever mais código.

Ultimamente tenho pensado numa programação Zen: o melhor código é o não-código. Quanto menos código você escrever, menos terá para manter, menos terá para entender, menos terá para depurar. Ou talvez esteja exacerbando apenas a melhor qualidade de um programador.

Chega de papo-furado, segue a lista (todas no namespace System):

ApplicationException The exception that is thrown when a non-fatal application error occurs.
ArgumentException The exception that is thrown when one of the arguments provided to a method is not valid.

ArgumentNullException

The exception that is thrown when a null reference (Nothing in Visual Basic) is passed to a method that does not accept it as a valid argument.

ArgumentOutOfRangeException

The exception that is thrown when the value of an argument is outside the allowable range of values as defined by the invoked method.

ArithmeticException

The exception that is thrown for errors in an arithmetic, casting, or conversion operation.

ArrayTypeMismatchException

The exception that is thrown when an attempt is made to store an element of the wrong type within an array.

FieldAccessException

The exception that is thrown when there is an invalid attempt to access a private or protected field inside a class.

FormatException

The exception that is thrown when the format of an argument does not meet the parameter specifications of the invoked method.

IndexOutOfRangeException

The exception that is thrown when an attempt is made to access an element of an array with an index that is outside the bounds of the array. This class cannot be inherited.

InvalidOperationException

The exception that is thrown when a method call is invalid for the object’s current state.

NotFiniteNumberException

The exception that is thrown when a floating-point value is positive infinity, negative infinity, or Not-a-Number (NaN).

NotImplementedException

The exception that is thrown when a requested method or operation is not implemented.

NotSupportedException

The exception that is thrown when an invoked method is not supported, or when there is an attempt to read, seek, or write to a stream that does not support the invoked functionality.

NullReferenceException

The exception that is thrown when there is an attempt to dereference a null object reference.

ObjectDisposedException

The exception that is thrown when an operation is performed on a disposed object.

PlatformNotSupportedException

The exception that is thrown when a feature does not run on a particular platform.

RankException

The exception that is thrown when an array with the wrong number of dimensions is passed to a method.

SystemException

Defines the base class for predefined exceptions in the namespace.

TimeoutException

The exception that is thrown when the time allotted for a process or operation has expired.

TypeInitializationException

The exception that is thrown as a wrapper around the exception thrown by the class initializer. This class cannot be inherited.

UnauthorizedAccessException

The exception that is thrown when the operating system denies access because of an I/O error or a specific type of security error.

Fonte: http://mikevallotton.wordpress.com/2009/07/08/net-exceptions-all-of-them/

Wodpress Logo

WordPress 3.0

Atualizei o site para o WordPress 3.0, em PT-BR e, como sempre, sem problemas! E junto vem o novo tema default Twenty Ten, que finalmente substitui o tema anterior, Kubrick.

E não é só para dar um tapa no visual, o novo tema mostra os novos recursos do WordPress, como podemos ver no vídeo.

Acho que está na hora de trocar a cara do site (se bem que, com o Google Reader e demais leitores de feeds, ninguém mais visita blogs)

butler

Erro no deploy automático: Hudson versus MSBuild

Usamos o excelente Hudson como servidor de integração contínua, junto do plugin MSBuild.

O fiel mordomo

Mas estes dias criei um projeto no Hudson, referente à uma solução já no framework .NET v4, escrita no Visual Studio 2010 (v10).

O primeiro passo foi entrar nas configurações do Hudson e criar outra entrada para o plugin MSBuild, apontando para a versão 4 do mesmo. Basta ir para Gerenciar HudsonConfigurar SistemaMSBuild e incluir:

C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe

Feito isto, configurei o novo projeto para usar esta nova entrada do MSBuild. E o projeto falhou na construção com a seguinte mensagem:

error MSB4019: The imported project "C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" was not found. Confirm that the path in the <Import> declaration is correct, and that the file exists on disk.

O jeito foi atender a demanda: criei as respectivas pastas e copiei o arquivo do meu micro para o servidor. Pronto. Agora só resta resolver alguns pepinos com assemblies

Update: parece que preciso instalar ou o Visual Studio 2010 ou o Windows 7 SDK  no servidor em questão. Mas ocorrem dois problemas: (1) o VS2010 é caro e (2) o SDK ainda não saiu. O jeito é aguardar meados de junho.

Apps favoritos no Milestone

Logo que consegui meu Motorola Milestone publiquei um post com os apps mais interessantes que encontrei. Passado quase 5 meses com o aparelho, e já com o Android 2.1 nos circuitos, é hora de mais uma lista!

Permaneço fie à alguns apps, como o APNDroid, NetCounter, MotoID,  Nesoid e o SNesoid. Mas muita coisa mudou.  O Twidroid eu deixei de lado pelo Seesmic, que também foi deixado de lado.  O wpToGo foi descontinuado, com o programador sendo contratado pela própria WordPress. O site da Wikipédia se tornou um exemplo de site projetado para browsers de dispositivos móveis, tornando o Wapedia quase obsoleto.

twitter para Android

É o cliente oficial do twitter, para Android. Possui uma excelente integração com o resto do sistema. Embora o Seesmic também seja excelente e venha com um bom widget, o twitter oficial será páreo duro. Só precisa de um tema com mais culhões.

EStrongs File Explorer

Um gerenciador de arquivos. Permite que você copie, cole, apague e abra tudo que estiver em seu SD, numa rede local ou até num ftp.

EStrongs Task Manager

Gerenciado de tarefas que as apresenta de uma maneira mais clara que o do próprio Android.

Super Mario Sounds & Ringtones

Este aqui baixei para poder personalizar as notificações. Ao receber um SMS ouço o som de um cogumelo verde.

Evernote

Um caderno de notas. Eu uso para visualizar as notas que guardo. Para criar as notas eu so o  email mesmo. É mais prático. Mas o app é bom para guardar fotos com comentários. Bem útil para levar nas lojas e mercados, para comparar os preços em outros lugares.

Para subir imagens no Flickr e notas no Evernote, como comentei acima, uso o bom e velho email (ou Gmail).

Dropbox

Dropbox. Em seu bolso.

Raging Thunder 2 Lite

Algo que sinto falta no Android são jogos bons. Que tenham produção caprichada, música e gráficos idem. Este jogo, apesar de ser uma versão light, atende a estes quesitos.  Finalmente um jogo que usa o poder do Milestone.  Muito bacana para jogar no metrô ou na fila.

MotoTorch LED

Finalmente uma lanterna útil. Diferente dos outros apps flashlight, este aqui não usa a tela do aparelho. Ele usa o flash LED, o mesmo da câmera. Ilumina bem mais, além de ser mais direcionável. E ainda vem com um widget para facilitar o uso. Uma mão na roda para quando falta luz.