Blog do Urubatan
msgbartop
Desenvolvedor, Palestrante, Escritor, Nerd Assumido e Pai do Marcus :D
msgbarbottom

23 May 09 Aee galera, sou papai :D

Aee galera, sou papai!!
O Marquinhos nasceu hoje a tarde!! 3k460g e 50cm!!
Fotos aqui http://picasaweb.google.com/urubatan/FotosDoMarquinhos
Um gurizão lindo, grandão e com saúde!
Parabéns pra eu :D

13 May 09 Java tem espelhos, e o mago deve saber jogar com eles (Básico da Reflexão)

Ok, o título deste post ficou meio estranho, mas como muita gente diz que isto é magia negra mesmo, então até que o título não esta tão ruim :D
Uma coisa que eu vejo bastante por ai, e não é de hoje, é que grande parte dos programadores Java não faz idéia do que seja Reflection, e normalmente tem medo de escrever, ou até mesmo de ler código “complicado”.
Não vou dizer que reflection é simples, mas é um recurso extremamente poderoso do Java que todo programador Java deveria conhecer.

O que é Reflection

Reflection em java, é como o nome diz, a possibilidade de programaticamente, visualizar um reflexo de um objeto ou uma classe, e como em um espelho, é possível também distorcer um pouco esta imagem quando necessário.
Como no reflexo em um espelho, o que você visualiza, não é o objeto real, apenas um reflexo deste, mas como na física, você pode deduzir como interagir com o objeto real, utilizando o seu reflexo.

Quando eu escrevi isto, lembrei de uma cena de um filme muito velho, acho que era “fúria de titâs” ou algo assim, onde alguem utilizava o reflexo da medusa em um escudo para lutar com ela sem se transformar em pedra.

Mas voltando ao assunto, reflection, é a possibilidade, de em tempo de execução, diversas informações sobre um objeto qualquer, incluindo mas não se limitando a seguinte lista:

  • Qual é a classe de um objeto
  • Quais métodos públicos a classe possui
  • Quais métodos foram declarados na classe (incluindo os privados)
  • Quais interfaces a classe implementa
  • Qual classe a classe do objeto estende
  • Quais anotações foram colocadas em uma classe
  • Quais anotações foram colocadas em um método
  • Quais anotações foram colocadas em um atributo
  • Quais anotações foram colocadas em um parâmetro de um método
  • Quais os tipos dos parâmetros de um método
  • Qual o tipo dos atributos de uma classe
  • Qual o tipo de retorno de um método

Via reflexão também é possível por exemplo, executar as seguintes ações em um objeto de uma classe que não existia no momento em que o código foi desenvolvido (um plugin por exemplo):

  • Instanciar um objeto
  • Chamar um método passando parâmetros ou não
  • Ler o valor de atributos privados de um objeto
  • Criar um clone de um objeto copiando o estado do mesmo
  • Chamar diretamente métodos privados de um objeto
  • Chamar métodos estáticos de uma classe
  • Ler atributos estáticos de uma classe

Claro que estes são só exemplos, a API de reflection adiciona muito mais flexibilidade do que isto, principalmente quando combinada com algum framework de AOP ou com a API de criação de Proxies disponível no próprio Java.
Mas para fazer tudo isto, é necessário conhecer algumas classes que a maior parte dos programadores Java não se preocupam em conhecer.
Só um detalhe antes de apresentar as novas classes, apenas combinando a API de reflection com a API de Proxies e o suporte a annotations do Java 5 é possível implementar todos os recursos do EJB3 por exemplo.
Agora vamos aprender a usar espelhos para fazer mágica :D

  • java.lang.Class – Esta é a classe que representa uma classe, todos os objetos tem um método “getClass” que retorna um objeto do tipo java.lang.Class, a partir de um objeto deste tipo, é possível obter diversas informações sobre uma classe, este é o ponto de entrada para o mundo dos espelhos, exatamente como aquele espelho do Alice no pais das maravilhas, mas sem o perigo de ficar preso por la como aconteceu com ela
  • java.lang.reflect.Field – Esta é a classe que representa um atributo de uma classe, objetos deste tipo nos permitem saber por exemplo, o nome dos campos de uma classe, e até mesmo ler o valor destes atributos
  • java.lang.reflect.Method – Objetos deste tipo representam métodos de uma classe, é possível utilizar estes objetos para chamar métodos passando ou não parâmetros para eles, mesmo que estes métodos sejam privados
  • java.lang.reflect.Modifier – Esta classe permite saber se um método ou atributo é privado ou publico, se ele é estático, ou seja, quais os modificadores de acesso foram utilizados na declaração do método, atributo ou classe
  • java.lang.reflect.Array – Esta classe representa um array, com objetos deste tipo é possível acessar todos os elementos de um array por exemplo
  • java.lang.reflect.Constructor – Esta classe representa um construtor de uma classe qualquer, uma classe pode ter diversos contrutores, e com referências para estes contrutores podemos saber quais os parâmetros necessários para instanciar uma objeto, ou até mesmo instanciar o objeto realmente
  • java.lang.reflect.AnnotatedElement – esta interface permite saber quais as anotações presentes em uma declaração, ela é implementada por Class, Method e Field por exemplo
  • Package java.lang.reflect – Antes de continuar lendo, por favor de uma olhada em quais as outras classes disponíveis no pacote responsável pela criação de espelhos e também pela distorção dos reflexos nestes espelhos no Java

