24 de dez. de 2010

Programador e Desenvolvedor: enfim, qual a diferença?

Este assunto é bem polêmico, para uns, programar e desenvolver significam a mesma coisa, para outros (como eu), são atividades distintas.

Então, um conceito de programador:

Um programador é um profissional preocupado com a qualidade do código - por isto também é chamado de coder. Normalmente, conhece muito uma determinada linguagem e tem sólidos conhecimentos de lógica e matemática. A sua atividade geralmente começa quando lhe é entregue uma especificação e, a partir desta, escreve o código necessário para cumpri-la. O programador geralmente atua em partes específicas da aplicação.

E o conceito de um desenvolvedor:

Um profissional preocupado com a qualidade do software. Normalmente tem um conhecimento mais interdisciplinar, não só da linguagem, mas de plataforma, tecnologia, negócio, administração. Com um olhar mais crítico, consegue avaliar soluções diferentes para o mesmo problema e selecionar aquela que tem o melhor custo benefício para o domínio do problema. O desenvolvedor geralmente está preocupado com a big picture e esforça-se para pensar fora da caixa.

Pré-conceitos, conceitos e pós-conceitos, por aí ...

Neste blog, é argumentado que o trabalho realizado por programadores e desenvolvedores é fruto das mudanças de mercado. Compara o desenvolvimento de software a uma linha de montagem de uma fábrica e o programador àquele funcionário que executa uma determinada pequena tarefa.

Neste outro, achei interessante a abordagem sobre o aspecto social de programadores e desenvolvedores; embora não concorde em totalidade.

Alguns são mais contundentes, ao ponto de dizer "seja um desenvolvedor, não um programador". Também não acho que é por aí, penso que se alguém é feliz codificando, sem as dores de cabeça do desenho e arquitetura, que mal há?

Para descontrair: vida de programador/desenvolvedor ...




Tem certeza que deseja seguir nesta carreira?

27 de nov. de 2010

Palestra sobre TDD no Tchê Linux Rio Grande

Hoje, 27 de novembro, é dia de Tchê Linux em Rio Grande. Eu estarei por lá com a apresentação sobre Metodologia Ágil: TDD com Java. Fico feliz de participar deste evento, já participei no de Pelotas, que tem muito valor para os profissionais e "aspiras" de TI Infraestrutura e Desenvolvimento. Agradeço a todos os organizadores do evento e patrocinadores.

Ainda lançarei mais posts sobre TDD. Os slides e código da palestra estão abaixo:
Para abrir o código-fonte sugiro que importe os projetos para um workspace do Eclipse.

Para quem está lendo este post durante ou após a apresentação, obrigado pela presença.

Quem não compareceu mas deseja saber do que se trata, não hesite em perguntar.

26 de set. de 2010

Documentar faz bem

Um recurso que às vezes não é aproveitado pelos desenvolvedores é a documentação.

Bem, já disse em outros posts que o código "fala", em outras palavras, um código bem escrito faz os outros programadores entenderem a intenção.

Também sou adepto do ditado que diz: "Sempre que for adicionar um comentário, pense: 'Como eu posso escrever este código para que este comentário não seja necessário?'".

Mas o que estou falando neste tópico é mais do que apenas inserir comentários, digo usar o método de documentação de código disponível na linguagem na hora de criar uma API.

Aqui Josh Bloch fala como desenhar uma boa API e em um trecho da apresentação diz:

Documente todas classes, interfaces, métodos ...

Também diz:

Reuso é algo mais fácil de falar do que fazer. Fazer requer bom design e muito boa documentação.

Cada linguagem fornece um meio de documentar as classes, interfaces e métodos, no Java tem o JavaDoc no .NET tem o XML Documentation e por aí vai.

No caso do Java, os profissionais que desenvolvem na linguagem já devem ter percebido quando usam um IDE com code completion/assist, como o Eclipse ou NetBens, que aparece a descrição dos métodos, exceções e parâmetros na janela de contexto, sempre que uma classe ou método é autocompletado ou o codeassist é invocado, como na ilustração:



Mãos a obra no Javadoc então

Vou ilustrar com uma aplicação baseada no modelo Transaction Script, onde disponibilizo uma classe de serviço com uma interface para operações de Crédito e classes de dados que representam o retorno desse serviço, ok?

Então eu tenho uma classe de dados que representa uma Analise de Crédito, como abaixo:



public class AnaliseCredito {

    // .. dados sobre a análise de crédito
}


A primeira documentação é sobre a classe, que irá expor detalhes importantes acerca do que as instâncias desta classe irão representar.

Todo início de documentação no padrão Javadoc inicia com /**, seguido de um * por linha e termina com */, como abaixo:



/**
 * 
 * @author Márcio Torres
 */
public class AnaliseCredito {

}


Outras informações pertinentes podem ser a versão e a qual a versão mínima, como segue:



/**
 * 
 * @author Márcio Torres
 * @version 1.0, 09/23/10
 * @since 1.5
 */


De acordo com a Oracle a versão deve usar o formato acima, mas obviamente cada equipe pode chegar em um consenso para isto, eu por exemplo gosto do formato timestamp (2010-09-23 13:55:52).

Ainda falta explicar a classe, como segue:



/**
 * Representa o resultado de uma Análise de Crédito com detalhes importantes
 * acerca de um determinado cliente e o risco a ele associado no que diz
 * respeito a empréstimos e financiamentos.
 * 
 * @author Márcio Torres
 * @version 1.0, 09/23/10
 * @since 1.5
 */
public class AnaliseCredito { ...


Tente sempre respeitar as 80 colunas para escrever esta descrição. Ainda é possível destacar certos trechos, como a tag tt que representa um trecho de código, i, strong, e outras tags HTML. Também é possível indicar a consulta para classes relacionadas através do @see, como abaixo:



/**
 * Representa o resultado de uma Análise de Crédito com detalhes importantes
 * acerca de um determinado cliente e o risco a ele associado no que diz
 * respeito a empréstimos e financiamentos, representados pelas
 * classes Emprestimo e Financiamento
 * 
 * Para analisar o risco use o método {@link #getRisco()}
 * 
 * @author Márcio Torres
 * @version 2010-09-23 13:40:25
 * @see Financiamento
 * @see Emprestimo
 * @since 1.5
 */
public class AnaliseCredito { ...



Como no código acima, ainda é possível estabelecer links para métodos importantes da classe. Embora existam outros detalhes, os que exemplifiquei acima já cobrem o básico, mais detalhes aqui: http://www.oracle.com/technetwork/java/javase/documentation/index-137868.html

Documentar as interfaces e classes é só o começo, é necessário comentar os métodos. Neste caso, é comum nas interfaces esclarecer detalhes do contrato, sendo normalmente mais detalhado, e que também de algum modo dê informações a um programador que venha a implementá-la, como segue o exemplo abaixo de uma interface e uma implementação simples:



public interface CreditoService {

 AnaliseCredito analisaCredito(String cpf);
 
}

public class CreditoServiceImpl implements CreditoService {

 @Override
 public AnaliseCredito analisaCredito(String cpf) {
  if (cpf == null) {
   throw new NullPointerException("O CPF não foi informado (nulo)");
  }
  if (cpf.length() < 11) {
   throw new IllegalArgumentException("O CPF não está completo, use apenas números e sem formato, ex: 11122233344");
  }
  if (cpf.length() > 11) {
   throw new IllegalArgumentException("O CPF tem caracteres a mais, use apenas números e sem formato, ex: 11122233344");
  }
  
  // Verifica o Crédito através de uma integração
  // pode lançar WebServiceException
  // webService.checkCredit(cpf) ... 
  
  AnaliseCredito analise = new AnaliseCredito();
  
  return analise;
 }

}


Documentando a interface:



/**
 * Contrato para as operações relacionadas a <strong>Crédito</strong> e
 * operações financeiras.
 * 
 * @author Márcio Torres
 * @version 2010-09-23 14:13:10
 * @see AnaliseCredito
 * @since 1.5
 */
public interface CreditoService {

