En una revisión de código aparece esta situación: abres el archivo y todas las funciones tienen cinco líneas o menos.
Este artículo continúa el anterior Olor de código #2.
Los nombres son buenos y cada clase tiene una sola responsabilidad. No hay nada que señalar.
Pero nadie puede responder de inmediato a la pregunta: «¿Qué ocurre al pulsar este botón?».
Este código se denomina código ravioli (Ravioli Code) (Texto original de C2).
No siempre era un insulto
Curiosamente, el término no siempre se usa de forma negativa. Los raviolis son pasta formada por pequeñas piezas que envuelven bien el relleno.
Son pequeños objetos bien encapsulados, justo lo que perseguía la orientación a objetos. De hecho, a veces se presenta el ravioli como lo opuesto al código espagueti.
El problema es la cantidad.
Cada pieza es perfecta, pero hay 200 en el plato y en ningún sitio se indica en qué orden ni cómo se conectan.
Concretamente, tiene este aspecto.
final class CheckoutCoordinator {
func start() { validator.validate(cart) }
}
final class CartValidator {
func validate(_ cart: Cart) { stockChecker.check(cart.items) }
}
final class StockChecker {
func check(_ items: [Item]) { priceCalculator.calculate(items) }
}
final class PriceCalculator {
func calculate(_ items: [Item]) { paymentPreparer.prepare(items) }
}
// ... Hay dieciséis clases más como esta
Cada clase es impecable. Tiene un nombre preciso y hace una sola cosa.
Pero no existe ningún archivo que conozca todo el flujo de pago.
El flujo solo existe en las relaciones de llamada entre clases, y solo se descubre conectando el depurador, no leyendo el código.
Por qué se divide demasiado
Cuando se acepta «cuanto más corta sea una función, mejor» como regla.『Clean Code』llega a decir que una función debe tener dos o tres líneas, o cuatro como máximo.
El objetivo real de este consejo se acerca a hacer que una función trate un solo nivel de abstracción. Al convertirlo en un número de líneas, se pierde el propósito.
El resultado son treinta funciones de cinco líneas, de las que veintiocho solo se llaman desde un lugar.
Cuando el nombre no resume el contenido., handleUserAction, processData y updateState no explican qué hacen.
Si divides el código en funciones con esos nombres, el lector debe abrir el cuerpo y aumenta el número de lugares que debe consultar.
Una buena extracción evita mirar el cuerpo; aquí ocurre lo contrario.
Cuando se mezclan niveles de abstracción. En una función conviven una frase de política como «validar el pedido» y otra de detalle como «incrementar el índice en 1». La mirada sube y baja continuamente.
Si divides sin criterio en este estado, creas fragmentos con niveles desordenados.
Cuando extraes código usado una sola vez pensando en reutilizarlo. Es la misma mentalidad que crea código lasaña; solo cambia la dirección, de vertical a horizontal.
El coste aparece en el número de saltos
El coste del código ravioli se resume en una frase: ¿cuántas veces abres un archivo para responder una pregunta?
Al leer código, las personas mantienen el flujo en la memoria a corto plazo. Se difumina al superar tres o cuatro elementos.
Después de saltar seis veces entre archivos, se pierde qué buscabas al principio y vuelves al inicio.
Cuando se repite, resulta más rápido ejecutar el código para comprobarlo que leerlo.
También aparecen efectos secundarios.
- Al añadir una función, no encuentras el fragmento existente y creas otro parecido. Los duplicados aumentan silenciosamente.
- Como no encuentras dónde corregir el error, añades un arreglo temporal al final del flujo, es decir, en la pantalla.
- Como el flujo completo no está escrito en el código, solo queda en la documentación o en la cabeza de alguien. Cuando esa persona se va del equipo, desaparece con ella.
Cómo recuperar el flujo
Crea un lugar donde escribir el flujo. Es la medida más eficaz.
Añade una función que muestre de un vistazo el orden completo y haz que solo describa ese orden.
func checkout(_ cart: Cart) async throws -> Receipt {
try validate(cart)
try await reserveStock(cart.items)
let amount = calculateTotal(cart)
let payment = try await charge(amount)
return try await confirm(cart, payment)
}
Los detalles siguen en sus respectivos lugares. Lo que cambia es que el flujo queda escrito en una sola pantalla.
A veces estas funciones se llaman orquestadores. Eso es exactamente lo que le falta al código ravioli.
**Mantén un solo nivel por capa.**Las cinco líneas de la función superior son frases del mismo nivel. Si entra una condición detallada como items.count > 0, se rompe el nivel.
Acostumbrarse a comprobar si las frases están al mismo nivel al leer una función resulta más útil que usar un criterio de división.
**Decide si extraer por el nombre.**El criterio no es el número de líneas, sino esta pregunta: «¿El nombre de este fragmento comunica más que el cuerpo?».
Extraer if user.age >= 19 como isAdult(user) revela la intención y aporta valor. Extraer array.append(item) como addItem no aporta nada.
**Mantén cerca lo que está cerca.**El código que cambia junto debe estar en el mismo archivo y carpeta.
Si, por respetar la convención de un tipo por archivo, separas tipos que siempre se abren juntos, la proximidad importa más que la convención.
**El mismo criterio se aplica a los servicios.**Una división excesiva de microservicios se denomina nanoservicios.
Una arquitectura que atraviesa doce servicios para procesar una petición es código ravioli extendido más allá de la red. Aquí al coste de los saltos se suman la latencia y los puntos de fallo.
Lasaña, ravioli y espagueti
Al ponerlos juntos, se resumen así.
| Forma | Estado de los fragmentos | Problema |
|---|---|---|
| Espagueti | Grande y enredado | No se puede predecir el flujo de ejecución |
| Lasaña | Capas verticales | Un cambio atraviesa varias capas |
| Ravioli | Pequeño y limpio | El flujo entre fragmentos no aparece en ningún sitio |
Los tres tienen un alto coste para comprender el conjunto; solo cambia el método.
Si mides la calidad del código solo por la belleza de cada fragmento, no detectarás la lasaña ni el ravioli. Ambos sacan la máxima puntuación por fragmento.
Resumen
- El código ravioli tiene tantos fragmentos pequeños y limpios que nadie puede explicar el flujo completo.
- También se usó de forma positiva para referirse a código bien encapsulado. El problema es la cantidad.
- Las causas principales son las reglas de líneas, los nombres ambiguos y los niveles de abstracción mezclados.
- La clave de la solución es un lugar donde escribir el flujo.
- El criterio de extracción no es la longitud, sino el nombre. Extrae solo cuando el nombre comunica más que el cuerpo.
La próxima entrega es el extremo opuesto: no hay demasiados fragmentos, sino uno solo.
Veremos el objeto Dios que conoce toda la aplicación desde una única clase.
Fuentes y criterios de verificación
- Ravioli Code — C2 Wiki · texto original del autor · verificado 2026-08-17 · fundamento: metáfora del código ravioli como objetos pequeños y encapsulados excesivamente fragmentados

![Imagen de portada de [Olor de código #3] Código ravioli: código cuyo flujo nadie conoce](/assets/images/posts/6faf8840-1640-4930-a94c-3ed202b71075/ravioli-code-disconnected-objects.jpg)