CodeNarc: Análisis estático de código Groovy

CodeNarc: Análisis estático de código Groovy
Sin comentarios Facebook Twitter Flipboard E-mail

Cuando escribimos código es importante seguir ciertas normas, buenas prácticas, reglas de estilo, coherencia en el mismo,... pero en ocasiones esto no es tan fácil, y más cuando trabajamos en un equipo en el que, al final, cada miembro tiene ciertas manías. Una forma de mejorar todo esto es utilizando un analizador estático de código.

Para Java tenemos ciertas herramientas como _FindBugs_, _PMD_ y _Checkstyle_ que llevamos utilizando durante mucho tiempo, pero tienen el problema de que con Groovy no funcionan correctamente. Para suplir esta necesidad aparece CodeNarc.

CodeNarc es un analizador estático de código Groovy que permite detectar defectos, malas prácticas, inconsistencias, problemas con el estilo del código,... y mucho más. Se trata de un framework muy flexible que por medio de reglas fácilmente configurables analiza nuestro código para mostrarnos un detallado informe a fin de que podamos mejorarlo.

Añadiendo CodeNarc a nuestro proyecto

Ok, nos hemos decidido a mejorar nuestro código Groovy, ¿cómo añadimos CodeNarc al proyecto? Tenemos diversas formas de añadirlo según nuestras necesidades y tipo de proyecto:

  • Desde línea de comandos: Una forma muy sencilla de ejecutar CodeNarc aunque probablemente no la más útil.
  • Tarea Ant: Probablemente se trata de una de las formas más _antiguas_ de ejecutar CodeNarc. Si tu proyecto todavía se basa en Ant y no has pensado en cambiar a Gradle 3.x, esta es tu solución.
  • Desde un test JUnit: Forma muy curiosa de ejecutar el análisis de CodeNarc aunque probablemente poco útil.
  • Plugin de Maven: Si usas Maven como herramienta de construcción de tu proyecto esta será la mejor opción puesto que el plugin se encarga de configurar todo y la integración es muy sencilla.
  • Plugin de Gradle: Al igual que en el caso anterior, si Gradle es tu herramienta de build, entonces este es el plugin a utilizar.
  • Adicionalmente también existen plugins para distintos IDEs como IntelliJ y Eclipse, frameworks como Grails y Griffon o incluso para Sonar y Jenkins.

Tipos de reglas

La última versión de CodeNarc, la 0.27.0, incluye 348 reglas agrupadas en 22 categorías:

  • Básicas: Por ejemplo para comprobar que no hay bloques else or finally vacíos.
  • "Llaves": ¿Cuántas veces habéis visto if o else de una sola línea sin las llaves? Yo personalmente los odio porque son una fuente de bugs a futuro. Podemos activar reglas en esta categoría para que realicen este tipo de comprobaciones.
  • Concurrencia: En esta categoría hay reglas que comprueban la coherencia de nuestro código concurrente cuando utilizamos synchronized o volatile principalmente.
  • Convención: Por ejemplo cuando escribimos un if invertido, un if que puede ser convertido a un operador elvis,...
  • Excepciones: Contiene reglas que fallarán si por ejemplo hacemos un throw de un NullPointerException.

Y existen muchas más como algunas que comprueban imports duplicados, variables sin utilizar, if innecesarios,...

Veamos un ejemplo

Configuración mínima

He creado un pequeño proyecto de ejemplo basado en Gradle con la configuración necesaria y unas cuantas clases con distintas infracciones para poder comprender mejor cómo funciona CodeNarc. Podeis ir revisando los commits de manera individual para comprender mejors los cambios.

Lo primero que hacemos es añadir el plugin al archivo build.gradle y configurarlo:

apply plugin: 'codenarc'
...

codenarc {
    toolVersion = '0.27.0'
    configFile = new File(projectDir, 'config/codenarc/rules.groovy')
    reportFormat = 'html'
}

Ahora añadimos el archivo de las reglas. Como veis he habilitado unas cuantas.

ruleset {
    description 'Example Project RuleSet'

    ruleset('rulesets/basic.xml')
    ruleset('rulesets/braces.xml')
    ruleset('rulesets/convention.xml')
    ruleset('rulesets/design.xml')
    ruleset('rulesets/dry.xml')
    ruleset('rulesets/exceptions.xml')
    ruleset('rulesets/formatting.xml')
    ruleset('rulesets/generic.xml')
    ruleset('rulesets/imports.xml')
    ruleset('rulesets/naming.xml')
    ruleset('rulesets/unnecessary.xml')
    ruleset('rulesets/unused.xml')
}

Con esto ya podemos empezar con el análisis del código. Sólo tenemos que ejecutar la tarea check para comprobar (en las primeras dos tareas) que se está ejecutando CodeNarc (codenarcMain) tanto para nuestro código como para los tests (codenarcTest). Eso sí, como no tenemos nada en el proyecto el informe no se ha generado.

$ ./gradlew check
:codenarcMain NO-SOURCE
:codenarcTest NO-SOURCE
:compileJava NO-SOURCE
:compileGroovy NO-SOURCE
:processResources NO-SOURCE
:classes UP-TO-DATE
:compileTestJava NO-SOURCE
:compileTestGroovy NO-SOURCE
:processTestResources NO-SOURCE
:testClasses UP-TO-DATE
:test NO-SOURCE
:check UP-TO-DATE

BUILD SUCCESSFUL

Total time: 0.67 secs

Añadiendo código de _dudosa calidad_

Vamos a empezar con algo muy sencillo, simplemente creamos la clase src/main/groovy/demo/Example1.groovy con lo siguiente:

