Introducción
En días pasados acabo de publicar un repositorio y un vídeo intentando llegar a una conclusión con Vertical Slice Architecture usando .NET 6 Minimal APIs.
Combinando conceptos DDD e incluso de clean architecture, me llevó a investigar mucho sobre este tema, y por esto escribo este post.
Vertical Slice Architecture
Este enfoque no es un tema nuevo, quien más veo que lo promueve es Jimmy Bogard (El creador de AutoMapper y MediatR).
Él de hecho creó MediatR por esta misma razón, y podemos ver muchos artículos escritos por él sobre este tema.
Clean Architecture
En mi equipo llevamos años implementando clean architecture con la solución que propone Jason Taylor. Y hasta ahora no hemos tenido problemas mayores, ya que el equipo es relativamente pequeño. Pero todos los conceptos hablados en las conferencias de Jason tienen mucho valor y muchos se comparten con vertical slice architecture.
Pero Jimmy en esta conferencia habla de este tema muy a detalle que captó mucho mi atención.
Habla que clean architecture te obliga a seguir muchas reglas y muchas abstracciones por poco beneficio. El cual lo entiendo, uno de los objetivos del clean architecture es eliminar la dependencia del Core
(Application y Domain) de cualquier framework y persistencia.
Pero en esta parte yo estoy de acuerdo con Jimmy, jamás he tenido un beneficio real en crear abstracciones (al menos que sea para testing) y al final no tener un beneficio a futuro, porque jamás hemos tenido la necesidad de cambiar de framework.
Seguir reglas por seguir es lo que ya no fue atractivo para mí. Por ejemplo, yo no uso el Repository Pattern para cumplir con el "Persistance Ignorance" y no crear dependencia del ORM. La razón es porque Entity Framework YA ES un repositorio (con UnitOfWork) y me crea la "Persistance Ignorance", solo que SÍ te quedas obligado a usar Entity Framework Core, que cada uno puede decidir si eso es un problema (nunca lo es).
Organizar por n-capas con clean a veces es algo así:
- Person.cs (domain)
- PersonController.cs (UI / Presentation)
- PersonService.cs (application logic)
- PersonRepository.cs (data access)
Y terminamos con algo asi:
Y si queremos cambiar algo en la funcionalidad (o agregar nueva) tenemos que editar todos estos archivos:
Jimmy propone, que en lugar de dividir todo por "cuestiones técnicas" debemos de dividir todo por funcionalidad.
Dividir un sistema por funcionalidad tiene el beneficio de que cada Request
tiene un caso de uso distinto, el cual tiene sus propias necesidades y se abordan como se necesite. Vertical Slice Architecture nos lleva inevitablemente implementar CQRS (por eso, Bogard creó MediatR).
¿Qué es Vertical Slice Architecture?
En esta arquitectura, el código es implementado alrededor de distintos requests (operaciones que cambian o no el estado del dominio), encapsulando y agrupando todos los "concerns" desde el UI/Presentation hasta el back. Es decir, tomas un modelo "n-tier" o clean architecture y eliminas las "puertas" entre esas capas y las acoplas según la funcionalidad.
Cuando estemos agregando o editando un "Feature" en la aplicación, en Clean Architecture por lo general editas varios archivos en distintas capas (DTOs, Repositorios, Validaciones, Servicios, etc) y usualmente distintos proyectos.
En lugar de acoplar las capas horizontalmente, es mejor acoplar de forma vertical (según un slice/feature) y evitar acoplar entre slices y más bien que un slice esté fuertemente acoplado consigo mismo.
Con este enfoque, la mayoría de las abstracciones desaparecen y no necesitamos ningún tipo de abstracción de capas "compartidas" como los repositorios, servicios y controladores. A veces, nuestras herramientas aun lo requieren, pero mantenemos nuestro intercambio de lógica vertical al mínimo.
Cada "vertical slice" puede decidir por sí misma como cumple con las necesidades del Request.
Los Domain logic patterns del libro "Patterns of Enterprise Architecture" ya no deben de ser una decisión que abarque toda la aplicación. En lugar de eso, podemos comenzar con algo muy sencillo y simplemente refactorizar a distintos patrones a causa de los "Code Smells" que vemos en la lógica de negocio, todo según se necesite (sin miedo al éxito) .
Una clase o un método largos y complejos, debe de ser refactorizados. ¿Cómo? puede ser una clase, una subclase, una interfaz, extraer el método, etc.
Nuevos "features" solo agregan código nuevo, no se está cambiando código compartido en las capas, así se asegura el aislamiento y el "Single responsability" verdadero.
Por supuesto que existen desventajas en este enfoque, y es que se está asumiendo que nuestro equipo de desarrollo detecta los "code smells" y aplica el refactoring. Si el equipo no entiende cuando un "servicio" está haciendo demasiado trabajo, tal vez este approach no es el que se debe seguir (o ninguno 🤣).
Si se comprende el refactoring y se reconoce cuando llevar lógica compleja al Domain (DDD services bien aplicados) y se está familiarizado con técnicas de refactorización como del libro de Martin Fowler, esta arquitectura puede funcionar mucho mejor que la tradicional n-capas o clean.
Algo que menciona Derek de CodeOpinion es que nuestro Domain será compartido (y tiene sentido) y tendrá su lógica pertenieciente al dominio (si se necesita, justo como lo dice Jimmy).
Y sigue siendo reusable según el host de la aplicación.
Por eso, en mi repositorio demo sigo haciendo uso de la capa "Application" y "Web". De ser necesario, podría agregar un worker sin problema.
Conclusión
Clean architecture y este enfoque puede que no estén peleados, el template de Jason Taylor de Clean hace uso de CQRS y esto nos permite hasta cierto punto enfocarte en los features.
Vertical Slice Architecture demanda conocimiento de refactoring y de DDD para un mejor rendimiento (aunque Clean architecturetambién) detectar los "code smells" y siempre estar dispuestos al refactoring es muy importante.
Patrones como Decorator, Chain of responsability o strategy pueden resultar útiles cuando se detectan los famosos "code smells".
Referencias
- presentation/VerticalSliceArchitecture by Jimmy Bogard
- Vertical Slice Architectore conference by Jimmy Bogard
- Vertical slice architecture article by Jimmy Bogard
- Restructuing to a Vertical Slice Architecture by Derek Comartin (Code Opinion)
- Choosing Between using Clean/Onion or Vertical Slice Architecture for Enterprise Apps in .NET by pdevito3
Top comments (18)
Muchas gracias por todos tus contenidos!!!! Ya los eh leido casi todos y eh mirado casi todos tus videos también...
Me gustaría solicitarte apoyo con una explicación a fondo (como la que te aventaste de todo el tema Identity - OpenID que estuvo genial...) sobre DDD o EDA por favor y en particular si conoces alguna técnica para hacer algún genérico para los publisher y consumer... en mi actual empresa es un área de oportunidad que me encantaría atacar... Gracias de nuevo por compartir tu conocimiento!!!
Acabo de escribir sobre Domain Events, algo ya visto en el template de Minimal API Architecture, mi intención es luego escribir sobre Integration Events con algun message broker.
Post: dev.to/isaacojeda/ddd-cqrs-aplican...
Excelente!!! leído y añadido a favoritos... Quedo pendiente de la próxima publicación!! Gracias de nuevo por todo!!!
Estoy por regresar de vacaciones, ya dejé listo el código de integration events, mañana sale 👌🏼 jeje
Saludos
A la espera y pendiente... Gracias
Listo 👍🏽 dev.to/isaacojeda/integration-even...
Mañana le daré una revisión para quitar errores o mejorar redacción, saludos!!
¡Muchas gracias!
Me da gusto que no escribo en vano jeje
Con gusto me programo para escribir algo sobre eso, que ademas es un tema muy interesante.
¡Saludos!
Nada de eso!!! hace falta más contenido como el tuyo en español!!! Mismo caso con tus videos... en verdad te mereces muchisimas más visitas que las que tienes... en mi equipo de desarrollo ya les eh estado compartiendo tu contenido!!! Gracis de new!
Te recomiendo este canal y esta serie de vídeos: https://www.youtube.com/watch?v=spnBzawswik&list=PLqqD43D6Mqz0AIDkHqaZDKaEKXdfMiIAo&ab_channel=DevMentors
Hay unos de Pub/Sub con Redis y otro que usan Message Broker, están muy buenos.
Muchas gracias... revisando... el inglés aun no es mi fuerte pero pues ahí lo veo poco a poco xD
Exelentes Publicaciones, tengo la impresión de que en el libro arquitectura limpia, en los capítulos "Arquitectura que grita" y "Límites parciales" aunqueno muestra una implementación concreta como en todo el libro, pero en mi opinión se dice vagamente algo de lo que comentas, gracias por implementarlo y mostrarlo. Todavía estoy digiriendo la publicación. Gracias nuevamente!!
Hola!, gracias por compartir tanto, eres un genio
Recién estoy aprendido clean architecture, tendrás algún post acerca de clean architecture con cqrs, mediatr, fluent validation desde cero?
como un proyecto donde se conjunten todos así paso por paso?
Me ayudaría mucho y te lo agradecería hasta el infinito.
Gracias, que estés excelente!
¡Gracias!
De clean architecture no tengo, pero sí tengo una seríe que se basa en Vertical Slice Architecture, que en muchas cosas es lo mismo
Serie ASP.NET
Saludos!
Estoy buscando un ejemplo de un Endpoint usando Carter, para usar ejecucion diferida que le pasas una clase con las propiedades por las cuales quieres filtrar. [FromQuery], tendras algun ejemplo ? si es que se puede. Gracias.
Hola!
Espero te sirva, en este post está este repositorio en el cual uso carter y minimal apis.
Saludos!
El el metodo Get tambien hace transaccion ?
Saludos, Se puede usar eventos de dominio para que al hacer la creacion de un registro, tambien cree otro registro en otra tabla que esta relacionada con la primera ?(Por el problema del Id que te lo da hasta que haces el SaveChanges)
Interesante, la única forma que se me ocurre de momento es mandar el Entity en el evento, ya que todo es por referencia, al ejecutar el
SaveChangesAsync
automaticamente el entity referenciado tendrá el ID generado.Estoy seguro que puede haber otras soluciones más elegantes, pero de momento no se me viene otra opción a la mente.
Saludos!