Pruebas y calidad de código

[Code Smell #2] Código lasaña: por qué corregir siete archivos por un campo

El código lasaña es aquel en el que añadir un campo obliga a modificar siete archivos, aunque las capas estén bien separadas. Resume por qué aumentan las capas, dónde aparecen los costes y cuándo conviene conservarlas o eliminarlas.

7 min de lectura
Imagen de portada de [Code Smell #2] Código lasaña: por qué corregir siete archivos por un campo

El código espagueti del artículo anterior tenía el flujo entrelazado. Entonces, ¿ordenar perfectamente el flujo lo convierte en buen código?

Este contenido continúa el artículo anterior Code Smell #1.

No necesariamente.

Separas las capas, haces que cada una llame solo a la inferior y marcas los límites con interfaces, pero el código sigue convirtiéndose en algo que nadie quiere tocar.

Código que obliga a modificar siete archivos para mostrar un solo campo de texto. Se llama código lasaña (Lasagna Code) (Original de C2).

Código con capas apiladas limpiamente

Es exactamente lo que indica el nombre. La lasaña se prepara apilando pasta y salsa en capas.

La sección transversal es ordenada y las capas están claras. El problema es que no puedes sacar una sola capa.

Veamos un caso típico. Se añade el campo nickname a los datos de usuario que devuelve el servidor y hay que mostrarlo en pantalla.

1. UserDTO            — Añadir un campo a la estructura de respuesta del servidor
2. UserMapper         — DTOAñadir una línea al código que lo convierte en el modelo de dominio
3. User               — Añadir una propiedad al modelo de dominio
4. UserRepository     — Modificar esto también si cambia la firma del protocolo
5. FetchUserUseCase   — Solo pasa por aquí, pero el tipo obliga a modificarlo
6. UserViewModel      — Convertirlo de nuevo en el modelo de pantalla
7. ProfileView        — Por fin, mostrarlo

Desde el DTO (Data Transfer Object, objeto de transferencia de datos) hasta la pantalla, la misma cadena se almacena en tres tipos distintos.

De los siete archivos, ¿en cuántos se toma realmente una decisión? Normalmente en uno o dos.

El resto solo pasa el valor sin modificarlo.

Estas capas se denominan capas de paso (pass-through layer).

En la literatura de patrones de arquitectura, el estado en que una solicitud atraviesa capas sin procesamiento también se denomina antipatrón del sumidero. Es el síntoma central del código lasaña.

Por qué ocurre

Nadie lo hace con malas intenciones. De hecho, suele ser justo lo contrario.

Las capas aumentan principalmente porque se aplican buenos consejos fuera de contexto.

Cuando «separa las capas» se toma como una regla. Se ve un diagrama de Clean Architecture y se crean tantas carpetas como círculos.

El diagrama no establece cuántas capas debe haber. Representa el principio de que las dependencias deben apuntar solo hacia dentro (Presentation-Domain-Data Layering).

Pero al trasladarlo a la estructura de carpetas, el significado cambia.

Cuando «depende de abstracciones, no de implementaciones» se aplica a todo. Aparecen muchos protocolos con una sola implementación.

UserRepositoryUn protocolo y UserRepositoryImpluna implementación. El protocolo solo añade un salto de código.

Es útil si el objetivo es insertar una implementación falsa en las pruebas, pero sin ese plan solo has añadido otra capa.

Cuando se prepara todo para «poder cambiarlo más adelante». Se abstrae la base de datos por si cambia y se añade otra envoltura por si cambia el servidor.

Este es exactamente el punto que advierte YAGNI (You Aren’t Gonna Need It).

Cuando el equipo crece y se divide en capas. Como dice la ley de Conway, la estructura de comunicación de la organización queda grabada directamente en la arquitectura.

Con cuatro equipos, es fácil acabar con cuatro capas, cuyos límites siguen a las personas más que a las necesidades técnicas.

Diagrama de la ruta de modificación de siete capas, del DTO a la pantalla, al añadir un campo
Los recuadros rojos son capas de paso que no toman decisiones

De dónde sale el coste

Veamos concretamente qué tiene de malo contar con muchas capas.

El coste de cambio crece con el número de capas. Un campo implica siete archivos. Lo más preocupante es que los desarrolladores intentan evitarlo.

En lugar de pasar por todas las capas, aparece el atajo de llamar directamente a la API desde el ViewModel.

Cuando cuesta seguir las reglas, aparece código que las evita. Al final las capas permanecen y el flujo se convierte en espagueti. La lasaña engendra espagueti.

Leer se vuelve costoso. Para saber de dónde viene un valor, hay que seguir las capas.

Cada capa es breve y clara, pero después de siete saltos olvidas cuál era la pregunta inicial.

La depuración se ralentiza. El stack trace se alarga y encontrar la capa donde se corrompió el valor exige poner puntos de interrupción en cada una.

Las compilaciones se ralentizan. Especialmente si las capas están divididas en módulos. Cada cambio en una capa inferior recompila todas las superiores.

Cuándo hacen falta capas y cuándo no

Eso no significa que debas eliminarlas. Necesitas criterios para decidir.

Una pregunta suele funcionar bien.

«¿Esta capa toma alguna decisión o solo pasa algo?»

Decidir significa transformar, validar, bifurcar o combinar. Un mapper que convierte una cadena de fecha del servidor en Date toma una decisión.

Un repositorio que usa la caché si existe y la red en caso contrario también decide. En cambio, un UseCase que recibe parámetros y los reenvía sin cambios no decide nada.

Otro criterio es el motivo del cambio. El formato de respuesta del servidor y las reglas de presentación cambian por motivos distintos.

Por eso merece la pena separar DTO y modelo de pantalla. Si el modelo de dominio y el de pantalla siempre cambian juntos, no hay motivo para separarlos.

Resumido en una tabla:

Situación ¿Conviene crear una capa?
El formato externo y el modelo interno evolucionan por separado Sí
Existe un plan real para cambiar la implementación Sí
Se necesita una implementación falsa en las pruebas Sí
La escala exige reflejar los límites del equipo en el código Depende
Solo existe una implementación y seguirá siendo así No
Solo recibe y reenvía valores sin cambios No
Se creó porque el diagrama tenía esa capa No
Imagen que compara capas que transforman valores con capas de paso
Si transforma, es una capa; si solo pasa el valor, es ruido

Cómo eliminar capas

El orden aproximado para tratar una lasaña ya apilada es el siguiente.

Busca primero las capas de paso. Si el cuerpo del método tiene una línea y esa línea llama a un método con el mismo nombre en otro objeto, es candidata.

Buscar este patrón en todo el proyecto produce rápidamente una lista.

Cuenta las implementaciones. Comprueba cuántas implementaciones tiene cada protocolo. Si solo hay una y tampoco se usa en pruebas, elimina el protocolo y usa directamente el tipo concreto.

Conviene no justificarlo por rendimiento. any UserRepositoryAl llamar mediante el mismo tipo existencial, sí se pasa por una witness table.

Pero si usas el protocolo como restricción genérica, se especializa y ese coste desaparece. En cambio, una clase que no es final sigue usando despacho dinámico por defecto incluso al llamarla por su tipo concreto.

Además, en una llamada de repositorio que cruza la red o la base de datos, esta diferencia no aparece en las mediciones.

El motivo para eliminar un protocolo no es el rendimiento, sino el número de saltos.

Fusiona tipos. Si un DTO y un modelo de dominio tienen los mismos campos y siempre cambian juntos, usa uno solo.

Algunos consideran contaminación añadir Codable directamente al modelo de dominio. Pero primero hay que evaluar cuándo esa contaminación se convierte en un problema.

Fúndelo dentro de una sola capa. Si eliminarla resulta difícil, conserva la capa y fusiona los archivos.

Poner el protocolo y la implementación en el mismo archivo ya reduce el número de saltos.

Resumen

  • El código lasaña tiene tantas capas que incluso un cambio pequeño exige modificar varios archivos.
  • Normalmente no surge por escribir mal código, sino por aplicar buenos consejos fuera de contexto.
  • El síntoma clave es la capa de paso: una capa que no decide nada y solo reenvía valores.
  • Hay dos criterios: si la capa toma decisiones y si cambia por un motivo distinto al de las demás.
  • Cuando cuesta seguir las reglas, aparecen atajos. Con demasiadas capas, el espagueti acaba creciendo junto a ellas.

El próximo artículo trata los casos en que el problema no son las capas, sino las piezas. Veremos el código ravioli: todas las clases son pequeñas y están bien encapsuladas, pero nadie puede explicar el flujo completo.

Fuentes y criterios de verificación

  • Lasagna Code — C2 Wiki · original del autor · verificado 2026-08-17 · base: la metáfora del código lasaña y el problema de las capas excesivas
  • Presentation-Domain-Data Layering — Martin Fowler · original del autor · verificado 2026-08-17 · base: propósito de separar capas y límites de cambio

Seguir leyendo