Agora um exemplo básico, por que acredito que vocês não conseguiram entender muita coisa até aqui, mas eu prometo que depois de um exemplo as coisas vão ficar um pouco mais claras.

Este exemplo, razoavelmente simples, vai listar todos os métodos e atributos públicos em uma classe.
Para o exemplo se tornar um pouco mais divertido, o nome da classe deve ser passado como parâmetro, isto também faz você poder listar uma classe que não existia quando o programa foi compilado.

test/List.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 
package test;
 
import java.lang.reflect.*;
 
public class List {
        public static void main(String[] args) throws Exception{
                if(args.length!=1)
                        throw new Exception("Voce precisa informar o nome da classe como unico parametro");
                Class<?> clazz = Class.forName(args[0]);
                printClassInformation(clazz);
                printClassAttributes(clazz);
                printClassMethods(clazz);
        }
        public static void printClassInformation(Class<?> clazz) throws Exception {
                System.out.println("Class Name: " + clazz.getName());
        }
        public static void printClassAttributes(Class<?> clazz) throws Exception {
                for(Field f : clazz.getDeclaredFields()){
                        System.out.format("\t--Private Attribute Name: %s, Attribute Type: %s\n",f.getName(),f.getType().getName());
                }
        }
        public static void printClassMethods(Class<?> clazz) throws Exception {
                for(Method m : clazz.getMethods()){
                        System.out.format("\tMethod Name: %s, Return Type: %s, Parameter Types: %s\n",m.getName(),m.getReturnType().getName(),m.getParameterTypes().toString());
                }
        }
}

Compile este exemplo, e execute passando por exemplo “java.lang.Class” como parâmetro e você vai ter um exemplo básico do funcionamento da API de Reflection.
Você pode também criar outra classe, empacotar ela em um arquivo .jar, adicionar este jar no classpath e executar este exemplo passando o nome da sua nova classe como parâmetro.

Claro que este é um exemplo extremamente básico, com um código que se não fosse pelo parâmetro passado para algumas classes, poderia ser executado até no Java 1.2, ou seja, a API de reflexão não é nova, é apenas sub utilizada pelo programador de nível médio.
Ahh, mas saber isto vai fazer com que eu seja um expert em java?
Claro que não! Mas não saber isto, com certeza te impede de ser um :D

test/Call.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
 
package test;
 
import java.lang.reflect.*;
 
public class Call {
        public static void main(String[] args) throws Exception {
                Class<?> clazz = Class.forName(args[0]);
                Method m = clazz.getMethod(args[1]);
                Object instance = clazz.newInstance();
                Object result = m.invoke(instance);
                System.out.println(result);
        }
}

Este é outro exemplo bastante simples, apenas para demonstrar algumas possibilidades, este exemplo bastante simples, chama um método sem parâmetros em uma classe qualquer que tenha um construtor padrão.
Para chamar métodos estáticos, seria necessária uma pequena alteração, o parâmetro passado para o método “invoke” da classe Method, é a instancia do objeto onde o método deve ser chamado, para métodos estáticos, esta instância é substituida pela classe que possui o método estático.
E o construtor padrão é necessário, por que precisamos de uma instância da classe para invocar o método, se a classe não possuir um construtor padrão, precisaremos passar parâmetros para o construtor, o que iria complicar bastante o exemplo, e a idéia aqui é só mostrar algumas possibilidades, e não complicar mais ainda a vida de vocês.
Mas como funciona o exemplo?
Tente compilar o exemplo, e executar ele passando os parâmetros:
java.lang.Object hashCode
ou
java.lang.Object toString
ou
QualquerNomeDeClasse nomeDeUmMétodoSemParâmetrosDestaClasse
e pronto, método executado.

Ai você vai pensar agora: Mas é muito mais fácil eu escrever direto “System.out.println(new Object().hashCode())” no meu código.
Claro que é, mas para isto você precisaria saber que o método que seria executado era o hashCode de uma nova instância de Object.
A idéia da API de reflection é obter informações em tempo de execução, é possibilitar um pouco de méta programação no Java.