 /**
  * Dado um CPF reúne informações pertinentes e traz a resposta na forma
  * de uma instância de {@link AnaliseCredito}.
         * 
         * Para obter uma análise com mais dados use
  * {@link #analiseCompletaCredito(String)}
         *
  * @param cpf
  *   O número do CPF que será utilizado para recolher as informações
  *   sendo apenas número e sem formato, por exemplo: <tt>11122233344</tt>
  * @return
  *   Uma análise de crédito representada pela classe
  *   {@link AnaliseCredito}.
         * @throws NullPointerException 
  *   Se for passado um parâmetro nulo
  * @throws IllegalArgumentException
  *   Se o CPF não tiver 11 números ou for inválido
  */
 AnaliseCredito analisaCredito(String cpf);
 
}



No exemplo foi documentada a interface e o método analisaCredito. Na documentação do método é explicada a pré-condição, pós-condição e efeitos colaterais, bem como o formato do parâmetro esperado e as exceções que podem ser lançadas. A classe de implementação pode ser mais espartana, mas ainda tem que documentar detalhes da implementação, como exceções novas. Segue exemplo:



/**
 * Executa operações relacionadas a <strong>Crédito</strong> e financeiras
 * 
 * @author Márcio Torres
 * @version 2010-09-23 14:24:20
 * @see AnaliseCredito
 * @since 1.5
 */
public class CreditoServiceImpl implements CreditoService {

 /**
  * Dado um CPF reúne informações pertinentes devolvendo
  * uma Análise de Crédito {@link AnaliseCredito}.
         * 
  * @param cpf
  *   O número do CPF que será utilizado para recolher as informações,
  *   por exemplo: <tt>11122233344</tt>
  * @return
  *   Uma análise de crédito
  * @throws NullPointerException 
  *   Se for passado um parâmetro nulo
  * @throws IllegalArgumentException
  *   Se o CPF for inválido
  * @throws WebServiceException
  *   Se houver um problema de comunicação com o subsitema de integração
  */
 @Override
 public AnaliseCredito analisaCredito(String cpf) {
 
     // implementação
     
 }
 
}



Resultados

O resultado da documentação, no IDE Eclipse por exemplo, é o que pode ser visto abaixo:



Ao completar o método fica assim:



E pelo Eclipse é possível exportar como HTML através de File -> Export -> Javadoc. Após concluir, se todas as opções ficarem em default, aparecerá um diretório doc no projeto e os HTML's. Basta usar um Open With -> Web Browser, e mais tarde disponibilizar a documentação em um lugar comum para a equipe.

Veja abaixo como ficou:



Outras linguagens

Outras linguagens disponibilizam o seu meio de documentação, PHP, ActionScript, C#, esta última posso dar um exemplo pois tenho mais contato:

C# com XML Documentation:



namespace Business.Services {

    /// <summary>
    ///     Executa as operações relacionadas a crédito e finanças.
    /// <summary>
    /// <remarks>
    ///     A partir desta classe são disponibilizados ...
    /// </remarks>
    public class CreditoServiceImpl : CreditoService {

