Métricas: A veces el remedio es peor que la enfermedad

 

Cuando somos novatos y empezamos a codificar, el código no es todo lo bueno que debiera ser, tendemos a hacer clases muy grandes y métodos muy grandes. En algún momento, alguien nos dice que debemos cumplir métricas, nos cuentan que no podemos tener una complejidad ciclomática (igual hasta nos dicen que es eso) mayor que X, que nuestras clases no pueden tener más de Y métodos, etc, etc.

Con buena voluntad, nos ponemos a tratar de cumplir esas métricas, pero las prisas y la comodidad hacen que quizás no las cumplamos a rajatabla. Nuestro código estará un poco mejor, porque nos preocupamos de ellas, pero no las cumplimos al 100%.

Más adelante, algún espabilidado, descubre que algo como maven+pmd puede hacer que si el código no pasa métricas directamente no compile y además pmd tiene un montón de métricas. Así que nuestro código deja de compilar y no nos queda más remedio que arreglarlo y cumplir estrictamente las métricas.

Conseguido, hemos arreglado nuestro código y pasa todas las métricas … y ahí es donde podemos encontrarnos el problema. Todas las métricas salen de algún sitio y están pensadas para que nuestro código sea más legible, tenga menos errores, sea más eficiente, más mantenible, etc. Es fundamental saber qué es lo que hay detrás de cada una de las métricas al intentar hacer/corregir el código para que pase esa métrica. No vale con hacer cualquier cosa para cumplir. Y pongo varios ejemplos:

  • Las clases no pueden tener demasiados métodos ni atributos. ¿Qué hay en el fondo de esta métrica?. En el fondo está que en un buen diseño orientado a objetos cada clase debe tener una y sólo una responsabilidad bien definida. Si una clase tiene muchos métodos y atributos, posiblemente tiene demasiadas responsabilidades y debemos partirla en varias clases, pero podemos hacerlo bien, replanteando el diseño para que esa clase reparta sus responsabilidades adecuadamente en varias, o podemos hacerlo mal, por ejemplo haciendo tres o cuatro clases que heredan unas de otras y repartiendo métodos y atributos entre ellas. Al final sólo instanciamos la más hija de todas, que hereda todos los métodos y atributos de sus padres, el código nos sigue funcionando igual que antes, pasa métricas y tenemos una clase con todo, que es lo que queríamos. Y si resulta que esa clase tiene muchas constantes, pues las metemos en un array de Object y en vez de acceder a la constante por su nombre, accedemos por su índice del array: hemos eliminado 27 constantes por un único arrray con 27 valores. Obviamente, no podemos definir los indices del array en constantes porque nos salta la métrica, así que usamos directamente el índice en nuestro código.
  • La complejidad ciclomática no puede ser muy alta. Obviamente, el objetivo final es que no haya código muy rebuscado y difícil de testear. Un switch-case con muchos case, por simples que sean, no pasa esta métrica. Si queremos hacerlo bien, debemos ver si hay una forma lógica de hacer eso sin un switch-case, como en este código maravilloso, que puede reemplazarse por una sola línea (si acaso dentro de un if). Si el switch-case realmente es inevitable y sencillo, deberíamos saltarnos la regla en este caso concreto. Pero claro, también podemos hacerlo mal, hago el switch-case con tres o cuatro cases y en el default llamo a otro método que a su vez trata otros tres o cuatro cases con otro default que llama a otro método…. Y así hasta que mi clase se pasa de métodos, entonces hago una clase hija con otro método que trata otros tres o cuatro cases…. Imagina el código maravilloso del enlace anterior con el switch-case repartido en varios métodos y unas clases hijas de otras. ¡¡ buff !!.
  • ¿A alguien se le ocurre alguna métrica más y el estropicio adecuado para pasarla?

Al final, tenemos un estupendo código que pasa todas las métricas que debe pasar, pero que es enrevesado como el sólo y no hay quien entienda. Desgraciadamente, la mayoría de los ejemplos que he puesto son reales y los he visto en código.

Nuevamente, el manifiesto ágil, en su principio "Personas sobre procedimientos", tiene toda la razón. Cuando hay programadores no muy expertos, antes de ponerles una herramienta/procedimiento (cumplir métricas o no compila), es mejor darles una formación, contarles las métricas, no lo que significa cada métricas, sino por qué está esa métricas ahí. Hay que enseñarles cómo se corrigen correctamente las más críticas o frecuentes. Es mucho mejor preparar a la gente, que limitarse a la herramienta. De hecho, preparando a la gente y no usando la herramienta saldrá el código mucho mejor que no preparando a la gente y poniendo la herramienta. Quizás no cumpla todas las métricas estrictamente, pero el código será bastante mejor.

Entradas relacionadas:

Esta entrada ha sido publicada en Herramientas y etiquetada como . Guarda el enlace permanente.