Imagine só, criar um proxy para uma interface que garante que todos os métodos executados, caso tenham a anotação @Transactional, serão executados dentro do contexto de uma transação.
Isto é meta programação, isto é manter a mente um pouco mais aberta do que o programador médio.

Outra possível pergunta: Tu não vai ser expulso do clubinho por que esta revelando os segredos, como aconteceu com o Mister M?
Resposta: Claro que não, isto não é segredo nenhum, tu só não tinha aprendido antes por que não parou para estudar. Se você fosse um pouco mais preguiçoso, como eu, você já teria parado para estudar uma forma de trabalhar menos com as ferramentas que você tem na mão, e se você é um programador, meta programação, é uma forma de fazer mais trabalhando menos.

Mais uma pergunta: Por que ninguem me contou isto antes? explicando assim até parece fácil!
Resposta: Provavelmente achavam que tu é burro demais para entender, agora tu pode provar que isto não é verdade. E não se engane, não é tão simples assim, código usando reflexão pode ficar bastante complicado, eu só mostrei uns exemplos bem básicos.

A API de Proxies eu vou deixar como assunto para um próximo post, minha imagina imaginação esta meio fraca hoje, estou de saco cheio de assistir esta aula maluca que eu não to nem prestando atenção, acho que vou pra casa já :D

Se vocês tiverem idéias de mais exemplos que vocês querem ver como pode ser feito com reflexão, ou se tiverem perguntas sobre reflexão em java, por favor sintam-se a vontade de registrar as perguntas, dúvidas e sugestões aqui nos comentários do blog, vou tentar responder todas as perguntas :D
E como sempre, se você gostou deste post, indique para seus amigos, e coloque um link no seu blog :D

Acho que daqui a uns dias eu escrevo mais sobre reflection, mas vou tentar utilizar uns exemplos mais complexos, se tiverem sugestões para o próximo post, é só deixar nos comentários.

Tags: , , ,

11 May 09 Mensagens de erro são feias mas não mentem (nem mordem)

Já sou desenvolvedor a algum tempo (comecei em 1997, façam as contas se quiserem :D ), e uma das coisas mais importantes que aprendi até hoje é com certeza que todas as mensagens de erro geradas por linguagens de programação, frameworks, e assemelhados, são realmente feias.
Os Stack Traces do Java são realmente muito feios, chegam a assustar quem esta começando, os do Ruby não são muito melhores.
Em C++ não tem stack traces, mas os memory dumps fazem um papel parecido, e memory dumps podem ser conseguidos a partir de qualquer linguagem compilada.
O C# tem stack traces também, bem próximos do Java, acredito que isto seja parte do .NET e não uma particularidade do C#, mas eu conheço muito pouco de .Net, então agradeço se alguem puder confirmar isto.

Outra coisa bastante importante, e uma verdade absoluta, regra inquebrável, e como tal, tem pouquíssimas exceções, é que o código que você vai escrever não vai funcionar de primeira, você não é perfeito, e você vai cometer erros.
Pode acontecer de uma ou duas vezes durante a sua vida, você conseguir testar alguma coisa e esta coisa funcionar de primeira, mas eu não faria com que a minha felicidade dependesse disto, por que esta é uma situação bastante incomum.

Beleza, e o que uma coisa tem a ver com a outra?
Se você vai cometer erros, você vai precisar descobrir o que você fez de errado, e muitas das vezes, isto não vai ser fácil, e o seu melhor amigo para esta situação, a melhor ajuda que você vai conseguir, não vai ser do seu colega do lado, por mais Nerd que ele seja, vai ser a mensagem de erro/stack trace/memory dump que vai salvar a sua pele nesta situação.
Se o seu colega Nerd for te ajudar, provavelmente, ele vai perguntar: “Qual foi o erro?”
E se preste atenção nesta listinha de respostas:

  • Não sei.
  • Ah, apareceu um stack trace aqui, mas eu já apaguei.
  • Foi um erro estranho, acontece de vez em quando, mas nunca prestei atenção na mensagem.
  • Não lembro se foi null pointer ou out of memory, mas tu pode me ajudar aqui?
  • Ahh, vem aqui ver, eu não sei ler esta mensagem.

Estas são resposta inválidas, e provavelmente vão fazer o seu colega, que poderia te ajudar, ficar bastante chateado, e te ajudar com má vontade.
Para resolver este problema, você precisa aprender a ler estas mensagens de erro, isto vai te poupar muito tempo, e tudo o que poupa tempo, acaba te tornando mais produtivo, se tu for mais produtivo, o teu chefe vai gostar mais de ti, e tu vai ganhar mais, se tu for mais produtivo, tu vai terminar o que tem que fazer mais rápido, e por conseqüência, vai pra casa mais cedo :D

