sexta-feira, dezembro 30, 2005

Adeus ano velho...

Feliz 2006! Sim eu sei que ainda não chegou, mas ninguém espera que eu vá bloggar durante a virada de ano, então, antes de viajar para Pipa - estou com preguiça de procurar algo no google para linkar, se vira! - ficam os votos para um ano melhor do que 2005, para todos vocês três, meus caros leitores.

Espero uma boa festa em Pipa, até porque, veja bem, apesar de nunca ter ido lá, nem ser lá, nem ir para ficar, sempre me falam bem, então as expectativas são as melhores possiveis. Blog novamente apenas lá para o dia 4 de janeiro de 2006 quando volto a falar sobre qualidade de código, sobre Ruby ou qualquer outra lombra/lenda/mito que atraia meu interesse.

valeuz...

quarta-feira, dezembro 28, 2005

Ruby no tempo livre.

Eu falei de Ruby apenas uma vez no blog até agora, na verdade, não diretamente de Ruby, e não escrevi nada mais do que algumas linhas embasbacadas por um video do RoR. De lá para cá, no tempo livre, parei para estudar um pouco sobre a linguagem e sempre fica aquela impressão de "não pode ser, só isso?" ou "hum, interessante". Esses dias enquanto fuçava no repositorio remoto do gem em busca de alguma biblioteca para rss - sei lá porque rss, oras - encontrei o Simple-RSS (para instalar gem install simple-rss), e convenhamos, o "simple" no nome é bem justificado. Para testar, resolvi ler o rss dos novos posts no forum do JavaFree. Nada de muito complicado, apenas acessar o rss, iterar sobre as entradas e mostrar os titulos dos posts. O código, gigantesco, 5 linhas, um absurdo, ficou assim:
require 'rubygems'
require 'simple-rss'
require 'open-uri'
rss = SimpleRSS.parse open('http://www.javafree.org/javabb/rss/newPosts.jbb')
rss.channel.entries.each {|e| puts e.title}
Nem quero imaginar como fazer um leitor RSS em Java. De qualquer modo, claro, uma ajudinha das closures, ausentes em Java, não fazem mal a ninguém. Por fim, nada de RoR, por enquanto, já que quero aprender Ruby para valer e depois sim usar o framework com alguns "add-ons". Os planos são fazer uma serie de exemplos simples e praticos até me sentir à vontade com a sintaxe. A proposito, acho que um livro não vai fazer mal.

valeuz...

domingo, dezembro 25, 2005

Boas novas!

Eis que chega o fim do ano, mais um, e espero que muitos outros fins de ano cheguem. Como de praxe, não fiz tudo que queria, tudo que poderia, mas fiz muita coisa boa esse ano, então, sem lamentações, muito menos promessas para ser mais isso menos aquilo ano que vem.

Se fosse fazer uma promessa seria a de ler mais, nada de livros técnicos, ou eles também. Apenas ler mais. Para não me esticar muito nesse post, afinal, fim de ano sempre se tem algo melhor para fazer do que postar em um blog, fica o Feliz Natal para todas as três pessoas que lêem os desvaneios publicados por aqui e os outros 2 que acessam para se certificarem de que eu continuo falando besteira, não tanta ainda, afinal falta tempo, fazer o que. Feliz Natal a todos, Feliz Ano novo e bla bla bla.

valeuz...

segunda-feira, dezembro 19, 2005

Por um codigo melhor - II

No post anterior eu postei alguns dos erros que mais me irritam quando leio código alheio. Na verdade, não chega a ser irritação de fato, se fosse não me surpreenderia se fosse diagnosticado com ulcera ou coisa pior. Penso apenas que talvez, com um pouco de pair programming, o autor provavelmente não teria cometido tais erros, ou talvez tivesse cometido menos erros. Essa segunda parte não é muita coisa além de adições de novas dicas esquecidas no post anterior. Na verdade, eu estava com preguiça, mas enfim... vamos a outras dicas para evitar que seu código dê mais trabalho do que deveria e, acredite, se vc comete esse tipo de erros, ele vai dar mais trabalho do que deveria:

1. Exceptions são um fluxo à parte e não o principal. Mas que espécie de dica é essa? Todo mundo já sabe disso, o nome já explica, ora bolas. É, explica, mas não impede ninguém de escrever algo assim:
public int foo(int num) {
if(num > 50) {

//faz um monte de coisas complicadas com num
//até chegar a um "resultado"

return resultado;

}

throw new IllegalArgumentException("num deve ser maior do que 50");
}
Estranho porque o fluxo que realiza a operação é tratado como secundário, à parte, ele é quem faz parte do desvio e não a exception. Esse exemplo - lembre-se, sou péssimo para exemplos - pode não parecer tão ruim, mas experimente lidar com mais de uma exception dessa maneira para vermos no que acontece:
public int foo(int num) {
if(num > 50) {

if(num%2 == 0) {

// faz um monte de coisas complicadas com num
// até chegar a um "resultado"
return resultado;
}

throw new IllegalArgumentException("num deve ser par");
}

throw new IllegalArgumentException("num deve ser maior do que 50");
}
Agora sim é possível perceber o problema com esse tipo de abordagem. Afinal, a grande questão é, porque as pessoas cometem esse tipo de erro? Pergunta retórica apenas. Exceptions, claro, devem ser tratadas em fluxos à parte, ou seja, se uma pré-condição não for satisfeita, uma exception devem ser lançada:
public int foo(int num) {

// eu sei que não é assim, mas o maldito do blogger não sabe!
if(num menorOuIgual 50) {
throw new IllegalArgumentException("num deve ser maior do que 50");
}

if(num%2 != 0) {
throw new IllegalArgumentException("num deve ser par");
}

// faz um monte de coisas complicadas com num
// até chegar a um "resultado"
return resultado;

}
Se vc ainda não se convenceu a escolher a segunda abordagem, experimente colocar uma nova pré-condição em cada um dos trechos e veja em qual faz isso de modo mais prático. Hoje, mesmo que ainda precise falar outras coisas sobre exception, fica apenas essa dica.

valeuz...

quinta-feira, dezembro 15, 2005

Por um codigo melhor I

Se vc é programador, mesmo sem nunca ter lido algum livro sobre refactoring[1], é bem provável que já tenha reescrito algum trecho de código para melhorá-lo, torná-lo mais legível, rápido, ou seja lá o que for. Refactoring é uma das práticas mais comuns em metodologias ágeis[2] porque, geralmente, metodologias ágeis estão preocupadas com a qualidade dos artefatos mais importantes e imprescindíveis. E, claro, em desenvolvimento de software, pouca coisa é realmente mais imprescindível do que o próprio código, afinal, código é o artefato sempre presente. Daí haver a necessidade de torná-lo tão legível quanto o possível para que ele represente um "documento" sobre o sistema. Refactoring também entra aí: arrumar a casa e fazer todos entenderem o propósito do código - ou seja, como citei logo acima, fazer um punhado de instruções funcionarem como um "documento" do sistema. Mas, nesse posts, não vou falar especificamente sobre um catalogo de refactoring, se quiser ler algum, nada mais recomendado do que o livro do Fowler[3]. Também vou passar ao largo de definições mais aprumadas sobre o refatoração de código ou explicações de como test unitários[4] permitem reescrever o código de maneira segura.

Minha intenção com esse post é citar algumas dicas para evitar código ruim logo de primeira. Isso não vai lhe eximir completamente de reescrever uma parte ou outra enquanto o sistema evolui, isso é natural. Minha pretensão é evitar que vc pense em trucidar alguém - talvez vc mesmo, talvez eu - quando precisa refatorar partes do software. Vamos as dicas:

1. Dê nomes entendíveis a seus pacotes, classes, métodos e variáveis. Nomes entendíveis também passam pelo conhecimento comum entre os desenvolvedores[5]. Se for costume chamar um método que soma valores de "add", não tente usar algo como "xyz". Em suma essa dica se resume a fazer as pessoas com conhecimento do domínio reconhecerem o propósito da classe/metodo/variavel apenas pelo nome. Exemplos bobos - em Java - de como não fazer:

public void copy(File x, File y);
public long diff(Date d1, Date d2);

Dã, essa ficou fácil copia um arquivo para outro e vê a diferença entre as datas. Não? Não estava tão claro assim. Hum, e se eu tentar assim:

public void copy(File source, File destination);
public long diffInSeconds(Date inicio, Date fim);

Melhor, agora vc sabe qual arquivo é copiado para onde, sabe qual é a data de origem e qual a final e sabe que a diferença é em segundos. Mesmo em um exemplo tão trivial dá para perceber como escolher bem os nomes ajuda a tornar o código mais legível.

2. Transforme operações pouco claras em métodos com nomes - ah, os nomes - que identifiquem melhor a operação. Mesmo em alguns casos aparentemente simples isso pode ajudar um bocado. Por exemplo:

String id = "A@1232143245547657465";
...
if(id.charAt(0) == 'A') {
// algumas linhas antes - bastam 5
Permissoes p = getPermissoesAdmin();
}

Nessa situação vc pode perceber que 1) a operação é simples mas não está clara para quem bate o olho sobre o código e 2) eu sou péssimo para dar exemplos. Deixe-me tentar novamente:

double precoFinal = preco + preco * (17/100) - 10;

Tá, desisto de dar bons exemplos, vamos ao que interessa: tornar os dois trechos mais fáceis de entender. Primeiro, vamos transformar a operação do if em um método e depois usar a dica 1 para facilitar ainda mais a minha vida no futuro. Então, o código será:

String userId = "A@1232143245547657465";
...
if(isAdministrador(userId)) {
// algumas linhas antes - bastam 5
Permissoes permissoes = getPermissoesAdministrativas();
}

private boolean isAdminitrador(String userId) {
return id.charAt(0) == 'A';
}

Talvez vc ache que estou forçando a escrita de mais código, mas, na verdade, melhorei a legibilidade e permiti que a operação para indicar permissões administrativas seja tratada em um único ponto. Já o segundo exemplo, ficaria melhor assim:

double precoFinal = precoComTaxasDescontos(preco);

private double precoComTaxasDescontos(double preco) {
double imposto = preco * (17/100);
double desconto = 10;
return (preco + imposto - desconto);
}

Você até pode ter pensado no aumento de código, mas há, em sistemas reais, vantagens menos perceptíveis, ao menos nesses exemplos, como aplicar o conceito de DRY[6].

3. Remova a complexidade das classes clientes para os métodos que elas usam. Isso faz com que o código nas classes clientes esteja preocupado com suas próprias operações, e não em dar suporte as operações dos métodos que elas usam. Exemplo bobo - mas (quase) real dessa vez:

int idBah = bah.getId();
int numBah = bah.getNum();
String name = foo.getName();
long somethingId = foo.getSomething().getId();

facaAlgo(idBah, numBah, name, somethingId);

Ruim, muito ruim. Imagine 10 classes clientes, pense na repetição de código e... ...isso mesmo, refatore para trazer a complexidade para o método assim:

public void facaAlgo(Bah bah, Foo foo) {

int idBah = bah.getId();
int numBah = bah.getNum();
String name = foo.getName();
long somethingId = foo.getSomething().getId();

// faz o treco

}

E a classe cliente, bem mais aliviada:

facaAlgo(bah, foo);

Bom, sem mais dicas por enquanto. Alias, eu gostaria de ouvir as de vcs. Quais as dicas, bastante práticas, se possível, para tornar meu código um pouco menos fedorento?

Referências:

[1] - Refactorings in Alphabetical Order
[2] - Google - Agile Methodologies
[3] - Refactoring: Improving the Design of Existing Code - Martin Fowler
[4] - JUnit, Testing Resources for Extreme Programming
[5] - Code Conventions for the Java Programming Language
[6] - Don't Repeat Yourseft
[7] - Making Wrong Code Look Wrong
[8] - Padrões de Nomenclatura - Forum GUJ

valeuz...