¿Por qué la complejidad ciclomática es tan importante para un solo método?

10

Estoy usando SonarLint para Eclipse desde hace poco, y me ayudó mucho. Sin embargo, me planteó una pregunta sobre la complejidad ciclomática.

SonarLint considera aceptable un CC de 10, y hay algunos casos en los que estoy más allá, alrededor de 5 o 6 unidades. Esas partes están relacionadas con los mapeadores donde los valores se basan en diferentes variables, por ejemplo:

  • El campo A se basa en la cadena sA;
  • El campo B se basa en String sB;
  • El campo C se basa en String sC;
  • etc ...

No tengo otra opción que poner un ifpara cada campo. Esta no es mi elección (afortunadamente) sino un sistema ya existente y complejo que no puedo cambiar por mí mismo.


El núcleo de mi pregunta es: ¿por qué es tan importante no tener un CC demasiado alto en un solo método ? Si mueve algunas de sus condiciones en uno o más submétodos para reducir la complejidad, no reduce el costo de su función general, solo está moviendo el problema a otra parte, supongo.

(Perdón por pequeños errores, si los hay).


EDITAR

Mi pregunta no se refiere a la complejidad ciclomática global, sino solo a la complejidad del método único y la división de métodos (me cuesta explicar lo que quiero decir exactamente, lo siento). Me pregunto por qué es permisible dividir sus condiciones en métodos más pequeños si todavía pertenece a un 'súper método', que solo ejecutará cada submétodo, agregando así complejidad al algoritmo.

Sin embargo, el segundo enlace ( sobre el antipatrón ) es de gran ayuda.

Yassine Badache
fuente
^^^ La pregunta "punta de flecha" es probablemente un mejor duplicado en el sentido de que explica cómo mejorar su código, pero elegí el primero debido a una explicación detallada que responde a la parte de su pregunta sobre la complejidad ciclomática
mosquito
Dividir un método en partes más pequeñas no reduce la cantidad total de código ejecutado, pero deja en claro las tareas individuales que están sucediendo; cada uno puede entenderse mucho más fácilmente individualmente que cuando están enredados en un todo más grande. Como mínimo, elimina muchas variables intermedias de un solo uso del alcance más amplio.
Doval
1
Para su caso particular descrito, haría algo en su método principal como "A = extractAFrom (sA);" para cada campo Probablemente pueda encontrar mejores nombres, ya que conoce los campos reales y sus usos.
Tin Man

Respuestas:

32

Lo central aquí: "capacidad cerebral".

Verá, una de las principales funciones del código es ... ser leída . Y el código puede ser fácil de leer y entender; o duro

Y tener un CC alto simplemente implica muchos "niveles" dentro de un método. Y eso implica: usted, como lector humano, tendrá dificultades para comprender ese método.

Cuando lees el código fuente, tu cerebro automáticamente intenta poner las cosas en perspectiva: en otras palabras, intenta crear alguna forma de "contexto".

Y cuando tiene un método pequeño (con un buen nombre) que solo consta de unas pocas líneas y un CC muy bajo; entonces su cerebro puede aceptar fácilmente este "bloque". Lo lees, lo entiendes; HECHO.

Por otro lado, si su código tiene un CC alto, su cerebro gastará muchos "ciclos" más para deducir lo que está sucediendo.

Otra forma de decir eso: siempre debe inclinarse hacia la preferencia de una red compleja de cosas simples sobre una red simple de cosas complejas. Porque tu cerebro es mejor para entender cosas pequeñas.

GhostCat saluda a Monica C.
fuente
99
Entonces, ¿básicamente no se trata de cuestiones técnicas , sino de humanos ? Esto suena, de hecho, un poco inteligente, no sé cómo no lo había pensado antes. Gracias !
Yassine Badache
44
Si es así, le recomiendo sinceramente que adquiera "Clean Code" de Robert Martin (puede encontrar el pdf gratis en las redes). Verá, crear código legible es una de las virtudes más importantes pero a menudo ignoradas de un buen programador.
GhostCat saluda a Monica C.Dic
@YassineBadache CC también dificulta la prueba de todos los rincones (cobertura total).
Tulains Córdova
Este fue también el quid de la hoja de papel de Dijkstra .
Seth Battin
En mi experiencia, los errores casi siempre están en los métodos con un CC alto y cuando los errores están en un método de CC bajo, generalmente son totalmente obvios, no hay forma de que se oculten más allá de la primera ejecución del código. Además, encuentro que casi nunca tengo que modificar un método de baja CC: se quita más carga del cerebro.
Loren Pechtel
6

CC, como todas las demás reglas generales para los olores de código, es una heurística . No es un criterio a prueba de fallas que te diga una verdad absoluta. Si lo fuera, lo razonable sería simplemente hacer que tales métodos sean ilegales en el idioma y obligar a las personas a lograr sus fines de otra manera.