A leitura de mensagens de erro, seja qual for a encarnação, requer quatro coisas:

  1. Conhecimento básico do código da aplicação, ou conhecimento profundo da linguagem/framework utilizado (o primeiro é mais fácil de conseguir, mas não tenho como ajudar muito)
  2. Um pouquinho de técnica – nisto eu posso dar uma ajudinha, inclusive é esta a idéia deste post
  3. Conhecimento no mínimo básico de inglês – posso fornecer alguns links para ajudar, mas se você realmente quer continuar trabalhando com desenvolvimento de sistemas, você precisa aprender, no mínimo a lêr em inglês.
  4. Que o stack seja impresso na tela, em arquivo, mostrado em um dialog, ou qualquer coisa que facilite a visualização, sugiro logar todos os stack traces

Técnica básica para leitura de stack traces no Java

Algumas vezes, apenas ler a mensagem ja resolve o problema, como neste exemplo que peguei por ai na web:

INFO 13:37:20 [org.hibernate.connection.ConnectionProviderFactory] - Initializing connection provider: org.springframework.orm.hibernate3.LocalDataSourceConnectionProvider
WARN 13:37:41 [org.hibernate.util.JDBCExceptionReporter] - SQL Error: 17002, SQLState: null
ERROR 13:37:41 [org.hibernate.util.JDBCExceptionReporter] - Io exception: The Network Adapter could not establish the connection
WARN 13:37:41 [org.hibernate.cfg.SettingsFactory] - Could not obtain connection metadata
java.sql.SQLException: Io exception: The Network Adapter could not establish the connection
 at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:125)
 at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:162)
 at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:274)
 at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:328)
 at oracle.jdbc.driver.PhysicalConnection.(PhysicalConnection.java:361)
 at oracle.jdbc.driver.T4CConnection.(T4CConnection.java:151)
 at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:32)
 at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:595)
 at java.sql.DriverManager.getConnection(DriverManager.java:525)
 at java.sql.DriverManager.getConnection(DriverManager.java:140)
 at org.springframework.jdbc.datasource.DriverManagerDataSource.getConnectionFromDriverManager(DriverManagerDataSource.java:291)
 at org.springframework.jdbc.datasource.DriverManagerDataSource.getConnectionFromDriverManager(DriverManagerDataSource.java:277)
 at org.springframework.jdbc.datasource.DriverManagerDataSource.getConnectionFromDriverManager(DriverManagerDataSource.java:259)
 at org.springframework.jdbc.datasource.DriverManagerDataSource.getConnection(DriverManagerDataSource.java:241)
 at org.springframework.orm.hibernate3.LocalDataSourceConnectionProvider.getConnection(LocalDataSourceConnectionProvider.java:80)
 at org.hibernate.cfg.SettingsFactory.buildSettings(SettingsFactory.java:72)
 at org.hibernate.cfg.Configuration.buildSettings(Configuration.java:1859)
 at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1152)
 at org.springframework.orm.hibernate3.LocalSessionFactoryBean.newSessionFactory(LocalSessionFactoryBean.java:800)
 at org.springframework.orm.hibernate3.LocalSessionFactoryBean.afterPropertiesSet(LocalSessionFactoryBean.java:726)
 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1059)
 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:363)
 at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:226)
 at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:147)
 at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:269)
 at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:320)
 at org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:87)
 at org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:72)
 at org.springframework.test.AbstractSpringContextTests.loadContextLocations(AbstractSpringContextTests.java:121)
 at org.springframework.test.AbstractDependencyInjectionSpringContextTests.loadContextLocations(AbstractDependencyInjectionSpringContextTests.java:210)
 at org.springframework.test.AbstractSpringContextTests.getContext(AbstractSpringContextTests.java:101)
 at org.springframework.test.AbstractDependencyInjectionSpringContextTests.setUp(AbstractDependencyInjectionSpringContextTests.java:178)
 at junit.framework.TestCase.runBare(TestCase.java:125)
 at junit.framework.TestResult$1.protect(TestResult.java:106)
 at junit.framework.TestResult.runProtected(TestResult.java:124)
 at junit.framework.TestResult.run(TestResult.java:109)
 at junit.framework.TestCase.run(TestCase.java:118)
 at junit.framework.TestSuite.runTest(TestSuite.java:208)
 at junit.framework.TestSuite.run(TestSuite.java:203)
 at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:128)
 at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)

