Implementando Event Sourcing Simplificado con Projections en PHP
Event Sourcing es un patrón de arquitectura donde el estado de una aplicación no se guarda directamente, sino que se registra una secuencia de eventos. Reconstruir el estado actual implica reproducir estos eventos. Este post explora una implementación simplificada en PHP, centrándonos en el uso de "projections" para crear vistas de datos optimizadas para consultas.
<?php
// Interfaz para un Evento
interface Event {
public function getType(): string;
public function getData(): array;
}
// Clase abstracta para un Evento base
abstract class BaseEvent implements Event {
protected array $data;
protected string $type;
public function __construct(array $data) {
$this->data = $data;
}
public function getType(): string {
return $this->type;
}
public function getData(): array {
return $this->data;
}
}
// Ejemplo de un Evento concreto: UsuarioCreado
class UsuarioCreado extends BaseEvent {
protected string $type = 'usuario.creado';
}
// Interfaz para una Proyección
interface Projection {
public function project(Event $event): void;
public function getState(): array;
}
// Ejemplo de una Proyección: Listado de Usuarios
class ListadoUsuariosProjection implements Projection {
private array $usuarios = [];
public function project(Event $event): void {
if ($event->getType() === 'usuario.creado') {
$this->usuarios[] = $event->getData();
}
}
public function getState(): array {
return $this->usuarios;
}
}
// Clase para el Event Store (simplificado - en memoria)
class EventStore {
private array $events = [];
private array $projections = [];
public function append(Event $event): void {
$this->events[] = $event;
foreach ($this->projections as $projection) {
$projection->project($event);
}
}
public function attach(Projection $projection): void {
$this->projections[] = $projection;
// Inicializar la proyección con eventos existentes (opcional para simplificar)
// foreach ($this->events as $event) {
// $projection->project($event);
// }
}
public function getEvents(): array {
return $this->events;
}
}
// Ejemplo de uso
$eventStore = new EventStore();
$listadoUsuarios = new ListadoUsuariosProjection();
$eventStore->attach($listadoUsuarios);
$eventStore->append(new UsuarioCreado(['id' => 1, 'nombre' => 'Alice']));
$eventStore->append(new UsuarioCreado(['id' => 2, 'nombre' => 'Bob']));
$usuarios = $listadoUsuarios->getState();
print_r($usuarios);
?>
Este ejemplo demuestra los componentes básicos de Event Sourcing con Projections. Un Event
representa algo que ocurrió en el sistema. Una Projection
consume eventos y mantiene una vista específica de los datos. El EventStore
almacena los eventos y aplica cada evento a las proyecciones adjuntas. En un escenario real, el EventStore
persistiría los eventos en una base de datos (ej. una base de datos de tipo log como Kafka) y las proyecciones se ejecutarían de forma asíncrona para mantener el rendimiento de la aplicación.
<?php
// Una posible mejora sería agregar un "EventDispatcher" para desacoplar la aplicación
// del EventStore y permitir el manejo de eventos de forma asíncrona.
interface EventDispatcher {
public function dispatch(Event $event): void;
public function subscribe(string $eventType, callable $handler): void;
}
class SimpleEventDispatcher implements EventDispatcher {
private array $subscribers = [];
public function dispatch(Event $event): void {
$eventType = $event->getType();
if (isset($this->subscribers[$eventType])) {
foreach ($this->subscribers[$eventType] as $handler) {
$handler($event);
}
}
}
public function subscribe(string $eventType, callable $handler): void {
if (!isset($this->subscribers[$eventType])) {
$this->subscribers[$eventType] = [];
}
$this->subscribers[$eventType][] = $handler;
}
}
?>
En conclusión, Event Sourcing con Projections ofrece una forma poderosa de manejar el estado de la aplicación y construir vistas de datos optimizadas. La implementación presentada aquí es una simplificación, pero sirve como punto de partida para comprender los conceptos fundamentales y explorar implementaciones más robustas utilizando bases de datos de eventos y colas de mensajes.
No hay comentarios:
Publicar un comentario