Hoy en día tenemos herramientas muy buenas para trabajar con Laravel de una forma mucho más profesional.
Podemos configurar análisis estático con PHPStan o Larastan, aplicar formateo automático con Laravel Pint, usar Rector para automatizar mejoras en el código, escribir tests con Pest, revisar calidad con SonarQube e integrar todo esto dentro de un flujo de CI/CD antes de desplegar a producción.
De hecho, este es prácticamente mi punto de partida ideal en un proyecto Laravel moderno.
En el curso Así arranco un proyecto Laravel en 2026 explico cómo configuro desde cero un proyecto con PHPStan, Rector, Pint, Pest Framework 4 y Laravel Boost.
Y en el curso Laravel 0 a producción: CI/CD multi-stage y multi-entorno llevo esa base un paso más allá, preparando un flujo real para automatizar validaciones, despliegues y entornos.
También he hablado de cómo añadir SonarQube a Laravel para analizar la calidad del código.
Pero hay una idea importante que conviene tener clara:
Que todas estas herramientas estén en verde no significa que tu aplicación no tenga deuda técnica.
Significa que tu código cumple una serie de reglas automatizables. Y eso está muy bien. Pero no todo lo importante en un proyecto se puede detectar con una regla.
Qué sí detectan estas herramientas
Herramientas como PHPStan, Rector, Pint o SonarQube nos ayudan muchísimo.
Pueden detectar errores de tipos, código muerto, problemas de estilo, complejidad excesiva, duplicación, posibles bugs, problemas básicos de seguridad o partes del código que se pueden modernizar.
También nos ayudan a mantener una base más consistente.
Un proyecto donde cada desarrollador formatea a su manera, donde no hay análisis estático, donde no se ejecutan tests y donde nadie mide nada, suele degradarse mucho más rápido.
Por eso creo que estas herramientas no son opcionales en proyectos serios.
El problema aparece cuando confundimos “el código pasa las herramientas” con “el código está bien diseñado”.
No es lo mismo.
La deuda técnica que no siempre se ve
Hay una deuda técnica más silenciosa.
No siempre rompe tests.
No siempre aparece en SonarQube.
No siempre hace fallar PHPStan.
No siempre puede arreglarla Rector.
Pero está ahí.
Y normalmente aparece en forma de malas decisiones de diseño.
Actions que hacen demasiado
A mí me gusta trabajar con Actions en Laravel.
Una acción debería representar una operación concreta del sistema. Por ejemplo:
CreateUserActionApproveDocumentActionEl problema aparece cuando una action empieza a crecer demasiado.
Por ejemplo, una CreateOrderAction que:
valida reglas de negocio
crea varios modelos
llama a una API externa
envía emails
lanza eventos
escribe logs
calcula permisos
decide el siguiente estado del pedido
Puede que PHPStan no se queje.
Puede que Pint la formatee perfectamente.
Puede que incluso tenga tests.
Pero esa action está acumulando demasiada responsabilidad.
La deuda técnica no está en que el código esté “mal escrito”.
Está en que esa clase se ha convertido en un punto donde todo acaba cayendo.
Jobs con lógica de negocio
Otro caso típico son los jobs.
Un job debería ejecutar una tarea en segundo plano. Pero muchas veces termina convirtiéndose en el caso de uso principal de la aplicación.
Por ejemplo:
ProcessPaymentJobY dentro encontramos validaciones, decisiones de negocio, cambios de estado, llamadas externas, notificaciones y persistencia.
El problema no es usar jobs.
El problema es esconder la lógica importante dentro de ellos.
Normalmente prefiero que el job delegue en una action o servicio de aplicación:
ProcessPaymentJob
-> handle()
-> ProcessPaymentActionAsí el job se encarga del contexto asíncrono, pero la lógica principal sigue estando en una pieza reutilizable, testeable y más fácil de razonar.
API Resources acoplados a demasiados contextos
Otro sitio donde se acumula deuda técnica en Laravel es en los API Resources.
Al principio solemos tener algo simple:
UserResourcePero con el tiempo empiezan los condicionales:
<?php
'is_admin' => $request->user()->isAdmin(),
'mobile_data' => $this->when($request->from_mobile, [
// ...
]),
'dashboard_info' => $this->when($request->for_dashboard, [
// ...
]),Y ese resource empieza a servir para todo:
panel de administración
SPA
app móvil
API pública
dashboard interno
El código puede funcionar.
Los tests pueden pasar.
PHPStan puede estar contento.
Pero el diseño empieza a ser frágil.
Cada cambio para una plataforma puede afectar a otra. Cada nuevo campo necesita más condicionales. Cada consumidor de la API empieza a depender de una estructura que ya no tiene un propósito claro.
Muchas veces es mejor separar recursos por contexto:
AdminUserResource
MobileUserResource
PublicUserResourceNo por capricho, sino porque cada consumidor tiene necesidades distintas.
Policies inconsistentes
Tener policies en Laravel no significa automáticamente tener bien resuelta la autorización.
La deuda aparece cuando las reglas están repartidas por toda la aplicación:
algo en una policy
algo en un controller
algo en una action
algo en un middleware
algo duplicado en frontend
El problema no es técnico en el sentido estricto.
El problema es de criterio.
Cuando alguien quiere saber si un usuario puede hacer algo, ¿dónde mira?
Si la respuesta no está clara, hay deuda técnica.
Tests que prueban implementación, no comportamiento
También podemos tener Pest perfectamente configurado y aun así escribir malos tests.
Un test puede estar en verde y no aportar demasiada confianza.
Por ejemplo, cuando testeamos demasiado la implementación:
$this->mock(CreateInvoiceAction::class)
->shouldReceive('execute')
->once();Esto puede tener sentido en algunos casos, pero si abusamos de este enfoque, acabamos probando que una clase llama a otra clase, no que el sistema se comporta correctamente.
Muchas veces es más útil comprobar el resultado real:
se ha creado la factura
el usuario correcto puede verla
se ha enviado la notificación
el estado ha cambiado
el evento esperado se ha producido
La deuda técnica no está solo en no tener tests.
También puede estar en tener tests que dificultan cambiar el código sin aportar demasiada seguridad.
La falsa tranquilidad del pipeline en verde
Un pipeline en verde es una buena señal.
Pero no es una garantía absoluta.
Significa que el proyecto ha pasado las reglas que hemos automatizado:
formato correcto
análisis estático correcto
tests correctos
calidad mínima aceptable
build correcto
despliegue correcto
Todo eso es muy importante.
Pero el pipeline no sabe si tus módulos están bien separados.
No sabe si tus actions tienen demasiadas responsabilidades.
No sabe si tu API está acoplada a tres clientes distintos.
No sabe si tus nombres expresan bien el dominio.
No sabe si una decisión que hoy parece cómoda dentro de seis meses será un problema.
Las herramientas ayudan, pero no sustituyen el criterio técnico.
Cómo reducir esta deuda técnica invisible
No hay una herramienta mágica para esto, pero sí hay hábitos que ayudan.
Revisar responsabilidades.
Una clase debería tener un motivo claro para existir.
Mantener pequeñas las actions.
Si una action empieza a hacer demasiadas cosas, probablemente necesita delegar.
Separar resources por contexto cuando tenga sentido.
No todos los consumidores necesitan la misma representación de los datos.
Evitar meter lógica de negocio importante en jobs, listeners o controllers.
Estas piezas deberían coordinar, no absorber todo el comportamiento del sistema.
Hacer code reviews arquitectónicos.
No revisar solo si el código está bien formateado, sino si la decisión tiene sentido.
Escribir tests de comportamiento.
Tests que validen qué hace el sistema, no solo cómo está implementado.
Y, sobre todo, aceptar que la calidad de un proyecto no depende únicamente de sus herramientas.
Depende también de las decisiones que tomamos cada día.
Conclusión
PHPStan, Rector, Pint, Pest, Laravel Boost, SonarQube y un buen flujo de CI/CD son una base excelente para cualquier proyecto Laravel moderno.
Yo los uso y los recomiendo.
Pero no eliminan toda la deuda técnica.
Eliminan una parte.
Hacen visible otra.
Y nos ayudan a prevenir muchos problemas.
Pero hay una deuda técnica que sigue dependiendo del diseño, la arquitectura y la experiencia del equipo.
Por eso, para mí, el objetivo no es solo tener el pipeline en verde.
El objetivo es tener una aplicación que siga siendo fácil de entender, modificar y mantener cuando el proyecto crece.
Porque un proyecto Laravel puede estar perfectamente formateado, pasar PHPStan, tener tests en verde y aun así estar mal diseñado.
Y esa es la deuda técnica más peligrosa: la que no aparece en rojo.
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.
star Incluido en cualquier suscripción