CQRS: el principio de "divide y vencer谩s" al servicio de un programador

La arquitectura Puff es la salvaci贸n en el mundo del desarrollo empresarial. Con su ayuda, puede descargar hierro, paralelizar procesos y restaurar el orden en el c贸digo. Intentamos usar el patr贸n CQRS al desarrollar un proyecto corporativo. Todo se ha vuelto m谩s l贸gico y ... m谩s complicado. Recientemente, habl茅 sobre lo que tuve que enfrentar en la reuni贸n Panda-Meetup C # .Net , y ahora estoy compartiendo con ustedes.



驴Alguna vez has notado c贸mo se ve tu aplicaci贸n corporativa? 驴Por qu茅 no puede ser como Apple y Google? S铆, porque tenemos una falta constante de tiempo. Los requisitos cambian con frecuencia, el t茅rmino para sus cambios suele ser "ayer". Y lo que es m谩s desagradable, al negocio realmente no le gustan los errores.



Para vivir de alguna manera con esto, los desarrolladores comenzaron a dividir sus aplicaciones en partes. Todo comenz贸 simple, con datos. Muchos est谩n familiarizados con el esquema cuando los datos est谩n separados, el cliente est谩 separado, mientras que la l贸gica se almacena en el mismo lugar que los datos.



Buen esquema Los DBMS m谩s grandes tienen extensiones de procedimiento completamente funcionales para SQL. Hay un proverbio sobre Oracle: "Donde hay Oracle, hay l贸gica". Es dif铆cil discutir sobre la conveniencia y la velocidad de tal configuraci贸n.

Pero tenemos una aplicaci贸n corporativa, y hay un problema: la l贸gica es dif铆cil de escalar. Y no es razonable cargar la capacidad de DBMS, que ya sufre problemas con la extracci贸n y actualizaci贸n de datos, y tambi茅n tareas empresariales triviales.

Bueno, para ser honesto, las herramientas de programaci贸n de l贸gica de negocios integradas en el DBMS son d茅biles para crear aplicaciones corporativas normales. Mantener la l贸gica empresarial en T-SQL / PL-SQL es una molestia. No sin raz贸n, los lenguajes OOP est谩n tan extendidos entre las aplicaciones corporativas: C #, Java, no tiene que ir muy lejos como ejemplo.



Parecer铆a una soluci贸n l贸gica: destacamos la l贸gica empresarial. Vivir谩 en su servidor, la base por su cuenta, el cliente por su cuenta.

驴Qu茅 se puede mejorar en esta arquitectura de tres niveles? La arquitectura est谩 involucrada en la capa de l贸gica empresarial, me gustar铆a evitar esto. La l贸gica empresarial no quiere saber nada sobre el almacenamiento de datos. La interfaz de usuario tambi茅n es un mundo separado en el que hay entidades que no son espec铆ficas de la l贸gica empresarial.

Aumentar capas ayudar谩. Esta soluci贸n se ve casi perfecta, tiene alg煤n tipo de belleza interior.



Tenemos un DAL (Data Access Layer): los datos se separan de la l贸gica, generalmente un repositorio CRUD que usa ORM, m谩s procedimientos almacenados para consultas complejas. Esta opci贸n le permite desarrollarse lo suficientemente r谩pido y tener un rendimiento aceptable.

La l贸gica empresarial puede ir como parte de los servicios o ser una capa separada. La interacci贸n entre capas se puede llevar a cabo a trav茅s de objetos de transporte (DTO).

La solicitud de la interfaz de usuario va al servicio, se comunica con la l贸gica de negocios, sube al DAL para acceder a los datos. Este enfoque se llama N-tier y tiene claras ventajas.

Cada capa tiene sus propias metas y objetivos obvios, que a nosotros, como programadores, nos gusta mucho. Cada capa de concreto se dedica solo a su propio negocio. Los servicios se pueden escalar horizontalmente. El enfoque es claro incluso para un desarrollador novato, una persona comprende r谩pidamente c贸mo funciona el sistema. Es muy f谩cil rastrear todas las interacciones a medida que la solicitud va de principio a fin.

