Por qué no utilizo métricas

Sería el año 2006 más o menos cuando leí Pragmatic Programmer, el libro que más me ha influido como desarrollador. Por su culpa decidí montar un servidor de integración continua que a día de hoy sigue siéndome de extrema utilidad lanzando vetustos scripts de msbuild que conviven con los mil sistemas de compilación de Javascript.

Lo que se ha caído de ese servidor, o mejor dicho, de los scripts varios que ejecuta, es el cálculo de métricas varias sobre el código.

Al principio me molestaba en calcular métricas sobre el código fuente (utilizaba cosas como Source Monitor para ello), que me indicaran número de líneas de código, complejidad ciclomática, nivel máximo de anidamiento, profundidad de jerarquías…., en fin todo tipo de datos para disfrutar con un poco de porno de estadísticas. Además, analizaba la cobertura de código que alcanzaban mis tests (con NCover, si no recuerdo mal), y tenía configurados mis avisos si no llegaban a determinados niveles.

Nunca les hice excesivo caso, pero era bonito tenerlas y consultarlas de vez en cuando, e incluso a veces me servían para ver áreas que podía mejorar refactorizando el código o añadiendo más tests.

Hoy en día no uso este tipo de indicadores y no los echo en absoluto de menos, pero antes de ver por qué yo no consigo sacarles mucho partido, vamos a ver qué razonamientos hay detrás del uso de métricas y por qué, a lo mejor a ti, sí que te resultan útiles.

Si no lo mides, no lo puedes mejorar

Es algo aceptado generalmente. Para poder mejorar algo, necesitas poder medirlo, porque es la única manera de saber si estás mejorando o no.

La idea de las métricas es crear una serie de valores que actúen como proxies de lo que realmente se quiere medir. Normalmente, lo que se quiere medir son cosas como la facilidad para mantener el código, la propensión a contener errores o la fiabilidad.

Para ello, se parte de características del código fácilmente medibles y se asume cierta relación entre ellas y la cualidad que realmente queremos medir. Por ejemplo, en general el código que tiene más complejidad ciclomática es más difícil de mantener. El código con un ratio de comentarios adecuado es más fácil de mantener. Las clases con más líneas de código son más propensas a contener errores. El código cubierto por tests suele tener menos fallos.

Desde un punto de vista puramente estadístico, las métricas pueden llegar a ser muy fiables. Sobre todo si tenemos una muestra lo suficientemente grande y representativa de código que nos permita afinar los valores a partir de los cuales debemos preocuparnos.

Ayuda bastante en ese sentido aplicar técnicas de análisis forense del código que nos ayuden a identificar áreas especialmente problemáticas. Lo bueno de estas técnicas es que trabajan sobre hechos reales, porque están analizando la historia del código, y no se limitan a establecer hipótesis en base al aspecto actual del mismo.

Cuando estamos trabajando con bases de código muy grandes, o con equipos con gente con poco conocimiento desigual, o con mucha rotación de personal, las métricas son una buena forma de mantener un cierto control sobre lo que se está haciendo. Por una parte podemos marcar límites a las barbaridades que hacemos («no puede haber contructores con más de 10 parámetros»), y por otra nos permiten señalizar potenciales problemas y nos dan una pista de dónde podemos empezar a dedicar esfuerzos para mejorar la salud de nuestro proyecto, como explica Jorge Sánchez.

Lo que mides, es lo que consigues

Es el mayor peligro de empezar a medir cosas y tratar de optimizarlas. Si lo haces bien, te arriesgas a conseguir mejorar esas métricas. Y sólo eso. Por eso es fundamental no olvidar que lo que quieres mejorar no son las métricas sino lo que ellas representan.

En un mundo ideal, estas métricas que hemos elegido como proxy reflejarían perfectamente las cualidades que buscamos en el software, pero en el mundo real, no siempre es así. Puede que ese método con 4 ifs sea más fácil de entender así. O que lleve funcionando 8 años y no haya dado ni un sólo problema. A lo mejor es código autogenerado. ¿El ratio de comentarios? Otro factor muy relativo que depende mucho del tipo de comentario.

En realidad, esto no debería ser un problema. No deberían tomarse las métricas como reglas rígidas, sino como indicadores de cosas que tal vez estén mal. Se supone que deberían servirnos para llamar la atención sobre ellas y decidir si necesitamos solucionarlas o no.

