uk
Feedback
Developer Advocate

Developer Advocate

Відкрити в Telegram
Buy Ad
1 035
Підписники
Немає даних24 години
Немає даних7 днів
-130 днів
Архів дописів
در مقیاس‌پذیری سیستم‌ها، یکی از مسائل کلیدی، نحوه افزایش ظرفیت سیستمی است که بتواند به تقاضای رو به رشد پاسخ دهد. در این زمینه، دو مفهوم اصلی مطرح می‌شوند: مقیاس‌پذیری عمودی (Vertical Scaling) و مقیاس‌پذیری افقی (Horizontal Scaling). هر کدام از این روش‌ها دارای مزایا و معایب خاص خود هستند و در محیط‌های ابری، انتخاب مناسب به نیازهای خاص سیستم شما بستگی دارد. ### مقیاس‌پذیری عمودی (Vertical Scaling) در این روش، توان محاسباتی سیستم با افزودن منابع بیشتر (مانند CPU یا RAM) به سرورهای موجود افزایش می‌یابد. در محیط‌های ابری، این به معنای انتخاب سایز بزر‌گتر برای ماشین‌های مجازی شماست. برای مثال در AWS، شما می‌توانید از یک T2.micro به یک M5.large مهاجرت کنید. مزیت عمده این روش سادگی و کمترین نیاز به تغییر در معماری سیستم است؛ اما نقطه ضعف آن، محدودیت‌های فیزیکی و افزایش هزینه‌ها در اندازه‌های بزرگ‌تر است. ### مقیاس‌پذیری افقی (Horizontal Scaling) این روش شامل افزودن تعداد بیشتری از ماشین‌ها یا سرورهای کوچکتر به سیستم است. در محیط‌های ابری، این حالت می‌تواند به صورت اتوماتیک با استفاده از ابزارهای مانند AWS Auto Scaling یا Azure Scale Sets انجام شود. مزیت کلیدی این روش، توانایی مدیریت حجم بالایی از بار کاری با افزایش تعداد نودها بدون محدودیت فیزیکی و نیز توزیع بهتر بار کاری است. اما این رویکرد نیازمند معماری مبتنی بر توزیع و پیاده‌سازی مکانیسم‌هایی مانند Load Balancing و مدیریت حالت میان سرورهاست. ### انتخاب مناسب انتخاب بین این دو روش بستگی به نیازهای خاص شما دارد. برای کاربردهایی که نیاز به پاسخگویی سریع به تغییرات ناگهانی بار کاری دارند و به جایگزینی سریع سرور نیاز دارند، مقیاس‌پذیری افقی مناسب‌تر است. اما اگر توسعه نرم‌افزار شما برای اجرای بر روی یک سرور واحد بهینه‌سازی شده و محدودیت‌های فیزیکی مشکلی ایجاد نمی‌کنند، مقیاس‌پذیری عمودی ممکن است گزینه بهتری باشد. به طور خلاصه، درک صحیح از نیازمندی‌های پروژه و چالش‌های مرتبط با هر نوع مقیاس‌پذیری، کلید انتخاب استراتژی مناسب برای رشد نرم‌افزار شماست. @DeveloperAdvocate 🥑

