¿Qué significa la 'complejidad ciclomática' de mi código?

42

Soy nuevo en el análisis estático de código. Mi aplicación tiene una complejidad ciclomática de 17,754. La aplicación en sí es solo 37,672 líneas de código. ¿Es válido decir que la complejidad es alta en función de las líneas de código? ¿Qué me dice exactamente la complejidad ciclomática?

Pájaro enojado
fuente
Eso depende completamente de lo que estés haciendo. Si estás tratando de hacer algo simple, entonces es muy, muy alto. No deberías tener esa relación en "hola mundo", por ejemplo.
cwallenpoole

Respuestas:

48

¿Qué me dice exactamente la complejidad ciclomática?

La complejidad ciclomática no es una medida de líneas de código, sino el número de rutas independientes a través de un módulo. Su complejidad ciclomática de 17,754 significa que su aplicación tiene 17,754 rutas únicas a través de ella. Esto tiene algunas implicaciones, generalmente en términos de lo difícil que es comprender y probar su aplicación. Por ejemplo, la complejidad ciclomática es el número de casos de prueba necesarios para lograr una cobertura de rama del 100%, suponiendo pruebas bien escritas.

Un buen punto de partida podría ser el artículo de Wikipedia sobre la complejidad ciclomática . Tiene un par de fragmentos de pseudocódigo y algunos gráficos que muestran de qué se trata la complejidad ciclomática. Si quieres saber más, también puedes leer el artículo de McCabe donde definió la complejidad ciclomática .

Mi aplicación tiene una complejidad ciclomática de 17,754 líneas de código. La aplicación en sí es solo 37,672 líneas de código. ¿Es válido decir que la complejidad es alta en función de las líneas de código?

De ningún modo. Una aplicación con pocas líneas de código y una gran cantidad de condicionales anidados dentro de bucles podría tener una complejidad ciclomática extremadamente alta. Por otro lado, una aplicación con pocas condiciones podría tener una baja complejidad ciclomática. Eso es simplificar demasiado, pero creo que hace que la idea se transmita.

Sin saber más sobre lo que hace su aplicación, podría ser normal tener una mayor complejidad ciclomática. Sin embargo, sugeriría medir la complejidad ciclomática a nivel de clase o método, en lugar de solo un nivel de aplicación. Creo que esto es un poco más manejable, conceptualmente: es más fácil visualizar o conceptualizar las rutas a través de un método que las rutas a través de una aplicación grande.

Thomas Owens
fuente
36

La complejidad ciclomática es una forma de determinar si su código necesita ser refactorizado. El código se analiza y se determina un número de complejidad. La complejidad se determina ramificando (si hay declaraciones, etc.) La complejidad también podría tener en cuenta el anidamiento de bucles, etc. y otros factores dependiendo del algoritmo utilizado.

El número es útil a nivel de método. En niveles superiores es solo un número.

Un número de 17,754 indica complejidad a nivel de proyecto (código total), que no tiene mucho significado.

Profundizar en la complejidad del nivel de clase y método determinará las áreas del código que deben refactorizarse en métodos más pequeños o rediseñados para eliminar la complejidad.

Considere una CASEdeclaración con 50 casos en un método. Quizás cada estado tiene una lógica de negocios diferente. Eso generará una complejidad ciclomática de 50. Hay 50 puntos de decisión. La declaración CASE puede tener que ser rediseñada utilizando un patrón de fábrica para deshacerse de la lógica de ramificación. A veces puede refactorizar (dividir el método en partes más pequeñas) y en algunos casos solo un rediseño reducirá la complejidad.

En general, para la complejidad del nivel de método:

  • <10 Fácil de mantener
  • 11-20 más difícil de mantener
  • Más de 21 candidatos para refactorización / rediseño

También tenga en cuenta que las complejidades más altas hacen que el código sea más difícil de probar.

La mayor complejidad que he visto en un solo método fue 560. Fue alrededor de 2000 líneas de declaraciones if en un método. Básicamente insostenible, no comprobable, lleno de posibles errores. ¡Imagine todos los casos de prueba de unidad necesarios para esa lógica de ramificación! No está bien.

Intente mantener todos los métodos por debajo de 20 y tenga en cuenta que hay un costo para refactorizar cualquier método para que sea menos complejo.

Jon Raynor
fuente
Esta es una mejor respuesta.
Pacerier
2
@Pacerier En ese caso, simplemente vota la respuesta;).
Zero3
> "En general, para la complejidad del nivel de método" ¿Cita?
Benny Bottema
Una de las aplicaciones originales de McCabe fue limitar la complejidad de las rutinas durante el desarrollo del programa; recomendó que los programadores deberían contar la complejidad de los módulos que están desarrollando y dividirlos en módulos más pequeños siempre que la complejidad ciclomática del módulo excediera de 10.
Jon Raynor
"La declaración CASE puede tener que ser rediseñada utilizando un patrón de fábrica para deshacerse de la lógica de ramificación". ¿Por qué? Eso no elimina la complejidad de la lógica; simplemente lo oculta y lo hace menos aparente, y por lo tanto más difícil de mantener
Mason Wheeler
1

Es el número de rutas distintas en su aplicación. Consulte este artículo de IBM sobre CC .

Parece alto, pero en su caso es la adición de CC de todos sus métodos de todas sus clases y métodos. Mis ejemplos están muy extendidos ya que no sé cómo está estructurado su código, pero también puede tener un método monstruo con 37672 líneas de código o 3767 métodos con aproximadamente 10 líneas de código. Lo que quiero decir es que a nivel de aplicación, este indicador no significa mucho, pero a nivel de método puede ayudarlo a optimizar / reescribir su código en métodos más pequeños para que sean menos propensos a errores.

Lo que he leído personalmente muchas veces es que los métodos con un CC superior a 10 tienen mayores riesgos de defectos.

Uso Sonar para probar la calidad del código de mis aplicaciones y, por defecto, creo que genera una advertencia si tiene métodos con +10 CC. Aún así, eso puede no significar nada. Un ejemplo concreto: si usa Eclipse para generar un equalsmétodo basado en las propiedades de su bean, el CC pasará rápidamente por encima del techo ...

Jalayn
fuente
1
La configuración predeterminada de PMD es también alertar a una complejidad ciclomática de 10. Observar la complejidad en un nivel por método también le permite ignorar los métodos que pueden tener buenas razones para un alto CC, como los equalsmétodos generados .
Thomas Owens
No estaba seguro, así que lo comprobé, pero Sonar usa PMD internamente para obtener esta medida. Entonces todo tiene sentido :-)
Jalayn
-1

Depende de qué herramienta utilizaste. Algunas de las herramientas de código abierto disponibles toman la clase como un módulo u otro nivel de estructura como un módulo. Por lo tanto, cuanto más grande es un proyecto, mayor complejidad ciclomática tiende a ser. Sin embargo, para mi comprensión personal, debería basarse en una función. Como cuanto más grande es un proyecto, las funciones que asume tiene.

Le recomiendo que use la herramienta llamada Lizard y puede encontrar el código de recursos y descargar el archivo zip en github. También tiene una versión en línea si no hay mucha información confidencial en su código.

El CCN significativo que debería interesarle está en una base de funciones diferente a cualquier otra. Además, mantener el CCN unber 15 de cada función sería el rango ideal.

Jiahang Li
fuente