Cuando sí que se puede convertir en un problema es cuando empezamos a evaluar o valorar a los desarrolladores en base a esas métricas.

Entonces es probable que se preocupen más de conseguir un 100% de cobertura de código en los tests, que de escribir tests que realmente sean útiles. Incluso aunque sólo usemos las métricas a título informativo, es fácil que si las estás viendo continuamente te acaben condicionando a la hora de organizarte el trabajo para intentar mejorarlas. Nos gusta jugar y mejorar nuestra puntuación.

No consigo sacarles partido

Con lo que hemos estado viendo hasta ahora, parece razonable pensar que calcular métricas sobre el código, si se hace con sentido común, es una herramienta práctica para desarrollar software.

Pese a ello, no soy capaz de sacarles suficiente partido como para que me compense ralentizar la compilación obteniendo métricas y asumir el riesgo de acabar jugando contra ellas en lugar de centrado en conseguir lo que realmente considero importante.

En mi caso, trabajo en un equipo pequeño, donde todos somos muy conscientes de lo que queremos conseguir y de los valores que queremos reflejar en nuestro código, por lo que el componente de control no me resulta útil.

Trabajo con una base de código relativamente grande, en la que el número de falsos positivos es importante.

Esos casos que mencionaba antes, de clases muy grandes pero que tienen su justificación, o de código feo pero que funciona y nunca hay que modificarlo, aunque son infrecuentes, existen, y si tienes un volumen de código suficiente, son los que acaban copando todos los listados de «métodos más inmatenibles».

Ello implica que si no quieres estar revisando una y otra vez lo mismo, necesitas mantener algún tipo de configuración en las herramientas de análisis estático para ignorar esos bloques de código, lo que complica el mantenimiento y te acaba llevando al otro extremo, el de los falsos negativos por culpa de haber marcado como «ignorables» partes de la aplicación que no deberían serlo.

Al final le acababa haciendo caso a las métricas para manteneras bonitas, pero no porque realmente me aportaran demasiado. Ya sabíamos de sobra las partes de la aplicación que eran difíciles de tocar y mantener, o dónde se solían concentrar los bugs.

De hecho, había ocasiones en que la solución que más nos gustaba podía ir en contra de las métricas de calidad que habíamos establecido, por ejemplo aumentando acoplamiento para conseguir una mayor cohesión, pero tener las métricas encima nos condicionaba, aunque fuera inconscientemente, a usar soluciones menos atractivas pero con mejor puntuación.

El problema para mi, en definitiva, es que las métricas analizan el código, y el código importa, pero el contexto más.

Cuanto menos contexto tienes, más valiosas se vuelven las métricas, porque al menos te aportan alguna información. Si puedes permitirte estar encima de las cosas y confiar en el sentido común de los que trabajan contigo, la utilidad de las métricas disminuye bastante porque puedes observar directamente la realidad sin necesidad de proxy.

