Mejora tu código con las herramientas de Visual Studio 2010

  • Por
Cómo podemos mejorar la calidad del código fuente creado con las herramientas de análisis estático de código, como Statick Checker de Visual Studio 2010.
Los que nos dedicamos a la programación seguramente hayamos podido pasar algunas veces por la sonrojante situación de mostrar un código que no era todo lo bueno que podríamos desear. Es algo que me suele ocurrir y aún sabiendo que tengo herramientas disponibles para evitarlo en gran medida. Estoy hablando de las herramientas de análisis estático de código, que veremos en este artículo.

Cada vez son más las herramientas disponibles para analizar un código fuente. Incluso la última versión del compilador de C# busca violaciones del principio de Liskov, aunque no lo califica como un error, sino como sólo un warning.

Visual Studio 2010 viene con una nueva característica de análisis de código que podemos usar para realizar un análisis más profundo y evitar que nos salten los colores cuando enseñamos un código de nuestra creación:


Opciones de Visual Studio 2010

Incluso con estas herramientas podemos establecer y personalizar las reglas que queremos cumplir:


Warnings de VS 2010

Estas herramientas nos ofrecen avisos sólo cuando se incumplen estas reglas, lo que no significa necesariamente que haya un bug, sino simplemente que pueda existir. Ante estos reportes siempre es mejor echar un vistazo al código y no dejar que las alarmas se conviertan en hechos por la ley de Murphy.

La herramienta Static Checker de Visual Studio 2010 y .NET 4

Ahora vamos a estudiar en detalle la herramienta que nos ofrece Visual Studio 2010 y .NET 4 para el análisis estático de código. La herramienta de la que estamos hablando es Static Checker creada por el equipo de Contratos de código, que tiene la particularidad de ir analizando nuestro código a medida que lo escribimos. Gracias a ello es capaz de mostrar aquellos contratos que no se cumplen. Si tenéis Visual Studio 2010 Premium o Últimate o Team System 2008. Podéis descargarla desde http://bit.ly/fF3wzl.

En cada proyecto donde queramos usar la herramienta tendremos que activarla explícitamente:


Imagen de la configuración de static checker

Veamos ahora un ejemplo de código que provocaría la alerta de esta herramienta en tiempo de compilación:

var numbers= new int[2];
numbers[3]=0;

Sin embargo, más útil puede resultarnos cuando la usamos con los contratos de código explícitos, con sus pre-condiciones y pos-condiciones. Veamos un pequeño ejemplo.

Supongamos que tenemos este código en alguno de nuestros métodos:

var idFactura= ObtenerUltimoId();
ProcesaFactura(idFactura);

A simple vista, ninguna herramienta de análisis estático haría nada con este código, a no ser que se le indicase algún tipo de información extra. Y aquí es donde entran los contratos. El código de la función ObtenerUltimoId() podría ser como este, si usamos contratos:

public int ObtenerUltimoId()
{
   Contract.Ensures(Contract.Result<int>()>0);
   ....
   return n;
}

Con los contratos se indica que el método tiene que devolver un valor mayor que cero. Esa información la usará el Checker para comprobar el código fuente.

Veamos ahora como podría ser el método ProcesaFactura():

public void ProcesaFactura(int idFactura)
{
   Contract.Requires<ArgumentException>(idFactura>0);
   .....
}

Bajo esa situación la herramienta Static Checker comprueba que un método tiene una condición de Requires y recibe datos de otro método, que no dice nada sobre lo que va a devolver. Esta sería la pantalla que nos mostraría el análisis:


Ventana de errores de Static Checker

Sobra decir que Static Checker se hace todavía más útil cuantos más contratos usemos.

Código heredado o Legacy Code

Ahora vamos a ver cómo actuar con el código heredado o legacy code, algo que a nadie nos gusta demasiado y que por desgracia significa un problema muy común en nuestro día a día.

Si el código heredado no tiene contratos, se obtendrán algunos warnings molestos del Static Checker. Sin embargo, la API de Code Contracts ofrece un pequeño workarround sobre esto.

Básicamente, este tipo de warnings son debidos a la falta de información, es decir, el Checker no es capaz de encontrar la información necesaria. Sin embargo, podemos observar algunos detalles en el siguiente código:


Código con un Warning

El checker nos avisa de una posible referencia nula. Aparentemente la variable context está siendo usada sin haber sido inicializada previamente. ¿Quién es el responsable del warning? ¿el Checker u otra cosa?

En este caso, el aviso lo está provocando ReSharper, cuyo motor de análisis identifica una posible referencia nula. ¿Pero porqué no nos lo da el Checker?, la respuesta es por la linea:

Contract.Assume(context!=null);

Con esa linea estamos diciendo al Checker que la variable context nunca va a ser nula. Gracias a ello el Checker confía en nosotros y añade esa información a sus procesos. Resharper no ofrece soporte completo a los contratos de .NET, de ahí el aviso. Sin embargo, ReSharper soporta su propio sistema de anotaciones que podéis usar de la misma manera. Para más información se puede consultar este artículo.

Optimizar el uso del análisis estático de código

El análisis estático es complejo y no suele ser una ciencia exacta. En ocasiones ocurre que, con la mejor intención, rellenamos nuestro código con información de contratos y al final lo único que conseguimos es que el tiempo de compilación se dispare. Para esto hay un par de soluciones que podríamos tomar para optimizar el uso de contratos y los análisis siguientes.

La primera es crear una configuración de compilación especial, y habilitamos únicamente las comprobaciones en ella. Compilamos en esa configuración de vez en cuando para obtener información, corregimos los posibles problemas y continuamos trabajando sin el análisis estático.

La segunda es probar a usar contratos poco a poco. Aplicamos contratos de manera extensiva en el código, pero deshabilitamos los contratos a nivel de assembly. Esto lo asemos añadiendo el siguiente atributo en las propiedades del assembly:

[assembly:ContractVerification(false)]

Lo siguiente, es re-habilitar la comprobación de contratos sólo cuando estemos centrados en clases, métodos o assemblies.

Conclusión

El análisis estático de código es una técnica que intenta evaluar el correcto funcionamiento de vuestro código sin ejecutarlo. Entre las herramientas que hacen esto, la más común es el propio compilador, otra es el Static Checker - un ejecutable que se integra en el proceso de compilación-. En .NET, una herramienta especial aprende desde los contratos que tengáis, evalúa la información y muestra posibles errores y violaciones de contratos.

En los proyectos la complejidad aumenta continuamente y el equipo de desarrollo se va quedando sin tiempo. Integrar este tipo de herramientas ahorra algún tiempo de compilación, pero más importante todavía es que nos protege de errores feos en nuestro software.