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.

28 de abr. de 2010

Design Pattern: Façade

Salve todos

Resolvi escrever este artigo depois de perceber alguns misconceptions, neste caso, sobre o design pattern Façade (é em francês com cedilha mesmo, significando fachada).


Definições da literatura

GOF Design Patterns by ... (ah, todo mundo sabe, o quarteto aquele):

Fornecer uma interface unificada para um conjunto de interfaces em um subsistema. Façade define uma interface de nível mais alto que torna o subsistema mais fácil de ser usado.



Core J2EE Patterns by Deepak Alur:

O Session Façade remove as interações de objeto de negócios subjacentes e proporciona uma camada de serviços que expõe apenas as interfaces necessárias, uniforme e de granulação grossa para os clientes.



Patterns Of Enterprise Application Architecture by Martin Fowler:

A Remote Facade is a coarse-grained facade [Gang of Four] over a web of fine-grained objects. None of the fine-grained objects have a remote interface, and the Remote Facade contains no domain logic. All the Remote Facade does is translate coarse-grained methods onto the underlying fine-grained objects.

Tradução livre: Um Façade Remoto é um façade de granulação grossa (coarse grained) acima de uma rede de objetos de granulação fina (fine grained). Nenhum dos objetos de granulação fina tem uma interface remota, e a interface remota não contém a lógica do domínio. Tudo que o Façade Remoto faz é traduzir métodos de granulação grossa para os objetos de granulação fina sob ele. 



Obs.: Existem várias discussões sobre a granulação de interfaces, como http://articles.techrepublic.com.com/5100-10878_11-5064520.html, sendo um aspecto importante do design. Não o li todo ainda, mas achei este muito interessante: http://www.ibm.com/developerworks/webservices/library/ws-soa-granularity/



Ilustrando (literalmente)

Acho que as ilustrações abaixo permitirão uma visão melhor:


usage of the facade pattern in UML

Parece claro que um Façade simplifica as chamadas utilizando uma interface uniforme e a frente de outros objetos que representam a lógica do domínio. Subentendido fica que os objetos do domínio compartilham informações entre si, e mesmo o façade pode "coreografar" (no mesmo sentido do SOA, mas não com a mesma implementação), obtendo a informação e entregando um resultado íntegro, construído de várias partes do negócio, para o cliente.

Estas mesmas partes, a granulação fina, podem depender de outras, penso afinal, se os objetos do meu domínio não trocam mensagens, o projeto não é orientado a objetos, é procedural*.

*Obs.: Há um code smell para isto http://c2.com/cgi/wiki?ShotgunSurgery e geralmente carece de grande refatoração, dificultando futuras manutenções.



Papel do Façade em uma aplicação distribuída

É custoso em vários sentidos um frontend utilizar chamadas remotas, especialmente síncronas. Não tenho explicação melhor que esta, do Fowler:

Within a single address space fine-grained interaction works well, but this happy state does not exist when you make calls between processes. Remote calls are much more expensive because there's a lot more to do: Data may have to be marshaled, security may need to be checked, packets may need to be routed through switches. If the two processes are running on machines on opposite sides of the globe, the speed of light may be a factor. The brutal truth is that any inter-process call is orders of magnitude more expensive than an in-process call - even if both processes are on the same machine. 


Tradução livre: Dentro de um simples espaço de endereço a interação com granulação fina funciona bem (i.e. mesma JVM, mesmo Host), mas este estadofeliz não existe quando você faz chamadas entre processos. Chamadas remotas são muito mais custosas por que há muito o que fazer: Dados podem precisar de serialização, talvez tenha-se que checar a  segurança, pacotes podem necessitar de roteamento através de switches, etc. Se os dois processos estão rodando em máquinas dispostas em lados opostos do globo, a velocidade da luz pode ser um fator significante. A verdade brutal é que qualquer chamada inter-processos é, em ordem de magnitude, mais custoso que uma chamada dentro do mesmo processo - mesmo se os dois processos estiverem na mesma máquina. 



Então ...

Patterns são assim mesmo, tem uma pitada de subjetividade e, obviamente, nem todo mundo tem o mesmo entendimento.

Se alguém quer acrescentar (ou subtrair) algo, fique a vontade, este tópico neste espaço é para todos juntos chegarmos a um consenso, com um pouco de cada, aproveitando a inteligência coletiva.

Márcio Torres

26 de abr. de 2010

three-valued logic (3VL)

Salve,

Já que tenho um tempinho livre, resolvi falar sobre o a lógica ternária. Provavelmente todos que estão lendo este tópico, entendem lógica boleana, e o tipo boleano (boolean), e é sobre ele que a discussão paira.

O tratamento da lógica ternária é um desafio para solução de implementação e abaixo mostrarei algumas idéias mais simples.


Tipo boleano

O tipo boleano, cuja premissa foi cunhada por Boole (http://en.wikipedia.org/wiki/Boole), identifica uma informação com dois, apenas dois, estados, como o BIT. Para programadores de linguagens de alto nível, tal como Java, entendemos como simplmesmente:

verdadeiro ou falso

Quem passou por uma cadeira de lógica e álgebra booleana, deve conhecer a famosa tabela, esta:

TRUE   AND  TRUE   =  TRUE
TRUE   AND  FALSE  =  FALSE
TRUE   OR   FALSE  =  TRUE
FALSE  OR   FALSE  =  FALSE

Bem simples não?


Three-valued logic

A lógica ternária, inclui um terceiro estado, indeterminado, ou formalmente unknown (desconhecido). Não é novidade, ele é utilizado no SQL, conhecido como o valor NULL.

Imagine um campo fumante em uma tabela qualquer de uma base de dados relacional (SQL), e que seja do tipo boolean. Este campo pode ter os seguintes estados:

+---------+------------+
| Nome    |  Fumante   |
+---------+------------+
| João    |  true      |
| Maria   |  null      |
| José    |  false     |
+---------+------------+

Em teoria, entende-se que João é fumante, José não, e não sabemos se Maria fuma ou não, correto?

Esse é o enfadonho "Boolean de três estados". Existe uma tabela, que inclui o valor desconhecido, como pode ser visto abaixo:

ABA OR BA AND BNOT A
TrueTrueTrueTrueFalse
TrueUnknownTrueUnknownFalse
TrueFalseTrueFalseFalse
UnknownTrueTrueUnknownUnknown
UnknownUnknownUnknownUnknownUnknown
UnknownFalseUnknownFalseUnknown
FalseTrueTrueFalseTrue
FalseUnknownUnknownFalseTrue
FalseFalseFalseFalseTrue
fonte: http://en.wikipedia.org/wiki/Ternary_logic


"Maldição do Boolean de Três Estados"

Quando se está programando, podemos cair nesta questão, neste detalhe.

Por exemplo, utlizando um método no Java para separar em uma lista somente os fumantes.

// uma classe de domínio

public class Funcionario {
    // bla bla bla

    public Boolean isFumante() {
        return isFumante;
    }
}

// em uma classe qualquer

private List getFumantes(List todos) {
    List fumantes = new ArrayList();

    for (Funcionario funcionario : todos) {
        if (funcionario.isFumante()) {
            fumantes.add(funcionario);
        }
    }
    return fumantes;
}

Pergunto, há algum problema com essa solução de implementação?

tic, tac, tic, tac, tic, tac, ....

CLARO.

Esta código está propenso a:

Exception in thread "main" java.lang.NullPointerException
at Teste.main(Teste.java:9)

E o problema está aqui:

if (funcionario.isFumante())

Se o retorno do método for null, já que estamos usando a classe Boolean como retorno e não o tipo primitivo boolean, o teste condicional lançará uma NPE.
Esta é a maldição do "boolean de três estados".



Programando ciente do 3VL

Existem algumas estratégias para solução deste problema, e o DataSource da classe de domínio é extremamente importante. Caso venha de uma base SQL, onde NULL é um valor aceitável, ou seja, quer dizer "não informado", a melhor estratégia é implementar na classe cliente, o chamador do método.

Implementar na classe servidora seria mais simples, por exemplo, testando se o valor é nulo e retornando falso, entretanto, se na camada de apresentação for necessário informar em um rótulo ou caixa de texto: Fumante: SIM, ou Fumante: Não, ou Fumante: ____, o terceiro valor (NULL) serviria para manter a informação vazia.

Então, tudo depende. Se não haverá problema na camada de apresentação, e o valor desconhecido, vindo do DataSource, na prática, não é necessário, o melhor é implementar na classe servidora, como no exemplo:

public class Funcionario {
    // bla bla bla
    public Boolean isFumante() {
        return isFumante == null ? false : isFumante;
    }
}

Sempre retornará falso caso o valor seja nulo, o que significa, NPE-Free!

Por outro lado, se o valor desconhecido (NULL) é necessário, implemente no cliente, como no exemplo:

for (Funcionario funcionario : todos) {
    if (funcionario.isFumante() != null && funcionario.isFumante()) {
        fumantes.add(funcionario);
    }
}


Lembre de testar se é diferente de nulo primeiro, assim se for nulo, a segunda parte da expressão não será avaliada, desde que você use o operador && e não apenas um & (o && é conhecido como operador de curto circuito: http://en.wikipedia.org/wiki/Short-circuit_evaluation).



Programação defensiva

Uma sugestão, é procurar saber se o retorno do método é seguro, por exemplo, consultando o Javadoc ou assistente de código do IDE.

Nem sempre temos a mão o código fonte para consultar, e até alterar, a classe servidora, então para garantir:

  • Se o retorno for Boolean, com B maiúsculo, significa que retorna um objeto, um wrapper, e que o valor NULL é admissível,  então, teste antes:

if (classeQualquer.metodoBoleano() != null && classeQualquer.metodoBoleano()) ...

  • Caso contrário, caso o retorno do método seja boolean, com B minúsculo, significa que retorna um tipo primitivo, e realmente, ou virá verdadeiro ou falso, e neste caso o teste não é necessário:

if (classeQualquer.metodoBoleano()) ...


Casos semelhantes acontecem com outros Wrappers, como Integer, Double, etc, mas que ficam para um próximo tópico.


Claro, existem outra soluções viáveis, fiquem a vontade para sugerir.

Obs.: Usando um exemplo, o Apache Velocity é ciente do 3VL, se eu utilizar #if($cliente.isFumante), e isFumante é nulo, a expressão avalia falso sem warnings.

Referências: