Forwarded from Code With HSN
با Copilot به تلگرامت وصل شو | MCP Server در 16 دقیقه
در ویدیو جدیدم بهصورت کامل با مفهوم MCP آشنا میشیم و یاد میگیریم چطور یه MCP Server و MCP Client بسازیم تا مدلهای هوش مصنوعی مثل Ollama و حتی GitHub Copilot بتونن باهاش ارتباط بگیرن.
همه مراحل از صفر تا اتصال به VS Code و تست روی تلگرام انجام میشن.
00:00 تعریف ساده از MCP
01:54 ساختار یک MCP Server
04:25 ساختار MCP Client با Ollama
06:50 نصب Ollama با llama3.1 model
09:15 تست MCP Client و ارسال پیام تلگرام
12:12 اتصال MCP Server به Copilot vs
15:48 جمع بندی نهایی
با آرزوی یک هفته خوب براتون بترکونید 💪🏻
ویدیو در یوتیوب: مشاهده
مدت ویدیو: 16 دقیقه با عشق 🙂↔️
در ویدیو جدیدم بهصورت کامل با مفهوم MCP آشنا میشیم و یاد میگیریم چطور یه MCP Server و MCP Client بسازیم تا مدلهای هوش مصنوعی مثل Ollama و حتی GitHub Copilot بتونن باهاش ارتباط بگیرن.
همه مراحل از صفر تا اتصال به VS Code و تست روی تلگرام انجام میشن.
00:00 تعریف ساده از MCP
01:54 ساختار یک MCP Server
04:25 ساختار MCP Client با Ollama
06:50 نصب Ollama با llama3.1 model
09:15 تست MCP Client و ارسال پیام تلگرام
12:12 اتصال MCP Server به Copilot vs
15:48 جمع بندی نهایی
با آرزوی یک هفته خوب براتون بترکونید 💪🏻
ویدیو در یوتیوب: مشاهده
مدت ویدیو: 16 دقیقه با عشق 🙂↔️
“Everything fails, all the time”
«همه چیز خراب میشود، همیشه.»
این فلسفه میگوید «نباید انتظار داشت هیچ خطایی رخ ندهد، بلکه باید سیستمها را طوری بسازیم که حتی در صورت وقوع خطاها هم عملکرد ادامه یابد.»
پذیرش شکست به عنوان یک واقعیت طبیعی
هیچ سیستم یا سرویس نرمافزاری کامل و بدون خطا نیست.
حتی سختافزارهای قدرتمند یا سرویسهای ابری معتبر هم ممکن است خراب شوند.
مثال: سرورهای دیتاسنتر، شبکهها، پایگاه دادهها، حتی کد نرمافزاری پیچیده، همه میتوانند دچار اختلال شوند.
طراحی برای تحمل خطا (Fault Tolerance):
مهندسین مدرن فرض میکنند که خطا همیشه رخ میدهد.
سیستمها باید به گونهای طراحی شوند که شکستها را تحمل کنند و سرویس ادامه پیدا کند.
ابزارها و الگوها: Retry، Circuit Breaker، Replication، Load Balancing، Redundancy.
مقیاسپذیری و قابلیت اطمینان:
وقتی میدانیم همه چیز ممکن است خراب شود، طراحی سیستم به سمت مقیاسپذیری و قابلیت اطمینان میرود.
مثال: سیستمهای توزیعشده مانند Netflix یا Amazon، از این فلسفه برای طراحی خود استفاده میکنند.
فرهنگ مهندسی معاصر:
این جمله بخشی از فلسفهی مهندسی مدرن است که “assume failure, build resilient systems” یا «خطا را فرض کن، سیستم مقاوم بساز» را تشویق میکند.
یعنی تمرکز روی پیشگیری از خرابی نیست، بلکه روی کاهش تأثیر خرابیها و بازیابی سریع است.
مثالهای عملی:
استفاده از چند دیتاسنتر برای تحمل خرابی یک دیتاسنتر.
طراحی سیستمهای توزیعشده با Replica و Failover خودکار.
کدنویسی با قابلیت Retry و Timeout برای سرویسهای خارجی.
اجرای Chaos Engineering برای شبیهسازی خرابیها و بهبود مقاومت سیستم.
#مهندسی_نرمافزار
#قابلیت_اطمینان
#تحمل_خطا
«همه چیز خراب میشود، همیشه.»
این فلسفه میگوید «نباید انتظار داشت هیچ خطایی رخ ندهد، بلکه باید سیستمها را طوری بسازیم که حتی در صورت وقوع خطاها هم عملکرد ادامه یابد.»
پذیرش شکست به عنوان یک واقعیت طبیعی
هیچ سیستم یا سرویس نرمافزاری کامل و بدون خطا نیست.
حتی سختافزارهای قدرتمند یا سرویسهای ابری معتبر هم ممکن است خراب شوند.
مثال: سرورهای دیتاسنتر، شبکهها، پایگاه دادهها، حتی کد نرمافزاری پیچیده، همه میتوانند دچار اختلال شوند.
طراحی برای تحمل خطا (Fault Tolerance):
مهندسین مدرن فرض میکنند که خطا همیشه رخ میدهد.
سیستمها باید به گونهای طراحی شوند که شکستها را تحمل کنند و سرویس ادامه پیدا کند.
ابزارها و الگوها: Retry، Circuit Breaker، Replication، Load Balancing، Redundancy.
مقیاسپذیری و قابلیت اطمینان:
وقتی میدانیم همه چیز ممکن است خراب شود، طراحی سیستم به سمت مقیاسپذیری و قابلیت اطمینان میرود.
مثال: سیستمهای توزیعشده مانند Netflix یا Amazon، از این فلسفه برای طراحی خود استفاده میکنند.
فرهنگ مهندسی معاصر:
این جمله بخشی از فلسفهی مهندسی مدرن است که “assume failure, build resilient systems” یا «خطا را فرض کن، سیستم مقاوم بساز» را تشویق میکند.
یعنی تمرکز روی پیشگیری از خرابی نیست، بلکه روی کاهش تأثیر خرابیها و بازیابی سریع است.
مثالهای عملی:
استفاده از چند دیتاسنتر برای تحمل خرابی یک دیتاسنتر.
طراحی سیستمهای توزیعشده با Replica و Failover خودکار.
کدنویسی با قابلیت Retry و Timeout برای سرویسهای خارجی.
اجرای Chaos Engineering برای شبیهسازی خرابیها و بهبود مقاومت سیستم.
#مهندسی_نرمافزار
#قابلیت_اطمینان
#تحمل_خطا
🚀 تفاوت readonly و const در #CSharp — نکتهای کلیدی برای بهبود Performance
در #CSharp، دو کلیدواژهی readonly و const هر دو برای مقادیر تغییرناپذیر استفاده میشوند،
اما تفاوت آنها فقط نحوی نیست — تفاوتی اساسی در نحوهی عملکرد و سرعت اجرای کد دارند.
⚙️ ۱. const
مقدار در زمان کامپایل مشخص میشود.
فقط برای انواع ساده (اعداد، رشتهها، enum) قابل استفاده است.
مقدار در تمام جاهایی که استفاده میشود inline میگردد، یعنی هیچ دسترسی به حافظه انجام نمیشود.
✅ سریعتر است چون کامپایلر آن را به عدد ثابت تبدیل میکند.
⚙️ ۲. readonly
مقدار در زمان اجرا مقداردهی میشود (در سازنده یا بهصورت inline).
میتواند شامل انواع پیچیده یا reference types باشد.
مقدار در حافظه نگهداری میشود و در هر دسترسی باید از حافظه خوانده شود.
⚠️ در مسیرهای پرتکرار (hot paths)، این دسترسیهای مکرر میتوانند باعث افت عملکرد شوند.
📊 ۳. تفاوت عملکردی
در بنچمارکها مشخص شده:
const عملکرد سریعتری دارد چون به مقدار حافظه دسترسی ندارد.
readonly کمی کندتر است چون مقدار از فیلد حافظه خوانده میشود.
💡 ۴. قوانین پیشنهادی برای استفاده درست
1️⃣ از const برای مقادیری که در زمان کامپایل مشخصاند استفاده کنید.
2️⃣ از readonly برای مقادیری که باید در زمان اجرا مقداردهی شوند استفاده کنید.
3️⃣ در مسیرهای پرتکرار از static readonly با احتیاط استفاده کنید.
4️⃣ همیشه عملکرد را Benchmark کنید — حدس نزنید، اندازهگیری کنید.
✅ نتیجه نهایی:
درک درست تفاوت بین readonly و const میتواند به کاهش مصرف CPU،
افزایش سرعت اجرای برنامه، و بهینهسازی عملکرد کلی سیستم منجر شود.
👨💻 #DotNet #CSharp #Performance #CodeOptimization #CleanCode
در #CSharp، دو کلیدواژهی readonly و const هر دو برای مقادیر تغییرناپذیر استفاده میشوند،
اما تفاوت آنها فقط نحوی نیست — تفاوتی اساسی در نحوهی عملکرد و سرعت اجرای کد دارند.
⚙️ ۱. const
مقدار در زمان کامپایل مشخص میشود.
فقط برای انواع ساده (اعداد، رشتهها، enum) قابل استفاده است.
مقدار در تمام جاهایی که استفاده میشود inline میگردد، یعنی هیچ دسترسی به حافظه انجام نمیشود.
public const double Pi = 3.14159;
double area = Pi * r * r;
✅ سریعتر است چون کامپایلر آن را به عدد ثابت تبدیل میکند.
⚙️ ۲. readonly
مقدار در زمان اجرا مقداردهی میشود (در سازنده یا بهصورت inline).
میتواند شامل انواع پیچیده یا reference types باشد.
مقدار در حافظه نگهداری میشود و در هر دسترسی باید از حافظه خوانده شود.
public static readonly double Factor = Math.Sqrt(2);
double result = Factor * x; // در هر بار اجرا از حافظه خوانده میشود
⚠️ در مسیرهای پرتکرار (hot paths)، این دسترسیهای مکرر میتوانند باعث افت عملکرد شوند.
📊 ۳. تفاوت عملکردی
در بنچمارکها مشخص شده:
const عملکرد سریعتری دارد چون به مقدار حافظه دسترسی ندارد.
readonly کمی کندتر است چون مقدار از فیلد حافظه خوانده میشود.
💡 ۴. قوانین پیشنهادی برای استفاده درست
1️⃣ از const برای مقادیری که در زمان کامپایل مشخصاند استفاده کنید.
2️⃣ از readonly برای مقادیری که باید در زمان اجرا مقداردهی شوند استفاده کنید.
3️⃣ در مسیرهای پرتکرار از static readonly با احتیاط استفاده کنید.
4️⃣ همیشه عملکرد را Benchmark کنید — حدس نزنید، اندازهگیری کنید.
✅ نتیجه نهایی:
درک درست تفاوت بین readonly و const میتواند به کاهش مصرف CPU،
افزایش سرعت اجرای برنامه، و بهینهسازی عملکرد کلی سیستم منجر شود.
👨💻 #DotNet #CSharp #Performance #CodeOptimization #CleanCode
🔥1
🚫 Antipattern: Extraneous Fetching در نرمافزارها
در توسعه نرمافزار، Extraneous Fetching زمانی رخ میدهد که برنامه بیش از دادههای لازم را از پایگاه داده میگیرد. این موضوع باعث افزایش I/O، کاهش پاسخدهی و کندی عملکرد میشود.
🔹 نمونهها:
گرفتن همه جزئیات محصولات وقتی کاربر فقط به بخشی از آنها نیاز دارد.
جمعآوری همه سفارشات و محاسبه مجموع در حافظه برنامه به جای پایگاه داده.
استفاده از LINQ با AsEnumerable که باعث میشود فیلترها در کلاینت اعمال شوند نه در دیتابیس.
💡 راهحلها:
فقط دادههای مورد نیاز را از دیتابیس دریافت کنید.
محاسبات و aggregation را در خود دیتابیس انجام دهید.
از IQueryable به جای IEnumerable استفاده کنید تا پردازشها سمت سرور انجام شود.
پیادهسازی pagination برای نتایج بزرگ.
📊 نتایج:
با اصلاح کد و کاهش دادههای اضافه، میتوان زمان پاسخ را از 4 ثانیه به 1.3 ثانیه کاهش داد و تعداد درخواستهای قابل پردازش در ثانیه را سه برابر افزایش داد.
✅ این بهبودها باعث کاهش فشار روی دیتابیس، افزایش کارایی و تجربه بهتر کاربران میشود.
در توسعه نرمافزار، Extraneous Fetching زمانی رخ میدهد که برنامه بیش از دادههای لازم را از پایگاه داده میگیرد. این موضوع باعث افزایش I/O، کاهش پاسخدهی و کندی عملکرد میشود.
🔹 نمونهها:
گرفتن همه جزئیات محصولات وقتی کاربر فقط به بخشی از آنها نیاز دارد.
جمعآوری همه سفارشات و محاسبه مجموع در حافظه برنامه به جای پایگاه داده.
استفاده از LINQ با AsEnumerable که باعث میشود فیلترها در کلاینت اعمال شوند نه در دیتابیس.
💡 راهحلها:
فقط دادههای مورد نیاز را از دیتابیس دریافت کنید.
محاسبات و aggregation را در خود دیتابیس انجام دهید.
از IQueryable به جای IEnumerable استفاده کنید تا پردازشها سمت سرور انجام شود.
پیادهسازی pagination برای نتایج بزرگ.
📊 نتایج:
با اصلاح کد و کاهش دادههای اضافه، میتوان زمان پاسخ را از 4 ثانیه به 1.3 ثانیه کاهش داد و تعداد درخواستهای قابل پردازش در ثانیه را سه برابر افزایش داد.
✅ این بهبودها باعث کاهش فشار روی دیتابیس، افزایش کارایی و تجربه بهتر کاربران میشود.
💡 تفاوت const و readonly در C#
در C# دو کلمه کلیدی داریم برای تعریف مقادیر ثابت:
🔹 const
🔹 readonly
اما فرقشون چیه؟ 👇
🧱 const
مقدار در زمان کامپایل مشخص میشه و بعدش دیگه قابل تغییر نیست
بهصورت static و مشترک بین همهی نمونههاست
📌 فقط برای مقادیر کاملاً ثابت مثل عدد π یا تعداد روزهای هفته استفاده میشه.
🧩 readonly
مقدار در زمان اجرا (Runtime) تعیین میشه، مثلاً داخل سازنده (Constructor).
برای هر نمونه (Instance) میتواند مقدار متفاوتی داشته باشد
📌 وقتی میخوای مقدار فقط یکبار تنظیم بشه ولی در زمان اجرا مشخص بشه، از readonly استفاده کن.
در C# دو کلمه کلیدی داریم برای تعریف مقادیر ثابت:
🔹 const
🔹 readonly
اما فرقشون چیه؟ 👇
🧱 const
مقدار در زمان کامپایل مشخص میشه و بعدش دیگه قابل تغییر نیست
بهصورت static و مشترک بین همهی نمونههاست
📌 فقط برای مقادیر کاملاً ثابت مثل عدد π یا تعداد روزهای هفته استفاده میشه.
🧩 readonly
مقدار در زمان اجرا (Runtime) تعیین میشه، مثلاً داخل سازنده (Constructor).
برای هر نمونه (Instance) میتواند مقدار متفاوتی داشته باشد
📌 وقتی میخوای مقدار فقط یکبار تنظیم بشه ولی در زمان اجرا مشخص بشه، از readonly استفاده کن.
مدیریت پکیجها در پروژههای بزرگ .NET همیشه یکی از چالشهای اصلی توسعهدهندگان بوده است. زمانی که چندین پروژه در یک Solution دارید، هماهنگ نگه داشتن نسخهی پکیجهای NuGet بهراحتی میتواند به یک کابوس تبدیل شود.
اینجاست که قابلیت Central Package Management (CPM) وارد عمل میشود و با استفاده از فایل
Directory.Packages.props مدیریت نسخهی پکیجها را متمرکز، ساده و قابل نگهداری میکند.
🔹 Directory.Packages.props چیست؟
این فایل در ریشهی Solution قرار میگیرد و تمام نسخههای پکیجهای مورد استفاده در پروژهها را در یکجا تعریف میکند. از این به بعد، در فایلهای .csproj فقط نام پکیج نوشته میشود و نسخهی آن از فایل مرکزی خوانده میشود.
🔹 مزایای اصلی:
✅ یکپارچگی نسخه پکیجها در تمام پروژهها
✅ کاهش خطاهای ناشی از اختلاف نسخهها
✅ ساده شدن آپدیت پکیجها در یک محل
✅ تمیز شدن فایلهای .csproj
✅ افزایش کنترل و نگهداری بهتر در تیمهای بزرگ
📌 مثال ساده:
در فایل Directory.Packages.props:
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.0" />
</ItemGroup>
</Project>
و در فایل csproj فقط مینویسیم:
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" />
</ItemGroup>
🔸 نکات مهم:
• در CPM نمیتوانید از نسخههای شناور مثل 9.0-* استفاده کنید.
• باید نسخهها را به صورت دستی در فایل مرکزی آپدیت کنید.
• پیشنهاد میشود ماهی یکبار (بعد از Patch Tuesday) نسخهها را بررسی و بهروزرسانی کنید.
• در صورت بروز مشکل، میتوانید برای یک پروژه خاص از VersionOverride استفاده کنید.
🎯 نتیجه:
اگر روی یک Solution بزرگ، تیمی یا سازمانی کار میکنید، استفاده از Directory.Packages.props یک «باید» است، نه یک انتخاب. این روش، معماری پروژهی شما را تمیزتر، حرفهایتر و قابل توسعهتر میکند.
اگر دوست دارید در پست بعدی، نحوه پیادهسازی کامل CPM در یک پروژه واقعی را مرحلهبهمرحله آموزش میدهم.
#dotnet #nuget #netdeveloper #csharp #softwarearchitecture #cleanarchitecture #programming #CentralPackageManagement
اینجاست که قابلیت Central Package Management (CPM) وارد عمل میشود و با استفاده از فایل
Directory.Packages.props مدیریت نسخهی پکیجها را متمرکز، ساده و قابل نگهداری میکند.
🔹 Directory.Packages.props چیست؟
این فایل در ریشهی Solution قرار میگیرد و تمام نسخههای پکیجهای مورد استفاده در پروژهها را در یکجا تعریف میکند. از این به بعد، در فایلهای .csproj فقط نام پکیج نوشته میشود و نسخهی آن از فایل مرکزی خوانده میشود.
🔹 مزایای اصلی:
✅ یکپارچگی نسخه پکیجها در تمام پروژهها
✅ کاهش خطاهای ناشی از اختلاف نسخهها
✅ ساده شدن آپدیت پکیجها در یک محل
✅ تمیز شدن فایلهای .csproj
✅ افزایش کنترل و نگهداری بهتر در تیمهای بزرگ
📌 مثال ساده:
در فایل Directory.Packages.props:
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.0" />
</ItemGroup>
</Project>
و در فایل csproj فقط مینویسیم:
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" />
</ItemGroup>
🔸 نکات مهم:
• در CPM نمیتوانید از نسخههای شناور مثل 9.0-* استفاده کنید.
• باید نسخهها را به صورت دستی در فایل مرکزی آپدیت کنید.
• پیشنهاد میشود ماهی یکبار (بعد از Patch Tuesday) نسخهها را بررسی و بهروزرسانی کنید.
• در صورت بروز مشکل، میتوانید برای یک پروژه خاص از VersionOverride استفاده کنید.
🎯 نتیجه:
اگر روی یک Solution بزرگ، تیمی یا سازمانی کار میکنید، استفاده از Directory.Packages.props یک «باید» است، نه یک انتخاب. این روش، معماری پروژهی شما را تمیزتر، حرفهایتر و قابل توسعهتر میکند.
اگر دوست دارید در پست بعدی، نحوه پیادهسازی کامل CPM در یک پروژه واقعی را مرحلهبهمرحله آموزش میدهم.
#dotnet #nuget #netdeveloper #csharp #softwarearchitecture #cleanarchitecture #programming #CentralPackageManagement
🔥1
🚀 استفاده از UUID قابل مرتبسازی (Version 7) در Entity Framework با .NET 9
در .NET 9 متدهای جدیدی مثل:
Guid.CreateVersion7()
Guid.CreateVersion7(DateTimeOffset)
اضافه شده که به شما اجازه میده GUIDهایی بر اساس زمان ایجادشون بسازید — یعنی قابل مرتبسازی (sortable) و بسیار مناسب برای دیتابیسهایی که ترتیب زمانی رکوردها مهمه (بههمراه مزایای performance).
📌 مشکل کجاست؟
فعلاً Entity Framework بهصورت native از این Guidها برای Primary Key پشتیبانی نمیکنه.
✅ راه حل: پیادهسازی یک Value Generator سفارشی
و سپس در DbContext:
🎯 نتیجه:
Id ها بر اساس زمان ایجاد مرتب میشوند
عملکرد بهتر در Index ها
آماده برای سیستمهای توزیعشده
بدون برخورد (collision)
اگر روی سیستمهای با حجم داده بالا یا معماری event-driven کار میکنی، این یک ارتقای ساده ولی بسیار مؤثره.
#dotnet #efcore #uuid #guid #softwarearchitecture #performance #backend #database
در .NET 9 متدهای جدیدی مثل:
Guid.CreateVersion7()
Guid.CreateVersion7(DateTimeOffset)
اضافه شده که به شما اجازه میده GUIDهایی بر اساس زمان ایجادشون بسازید — یعنی قابل مرتبسازی (sortable) و بسیار مناسب برای دیتابیسهایی که ترتیب زمانی رکوردها مهمه (بههمراه مزایای performance).
📌 مشکل کجاست؟
فعلاً Entity Framework بهصورت native از این Guidها برای Primary Key پشتیبانی نمیکنه.
✅ راه حل: پیادهسازی یک Value Generator سفارشی
public class UUIDv7Generator : ValueGenerator<Guid>
{
public override bool GeneratesTemporaryValues => false;
public override Guid Next(EntityEntry entry)
{
return Guid.CreateVersion7();
}
}
و سپس در DbContext:
modelBuilder.Entity<MyEntity>()
.Property(e => e.Id)
.HasValueGenerator<UUIDv7Generator>()
.ValueGeneratedOnAdd();
🎯 نتیجه:
Id ها بر اساس زمان ایجاد مرتب میشوند
عملکرد بهتر در Index ها
آماده برای سیستمهای توزیعشده
بدون برخورد (collision)
اگر روی سیستمهای با حجم داده بالا یا معماری event-driven کار میکنی، این یک ارتقای ساده ولی بسیار مؤثره.
#dotnet #efcore #uuid #guid #softwarearchitecture #performance #backend #database
دیتابیس جداگانه برای هر سرویس: دستیابی به استقلال واقعی
الگوی «دیتابیس به ازای هر سرویس» (Database per Service) برخلاف باور رایج دربارهٔ استفاده از دیتابیس مشترک است. بهجای اینکه چندین سرویس به یک دیتابیس مشترک دسترسی داشته باشند، هر میکروسرویس دیتابیس خصوصی و اختصاصی خودش را دارد و اطلاعات را فقط از طریق APIهای کاملاً تعریفشده در اختیار بقیه قرار میدهد.
این تصمیم معماری مزایای بسیار بزرگی به همراه دارد. وقتی نتفلیکس و آمازون به سمت پردازش میلیاردها درخواست در روز حرکت کردند، به شدت به این الگو وابسته شدند. هر تیم سرویس میتواند بهترین تکنولوژی دیتابیس را برای نیازهای خاص خودش انتخاب کند:
PostgreSQL برای دادههای رابطهای
MongoDB برای اسکیماهای انعطافپذیر
Redis برای کشینگ
و همهٔ اینها بدون نیاز به هماهنگی طولانی با تیمهای دیگر انجام میشود.
تیم سرویس کاربر (User Service) میتواند کل اسکیمای دیتابیس خودش را بازنویسی و ریفکتور کند بدون اینکه حتی یک نوتیفیکیشن برای تیمهای دیگر بفرستد. این یعنی استقلال واقعی سرویسها.
با این حال، این استقلال هزینه و چالشهای خودش را هم دارد. عملیات JOIN سنتی در SQL بین سرویسهای مختلف عملاً غیرممکن میشود. تیمها مجبورند الگوهای دسترسی به داده را از نو طراحی کنند و به جای آن از ترکیب APIها (API Composition) و بهروزرسانیهای مبتنی بر رویداد (Event-Driven Updates) برای حفظ سازگاری دادهها استفاده کنند.
تحقیقات نشان میدهد سازمانهایی که این الگو را بهدرستی پیادهسازی کردهاند، سرعت دیپلوی (Deployment Velocity) بسیار بالاتری دارند و وابستگی بینتیمی به شدت کاهش پیدا میکند. سرمایهگذاری اولیه روی پیچیدگی این معماری در بلندمدت با قابلیت نگهداری بسیار بهتر سیستم جبران میشود.
الگوی «دیتابیس به ازای هر سرویس» (Database per Service) برخلاف باور رایج دربارهٔ استفاده از دیتابیس مشترک است. بهجای اینکه چندین سرویس به یک دیتابیس مشترک دسترسی داشته باشند، هر میکروسرویس دیتابیس خصوصی و اختصاصی خودش را دارد و اطلاعات را فقط از طریق APIهای کاملاً تعریفشده در اختیار بقیه قرار میدهد.
این تصمیم معماری مزایای بسیار بزرگی به همراه دارد. وقتی نتفلیکس و آمازون به سمت پردازش میلیاردها درخواست در روز حرکت کردند، به شدت به این الگو وابسته شدند. هر تیم سرویس میتواند بهترین تکنولوژی دیتابیس را برای نیازهای خاص خودش انتخاب کند:
PostgreSQL برای دادههای رابطهای
MongoDB برای اسکیماهای انعطافپذیر
Redis برای کشینگ
و همهٔ اینها بدون نیاز به هماهنگی طولانی با تیمهای دیگر انجام میشود.
تیم سرویس کاربر (User Service) میتواند کل اسکیمای دیتابیس خودش را بازنویسی و ریفکتور کند بدون اینکه حتی یک نوتیفیکیشن برای تیمهای دیگر بفرستد. این یعنی استقلال واقعی سرویسها.
با این حال، این استقلال هزینه و چالشهای خودش را هم دارد. عملیات JOIN سنتی در SQL بین سرویسهای مختلف عملاً غیرممکن میشود. تیمها مجبورند الگوهای دسترسی به داده را از نو طراحی کنند و به جای آن از ترکیب APIها (API Composition) و بهروزرسانیهای مبتنی بر رویداد (Event-Driven Updates) برای حفظ سازگاری دادهها استفاده کنند.
تحقیقات نشان میدهد سازمانهایی که این الگو را بهدرستی پیادهسازی کردهاند، سرعت دیپلوی (Deployment Velocity) بسیار بالاتری دارند و وابستگی بینتیمی به شدت کاهش پیدا میکند. سرمایهگذاری اولیه روی پیچیدگی این معماری در بلندمدت با قابلیت نگهداری بسیار بهتر سیستم جبران میشود.
🚀 بهینهسازی پروژههای .NET با Directory.Build.props
اگر روی پروژههای چندپروژهای یا بزرگ در .NET کار میکنید، احتمالاً با مشکلاتی مثل:
ناسازگاری نسخهها
تعریف تنظیمات تکراری برای هر پروژه
مدیریت مسیرهای خروجی و تنظیمات کامپایلر
روبرو شدهاید. اینجاست که Directory.Build.props میتواند ناجی شما باشد!
چرا Directory.Build.props مهم است؟
پیکربندی مرکزی پروژهها: میتوانید تنظیمات عمومی مانند نسخه C# (LangVersion)، مسیر خروجی (OutputPath)، Company و Version را یکجا تعریف کنید.
صرفهجویی در زمان: دیگر نیازی به تغییر دستی تنظیمات در هر پروژه نیست.
ثبات و هماهنگی: تمام پروژههای زیرشاخه از این تنظیمات به ارث میبرند، بنابراین رفتار یکسانی خواهند داشت.
کنترل Warningها و Build Options: میتوانید به راحتی فعال یا غیرفعال کردن Warningها و گزینههای کامپایلر را مدیریت کنید.
نکته عملی:
کافیست یک فایل Directory.Build.props در ریشه Solution ایجاد کنید و Propertyهای مشترک را در آن تعریف کنید. این فایل به صورت خودکار روی تمام پروژههای زیرشاخه اعمال میشود و از تکرار کد و ناسازگاری جلوگیری میکند.
💡 استفاده از Directory.Build.props مخصوصاً در تیمهای بزرگ، باعث سادگی، امنیت و ثبات پروژهها میشود و توسعهدهندگان میتوانند روی نوشتن کد تمرکز کنند، نه تنظیمات پروژه.
#DotNet #CSharp #MSBuild #DirectoryBuildProps #SoftwareDevelopment #BestPractices
اگر روی پروژههای چندپروژهای یا بزرگ در .NET کار میکنید، احتمالاً با مشکلاتی مثل:
ناسازگاری نسخهها
تعریف تنظیمات تکراری برای هر پروژه
مدیریت مسیرهای خروجی و تنظیمات کامپایلر
روبرو شدهاید. اینجاست که Directory.Build.props میتواند ناجی شما باشد!
چرا Directory.Build.props مهم است؟
پیکربندی مرکزی پروژهها: میتوانید تنظیمات عمومی مانند نسخه C# (LangVersion)، مسیر خروجی (OutputPath)، Company و Version را یکجا تعریف کنید.
صرفهجویی در زمان: دیگر نیازی به تغییر دستی تنظیمات در هر پروژه نیست.
ثبات و هماهنگی: تمام پروژههای زیرشاخه از این تنظیمات به ارث میبرند، بنابراین رفتار یکسانی خواهند داشت.
کنترل Warningها و Build Options: میتوانید به راحتی فعال یا غیرفعال کردن Warningها و گزینههای کامپایلر را مدیریت کنید.
نکته عملی:
کافیست یک فایل Directory.Build.props در ریشه Solution ایجاد کنید و Propertyهای مشترک را در آن تعریف کنید. این فایل به صورت خودکار روی تمام پروژههای زیرشاخه اعمال میشود و از تکرار کد و ناسازگاری جلوگیری میکند.
💡 استفاده از Directory.Build.props مخصوصاً در تیمهای بزرگ، باعث سادگی، امنیت و ثبات پروژهها میشود و توسعهدهندگان میتوانند روی نوشتن کد تمرکز کنند، نه تنظیمات پروژه.
#DotNet #CSharp #MSBuild #DirectoryBuildProps #SoftwareDevelopment #BestPractices
🔥1
global.json در .NET؛ کنترل دقیق نسخهی SDK در build pipeline
در اکوسیستم .NET، فایل global.json مکانیزم رسمی برای pin کردن نسخهی .NET SDK است که توسط dotnet CLI استفاده میشود.
این فایل تعیین میکند عملیاتهایی مثل dotnet build، dotnet test و dotnet publish با کدام SDK اجرا شوند.
نکتهی کلیدی:
global.json نسخهی SDK را کنترل میکند، نه Runtime و نه Target Framework پروژه.
نحوهی کار
وقتی یک دستور CLI اجرا میشود، داتنت از مسیر فعلی به سمت بالا حرکت میکند تا اولین global.json را پیدا کند و بر اساس آن SDK را انتخاب کند.
در نبود این فایل، بالاترین نسخهی نصبشدهی SDK انتخاب میشود.
مثال پایه
{
"sdk": {
"version": "8.0.100"
}
}
این تنظیم تضمین میکند که:
کامپایلر
Analyzerها
رفتار build
در تمام محیطها یکسان باشد.
rollForward و رفتار انتخاب نسخه
{
"sdk": {
"version": "8.0.100",
"rollForward": "latestPatch"
}
}
مقدار rollForward مشخص میکند اگر نسخهی دقیق موجود نبود، CLI چقدر اجازهی انعطاف داشته باشد:
disable → فقط همان نسخه
latestPatch → آخرین patch همان نسخه
minor / major → اجازهی نسخههای بالاتر
انتخاب نادرست این مقدار میتواند باعث تفاوت رفتار build بین محیطها شود.
تفاوت با TargetFramework
<TargetFramework>net8.0</TargetFramework>
TargetFramework → خروجی برنامه روی چه runtimeای اجرا میشود
global.json → ابزار build (SDK) با چه نسخهای اجرا میشود
این دو مستقل ولی مکمل هم هستند.
کاربردهای واقعی
پروژههای تیمی
CI/CD pipelineها
monorepoها با چند پروژه
جلوگیری از breaking changeهای ناگهانی SDK
reproducible build
Best Practice
global.json را در ریشهی repository قرار دهید
در CI قبل از build نسخهی SDK را verify کنید
فقط در صورت نیاز از rollForwardهای آزاد استفاده کنید
تغییر نسخهی SDK را مثل dependency آپدیت، review کنید
#dotnet #csharp #softwareengineering #build #cicd #globaljson
در اکوسیستم .NET، فایل global.json مکانیزم رسمی برای pin کردن نسخهی .NET SDK است که توسط dotnet CLI استفاده میشود.
این فایل تعیین میکند عملیاتهایی مثل dotnet build، dotnet test و dotnet publish با کدام SDK اجرا شوند.
نکتهی کلیدی:
global.json نسخهی SDK را کنترل میکند، نه Runtime و نه Target Framework پروژه.
نحوهی کار
وقتی یک دستور CLI اجرا میشود، داتنت از مسیر فعلی به سمت بالا حرکت میکند تا اولین global.json را پیدا کند و بر اساس آن SDK را انتخاب کند.
در نبود این فایل، بالاترین نسخهی نصبشدهی SDK انتخاب میشود.
مثال پایه
{
"sdk": {
"version": "8.0.100"
}
}
این تنظیم تضمین میکند که:
کامپایلر
Analyzerها
رفتار build
در تمام محیطها یکسان باشد.
rollForward و رفتار انتخاب نسخه
{
"sdk": {
"version": "8.0.100",
"rollForward": "latestPatch"
}
}
مقدار rollForward مشخص میکند اگر نسخهی دقیق موجود نبود، CLI چقدر اجازهی انعطاف داشته باشد:
disable → فقط همان نسخه
latestPatch → آخرین patch همان نسخه
minor / major → اجازهی نسخههای بالاتر
انتخاب نادرست این مقدار میتواند باعث تفاوت رفتار build بین محیطها شود.
تفاوت با TargetFramework
<TargetFramework>net8.0</TargetFramework>
TargetFramework → خروجی برنامه روی چه runtimeای اجرا میشود
global.json → ابزار build (SDK) با چه نسخهای اجرا میشود
این دو مستقل ولی مکمل هم هستند.
کاربردهای واقعی
پروژههای تیمی
CI/CD pipelineها
monorepoها با چند پروژه
جلوگیری از breaking changeهای ناگهانی SDK
reproducible build
Best Practice
global.json را در ریشهی repository قرار دهید
در CI قبل از build نسخهی SDK را verify کنید
فقط در صورت نیاز از rollForwardهای آزاد استفاده کنید
تغییر نسخهی SDK را مثل dependency آپدیت، review کنید
#dotnet #csharp #softwareengineering #build #cicd #globaljson
🛠 حل مشکل 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
🔥2
Forwarded from iCodeNext
✨ Managers Have been vibe coding forever.
مدیران برای همیشه وایب کدینگ میکنن:
- به توسعه دهنده ها میگن که یه فیچر جدید بساز ( وایب کدینگ )
- توسعه دهنده ها کد هارو تغییر میدن.
- مدیر اون اپلیکیشن رو تست میکنه.
- مدیر کد رو نمیخونه.
- مدیر از باگ های توی سیستم شکایت میکنه.
- توسعه دهنده ها کد رو تغییر میدن تا اون باگ ها فیکس بشن.
کمی فان.
مدیران برای همیشه وایب کدینگ میکنن:
- به توسعه دهنده ها میگن که یه فیچر جدید بساز ( وایب کدینگ )
- توسعه دهنده ها کد هارو تغییر میدن.
- مدیر اون اپلیکیشن رو تست میکنه.
- مدیر کد رو نمیخونه.
- مدیر از باگ های توی سیستم شکایت میکنه.
- توسعه دهنده ها کد رو تغییر میدن تا اون باگ ها فیکس بشن.
کمی فان.
طراحی نرمافزار یعنی ایجاد اجزا و برقرار کردن رابطهای مفید بین آنها. هر سیستم از بخشهایی مثل توابع، کلاسها و ماژولها تشکیل شده که بهتنهایی ارزشی ندارند مگر اینکه درست به هم متصل شوند. طراحی خوب پیچیدگی را به جای مناسب منتقل میکند تا بخشهای دیگر سادهتر شوند. هدف این است که اجزا از همکاری با هم سود ببرند، نه اینکه به هم گره بخورند. حتی اگر دو سیستم رفتار یکسانی داشته باشند، ساختار درونی آنها میتواند کاملاً متفاوت باشد. کیفیت طراحی دقیقاً در همین ساختار و روابط مشخص میشود.