اهمیت ایندکس‌گذاری در پایگاه‌داده‌ها را نمی‌توان دست کم گرفت، به خصوص وقتی با مجموعه داده‌های بزرگ سروکار داریم. ایندکس‌ها به پایگاه‌داده امکان می‌دهند تا بدون نیاز به پیمایش تمام رکوردها، به سرعت به داده‌های مورد نظر دسترسی پیدا کند. به این ترتیب، زمان اجرای کوئری‌ها به طور قابل‌توجهی کاهش می‌یابد. برای درک بهتر این موضوع، فرض کنید یک جدول `Customers` دارید که شامل هزاران مشتری است. بدون ایندکس، جستجوی مشتری بر اساس نام می‌تواند بسیار زمان‌بر باشد: ```sql SELECT * FROM Customers WHERE LastName = 'Smith' ``` در این شرایط، پایگاه‌داده باید هر رکورد را یک به یک بررسی کند تا موارد مطابقت را پیدا کند. حالا فرض کنید یک ایندکس بر روی ستون `LastName` ایجاد کرده‌ایم: ```sql CREATE INDEX idx_lastname ON Customers(LastName) ``` با ایجاد این ایندکس، پایگاه‌داده می‌تواند به سرعت نحوه توزیع داده‌ها در ستون `LastName` را درک کند و بنابراین کوئری بالا بسیار سریع‌تر اجرا می‌شود. مثال‌ها در زبان‌های برنامه‌نویسی، چیزی مشابه دارند. در C# می‌توانید مثالی را تصور کنید که با بهینه‌سازی و اشاره به مجموعه داده‌ها با ساختارهای داده‌ای مناسب مانند `Dictionary` یا `HashSet` به جای `List`، زمان جستجو را با کارایی فوق‌العاده بالاتر بهبود می‌بخشد: ```csharp using System.Collections.Generic; public class CustomerSearch { private Dictionary<string, Customer> _customerIndex; public CustomerSearch(IEnumerable<Customer> customers) { _customerIndex = new Dictionary<string, Customer>(); foreach (var customer in customers) { _customerIndex[customer.LastName] = customer; } } public Customer FindByLastName(string lastName) { _customerIndex.TryGetValue(lastName, out var customer); return customer; } } ``` با استفاده از `Dictionary` یا همان دیکشنری، عملیات جستجو به طور متوسط به زمان ثابت `O(1)` تقلیل می‌یابد، درست مانند آنچه که ایندکس‌ها در سطح پایگاه‌داده انجام می‌دهند. چنین بهینه‌سازی‌هایی در عمل، تأثیر بسزایی بر روی عملکرد و کارایی سیستم دارند. درک عمیق‌تر این گونه مفاهیم به شما کمک می‌کند تا به طور مؤثرتری به طراحی و پیاده‌سازی سیستم‌های پیچیده بپردازید. @DeveloperAdvocate 🥑

همکاران گرامی، امروز به مسئله‌ای می‌پردازیم که در زندگی روزمره‌ی توسعه‌دهنده‌ها بسیار متداول است: بهبود کارایی کد در یک سامانهٔ مبتنی بر .NET. یکی از الگوهای مفید برای بهینه‌سازی، استفاده از الگوی «کشال» (Cache) برای جلوگیری از انجام محاسبات سنگین و تکراری است. فرض کنید کدی دارید که به‌طور مکرر به یک دیتابیس خیلی بزرگ برای خواندن مقادیر یکسان دسترسی پیدا می‌کند. احتمالاً متوجه افت کارایی شده‌اید. به‌راحتی می‌توانید با کشال‌سازی این نتایج از تکرار این عملیات زمان‌بر جلوگیری کنید. ابتدا، بیایید ببینیم چطور می‌توانیم با استفاده از یک کشال ساده و استفاده از `MemoryCache` در .NET نتایج را ذخیره کنیم: ```csharp using System; using System.Runtime.Caching; public class DataService { private MemoryCache _cache = MemoryCache.Default; public string GetData(string key) { if (_cache.Contains(key)) { return _cache.Get(key) as string; } // Assume GetDataFromDatabase is a method that fetches data from the database var data = GetDataFromDatabase(key); _cache.Add(key, data, DateTimeOffset.UtcNow.AddMinutes(5)); return data; } private string GetDataFromDatabase(string key) { // Simulating a database call Console.WriteLine("Fetching data from database..."); return $"Value for {key}"; } } ``` در این مثال: - از `MemoryCache` برای ذخیره‌سازی نتایج دریافتی استفاده می‌کنیم. - ابتداء بررسی می‌شود که آیا داده در کشال موجود است یا خیر. اگر بله، مقدار کشال‌شده برگردانده می‌شود. - اگر نه، داده از دیتابیس خوانده و سپس در کشال ذخیره‌سازی می‌گردد تا برای درخواست‌های بعدی از آن استفاده شود. با این روش ساده، می‌توانید کارایی برنامه خود را به‌طور قابل توجهی بهبود بخشید و بار روی سیستم را کاهش دهید. دفعه‌ی بعد که به‌روزرسانی دیتابیس یا گزارش‌دهی را اجرا می‌کنید، از این تکنیک استفاده کنید و تفاوت را احساس خواهید کرد! @DeveloperAdvocate 🥑

