MOISESDANIEL.COM

Ingeniero Informático, y… aprendiz de casi todo.

 

Software

Artículos

mp3 & arte

BLOG

 

 

Inicio > Artículos

 

 

 

           

Métrica y Complejidad del software: ToroMetrics v1.0.

Junio de 2006

 

 

 

 

 

1.- Introducción.

 

En la antigüedad el reto principal en la construcción de catedrales fue el asegurar su estabilidad, es decir el estar seguros de que aquella estructura no se caería.

 

Podría parecernos que sin herramientas matemáticas era difícil poder conseguirlo, y de hecho lo era. Siempre se podía acudir a una maqueta, un modelo, pero ¿cómo escalar un diseño estable? No es una pregunta fácil de responder.

De hecho la experimentación ha sido la base sobre la que se han desarrollado muchas tecnologías, aún sin tener una sólida base científica. Los ingenieros han tenido una cultura con profundas raíces empíricas, trabajando desde las pruebas y la experimentación hacia las reglas, las fórmulas y las teorías que han demostrado ser de un valor incalculable en trasladar sus ideas a los artefactos.

La experimentación y la observación nos han llevado, cuando no a teorías, sí a reglas de diseño y criterios. ¿Pero cómo expresar estas observaciones y estas reglas? El primer paso es medir.

 

 

Una vez que somos capaces de obtener medidas, podremos desarrollar reglas, hipótesis, y teorías para analizar sistemas complejos en términos de las propiedades de los elementos que lo forman y las relaciones entre estos.

 

En el mundo del software, existen tres categorías de métricas: métricas del producto (es decir, del software en sí mismo), métricas del proceso (de desarrollo) y métricas del proyecto.

Las métricas del producto describen características como el tamaño, la complejidad, el rendimiento, etc, etc.

 

La medida que desarrolla ToroMetrics (y que llamaremos LOCE (Equivalencia en Número de Líneas de Código)) relaciona el tamaño del código con su complejidad, de tal forma que intenta asociar al código un número. Este número ayudaría a:

§         Estimar el número de errores en el código.

§         El esfuerzo que requiere testearlo y/o mantenerlo.

§         El tiempo que requiere su desarrollo.

§         Comparar diferentes trozos de código.

 

De esta forma podríamos identificar código crítico, en cuanto a los errores que pueda contener.

 

Como hemos explicado, esta métrica se relaciona con la complejidad del código ya que hoy día, al igual que anteriormente con las catedrales, uno de los objetivos principales al desarrollar software debe ser asegurar su estabilidad, controlar su complejidad, y por lo tanto saber que lo que se ha realizado no caerá al menor contratiempo como un castillo de naipes.

 

The image “http://www.divulgamat.net/weborriak/RetosMatematicos/Problemas/Irudiak/18A.gif” cannot be displayed, because it contains errors.

 

 

 

2.- Descripción de las métricas en las que se fundamenta la métrica LOCE (Equivalencia en Número de Líneas de Código).

 

Existen muchas métricas para el código fuente. Muchas de ellas se basan simplemente en contar elementos, mientras que otras son bastante más complejas. De alguna forma las métricas de conteo simple son métricas relacionadas con la complejidad, ya que existe una relación grande entre el tamaño del código y su complejidad. Para el desarrollo de la métrica LOCE nos hemos basado en las siguientes métricas:

 

2.1.- LOC (Lines Of Code).

 

Una de las métricas más usadas es la del número de líneas de código (LOC), que aunque parece sencilla no lo es tanto, ya que existen diferentes alternativas: contar sólo las líneas de código ejecutable, añadirle las declaraciones de datos, también podemos contas las líneas de comentarios, añadir las sentencias de control, etc, etc.

De hecho suele ser frecuente, que al usar diferentes programas de métricas, estas generen diferentes valores de LOCs para un mismo fichero.

 

El uso principal que tiene contar líneas de código, es poder determinar proporciones entre líneas de código y fallos, es decir, generar medidas (y heurísticas) sobre el número de líneas de código y el número de fallos de una aplicación (‘número de defectos por KLOC (1000 LOC)’).

 

