Post #754
287
Channel Public Channel
C# C# Geeks (.NET)
@csharpgeeks
- Subscribers
- 550
- Photos
- 157
- Videos
- 4
- Links
- 177
Showing posts older than #755 · Back to latest
Older Posts 20 shown
Post #753
351

Post #752
360
Post #751
391
Post #750
303
Forwarded from thisisnabi.dev [Farsi]

8. Leaderless replication
—-
1. Designing Data Intensive Applications
- Replication [6]
@thisisnabi_dev
—-
1. Designing Data Intensive Applications
- Replication [6]
/three-lens-tutor Leaderless replication
@thisisnabi_dev
Post #749
320
#تصمیمهای_مهندسی (Engineering Decisions)
یکی از سختترین تصمیمهای مهندسی، انتخاب بین درست بودن و در دسترس بودن است.
فرض کنید Database اصلی شما از دسترس خارج شده است.
یک Replica دارید که چند ثانیه از دیتای اصلی عقبتر است.
حالا دو انتخاب دارید.
انتخاب اول:
کاربر را منتظر نگه دارید یا حتی درخواست را Fail کنید، تا مطمئن شوید دادهای که نمایش میدهید کاملاً بهروز است.
انتخاب دوم:
درخواست را از Replica پاسخ دهید.
کاربر سرویس را دریافت میکند...
اما شاید اطلاعاتی را ببیند که چند ثانیه قدیمی است.
کدام تصمیم درست است؟
اگر در حال نمایش تعداد لایک یک پست باشید،
احتمالاً چند ثانیه اختلاف اهمیتی ندارد.
اما اگر موجودی حساب بانکی یا تعداد باقیمانده بلیت یک کنسرت را نمایش میدهید،
همان چند ثانیه میتواند یک فاجعه ایجاد کند.
به همین دلیل، مهندسان باتجربه هیچوقت نمیپرسند:
«ءConsistency بهتر است یا Availability؟»
بلکه میپرسند:
«در این Domain، هزینهی کدام اشتباه بیشتر است؟»
چون هیچ معماریای وجود ندارد که در هر شرایطی، هم بیشترین Availability را داشته باشد و هم قویترین Consistency را.
هر تصمیم، یک Trade-off است.
و ارزش یک مهندس، در انتخاب تکنولوژی نیست.
در درک هزینهی انتخابها است.
چون در مهندسی نرمافزار،
بهترین تصمیم، تصمیمی نیست که هیچ هزینهای نداشته باشد.
بهترین تصمیم، تصمیمی است که هزینهی درست را بپردازد.
یکی از سختترین تصمیمهای مهندسی، انتخاب بین درست بودن و در دسترس بودن است.
فرض کنید Database اصلی شما از دسترس خارج شده است.
یک Replica دارید که چند ثانیه از دیتای اصلی عقبتر است.
حالا دو انتخاب دارید.
انتخاب اول:
کاربر را منتظر نگه دارید یا حتی درخواست را Fail کنید، تا مطمئن شوید دادهای که نمایش میدهید کاملاً بهروز است.
انتخاب دوم:
درخواست را از Replica پاسخ دهید.
کاربر سرویس را دریافت میکند...
اما شاید اطلاعاتی را ببیند که چند ثانیه قدیمی است.
کدام تصمیم درست است؟
اگر در حال نمایش تعداد لایک یک پست باشید،
احتمالاً چند ثانیه اختلاف اهمیتی ندارد.
اما اگر موجودی حساب بانکی یا تعداد باقیمانده بلیت یک کنسرت را نمایش میدهید،
همان چند ثانیه میتواند یک فاجعه ایجاد کند.
به همین دلیل، مهندسان باتجربه هیچوقت نمیپرسند:
«ءConsistency بهتر است یا Availability؟»
بلکه میپرسند:
«در این Domain، هزینهی کدام اشتباه بیشتر است؟»
چون هیچ معماریای وجود ندارد که در هر شرایطی، هم بیشترین Availability را داشته باشد و هم قویترین Consistency را.
هر تصمیم، یک Trade-off است.
و ارزش یک مهندس، در انتخاب تکنولوژی نیست.
در درک هزینهی انتخابها است.
چون در مهندسی نرمافزار،
بهترین تصمیم، تصمیمی نیست که هیچ هزینهای نداشته باشد.
بهترین تصمیم، تصمیمی است که هزینهی درست را بپردازد.
Post #748
266
Post #747
301
#تحلیل_و_طرز_تفکر (Engineering Mindset)
یک سؤال هست که مهندسهای باتجربه بیشتر از بقیه از خودشان میپرسند:
«اگر من شش ماه دیگر از این تیم بروم، چه اتفاقی برای این سیستم میافتد؟»
اگر جواب این باشد که:
فقط خودم میدانم این بخش چطور کار میکند.
فقط خودم میتوانم آن را Deploy کنم.
فقط خودم میتوانم باگش را پیدا کنم.
فقط خودم میدانم چرا این تصمیم را گرفتهایم.
شاید مسئله، مهارت بالا نباشد.
شاید سیستم، بیش از حد به یک نفر وابسته شده است.
یکی از نشانههای بلوغ مهندسی این نیست که خودت بتوانی همه مشکلات را حل کنی.
این است که دیگران هم بتوانند بعد از تو سیستم را ادامه دهند.
به همین دلیل، مستندسازی، Code Review، Naming مناسب، تست و ثبت تصمیمهای معماری فقط برای امروز نیستند.
همهی آنها برای روزی هستند که شخص دیگری باید بدون حضور تو، روی همان سیستم کار کند.
یک مهندس خوب، سیستم میسازد.
یک مهندس بالغ، سیستمی میسازد که به خودش وابسته نباشد.
چون در نهایت،
بهترین کد، کدی نیست که فقط نویسندهاش آن را بفهمد.
بهترین کد، کدی است که نبودِ نویسندهاش، تیم را متوقف نکند.
یک سؤال هست که مهندسهای باتجربه بیشتر از بقیه از خودشان میپرسند:
«اگر من شش ماه دیگر از این تیم بروم، چه اتفاقی برای این سیستم میافتد؟»
اگر جواب این باشد که:
فقط خودم میدانم این بخش چطور کار میکند.
فقط خودم میتوانم آن را Deploy کنم.
فقط خودم میتوانم باگش را پیدا کنم.
فقط خودم میدانم چرا این تصمیم را گرفتهایم.
شاید مسئله، مهارت بالا نباشد.
شاید سیستم، بیش از حد به یک نفر وابسته شده است.
یکی از نشانههای بلوغ مهندسی این نیست که خودت بتوانی همه مشکلات را حل کنی.
این است که دیگران هم بتوانند بعد از تو سیستم را ادامه دهند.
به همین دلیل، مستندسازی، Code Review، Naming مناسب، تست و ثبت تصمیمهای معماری فقط برای امروز نیستند.
همهی آنها برای روزی هستند که شخص دیگری باید بدون حضور تو، روی همان سیستم کار کند.
یک مهندس خوب، سیستم میسازد.
یک مهندس بالغ، سیستمی میسازد که به خودش وابسته نباشد.
چون در نهایت،
بهترین کد، کدی نیست که فقط نویسندهاش آن را بفهمد.
بهترین کد، کدی است که نبودِ نویسندهاش، تیم را متوقف نکند.
Post #746
286
Post #745
321
🚦 چه زمانی در ASP.NET Core باید از CancellationTokenSource استفاده کنیم؟یکی از قابلیتهایی که از NET 4. به این طرف وارد فریمورک شد، Cooperative Cancellation است.
قبل از آن، برای متوقف کردن Threadها معمولاً از APIهایی مانند
Thread.Abort() استفاده میشد؛ APIهایی که میتوانستند Thread را در هر نقطهای متوقف کنند و باعث ناپایداری برنامه شوند.به همین دلیل مایکروسافت مدل جدیدی را معرفی کرد:
هیچ عملیاتی نباید به زور متوقف شود؛ خود عملیات باید تصمیم بگیرد که چه زمانی متوقف شود.
به این مدل Cooperative Cancellation گفته میشود.
💡 سه بازیگر اصلی در Cancellation
مستندات NET. سه جزء اصلی را معرفی میکنند:
1️⃣
CancellationTokenSourceاین کلاس مسئول ارسال درخواست لغو است.
using var cts = new CancellationTokenSource();
2️⃣
CancellationTokenاین ساختار فقط وضعیت لغو را نگه میدارد.
CancellationToken token = cts.Token;
هرگز خودش عملیات را متوقف نمیکند.
3️⃣ عملیاتی که Token را دریافت میکند
مثلاً:
HttpClient
EF Core
Task.Delay
Stream
File APIs
Parallel APIs
همگی Token را دریافت میکنند.
await Task.Delay(
TimeSpan.FromSeconds(10),
token);
اگر درخواست لغو ارسال شود، خود
Task.Delay تصمیم میگیرد عملیات را متوقف کند.🏗 جریان کار چگونه است؟
CancellationTokenSource
│
│ Cancel()
▼
CancellationToken
│
▼
HttpClient / EF Core / Task / ...
│
▼
OperationCanceledException
نکته مهم:
ء
CancellationTokenSource هیچ Task یا Threadی را Kill نمیکند.فقط اعلام میکند:
"اگر هنوز مشغول کار هستی، لطفاً متوقف شو."
این دقیقاً همان چیزی است که Microsoft از آن با عنوان Cooperative Cancellation یاد میکند.
🎯 حالا سؤال اصلی:
در ASP.NET Core چه زمانی باید خودمان
CancellationTokenSource بسازیم؟✅ سناریو اول: Timeout اختصاصی
فرض کنید فراخوانی یک سرویس پرداخت نباید بیشتر از ۵ ثانیه طول بکشد.
using var cts =
new CancellationTokenSource(
TimeSpan.FromSeconds(5));
await gateway.PayAsync(
request,
cts.Token);
بعد از ۵ ثانیه:
cts.Cancel()
به صورت خودکار اجرا میشود.
طبق مستندات، این یکی از رایجترین کاربردهای
CancellationTokenSource است.✅ سناریو دوم: لغو دستی عملیات
فرض کنید کاربر دکمه Cancel را فشار میدهد.
cts.Cancel();
از این لحظه تمام عملیاتهایی که این Token را دریافت کردهاند متوجه درخواست لغو میشوند.
✅ سناریو سوم: ترکیب چند Token
در ASP.NET Core معمولاً این Token را دارید:
HttpContext.RequestAborted
این Token زمانی Cancel میشود که:
مرورگر بسته شود. Client ارتباط را قطع کند. حالا فرض کنید علاوه بر آن، میخواهید Timeout هم داشته باشید.
مایکروسافت پیشنهاد میکند:
using var timeout =
new CancellationTokenSource(
TimeSpan.FromSeconds(10));
using var linked =
CancellationTokenSource
.CreateLinkedTokenSource(
HttpContext.RequestAborted,
timeout.Token);
در این حالت اگر هر کدام از Tokenها Cancel شوند، عملیات نیز Cancel خواهد شد.
❌ اشتباه رایج
در بسیاری از پروژهها میبینیم:
public async Task Handle()
{
using var cts =
new CancellationTokenSource();
...
}
بدون هیچ دلیل مشخصی.
در حالی که ASP.NET Core خودش Token مناسب را در اختیار شما قرار داده است:
public async Task<IActionResult> Create(
CancellationToken cancellationToken)
اگر فقط میخواهید عملیات در صورت لغو Request متوقف شود، همان Token را به تمام لایهها پاس دهید.
ساخت
CancellationTokenSource جدید، ارتباط عملیات با Request اصلی را قطع میکند.⚠️ نکتهای که خیلیها نمیدانند
ء
CancellationTokenSource از IDisposable پیروی میکند.مایکروسافت صراحتاً توصیه میکند بعد از اتمام کار آن را Dispose کنید.
using var cts =
new CancellationTokenSource();
⚠️ یک باور اشتباه
بعضیها تصور میکنند:
Cancel()
یعنی Task فوراً متوقف میشود.
اما مستندات دقیقاً برعکس این را میگویند.
بعد از ارسال درخواست لغو، این خود عملیات است که باید:
token.ThrowIfCancellationRequested();
را بررسی کند یا APIای که Token را دریافت کرده، به آن واکنش نشان دهد.
به همین دلیل به این مدل میگویند:
Cooperative Cancellation
نه
Forced Cancellation.
Post #744
284
Post #743
331
#AI_Software_Engineering
مدتی قبل فکر میکردم برای کار کردن با AI حتماً باید یک فرآیند جدید، یک چارچوب پیچیده و یک روش توسعه کاملاً متفاوت داشته باشیم.Prompt Engineering. Workflowهای عجیب.
قوانین سخت برای استفاده از AI.
اما کمکم یک سؤال در ذهنم شکل گرفت:
نکند بخشی از این پیچیدگیها را خودمان ساختهایم، فقط چون هنوز نمیدانیم چطور با این ابزار جدید کنار بیاییم؟
ما سالها برای اینکه سیستمها قابل کنترل باشند، ساختار ایجاد کردیم.
Architecture.
Design Pattern.
Code Review.
Testing.
Documentation.
همه اینها ارزشمند هستند.
اما شاید بخشی از آنها، پاسخی به محدودیتهای گذشته بودهاند.
امروز یک AI Agent میتواند در چند دقیقه کاری را انجام دهد که قبلاً ساعتها زمان میبرد. Refactor کردن یک بخش بزرگ از سیستم.
پیدا کردن Dependencyها.
نوشتن Test.
پیشنهاد تغییرات.
حتی آماده کردن یک Pull Request.
اینجا یک سؤال مهم مطرح میشود:
آیا ما باید AI را مجبور کنیم مثل یک Developer قدیمی کار کند؟
یا باید یاد بگیریم چطور سطح تعامل خودمان با سیستمها را بالاتر ببریم؟
چون شاید در آینده، ارزش یک مهندس کمتر در این باشد که:
«چقدر سریع کد مینویسی؟»
و بیشتر در این باشد که:
«آیا میدانی چه چیزی باید ساخته شود؟»
اما یک نکته هنوز تغییر نکرده. AI میتواند تغییر ایجاد کند.
اما مسئولیت تصمیمگیری هنوز با انسان است.
چون یک سیستم اشتباه، اگر با AI سریعتر ساخته شود...
فقط سریعتر به یک مشکل بزرگ تبدیل میشود.
شاید آینده برنامهنویسی این نباشد که انسانها کمتر کد بنویسند.
شاید آینده این باشد که انسانها کمتر درگیر جزئیات شوند و بیشتر روی تفکر مهندسی تمرکز کنند.
چون ابزارها همیشه تغییر میکنند.
اما توانایی تشخیص یک تصمیم درست از یک تصمیم اشتباه،
همیشه ارزشمند باقی میماند.
مدتی قبل فکر میکردم برای کار کردن با AI حتماً باید یک فرآیند جدید، یک چارچوب پیچیده و یک روش توسعه کاملاً متفاوت داشته باشیم.Prompt Engineering. Workflowهای عجیب.
قوانین سخت برای استفاده از AI.
اما کمکم یک سؤال در ذهنم شکل گرفت:
نکند بخشی از این پیچیدگیها را خودمان ساختهایم، فقط چون هنوز نمیدانیم چطور با این ابزار جدید کنار بیاییم؟
ما سالها برای اینکه سیستمها قابل کنترل باشند، ساختار ایجاد کردیم.
Architecture.
Design Pattern.
Code Review.
Testing.
Documentation.
همه اینها ارزشمند هستند.
اما شاید بخشی از آنها، پاسخی به محدودیتهای گذشته بودهاند.
امروز یک AI Agent میتواند در چند دقیقه کاری را انجام دهد که قبلاً ساعتها زمان میبرد. Refactor کردن یک بخش بزرگ از سیستم.
پیدا کردن Dependencyها.
نوشتن Test.
پیشنهاد تغییرات.
حتی آماده کردن یک Pull Request.
اینجا یک سؤال مهم مطرح میشود:
آیا ما باید AI را مجبور کنیم مثل یک Developer قدیمی کار کند؟
یا باید یاد بگیریم چطور سطح تعامل خودمان با سیستمها را بالاتر ببریم؟
چون شاید در آینده، ارزش یک مهندس کمتر در این باشد که:
«چقدر سریع کد مینویسی؟»
و بیشتر در این باشد که:
«آیا میدانی چه چیزی باید ساخته شود؟»
اما یک نکته هنوز تغییر نکرده. AI میتواند تغییر ایجاد کند.
اما مسئولیت تصمیمگیری هنوز با انسان است.
چون یک سیستم اشتباه، اگر با AI سریعتر ساخته شود...
فقط سریعتر به یک مشکل بزرگ تبدیل میشود.
شاید آینده برنامهنویسی این نباشد که انسانها کمتر کد بنویسند.
شاید آینده این باشد که انسانها کمتر درگیر جزئیات شوند و بیشتر روی تفکر مهندسی تمرکز کنند.
چون ابزارها همیشه تغییر میکنند.
اما توانایی تشخیص یک تصمیم درست از یک تصمیم اشتباه،
همیشه ارزشمند باقی میماند.
Post #742
301
Post #741
360
#روایت_تجربه (Storytelling)
چند وقت پیش، یکی از مهندسهای یک شرکت تعریف میکرد که بعد از چند ماه کار روی یک قابلیت جدید، بالاخره آن را وارد محیط Production کردند.
همهچیز عالی پیش رفت.
هیچ Errorی ثبت نشد.Latency هم طبیعی بود.
همه فکر میکردند انتشار موفقیتآمیز بوده است.
اما چند روز بعد، تیم محصول گزارش داد که کاربران تقریباً از آن قابلیت استفاده نمیکنند.
مشکل از کد نبود.
مشکل این بود که قابلیتی ساخته شده بود که کسی واقعاً به آن نیاز نداشت.
او میگفت:
«ما موفق شدیم چیزی را بسازیم که هیچکس منتظرش نبود.»
این جمله مدتها در ذهنم ماند.
چون ما مهندسها معمولاً موفقیت را با معیارهای فنی میسنجیم:
باگ نداشت. تستها پاس شدند. Performance خوب بود. Deployment بدون مشکل انجام شد.
اما بیزینس سؤال دیگری میپرسد:
«آیا این قابلیت ارزشی برای کاربر ایجاد کرد؟»
اگر جواب این سؤال «نه» باشد،
ممکن است از نظر فنی یک شاهکار ساخته باشیم، اما از نظر محصول، شکست خورده باشیم.
از آن روز، هر بار که درباره کیفیت یک Feature صحبت میشود، یادم میآید که کیفیت فقط به این نیست که درست کار کند.
باید دلیل وجود داشتنش هم درست باشد.
چون در مهندسی نرمافزار،ساختن چیز درست،بهاندازهی ساختن چیزِ درست برای کاربر مهم نیست.
چند وقت پیش، یکی از مهندسهای یک شرکت تعریف میکرد که بعد از چند ماه کار روی یک قابلیت جدید، بالاخره آن را وارد محیط Production کردند.
همهچیز عالی پیش رفت.
هیچ Errorی ثبت نشد.Latency هم طبیعی بود.
همه فکر میکردند انتشار موفقیتآمیز بوده است.
اما چند روز بعد، تیم محصول گزارش داد که کاربران تقریباً از آن قابلیت استفاده نمیکنند.
مشکل از کد نبود.
مشکل این بود که قابلیتی ساخته شده بود که کسی واقعاً به آن نیاز نداشت.
او میگفت:
«ما موفق شدیم چیزی را بسازیم که هیچکس منتظرش نبود.»
این جمله مدتها در ذهنم ماند.
چون ما مهندسها معمولاً موفقیت را با معیارهای فنی میسنجیم:
باگ نداشت. تستها پاس شدند. Performance خوب بود. Deployment بدون مشکل انجام شد.
اما بیزینس سؤال دیگری میپرسد:
«آیا این قابلیت ارزشی برای کاربر ایجاد کرد؟»
اگر جواب این سؤال «نه» باشد،
ممکن است از نظر فنی یک شاهکار ساخته باشیم، اما از نظر محصول، شکست خورده باشیم.
از آن روز، هر بار که درباره کیفیت یک Feature صحبت میشود، یادم میآید که کیفیت فقط به این نیست که درست کار کند.
باید دلیل وجود داشتنش هم درست باشد.
چون در مهندسی نرمافزار،ساختن چیز درست،بهاندازهی ساختن چیزِ درست برای کاربر مهم نیست.
Post #740
322
Post #739
418
📚 36 سؤال #C که تقریباً در هر مصاحبهای پرسیده میشوند
1️⃣ ءBoxing چیست، چه زمانی بهصورت ضمنی (Implicit) اتفاق میافتد و چه هزینهای دارد؟
2️⃣ چرا زمانی که یک struct یک interface را پیادهسازی میکند، Boxing رخ میدهد؟
3️⃣ء ref struct چیست و چه محدودیتهایی دارد؟
4️⃣ تفاوت record struct و record class از نظر رفتار (Semantics) و Performance چیست؟
5️⃣ اگر Equals را Override کنید اما GetHashCode را Override نکنید، چه مشکلاتی به وجود میآید؟
6️⃣ چرا عملگر == برای متغیرهای string با متغیرهایی از نوع object که رشته را نگه میدارند، رفتار متفاوتی دارد؟
7️⃣ ءString Interning چیست و در چه شرایطی دو رشته با محتوای یکسان از نظر Reference برابر نیستند؟
8️⃣ تفاوت float، double و decimal چیست و برای محاسبات مالی از کدام باید استفاده کرد؟
9️⃣ تفاوت DateTime، DateTimeOffset، DateOnly و TimeOnly چیست؟
🔟 ءJIT چگونه کدهای Generic را برای Value Typeها و Reference Typeها بهینهسازی (Specialize) میکند؟
1️⃣1️⃣ ءCovariance و Contravariance در Genericها را توضیح دهید.
2️⃣1️⃣ چرا آرایهها (Arrays) در #C دارای Covariance هستند؟
3️⃣1️⃣ اعضای static abstract در Interfaceها چیستند و چه کاربردی دارند؟
4️⃣1️⃣ آیا استفاده از async یک Thread جدید ایجاد میکند؟ هنگام رسیدن به await دقیقاً چه اتفاقی میافتد؟
5️⃣1️⃣ کامپایلر برای یک متد async چه State Machineای تولید میکند؟
6️⃣1️⃣ تفاوت Task و <ValueTask<T چیست؟
7️⃣1️⃣ چرا استفاده از async void خطرناک است؟
8️⃣1️⃣ چرا فراخوانی Result. یا ()Wait. در محیطی که SynchronizationContext دارد، میتواند باعث Deadlock شود؟
9️⃣1️⃣ ءConfigureAwait(false) دقیقاً چه کاری انجام میدهد؟
0️⃣2️⃣ هزینه واقعی استفاده از Task.Run در یک برنامه سمت سرور چیست؟
1️⃣2️⃣ ءThread Pool Starvation چیست و چگونه آن را تشخیص میدهید؟
2️⃣2️⃣ چگونه باید از CancellationToken بهدرستی استفاده کرد؟
3️⃣2️⃣ مدیریت Exception در Task.WhenAll چه تفاوتی با یک await معمولی دارد؟
4️⃣2️⃣ کلمه کلیدی lock به چه چیزی کامپایل میشود و System.Threading.Lock در C# 13 چه بهبودهایی ارائه میدهد؟
5️⃣2️⃣ کلمه کلیدی volatile چه تضمینهایی ارائه میدهد و در چه شرایطی باید به جای آن از Interlocked استفاده کرد؟
6️⃣2️⃣ چه زمانی باید از <Channel<T به جای <BlockingCollection<T استفاده کرد؟
7️⃣2️⃣ تفاوت <AsyncLocal<T و <ThreadLocal<T چیست؟
8️⃣2️⃣ نسلهای مختلف Garbage Collector (GC Generations) و مفهوم Object Promotion را توضیح دهید. چرا جمعآوری نسل دوم (Gen 2) پرهزینه است؟
9️⃣2️⃣ ءLarge Object Heap (LOH) چیست و چرا برای سرویسهای Long-Running اهمیت دارد؟
0️⃣3️⃣ وجود Finalizer چه تأثیری بر طول عمر یک شیء دارد و چرا در متد Dispose از GC.SuppressFinalize استفاده میشود؟
1️⃣3️⃣ تفاوت Workstation GC و Server GC چیست؟
2️⃣3️⃣ ء<Span<T چه مشکلی را حل میکند و در چه شرایطی باعث حذف Allocationها میشود؟
3️⃣3️⃣ چه زمانی باید از <ArrayPool<T استفاده کرد؟
4️⃣3️⃣ ءClosureها چگونه متغیرها را Capture میکنند؟
5️⃣3️⃣ ءDeferred Execution در LINQ چیست؟
6️⃣3️⃣ ءNative AOT چه مزایایی ارائه میدهد و چه قابلیتهایی را پشتیبانی نمیکند؟
🧠 مفاهیم پایه #C
1️⃣ ءBoxing چیست، چه زمانی بهصورت ضمنی (Implicit) اتفاق میافتد و چه هزینهای دارد؟
2️⃣ چرا زمانی که یک struct یک interface را پیادهسازی میکند، Boxing رخ میدهد؟
3️⃣ء ref struct چیست و چه محدودیتهایی دارد؟
4️⃣ تفاوت record struct و record class از نظر رفتار (Semantics) و Performance چیست؟
5️⃣ اگر Equals را Override کنید اما GetHashCode را Override نکنید، چه مشکلاتی به وجود میآید؟
6️⃣ چرا عملگر == برای متغیرهای string با متغیرهایی از نوع object که رشته را نگه میدارند، رفتار متفاوتی دارد؟
7️⃣ ءString Interning چیست و در چه شرایطی دو رشته با محتوای یکسان از نظر Reference برابر نیستند؟
8️⃣ تفاوت float، double و decimal چیست و برای محاسبات مالی از کدام باید استفاده کرد؟
9️⃣ تفاوت DateTime، DateTimeOffset، DateOnly و TimeOnly چیست؟
⚙️ CLR و Generics
🔟 ءJIT چگونه کدهای Generic را برای Value Typeها و Reference Typeها بهینهسازی (Specialize) میکند؟
1️⃣1️⃣ ءCovariance و Contravariance در Genericها را توضیح دهید.
2️⃣1️⃣ چرا آرایهها (Arrays) در #C دارای Covariance هستند؟
3️⃣1️⃣ اعضای static abstract در Interfaceها چیستند و چه کاربردی دارند؟
🚀 Async و Threading
4️⃣1️⃣ آیا استفاده از async یک Thread جدید ایجاد میکند؟ هنگام رسیدن به await دقیقاً چه اتفاقی میافتد؟
5️⃣1️⃣ کامپایلر برای یک متد async چه State Machineای تولید میکند؟
6️⃣1️⃣ تفاوت Task و <ValueTask<T چیست؟
7️⃣1️⃣ چرا استفاده از async void خطرناک است؟
8️⃣1️⃣ چرا فراخوانی Result. یا ()Wait. در محیطی که SynchronizationContext دارد، میتواند باعث Deadlock شود؟
9️⃣1️⃣ ءConfigureAwait(false) دقیقاً چه کاری انجام میدهد؟
0️⃣2️⃣ هزینه واقعی استفاده از Task.Run در یک برنامه سمت سرور چیست؟
1️⃣2️⃣ ءThread Pool Starvation چیست و چگونه آن را تشخیص میدهید؟
2️⃣2️⃣ چگونه باید از CancellationToken بهدرستی استفاده کرد؟
3️⃣2️⃣ مدیریت Exception در Task.WhenAll چه تفاوتی با یک await معمولی دارد؟
4️⃣2️⃣ کلمه کلیدی lock به چه چیزی کامپایل میشود و System.Threading.Lock در C# 13 چه بهبودهایی ارائه میدهد؟
5️⃣2️⃣ کلمه کلیدی volatile چه تضمینهایی ارائه میدهد و در چه شرایطی باید به جای آن از Interlocked استفاده کرد؟
6️⃣2️⃣ چه زمانی باید از <Channel<T به جای <BlockingCollection<T استفاده کرد؟
7️⃣2️⃣ تفاوت <AsyncLocal<T و <ThreadLocal<T چیست؟
🧹 مدیریت حافظه (Memory Management)
8️⃣2️⃣ نسلهای مختلف Garbage Collector (GC Generations) و مفهوم Object Promotion را توضیح دهید. چرا جمعآوری نسل دوم (Gen 2) پرهزینه است؟
9️⃣2️⃣ ءLarge Object Heap (LOH) چیست و چرا برای سرویسهای Long-Running اهمیت دارد؟
0️⃣3️⃣ وجود Finalizer چه تأثیری بر طول عمر یک شیء دارد و چرا در متد Dispose از GC.SuppressFinalize استفاده میشود؟
1️⃣3️⃣ تفاوت Workstation GC و Server GC چیست؟
2️⃣3️⃣ ء<Span<T چه مشکلی را حل میکند و در چه شرایطی باعث حذف Allocationها میشود؟
3️⃣3️⃣ چه زمانی باید از <ArrayPool<T استفاده کرد؟
4️⃣3️⃣ ءClosureها چگونه متغیرها را Capture میکنند؟
5️⃣3️⃣ ءDeferred Execution در LINQ چیست؟
6️⃣3️⃣ ءNative AOT چه مزایایی ارائه میدهد و چه قابلیتهایی را پشتیبانی نمیکند؟
Post #738
268
در طول سالهای گذشته، سیستم اعتبارسنجی مدل (Model Validation) توکار در اکوسیستم داتنت که عمدتاً بر پایهی فضای نام
این طراحی سنتی، پیادهسازی قواعد اعتبارسنجی پیچیدهای را که به عملیاتهای ورودی/خروجی (I/O-bound) وابسته بودند با چالش مواجه میکرد؛ سناریوهایی مانند:
✅ بررسی منحصربهفرد بودن نام کاربری در پایگاه داده
✅ استعلام وضعیت یک شناسه از طریق Web API خارجی
✅ سنجش موجودی انبار
توسعهدهندگان برای پیادهسازی این زیرساختها ناچار بودند یا به ابزارهای شخص ثالث مانند کتابخانه محبوب FluentValidation روی آورند، یا متدهای ناهمگام را به صورت ناامن و مسدودکننده (Thread Blocking) با استفاده از امضاهایی مانند
این رویکرد نامناسب، مستقیماً ریسک بروز گلوگاه در پایگاه ریسمانها (Thread Pool Starvation) را افزایش میداد. 📉
در پی درخواستهای مکرر جامعه توسعهدهندگان، مایکروسافت بالاخره در NET 11 Preview 6. زیرساخت اعتبارسنجی ناهمگام را به صورت بومی به هسته فریمورک اضافه کرد تا به یکی از پررأیترین درخواستهای گیتهاب پاسخ دهد. 🎉
این تغییرات زیرساختی، معماری اعتبارسنجی داتنت را متحول کرده است. 🔥
در این مکانیزم جدید، سه افزونه اساسی به فضای نام
اضافه شده است که به توسعهدهندگان اجازه میدهد منطق ناهمگام خود را بدون مسدود کردن ریسمانها پیادهسازی کنند:
🟢 کلاس انتزاعی
این کلاس پایه جدید، جایگزین مستقیم
🟢 اینترفیس
همتای ناهمگام اینترفیس شناختهشدهی
🟢 متدهای نوین در کلاس static اعتبارسنجی (
معرفی متدهای جدید از جمله:
✅
✅
✅
✅
جهت اجرای غیرمسدودکننده عملیات سنجش صحت دادهها. 🚀
در نمونه کد زیر، شیوه تعریف یک قانون اعتبارسنجی ناهمگام جهت بررسی منحصربهفرد بودن نام کاربری به سادهترین شکل ممکن ارائه شده است. ✨
متد سنتی IsValid به صورت پیشفرض برای سازگاری عقبرو (Backward Compatibility) مقدار ValidationResult.Success را برمیگرداند و منطق اصلی در IsValidAsync به همراه پشتیبانی از CancellationToken پیادهسازی میشود.
🚀 اجرای اعتبارسنجی ناهمگام
جهت فراخوانی و اعتبارسنجی ناهمگام این مدل در خط لولههای دستی یا خارج از لایه کنترلر، موتور Validator متدهای الحاقی جدید خود را ارائه میدهد.
System.ComponentModel.DataAnnotations استوار است، ساختاری کاملاً همگام (Synchronous) داشت. ⚙️این طراحی سنتی، پیادهسازی قواعد اعتبارسنجی پیچیدهای را که به عملیاتهای ورودی/خروجی (I/O-bound) وابسته بودند با چالش مواجه میکرد؛ سناریوهایی مانند:
✅ بررسی منحصربهفرد بودن نام کاربری در پایگاه داده
✅ استعلام وضعیت یک شناسه از طریق Web API خارجی
✅ سنجش موجودی انبار
توسعهدهندگان برای پیادهسازی این زیرساختها ناچار بودند یا به ابزارهای شخص ثالث مانند کتابخانه محبوب FluentValidation روی آورند، یا متدهای ناهمگام را به صورت ناامن و مسدودکننده (Thread Blocking) با استفاده از امضاهایی مانند
.Result یا .Wait() فراخوانی کنند. ⚠️این رویکرد نامناسب، مستقیماً ریسک بروز گلوگاه در پایگاه ریسمانها (Thread Pool Starvation) را افزایش میداد. 📉
در پی درخواستهای مکرر جامعه توسعهدهندگان، مایکروسافت بالاخره در NET 11 Preview 6. زیرساخت اعتبارسنجی ناهمگام را به صورت بومی به هسته فریمورک اضافه کرد تا به یکی از پررأیترین درخواستهای گیتهاب پاسخ دهد. 🎉
🆕 معماری و قابلیتهای جدید در NET 11.
این تغییرات زیرساختی، معماری اعتبارسنجی داتنت را متحول کرده است. 🔥
در این مکانیزم جدید، سه افزونه اساسی به فضای نام
System.ComponentModel.DataAnnotationsاضافه شده است که به توسعهدهندگان اجازه میدهد منطق ناهمگام خود را بدون مسدود کردن ریسمانها پیادهسازی کنند:
🟢 کلاس انتزاعی
AsyncValidationAttributeاین کلاس پایه جدید، جایگزین مستقیم
ValidationAttribute برای سناریوهای ناهمگام است و امکان نوشتن اتریبیوتهای سفارشی را با بازنویسی (Override) متد IsValidAsync فراهم میکند.🟢 اینترفیس
IAsyncValidatableObjectهمتای ناهمگام اینترفیس شناختهشدهی
IValidatableObject که به خودِ مدل یا DTO اجازه میدهد منطق اعتبارسنجی درونیاش را به صورت اسنک (Async) پیادهسازی کند.🟢 متدهای نوین در کلاس static اعتبارسنجی (
Validator)معرفی متدهای جدید از جمله:
✅
ValidateObjectAsync✅
TryValidateObjectAsync✅
ValidatePropertyAsync✅
ValidateValueAsyncجهت اجرای غیرمسدودکننده عملیات سنجش صحت دادهها. 🚀
🧩 پیادهسازی عملی اتریبیوت اعتبارسنجی ناهمگام
در نمونه کد زیر، شیوه تعریف یک قانون اعتبارسنجی ناهمگام جهت بررسی منحصربهفرد بودن نام کاربری به سادهترین شکل ممکن ارائه شده است. ✨
متد سنتی IsValid به صورت پیشفرض برای سازگاری عقبرو (Backward Compatibility) مقدار ValidationResult.Success را برمیگرداند و منطق اصلی در IsValidAsync به همراه پشتیبانی از CancellationToken پیادهسازی میشود.
using System.ComponentModel.DataAnnotations;
using Microsoft.Extensions.DependencyInjection;
public sealed class UniqueUserNameAttribute : AsyncValidationAttribute
{
// سازگاری با خط لولههای همگام قدیمی
protected override ValidationResult? IsValid(object? value, ValidationContext context)
=> ValidationResult.Success;
// پیادهسازی اصلی برای خط لوله ناهمگام داتنت ۱۱
protected override async Task<ValidationResult?> IsValidAsync(
object? value, ValidationContext context, CancellationToken cancellationToken)
{
// دریافت مستقیم سرویسها از کانتینر DI با استفاده از Context موجود
var users = context.GetRequiredService<IUserStore>();
bool isTaken = await users.ExistsAsync((string?)value, cancellationToken);
return isTaken
? new ValidationResult("این نام کاربری قبلاً توسط کاربر دیگری انتخاب شده است.")
: ValidationResult.Success;
}
}
public class RegistrationRequest
{
[Required]
[UniqueUserName]
public string UserName { get; set; } = "";
}
🚀 اجرای اعتبارسنجی ناهمگام
جهت فراخوانی و اعتبارسنجی ناهمگام این مدل در خط لولههای دستی یا خارج از لایه کنترلر، موتور Validator متدهای الحاقی جدید خود را ارائه میدهد.
// اجرای فرآیند اعتبارسنجی ناهمگام بدون Block کردن Thread
var context = new ValidationContext(model, serviceProvider, items: null);
await Validator.ValidateObjectAsync(
model,
context,
validateAllProperties: true);
Post #737
284
Post #736
312
این سؤال را چند وقت پیش دیدم و به نظرم سؤال جالبی بود.
سؤال این بود:
برداشت اولیه این سؤال این است که انگار اگر در یک حوزه خاص کار کنید، خودبهخود درآمد بالایی خواهید داشت.
اما واقعیت کمی متفاوت است.
شرکتهای مختلف، کشورهای مختلف و حتی دو استارتاپ در یک صنعت، مدلهای پرداخت کاملاً متفاوتی دارند.
یک استارتاپ تازهتأسیس ممکن است با بودجه محدود حقوق پرداخت کند، در حالی که یک شرکت بزرگ فناوری برای همان نقش چند برابر بیشتر هزینه کند.
بنابراین ارتباط مستقیم بین نوع مسئله و میزان حقوق همیشه وجود ندارد.
در واقع این رابطه، یک رابطه علت و معلولی ساده نیست.
بر اساس تجربهای که در شرکتهای مختلف دیدهام، مهندسهایی که بیشترین ارزش را ایجاد میکنند معمولاً در یکی از این سه دسته قرار میگیرند:
🚀 1️⃣ حل مسائل با ارزش تجاری بالا در حوزههای تخصصی
آنها روی مسائلی کار میکنند که شاید افراد کمی توانایی حلشان را داشته باشند، اما تأثیر بسیار بزرگی روی کسبوکار دارند.
مثلاً:
بهینهسازی یک سیستم پرداخت که روزانه میلیونها تراکنش پردازش میکند.
طراحی زیرساختی که هزینه سرورها را ۳۰٪ کاهش میدهد.
افزایش Availability یک سرویس حیاتی.
🤝 2️⃣ تبدیل شدن به یک «Multiplier»
این افراد فقط خودشان سریع کدنویسی نمیکنند.
آنها باعث میشوند کل تیم سریعتر و بهتر کار کند.
مثلاً:
طراحی معماری مناسب
ایجاد ابزارهای داخلی
ءMentor کردن اعضای تیم
بهبود فرآیندهای توسعه
حذف گلوگاههای فنی
گاهی ارزش واقعی یک مهندس، در تعداد خط کدی که مینویسد نیست؛ بلکه در تعداد افرادی است که بهرهوری آنها را افزایش میدهد.
📈 3️⃣ ایجاد ارزش پایدار در بخشهای مختلف سیستم
برخی مهندسها فقط روی یک Feature کار نمیکنند.
آنها به صورت مداوم روی بخشهای مختلف سیستم اثر مثبت میگذارند.
برای مثال:
بهبود Performance
افزایش Security
کاهش هزینههای زیرساخت
افزایش Reliability
سادهتر کردن فرآیند توسعه
💡 اگر بخواهیم خیلی ساده بیان کنیم...
میتوان گفت:
هرچه خروجی شما ارزشمندتر باشد و افراد یا بخشهای بیشتری از آن بهره ببرند، احتمال دریافت مسئولیتها و جبران خدمات بالاتر نیز بیشتر خواهد بود.
نه همیشه.
داشتن تخصص عمیق در یک حوزه خاص میتواند بسیار ارزشمند باشد.
اما اگر تمام استراتژی شغلی خود را فقط بر اساس یک مهارت بسیار محدود و خاص بنا کنید، ریسک بالایی دارد.
ممکن است آن مهارت در بازار امروز بسیار پرتقاضا باشد، اما چند سال بعد شرایط کاملاً تغییر کند.
🎯 پس روی چه چیزی سرمایهگذاری کنیم؟
اگر هدف رشد حرفهای است، بهتر است روی مهارتهایی تمرکز کنید که در هر پروژه و هر سازمانی ارزش ایجاد میکنند.
مانند:
✅ توانایی حل مسئله
✅ طراحی معماری
✅ تصمیمگیری مهندسی
✅ درک Trade-offها
✅ ارتباط مؤثر با تیم
✅ ایجاد ارزش برای کسبوکار، نه فقط نوشتن کد
💬 مهمترین نکته
بسیاری از افراد فکر میکنند:
اما در عمل، تفاوت اصلی آنها معمولاً در میزان ارزشی است که برای کسبوکار ایجاد میکنند، نه صرفاً در تعداد خطوط کدی که مینویسند.
در نهایت، شرکتها برای «کد» پول پرداخت نمیکنند؛ برای حل مسئله و ایجاد ارزش هزینه میکنند.
سؤال این بود:
مهندسهای نرمافزاری که حقوقهای بسیار بالایی میگیرند، دقیقاً چه نوع مسائلی را حل میکنند؟
برداشت اولیه این سؤال این است که انگار اگر در یک حوزه خاص کار کنید، خودبهخود درآمد بالایی خواهید داشت.
اما واقعیت کمی متفاوت است.
شرکتهای مختلف، کشورهای مختلف و حتی دو استارتاپ در یک صنعت، مدلهای پرداخت کاملاً متفاوتی دارند.
یک استارتاپ تازهتأسیس ممکن است با بودجه محدود حقوق پرداخت کند، در حالی که یک شرکت بزرگ فناوری برای همان نقش چند برابر بیشتر هزینه کند.
بنابراین ارتباط مستقیم بین نوع مسئله و میزان حقوق همیشه وجود ندارد.
در واقع این رابطه، یک رابطه علت و معلولی ساده نیست.
🎯 چیزی که واقعاً ارزش شما را تعیین میکند چیست؟
بر اساس تجربهای که در شرکتهای مختلف دیدهام، مهندسهایی که بیشترین ارزش را ایجاد میکنند معمولاً در یکی از این سه دسته قرار میگیرند:
🚀 1️⃣ حل مسائل با ارزش تجاری بالا در حوزههای تخصصی
آنها روی مسائلی کار میکنند که شاید افراد کمی توانایی حلشان را داشته باشند، اما تأثیر بسیار بزرگی روی کسبوکار دارند.
مثلاً:
بهینهسازی یک سیستم پرداخت که روزانه میلیونها تراکنش پردازش میکند.
طراحی زیرساختی که هزینه سرورها را ۳۰٪ کاهش میدهد.
افزایش Availability یک سرویس حیاتی.
🤝 2️⃣ تبدیل شدن به یک «Multiplier»
این افراد فقط خودشان سریع کدنویسی نمیکنند.
آنها باعث میشوند کل تیم سریعتر و بهتر کار کند.
مثلاً:
طراحی معماری مناسب
ایجاد ابزارهای داخلی
ءMentor کردن اعضای تیم
بهبود فرآیندهای توسعه
حذف گلوگاههای فنی
گاهی ارزش واقعی یک مهندس، در تعداد خط کدی که مینویسد نیست؛ بلکه در تعداد افرادی است که بهرهوری آنها را افزایش میدهد.
📈 3️⃣ ایجاد ارزش پایدار در بخشهای مختلف سیستم
برخی مهندسها فقط روی یک Feature کار نمیکنند.
آنها به صورت مداوم روی بخشهای مختلف سیستم اثر مثبت میگذارند.
برای مثال:
بهبود Performance
افزایش Security
کاهش هزینههای زیرساخت
افزایش Reliability
سادهتر کردن فرآیند توسعه
💡 اگر بخواهیم خیلی ساده بیان کنیم...
میتوان گفت:
حقوق ≈ ارزشی که ایجاد میکنید × گستره تأثیرگذاری شما
هرچه خروجی شما ارزشمندتر باشد و افراد یا بخشهای بیشتری از آن بهره ببرند، احتمال دریافت مسئولیتها و جبران خدمات بالاتر نیز بیشتر خواهد بود.
⚠️ آیا متخصص شدن در یک حوزه بسیار خاص بهترین راه است؟
نه همیشه.
داشتن تخصص عمیق در یک حوزه خاص میتواند بسیار ارزشمند باشد.
اما اگر تمام استراتژی شغلی خود را فقط بر اساس یک مهارت بسیار محدود و خاص بنا کنید، ریسک بالایی دارد.
ممکن است آن مهارت در بازار امروز بسیار پرتقاضا باشد، اما چند سال بعد شرایط کاملاً تغییر کند.
🎯 پس روی چه چیزی سرمایهگذاری کنیم؟
اگر هدف رشد حرفهای است، بهتر است روی مهارتهایی تمرکز کنید که در هر پروژه و هر سازمانی ارزش ایجاد میکنند.
مانند:
✅ توانایی حل مسئله
✅ طراحی معماری
✅ تصمیمگیری مهندسی
✅ درک Trade-offها
✅ ارتباط مؤثر با تیم
✅ ایجاد ارزش برای کسبوکار، نه فقط نوشتن کد
💬 مهمترین نکته
بسیاری از افراد فکر میکنند:
مهندسهایی که بیشترین حقوق را میگیرند، فقط کدنویسهای بهتری هستند.
اما در عمل، تفاوت اصلی آنها معمولاً در میزان ارزشی است که برای کسبوکار ایجاد میکنند، نه صرفاً در تعداد خطوط کدی که مینویسند.
در نهایت، شرکتها برای «کد» پول پرداخت نمیکنند؛ برای حل مسئله و ایجاد ارزش هزینه میکنند.
Post #735
375
#روایت_تجربه (Storytelling)
چند وقت پیش، یکی از مهندسهای ارشد در یک کنفرانس جملهای گفت که توجهم را جلب کرد.
گفت:
«هر وقت وارد یک کدبیس جدید میشوم، قبل از اینکه اولین خط کد را تغییر دهم، سعی میکنم بفهمم تیم از تغییر دادن کدام قسمت میترسد.»
ابتدا فکر کردم منظورش کیفیت کد است.
اما ادامه داد:
«در همه پروژهها یک یا چند فایل وجود دارد که وقتی اسمشان میآید، همه میگویند:
لطفاً تا جای ممکن به آن دست نزن...»
نه چون آن فایل مهمترین بخش سیستم است.
بلکه چون هیچکس مطمئن نیست بعد از تغییرش چه اتفاقی میافتد.
او میگفت:
«همان فایل، معمولاً بیشترین بدهی فنی پروژه را دارد؛ نه لزوماً بزرگترین فایل.»
این حرف برایم جالب بود.
چون ما معمولاً بدهی فنی را با تعداد خطوط کد، پیچیدگی یا قدمت پروژه اندازه میگیریم.
اما شاید معیار بهتری وجود داشته باشد.
ترس تیم از تغییر.
اگر تیم از تغییر دادن بخشی از سیستم واهمه داشته باشد،
احتمالاً آن بخش، مدتهاست که از کنترل خارج شده است.
از آن روز، هر وقت درباره سلامت یک کدبیس صحبت میشود، کمتر به تعداد کلاسها یا متدها فکر میکنم.
بیشتر به این فکر میکنم که:
«اگر فردا یک تغییر کوچک در این قسمت لازم باشد، آیا تیم با اطمینان آن را انجام میدهد؟»
چون در مهندسی نرمافزار،
گاهی خطرناکترین بخش سیستم،
بخشی نیست که بیشترین باگ را دارد.
بخشی است که همه از تغییر دادنش میترسند.
چند وقت پیش، یکی از مهندسهای ارشد در یک کنفرانس جملهای گفت که توجهم را جلب کرد.
گفت:
«هر وقت وارد یک کدبیس جدید میشوم، قبل از اینکه اولین خط کد را تغییر دهم، سعی میکنم بفهمم تیم از تغییر دادن کدام قسمت میترسد.»
ابتدا فکر کردم منظورش کیفیت کد است.
اما ادامه داد:
«در همه پروژهها یک یا چند فایل وجود دارد که وقتی اسمشان میآید، همه میگویند:
لطفاً تا جای ممکن به آن دست نزن...»
نه چون آن فایل مهمترین بخش سیستم است.
بلکه چون هیچکس مطمئن نیست بعد از تغییرش چه اتفاقی میافتد.
او میگفت:
«همان فایل، معمولاً بیشترین بدهی فنی پروژه را دارد؛ نه لزوماً بزرگترین فایل.»
این حرف برایم جالب بود.
چون ما معمولاً بدهی فنی را با تعداد خطوط کد، پیچیدگی یا قدمت پروژه اندازه میگیریم.
اما شاید معیار بهتری وجود داشته باشد.
ترس تیم از تغییر.
اگر تیم از تغییر دادن بخشی از سیستم واهمه داشته باشد،
احتمالاً آن بخش، مدتهاست که از کنترل خارج شده است.
از آن روز، هر وقت درباره سلامت یک کدبیس صحبت میشود، کمتر به تعداد کلاسها یا متدها فکر میکنم.
بیشتر به این فکر میکنم که:
«اگر فردا یک تغییر کوچک در این قسمت لازم باشد، آیا تیم با اطمینان آن را انجام میدهد؟»
چون در مهندسی نرمافزار،
گاهی خطرناکترین بخش سیستم،
بخشی نیست که بیشترین باگ را دارد.
بخشی است که همه از تغییر دادنش میترسند.
