Um código limpo diz mais que mil comentários

July 21st, 2010 No comments

Você comenta seu código? Sim? Por quê?

Cuidado! Comentários podem ser perigosos! O uso deles pode ser um indício de que seu código está confuso e você tem medo de precisar alterar algo mais tarde e esquecer o que aquela variável aux armazena.

A forma mais elegante de se remover comentários é refatorando. Aux é um nome sem sentido, você pode até lembrar o que essa variável significa enquanto você ainda está programando, mas daqui duas semanas você já vai ter esquecido. Nomeie melhor suas variáveis, não tenha medo de ter uma variável assim: listaDeClientesInativos ao invés de lista.

Outro caso bastante comum de comentários é quando você tem aquele método gigante com 100 linhas e a cada 10 você resolve colocar um comentário para dizer o que está acontecendo. Nestes casos você pode (e deve) utilizar extract method. Divida seu grande método em outros pequenos, assim você pode substituir os comentários por métodos com nome auto-explicativos, além disso estará de acordo com o Single responsibility principle.

Não é possível garantir que outras pessoas do seu time irão atualizar o comentário quando alguma alteração for feita. Pior do que ter um método cheio de comentário é ter um método com um comentário obsoleto. Além disso, a leitura do comentário é opcional, você não tem como saber se seu comentário será lido ou não. Se você tem algo importante para dizer, diga no seu código, através de nomes bem definidos e código limpo.

Dito tudo isso, não preciso nem comentar sobre o exemplo abaixo né?

//Chamado #213: Corrigido bug onde o desconto final estava sendo somado ao invés de descontar.
int total = pedido.getTotal() - descontoFinal;

Se você faz isso, sugiro procurar algum software de controle de versão.

Algum tempo atrás escrevi sobre Expressões Regulares (aqui) e falei sobre comentários em Regex pattern. Continuo achando uma forma elegante de se utilizar comentários já que um pattern quase nunca é limpo, é sempre complicado ler aquilo e entender. Os comentários ajudam neste caso tornando-o mais legível. Outra opção seria escrever testes automatizados para seu Regex. Além dos testes servirem como exemplos de uso, você estará tendo uma maior cobertura do seu código e a garantia de poder alterar o pattern sem medo de inserir um novo bug.

Falando em Regex e Testes, lembrei deste tweet do @gchapiewski.

It’s impossible to program complex regular expressions without TDD. Period.

Resumindo. Mais código limpo e menos comentários. Ah, não esqueça de ler o livro Clean Code. :)

Evitando o excesso de ‘null check’ (continuação)

July 10th, 2010 No comments

Conforme comentado no outro post, vou descrever aqui outra forma de evitar a verificação de um objeto nulo. Este tipo de verificação que é tão usada causa um bad smell tremendo.

Imagine a seguinte funcionalidade de um sistema de vendas e-commerce:

Quando nós enviarmos um pedido para um cliente que comprou em nossa loja, nós queremos que este cliente seja avisado que seu produto já foi deixado nos correios. Gostariamos de enviar um SMS para os clientes que consideramos ótimo e um e-mail para aqueles que achamos que são bons clientes. Qualquer outro cliente não deve receber o aviso, se ele tiver interesse ele passa no site e verifica o status.

Então, modelando esta user story, podemos ter uma interface chamada de Notificador e algumas implementações como NotificadorViaSms e NotificadorViaEmail. Isso nos permite que em um dado momento possamos incluir algum outro tipo de notificador, por exemplo, NotificadorViaTwitter.

Pois bem, tendo múltiplas implementações eu vou precisar de um factory que vai ser responsável por criar um notificador baseado no tipo do cliente. Aqui vai um exemplo do código:

public class NotificadorFactory {
	public static Notificador cria(Pedido pedido) {
		if (pedido.getCliente().getTipo() == TipoCliente.Otimo)
			return new NotificadorPorSms(pedido);
		else if (pedido.getCliente().getTipo() == TipoCliente.Bom)
			return new NotificadorPorEmail(pedido);
		else
			return null;
	}
}

Seu uso ficaria assim:

Cliente maria = new Cliente("Maria", TipoCliente.Otimo);
Pedido pedido2 = new Pedido(maria);
pedido2.setTotal(520.10f);

Notificador notificador = NotificadorFactory.cria(pedido2);
notificador.enviar();

Então, o que acharam? Ficou legal, não? Eu gostei :) (só não gostei do nome da factory e do seu método, mas não é esse o objetivo).

