Dominando el desacoplamiento basado en eventos en Laravel
Tus controladores de Laravel a menudo se convierten en vertederos de lógica de negocio.
Empiezas con un flujo de registro sencillo. Pronto, añades notificaciones por correo electrónico, alertas de Slack, registros de auditoría y llamadas a API en un solo método. Esto crea un controlador pesado (fat controller).
Los controladores pesados hacen que tu código sea frágil. Son difíciles de probar. Rompen el Principio de Responsabilidad Única (Single Responsibility Principle).
No necesitas herramientas complejas como RabbitMQ para solucionar esto. Laravel tiene un sistema de eventos integrado que funciona para la mayoría de las necesidades.
El problema del acoplamiento fuerte: Si una API de boletines informativos es lenta, el registro de usuarios se ralentiza. Si un servicio de correo falla, toda la solicitud falla.
La solución: Arquitectura orientada a eventos.
Los eventos actúan como una capa intermedia. Tu controlador anuncia una acción. Los listeners reaccionan a esa acción de forma independiente.
Un controlador ligero se ve así:
public function register(RegisterRequest $request)
{
$user = User::create($request->validated());
UserRegistered::dispatch($user);
return response()->json(['message' => 'Success'], 201);
}
El controlador ahora solo se encarga de la persistencia de datos. No le importan los efectos secundarios.
Obtienes tres beneficios principales:
- Rendimiento: Los usuarios reciben una respuesta de inmediato. Las tareas pesadas se ejecutan en segundo plano utilizando la interfaz
ShouldQueue. - Resiliencia: Si un servicio está caído, el listener puede reintentar la tarea sin interrumpir la aplicación principal.
- Extensibilidad: Puedes añadir nuevas funcionalidades, como notificaciones push, añadiendo un nuevo listener. No tienes que tocar el controlador original.
Mejores prácticas a seguir:
- Enfócate en los efectos secundarios: Usa eventos para el post-procesamiento. No los uses para la lógica principal que debe ocurrir instantáneamente.
- Usa nombres descriptivos: Usa nombres en tiempo pasado como
OrderPlacedoUserRegistered. Esto indica que la acción ya ha ocurrido. - Evita la sobre-abstracción: Si un fragmento de código es sencillo y se usa en un solo lugar, una llamada a una función es mejor que un evento.
Usa Eloquent Observers para cambios en la base de datos. Usa Events para acciones de negocio.
Refactorizar hacia eventos es una cuestión de durabilidad. Hace que tu código sea más fácil de depurar y más rápido de probar.
Elige un efecto secundario ruidoso en tu controlador y muévelo a un listener hoy mismo.
Prueba este ejemplo en el sandbox: https://onlinephp.io/c/1f7b2