La complejidad ciclomática es una métrica a tener en cuenta para
evaluar la mantenibilidad, comprensión, testeabilidad y probabilidad de
errores de una determinada aplicación.
Este término fue propuesto por Thomas J. McCabe en 1976 y tiene como
una de sus características principales su independencia respecto a los
lenguajes de programación (por lo menos, de los más convencionales), por
lo que teóricamente podrían ser comparables aplicaciones realizadas con
tecnologías distintas en base a su complejidad ciclomática. Digo
teóricamente, porque además de la algorítmica las características
propias del lenguaje de programación pueden influir en que sean más
sencillas o no su inteligibilidad, mantenibilidad, etc… No obstante y en
cualquier caso, resulta una aproximación muy a tener en cuenta de esos
factores.
¿Qué mide la complejidad ciclomática? Pues el número de posibles
caminos lógicos que tiene una aplicación. ¿Quiénes crean esos posibles
caminos lógicos? Los métodos, las sentencias selectivas (if, case),
sentencias iterativas (while, for), lanzamiento y tratamiento de
excepciones (throw, catch), devolución de resultados de un método cuando
no es lá última línea del mismo (return), operadores lógicos en
guardas, etc…
Cuanto más caminos lógicos tenga una aplicación, una clase o un
método más complejo resulta y por tanto, requiere un mayor esfuerzo
desde el punto de vista de las pruebas unitarias (el número de pruebas
unitarias para recorrer todo el código crece linealmente con la
complejidad ciclomática (además de cumplirse eso, se verifica que: 1) la
complejidad ciclomática es menor o igual que el número de casos de
pruebas que se requiere para hacer cobertura de todo el código de la
aplicación (téngase en cuenta que los else no suman complejidad
ciclomática), 2) la complejidad ciclomática es mayor o igual que el
número de casos de prueba que se requieren para verificar que realmente
se “abren” los distintos caminos físicos)).
Por tanto, una baja cobertura de una aplicación viene a decir que
existe una gran cantidad de código que no se ha verificado (utilizando
esta estrategia), que se recorra, por lo que probablemente si no se ha
recurrido a pruebas intensivas de la aplicación, muy probablemente se
traduzca en errores evitables que se detectan posteriormente, incluso en
producción).
También se requiere un mayor esfuerzo para la mantenibilidad y
comprensión del código (¿cuántas veces nos hemos perdido en un mar de
sentencias if anidadas?) y por todo lo anterior se incrementan las
posibilidades de que existan errores, porque ¿cuántas veces nos hemos
encontrado con que un problema en un método era provocado porque no se
metía por la guarda correspondiente de una condicional o porque no
entraba en un determinado bucle?, por lo que simplemente la mera
experiencia nos indica que debe existir una relación entre la
complejidad ciclomática y el número de errores de una aplicación.
Como la complejidad ciclomática es el resultado de los diferentes
caminos lógicos que puede tener una aplicación es lógico que esta crezca
conforme más extensa (en líneas de código) es una aplicación y por
regla general una aplicación con muchas funcionalidades, grande, etc…,
es más compleja, requiere mayor codificación y tendrá como consecuencia
una mayor complejidad ciclomática (de esta manera existirá prácticamente
una relación entre una clasificación de las aplicaciones por líneas de
código y una clasificación de las aplicaciones por complejidad
ciclomática, es importante señalar que no tienen por qué conservar el
mismo orden aunque sí más o menos estarán por el mismo entorno, es
decir, la segunda aplicación con más líneas de código, puede ser la
cuarta en complejidad ciclomática o la quinta aplicación con más código,
la segunda en complejidad. Por tanto este tipo de complejidad es
inherente a las aplicaciones y existe por el simple hecho de la
existencia de las mismas y por tanto, aplicaciones con envergadura se
traducen en aplicaciones complejas de mantener y eso es consecuencia de
su complejidad ciclomática intrínseca.
Independientemente de que una codificación eficiente puede eliminar
caminos lógicos innecesarios, existe un límite y es el que da la propia
dinámica de funcionamiento de un sistema de información que provoca que
se codifique su comportamiento en algoritmos que como se han comentado
anteriormente pueden ser complejos. Cuando se aproxima a este límite, lo
más que se puede hacer es utilizar la complejidad ciclomática para
determinar si determinados métodos o clases son demasiado complejas y
requerirían ser analizadas de cara a dividirlas en otras más simples,
mejorando así la mantenibilidad de las mismas.
Existen algunas clasificaciones basadas en rangos de complejidad
ciclomática que determinan cuando es recomendable hacer la
simplificación de determinadas clases y métodos y también hay casos de
éxito de la aplicación de los mismos en algunas compañías.
En muchas ocasiones a simple vista se puede determinar si un método o
una clase tienen una complejidad ciclomática alta, no obstante, esta
tarea puede ser agotadora si la aplicación a analizar es muy grande, por
ese motivo, lo mejor es delegar esa función en analizadores estáticos
de código, como es el caso de Sonar, que permite obtener métricas de la
complejidad ciclomática tanto a nivel de aplicación, como de clases y de
métodos y utilizando su implementación de funcionalidades de drill down
ir de datos más generales a información más de detalle.
Como todas las métricas de ingeniería del software, no hay que
tomarse los resultados de la complejidad ciclomática al pie de la letra,
sino saber interpretar qué es lo que están diciendo y tomar medidas
para reducir el impacto de dicha complejidad en la aplicación (mayor
cobertura de pruebas unitarias) y para tomar decisiones de revisión de
la codificación en métodos y clases complejos y su posible
simplificación en otros más sencillos.
http://jummp.wordpress.com/2010/04/27/complejidad-ciclomatica/
No hay comentarios.:
Publicar un comentario