Como pode ser visto na linha 5, os stack traces no Java, começam sempre pelo nome completo da classe da última exceção gerada, seguida imediatamente pela mensagem de erro, separadas por “:”.
No caso deste exemplo, precisamos apenas acreditar que não foi possível conectar no banco de dados, ocorreu algum problema de rede.
Isto nos leva a um ponto que você vai descobrir sozinho quando trabalhar com oracle por um tempo, eles não ajudam muito a descobrir qual o problema :D
Acredito que este erro tenha ocorrido por problemas de configuração da conexão com o banco de dados ou então problemas com o banco de dados real …
Mas este stack esta aqui só pra eu poder reclamar um pouquinho da Oracle :D
Não serve como um exemplo do que eu quero mostrar para vocês (que tiveram paciência de ler até aqui);
Vejam este outro stack que eu gerei de propósito como exemplo:

Exception in thread "main" java.lang.NullPointerException
	at java.io.File.(File.java:222)
	at utils.urubatan.StackTraceReadingExample.readConfigurationFromFileName(StackTraceReadingExample.java:29)
	at utils.urubatan.StackTraceReadingExample.readConfiguration(StackTraceReadingExample.java:25)
	at utils.urubatan.StackTraceReadingExample.verifyConfiguration(StackTraceReadingExample.java:21)
	at utils.urubatan.StackTraceReadingExample.connectAndExecuteQuery(StackTraceReadingExample.java:17)
	at utils.urubatan.StackTraceReadingExample.main(StackTraceReadingExample.java:11)

Na linha 1, já temos um erro bastante comum, e se você ler isto, olhar para o seu colega do lado, e reclamar que o seu codigo gera um NullPointerException sem dizer o que esta acontecendo, por favor, desista de programar agora, antes que você fique realmente frustrado, ou se for muito insistente, coloque o seu amigo na cadeira de um psicólogo achando que trabalha com retardados :D
Este stack é até bem fácil, e serve para demonstrar o que eu quero …
Para ler um Stack trace, comece a ler de traz para frente, ou seja, leia normalmente de cima para baixo, e pare de ler na primeira linha em que o nome da classe pertencer ao seu projeto.
Neste caso, isto ocorre na linha 3 do stack trace: utils.urubatan.StackTraceReadingExample.readConfigurationFromFileName(StackTraceReadingExample.java:29)
Onde podemos ver que o erro esta sendo gerado no método “readConfigurationFromFileName”, da classe “StackTraceReadingExample”, na linha 29 do arquivo “StackTraceReadingExample.java”, ou seja, para corrigir o problema vamos para esta linha ver o que acontece lá, segue o código do exemplo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package utils.urubatan;
 
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;
 
public class StackTraceReadingExample {
	public static void main(String[] args) throws IOException {
		StackTraceReadingExample ex = new StackTraceReadingExample();
		ex.connectAndExecuteQuery();
	}
	private String fileName;
	private Properties configuration;
 
	private void connectAndExecuteQuery() throws IOException {
		verifyConfiguration();
	}
 
	private void verifyConfiguration() throws IOException {
		readConfiguration();
	}
 
	private void readConfiguration() throws IOException {
		readConfigurationFromFileName(fileName);
	}
 
	private void readConfigurationFromFileName(String theFileName) throws IOException {
		FileReader fr = new FileReader(new File(theFileName));
		createEmptyConfigurationIfNeeded();
		configuration.load(fr);
		fr.close();
	}
 
	private void createEmptyConfigurationIfNeeded() {
		if (configuration == null) {
			configuration = new Properties();
		}
	}
}

Na linha informada, a única variável que esta sendo utilizada é o nome do arquivo, que se formos ler o código, realmente nunca foi inicializado, para resolver este problema, basta que alteremos a linha 13 para inicializar a variável para algum nome de arquivo, vou adicionar: = “teste.config” e vamos ver o que acontece.

Depois desta alteração continuamos com um erro, e este stack continua bastante simples, mas é um pouco mais complicado que o anterior:

Exception in thread "main" java.io.FileNotFoundException: teste.config (The system cannot find the file specified)
	at java.io.FileInputStream.open(Native Method)
	at java.io.FileInputStream.(FileInputStream.java:106)
	at java.io.FileReader.(FileReader.java:55)
	at utils.urubatan.StackTraceReadingExample.readConfigurationFromFileName(StackTraceReadingExample.java:29)
	at utils.urubatan.StackTraceReadingExample.readConfiguration(StackTraceReadingExample.java:25)
	at utils.urubatan.StackTraceReadingExample.verifyConfiguration(StackTraceReadingExample.java:21)
	at utils.urubatan.StackTraceReadingExample.connectAndExecuteQuery(StackTraceReadingExample.java:17)
	at utils.urubatan.StackTraceReadingExample.main(StackTraceReadingExample.java:11)

