معماری برش عمودی (Vertical Slice): ساختاربندی برشهای عمودی 🔪
از سازماندهی پروژه خود در لایههای مختلف خسته شدهاید؟ 😫
معماری برش عمودی (VSA) یک جایگزین قانعکننده برای معماریهای لایهای سنتی است. VSA فیلمنامه را در مورد نحوه ساختاردهی کد ما برعکس میکند.
به جای لایههای افقی (Presentation, Application, Domain)، VSA کد را بر اساس ویژگی (feature) سازماندهی میکند. هر ویژگی همه چیز مورد نیاز خود را، از endpointهای API گرفته تا دسترسی به داده، در بر میگیرد.
در این مقاله، ما بررسی خواهیم کرد که چگونه میتوانید برشهای عمودی را در VSA ساختاربندی کنید.
درک برشهای عمودی 🧩
در هسته خود، یک برش عمودی یک واحد مستقل از عملکرد را نشان میدهد. این یک برش از طریق کل پشته اپلیکیشن است. این برش، تمام کدها و کامپوننتهای لازم برای تحقق یک ویژگی خاص را کپسوله میکند.
در معماریهای لایهای سنتی، کد به صورت افقی در لایههای مختلف سازماندهی میشود. پیادهسازی یک ویژگی میتواند در چندین لایه پراکنده شود. تغییر یک ویژگی نیازمند اصلاح کد در چندین لایه است.
VSA
با گروهبندی تمام کدها برای یک ویژگی در یک برش واحد، به این مشکل رسیدگی میکند.
📌این تغییر دیدگاه چندین مزیت به همراه دارد:
✅ انسجام بهبود یافته: کدهای مربوط به یک ویژگی خاص در کنار هم قرار میگیرند، که درک، اصلاح و تست آن را آسانتر میکند.
✅ پیچیدگی کاهش یافته: VSA با اجتناب از نیاز به پیمایش چندین لایه، مدل ذهنی اپلیکیشن شما را ساده میکند.
✅ تمرکز بر منطق بیزینس: ساختار به طور طبیعی بر روی مورد استفاده بیزینس تأکید میکند تا جزئیات پیادهسازی فنی.
✅ نگهداری آسانتر: تغییرات در یک ویژگی، در داخل برش آن محلیسازی میشوند و ریسک عوارض جانبی ناخواسته را کاهش میدهند.
پیادهسازی معماری برش عمودی 👨💻
در اینجا یک مثال از برش عمودی که ویژگی CreateProduct را نشان میدهد، آمده است. ما از یک کلاس استاتیک برای نمایش ویژگی و گروهبندی انواع مرتبط استفاده میکنیم.
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));
}
}
}
کد برای کل ویژگی CreateProduct به طور فشرده در یک فایل واحد گروهبندی شده است. این کار مکانیابی، درک و اصلاح همه چیز مربوط به این عملکرد را بسیار آسان میکند. ما نیازی به پیمایش چندین لایه (مانند کنترلرها، سرویسها، ریپازیتوریها و غیره) نداریم.
معرفی اعتبارسنجی (Validation) در برشهای عمودی 🛡
برشهای عمودی معمولاً نیاز به حل برخی دغدغههای مشترک (cross-cutting concerns) دارند که یکی از آنها اعتبارسنجی است. ما میتوانیم به راحتی اعتبارسنجی را با کتابخانه FluentValidation پیادهسازی کنیم.
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);
}
// ... (ایجاد محصول و بازگرداندن پاسخ)
}
}
}