Complejidad Ciclomática: Qué Mide y Por Qué Discrepan
Resumen
La complejidad ciclomática cuenta decisiones en una función: cada if, switch, while suma 1. El número '10' viene de NIST, pero ESLint usa 20, Microsoft 25. Lo que importa: una función con complejidad 6 puede ser ilegible, y una de 14 puede ser trivial. Tu herramienta mide caminos, no nesting, no contexto. Aprende cuándo confiar en el número y cuándo ignorarlo.
La complejidad ciclomática cuenta el número de caminos independientes a través de una función. Una función sin ramificaciones punúa 1. Agrega un if, se convierte en 2. Agrega un switch con cuatro cases, salta a 6. El número te dice cuántos casos de prueba necesitas para cubrir cada camino, y correlaciona con el tiempo que tarda un extraño en sostener la función en su cabeza.
Eso es toda la métrica. Lo que importa es qué equipos hacen con ella, y dónde se equivocan.
Qué Cuenta Realmente la Complejidad Ciclomática
McCabe la definió en 1976 como aristas menos nodos más dos, en términos de teoría de grafos. En la práctica, no necesitas la teoría de grafos. Cuenta los puntos de decisión: if, else if, case, while, for, catch, &&, ||, ternarios. Suma 1. Ese es el resultado.
def price(order):
if order.is_vip: # +1
if order.total > 100: # +1
return order.total * 0.8
return order.total * 0.9
elif order.has_coupon: # +1
return order.total * 0.95
return order.totalEsta función punúa 4. No es alto. Pero ya son tres niveles de ramificación para una función que comenzó como "aplicar un descuento". Ese es el patrón que vale la pena notar: la complejidad se cuela de un elif a la vez, y nadie es el villano.
De Dónde Viene el Umbral de "10" (Y Por Qué los Linters Discrepan)
El número que todos citan es 10. Viene de NIST Special Publication 500-235, donde McCabe y Watson escribieron que los límites superiores a 10 debería reservarse para equipos con personal experimentado, diseño formal, y un plan de prueba comprehensivo. En otras palabras: 10 es el default, no una ley.
Los linters no se ponen de acuerdo sobre dónde trazar la línea, y es importante saberlo antes de configurar una compuerta:
NIST SP 500-235: 10
ESLint
complexityrule: 20Microsoft CA1502: 25
Steve McConnell, Code Complete: 0-5 bien, 6-10 vigilancia, 10+ refactorizar
Rangos de referencia Carnegie Mellon: 1-10 simple, 11-20 más difícil de probar, 20+ difícil de comprender, 50+ imposible de mantener
Cuatro fuentes, cuatro números. Si tu compuerta de CI falla en 10 y el proyecto de un compañero se cierra en 25, ninguno de vosotros estás equivocados. Solo están midiendo contra tolerancias de riesgo diferentes. La documentación propia de Microsoft te guía por el razonamiento de NIST con más detalle si quieres la fuente en lugar del resumen.
Lo que realmente configuraríamos: 10-15 como línea de advertencia para código nuevo, 20 como el punto donde un PR obtiene una segunda mirada, 50 como un alto absoluto. Por debajo de 10, no gastes tiempo de revisión discutiendo sobre ello.
La Trampa: Una Puntuación Limpia No Significa una Función Legible
Aquí es donde los equipos se queman. Una función puede punuar 6 y ser genuinamente difícil de leer, y una función puede punuar 14 y ser trivial.
Toma un switch plano con diez cases, cada uno retornando una constante. Eso es una complejidad de 10, y la mayoría de ingenieros lo leen en quince segundos porque el patrón es obvio: entra una cosa, sale una cosa, no hay estado transportado entre branches. Ahora toma una función con tres bloques if anidados y un bucle que muta una variable compartida. Eso podría punuar 6, y le tomará a un ingeniero senior cinco minutos rastrearla, porque tienes que sostener toda la pila de llamadas en tu cabeza para saber qué rama estás realmente siguiendo.
La complejidad ciclomática mide caminos. No mide profundidad de anidamiento, alcance de variables, o qué tan lejos se encuentran una condición y su efecto en el archivo. Dos funciones con la misma puntuación pueden ser una lectura completamente diferente.
Hemos visto equipos tratar "bajo 10" como un proxy para "revisable", empujar un PR porque el linter estaba verde, y luego ver a un ingeniero junior perder una tarde dentro de esa misma función tres semanas después. La puntuación pasó. La lectura no se hizo más fácil.
Complejidad Ciclomática vs. Complejidad Cognitiva: Dos Preguntas Diferentes
SonarSource introdujo Complejidad Cognitiva en 2017 específicamente para cerrar esta brecha. La complejidad ciclomática responde "cuántos caminos tiene esta función." La complejidad cognitiva responde "cuán difícil es sostener esta función en mi cabeza", y lo hace penalizando el anidamiento más que la estructura plana.
Una instrucción switch apenas mueve la puntuación cognitiva. Un if anidado tres niveles profundos dentro de un bucle la mueve rápidamente, porque cada nivel de anidamiento agregado compone el costo mental del anterior. El propio escrito de SonarSource desglosa las reglas de puntuación si quieres implementarla tú mismo, y la mayoría de linters que soportan complejidad ciclomática ahora soportan complejidad cognitiva como una segunda regla separada.
Omite la complejidad cognitiva si tu equipo es lo suficientemente pequeño como para que todos ya sepan dónde viven las funciones desordenadas. Actívala en el momento en que tengas más de dos personas que no escribieron el código que están revisando, porque ese es exactamente el hueco que fue construida para cerrar.