Agora o erro esta na 5a linha do stack, que é a primeira linha com código fonte da aplicação …
Esta é a técnica básica para ler stack traces:

  1. Leia a mensagem de erro na primeira linha, as vezes ela pode te ajudar, se a mensagem não ajudar, você pode anotar o nome da classe do erro, que algumas vezes também já é informação o suficiente
  2. Logo em sequida, leia o stack de traz para frente (que é a mesma coisa que de cima para baixo no Java) e procure a primeira linha de código da tua aplicação, ou do framework que você esta utilizando, dependendo do caso e do erro que esta acontecendo, assim você acabou de localizar a linha de código que esta gerando o erro
  3. Se isto ainda não for o suficiente (muitas vezes não é), seguindo pelo Stack, mais para baixo, você pode literalmente voltar no tempo e saber quem chamou aquele método até o início dos tempos
  4. Se apenas ler o código não resolver, utilize a informação obtida no passo anterior, para saber onde colocar o “break point” e utilize o debugger da sua IDE para encontrar o problema, ou pelo menos a raiz do problema

Com estes passos, os stack traces vão te ajudar bastante, algumas IDEs como o Eclipse por exemplo, imprimem os stack clicaveis no console, ou seja, você clica em uma linha do stack trace, e o eclipse abre o arquivo, na linha em que o erro ocorreu.

Estes passos servem também para builds ANT, para programas escritos em action script (Flash ou Flex), para programas escritos em Ruby, incluindo o Rails.
E com pequenas adaptações, funciona também para C++, C, qualquer outra linguagem que gere algo parecido com um stack trace.

Agora uma perguntinha, só pra não perder o costume, você que leu até aqui, acha que valeu a pena a leitura? tem algum colega que você gostaria de poder obrigar a ler isto? ou tem algum exemplo que não se enquadra no que eu escrevi?
Eu tenho alguns amigos que eu gostaria de obrigar a ler isto, ou então abrir a cabeça e jogar isto para dentro, mas infelizmente eu não posso fazer isto.
Se você acha que o texto ficou bom, indique a leitura, se acha que precisa melhorar alguma coisa, deixe nos comentários que eu incorporo a melhoria no texto do post :D

PS.: este versionamento de posts do WP até que é legal, apaguei tudo sem querer, e acho que consegui recuperar legal com ele :D

Tags:

11 May 09 Até propaganda internacional tem meu livro agora :D

É issai :D

rubylearning

Em parceria com o pessoal do RubyLearning.org, e com a Novatec, estamos fazendo mais um sorteio do melhor livro sobre Ruby on Rails em português que eu já escrevi até hoje :D
O RubyLearning é um dos maiores e melhores sites disponíveis hoje para quem quer aprender Ruby, e o meu livro é uma ótima forma de se aprender Rails (pelo menos eu acho que é, e pelos reviews publicados, tem mais gente que concorda :D )

Quem quiser participar do sorteio, é só se cadastrar neste link, e informar o código BPCE101.

E tem também desconto para quem não ganhar o livro sorteado. Informações sobre o desconto de 30% no mesmo link, ou então na home do meu blog, logo abaixo da capa do livro :D

Bom, espero que gostem de mais esta promoção, que gostem do desconto, e que comprem muitas copias do meu livro, pra quem estiver com preguiça de acessar o blog para pegar o código de desconto, segue o banner :D




PS.: eu sei que só tenho falado do livro aqui, mas prometo que esta semana vou publicar uns posts muito legais, e que não vão ter nada a ver com o livro …

Tags: , , ,

11 May 09 Em time que esta ganhando se mexe sim (Refactoring básico)

Por mais que você seja um excelente programador, que todo o seu código funcione perfeitamente na primeira vez em que é executado (o que eu acho bem pouco provável que aconteça), por mais que você conheça pouco do código do sistema, ou por qualquer outro motivo que você possa lembrar agora ou daqui a 10 anos.
Em código que esta funcionando se mexe sim!
Mas por que estou dizendo isto? Porque se você fizer como eu, e de vez em quando, mas só de vez em quando para não ficar muito decepcionado consigo mesmo, pegar algum código que você escreveu no mês passado, ou a seis meses atrás, ou a um, dois, cinco ou dez anos, você vai achar este código muito mal escrito, mal organizado, feio, escrito por alguém que ainda precisava aprender tudo o que você aprendeu neste intervalo.
Se isto não acontecer com você, com certeza você está se tornando um programador medíocre que não aprendeu absolutamente nada neste intervalo, que não está melhor hoje do que era na semana passada, ou no mês passado ou no ano passado.
Esta sensação de que o código velho é ruim, não quer dizer que você era um programador ruim, é apenas o sinal de que você se esforçou e que hoje você é muito melhor do que era quando escreveu aquele código.