Una alternativa a las líneas de código son los puntos de función, que también intentan medir el tamaño del software. Este es bastante independiente del lenguaje de programación utilizado. Sacado de la Wikipedia: la técnica de medición del tamaño en punto-función consiste en asignar una cantidad de "puntos" a una aplicación informática según la complejidad de los datos que maneja y de los procesos que realiza sobre ellos. Como podemos ver, bastante compleja de calcular. Aquí también existen diferentes procedimientos para obtener esta métrica.

 

2.2.- Complejidad ciclomática.

 

La métrica de la complejidad ciclomática fue diseñada por McCabe (1976) para indicar la facilidad para testear y entender el código. Esta medida está secada de la teoría de grafos, e indica el número de regiones en un grafo.

Aplicada al software, es el número de caminos linealmente independientes que contiene un programa. Como tal, puede ser usado para indicar el esfuerzo necesario para testear un programa.

Tomado de la Wikipedia: La complejidad ciclomática de un bloque de código fuente es el número de caminos ejecutables en el código fuente. Por ejemplo si el código fuente no contiene puntos de decisión (es decir no contiene instrucciones IF, ni For, etc) la complejidad ciclomática sería igual a 1, ya que sólo existe un camino de ejecución para ese código. Si el código contuviera un IF entonces existirían dos, uno si la expresión condicional del IF resulta cierta, y otro para cuando es falsa.

 

Existen numerosos estudios empíricos que han demostrado una alta correlación entre código con fallos y código con alta complejidad ciclomática.

 

 

3.- Descripción de la LOCE (Lines Of Code Equivalence, Equivalencia en número de líneas de código).

 

LOCE viene de “Lines Of Code Equivalence”, es decir, “Equivalencia en Número de Líneas de Código”, y como ya hemos dicho es una métrica que intenta mejorar las métricas de conteo de número de líneas y de complejidad ciclomática, ya que ¿acaso es igual de complejo un método con 3 IF separados que con 3 bucles FOR anidades? No lo creemos.

 

ToroMetrics hace una suposición muy sencilla y es que cuanto más anidada está una línea de código más difícil es de entender, o lo que es lo mismo, más complejo es el código y más probabilidades tiene de contener un error,  ya que una línea de código dentro de un IF o un FOR podrá o no ejecutarse, o incluso ejecutarse numerosas veces, por lo general tendrá una semántica adicional y tendrá una relación más estrecha con el resto de líneas de código de su bloque.

 

La medición de la LOCE de una sentencia será sencilla, si la línea está directamente dentro del método diremos que está a nivel de profundidad igual a 0, si está anidada dentro de sentencias IF, FOR, WHILE, y DO tendrá un nivel de produndidad igual a la suma de estas sentencias que la engloben. La LOCE de una línea será por tanto:

§         Para niveles igual a cero, su LOCE será uno.

§         Para niveles mayores que cero, su LOCE será 2 * Nivel.

 

La LOCE del método (el peso del método) sería igual al sumatorio del peso de cada una de sus líneas.

 

El número 2 representaría el incremento de complejidad por estar dentro de una rama de la ejecución (un IF, FOR, WHILE, etc).

 

Veamos un pequeño ejemplo con la clase Dummy para ver cómo funciona esta aplicación:

 

package org.opentoro.utils.metrics;

 

public class Dummy  {

  public Dummy() {

  }

 

  public void doit(){

    for (int i = 0; i < 10; i++){

      for(int j = 0; j < i; j++){

        System.out.println("i = " + i);

        System.out.println("j = " + j);

      }//End For j

    }//End For i

  }

 

}

 

 

El resultado que obtendríamos al ejecutar la aplicación ToroMetrics a dicha clase sería la siguiente:

  <?xml version="1.0" encoding="ISO-8859-1" ?>

- <Report>

