Febrero de 2017
Volumen 32, número 2
Tecnología de vanguardia: inteligencia empresarial interna con eventos y CQRS
Por Dino Esposito | Febrero de 2017
Estaba hablando de algunas estructuras de alambre con un cliente recientemente para comprobar la eficacia de un proceso empresarial y la calidad general de la experiencia del usuario que el equipo estaba creando. En el sistema había algunos elementos de trabajo compartidos que los usuarios podían elegir y comenzar a procesar. La clienta era técnica general, pero todo lo que pudo visualizar fue una tabla de base de datos relacional con un registro que indicaba quién había seleccionado cada elemento y el estado actual del procesamiento.
No es necesario decir que una arquitectura similar haría indudablemente el trabajo. Con una arquitectura diferente basada en eventos, sin embargo, puede captar mucha más información sobre lo que ocurre en el sistema. La cuestión principal es, por tanto, la siguiente: ¿Es posible que su cliente necesite, ahora o en un futuro cercano, acceder a la información adicional que usted pueda obtener de los eventos, así como usarla?
En esta columna, continuaré donde lo dejé en la columna del mes pasado y agregaré un módulo de inteligencia empresarial (BI) a la aplicación de ejemplo relacionada con las salas de reuniones que se deben reservar. Actualmente, el término BI es una expresión en boga sobrecargada que suele asociarse a tecnologías y productos específicos. Fundamentalmente, BI hace referencia a un conjunto de técnicas para adquirir datos sin procesar y transformarlos en información útil disponible para que los analistas puedan mejorar los procesos o usarla como meras evidencias estadísticas.
Al agregar el abastecimiento de eventos a una aplicación, obtiene una percepción de los datos sin procesar. Al combinar el abastecimiento de eventos con CQRS, termina con los eventos empresariales sin procesar almacenados en la pila de comandos debidamente desnormalizada por el bien de las principales funciones de la aplicación. En cualquier momento, puede agregar un módulo adicional que lea datos sin procesar y los transforme en otros fragmentos de información significativos para cualquier propósito empresarial que pueda tener.
No se pierda nada
A la hora de resaltar las ventajas del abastecimiento de eventos, el primer punto que se suele mencionar es el siguiente: "Con los eventos, nunca se perderá nada de lo que ocurre en el sistema". No podría ser más cierto, aunque probablemente merece alguna explicación pragmática. Eche un vistazo a la Figura 1.
Figura 1 Se pueden crear varias proyecciones sobre los eventos sin procesar
En un sistema CRUD (crear, leer, actualizar y eliminar), se suele tener una representación de datos, principalmente relacional, y una o varias proyecciones simples que la mayor parte del tiempo solo adaptan los datos tabulares a las necesidades de la capa de presentación. Con el abastecimiento de eventos, este modelo se lleva mucho más lejos y la reducción del nivel de abstracción de los datos almacenados es un factor fundamental. Cuanta más información con el dominio exacto almacene, más numerosas y mejores serán las proyecciones que podrá crear en cualquier momento posterior.
En un sistema de software, las acciones del usuario son la unidad más pequeña de comportamiento que se puede observar y los eventos empresariales que se desencadenan con estas acciones son la porción de información más básica que se puede almacenar. En mi columna anterior (msdn.com/magazine/mt790196), usé el marco de MementoFX a través de NuGet para controlar y mantener de manera transparente los eventos importantes de la duración de los objetos agregados de dominio. También usé herramientas de sincronización especiales, denominadas desnormalizadores, para crear una proyección visualizable después de cada evento empresarial importante. Al final, toda la columna mostró que estaba reescribiendo un sistema CRUD de acuerdo con el patrón de evento-comando-saga (ECS). Veamos qué se necesita ahora para agregar otra proyección que llene la pantalla del panel de un administrador.
Creación de su propia capa de BI
En la Figura 2, puede observar la pantalla principal de la aplicación de ejemplo. Como mencioné anteriormente, este es un sistema de reserva para un recurso compartido, como un conjunto de salas de reuniones.
Figura 2 Interfaz de usuario del sistema de reservas de muestra
Como puede intuir a través de la figura, todos los usuarios permitidos en el sistema tienen la oportunidad de reservar una habitación y, posteriormente, cambiar o cancelar la reserva. En un sistema orientado a CRUD clásico, existe una tabla de reservas donde cada registro identifica una reserva. Al cambiar una reserva, la hora de inicio y la duración se sobrescriben y, al cancelarla, el registro se elimina simplemente. En cualquier momento, una consulta simple de registros devuelve el estado actual de las reservas. Si convierte un sistema CRUD simple en un sistema CRUD histórico (véanse las ediciones de mayo y junio de 2016 de esta columna en msdn.com/magazine/mt703431 y msdn.com/magazine/mt707524, respectivamente), puede realizar un seguimiento de un número fijo de eventos y guardarlos con cualquier información importante en otras tablas. Entonces, ¿de qué modo una solución de abastecimiento de eventos basada en MementoFX es preferible a un sistema CRUD histórico simple? Todo se basa en la flexibilidad del código y la resistencia del artefacto de software final.
Con MementoFX, se centra en el comportamiento y los eventos del dominio pertinente. Los objetos del dominio se modelan en torno a estas necesidades y se dejan ir. A cambio, tiene una API para consultar qué sucedió, el estado del sistema un día y a una hora determinados, y si tiene un registro de todos los eventos o solo datos sin formato agregados y transformados de alguna manera personalizada que tenga sentido para alguna finalidad empresarial ocasional. Este es el significado original previsto y la esencia de lo que la gente denomina BI.
Compilación de un registro de eventos simple
Con referencia a la aplicación de muestra, tiene una base de datos RavenDB que almacena todos los eventos sin procesar y una tabla de SQL Server no normalizada que contiene la lista de reservas pendientes. Los eventos almacenados comprenden el evento que creó una reserva y todos los eventos posteriores que cambiaron esa reserva a otra hora, e incluso los eventos que la cancelaron. Un evento cancelado deja de mostrarse en la interfaz de usuario principal, lo mismo que sucede con las posiciones intermedias a las que se cambió una reserva. Estos eventos no son importantes para la compilación de la interfaz de usuario principal, pero son fundamentales para compilar una interfaz de usuario de panel para un administrador.
Como ejemplo, vamos a ver qué se necesita para agrupar todas las reservas del sistema (o las reservas creadas en un intervalo de tiempo determinado) y mostrar el historial completo de cada una, como se muestra en la Figura 3.
Figura 3 Registro de eventos completo del sistema
El sistema cuenta 16 reservas pendientes, pero cada una de ellas consta de uno o más eventos. Por ejemplo, la reserva resaltada se creó inicialmente y luego se cambió dos veces a distintas posiciones con fechas diferentes.
Para producir una pantalla similar, debe consultar indudablemente todos los eventos del almacén de eventos y, luego, resolverlos para conseguir una forma que se ajuste a la interfaz de usuario deseada. El código de Razor que produjo la vista real recibió un modelo de datos como el siguiente:
public class BookingWithHistory
{
public BookingWithHistory()
{
History = new List<BookingHistory>();
}
public BookingSummary Current { get; set; }
public IList<BookingHistory> History { get; set; }
}
La clase BookingSummary representa el estado actual de una reserva determinada y es la clase que se encuentra detrás de la vista principal de la Figura 1.
public class BookingSummary : Dto
{
public Guid BookingId { get; set; }
public string DisplayName { get; set; }
public DateTime Day { get; set; }
public int StartHour { get; set; }
public int StartMins { get; set; }
public int NumberOfSlots { get; set; }
public BookingReason Reason { get; set; }}
Una instancia de esta clase se creó durante el proceso de desnormalización después de cada acción "crear" o "cambiar". Esta clase se mantiene y lee a través de Entity Framework hacia y desde una base de datos clásica de SQL Server. En otras palabras, esta clase es el elemento que forma la vista predeterminada del sistema en torno a la instantánea actual y actualizada del estado. Técnicamente, esta clase pertenece al modelo leído.
En su lugar, la vista que se obtiene en la Figura 3 recopila datos también de eventos sin procesar registrados en el almacén de eventos, un almacén RavenDB en el ejemplo. El fragmento de código siguiente muestra las consultas ejecutadas en el almacén de eventos para obtener todos los eventos de interés que se produjeron durante la reserva con el id. especificado:
var createdEvents = EventStore.Find<NewBookingCreatedEvent>(e =>
e.BookingId == bookingId).ToList();
var movedEvents = EventStore.Find<BookingMovedEvent>(e =>
e.BookingId == bookingId).ToList();
var deletedEvents = EventStore.Find<BookingCanceledEvent>(e =>
e.BookingId == bookingId).ToList();
La unión de estos eventos proporciona el historial completo de un agregado determinado. La reproducción de todos esos eventos (específicamente, la aplicación secuencial del estado de cada evento a una nueva instancia del objeto agregado) devuelve el estado actual del objeto con fines de visualización o procesamiento. No es necesario decir que puede agregar un filtro de fecha a la consulta sobre los eventos y recompilar así el estado del objeto de dominio (la reserva) hasta una fecha determinada.
Extrapolación de algunos datos empresariales
Pongamos que es un administrador responsable de los procesos internos. En su rol, quiere que los recursos compartidos, como una sala de reuniones, se usen de manera eficiente. ¿Cómo se puede comprobar esto y actualizar las directivas de reserva en consecuencia? En la Figura 4 se proporciona información útil para responder a esta pregunta.
El gráfico circular muestra cuántas reservas se crearon en el intervalo de tiempo y cuántas de ellas se movieron o cancelaron posteriormente. El gráfico de barras, en cambio, desglosa la misma información por semanas. Con un primer análisis aproximado, parece que cerca de la mitad de las reservas se cambiaron en algún momento y que aproximadamente una de cada cuatro llegó a cancelarse.
Si es un administrador con el objetivo de mejorar los procesos, los gráficos de la Figura 4 podrían activar una alarma. Lo mire como lo mire, el número de cambios después de realizar las reservas es considerable. ¿Impide esto que otros usuarios potenciales reserven habitaciones fácilmente? Para que la alarma deje de sonar, es posible que quiera echar un vistazo a la cobertura media de cada habitación en el mismo intervalo de tiempo. Si este gráfico de cobertura concreto no está todavía en el panel, pedir a los desarrolladores que lo agreguen no requerirá muchas horas de trabajo. Al final, se trata solo de escribir otro predicado para una consulta de estilo a LINQ:
var eventsByWeek = bookingStatuses.GroupBy(b => b.WeekDate).ToList();
foreach (var weekEvents in eventsByWeek)
{
var wr = new WeekActivityReport
{
StartOfWeek = weekEvents.Key,
TotalBookingCreated = weekEvents.Count(),
TotalBookingMoved = weekEvents.Count(b => b.Moved),
TotalBookingDeleted = weekEvents.Count(b => b.Deleted)
};
reports.Add(wr);
}
Figura 4 Informe gráfico de acciones de reserva en un intervalo de tiempo determinado
En concreto, la aplicación de ejemplo obtiene todos los eventos de todas las reservas del intervalo de tiempo especificado y los agrupa por semanas. A continuación, crea un objeto de informe de actividad semanal que resulta fácil de pasar posteriormente a ChartJS para crear gráficos deslumbrantes.
El aspecto más importante del abastecimiento de eventos que quiero destacar en esta columna es que, una vez que tenga la información sin procesar guardada en el nivel de abstracción más bajo posible, podrá usarla de muchas maneras distintas en muchos momentos diferentes. Basándose en la demostración de salas de reuniones, puede implementar el panel de administrador en una versión posterior o crear un producto completamente nuevo. También puede analizar todos los eventos de la duración de la aplicación y crear nuevas proyecciones de datos sobre esta para alcanzar los objetivos empresariales que se haya marcado. Más que nada, cualquier esfuerzo de desarrollo posterior es, en mayor parte, independiente de lo que tiene y su compilación no afecta a lo que ya tiene implementado. Ese es el retorno definitivo de todas las inversiones realizadas en la combinación de CQRS y el abastecimiento de eventos.
Resumen
El procesamiento de eventos empresariales en software no es nada nuevo. Probablemente, pueda conseguir resultados similares con un CRUD histórico (H-CRUD), simplemente un nombre extravagante para cualquier tipo de solución artesanal que le permita realizar un seguimiento de todos los estados diferentes de un objeto empresarial. El abastecimiento de eventos realiza el mismo trabajo, excepto en que funciona con un nivel de abstracción diferente y depende de herramientas personalizadas más eficaces (como los almacenes de eventos) y patrones (como al abastecimiento de eventos) en el contexto de las arquitecturas especializadas (por ejemplo, CQRS).
Llevo escribiendo sobre CQRS y el abastecimiento de eventos en MSDN Magazine bastante tiempo y, de algún modo, entendí que la mayoría de la gente está de acuerdo con la importancia de CQRS y de los eventos, pero no encuentra fácilmente un punto donde comenzar. A estas personas, les recomiendo volver a H-CRUD, que escribí en mayo (msdn.com/magazine/mt703431) y junio (msdn.com/magazine/mt707524), para luego volver a artículos más recientes sobre el patrón de ECS (también conocido como CQRS/ES) y de MementoFX. Esto debería ayudarle a comenzar partiendo de una mentalidad conocida y, luego, mejorarla progresivamente hasta alcanzar un punto en que realice sus antiguas tareas de una manera nueva y más eficaz.
Dicho esto, el software no tiene nada que ver con la magia ni la religión. El software tiene que ver con hacer cosas, preferiblemente de una manera que funcione para el cliente y para el equipo de desarrollo. Junto con los almacenes de eventos, los buses, los patrones de eventos y las arquitecturas, MementoFX ayuda a hacer las cosas de manera rápida y eficaz.
Dino Esposito es el autor de "Microsoft .NET: Architecting Applications for the Enterprise" (Microsoft Press, 2014) y "Modern Web Applications with ASP.NET" (Microsoft Press, 2016). Como experto técnico para las plataformas .NET y Android en JetBrains y orador frecuente en eventos internacionales del sector, Esposito comparte su visión sobre el software en software2cents.wordpress.com y en su Twitter @despos.
Gracias al siguiente experto técnico de Microsoft por revisar este artículo: Andrea Saltarello