Só que este código tem um problema. E se a cliente “maria” fosse do tipo Ruim ao invés de Otimo? Segundo a minha user story, eu não deveria avisar ela. Minha factory está correta, se o cliente for do tipo Ruim ela não vai retornar nenhum Notificador, vai retornar null. Quando meu código cliente for chamar o método enviar() vai surgir um NullPointerException.

Solução: coloca um “if notificador != null” antes de chamar o método. Yeah! Resolvemos o problema, mas criamos outro… Em todo lugar que você for usar o NotificadorFactory você vai ter que se lembrar de que ele pode retornar um valor nulo, e por isso será necessário verificar se o retorno é nulo na maioria das chamadas.

Outra solução seria aplicar o Null Object Pattern. Segundo a definição encontrada no Wikipedia:

Original:

In object-oriented computer programming, a Null Object is an object with defined neutral (“null”) behavior. The Null Object design pattern describes the uses of such objects and their behavior (or lack thereof).

Traduzido:

Em programação orientada a objetos, um Objeto Nulo é um objeto que possui comportamento neutro (nulo). O padrão de projeto Null Object descreve o uso de tais objetos e seu comportamento (ou a falta dela).

De forma simplificada, o Objeto Nulo segundo o padrão de projeto é um objeto que não faz nada, que possui um comportamento neutro. Em nosso caso poderiamos ter um notificador chamado NotificadorVazio que seria criado pelo NotificadorFactory ao invés de retornar null. Sendo assim, o código cliente ficaria livre para utilizar o retorno da factory sem se preocupar com NullPointerException pois o retorno nunca seria nulo. Curioso para saber como fica a implementação do NotificadorVazio? Olha que simples:

A Interface:

public interface Notificador {
	void enviar();
}

A implementação nula:

public class NotificadorVazio implements Notificador {
	@Override
	public void enviar() {
		//Não fazer nada
	}
}

A factory:

public class NotificadorFactory {
	public static Notificador cria(Pedido pedido) {
		if (pedido.getCliente().getTipo() == TipoCliente.Otimo)
			return new NotificadorPorSms(pedido);
		else if (pedido.getCliente().getTipo() == TipoCliente.Bom)
			return new NotificadorPorEmail(pedido);
		else
			return new NotificadorVazio();
	}
}

Pronto, resolvemos o problema de forma organizada, orientada a objetos e utilizando padrões bem definidos.

Até mais :D

Retrospectiva ~ Agile Brazil 2010

June 27th, 2010 1 comment

Nos dias 24 e 25 de Junho estive presente no Agile Brazil 2010, a maior conferência de agilidade do Brasil. Gostei bastante do evento, muito bem organizado para um evento tão barato e sem fins lucrativos. Tivemos a presença de várias estrelas internacionais como Martin Fowler, Philippe Kruchten, David Hussman entre outros.

Não vou falar passo-a-passo como foi o evento porque não faz muito sentido já que muita gente estava lá. E quem não estava é só pesquisar no Twitter pela hashtag #agilebrazil.

Achei muito bom o workshop sobre modelagem ágil do Rodrigo Yoshima e do Phillip Calçado. Pelo o que eu vi e entendi, modelagem é tudo aquilo que ajuda a entender um problema, desde uma frase, um desenho ou um fluxograma. É engraçado saber que aquilo eu faço na empresa é modelar, eu não sabia disso.

Quando iniciamos o projeto do Greenbi, estabelecemos uma meta de 3 dias para finalizar. Não havia tempo para criar documentos e muito menos criar diagramas UML ou esboço das telas em HTML. O que fizemos? Pegamos algumas folha A4, algumas canetas e colocamos no papel tudo aquilo que vinha em nossa mente em forma de desenho. Aquele papel serviu de base para todo o projeto. E como disse o Phillip Calçado durante o workshop: “O mais legal desse tipo de modelagem é que, se em algum momento você perceber que fez errado, você simplesmente rasga e joga fora.”.

Durante a palestra do Giovanni Bassi deu para entender de fato a diferença entre ser Ágil e ser Rápido. Acho que essa imagem que o Giovanni colocou no slide diz tudo:

O coiote é rápido,  o papa-léguas é ágil. Preciso explicar algo? :)

Algumas outras palestras e keynotes também chamaram atenção, principalmente a do Fowler falando da importância do Software Design. Além disso, foi apresentado sobre Continous Integration e Deployment, apesar de já ter lido muito sobre o assunto consegui aprender muita coisa.