- <Class name="C:\temp\ToroMetricsv1.0\src\org\opentoro\utils\metrics\Dummy.java" loce="14.0">

  <Method name="doit" loce="14.0" avLocePerLoc="3.5" loc="4" />

  <Method name="Constructor" loce="0.0" avLocePerLoc="0.0" loc="0" />

  </Class>

  </Report>

 

 

Modifiquemos ahora esta clase Dummy:

 

 

package org.opentoro.utils.metrics;

 

public class Dummy  {

  public Dummy() {

  }

 

  public void doit(){

    for (int i = 0; i < 10; i++){

      for(int j = 0; j < i; j++){

        printMessages(i, j);

      }//End For j

    }//End For i

  }

 

  void printMessages(int i, int j) {

    System.out.println("i = " + i);

    System.out.println("j = " + j);

  }

 

}

 

Si volvemos a aplicarle ToroMetrics obtendríamos el siguiente resultado:

  <?xml version="1.0" encoding="ISO-8859-1" ?>

- <Report>

- <Class name="C:\temp\ToroMetricsv1.0\src\org\opentoro\utils\metrics\Dummy.java" loce="12.0">

  <Method name="doit" loce="10.0" avLocePerLoc="3.33" loc="3" />

  <Method name="printMessages" loce="2.0" avLocePerLoc="1.0" loc="2" />

  <Method name="Constructor" loce="0.0" avLocePerLoc="0.0" loc="0" />

  </Class>

  </Report>

 

 

 

 

4.- Cómo usar ToroMetrics

  1. Descomprimir el fichero ToroMetricsv1.0.zip
  2. Si queremos ver que todo está bien ejecutar example.bat. Esto nos generará el fichero report.xml, el cual contiene las medidas LOC y LOCE de los propios fuentes de ToroMetrics.
  3. Para pasarle el ToroMetrics a nuestro proyecto ejecutar:

                        torometrics.bat   RutaCodigoFuente     NombreFicheroaGenerar

Ejemplo:

                              torometrics.bat    c:\temp\ToroMetricsv1.0\src     out.xml

 

<?xml version="1.0" encoding="ISO-8859-1" ?>

- <Report>

- <Class name="c:\temp\ToroMetricsv1.0\src\org\opentoro\utils\metrics\ClassWrapper.java" loce="17.0">

  <Method name="getClassName" loce="1.0" avLocePerLoc="1.0" loc="1" />

  <Method name="getXml" loce="1.0" avLocePerLoc="1.0" loc="1" />

  <Method name="setXml" loce="1.0" avLocePerLoc="1.0" loc="1" />

  <Method name="computeWeight" loce="8.0" avLocePerLoc="1.3" loc="6" />

  <Method name="getWeight" loce="1.0" avLocePerLoc="1.0" loc="1" />

  <Method name="setMethods" loce="1.0" avLocePerLoc="1.0" loc="1" />

  <Method name="getMethods" loce="1.0" avLocePerLoc="1.0" loc="1" />

  <Method name="Constructor" loce="1.0" avLocePerLoc="1.0" loc="1" />

  <Method name="Constructor" loce="2.0" avLocePerLoc="1.0" loc="2" />

  </Class>

- <Class name="c:\temp\ToroMetricsv1.0\src\org\opentoro\utils\metrics\Dummy.java" loce="12.0">

  <Method name="doit" loce="10.0" avLocePerLoc="3.3" loc="3" />

  <Method name="printMessages" loce="2.0" avLocePerLoc="1.0" loc="2" />

  <Method name="Constructor" loce="0.0" avLocePerLoc="0.0" loc="0" />

  </Class>

.....

 

 

 

5.- Algunas recomendaciones.

 

Basándonos en nuestra experiencia se recomendaría para cada método lo siguiente:

 

Todos queremos construir software correcto, robusto, extensible y reusable. Debemos ser conscientes que el mejor camino para lograrlo, está precisamente en hacer una programación de calidad, y para conseguir ésto es bueno detectar el código crítico y tratarlo de forma adecuada.

Añada comentarios aquí.

 

© Moisés D. Díaz. http://www.moisesdaniel.com/, email: md (at) moisesdaniel.com. All Rights Reserved. RSS