       /// <summary>
       ///     Checa o crédito dado um CPF ...
       /// </summary>
       /// <param name="cpf">
       ///     CPF para consultar ....
       /// </param>
       /// <seealso cref="AnaliseCompletaCredito">
       ///     Veja o método AnaliseCompletaCredito
       /// </seealso>
       /// <exception cref="System.ArgumentException">
       ///     Lançada quando o CPF não é válido
       /// </exception>
       /// <exception cref="System.ArgumentNullException">
       ///     Lançada quando o CPF não é nulo
       /// </exception>
       public AnaliseCredito AnaliseCredito(String cpf) {
         ...


Acho que é isso. A implementação no exemplo não foi perfeita, mas penso ter coberto o objetivo de apresentar a documentação e espero ter ficado entendido a necessidade da mesma.

Abraço, até a próxima.

31 de ago. de 2010

Tchê Linux: Boas práticas e Refatorações

Olá,

A apresentação no último sábado (28/ago) foi muito legal. Encontrei vários amigos, conversei com pessoas do ramo, etc. Esses encontros sempre são bons.

Na apresentação falei sobre Boas práticas e refatorações com Java, e fiz mais slides e código do que tinha de tempo disponível, para variar. Bem, o fato é que deixei disponível tanto a apresentação quanto o código que podem ser baixados nestes links abaixo:

Apresentação:
https://docs.google.com/leaf?id=0B3CElJmzM2Y6YjlmYjY2NWMtYTQ1Yi00YjIxLWExNGQtMGY1NzBkYTZiODk0&sort=name&layout=list&num=50

Código fonte:
https://docs.google.com/leaf?id=0B3CElJmzM2Y6MzlmZDNkYjQtOWQ2Mi00NDM1LWFjMjYtNTFmMTAwOGNhYWE3&sort=name&layout=list&num=50

Desculpem o atraso para disponibilizar, pois resolvi deixar uns comentários no código para facilitar o entendimento e editei o texto e Layout dos slides também.

Breve postarei mais coisas neste blog. Um abraço a todos e até a próxima, quem sabe estarei no Tchê Linux Rio Grande na FURG? Vou tentar. Até!

28 de jun. de 2010

Strings no Java


Intro

Salve,

Após conversar com colegas e tal, resolvi compartilhar o conhecimento sobre Strings e sua implementação e características na linguagem Java. Alguns detalhes inclusive fazem parte do exame para Programador Java Certificado (SCJP) e a utilização em outras linguagens é semelhante, como no C#, ActionScript, etc.

Espero que seja de bom proveito.


Strings

As Strings diferentemente dos tipos primitivos (int, long, float, double, char, double) são reprentadas por uma classe. Logo, toda declaração de String é uma instância. 

Ver exemplo:

import static java.lang.System.out;

public class Teste {
public static void main(String[] args) {
out.println("Teste");
}
}

No exemplo, a simples declaração de "Teste" gera uma instância (automaticamente) da classe String. Isto permite que eu faça código desta maneira:

String texto = "Teste";
out.println(texto.toUpperCase());
out.println("Teste".toUpperCase());

Ambas instruções de saída geram: TESTE

Como qualquer instância de uma classe, sendo um objeto, as String tem atributos e métodos. Mas existem duas características que fazem o tratamento de String um pouco diferente:

- Strings são imutáveis
- Strings literais são armazenadas no pool no espaço de geração permanente (PermGen Space).




Strings são imutáveis

Cada operação chamada em uma instância de String cria outra String (nova instância). Isto garante a integridade das referências. Ver exemplo:

String texto = "teste";
texto.toUpperCase()
out.println(texto);

Produz a saída: "teste".

Ao usar o método toUpperCase na variável texto, foi criado uma nova String em maiúscula. A String referenciada pela variável texto ainda é "teste" e, enquanto a variável texto não for reatribuida, sempre será. Se quiser que a variável texto aponte para o novo objeto String em maiúsculo faça o seguinte:

String texto = "teste";
texto = texto.toUpperCase()
out.println(texto);

É importante entender que cada alteração na String gera uma nova instância, e isto implica em questões de performance e confiabilidade. Exemplo:

String frase = "texto";
frase = frase + " de ";
frase = frase + "exemplo";

Neste caso, eu criei pelo menos 5 instâncias: "texto", " de ", "texto de", "exemplo", "texto de exemplo".

Este é um dos motivos por que é preferível usar StringBuilder quando é necessário concatenar muitas Strings. Exemplo:

StringBuilder frase = new StringBuilder();
frase.append("texto");
frase.append(" de ");
frase.append("exemplo");

Note que ainda assim, cada declaração literal gera uma instância, mas o StringBuilder (StringBuffer se for necessário sincronização para Threads) pode receber variáveis por exemplo.

[ :( ] Por exemplo, nunca faça isso:

String nomes = "";
for (String nome : dataSource.getNomes()) {
nomes = nomes + "; " + nome;
}

Supondo que seja uma lista de 100 nomes. A cada iteração é gerado uma nova String com o nomes + ";", e depois outra com nomes (já com o ;) mais o nome.

[ :) ] Faça assim:

StringBuilder nomes = new StringBuilder();
for (String nome : dataSource.getNomes()) {
nomes.append(nome);
}

Para pegar a String gerada faça: nomes.toString();


[ :( ] Como não há garantia de estar referenciando a mesma instância nunca faça isto:

if (texto == "sim") { ...

[ :| ] Talvez faça isto:

if (texto.equals("sim")) { ...

[ :) ] Mas, prefira fazer assim:

if ("sim".equals(texto)) { ...

Por que? Por que se texto vier nulo, no caso de texto.equals("sim") receberemos um belo NullPointerException. No caso de "sim".equals(texto), se a variável for nulo simplesmente avaliará falso. Estude o contrato do equals: http://java.sun.com/javase/6/docs/api/java/lang/Object.html#equals(java.lang.Object)


Entendido?




Strings são armazenadas no espaço de geração permanentente

O Java reutiliza Strings utilizando o pool de String, que é guardado no espaço de geração permanente, o PermGen Space.

Em outro artigo já falei sobre como a memória é gerenciada no Java, mas para clarear, existem 3 espaços básicos:
- A pilha (Stack): onde ficam as variáveis e os métodos;
- O Heap: onde ficam as instâncias de objetos;
- O espaço de geração permanente (PermGen): onde ficam armazenadas informações até o fim da aplicação, como as Classes e as Strings.

Ou seja, se eu declarar uma String "teste", assim, literalmente na aplicação, ela irá para o PermGen.

Acredito que os leitores saibam que o operador == compara igualdade de referências, não de conteúdos, certo? Bem, vamos a um exemplo:

String a = "teste";
String b = "teste";
out.println(a == b);

Qual é a saída?

true

Embora pareça óbvio, nem sempre é. Neste caso, acusou verdadeiro por que ambas variáveis apontam para a mesma instância, já que o primeiro "teste" foi colocado no pool e reutilizado para a variável b, então NESTE CASO 'a' e 'b' referenciam o mesmo objeto. 

O fato de as String serem imutáveis favorecem esta técnica, já que a instância "teste" no PermGen nunca será alterada.


Bem, eu posso forçar a criação de uma nova instância, em outras palavras, não aproveitar do pool, fazendo assim:

String a = "teste";
String b = new String("teste");
out.println(a == b); 

Ambas valem "teste", mas a saída da operação é false. Sempre que eu utilizo a palavra-chave new com Strings, eu estou ignorando o pool.

[ :( ] Evite usar o new para Strings, por exemplo, a instrução new String("teste") gera duas instâncias, a literal "teste" vai para o PermGen, e outra instância é gerada no Heap devido a palavra-chave new. 

[ :) ] Aproveite o pool e só instancie diretamente quando tiver uma razão clara para isto.



Operações com Strings

A classe String já tem inumeras operações, desde conversão de caixa até extrações (substrings). 

Contudo, algumas operações podem lhe fazer falta de alguma maneira.

Inicialmente, é normal pensarmos em estender a classe String, só que isto não é possível.

Devido ao contrato de imutabilidade, a classe String é final (sealed), e não pode ser estendida.

Por isso é comum criarmos métodos auxiliares em outra classe, tipo, uma StringUtil (no java temos muito destas xxxUtil).

Por exemplo, se preciso de um método que me diga se a String é um número posso fazer um método nesta classe utilitária. Fiz um exemplo tosco abaixo:


import static java.lang.System.out;
import java.util.regex.*;

public class Teste {
public static void main(String[] args) {
String b = new String("2132");
out.println(StringUtil.isNumber(b));
}

}

class StringUtil {
public static boolean isNumber(String s) {
if (s == null) return false;
Pattern p = Pattern.compile("\\d*");
Matcher m = p.matcher(s);
return m.matches();
}
}


Do meu ponto de vista este é um código procedural, não que seja ruim antes que me atirem pedras, mas que não é bem a proposta do paradigma OO. 

[ ! ] Não necessariamente por utilizar uma linguagem orientada a objetos estamos desenvolvendo um programa orientado a objetos, entende?

Bem, isto fica para outro tópico.


Dúvidas, comentários, críticas, sugestões, etc, fiquem a vontade.


Um abraço

Márcio Torres

29 de abr. de 2010

Instanciar ou não instanciar coleções

Intro

Em um papo de almoço, conversávamos sobre instanciar ou não instanciar uma coleção membro de alguma classe do domínio, exemplo:


public class Cliente {
    List enderecos; //null por default
}

ou

public class Cliente {
    List enderecos = new ArrayList();
}

E a questão fica entre performance e complexidade.


Performance

Performance por que quando um Cliente é instanciado, o seu atributo, enderecos, não é instanciado junto. No segundo caso, cada vez que em algum lugar em der um new Cliente() automaticamente está acontecendo um new ArrayList(), que constrói um Array interno de 10 posições (referências nulas claro).


Complexidade

Imagine que a classe Cliente seja um JavaBean, e a partir de uma classe cliente eu deseje iterar os endereços:

public class MinhaClasseDeNegocio {

    public Endereco enderecoDefault(Integer idCliente) {
        Cliente cliente = meuDataSource.find(idCliente);

        for (Endereco e : cliente.getEnderecos()) {
            if (e.isDefault()) return e;
        }

        return null;
    }

}

O que acontecerá se o Cliente não tiver endereços? Tchananam... NullPointerException

Então, se há a possibilidade de a lista vir vazia, eu tenho que lidar com isso, garantir, como abaixo:

public class MinhaClasseDeNegocio {

    public Endereco enderecoDefault(Integer idCliente) {
        Cliente cliente = meuDataSource.find(idCliente);

        if (cliente.getEndereco() != null) {
            for (Endereco e : cliente.getEnderecos()) {
                if (e.isDefault()) return e;
            }
        }
        return null;
    }

}


Obs.: Existe o modo Domain-Driven (o qual prefiro) de lidar com isso, mas fica para outro tópico.



Profiling

Para ilustrar a performance, fiz um pequeno benchmark, que pode ser visto abaixo:

import java.util.*;

public class ArrayProfile {
static final int ITENS = 1000000;

public static void main (String[] args) throws Exception {
long memoryBefore = Runtime.getRuntime().totalMemory();
long startTime = System.currentTimeMillis();
List lista = new ArrayList();
for (int i = 0; i < ITENS; i++) {
lista.add(new FaixaRepository());
}
long endTime = System.currentTimeMillis();

Thread.sleep(1000);
long memoryAfter = Runtime.getRuntime().totalMemory();
System.out.format("%nItens instanciados: %,d %n", ITENS);
System.out.format("%nMemória usada: %,d bytes %n", (memoryAfter - memoryBefore));
System.out.format("%nTempo necessário: %d ms %n%n",  (endTime - startTime));
}

}

class FaixaRepository {
List lista = new ArrayList();
}

class Faixa {
Integer codigo;
Double  remuneracao;
}


Neste primeiro caso, eu instancio o ArrayList, membro de FaixaRepository, e o resultado foi o seguinte:

mtorres@independiente:~/temp/sparring/collections$ java ArrayProfile 

Itens instanciados: 1.000.000 

Memória usada: 101.974.016 bytes 

Tempo necessário: 1359 ms 



Fazendo uma alteração, deixando o membro lista nulo, como abaixo:

...
class FaixaRepository {
List lista;
}
...

Obtive o seguinte resultado:

mtorres@independiente:~/temp/sparring/collections$ java ArrayProfile 

Itens instanciados: 1.000.000 

Memória usada: 9.437.184 bytes 

Tempo necessário: 111 ms 



Conclusão

Este é outro caso em que não se está definido o que é certo ou errado, cada caso é um caso, faz parte do design decidir qual estratégia será utilizada.



Obs: O tempo que eu uso para fazer estes micro artigos é a espera do build e do start dos servidores, eu instrumentei, hehehe, abaixo:

mtorres@independiente:~/desenvolvimento/bla/bla/bla$ time mvn install -Plocal
======= Construindo ... bla bla bla =======
... muitas linhas depois ....

real 0m48.702s
user 0m35.430s
sys 0m2.904s

mtorres@independiente:~/desenvolvimento/bla/bla/bla$ $ time mvn jetty:run -Plocal
... bla bla bla ...
real 0m28.685s
user 0m29.782s
sys 0m0.844s

mtorres@independiente:~/desenvolvimento/bla/bla/bla$ $ time mvn jetty:run -Plocal
... bla bla bla ...
real 0m12.671s
user 0m12.369s
sys 0m0.300s

Plataforma .NET, ASP.NET e C#


Um dia disse que escrever ajuda a aprender, a decorar, é como se eu estivesse falando comigo mesmo (não disse que eu era esquizofrênico?).

Pensando nisto, vou focar alguns artigos nos meus objetos de estudos atuais, entre eles, boas práticas de design e implementação, detalhes importantes necessários para a certificação Java e a plataforma .NET para Web (ASP.NET) com a linguagem C# (lê-se C sharp).


Todas as abordagens serão o mais simples possível, se precisar de detalhes acessem as páginas dos respectivos assuntos.



Plataforma .NET

A plataforma .NET é utilizada para criar aplicações portáveis para várias plataformas. Semelhante a plataforma Java, no entanto mais limitada. O principal sistema operacional suportado é o Windows e família, seguido por outros projetos como o Mono, onde é possível rodar código .NET no Linux e Mac OS, mas que não tem a mesma entrada do Java por exemplo.

Existem várias linguagens disponíveis para .NET. Isto é possível devido a compilação para código intermediário (Common Intermediate Language -CIL) que é traduzida para o código nativo através do Ambiente de Execução Comum às Linguagens (Common Language Runtime -CLR).

Todo o ambiente é chamado de Infraestrutura Comum às Linguagens (Common Language Infrastructure -CLI).



A plataforma .NET está na versão 4.0, lançada agora em abril, entretanto falarei mais sobre a 3.5.



Linguagem C#

Existem várias linguagens para .NET, entre elas, as que me lembro: VB.net, C#, F#, J#, etc. Contudo, a própria Microsoft declara como linguagem padrão a C#. C# é uma linguagem totalmente orientada a objetos, inspirada e com sintaxe semelhante a C/C++, parecida com Java, e com aspectos semelhantes a linguagens funcionais como Haskell.



ASP.NET

É a parte do framework voltado para Web. Possui uma biblioteca rica em componentes, suporte a MVC e Ajax através de extensões, que roda sobre o Internet Information Services (IIS), servidor Web da Microsoft. Para quem conhece ASP, ASP.NET é bem diferente, não é interpretado, tem código compilado para o Runtime, é mais rápido e, segundo a Microsoft, mais seguro (e de fácil manutenção, hahaha).



Microsoft Express Tools

Para começar a desenvolver com .NET é possível baixar toda a infraestrutura, o IDE Visual Studio para C# e até o RDBMS SQL Server, gratuitamente, na versão Express.

Para desenvolver aplicações ASP.NET com C# e SQL Server baixe o seguinte:

Microsoft Visual Studio com Visual C# e Visual Web Development

Microsoft SQL Server 2005 Express

Microsoft SQL Server Management Studio Express


Nos meus testes estou usando o Visual Studio 2008 Express sobre .NET 3.5 e SQL Express 2005.



Migração

O aprendizado de C# é bem suave para quem tem background Java, e o aprendizado de ASP.NET é facilitado para quem tem background Java com um framework Web como Struts(2) e JavaServer Faces. 

Com bom conhecimento de OO, talvez um pouco de linguagens funcionais*, e uma base sólida de Web, não há grande dificuldade.

* Tomei uma surrinha de expressões lambda e extensions, mas depois fiquei até frustrado por não ter no Java, dá para fazer milagres!


Acho que é isso, no próximo, dou exemplos de C#, se possível sempre relacionando com Java.

Abraço a todos

Primitivos vs Wrappers, profiling ...


Intro

A linguagem Java, na verdade, não é totalmente orientada a objetos, como pode ser visto pela existência de tipos primitivos. São eles:

boolean, char, byte, short, int, long, float, double


Sempre que um variável primitiva é declarada, é inserida uma posição na pilha com o valor atribuído, ex:

int numero = 5;


E existem as classes que representam estes tipos primitivos, os Wrappers. Existe um Wrapper para cada tipo primitivo, são eles:

Boolean, Character, Byte, Short, Integer, Long, Float, Double


Até o Java 1.4, eu deveria declarar assim:

Integer numero = new Integer(5);


Este tipo de declaração abaixo causava um erro:

Integer numero = 5;


Então sempre era necessário, até o Java 1.4, fazer o Boxing ou Unboxing, como abaixo:

int numero = 3;

Integer outroNumero = new Integer(numero); //Boxing

int outroPrimitivo = outroNumero.intValue(); //Unboxing


A partir do Java 1.5 (Java 5 se preferir), foi introduzido o recurso de autoboxing-unboxing, liberando o desenvolvedor deste trabalho. As instruções abaixo são válidas a partir do Java 1.5:

Integer numero = 2; //O boxing é implícito

int numeroPrimitivo = numero; //O unboxing é implícito



Mito

Usar Wrappers ao invés de primitivos impacta na performance

Fazer o boxing (ou unboxing) tem um custo, todos sabem que há um overhead, mas não quanto. A questão é simples, usar Wrappers ou tipos primitivos causa muito impacto na performance?

Bem, resolvi testar usando a classe abaixo:

import java.util.*;

public class BoxingProfile {

private static int loop = 0;

public static void main (String[] args) {
long totalTime = 0;
for (int i = 0; i < 5; i++) { 
totalTime += test(); 
}
System.out.println("\nTempo total: " + totalTime + "ms");
System.out.println("\nTempo médio: " + (totalTime/5) + "ms");
}
private static long test() {
long startTime = System.currentTimeMillis();
List lista = new ArrayList();
FaixaRemuneracao f = null;
for (int i = 0; i < 1000000; i++) {
f = new FaixaRemuneracao();
f.setCodigo(i); //aqui é feito o Boxing
f.setRemuneracao(i * 2.0); //aqui também
lista.add(f);
}
int    codigo      = 0;
double remuneracao = 0.0;
for (FaixaRemuneracao faixa : lista) {
codigo = faixa.getCodigo(); //aqui é feito o Unboxing
remuneracao = faixa.getRemuneracao(); //aqui também
}
long endTime = System.currentTimeMillis();
System.out.println("loop #" + ++loop + ", tempo decorrido: " + (endTime - startTime) + "ms");
return (endTime - startTime);
}

}

// classe modelo
class FaixaRemuneracao {
private Integer codigo;
private Double  remuneracao;
public Integer getCodigo() { return codigo; }
public void setCodigo(Integer novoCodigo) { codigo = novoCodigo; }
public Double getRemuneracao() { return remuneracao; }
public void setRemuneracao(Double novaRemuneracao) { remuneracao = novaRemuneracao; }
}


É um exemplo bem simples, onde o foco está na classe modelo, onde são usados ou Wrappers (Objetos) ou primitivos. Executando como está acima (se alguém quiser testar o código está anexo) deu o seguinte resultado (na minha máquina):

mtorres@independiente:~/temp/sparring$ java BoxingProfile 
loop #1, tempo decorrido: 431ms
loop #2, tempo decorrido: 760ms
loop #3, tempo decorrido: 626ms
loop #4, tempo decorrido: 821ms
loop #5, tempo decorrido: 542ms

Tempo total: 3180ms

Tempo médio: 636ms

Alterando a classe modelo para utilizar tipos primitivos, ou seja, sem necessidade de (un)boxing:

// classe modelo
class FaixaRemuneracao {
private int codigo;
private double  remuneracao;
public int getCodigo() { return codigo; }
public void setCodigo(int novoCodigo) { codigo = novoCodigo; }
public double getRemuneracao() { return remuneracao; }
public void setRemuneracao(double novaRemuneracao) { remuneracao = novaRemuneracao; }
}


Deu o seguinte resultado:

mtorres@independiente:~/temp/sparring$ java BoxingProfile 
loop #1, tempo decorrido: 228ms
loop #2, tempo decorrido: 268ms
loop #3, tempo decorrido: 260ms
loop #4, tempo decorrido: 215ms
loop #5, tempo decorrido: 256ms

Tempo total: 1227ms

Tempo médio: 245ms



Conclusão

Nos testes, usar Wrapper aumentou em torno de 150% o tempo para popular dois campos de um objeto.

Usar tipos primitivos ou Wrapper é um assunto polêmico, e depende do caso, tipo, como quando existe a necessidade de atribuir NULL a uma campo (classe de entidade Objeto-Relacional por exemplo). 


mythbusters_plausible_spray.png Plausible! picture by Xinkz

Não é possível criar uma aplicação usando só primitivos ou só Wrappers, é necessário o melhor dos dois mundos, buscando onde é melhor usar cada estratégia.