Cuando el código es un desastre, los desarrolladores dicen que parece espagueti. Pero ¿qué es exactamente el espagueti?
En el próximo Olor de código #2 continuaremos con el siguiente paquete.
¿Porque es largo? ¿Porque está desordenado?
Por ninguna de las dos razones. Espagueti se refiere al flujo de control.
Su significado original describe un estado en el que la ejecución se enreda como fideos y resulta imposible saber adónde saltará después.
El proceso de separar código con el flujo de control y las responsabilidades mezclados en un solo archivo continúa en Caso de aplicación de la separación de responsabilidades a un componente de 800 líneas.
Si seguimos el origen de esta expresión, llegamos a una carta publicada en 1968.
Una carta de Dijkstra
En marzo de 1968, Edsger Dijkstra publicó un texto breve en la revista de la ACM (Association for Computing Machinery, Asociación de Maquinaria de Computación de Estados Unidos) (Texto original).
El título era «Go To Statement Considered Harmful». Era una carta de dos páginas.
El título original de Dijkstra era «A Case Against the Go To Statement». El título provocador actual lo añadió el editor de entonces, Niklaus Wirth.
Ese formato acabó convirtiéndose en la expresión «○○ Considered Harmful», así que la intervención del editor llegó bastante lejos.
La idea central es esta: las personas leen código estático y reconstruyen mentalmente el proceso dinámico de ejecución.
Pero en un código con muchos goto, saber solo que «ahora se ejecuta esta línea» no permite explicar el estado del programa. No sabemos de dónde se llegó.
El código que usa únicamente ejecución secuencial, bifurcación condicional y repetición es diferente.
Puedes describir la posición de ejecución como coordenadas: «tercera iteración del bucle externo, rama verdadera del if interno».
goto destruye este sistema de coordenadas.
Esta afirmación también tenía respaldo teórico. Dos años antes, en 1966, Corrado Böhm y Giuseppe Jacopini demostraron que cualquier programa puede expresarse usando solo secuencia, selección y repetición (Artículo).
La matemática garantizaba así que era posible incluso sin goto.
La imagen creada por goto
Basta con ver qué aspecto tenía el código de entonces para entenderlo.
10 IF X > 100 THEN GOTO 70
20 IF X < 0 THEN GOTO 90
30 Y = X * 2
40 IF Y > 50 THEN GOTO 70
50 PRINT Y
60 GOTO 100
70 PRINT "TOO BIG"
80 GOTO 100
90 PRINT "NEGATIVE"
100 END
Incluso con diez líneas había que dibujar el flujo en papel para comprenderlo. Cada GOTO era una línea, y esas líneas se cruzaban arriba y abajo.
No es difícil imaginar qué ocurre cuando llegan a 500 líneas.
Así eran realmente los códigos BASIC y Fortran iniciales de las décadas de 1970 y 1980, y al conjunto resultante se le llamó espagueti.
goto desapareció, pero el espagueti permaneció
Aquí ocurre algo extraño. El código moderno casi no contiene goto.
Swift ni siquiera lo tiene. En los lenguajes que sí lo incluyen, su uso se ha reducido en gran medida a expresiones idiomáticas para volver a puntos de limpieza de recursos.
Sin embargo, la expresión código espagueti se usa cada vez más.
goto era solo una de las causas, no el síntoma en sí.
El problema real es que el lector no puede predecir el flujo, y el código moderno tiene muchas otras formas de producirlo.
Infierno de anidamiento. Un if dentro de otro if, luego un cierre y después otro if.
Como la indentación se profundiza en forma de flecha, se llama pirámide de la perdición. No salta como goto, pero es igual de difícil rastrear a qué línea se llega con cada combinación de condiciones.
Infierno de callbacks. Encadenar tareas asíncronas mediante callbacks hace que el orden de ejecución deje de coincidir con el orden del código.
Cuando leer de arriba abajo deja de ser el orden de ejecución, el sistema de coordenadas vuelve a desmoronarse.
// No se puede leer el orden de ejecución como orden del código
loadUser(id) { user in
loadProfile(user) { profile in
loadPosts(profile) { posts in
DispatchQueue.main.async {
self.render(posts) // En qué capa debe estar el manejo de errores?
}
}
}
}
Estado global. Si cualquier función puede cambiar una variable en cualquier momento, hay que revisar todo el proyecto para rastrear por qué su valor terminó así.
Por eso los singleton suelen estar en el punto de mira.
Sopa de eventos. A envía una notificación, B la recibe y cambia el estado, y C, que observaba ese estado, envía otra notificación.
Cada pieza es breve y limpia, pero el flujo global no está escrito en ninguna parte.
Es una forma habitual del código reactivo y, en cierto sentido, más difícil de rastrear que goto. El destino del salto no aparece en el código.
¿Se puede medir con números?
«Este código parece espagueti» es una afirmación subjetiva. Por eso, en 1976, Thomas McCabe propuso una métrica llamada complejidad ciclomática (Cyclomatic Complexity) (Artículo).
El cálculo es sencillo: dibuja el flujo de control del código como un grafo y cuenta cuántas rutas independientes hay.
En la práctica se aproxima sumando uno al número de puntos de bifurcación. Cada if, for, while, case, && y ?? añade aproximadamente uno.
Existe la convención de que, si el valor supera 10, ha llegado el momento de dividir la función. McCabe también presentó este número como un límite superior razonable, no como un estándar absoluto.
En la práctica, una función que enumera 20 casos con un solo switch supera una complejidad de 20, pero puede ser fácil de leer.
La regla cyclomatic_complexity de SwiftLint mide un valor parecido.
Sin embargo, SwiftLint solo cuenta if, guard, for, while, repeat, case y catch, y no cuenta && ni ??. El umbral de advertencia predeterminado es 10.
Actívala en el proyecto y esa función que crecía silenciosamente acabará siendo detectada.
La réplica de Knuth
Si terminamos esta historia con «Dijkstra ganó», solo conoceremos la mitad.
En 1974, Donald Knuth presentó una réplica en un extenso artículo titulado «Structured Programming with go to Statements» (Artículo).
La idea era que goto no es malo por sí mismo. Hay situaciones, como salir de bucles anidados de una vez, en las que usar goto hace el flujo más claro.
Si intentas eliminarlo a la fuerza creando una variable bandera booleana y añadiendo condicionales, el código resultante será peor.
La conclusión de los lenguajes actuales se parece a un compromiso: eliminar los saltos ilimitados, pero ofrecer sintaxis específica para los patrones frecuentes.
break, continue, break label con etiquetas, y defer y guard de Swift son ejemplos.
// guard: Elimina las excepciones desde arriba y mantén el cuerpo plano
func process(_ data: Data?) throws -> Packet {
guard let data else { throw ParseError.empty }
guard data.count > headerSize else { throw ParseError.tooShort }
// A partir de aquí, todas las condiciones ya están resueltas
return try decode(data)
}
guard se parece a que el patrón goto cleanup de la época de C se consolidara como una función del lenguaje. Fija el destino del salto en un único lugar y le asigna un nombre.
Resumen
- El código espagueti no es código desordenado, sino código cuyo flujo de control no se puede predecir.
- El punto de partida fue la carta de Dijkstra de 1968, cuyo argumento central era que «hay que poder describir la posición de ejecución como coordenadas».
gotodesapareció, pero el anidamiento profundo, los callbacks anidados, el estado global y las cadenas de eventos vuelven a crear el mismo problema.- Puede medirse de forma aproximada con complejidad ciclomática, y alrededor de 10 es una línea de advertencia habitual.
- Como sostuvo Knuth, el objetivo no es erradicar
goto, sino lograr que el flujo sea predecible.guardyasync/awaitson mecanismos del lenguaje que protegen ese objetivo.
En el próximo artículo veremos código roto en la dirección opuesta. El flujo es muy ordenado, pero para añadir un valor hay que modificar siete archivos.
Es código lasaña.
Seguir leyendo
Fuentes y verificación
- Go To Statement Considered HarmfulEdsger W. Dijkstra Archive · Fuente original del autor · Consultado 17 de agosto de 2026Respalda: La crítica de goto en 1968 y el problema de inferir el flujo de control
- Flow Diagrams, Turing Machines and LanguagesCorrado Böhm·Giuseppe Jacopini · Artículo de investigación · Consultado 17 de agosto de 2026Respalda: La expresividad de las estructuras secuenciales, de selección y de repetición en 1966
- A Complexity MeasureThomas J. McCabe · Artículo de investigación · Consultado 17 de agosto de 2026Respalda: La definición de complejidad ciclomática y los grafos de flujo de control de 1976
- Structured Programming with go to StatementsDonald E. Knuth · Artículo de investigación · Consultado 17 de agosto de 2026Respalda: La programación estructurada y el papel limitado de goto en 1974

![Imagen de portada de [Olor de código #1] ¿Por qué el código espagueti es espagueti?](/assets/images/posts/a1c72f38-347f-4ee2-8e53-9a021038d44f/spaghetti-code-1.jpg)