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

Discussion (0)