اگر به دنبال آزمون‌های E2E (End-to-End) مؤثر برای اپلیکیشن‌های وب خود هستید، ابزار Playwright می‌تواند یک گزینه عالی برای شما باشد. امروز به یک سناریوی ساده اما پرکاربرد می‌پردازیم: جریان ورود کاربر. تصور کنید ما یک فرم ورودی ساده داریم که نام کاربری و گذرواژه را از کاربر دریافت می‌کند. هدف این سناریو آزمایش موفقیت در ورود کاربر به سیستم است. برای شروع، نیاز به یک تست ساده داریم که این جریان را پوشش دهد: ```javascript // playwright.config.js import { test, expect } from '@playwright/test'; test('User Login Flow', async ({ page }) => { // صفحه ورود به سامانه را باز کنید await page.goto('https://your-app-url.com/login'); // مقادیر نام کاربری و گذرواژه معتبر را وارد کنید await page.fill('input[name="username"]', 'your-username'); await page.fill('input[name="password"]', 'your-password'); // روی دکمه ورود کلیک کنید await page.click('button[type="submit"]'); // انتظار داشته باشید که کاربر پس از ورود موفق به صفحه داشبورد هدایت شود await expect(page).toHaveURL('https://your-app-url.com/dashboard'); // اطمینان حاصل کنید که عنصری که مشخص‌کننده ورود موفق است، در صفحه موجود باشد await expect(page.locator('text=Welcome, your-username')).toBeVisible(); }); ``` توضیحات: - این تست به طور خودکار صفحه ورود را باز می‌کند و اطلاعات ورود را پر می‌کند. - دکمه ورود را فشار می‌دهد و انتظار دارد که کاربر به صفحه داشبورد هدایت شود. - با استفاده از `expect` اطمینان حاصل می‌کنیم که کاربر به درستی وارد شده و عنصری که ورود موفق را نشان می‌دهد قابل مشاهده است. این سناریو می‌تواند به شما کمک کند تا اطمینان حاصل کنید فرآیند ورود کاربران به درستی کار می‌کند، و همچنین به شما اجازه می‌دهد روند آزمون‌های خودکار را بهبود بخشید. در دنیای امروز که سرعت تغییرات بالا است، ابزارهایی مثل Playwright می‌توانند کیفیت محصولات ما را تضمین کنند. @DeveloperAdvocate 🥑

اگر تا به حال با پایگاه‌داده PostgreSQL کار کرده‌اید، احتمالاً به چالش‌های بهبود کارایی کوئری‌های سنگین برخورد کرده‌اید. یکی از ابزارهای قدرتمند برای بهینه‌سازی عملکرد، نمای مادی (Materialized View) است که راهکاری فوق‌العاده برای کاهش زمان اجرا در کوئری‌های چندباره و سنگین می‌باشد. در یک نمای مادی، نتایج کوئری از پیش محاسبه و ذخیره می‌شود، که باعث می‌شود هنگام اعمال کوئری‌های تکراری به جای محاسبه مجدد، به داده‌های ذخیره‌شده رجوع شود. این امر به ویژه در شرایطی مفید است که داده‌ها به‌ندرت تغییر می‌کنند و محاسبات پیچیده و هزینه‌بر هستند. ### چگونه یک نمای مادی ایجاد کنیم؟ ایجاد یک نمای مادی در PostgreSQL بسیار ساده است و مشابه ایجاد یک View معمولی است، با این تفاوت که از کلمه کلیدی `MATERIALIZED` استفاده می‌کنیم. مثالی از ایجاد یک نمای مادی: ```sql CREATE MATERIALIZED VIEW summary AS SELECT category, COUNT(*) AS product_count FROM products GROUP BY category; ``` ### به‌روزرسانی نمای مادی: برخلاف Viewهای معمولی، داده‌های یک نمای مادی به‌صورت خودکار با تغییرات در جداول زیرین به‌روزرسانی نمی‌شوند. بنابراین، لازم است گاه‌به‌گاه آن‌ها را تازه‌سازی کنیم تا با داده‌های جدید همگام باشند. برای این کار به‌سادگی می‌توانید از دستور زیر استفاده کنید: ```sql REFRESH MATERIALIZED VIEW summary; ``` ### چه زمانی از نمای مادی استفاده کنیم؟ - **پرس‌وجوهای سنگینی که به‌ندرت اجرا می‌شوند**: اگر تعداد زیادی داده نیاز به محاسبات پیچیده داشته باشند، اما نتایج به‌ندرت تغییر کنند. - **اجرای مکرر کوئری‌های پیچیده**: برای کوئری‌هایی که به دفعات زیاد اجرا می‌شوند. - **بهبود عملکرد در تحلیل‌های زمانی یا داده‌محوری**: زمانی که شما به Summit Analytics نیاز دارید و بخشی از داده‌ها به‌ندرت تغییر می‌کند. استفاده دقیق و اندیشیده از نمای مادی می‌تواند به‌شدت قرارداد شما را با کارایی و عملکرد پایگاه‌داده‌تان ارتقا دهد. پس با توجه به نیازمندی‌تان، از این قابلیت بهینه استفاده کنید. 🚀 @DeveloperAdvocate 🥑