Não foi um evento onde consegui aprender muitas coisas novas, foi uma oportunidade para lapidar o que já conheço e corrigir algumas definições erradas que eu tinha. Em geral, nota 10, espero poder ir no Agile Brazil 2011. Aliás, tem a presença confirmado do Ken Schwaber.

http://en.wikipedia.org/wiki/Ken_Schwaber
Categories: Eventos Tags: , ,

Evitando o excesso de ‘null check’

June 6th, 2010 No comments

Que atire uma pedra aquele que ainda não está cansado de ver/escrever código assim:

public Departamento insere(Integer codigo, String descricao) {
    if (descricao == null) || (descricao.equals("")) {
        //faz alguma coisa
    }
}

Poxa, é impossível. Cada desenvolvedor deve escrever isso no mínimo umas 10 vezes por dia. Se você faz isso todo dia, acha um saco e nunca achou uma maneira para resolver esse ‘problema’, eis a solução:

public Departamento insere(Integer codigo, String descricao) {
    //faz alguma coisa
}

Simples não? Problema resolvido.

A documentação deve deixar bem claro que este método não aceita nulo ou vazio no parâmetro ‘descricao’.

NOOOOOOOO! Null Pointer Exception.

NOOOOOOOO! Null Pointer Exception.

Se este método for interno à sua aplicação, fica fácil, você sabe que as classes que irão chamar este método precisam estar escritas de tal maneira que não passe nenhum valor nulo ou vazio, caso contrário, haverá algumas excessões não esperadas.
Se você prestar atenção, ao remover essas verificações de toda a hierarquia de classes, as únicas classes que realmente irão precisar da verificação são as classes que interajem com a interface do usuário.

Agora se seu método estiver exposto em um WebService, isso significa que outros desenvolvedores poderão chamar este método e você não tem controle sobre o que estes desenvolvedores irão passar para o método. Neste caso, ainda assim, deixe o método sem as verificações e faça-as nas interfaces do WebService. Crie pré-condições para seus serviços, deixe claro que o parâmetro descrição deve conter algum valor. Se a condição estiver válida, você pode chamar o método tendo a garantia de que não haverá excessões.

