domingo, 23 de fevereiro de 2014

Ajuda para resolver problemas detetados no código fonte


Recebi um email furioso / desesperado de um leitor do Blog, o qual, com razão, solicita ajuda para resolver problemas detetados em uma recente análise de código, feita depois do nosso artigo "Análise de código fonte em Java com ferramentas livres". Apesar de ser um Domingo, e eu ter acabado de acordar, acho que vale um post sobre o assunto, pois tenho responsabilidade com aquilo que publico para vocês. Vamos ver rapidamente em que posso ajudar.


Problemas, problemas problemas...

Vamos começar mostrando um pedaço do email que recebi:
"Nosso Cliente leu seu artigo ("Análise de código fonte em Java com ferramentas livres") e exigiu que nós apresentássemos o resultado da análise do projeto que estamos fazendo para ele. Só que nada havia sido tratado sobre requisitos de qualidade, e agora, ele quer valores muito exigentes para o projeto..."
Bem, realmente, isso é um grande problema, afinal, você não orçou o custo da alta qualidade para ele, logo, pode haver um impacto significativo no custo final para você. Porém, Qualidade de software é um requisito não funcional, e, como desempenho, segurança e outros, deveria ser discutido com o Cliente antecipadamente. Porém, existem duas coisas que você pode fazer:
  1. Discutir com ele a possibilidade de manter a Dívida técnica sob conrole, afinal, não vale a pena tentar zerar tudo, conforme eu disse na palestra "Dívida técnica em projetos Java". Você pode e deve assumir um pouco de dívida técnica, para manter a viabilidade econômica do projeto, já que não era um requisito do projeto entregar código com altos indicadores de qualidade. Mas você deve ser transparente: mostre a Dívida técnica resitual e faça um orçamento para zerá-la;
  2.  Priorize os problemas de qualidade. Rola um "pareto" na qualidade de software, segundo o qual, 80% dos problemas são baseados em 20% das causas. Resolver alguns poucos itens importantes, pode melhorar significativamente a qualidade geral do código, colocando a dívida técnica sob controle.
"... então, usamos o jQana, conforme você recomendou, e temos vários números vermelhos... e o que fazer agora? O seu "help" é em inglês e você não tem email nem telefone de contato e nós o achamos depois de pesquisar muito na Internet..."
Vamos lá... Para começar, no próprio site do jQana temo endereço do fórum (mailing list), através do qual é possível me enviar mensagens. E, sobre o "help" ser em inglês, eu agradeceria muito se alguém se oferecesse para criar versões em outros idiomas, incluindo Português. O problema é que o jQana é uma ferramenta utilizada internacionalmente, e o inglês é a língua padrão para informática.

Eu sempre posto artigos no "Bom Programador" sobre métricas, análise de código e sobre o prório jQana, logo, você pode fazer uma pesquisa aqui e verá muitas dicas sobre isso.

Finalmente, para usuários mais avançados, eu recomendo os meus LIVROS, especialmente o que fala sobre Análise de Código, no qual eu discuto mais detalhadamente os assuntos.
"Para começar, nosso projeto é JSF e temos um managed been" (ele quis dizer "Managed Bean") "...o jQana apontou um valor de LCOM4 = 4. Será que temos que mexer nisso? Qual é a melhor forma?"
LCOM4

No Wiki do jQana, eu explico a métrica LCOM4. Essa métrica verifica quandos ˜Componentes conectados" existem dentro de uma única classe.

Cálculo LCOM4 é complicado! Primeiro, precisamos de construir uma lista com todos os métodos e variáveis ​​de classe, e listar quais os métodos ou variáveis que cada um faz referência. Então, precisamos de ler esta lista e tentar encontrar componentes conectados.

