⚡️ Cross-Cutting Concern شماره ۳ — کشینگ (Caching)
کشینگ یکی از دغدغههای کلیدی در توسعه نرمافزار است که هدف اصلی آن افزایش کارایی (Performance) و مقیاسپذیری (Scalability) سیستم میباشد.
کشینگ بهطور خلاصه یعنی ذخیره موقت دادهها در یک لایه با دسترسی سریعتر تا نیاز به واکشی یا محاسبهی مکرر همان اطلاعات کاهش یابد.
🧠 الگوی Cache Aside
رفتار Pipeline مربوط به کشینگ که در پایین مشاهده میکنی، الگوی Cache Aside را پیادهسازی میکند.
در این الگو، ابتدا کش بررسی میشود تا ببینیم آیا داده از قبل موجود است یا خیر.
در صورتی که داده وجود نداشته باشد، درخواست پردازش شده و نتیجهی جدید در کش ذخیره میشود.
این الگو به دلیل سادگی و کارایی بالا، یکی از محبوبترین استراتژیهای کشینگ به شمار میرود.
📺 (اگر بخواهی نحوهی پیادهسازی آن را ببینی، در مقالهی اصلی نویسنده ویدیو آموزشیاش را قرار داده است.)
⚙️ نکات کلیدی در پیادهسازی کشینگ
در هنگام طراحی و پیادهسازی کشینگ، باید به سه عامل مهم توجه کنی:
چه چیزی را کش کنیم؟
دادههایی را انتخاب کن که واکشی یا محاسبهٔ آنها پرهزینه است و از ثبات کافی برای ذخیره موقت برخوردارند.
ابطال کش (Cache Invalidations)
تصمیم بگیر چه زمانی و چگونه دادههای کششده باید از بین بروند یا بهروزرسانی شوند.
پیکربندی کش (Cache Configuration)
پارامترهایی مثل زمان انقضا (Expiration) و اندازهٔ حافظه را بهدرستی تنظیم کن.
✨ اجرای مؤثر کشینگ باعث بهبود چشمگیر زمان پاسخدهی و کاهش بار روی سیستم میشود —
در نتیجه، به استراتژیای حیاتی برای ساخت برنامههای مقیاسپذیر در NET. تبدیل میگردد.
💻 نمونهکد: Query Caching Pipeline Behavior
internal sealed class QueryCachingPipelineBehavior<TRequest, TResponse>(
ICacheService cacheService,
ILogger<QueryCachingPipelineBehavior<TRequest, TResponse>> logger)
: IPipelineBehavior<TRequest, TResponse>
where TRequest : ICachedQuery
where TResponse : Result
{
public async Task<TResponse> Handle(
TRequest request,
RequestHandlerDelegate<TResponse> next,
CancellationToken cancellationToken)
{
TResponse? cachedResult = await cacheService.GetAsync<TResponse>(
request.CacheKey,
cancellationToken);
string requestName = typeof(TRequest).Name;
if (cachedResult is not null)
{
logger.LogInformation("Cache hit for {RequestName}", requestName);
return cachedResult;
}
logger.LogInformation("Cache miss for {RequestName}", requestName);
TResponse result = await next();
if (result.IsSuccess)
{
await cacheService.SetAsync(
request.CacheKey,
result,
request.Expiration,
cancellationToken);
}
return result;
}
}
با بهکارگیری تکنیکهای جداسازی وابستگیها (Decoupling) که در این مجموعه مرور کردیم، میتونی مطمئن باشی پروژههای NET. تو قابل نگهداری، توسعهپذیر و پایدار خواهند بود.
هر قدمی که برای بهبود مدیریت این دغدغههای مشترک برمیداری،
در واقع گامی است بهسوی معماری نرمافزاری بهتر 🧱
اگر علاقهمند به راهنمای گامبهگام و عمیق در این زمینه هستی، مطالعهٔ کتاب
📗 Pragmatic Clean Architecture
رو از دست نده.
به یاد داشته باش 💬
زیبایی توسعهٔ نرمافزار در تکامل مداوم و جستوجوی بیپایان برای بهبود نهفته است.
👋 این هم از این بخش
امیدوارم برات مفید بوده باشه.
🔖 هشتگها:
#CrossCuttingConcerns
#SoftwareArchitecture
#Scalability #DotNetCore