É comum que quando nos deparamos com um erro de NullReferenceException (C#) ou NullPointerException (Java) no log da aplicação, a primeira coisa que fazemos é ir direto na linha que deu erro e adicionar a verificação se é nula apenas para que não ocorra tais erros. Se um valor nulo chegou até ali é porque ele deveria ter parado em algum lugar antes, geralmente na camada entre a interface do cliente e o código de negócio.

Lembre-se do princípio da responsabilidade exclusiva! Não é responsabilidade do método ‘insere’ garantir que os parâmetros estejam válidos.

Além deste caso onde você pode ter problemas com parâmetros nulo, existem lugares em que você faz a verificação de nulo com o retorno de um método, ficando mais ou menos assim:

Departamento depto = dao.insere(1, "Compras");
if (depto != null) {
    //Faz algo
}

E nesses caso, como se comportar? Isso vai ficar para o próximo post, lá eu falo sobre isso e um pattern relacionado, chamado de Null Object Pattern. Até mais!

Edit #1: O post sobre Null Object Pattern é este aqui.

Conselho do Tio Bob

May 22nd, 2010 No comments

Esse vídeo foi gravado já faz um tempo pelo Fabio Akita e foi postado no blog dele. Eu acho este vídeo tão bom que resolvi colocá-lo aqui, talvez alguém ainda não tenha visto.

100% de Code Coverage?

May 20th, 2010 No comments

De forma simplificada,  o code coverage é uma métrica usada em testes automatizados que aponta o percentual de linhas de código que estão sendo cobertas pela suite de teste. Ter 100% de coverage significa que toda linha do seu código de produção está sendo executada pelo menos uma vez.

Sabendo disto, lhe pergunto, o que você ganha ao atingir 100%?

Ter um software com 100% de cobertura de testes não significa que seu software é bug-free e muito menos que ele é melhor que um software que possui apenas 80%. Além disso, eu poderia até dizer que 100% de cobertura é quase impossível. Nos projetos em que eu tentei cobertura total, geralmente eu conseguia no máximo 95% usando testes um tanto quanto inúteis, apenas para aumentar o percentual. O maior problema ao estabelecer uma meta de 100% é que seu foco ao escrever um teste acaba se voltando para atender esta meta, e não mais para testar um requisito.

Um adepto de TDD geralmente terá perto de 90% de coverage. Porquê? Porque se você escreve o teste antes, ao codificar o código de produção você fará apenas o necessário para o teste passar, nem uma linha de código a mais, nem a menos, ou seja, 100%. Em todo caso, por algum motivo de seu framework ou linguagem, você é obrigado a escrever algumas linhas não esperadas no seu teste, e isso vai fazer seu coverage baixar, por isso o 90%.

Eu não tenho o costume de verificar o coverage constantemente, executo apenas uma vez ou outra para ter uma idéia de como está a situação. Se está muito baixo, e eu considero baixo até 80%, eu busco encontrar o que está baixando tanto assim minha coberturda. As vezes é porque um método que foi criado e que não é mais utilizado ainda está dentro de uma classe, ou então uma classe que por algum motivo eu esqueci de testar. Enfim, para mim, 80% ~ 100% é um valor aceitável.

Para quem nunca usou code coverage em C#, eu recomendo baixar o plugin TestDriven.Net que já vem com diversos frameworks de teste como MbUnit e NUnit além do NCover.

Veja abaixo uma imagem das informações mostradas pelo NCover. Aquele percentual vermelho ali mostra que apenas X% das linhas daquela classe estão sendo executadas no teste. Por exemplo a classe CodeUtil (0%), não possui teste nenhum.

Model Binding de enumeration no Struts2

May 9th, 2010 No comments

Depois de perder 1 dia inteiro pesquisando e de inúmeras tentativas falhas de como usar o model binding do struts2 com enumerations do Java5, eu finalmente encontrei a solução em um site Japonês. Sim, Japonês. Não entendi nada do que estavam falando, mas consegui entender parte do código, o que foi suficiente.

Resolvi registrar para ajudar quem estiver passando pelo mesmo problema. Infelizmente não tenho o link da onde tirei a solução, se eu achar novamente, eu coloca aqui a fonte.

Usando a seguinte enum e entidade:

public enum Sexo {
    Masculino, Feminino
}

public class Cliente {
    private Sexo sexo;
    public void setSexo(Sexo sexo) {
        this.sexo = sexo;
    }
    public void setSexo(String sexo) {
        this.sexo = Sexo.valueOf(sexo);
    }
    public Sexo getSexo() {
        return this.sexo;
    }
}

A view ficaria assim:

<select name="cliente.sexo">
	<option <s:if test="%{cliente.sexo == @com.pacote.Sexo@Masculino}">selected="selected"</s:if> value="Masculino">Masculino</option>
	<option <s:if test="%{cliente.sexo == @com.pacote.Sexo@Feminino}">selected="selected"</s:if> value="Feminino">Feminino</option>
</select>

Neste caso, estou considerando que a action tenha uma propriedade do tipo Cliente com nome cliente.
Eu havia tentado de tudo ali nos atributos values da tag option, principalmente 0 e 1 por estar acostumado com o ASP.NET MVC. Mas acabei descobrindo que nas values o correto é ir o nome dos valores da enumeração e a entidade precisa ter um método set que receba uma string. Veja na classe Cliente o método setSexo(String), dentro dele, apenas converto para a enumeração.

Até a próxima!

CSharpista falando Javanês, minha opinião sobre o Java

May 9th, 2010 No comments


Até duas semanas atrás, meu conhecimento de Java beirava o nulo. Eu já conhecia a sintaxe, afinal, é parecida com C#. Conhecia alguns frameworks famosos também, como o Hibernate e log4j, mas colocar a mão na massa, nunca.

O projeto em que eu iria iniciar tinha como pré-requisito ser escrito em Java, com isso, tive que aprender linguagem e alguns de seus frameworks. Foi e está sendo uma experiência bem legal, e por isso resolvi compartilhar ela, bem como falar um pouco da minha opinião sobre o Java.

Sintaxe e Padrões

Preciso adminir que sou fã da forma como é implementado o get/set em C#, acho o resultado muito mais legível e de fácil compreensão. Um pequeno comparativo:

Em C#:

//definição
public class Cliente
{
    public string Nome { get; set; }
    public int Idade { get; set; }
}

//uso
public class ClienteController
{
    public void Adicionar()
    {
        Cliente cliente = new Cliente();
        cliente.Nome = "João Salsa";
        cliente.Idade = 23;

        if (cliente.Idade > 20)
        {
            //stuff
        }
    }
}

Em Java:

//definição
public class Cliente {
    private String nome;
    private Integer idade;

    public void setNome(String nome) {
        this.nome = nome;
    }

    public String getNome() {
        return this.nome;
    }

    public void setIdade(Integer idade) {
        this.idade = idade;
    }

    public String getIdade() {
        return this.idade;
    }
}

//uso
public class ClienteController {
    public void adicionar() {
        Cliente cliente = new Cliente();
        cliente.setNome("João Salsa");
        cliente.setIdade(23);

        if (cliente.getIdade() > 20) {
            //stuff
        }
    }
}

Self-explanatory, além de menor, fica mais fluente, não?

A questão das chaves também me chamou a atenção. Tanto no PHP quanto no Java, o padrão é utilizar as chaves na mesma linha da instrução, já no C#, na linha abaixo. Neste ponto eu fico com o padrão do Java. Compare o if dos dois códigos acima, se no lugar do comentário “//stuff” tivesse realmente uma única instrução, no Java ficaria mais junto e fácil de ler. Eu sei que não há necessidade de se usar chaves nestes casos, mas eu gosto.

IDE (eclipse)

Algumas hotkeys do eclipse são interessantes, por exemplo, o CTRL+SHIFT+T. Este atalho abre uma janela para pesquisar classes pelo nome usando wildcards, * e ?. Vejam a imagem abaixo:


Imagem retirada de Java Place Blog

Existe isso no Visual Studio? Eu quero :D

Outro recurso do eclipse que gostei bastante foi o do highlight que ele faz quando você clica em alguma variável ou método, vejam só:


Imagem retirada de satukubik

Ah, outro detalhe importante. Levei menos de 2 minutos para “instalar” o eclipse contra as quase 1 hora que leva o Visual Studio. Copy and Paste definitivamente é melhor que Next, Next, Finish. E isso ocorreu com tudo o que eu precisei instalar de Java na máquina: Tomcat, Eclipse e JBoss. Apenas a JDK foi no instalador. Kick ass, definitivamente.

Frameworks

Até o momento tive pouco contato com os frameworks Java, mas é impossível não falar do maven. Caramba, que fantástico, é muito útil mesmo, e até o momento não tive nenhum problema com ele. De forma simplificada, é um framework onde você define quais são as dependências do seu projeto e ele se encarrega de montar seu projeto com todas as dependências definidas, fazendo download e adicionando as referências necessárias.

Outros frameworks que tive contato foram Struts2 e JSF. Pelo o que pudi perceber, o JSF é para o ASP.NET WebForms o que o Struts2 é para o ASP.NET MVC. Eu, sendo fã de ASP.NET MVC, optei por usar Struts2. De modo geral, eu estou gostando, alguns itens como model binding e configuração deixam a desejar. A configuração é toda feita em arquivos *.xml e cada dia que passa os xml estão ficando maiores. Saudade do ASP.NET MVC onde eu configurava as rotas via C# e com sintaxe fluente…

Tirando essa parte da configuração, achei bem fácil de customizar os filters, results e interceptor, não tive que ir em nenhum tutorial, descobri sozinho, e isso só mostra o quanto é fácil.

Quanto ao JSF, um dia foi suficiente para eu largá-lo. Muita semelhança com o ASP.NET WebForms me deixou com medo, a falta de controle no HTML foi um dos motivos maiores, além disso a curva de aprendizado do JSF foi maior que o Struts2. Não fui muito a fundo no JSF, posso ter me enganado, mas a primeira impressão não agradou.

Comunidade

Aqui é que geralmente a maior partes das intrigas são geradas. Conforme este meu post, acho o GUJ um excelente fórum de discussão de alto nível. Vejo que falta isso na comunidade .NET, as dúvidas que surgem em alguns fórum são geralmente relacionados às funções de wizard e drag and drop do Visual Studio. É mais fácil achar uma discussão de algum design pattern ou arquitetura em um grupo de Java do que em um de C#.

Felizmente as coisas estão mudando, a grande movimentação que há no grupo de discussão .Net Architects prova que existe muita gente interessada em aprender e discutir este tipo de assunto.

Conclusão

Cada linguagem/plataforma tem seu espaço e momento, nunca vi uma discussão entre duas linguagens que tivesse um fim. Além disso, cada pessoa tem sua preferência e sua opinião, e devemos saber respeitá-las. Eu, por exemplo, não me dou bem com Ruby, já tentei, mas não consigo, eu prefico ficar com PHP e Python. Não digo que Ruby é ruim ou qualquer coisa do tipo, apenas não gosto. Eu não gostava de Java até então, achava tudo muito complicado, agora já estou mudando de opinião, conforme eu fui aprendendo, fui vendo que não é um bixo de 7 cabeças.

Gostei de Java, adorei a oportunidade que estou tendo de aprender, consegui sair um pouco do meu mundinho csharpista e abriu algumas portas em minha mente, porém, minha preferência continua sendo C#, I love it <3 :D

Dica #5: Escondendo teclado no Windows Mobile com C#

February 6th, 2010 No comments

Olá a todos,

Neste post vou explicar como remover o teclado dos smartphones que possuem windows mobile. Além disso, vou repassar uma dica de como utilizar esse recurso com maior eficiência, prontos?

Porque eu deveria esconder o teclado?

Talvez você esteja se perguntando isso neste momento, é simples, imagine uma tela onde há apenas botões e nenhum campo para digitar, faz sentido dar ao usuário um teclado que ele não vai usar? É muito mais prático remover o teclado e evitar que ele aperte acidentalmente e deixar apenas o que importa na tela.

Como fazer?

Essas funções que envolvem alterações no core são feitas através de P/Invoke. Basicamente, são chamadas feitas à DLLs do próprio sistema operacional através do C#.

Sem mais delongas, vou colocar aqui uma classe com um método para remover o teclado, e é claro, outro para fazer o teclado aparecer novamente.

public static class Keyboard
{
    [DllImport("coredll.dll")]
    private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

    [DllImport("coredll.dll")]
    private static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd);

    [DllImport("coredll.dll")]
    private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

    private static void SetSipButton(bool show)
    {
        IntPtr hSipWindow = FindWindow("MS_SIPBUTTON", "MS_SIPBUTTON");
        if (hSipWindow != IntPtr.Zero)
        {
            IntPtr hSipButton = GetWindow(hSipWindow, 5);
            if (hSipButton != IntPtr.Zero)
                ShowWindow(hSipButton, (show) ? 1 : 0);
        }
    }

    public static void Hide()
    {
        SetSipButton(false);
    }

    public static void Show()
    {
        SetSipButton(true);
    }
}