Qué Hacen las Herramientas de Revisión de Código IA con Este Número (Y Qué Se Pierden)
GitHub Copilot code review, CodeRabbit, Qodo y Greptile todas surfacean señales de complejidad en un PR hasta cierto punto. Algunas marcan una función que cruzó un umbral. Algunas resumen "este PR aumenta complejidad en tres archivos". Casi ninguna te dice por qué eso importa para la persona que abrirá el archivo seis meses después sin contexto.
Esa es la brecha real. Una advertencia de complejidad en un PR es un número en un comentario. No le dice a un revisor si la rama agregada pertenece ahí, si duplica lógica en tres archivos de distancia, o si el arreglo correcto es una guard clause versus un pase de extract-method completo. Las herramientas IA son buenas contando. Aún no son buenas explicando la forma del desorden.
Lo que realmente cierra esa brecha en la práctica es emparejar el número con una pregunta que un humano aún tiene que responder: ¿esta función hace una cosa, o hace tres cosas envueltas en instrucciones if? Ningún linter responde eso por ti. Solo te dice dónde mirar.
Por Qué Esto Importa Más en un Repositorio de 100K LOC Que en un Proyecto Personal
En una base de código que escribiste solo, la complejidad es un problema de memoria que ya resolviste. Conoces las diez funciones enmarañadas por nombre, sabes por qué están enmarañadas, y las evitas sin pensar. Esa no es la situación en la que se encuentra la mayoría de esta audiencia.
En un repositorio compartido con cinco a cincuenta ingenieros, nadie sostiene el mapa completo. Una función que punúa 22 que el autor original entendía perfectamente se convierte, seis meses después, en una función que un ingeniero diferente tiene que reconstruir desde cero, usualmente bajo una fecha límite. Ya lo has hecho: grep por el nombre de la función, Ctrl+F a través del archivo, git blame las líneas sospechosas, luego mensaje a alguien que dejó el equipo hace ocho meses.
Este es también el lugar donde el número de complejidad comienza a interactuar con la búsqueda. Una función de alta complejidad es más difícil de resumir correctamente, lo que significa que es más difícil para un compañero, o una herramienta de búsqueda de código, describirla con precisión en una oración. Pregunta "¿qué hace esta función?" sobre una función de complejidad-4 y obtienes una respuesta limpia. Haz la misma pregunta sobre una función de complejidad-22 con cuatro branches anidadas y la respuesta honesta es "depende de qué camino estés preguntando." Esa ambigüedad es exactamente lo que ralentiza a un nuevo empleado el primer día, y es por eso que la complejidad vale la pena rastrear a nivel de repositorio, no solo como una advertencia de lint por PR.
El Costo Real Que Nadie Pone en la Métrica: Tiempo de Onboarding
Aquí está la parte que no aparece en un dashboard. Un ingeniero junior que se une a un equipo no experimenta "complejidad ciclomática de 23." Experimenta: abrí este archivo, no sé qué rama se ejecuta cuándo, y he estado leyendo durante cuarenta minutos.
Medimos esto vagamente a través de algunos ciclos de onboarding: las funciones con una puntuación de complejidad superior a 15 les tomaban a los nuevos empleados aproximadamente tres o cuatro veces más tiempo para explicar correctamente en un recorrido que las funciones que punúan bajo 8. No porque las funciones de alta complejidad hicieran más, sino porque rastrear qué rama se dispara bajo qué condición toma tiempo de lectura real y secuencial, y nadie lee correctamente un condicional anidado en el primer intento.
Este es donde la métrica se gana sus galones para equipos que onboardean a menudo. En realidad, no es un número de calidad de código. Es un proxy para "cuántos minutos le costará esto a la siguiente persona que no lo escribió." Rastrear así y la conversación del umbral se vuelve mucho menos abstracta.

Cómo Configurarla Sin Bloquear Tu Equipo
Mide antes de configurar. Elige uno:
Python:
radon cc -a -s .muestra cada función con una calificación de letra;radon cc -n c .filtra a calificación C y peor.JavaScript / TypeScript: regla de
complexityde ESLint, configura con['warn', { max: 15 }]para comenzar.Go:
gocyclo, apúntalo a un paquete e imprime cada función sobre un umbral.Java / C#: SonarQube o PMD, usualmente ya cableado en CI si tu equipo ejecuta cualquiera de los dos.
Ejecútalo una vez en todo el repositorio antes de activar la aplicación. Obtendrás una línea base, y probablemente algunas funciones en el rango de 40-más que son anteriores a cualquiera actualmente en el equipo. No bloquees la compilación en aquellas retroactivamente; eso solo enseña a las personas a enrutar alrededor del linter.
Configura código nuevo en 10-15. Marca cualquier cosa que cruce 20 para una segunda revisión, no un rechazo automático; algunas de esas funciones, como el switch plano, están bien. Trata cualquier cosa pasada 50 como un ticket de deuda técnica, no un comentario en alguien's PR.

El límite solo se mantiene si la cadena de herramientas la ejecuta de la misma manera cada vez. Una regla que se obtiene una vez para una fecha límite se obtiene para siempre.
¿Persigues la Puntuación o la Función?
Un equipo que configura duro en 10 y envía funciones planas, aburridas, fáciles de leer está en buena forma. Un equipo que configura duro en 10 y comienza a dividir funciones en cuatro funciones más pequeñas que se llaman entre sí en una cadena que nadie puede rastrear sin tres pestañas abiertas ha hecho el número mejor y la base de código peor.
La complejidad ciclomática es un detector de humo, no un extintor de incendios. Te dice dónde mirar. No te dice qué hacer una vez que estés ahí, y tratar la puntuación como el objetivo en lugar de la legibilidad que se supone debe representar es cómo los equipos terminan con un dashboard verde y un repositorio que aún le toma a un nuevo empleado tres semanas sentirse útil.