Otra coherencia: todos los subsistemas del proyecto funcionan con los mismos datos, no tiene que preocuparse de que hayamos registrado datos en un lugar y que el usuario no los vea en otra parte.

Pastel de capas 1. N-Tier


A continuaci贸n se muestra un ejemplo de un fragmento t铆pico de una aplicaci贸n basada en estos principios. Tenemos un requisito monetario, aqu铆 examin茅 el modelo an茅mico. Y hay un repositorio cl谩sico, trabajo con el que pasa ORM.



Este es un servicio t铆pico, tambi茅n se les llama gerentes. Trabaja con el repositorio, recibe solicitudes y da respuestas a los clientes. En este servicio vemos cierta confusi贸n: tenemos un proceso de procesamiento, un proceso para trabajar con UI y un proceso para algunas unidades de control interno, est谩n d茅bilmente interconectados.

As铆 es como se ve un m茅todo t铆pico de este servicio. Por ejemplo, el registro de un reclamo monetario.



Recibimos datos, realizamos algunos controles comerciales. Luego hay una actualizaci贸n, y despu茅s algunas acciones posteriores, por ejemplo, enviar una notificaci贸n o escribir en el registro de usuario.

En este enfoque, a pesar de toda su belleza, hay problemas. Muy a menudo en aplicaciones corporativas, la carga es asim茅trica: las operaciones de lectura son una orden o dos m谩s que las escritas. Ya existe un problema al escalar la base de datos en s铆. Por supuesto, esto se hace, e incluso por medio de un DBMS en una escala de base de datos, se llama partici贸n. Pero es dificil. Si esto se hace con las calificaciones incorrectas o antes de lo necesario, la partici贸n fallar谩.

Por ejemplo, en uno de nuestros sistemas el volumen de datos alcanz贸 los 25 TB, aparecieron problemas. Nosotros mismos intentamos escalar, invitamos a tipos duros de una empresa conocida. Miraron y dijeron: necesitamos 14 horas de tiempo de inactividad completo de la base. Pensamos y dijimos: muchachos, no funcionar谩, el negocio no lo aceptar谩.

Adem谩s del volumen de la base de datos, el n煤mero de m茅todos en servicios y repositorios est谩 creciendo. Por ejemplo, en un servicio de reclamos monetarios hay m谩s de cien m茅todos. Es dif铆cil de mantener, existen conflictos constantes cuando se fusiona la solicitud, la revisi贸n del c贸digo es m谩s dif铆cil de realizar. Y si tiene en cuenta que los procesos son diferentes, diferentes grupos de desarrolladores trabajan en ellos, entonces la tarea de rastrear todos los cambios asociados con un problema se convierte en un verdadero dolor de cabeza.

Hojaldre 2. CQRS


Entonces que hacer? Hay una soluci贸n que se invent贸 en la antigua Roma: dividir y gobernar.



Como dicen, todo lo nuevo est谩 bien olvidado, viejo. En 1988, Bertrand Meyer formul贸 el principio de la programaci贸n imperativa de CQS (separaci贸n de consulta de comandos) para trabajar con objetos. Todos los m茅todos est谩n claramente divididos en dos tipos. La primera - Consulta - consultas que devuelven el resultado sin cambiar el estado del objeto. Es decir, cuando observa los requisitos monetarios del cliente, nadie debe escribir en la base de datos que el cliente se haya visto tal o cual, no deber铆a haber efectos secundarios en la solicitud.

El segundo - Comandos - comandos que cambian el estado de un objeto sin devolver datos. Es decir, orden贸 que se cambiara algo y, a cambio, no espere un informe de 10 mil l铆neas.



Aqu铆, el modelo de datos de lectura est谩 claramente separado del modelo de escritura. La mayor parte de la l贸gica de negocios funciona en operaciones de escritura. La lectura puede funcionar en representaciones materializadas o, en general, de manera diferente. Se pueden dividir y sincronizar a trav茅s de eventos o algunos servicios internos. Hay muchas opciones