Para usar é muito fácil. Quer esconder o teclado? Basta escrever:

Keyboard.Hide();

E agora você quer fazer o teclado voltar ao normal?

Keyboard.Show();

Difícil? :}

Agora há um problema, se você colocar isso em todo formulário que você for fazer, você vai repetir este código x vezes, onde x é a quantidade de formulários que você possui.
No coméco eu disse que eu daria uma dica, e a dica é para resolver isso.

Dica

Crie dois formulários que servirão de base. Chame um de KeyboardForm e outro de NoKeyboardForm, faça com que ambos formulários herdem de Form.

No formulário KeyboardForm coloque o código para MOSTRAR o teclado, no formulário NoKeyboardForm coloque o código para ESCONDER o teclado.

Toda novo formulário que você criar, ao invés de herdar de Form (padrão), faça ele herdar de KeyboardForm caso sua tela tenha necessidade de um teclado, caso contrário, herde de NoKeyboardForm.

Simples, elegante, eficiente, e como diria o Steve Jobs, “amazing”, “incredible”, “awesome”, “great”.

Abaixo estou deixando um pacote com uma solução que eu fiz no Visual Studio 2008 com exemplos de uso. É só baixar, abrir e executar.

Clique aqui para fazer o download de 'Removendo teclado no Windows Mobile' (40.28 kB)