Ok, e o que isto tem a ver com este post? Tudo!
Se este código velho faz parte de algum sistema, biblioteca, projeto ou qualquer coisa do gênero que você não trabalha mais, deixe da forma como está, as pessoas que estão trabalhando nele agora que se preocupem com ele. Mas se ao contrário ele ainda faz parte de um código que você evolui dia a dia, então é sua responsabilidade fazer com que este código velho e maltrapilho, escrito por você ou não, evolua também, pelo menos o suficiente para não atrapalhar o código novo, escrito por este programador muito melhor do que aquele que escreveu o lixo que está sob seus olhos, mesmo que este tenha sido você ontem.
E este ato de piedade, generosidade e auto compaixão, é chamado de refactoring.
Ou seja, você vai fazer com que o código legado, melhore, seja mais testável, mais estável, mais bonito, sem quebrar todo o resto do sistema que já depende daquele pedaço de lixo que você escreveu no passado :D
E por que isto é também um ato de “auto compaixão”? Porque como eu ouvi um amigo comentar várias vezes, assim você esta diminuindo a quantidade de problemas legados que você vai ter que lidar no futuro próximo.

O que é rafactoring

Segundo a wikipedia: Refatoração (do inglês Refactoring) é o processo de modificar um sistema de software para melhorar a estrutura interna do código sem alterar seu comportamento externo.

Segundo o papa: Refatoração é uma técnica disciplinada para reestruturar um corpo de código existente, alterando a sua estrutura interna sem alterar o seu comportamento externo. O coração da técnica é uma série de pequenas transformações preservando o comportamento. Cada transformação (chamada de refactoring) faz um pouco, mas uma série de transformações podem produzir um resultado significante para a qualidade do sistema. Já que cada refatoração é pequena, é menos provável que ela cause algum problema. O sistema é mantido 100% funcional depois de cada refactoring. Reduzindo as chances de algum problema grave no sistema no final da reestruturação.

O que indica que um código precisa ser refatorado?

Basicamente se você acha que pode melhorar o código, isto já vale o rafactoring. Você achar que pode melhorar o código quer dizer que você esta sentindo que tem alguma coisa errada com ele, mesmo que você não tenha muita certeza de o que esta errado. Isto só quer dizer que você já aprendeu mais coisas depois que escreveu o código que esta lendo agora.
Mas podemos também formalizar isto um pouco, ou seja, definir alguns pontos nos quais todos concordam haver problemas no código, estes servem como argumento inclusive para você dizer que o código dos outros não esta muito bom, ou para você ter certeza de que o seu esta um lixo logo depois que escreve-lo.

  • Código duplicado (duplicated code)
  • Método longo (long method)
  • Classe grande (large class)
  • Lista de parâmetros longa (long parameter list)
  • Má indentação (Bad Indentation)

Os nomes em inglês estão ali por que eu não inventei isto, eu retirei esta pequena lista do livro do Fowler sobre rafactoring, também referenciado como “a biblia” pelo menos por mim :D

Alguns exemplos de refactoring

Ok, agora que você já sabe como identificar alguns problemas (é fácil, é só você achar que hoje sabe mais do que ontem :D ), vamos ver algumas soluções engarrafadas, prontinhas para beber, ou utilizar na sua IDE preferida (todas as IDEs Java hoje em dia possuem um suporte muito bom para refactorings).

  • Adicionar parâmetro – Add Parameter
     Muitas vezes é necessário adicionar mais um parâmetro em um método já existente, quando fizer isto, sera necessário alterar todos os lugares que já chamam o método existente, ou pelo menos deixar o método original como um delegate passando um valor padrão para o novo método, tudo depende de por que você esta utilizando este refactoring
  • Converter inicialização dinâmica por estática – Convert Dynamic to Static Construction
     Algumas vezes a utilização de reflection pode criar fraquezas para o sistema, se isto não for necessário, então prefira inicializar estaticamente os objetos
  • Converter inicialização estática por dinâmica – Convert Static to Dynamic Construction
     Algumas vezes o sistema tem bastante a ganhar com a utilização de reflection para reduzir código duplicado ou pelo menos para adicionar flexibilidade
  • Encapsular atributo – Encapsulate Field
     Nunca, e eu disse nunca mesmo, exponha um atributo diretamente em java, isto simplesmente não esta certo, prefica utilizar métodos de leitura e escrita
  • Extrair classe – Extract Class
     Várias vezes é possível encapsular parte do comportamento de uma classe maior em outra classe
  • Extrair interface – Extract Interface
     Algumas vezes acessar diretamente uma classe de outras partes do sistema aumenta muito o acoplamento do sistema, nestes casos, prefira criar uma interface com os métodos públicos e esconder um pouco a implementação, ou até mesmo criar mais de uma implementação
  • Extrair metodo – Extract Method
     Diversas vezes, quando o código de um método esta muito grande, é possível extrair parte dele para um outro método, preservando o comportamento e reduzindo a duplicação de código
  • Extrair sub classe – Extract Subclass
     Quando parte do comportamento de uma classe é utilizado apenas em situações especificas, criar uma sub classe pode ser uma boa idéia
  • Introduzir “objeto parâmetro” – Introduce Parameter Object
     Quando um método tem muitos parâmetros, algumas vezes é útil encapsular estes parâmetros em um objeto, e faer com que o método receba apenas aquele objeto como parâmetro
  • Mover classe – Move Class
     Quando um package tem muitas classes, algumas vezes é útil mover uma ou mais classes para outro package, também pode ser utilizado quando uma classe simplesmente esta no lugar errado.
  • Subir método – Pull Up Method
     Quando um método é implementado em mais de uma classe e estas classes compartilham uma super classe, pode ser útil mover a implementação deste método para esta super classe
  • Remover parâmetro – Remove Parameter
     Algumas vezes um dos parâmetros de um método simplesmente não é mais utilizado
  • Remover método de escrita – Remove Setting Method
     Quando um atributo deve ser somente leitura, não é interessante que exista um método de escrita para este atributo
  • Renomear método – Rename Method
     Algumas vezes o nome de um método simplesmente não parece certo, ou então não diz o que aquele método faz.


