¿Los métodos iterativos reducen la complejidad ciclomática y mejoran la capacidad de soporte?

11

¿Los métodos iterativos como los que se encuentran comúnmente en lenguajes modernos como C #, JavaScript y (con suerte) en Java 8 reducen el impacto de la complejidad ciclomática en la comprensibilidad y compatibilidad del código?

Por ejemplo, en C # podríamos tener el siguiente código:

List<String> filteredList = new List<String>();

foreach (String s in originalList){
   if (matches(s)){
      filteredList.add(s);
   }
}

Esto tiene una complejidad ciclomática simple de 2.

Podríamos reescribir esto fácilmente como:

List<String> filteredList = originalList.where(s => matches(s));

Que tiene una complejidad ciclomática simple de 0.

¿Esto realmente da como resultado un código más compatible? ¿Hay alguna investigación real sobre este tema?

Cruzar
fuente
2
Su título pregunta sobre la reducción de la complejidad ciclomática, pero su texto asume la reducción CC y pregunta sobre la capacidad de mantenimiento. Esto tiene el potencial de ser una pregunta valiosa, ¿puedes editar el título para que sea más preciso?
Kilian Foth
@KilianFoth ¿Eso es mejor?
C. Ross
Asociaría métodos iterativos con metodologías de desarrollo iterativo. Creo que un término mejor sería funciones de orden superior. (Y aparte, los métodos no tienen ningún tipo de retorno / vacío mientras que las funciones devuelven algo).
Johannes Rudolph el
@JohannesRudolph "los métodos no tienen ningún tipo de retorno / vacío mientras que las funciones devuelven algo" - ¿en qué idioma es esto cierto? Nunca he escuchado esto; de hecho, la única distinción real que he escuchado es que los métodos están asociados con una clase, las funciones no.
threed

Respuestas:

14

Supongo que acabas de dividir / mover la complejidad. Disminuyó porque no cuenta la implementación de .where()en su CC.

El CC general no se ha movido realmente, el CC de su propio código disminuyó, solo porque ahora se ha movido al código del marco.

Yo diría que es más fácil de mantener. Cuando es una característica del lenguaje, úselo. No es un "ohh, ya veo, es un truco inteligente" lo que estás usando, solo una simple función de reducción en línea.

Clemente Herreman
fuente
11

Todo lo que está haciendo es resaltar una falla en la complejidad ciclomática como una métrica, la complejidad del código realmente no ha cambiado. Tiene una rama explícita en el primer ejemplo y necesita comprender que hay una rama implícita en el segundo. El segundo es más claro y fácil de entender siempre que comprenda la sintaxis, y dado que utiliza una sintaxis menos básica, puede ser un problema.

Ryathal
fuente
1
Uno podría argumentar que la complejidad ciclomática del propio código se reduce aquí, ya que whereaquí es probable que provenga de un marco. Creo que la complejidad ciclomática como métrica es útil incluso aquí porque, si bien dividir una función en varias no disminuye la complejidad general del sistema (de hecho, a menudo la aumenta, aunque solo sea un poco), te ayuda a determinar cuándo Una parte del sistema se vuelve demasiado compleja y necesita ser desglosada.
threed
6

Para responder la pregunta objetivamente, necesitaríamos algún tipo de métrica para la mantenibilidad. La complejidad ciclomática en sí misma no es una medida de mantenibilidad, pero es un componente de algunas métricas que pretenden medir la mantenibilidad. Por ejemplo, la fórmula para el índice de mantenimiento es:

MI = 171 - 5.2 * ln(V) - 0.23 * (G) - 16.2 * ln(LOC)

¿Dónde Gestá la complejidad ciclomática del código en cuestión? Por lo tanto, la reducción de la complejidad ciclomática de un código mejora, por definición, el índice de mantenimiento del código y otras métricas que utilizan de manera similar la complejidad ciclomática .

Es difícil decir si el tipo de cambio que propone hace que el programa parezca más fácil de mantener para los programadores; eso probablemente depende de qué tan familiarizados estén (en su caso) con el wheremétodo.

