Esse artigo faz parte da revista Java Magazine edição 36. Clique aqui para ler todos os artigos desta edição

ht=34 alt=imagem_pdf.jpg src="/imagens/imagem_pdf.jpg" width=34 border=0>

Qualidade Aplicada

Aperfeiçoe seu código com ferramentas e plug-ins

Conheça regras que auxiliam a escrita de código de qualidade, e podem ser verificadas automaticamente por ferramentas como PMD e Checkstyle, e recursos embutidos no Eclipse

Osvaldo Pinali Doederlein

Qualidade é um dos principais requisitos de qualquer produto – mas também o mais difícil de definir e medir. Num sistema de software, existem várias dimensões de qualidade: bugs, aderência às especificações, desempenho, facilidade de uso e outros fatores. Neste artigo vamos nos concentrar numa única dimensão: a qualidade de código, ou mais precisamente, a qualidade de artefatos individuais de código – como classes e métodos Java.

A redação da Java Magazine recebe solicitações freqüentes de práticas recomendadas de programação, ou dicas para aprender a escrever código de qualidade. Uma das melhores respostas é o já clássico livro Effective Java, de Joshua Bloch, que introduz várias regras fundamentais. Essa referência é um excelente começo, mas ainda que você aprenda centenas de regras, permanece o problema de garantir que não esquecerá de observá-las ao escrever cada linha de código – ou determinar se foram seguidas em código criado por outros desenvolvedores.

Qualquer disciplina de qualidade depende da medição contínua de indicadores de qualidade dos produtos ou processos relevantes, o que em geral é bastante trabalhoso. Como nossa preocupação é com código fonte, temos a facilidade de utilizar ferramentas que automatizam boa parte do trabalho. Estas ferramentas verificam se o código adere a padrões configurados de estilo e de uso de recursos da linguagem e APIs. São padrões que servem como indicadores de qualidade, mas que são apenas "suspeitas" de problemas potenciais (como bugs, código confuso ou ineficiente), cabendo ao desenvolvedor avaliar estas suspeitas e verificar se alguma ação corretiva é necessária.

Neste artigo, apresentaremos uma seleção de regras, enfocando as que são verificáveis automaticamente por ferramentas de qualidade de código Java. Abordaremos especificamente os programas PMD e Checkstyle e explicaremos de forma prática, com exemplos de código, o raciocínio por trás de cada regra. Visamos com isso a incentivar o leitor a justificar o esforço de revisar código existente, ou pelo menos aderir a estes critérios para código novo. É comum que regras aparentemente arbitrárias sejam capazes até de evitar bugs sutis.

Finalmente, veremos como utilizar facilidades de IDEs modernos para revisar de forma automática muitos dos problemas detectados, o que torna a adoção destas ferramentas bem mais fácil e segura.

Ferramentas de Qualidade Java

A plataforma Java conta com várias ferramentas de verificação de qualidade de código, havendo opções comerciais e open source. Entre estas últimas, destacam-se o Checkstyle e o PMD. São ferramentas que podem ser utilizadas de forma isolada na linha de comando, como tasks do Ant, como plug-ins do Maven, ou através de plug-ins de IDEs. A Figura 1 ilustra o efeito de algumas das regras de estilo e qualidade apresentados neste artigo; as advertências são geradas automaticamente quando os fontes são recompilados. Além disso, o compilador do JDT (Eclipse) também incorpora muitas validações de qualidade de código.

Este artigo procura ser independente de ferramentas específicas, utilizando nomes e descrições genéricas para as regras discutidas (ao invés, por exemplo, dos identificadores de regras do PMD). Mas para um início fácil e prático, o quadro "Usando os plug-ins para Eclipse e NetBeans" mostra como instalar, configurar e utilizar os plug-ins do Checkstyle e do PMD para estes dois IDEs.

Após esta configuração inicial, seja na forma de plug-ins ou de outra forma preferida (como via Ant), recomendo fazer um teste com algum projeto seu. É provável que a experiência inicial seja traumática: você tem um projeto que compila limpinho, sem nenhuma reclamação do compilador; ativa uma ferramenta de validação, e pumba! – milhares de advertências aparecem na janela de problemas do IDE, ou no log de build.

Veja, por exemplo, na Figura 1, o resultado do acionamento do Checkstyle e PMD (com todas as regras ativas) sobre o código de um artigo anterior desta mesma coluna: dez advertências para apenas 28 linhas de código. Multiplique isso por um projeto realista, digamos com 10 mil linhas de código, e o resultado é que muita gente decide que é trabalhoso demais revisar o código para eliminar tantas advertências – e que é arriscado mexer tanto em código já estável.

Também é comum a impressão que estas ferramentas são muito "chatas" para serem toleráveis em projetos maiores. Mas não precisa ser assim: as ferramentas de validação são muito configuráveis, nem todas as regras são obrigatórias, e vários problemas podem ser corrigidos de forma automatizada.

 

image002.jpg
Figura 1.
Algumas advertências geradas pelo Checkstyle e pelo PMD, com seus plug-ins para Eclipse.

Problemas detectados

Ferramentas como Checkstyle e PMD diagnosticam três tipos de questões: violações de estilo, problemas potenciais, e boas práticas de programação.

As violações de estilo são desvios em relação a algum padrão de estilo de codificação, o que inclui regras de formatação, espaçamento, uso de operadores etc.

