Análise dos Refatoramentos jMemorize 1.2.3 Professor: Equipe: Adalberto Júnior Fábio Leal Jeysibel Dantas Renato Almeida Solon Aguiar Rohit Gheyi Julho / 2010 106 1. Objetivo Ao longo desse documento procuramos evidenciar quais foram os refatoramentos aplicados ao código do sistema jMemorize. A versão do sistema tomada como base para a aplicação dos refatoramentos foi a 1.2.3. As modificações no código da aplicação foram motivadas por ferramentas de análise estática, tais como o Findbugs e o Metrics. Seguimos os seguintes passos para a aplicação de refatoramentos: Análise do código por ferramentas de análise estática; Verificação do código (descobrir se há, de fato, motivos para mudança nos trechos de código); Rodar testes (do Sistema e os gerados pelo Randoop); Realizar Mudanças; Rodar testes novamente. Seguindo essa rotina pudemos perceber que o processo de refatoramento torna-se mais seguro. 2. Refatoramentos Durante o processo de estudo da evolução do jMemorize foram feitos refatoramentos tanto de forma automática quanto de forma manual. Os refatoramentos assistidos por ferramentas foram realizados pelas ferramentas de refatoramentos da IDE Eclipse. Esses refatoramentos foram guiados pelos resultados das ferramentas de análise (Findbugs, Randoop). Isso ocorreu devido ao fato de que realizar refatoramentos sobre um sistema desconhecido sem auxilio de guia é uma tarefa complicada e demorada. Essa também foi uma forma utilizada para confrontar as saídas dessas ferramentas com resultados reais. A seguinte imagem representa a análise inicial do Plugin Metrics (mais detalhes sobre essa análise inicial podem ser vistos no documento de Análise de Qualidade). Figura 1 – Análise do código original 107 Durante o processo de refatoramento, foram utilizados, dentre outros, os seguintes tipos de transformações: • • • • • Remoção de atributos não utilizados; Tratamento adequado de exceções; Fechamento de Streams que permaneciam abertas quando não era necessário; Melhoramento de performance do sistema (através das dicas do Findbugs); Rename de atributos e métodos. Exemplos dos refatoramentos aplicados Nas imagens seguintes, o lado esquerdo representa o código original e o lado direito o código refatorado. Isso foi feito para facilidade de comparação. 1) Exclusão de checagens desnecessárias ao longo do código. Figura 2 – Checagem desnecessária da nulidade de Lesson 2) Evitar criação de objetos desnecessários: Esse tipo de modificação pode ter alterado de maneira decisiva a performance do sistema, uma vez que encontrávamos essa situação dentro de loops. Figura 3 – Criação de objetos desnecessários 3) Má utilização da API: Ao invés de usar classes superiores como o entrySet, o código faz uso de keySets. Isso também foi verificado para “Lists” Figura 4 – Má utilização da API 4) Criação de um Comparator sem fazer uso da interface Serializable: A documentação de Java recomenda fortemente que seja implementada a interface serializable em objetos do tipo Comparator. Figura 5 – Má implementação de objetos Comparators 5) Tratamento incorreto para exceções: Muitos trechos de código da aplicação não têm o devido tratamento de exceções. Figura 6 – Tratamento de exceções indevido 108 Feitos os refatoramentos propostos, no total, 20 entidades sofreram alguma mudança. Os tipos de refatoramentos propostos mostram que tratamos tanto de refatoramentos high level, como nos casos de rename de atributos, como refatoramentos low level, que foi o caso de rename de métodos e tratamento de exceções, por exemplo. Dependendo do impacto das entidades e métodos refatorados, esses refatoramentos podem ser classificados em local e global. Enquanto executávamos os refatoramentos percebemos que as ferramentas de análise estática, apesar de servirem como um bom guia, não são 100% confiáveis. A implementação de simples refatoramentos (feitos tanto de forma manual, como de forma automática) sugeridos pelo Findbugs faziam com que o sistema mudasse de comportamento ao lançar exceções inesperadas. Esse tipo de erro foi possível de captar mediante a execução dos testes gerados pelo Randoop após a realização do refatoramento. O objetivo desse teste de regressão era justamente checar a preservação do comportamento. Sendo assim, ratificamos aqui a importância de se ter uma boa coleção de testes ao refatorar um sistema real. Se o processo de refatoramento, conforme foi exposto em sala de aula, não for seguido à risca, desenvolvedores podem perder bastante tempo à procura de faltas geradas por refatoramentos originalmente sugeridos por ferramentas. Podemos ver, na Figura 7, a maneira como o software evoluiu após os refatoramentos. Ao fazer uma breve comparação com os resultados obtidos para o sistema não refatorado, podemos traçar um paralelo entre o valor anterior e o obtido após refatormarmos o sistema. Dessa maneira, percebemos que os números após os refatoramentos tornaram-se melhores (segundo nossas métricas) quando comparados às medidas sugeridas pelo plug-in Metrics antes do refatoramento. Mais detalhes podem ser vistos no documento de Análise de Qualidade. Figura 7 – Análise do código refatorado 109 As mudanças feitas após a utilização das ferramentas FindBugs e Randoop totalizaram 90 LOC. Tudo o que foi modificado pode ser observado no endereço: http://pastebin.com/RbyP1yY5, onde é feita a comparação da versão inicial com a versão refatorada. 110