Algumas regras que usamos:

  •      Construtores são ignorados, pois eles tendem a inicializar todas as variáveis​​, de modo que eles podem reduzir artificialmente o valor LCOM4;
  •      Classes internas e classes anônimas não são consideradas;
  •      Métodos anotados com "@Override" são ignorados;
  •      Métodos órfãos são ignorados (métodos que não estão sendo invocadas por outros métodos;
  •      Getters e Setters são considerados campos;
  •      Métodos sobrecarregados são consideradas um método único;
Managed beans são classes exigidas pelo Javaserver Faces, um framework que agrega alta complexidade acidental e que já criticamos no artigo "É hora de balançar a árvore!". E esses componentes, Managed beans, quase sempre acabam sendo implementados como classes que violam o SRP (Princípio da Responsabilidade Única), e acabamos embutindo regras de negócio neles.

Um Managed bean, normalmente, tem muitas variáveis de instância, e métodos que acessam apenas um subconjunto delas. Isso cria necessariamente classes com baixa coesão de métodos. E é um problema? É, sim. Um enorme Managed bean, com muitos campos que são acessados por subconjuntos de métodos, representa uma classe que viola o SRP. Na verdade, estamos juntando várias "helper classes" dentro de uma só. O ideal é separarmos os Managed beans, seja por páginas que atendem ou por tipo de conversação, diluindo o risco de problemas e diminuindo o "britleness" do sistema.
"... e também tivemos altos valores de RFC... Esse limite de 50 é muito baixo. O que devemos fazer?"
RFC

Response for a class é uma métrica de acoplamento e também de complexidade. É a quantidade de métodos potencialmente ivocados a qualquer invocação de método de uma classe.  

Contamos cada método, construtor e método invocado, seja interno ou externo. Note que há duas abordagens para calcular RFC: RFC completa e RFC implementada. RFC completa é recursivo, e conta com todas as chamadas de método dentro da classe e em outras classes também. RFC Implementada conta apenas os métodos invocados pela classe em análise. Utilizamos abordagem RFC implementada.

Regras seguimos:

  •      Cada classe 'contagem método 1, incluindo getters / setters;
  •      Cada contagem método invocado como 1;
  •      Cada construtor, incluindo no-args contam como um Object () e;
Observe que cada método invocado é contado apenas uma vez.

O que provoca alto RFC? Uma classe que está fazendo "mais do que deveria"! No seu caso, não sei exatamente em quais tipos de classes você teve alto RFC, mas, provavelmente, essas classes estão invocando mais de uma API de componentes diversos. Vamos supor uma classe que implementa um Web Service, que recebe um XML dentro de um CDATA, acessa um banco, grava o XML recebido como String, e também acessa outros Web Services. Neste caso, ela vai usar várias APIs:
  • JAX-WS;
  • IAXB;
  • JPA;
  • Hibernate.
Ela poderá facilmente superar o valor de 50, se tornando um problema pra o seu sistema. Qual seria a solução? Delegar! Refatorar, delegando as tarefas para classes auxiliares. Isso diluiria o valor de RFC através de várias outras classes e desacoplaria a classe principal, diminuindo a possibilidade de "britleness".
 "... e temos o problema apontado pelo jdepend a Distance from the Main Sequence, que não sabemos como resolver..."
Problemas arquiteturais

Bão, nesse caso, você tem um problema sério, meu caro! A arquitetura do seu software apresenta baixa flexibilidade e manutenibilidade, tornando a manutenção futura (seja corretiva ou evolutiva) mais cara e arriscada.

O que causa isso? A métrica DMS indica a relação entre Abstração e Instabilidade de um pacote de classes. Eu recomendaria a você assistir à minha palestra: "Análise de código java com ferramentas Open Source", ministrada pelo CISL, cujo vídeo gravado está disponível AQUI.

Um pacote com DMS = 1 (ou 100%) apresenta um desequilíbrio sério ente Abstração e Instabilidade, ferindo os princípios: Stable Dependencies Principle, Stable Abstractions Principle e Dependency Inversion Principle (veja tudo em: "Dependências entre Pacotes").

Prolemas arquiteturais é melhor você negociar com seu Cliente, afinal, possuem alto custo para resolver. Eu investiria no refactoring dos Managed beans e das classes que estão com alto RFC, em primeiro lugar.

Problemas com violações de regras

Você também mencionou centendas de erros no Checkstyle... Para começar, você pode reduzir drasticamente os erros se fizer duas coisas:
  • Faça "bulk replace" dos caracteres TAB por quatro espaços. Isso fará com que várias linhas de mensagem (das que você me mandou) desapareçam;
  • Retire os espaços extras nos finais de linha do seu código. Existem ferramentas para isso. 
O resto, pode ser cofigurado.

Já os problemas de PMD, infelizmente, não são tão simples. E eu precisaria ter acesso ao código fonte para ver o que está acontecendo, mas existem problemas sérios, como o "Empty database password", que significa que você está usando um banco de dados sem segurança alguma. Reveja isso urgentemente.

Espero ter ajudado um pouco

Na empresa, que não vou identificar, um Cliente (do nada) incluiu no Contrato que a complexidade ciclomática média de cada classe não poderia ser maior que 10. Olhe que é um pedido muito conservador...

Construíram o sistema "defecando" para esse item do Contrato. Bem, testaram, homologaram o sistema e entregaram para o Cliente, que suspendeu o pagamento por violação de contrato. O Cliente rodou uma avaliação e notou diversos problemas:
  • Falta de código de teste;
  • Diversas violações de regras importante, incluindo de segurança;
  • Classes com CC média maior que 15.
O que fazer? Depois do "leite derramado" não adianta chorar...

Estamos vivendo a grande revolução da qualidade de software, logo, nós, que desenvolvemos aplicações, temos que adotar princípios e processos que privilegiem a criação de sistemas mais seguros, estáveis, robustos e com maior qualidade.

Afinal, é o que você exige do Fabricante, quando compra um carro, não? E quando compra um sistema, que custa 10 ou até 100 vezes mais?