Últimamente he participado en algunas discusiones sobre la utilidad de la métrica LOC (Lines Of Code o líneas de código). Como explicado en algunos posts anteriores, esta es la métrica que busco primero cuando hago una auditoría de la calidad de una aplicación. Y uso esta métrica sólo con el fin de obtener una idea del tamaño de la aplicación.
Luego, consideraré otras medidas tales como la Complejidad Ciclomática (CC) para tener una idea de su peso funcional. Siempre es interesante cruzar estas medidas, por ejemplo, calcular el número de LOC y la CC promedio por método o por clase. Esto permite identificar a las clases o métodos que son difíciles de entender, ya sea porque el programador tendra que ir en su pantalla de arriba a abajo en un archivo largo para seguir el flujo de instrucciones, o por un número significativo de condiciones y / o los enlaces y una lógica funcional más compleja de entender. Así que el riesgo es mayor de introducir un defecto cuando se realiza un cambio en el código.
Si se habla de LOC en una discusión, probablemente te encontrarás con algunas personas que te dirán que esta métrica no debe ser utilizada para medir la productividad o el esfuerzo de mantenimiento. Estoy de acuerdo que esto es incorrecto, el uso de esta métrica debe limitarse a medir el tamaño.
Los puntos de función (Function Points) se consideran a menudo la mejor métrica para medir la productividad. Tienen ciertas ventajas, sobre todo que se pueden utilizar con especificaciones funcionales, incluso antes de empezar el desarrollo, por lo que es útil para evaluar el esfuerzo necesario para implementar estas especificaciones en el código y para estimar la la carga necesaria en días / hombre. Sin embargo, esta medida tiene, en mi opinión, un gran inconveniente: no es fácil de automatizar el cálculo con una herramienta de análisis de código y un experto de FP estará muy cuidadoso, para no decir sospechoso a la hora de utilizar puntos de función calculados de forma automática.
Mientras trabajaba en los posts anteriores con el plugin City Model para Sonar, descubrí que eXcentia, la compañía española autora de este plugin, también ha creado uno para calcular una métrica ABC.
Os dejaré ver la descripción de esta métrica, a partir de un documento de su autor Jerry Fitzpatrick, aquí.
Esta métrica se basa en:
- A: Assignment, o asignación de valor a una variable.
- B: Branch, o llamada a una función o un nuevo objeto.
- C: Condition, una prueba basada en una condición.
He descargado el plugin ABC desde esta pagina en el sitio web de eXcentia, y lo he instalado en mi entorno Sonar.
A continuación, he creado una clase ‘TestAssignment.java’ con 50 instrucciones como las siguientes:
int var1=0; int var2=0; …Puse en marcha un análisis Sonar con Jenkins (si quieres probar por ti mismo, puedes ver a algunos posts anteriores, como este).
El resultado: un único edificio de una sola clase con los siguientes valores:
- ABC = 50, correspondiente a las 50 asignaciones que hemos creado.
- LOC = 55, correspondiente a las 50 líneas para estas asignaciones más unas pocas líneas adicionales para declarar la clase y su único método.
- Complexity = 1, el mínimo posible ya que no hay complejidad.
Luego, he creado una nueva clase ‘TestCondition.java’ con el siguiente código:
public class TestCondition { int var1=0; public TestCondition() { if (this.var1 = 0){ this.var1 = 1; } else{ this.var1 = 2; } …y las condiciones en este código duplicadas 8 veces para obtener aproximadamente el mismo número de líneas de código que la clase anterior. Hay que tener en cuenta que también tendremos 25 asignaciones: 3 en cada test duplicado 8 veces = 24 + 1 correspondiente a la declaración inicial de la variable var1.
Ahora tengo dos edificios, del mismo tamaño pero uno es rojo porque su nivel de CC por método es alto.
Sin embargo, la métrica ABC para esta nueva clase ABC es sólo ligeramente superior a las 25 asignaciones presente en su código, lo que demuestra que la complejidad no pesa mucho en el resultado.
Como se puede imaginar, he creado una tercera clase ‘TestBranch.java’ con 50 instrucciones «new»:
TestCondition myCondition1 = new TestCondition(); TestCondition myCondition2 = new TestCondition(); … TestCondition myCondition50 = new TestCondition();La altura sigue la misma, pero el valor ABC ahora es el más importante ya que tenemos 50 asignaciones que acompañan los 50 tratamientos de tipo ‘Branch’.
Sin embargo, la métrica ABC no se ha duplicado en comparación con la clase TestAssignement. Esta se compone de 50 asignaciones por un valor ABC de 50, mientras que la clase TestBranch tiene 50 asignaciones y 50 ‘new’, pero un valor ABC ligeramente por encima de 70.
Entonces, ¿qué podemos decir acerca de esta métrica ABC?
En primer lugar, podemos ver diferentes valores para estas tres clases con el mismo número de LOC. Así la métrica ABC es independiente del número de líneas de código.
Ahora, no estoy seguro de que puede ser usada como una medida de la productividad o el esfuerzo de mantenimiento: se puede ver que la A de Asignación pesa en su calculo. La condición C está claramente infravalorada. Es evidente que el esfuerzo requerido para hacer un cambio en una estructura de 8 ‘if-endif’ es mayor que para introducir un cambio en una secuencia de 50 asignaciones. Especialmente que las condiciones son más a menudo imbricadas (if dentro de un if dentro de un if …).
Y la mayor parte del tiempo, un enlace de tipo ‘Branch’ provocará nuevas asignaciones. Y también podemos ver que la adición de 50 ‘new’ y 50 asignaciones no duplica el resultado en comparación con 50 asignaciones sin ningún tipo de ‘Branch’ cuando, de hecho, creo que el esfuerzo para el programador se multiplicará por más de dos. Esto es debido a la fórmula para calcular la métrica ABC.
Pues, ¿qué uso podemos hacer de la métrica ABC? Debido a la predominancia de las asignaciones y la subvaloración de la condición C y de las llamadas B, creo que esta medida se orienta más a ‘estructura de datos’ que a ‘lógica’. Esto no es un problema, puesto que ya tenemos la complejidad ciclomática para evaluar la lógica funcional.
Así que he creado un nuevo modelo de City con los siguientes parámetros:
- La altura sigue basándose en el número de LOC.
- La anchura basada en el número de asignaciones, el A de la métrica ABC.
- El color basado en el valor total de la métrica ABC, de 1 (verde) hasta 100 (rojo).
Esto es lo que obtengo con mis tres clases:
Los tres edificios todavía siguen con la misma altura.
El más pequeño con color verde es la clase TestCondition con una anchura de 25 correspondiente a sus 25 asignaciones y un color correspondiente al valor ABC de 26.2, subestimando así el C de Condición.
Los otros dos bloques corresponden a las clases TestBranch y TestAssignment con el mismo ancho correspondiente al número de 50 asignaciones, pero TestBranch es más roja que TestAssignment con los tratamientos de llamadas adicionales.
Esta representación visual permite entender mejor cómo utilizar la métrica ABC. Yo no la usaría para medir el esfuerzo de mantenimiento, sino para medir la orientación a estructura de datos o el peso de los datos en un objeto, teniendo en cuenta el ancho de cada edificio, y una medida global de riesgo del componente, en función de su color. Un componente presentará un nivel de riesgo más o menos importante debido a que es bastante complejo, o más probablemente debido a un nivel de acoplamiento más elevado, además de su peso en estructuras de datos.
El plugin ABC de eXcentia viene con su propio widget (hemos visto en el post anterior la forma de agregarlo a nuestro dashboard para personalizar Sonar):
Podemos ver diferentes resultados para la métrica ABC:
- Un total de 134.9 para toda la aplicación.
- Un promedio de 45 por clase, lo que representa un nivel de riesgo moderado para una clase.
- Un promedio de 45 por cada método, lo que representa un riesgo más alto y se debe considerar un refactoring para los dos métodos con un valor ABC superior a 45.
Así que este widget está en línea con el uso que he recomendado, basado en el riesgo de introducir un defecto cuando se realiza un cambio en un componente.
¿Y si quiero una mejor apreciación de este riesgo, el plugin ABC me permite hacer un drill-down.
Aquí he seleccionado el edificio de mayor riesgo en mi City, la clase TestBranch, con sus diferentes valores.
Me basta con hacer clic sobre su nombre para ir a una ficha específica de la métrica ABC con las medidas para este objeto, y los valores para los diferentes elementos A, B y C así que por método y clase.
La mezcla de los dos plugins eXcentia para Sonar, City Model y ABC permite una evaluación visual del nivel de riesgo y la necesidad de refactorización de la aplicación.
Aquí está un ejemplo real: he analizado un paquete que sé que contiene algunas clases peligrosas:
Podemos ver en el barrio de derecha el paquete ‘TestABC’ con las tres clases que hemos creado para nuestras pruebas. Ahora, en esta representación, modifiqué la expresión para calcular la anchura de cada edificio con el número promedio de asignaciones por método, en lugar del total de asignaciones para la clase como antes.
En la figura anterior, apunto a la torre roja alta a la izquierda, una clase ‘SesionUsuario’ que administra todos los datos de un usuario quien se registra en la aplicación. Podemos ver:
- Un número de líneas de código de 2 700 LOC, lo que explica la altura de la torre.
- Un valor ABC global de 538.6 muy alto, lo que explica el color rojo de la torre.
- Que este valor global se basa en 522 asignaciones.
- Un número considerable de métodos: 67, lo que explica la anchura de la torre (522 asignaciones / 67 métodos).
Un drill-down en esta clase muestra la presencia de 71 Branchs y 112 Conditions en su código. Esto confirma la sobrevaloración de las asignaciones en el valor total de la métrica ABC.
Con la configuración inicial del plugin City Model, esta clase también aparece de altura, con una base más amplia basada en el número de sus métodos, pero verde por completo debido a su complejidad por método bastante baja. Por lo tanto, parecería un componente importante, pero no necesariamente en la primera posición de una refactorización.
Utilizando mediciones de ABC, el ancho es mucho menor, ya que el valor ABC por método no es muy alto, pero el edificio es completamente rojo, lo que inmediatamente llama la atención sobre el riesgo por esta clase. Así que ahora este componente es un buen candidato para una operación de refactorización.
Por supuesto, debemos tener en cuenta otros factores como la calidad del código y la falta de respecto a buenas prácticas de programación. Pero con este ejemplo, podemos ver que:
- La métrica LOC es una medida del tamaño técnico de una aplicación, que no es adecuada para evaluar el peso funcional, la productividad de un equipo de proyecto o una estimación de esfuerzo de mantenimiento.
- CC es una buena medida del peso funcional basada en el número de caminos lógicos en el código pero no es necesariamente un buen indicador para priorizar refactoring.
- Creo que la métrica ABC es una buena medida del «peso de datos» o del nivel de estructuras de datos en un componente, y como tal, un buen complemento para la Complejidad Ciclomatica, más orientada a «lógica».
- Hemos modelado una ciudad basada en los plugins de eXcentia para Sonar, que nos ayuda a identificar rápidamente cuáles son los componentes de riesgo y definir una lista de los candidatos prioritarios para un plan de refactorización.
Es probable que se puede imaginar muchas representaciones con el plugin City Model, para tratar diferentes preguntas. Sin embargo, tendremos otras oportunidades para experimentar con estas herramientas.
Esta entrada está disponible también en Lire cet article en français y Read that post in english.