Para controlar o estilo do código, o Eclipse suporta dezenas de opções de formatação e permite reformatar automaticamente o código existente. Mas mesmo no Eclipse, permanece o problema de saber se algum código já escrito adere aos seus padrões de estilo. Não é uma boa prática rodar formatadores automáticos arbitrariamente, pois estas ferramentas nem sempre fazem um trabalho perfeito (é comum o código precisar de alguns "retoques" manuais). A solução para o problema é uma ferramenta como o Checkstyle, que verifica se o seu código está aderindo ao estilo desejado.

Um dos problemas do uso dessas ferramentas é que se deve escolher uma configuração de estilo uniforme para todo o projeto (ou mesmo toda a empresa), mas alguns programadores podem ter resistência a se submeter a estes padrões, acreditando que isso é uma “questão de gosto, que não se discute".

Na prática não é bem assim. Primeiro, várias regras de estilo têm razões objetivas, como prevenir bugs de ocorrência comprovadamente comum com o estilo "errado". Ou tornar o código mais legível: há vários critérios objetivos de legibilidade, por exemplo o uso de identificadores longos e descritivos (um dos principais truques dos ofuscadores de código, para tornar o código menos legível, é substituir tais identificadores por outros, arbitrários e de uma só letra).

Segundo, mais importante que a escolha de um estilo em particular é a padronização. Trabalhar com um grande volume de código escrito num estilo diferente do seu favorito, e escrever código novo nesse estilo, pode ser chato. Mas não há nada pior do que trabalhar com código que utiliza uma mistura aleatória de estilos, com cada classe ou método formatado de maneira diferente.

Mais importante que um estilo em particular é a padronização. Não há nada pior que uma mistura aleatória de estilos.

Os problemas potenciais são o segundo item detectado por ferramentas de checagem de qualidade. São padrões de codificação que provavelmente indicam um erro ou outro tipo de problema (como de desempenho).

Um exemplo nesta categoria é um loop sem nenhum corpo, como "while (x++ < 0);". Embora seja possível escrever loops que realizam trabalho útil sem possuir corpo, na prática isso é muito raro, e a maioria dos loops sem corpo indica um bug – tipicamente um “;” indevido logo em seguida ao “)”.

Por fim, as ferramentas checam as boas práticas de programação: recomendações que tendem a tornar seu código mais legível, seguro, eficiente ou fácil de modificar.

Um exemplo nesta categoria é proibir a construção de strings complexas através de sucessivas concatenações (operadores + e +=), o que em Java é ineficiente, sendo preferível utilizar um StringBuilder (JSE 5.0+) ou StringBuffer.

Regras de qualidade

Nesta seção, apresentamos uma seleção de recomendações que devem ser levadas em consideração ao escrever código Java. Abordaremos regras que podem ser verificadas de forma automática por pelo menos uma destas ferramentas: Checkstyle, PMD e Eclipse JDT.

Tamanho e complexidade de código

Há várias regras nesta categoria. Por exemplo, evite cláusulas else desnecessárias, se o código do else executa incondicionalmente caso o processamento chegue naquele ponto do método.

 

public int max (int a, int b) {

  if (a >= b)

?  return a;

  else

?  return b;

}

 

O else acima é redundante pois, se fosse removido, a cláusula ? nunca seria executada se ? for executada, já que a primeira faz um return. Este if de quatro linhas (isso sem { }) pode ser substituído por um simples "return (a >= b) ? a : b;".

De bônus, a modificação também satisfaz a outra regra, que vem desde a programação estruturada: um algoritmo deve possuir um único retorno, de preferência no final; isso torna o fluxo de controle mais claro e legível.

Outra regra recomendada é evitar aninhamento desnecessário de condições:

 

if (a) {

  if (x != null)

    fazAlgo(x);

}

 

Os dois ifs acima poderiam ser condensados: "if (a && x != null)". O aninhamento desnecessário é um problema de clareza, pois torna o código mais complexo. Pode também estar ocultando bugs, por exemplo o esquecimento de codificar condições alternativas (else) de algum destes ifs.

Outra regra importante: evitar métodos muito grandes, ou muito complexos. Ferramentas de qualidade costumam flagrar métodos cujo número de linhas ou complexidade ciclomática[1] excedam algum limite fixo ou configurável:

 

void criaUsuario (FormUsuario form) {

  if (form.valida()) {

    // 20 linhas de código para criar o usuário,

    // ir para página de sucesso, fazer logging, etc.

  } else {

    // 15 linhas de código para cancelar operação,

    // gerar dados de erro, ir para tela de erro, fazer logging, etc.

  }

}

 

O código acima é mal estruturado. A solução é usar refatorações como "extrair método" para transformar todo o bloco que faz a criação de usuário num novo método (privado, se não for útil em outros lugares), e o mesmo para o bloco que cancela a operação.

Uma regra de ouro da programação (em qualquer paradigma) é que uma subrotina deve executar uma única tarefa. Nosso criaUsuario() faz três coisas: uma decisão baseada na validação, a criação, e o cancelamento.

Só não siga esta regra de forma muito radical. Devem ser observados fatores como a coesão: os códigos alternativos são intimamente relacionados, ou são subtarefas independentes? E o volume: se os códigos para "criar" e "cancelar" tivessem apenas uma ou duas linhas, não valeria a pena extraí-los para novos métodos, a não ser que estes fossem reusáveis em outros lugares? ...

Quer ler esse conteúdo completo? Tenha acesso completo