Tag Archives: qualidade de código

Maus cheiros em códigos de teste… Eles existem!

Acabei de ler um paper muito legal sobre code smells em código de testes [1]. Resumindo aqui os resultados:

  1. Maus cheiros em testes não são percebidos pelos desenvolvedores como problemas reais de código. Ou seja, desenvolvedores não costumam enxergá-los como problemas.
  2. Na maioria dos casos, as classes de teste são afetadas pelos smells desde o momento da sua criação. Ou seja, a maioria dos testes mal escritos foram mal escritos desde o começo.
  3. Os maus cheiros tem uma taxa de sobrevivência altíssima. Ou seja, o mau cheiro fica lá no código por muito tempo, até alguém decidir refatorá-lo.
  4. Existe uma relação entre maus cheiros no código de teste e maus cheiros no código de produção. Ou seja, código de produção ruim faz com que desenvolvedores escrevam testes problemáticos também.

Você quer ler mais sobre possíveis maus cheiros em código de teste? Então veja o excelente paper do Arie van Deursen et al. [2], onde eles listam diversos maus cheiros que podem acontecer nesse tipo de classe.

[1] Tufano, M., Palomba, F., Bavota, G., Di Penta, M., Oliveto, R., De Lucia, A., Poshyvanyk, D.Towards Automated Tools for Detecting Test Smells: An Empirical Investigation into the Nature of Test Smells. In 31st Automated Software Engineering, 2016. Link aberto pro paper.

[2] A. van Deursen, L. Moonen, A. Bergh, and G. Kok. Refactoring test code. In Proceedings of the 2nd International Conference on Extreme Programming and Flexible Processes in Software Engineering (XP), pages 92–95, 2001. Link aberto pro paper.

Variáveis de explicação melhoram o código?

É impressionante nossa capacidade de escrever “ifs” complicados ou com condições malucas. Veja, por exemplo, o if que escrevi no fim de semana. Consegue me dizer o que ele faz em 5 segundos?


if(!m.wasDeleted() && m.getFileName().toLowerCase().endsWith(".java") && m.hasDiff()) {
// ...
}

Uma simples maneira de refatorá-lo é extraindo partes da condição para variáveis com nomes significativos, que explicam melhor o que aquela condição significa. Por exemplo:


boolean naoDeletado = !m.wasDeleted();
boolean ehJava = m.getFileName().toLowerCase().endsWith(".java");
boolean temDiff = m.hasDiff();

if(naoDeletado && ehJava && temDiff) {
// ...
}

Perceba como é muito fácil agora ler a condição. Afinal, “as variáveis explicam”. Essa refatoração é conhecida por “Introducing Explaining Variable”, e você pode vê-la no famoso livro de Refatoração do Martin Fowler, ou mesmo nos atalhos da sua IDE favorita de desenvolvimento.

Li um artigo sobre esse tipo de refatoração há pouco tempo [1]. Nele, os autores mostram que desenvolvedores costumam fazer essa refatoração justamente em classes que já apresentaram muitos defeitos no passado. Para tal, ele observou refatorações feitas em 5 diferentes releases do projeto Eclipse.

O artigo tem lá seus viéses. O autor separa classes que receberam essa refatoração, e classes que não receberam essa refatoração, e mostra a média e a mediana da propensão das classes terem defeitos. Apesar da média ser realmente diferente, a mediana é igual em alguns casos. E, claro, em distribuições como essas, a mediana faz muito mais sentido. Ou seja, os resultados dele parecem ser mais fracos do que o que eles argumentam. Um ponto positivo é que o autor preocupou-se em mostrar que as classes tinham os mesmos tamanhos (afinal, classes maiores são mais propensas a terem bugs).

A pergunta que o artigo nos levanta é: Por que os desenvolvedores resolveram aplicar essa refatoração, justamente em classes problemáticas? Será que é por que essa refatoração realmente deixa o código mais claro de ler e, por consequência, menos suscetível a defeitos? Meu coração diz que sim.

Eu, particularmente, costumo sempre aplicar esse tipo de refatoração em ifs complicados como esse. Aliás, sempre que extraio variáveis de explicação, penso se esse código não deveria estar dentro da classe de origem.

A condição da variável ehJava, por exemplo, poderia estar dentro da classe Modification (que é o tipo da variável m). Dessa forma, fica fácil reusar a condição, e fácil de ler:


boolean ehJava = m.isJava();

[1] S. Counsell, X. Liu, S. Swift, J. Buckley, M. English, S. Herold, S. Eldh, and A. Ermedahl. 2015. An exploration of the ‘introduce explaining variable’ refactoring. In Scientific Workshop Proceedings of the XP2015 (XP ’15 workshops). ACM, New York, NY, USA, , Article 9 , 5 pages. DOI=10.1145/2764979.2764988 http://doi.acm.org/10.1145/2764979.2764988