CQRS no es complicado. Debemos distinguir claramente los equipos que cambian el estado del sistema, pero no devuelven nada. Aqu铆 el enfoque puede ser m谩s equilibrado. No es particularmente aterrador si el comando devuelve el resultado de la ejecuci贸n: un error o, por ejemplo, el identificador de la entidad creada, entonces no hay delito en esto. Es importante que el equipo no trabaje con la solicitud, no debe buscar datos y devolver entidades comerciales.

Solicitudes: todo es simple all铆. No cambia la condici贸n para que no haya efectos secundarios. Esto significa que si llamamos a la solicitud dos veces seguidas, y no hubo otros comandos, el estado del objeto en ambos casos deber铆a permanecer id茅ntico. Esto le permite paralelizar consultas. Curiosamente, un modelo separado para consultas no es necesario para el trabajo, porque no tiene sentido extraer l贸gica de negocios de un modelo de dominio para esto.

Nuestro proyecto CQRS


Esto es lo que quer铆amos hacer en nuestro proyecto:



Nuestra aplicaci贸n existente ha estado operando desde 2006, tiene una arquitectura cl谩sica en capas. Pasado de moda pero sigue funcionando. Nadie quiere cambiarlo y ni siquiera sabe con qu茅 reemplazarlo. Lleg贸 el momento en que era necesario desarrollar algo nuevo, pr谩cticamente desde cero. En 2011-2012, Event Sourcing y CQRS fueron un tema muy de moda. Pensamos que era genial, para poder almacenar el estado original del objeto y los eventos que lo condujeron.

Es decir, no estamos, por as铆 decirlo, actualizando el objeto. Hay un estado original y al lado est谩 lo que se le aplic贸. En este caso, hay una gran ventaja: podemos restaurar el estado de un objeto en cualquier momento de la historia. De hecho, la revista ya no es necesaria. A medida que almacenamos eventos, entendemos qu茅 sucedi贸 exactamente. Es decir, no solo se actualiz贸 el valor del cliente en la celda de "direcci贸n", sino que registraremos el evento exacto, por ejemplo, el movimiento del cliente.

Est谩 claro que dicho esquema funciona lentamente cuando se reciben datos, por lo que tenemos una base de datos separada con representaciones de materiales para la selecci贸n. Bueno, y sincronizaci贸n de eventos: con cada llegada de eventos en un cambio de estado, se produce una publicaci贸n. En teor铆a, todo parece estar bien, pero ... Nunca conoc铆 a personas que se dieran cuenta de esto en la producci贸n, en grandes cargas con una consistencia comercial aceptable.



El esquema puede desarrollarse a煤n m谩s si los controladores y comandos / solicitudes est谩n separados. Aqu铆, como ejemplo, tenemos un equipo: un reclamo monetario registrado: hay una fecha, monto, cliente y otros campos.

Ponemos una restricci贸n al procesador de registro del reclamo monetario de que solo puede aceptar a nuestro equipo (donde TCommand: ICommand). Podemos escribir controladores sin cambiar los antiguos, simplemente agregando requisitos complejos. Por ejemplo, primero actualice la fecha, luego escriba el valor, y aqu铆 env铆a una notificaci贸n al cliente: todo esto se escribe en diferentes controladores por comando.

驴C贸mo causamos todo esto? Hay un despachador que sabe d贸nde tiene almacenados todos estos controladores.



El despachador se pasa (por ejemplo, a trav茅s de un contenedor DI) a la API. Y cuando llega el comando, solo se ejecuta. 脡l sabe d贸nde est谩 el contenedor, d贸nde est谩n los equipos y los ejecuta. Con solicitudes, de manera similar.

