DEV Community

Isaac Ojeda
Isaac Ojeda

Posted on • Updated on

Explorando Vertical Slice Architecture con .NET 6

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

Image description

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:

Image description

Y si queremos cambiar algo en la funcionalidad (o agregar nueva) tenemos que editar todos estos archivos:

Image description

Image description

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).

Image description

¿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.

Image description

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.

Image description

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.

Image description

Image description

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.

Image description

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).

Image description

Y sigue siendo reusable según el host de la aplicación.

Image description

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

Top comments (18)

Collapse
 
erickgonzalezs profile image
Erick González Sánchez

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!!!

Collapse
 
isaacojeda profile image
Isaac Ojeda

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...

Collapse
 
erickgonzalezs profile image
Erick González Sánchez

Excelente!!! leído y añadido a favoritos... Quedo pendiente de la próxima publicación!! Gracias de nuevo por todo!!!

Thread Thread
 
isaacojeda profile image
Isaac Ojeda

Estoy por regresar de vacaciones, ya dejé listo el código de integration events, mañana sale 👌🏼 jeje

Saludos

Thread Thread
 
erickgonzalezs profile image
Erick González Sánchez

A la espera y pendiente... Gracias

Thread Thread
 
isaacojeda profile image
Isaac Ojeda

Listo 👍🏽 dev.to/isaacojeda/integration-even...

Mañana le daré una revisión para quitar errores o mejorar redacción, saludos!!

Collapse
 
isaacojeda profile image
Isaac Ojeda

¡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!

Collapse
 
erickgonzalezs profile image
Erick González Sánchez

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!

Thread Thread
 
isaacojeda profile image
Isaac Ojeda

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.

Thread Thread
 
erickgonzalezs profile image
Erick González Sánchez

Muchas gracias... revisando... el inglés aun no es mi fuerte pero pues ahí lo veo poco a poco xD

Collapse
 
amilcar31416 profile image
amilcar31416 • Edited

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!!

Collapse
 
v5n5g45 profile image
v5n5g45

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!

Collapse
 
isaacojeda profile image
Isaac Ojeda

¡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!

Collapse
 
edd profile image
NSysX

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.

Collapse
 
isaacojeda profile image
Isaac Ojeda

Hola!

Espero te sirva, en este post está este repositorio en el cual uso carter y minimal apis.

Saludos!

Collapse
 
edd profile image
NSysX

El el metodo Get tambien hace transaccion ?

Collapse
 
edd profile image
NSysX

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)

Collapse
 
isaacojeda profile image
Isaac Ojeda

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!