Mayo de 2016

Volumen 31, número 5

Tecnología de vanguardia: creación de un CRUD histórico

Por Dino Esposito | Mayo de 2016

Dino EspositoLas bases de datos relacionales existen desde la década de los 70, y algunas generaciones de desarrolladores iniciaron y terminaron sus carreras sin aprender, o incluso sin considerar ligeramente, una estrategia alternativa para el almacenamiento de datos. Recientemente, las redes sociales importantes han proporcionado claras evidencias de la incapacidad de las bases de datos relacionales de servir a todos los escenarios empresariales posibles. Si se encuentra con una cantidad (realmente) enorme de datos sin esquema, las bases de datos relacionales podrían convertirse en ocasiones en un cuello de botella en lugar de en una canalización.

¿Puede imaginar lo que podría tardar en contar al instante los me gusta de un comentario que sus amigos han realizado en una publicación en una base de datos relacional generalizada con un total de varios miles de millones de registros? Por no hablar del reto que supone restringir la definición de una publicación en un esquema rígido. Por una mera cuestión de supervivencia empresarial, las redes sociales evolucionaron en algún punto y cambiaron su foco de almacenamiento por una combinación de almacenes de datos relacionales y no relacionales, abriendo así oficialmente el negocio de los datos políglotas.

La lección fundamental aprendida de la arquitectura de software de las redes sociales es que, en ocasiones, su almacenamiento convencional de los datos no es el enfoque ideal para su empresa. En lugar de simplemente almacenar los datos que obran en su poder, es preferible almacenar los detalles sobre el evento que se produce y los datos involucrados en ese evento concreto.

En este artículo, desenterraremos primero la base empresarial del abastecimiento de eventos (eventos registrados como el origen de datos principal de las aplicaciones) y, posteriormente, hablaremos de cómo actualizar las aptitudes de creación, lectura, actualización y eliminación (CRUD) existentes teniendo en cuenta los eventos. Para que quede claro desde el principio, la cuestión no es si necesita el abastecimiento de datos. La cuestión es cuándo lo necesita y cómo lo codifica.

Tendencia hacia modelos de datos dinámicos

El uso de datos políglotas es un tema de actualidad: las bases de datos relacionales para datos estructurados, los almacenes de datos NoSQL para datos menos estructurados, los diccionarios de clave-valor para preferencias y registros, y las bases de datos de gráficos para relaciones y correlaciones. La presentación de distintos modelos de almacenamiento que se ejecutan en paralelo es un paso en la dirección correcta, pero parece ser más bien un remedio eficaz para un síntoma visible que la cura para la enfermedad subyacente real.

El modelo relacional debe su eficacia de décadas a un conjunto de ventajas equilibrado que incorpora en la lectura y la escritura de datos. Un modelo relacional es fácil de consultar y actualizar, aunque presenta límites en algunas condiciones (muy) extremas. El rendimiento global disminuye comprensiblemente en tablas con algunos millones de registros y varios cientos de columnas. Además, el esquema de datos es fijo y el conocimiento de la estructura de la base de datos es necesario para crear consultas ad hoc y rápidas. En otras palabras, en el mundo donde codifica hoy, un modelo completo, como el gran modelo relacional creado anteriormente, es una enorme restricción que primero limita su expresividad y, luego, su capacidad de programación. Al final, un modelo es solo un modelo y no lo que se observa directamente en el mundo real. En el mundo real, no observa ningún modelo. En su lugar, usa un modelo para encapsular algún comportamiento repetible y comprendido. En última instancia, en el mundo real, observa eventos, pero espera almacenar la información relacionada con estos en un modelo restringido (relacional). Cuando esto le resulte difícil, observe modelos de almacenamiento alternativos que liberen algunas restricciones de esquema y de indexación.

Modelo de almacenamiento basado en eventos

Durante décadas, guardar el estado actual de las entidades ha probado ser útil y eficaz. Al guardar un estado determinado, se sobrescribe el estado existente y se pierde la información anterior. Este comportamiento no merece elogios ni reproches, por sí mismo. Durante años, ha demostrado ser un enfoque eficaz y ha obtenido una amplia aceptación. Solo los clientes y dominios empresariales pueden declarar realmente si perder un estado pasado es aceptable. Los hechos revelan que, durante muchos años y para la mayoría de las empresas, fue aceptable. Esta tendencia está cambiando, ya que cada vez más aplicaciones empresariales requieren el seguimiento del historial completo de las entidades empresariales. Las operaciones de creación, lectura, actualización y eliminación (que durante años hemos conocido como CRUD) modeladas sobre tablas relacionales estándar están evolucionando ahora en lo que podríamos denominar genéricamente CRUD histórico. El CRUD histórico es simplemente una base de código donde la implementación es capaz de rastrear toda la lista de cambios.