Caleb
fuente
Advertencia: ¡números mágicos! (>_<)
Izkata
Solo hay un pequeño problema con el índice de mantenimiento. Los tres componentes son Volumen de Halstead, Complejidad ciclomática y Líneas de código. Se ha demostrado que tanto el volumen de Halstead como la complejidad ciclomática están muy correlacionados con las líneas de código. Esto significa que se podría derivar una ecuación aproximada alternativa para el índice de mantenimiento que dependía SOLO de líneas de código que sería casi tan precisa como la original, con una dificultad computacional considerablemente menor.
John R. Strohm
@ JohnR.Strohm Creo que obtendría un resultado similar incluso si solo usa LOC como la métrica de mantenibilidad. El cambio del OP reduce el LOC a 1 de 4, y otros cambios que reducen la complejidad ciclomática también tienen probabilidades de reducir el LOC. De cualquier manera, todo se reduce a cómo define y mide la mantenibilidad.
Caleb
1
@Caleb: De acuerdo. El punto que trato de hacer es que las personas con demasiada frecuencia optan por estas métricas y combinaciones de métricas realmente complicadas, sin darse cuenta de que casi todas ellas se han correlacionado fuertemente en el código real con líneas de código antiguas (LOC) simples. y, por lo tanto, no tienen más valor predictivo o descriptivo que LOC.
John R. Strohm
3

Debido a que se ha demostrado que la complejidad ciclomática (CC) está fuertemente correlacionada con el tamaño del código, "tanto que se puede decir que CC no tiene absolutamente ningún poder explicativo propio". lo que realmente se pregunta es si "los métodos iterativos como los que se encuentran comúnmente en lenguajes modernos como C #, JavaScript y (con suerte) en Java 8 reducen el impacto del tamaño del código en la comprensibilidad y compatibilidad del código".

En ese punto, uno esperaría que la respuesta fuera obvia. Se sabe desde hace décadas que un código más corto es generalmente más fácil de entender, mantener y soportar.

John R. Strohm
fuente
2

Si está hablando de la estadística bruta de la complejidad ciclomática, seguro. Acaba de disparar de 2 a 0. Si va por números, ganancia pura, hasta el final.

Sin embargo, desde una perspectiva práctica (léase: humana), diría que en realidad has aumentado la complejidad en 2. Un punto de eso proviene del hecho de que ahora algún otro programador debe traer u obtener conocimiento de LINQ de sintaxis fluida para comprender esto. código.

Otro punto de mayor dificultad proviene de comprender las expresiones Lambda; Aunque un Lambda es bastante sencillo en este caso , hay algunos cambios de paradigma que deben hacerse para apreciarlos completamente.

Este caso, el uso a.where(x => matches(x, arg))no es terrible, y para ser sincero, es una excelente manera de hacer que un compañero de trabajo vea y trabaje con expresiones LINQ y Lambda por primera vez (en realidad presenté un tutorial sobre LINQ / Lambdas a algunos ex compañeros de trabajo que usan esto y otros conjuntos de código, con gran efecto.) Sin embargo, el uso de estos requiere cierto conocimiento.

Recomiendo precaución, porque he visto casos en los que el refactorizador LINQ en realidad es significativamente peor de leer de lo que se foreachconvierte ese ciclo.

Andrew Gray
fuente
1

Subjetivamente, depende de la audiencia del desarrollador, si entienden las expresiones lambda, entonces;

List<String> filteredList = originalList.where(s => matches(s));

es más rápido de entender y quizás un poco más fácil. Me preocuparía más el uso de s, y coincidencias (). Tampoco es autodescriptivo, algo así como;

List<String> filteredList = 
    originalList.where(stringToBeTested => matchesNameTest(stringToBeTested));

O

List<String> filteredList = 
        originalList.where(originalListString => matchesNameTest(originalListString));

le da al desarrollador información más significativa y es más fácil de analizar, sin tener que sumergirse en la función coincidencias () para determinar qué coincidencia se está realizando.

La capacidad de mantenimiento no solo se trata de la capacidad de comprender el código, sino principalmente de la velocidad y precisión con la que se puede comprender el código.

AceCTO
fuente
2
Hola as Es un ejemplo, intencionalmente desprovisto de contenido semántico para resaltar la estructura.
C. Ross