1️⃣ API Gateway 🛂🚪(بخش اول)
ءAPI Gateway یک نقطهٔ ورودی واحد است که بین Clientها و سرویسهای Backend قرار میگیرد.
این کامپوننت در نقش Reverse Proxy عمل میکند و درخواستها را به Microservice مناسب Route میکند. علاوهبراین، بسیاری از Cross-Cutting Concernها مثل احراز هویت، Rate Limiting، و Transform کردن درخواستها را مدیریت میکند.
نحوهٔ کارکرد API Gateway ⚙️📨
تمام درخواستهای Client به یک Endpoint واحد (API Gateway) ارسال میشود، نه به تکتک سرویسها
ءGateway پس از دریافت درخواست، عملیات Authentication و Authorization را انجام میدهد
قوانین Rate Limiting و Throttling اعمال میشود تا سرویسها زیر فشار از کار نیفتند
ءGateway با توجه به مسیر URL یا Headerها، Request را به سرویس مناسب Route میکند
میتواند پاسخ چند سرویس را جمعآوری و به یک Response تجمیعشده برای Client تبدیل کند
مزایا ✨
🔹️سادهسازی سمت Client با ارائهٔ یک Endpoint واحد
🔹️ایجاد لایهٔ انتزاعی برای تغییر سرویسهای Backend بدون اثرگذاری روی Client
🔹️بهبود امنیت با مخفی کردن ساختار داخلی سرویسها و Endpointهای واقعی آنها
معایب ⚠️
🔸️تبدیل شدن به Single Point of Failure در صورت طراحی غلط
🔸️احتمال تبدیل شدن به Bottleneck در ترافیکهای بالا
🔸️افزودن Latency به هر درخواست بهخاطر یک Roundtrip اضافی شبکه
موارد استفاده 🎯
• معماریهای Microservices که نیاز به یک رابط یکپارچه برای چند سرویس مختلف دارند
• سیستمهایی که Authentication و Authorization یکپارچه نیاز دارند
• مدرنسازی سیستمهای Legacy با پنهان کردن سرویسهای قدیمی پشت یک API مدرن
تفاوت Task و ValueTask چیه؟ 🤔⚡️
خیلیها فکر میکنن ValueTask فقط یک نسخه سبکتر از Task هست…
ولی داستان خیلی جالبتره!
بیاین با یک مثال واقعی درکش کنیم 👇
📌 ءTask چیه؟
🔹️ءTask یعنی:
«یک عملیات async که ممکنه هنوز انجام نشده باشه.»
در NET.، حتی اگر عملیات نتیجهای داشته باشه، یه Task جدید ساخته میشه.
این ساخت Task هزینه داره:
• یک Object جدید ساخته میشه
• ءGC باید بعداً جمعش کنه
• ءMemory Allocation رخ میده
در عملیات سبک و پرتکرار؟
این Allocations میتونه پرفورمنس رو زمین بزنه.
📌 ءValueTask چیه؟
ءValueTask اومده همین مشکل رو حل کنه!
🔸️ءValueTask یعنی:
«یک عملیات async که ممکنه نتیجه رو همین الان داشته باشه.»
اگر نتیجه آماده باشه، ValueTask هیچ object اضافهای ایجاد نمیکنه
• یعنی Zero Allocation
• یعنی سرعت بیشتر
• یعنی فشار کمتر روی GC
به همین دلیل یکی از سریعترین Primitiveهای داتنته.
💥 یک مثال واقعی
تصور کن یک Cache داری:
public Task<Item> GetItemAsync(string key)
{
if (_cache.TryGetValue(key, out var item))
return Task.FromResult(item); // Allocates
return FetchFromDbAsync(key);
}
در حالت بالا حتی برای cache hit هم یک Task جدید ساخته میشه!
ولی با ValueTask:
public ValueTask<Item> GetItemAsync(string key)
{
if (_cache.TryGetValue(key, out var item))
return new ValueTask<Item>(item); // No allocation
return new ValueTask<Item>(FetchFromDbAsync(key));
}
نتیجه؟
در حالت cache hit → هیچ Task اضافهای ساخته نمیشود.
⚠️ اما ValueTask همیشه بهتر نیست!
نکات مهم:
1️⃣ فقط یک بار میتونی awaitش کنی
چون value-type هست
اگر چند بار await کنی → Undefined Behavior
2️⃣ اگر عملیات همیشه async باشه ValueTask فقط پیچیدگی اضافه میکنه. Task مناسبتره.
3️⃣ ءchaining پیچیدهتره
ءConfigureAwait، ContinueWith و … روی ValueTask رفتارهای خاص دارند.
🎯 کی Task؟ کی ValueTask؟
🔸️ از Task استفاده کن وقتی:🔸️
عملیات همیشه async هست
مثل: query دیتابیس، ارسال ایمیل، فراخوانی API
نتیجه زود آماده نمیشود
سرویس ساده و خوانایی مهمتر از پرفورمنسه
🔸️ از ValueTask استفاده کن وقتی:🔸️
عملیات گاهی sync و گاهی async است
مانند: Cache, MemoryReader, CPU-bound operations
عملیات پرتکرار است و performance حیاتی است
میخواهی مخصــوصاً Allocation را صفر کنی
📝 جمعبندی
ءTask → همیشه async → همیشه object جدید → هزینه بیشتر
ءValueTask → async یا sync → گاهی بدون object → سریعتر
اما ValueTask ابزار پیشرفتهست.
نسبت به Task مسئولیت بیشتری روی دوش برنامهنویسه میذاره.
پیشنهاد مایکروسافت:
“Only use ValueTask when performance measurements justify it.”
2️⃣ Point To Point Async Integration ⚡️📩(بخش دوم)
ءPoint To Point Async Integration یک الگوی ارتباطی هست که در آن یک سرویس، پیامها را از طریق یک Message Queue برای سرویس دیگر ارسال میکند.
برخلاف ارتباط synchronous، فرستنده منتظر پاسخ نمیماند و به کار خودش ادامه میدهد؛ درحالیکه سرویس گیرنده پیامها را با سرعت و زمانبندی خودش مصرف میکند.
این موضوع یک رابطه غیرهمزمان اما همچنان مستقیم بین دو سرویس ایجاد میکند.
🔧 How it works:
🔸️ءService A پیام را به یک صف اختصاصی که فقط Service B از آن مصرف میکند ارسال میکند
🔹️ءMessage Queue بهعنوان بافر بین فرستنده و گیرنده عمل میکند
🔸️ءService A بلافاصله بعد از ارسال پیام ادامه پروسه را انجام میدهد
🔹️ءService B پیامها را در زمان موردنظر خودش مصرف میکند
🔸️ءMessage Broker تضمین میکند که پیامها بهدرستی و قابلاعتماد ارسال شوند
🔹️اگر سرویـس B موقتاً در دسترس نباشد، پیامها در صف باقی میمانند
🔸️ءDead Letter Queue برای پیامهایی که بعد از چند تلاش دوباره fail میشوند استفاده میشود
✅ Benefits:
• ءDecouples services in time → سرویسها میتوانند با سرعتهای متفاوت کار کنند
• ءResilience بالاتر → قطع بودن Service B روی A تأثیری ندارد
• ءLoad leveling طبیعی از طریق صف
• ءAsync processing برای کارهای طولانی بدون بلاک کردن سرویس فرستنده
• ءScalability آسان با افزودن Consumerهای بیشتر
❌ Drawbacks:
• ءMessage Broker یک وابستگی اضافه است و ممکن است Single Point of Failure ایجاد کند
• منجر به Eventual Consistency میشود
• ءDebugging سختتر بهدلیل جریان غیرهمزمان پیامها
🎯 Use cases:
1️⃣ءBackground Job Processing
2️⃣سیستمهای پردازش سفارش (Order Fulfillment)
3️⃣ءEmail / Notification Services
4️⃣سیستمهایی با Load نامتوازن که Queue نقش بافر ایفا میکند
Forwarded from tech-afternoon (Amin Mesbahi)
چند سالیه که سهم عبارت «AI» لابلای جملات، تیتر اخبار، صحبتهای یومیهی عوام تا متخصصین، شهروند تا دولتمرد، مصرفکننده تا صنعتگر روز به روز بیشتر شده. ترمهایی مثل Vibe Coding یا AI-Driven Development یا AI Slop به دایرهی واژگانمون اضافه شدن. حالا این وسط یه عده سودهای کوتاهمدت میبرن، مثل پکیجفروشها، سرویسهایی که چند تا API رو صدا میکنن و یه سرویس مثلا هوشمند ارائه میکنن؛ و برخی هم بیزنسهای بر پایهی این تحول ایجاد کردن، مثل سازندههای مدلهای پایه، سرویسهای کاربردی مدیریت AI مثل Agent Manager یا Prompt Engineering Platform و… یا اینکه AI رو مثل یک ابزار دیدن و کاربری اون رو «صحیح و اصولی» یاد گرفتن و مرتبا بهروز میشن تا مثل دورانی که اکثریت با محدودیتهای نرمافزارهای دسکتاپ دستوپنجه نرم میکردن و عدهای خیلی زود و به موقع، توسعه مبتنی بر وب رو جایگزین کردن، بتونن از مواهب AI به نفع بهرهوری، خلاقیت، و توسعه پایدار بهره ببرن.
این مطلب رو در چند بخش مینویسم، با توجه به فضای جامعه توسعه نرمافزار، متن رو خیلی مطالعه-محور مینویسم تا مقاومت کمتری نسبت به تحلیل شخصی داشته باشه؛ اول به «بد»، و در ادامه به «زشت» و نهایتا به «خوب» میپردازم:
- کد چرخشی (Code Churn): سیگنال خطر: تحقیقات GitClear روی ۲۱۱ میلیون خط کد تغییریافته بین سالهای ۲۰۲۰ تا ۲۰۲۴ نشون میده که Code Churn (درصد کدی که کمتر از دو هفته پس از نوشته شدن اصلاح یا حذف میشه) در سال ۲۰۲۴ دو برابر سال ۲۰۲۱ شده. این یعنی کدی که AI تولید میکنه، اغلب ناقص یا اشتباهه و نیاز به بازنگری سریع داره.
- کپیپیست به جای معماری: در سال ۲۰۲۴، GitClear افزایش ۸ برابری در بلوکهای کد تکراری (۵ خط یا بیشتر) رو ثبت کرده (یعنی ۱۰ برابر بیشتر از دو سال پیشش). مشکل اینجاست که AI به جای refactor کردن و استفاده مجدد از کد موجود، ترجیح میده کد جدید بنویسه. نتیجه؟ نقض اصل (DRY (Don't Repeat Yourself و کدبیسی که مدیریتش کابوسه.
در سال ۲۰۲۴، ۴۶٪ تغییرات کد، خطوط جدید بودند و کد کپیپیست شده، بیش از کد جابجا شده (moved) بوده (یعنی کمتر refactoring شده و بیشتر به صورت بیرویه کد اضافه شده).
- افزایش باگ و کاهش پایداری: مطالعه شرکت Uplevel که توسعهدهندههای با دسترسی به Copilot رو بررسی کرده، نشون میده این دولوپرها به طور معناداری نرخ باگ بالاتری تولید کردن، در حالی که بهرهوری کلیشون ثابت مونده. گزارش DORA 2024 گوگل هم تأیید میکنه: ۲۵٪ افزایش در استفاده از AI منجر به بهبود در code review و مستندات میشه، اما ۷.۲٪ کاهش در پایداری تحویل (delivery stability) ایجاد میکنه. همچنین گزارش Harness 2025 نشون داد اکثر توسعهدهندگان زمان بیشتری صرف debugging کد تولیدشده توسط AI و رفع آسیبپذیریهای امنیتی میکنند.
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from tech-afternoon (Amin Mesbahi)
اگر "بد" نمایانگر اصطکاک عملیاتیه، "زشت" نمایانگر ریسک سیستمیه. دادههای سالهای ۲۰۲۴ و ۲۰۲۵ به بحرانی قریبالوقوع در قابلیت نگهداری و امنیت نرمافزار اشاره میکنن...
جنبهی «زشت» ماجرا اینه که نتیجهی نهایی استفاده از هوش مصنوعی مولد بهشدت وابسته به بلوغ فنی و انضباط تیمه. اگر تیمی فرهنگ کدنویسی سالم، معیارهای کیفی و فرایندهای بازبینی روشن نداشته باشه، برای استفاده از GenAI دستورالعمل «فکر شده» و متناسب با نیازها و استعداد تیم نداشته باشه؛ AI میتونه هرجومرج ایجاد کنه یا هرجومرج موجود رو تشدید کنه. توی برخی نظرسنجیها دیده شده که کارکنان احساس کردن بهرهوریشون با وجود هوش مصنوعی کاهش یافته!
بدهی فنی که قابل پرداخت نیست
پروفسور Armando Solar-Lezama استاد دانشگاه MIT میگه: "AI مثل یه کارت اعتباری جدیده که به ما اجازه میده بدهی فنی رو به روشهایی انباشته کنیم که هرگز قبلاً نتونسته بودیم."
مطالعه دانشگاه Carnegie Mellon روی ۸۰۷ ریپو GitHub که بین ژانویه ۲۰۲۴ تا مارچ ۲۰۲۵ که از Cursor استفاده کرده بودن، نشون میده که با وجود بهبودهای مدلهای AI (Sonnet، GPT و غیره)، الگوی کاهش کیفیت کد همچنان ادامه داره. حتی با ارتقای ابزارها، کیفیت کد مسیر خودش رو به سمت افول طی میکنه! دلایلی مثل زمان صرف زیاد برای آزمونوخطا با ابزار یا رفع خطاهای ناشی از اون رو میشه در نظر گرفت؛ و تفاوت نتایج بین شرکتهای مختلف (از افزایش کارامدی تا معضلات عمیق) نشون میده که صرف خریداری یا فعالسازی ابزار یا سرویس هوشمصنوعی تضمینی برای موفقیت نیست.
- نابودی دانش تیمی: باز هم مطالعات نشون میدن در ۱۶.۸٪ از چتهای ChatGPT، کد تولید شده به صورت دقیق (با تغییرات جزئی) توی پروژههای GitHub استفاده شدن. مشکل اینجاست: وقتی توسعهدهندهها کد AI رو بدون درک عمیق copy میکنن، expertise model توی تیم توسعه آسیب میبینه و Truck Factor (تعداد اعضای تیم که از دست دادنشون پروژه را میتونه نابود کنه، گاهی هم bus factor گفته میشه) بدتر میشه.
- معضل Context Collapse در آینده: اگه کدهایی که مدلهای آینده از روی اونها train میشن، پیچیدهتر و غیرقابل نگهداریتر بشه، خطر واقعی اینه که مدلهای جدیدتر این روندها رو به صورت نمایی تقویت و تشدید میکنن و کد بدتری تولید خواهند کرد؛ دلیلش هم اینه که از روی کدهای شلوغ و بیکیفیتی آموزش دیدهاند.
- مشارکتکننده دورهگرد: کدهای تولید شده توسط هوش مصنوعی شبیه کار یک پیمانکار کوتاهمدته: از نظر عملکردی در انزوا، صحیح، اما منفک از قراردادها و معماری سیستم کلی! این منجر به تکهتکه شدن (Fragmentation) سبک و منطق کد میشه.
- پارادوکس بهرهوری مهندسی: ترکیب "خوب" (سرعت) و "زشت" (ریزش/کیفیت) منجر به شکلگیری "پارادوکس بهرهوری مهندسی" شده. سازمانها شاهد افزایش چشمگیر خروجی (پولریکوئستها، ویژگیها) هستن، اما همزمان کاهش پایداری و افزایش هزینههای نگهداری رو تجربه میکنن. گزارش سال ۲۰۲۵ DORA از گوگل نشون داد که افزایش ۹۰ درصدی در پذیرش هوش مصنوعی با افزایش ۹ درصدی نرخ باگ و افزایش ۹۱ درصدی زمان بازبینی کد همبستگی داره (بدتر از گزارش DORA در سال ۲۰۲۴ که پیشتر در بخش افزایش باگ و کاهش پایداری قسمت اول اشاره کردم). زمان صرفهجویی شده در تایپ کردن کد، عملاً به مرحله بازبینی و دیباگ منتقل شده؛ با این تفاوت که هزینه این مرحله بالاتره، چون خوندن کد تولید شده سختتر از نوشتنشه.
- انباشت بدهی فنی: انباشت کدهای ضعیف ساختاری، که با پیچیدگی بالا (Cyclomatic Complexity) و تکرار زیاد مشخص میشن؛ بدهیای ایجاد میکنه که باید با بهره پرداخت بشه. Forrester پیشبینی میکنه که سال ۲۰۲۶، ۷۵٪ از شرکتها به دلیل تولید کد کنترلنشدهی هوش مصنوعی، با بدهی فنی "متوسط تا شدید" مواجه خواهند شد.
Please open Telegram to view this post
VIEW IN TELEGRAM
3️⃣ Publish/Subscribe Pattern 📣📡(بخش سوم)
ءPublish/Subscribe Pattern یک الگوی پیامرسانی غیرهمزمان است که در آن Publisherها پیامها یا Eventها را به یک Message Broker یا Event Bus مرکزی ارسال میکنند، بدون اینکه بدانند چه کسی مصرفکننده آنهاست.
در مقابل، Subscriberها علاقهمندی خود را به انواع خاصی از پیامها ثبت میکنند و بهصورت خودکار هنگام انتشار آنها را دریافت میکنند. این الگو منجر به یک Event-Driven Architecture با Coupling بسیار کم میشود.
🔍 تفاوت اصلی Publish/Subscribe با Point To Point Async Integration
ءPublish/Subscribe فرض میکند که چندین Subscriber میتوانند برای یک نوع Event وجود داشته باشند
ءPoint To Point Async Integration فرض میکند که فقط یک Subscriber برای هر نوع پیام وجود دارد
🔧 How it works:
🔹️ءPublisherها پیامها یا Eventها را به Topic یا Channelهای Message Broker ارسال میکنند بدون اینکه از Subscriberها اطلاعی داشته باشند
🔸️ءMessage Broker پیامها را دریافت، ذخیره و توزیع میکند
🔹️ءSubscriberها علاقهمندی خود را به Topic یا Event Type خاص ثبت میکنند
🔸️با انتشار یک پیام، Broker نسخهای از آن را به تمام Subscriberهای فعال ارسال میکند
🔹️چندین Subscriber میتوانند همزمان و مستقل یک پیام یکسان را پردازش کنند
🔸️این الگو از ارتباط One-to-Many پشتیبانی میکند
🔹️اضافه یا حذف Subscriberها نیازی به تغییر در Publisher ندارد
🔸️امکان Message Filtering وجود دارد تا هر Subscriber فقط پیامهای مرتبط را دریافت کند
✅ Benefits:
• ءDecoupling کامل بین Publisher و Subscriber
• ءScalability بالا با پردازش موازی پیامها توسط چند Subscriber
• مناسب برای Event-Driven Architecture
• افزودن قابلیتهای جدید فقط با اضافه کردن Subscriber جدید
• ءResilience بهتر؛ خطای یک Subscriber روی بقیه تأثیر ندارد
❌ Drawbacks:
• ءMessage Broker یک وابستگی مهم است و میتواند Single Point of Failure باشد
• ءDebugging و Tracing سختتر بهدلیل ماهیت غیرهمزمان
• چالشهای Eventual Consistency
• نیاز به طراحی دقیق برای Ordering پیامها و Duplicate Handling
🎯 Use cases:
🔹️سیستمهای Event-Driven که چند سرویس باید به یک Event واکنش نشان دهند
🔸️ءReal-time Notification (چت، داشبوردها، مانیتورینگ)
🔹️ءMicroservices برای همگامسازی دادهها از طریق Integration Events
🔸️سناریوهایی که سرویسهای جدید باید بدون تغییر Publisher به Eventها گوش دهند
🔹️ءWorkflowهایی که با یک Event چند مرحله در سرویسهای مختلف فعال میشوند
Forwarded from Sonora.Dev
🛠 حل مشکل Double Booking در سیستمهای رزرو
تمام پلتفرمهای رزرو مدرن با چالش Double Booking روبرو هستند: وقتی دو یا چند کاربر بهطور همزمان تلاش میکنند یک منبع محدود را رزرو کنند.
این مشکل، یک race condition است که میتواند اعتماد کاربر را نابود کند و برای سیستمهای پرترافیک، بحرانی است.
1️⃣ Pessimistic Locking
مکانیزم: قفل روی رکورد دیتابیس (SELECT ... FOR UPDATE)
مزایا: تضمین Consistency، جلوگیری از race condition
معایب: Throughput محدود، Deadlock Risk، مقیاسپذیری پایین
مناسب برای: Low-traffic / کمرقابت (مثل Web Check-in هواپیما)
2️⃣ Optimistic Locking
مکانیزم: بدون قفل، با استفاده از Versioning
مزایا: عملکرد خواندن بالا، افزایش concurrency
معایب: Conflict و Retry در High Contention، افزایش load روی DB
مناسب برای: Moderate traffic و منابع کمرقابت (رزرو هتل، رستوران)
3️⃣ In-Memory Distributed Locking
مکانیزم: Lock توزیعشده در Redis / In-Memory Cache
مزایا: کاهش فشار روی دیتابیس، High Concurrency، Low Latency
معایب: پیچیدگی زیرساخت، مدیریت crash و expiration، ریسک Lock ناتمام
مناسب برای: Popular events با 1K–10K RPS
4️⃣ Virtual Waiting Queue
مکانیزم: Async Queue + Backpressure + FIFO
مزایا:
محافظت از دیتابیس و cache در برابر surge
بهبود تجربه کاربری و fairness
مقیاسپذیری بسیار بالا (High Throughput)
معایب: پیچیدگی عملیاتی، نیاز به SSE یا WebSocket برای اطلاعرسانی
مناسب برای: Ultra High Traffic events (کنسرتها، فیلمهای بلاکباستر)
✅ جمعبندی فنی
هیچ راهحل واحدی برای همه سناریوها وجود ندارد
انتخاب معماری به الگوی ترافیک، سطح رقابت و محدودیت منابع وابسته است
سیستمهای High-Traffic باید Lock-free + Async + Fair Queue داشته باشند تا Tail Latency و double booking کنترل شود
Monitoring، Retry Policies و Backpressure، اجزای کلیدی در طراحی سیستم رزرو مقیاسپذیر هستند
#SystemDesign #DistributedSystems #Scalability #Concurrency #BackendArchitecture #HighTraffic #BookingSystems #Microservices #Queueing
تمام پلتفرمهای رزرو مدرن با چالش Double Booking روبرو هستند: وقتی دو یا چند کاربر بهطور همزمان تلاش میکنند یک منبع محدود را رزرو کنند.
این مشکل، یک race condition است که میتواند اعتماد کاربر را نابود کند و برای سیستمهای پرترافیک، بحرانی است.
1️⃣ Pessimistic Locking
مکانیزم: قفل روی رکورد دیتابیس (SELECT ... FOR UPDATE)
مزایا: تضمین Consistency، جلوگیری از race condition
معایب: Throughput محدود، Deadlock Risk، مقیاسپذیری پایین
مناسب برای: Low-traffic / کمرقابت (مثل Web Check-in هواپیما)
2️⃣ Optimistic Locking
مکانیزم: بدون قفل، با استفاده از Versioning
مزایا: عملکرد خواندن بالا، افزایش concurrency
معایب: Conflict و Retry در High Contention، افزایش load روی DB
مناسب برای: Moderate traffic و منابع کمرقابت (رزرو هتل، رستوران)
3️⃣ In-Memory Distributed Locking
مکانیزم: Lock توزیعشده در Redis / In-Memory Cache
مزایا: کاهش فشار روی دیتابیس، High Concurrency، Low Latency
معایب: پیچیدگی زیرساخت، مدیریت crash و expiration، ریسک Lock ناتمام
مناسب برای: Popular events با 1K–10K RPS
4️⃣ Virtual Waiting Queue
مکانیزم: Async Queue + Backpressure + FIFO
مزایا:
محافظت از دیتابیس و cache در برابر surge
بهبود تجربه کاربری و fairness
مقیاسپذیری بسیار بالا (High Throughput)
معایب: پیچیدگی عملیاتی، نیاز به SSE یا WebSocket برای اطلاعرسانی
مناسب برای: Ultra High Traffic events (کنسرتها، فیلمهای بلاکباستر)
✅ جمعبندی فنی
هیچ راهحل واحدی برای همه سناریوها وجود ندارد
انتخاب معماری به الگوی ترافیک، سطح رقابت و محدودیت منابع وابسته است
سیستمهای High-Traffic باید Lock-free + Async + Fair Queue داشته باشند تا Tail Latency و double booking کنترل شود
Monitoring، Retry Policies و Backpressure، اجزای کلیدی در طراحی سیستم رزرو مقیاسپذیر هستند
#SystemDesign #DistributedSystems #Scalability #Concurrency #BackendArchitecture #HighTraffic #BookingSystems #Microservices #Queueing
بهترین رهبران پر سروصدا نیستند.
برخی از مورد اعتمادترین افراد در جمع، کمترین صحبت را میکنند.
شما این نوع افراد را میشناسید:
🔹️حرفشان را عملی میکنند و به قول خود پایبندند
🔸️قبل از صحبت کردن با دقت گوش میدهند
🔹️برای دیگران فضا ایجاد میکنند بدون اینکه دنبال اعتبار باشند
🔸️آنها در میان آشوب، آرامش میآورند. نیازی ندارند قدرت یا نفوذ خود را نشان دهند.
آنها این اعتماد را به دست آوردهاند.
اغلب ما رهبر بودن را با کاریزما، دیدهشدن یا جسارت مرتبط میکنیم، اما قابل اعتماد بودن، تواضع و شایستگی، توان رهبر بودن را چند برابر میکند.
اگر میخواهید بدون داشتن عنوان، رهبری کنید، ابتدا با کسی باشید که دیگران بتوانند روی او حساب کنند، بهویژه زمانی که اوضاع پیچیده و نامنظم است.
برخی از مورد اعتمادترین افراد در جمع، کمترین صحبت را میکنند.
شما این نوع افراد را میشناسید:
🔹️حرفشان را عملی میکنند و به قول خود پایبندند
🔸️قبل از صحبت کردن با دقت گوش میدهند
🔹️برای دیگران فضا ایجاد میکنند بدون اینکه دنبال اعتبار باشند
🔸️آنها در میان آشوب، آرامش میآورند. نیازی ندارند قدرت یا نفوذ خود را نشان دهند.
آنها این اعتماد را به دست آوردهاند.
اغلب ما رهبر بودن را با کاریزما، دیدهشدن یا جسارت مرتبط میکنیم، اما قابل اعتماد بودن، تواضع و شایستگی، توان رهبر بودن را چند برابر میکند.
اگر میخواهید بدون داشتن عنوان، رهبری کنید، ابتدا با کسی باشید که دیگران بتوانند روی او حساب کنند، بهویژه زمانی که اوضاع پیچیده و نامنظم است.
4️⃣ Outbox Pattern 📤📦(بخش چهارم)
ءOutbox Pattern با ذخیرهکردن Eventها در یک جدول دیتابیس (Outbox) در همان Transaction تغییرات دادههای بیزینسی، انتشار قابلاعتماد Eventها را تضمین میکند.
سپس یک فرآیند جداگانه، Eventها را از Outbox خوانده و به Message Broker منتشر میکند.
به این شکل تضمین میشود که Eventها اگر و فقط اگر Transaction بیزینسی موفق باشد منتشر شوند.
🔧 How it works:
🔹️وقتی یک سرویس داده بیزینسی را تغییر میدهد، همزمان رکورد Event را در جدول Outbox و در همان Transaction دیتابیس درج میکند
🔸️ءTransaction دیتابیس، Atomicity بین تغییر داده و ایجاد Event را تضمین میکند
🔹️یک فرآیند Background یا Worker بهصورت مداوم جدول Outbox را برای Eventهای منتشرنشده بررسی میکند
🔸️این فرآیند Eventها را خوانده و به Message Broker ارسال میکند
🔹️بعد از انتشار موفق، Event بهعنوان پردازششده علامتگذاری یا از Outbox حذف میشود
🔸️اگر انتشار شکست بخورد، Event در Outbox باقی میماند و بهصورت خودکار Retry میشود
🔹️این الگو مشکل Dual-Write (ذخیره داده موفق، اما انتشار Event ناموفق) را حذف میکند
🔸️ءEventها حداقل یکبار (At-Least-Once) منتشر میشوند و Consumerها باید Duplicateها را مدیریت کنند
✅ Benefits:
• تضمین میکند Eventها فقط در صورت موفقیت Transaction بیزینسی منتشر شوند
• مشکل Dual-Write بین دیتابیس و Message Broker را بهطور کامل حذف میکند
• یک Audit Trail قابلاعتماد از تمام Eventهای سیستم در دیتابیس فراهم میکند
• امکان Event Replay و Recovery با نگهداشتن تاریخچه Eventها
❌ Drawbacks:
• ایجاد Eventual Consistency چون Eventها بلافاصله منتشر نمیشوند و Polling دارند
• نیاز به زیرساخت اضافی برای Outbox Processor و مانیتورینگ آن
• ایجاد سربار عملکردی بهدلیل نوشتنهای اضافی در دیتابیس و Polling
• نیاز به مدیریت Duplicate Eventها در Consumer (میتوان از InBox Pattern + Idempotence استفاده کرد)
🎯 Use cases:
🔹️ءMicroservices که باید انتشار Event بعد از تغییر دادهها را قطعاً تضمین کنند
🔹️سیستمهای Event Sourcing که هر تغییر وضعیت باید بهعنوان Event ثبت شود
🔹️هر سناریویی که Consistency بین سرویسها حیاتی است و از دست رفتن پیام غیرقابلقبول است
🧠 4️⃣2️⃣ سؤال مهم مصاحبه برای Software Architect
اگر قراره در نقش Software Architect مصاحبه بدی (یا مصاحبه بگیری)، این سؤالها فقط دانش فنی رو نمیسنجن؛
بلکه طرز فکر معماری، تصمیمگیری و تجربهی واقعی تو رو محک میزنن.
1️⃣ چطور بین Monolith، Modular Monolith و Microservices برای یک سیستم جدید تصمیم میگیری؟
2️⃣ ءTrade-off بین Layered Architecture، Vertical Slice و Hexagonal Architecture چیه؟
3️⃣ چطور اصل Principle of Least Surprise رو در طراحی کامپوننتها رعایت میکنی؟
4️⃣ موقع Scale کردن سیستم، چطور جلوی Accidental Complexity رو میگیری؟
5️⃣ چه زمانی Synchronous و چه زمانی Asynchronous Communication رو انتخاب میکنی؟
6️⃣ چطور Idempotent Operation طراحی میکنی وقتی سیستم Retry داره؟
7️⃣ در یک Workflow با throughput بالا، چطور از Race Condition جلوگیری میکنی؟
8️⃣ چه زمانی از Queue، چه زمانی از Stream و چه زمانی از Direct Call استفاده میکنی؟
9️⃣ نقش Saga Pattern در workflowهای طولانی چیه؟
🔟 چطور سیستم رو برای Exactly-once یا Effectively-once processing طراحی میکنی؟
1️⃣1️⃣ با Partial Failure در سیستمهای توزیعشده چطور برخورد میکنی؟
2️⃣1️⃣ چه Patternهایی به حفظ Consistency بین چند سرویس کمک میکنن؟
3️⃣1️⃣ چطور سیستمی طراحی میکنی که در برابر Failure وابستگیهای خارجی دوام بیاره؟
4️⃣1️⃣ رویکردت برای تشخیص و ایزوله کردن سرویسهای کند چیه؟
5️⃣1️⃣ چطور Caching Layer (L1/L2) طراحی میکنی که هم Stale Data نداشته باشه هم Thundering Herd ایجاد نکنه؟
6️⃣1️⃣ چه نشانههایی میگه سیستم به Vertical Scaling نیاز داره یا Horizontal Scaling؟
7️⃣1️⃣ چطور Read-heavy workload طراحی میکنی برای بیشترین throughput؟
8️⃣1️⃣ چه Patternهایی باعث کاهش Load دیتابیس میشن بدون ضربه زدن به Consistency؟
9️⃣1️⃣ با مشکل Hot Partition چطور برخورد میکنی؟
0️⃣2️⃣ سیستمهای با Write Volume بالا رو چطور مدیریت میکنی؟
1️⃣2️⃣ چطور بین Relational Database و Document Database انتخاب میکنی؟
2️⃣2️⃣ چه زمانی Distributed Transaction و چه زمانی Eventual Consistency؟
3️⃣2️⃣ چطور یک سیستم Audit-friendly طراحی میکنی بدون اینکه Performance نابود بشه؟
4️⃣2️⃣ استراتژیت برای Schema Evolution بدون Downtime چیه؟
🎯 جمعبندی
این سؤالها دنبال جواب کتابی نیستن.
مصاحبهکننده میخواد بدونه:
• چطور فکر میکنی
• چطور تصمیم میگیری
• چطور با Trade-offها کنار میای
اگه بتونی پشت هر جواب، تجربه یا منطق داشته باشی، یعنی واقعاً Architect هستی نه فقط عنوانش رو داری.
چگونه با GitHub Actions و NET. یک CI/CD Pipeline بسازیم
آیا میخواهید فرآیند توسعه نرمافزار خود را سادهتر کنید و چرخههای انتشار را سریعتر انجام دهید؟ 🚀
تصور کنید بتوانید با هر تغییر کد، برنامههای NET. خود را بهصورت خودکار build، test و deploy کنید.
با CI/CD میتوانید بهطور قابلتوجهی کارهای دستی را کاهش دهید و تمرکز بیشتری روی ساخت نرمافزار داشته باشید، در نتیجه انتشارهای سریعتر و قابلاعتمادتری خواهید داشت.
و شروع CI/CD هیچوقت به این اندازه آسان نبوده است.
ءGitHub Actions کاملاً رایگان و ساده برای استفاده هستند. ✅
بنابراین، در این مطلب موارد زیر را بررسی میکنیم:
• معرفی CI/CD و GitHub Actions
• ساخت pipeline برای build و test در NET.
• ساخت pipeline برای deployment روی Azure App Service
ءContinuous Integration و Continuous Delivery چیست؟
قبل از اینکه به GitHub Actions بپردازیم، سعی میکنم بهصورت خلاصه توضیح بدهم CI/CD چیست.
ءCI/CD روشی است برای افزایش دفعات تحویل قابلیتهای جدید، با اضافه کردن اتوماسیون به workflow توسعه نرمافزار.
ءContinuous Integration یا «CI» به فرآیند خودکار همگامسازی کد جدید با repository اشاره دارد. هر تغییر جدید در کد برنامه بلافاصله build، test و merge میشود.
ءContinuous Delivery یا Deployment یا «CD» به خودکارسازی بخش deployment از workflow اشاره دارد. زمانی که تغییری ایجاد میکنید که در repository merge میشود، این مرحله مسئول deploy کردن آن تغییرات روی محیط production (یا هر محیط دیگری) است.
ءContinuous Integration با GitHub Actions
اگر از GitHub استفاده میکنید، شروع Continuous Integration هیچوقت به این راحتی نبوده است.
میتوانید از GitHub Actions برای خودکارسازی pipeline مربوط به build، test و deployment استفاده کنید. میتوانید workflowهایی بسازید که هر commit روی repository شما را build و test کنند، یا زمانی که یک tag جدید ساخته میشود، deploy به production انجام دهند.
برای ساخت یک GitHub Action، شما یک workflow مینویسید که هنگام وقوع یک event خاص در repository اجرا شود. نمونهای از این eventها شامل commit روی branch اصلی، ایجاد یک tag یا اجرای دستی workflow است.
در ادامه یک workflow در GitHub Actions برای build و test یک پروژه NET. آورده شده است:
name: Build & Test 🧪
on:
push:
branches:
- main
env:
DOTNET_VERSION: '7.0.x'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup .NET 📦
uses: actions/setup-dotnet@v3
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
- name: Install dependencies 📂
run: dotnet restore WebApi
- name: Build 🧱
run: dotnet build WebApi --configuration Release --no-restore
- name: Test 🧪
run: dotnet test WebApi --configuration Release --no-build
بیایید ببینیم اینجا دقیقاً چه اتفاقی میافتد 🔍
• تعریف یک event برای trigger کردن workflow ⚡️
• راهاندازی NET SDK. با نسخهای که از env.DOTNET_VERSION خوانده میشود 📦
• ءRestore، build و test کردن پروژه با استفاده از ابزار dotnet CLI 🧪🧱
میتوانید همین امروز این workflow را به repository گیتهاب خود اضافه کنید 🧑💻 و بهمحض commit کردن کد، بازخورد فوری دریافت کنید 🚀
وقتی اجرای workflow به دلیل خطای build یا شکست تستها fail شود ❌، یک ایمیل اعلان دریافت خواهید کرد 📧
ءContinuous Delivery به Azure با GitHub Actions ☁️
ءContinuous Integration نقطه شروع بسیار خوبی برای CI/CD است، اما ارزش واقعی زمانی مشخص میشود که فرآیند deployment را خودکار کنید 🤖
این سناریو را تصور کنید 👇
• شما تغییری در کد ایجاد میکنید ✏️
• ءcommit باعث trigger شدن pipeline deployment میشود 🔄
• چند دقیقه بعد، تغییرات شما در production در دسترس هستند 🌍
معمولاً موضوع کمی پیچیدهتر است، چون باید به پیکربندیها، migration دیتابیس و موارد دیگر هم فکر کنیم ⚙️🗄
اما سعی کنید تصویر کلی را ببینید 🧠
اگر برنامه خود را در cloud اجرا میکنید، مثلاً روی Azure ☁️، به احتمال زیاد یک GitHub Action آماده برای این کار وجود دارد که میتوانید از آن استفاده کنید.
در ادامه یک deployment pipeline آورده شده که من برای انتشار برنامهام روی Azure App Service استفاده میکنم 🚀
name: Publish 🚀
on:
push:
branches:
- main
env:
AZURE_WEBAPP_NAME: web-api
AZURE_WEBAPP_PACKAGE_PATH: './publish'
DOTNET_VERSION: '7.0.x'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup .NET 📦
uses: actions/setup-dotnet@v3
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
- name: Build and Publish 📂
run: |
dotnet restore WebApi
dotnet build WebApi -c Release --no-restore
dotnet publish WebApi -c Release --no-build
--output '${{ env.AZURE_WEBAPP_PACKAGE_PATH }}'
- name: Deploy to Azure 🌌
uses: azure/webapps-deploy@v2
with:
app-name: ${{ env.AZURE_WEBAPP_NAME }}
publish-profile: ${{ secrets.AZURE_PUBLISH_PROFILE }}
package: '${{ env.AZURE_WEBAPP_PACKAGE_PATH }}'
این workflow شباهت زیادی به workflow قبلی دارد، با این تفاوتها 🔍
اضافه شدن مرحله publish و پیکربندی مسیر خروجی 📤
استفاده از اکشن azure/webapps-deploy@v2 برای deploy روی Azure ☁️
اگر نیاز دارید مقادیر حساس (secret) را بهصورت امن در workflowها استفاده کنید 🔐، میتوانید از GitHub secrets استفاده کنید.
شما میتوانید secrets را در GitHub تعریف کنید و بدون اضافه کردن آنها به source control، در actionها از آنها استفاده کنید.
در workflow مربوط به deployment، من از secrets.AZURE_PUBLISH_PROFILE برای دسترسی به publish profile مربوط به App Service استفاده میکنم 🔑
جمعبندی 🧩
ءContinuous Integration و Continuous Delivery میتوانند فرآیند توسعه شما را متحول کنند ⚡️ و سرعت انتشار تغییرات را بهشدت افزایش دهند 🚀
سعی کنید محاسبه کنید چقدر زمان صرف deployment میکنید ⏱️
تقریباً مطمئنم از میزان زمانی که میتوانید با خودکارسازی ذخیره کنید شگفتزده خواهید شد 😮
نکته خوب اینجاست که معمولاً pipelineهای build و deployment را یکبار راهاندازی میکنید ✅ و سپس در تمام طول عمر پروژه از مزایای آنها استفاده میکنید ♻️
ممنون که خوندید 🙏
امیدوارم مفید بوده باشه ✨
اگر هر مشکلی را برای تیمت حل کنی، در واقع رهبر نیستی. داری جلوی رشدشان را میگیری. 🚧🧠
حتی اگر در ظاهر اینطور به نظر نرسد.
این وسوسه کاملاً طبیعی است، مخصوصاً وقتی باتجربهای.
• مشکل را میبینی 👀
• راهحل را میدانی ✅
• و دلت میخواهد کمک کنی 🤝
اما اگر هر بار خودت وارد عمل شوی، این اتفاقها میافتد:
1️⃣ تیم به تو وابسته میشود
2️⃣ مهارت حل مسئله در آنها رشد نمیکند
3️⃣ بدون اینکه بفهمی، خودت تبدیل به گلوگاه سیستم میشوی ⛔️
بهجای آن، این رویکرد را امتحان کن 👇
راهنمایی بده، نه جواب آماده 🧭
بپرس: «به نظرت خودمون باید چیکار کنیم؟» 🤔
اجازه بده افراد (در حد معقول) تقلا کنند تا رشد کنند 💪
کانتکست و دید کلی بده، نه فقط تصمیم نهایی یا اقدام آماده 📚
حتی اگر در ظاهر اینطور به نظر نرسد.
این وسوسه کاملاً طبیعی است، مخصوصاً وقتی باتجربهای.
• مشکل را میبینی 👀
• راهحل را میدانی ✅
• و دلت میخواهد کمک کنی 🤝
اما اگر هر بار خودت وارد عمل شوی، این اتفاقها میافتد:
1️⃣ تیم به تو وابسته میشود
2️⃣ مهارت حل مسئله در آنها رشد نمیکند
3️⃣ بدون اینکه بفهمی، خودت تبدیل به گلوگاه سیستم میشوی ⛔️
بهجای آن، این رویکرد را امتحان کن 👇
راهنمایی بده، نه جواب آماده 🧭
بپرس: «به نظرت خودمون باید چیکار کنیم؟» 🤔
اجازه بده افراد (در حد معقول) تقلا کنند تا رشد کنند 💪
کانتکست و دید کلی بده، نه فقط تصمیم نهایی یا اقدام آماده 📚
ءServer-Sent Events در ASP.NET Core و NET 10. 📡🚀
بهروزرسانیهای Real-time دیگر یک قابلیت «خوب است داشته باشیم» نیستند.
بیشتر رابطهای کاربری مدرن انتظار دارند به نوعی جریان زندهای از داده را از سمت سرور دریافت کنند.
سالها در اکوسیستم NET. ، پاسخ پیشفرض برای این نیاز SignalR بوده است.
در حالی که SignalR فوقالعاده قدرتمند است، اما برای سناریوهای سادهتر، داشتن گزینههای دیگر هم بسیار مفید است ✨
با انتشار ASP.NET Core 10، بالاخره یک API بومی و سطحبالا برای Server-Sent Events (SSE) داریم 🎉
این قابلیت فاصله بین polling سادهی HTTP و WebSocketهای دوطرفه از طریق SignalR را پر میکند.
🤔 چرا SSE بهجای SignalR؟
ءSignalR یک ابزار بسیار قدرتمند است که WebSockets، Long Polling و SSE را بهصورت خودکار مدیریت میکند و یک کانال ارتباطی دوطرفه (Full-Duplex) فراهم میکند.
اما این قدرت، هزینههایی هم دارد:
• استفاده از یک پروتکل مشخص (Hubs)
• نیاز به کتابخانهی سمت کلاینت
• نیاز به Sticky Session یا Backplane (مثل Redis) برای مقیاسپذیری
ءSSE متفاوت است، چون:
➡️ یکطرفه (Unidirectional) است: مخصوص استریم داده از سرور به کلاینت
🌐 ءHTTP بومی است: فقط یک درخواست استاندارد HTTP با text/event-stream
🔄 ءReconnect خودکار دارد: مرورگرها بهصورت Native با API به نام EventSource اتصال مجدد را مدیریت میکنند
🪶 سبک و ساده است: بدون کتابخانههای سنگین سمت کلاینت یا منطق handshake پیچیده
✨ سادهترین Endpoint برای Server-Sent Events
زیبایی API جدید SSE در NET 10.، سادگی آن است.
میتوانید از Results.ServerSentEvents استفاده کنید تا یک جریان از رویدادها را از هر <IAsyncEnumerable<T برگردانید.
از آنجایی که IAsyncEnumerable نمایانگر یک جریان داده است که در طول زمان میرسد، سرور متوجه میشود که باید اتصال HTTP را باز نگه دارد، بهجای اینکه بعد از اولین «chunk» آن را ببندد 🔓
در اینجا یک مثال مینیمال از یک Endpoint برای SSE وجود دارد که ثبت سفارشها را بهصورت Real-time استریم میکند 📦📊
app.MapGet("orders/realtime", (
ChannelReader<OrderPlacement> channelReader,
CancellationToken cancellationToken) =>
{
// 1. ReadAllAsync یک IAsyncEnumerable برمیگرداند
// 2. Results.ServerSentEvents به مرورگر میگوید: «این اتصال را باز نگه دار»
// 3. به محض ورود دادهی جدید به Channel، داده به کلاینت Push میشود
return Results.ServerSentEvents(
channelReader.ReadAllAsync(cancellationToken),
eventType: "orders");
});🔍 وقتی کلاینت این Endpoint را صدا میزند چه اتفاقی میافتد؟
🔹️سرور هدر Content-Type: text/event-stream را ارسال میکند 📬
🔸️اتصال باز میماند و در حالت انتظار برای داده قرار میگیرد ⏳
🔹️به محض اینکه اپلیکیشن شما یک سفارش جدید داخل Channel قرار دهد:
🔸️ءIAsyncEnumerable آن آیتم را yield میکند
🔹️ءNET. بلافاصله آن را از طریق همان اتصال HTTP باز به مرورگر ارسال میکند ⚡️
این یک روش فوقالعاده بهینه برای پیادهسازی اعلانهای Push است، بدون سربار یک پروتکل stateful.
🧠 نکتهی پایانی
در این مثال، از Channel فقط بهعنوان یک ابزار استفاده شده است.
در یک اپلیکیشن واقعی، ممکن است:
یک Background Service داشته باشید 🛠
به یک صف پیام مثل RabbitMQ یا Azure Service Bus گوش دهید 📮
یا به تغییرات دیتابیس واکنش نشان دهید 🗄
و سپس رویدادهای جدید را داخل Channel قرار دهید تا کلاینتهای متصل آنها را مصرف کنند.