El mundo real está lleno de sistemas de línea de negocio (LOB) que, de algún modo, realizan el seguimiento de eventos a medida que se producen en el dominio. Estas clases de aplicación han existido durante décadas, algunas incluso estaban escritas en COBOL o Visual Basic 6. Por ejemplo, no hay duda de que una aplicación de contabilidad realiza el seguimiento de todos los cambios que puedan producirse en facturas, como un cambio de fecha o dirección, la emisión de una nota de crédito, etc. En algunos escenarios empresariales, el seguimiento de eventos es una característica solicitada desde los inicios del software, que a menudo quedaba al amparo de la funcionalidad de auditoría.

Por tanto, la auditoría de eventos empresariales no es un nuevo concepto del software. Durante décadas, los equipos de desarrollo han resuelto el mismo problema una y otra vez, repitiendo y recombinando las técnicas conocidas de la mejor manera posible. Hoy, este procedimiento recomendado antiguo para auditar los eventos empresariales recibe el nombre más atractivo de "abastecimiento de eventos".

Codificación del recorrido a los eventos empresariales

Supongamos que tiene una aplicación simple desde el punto de vista conceptual. Por ejemplo, una que permite a los usuarios reservar un recurso compartido, como una sala de reuniones. Al revisar el estado de una reserva determinada, es posible que el usuario obtenga no solo su estado actual, sino también la lista completa de actualizaciones desde su creación. En la Figura 1 se esboza una interfaz de usuario posible basada en la escala de tiempo para la vista.

Vista basada en la escala de tiempo del historial completo de una reserva
Figura 1 Vista basada en la escala de tiempo del historial completo de una reserva

¿Cómo diseñaría un modelo de datos de reserva que se comportara como un CRUD histórico en lugar de un CRUD estándar basado en el estado? Agregar más columnas a la definición de tabla no es suficiente. La principal diferencia entre un CRUD y un CRUD histórico es que, en el último escenario, tiene la intención de almacenar varias copias de la misma entidad, una por cada evento empresarial realizado en un momento determinado. En la Figura 2 se muestra una nueva estructura posible para la tabla de reservas de la base de datos relacional.

Modelo de datos relacional posible para una aplicación de CRUD histórico
Figura 2 Modelo de datos relacional posible para una aplicación de CRUD histórico

La tabla representada en la Figura 2 incluye el conjunto de columnas previsto que expone el estado de una entidad empresarial, además de algunas otras. Como mínimo, querrá tener una columna de clave principal que identifique de manera exclusiva una fila de la tabla. A continuación, querrá tener una columna de marca de tiempo que indique la hora de la operación en la base de datos o cualquier marca de tiempo que tenga sentido para la empresa. De manera más general, la columna cumple la función de asociar una fecha segura al estado de la entidad. Finalmente, querrá tener una columna que describa el evento registrado.

Sigue siendo una tabla relacional y aún administra la lista de reservas que la aplicación necesita. No se agregó nueva tecnología, pero la tabla esquematizada en la Figura 2 constituye, desde el punto de vista conceptual, un gran avance respecto de un CRUD clásico. Agregar registros a la nueva tabla es muy sencillo. Solo tiene que rellenar los registros y anexarlos a medida que obtiene la notificación de acontecimientos en el sistema que deben rastrearse. Mucho hemos hablado de la copia de CRUD, pero ¿qué sucede con las otras operaciones?

Actualizaciones y eliminaciones en un CRUD histórico

Una vez que la tabla relacional clásica se convierte en una tabla histórica basada en eventos, el rol y la relevancia de las actualizaciones y eliminaciones cambia considerablemente. Para empezar, las actualizaciones desaparecen. Todas las actualizaciones del estado lógico de la entidad se implementan ahora como un nuevo registro anexado que realiza el seguimiento del nuevo estado.

Las eliminaciones son un aspecto más delicado y la última palabra sobre la codificación la tiene la lógica empresarial del dominio. En un mundo basado en eventos ideal, no existen eliminaciones. Los datos simplemente se agregan y, por tanto, una eliminación solo es la adición de un nuevo evento que indica que la entidad ya no existe de forma lógica. No obstante, la eliminación física de datos de una tabla no está prohibida y sigue siendo posible. A pesar de ello, tenga en cuenta que, en un escenario basado en eventos, la entidad que se quiere quitar no está formada por un solo registro, sino por una colección de registros, tal como se representa en la Figura 2. Si decide eliminar una entidad, debe quitar todos los eventos (y registros) relacionados con esta.