package demo

class Ejemplo1 {

}

Si ahora ejecutamos de nuevo la tarea check podemos comprobar que se genera el informe con las infracciones y que además la build falla.

Codenarc Report 01

Primer encontramos un bloque con la fecha de ejecución y la versión de CodeNarc con la que se ha generado el informe. A continuación tenemos un bloque de resumen por paquete con el total de archivos con infracciones y también el total de infracciones de prioridad 1, 2 y 3. Después tendremos un bloque por cada archivo en el que vemos todas las infracciones del archivo con la línea de código en donde están y un pequeño fragmento del mismo. Además el nombre de la regla es un enlace a una descripción un poco más detallada de lo que significa.

Añadiendo más código

Creamos a continuación otro archivo en src/main/groovy/demo/Example2.groovy:

package demo

class Example2 {

    boolean isEvenNumber(Integer number) {
        if (number % 2 == 0)
            println "The number $number is even"
        else
            println "The number $number is odd"
    }

    void lorem() {
        println 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis volutpat fermentum enim. enean in viverra arcu.'
    }
}

Y si ejecutamos de nuevo CodeNarc vemos que tenemos nuevas infracciones: Sentencia if sin llaves, sentencia else sin llaves y longitud máxima de una línea.

Codenarc Report 02

Configurando y deshabilitando reglas

Lo primero que queremos evitar es que CodeNarc haga que falle la build cuando tenemos alguna infracción. Para ello, añadimos a la configuración en build.gradle:

codenarc {
    ...

    ignoreFailures = true
}

Ahora ejecutándolo de nuevo veremos que la build no falla. Aún así seguimos teniendo infracciones con las que puede que no estemos de acuerdo o que queramos personalizar de cierta forma.

Vamos a deshabilitar la regla ClassJavadoc porque aunque sea una buena práctica escribir el Javadoc de todas nuestras clases públicas, para este proyecto de ejemplo no nos interesa.
Para ello, primero tenemos que buscar en qué categoría está incluída la regla. Esto podemos hacerlo directamente en el índice de reglas. Después, editamos el archivo de reglas rules.groovy para deshabilitarla:

ruleset {
    ...
    ruleset('rulesets/formatting.xml') {
        'ClassJavadoc' {
            enabled = false
        }
    }
    ...
}

Si ahora generamos de nuevo el informe vemos que hemos _"arreglado"_ esas infracciones.

Codenarc Report 03

Adicionalmente, también podemos excluir una regla en una clase concreta. Imaginad que necesitamos la clase vacía creada anteriormente pero no queremos ni desactivar la regla (porque entonces no detectaría más clases vacías) ni queremos tener de manera perpetua esa infracción en el informe. Para ello podemos hacer uso de la anotación @SuppressWarnings de Java:

package demo

@SuppressWarnings('EmptyClass')
class Example1 {

}

Y entonces, sólo para ese archivo esa regla concreta es ignorada:

Codenarc Report 04

Otra opción que tenemos disponible es configurar algunas reglas para adaptarlas a nuestras necesidades. Así, anteriormente vimos en el ejemplo 2 que teníamos una infracción de tipo LineLength porque una línea era mayor de 120 caracteres. Imaginemos que hemos decidido que queremos permitir líneas de hasta 130 caracteres:

ruleset {
    ...
    ruleset('rulesets/formatting.xml') {
        ...
        'LineLength' {
            length = 130
        }
        ...
    }
    ...
}

Haciendo esto _"arreglaríamos"_ de nuevo esta nueva infracción.

¿Y como configuro esto para empezar?

Si no sois muy cuidadosos con el código que escribís y vuestro proyecto tiene cierto tamaño, lo más probable que ocurra nada más instalar CodeNarc es que tengais cientos o incluso miles de infracciones.
Incluso siendo muy escrupulosos es probable que haya algunas reglas que no os gusten o que su configuración por defecto no se adapte a las necesidades del equipo. Mi consejo es que vayais revisando una por una las infracciones, leyendo la documentación de las mismas y decidais si las desactivais, las configurais para que se adapten a vuestro estilo y finalmente, las respetais y corregís.

Una vez decididas las reglas y configuración con las que el equipo se siente cómodo, el paso final será decidir los umbrales para hacer que la build falle. Esto permite tener builds válidas con ciertos niveles de infracciones según la severidad de las mismas pero que, superados esos niveles, la build finalmente falle y os obligue a corregirlas.
Para hacer esto, editamos una vez más el archivo build.gradle:

codenarc {
    // Es necesario eliminar esta opción
    //ignoreFailures = true

    maxPriority1Violations = 0
    maxPriority2Violations = 5
    maxPriority3Violations = 9
}

Así, la build no fallará a menos que superemos alguno de esos umbrales.

Conclusiones

Hemos visto por qué es importante asegurar el estilo y la calidad del código en nuestro proyecto y cómo una herramienta de análisis estático de código como CodeNarc nos puede ayudar a conseguirlo. Además también hemos comprobado que es muy fácil de añadir a un proyecto y de configurar y personalizar para adaptarlo a nuestras necesidades.

Porque en ocasiones no basta sólo con creer que escribimos buen código y además también testearlo, sino que hay que tener herramientas que nos aseguren su calidad, homogeneidad y estilo. Para todo esto cuando se trata de código Groovy, sin duda CodeNarc es el mejor.

Más información | CodeNarc En Genbeta Dev | Testeando tus aplicaciones Java con Spock: tests más expresivos, fáciles de leer y mantener

Comentarios cerrados
Inicio