Buscando aclaraciones sobre la estructuración del código para reducir la complejidad ciclomática

StackOverflow https://stackoverflow.com/questions/204369

Pregunta

Recientemente, nuestra empresa ha comenzado a medir la complejidad ciclomática (CC) de las funciones de nuestro código semanalmente y a informar qué funciones han mejorado o empeorado. Así que hemos comenzado a prestar mucha más atención al CC de funciones.

He leído que CC podría calcularse informalmente como 1 + el número de puntos de decisión en una función (por ejemplo, si la instrucción, para el bucle, seleccionar, etc.), o también el número de rutas a través de una función ...

Entiendo que la forma más fácil de reducir CC es usar el método de extracción refactorizando repetidamente ...

Hay algunas cosas de las que no estoy seguro, p. ¿Cuál es el CC de los siguientes fragmentos de código?

1)

for (int i = 0; i < 3; i++)
    Console.WriteLine("Hello");

Y

Console.WriteLine("Hello");
Console.WriteLine("Hello");
Console.WriteLine("Hello");

Ambos hacen lo mismo, pero ¿la primera versión tiene un CC más alto debido a la declaración for?

2)

if (condition1)
    if (condition2)
        if (condition 3)
            Console.WriteLine("wibble");

Y

if (condition1 && condition2 && condition3)
    Console.WriteLine("wibble");

Suponiendo que el lenguaje realiza una evaluación de cortocircuito, como C #, entonces estos dos fragmentos de código tienen el mismo efecto ... pero ¿es el CC del primer fragmento más alto porque tiene 3 puntos de decisión / declaraciones if?

3)

if (condition1)
{
    Console.WriteLine("one");

    if (condition2)
        Console.WriteLine("one and two");
}

Y

if (condition3)
    Console.WriteLine("fizz");

if (condition4)
    Console.WriteLine("buzz");

Estos dos fragmentos de código hacen cosas diferentes, pero ¿tienen el mismo CC? ¿O la declaración anidada if en el primer fragmento tiene un CC más alto? es decir, anidadas si las declaraciones son mentalmente más complejas de entender, pero ¿se refleja eso en el CC?

¿Fue útil?

Solución

  1. Sí. Su primer ejemplo tiene un punto de decisión y su segundo no, por lo que el primero tiene un CC más alto.
  2. Sí, tal vez, su primer ejemplo tiene múltiples puntos de decisión y, por lo tanto, un CC más alto. (Consulte a continuación para obtener una explicación).
  3. Sí, tal vez. Obviamente tienen el mismo número de puntos de decisión, pero hay diferentes formas de calcular CC, lo que significa ...

... si su empresa está midiendo CC de una manera específica, entonces necesita familiarizarse con ese método (es de esperar que estén utilizando herramientas para hacerlo). Hay diferentes formas de calcular CC para diferentes situaciones (declaraciones de casos, operadores booleanos, etc.), pero debe obtener el mismo tipo de información de la métrica, independientemente de la convención que utilice.

El mayor problema es lo que otros han mencionado, que su empresa parece centrarse más en CC que en el código detrás de él. En general, claro, menos de 5 es excelente, menos de 10 es bueno, menos de 20 está bien, 21 a 50 debería ser una señal de advertencia y más de 50 debería ser una gran señal de advertencia, pero esas son guías, no reglas absolutas. Probablemente debería examinar el código en un procedimiento que tenga un CC superior a 50 para asegurarse de que no sea solo un montón de código, sino que tal vez haya una razón específica por la cual el procedimiento está escrito de esa manera, y no es factible (para cualquier número de razones) para refactorizarlo.

Si usa herramientas para refactorizar su código para reducir CC, asegúrese de comprender lo que están haciendo las herramientas, y que no están simplemente cambiando un problema a otro lugar. En última instancia, desea que su código tenga pocos defectos, funcione correctamente y sea relativamente fácil de mantener. Si ese código también tiene un CC bajo, bien por eso. Si su código cumple con estos criterios y tiene un CC superior a 10, tal vez sea hora de sentarse con la administración que pueda y defender su código (y quizás hacer que examinen su política).

Otros consejos

Después de navegar a través de la entrada de Wikipedia y en el papel original de Thomas J. McCabe, parece que los elementos que mencionó anteriormente son problemas conocidos con la métrica.

Sin embargo, la mayoría de las métricas tienen pros y contras. Supongo que en un programa lo suficientemente grande, el valor CC podría apuntar a partes posiblemente complejas de su código. Pero ese CC más alto no necesariamente significa complejo.

Como todas las métricas de software, CC no es perfecto. Utilizado en una base de código lo suficientemente grande, puede darle una idea de dónde podría ser una zona problemática.

Hay dos cosas a tener en cuenta aquí:

  1. Base de código suficientemente grande: en cualquier proyecto no trivial tendrá funciones que tienen un valor CC realmente alto. Tan alto que no importa si en uno de sus ejemplos, el CC sería 2 o 3. Una función con un CC de digamos más de 300 es definitivamente algo para analizar. No importa si el CC es 301 o 302.
  2. No olvides usar tu cabeza. Hay métodos que necesitan muchos puntos de decisión. A menudo pueden ser refactorizados de alguna manera para tener menos, pero a veces no pueden. No utilice una regla como & Quot; Refactorice todos los métodos con un CC & Gt; xy " ;. Míralos y usa tu cerebro para decidir qué hacer.

