¿No es la sobreingeniería CQRS?

15

Todavía recuerdo los viejos tiempos de repositorios. Pero los repositorios solían ponerse feos con el tiempo. Luego, CQRS se hizo popular. Eran agradables, eran un soplo de aire fresco. Pero recientemente me he estado preguntando una y otra vez por qué no mantengo la lógica correcta en el método de acción del controlador (especialmente en Web Api, donde la acción es algún tipo de controlador de comando / consulta en sí mismo).

Anteriormente tenía una respuesta clara para eso: lo hago para probar, ya que es difícil probar el Controlador con todos esos singleton inamovibles y la infraestructura ASP.NET fea en general. Pero los tiempos han cambiado y las clases de infraestructura ASP.NET son mucho más amigables con las pruebas unitarias hoy en día (especialmente en ASP.NET Core).

Aquí hay una llamada típica de WebApi: se agrega un comando y se notifica a los clientes de SignalR al respecto:

public void AddClient(string clientName)
{
    using (var dataContext = new DataContext())
    {
        var client = new Client() { Name = clientName };

        dataContext.Clients.Add(client);

        dataContext.SaveChanges();

        GlobalHost.ConnectionManager.GetHubContext<ClientsHub>().ClientWasAdded(client);
    }
}

Puedo fácilmente probarlo / simularlo. Además, gracias a OWIN puedo configurar los servidores locales WebApi y SignalR y hacer una prueba de integración (y bastante rápido).

Recientemente me sentí cada vez menos motivado para crear engorrosos manejadores de Comandos / Consultas y tiendo a mantener el código en las acciones de Web Api. Hago una excepción solo si la lógica se repite o si es realmente complicada y quiero aislarla. Pero no estoy seguro si estoy haciendo lo correcto aquí.

¿Cuál es el enfoque más razonable para administrar la lógica en una aplicación ASP.NET moderna típica? ¿Cuándo es razonable mover su código a los controladores de Comandos y Consultas? ¿Hay mejores patrones?

Actualizar. Encontré este artículo sobre el enfoque DDD-lite. Entonces parece que mi enfoque de mover partes complicadas de código a los controladores de comandos / consultas podría llamarse CQRS-lite.

SiberianGuy
fuente
1
No veo cómo CQRS hace las cosas más comprobables / es de alguna ayuda con singletons / controllers / etc. En gran medida no están relacionados. Además, todavía está creando un comando en su ejemplo (¿contador?), Lo cual es extraño.
guillaume31
Si mantiene su código con código de infraestructura (es decir, obtenga la dirección IP del cliente), es difícil de probar. Si aísla la lógica en una consulta / comando, es mucho más fácil. El ejemplo de código era un poco confuso, así que lo actualicé.
SiberianGuy
1
Las consultas y los comandos no tienen lógica. Son tontos DTO. Luego tiene sus manejadores de comando / consulta , pero son exactamente los mismos que los servicios de aplicación, los interactuadores, los servicios comerciales, lo que sea ... en un contexto que no sea CQRS. Colocar la lógica de caso de uso / aplicación en un objeto separado que el Controlador no es una cosa específica de CQRS.
guillaume31
Además, la cuestión de Singleton vs dependencia inyectada es completamente ortogonal a CQRS. Podría tener un controlador que llame a un singleton CommandHandler que llame a un singleton Repository ...
guillaume31
1
@ guillaume31, CQRS tiende a ser más engorroso que las llamadas al servicio de repositorio / aplicación. Por lo general, necesitan 2-3 clases (es decir, consulta, controlador de consulta, resultado de consulta), infraestructura, etc.
SiberianGuy

Respuestas:

17

¿Es CQRS un patrón relativamente complicado y costoso? Si.

¿Es sobre ingeniería? Absolutamente no.

En el artículo original donde Martin Fowler habla sobre CQRS , puede ver muchas advertencias sobre no usar CQRS donde no es aplicable:

Como cualquier patrón, CQRS es útil en algunos lugares, pero no en otros.

CQRS es un salto mental significativo para todos los involucrados, por lo que no debe abordarse a menos que el beneficio valga la pena .

Si bien he encontrado usos exitosos de CQRS, hasta ahora la mayoría de los casos con los que me he encontrado no han sido tan buenos ...

A pesar de estos beneficios, debe tener mucho cuidado al usar CQRS .

... agregar CQRS a dicho sistema puede agregar una complejidad significativa .

