مزایا و معایب استفاده از الگوی Result ⚖️
مزایای استفاده از الگوی Result: ✅
• مدیریت خطای صریح: فراخواننده باید به صراحت حالتهای موفقیت و شکست را مدیریت کند. از امضای متد، واضح است که ممکن است یک خطا برگردانده شود.
• عملکرد بهبود یافته: سربار مرتبط با استثناها را کاهش میدهد.
• تست بهتر: تست واحد را ساده میکند زیرا mock کردن آبجکت Result بسیار آسانتر از پرتاب و مدیریت استثناها است.
• ایمنی: یک آبجکت result باید حاوی اطلاعاتی باشد که بتواند به دنیای خارج نمایش داده شود. در حالی که شما میتوانید تمام جزئیات را با استفاده از Logger یا ابزارهای دیگر ذخیره کنید.
معایب بالقوه: ❌
• پرحرفی (Verbosity): میتواند در مقایسه با استفاده از استثناها کد بیشتری را به همراه داشته باشد، زیرا شما باید تمام متدها در stacktrace را برای برگرداندن آبجکت Result علامتگذاری کنید.
• برای همه موارد مناسب نیست: استثناها هنوز برای شرایط واقعاً استثنایی که در طول عملیات عادی انتظار نمیرود، مناسب هستند.
الگوی Result عالی به نظر میرسد، اما آیا باید استثناها را فراموش کنیم؟ قطعاً نه! استثناها هنوز کاربرد خود را دارند. بیایید در مورد آن صحبت کنیم.
چه زمانی از استثناها (Exceptions) استفاده کنیم؟ 🤔
استثناها برای موارد استثنایی هستند و من موارد استفاده زیر را میبینم که در آنها ممکن است مناسب باشند:
🔹 مدیریت خطای سراسری
🔹 کد کتابخانه
🔹 اعتبارسنجی محافظ (Guard Validation) در انتیتیهای دامین
بیایید نگاهی دقیقتر به این ۳ مورد بیندازیم:
مدیریت خطای سراسری (Global Exception Handling) 🌍
در اپلیکیشنهای
asp.net core شما، قطعاً باید استثناها را مدیریت کنید. آنها میتوانند از هر جایی پرتاب شوند: دسترسی به دیتابیس، فراخوانیهای شبکه، عملیات I/O، کتابخانهها و غیره.
شما باید آماده باشید که استثناها رخ خواهند داد و آنها را باظرافت مدیریت کنید. برای این کار من IExceptionHandler را پیادهسازی میکنم که از NET 8. به بعد در دسترس است:
internal sealed class GlobalExceptionHandler : IExceptionHandler
{
private readonly ILogger<GlobalExceptionHandler> _logger;
public GlobalExceptionHandler(ILogger<GlobalExceptionHandler> logger)
{
_logger = logger;
}
public async ValueTask<bool> TryHandleAsync(
HttpContext httpContext,
Exception exception,
CancellationToken cancellationToken)
{
_logger.LogError(exception, "Exception occurred: {Message}", exception.Message);
var problemDetails = new ProblemDetails
{
Status = StatusCodes.Status500InternalServerError,
Title = "Server error"
};
httpContext.Response.StatusCode = StatusCodes.Status500InternalServerError;
await httpContext.Response.WriteAsJsonAsync(problemDetails, cancellationToken);
return true;
}
}
کد کتابخانه (Library Code) 📚
در کتابخانهها، معمولاً وقتی چیزی اشتباه پیش میرود، استثناها پرتاب میشوند.
دلایل این امر عبارتند از:
🔹 اکثر توسعهدهندگان با استثناها آشنا هستند و میدانند چگونه آنها را مدیریت کنند.
🔹 کتابخانهها نمیخواهند نظرکرده (opinionated) باشند و از یک کتابخانه الگوی Result خاص استفاده کنند یا نسخه خود را پیادهسازی کنند.
اما به یاد داشته باشید هنگام ساخت کتابخانهها، از استثناها به عنوان آخرین گزینه موجود استفاده کنید. اغلب بهتر است که یک null، یک کالکشن خالی، یا مقدار بولین false را برگردانید تا اینکه یک استثنا پرتاب کنید.
اعتبارسنجی محافظ در انتیتیهای دامین (Domain Entities Guard Validation) 🛡
هنگام پیروی از اصول طراحی دامنه محور (DDD)، شما مدلهای دامین خود را با استفاده از سازندهها یا متدهای factory میسازید. اگر شما دادهای را برای ساخت آبجکت دامین پاس دهید و این داده نامعتبر باشد (که هرگز نباید باشد) - شما میتوانید یک استثنا پرتاب کنید. این نشانهای خواهد بود که اعتبارسنجی ورودی، مپینگ یا دیگر لایههای اپلیکیشن شما یک باگ دارند که باید برطرف شود.
خلاصه 📝
جایگزین کردن استثناها با الگوی Result در NET. میتواند به کد قویتر و قابل نگهداریتر منجر شود.
با مدیریت صریح موارد موفقیت و شکست، توسعهدهندگان میتوانند کد واضحتری بنویسند که تست و درک آن آسانتر است.
در حالی که ممکن است برای همه سناریوها مناسب نباشد، گنجاندن الگوی Result میتواند به طور قابل توجهی مدیریت خطا را در اپلیکیشنهای شما بهبود ببخشد.
امیدوارم این مقاله برایتان مفید باشد.