Claro que estes não são os únicos refactorings existentes, esta é apenas parte da lista que pode ser encontrada no site do livro de refactorings do Martin Fowler. Apenas as descrições foram escritas por mim, e mesmo no site, ou no livro do Fowler você não vai encontrar uma lista completa, por que é bem possível que outro refactoring seja criado hoje ou amanha, o importante é entender a idéia.

E eu tenho que decorar tudo isto? Tenho que fazer na mão e garantir que funciona?

Uma das coisas boas de ótimas idéias é que muita gente gosta delas, e acaba copiando.
Em algum momento do passado remoto do desenvolvimento java, quando as boas IDEs eram todas pagas, o pessoal da JetBrains, leu “a biblia” e disse: Que o IntelliJ IDEA ajude os desenvolvedores a fazerem os rafactorings para que o código se torne bonito e legível. E assim fez o IntelliJ IDEA.
Algum tempo depois, o eclipse copiou a idéia e passou a suportar muitos refactorings também, e hoje em dia o NetBeans também suporta muitos refactorings, e assim o desenvolvedor vive feliz podendo ser produtivo com a sua IDE favorita.
Eu adoro o IntelliJ IDEA, mas utilizo muito mais o eclipse, e algumas vezes até o NetBeans.
Todas as 3 IDEs suportam refactorings, e até o VIM e o Emacs suportam refactorings, mas não se iludam desenvolvedores Java, o pessoal da microsoft viu que isto era bom, e também adicionou suporte a diversos refactorings no visual studio, por tanto vocês não são mais os únicos com boas ferramentas.
Então respondendo a pergunta do título, não precisa decorar tudo, e não precisa fazer tudo na unha não, mas por favor, decore pelo menos os atalhos para os refactorings suportados pela sua IDE, o seu código agradece.
Outro dia eu coloco uma lista de atalhos de cada IDE para alguns refactorings por aqui (se der tempo :D )

Mas só isto basta? Meu código não vai parar de funcionar mesmo?

Um dos valores do Extreme Programming é a coragem, e este valor é necessário para se refatorar o código por exemplo, a probabilidade de o seu código parar de funcionar depois de um refactoring com a ajuda da sua IDE é bem pequena, um refactoring manual é mais arriscado, mas o código limpo bonito e funcional vale o risco.
Outra coisa, para diminuir o risco, escreva testes para o seu código sempre, com os testes, você tem algo para garantir que você não quebrou nada enquanto estava refatorando.
Mas se o mariquinhas ai não tem coragem de mexer no próprio código, pode continuar escrevendo código mediocre por ai, deve ter alguem com coragem o suficiente para fazer um trabalho decente e entregar código de qualidade na sua empresa, só espero que o seu chefe não se preocupe muito com qualidade, se não o teu medinho vai custar o teu emprego, por que com certeza, esta tua frescura já ta custando a qualidade do teu trabalho sua franguinha!

Sem brincadeiras agora, nem toda hora é hora de refatorar, nem todo refactoring vale a pena, nem sempre se tem tempo para melhorar o que já esta pronto, mas ler o código e saber o que pode ser melhorado, e como melhora-lo vai garantir que você faça menos porcaria no futuro, pelo menos comigo isto funciona :D

Tags: , ,

08 May 09 Fotos do Porto Alegre Agile Weekend 2009

Foram publicadas as fotos do Porto Alegre Agile Weekend 2009.
Tem até algumas fotos do gordo que vos escreve palestrando :D
Aqui, aqui e aqui.

Eu só não sei quem foi o fotografo, que quase não tirou fotos das moças da recepção :D
Bom, era isto, falta do que escrever é algo complicado :D

Tags: ,