🌐 **WebSockets vs. Server-Sent Events در .NET: بررسی و مثال‌های کاربردی** یکی از چالش‌های اساسی در معماری برنامه‌های مدرن وب، فراهم آوردن قابلیت‌های ارتباطی از نوع Real-Time است. دو مکانیزم پرکاربرد در .NET برای این منظور WebSockets و Server-Sent Events (SSE) هستند. بیایید برای هر دو مثالی را پیاده‌سازی کنیم. ### WebSockets WebSockets یک پروتکل full-duplex برای ارتباطات بلادرنگ بین کلاینت و سرور است. در اینجا نمونه‌ کدی برای پیاده‌سازی WebSocket در ASP.NET Core را داریم: ```csharp public class ChatWebSocketMiddleware { private readonly RequestDelegate _next; public ChatWebSocketMiddleware(RequestDelegate next) { _next = next; } public async Task InvokeAsync(HttpContext context) { if (context.WebSockets.IsWebSocketRequest) { WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync(); await Echo(context, webSocket); } else { await _next(context); } } private async Task Echo(HttpContext context, WebSocket webSocket) { var buffer = new byte[1024 * 4]; WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None); while (!result.CloseStatus.HasValue) { await webSocket.SendAsync(new ArraySegment<byte>(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None); result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None); } await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None); } } ``` ### Server-Sent Events (SSE) Server-Sent Events برای ارسال پیام‌های یک‌طرفه از سرور به کلاینت مورد استفاده قرار می‌گیرد. در زیر مثالی از پیاده‌سازی SSE در ASP.NET Core آمده است: ```csharp public class NotificationsController : Controller { [HttpGet("/notifications")] public async Task Get() { Response.ContentType = "text/event-stream"; for (var i = 0; i < 10; i++) { await Response.WriteAsync($"data: Notification {i}\n\n"); await Response.Body.FlushAsync(); await Task.Delay(2000); } } } ``` ### مقایسه و موارد استفاده: - **WebSockets:* مناسب برای ارتباطات full-duplex و زمانی که نیاز به ارسال پیام‌های در هر دو جهت است. به‌طور مثال در برنامه‌های چت آنلاین. - **SSE:** ساده‌تر و بهینه‌سازی‌شده برای ارسال داده از سرور به کلاینت با پشتیبانی بازپیوند مجدد (reconnect). معمولاً در فیدهای خبری یا اعلان‌های سیستم استفاده می‌شود. هر کدام از این تکنولوژی‌ها ملاحظات و کاربردهای خاص خود را دارند که باید در انتخاب بر اساس نیازهای دقیق پروژه در نظر گرفته شوند. 👨‍💻🔗 @DeveloperAdvocate 🥑