16 comentarios en “Por qué no utilizo métricas

  1. Totalmente de acuerdo. Es una de esas cosas que a partir de una buena idea, la cosa se desmelena totalmente y la gente se obsesiona con los números.
    Se entiende por la necesidad que tiene la gente de medir cosas difíciles de medir, como la calidad del código, pero se convierte en una obsesión.
    Para detectar posibles problemas (variables que se usan y podrían ser null, parametros que no se usan, algunas buenas practicas mínimas)… pero «las métricas estrictas son el refugio de las mentes simples» yo dixit :D

  2. No es que no sepas sacar partido a las métricas, lo que en realidad pasa es que el equipo no las necesitas. Lo del tiempo de demora es una excusa :-P puedes sacar ese proceso fuera (a un Sonar por ejemplo) y ya no te ocupa tiempo.

    Las métricas son herramientas de «mejora continua» para el equipo y nunca para «controlar» al equipo. Antes de iniciar o ya iniciado un proyecto, todo el equipo define un grupo de reglas que garantiza una calidad determinada. Quizás unos están acostumbrados a unas reglas, otros estén acostumbrados a otras, por lo que las métricas permite mantener estos niveles de calidad a los que todo el equipo se comprometió.

    ¿Qué pasa si es un equipo pequeño en el que todos estamos comprometidos y acostumbrados a las reglas que se han definido? Pues las métricas te darán un resultado con el que seguramente todo el equipo se sentirá conforme y que aproximadamente será siempre el mismo. En estos casos, la conclusión es que el equipo no necesita de las métricas.

    Piensa si habrías podido sacar la misma conclusión sin una primera definición de reglas y un primer resultado.

    :)

  3. Hola Omar,

    Discrepo en la parte de «un grupo de reglas que garantiza una calidad determinada». Las reglas no garantizan calidad, sólo que se cumplen ciertas métricas.

    En nuestro caso, la «mejora continua» de la base de código procede de prácticas como pair programming, code reviews, aplicar el principio del boy scout, o tener una suite de tests que nos permite refactorizar con confianza (y ojo que eso es muy distinto de tener un X% de cobertura).

    Mi teoría es que si la gente es reponsable y tiene sentido común, las métricas no les ayudan demasiado, y si no lo es, en el mejor de los casos vas a conseguir que cumplan métricas a rajatabla, pero eso no te garantiza demasiado. Por ejemplo, en lugar de tener código sin tests, tendrás código con un 100% de cobertura de tests que no aportan valor.

    Pero es sólo una teoría :-)

  4. Es verdad que las métricas por sí solas no garantizan calidad, me refería a que son una guía que sí garantizan calidad. La gente puede ser responsable y tener sentido común, pero eso no quita que tengamos costumbres distintas a la hora de programar.

    Variables declaradas y no usadas, niveles altos de comentarios que termina siendo código antiguo comentado, niveles de complejidad dentro de clases o métodos, baja cobertura de código. Nadie nace sabiendo, y al equipo se le puede educar a ser responsable y tener sentido común.

    Yo discrepo en que el equipo pueda terminar cumpliendo métricas que no aporten valor. No olvides que parto de la base de que esas métricas las seleccionó todo el equipo porque creen en el valor que aporta. Cuando ellos vean que una métrica no aporta valor, la quitan y listo.

    En resumen, aunque el equipo tenga o no sentido común y sea responsable, usar métricas o no, es una decisión de ellos y no nuestra :-) Si deciden usar métricas, puedes estar seguro que aportará valor.

    Por cierto, nosotros teníamos (como equipo) un radar ágil para medir pair programming, ATDD, SOLID, Code review, commit on review, daily, retrospective, DoR, DoD y demás best practices en un equipo SCRUM. Eso no sale de ningún proceso automático de revisión de código, simplemente el equipo reconoce que son buenas prácticas y a partir de ahí evalúa su aplicación o no.

    Un abrazo ;-)

  5. El problema que yo le veo, Omar, es que partes de unos supuestos que en muchos casos simplemente no se cumplen. «Si deciden usar métricas, puedes estar seguro que aportará valor.» ¿Despues de decir que aunque el equipo no tenga sentido comun? En mi caso, se ha decido a nivel de toda la organización con gran parte del equipo de desarrollo en contra.
    ¿Aporta valor? Dudoso. En un proyecto en el que estoy ahora hay un monton de gente únicamente enfocada a conseguir que el código pase unas metricas determinadas y el software todavía no hace nada, dejan la rama master descompilada, el código se hace de cualquier manera sin mirar como hacerlo mejor… mientras cumpla las metricas. Los plazos se van de madre, los problemas reales de implementación no se están abordando…. por que hay que cumplir las métrica y si no el sonar no te deja avanzar…

    Cualquier teoría que se base en que la gente use el sentido común y las herramientas de la forma adecuada… lo tiene crudo en la realidad :D.

  6. jajaja. Sí que ha dado para un buen debate este post :-)

    Ordenemos las ideas.
    1- Lo que quise decir con que el equipo no tiene sentido común, es que todos no están acostumbrados a hacer las cosas de la misma manera. El sentido de hacer algo no es común en todo el equipo.
    2- Si entre todos deciden que algo es bueno para ellos desde el punto de vista productivo, sea métricas o sea trabajar 6 horas en lugar de 8, habrá que confiar en que eso aporta valor. ¿no?

    Si esto no ocurriese, ya tenemos un problema de actitud y eso es otra peli.

    No entendí bien si lo que se decidió fue no aplicar las métricas con todo el equipo en contra, si es así querido amigo, desde mi punto de vista es un error. El problema seguramente no esté (me puedo equivocar) en que el equipo se preocupa más por las métricas que por hacer funcionar el producto. Deberías pensar que quizás hay algo más de fondo. ¿Seguro que las métricas no se estaban usando como control al equipo y por eso le daban más importancia?

    En el último equipo que trabajé, no se usaban métricas. Después de comentarlo con todo el equipo y ellos estar de acuerdo en que sería «útil para ellos», el resultado fue un 2% de cobertura en test y más de 1 año de deuda técnica. ¿Te puedes imaginar el estado de un proyecto con ese resultado? :-)

    El análisis con el equipo fue: «Bien, no pasa nada. Nuestro compromiso a partir de ahora es no empeorar esos números.

    – No podíamos tener menos del 2% de cobertura de test
    – No podíamos tener más de 1 año de deuda técnica.
    – El otro compromiso fue, incluir en cada sprint parte de esa deuda técnica y aumentar la cobertura de test. Siempre sobre objetivos medibles y priorizando según la importancia para el producto.»

    Aquí logras dos cosas. Por una parte quitas peso a que las métricas son un desastre, por la otra, enfocas el problema manteniendo la prioridad de «entregar algo que funciona al final de cada sprint».

    A los 6 meses, teníamos un 6% de cobertura en test y la deuda técnica había bajado a unos 5 meses. También teníamos un producto que funcionaba :-)

    Saludos

  7. Gracias a ambos por los comentarios, así da gusto :-)

    Omar, me ha parecido interesante estimar la deuda técnica acumulada en tiempo (y no sólo hablar de ella como concepto). ¿Cómo lo hacéis? ¿Tienes alguna referencia sobre eso?

  8. Lo que quiero decir es que presupones que en todos los equipos impera el sentido común y no es el caso.

    En el proyecto que te digo, se decidió, entre otras decisiones sacadas de la chistera de las «buenas prácticas no practicadas» que la cobertura tenía que ser desde el principio de un 80% y como máximo con 5 o 10 minor de sonar, incluyendo reglas bastante controvertidas que la mayoría de librerias que acabas usando no cumplen y que tienes que «arreglar» tú en tu codigo.
    Y si no se cumplen, el proyecto ni se despliega en Jenkins.
    Así que lo que tienes es un proyecto que todavía no hace nada consumiendo un monton de recursos para que salte por unos aros artificiales mientras las cuestiones realmente importantes todavía ni se han abordado ni probado… por que no hay tiempo ni recursos.

    No es que digamos que las metricas no sirvan, lo que decimos es que desgraciadamente en muchos sitios se acaba como el segundo caso en vez de como el primero.

    Te pongo un ejemplo de las cosas que a veces pasan. Alguien pone una regla como que «las variables no pueden ser de una letra», parece razonable, y todos los bloques catch (XException e) y los bucles for(int i… saltan. Una deuda técnica de aupa, un monton de violaciones, el proyecto es una mierda… y ahora que alguien me explique lo malísimo que es ese codigo que es casi una convención y lo buenísimo que es poner exception y count. Ala, todos a correr, se hace un search&replace en el 90% de las clases y ahora el proyecto es cojonudo… Y mientras tanto la lógica de negocio sin implementar.
    Que sí, que usadas con tino son como todas las herramientas, pero ahora se están usando, como bien dices, para control de otras cosas y pierden el sentido.

  9. El sonar saca una medida de la deuda técnica en tiempo. Por lo que me parecio ver, estima cada violación en un tiempo, aquí es donde no se de donde sacan los datos para asignar los tiempos a cada violación, y lo suman todo.
    IMHO, le podían quitar las unidades de tiempo y llamarlo cualquier otra cosa, por que la relación real con el tiempo es… estimada, por decirlo finamente :).

  10. @Juanma: Sonar te expresa la deuda técnica en tiempo :-)

    Ejemplo de mi último análisis con Sonar:
    9 New Code Smells
    2h New Debt

    @GreenEyed, En todo lo que mencionas me queda claro que la forma de abordar el problema no es la correcta.

    1- Yo no asumo que todo el equipo tiene el mismo sentido común. Si eso pasara sería el caso de Juanma, no necesita métricas :-) Si apoyo las métricas es justamente porque creo que este tipo de equipos no son los más comunes.
    2- «¿Alguien llega y pone una regla?» Las reglas no las pone nadie. Es el equipo quien decide qué poner y qué no poner.
    3- Las reglas normalmente se deciden todas en el momento en que deseas empezar a medir. Da igual que sea al inicio o a mitad de un proyecto. Una vez fijadas las reglas, estas no se cambian porque te desvirtúa el resultado.
    4- Si junto a todas las reglas decido poner la que mencionas, no significa que el proyecto esté mal, ni que haya que correr a cambiar todo eso. Significa que entre todos hemos acordado que poco a poco, sin variar el verdadero objetivo que es «escribir código que funcione», vamos a dar mayor claridad al código escribiendo nombres de variables que expresen mejor lo que hacen.

    ;)

    Saludos

  11. Me alegro por ti que trabajes en un sitio donde 2, 3 y 4 se cumplen. Pero no todo el mundo es así. Ojalá. :D

  12. Un debate muy interesante.

    Mi experiencia con el sonar siempre ha ido para cumplir el QA del cliente y con spas de javaScript (en angular o lo que sea), por lo que ni he podido decidir la cobertura ni, mucho menos, las reglas.

    Hay cosas que están bien, aunque sean meras validaciones formales, quitando la discutible complejidad ciclomática, pues no está de más que te detecten una variable no usada y esas cosas. Sin embargo, creo que a cambio tiene dos problemas:

    1. Uno muy grave es que te obliga a exponer métodos que deberían ser privados, pues de lo contrario no hay forma de alcanzar el 80% por ciento de cobertura, que es lo que te suelen pedir (al menos en el banco santander y barceló). Tal y como me explicaba un crack en la materia, Jani Hartikainen (codeutopia):

    «If you test the public interface, then, as a side-effect of that, your private methods are tested too. After all, if a private method had a bug, then the public interface would not work either :)

    However, sometimes you might end up having fairly complicated internal logic. It might become tricky to test the public interface because of this… That could be a sign that you should consider splitting it into multiple modules or functions. This again would bypass testing privates, as you would move the internal logic into a separate module, which you can then test as normal».

    peeeero, claro, así no se llega a la cobertura, que es lo único que entienden.

    2. Otro, también grave pero evitable, es que al final hay gente que se piensa que por pasar los test y alcanzar n% de cobertura el código es de calidad, mantenible y escalable. Esto no es así. Será condición necesaria, pero ni de lejos suficiente. Puede haber un desastre de código espaguitoso que, sin embargo, pase un test, ya que al fin y al cabo solo evalúa un return.

    s2

  13. Pues la verdad, después de leer los comentarios, sí que he tenido la «suerte» de poder manejar estas situaciones de otra manera.

    @GreenEyed no es trabajar en un sitio donde se cumpla 2, 3 y 4. Si eres responsable de un equipo, tienes que guiarles a que se cumpla 2, 3 y 4. Lo haces por el bien de todos incluyendo al proyecto. Si hay resultados, casi siempre los stakeholders dejan que te muevas con bastante libertad. :-) Hay que aprender a manipular el entorno por el bien común, aunque tu nombre nunca se escuche en los aplausos (teoría del bien superior).

    @mmfilesi es lo que venimos discutiendo y por lo que pasan las cosas que comenta @GreenEyed. Cómo alguien puede llegar a un proyecto y decir «hay que tener el 80% de cobertura». El resultado de esa frase es que todo el equipo se ponga a hacer test sin tener aún un producto que funciona, y sin saber si lo que están haciendo aporta algún valor :-)

    Saludos

  14. Solo decir que yo no soy el responsable del equipo, sigues hablando de entornos en los que no has trabajado y solo me falta encima la teoría no hacerlo por que no se escuche mi nombre en los aplausos. Jajaja, esa es buena. Ya en ese tono para mi la discusión ha terminado.

  15. Ops! @GreenEyed, no sé cómo habrá sonado lo que escribí o lo que quise decir. El comentario iba en respuesta a ti, pero refiriéndome a lo que hacía yo. En ningún momento pretendí que lo tomaras como algo personal. Si lo has interpretado así, mil disculpas.

    Es lo que tiene estos debates en blogs, al no poder ver caras y gestos, se pueden mal interpretar los comentarios.Y mira que me la paso poniendo caritas :-) para evitar estas cosas.

    Nada, que mil disculpas si sonó a algo personal. :-)

    Saludos

Comentarios cerrados.