Mi énfasis arriba.

Si su aplicación está utilizando CQRS para todo, entonces no es CQRS lo que está sobre-diseñado, es su aplicación. Este es un patrón excelente para resolver algunos problemas específicos, especialmente aplicaciones de alto rendimiento / alto volumen donde la concurrencia de escritura puede ser una preocupación importante.

Y puede que no sea la aplicación completa, sino solo una pequeña parte de ella.

Un ejemplo en vivo de mi trabajo, empleamos CQRS en el sistema de entrada de pedidos, donde no podemos perder ningún pedido, y tenemos picos en los que miles de pedidos provienen al mismo tiempo de diferentes fuentes, en algunas horas específicas. CQRS nos ayudó a mantener el sistema vivo y receptivo, al tiempo que nos permitió escalar bien los sistemas de back-end para procesar estos pedidos más rápido cuando sea necesario (más servidores de back-end) y más lento / más barato cuando no es necesario.

CQRS es perfecto para el problema en el que hay varios actores que colaboran en el mismo conjunto de datos o escriben en el mismo recurso.

Aparte de eso, difundir un patrón hecho para resolver un solo problema a todos tus problemas solo creará más problemas para ti.


Algunos otros enlaces útiles:

http://udidahan.com/2011/04/22/when-to-avoid-cqrs/

http://codebetter.com/gregyoung/2012/09/09/cqrs-is-not-an-architecture-2/

Machado
fuente
3
Acuerde todo excepto la parte del "patrón relativamente complicado y costoso". CQRS solo está separando las lecturas de las escrituras. Puede hacerlo con cinta adhesiva, cero middleware / herramientas complicadas, y manteniendo la misma base de datos que antes, para todo lo que le importa.
guillaume31
@ guillaume31, ese es un punto justo. Creo que se correlaciona bastante con la idea de la pregunta original: "en Web Api, donde la acción es algún tipo de comando / consulta en sí misma". Pero, ¿ha visto alguna muestra de CQRS que funcione (preferiblemente github) que no use clases separadas para comandos y consultas? Eso es lo que encuentro cuando intento ver cómo otras personas implementan CQRS en .NET.
SiberianGuy
Sí, pero no es sobre ingeniería. Es la premisa básica del patrón: separar las consultas de las escrituras, leer el modelo del modelo de dominio.
guillaume31
El enfoque CQRS podría ser más de matanza en muchos contextos, pero eso es una historia totalmente diferente. No es excesivo debido a todos los pequeños detalles técnicos que atribuye erróneamente a CQRS en su Q, es excesivo porque no siempre necesita lo que CQRS le brinda.
guillaume31
Creo que el punto de Fowler solo es válido hasta cierto punto. SQL Views es un tipo de CQRS y está con nosotros por siglos y nadie dice que sean muy complejos. Dado que hay muchos sabores de CQRS, es decir, proyecciones de aprovisionamiento de eventos, eso puede verse como complejo en algunas áreas, mientras que puede ser trivial en otra.
Alexey Zimarev el
3

CQRS no es un reemplazo uno por uno para los repositorios, exactamente porque es un patrón complejo y costoso que solo es útil en algunos casos.

Esto es lo que Udi Dahan tiene que decir en mérito:

La mayoría de las personas que usan CQRS (y también el Abastecimiento de eventos) no deberían haberlo hecho.

[...]

Lamento decir que la mayoría de las aplicaciones de muestra que verá en línea que muestran que CQRS son arquitectónicamente incorrectas. También sería extremadamente cauteloso con los marcos que lo guían hacia un modelo CQRS raíz agregado de estilo de entidad.

( fuente )

Martin Fowler:

[...] debe ser muy cauteloso al usar CQRS . Muchos sistemas de información encajan bien con la noción de una base de información que se actualiza de la misma manera que se lee, agregar CQRS a dicho sistema puede agregar una complejidad significativa.

( fuente )

Finalmente, Greg Young:

CQRS puede llamarse un patrón arquitectónico.

[...]

Esto es muy importante para entender que la mayoría de los patrones arquitectónicos no son buenos para aplicar en todas partes. Si ve patrones arquitectónicos en una guía arquitectónica, probablemente tenga un problema

[...]

El mayor error que veo de las personas que usan el abastecimiento de eventos es que intentan usarlo en todas partes.

( fuente )

Sklivvz
fuente