در معماری میکروسرویس‌ها، یکی از چالش‌های اصلی اطمینان از ارسال صحیح و قابل اعتماد پیام‌ها بین سرویس‌هاست. اینجاست که الگوی **Outbox** نقش مهمی ایفا می‌کند. این الگو به ما کمک می‌کند ناکامی‌های احتمالی در ارسال پیام‌ها را کاهش دهیم و به همین ترتیب، یکپارچگی داده‌ها و پیام‌ها را حفظ کنیم. ### اصول الگوی Outbox: الگوی Outbox بر روی این اصل استوار است که تغییرات در دیتابیس و رویداد پیام‌ها در همان تراکنش ذخیره شوند. زمانی که یک سرویس تغییراتی در دیتابیس ایجاد می‌کند، این تغییرات همراه با پیام‌های خروجی در جدول Outbox همان دیتابیس ذخیره می‌شوند. فرآیند ارسال پیام به صورت غیرهمزمان انجام می‌شود و معمولاً توسط پروسسور دیگری که به صورت مرتب جدول Outbox را چک می‌کند، عملیاتی می‌شود. ### پیاده‌سازی C#: در اینجا یک مثال ساده از اینکه چگونه می‌توانید Outbox Pattern را در یک سرویس میکرو با استفاده از Entity Framework پیاده‌سازی کنید آمده است: ```csharp public class OutboxMessage { public int Id { get; set; } public string MessageType { get; set; } public string Payload { get; set; } public DateTime CreatedAt { get; set; } public bool IsPublished { get; set; } } public void AddToOutbox(string messageType, string payload) { using (var dbContext = new MyDbContext()) { // Add business logic changes // ... // Add to Outbox var outboxMessage = new OutboxMessage { MessageType = messageType, Payload = payload, CreatedAt = DateTime.UtcNow, IsPublished = false }; dbContext.OutboxMessages.Add(outboxMessage); // Save all changes in a single transaction dbContext.SaveChanges(); } } public async Task ProcessOutboxMessagesAsync() { using (var dbContext = new MyDbContext()) { var messages = dbContext.OutboxMessages .Where(x => !x.IsPublished) .ToList(); foreach (var message in messages) { // Send message logic, for example, publish to a message broker // ... // Mark message as published message.IsPublished = true; dbContext.OutboxMessages.Update(message); } await dbContext.SaveChangesAsync(); } } ``` ### مزایای کلیدی: - **اتمیت**: تضمین می‌شود که هم دیتابیس و هم پیام‌های خروجی در یک تراکنش ثبت می‌شوند. - **کاهش دوپلیکیت‌پذیری پیام‌ها**: پیام‌ها تا زمانی که منتشر نشده‌اند در Outbox دیده می‌شوند. - **ارتباط غیرهمزمان**: فرآیند ارسال پیام‌ها می‌تواند با عملیات اصلی سرویس آسنکرون باشد و عملکرد سرویس را تحت تأثیر قرار ندهد. با استفاده از الگوی Outbox، می‌توان به راحتی بین سرویس‌های مختلف با اطمینان و بدون از دست رفتن داده‌ها ارتباط برقرار کرد و تجربه‌ای پایدار و قابل اعتماد از میکروسرویس‌ها ارائه داد. @DeveloperAdvocate 🥑

🔐 سه هدر حیاتی امنیتی در HTTP که نباید نادیده بگیرید: ۱. **Content-Security-Policy (CSP)** یک سیاست CSP به طور فعال جلوی بسیاری از حملات XSS و data injection را می‌گیرد—با تعریف اینکه مرورگر فقط منابع اسکریپت/استایل/ایمیج را از دامنه‌های معتبر شما لود کند. به این ترتیب حتی اگر کد مخربی تزریق شد، اجازه اجرای آن داده نمی‌شود. ۲. **X-Frame-Options** این هدر جلوگیری می‌کند صفحه شما داخل iframe در سایت بیگانه بارگذاری شود (حمله کلیک‌جکینگ). مقدار توصیه‌شده آن: ``` X-Frame-Options: DENY ``` یا اگر فقط باید روی یک یا چند دامنه خاص نمایش داده شود، از: ``` X-Frame-Options: ALLOW-FROM https://yourdomain.com ``` استفاده کنید. ۳. **Strict-Transport-Security (HSTS)** HSTS تضمین می‌کند مرورگرها فقط ارتباط HTTPS با سایت شما برقرار کنند؛ حتی اگر کاربر آدرس HTTP را وارد کند. این بسیار مهم است برای محافظت در مقابل حملات man-in-the-middle و Downgrade Attack. ``` Strict-Transport-Security: max-age=31536000; includeSubDomains; preload ``` ‌ در ASP.NET Core ساده‌ترین راه، اضافه کردن این هدرها در Middleware است: ```csharp app.Use(async (context, next) => { context.Response.Headers["Content-Security-Policy"] = "default-src 'self';"; context.Response.Headers["X-Frame-Options"] = "DENY"; context.Response.Headers["Strict-Transport-Security"] = "max-age=31536000; includeSubDomains; preload"; await next(); }); ``` حتما این هدرها را بررسی، مستند و در Production فعال کنید—زیرساخت شما فقط به اندازه ضعیف‌ترین گره امنیتی‌اش مقاوم خواهد بود. @DeveloperAdvocate 🥑