驴Cu谩l es el problema con este esquema? Todas las interacciones se vuelven menos obvias. Construimos una jerarqu铆a sobre tipos que est谩n registrados en contenedores y luego respondemos a nuestros comandos / solicitudes. Requiere un dise帽o muy claro de la arquitectura. Cualquier acci贸n con un m茅todo con un par谩metro ya no est谩 limitada. Escribe un comando, escribe un controlador, se registra en un contenedor. La cantidad de gastos generales est谩 aumentando. En un proyecto grande, surgen problemas con la navegaci贸n primaria. Decidimos ir de una manera m谩s cl谩sica.

Para la comunicaci贸n asincr贸nica, se utiliz贸 el bus de servicio Rebus.



Para tareas simples, es m谩s que suficiente.

CQRS te hace enfocar el c贸digo un poco diferente, concentrarte en el proceso, porque todas las acciones nacen como parte del proceso. Asignamos un repositorio para solicitudes, procesamos comandos relacionados por separado y procesamos solicitudes relacionadas por separado. Para leer, no utilizamos un repositorio separado, solo trabajamos con ORM en equipos.



Aqu铆, por ejemplo, hay un m茅todo desde el cual se tira todo lo superfluo. En el equipo de registro de reclamo de dinero, registramos la demanda y publicamos el evento en el autob煤s en el que se registra el reclamo de dinero.



Cualquier persona interesada en esto reaccionar谩 a ella. Por ejemplo, la autenticaci贸n y el registro de usuarios funcionar谩n all铆.

Aqu铆 hay una solicitud de ejemplo. Todo se volvi贸 simple tambi茅n: leemos y entregamos al repositorio.



Quiero quedarme por separado en Rebus.Saga. Este es un patr贸n que le permite dividir una transacci贸n comercial en acciones at贸micas. Esto le permite bloquear no todos a la vez, sino gradualmente y a su vez.



El primer elemento toma medidas y env铆a un mensaje, el segundo suscriptor reacciona, lo cumple, env铆a su mensaje, al que la tercera parte del sistema ya est谩 respondiendo. Si todo termin贸 bien, Saga genera su propio mensaje del tipo especificado, al que otros suscriptores ya responder谩n.

Veamos c贸mo se ve la clase para procesar un reclamo de dinero en este caso. Todo est谩 claro: hay comandos, hay solicitudes relacionadas con el proceso de registro, bueno, un bus con registros.



En este caso, hay un controlador. Cuando ocurre un evento y llega un equipo para registrar reclamos monetarios, 茅l responde. En el interior, todo es igual que antes, pero la peculiaridad es que hay una agrupaci贸n por proceso.



Debido a esto, se hizo un poco m谩s f谩cil, menos cambios en cada archivo.

Conclusiones


驴Qu茅 debe recordar al trabajar con CQRS? Necesita un mejor enfoque para el dise帽o, porque reescribir el proceso es un poco m谩s complicado. Hay una peque帽a sobrecarga, se han convertido en un poco m谩s de clases, pero esto no es cr铆tico. El c贸digo se ha vuelto menos conectado, sin embargo, no es tanto por CQRS, sino por la transici贸n al bus. Pero fue CQRS lo que nos impuls贸 a usar esta interacci贸n de eventos. El c贸digo se ha agregado m谩s a menudo que cambiado. Hay m谩s clases, pero ahora son m谩s especializadas.

驴Todos necesitan dejar todo y cambiar masivamente a CQRS? No, debe observar qu茅 escenario funciona mejor para un proyecto en particular. Por ejemplo, si su subsistema funciona con directorios, no se necesita CQRS, el enfoque cl谩sico en capas brinda un resultado m谩s simple y conveniente.

La versi贸n completa del rendimiento en Panda Meetup est谩 disponible a continuaci贸n.


Si desea profundizar en el tema, tiene sentido estudiar estos recursos:

Estilo de arquitectura CQRS - de Microsoft

Blog de Alexander Bendyu

Ejemplos de la Universidad de Contoso con CQRS, MediatR, AutoMapper y m谩s - por Jimmy Bogard

CQRS - por Martin Fowler

Rebus

Source: https://habr.com/ru/post/440172/


All Articles