Me gusta la idea de un análisis semanal. En el control de calidad, el análisis de tendencias es una herramienta muy efectiva para identificar problemas durante su creación . Esto es mucho mejor que tener que esperar hasta que sean tan grandes que se vuelvan obvios (vea SPC para algunos detalles).

CC no es una panacea para medir la calidad. Claramente, una declaración repetida no es & Quot; mejor & Quot; que un bucle, incluso si un bucle tiene un CC más grande. La razón por la que el bucle tiene un CC más grande es que a veces puede ejecutarse y otras no, lo que lleva a dos & Quot; casos & Quot; que ambos deben ser probados. En su caso, el bucle siempre se ejecutará tres veces porque usa una constante, pero CC no es lo suficientemente inteligente como para detectar esto.

Lo mismo con los ifs encadenados en el ejemplo 2: esta estructura le permite tener una declaración que se ejecutaría si solo condición1 y condición2 es verdadera. Este es un caso especial que no es posible en el caso de usar & Amp; & Amp ;. Por lo tanto, la cadena if tiene un mayor potencial para casos especiales, incluso si no utiliza esto en su código.

Este es el peligro de aplicar any métrica a ciegas. La métrica CC ciertamente tiene mucho mérito, pero como con cualquier otra técnica para mejorar el código, no puede evaluarse divorciada del contexto. Dirija su gestión a la discusión de Casper Jone sobre la medición de las Líneas de Código (ojalá pudiera encontrar un enlace para usted). Señala que si Lines of Code es una buena medida de productividad, los desarrolladores de lenguaje ensamblador son los desarrolladores más productivos del mundo. Por supuesto, no son más productivos que otros desarrolladores; solo les toma mucho más código para lograr lo que hacen los lenguajes de nivel superior con menos código fuente. Menciono esto, como digo, para que pueda mostrar a sus gerentes lo tonto que es aplicar ciegamente las métricas sin una revisión inteligente de lo que la métrica le dice.

Sugeriría que si no lo son, que su administración sería prudente utilizar la medida CC como una forma de detectar posibles puntos calientes en el código que deberían revisarse más a fondo. Apuntar ciegamente al objetivo de un CC inferior sin ninguna referencia al mantenimiento del código u otras medidas de buena codificación es una tontería.

La complejidad ciclomática es análoga a la temperatura. Ambas son medidas y, en la mayoría de los casos, no tienen sentido sin contexto. Si dijera que la temperatura exterior era de 72 grados, eso no significa mucho; pero si agregué el hecho de que estaba en el Polo Norte, el número 72 se vuelve significativo. Si alguien me dijo que un método tiene una complejidad ciclomática de 10, no puedo & # 8217; no puedo determinar si eso es bueno o malo sin su contexto.

Cuando reviso el código de una aplicación existente, encuentro que la complejidad ciclomática es útil & # 8220; punto de partida & # 8221; métrico. Lo primero que busco son métodos con CC & Gt; 10. Estos & # 8220; & Gt; 10 & # 8221; Los métodos no son necesariamente malos. Simplemente me proporcionan un punto de partida para revisar el código.

Reglas generales al considerar un número CC:

  • La relación entre CC # y # de pruebas, debe ser CC # < = #tests
  • Refactorizar para CC # solo si aumenta mantenibilidad
  • CC por encima de 10 a menudo indica uno o más olores de código

[Fuera de tema] Si está a favor de la legibilidad sobre la buena puntuación en las métricas (¿Fue J.Spolsky quien dijo, " lo que se mide, se hace "? - lo que significa que las métricas se abusan con más frecuencia supongo que no), a menudo es mejor usar un booleano bien nombrado para reemplazar su declaración condicional compleja.

luego

if (condition1 && condition2 && condition3)
    Console.WriteLine("wibble");

convertirse

bool/boolean theWeatherIsFine =  condition1 && condition2 && condition3;

if (theWeatherIsFine)
    Console.WriteLine("wibble");

No soy un experto en este tema, pero pensé que daría mis dos centavos. Y tal vez eso es todo lo que vale.

La Complejidad Ciclomática parece ser solo un atajo automatizado particular para encontrar fragmentos de código potencialmente (pero no definitivamente) problemáticos. ¿Pero no es el verdadero problema a resolver uno de las pruebas? ¿Cuántos casos de prueba requiere el código? Si CC es mayor, pero el número de casos de prueba es el mismo y el código es más limpio, no se preocupe por CC.

1.) No hay un punto de decisión allí. Hay una y solo una ruta a través del programa allí, solo un resultado posible con cualquiera de las dos versiones. El primero es más conciso y mejor, la complejidad ciclomática sea condenada.

1 caso de prueba para ambos

2.) En ambos casos, usted escribe " wibble " o no lo haces.

2 casos de prueba para ambos

3.) Primero, uno podría resultar en nada, " one " ;, o " one " y " uno y dos " ;. 3 caminos. El segundo no puede resultar en nada, ninguno de los dos, o ambos. 4 caminos.

3 casos de prueba para el primero 4 casos de prueba para el segundo

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top