Pero esa no es la forma en que funcionan los indicadores. La mayoría de las veces su función es alertar a las personas de cosas de las que no eran conscientes. En su caso, sabe que la lógica es complicada y las soluciones alternativas la harían aún más complicada. Por lo tanto, no tiene sentido tratar de satisfacer la regla general primitiva, cuando su propósito principal es emitir advertencias a las personas que no son conscientes de que hay un problema.

Kilian Foth
fuente
2
Si "FieldA se basa en String sA" como indica OP, no estoy convencido de que mover esto a CalculateFieldA (String sA) genere un código más complicado.
Taemyr
2

En resumen: se trata de la legibilidad y, por lo tanto, de la mantenibilidad de su código.

Si tiene un método largo y complejo con muchos (anidados) if, se hace difícil saber qué hace realmente. Si extrae algunos métodos privados y los nombra de manera significativa, es mucho más fácil.

André Stannek
fuente
Si bien esta es una buena respuesta, es un poco corta. Sería bueno si pudieras dar un ejemplo de lo que estás diciendo y ser más específico con respecto a la pregunta formulada por OP: "¿por qué es tan importante no tener un CC demasiado alto en un solo método?".
Machado
2

La complejidad ciclomática de un método está relacionada con el número de casos de prueba requeridos para un método. Específicamente, una complejidad ciclomática de 10 significa que 10 es el límite superior para que los casos de prueba tengan una cobertura de ramificación total para su método. También está relacionado con la cantidad de rutas que se deben probar, menos las rutas imposibles.

Más allá de eso, estoy de acuerdo con las otras respuestas para otras consideraciones: la capacidad mental de un desarrollador o un indicador de posibles problemas o refactorización o una medida de legibilidad y facilidad de mantenimiento del código .

Thomas Owens
fuente
0

CC es solo una heurística, y cuán "malo" es un puntaje particular depende de muchas cosas.

Dicho esto, siempre debe ver un CC alto como algo que resalta el código que podría / debería ser refactorizado. Dices que mover la ifdeclaración a otro método está ocultando el problema, pero ¿hay un patrón allí que puedas abstraer en lugar de copiar pegando n veces? Si es una if-elsecadena larga , ¿puede convertirla en una declaración de cambio, o tal vez usar polimorfismo u otra cosa? Si hay una anidación profunda, ¿se pueden unir algunas de sus cláusulas condicionales o indica responsabilidades separadas que deberían dividirse en diferentes clases?

GoatInTheMachine
fuente
0

Veo la complejidad ciclomática como una advertencia. Si puede leer el código y no es demasiado complejo de entender, entonces no me preocuparía demasiado, probablemente haya cosas más importantes de las que preocuparse, siempre las hay.

Una forma de reducir el tipo de CC que menciona es usar polimorfismo, ya que ha etiquetado su pregunta con la etiqueta Java. Entonces, en lugar de que las rutas de código se escriban en cadena , puede usar clases bien nombradas. Esto puede ayudar, pero a veces es excesivo y puede hacer que su código sea aún más difícil de entender.

Sin embargo, puede ser una señal de código que será difícil de mantener. Al leer el método, ¿es fácil ver qué ruta de código va a seguir para cada caso? ¿Podría saltarse este método si no conoce bien la base del código y está buscando algo relacionado pero más adelante en el código? Sé que algunas personas abogan por dividir los métodos en muchos métodos de 1/2 línea con nombres descriptivos, pero a veces creo que es aún más difícil de leer que el código que debía reemplazar.

En última instancia, la mantenibilidad es un problema difícil y depende de usted decidir cuál cree que será más fácil de leer. El hecho de que esté pensando en esto significa que está en el camino correcto. Solo recuerde, el responsable de mantenimiento que tiene que intentar descifrar este código en años podría ser usted. Así que hazlo lo más fácil posible para ellos.

Encaitar
fuente
0

Se trata de cuánto tiempo se pasa mirando (ciclos cerebrales) el código y comprendiendo lo que está haciendo el código.

  • Considere un método de 10 líneas: probablemente tome unos minutos para comprender lo que está haciendo.
  • Considere un método de 100 líneas: probablemente tome una hora o más para comprender lo que está haciendo.
  • Considere un método de 1000 líneas: probablemente tome un día o más para comprender lo que está haciendo.

También los métodos más grandes son más difíciles de probar y más difíciles de predecir qué tipo de comportamiento podría ocurrir.

La complejidad ciclomática es una medida. En este caso, los valores más altos son indicadores de posibles problemas. El código complejo tarda más en comprender y probablemente no se pruebe tan a fondo como los métodos menos complejos. Por lo tanto, es importante tener en cuenta qué áreas del código son complejas con esta medida para fines de refactorización y mantenimiento.

Otra cosa a considerar es actualizar el código complejo. Al hacer el análisis, un desarrollador podría informar que cambiar el código es más o menos arriesgado al observar su complejidad.

Por lo tanto, existe un gran valor para medir la complejidad que se puede aprovechar y utilizar para la toma de decisiones.

Jon Raynor
fuente
1
Lo siento Ghost Cat responde muy similar, debería haber actualizado la página.
Jon Raynor