🔹 **Canary Deployment با Service Mesh (مانند Istio/Linkerd): طراحی، مکانیزم و مثال عملی** با ظهور Service Meshهایی مثل Istio و Linkerd، الگوی Canary Deployment به شکل چشمگیری آسان‌تر و قدرتمندتر شده است. به جای کد پیچیده در CI/CD یا پیاده‌سازی فیلترهای Application-Level،‌ **توزیع ترافیک هوشمند توسط Mesh و در لایه شبکه انجام می‌شود.** فرض کنیم دو نسخه از سرویس `orders` داریم: نسخه v1 (پایدار) و v2 (جدید). می‌خواهیم فقط ۱۰٪ ترافیک را به v2 بفرستیم تا کیفیت و پایداری آن سنجیده شود. --- **در Istio:** ابتدا دو Deployment یا Pod مربوط به v1 و v2 را دارید. سپس با ابزارهایی مثل Kubectl و YAML، ترافیک را در سطح شبکه تقسیم می‌کنید. ```yaml apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: orders spec: hosts: - orders http: - route: - destination: host: orders subset: v2 weight: 10 - destination: host: orders subset: v1 weight: 90 ``` در اینجا: - **VirtualService** تعریف می‌کند که چگونه درخواست‌ها تقسیم شوند. - هر **subset** به نسخه‌ای از سرویس با Label خاص اشاره دارد (که در DestinationRule آمده). برای تکمیل، یک DestinationRule نیاز دارید: ```yaml apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: orders spec: host: orders subsets: - name: v1 labels: version: v1 - name: v2 labels: version: v2 ``` --- **در Linkerd:** Linkerd در سطح بالاتر با ابزار‌هایی مثل Flagger (یا SMI) ترافیک را تقسیم می‌کند. مفهوم Canary در Linkerd native نیست اما با این اکوسیستم می‌توانید Canaryها را orchestrate کنید. مثلاً با Flagger: ```yaml apiVersion: flagger.app/v1beta1 kind: Canary metadata: name: orders spec: targetRef: apiVersion: apps/v1 kind: Deployment name: orders service: port: 80 analysis: interval: 1m threshold: 5 stepWeight: 10 maxWeight: 50 ``` - در اینجا **stepWeight** میزان ترافیکی است که در هر مرحله به نسخه جدید داده می‌شود. Flagger با استفاده از Linkerd ترافیک را مدیریت و مانیتور می‌کند. --- 👀 **نکته عملیاتی**: - **استثنائات یا بازگرداندن فوری به نسخه پایدار (Abort)** را با خطای مشاهده شده یا مانیتورنگ‌ها به سادگی و بدون ری‌دپلوی می‌توانید انجام دهید. - این approach در پروژه‌های حساس و پراهمیت microservices مقیاس‌پذیر، ایجاد rollbackهای بدون Downtime و بستر تست زنده (در عین پایش کامل) را آسان می‌کند. ⚡️استفاده از Service Mesh به شما اهرم قدرتمند "توزیع ترافیک لایه ۷" را بدون منطق سفارشی یا تغییر در اپلیکیشن می‌دهد—و پایه‌ای برای progressive delivery است. #DevOps #Microservices #Istio #Linkerd #کاناری_دیپلویمنت @DeveloperAdvocate 🥑