Lectura del estado de una entidad

La ventaja más importante que obtiene al registrar eventos empresariales en su aplicación es que nunca pierde nada. Puede realizar el seguimiento del estado del sistema en cualquier momento, descifrar la secuencia exacta de acciones que conducen a un estado determinado y deshacer, total o parcialmente, esos eventos. Así, prepara la base de la inteligencia empresarial propia y los posibles escenarios del análisis de negocio. Para ser más exactos, no obtendrá estas características automáticamente con la aplicación, pero ya tiene todos los datos que necesita desarrollar, tales como las extensiones de la aplicación existente.

La parte más compleja de un CRUD histórico es la lectura de datos. Está rastreando todos los eventos empresariales importantes del sistema de reservas de ejemplo, pero no existe ningún lugar donde pueda obtener fácilmente la lista completa de reservas vigentes. No existe una manera rápida y fácil de averiguar cuántas reservas tiene para la próxima semana. Aquí es donde entran las proyecciones. En la Figura 3 se resume la arquitectura global de un sistema que evoluciona de un CRUD estándar a un CRUD histórico.

Arquitectura de un sistema CRUD histórico
Figura 3 Arquitectura de un sistema CRUD histórico

Un sistema basado en eventos está orientado inevitablemente hacia la implementación de una clara separación entre el comando y la pila de consultas. Partiendo del nivel de presentación, el usuario desencadena una tarea que se desarrolla a través del nivel de aplicación y dominio, e involucra en el proceso todos los componentes de la lógica empresarial. Un comando es el desencadenador de una tarea empresarial que altera el estado actual del sistema, lo que significa que debe confirmarse algo que modifique de forma lógica el estado existente. Como hemos mencionado, en un sistema basado en eventos (aunque sea un sistema CRUD estándar simple), el estado implica agregar un registro que indique que los usuarios han creado o actualizado una reserva concreta. El bloque de la Figura 3 con la etiqueta "Event Repository" representa cualquier nivel de código responsable de continuar con el evento. En términos de tecnologías concretas, el bloque Event Repository puede ser una clase de repositorio basada en Entity Framework, así como un contenedor en una base de datos de documentos (Azure DocumentDB, RavenDB o MongoDB). Y aún más interesante, puede ser una clase contenedora que use la API de un almacén de eventos, como EventStore o NEventStore.

En una arquitectura basada en eventos, el estado de una entidad determinada se calcula de forma algorítmica a petición. Este proceso recibe el nombre de reproducción de evento y consiste en consultar todos los eventos relacionados con la entidad especificada y en aplicarlos a una nueva instancia de la clase de entidad. Al final del bucle, la instancia de entidad está actualizada porque tiene el estado de una nueva instancia que ha pasado por todos los eventos registrados.

En términos más generales, al procesar el registro de eventos se compila una proyección de datos y se extrae un modelo de datos dinámicos a partir de una cantidad de datos de nivel inferior. Es lo que se denomina Read Model en la Figura 3. Se puede basar en el mismo registro de eventos para compilar todos los modelos de datos que sirven a varios front-end. Para usar la analogía de SQL, compilar una proyección de datos a partir de los eventos registrados es igual que compilar una vista a partir de una tabla relacional.

La reproducción de eventos para determinar el estado actual de una entidad con fines de consulta suele ser una opción viable, pero es cada vez menos eficaz, ya que el número de eventos o la frecuencia de las solicitudes aumenta con el tiempo. Su objetivo no es pasar por miles de registros cada vez para averiguar el saldo actual de una cuenta bancaria. Del mismo modo, le recomiendo que no pase por cientos de eventos para presentar la lista de reservas pendientes. Para resolver estos problemas, el modelo de lectura suele adoptar la forma de una tabla relacional clásica que se mantiene sincronizada con la tabla de eventos registrados mediante programación.

Resumen

La mayoría de las aplicaciones se pueden catalogar a simple vista como aplicaciones CRUD. Del mismo modo, Facebook se puede presentar de algún modo como un CRUD, quizás un poco más grande que la media. En realidad, para la mayoría de los usuarios, el último buen estado conocido sigue siendo suficiente, pero el número de clientes para los que esta vista es insuficiente va en aumento. El siguiente podría ser su mejor cliente. En este artículo se muestra de manera superficial un CRUD histórico. El próximo mes presentaré un ejemplo concreto. Permanezca atento a las novedades.


Dino Espositoes 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: Jon Arne Saeteras