Are you tired of organizing your project across layers? Traditional layered architecture, with its separation of concerns into horizontal layers such as Presentation, Application, and Domain, often results in scattered code. This approach can make changes and maintenance cumbersome, as a single feature might be spread across multiple layers. But there’s a compelling alternative: Vertical Slice Architecture (VSA).
Vertical Slice Architecture flips the script on how we structure code. Instead of organizing by layers, VSA structures code by feature. Each feature encompasses everything it needs, from API endpoints to data access. In this article, we will explore the basics of VSA, how to implement it in your projects, and the benefits it brings to your development process.
At its core, a vertical slice represents a self-contained unit of functionality. It’s a slice through the entire application stack, encapsulating all the code and components necessary to fulfill a specific feature. In traditional layered architectures, code is organized horizontally across various layers, making feature implementation scattered and complex. VSA addresses this by grouping all the code for a feature into a single slice.
This shift in perspective brings several advantages:
Implementing VSA starts with structuring your code around features. Here’s an example vertical slice representing the CreateProduct feature. We use a static class to represent the feature and group the related types. Each feature can have respective Request and Response classes, with the business logic implemented in a Minimal API endpoint.
public static class CreateProduct
{
public record Request(string Name, decimal Price);
public record Response(int Id, string Name, decimal Price);
public class Endpoint : IEndpoint
{
public void MapEndpoint(IEndpointRouteBuilder app)
{
app.MapPost("products", Handler).WithTags("Products");
}
public static IResult Handler(Request request, AppDbContext context)
{
var product = new Product
{
Name = request.Name,
Price = request.Price
};
context.Products.Add(product);
context.SaveChanges();
return Results.Ok(new Response(product.Id, product.Name, product.Price));
}
}
}
In this example, the code for the entire CreateProduct feature is tightly grouped within a single file. This makes it extremely easy to locate, understand, and modify everything related to this functionality. We don’t need to navigate multiple layers like controllers, services, and repositories.
Validation is a critical cross-cutting concern in any application. VSA allows for straightforward integration of validation, ensuring data integrity and preventing malicious inputs. We can easily implement validation using the FluentValidation library. Within your slice, you’d define a Validator class that encapsulates the rules specific to your feature’s request model.
public class Validator : AbstractValidator<Request>
{
public Validator()
{
RuleFor(x => x.Name).NotEmpty().MaximumLength(100);
RuleFor(x => x.Price).GreaterThanOrEqualTo(0);
}
}
This validator can then be injected into your endpoint using dependency injection, allowing you to perform validation before processing the request.
public static class CreateProduct
{
public record Request(string Name, decimal Price);
public record Response(int Id, string Name, decimal Price);
public class Validator : AbstractValidator<Request> { ... }
public class Endpoint : IEndpoint
{
public void MapEndpoint(IEndpointRouteBuilder app)
{
app.MapPost("products", Handler).WithTags("Products");
}
public static async Task<IResult> Handler(Request request, IValidator<Request> validator, AppDbContext context)
{
var validationResult = await validator.ValidateAsync(request);
if (!validationResult.IsValid)
{
return Results.BadRequest(validationResult.Errors);
}
var product = new Product
{
Name = request.Name,
Price = request.Price
};
context.Products.Add(product);
context.SaveChanges();
return Results.Ok(new Response(product.Id, product.Name, product.Price));
}
}
}
While VSA excels at managing self-contained features, real-world applications often involve complex interactions and shared logic. Here are a few strategies to address this:
Understanding code smells and refactorings will help you make the most of VSA, ensuring your application remains maintainable and scalable.
VSA is not just a theoretical concept; it has practical applications in real-world projects. Here are a few best practices and considerations for implementing VSA:
Vertical Slice Architecture offers a refreshing approach to structuring your code. By focusing on features, VSA allows you to create cohesive and maintainable applications. Vertical slices are self-contained, making unit and integration testing more straightforward. VSA brings benefits in terms of code organization and development speed, making it a valuable tool in your toolbox. Consider embracing Vertical Slice Architecture in your next project. While it represents a significant mindset shift from Clean Architecture, both approaches have their place and share similar ideas.
How to start with it?
We prepared a simple VSA Project Template that you can download for free.
Download the source code and start exploring.
Download here
https://www.jimmybogard.com/vertical-slice-architecture
Ref : https://medium.com/@andrew.macconnell/exploring-software-architecture-vertical-slice-789fa0a09be6