یکی از چهار متریک کلیدی DORA، «Lead Time for Changes» است که تاثیر مستقیم بر سرعت توسعه و تحویل ارزش به مشتری دارد. این متریک، فاصله زمانی بین لحظه commit‌شدن یک تغییر در کد (مثلاً merge در main branch) تا زمانی که همان تغییر به صورت موفقیت‌آمیز در محیط Production دیپلوی شود را اندازه‌گیری می‌کند. در پروژه‌های Enterprise، برای محاسبه این متریک، باید به صورت اتوماتیک از داده‌های Git و لاگ‌های CI/CD Pipelines استفاده کنید. به طور معمول، روی هر Pull Request یا Merge درخواست، یک label یا tag ثبت می‌کنید و سپس، پس از دیپلوی، یک event لاگ می‌شود. فرض کنید می‌خواهید یک ابزار کوچک برای اندازه‌گیری Lead Time بنویسید: 1. ساعت Commit آخر مرتبط با یک Feature را از Git استخراج کنید. 2. زمان دیپلوی همان commit به Production را (مثلاً از لاگ Octopus Deploy یا Azure DevOps) واکشی کنید. 3. Lead time را محاسبه کنید. نمونه کد مفهومی برای این کار با استفاده از libgit2sharp و فرض ثبت deployment info در یک دیتابیس: ```csharp using LibGit2Sharp; // commitSha: شناسه commit feature موردنظر // GetDeploymentTime: تابعی که زمان دیپلوی روی Prod را برمی‌گرداند public TimeSpan CalculateLeadTime(string repoPath, string commitSha) { using var repo = new Repository(repoPath); var commit = repo.Lookup<Commit>(commitSha); if (commit == null) throw new Exception("Commit not found."); DateTime commitTime = commit.Committer.When.UtcDateTime; DateTime deployTime = GetDeploymentTime(commitSha); // استخراج از دیتا‌استور return deployTime - commitTime; } ``` جمع‌آوری و تحلیل این داده‌ها به شما امکان می‌دهد گلوگاه‌های مهندسی را شناسایی و حذف کنید. تیم‌هایی با Lead Time کوتاه‌تر، قابلیت پاسخگویی و نوآوری بسیار بالاتری دارند. پیشنهاد حرفه‌ای: این متریک را در فلو CI/CD خود با ابزارهای observability مثل Grafana به‌روز و شفاف نگه دارید تا روند تغییرات همیشه قابل مشاهده و بهبود باشد. @DeveloperAdvocate 🥑

Emit logs on-demand with log buffering Learn how to delay log emission with the new log buffering feature for more intelligent, context-aware logging in .NET 9 The post Emit logs on-demand with log buffering appeared first on .NET Blog. Link👇🏻👇🏻👇🏻👇🏻 https://devblogs.microsoft.com/dotnet/emit-logs-on-demand-with-log-buffering/ #.NET,#.NETFundamentals,#.NET9,#logging,#Observability @DeveloperAdvocate 🥑

Multimodal Voice Intelligence with .NET MAUI Learn how to enhance your .NET MAUI apps with multimodal AI capabilities, enabling users to interact through voice using plugins and Microsoft.Extensions.AI. The post Multimodal Voice Intelligence with .NET MAUI appeared first on .NET Blog. Link👇🏻👇🏻👇🏻👇🏻 https://devblogs.microsoft.com/dotnet/multimodal-voice-intelligence-with-dotnet-maui/ #.NET,#.NETMAUI,#AI,#.netmaui,#aifoundry,#copilot,#speech-to-text @DeveloperAdvocate 🥑

Using AI Foundry with .NET MAUI Using AI Foundry with .NET MAUI brings the power of LLMs to mobile and desktop applications. The post Using AI Foundry with .NET MAUI appeared first on .NET Blog. Link👇🏻👇🏻👇🏻👇🏻 https://devblogs.microsoft.com/dotnet/using-ai-foundry-with-dotnet-maui/ #.NET,#.NETMAUI,#AI,#C#,#MEAI @DeveloperAdvocate 🥑

