-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpart2.js
More file actions
132 lines (132 loc) · 54.3 KB
/
Copy pathpart2.js
File metadata and controls
132 lines (132 loc) · 54.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
window.__PART2 = [
{
title: "ASP.NET Core",
desc: "پرسشهای مصاحبهای درباره چرخه درخواست، تزریق وابستگی، میزبانی، اعتبارسنجی و قابلیتهای عملیاتی ASP.NET Core.",
questions: [
{ q: "Pipeline در ASP.NET Core چیست و درخواست چگونه در آن حرکت میکند؟", a: "**Pipeline** زنجیرهای مرتب از Middlewareها است که هر درخواست و پاسخ از آن عبور میکند. هر Middleware میتواند قبل و بعد از فراخوانی `next` کاری انجام دهد یا با نخواندن آن زنجیره را کوتاه کند. ترتیب ثبت Middlewareها حیاتی است؛ مثلاً احراز هویت باید قبل از مجوزدهی و نگاشت Endpointها قرار گیرد.\nTIP: Pipeline را مانند پشتهای در نظر بگیرید که مسیر پاسخ را برعکس طی میکند." },
{ q: "Middleware چیست و چه زمانی Middleware سفارشی مینویسید؟", a: "Middleware مؤلفهای برای رسیدگی به دغدغههای سراسری مانند لاگ، شناسه همبستگی، خطا و امنیت است. Middleware سفارشی معمولاً متدی به نام `InvokeAsync(HttpContext)` دارد و وابستگیهایش را از DI میگیرد. منطق مخصوص یک Action را در Middleware نمیگذاریم، چون Middleware برای رفتار مشترک کل درخواستها مناسب است." },
{ q: "تفاوت Use، Run و Map چیست؟", a: "`Use` میتواند Middleware بعدی را با `next` فراخوانی کند و برای ساخت زنجیره بهکار میرود. `Run` یک Terminal Middleware است و پس از اجرای آن ادامه زنجیره وجود ندارد. `Map` بر اساس پیشوند مسیر یک شاخه مستقل میسازد؛ برای شرطهای پیچیدهتر نیز `MapWhen` یا `UseWhen` مناسب است." },
{ q: "چرا ترتیب Middlewareها مهم است؟", a: "هر Middleware فقط قابلیتهایی را میبیند که Middlewareهای قبلی فراهم کردهاند. برای نمونه `UseCors`، `UseAuthentication` و `UseAuthorization` باید در جای درست نسبت به Routing و Endpointها باشند. ترتیب اشتباه میتواند بدون خطای کامپایل، پاسخ امنیتی نادرست، CORS ناموفق یا Exception مدیریتنشده ایجاد کند." },
{ q: "تفاوت Transient، Scoped و Singleton در DI چیست؟", a: "`Transient` در هر Resolve نمونه جدید، `Scoped` در هر Scope وب معمولاً یک نمونه، و `Singleton` در کل عمر برنامه یک نمونه میسازد. سرویسهای بدون State سبک اغلب Transient و واحد کار مانند `DbContext` معمولاً Scoped هستند. Singleton باید Thread-safe باشد و نباید State وابسته به کاربر یا درخواست را نگه دارد." },
{ q: "Captive Dependency چیست و چرا خطرناک است؟", a: "**Captive Dependency** زمانی رخ میدهد که یک Singleton به سرویس Scoped یا Transient کوتاهعمر وابسته شود و آن را بیش از عمر مورد انتظار نگه دارد. نتیجه میتواند State مشترک ناخواسته، مصرف نادرست `DbContext` یا خطاهای همزمانی باشد. راهحل معمول اصلاح Lifetime یا ساخت Scope صریح با `IServiceScopeFactory` برای هر عملیات مستقل است." },
{ q: "آیا میتوان Scoped Service را مستقیماً داخل Singleton تزریق کرد؟", a: "خیر، تزریق مستقیم معمولاً طراحی نادرست است و در حالت ValidateScopes خطا میدهد. Singleton میتواند `IServiceScopeFactory` بگیرد و هنگام نیاز یک Scope کوتاه بسازد، سپس سرویس Scoped را از آن Resolve کند. Scope باید با `using` آزاد شود تا منابعی مانند Connection و `DbContext` نشت نکنند." },
{ q: "IHostedService چیست و چه کاربردی دارد؟", a: "`IHostedService` قرارداد اجرای کار در شروع و توقف Host با متدهای `StartAsync` و `StopAsync` است. برای مقداردهی اولیه، مصرف Queue یا هماهنگی سرویسهای پسزمینه استفاده میشود. پیادهسازی باید Cancellation، خطا و توقف Graceful را رعایت کند و Startup را بیدلیل مسدود نسازد." },
{ q: "BackgroundService چه تفاوتی با IHostedService دارد؟", a: "`BackgroundService` یک کلاس پایه و پیادهسازی سادهتر `IHostedService` است که منطق اصلی در `ExecuteAsync` قرار میگیرد. حلقه طولانی باید `stoppingToken` را بررسی کند و در Delay یا I/O به آن پاس دهد. برای سرویسهای Scoped در هر دور باید Scope تازه ساخت، نه اینکه یک نمونه را برای همیشه نگه داشت." },
{ q: "Controllerها چگونه ثبت و کشف میشوند؟", a: "با `AddControllers` سرویسهای MVC و Model Binding ثبت میشوند و با `MapControllers` Endpointهای Attribute Routing نگاشت میگردند. Controller عمومی با پسوند یا ویژگی مناسب و Actionهای قابل دسترس توسط Application Model کشف میشود. اگر View هم لازم باشد `AddControllersWithViews` و برای Razor Pages نیز ثبت متناظر استفاده میشود." },
{ q: "Minimal API بهتر است یا Controller؟", a: "Minimal API برای Endpointهای کوچک، سرویسهای سبک و کد کمتشریفات مناسب است. Controller برای APIهای بزرگ با Convention، Filter، ساختار تیمی و جداسازی Actionها خواناتر میشود. انتخاب مطلق نیست؛ معیارها شامل اندازه دامنه، نیازهای تست، استاندارد تیم و قابلیتهای MVC است." },
{ q: "Model Binding در ASP.NET Core چگونه کار میکند؟", a: "Model Binding دادههای Route، Query، Form، Header و Body را به پارامتر یا مدل .NET تبدیل میکند. Binderها بر اساس Metadata، Source و Type Converter مقدار را پیدا و تبدیل میکنند و خطاها را در `ModelState` میگذارند. در Controller دارای `[ApiController]`، خطای Binding یا Validation معمولاً خودکار پاسخ 400 تولید میکند." },
{ q: "تفاوت FromBody، FromRoute و FromQuery چیست؟", a: "`[FromRoute]` مقدار را از الگوی مسیر، `[FromQuery]` از Query String و `[FromBody]` از بدنه با Input Formatter میخواند. معمولاً در هر Action فقط یک پارامتر از Body خوانده میشود، چون Stream بدنه یکبار مصرف است. برای API شفاف، Source را در موارد مبهم صریح میکنیم و قرارداد OpenAPI را نیز بررسی میکنیم." },
{ q: "اعتبارسنجی مدلها چگونه انجام میشود؟", a: "Data Annotationهایی مانند `[Required]` و `[Range]` هنگام Model Binding اجرا و نتیجه در `ModelState` ثبت میشود. برای قواعد پیچیده میتوان از `IValidatableObject` یا کتابخانهای مانند FluentValidation استفاده کرد، ولی قواعد دامنه نباید فقط به لایه HTTP وابسته باشند. پیام خطا باید پایدار، قابل محلیسازی و بدون افشای اطلاعات داخلی باشد." },
{ q: "Filterها در MVC چه انواعی دارند؟", a: "Filterهای اصلی شامل Authorization، Resource، Action، Exception و Result هستند و هرکدام نقطه متفاوتی از چرخه MVC را پوشش میدهند. Filter برای دغدغه وابسته به MVC و Action مناسب است، درحالیکه Middleware کل Pipeline را پوشش میدهد. ترتیب با Scope، `Order` و نوع Filter تعیین میشود و باید از منطق تجاری سنگین در آن پرهیز کرد." },
{ q: "Action Filter چیست و چه کاربردی دارد؟", a: "Action Filter قبل و بعد از اجرای Action اجرا میشود و به آرگومانها، نتیجه و Context دسترسی دارد. برای لاگ ساختاریافته، اندازهگیری زمان یا قواعد مشترک Actionها مفید است. اگر رفتار باید Minimal API را هم پوشش دهد، Endpoint Filter یا Middleware گزینه مناسبتری است." },
{ q: "مدیریت خطا با Exception Middleware چگونه طراحی میشود؟", a: "یک Exception Middleware مرکزی خطاهای مدیریتنشده را میگیرد، لاگ میکند و به پاسخ استاندارد تبدیل میکند. نگاشت Exception دامنه به Status Code باید مشخص باشد؛ مثلاً NotFound به 404 و Conflict به 409 تبدیل شود. جزئیات Stack Trace در Production ارسال نمیشود و پاسخ بهتر است قالب `ProblemDetails` داشته باشد." },
{ q: "CORS چیست و چگونه امن تنظیم میشود؟", a: "**CORS** سیاست مرورگر برای اجازه دسترسی Cross-Origin است و مکانیزم احراز هویت سرور محسوب نمیشود. باید Origin، Method و Headerهای لازم را حداقلی Allow کرد و از ترکیب `AllowAnyOrigin` با Credentials پرهیز نمود. Preflight با متد `OPTIONS` اجرا میشود و Middleware باید پیش از Endpoint پاسخ مناسب بدهد." },
{ q: "API Versioning را چگونه پیادهسازی میکنید؟", a: "نسخه میتواند در URL، Query، Header یا Media Type قرار گیرد و هر روش Trade-off کش و خوانایی دارد. نسخه URL مانند `/api/v1/orders` شفاف است، ولی Versioning مبتنی بر Header آدرس منابع را ثابت نگه میدارد. باید سیاست Deprecation، مستندات نسخهها و بازه پشتیبانی از ابتدا تعریف شود." },
{ q: "تفاوت IOptions، IOptionsSnapshot و IOptionsMonitor چیست؟", a: "`IOptions<T>` مقدار تنظیمات را معمولاً یکبار میدهد و برای Singleton مناسب است. `IOptionsSnapshot<T>` در هر Scope مقدار جدید میسازد و در سرویس وب Scoped کاربرد دارد. `IOptionsMonitor<T>` تغییرات Runtime و `OnChange` را پشتیبانی میکند؛ Callback آن باید Thread-safe و قابل Dispose باشد." },
{ q: "Kestrel چیست و چه نقشی در Hosting دارد؟", a: "Kestrel وبسرور چندسکویی و پیشفرض ASP.NET Core است که HTTP/1.1، HTTP/2 و در شرایط لازم HTTP/3 را پردازش میکند. میتواند مستقیم در لبه اجرا شود، اما اغلب پشت Reverse Proxy مانند IIS یا Nginx قرار میگیرد. محدودیت اندازه درخواست، Timeout، Certificate و Forwarded Headers باید متناسب با محیط تنظیم شوند." },
{ q: "Generic Host و WebApplication چه کاری انجام میدهند؟", a: "Host عمر برنامه، Configuration، Logging، DI و Hosted Serviceها را مدیریت میکند. `WebApplicationBuilder` API یکپارچه و سادهای روی Generic Host برای برنامههای وب ارائه میدهد. تنظیمات از Providerهای مختلف با اولویت مشخص خوانده میشوند و Secretها نباید داخل فایل منبع Commit شوند." },
{ q: "Endpoint Routing چیست؟", a: "Endpoint Routing ابتدا Endpointهای نامزد را Match و سپس Endpoint منتخب را اجرا میکند. Metadataهایی مانند Authorization، CORS و Rate Limit به Endpoint متصل میشوند و Middlewareها میتوانند از آن استفاده کنند. `MapControllers`، `MapGet` و Route Groupها همگی Endpoint به جدول Routing اضافه میکنند." },
{ q: "Rate Limiting Middleware چگونه کار میکند؟", a: "Rate Limiting تعداد درخواست را بر اساس Partition مانند کاربر، IP یا API Key محدود میکند. الگوریتمهای Fixed Window، Sliding Window، Token Bucket و Concurrency برای الگوهای بار متفاوت مناسباند. پاسخ ردشده معمولاً 429 است و بهتر است `Retry-After` بدهد؛ محدودسازی توزیعشده نیازمند هماهنگی بین Instanceها است." },
{ q: "ProblemDetails چیست و چرا مفید است؟", a: "`ProblemDetails` قالب استاندارد RFC برای نمایش خطاهای HTTP با فیلدهایی مانند `type`، `title`، `status` و `detail` است. استفاده یکپارچه از آن قرارداد خطای Client را پایدار و مستندسازی را ساده میکند. داده حساس نباید در `detail` بیاید و میتوان `traceId` را برای عیبیابی امن به Extensions افزود." },
{ q: "Output Caching چیست و چه تفاوتی با Response Caching دارد؟", a: "Output Caching پاسخ را در سرور ذخیره و سیاست استفاده مجدد را خود برنامه کنترل میکند. Response Caching بیشتر به Headerهای استاندارد Cache و رفتار Client یا Proxy متکی است. کلید Cache باید Query، Header یا هویت مؤثر را لحاظ کند و پاسخ شخصیسازیشده بدون Policy درست نباید Cache شود." },
{ q: "چگونه درخواست را بهصورت Graceful متوقف و لغو میکنید؟", a: "`HttpContext.RequestAborted` هنگام قطع Client یا توقف درخواست Cancellation را اعلام میکند. این Token باید تا فراخوانیهای دیتابیس و HTTP پاییندست منتقل شود تا منابع بیهوده مصرف نشوند. Cancellation خطای تجاری نیست؛ آن را جداگانه مدیریت میکنیم و از بلعیدن بدون دلیل `OperationCanceledException` پرهیز میکنیم." },
{ q: "تفاوت Middleware و Endpoint Filter چیست؟", a: "Middleware برای همه درخواستها و پیش از انتخاب یا اجرای Handler قابل استفاده است. Endpoint Filter به آرگومانها و نتیجه Handler در Minimal API نزدیکتر است و میتواند روی Endpoint یا Route Group اعمال شود. اعتبارسنجی پارامترهای Minimal API در Filter طبیعیتر است، اما لاگ سراسری در Middleware باقی میماند." }
]
},
{
title: "Entity Framework Core",
desc: "پرسشهای عملی EF Core درباره مدلسازی، Query، همزمانی، Migration، تراکنش و کارایی.",
questions: [
{ q: "DbContext چیست و چه مسئولیتی دارد؟", a: "`DbContext` نماینده Session با دیتابیس و پیادهساز الگوهایی مانند Unit of Work و Identity Map است. Query، Change Tracking، نگاشت مدل و `SaveChanges` را هماهنگ میکند. Thread-safe نیست و باید عمر کوتاه و مشخص، معمولاً یک Scope درخواست، داشته باشد." },
{ q: "Change Tracking چگونه کار میکند؟", a: "EF Core Entityهای بارگذاریشده را در Change Tracker نگه میدارد و Stateهایی مانند Added، Modified و Deleted به آنها میدهد. هنگام `SaveChanges` تغییرات تشخیص داده و SQL مناسب تولید میشود. Track کردن تعداد بسیار زیاد Entity حافظه و زمان DetectChanges را افزایش میدهد، پس برای خواندن صرف لازم نیست." },
{ q: "AsNoTracking چه زمانی استفاده میشود؟", a: "`AsNoTracking` برای Queryهای فقطخواندنی Tracking را غیرفعال و مصرف حافظه را کمتر میکند. Entity حاصل اگر تغییر کند خودکار در `SaveChanges` ثبت نخواهد شد. برای حفظ یک نمونه واحد از Entityهای تکراری بدون Tracking میتوان `AsNoTrackingWithIdentityResolution` را بررسی کرد." },
{ q: "Include و ThenInclude چه میکنند؟", a: "`Include` Navigation مرتبط و `ThenInclude` سطوح بعدی رابطه را Eager Load میکنند. Include چند Collection ممکن است Join بسیار بزرگ و تکرار داده ایجاد کند. Projection با `Select` معمولاً برای API بهتر است، چون فقط ستونها و شکل داده موردنیاز را میگیرد." },
{ q: "AsSplitQuery چه مسئلهای را حل میکند؟", a: "`AsSplitQuery` برای Includeهای مجموعهای بهجای یک Join عظیم چند Query تولید میکند و از Cartesian Explosion جلوگیری مینماید. هزینه آن Round-trip بیشتر و احتمال مشاهده Snapshotهای متفاوت بین Queryها است. تصمیم باید با اندازه داده، Latency و اندازهگیری واقعی گرفته شود." },
{ q: "تفاوت Lazy، Eager و Explicit Loading چیست؟", a: "Eager Loading روابط را همراه Query اصلی با `Include`، و Explicit Loading آنها را به درخواست صریح بارگذاری میکند. Lazy Loading هنگام دسترسی به Navigation Query مخفی میزند و میتواند مشکل N+1 بسازد. در APIها معمولاً Projection یا بارگذاری صریح قابل پیشبینیتر از Lazy Loading است." },
{ q: "Migration در EF Core چیست؟", a: "Migration تغییرات مدل را به عملیات قابل اعمال و بازگشت روی Schema تبدیل میکند. فایل Migration باید Review شود، چون SQL تولیدی همیشه برای داده موجود یا Production بیخطر نیست. در استقرار حرفهای Script یا Bundle کنترلشده اجرا میشود و برنامه لزوماً هنگام Startup Schema را تغییر نمیدهد." },
{ q: "Migrationها را در تیم چگونه مدیریت میکنید؟", a: "هر تغییر Schema باید Migration کوچک، نامدار و همراه کد مدل در همان Branch داشته باشد. تعارض Snapshot با Rebase و بازتولید Migration حل میشود، نه ویرایش کور شناسهها. Migration اعمالشده در محیط مشترک معمولاً حذف یا بازنویسی نمیشود و اصلاح آن با Migration جدید انجام میگیرد." },
{ q: "Fluent API چه مزیتی نسبت به Data Annotation دارد؟", a: "Fluent API در `OnModelCreating` تنظیمات کاملتر و جدا از کلاس دامنه ارائه میدهد. رابطه پیچیده، Index، Conversion، Constraint و Owned Type را دقیقتر پیکربندی میکند. استفاده از `IEntityTypeConfiguration<T>` تنظیمات بزرگ را ماژولار و قابل نگهداری میسازد." },
{ q: "رابطه One-to-Many چگونه تعریف میشود؟", a: "یک Principal چند Dependent دارد و Foreign Key معمولاً روی Dependent قرار میگیرد. با `HasOne(...).WithMany(...).HasForeignKey(...)` رابطه و رفتار حذف مشخص میشود. Required بودن FK و `DeleteBehavior` باید آگاهانه انتخاب شود تا Cascade ناخواسته رخ ندهد." },
{ q: "رابطه Many-to-Many چگونه مدل میشود؟", a: "EF Core میتواند Many-to-Many ساده را با Join Entity ضمنی و `UsingEntity` نگاشت کند. اگر رابطه دادهای مانند تاریخ عضویت دارد باید Join Entity صریح بسازیم. کلید مرکب یا Unique Index روی دو FK از تکرار رابطه جلوگیری میکند." },
{ q: "Owned Entity چیست؟", a: "Owned Entity بخشی از مالک است و هویت مستقل دامنهای ندارد. میتواند در همان جدول یا جدول جدا نگاشت شود، ولی چرخه عمرش به Owner وابسته است. برای ساختارهایی مانند Address مناسب است، اما برای موجودیتی که مستقل Query یا Share میشود انتخاب خوبی نیست." },
{ q: "Value Object را چگونه در EF Core نگاشت میکنید؟", a: "Value Object با مقدارهایش شناخته میشود، Immutable است و برابری ساختاری دارد. میتوان آن را بهصورت Complex/Owned Type یا با `ValueConverter` برای مقدار تکستونی نگاشت کرد. Constructor، Comparator و محدودیتهای دامنه باید مانع ایجاد حالت نامعتبر شوند." },
{ q: "Concurrency Token چیست؟", a: "Concurrency Token ستونی است که EF مقدار اولیه آن را در شرط `UPDATE` یا `DELETE` قرار میدهد. اگر رکورد بین خواندن و ذخیره تغییر کرده باشد تعداد ردیف اثرکرده صفر و `DbUpdateConcurrencyException` ایجاد میشود. برنامه باید سیاست Retry، Merge یا اعلام Conflict به کاربر را صریح انتخاب کند." },
{ q: "RowVersion در SQL Server چگونه با EF Core استفاده میشود؟", a: "`rowversion` مقدار باینری افزایشی SQL Server برای تشخیص تغییر ردیف است و زمان واقعی نیست. در EF با `IsRowVersion()` یا ویژگی `[Timestamp]` بهعنوان Concurrency Token تنظیم میشود. Client میتواند نسخه را برگرداند و در تعارض پاسخ 409 یا 412 مناسب دریافت کند." },
{ q: "SaveChanges بهصورت پیشفرض تراکنشی است؟", a: "اگر Provider تراکنش را پشتیبانی کند، یک فراخوانی `SaveChanges` معمولاً همه تغییرات را در تراکنش اجرا میکند. در شکست، عملیات آن فراخوانی Commit نمیشود. برای چند SaveChanges یا ترکیب عملیات دیگر باید تراکنش صریح و مرز آن کوتاه نگه داشته شود." },
{ q: "تراکنش صریح در EF Core چگونه ایجاد میشود؟", a: "با `Database.BeginTransactionAsync` تراکنش آغاز و پس از موفقیت `CommitAsync` میشود. همه مسیرهای خطا باید Rollback یا Dispose را تضمین کنند و Cancellation نیز منتقل شود. نگه داشتن تراکنش هنگام تماس شبکهای طولانی Lock و احتمال Deadlock را افزایش میدهد." },
{ q: "TransactionScope چه تفاوتی با تراکنش DbContext دارد؟", a: "`TransactionScope` یک تراکنش Ambient برای چند عملیات هماهنگ ایجاد میکند و ممکن است با چند Connection به تراکنش توزیعشده ارتقا یابد. در کد Async باید `TransactionScopeAsyncFlowOption.Enabled` فعال باشد. تراکنش مستقیم DbContext شفافتر و برای یک دیتابیس معمولاً سادهتر است." },
{ q: "Lifetime مناسب DbContext چیست؟", a: "`DbContext` معمولاً Scoped و متناظر با یک درخواست یا یک واحد کار است. Singleton بودن آن بهدلیل Thread-safety، رشد Tracker و State کهنه خطرناک است. در کار پسزمینه یا پردازش موازی از `IDbContextFactory<T>` یا Scope مستقل برای هر واحد کار استفاده میشود." },
{ q: "Compiled Query چیست و چه زمانی ارزش دارد؟", a: "Compiled Query هزینه ترجمه مکرر یک شکل LINQ به Query Plan داخلی EF را کاهش میدهد. با `EF.CompileQuery` یا نسخه Async ساخته میشود و برای مسیرهای بسیار پرتکرار با ساختار ثابت مفید است. قبل از استفاده باید Benchmark کرد، چون Cache داخلی EF در بسیاری از سناریوها کافی است." },
{ q: "Global Query Filter چیست؟", a: "Global Filter شرطی است که خودکار به Queryهای Entity اضافه میشود؛ مثلاً برای Soft Delete یا Tenant. با `HasQueryFilter` تعریف و در موارد کنترلشده با `IgnoreQueryFilters` غیرفعال میشود. فیلتر Tenant نباید تنها لایه امنیت باشد و مقدار Tenant باید از منبع Scoped معتبر بیاید." },
{ q: "Interceptor در EF Core چه کاربردی دارد؟", a: "Interceptor امکان مشاهده یا تغییر Command، Connection، SaveChanges و تراکنش را میدهد. برای Audit، اندازهگیری، افزودن Tag یا سیاستهای فنی مشترک مناسب است. منطق دامنه و تغییر مخفی Queryها در Interceptor میتواند رفتار را غیرقابل پیشبینی کند، پس باید محدود و تستشده باشد." },
{ q: "Raw SQL را چگونه امن اجرا میکنید؟", a: "برای Query Entity میتوان از `FromSqlInterpolated` یا APIهای پارامتری استفاده کرد تا مقدارها Parameter شوند. چسباندن ورودی کاربر به رشته SQL خطر Injection دارد، مخصوصاً برای نام ستون و Order By که Parameterپذیر نیستند. خروجی باید با مدل سازگار باشد و Tracking و Composition آن آگاهانه انتخاب شود." },
{ q: "ExecuteUpdate و ExecuteDelete چه مزیتی دارند؟", a: "`ExecuteUpdate` و `ExecuteDelete` عملیات Set-based را مستقیم در دیتابیس و بدون بارگذاری Entityها اجرا میکنند. سریعتر و کمحافظهترند، اما Change Tracker و رویدادهای معمول SaveChanges را دور میزنند. پس از آن Entityهای Trackشده ممکن است کهنه باشند و باید Clear یا Reload شوند." },
{ q: "Shadow Property چیست؟", a: "Shadow Property در مدل EF وجود دارد ولی Property متناظر در کلاس CLR ندارد. برای Foreign Key، زمان ثبت یا داده زیرساختی بدون آلوده کردن مدل دامنه استفاده میشود. دسترسی در Query با `EF.Property<T>(entity, \"Name\")` انجام میشود و نام رشتهای باید با تست محافظت شود." },
{ q: "N+1 Query چیست و چگونه شناسایی میشود؟", a: "N+1 یعنی یک Query اولیه و سپس یک Query جدا برای هر ردیف، معمولاً بهعلت Lazy Loading یا Query داخل حلقه. Logging SQL، Profiler و شمارش Commandها در تست یکپارچه آن را آشکار میکنند. Projection، Include مناسب یا Batch Query راهحلهای رایجاند، ولی Join عظیم نیز باید کنترل شود." },
{ q: "چرا IQueryable را نباید بیمحابا از Repository بیرون داد؟", a: "`IQueryable` اجرای Query و جزئیات Provider را به لایه مصرفکننده نشت میدهد و مرز معماری را مبهم میکند. همچنین Query ممکن است دیرتر و خارج از عمر DbContext اجرا شود. Specification یا متدهای Query هدفمند کنترل و تستپذیری بیشتری میدهند، هرچند در لایه Application نزدیک به EF استفاده محدود میتواند منطقی باشد." },
{ q: "Projection چه مزیتی نسبت به برگرداندن Entity دارد؟", a: "Projection با `Select` فقط ستونهای لازم را میخواند و DTO مناسب قرارداد API میسازد. این کار Payload، Tracking و خطر Serialization چرخهای Navigationها را کم میکند. محاسبات باید تا حد ممکن قابل ترجمه به SQL باشند و Query تولیدی با `ToQueryString` بررسی شود." }
]
},
{
title: "SQL Server و دیتابیس",
desc: "پرسشهای مصاحبهای طراحی Schema، Index، Query Plan، تراکنش، همزمانی و بهینهسازی SQL Server.",
questions: [
{ q: "تفاوت Primary Key و Unique Constraint چیست؟", a: "Primary Key هویت اصلی هر ردیف است، Null نمیپذیرد و در هر جدول فقط یکی وجود دارد. Unique Constraint یکتایی یک یا چند ستون را تضمین میکند و میتوان چند مورد داشت. هر دو معمولاً Index پشتیبان میسازند، اما انتخاب Clustered یا Nonclustered مستقل از مفهوم کلید است." },
{ q: "Clustered و Nonclustered Index چه تفاوتی دارند؟", a: "Clustered Index ترتیب منطقی ذخیره ردیفهای داده در B-Tree را تعیین میکند و هر جدول فقط یکی دارد. Nonclustered Index ساختار جداگانهای با کلید و Row Locator است و تعداد بیشتری از آن ممکن است. Index بیشتر خواندن را سریع میکند، اما هزینه Insert، Update، فضا و نگهداری را افزایش میدهد." },
{ q: "Composite Index چگونه طراحی میشود؟", a: "در Index مرکب ترتیب ستونها مهم است و باید با Predicate، Join و Sort پرتکرار هماهنگ شود. قاعده Leftmost Prefix یعنی استفاده مؤثر معمولاً از ستونهای ابتدایی آغاز میشود. ستونهای برابری اغلب قبل از Range قرار میگیرند، ولی تصمیم نهایی با Selectivity و Execution Plan است." },
{ q: "Covering Index چیست؟", a: "Covering Index همه ستونهای لازم Query را در Key یا `INCLUDE` دارد و نیاز به Lookup جدول را حذف میکند. ستونهای Filter و Sort معمولاً Key و ستونهای صرفاً خروجی میتوانند Included باشند. پوشش بیشازحد Index را پهن و هزینه Write و Storage را زیاد میکند.\nTIP: یک Query پرتکرار و پرهزینه را پوشش دهید، نه هر Query ممکن را." },
{ q: "Execution Plan چه اطلاعاتی میدهد؟", a: "Execution Plan عملگرهایی مانند Seek، Scan، Join، Sort و تخمین تعداد ردیف را نشان میدهد. اختلاف بزرگ Estimated و Actual Rows معمولاً به آمار، Parameter یا Predicate دشوار اشاره دارد. هزینه درصدی فقط تخمین نسبی است؛ Logical Reads، زمان و Spill نیز باید اندازهگیری شوند." },
{ q: "Index Seek همیشه بهتر از Index Scan است؟", a: "خیر، Seek برای بخش کوچک داده عالی است ولی اگر درصد بزرگی از جدول لازم باشد Scan میتواند ارزانتر باشد. Seek همراه هزاران Key Lookup حتی از Scan بدتر میشود. معیار درست مصرف I/O، CPU و زمان روی حجم واقعی است، نه نام عملگر." },
{ q: "SARGable بودن شرط یعنی چه؟", a: "Predicate نوع SARGable اجازه میدهد موتور از ساختار Index برای محدود کردن جستوجو استفاده کند. اعمال تابع روی ستون مانند `YEAR(OrderDate)=2026` اغلب Seek را دشوار میکند و بهتر است به بازه تاریخ تبدیل شود. تبدیل نوع ضمنی و Wildcard ابتدای `LIKE` نیز میتواند استفاده مؤثر از Index را مختل کند." },
{ q: "Normalization و Denormalization چه Trade-offی دارند؟", a: "Normalization تکرار داده و ناهنجاری Insert، Update و Delete را با تفکیک موجودیتها کم میکند. Denormalization برای مسیرهای خواندن خاص Join را کاهش میدهد، اما سازگاری داده را پیچیدهتر میکند. ابتدا مدل صحیح نرمال میسازیم و فقط با اندازهگیری و سازوکار همگامسازی روشن Denormalize میکنیم." },
{ q: "تفاوت INNER، LEFT و FULL JOIN چیست؟", a: "`INNER JOIN` فقط ردیفهای Matchشده دو طرف را میدهد و `LEFT JOIN` همه ردیفهای چپ را حفظ میکند. `FULL JOIN` ردیفهای بدون Match هر دو طرف را نیز برمیگرداند. قرار دادن شرط جدول راست در `WHERE` ممکن است ناخواسته LEFT JOIN را عملاً به INNER JOIN تبدیل کند." },
{ q: "تفاوت WHERE و HAVING چیست؟", a: "`WHERE` ردیفها را پیش از Grouping و Aggregation فیلتر میکند. `HAVING` گروههای ساختهشده را پس از Aggregate محدود مینماید. شرطهای غیرتجمیعی بهتر است در WHERE باشند تا داده کمتری وارد Grouping شود." },
{ q: "CTE چیست و چه تفاوتی با Subquery دارد؟", a: "CTE یک نتیجه نامگذاریشده در محدوده همان Statement است و خوانایی Queryهای چندمرحلهای یا Recursive را بهتر میکند. بهطور پیشفرض تضمین Materialize شدن ندارد و موتور میتواند آن را Inline کند. برای استفاده چندباره سنگین، Temp Table همراه Index و آمار ممکن است بهتر باشد." },
{ q: "Window Function چه کاربردی دارد؟", a: "Window Function محاسبهای مانند رتبه، جمع تجمعی یا مقدار ردیف قبلی را بدون Collapse کردن ردیفها انجام میدهد. عبارت `OVER(PARTITION BY ... ORDER BY ...)` پنجره را تعریف میکند. `ROW_NUMBER` برای انتخاب آخرین رکورد هر گروه مفید است، ولی ترتیب باید یکتا و قطعی باشد." },
{ q: "تفاوت DELETE، TRUNCATE و DROP چیست؟", a: "`DELETE` ردیفها را با امکان شرط حذف و عملیات را Row-oriented لاگ میکند. `TRUNCATE` همه ردیفها را با آزادسازی Pageها سریعتر حذف و Identity را Reset میکند، اما محدودیتهایی مانند Foreign Key دارد. `DROP` خود Object و Metadata آن را حذف میکند و هدف متفاوتی دارد." },
{ q: "ACID چیست؟", a: "**Atomicity** همه یا هیچ، **Consistency** حفظ قواعد معتبر، **Isolation** کنترل اثر تراکنشهای همزمان و **Durability** ماندگاری Commit است. دیتابیس ابزار اجرای این ویژگیها را فراهم میکند، ولی طراحی Constraint و مرز تراکنش بر عهده برنامه است. افزایش Isolation معمولاً سازگاری را بیشتر و همزمانی را کمتر میکند." },
{ q: "Isolation Levelهای رایج SQL Server چه تفاوتی دارند؟", a: "`Read Committed` پیشفرض است و Dirty Read را جلوگیری میکند، اما Nonrepeatable Read ممکن است رخ دهد. `Repeatable Read` و `Serializable` Lock بیشتری نگه میدارند، درحالیکه Snapshot از Row Versioning برای خواندن سازگار استفاده میکند. انتخاب باید بر اساس ناهنجاری قابلقبول، Contention و هزینه `tempdb` باشد." },
{ q: "Deadlock چیست و چگونه کاهش مییابد؟", a: "Deadlock چرخهای از انتظار Lockها است و SQL Server یکی از تراکنشها را Victim میکند. ترتیب یکسان دسترسی به منابع، تراکنش کوتاه و Index مناسب احتمال آن را کم میکند. برنامه باید خطای Deadlock را با Backoff محدود Retry کند و Deadlock Graph برای علت اصلی تحلیل شود." },
{ q: "Blocking با Deadlock چه تفاوتی دارد؟", a: "Blocking انتظار طبیعی یک Session برای آزاد شدن Lock توسط Session دیگر است و ممکن است پایان یابد. Deadlock یک چرخه انتظار بدون راه پیشرفت است که موتور باید آن را بشکند. Blocking طولانی را با Session مسدودکننده، تراکنش باز و Query Plan بررسی میکنیم، نه اینکه فوراً همه Lockها را مشکل بدانیم." },
{ q: "Parameter Sniffing چیست؟", a: "SQL Server هنگام Compile ممکن است Plan را بر اساس مقدار Parameter نخست بهینه و برای اجراهای بعدی Cache کند. اگر توزیع داده ناهمگون باشد، همان Plan برای مقادیر دیگر بسیار نامناسب میشود. راهحلها شامل Query بازطراحیشده، آمار مناسب، `OPTION(RECOMPILE)` هدفمند یا `OPTIMIZE FOR` است و باید با Plan واقعی اثبات شود." },
{ q: "Stored Procedure چه مزایا و معایبی دارد؟", a: "Stored Procedure قرارداد نزدیک دیتابیس، Permission محدود و استفاده مجدد از Plan فراهم میکند. در مقابل Versioning، تست و نگهداری منطق پراکنده بین برنامه و دیتابیس را دشوار میسازد. برای عملیات دادهمحور سنگین مناسب است، اما انتقال تمام منطق دامنه به Procedure لزوماً معماری خوبی نیست." },
{ q: "Temp Table و Table Variable چه تفاوتی دارند؟", a: "Temp Table با نام `#T` در `tempdb` ساخته میشود، آمار و Indexهای انعطافپذیر دارد و برای داده متوسط یا زیاد مناسب است. Table Variable Scope محدودتری دارد و در نسخههای جدید تخمین آن بهتر شده، اما برای حجم بزرگ همیشه سبکتر نیست. انتخاب باید با حجم واقعی، Recompile و Plan سنجیده شود." },
{ q: "Indexed View چیست؟", a: "Indexed View نتیجه View را با Unique Clustered Index فیزیکی نگه میدارد و میتواند Queryهای تجمیعی پرتکرار را سریع کند. محدودیتهای Schema Binding و گزینههای Session دارد و هر Write به جداول پایه هزینه نگهداری ایجاد میکند. پیش از استفاده باید نسبت خواندن به نوشتن و امکان استفاده Optimizer بررسی شود." },
{ q: "MERGE چه کاربرد و چه ریسکهایی دارد؟", a: "`MERGE` میتواند Insert، Update و Delete را بر اساس Match در یک Statement بیان کند. بااینحال پیچیدگی همزمانی، رفتار چند Match و سابقه اشکالات باعث میشود در مسیرهای حساس با احتیاط استفاده شود. اغلب `UPDATE` و `INSERT` جدا در تراکنش، با Constraint یکتا و مدیریت Race، شفافتر است." },
{ q: "TRY/CATCH را در تراکنش SQL چگونه مینویسید؟", a: "در `TRY` تراکنش آغاز، عملیات اجرا و سپس Commit میشود و در `CATCH` وضعیت با `XACT_STATE()` بررسی میگردد. اگر تراکنش فعال یا غیرقابل Commit باشد `ROLLBACK` انجام و خطا با `THROW` دوباره پرتاب میشود. `SET XACT_ABORT ON` برای بسیاری از خطاهای Runtime رفتار تراکنش را قابل پیشبینیتر میکند." },
{ q: "آمار Statistics چه اثری بر Query Plan دارد؟", a: "Optimizer با Statistics توزیع تقریبی مقدارها و Cardinality را تخمین میزند. آمار کهنه یا نمونهبرداری نامناسب میتواند Join Order، Memory Grant و نوع دسترسی بدی ایجاد کند. Update Statistics باید هدفمند باشد؛ اجرای بیرویه Full Scan روی جداول بزرگ نیز هزینه قابلتوجه دارد." },
{ q: "Pagination با OFFSET چه مشکلی دارد و Keyset چیست؟", a: "`OFFSET/FETCH` ساده است، اما صفحات عمیق باید ردیفهای زیادی را Sort و رد کنند و در تغییر همزمان داده ممکن است تکرار یا جاافتادگی رخ دهد. Keyset Pagination با آخرین کلید مرتبسازی شرط ادامه میسازد و عملکرد پایدارتری دارد. ترتیب باید قطعی باشد؛ مثلاً `(CreatedAt, Id)` و Index متناظر داشته باشد." },
{ q: "چگونه SQL Injection را جلوگیری میکنید؟", a: "مقدار ورودی همیشه باید Parameter شود و Query با اتصال رشتهای ساخته نشود. نام جدول، ستون یا جهت Sort را نمیتوان معمولاً Parameter کرد، پس باید از Allowlist معتبر انتخاب شوند. کمینهسازی Permission حساب دیتابیس لایه دفاعی دوم است و جای Parameterization را نمیگیرد." },
{ q: "چرا SELECT * در Queryهای Production نامناسب است؟", a: "`SELECT *` داده و I/O اضافی منتقل میکند و ممکن است مانع Covering Index شود. تغییر Schema نیز ناخواسته قرارداد خروجی و Mapping را تغییر میدهد. انتخاب صریح ستونها خوانایی، امنیت داده و پایداری Plan و قرارداد را بهتر میکند." },
{ q: "Connection Pooling چگونه کار میکند؟", a: "Pooling اتصال فیزیکی باز را برای Connection String یکسان دوباره استفاده میکند تا هزینه Handshake کم شود. `Close` یا Dispose معمولاً Connection را به Pool برمیگرداند، نه اینکه Socket را حتماً ببندد. تراکنش طولانی، Reader باز یا نشت Connection میتواند Pool را Exhaust کند و Timeout بسازد." }
]
},
{
title: "HTTP، REST و طراحی API",
desc: "پرسشهای طراحی قرارداد HTTP، معنای REST، نسخهبندی، مستندسازی، صفحهبندی و انتخاب سبک API.",
questions: [
{ q: "اصول اصلی REST چیست؟", a: "REST سبک معماری مبتنی بر Resource، رابط یکنواخت، Stateless بودن، Cacheability و تفکیک Client از Server است. URL بهتر است اسم Resource باشد و رفتار با Verbهای HTTP بیان شود. REST فقط JSON روی HTTP نیست؛ رعایت Semantics متدها و Status Codeها بخش مهم قرارداد است." },
{ q: "Stateless بودن API یعنی چه؟", a: "هر درخواست باید اطلاعات لازم برای پردازش خود را داشته باشد و Server به Session پنهان درخواست قبلی وابسته نباشد. این ویژگی Scale-out و بازیابی خطا را سادهتر میکند. Stateless به معنی نداشتن State در دیتابیس نیست؛ State منبع روی Storage پایدار نگه داشته میشود." },
{ q: "Idempotency چیست و کدام متدها Idempotent هستند؟", a: "عملیات Idempotent با تکرار همان درخواست اثر نهایی یکسانی دارد، هرچند پاسخ یا لاگ میتواند متفاوت باشد. `GET`، `PUT` و `DELETE` از نظر Semantics باید Idempotent باشند، ولی `POST` معمولاً نیست. برای پرداخت یا ایجاد حساس، `Idempotency-Key` و ذخیره نتیجه از ایجاد تکراری جلوگیری میکند." },
{ q: "تفاوت Safe و Idempotent در HTTP چیست؟", a: "متد Safe مانند `GET` نباید State تجاری منبع را تغییر دهد. Idempotent ممکن است State را تغییر دهد، اما تکرار آن اثر اضافه نسازد؛ مانند `DELETE`. ثبت لاگ یا شمارنده فنی در GET مفهوم Safe را نقض نمیکند، بهشرطی که اثر مورد انتظار کاربر تغییر منبع نباشد." },
{ q: "PUT و PATCH چه تفاوتی دارند؟", a: "`PUT` معمولاً جایگزینی کامل نمایش منبع در URI مشخص و Idempotent است. `PATCH` تغییر جزئی را با قالبی مانند JSON Patch یا Merge Patch بیان میکند. قرارداد فیلدهای حذفشده، Null و Validation باید شفاف باشد تا Partial Update داده را ناخواسته پاک نکند." },
{ q: "POST چه زمانی باید 201 برگرداند؟", a: "وقتی درخواست منبع جدیدی میسازد، پاسخ `201 Created` مناسب است. Header به نام `Location` بهتر است URI منبع ایجادشده را بدهد و Body میتواند نمایش آن را برگرداند. اگر کار Async فقط پذیرفته شده، `202 Accepted` همراه URI وضعیت دقیقتر است." },
{ q: "مهمترین Status Codeهای موفق کداماند؟", a: "`200 OK` برای پاسخ موفق دارای Body، `201 Created` برای ایجاد و `204 No Content` برای موفقیت بدون Body رایجاند. `202 Accepted` یعنی پردازش پذیرفته شده ولی هنوز کامل نیست. انتخاب Status باید معنای واقعی عملیات را منتقل کند، نه اینکه همه نتایج با 200 و فیلد داخلی گزارش شوند." },
{ q: "تفاوت 400، 401، 403 و 404 چیست؟", a: "`400` درخواست نامعتبر، `401` نبودن یا نامعتبر بودن احراز هویت و `403` نداشتن مجوز با وجود هویت معتبر است. `404` نبودن منبع را میرساند و گاهی برای جلوگیری از افشای وجود منبع استفاده میشود. پاسخ `401` معمولاً Header به نام `WWW-Authenticate` دارد." },
{ q: "چه زمانی 409، 412 و 422 استفاده میشوند؟", a: "`409 Conflict` برای تعارض با State فعلی مانند نسخه همزمانی یا کلید تکراری مناسب است. `412 Precondition Failed` وقتی شرط Headerهایی مانند `If-Match` برقرار نیست استفاده میشود. `422 Unprocessable Content` برای ساختار قابلفهم ولی قواعد معنایی نامعتبر کاربرد دارد، البته قرارداد تیم باید یکدست باشد." },
{ q: "HATEOAS چیست و آیا همیشه لازم است؟", a: "HATEOAS یعنی پاسخ علاوه بر داده، Linkهای عملیات و انتقالهای مجاز بعدی را ارائه کند. این کار Client را از ساخت دستی URL جدا میکند و Workflow قابل کشف میسازد. برای API داخلی ساده هزینه پیچیدگی ممکن است بیشتر از سود باشد، پس سطح بلوغ REST باید آگاهانه انتخاب شود." },
{ q: "Offset Pagination و Cursor Pagination چه تفاوتی دارند؟", a: "Offset Pagination با `page` و `size` ساده و مناسب پرش به صفحه است، اما روی داده بزرگ و متغیر کند یا ناپایدار میشود. Cursor Pagination یک Token ادامه بر اساس ترتیب پایدار میدهد و برای Feed و داده پرتغییر مناسبتر است. Cursor باید Opaque، قابل اعتبارسنجی و وابسته به Filter و Sort فعلی باشد." },
{ q: "در پاسخ صفحهبندی چه Metadataی میدهید؟", a: "حداقل داده شامل Items و نشانه ادامه مانند `nextCursor` یا Link صفحه بعد است. Total Count فقط وقتی محاسبه آن لازم و مقرونبهصرفه است ارائه میشود، چون روی Query پیچیده میتواند گران باشد. حداکثر اندازه صفحه باید در Server محدود شود تا Client نتواند Payload نامحدود درخواست کند." },
{ q: "روشهای API Versioning چه هستند؟", a: "نسخه در Path مانند `/v1`، Query، Header یا Media Type قابل قرار دادن است. Path برای مشاهده و Routing ساده است، Header URI را تمیز نگه میدارد و Media Type دقیق ولی پیچیدهتر است. راهبرد باید همراه Sunset، Deprecation و Migration Guide باشد، نه فقط افزودن شماره نسخه." },
{ q: "چه تغییری Breaking Change محسوب میشود؟", a: "حذف یا تغییر نام فیلد، تغییر Type، سختتر کردن Validation و تغییر معنای Status Code معمولاً Breaking است. افزودن فیلد اغلب سازگار است، اما Clientهای سختگیر نیز باید در نظر گرفته شوند. Contract Test و Schema Diff میتواند شکست ناخواسته قرارداد را پیش از انتشار کشف کند." },
{ q: "OpenAPI چه کاربردی دارد؟", a: "OpenAPI قرارداد ماشینخوان Endpointها، پارامترها، Schemaها، پاسخها و امنیت را توصیف میکند. از آن برای مستندات تعاملی، تولید Client و Contract Testing استفاده میشود. سند تولیدشده باید Review شود، چون Annotation ناقص میتواند مستندی متفاوت از رفتار واقعی بسازد." },
{ q: "Content Negotiation چیست؟", a: "Client با Header به نام `Accept` نوع نمایش مطلوب را اعلام و Server با `Content-Type` قالب واقعی را مشخص میکند. اگر هیچ Formatter قابلقبولی نباشد `406 Not Acceptable` میتواند برگردد. در APIهای JSON-only نیز اعلام صریح Media Type و Charset قرارداد را روشن میکند." },
{ q: "GraphQL چه زمانی از REST مناسبتر است؟", a: "GraphQL زمانی مفید است که Clientها شکلهای داده بسیار متفاوت دارند و نیاز به ترکیب Graph پیچیده در یک درخواست است. Schema قوی و انتخاب فیلد Over-fetching را کم میکند، ولی Cache HTTP، Authorization سطح فیلد و کنترل هزینه Query پیچیدهتر میشود. برای CRUD ساده و عملیات همسو با Semantics HTTP، REST غالباً کمهزینهتر است." },
{ q: "چگونه Cache HTTP را طراحی میکنید؟", a: "`Cache-Control` سیاست تازگی و اشتراکپذیری را مشخص و `ETag` یا `Last-Modified` اعتبارسنجی مجدد را ممکن میکند. پاسخ خصوصی نباید در Cache مشترک قرار گیرد و `Vary` باید Headerهای مؤثر را اعلام کند. Cache Invalidation با مدل تغییر داده هماهنگ میشود و اطلاعات حساس بدون Policy صریح Cache نمیشوند." },
{ q: "ETag و If-Match چه کاربردی دارند؟", a: "ETag شناسه نسخه نمایش منبع است و میتواند از RowVersion ساخته شود. Client در Update، مقدار قبلی را با `If-Match` میفرستد و Server در صورت تغییر منبع پاسخ `412` میدهد. این روش Optimistic Concurrency را وارد قرارداد HTTP میکند و از Lost Update جلوگیری مینماید." },
{ q: "طراحی URL مناسب برای REST چگونه است؟", a: "URLها بهتر است Resourceمحور، جمع و پایدار باشند؛ مانند `/orders/{id}/items`. فعلهایی مانند `/getOrders` معمولاً زائداند، چون Method عمل را بیان میکند. عمق زیاد Nested Resource و افشای ساختار دیتابیس نگهداری قرارداد را سخت میکند." },
{ q: "چگونه خطاهای API را استاندارد میکنید؟", a: "همه Endpointها باید Envelope خطای ثابت، ترجیحاً `application/problem+json` با Status درست برگردانند. کد خطای دامنهای پایدار برای تصمیم Client مفید است و `traceId` عیبیابی را ساده میکند. Stack Trace، SQL و اطلاعات شخصی نباید در پاسخ Production افشا شوند." },
{ q: "Timeout، Retry و Idempotency چگونه به هم مرتبطاند؟", a: "Timeout Client به معنی اجرا نشدن عملیات در Server نیست و ممکن است پاسخ فقط گم شده باشد. Retry کور روی POST غیر Idempotent میتواند سفارش یا پرداخت تکراری بسازد. عملیات حساس باید Idempotency Key، وضعیت قابل Query و Retry با Backoff و Jitter داشته باشد." }
]
}
];