JSHint, herramienta para medir la calidad del código Javascript

19 Feb 2011

Todos los desarrolladores Javascript tenemos una gran deuda con JSLint, la herramienta creada por Douglas Crockford para medir la calidad de nuestros códigos Javascript.

El funcionamiento de JSLint es el siguiente: toma nuestro código, lo escanea y, si encuentra un problema, devuelve un mensaje describiéndolo y mostrando su ubicación aproximada. El aviso no tiene que ser necesariamente un error de sintaxis, sino que puede ser de estilo o estructural. Esto no significa que el programa no sea correcto, sino que nos ofrece otro punto de vista para mejorar su construcción a partir de patrones y recomendaciones tomadas de las Convenciones de Código el Lenguaje de Programación Javascript definidas en la especificación ECMAScript.

Sin embargo, JSLint tiene algunos inconvenientes. El más importante es la rigidez de sus estructuras durante la evaluación del código; esto hace que, cómo indican sus detractores, nuestras aplicaciones termina siendo tiranizadas por la herramienta. Todas las directrices que utiliza, pese a participar de la especificación correspondiente, son el resultado del criterio personal de una única persona, aunque dado el caso, hablemos posiblemente del mejor conocedor del lenguaje.

Es por esto que muchas veces tratamos de validar patrones que han sido definidos por otros desarrolladores obteniendo un sin fin de advertencias que sabemos positivamente que no van a producir error. Esta circunstancia hace que en muchas ocasiones, JSLint no resulte de utilidad al no validar códigos contrastados.

JSHint, una nueva alternativa

Partiendo de este problema, la comunidad de desarrollardores Javascript ha creado una ramificación del proyecto original denominada JSHint cuya finalidad es medir la calidad de un código en el mundo moderno actual. La idea es prescindir de algunas reglas demasiado estrictas presentes en JSLint para ofrecer un conjunto más flexible de estilos y convencioes.

JSHint está preparado para soportar los siguientes entornos de producción:

Además, permite configurar una serie de parámetros dependiendo de nuestro estilo de programación para que los pase por alto cuando realice la validación:

  • Permitir estamentos de debug y logging (los típicos ‘console.log()’)
  • Tolerar eval
  • Exigir siempre igualdad estricta ‘===’
  • Permitir asignaciones dentro de los bucles if/for/while/do
  • etc…

Probando la herramienta

Bien, vamos aprobarlo. Probemos con un ejemplo sencillo y cotidiano:

(function(){
  return console.log( 'Hello World' );
})();

Tenemos aquí un patrón bastante usual y, sin embargo, JSLint ya lanza errores:

Problem at line 3 character 3: Move the invocation into the parens that contain the function.

El resultado de JSHint es mucho más positivo:

The code check passed.

Bien; parece que la cosa funciona como se espera. Probemos ahora con uno de los casos que siempre me resultan más incómodos en JSLint, un bucle:

// Function top
// ... more code here ...
for (var i = 0; i < 100; i++) {
  console.log( i );
}

La herramienta de Crockford me da su opinión:

Error:
Problem at line 1 character 6: Move 'var' declarations to the top of the function.

Está claro que le gustan las declaraciones al comienzo de cada función por el tema del hoisting, pero personalmente no me gusta la alternativa:

// Top of the function
var i = 0;
// ... more code here...
 
for( i; i < 100; i++ ){
  console.log( i );
}

Lo siento, pero me parece poco legible. Si hay mucho código entre la declaración y el bucle, perdemos la referencia de lo que vale la variable. Prefiero declararla al inicio del bucle aunque a JSLint no le parezca una buena práctica.

JSHint no encuentra nada malo en el código:

The code check passed.

¿Y qué pasa con las declaraciones en línea?

if ( foo ) console.log( 'Foo' );
if ( bar ) console.log( 'Bar' );
if ( fooBar ) console.log( 'FooBar' );

JSLint nos dice que tenemos que usar siempre llaves:

Error:
Problem at line 1 character 12: Expected '{' and instead saw 'console'.
if ( foo ) console.log( 'Foo' );
 
Problem at line 2 character 12: Expected '{' and instead saw 'console'.
if ( bar ) console.log( 'Bar' );
 
Problem at line 3 character 15: Expected '{' and instead saw 'console'.
if ( fooBar ) console.log( 'FooBar' );

Utilizar llaves es una buena práctica, pero quizá hay que resaltarla cuando comenzamos a aprender este lenguaje. Para el programador experimentado, que sabe lo que hace, no es necesario advertirle de los riesgos que conlleva. JSHint así lo entiende y no nos lanza errores:

The code check passed.

Conclusión

Y esto es sólo el principio. JSHint es una herramienta de desarrolladores para desarrolladores, por los que sus criterios no dependen de una única fuente sino de toda la comunidad. El mismo John Resig ha aplaudido el proyecto.

JSHint

Está claro que, a partir de ahora, habrá que añadir esta herramienta a nuestro repositorio buscando códigos más sólidos y acordes a las convenciones de estilo más modernas.

Más:

{4} Comentarios.

  1. pepe

    no lo he probado a ver si JSLint lo acepta, pero también se puede hacer esto en los bucles

    var i = 0;
    
    for( ; i < 100; i++ ){
      console.log( i );
    }
    

    yo soy más partidario de esto, en bucles inversos, claro:

    var i = 100;
    while(i--)
      console.log(i);
    
    • Carlos Benítez

      Hola Pepe,
      efectivamente, tanto JSLint como JSHint aceptan tu propuesta de bucle.

      La verdad es que, con el tiempo, JSLint ha relajado un poco los criterios de validación. Me da que hace un año, habría lanzado error por omisión de parámetros.

      En cuanto a tu bucle inverso, ten cuidado con la estructura:

      var i = 100;
      while( --i )
      console.log( i );
      

      Es una solución muy rápida si no importa que el array sea recorrido en orden inverso.

      Un saludo!

  2. pepe

    conozco el peligro 😉 va bien para arrays en que el índice empieza por 1

    y si queremos que sea un poco más rápido:

    var i = 100;
    while( i )
    console.log( --i );
    

    un saludo

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *