Saltar al contenido

El problema del código sin arquitectura

Trabajar en proyectos Laravel sin una arquitectura definida es una experiencia dolorosa. Controladores con miles de líneas, métodos imposibles de seguir, modelos inflados con responsabilidades que no les corresponden, y lo peor: la imposibilidad de explicar a un nuevo desarrollador dónde está cada cosa. Esta realidad es más común de lo que parece, especialmente ahora con la IA generando código que no revisamos adecuadamente.

Mi forma de abarcar cada proyecto es clara: busco soluciones simples, piezas pequeñas que cohesionen naturalmente dentro del proyecto. No necesito arquitecturas complejas ni sobre-ingeniería para tener código mantenible. Lo que necesito son patrones claros y organización consistente.

Filtros que permitan composición: El ejemplo perfecto

Los filtros en Laravel ilustran perfectamente este enfoque. En lugar de tener scopes gigantescos en los modelos o lógica de filtrado dispersa en controladores, creo clases independientes para cada filtro. Cada una tiene una única responsabilidad y utiliza el patrón Pipeline de Laravel.

Por ejemplo, un ActiveFilter puede ser compartido entre múltiples modelos, viviendo en una capa Shared. Un QueryFilter específico para categorías maneja búsquedas en sus columnas. Un SortFilter gestiona la ordenación. Todos implementan el mismo método handle con una closure, permitiendo su encadenamiento mediante Pipeline.

La magia está en la composición. Puedo crear un enum CategoryFilters que agrupe los filtros necesarios para un contexto específico. Una aplicación web puede usar ciertos filtros, mientras que una API móvil utiliza otros. Esta flexibilidad es imposible con código monolítico.

No te pierdas mi libro Filtros Escalables en Laravel.

ViewModels: Separando la presentación

Los ViewModels resuelven otro problema común: mezclar lógica de presentación con lógica de negocio. Son clases dedicadas exclusivamente a preparar datos para la interfaz, sea Blade, Vue, Inertia o una API.

Un ViewModel típico tiene métodos que se convierten en variables disponibles en la vista. Puede aplicar filtros mediante Pipeline, paginar resultados, formatear datos. Todo esto fuera del controlador y del modelo, manteniendo cada capa con su responsabilidad única.

El resultado en el controlador es limpio: tres o cuatro líneas que instancian el ViewModel y retornan los datos. Sin lógica de filtrado, sin transformaciones complejas, sin código que no debería estar ahí.

No te pierdas mi libro ViewModels en Laravel.

Actions: Una responsabilidad, un propósito

Las Actions son una parte muy importante de mi arquitectura. Una clase, una responsabilidad. CreateCategoryAction solo crea categorías. Si el proceso es complejo (crear registro, subir imagen, sincronizar con API, notificar), uso composición con Pipeline.

Cada paso del proceso se convierte en una clase independiente: CreateCategoryModel, UploadCategoryImage, SyncWithExternalAPI, NotifyAdmins. Todas reciben un passable que transporta la información entre etapas. Si algo falla, puedo manejarlo de diferentes maneras sin romper todo el flujo, todo depende de cada caso.

Las Actions reciben datos primitivos, arrays o modelos, nunca objetos complejos como Requests. Esto las hace reutilizables desde controladores, jobs, comandos, tests. Son piezas verdaderamente independientes.

No te pierdas mi libro Acciones en Laravel.

Modelos Eloquent organizados

Los modelos en Laravel tienden a convertirse en clases enormes: configuración, atributos, relaciones, scopes, eventos, lógica de negocio. Mi solución: separar responsabilidades sistemáticamente.

La configuración del modelo va en traits o clases de configuración. Los scopes y métodos de consulta adicional se definen todos en un Builder exclusivo para ese modelo. Los eventos se manejan mediante observers o listeners dedicados, aunque sinceramente, es algo que prefiero evitar en todos mis proyectos, ya que ocultan mucha información de lo que realmente pasa en mis modelos.

Resultado de todo lo anterior: El modelo final, el que está en app/Models, queda limpio, enfocado en su propósito principal: representar la entidad, pero con todo su potencial, aunque en pequeñas piezas que hacen la composición.

No te pierdas mi libro Modelos Eloquent Organizados.

Testing en pirámide

Esta arquitectura facilita el testing siguiendo la pirámide correcta. Muchos tests unitarios para cada pieza pequeña (filtros individuales, actions, procesos del pipeline). Tests funcionales para flujos completos. Pocos tests end-to-end para validar procesos críticos.

Cada clase pequeña es fácil de testear aisladamente. No necesito mocks complejos ni configuraciones elaboradas. El test de un filtro son 20 líneas. El test de una action, 30. Simple, directo, mantenible.

La importancia del inicio

Empezar un proyecto con esta organización es crucial. Es exponencialmente más difícil refactorizar un proyecto caótico que mantener uno bien estructurado desde el principio. No se trata de sobre-ingeniería anticipada, sino de establecer patrones claros que escalen naturalmente.

Cuando incorporas a alguien nuevo, puedes explicar: "Los filtros están aquí, las actions allá, los view models manejan la presentación". En minutos entiende la estructura. En proyectos caóticos, semanas después siguen perdidos.

El equilibrio perfecto

No necesitamos arquitecturas hexagonales completas, DDD estricto o CQRS para proyectos típicos de Laravel. Eso, en la mayoría de los casos es over-engineering. Lo que necesitamos son piezas pequeñas, bien organizadas, con responsabilidades claras.

Este enfoque escala naturalmente. Empiezas simple y añades complejidad solo donde se necesita. El código permanece legible, testeable y mantenible. Los nuevos desarrolladores se integran rápidamente. Los bugs se localizan fácilmente.

La clave está en la disciplina: mantener controladores delgados, modelos enfocados, y extraer responsabilidades a clases dedicadas. No es más trabajo, es trabajo más inteligente. El tiempo que "pierdes" creando estas estructuras lo recuperas multiplicado en mantenimiento, debugging y onboarding.

Mi experiencia en proyectos fallidos con controladores de miles de líneas me enseñó que el dolor de mantener código mal estructurado supera infinitamente el esfuerzo de estructurarlo bien desde el inicio. No se trata de ser purista, sino pragmático: código que funciona hoy y seguirá siendo mantenible durante varios años.


school Curso completo

Curso Laravel 12
Completo 2026

El único curso 100% actualizado que incluye Laravel 12, Livewire 3, Vue 3, React 19 e Inertia 2. Aprende con proyectos reales y las últimas funcionalidades.

access_time 8 horas de contenido
layers 4 tecnologías en 1
update 100% actualizado
code Proyectos prácticos
Ver Curso Laravel 12 arrow_forward

star Incluido en cualquier suscripción

Rutas de aprendizaje