Espero ter ajudado.

Configurar NHibernate em um projeto Web

January 14th, 2010 7 comments

Neste tutorial vou explicar como dar o primeiro passo com o NHibernate. A configuração não é nada trivial e por isso gera bastante dúvidas.

Vou estar usando a versão mais recente do NHibernate até o momento, se você quiser usar a mesma versão, utilize este link para fazer o download.

Primero passo, criando a estrutura de projetos

Abra o Visual Studio, crie um projeto Web Application e uma Class Library na mesma solução. Vai ficar assim:

Obs.: Eu tenho o costume de deletar a pasta App_Data e a classe Class1 porque não vou utilizar.

Segundo passo, criando o arquivo de configuração

Dentro do projeto Class Library, crie um xml e chame-o de hibernate.cfg.xml. Atenção, é hibernate e não nhibernate!

Dentro deste arquivo ficam as configurações do banco de dados que iremos usar. Aqui será informado qual o provider (sqlserver, mysql, oracle etc), qual a string de conexão, dialeto etc.

Estou usando MSSQL Server e meu arquivo de configuração ficou assim:


<?xml version="1.0" encoding="utf-8"?>
<hibernate-configuration  xmlns="urn:nhibernate-configuration-2.2" >
 <session-factory name="NHibernate">
 <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
 <property name="connection.connection_string">Server=(local);initial catalog=MinhaBase;Integrated Security=SSPI</property>
 <property name="show_sql">false</property>
 <property name="dialect">NHibernate.Dialect.MsSql2000Dialect</property>
 <property name="query.substitutions">true 1, false 0, yes 'Y', no 'N'</property>
 <property name="proxyfactory.factory_class">NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle</property>
 <mapping assembly="MercadoVader.NHibernateModule" />
 </session-factory>