9 respuestas a Métricas: A veces el remedio es peor que la enfermedad

  1. blaxter dijo:

    Curiosamente llevo los dos últimos días con el tema de métricas. Realmente creo que lo estás planteando mal, las métricas son un medio, no un fin (aunque siempre mola mirar tablas y gráficos :D).

    En concreto, métricas sobre código fuente, son de los peores indicadores que puedes encontrarte, al menos todo lo relacionado con análisis estático (kloc, complejidad, nº variables/métodos y similares). Es decir, no son incorrectas, pero en muy pocas ocasiones te van a servir para algo realmente útil (definiendo útil algo que te ayuda a tomar decisiones o mejorar en algo).

    Si tuviese que elegir alguna métrica sobre el código, elegiría algún indicador relacionado con test unitarios (ejecuciones con éxito, coverage, bug detectados por test, …) o con la historia del mismo (evolución de código nuevo vs modificado, comprobación de partes copypasteadas, incluso respecto a código de otros proyectos).

    Si quieres leer del tema, este par de links son realmente buenos y merece la pena echarles un vistazo.

  2. Chuidiang dijo:

    Estoy de acuerdo contigo en que las métricas no son el fin, sino un medio. De todas formas, aunque seguirlas todas a rajatabla puede ser contraproducente (siempre hay que evitar los extremismos y usar un poco la cabeza), tampoco se pueden ignorar totalmente.

    Todavía anda por ahí una de las primeras clases que hice en serio para un proyecto, a la que posteriormente alguien bautizó como «la mega clase». Una única clase con más de tres mil líneas de código y unos cien métodos. Y eso que de aquella me había hecho mi clase de «modelo de datos», mis clases de «comunicaciones con el exterior», mis clases de «interface de usuario/vista» y todo eso que es bueno. Pero la falta de experiencia me hizo hacer la clase principal que junta todo eso como esa gran «mega clase». No me habría venido mal que alguien me contara algo de métricas entonces.

    Gracias por los enlaces, les echaré un ojo.

    Se bueno.

  3. Me atrevo a proponer la siguiente herramienta «testability-explorer» [1], con la que se persigue mejorar la calidad de nuestros diseños basándose en que un diseño es mejor que otro si es más fácil de probar unitariamente.

    De todos modos, yo no me obsesionaría con pasar las métricas, pero sí que empujaría a mis equipos a que fueran sistemáticamente mejorándolas. Además de leer dos libros estupendos:
    * Implementation Patterns [2] de Kent Beck
    * Clean Code [3] de Robert C. Martin

    [1] http://code.google.com/p/testability-explorer/
    [2] http://www.infoq.com/articles/implementations-patterns-br
    [3] http://www.infoq.com/articles/clean-code-book-review

  4. Lek dijo:

    Desde mi humilde opinión, las métricas como directrices están muy bien, pero es imposible cumplir todas. Uno de los problemas de PMD es que no distingue entre clases de test y clases normales. Otro es su manía de decir que definas las variables como finales, algo que podría tener sentido hace años a nivel de rendimiento, pero actualmente está desfasado.

    Y más cosas por el estilo, como crear objetos dentro de bucles o la métrica de un único «return»… ya no es sólo cuestión de entender la métrica y hacer un código limpio y eficiente 😉

  5. Chuidiang dijo:

    Hola Lek:

    Por eso precisamente comento que hay que entender el porqué de la métrica. Si esta desfasada, como lo de final o del único return, debemos saberlo y sabiéndolo, podemos configurar PMD para que no tenga esa métrica en cuenta.

    No se debe arreglar el código sin saber el por qué de la métrica, pero tampoco se puede uno emperrar en cumplir TODAS las métricas sin analizar primero si realmente son útiles o no.

    Se bueno.

  6. Bueno,

    creo que el número de parámetros de las funciones también es una buena métrica: cuando hay que pasar demasiados es probablemente porque una parte de esos parámetros (si no todos) podría pasar a ser una clase (una instancia de una clase) de la que no se es consciente. Por lo general, si uno no se acuerda de cuántos parámetros hay que pasar es que hay demasiados (y se deben agrupar en una clase).

    Pero yo no soy IS sino matemático.

    Pedro.

  7. Pingback: Métricas - sudo

  8. gux dijo:

    Parte de mi trabajo consiste en forzar (si, se que FORZAR no suena bien, pero cuando hago revisiones de codigo es lo que toca…) a que los desarrolladores mejoren su codigo con los resultados de metricas tipo PMD/Checkstyle…

    Una de las cosas que mas gracia me hizo fue encontrarme un codigo que usaba un numero raro (digamos 313) tal cual. Le pedi al desarrollador que cambiara ese 313 por una constante, y que la constante tuviera un nombre explicativo. Resultado? el codigo empezo a utilizar la constante THREE_HUNDRED_THIRTEEN

  9. fernando dijo:

    En mi trabajo usasmos plugin open source tanto para métricas como para estimaciones de software. No sé si os puede ayudar pero os dejo el enlace de una forja que los aloja por si os puede facilitar las cosas

    http://forge.isotrol.org/

Deja una respuesta

Tu dirección de correo electrónico no será publicada.

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.