Catch Up on Microsoft Build 2025: Essential Sessions for .NET Developers Get up to date on all of the .NET sessions from Microsoft Build 2025 covering .NET 10, C# 14, .NET Aspire, ASP.NET Core, Blazor, AI development, and more! The post Catch Up on Microsoft Build 2025: Essential Sessions for .NET Developers appeared first on .NET Blog. Link👇🏻👇🏻👇🏻👇🏻 https://devblogs.microsoft.com/dotnet/catching-up-on-microsoft-build-2025-essential-sessions-for-dotnet-developers/ #.NET,#AI,#ASP.NETCore,#Blazor,#C#,#CloudNative,#VisualStudioCode,#.NET10,#C#14,#GitHubCopilot,#microsoftbuild,#microsoftbuild2025 @DeveloperAdvocate 🥑

Improve Your Productivity with New GitHub Copilot Features for .NET! We recently introduced several new GitHub Copilot-powered .NET experiences designed to help you be more productive. Take a look! The post Improve Your Productivity with New GitHub Copilot Features for .NET! appeared first on .NET Blog. Link👇🏻👇🏻👇🏻👇🏻 https://devblogs.microsoft.com/dotnet/improve-productivity-with-github-copilot-dotnet/ #.NET,#AI,#C#,#VisualStudio,#VisualStudioCode,#dotnet,#GitHubCopilot,#visualstudio,#VSCode @DeveloperAdvocate 🥑

.NET 10 Preview 5 is now available! Find out about the new features in .NET 10 Preview 5 across the .NET runtime, SDK, libraries, ASP.NET Core, Blazor, C#, .NET MAUI, and more! The post .NET 10 Preview 5 is now available! appeared first on .NET Blog. Link👇🏻👇🏻👇🏻👇🏻 https://devblogs.microsoft.com/dotnet/dotnet-10-preview-5/ #.NET,#.NETMAUI,#ASP.NETCore,#Blazor,#C#,#.NET10,#Featured @DeveloperAdvocate 🥑

Fine-tune the volume of logs your app produces Explores the new log sampling feature The post Fine-tune the volume of logs your app produces appeared first on .NET Blog. Link👇🏻👇🏻👇🏻👇🏻 https://devblogs.microsoft.com/dotnet/finetune-the-volume-of-logs-your-app-produces/ #.NET,#.NETFundamentals,#.NET8,#logging @DeveloperAdvocate 🥑

Circuit Breaker Policy Fine-tuning Best Practice Summary of some best practice and insights about circuit breaker resilience policy fine-tuning. The post Circuit Breaker Policy Fine-tuning Best Practice appeared first on .NET Blog. Link👇🏻👇🏻👇🏻👇🏻 https://devblogs.microsoft.com/dotnet/circuit-breaker-policy-finetuning-best-practice/ #.NET,#C#,#CircuitBreaker,#Polly,#resilience @DeveloperAdvocate 🥑

.NET and .NET Framework June 2025 servicing releases updates A recap of the latest servicing updates for .NET and .NET Framework for June 2025. The post .NET and .NET Framework June 2025 servicing releases updates appeared first on .NET Blog. Link👇🏻👇🏻👇🏻👇🏻 https://devblogs.microsoft.com/dotnet/dotnet-and-dotnet-framework-june-2025-servicing-updates/ #.NET,#.NETFramework,#Maintenance&Updates,#.netframework @DeveloperAdvocate 🥑

Announcing dotnet run app.cs – A simpler way to start with C# and .NET 10 We are super excited to introduce a new feature that was released as part of .NET 10 Preview 4 that makes getting started with C# easier than ever. You can now run a C# file directly using dotnet run app.cs. This means you no longer need to create a project file or scaffold a whole […] The post Announcing dotnet run app.cs – A simpler way to start with C# and .NET 10 appeared first on .NET Blog. Link👇🏻👇🏻👇🏻👇🏻 https://devblogs.microsoft.com/dotnet/announcing-dotnet-run-app/ #.NET,#.NET10,#Featured @DeveloperAdvocate 🥑

Developer Advocate - Статистика та аналітика Telegram каналу @developeradvocate