</hibernate-configuration>

Obs.: A única configuração que muda entre meu arquivo e o seu será a string de conexão. No meu caso estou usando localhost com um banco de dados chamado e usando windows authentication.

Clique com o botão direito no arquivo hibernate.cfg.xml e vá em suas propriedades, na opção Copy to Output Directory escolha o valor Copy Always.

Terceiro passo, banco de dados

Não há muito segredo aqui, apenas crie uma base de dados e rode este script para criar uma tabela de produtos.


CREATE TABLE [dbo].[PRODUTO](
 [ID] [int] IDENTITY(1,1) NOT NULL,
 [NOME] [varchar](100) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
 [PRECO] [decimal](18, 2) NOT NULL,
 [DATA_CADASTRO] [datetime] NOT NULL,
 CONSTRAINT [PK_PRODUTO] PRIMARY KEY CLUSTERED
(
 [ID] ASC
)WITH (PAD_INDEX  = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]

Terceiro passo, banco de dados

Não há muito segredo aqui, apenas crie uma base de dados e rode este script para criar uma tabela de produtos.


CREATE TABLE [dbo].[PRODUTO](
 [ID] [int] IDENTITY(1,1) NOT NULL,
 [NOME] [varchar](100) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
 [PRECO] [decimal](18, 2) NOT NULL,
 [DATA_CADASTRO] [datetime] NOT NULL,
 CONSTRAINT [PK_PRODUTO] PRIMARY KEY CLUSTERED
(
 [ID] ASC
)WITH (PAD_INDEX  = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]

Quarto passo, criando um HttpModule pro NHibernate

Essa parte é mais chata, primeiro de tudo, selecione o projeto Class Library e adicione referência à NHibernate.dll que está na pasta Required_Bin dentro do arquivo zip que foi baixado no início do tutorial. Adicione também uma referência à NHibernate.ByteCode.Castle que também veio no arquivo zip. Por último, adicione referência à System.Web, será necessário para poder criar uma classe que herde da System.Web.IHttpModule.

Crie uma classe chamada NHibernateSessionModule dentro da Class Library e coloque este conteúdo nela:

public class NHibernateSessionModule : IHttpModule
{
    public static readonly string KEY = "NHibernateSession";
    private static ISession _session;

    public void Dispose()
    {
    }

    public void Init(HttpApplication context)
    {
        context.BeginRequest += new EventHandler(context_BeginRequest);
        context.EndRequest += new EventHandler(context_EndRequest);
    }

    private void context_EndRequest(object sender, EventArgs e)
    {
        HttpApplication application = (HttpApplication)sender;
        HttpContext context = application.Context;

        ISession session = context.Items[KEY] as ISession;
        if (session != null)
        {
            try
            {
                session.Flush();
                session.Close();
            }
            catch { }
        }
        context.Items[KEY] = null;
    }

    private static ISessionFactory factory = null;

    private static ISessionFactory GetFactory()
    {
        if (factory == null)
        {
            Configuration config = new Configuration();
            if (config == null)
                throw new InvalidOperationException("NHibernate configuration is null.");

            config.Configure();

            factory = config.BuildSessionFactory();
            if (factory == null)
                throw new InvalidOperationException("Call to Configuration.BuildSessionFactory() returned null.");
        }
        return factory;

    }

    public static ISession OpenSession()
    {
        ISession session;
        session = GetFactory().OpenSession();
        if (session == null)
            throw new InvalidOperationException("Call to factory.OpenSession() returned null.");
        return session;
    }

    public static ISession CurrentSession
    {
        get
        {
            if (HttpContext.Current == null)
            {
                if (_session != null)
                {
                    return _session;
                }
                else
                {
                    _session = OpenSession();
                    return _session;
                }
            }
            else
            {
                HttpContext currentContext = HttpContext.Current;
                ISession session = currentContext.Items[KEY] as ISession;
                if (session == null)
                {
                    session = OpenSession();
                    currentContext.Items[KEY] = session;
                }
                return session;
            }
        }
    }

    private void context_BeginRequest(object sender, EventArgs e)
    {
        HttpApplication application = (HttpApplication)sender;
        HttpContext context = application.Context;
        context.Items[KEY] = OpenSession();
    }
}

Pelo fato de esta classe herdar de IHttpModule, ela será chamada toda vez que um HttpRequest for feito para sua aplicação Web. Esta classe cria uma objeto do tipo Session para cada request e só destroi ele no final.Isso garante que teremos apenas uma Sessão aberta para cada request.

Essa parte não é necessária fazer, mas é considerado uma boa prática trabalhar com apenas uma Sessão ao invés de sair criando várias.

Abra o arquivo web.config e procure pela tag httpModules, dentro desta tag adicione mais um valor, que será referência ao módulo que acabamos de criar. Fica assim:

<httpModules>
 <add name="NHibernateSessionModule" type="MercadoVader.NHibernateModule.NHibernateSessionModule, MercadoVader.NHibernateModule"/>
 <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
</httpModules>

Quinto passo, o mapeamento

Ufa, quase acabando :)

Dentro da Class Library crie uma classe chamada Produto. Crie também uma pasta chamada Mapping e dentro dela crie o arquivo Produto.hbm.xml.

A classe produto fica assim:

public class Produto
{
    public int Id { get; set; }
    public string Nome { get; set; }
    public DateTime DataCadastro { get; set; }
    public decimal Preco { get; set; }
}

O arquivo Produto.hbm.xml fica assim:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="MercadoVader.NHibernateModule" assembly="MercadoVader.NHibernateModule">

  <class name="Produto" table="PRODUTO">

    <id name="Id">
      <column name="ID" sql-type="int" not-null="true"/>
      <generator class="identity" />
    </id>

    <property name="Nome" type="String">
      <column name="NOME" length="100" not-null="true" />
    </property>

    <property name="Preco" type="Decimal">
      <column name="PRECO" precision="18" scale="2" not-null="true" />
    </property>

    <property name="DataCadastro" type="DateTime">
      <column name="DATA_CADASTRO" not-null="true" />
    </property>
  </class>

</hibernate-mapping>

O que estamos fazendo aqui é criar uma classe que é espelho da nossa tabela no banco de dados e também criando um arquivo de mapeamento que liga a classe com a tabela, nada muito complexo.

Clique com o botão direito no arquivo Produto.hbm.xml e vá em suas propriedades. Na opção Build Action selecione o valor “Embedded Resource”, isso fará com que o arquivo seja compilado dentro de uma DLL.

Sexto passo, será que funciona funciona?

Para testar, você deve selecionar o projeto Web e adicionar referência ao projeto Class Library e também à NHibernate.dll.

Feito isso, entre no Default.aspx.cs e coloque isso no Page_Load:

protected void Page_Load(object sender, EventArgs e)
{
    Produto produto = new Produto();
    produto.Nome = "Biscoito Trakinas";
    produto.Preco = 1.10M;
    produto.DataCadastro = DateTime.Now;
    NHibernateSessionModule.CurrentSession.Save(produto);
}

Se tudo der certo, deverá haver um registro salvo no banco de dados agora.
Deu certo? Parabéns, o NHibernate está configurando e funcionando.
Não deu? Faça um comentário descrevendo o erro e verei se consigo ajudar.

Documentação do NHibernate está aqui: https://www.hibernate.org/hib_docs/nhibernate/1.2/reference/en/html/

Utilize a documentação para aprender sobre HQL e como buscar dados do banco de dados.
Conforme eu havia comentado neste post, o site summer of nhibernate é muito bom para aprender.
Se eu escrevi algo errado, por favor, me corrijam, já é meio tarde e o sono já está batendo.

Aqui está o projeto que eu criei para download.

Clique aqui para fazer o download de 'MercadorVader, NH + ASP.NET' (113.11 kB)

Até a próxima!