<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های Amir Mokarchi</title>
        <link>https://virgool.io/feed/@mokarchi</link>
        <description>A software engineer</description>
        <language>fa</language>
        <pubDate>2026-06-16 05:29:46</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/8262/avatar/avatar.png?height=120&amp;width=120</url>
            <title>Amir Mokarchi</title>
            <link>https://virgool.io/@mokarchi</link>
        </image>

                    <item>
                <title>کانال‌های رویداد (Event Channels) در معماری مبتنی بر رویداد (EDA) چیست؟</title>
                <link>https://virgool.io/@mokarchi/%DA%A9%D8%A7%D9%86%D8%A7%D9%84-%D9%87%D8%A7%DB%8C-%D8%B1%D9%88%DB%8C%D8%AF%D8%A7%D8%AF-event-channels-%D8%AF%D8%B1-%D9%85%D8%B9%D9%85%D8%A7%D8%B1%DB%8C-%D9%85%D8%A8%D8%AA%D9%86%DB%8C-%D8%A8%D8%B1-%D8%B1%D9%88%DB%8C%D8%AF%D8%A7%D8%AF-eda-%DA%86%DB%8C%D8%B3%D8%AA-ldn85oxrbzby</link>
                <description>کانال‌های رویداد مسیرهایی هستند که از طریق آن‌ها رویدادها بین  سرویس‌های مختلف منتقل می‌شوند. می‌توان این کانال‌ها را مشابه خطوط لوله  (Pipeline) یا صف‌های پیام (Queue) در نظر گرفت که وظیفه انتقال رویدادها  از یک سرویس تولیدکننده (Producer) به یک یا چند سرویس مصرف‌کننده  (Consumer) را بر عهده دارند.تعریف و نقش کانال‌های رویدادزمانی که یک Event Generator (مانند یک سرویس پرداخت یا ثبت سفارش) رویدادی را ایجاد می‌کند، این  رویداد باید از طریق یک کانال مناسب به مقصد برسد. این کانال می‌تواند به  صورت صف (Queue)، موضوع (Topic) یا جریان داده (Stream) پیاده‌سازی شود.اهمیت کانال‌های رویدادانتقال ناهمزمان (Asynchronous): رویدادها بدون نیاز به پاسخ فوری پردازش می‌شوند.انعطاف‌پذیری (Resilience): در صورت عدم دسترسی موقت یک سرویس، رویدادها در کانال باقی می‌مانند تا زمانی که سرویس مجدداً فعال شود.مقیاس‌پذیری (Scalability): امکان اتصال چندین سرویس به یک کانال و پردازش موازی رویدادها وجود دارد.اتصال سست (Loose Coupling): سرویس‌های تولیدکننده و مصرف‌کننده از یکدیگر مستقل هستند و وابستگی مستقیم ندارند.انواع کانال‌های رویداد1. صف (Queue)هر رویداد فقط توسط یک مصرف‌کننده پردازش می‌شود.مثال: صف OrderQueue برای پردازش سفارش‌ها.کاربرد: مناسب برای سناریوهایی که پردازش رویداد باید دقیقاً یک بار انجام شود (مانند پردازش پرداخت).2. موضوع (Topic)هر رویداد می‌تواند توسط چندین مصرف‌کننده دریافت شود.مثال: موضوع OrderPlacedTopic که هم توسط سرویس ارسال و هم سرویس فاکتورخوانی استفاده می‌شود.کاربرد: مناسب برای مواردی که چندین سرویس باید از یک رویداد مطلع شوند.3. جریان داده (Stream)رویدادها به صورت یک جریان پیوسته ذخیره و پردازش می‌شوند.مثال: PaymentStream که تاریخچه تراکنش‌ها را نگهداری می‌کند.کاربرد: مناسب برای پردازش بلادرنگ (Real-time) و تحلیل داده‌های حجیم.پیاده‌سازی در .NET (با RabbitMQ یا Kafka)1. تعریف صف برای پردازش سفارش‌هاpublic class OrderPlacedHandler
{
    private readonly IEventBus _eventBus;

    public OrderPlacedHandler(IEventBus eventBus)
    {
        _eventBus = eventBus;
    }

    public void HandleOrderPlaced(OrderPlacedEvent orderEvent)
    {
        Console.WriteLine($&amp;quotProcessing order {orderEvent.OrderId}&amp;quot);
        _eventBus.PublishToQueue(&amp;quotOrderQueue&amp;quot, orderEvent);
    }
}2. تعریف موضوع برای اطلاع‌رسانی به چند سرویسpublic class OrderNotifier
{
    private readonly IEventBus _eventBus;

    public OrderNotifier(IEventBus eventBus)
    {
        _eventBus = eventBus;
    }

    public void NotifyServices(OrderPlacedEvent orderEvent)
    {
        _eventBus.PublishToTopic(&amp;quotOrderPlacedTopic&amp;quot, orderEvent);
    }
}نکات کلیدی در طراحی کانال‌های رویدادچند مصرف‌کننده (Multiple Consumers): در مدل Topic، چندین سرویس می‌توانند یک رویداد را دریافت کنند.صف مرده (Dead Letter Queue - DLQ): رویدادهای پردازش‌نشده به یک صف جداگانه منتقل می‌شوند تا بعداً بررسی شوند.حفظ ترتیب رویدادها (Event Ordering): در برخی سیستم‌ها مانند Kafka، ترتیب رویدادها حفظ می‌شود.کاربردهای واقعیپردازش پرداخت: ارسال رویداد PaymentProcessed به سرویس‌های حسابداری و انبارداری.مانیتورینگ: ارسال رویداد ErrorOccurred به سرویس‌های گزارش‌گیری.اینترنت اشیا (IoT): ارسال داده‌های سنسورها به یک جریان برای تحلیل بلادرنگ.چالش‌های اضافه بار در سیستم‌های مبتنی بر رویدادزمانی که حجم رویدادها از حد معمول فراتر رود، سیستم با مشکلات متعددی مواجه می‌شود:افزایش تأخیر در پردازش (Latency)انباشت پیام‌ها در صف‌ها (Queue Overflow)از کار افتادن مصرف‌کننده‌ها (Consumers Crash)از دست رفتن پیام‌ها (Message Loss)استراتژی‌های مدیریت اضافه بار۱. کنترل فشار پردازش (Backpressure Handling)مشکل: عدم توانایی مصرف‌کننده‌ها در پردازش رویدادها با سرعت مناسبراهکارها:محدودسازی نرخ تولید (Rate Limiting): کنترل تعداد رویدادهای تولید شده در واحد زمانکنترل جریان در Message Broker: تنظیم حداکثر پیام‌های در حال پردازشالگوی قطع ارتباط (Circuit Breaker): توقف موقت پردازش در صورت overloadمثال پیاده‌سازی در RabbitMQ:channel.BasicQos(prefetchSize: 0, prefetchCount: 10, global: false);۲. توازن بار بین مصرف‌کننده‌ها (Load Balancing)مشکل: توزیع ناعادلانه بار پردازش بین مصرف‌کننده‌هاراهکارها:افزایش افقی مصرف‌کننده‌ها (Horizontal Scaling)استفاده از Consumer Groups در Kafkaپیاده سازی Autoscaling در Kubernetesمثال پیاده‌سازی در Kafka:var config = new ConsumerConfig
{
    BootstrapServers = &amp;quotlocalhost:9092&amp;quot,
    GroupId = &amp;quotorder-processing-group&amp;quot,
    EnableAutoCommit = false
};

using var consumer = new ConsumerBuilder&lt;Ignore, string&gt;(config).Build();
consumer.Subscribe(&amp;quotorder-events&amp;quot);
var consumeResult = consumer.Consume();
Console.WriteLine($&amp;quotProcessing event: {consumeResult.Message.Value}&amp;quot);
consumer.Commit(consumeResult);۳. اولویت‌بندی پیام‌ها (Message Prioritization)مشکل: تأخیر در پردازش رویدادهای حیاتیراهکارها:پیاده‌سازی صف‌های با اولویتمسیریابی مبتنی بر موضوع برای رویدادهای مهممثال در RabbitMQ:var args = new Dictionary&lt;string, object&gt; { { &amp;quotx-max-priority&amp;quot, 10 } };
channel.QueueDeclare(&amp;quotpriority-queue&amp;quot, true, false, false, args);۴. صف مرده (Dead Letter Queue - DLQ)مشکل: از دست رفتن پیام‌های پردازش نشدهراهکارها:انتقال پیام‌های ناموفق به صف جداگانهپیاده‌سازی سیاست‌های تکرار پردازشمثال در RabbitMQ:var args = new Dictionary&lt;string, object&gt;
{
    { &amp;quotx-dead-letter-exchange&amp;quot, &amp;quotdlx-exchange&amp;quot }
};
channel.QueueDeclare(&amp;quotorder-queue&amp;quot, true, false, false, args);۵. پردازش دسته‌ای (Batch Processing)مشکل: ناکارآمدی در پردازش تک‌تک پیام‌هاراهکارها:پردازش گروهی پیام‌هااستفاده از Kafka Streamsمثال در Kafka:public void ProcessBatch(IEnumerable&lt;ConsumeResult&lt;Ignore, string&gt;&gt; messages)
{
    foreach (var message in messages)
    {
        Console.WriteLine($&amp;quotProcessing batch message: {message.Value}&amp;quot);
    }
}۶. پردازش جریانی (Stream Processing)مشکل: چالش در پردازش بلادرنگ حجم بالای رویدادهاراهکارها:استفاده از Apache Flink یا Kafka Streamsتکنیک‌های پنجره‌بندی زمانیمثال در Kafka Streams:var builder = new StreamsBuilder();
var stream = builder.Stream&lt;string, string&gt;(&amp;quotpayment-stream&amp;quot);

stream.GroupByKey()
    .WindowedBy(TimeWindows.Of(TimeSpan.FromSeconds(5)))
    .Reduce((value1, value2) =&gt; value1 + value2);</description>
                <category>Amir Mokarchi</category>
                <author>Amir Mokarchi</author>
                <pubDate>Wed, 02 Apr 2025 21:59:34 +0330</pubDate>
            </item>
                    <item>
                <title>تفاوت بین Event Choreography و Event Orchestration در EDA</title>
                <link>https://virgool.io/@mokarchi/%D8%AA%D9%81%D8%A7%D9%88%D8%AA-%D8%A8%DB%8C%D9%86-event-choreography-%D9%88-event-orchestration-%D8%AF%D8%B1-eda-djpnwukjyn18</link>
                <description>در معماری Event-Driven Architecture (EDA)، مدیریت جریان داده‌ها و هماهنگی بین سرویس‌های مختلف می‌تواند به دو روش Event Choreography و Event Orchestration انجام شود.در Event Choreography: سرویس‌ها به‌طور مستقل با هم تعامل دارند و هیچ کنترل‌کننده‌ی مرکزی وجود ندارد. در Event Orchestration: یک سرویس مرکزی (Orchestrator) مدیریت جریان داده‌ها و تعامل بین سرویس‌ها را برعهده دارد.سوال مهم:چه تفاوتی بین این دو روش وجود دارد؟کدام‌یک بهتر است؟ و در چه شرایطی باید از هر کدام استفاده کنیم؟رویکرد Event Choreography – هماهنگی غیرمتمرکز بین سرویس‌هادر Event Choreography، هر سرویس وقتی نیاز به انجام کاری دارد، یک Event منتشر می‌کند و سایر سرویس‌های مرتبط به این Event گوش می‌دهند و واکنش نشان می‌دهند.کنترل غیرمتمرکز: هیچ سرویس مرکزی وجود ندارد که فرایند را مدیریت کند. وابستگی کم(Loose Coupling): سرویس‌ها فقط Eventها را می‌شنوند و به آن‌ها پاسخ می‌دهند. مقیاس پذیری بالا: چون هیچ نقطه‌ی مرکزی کنترل‌کننده‌ای وجود ندارد، مقیاس‌پذیری بهتر است.مثال: پردازش سفارش در یک سیستم E-Commerceکلاس OrderService یک OrderPlaced Event منتشر می‌کند.کلاس PaymentService این Event را می‌شنود و پرداخت را پردازش کرده و یک PaymentProcessed Event منتشر می‌کند.کلاس InventoryService به OrderPlaced گوش می‌دهد و موجودی را کاهش می‌دهد.کلاس ShippingService به PaymentProcessed گوش می‌دهد و سفارش را ارسال می‌کند.در این روش، هیچ سرویس مرکزی مدیریت کل جریان را انجام نمی‌دهد، بلکه هر سرویس مستقل از دیگری واکنش نشان می‌دهد.مزایای Event Choreographyمقیاس‌پذیری بالا (Highly Scalable) توسعه و تغییر آسان (Flexible and Extensible) : اضافه کردن یک سرویس جدید فقط نیاز به گوش دادن به Eventهای موجود دارد. حداقل وابستگی بین سرویس‌ها (Loose Coupling)معایب Event Choreographyپیچیدگی بالا در مدیریت جریان داده‌ها : وقتی تعداد سرویس‌ها زیاد شود، ردگیری اینکه چه اتفاقی در سیستم رخ می‌دهد، دشوار می‌شود. دیباگ و مانیتورینگ سخت‌تر : چون هیچ کنترل‌کننده‌ای وجود ندارد، اشکال‌یابی بسیار پیچیده است.رویکرد Event Orchestration – هماهنگی متمرکز توسط یک Orchestratorدر Event Orchestration، یک سرویس مرکزی (Orchestrator) تعامل بین سرویس‌ها را مدیریت می‌کند.کنترل متمرکز: یک سرویس مرکزی مدیریت کل فرایند را بر عهده دارد. مدیریت وابستگی ها: Orchestrator تصمیم می‌گیرد که چه زمانی و چگونه هر سرویس باید فراخوانی شود. ردیابی و اشکال زدایی ساده‌تر: چون یک کنترل‌کننده‌ی مرکزی داریم، بررسی فرآیندها راحت‌تر است.مثال: پردازش سفارش در یک سیستم E-Commerce با استفاده از Orchestrationکلاس OrderService یک درخواست پردازش سفارش به OrderOrchestrator ارسال می‌کند.سپس OrderOrchestrator اول PaymentService را صدا می‌زند.بعد از تأیید پرداخت، OrderOrchestrator به InventoryService پیام می‌فرستد تا موجودی کالا را کاهش دهد.اگر موجودی کافی بود، OrderOrchestrator به ShippingService پیام می‌دهد تا سفارش را ارسال کند.در این روش، تمام تعاملات بین سرویس‌ها توسط یک Orchestrator کنترل و مدیریت می‌شوند.مزایای Event Orchestrationمدیریت و اشکال‌زدایی ساده‌تر (Easier Debugging &amp; Monitoring) هماهنگی بهتر بین سرویس‌ها (Better Coordination &amp; Dependencies Handling) کنترل بهینه بر ترتیب اجرای فرایندها (Explicit Execution Flow)معایب Event Orchestrationوابستگی بالا بین سرویس‌ها (Tight Coupling) : اگر Orchestrator خراب شود، کل سیستم ممکن است متوقف شود. مقیاس‌پذیری محدودتر نسبت به Choreography : تمام پردازش‌ها باید از طریق یک نقطه‌ی مرکزی انجام شوند.کدام‌یک بهتر است؟ Choreography یا Orchestration؟پاسخ: بستگی به سناریو دارد!بهتر است از Choreography استفاده کنیم اگر:تعداد زیادی سرویس کوچک داریم که مستقل از هم کار می‌کنند. می‌خواهیم مقیاس‌پذیری بالا داشته باشیم.اگر Eventها به طور طبیعی با هم تعامل دارند و نیازی به کنترل مرکزی نداریم. مثال: سیستم‌های مبتنی بر Microservices در یک پلتفرم Cloud-native.بهتر است از Orchestration استفاده کنیم اگر:فرآیندها به شدت به هم وابسته هستند و نیاز به هماهنگی دقیق دارند. نیاز به کنترل کامل روی اجرای فرآیندها داریم. مانیتورینگ و اشکال‌یابی فرآیندها مهم است. مثال: مدیریت فرآیندهای تجاری پیچیده (Business Process Management).روش ترکیبی: بهترین رویکرد؟در بسیاری از سیستم‌ها، ترکیب Choreography و Orchestration بهترین گزینه است.از Choreography برای تعاملات ساده و کم‌وابسته استفاده می‌کنیم.از Orchestration برای کنترل دقیق فرآیندهای حیاتی و وابسته بهره می‌بریم.مثال:کلاس OrderService یک Event OrderPlaced منتشر می‌کند.سپس Orchestrator به PaymentService و InventoryService پیام ارسال می‌کند.بعد از تأیید پرداخت و به‌روزرسانی موجودی، یک Event جدید منتشر می‌شود که سرویس‌های دیگر از طریق Choreography واکنش نشان می‌دهند.جمع‌بندیرویکرد Event Choreography: مناسب برای سیستم‌های توزیع‌شده‌ی مقیاس‌پذیر و منعطف که در آن سرویس‌ها مستقل هستند. رویکرد Event Orchestration: مناسب برای فرآیندهای پیچیده که به کنترل و مانیتورینگ دقیق نیاز دارند. رویکرد ترکیبی: استفاده‌ی هم‌زمان از هر دو روش برای مدیریت بهتر فرآیندها.</description>
                <category>Amir Mokarchi</category>
                <author>Amir Mokarchi</author>
                <pubDate>Tue, 01 Apr 2025 10:53:07 +0330</pubDate>
            </item>
                    <item>
                <title>ملاحظات طراحی در Domain Model</title>
                <link>https://virgool.io/@mokarchi/%D9%85%D9%84%D8%A7%D8%AD%D8%B8%D8%A7%D8%AA-%D8%B7%D8%B1%D8%A7%D8%AD%DB%8C-%D8%AF%D8%B1-domain-model-h0vgyjwfxf97</link>
                <description>مدل، همیشه یک نمایش ساده‌شده از واقعیت است که بسته به هدفی که داریم، سطح جزئیاتش متفاوت می‌شود. مثلا یه ماکت ساختمان را در نظر بگیرید. این ماکت نشان میدهد که ساختمان چقدر فضا اشغال می‌کند، چند طبقه دارد، ولی نشان نمیدهد که سیم‌کشی داخلی یا سیستم تهویه چطور کار می‌کند.پس هر مدل، یک بخش خاص از واقعیت را نمایش میدهد و بقیه جزئیات رو حذف می‌کند، چون برای هدف فعلی ما مهم نیستند.مدل دامنه‌ای باید بخش‌هایی از دامنه را که برای حل مشکل مهم هستن نمایش بدهد. اضافه کردن اطلاعات اضافی باعث پیچیدگی بی‌مورد و افزایش هزینه‌ی توسعه می‌شود.مدل دامنه‌ای فقط باید به مسئله‌ای که قرار است حل شود مربوط باشد، نه چیزهای جانبی.چند تفاوت مهم بین مدل دامنه‌ای و مدل داده‌ای مدل دامنه‌ای (Domain Model)  بر روی رفتارها و قوانین کسب‌وکار تمرکز دارد در حالی که مدل داده‌ای (Data Model) بر روی ذخیره‌سازی داده‌ها تمرکز دارد.مدل دامنه‌ای (Domain Model) تعاملات بین مفاهیم و فرآیندها رو نمایش می‌دهد در حالی که مدل داده‌ای (Data Model) ارتباط بین جداول و فیلدهای دیتابیس را نمایش می‌دهد.مدل دامنه‌ای (Domain Model) برای ارتباط بین تیم‌ها استفاده می‌شود در حالی که مدل داده‌ای (Data Model) برای طراحی دیتابیس استفاده می‌شود.مدل دامنه‌ای (Domain Model) با EventStorming ساخته می‌شود اما مدل داده‌ای (Data Model) با ERD (Entity-Relationship Diagram) ساخته می‌شود.طراحی مدل دامنه‌ای یک فرآیند تکاملی است. ما نمی‌توانیم از ابتدا یک مدل بی‌نقص داشته باشیم، ولی یک سری اصول هست که به ما کمک میکنه:۱. از EventStorming برای کشف رویدادهای کلیدی استفاده کنیدقبل از هر چیز، باید Big Picture EventStorming رو اجرا کنیم تا درک بهتری از دامنه پیدا کنیم.سپس باید ، Design-Level EventStorming را انجام دهیم تا روی جزئیات بیشتر تمرکز کنیم.۲. مدل را ساده ولی دقیق طراحی کنیدمفاهیم پیچیده رو شکسته و به مدل‌های کوچک‌تر تقسیم کنید.از Ubiquitous Language استفاده کنید که همه افراد تیم متوجه مدل شوند.۳. مدل رو با استفاده از Aggregates، Entities و Value Objects بسازید۴. رفتارها و فرآیندها را در مدل نمایش بدهیدتمرکز فقط روی داده‌ها نباشد! باید مشخص کنیم که هر بخش از سیستم چطور عمل می‌کند و چه قوانینی دارد.۵. مدل را تست کنید و اصلاح کنیدبعد از طراحی اولیه، باید مدل را در عمل تست کنیم و مشکلاتش رو پیدا کنیم.مهم‌ترین چیز این است که مدل، نیازهای واقعی کسب‌وکار را پوشش دهد.چطور از EventStorming به طراحی مدل برسیم؟با استفاده از Big Picture EventStorming  میتوان فرآیندهای اصلی را پیدا کرد.رویدادهای دامنه‌ای(Domain Events) را تحلیل کنید تا رفتارها و قوانین مشخص شوند.موجودیت‌ها (Entities)، مقدارها(Value Objects) و Aggregates ر تعریف کنید.مدل را ابتدا روی کاغذ یا Whiteboard بررسی کنید و سپس در کد پیاده‌سازی کنید.تمرکز فقط روی داده‌ها نباشد، بلکه رفتارهای مهم دامنه‌ای را هم در مدل لحاظ کنید.</description>
                <category>Amir Mokarchi</category>
                <author>Amir Mokarchi</author>
                <pubDate>Tue, 21 Jan 2025 19:33:48 +0330</pubDate>
            </item>
                    <item>
                <title>آشکارسازی مفاهیم پنهان در طراحی سیستم‌ها</title>
                <link>https://virgool.io/@mokarchi/%D8%A2%D8%B4%DA%A9%D8%A7%D8%B1%D8%B3%D8%A7%D8%B2%DB%8C-%D9%85%D9%81%D8%A7%D9%87%DB%8C%D9%85-%D9%BE%D9%86%D9%87%D8%A7%D9%86-%D8%AF%D8%B1-%D8%B7%D8%B1%D8%A7%D8%AD%DB%8C-%D8%B3%DB%8C%D8%B3%D8%AA%D9%85-%D9%87%D8%A7-dtdyxbvjqwt9</link>
                <description>وقتی سیستم ساخته می‌شود، مشکلاتی بوجود میاد که ظاهراً به خاطر سوءتفاهم‌های اولیه بوده است. این سوءتفاهم‌ها چطور ایجاد می‌شوند؟معمولاً این مشکلات به این خاطر به وجود میایند که چیزهایی که باید صریح و واضح باشند، مبهم یا ضمنی باقی میمانند. Implicit Concepts یا مفاهیم پنهان به زمانی گفته میشود که مفاهیم را شفاف نکنیم، که باعث برداشت های متفاوتی شود و همین باعث اختلاف یا اشتباه میگردد.مسأله: سوءتفاهم‌های ناشی از مفاهیم پنهانفرض کند در جلسه‌ای هستیم و درباره‌ی مشکلی حرف می‌زنیم. هرکسی تصویری در ذهنش از مشکل و راه‌حل دارد، ولی چون این تصاویر شفاف بیان نمی‌شوند، همه فکر می‌کنند با هم موافقند، در حالی که ممکن است کاملاً برداشت‌های متفاوتی داشته باشند.مثل وقتی که فکر می‌کنید منظور شخصی رو فهمیدید، ولی بعداً معلوم می‌شود اشتباه برداشت کردید؟این اتفاق معمولاً به خاطر سوگیری‌های شناختی مثل WYSIATI (What You See Is All There Is) رخ می‌دهد. ما براساس اطلاعات محدودی که داریم، تصمیم‌گیری می‌کنیم و فکر می‌کنیم کاملاً مشکل را فهمیدیم.مثال: فرم ثبت مرخصی پزشکییک فرم ساده ثبت مرخصی پزشکی رو در نظر بگیرید. فرض کند فرم اینگونه طراحی شده:یک فیلد برای Start Dateیک فیلد برای End Dateیک چک‌باکس برای Half Dayو یک دکمه برای Saveدر نگاه اول، این فرم ممکن است ساده به نظر برسد. ولی وقتی دقت کنید، کلی ابهام دارد:فیلد Start Date: این تاریخ یعنی چه زمانی؟ روزی که مرخصی ثبت شده یا روزی که کارمند سر کار نیامده است؟فیلد End Date: این یعنی آخرین روز مرخصی؟ یا روزی که کارمند برگشته است سر کار؟فیلد Half Day: آیا به شروع مرخصی اشاره دارد یا به پایان اش؟فیلد Save: وقتی کاربر روی این دکمه کلیک می‌کند، چه اتفاقی می‌افتد؟ آیا فقط داده ذخیره می‌شود یا فرآیند تأیید مرخصی هم شروع می‌شود؟این فرم خیلی گنگ است. حالا یک فرم مشابه رو در نظر بگیر که فیلدها و دکمه‌هاش شفاف‌تر تعریف شده اند:فیلد First Day Not At Work (اولین روزی که کارمند سر کار نیامده است)فیلد Came Back To Work (روزی که کارمند برگشته است)فیلد Left During Workday (آیا مرخصی از وسط روز شروع شده است؟)و یک دکمه مثل Submit for Approval (ارسال برای تأیید).این فرم مشخص و واضح طراحی شده است.</description>
                <category>Amir Mokarchi</category>
                <author>Amir Mokarchi</author>
                <pubDate>Tue, 21 Jan 2025 07:52:31 +0330</pubDate>
            </item>
                    <item>
                <title>دانش دامنه</title>
                <link>https://virgool.io/@mokarchi/%D8%AF%D8%A7%D9%86%D8%B4-%D8%AF%D8%A7%D9%85%D9%86%D9%87-ude8ob26t1ob</link>
                <description>دانش دامنه یا Domain Knowledge به دانش مرتبط با حوزه‌ای که نرم‌افزار در اون کار می‌کنه اشاره میکنه. مثلاً اگه دارید یک سیستم معاملات مالی طراحی می‌کنید، باید درباره معاملات مالی اطلاعات داشته باشید. بدون این دانش، نمی‌توانید به درستی مشکلات کاربران را درک کنید یا حتی زبانشان را بفهمید.اما، مگر نمی‌شود از مشخصات یا اسناد فنی استفاده کرد؟ چرا باید درباره دامنه چیزی بدانیم؟مشخصات و اسناد فقط بخشی از اطلاعات را بیان میکنند. ولی اگر دانش دامنه نداشته باشید:نمی‌توانید به درستی با کاربران صحبت کنید، چون اصطلاحاتشان رو نمی‌فهمید.اعتماد بین شما و مشتری سخت‌تر شکل می‌گیرد.ممکن است فقط همان چیزی را که در سند نوشته شده است، بسازید، ولی راه‌حل واقعی که مشکل را حل می‌کند، را پیدا نکنید.وقتی دانش دامنه داشته باشید، مکالمه با کاربران مفیدتر می‌شود. در نهایت وقتی شما به زبانشان صحبت می‌کنید و مشکلاتشان را می‌فهمید، بیشتر به شما اعتماد می‌کنند.چطور دانش دامنه به دست بیاریم؟با همکاری مؤثر می‌توانیم دانش لازم را کسب کنیم. چند روش اصلی برای به دست آوردن دانش دامنه وجود دارد:مکالمات (Conversations):رایج‌ترین روش است. در جلسات یا گفتگوهای رسمی و غیررسمی از کاربران سوال بپرسد. باید خوب گوش بدهید و سوال‌های دقیق بپرسید تا اطلاعات مفید بگیرید.مشاهده (Observation):این روش خیلی قدرتمند است. باید از پشت میز بلند شوید و ببینید کاربران چطور کار می‌کنند. مثلاً به انبار، هتل یا دفتر معاملات سر بزنید. به کارهایی که انجام می‌دهند دقت کنید. Jeff Patton در یکی از سخنرانی‌هاش مثال‌های خوبی در این مورد دارد.داستان‌سرایی دامنه (Domain Storytelling):این روش توسط Stefan Hofer و همکارانش معرفی شده است. از تصاویر ساده، فلش‌ها و کمی متن برای توضیح تعاملات درون دامنه استفاده می‌کند. این روش آسان و نیاز به توضیحات پیچیده ندارد.و EventStorming:این روش توسط Alberto Brandolini ابداع شده است و از Post-it Notes و یک رول کاغذ استفاده می‌کند. در کارگاه‌های EventStorming، شرکت‌کننده‌ها اتفاقات گذشته (Events) را روی یادداشت‌های چسبان می‌نویسند و در روی دیوار به ترتیب زمانی می‌چسبانند. این روش به کشف فرآیندها، فعالیت‌ها و حتی ابهامات کمک می‌کند.چالش‌های یادگیری دانش دامنهافراد در دامنه خودشان سال‌ها کار می‌کنند و متخصص می‌شوند. یادگیری این دانش برای ما که توسعه‌دهنده‌ هستیم، زمان‌بر است. به‌علاوه:گاهی دانش در سازمان پراکنده‌ است.ممکن است بعضی افراد اطلاعات اشتباه داشته باشند یا بخشی از دانش شان نادیده گرفته شده باشد.چطور دانش دامنه خوب را تشخیص بدیم؟باید با افراد مختلف از بخش‌های مختلف سازمان صحبت کنیم. از مدیران تا کارمندهای سطح پایین‌تر گرفته. هر کسی یک بخش از پازل را دارد. وظیفه ما این است که این تکه‌ها را کنار هم بگذاریم.</description>
                <category>Amir Mokarchi</category>
                <author>Amir Mokarchi</author>
                <pubDate>Sun, 19 Jan 2025 22:42:11 +0330</pubDate>
            </item>
                    <item>
                <title>تصمیم‌گیری و سوگیری‌های شناختی</title>
                <link>https://virgool.io/@mokarchi/%D8%AA%D8%B5%D9%85%DB%8C%D9%85-%DA%AF%DB%8C%D8%B1%DB%8C-%D9%88-%D8%B3%D9%88%DA%AF%DB%8C%D8%B1%DB%8C-%D9%87%D8%A7%DB%8C-%D8%B4%D9%86%D8%A7%D8%AE%D8%AA%DB%8C-klclhkpjxuoi</link>
                <description>ما چطور تصمیم می‌گیریم و چرا گاهی تصمیمات اشتباه می‌گیریم؟ انگار یه چیزی تو مغزمون باعث میشه منطقی عمل نکنیم.مغز ما همیشه در حال پردازش اطلاعاته و برای اینکه این حجم از اطلاعات رو مدیریت کنه، دو نوع فرآیند داره:فرآیند خودکار (Implicit/Automatic Process)، که ناخودآگاه و سریع انجام می‌شه.فرآیند آگاهانه (Explicit/Conscious Process)، که آهسته‌تر و نیاز به تلاش و انرژی بیشتری داره.این تقسیم‌بندی به اسم Dual Process Theory شناخته می‌شه و توسط Keith Stanovich و Richard West به عنوان System 1 و System 2 معرفی شده.دو سیستم تصمیم‌گیری مغز System 1 و System 2: در System 1: سریع، خودکار و مبتنی بر تجربه‌های گذشته است. مثل رانندگی وقتی دیگه مهارت پیدا کردی.در System 2: آهسته، منطقی و نیازمند تلاش فکریه. مثل وقتی که داری یه مسأله پیچیده ریاضی حل می‌کنی.دنیل کانمن توی کتاب معروفش Thinking, Fast and Slow این سیستم‌ها رو توضیح داده. System 1 معمولاً سوگیری‌های شناختی (Cognitive Biases) ایجاد می‌کنه، چون به جای تحلیل، به تجربیات گذشته و احساسات تکیه می‌کنه.سوگیری‌های شناختی و تأثیر آن‌ها در تصمیم‌گیریسوگیری‌ها افکار و تمایلات ناخودآگاه هستن که روی قضاوت‌ها و تصمیمات ما تأثیر می‌ذارن. چند مثال از این سوگیری‌ها در طراحی سیستم‌ها:سوگیری تأیید انتخاب Choice-Supportive Bias :وقتی یه چیزی رو انتخاب می‌کنی، حتی اگه نقص داشته باشه، بهش پایبند می‌مونی. مثلاً وقتی یه فریم‌ورک انتخاب کردی، ممکنه حتی اگه بهترهاش وجود داشته باشه، همچنان ازش استفاده کنی.سوگیری تأیید Confirmation Bias :فقط دلایلی که انتخابت رو تأیید می‌کنن می‌شنوی و بقیه رو نادیده می‌گیری.اثر همراهی با جمع Bandwagon Effect :وقتی اکثریت با چیزی موافق باشن، ناخودآگاه فکر می‌کنی اونا درست می‌گن، حتی اگه دلیل منطقی وجود نداشته باشه.اعتماد به نفس بیش از حد Overconfidence :معمولاً افراد در توانایی‌هاشون بیش از حد خوش‌بین هستن. مثلاً زمان لازم برای انجام یه پروژه رو کمتر از واقعیت تخمین می‌زنن.هیوریستیک در دسترس Availability Heuristic :فقط به اطلاعاتی که در دسترس داری تکیه می‌کنی و نمی‌ری اطلاعات بیشتری جمع کنی. این باعث می‌شه پیچیدگی مسأله رو دست‌کم بگیری.وقتی از Domain-Driven Design (DDD) استفاده می‌کنیم، باید تصمیم‌های دقیقی بگیریم. برای این کار، باید از System 2 بیشتر استفاده کنیم و جلوی System 1 و سوگیری‌هاش رو بگیریم. مثلاً وقتی قراره یک مسأله پیچیده رو دسته‌بندی کنیم (مثل چارچوب Cynefin)، ممکنه System 1 سریع تصمیم بگیره و مسأله رو ساده‌تر از واقعیت دسته‌بندی کنه. این باعث می‌شه راه‌حل اشتباهی انتخاب کنیم.چطور سوگیری‌ها رو مدیریت کنیم؟آگاه باش: همیشه بدون که سوگیری‌ها وجود دارن.فعال  کردن System 2 : قبل از تصمیم‌گیری، فکر کن و اطلاعات بیشتری جمع کن.نظر دیگران رو بپرس: چون ممکنه دیگران زاویه‌های مختلفی رو ببینن که تو نمی‌بینی.از روش‌های طراحی مشارکتی استفاده کن: مثل EventStorming که توش همه ذینفعان درگیر می‌شن و می‌تونن دیدگاه‌های خودشون رو ارائه بدن.آموزش ببین</description>
                <category>Amir Mokarchi</category>
                <author>Amir Mokarchi</author>
                <pubDate>Sun, 19 Jan 2025 07:55:46 +0330</pubDate>
            </item>
                    <item>
                <title>پیچیدگی ذاتی و پیچیدگی تصادفی</title>
                <link>https://virgool.io/@mokarchi/%D9%BE%DB%8C%DA%86%DB%8C%D8%AF%DA%AF%DB%8C-%D8%B0%D8%A7%D8%AA%DB%8C-%D9%88-%D9%BE%DB%8C%DA%86%DB%8C%D8%AF%DA%AF%DB%8C-%D8%AA%D8%B5%D8%A7%D8%AF%D9%81%DB%8C-gylsxer6y7x1</link>
                <description>دو مفهوم &quot;Essential Complexity&quot; و &quot;Accidental Complexity&quot; اولین بار توسط فرد بروکس (Fred Brooks)، برنده جایزه تورینگ، در مقاله معروفش No Silver Bullet در سال ۱۹۸۶ مطرح شد. بروکس دو نوع پیچیدگی رو تعریف کرد:پیچیدگی ذاتی Essential Complexity که از خود دامنه مسأله و مشکل نشأت گرفته میشه و بدون کاهش محدوده مسأله حذف شدنی نیست.پیچیدگی تصادفی Accidental Complexity که توسط خود راه‌حل ایجاد میشه، مثل استفاده از یک فریم‌ورک (Framework)، پایگاه داده، یا زیرساخت‌های دیگر...بروکس معتقد بود که با رشد صنعت نرم‌افزار، پیچیدگی تصادفی کم شده است. ابزارهای پیشرفته و زبان‌های برنامه‌نویسی سطح بالا به توسعه‌دهنده‌ها زمان بیشتری برای کار روی مسائل کسب‌وکار میدهند. ولی با این وجود بعد از ۳۰ سال، هنوز با پیچیدگی تصادفی درگیر هستیم.مثلاً کانتینرها (Containers) رو در نظر بگیرید که قرار بود میزبانی از اپلیکیشن‌ها ما رو راحت کنه. ولی بعدتر نیاز به ارکستریتور (Orchestrator) داشتیم و کار به Kubernetes رسید. و حالا بیشتر زمان خودمون رو صرف نوشتن فایل‌های YAML میکنیم تا کدنویسی واقعی.پیچیدگی ذاتی مستقیماً به فضای مشکل مربوط میشه، چون از خود مشکل ناشی میشه. ولی پیچیدگی تصادفی بیشتر به فضای راه‌حل مرتبط هست، چون از ابزارها و روش‌هایی که برای حل مشکل استفاده می‌کنیم، میاد.بیاید برای نمونه یک مثال واقعی رو بررسی کنیم: یک گزارش که قبلاً ماهانه تولید میشد، حالا باید به صورت بلادرنگ (Real-Time) اجرا بشه. بعد از چند ماه تیم توسعه، تخمین زد که تکمیل این قابلیت حداقل ۶ ماه دیگه زمان میبره و ۱ میلیون پوند هزینه داره. دلیلش هم این بود که دیتابیس تراکنشی (Transactional Database) بهینه نبود و باید از روش‌هایی مثل شاردینگ (Sharding)، توزیع جغرافیایی (Geographical Distribution)، و تکرار داده‌ها (Replication) استفاده میشد.وقتی نیاز واقعی مشتری رو تحلیل کردن، فهمیدن که مشتری فقط می‌خواست همون گزارش ماهانه رو هفتگی اجرا کنه. با یه تغییر ساده در زمان‌بندی، مشکل حل شد و نیازی به طراحی مجدد کل سیستم نبود.خیلی وقت‌ها ما توسعه‌دهنده‌ها عاشق اصولی مثل DRY هستیم و به دنبال انتزاع‌هایی هستیم که کدمون رو شیک‌تر کنه. ولی گاهی این انتزاع‌ها کاملاً غیرضروریه. این همون چیزی هست که بهش میگن Over-Engineeringپس قانون کلی اینه که پیچیدگی ذاتی رو بپذیریم و پیچیدگی تصادفی رو کم کنیم، و معمولاً این پیچیدگی تصادفی به خاطر مهندسی بیش از حد (Over-Engineering) به وجود میاد.دسته‌بندی پیچیدگی‌ها کمک می‌کنه قبل از حل مسأله بفهمیم که با چه سطحی از پیچیدگی روبرو هستیم. یک چارچوب خیلی معروف برای این کار هست به اسم Cynefin که توسط Dave Snowden و Mary Boone در یک مقاله در سال ۲۰۰۷ معرفی شد. ابزارهایی مثل DDD، EventStorming و Event Sourcing به ما کمک می‌کنن پیچیدگی‌های رو بهتر مدیریت کنیم.</description>
                <category>Amir Mokarchi</category>
                <author>Amir Mokarchi</author>
                <pubDate>Sat, 18 Jan 2025 15:12:32 +0330</pubDate>
            </item>
                    <item>
                <title>چالش‌ها و راهکارهای تعیین نیازمندی‌های نرم‌افزار</title>
                <link>https://virgool.io/@mokarchi/%DA%86%D8%A7%D9%84%D8%B4-%D9%87%D8%A7-%D9%88-%D8%B1%D8%A7%D9%87%DA%A9%D8%A7%D8%B1%D9%87%D8%A7%DB%8C-%D8%AA%D8%B9%DB%8C%DB%8C%D9%86-%D9%86%DB%8C%D8%A7%D8%B2%D9%85%D9%86%D8%AF%DB%8C-%D9%87%D8%A7%DB%8C-%D9%86%D8%B1%D9%85-%D8%A7%D9%81%D8%B2%D8%A7%D8%B1-janfv7daxxhn</link>
                <description>یکی از حساس‌ترین و مهم‌ترین مراحل در توسعه‌ی هر نرم‌افزار، مشخص کردن نیازمندی‌ها (Requirements) است. کیفیت و شفافیت نیازمندی‌ها تأثیر مستقیمی بر موفقیت پروژه دارد؛ اما متأسفانه، اغلب در این مرحله با مشکلاتی مواجه می‌شویم. مشکل کجاست؟1. فاصله بین مشتری و توسعه‌دهندهدر فرآیندهای سنتی، توسعه‌دهندگان معمولاً به‌صورت مستقیم با کسانی که مشکل واقعی را تجربه می‌کنند، در ارتباط نیستند.نقش تحلیل‌گران: افرادی مانند تحلیل‌گران نیازمندی، تحلیل‌گران کسب‌وکار یا مدیران محصول، میانجی بین تیم توسعه و مشتری هستند.ریسک انتقال ناقص اطلاعات: وقتی دیدگاه و تفسیر تحلیل‌گر وارد اسناد نیازمندی می‌شود، ممکن است بخش مهمی از مشکل یا انتظارات واقعی کاربر نادیده گرفته شود یا به اشتباه فهمیده شود.2. توصیف راه‌حل به‌جای مشکلدر اغلب اسناد نیازمندی‌ها، راه‌حل توصیف می‌شود نه خود مشکل.مثال: جمله‌ای مثل «هر روز، سیستم باید لیستی از مهمانان هتل که قرار است وارد یا خارج شوند را تولید کند» تنها راه‌حل را توصیف می‌کند، نه این‌که مشکل اصلی چیست.خطر تمرکز بر راه‌حل: وقتی تنها راه‌حل مطرح باشد، احتمال این‌که راه‌حل‌های بهتر و مؤثرتر را از دست بدهیم، زیاد می‌شود.3. حتی داستان‌های کاربری (User Stories) هم ممکن است راه‌حل نباشندروش‌های چابک (Agile) معمولاً از User Story برای بیان نیازمندی‌ها استفاده می‌کنند. این داستان‌ها تا حدی بهتر عمل می‌کنند، اما همچنان گاهی مشکل اصلی را پنهان می‌کنند.مثال: در جمله «به‌عنوان مدیر انبار، من نیاز دارم گزارش سطح موجودی را چاپ کنم تا بتوانم به‌موقع سفارش بدهم»، مشکل ریشه‌ای می‌تواند خیلی عمیق‌تر باشد: شاید سیستم خرید نیاز به اتوماسیون و پیش‌بینی داشته باشد تا دیگر نیازی به گزارش دستی نباشد.راهکارها برای حل مشکلات نیازمندی‌ها1. ارتباط مستقیم تیم توسعه با کاربران نهاییدر روش‌های Lean و Agile بر اهمیت ارتباط مستقیم بین تیم توسعه و کاربران نهایی تأکید می‌شود.مزیت: وقتی تیم توسعه مشکل را از زبان کاربر بشنود، هم شناخت بهتری از ابعاد مسئله پیدا می‌کند، هم احتمال سوءتفاهم کاهش می‌یابد.2. استفاده از پروتوتایپ (Prototype)ساخت نمونه‌ی اولیه و گرفتن بازخورد از کاربران نهایی، می‌تواند به شناسایی نیازهای واقعی و حذف فرضیات نادرست کمک کند.چرخه‌ی سریع: در هر تکرار (Iteration) یک پروتوتایپ تولید و تست می‌شود و بازخوردها به‌سرعت به تیم توسعه منتقل می‌گردند.3. رویکردهای طراحی دامنه‌محور (DDD)در Domain-Driven Design (DDD) توصیه میشود تیم‌ها با درک عمیق از دامنه‌ی کاری مشتری (Domain)، به راهکارهای نرم‌افزاری دست یابند.مزیت: با درک دقیق مدل کسب‌وکار، نیازمندی‌ها به‌صورت شفاف‌تری بیان می‌شوند و درک مشترک بین تیم‌های فنی و کسب‌وکار شکل می‌گیرد.4. تمرکز بر «مشکل» پیش از «راه‌حل»به‌جای این‌که بپرسید «چه چیزی باید بسازیم؟»، بهتر است ابتدا پرسیده شود «چه مشکلی باید حل شود؟» یا «چه نیازی باید برطرف شود؟».مزیت: تعریف دقیق مشکل، راه را برای یافتن راه‌حل خلاقانه باز می‌کند و گزینه‌های بیشتری را پیش روی تیم توسعه می‌گذارد.نتیجه‌گیریاگرچه تدوین نیازمندی‌های نرم‌افزار اغلب مشکل‌ساز و گیج‌کننده است، اما با تمرکز بر فهم مشکل به‌جای تمرکز صرف بر راه‌حل، استفاده از متدولوژی‌های چابک و Lean، به‌کارگیری پروتوتایپ‌ها و بهره‌گیری از رویکردهایی همچون Domain-Driven Design، می‌توان کیفیت نیازمندی‌ها را به‌شدت ارتقا داد. در نهایت، هر چه تیم توسعه و ذی‌نفعان پروژه با هم ارتباط بیشتری داشته باشند و مشکل واقعی کاربر را بهتر درک کنند، احتمال موفقیت محصول نرم‌افزاری بالاتر می‌رود.</description>
                <category>Amir Mokarchi</category>
                <author>Amir Mokarchi</author>
                <pubDate>Sat, 18 Jan 2025 12:04:10 +0330</pubDate>
            </item>
                    <item>
                <title>درباره Problem Space و Solution Space</title>
                <link>https://virgool.io/@mokarchi/%D8%AF%D8%B1%D8%A8%D8%A7%D8%B1%D9%87-problem-space-%D9%88-solution-space-kmtyfkhhwmhg</link>
                <description>این دو نظریه‌ که توسط &quot;Allen Newell&quot; و &quot;Herbert Simon&quot; در کتاب Human Problem Solving مطرح شده است. اساساً، بیان میکند که ما آدم‌ها برای حل مسائل، در یک فضای خاص به نام &quot;Problem Space&quot; به دنبال راه‌حل می‌گردیم.در &quot;Problem Space&quot; حالت اولیه (Initial State) و حالت مطلوب یا نهایی (Desired State) یک مسأله را تعریف میکنیم. همچنین حالت‌های میانی (Intermediate States)، محدودیت‌ها (Constraints) از جمله قوانینی است که به نوعی زمینه مسأله رو مشخص می‌کند.در صنعت نرم‌افزار، افرادی که بیشتر در &quot;Problem Space&quot; فعالیت می‌کنند، معمولاً مشتری‌ها (Customers) و کاربران (Users) هستند. &quot;Solution Space&quot; اساساً همان مسیری است که از وضعیت اولیه تا وضعیت نهایی و همه جزئیات مربوط به راه‌حل را شامل میشود. هر مسأله واقعی نیاز به راه‌حل دارد، و اگر درست درProblem Space جستجو کنیم، می‌توانیم بفهمیم که چه گام‌هایی باید برداریم. نمونه زیر مثال روشنی از این موضوع است.داستان کلاسیک نوشتن در فضا. در دهه ۱۹۶۰ کشورهایی که دنبال اکتشافات فضایی بودند فهمیدند که خودکار معمولی در فضا کار نمی‌کند چون جاذبه وجود ندارد. ظاهراً ناسا یک میلیون دلار خرج کرد تا خودکاری طراحی کند که در فضا کار کند، اما شوروی‌ها از مداد استفاده کردند که تقریباً هیچ هزینه ای نداشت.اما واقعیت ماجرا چیست!!!این داستان یک افسانه‌ست. ناسا هم مداد رو امتحان کرد ولی به خاطر مشکلاتی مثل تولید گرد و غبار ریز (Microdust)، شکستن نوک‌ها و قابلیت اشتعال چوب مداد، کنار گذاشته شد. در نهایت، یک شرکت خصوصی به اسم &quot;Fisher&quot; خودکاری به نام &quot;Space Pen&quot; طراحی کرد که بعد از آزمایش، هم ناسا و هم شوروی از آن استفاده کردند. قیمت برای هر خودکار هم فقط ۲.۳۹ دلار بود.پس مشکل از مداد بود؟ مشکل پیچیده‌تر از چیزی بود که در نگاه اول به نظر می‌رسید. اینجا محدودیت‌های اضافی یا به اصطلاح نیازمندی‌های غیرعملکردی (Non-Functional Requirements) و دقیق‌تر بیان کنم، نیازمندی‌های عملیاتی (Operational Requirements)، کار راسخت‌تر کرده بود.وقتی سریع به راه‌حل فکر می‌کنی، مغز دیگر روی خود مشکل متمرکز نمی‌شود. مثلاً &quot;Bart Barthelemy&quot; و &quot;Candace Dalmagne-Rouge&quot; در مقاله‌ای که در مجله Harvard Business Review منتشر شد بیان میکنند که وقتی به نوآوری فکر می‌کنید، باید از اینکه سریع دنبال راه‌حل بروید، خودداری کنید.چون، وقتی به اولین راه‌حلی که به ذهن می‌رسه فکر می‌کنید، شروع می‌کنید به گسترش جزئیات همون راه‌حل و به جای حل مسأله، روی ایده‌ای که به نظرت خوبه کار می‌کنید. ممکنه این ایده اصلاً بهترین راه‌حل نباشه.رویکرد Exploratory Approachدر این رویکرد، همیشه باید به دنبال ایده‌های دیگر هم بگردیم به جای اینکه فقط ایده اولیه رو بهتر کنیم باید چندین گزینه دیگر رو نیز آزمایش کنیم. این ممکنه سخت‌تر باشه ولی معمولاً جواب دقیق‌تر و ارزشمندتری میده.</description>
                <category>Amir Mokarchi</category>
                <author>Amir Mokarchi</author>
                <pubDate>Fri, 17 Jan 2025 19:08:41 +0330</pubDate>
            </item>
                    <item>
                <title>چارچوب Cynefin</title>
                <link>https://virgool.io/@mokarchi/%DA%86%D8%A7%D8%B1%DA%86%D9%88%D8%A8-cynefin-v0szp1gf5siw</link>
                <description>یک چارچوب شناختی (Sensemaking Framework) است که توسط دیو اسنودن (Dave Snowden) و مری بون (Mary Boone) در سال ۲۰۰۷ معرفی شد، ابزاری است برای کمک به رهبران و تصمیم‌گیران تا بتوانند با درک ماهیت موقعیت‌ها، رویکرد و شیوه‌ی واکنش بهتری انتخاب کنند. این چارچوب فقط مختص مدیریت کلان یا تصمیم‌گیری راهبردی نیست؛ می‌توان آن را در حوزه‌های مختلف از جمله توسعه نرم‌افزار نیز به‌خوبی به کار گرفت. ایده‌ی اصلی این است که هنگام تصمیم‌گیری در مورد نحوه‌ی طراحی، پیاده‌سازی، تست، دیباگ یا حتی مدیریت تیم و فرایندهای توسعه، ابتدا تشخیص دهید که با چه نوع مسئله‌ای روبه‌رو هستید و بعد متناسب با همان فضا عمل کنید. این چارچوب پنج حوزه (Domain) اصلی دارد که هر کدام نوع خاصی از پیچیدگی و عدم‌قطعیت را نشان می‌دهند:۱. حوزه‌ی ساده (Obvious/Simple)مشخصه: رابطه‌ی علی و معلولی روشن است و روش‌های راه‌حل از پیش مشخص و اثبات‌شده‌اند.رویکرد پیشنهادی: «حس کردن - دسته‌بندی کردن - پاسخ دادن» (Sense – Categorize – Respond)مثال کاربردی: فرض کنید شما مسئول موجودی انبار یک سوپرمارکت کوچک هستید. روش‌های استانداردی برای سفارش مجدد کالا وجود دارد (مثلاً وقتی کالایی به زیر یک حد خاص رسید سفارش جدید دهید). مسئله روشن است، راه‌حل‌ها مشخص هستند، و خطای زیادی هم ممکن است رخ ندهد. کافی است دستورالعمل‌های مشخص را دنبال کنید.چالش بالقوه در این حوزه این است که مدیر یا مسئول ممکن است دچار اعتماد به نفس کاذب شود و شرایط را بیش از حد ساده ببیند. در این صورت، ممکن است زمانی‌که اوضاع پیچیده یا پیچیده‌تر می‌شود، غافلگیر شود.۲. حوزه‌ی پیچیده (Complicated)مشخصه: رابطه‌ی علت و معلولی وجود دارد، اما برای تشخیص و استفاده از راه‌حل باید از کارشناسان و تخصص‌های مختلف کمک گرفت. پاسخ‌های صحیح متنوع هستند، اما می‌توان با تحلیل و دانش تخصصی به جواب رسید.رویکرد پیشنهادی: «حس کردن - تحلیل کردن - پاسخ دادن» (Sense – Analyze – Respond)مثال کاربردی: فرض کنید می‌خواهید یک کمپین بازاریابی در فضای آنلاین اجرا کنید. شما برای بخش‌های مختلف (سئو، تبلیغات کلیکی، شبکه‌های اجتماعی و ...) احتمالاً از متخصصان کمک می‌گیرید. همه چیز مبهم نیست، اما تحلیل و دانش عمیق در بخش‌های مختلف لازم است تا نتیجه‌ی مطلوب حاصل شود.مسئله‌ی کلیدی: روش پاسخ در حوزه‌ی پیچیده این است که ابتدا حس کنید و اطلاعات جمع کنید، سپس با تحلیل تخصصی به راهکار دست یابید. مدیران در این حوزه باید به کارشناسان اعتماد کنند.۳. حوزه‌ی پیچیده (Complex)مشخصه: روابط علت و معلولی به‌صورت شفاف قابل شناسایی نیستند و از قبل نمی‌دانید کدام راه‌حل حتماً موفقیت‌آمیز خواهد بود. بهترین رویکرد، آزمایش و تست روش‌های مختلف، مشاهده‌ی نتایج و سپس انطباق با شرایط است.رویکرد پیشنهادی: «پروب کردن - حس کردن - پاسخ دادن» (Probe – Sense – Respond)مثال کاربردی: شما یک استارتاپ دارید که راه‌حل نوآورانه‌ای ارائه می‌دهد و بازار هدف هم جدید است. دقیقاً نمی‌دانید کدام استراتژی فروش، جذب سرمایه یا توسعه‌ی محصول بهترین نتیجه را خواهد داشت. در این شرایط، ابتدا چند آزمایش کوچک (پایلوت) انجام می‌دهید تا رفتار مشتریان را بسنجید، سپس با مشاهده‌ی نتایج، مسیرتان را اصلاح می‌کنید.نکته‌ی مهم: در حوزه‌ی پیچیده «پروب کردن» (ساختن آزمایش‌های کنترل‌شده) و جمع‌آوری بازخورد، کلید موفقیت است.۴. حوزه‌ی آشوبناک (Chaotic)مشخصه: هیچ رابطه‌ی علی و معلولی مشخص نیست و یا اگر باشد آن‌قدر شرایط بی‌ثبات و بحرانی است که فرصتِ تحلیل دقیق وجود ندارد. اولین کار، ایجاد ثبات اولیه و جلوگیری از گسترش بحران است.رویکرد پیشنهادی: «اقدام کردن - حس کردن - پاسخ دادن» (Act – Sense – Respond)مثال کاربردی: در دقایق اولیه بعد از یک فاجعه طبیعی، مهم‌ترین کار نجات جان افراد و تأمین نیازهای فوری است. برنامه‌ریزی‌های بلندمدت یا تحلیل‌های پیچیده بعداً انجام می‌شود. اول باید عمل کنید تا بحران را از حادترین حالت بیرون بیاورید.فلسفه‌ی اقدام: «اول عمل کن تا جلوی فاجعه را بگیری، بعد ببین اوضاع چطور است، سپس تصمیم‌های بعدی را بگیر.»۵. حوزه‌ی نابه‌سامانی (Disorder)مشخصه: در این حوزه مشخص نیست که وضعیت ما جزو کدام یک از چهار حوزه‌ی قبلی است. ممکن است بخشی از سیستم ساده باشد، قسمتی پیچیده باشد و بخشی هم کاملاً آشفته باشد. در این حالت بهترین رویکرد، «تقسیم وضعیت به بخش‌های قابل فهم» است تا بتوان آن‌ها را در حوزه‌ی مناسب خود قرار داد.مثال کاربردی: گاهی آن‌قدر ابعاد پروژه وسیع است که نمی‌توان به‌سرعت تشخیص داد کدام بخش روتین و ساده است، کدام بخش نیازمند تخصص بیشتر است، کدام بخش پیچیده (Complex) و کدام بخش در آشوب به‌سر می‌برد. در این حالت باید پروژه را خرد کرد و اجزای آن را در حوزه‌های مناسب قرار داد و بر اساس آن‌ها تصمیم‌گیری کرد.نکات تکمیلی و توصیه‌های عملیجابه‌جایی حوزه‌ها: ممکن است وضعیت از یک حوزه به حوزه‌ی دیگر تغییر کند. برای مثال، اگر بحران مدیریت نشود، حوزه‌ی پیچیده (Complex) می‌تواند به آشوب (Chaotic) تبدیل شود. یا ممکن است بعد از یک دوره‌ی طولانی نوآوری در حوزه‌ی پیچیده، در نهایت به یک دستورالعمل تثبیت‌شده برسیم که آن را به حوزه‌ی ساده منتقل کند.هم‌پوشانی حوزه‌ها: گاهی در یک پروژه‌ی بزرگ، بخش‌هایی از آن ساده و روتین هستند (مثلاً کارهای تکراری اداری)، ولی بخش‌هایی دیگر Complex یا حتی Chaotic هستند (مثلاً درگیرشدن با یک بحران تأمین کالا). مدیران باید بخش‌ها را تفکیک کنند و برای هر بخش روش تصمیم‌گیری مناسبی اتخاذ کنند.اهمیت فرهنگ سازمانی: در حوزه‌ی پیچیده، نیاز به فرهنگ «یادگیری مداوم» و «آزمایش سریع و ارزان» (Fail Fast) پررنگ است. سازمان‌هایی که اشتباه را تاب نمی‌آورند، در این حوزه مشکل خواهند داشت، زیرا از ترس شکست دست به هیچ آزمایشی نمی‌زنند.آگاه‌بودن از تعصب‌ها (Biases): انسان تمایل دارد مسائل را ساده ببیند یا گاهی هم بدون دلیل آن را پیچیده‌تر کند. آگاهی از سوگیری‌های شناختی (مثلاً توهم دانایی، ترس از ناشناخته‌ها و ...) می‌تواند کمک کند تا واقع‌بینانه‌تر قضاوت کنیم.به‌عنوان یک رهبر فنی (Technical Lead) در تیم نرم‌افزاری، این چارچوب می‌تواند در تصمیم‌گیری‌ها، مدیریت تسک‌ها، رهبری تیم و حتی در تعیین استراتژی توسعه بسیار راهگشا باشد. در ادامه چند پیشنهاد و راهکار عملی ارائه می‌شود که نشان می‌دهد چگونه می‌توانید از این چارچوب در نقش رهبری فنی استفاده کنید:۱. پایش مداوم و شناسایی نوع مسئلهبهترین کاربرد ساینِفین این است که قبل از هر تصمیم یا اقدام، به‌صورت آگاهانه از خودتان بپرسید:آیا مسئله/تسک، ساده و دارای بهترین‌روش اثبات‌شده (Best Practice) است؟آیا نیاز داریم با متخصصان مشورت کنیم و داده‌ها را عمیق تحلیل کنیم (پیچیده/Complicated)؟آیا نمی‌توان از قبل پاسخ را پیش‌بینی کرد و باید آزمایش و تکرار (Complex) انجام دهیم؟آیا شرایط بحرانی یا فوریتی است و باید بلافاصله عمل کنیم (Chaotic)؟به این ترتیب، شما به‌صورت سیستماتیک یاد می‌گیرید برای هر تسک و چالشی روش متناسبی به کار بگیرید، به‌جای اینکه یک الگوی ثابت برای همه‌ی مسائل تجویز کنید.۲. مدیریت و اولویت‌بندی تسک‌ها بر اساس حوزهدر نقش رهبر فنی معمولاً به شما رجوع می‌کنند که کدام تسک فوری است، کدام تسک پیچیده است و به تحلیل نیاز دارد، و کدام تسک را می‌توان با یک دستورالعمل ساده انجام داد. با بهره‌گیری از ساینِفین می‌توانید:تسک‌های ساده (Obvious) یا روتین را به نیروهای کم‌تجربه یا تازه‌وارد بسپارید تا به‌سرعت کار را یاد بگیرند. این تسک‌ها نباید وقت نیروهای ارشد را زیاد بگیرد.تسک‌های پیچیده (Complicated) را شناسایی کنید و برایشان زمان تحلیل و بررسی کارشناسی کافی بگذارید. اگر لازم است، متخصصان خارجی یا ابزارهای پیشرفته را وارد کنید.تسک‌های با عدم قطعیت بالا (Complex) را با رویکرد «Proof of Concept» یا «MVP» جلو ببرید. از اسپرینت‌های کوتاه و بازخورد مداوم استفاده کنید تا ریسک را کنترل کنید.تسک‌های بحرانی (Chaotic) را فوری در اولویت اول قرار دهید. برنامه‌ها را متوقف کنید و ابتدا بحران را مهار کنید؛ مثلاً باگ تولیدی(Production) یا حمله امنیتی.این کار باعث می‌شود منابع (زمان، نیرو، هزینه) را دقیق‌تر تقسیم کنید و تیم‌تان را کاراتر جلو ببرید.۳. انتخاب روش توسعه و متدولوژی مناسبساینِفین به شما کمک می‌کند تشخیص دهید چه رویکردی در توسعه باید به کار گرفته شود:در مسائل ساده: استفاده از مستندات آماده، چک‌لیست‌ها و Best Practiceهای رایج. مثلاً وقتی می‌خواهید یک API ساده با یک الگوی شناخته‌شده درست کنید.در مسائل پیچیده (Complicated): معمولاً مهندسی پیش از اجرا (Upfront Engineering)، بررسی چندین سناریو و تهیه مستندات طراحی (Design Documents) مفید است.در مسائل پیچیده (Complex): توسعه‌ی چابک (Agile)، اسپرینت‌های کوتاه، ساخت پروتوتایپ و گرفتن بازخورد.در حوزه‌ی آشوبناک (Chaotic): فرایند رسمی را کنار بگذارید و سریع اقدام اضطراری کنید (Hotfix، Rollback و ...).به‌عنوان رهبر فنی، می‌توانید برای هر بخش یا فاز پروژه، متدولوژی منطبق با حوزه‌ی مربوطه را پیشنهاد کنید و از یک روش واحد برای همه‌ی قسمت‌ها استفاده نکنید.۴. آموزش و توانمندسازی تیمبسیاری از مشکلات در توسعه نرم‌افزار زمانی ایجاد می‌شوند که اعضای تیم نمی‌دانند باید از چه رویکرد یا ابزاری استفاده کنند. شما می‌توانید:تیم‌تان را با چارچوب ساینِفین آشنا کنید: در جلسات داخلی، با مثال‌های واقعی از پروژه‌ی خودتان، توضیح دهید که کدام تسک‌ها را می‌توان در حوزه‌ی ساده در نظر گرفت و کدام در حوزه‌ی پیچیده.برای هر حوزه دستورالعمل کلی داشته باشید: مثلاً یک راهنمای مختصر بنویسید که اگر تسک ساده است، راهنمایی اصلی چیست (چک‌لیست‌ها؟ مستندات خاص؟). اگر پیچیده/Complicated است، بهتر است سراغ چه ابزارها یا افراد متخصصی برویم و چه مدت زمان برای تحلیل لازم داریم.چشم‌انداز مشترک بسازید: وقتی همه‌ی اعضا یک زبان مشترک برای توصیف پیچیدگی یا بحران داشته باشند، سریع‌تر و شفاف‌تر می‌توانند در مورد راه‌حل توافق کنند.۵. مدیریت تغییر و نوآوریاغلب رهبران فنی وظیفه دارند تیم را به سمت فناوری‌های جدید، ابزارهای به‌روز یا معماری‌های مدرن سوق دهند. اما میزان ریسک و عدم قطعیتی که هر تکنولوژی جدید به همراه دارد، در ساینِفین می‌تواند به شما نشان دهد در کدام حوزه قرار می‌گیرید:اگر فناوری یا ابزار جدید، تا حد زیادی تست‌شده و سندیت دارد (مثلاً استفاده از یک کتابخانه‌ی محبوب در جامعه‌ی متن‌باز)، این موضوع می‌تواند نزدیک به حوزه‌ی پیچیده (Complicated) باشد و با بررسی کارشناسی سراغش بروید.اگر هنوز ناشناخته است و مطمئن نیستید چه نتایجی خواهد داشت (مثلاً ابزارهای بسیار نوپا، یا ترکیب معماری‌های عجیب‌وغریب)، به حوزه‌ی پیچیده (Complex) نزدیک است و باید با رویکرد آزمایشی (Proof of Concept) عمل کنید.با این شیوه، می‌توانید از پریدن ناگهانی کل تیم به سمت فناوری‌های ناشناخته جلوگیری کرده و ابتدا با چند آزمایش و پروتوتایپ جلو بروید.۶. رسیدگی به بحران‌ها (Incident Management)یکی از وظایف مهم رهبر فنی، مدیریت بحران‌های فنی است. ساینِفین می‌گوید در حوزه‌ی آشوبناک (Chaotic):اولویت اول: اقدام فوری برای جلوگیری از گسترش بحران (مثلاً از دسترس خارج‌کردن سرویس، ری‌بوت سرور، Rollback انتشار جدید و ...).سپس حس کردن (Sense) و تشخیص ابعاد مسئلهدر نهایت پاسخ دادن (Respond) به شکل ساختارمند (مثلاً پس از بازگرداندن شرایط عادی، وارد دلایل ریشه‌ای (Root Cause Analysis) شوید).این رویکرد باعث می‌شود هم سرعت عمل داشته باشید و هم پس از آرامش اولیه، با تحلیل درست، از بروز مجدد مشکل جلوگیری کنید.۷. جلوگیری از سردرگمی (حوزه‌ی Disorder) در تیمحوزه‌ی «نابه‌سامانی (Disorder)» زمانی اتفاق می‌افتد که تیم شما نمی‌داند نوع چالش چیست یا حتی تعریف درستی از مسئله ندارد. به‌عنوان رهبر فنی می‌توانید:تفکیک مسئله به بخش‌های کوچکتر: اگر یک مشکل یا پروژه خیلی مبهم است، سعی کنید اجزایش را جدا کنید و برای هر بخش، یک دامنه یا حوزه‌ (Domain) را تشخیص دهید.شفاف‌سازی نیازمندی‌ها: با ذی‌نفعان (مدیر محصول، کاربران، مشتریان) جلساتی بگذارید تا نیازمندی‌ها را واضح‌تر کنید.همکاری با اسکرام مستر یا مدیر پروژه: اگر در تیم‌تان شخصی برای مدیریت فرایند وجود دارد، با او هماهنگ شوید که در جلسه‌های Grooming یا Planning به تیم کمک کند تا کارها را خوب دسته‌بندی کنند.۸. نظارت و بازنگری مداومساینِفین یک چارچوب پویا است؛ ممکن است مسئله‌ای که ابتدا ساده به‌نظر می‌رسد، ناگهان پیچیده یا حتی آشوبناک شود (یا برعکس). بنابراین، به‌صورت دوره‌ای (مثلاً در جلسات اسپرینت ریویو یا جلسات هفتگی) این سوال‌ها را مطرح کنید:آیا تغییری در وضعیت پروژه یا تیم ایجاد شده که نوع تسک/مسئله را عوض کند؟آیا حوزه‌ی تسک‌ها از Complex به Complicated منتقل شده و حالا دستورالعمل بهتری برایش داریم؟آیا تسک یا مشکل خاصی پیش آمده که باید فوری وارد عمل شویم (Chaotic)؟این بازنگری‌ها به شما امکان می‌دهد رویکرد و منابع‌تان را به‌روز کرده و از غافل‌گیری جلوگیری کنید.جمع‌بندیاستفاده از این چارچوب باعث می‌شود که رهبران و مدیران، به جای تلاش برای تحمیل یک روش ثابت به همه موقعیت‌ها، ابتدا نوع موقعیت را بشناسند و سپس متناسب با آن بهترین سبک رهبری و تصمیم‌گیری را انتخاب کنند.</description>
                <category>Amir Mokarchi</category>
                <author>Amir Mokarchi</author>
                <pubDate>Mon, 13 Jan 2025 14:20:56 +0330</pubDate>
            </item>
                    <item>
                <title>پنج سطح جهل The Five Orders of Ignorance</title>
                <link>https://virgool.io/@mokarchi/%D9%BE%D9%86%D8%AC-%D8%B3%D8%B7%D8%AD-%D8%AC%D9%87%D9%84-the-five-orders-of-ignorance-tix2poecw9t2</link>
                <description>موضوع پنج سطح جهل ابتدا توسط Philip Armour در مقاله‌ای تحت عنوان The Laws of Software Process در سال 2000 ارائه شد. Armour در مقاله خود به این اشاره کرد که:نرم‌افزار منبع دانش است: برخلاف محصولات فیزیکی که ماده‌ی اولیه تولید می‌کنند، نرم‌افزار محصولی از دانش انسان است.فرآیند توسعه نرم‌افزار معطوف به یادگیری است: بسیاری از شکست‌های پروژه‌های نرم‌افزاری به دلیل فقدان درک صحیح از مسئله و ناتوانی در مدیریت دانش رخ می‌دهد.مدیریت جهل مهم‌تر از مدیریت دانش است: برای موفقیت، تیم‌ها باید ابتدا بفهمند که چه چیزهایی را نمی‌دانند.پنج سطح جهل یک چارچوب فکری ارزشمند است که درک بهتری از دانش، نادانسته‌ها، و نحوه یادگیری ارائه می‌دهد. این چارچوب برای توسعه‌دهندگان نرم‌افزار و مدیران پروژه بسیار مفید است، زیرا به درک عمیق‌تر مشکلات، شناسایی خطرات، و مدیریت دانش در فرایند توسعه کمک می‌کند.سطح صفر: دانش (0th Order of Ignorance)شما می‌دانید که چه چیزی را می‌دانید. این دانش شامل مهارت‌ها، مفاهیم، و اطلاعاتی است که به آن‌ها تسلط دارید.مثال عملی:شما می‌دانید که چگونه یک الگوریتم مرتب‌سازی را پیاده‌سازی کنید.می‌دانید که برای رفع یک خطا (bug)، از کدام ابزار (debugger) استفاده کنید.کاربرد: در این سطح، شما در حال استفاده از دانش خود برای حل مشکلات یا انجام کارها هستید.سطح اول: ندانستن (1st Order of Ignorance)شما نمی‌دانید که چه چیزی را نمی‌دانید، اما می‌دانید چگونه بفهمید.ویژگی کلیدی: این سطح به توانایی تحقیق و یادگیری اشاره دارد.مثال عملی:شما می‌دانید که یک فناوری جدید (مثلاً Docker) وجود دارد و نیاز دارید که آن را یاد بگیرید.برای یادگیری، به مستندات رسمی، دوره‌های آموزشی، یا کمک همکاران مراجعه می‌کنید.چالش: این سطح نیازمند زمان و منابع برای یادگیری است.سطح دوم: نادانی درباره نادانی (2nd Order of Ignorance)شما نمی‌دانید که چه چیزی را نمی‌دانید. به عبارتی، «چیزهای ناشناخته ناشناخته» وجود دارند.ویژگی کلیدی: این سطح زمانی رخ می‌دهد که شما حتی نمی‌دانید که باید به دنبال چه چیزی باشید.مثال عملی:شما نمی‌دانید که یک فناوری جایگزین بهتر (مثلاً Kubernetes به جای Docker) وجود دارد.در پروژه، ممکن است تیم متوجه نباشد که یک وابستگی کلیدی وجود دارد که باید مدیریت شود.چالش: این سطح ریسک بسیار بالایی دارد، زیرا ممکن است پروژه را با خطرات غیرمنتظره مواجه کند.راه‌حل: کاوش، تحلیل، و استفاده از تجربیات دیگران می‌تواند به شناسایی این ناشناخته‌ها کمک کند.سطح سوم: فرآیند ندانستن (3rd Order of Ignorance)شما نمی‌دانید که چگونه بفهمید. به عبارتی، فرآیند یا متدی برای شناسایی و یادگیری ندارید.ویژگی کلیدی: این سطح زمانی رخ می‌دهد که تیم یا فرد نمی‌داند از کجا شروع کند.مثال عملی:یک تیم نرم‌افزاری نمی‌داند چگونه نیازمندی‌های مشتری را شناسایی کند.ممکن است فرآیندهای مدیریت پروژه مانند Scrum یا Kanban وجود نداشته باشد.چالش: بدون داشتن فرآیند مناسب، تیم در مواجهه با مشکلات سردرگم می‌شود.راه‌حل: تعریف فرآیندهای یادگیری و تصمیم‌گیری، مانند کارگاه‌های آموزشی (workshops)، جلسات طوفان فکری (brainstorming)، و تحلیل نیازمندی‌ها.سطح چهارم: متافیزیک ندانستن (4th Order of Ignorance)شما حتی نمی‌دانید که جهل وجود دارد.ویژگی کلیدی: این سطح به ناآگاهی مطلق اشاره دارد. فرد یا تیم حتی متوجه نمی‌شود که باید چیزی را یاد بگیرد یا تغییر دهد.مثال عملی:یک سازمان معتقد است که فرآیندهای فعلی آن‌ها کامل هستند و نیازی به بهبود ندارند.یک مدیر پروژه ممکن است فکر کند که مشکلات تیم ناشی از کم‌کاری است، در حالی که دلیل واقعی ضعف فرآیندهاست.چالش: این خطرناک‌ترین سطح است، زیرا تغییر تنها زمانی رخ می‌دهد که این سطح جهل شناسایی شود.راه‌حل: استفاده از مشاوران خارجی، بازخورد مشتریان، و تحلیل عملکرد سازمان.جنبه‌های عملی‌تر این چارچوب :تیم‌ها باید به یادگیری مداوم متعهد باشند.تیم‌ها باید به صورت فعالانه ناشناخته‌ها را بررسی کرده و با آن‌ها مواجه شوند.ترکیب افراد با دیدگاه‌ها و تخصص‌های مختلف می‌تواند به کاهش جهل در همه سطوح کمک کند.جمع‌بندی: چگونه از این چارچوب استفاده کنیم؟شناسایی سطوح جهل در پروژه:بررسی کنید که تیم در کدام سطح از جهل قرار دارد.برنامه‌ریزی برای کاهش جهل:سطح صفر: استفاده از دانش موجود.سطح اول: تحقیق و یادگیری.سطح دوم: تحلیل نیازمندی‌ها و پیش‌بینی ناشناخته‌ها.سطح سوم: تعریف فرآیندهای یادگیری و تحلیل.سطح چهارم: بازنگری عمیق و مشاوره خارجی.تمرکز بر یادگیری مداوم:تیم‌ها باید همیشه آماده یادگیری، تحقیق، و بازنگری فرآیندها باشند.کاربرد ابزارهای مناسب:استفاده از User Story Mapping برای کاهش سطح دوم جهل .استفاده از Scrum یا Kanban برای کاهش سطح سوم جهل.استفاده از Retrospective و External Audit برای شناسایی سطح چهارم جهل.</description>
                <category>Amir Mokarchi</category>
                <author>Amir Mokarchi</author>
                <pubDate>Mon, 13 Jan 2025 14:01:23 +0330</pubDate>
            </item>
                    <item>
                <title>مفهوم کلی انتزاع و کپسوله سازی در Repository و UnitOfWork</title>
                <link>https://virgool.io/@mokarchi/%D9%85%D9%81%D9%87%D9%88%D9%85-%DA%A9%D9%84%DB%8C-%D8%A7%D9%86%D8%AA%D8%B2%D8%A7%D8%B9-%D9%88-%DA%A9%D9%BE%D8%B3%D9%88%D9%84%D9%87-%D8%B3%D8%A7%D8%B2%DB%8C-%D8%AF%D8%B1-repository-%D9%88-unitofwork-jalerlhdbdcl</link>
                <description>در این یادداشت به باید ها و نباید ها،الگو ها و ضدالگوها اشاره ای نمی شود و صرفا به بررسی مفاهیم پایه ای برنامه نویسی شی گرا در قالب Repository و Unit Of Work می پردازیم. پایه و اساس مطلب فوق برگرفته شده از دوره کپسوله سازی entity framework آقای Vladimir Khorikov می باشد و همچنین دارای ارجاعات متعددی به مقالاتی در این زمینه در وب می باشد تا حد ممکن سعی شده است که به منابع در پایان یادداشت اشاره شود.کپسوله سازی (Encapsulation) چیست؟ایده کپسوله سازی (Encapsulation) در مورد محتوی یک شی(Object) است. نه تنها برای نگه داشتن آنها، بلکه برای محافظت از آنها می باشد. بعضی مواقع تعریفی که از کپسوله سازی میبنید ممکن است Information Hiding یا مخفی کردن اطلاعات باشد یا حتی در کنار هم قرار دادن داده ها و یا عملیاتی که روی داده ها انجام میشود و یا به اصطلاح Bundle کردن داده ها باشد.هر چند که این دو تکنیک میتوانند کپسوله سازی رو ایجاد کنند اما Encapsulation این نیست.کپسوله سازی یا Encapsulation به معنای محافظت کردن از جامعیت داده ها یا Data Integrity است. یعنی یک کلاس وقتی به خوبی کپسوله شود داده های درونی یا Internal Data آن نمیتواند درون یک مقدار یا حالت Inconsistent  یا ناسازگار یا نامعتبری قرار بگیرد. یعنی محافظت از جامعیت و صحت داده ها که به آن Encapsulation یا کپسوله سازی گفته می شود.همانطور که ذکر شد  Information Hiding و Bundle کردن داده ها و یا عملیاتی که روی داده ها انجام میشود در کنار هم به کپسوله سازی کمک میکند. Information Hiding داده های درونی رو از دید کلاینت های آن کلاس مخفی میکند و قرار دادن داده ها و Operation در کنار هم یک نقطه ورود یگانه ایجاد میکند برای تمامی عملیاتی که میتواند روی کلاس انجام گیرد.به این ترتیب شما میتوانید قبل از اینکه اقدام به تغییر دادن State  یا داده های یک کلاس بکنید چک انجام بدهید و Integrity آن داده هایی که قرار هست در واقع درون کلاس شما قرار بگیرد را بررسی کنید.در بحث کپسوله سازی Invariant  ها هم مطرح میشود. Invariant یعنی یک سری شروط که باید در تمامی اوقات برقرار باشد. به عنوان یک برنامه نویس شما باید کاری کنید که هیچ کدام از Invariant ها هیچ وقت نقص نشوند و این وظیفه شماست که تمهیدات لازم برای یک همچنین کاری رو در نظر بگیرید.انتزاع (Abstraction) چیست؟بزرگ کردن ضروریات و حذف کردن نامرتبط ها تعریف کامل و جامعی از Abstraction می باشد که توسط رابرت مارتین ارائه شده است.وقتی شما یک کدی مینوسید روش های نامحدودی برای نوشتن یک برنامه دارید بعضی از زبان های برنامه نویسی هم Turing-complete هستند که این اجازه رو به شما میدهد که یک برنامه را به n  روش مختلف پیاده سازی کنید.در سبک برنامه نویسی Freestyle شما این امکان رو خواهید داشت که کل برنامه رو با یک کلاس و یک متد پیاده سازی کنید که مسلما اشتباه است به این علت که ذهن انسان محدود می باشد و همزمان قادر به مدیریت اطلاعات محدودی می باشد به همین علت هم هست که کلی روش و راهنمای نوشتن برنامه خوب بوجود آمده است تا سطح Productivity ما رو بالا ببرد. چون با کاهش سطح بهره وری امکان اشتباه ما بالا میرود و به عبارت دیگر ما با این ساختار باید جلوی پیچیدگی کد رو گرفته و کد برنامه را قابل مدیریت کنیم.انتزاع یا Abstraction هم اشاره دارد به اینکه به جای تمرکز بر روی مجموعه ای از کارها به صورت همزمان فقط و فقط بر روی یک موضوع متمرکز شود و آنچه که فعلا موضوعیت ندارد رو در نظر نگیرد و یا به عبارت دیگر برنامه ات را به قطعات کوچیکتر شکسته و روی هر کدام به صورت مجزا متمرکز شود.انتزاع یا Abstraction میتواند سلسله مراتب هم داشته باشد. یعنی Abstraction ای سوار بر Abstraction های دیگر که این به شما کمک میکند ایده های پیچیده تان را به سطوح مختلف شکسته و در هرکدام از سطوح فکر کنید و کد بزنید.انتزاع های سطح پایین رو lower-order abstraction و انتزاع های سطح بالا رو higher-order abstraction می گویند.این سلسله مراتب کمک میکند که شما تمرکز کنید که در هر لحظه در یک سطح کد برنید و به سطح دیگر فکر نکنید و درگیر جزئیات سطوح دیگر نشوید.چه تفاوتی بین Encapsulation و Abstraction وجود دارداین دو مفهوم گره خورده بهم هستند ولی تفاوت های زیادی نیز باهم دارند. Encapsulation درمورد سازگاری دیتا صحبت میکند در حالی که Abstraction  به بزرگنمایی ضروریات و حذف کردن نامرتبط ها اشاره دارد.کمکی که Abstraction به ما میکند این می باشد که دیگر نگران اینکه عملیاتی که انجام میدهیم معتبرهست یا نه نیستیم و این وظیفه را به عهده Encapsulation میگذاریم و تمرکز را بر روی آنچه که کد انجام میدهد و نه چگونگی آن قرار میدهیم.الگوی Repository چیست؟وظیفه اصلی این الگو این است که تمامی کار های مربوط به دیتابیس را در یک محیط یکسان متمرکز کند و در سرتاسر برنامه پخش نباشد و اجازه دسترسی در سرتاسر برنامه و از هرجایی به دیتابیس را نتوانید پیدا کنید.ریپازیتوری ها با استفاده دامین کلاس ها، نه دیتابیس آبجکت ها ارتباط برقرار میکنند.یعنی StudentRepository اگر متد GetById داشته باشد یک instance از student به عنوان یه دامین کلاس برای شما return میکند.به عبارت دیگر ریپازیتوری ها نه تنها کد دسترسی به داده را دارند مثلا کوئری های SQL را داخل خودشان قرار میدهند بلکه Mapping بین دامین مدل و دیتابیس را نیز انجام میدهند. هدف این پترن این است که دسترسی به داده ها را برای شما ساده تر کند و داده هایی که داخل دیتابیس هستند و دامین آبجکت هایی که داخل دیتابیس هستند را براحتی واکشی کند که اصلا شما مجبور نباشید بدانید که آیا این دامین آبجکت ها از داخل دیتابیس یا مثلا از درون رم و یا ... واکشی می شوند.همه این موارد را تجمیع و Abstract میکند. پس تمام جزئیات پیاده سازی با این پترن Abstract میشوند.حالا بیاید برای روشن تر شدن قضیه به این کد یک نگاه بیندازیم. https://gist.github.com/mokarchi/a484d21b926d0141a99a2cce29c02484 اگر بخواهیم این قطعه کد رو با Repository جایگزین کنیم چنین تغییری خواهم داشتStudent student = _repository.GetById(id);میبینید که این دو قطعه کد تفاوت چندانی با هم ندارن. پراپرتی Student از نوع DbSet است و کل متد هایی که برای student در یک Repository میتوانید قرار بدهید در این نوع وجود دارد مثل find,add,update و ...اینجاست که اختلاف نظر ایجاد Repository ها بوجود میاد از یک طرف طرفدارن Repository معتقد هستن که میبایست همه دیتابیس اکسس کد درون Repository قرار بگیرد و از طرفی کسانی که با DbSet و EF کار میکنند اذعان دارند که DbSet به خودی خود Repository است پس نیازی به ایجاد Repository دیگری نیست.هر دو این نوع تفکر تا حدودی درست می باشد. پترن Repository و ایده پشت آن برای کار کردن با دیتابیس ها مفید است ولی خیلی قبل تر از معرفی ORM هایی مثل EF شکل گرفته است و امروزه با وجود ORM های پرقدرتی مثل EF شاید خیلی استفاده از این پترن مفید نباشد.حالا سوالی که مطرح هست این است که باید از کدام روش استفاده کنیم. از DbSet ها استفاده کنیم یا نه بریم یک لایه Abstraction دیگه اضافه کنیم و از Repository های سفارشی خودمون استفاده کنیم. این بسته به نوع پروژه شما دارد.به عبارت دیگه پترن Repository مباحث مربوط به persistence یا ذحیره کردن اطلاعات داخل دیتابیس رو abstract میکنه پس Repository یک Abstraction است.برای مثال پیچیدگی مربوط به بازیابی یک student با استفاده از شناسه اون و یا اضافه کردن یک student را abstract میکند. کاری که DbSet هم انجام میدهد. بنابراین اگر پروژه شما نیاز به پیچیدگی بیش از حدی ندارد عملا نیازی به اضافه کردن Abstraction جدید و اضافه کردن یک لایه Repository جدید ندارید.ولی اگر پروژه شما دارای پیچیدگی ای بیشتر از آنچه هست که DbSet ها در اختیار شما قرار میدهند اضافه کردن یه لایه Abstraction جدید میتواند مفید باشد.حالا چطور پیچیدگی های برنامه را مدیریت کنیم.با اضافه کردن سلسله مراتب Abstraction روی همدیگر. به این شکل که Abstraction های سطح بالاتر وابسته به Abstraction های سطح پایین تر شوند.فقط باید این را در نظر بگیرید که فقط زمانی منطقی هست که شما Repository ها را اضافه کنید که واقعا رسالت مخفی کردن یکسری پیچیدگی ها را برعهده داشته باشند. کلاس هایی که شامل پیچیدگی های اضافه ای نیستن و هیچ چیزی را abstract نمیکنند به Abstraction های کم عمق معروف هستن.(Shallow abstractions)استفاده از Repository های جنریک یا غیر جنریکسازگاری یا consistency یا به عبارتی یک شکل بودن باعث میشود که من توصیه کنم همیشه از Repository های غیر جنریک استفاده کنید.وقتی شما همیشه از Repository های غیر جنریک استفاده میکنید آگاهید که همیشه از برگ های سلسه مراتب Repository و اون درخت Repository تون رو استفاده میکنید.خیلی خوبه که به صورت Explicit تمامی Repository هاتون رو بررسی کنید و ببینید که چه Repository های توی کد بیس تون وجود دارند. ایده کلی اینه که Aggregate Root ها توی بحث DDD نیاز به Repository دارند.کلاس های غیر برگ در این سلسه مراتب باید به صورت یک کلاس Abstract تعریف شود که امکان استفاده به صورت مستقیم فراهم نباشد. این موضوع برای Repository های جنریک هم صدق می کند.در نهایت باید به این نکته توجه داشته باشید که شما باید به دید صرفا یک Abstraction بهش نگاه کنید. مثلا فرض کنید تا الان استراتژی حذف شما به صورت Physical (حذف واقعی از دیتابیس) بوده و اکنون میخواین اون رو به حذف Logical (حذف منطقی توسط IsDelete) تغییر بدین. در این صورت باید تمام جا هایی که مستقیما از متد Removeخود DbSet استفاده میکردین رو تغییر بدین و این تغییر در یک پروژه بزرگ دردسر زیادی رو به همراه داره، در صورتی که استفاده از یک Abstraction کار رو بسیار ساده میکرد.درواقع به جای اینکه مستقیما با DbContext و DbSet ها سرو کار داشته باشیم بهتره یک لایه انتزاعی (Abstraction) روی اون ایجاد کنیم و همه جا از اون Abstraction استفاده کنیم، یعنی به جای اینکه در همه جای پروژه متد Remove خود EF رو صدا بزنیم، اون رو داخل کلاس Repository نامی بنویسیم و همه جا متد Delete ریپازیتوری رو فراخوانی کنیم. این باعث میشه اگه یه روزی لازم شد متد Delete ریپازیتوری رو سفارشی کنیم و تغییر بدیم، اون تغییر تو کل پروژه اعمال بشه، چرا که تو کل پروژه از متد Delete ریپازیتوری استفاده کردیم.به همین ترتیب اگر نیاز به سفارشی سازی متد های دیگر (مثلا Add یا Update) دارید (مثلا اعمال اعتبارسنجی خاص به هنگام افزودن و ویرایش یا لاگ گرفتن تغییرات به هنگام ویرایش و... ) فقط کافیه متد های اون رو داخل Repository تغییر بدین و نه اینکه مجبور باشین تو کل پروژه کد هاتون رو تغییر بدین.الگوی Unit Of Workهمانطور که پیشتر اشاره شد زمانی ما از یک Abstraction استفاده میکنیم که یک Abstraction سطح بالا یکسری از پیچیدگی های سطح پایین تر رو abstract کرده باشد وقتی خود DbContext یک Unit Of Work هست دلیلی نداریم که یک Unit Of Work تعریف کنیم. با این پیاده سازی عملا دچار Abstraction های کم عمق می شویم که با عنوان Shallow abstractions با اون آشنا شدیم. در سناریو هایی که پیچدگی بر روی DbContext بیش از حد می شود Unit Of Work از حالت shallow خارج شده و پیاده سازی اون توجیح پذیر می شود.هنگامی که شما از EF استفاده می‌کنید و یک DbContext را وهله سازی می‌کنید، در واقع یک Unit Of Work می‌سازید. در عمده سناریو ها نیاز هست تا داده های زیادی از پایگاه داده فراخوانی شده و سپس در برخی از آن ها تغییراتی بدهیم، داده ای را اضافه کنیم و داده های دیگر ( مثلا نامعتبر ) را حذف کنیم. طبیعتا نمی توانیم به ازای هر تغییر و هر بار افزودن و حذف داده ها، بلافاصله و تک به تک، داده ها را به سمت پایگاه داده ارسال کنیم. چرا که این امر هم موجب کاهش کارایی و مصرف منابع خواهد شد و هم ممکن است در حین ثبت داده ها ناگهان خطایی رخ دهد و باقی تغییرات در پایگاه داده منعکس نشوند و خاصیت تراکنشی (Transactional) بیزینس از بین برود.الگوی Unit Of Work راهکاری را ارائه می دهد که در آن تمامی تغییرات داده شده در مدل، مانیتور می شوند. یعنی دقیقا در جایی ثبت می کنیم که چه مشخصاتی از چه اشیایی تغییر کرده، چه اشیایی اضافه شده و چه اشیایی حذف شده اند. سپس در انتها و پس از انجام کارها، با صدا زدن متد Save خواهیم فهمید که باید چه تغییراتی را به سمت پایگاه داده ارسال کنیم و البته این کار هم به صورت Transactional انجام خواهد گرفت.اگر کلاس Unit Of Work شما ارجاعی به تمام Repository های شما دارد طبیعاتا نقض اصل Abstraction می باشد. به این علت که Unit Of Work یک Abstraction سطح پایین می باشد ولی Repository ها Abstraction سطح بالا می باشد. با استناد به این دانش که Unit Of Work بدون Repository میتواند کار کند ولی Repository بدون Unit Of Work نمیتواند کار کند.همانطور که میدانید ارتباط بین Abstraction های سطح بالا و سطح پایین همیشه یک طرفه است از سطح بالا به سطح پایین. بنابراین بجای استفاده از DbSet ها باید از نوع جنریک اون استفاده بشه حالا بنظرتون این همون اتفاق قبلی نیست. DbContext همچنان به DbSet دسترسی داره؟تفاوت اینجا این هست که DbSet جنریک یه Abstraction سطح پایین تر نسبت به DbContext هست. این کار عینا استفاده از یک اینترفیس بجای کلاس concrete می باشد.اگر صرفا برای دست یابی به الگوی &quot;Context Per Request&quot; یا &quot;Session Per Request&quot; از Unit Of Work استفاده میکنید باید بدونید که اینکار نه توسط Unit Of Work و یا حتی خود EF بلکه توسط سیستم تزریق وابستگی و در اصل توسط IOC Container ها اتفاق میافته.درواقع IOC Container هست که میدونه باید برای هر درخواست (یا اصولا Scope)، فقط و فقط یک DbContext ساخته بشه (به جای اینکه چندین DbContext ایجاد بشه!)اگه بخوایم دقیق تر بحث درخواست و Scope رو باز کنیم باید بگیم که Scope یک &quot;محدوده&quot; هست که وقتی ایجاد میشه، اشیایی که درون اون ایجاد میشوند داخل همون Scope (محدوده) قابل استفاده هستند و در واقع &quot;زنده&quot; هستند و پس از پایان اون محدوده (Scope)، تمام اشیایی که در اون Scope ایجاد شده اند نیز &quot;میمیرند&quot; (در واقع Dispose میشوند و از بین میروند)البته تمامی این حرف ها &quot;فقط&quot; برای اشیایی صادق است که Lifetime (بازه عمر) آنها به صورت Scope تنظیم شده باشند.حال جالبه بدونین که IOC Container میاد و در ابتدای یک درخواست وب (Request)، یک Scope ایجاد میکنه و در پایان اون درخواست وب، اون Scope رو از بین میبره (در نتیجه تمام اشیایی آن Scope هم از بین میروند)در این حالت وقتی ما DbContext رو به صورت Scope (درواقع با Lifetime یا همون بازه عمر برابر با Scope) تعریف میکنیم، اتفاقی که میافته اینه که IOC Container در ابتدای هر درخواست، یک Scope ایجاد میکنه و درنتیجه DbContext ما هم (که قبلا به صورت Scope تنظیم شده است)، فقط و فقط یک نسخه از آن داخل Scope مربوطه (که اول درخواست ساخته شده) ایجاد میشه؛ در نتیجه طی اون Scope ما هر چندبار هم که DbContext رو فراخوانی کنیم، توسط سیستم تزریق وابستگی، &quot;فقط و فقط&quot; همون یک نسخه اولیه به ما ارجاع(پاس) داده میشه و در این حالت الگوی Context Per Request تحقق میابد.در پایان درخواست وب هم، چون Scope مربوطه ازبین میره، تمامی اشیای داخل آن(ایجاد شده توسط آن Scope) نیز از بین میروند از جمله همین DbContext ما و درواقع در پایان درخواست، DbContext ما هم Dispose میشهمنابع:https://www.pluralsight.com/courses/ef-core-6-encapsulating-usagehttps://www.dntips.ir/https://t.me/c/1029399467/77614</description>
                <category>Amir Mokarchi</category>
                <author>Amir Mokarchi</author>
                <pubDate>Sun, 16 Apr 2023 11:07:36 +0330</pubDate>
            </item>
                    <item>
                <title>کیفیت کد خود را تقویت کنید</title>
                <link>https://virgool.io/@mokarchi/%DA%A9%DB%8C%D9%81%DB%8C%D8%AA-%DA%A9%D8%AF-%D8%AE%D9%88%D8%AF-%D8%B1%D8%A7-%D8%AA%D9%82%D9%88%DB%8C%D8%AA-%DA%A9%D9%86%DB%8C%D8%AF-hbsk42l8mp0m</link>
                <description>اگر مجبورید کلاسی را با آمدن یک ویژگی جدید تغییر دهید، ممکن است اصل SRP را نقض کرده باشید. به طور معمول، هر زمان که شما نیاز به پیاده سازی cross-cutting concerns ها مانند logging، caching و غیره داشته باشید، این اتفاق می افتد.ما با ایجاد دو کلاس مجزا refactoring را انجام دادیم. یکی برای تزئین (decorate) دیگری استفاده می شود. توجه داشته باشید که همچنین یک اینترفیس را استخراج و کلاس decorator نمونه ای از اینترفیس را به عنوان یک وابستگی در نظر می‌گیریم. به همین راحتی می توانید یک کلاس را تزئین (decorate) کنید.می‌بینید که UserRepository چقدر ساده است، و حالا فقط یک مسئولیت دارد؟ Logging دیگر نگرانی نیست.ما یک کلاس UserRepositoryLoggingDecorator جداگانه ایجاد کرده‌ایم که از logging مراقبت می‌کند.کلاس‌های موجود را تغییر ندهیداین اصل مورد علاقه من است. اینکه بتوانید فقط کلاس های جدید را اضافه کنید و کلاس های موجود را لمس نکنید، بسیار عالی است.شما به سرعت نقض OC را تشخیص می دهید. هر ویژگی جدید نیاز به یک if جدید دارد. درست مانند کلاس ProductFormatter، که یک نوع product را می‌گیرد و رشته‌ای را که به روشی دلخواه قالب‌بندی شده است را برمی‌گرداند.در ابتدا خیلی بد به نظر نمی رسد.با این حال، برای هر نوع قالب بندی جدید، شما باید OCP را زیر پا بگذارید. همچنین، اگر اشکالی وجود دارد و باید منطق قالب بندی را اصلاح کنید، باید این کار را در جایی که توسط کد غیر مرتبط احاطه شده‌است انجام دهید.استفاده از polymorphism برای حذف if-else  دیوانه کننده و غیر ضروری، یکی از بهترین و آسان‌ترین روش‌ها است. به این ترتیب، شما به اصل Substitution Liskov دست می‌زنید. اکنون، ما کد غیرقابل انعطاف بالا را refactor کرده ایم.بنابراین، شما به وضوح متوجه شده اید که اکنون چقدر کد بیشتری وجود دارد. Refactoring به معنای کوچک کردن کد نیست، بلکه در مورد ایجاد کدهایی است آسان‌تر که با عقل و منطق کنار بیاید.ابتدا هر تکه منطقی را داخل if و else-if قرار می دهیم و آن را در داخل کلاس formatter قرار دهیم. اکنون هر کلاس یک هدف واحد دارد. زمانی که شما نیاز به رفع یک باگ دارید، می دانید که تمام کدهای اطراف به آن مربوط می شود.ثانیاً، هر formatter با فراخوانی RegisterFormatter آن در ProductFormatter فراخوانی می‌شود.پیاده‌سازی Format در حالی که خود قالب‌بندی را کنترل می‌کند، برای استفاده از جستجوی formatter  تغییر داده شده‌است.همچنین، توجه داشته باشید که اکنون یک JSON formatter وجود دارد. که به سادگی با اضافه کردن یک کلاس برای آن مدیریت می شود.در اینجا مثالی از نحوه استفاده از product formatter آورده شده است.فقط از مواردی استفاده کنید که مربوط به کلاس شما استشما احتمالاً از کلاس های استفاده کرده اید یا حتی ساخته اید که مشابه چاقوی سوئیسی عمل می کنند.به اندازه کافی عمومی برای هر چیزی. آنها اساساً بدردنخور هستند.فرض کنید ما یک کلاس داریم که برای به روز رسانی یک کاربر استفاده می شود. این کلاس به یک UserManager وابسته است که شامل مهم ترین و اصولی ترین ویژگی های یک چیز است.همه چیز عالی است اما، ما می توانیم بهتر عمل کنیم.در حال حاضر، کلاس UpdateUser می تواند آزادانه به هر روشی که توسط user manager در معرض نمایش قرار می گیرد دسترسی داشته باشد. دقیقاً آن چیزی نیست که ما می خواهیم، درست است؟ما با یک ابزار تک منظوره مانند آنچه در قسمت پایین آمده، وابستگی به چاقو سوئیسی را عوض می‌کنیم.توجه کنید که چگونه UpdateUserCommand و UserManager تقریباً بدون تغییر باقی مانده است.پاک کردن کدهای کثیف به همین سادگی است.کلاس های خود را مجزا (decouple) کنیدشما قبلاً در این مقاله با اصل وارونگی وابستگی آشنا شده اید. همه چیز در مورد تکیه کردن به انتزاعی در کلاس های concrete است. بنابراین، کلاس زیر چندین اصل را نقض می کند. وابستگی خود به AppDatabase را «new» می کند.به‌جای «new» کردن در نمونه‌های عینی، آنها را به‌عنوان وابستگی‌های صریح و روشن در نظر می‌گیرید، و می‌خواهید به جای یک کلاس مشخص، بر انتزاع تکیه کنید. به بیان ساده، شما می خواهید یک interface را به عنوان آرگومان سازنده در نظر بگیرید.به این کلاس GetUsersCommand بهبود یافته نگاهی بیندازید.«new» کردن کلاس ها را متوقف کنید و interface ها را به عنوان آرگومان های سازنده در نظر بگیرید. انصافاً به همین سادگی است.&quot;تعداد کلاس ها با هر refactor که شما انجام می دهید افزایش می یابد!&quot;این ممکن است یکی از اعتراضات شما به رویکرد refactoring باشد. به یاد داشته باشید که refactoring به معنای کوچک کردن کد یا حتی لزوماً ساده‌تر کردن همه چیز نیست. این در مورد تغییر کد شما برای مطابقت با پیچیدگی برنامه و تسهیل کار با کد است.متن فوق برگرفته شده از مدیوم Nicklas Millard می باشد</description>
                <category>Amir Mokarchi</category>
                <author>Amir Mokarchi</author>
                <pubDate>Mon, 20 Dec 2021 12:09:40 +0330</pubDate>
            </item>
                    <item>
                <title>لیست کتابهای برگزیده جذاب با محوریت Performance در استک دات نت</title>
                <link>https://virgool.io/@mokarchi/%D9%84%DB%8C%D8%B3%D8%AA-%DA%A9%D8%AA%D8%A7%D8%A8%D9%87%D8%A7%DB%8C-%D8%A8%D8%B1%DA%AF%D8%B2%DB%8C%D8%AF%D9%87-%D8%AC%D8%B0%D8%A7%D8%A8-%D8%A8%D8%A7-%D9%85%D8%AD%D9%88%D8%B1%DB%8C%D8%AA-performance-%D8%AF%D8%B1-%D8%A7%D8%B3%D8%AA%DA%A9-%D8%AF%D8%A7%D8%AA-%D9%86%D8%AA-oaaaghqptwqw</link>
                <description>بهینه سازی عملکرد اپلیکیشن بسیار اهمیت دارد و  به عوامل متعددی مانند معماری اپلیکیشن، طراحی و روش پیاده سازی آن (نوع  کد نویسی) بستگی دارد. قبل از هرگونه اقدامی ابتدا باید ناحیه ی مورد نظر  برای بهبود را مشخص کنیم و تغییرات را تنها بر اساس نیاز های خود اعمال  کنیم .با مطالعه این مجموعه ارزشمند به اطلاعات کاملی از پشت صحنه آنچه در دات نت اتفاق میافتد آشنا خواهید شد.by Sasha Goldshtein, Dima Zurbalev, Ido Flatow (2012)by Konrad Kokosa (2018)by Andrey Akinshin (2019)by Jeffrey Richter (2012)by Richard Blewett, Andrew Clymer (2013)by Ben Watson (2018)by Mario Hewardt (2009)by Joe Duffy (2008)by Serge Lidin (2014)by Brian Rasmussen (2014)by Steven Pratschner (2005)by Chris Farrell and Nick Harrison (2011)by Riccardo Terrell (2018)</description>
                <category>Amir Mokarchi</category>
                <author>Amir Mokarchi</author>
                <pubDate>Sat, 01 May 2021 10:30:04 +0430</pubDate>
            </item>
                    <item>
                <title>هنر تبدیل 6 خط کد به 92 خط کد</title>
                <link>https://virgool.io/@mokarchi/%D9%87%D9%86%D8%B1-%D8%AA%D8%A8%D8%AF%DB%8C%D9%84-6-%D8%AE%D8%B7-%DA%A9%D8%AF-%D8%A8%D9%87-92-%D8%AE%D8%B7-%DA%A9%D8%AF-utvvtwklobss</link>
                <description>مطمئناً ، if-else و switch کدهای متراکم و ساده را ایجاد می کند. اما نرم افزار شما نباید از کمترین خط ممکن تشکیل شود ، که maintainability ، readability یا flexibility را از بین ببرد.من بخش زیادی از تقسیم‌بندی کد را می‌بینم که بر روی enum ها یا دیگر مقادیر گسسته اتفاق می‌افتد. برخی از توسعه دهندگان حتی زمانی که به آن‌ها گفته می‌شود از if-then-else استفاده نکنند وضعیت را وخیم تر می کنند.اما ، به نظر شما عواقب استفاده از enum در عبارت if-then-else چیست؟انشعاب بر روی مقادیر گسسته ، تغییر نرم افزار شما را دشوار می کند. هر ویژگی جدید شما را ملزم می کند تا محل انشعاب را ردیابی کنید و کد موجود خود را متناسب با آن اصلاح کنید.قطعاً اینگونه نیست که ما می خواهیم یک نرم افزار عالی بسازیم. این شاید اولین گام عالی برای کارکرد کد شما باشد. اما ، همانطور که به سمت بهبود کد خود پیشرفت می کنید ، switch  و if-then-else باید دیگر از بین رفته باشند.روش سنتی انشعاب سازی با استفاده از if-else و switch منسوخ شده است. این SOLID نیست. انعطاف پذیر نیستبگذارید من این موضوع را تجسم کنمفرض کنید که شما با توجه به دلایلی باید راهی برای به روز رسانی کاربران داشته باشید. برای سادگی، یک کاربر تنها دو دلیل دارد که در سیستم شما به روز می‌شود.تغییر آدرس برای تغییر آدرس در سیستم CRM باید به بازاریابی اطلاع داده شود.تغییر نام کاربری (1) دنبال کنندگان کاربر باید در مورد تغییر نام کاربری مطلع شوند- (2) url slug کاربر باید به روز شود.شما این دو مورد ساده را در قطعه کد زیر پیاده سازی می کنید.یک ثانیه وقت بگذارید و این کد ضعیف طراحی شده را بخوانید. بدون شک بسیاری از توسعه دهندگان ارشد  نسبت به این مساله کابوس می‌بینند و ممکن است یک محرک استرس پس از حادثه (PTSD) تلقی شوند.بله، من قوانین دیوانه کننده‌ای مثل این را در حیات وحش دیده‌ام. این یک اجرای فوق العاده ساده لوحانه است که فرض می‌کند هیچ وقت دلایل دیگری برای تغییر کاربری وجود نخواهد داشت.تنها نکته خوبی که می توان در مورد این کد گفت ، تلاش برای ایجاد یک الگوی طراحی نیمه CQS گونه است.اگر تمایل شما این است که بگویید &quot;این باید یک switch باشد!&quot; باید لحظه ای فکر کنید و در مورد آنچه در توسعه نرم افزار مهم است تأمل کنید.شما تمام مدت با الزامات جدید برخورد خواهید کرد.بگویید که الزامات شما حالا این شکلی هستند.فعال سازی تایید دو مرحله ای و تغییر ایمیل هم باید باعث بروزرسانی کاربر شود.سوال این است که آیا شما واقعا قصد دارید این دو دلیل جدید را برای به روز رسانی یک کاربر با اضافه کردن مقادیر اضافه enum و اضافه کردن دو else-if اجرا کنید؟اگر تصمیم بگیرید که از راه اشتباهی پیش بروید ، در اینجا به نظر می رسد. این کد بخوبی خوانده نمی شودعلاوه بر اینکه به طورم مداوم نیاز به افزودن شاخه‌های اضافی هستید - که به خودی خود یک عمل سوال‌برانگیز است - هر زمان که باید debug یا یک bugfix را انجام دهید، شما این کار را با کد کاملا بی‌ربط احاطه شده انجام می دهید.یک مساله دیگر هم وجود دارد. امضای این متد به ما دروغ می‌گوید، زیرا فقط به روزرسانی کاربر نیست. همچنین انتخاب می کند کدام الگوریتم بر اساس دلیل بروزرسانی اجرا شود و حتی از هر یک از پیاده سازی ها اطلاع دارد. این برای همه واضح است که این متد مسئولیت های بی شماری را بر عهده دارد.بیایید نگاهی بیندازیم که چگونه می توانید از رویکردهای زننده مانند این جلوگیری کنید.بازسازی (Refactoring) برای اجرای polymorphic بسیار حیرت انگیز استقبل از اینکه کسی از استفاده از کلاس ها وحشت کند ، اجازه دهید فقط یک موضوع را روشن کنم. هزینه instantiating کلاسهای جدید اغلب قابل اغماض است. سعی نکنید کد خود را قبل از یک گلوگاه اثبات شده بهینه کنید.قبلاً اشاره کردم ما می توانیم خیلی بهتر عمل کنیم. منظور من از بهتر نوشتن، کدی است که 1) قابل خواندن ، 2) قابل نگهداری و 3) انعطاف پذیر باشد.با جایگزین کردن انشعابات سنتی با اجرای پلی مورفیک، یک رابطه واضح بین کلاس و نیازمندی‌ها که مدیریت می‌کند وجود دارد. کلاس‌های ساده و بسیار منسجم دارای مسئولیتهای روشن به راحتی قابل نگهداری هستند. علاوه بر این ، نرم افزار شما بدون نیاز به تغییر کلاس موجود ، به راحتی ویژگی های جدید را در خود جای می دهد.شما خواهید دید که ما تا چه حد می‌توانیم بدون if-then-else و یا switch پیش برویم.اکنون UpdateAsync به همین سادگی تبدیل شده است.Simplified UpdateAsync method implementationتوجه داشته باشید که چگونه اکنون به جای enum یک آرگومان اینترفیس می گیرید. اکنون ، این متد مسئولیت دانستن نحوه انجام به روزرسانی را به یک شی specialized خاص تفویض می کند.پیاده سازی های IUpdateReason به این شکل است. من جزئیات مربوط به arguments سازنده و اجرای متد را به تخیل شما می سپارم.UpdateReason interface and its concrete implementationsهر کلاس کاملا با نیازمندی‌ها همسو است و آن را مدیریت می‌کند. Debugging ، fixing bugs، و testing اکنون بسیار آسان‌تر از مقایسه با رویکرد منسوخ افتضاح است.در این حالت ، هر نیاز جدید منجر به یک کلاس specialized می شود.کد شما اکنون شی گرا است و نگهداری آن بسیار آسان است. کارت عالی بود.اما یک مسئله نهایی وجود دارداکنون UpdateAsync شما حدودی زائد است.برای حل این مشکل، ما دیگر refactoring را انجام نمی‌دهیم. ما در حال انتقال به بخش‌های طراحی مجدد سیستم هستیم.منطقی است که در این حالتcommand objects و command handlers ایجاد کنید.این کد فراخوانی را ساده می کند ، زیرا فقط یک command مانند UpdateUserAddress ارسال می کند و handler&#x27;s action مربوطه فراخوانی می شود.و در نهایتبه طور خلاصه if-then-else و switch کد شما را به طور قابل توجهی دشوارتر برای خواندن ، نگهداری و تنظیم می کند. دفعه بعدی که در حین اجرای یک ویژگی با استفاده از انشعاب سنتی چند منظوره قرار گرفتید ، لحظه ای وقت بگذارید و تحلیل کنید که چگونه می توانید از polymorphism  و رویکردهای مدرن استفاده کنید.</description>
                <category>Amir Mokarchi</category>
                <author>Amir Mokarchi</author>
                <pubDate>Fri, 30 Apr 2021 21:53:21 +0430</pubDate>
            </item>
                    <item>
                <title>دیگه وقتشه استفاده از If-Else رو کنار بزاری</title>
                <link>https://virgool.io/@mokarchi/%D8%AF%DB%8C%DA%AF%D9%87-%D9%88%D9%82%D8%AA%D8%B4%D9%87-%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%A7%D8%B2-if-else-%D8%B1%D9%88-%DA%A9%D9%86%D8%A7%D8%B1-%D8%A8%D8%B2%D8%A7%D8%B1%DB%8C-emz70ithcxsq</link>
                <description>شما آموزش‌های بی شماری از دستورات If-Else شاهد بوده‌اید. همچنین احتمالاً شما کتابهای برنامه نویسی را نیز خوانده اید که استفاده از If-Else را به عنوان تکنیک منشعب سازی عملاً ترویج می کنند.شاید حتی استفاده از If-Else حالت پیش فرض ذهنی شما باشد. اما ، بیایید با جایگزینی If-Else با اشیا state به این مساله خاتمه دهیم.توجه داشته باشید که اگر در حال نوشتن کلاسی با متدهایی هستید که نیاز به اجرای آن با توجه به وضعیت فعلی داشته باشید، از این رویکرد استفاده خواهید کرد.شما به راحتی می توانید رفتار اشیا را با استفاده از الگوی state به جای عبارات If-Else تغییر دهید.به کد زیر دقت کنید:منطق انشعاب در بالا حتی خیلی پیچیده نیست. اما سعی کنید شرط جدیدی اضافه کنید تا ببینید که همه چیز منفجر می شود.نرم افزار بهتر بدون (If/Else) : 5 راه برای جایگزینی&quot; بسیار خوب، من متقاعد شده‌ام که If-Else بد است، حالا به من نشان بده که چطور از تقسیم‌بندی درهم و برهم کد اجتناب کنم.&quot;بیایید یک کلاس Booking بسیار ساده ایجاد کنیم که دارای چند حالت است. همچنین دارای دو متد عمومی است: Accept  و Cancel .من حالت های مختلف رزرو بلیط رو به این صورت تصویر کردممنطق Refactoring کد ما یک فرآیند سه‌مرحله‌ای است:ایجاد یک کلاس state انتزاعیهر حالت را به عنوان یک کلاس جداگانه که از کلاس پایه مرحله قبل به ارث می برد پیاده سازی کنیداجازه دهید کلاس رزرو شده یک متد private یا internal داشته باشد که کلاس پایه را به عنوان یک پارامتر در نظر بگیردزمان نمایشاول از همه ، ما به یک کلاس پایه نیاز داریم که همه state ها از آن به ارث می برند.توجه کنید که چگونه این کلاس پایه دارای دو متد Accept و Cancel است - اگرچه در اینجا internal مشخص شده اند.علاوه بر این ، کلاس پایه، یک متد &quot;ویژه&quot; EnterState(Booking booking) دارد. هر زمان که state جدیدی به شی book اختصاص داده شود ، فراخوانی می شود.ثانیا ، ما برای هر state که می خواهیم نمایندگی کنیم کلاسهای جداگانه ای در نظر می گیریم.توجه کنید که چگونه هر کلاس یک state را نشان می‌دهد همانطور که در نمودار زیبای بالا توضیح داده شد. همچنین، CancelledState اجازه انتقال به یک state جدید را نخواهد داد. این کلاس بسیار شبیه به الگوی Null Object است.سرانجام خود کلاس booking به این شکل خواهد بود.ببینید چگونه کلاس booking به سادگی اجرای Accept و Cancel را به state object خود واگذار می کند؟انجام این کار به ما امکان می دهد بسیاری از منطق های شرطی را حذف کنیم و به هر state اجازه می دهیم فقط بر روی آنچه برای خود مهم است تمرکز کند - state فعلی همچنین این امکان را دارد که booking را به state جدید منتقل کند.چگونه با ویژگی های شرطی جدید کنار بیاییم؟اگر ویژگی جدید به طور معمول با استفاده از برخی بررسی های مشروط اجرا می شد ، اکنون می توانید فقط یک کلاس state جدید ایجاد کنید.به همین سادگی. دیگر نیازی به کار با عبارت های نامطلوب if-else نیست.چگونه می توانم state object را در یک پایگاه داده ادامه دهم؟تو این کار رو نمی‌کنی.تنها دانستن state object و چگونگی نگاشت آن به ستون مهم است.شما می‌توانید یک state را با یک نوع ، یک enum یا یک عدد صحیح نگاشت کنید. یا هر چیزی که با آن راحت هستی، تا وقتی که راهی برای تبدیل مقدار ذخیره‌شده به یک  state object داشته باشید.آیا این تعداد کلاس های اضافی، زیاد نیست؟در واقع. همانطور که در مقاله دیگری اشاره کردم ، پیچیدگی از تعداد کلاسهایی که شما تشکیل می دهید ناشی نمی شود ، بلکه از مسئولیتهایی است که کلاسها بر عهده دارند. داشتن کلاسهای بسیار زیاد ، کد شما را قابل خواندن ، نگهداری و به طور کلی کار با آن لذت بیشتری می بخشد.برگرفته شده از مدیوم Nicklas Millard</description>
                <category>Amir Mokarchi</category>
                <author>Amir Mokarchi</author>
                <pubDate>Fri, 23 Apr 2021 19:24:26 +0430</pubDate>
            </item>
                    <item>
                <title>نرم افزار بهتر بدون (If/Else) : 5 راه برای جایگزینی</title>
                <link>https://virgool.io/@mokarchi/%D9%86%D8%B1%D9%85-%D8%A7%D9%81%D8%B2%D8%A7%D8%B1-%D8%A8%D9%87%D8%AA%D8%B1-%D8%A8%D8%AF%D9%88%D9%86-ifelse-5-%D8%B1%D8%A7%D9%87-%D8%A8%D8%B1%D8%A7%DB%8C-%D8%AC%D8%A7%DB%8C%DA%AF%D8%B2%DB%8C%D9%86%DB%8C-wnrcbljt3tii</link>
                <description>استفاده از if/else در اغلب اوقات منجر به طراحی پیچیده می شود و در نهایت کدی خواهیم داشت که خوانایی کمتری دارد.با این وجود، if/else به عنوان یک راه‌حل بالفعل برای تقسیم‌بندی و انشعاب کدها تبدیل شده‌است. که این مساله منطقی به نظر می‌رسد. این یکی از اولین چیزهایی است که به هر یک از توسعه دهندگان مشتاق آموزش داده می‌شود. متاسفانه، بسیاری از توسعه دهندگان هرگز به استراتژی‌های مدیریتی مناسب‌تری پیشرفت نمی‌کنند.برخی با این شعار زندگی می‌کنند: if/else یک چکش است و همه چیز میخ است.ناتوانی در تعیین زمان استفاده از یک رویکرد مناسب‌تر، از جمله آن‌ مواردی است که نیروی تازه کار (Junior) را از نیروی متخصص (Senior) متمایز می‌سازد.من برخی از تکنیک ها و الگوها را به شما نشان می دهم که به این عمل هولناک پایان می دهد.1-بلوک های کاملاً غیر ضروریمثال زیر یک تصویر برجسته از آنچه اتفاق می افتد را نمایش میدهد هنگامی که شما درمانده هستید و فکر می کنید If-Else عالی است.Simple if-elseفقط با حذف بلوک else می توان آن را ساده کرد.Removed elseحرفه ای تری شد ، درست است؟به طور مرتب متوجه خواهید شد که هیچ نیازی به یک بلوک دیگر وجود ندارد. مانند این مورد، شما می‌خواهید کاری انجام دهید که اگر یک شرط خاص برای شما برآورده شود فورا return شود.2-تخصیص ارزشاگر می خواهید براساس برخی ورودی های ارائه شده مقدار جدیدی به یک متغیر اختصاص دهید ، مزخرفات If-Else را متوقف کنید - رویکرد قابل خواندن تری وجود دارد.Value assignment with if-elseبا وجود سادگی ، افتضاح است. در ابتدا ، If-Else به راحتی با یک سوئیچ در اینجا جایگزین می شود. اما ، ما می توانیم با حذف Else-if و موارد دیگر این کد را حتی بیشتر ساده کنیم.If statements with fast returnاگر else if و else را بردارید کدی تمیز و قابل خواندن برای ما باقی مانده است. توجه داشته باشید که من همچنین سبک را تغییر داده ام.3-بررسی پیش شرطاغلب، من متوجه‌شده‌ام که اجرای یک متد در صورتی که با مقادیر نامعتبر فراهم شده‌باشد، منطقی نخواهد بود.فرض کنید که ما متد DetermineGender را از قبل داریم، با این شرط که مقدار ورودی ارایه‌شده باید همیشه ۰ یا ۱ باشد.Method without value checksاجرای متد بدون اعتبار سنجی معنی ندارد. بنابراین ، قبل از اینکه اجازه دهیم متد به اجرای خود ادامه دهد ، باید برخی پیش شرط ها را بررسی کنیم.با استفاده از تکنیک guard clause defensive coding مقادیر ورودی متد را بررسی خواهید کرد و تنها در صورتی پیش خواهید رفت که این متد را اجرا کنید.Check preconditions with guard clausesدر این مرحله ، ما اطمینان حاصل کرده ایم که منطق اصلی تنها در صورتی اجرا می شود که مقدار در محدوده مورد انتظار قرار گیرد.هم اکنون IF ها با ternary operator جایگزین شده اند بنابراین دیگر منطقی نیست که در پایان پیش فرض &quot;Unknown&quot; وجود داشته باشد.4-تبدیل If-Else به Dictionary - به طور کامل از If-Else خودداری کنیدفرض کنید به شما بگویند که باید عملیاتی را انجام دهید که براساس برخی شرایط تصمیم گیری های متناسب دارد، و ما می‌دانیم که بعدا و  در آینده باید عملیات بیشتری را به این موارد اضافه کنیم.شاید یکی تمایل به استفاده از If-Else داشته باشد. و درست هم هست که اضافه کردن شرط جدید به این شروط کار راحتی است. با این حال این روش از نظر نگهداری طراحی خوبی نیست.با دانستن اینکه بعداً باید عملیات جدید اضافه کنیم ، می توانیم If-Else را به یک dictionary تبدیل کنیم.خوانایی بسیار افزایش یافته است و استدلال در مورد این کد آسان تر است.توجه داشته باشید که ، dictionary  فقط در داخل متد برای اهداف نمایشی قرار داده شده است.5-گسترش برنامه ها - از If-Else کاملاً خودداری کنیداین یک مثال کمی پیشرفته تر است.اغلب، شما خودتان خواهید دید که باید بخشی از یک برنامه را گسترش دهید. به عنوان یک توسعه دهنده تازه‌کار، ممکن است تمایل داشته باشید این کار را فقط با اضافه کردن یک عبارت اضافی If-Else انجام دهید.بیاید با یک مثال گویا جلو برویم. در اینجا ، ما باید یک نمونه Order را به عنوان یک رشته ارائه دهیم. اول ، ما فقط دو نوع نمایش رشته داریم ، JSON و متن ساده. استفاده از If-Else در این مرحله مسئله چندان مهمی نیست ، بنابراین ما می توانیم به راحتی جای دیگری را جایگزین کنیم.با علم به اینکه ما باید این قسمت از برنامه را گسترش دهیم ، این روش قطعاً قابل قبول نیست.کد بالا نه تنها اصل Open / Closed را نقض می کند ، بلکه بخوبی خوانده نمی شود و باعث سردردهای دائمی نگهداری می شود.رویکرد صحیح روشی است که به اصول SOLID پایبند باشد - و ما این کار را با اجرای یک فرآیند dynamic type discovery، و در این مورد، الگوی استراتژی انجام می‌دهیم.روند refactor  این قطعه به شرح زیر است:استخراج هر شاخه یا انشعاب به کلاس های استراتژی جداگانه با یک اینترفیس مشترکبدست آوردن تمامی کلاس هایی که این اینترفیس ها را پیاده سازی می کند.تصمیم بگیرید که کدام استراتژی را براساس ورودی اجرا کنیدکدی که جایگزین مثال بالا می شود به این شکل است. و بله ، این کد بیشتر است.من فقط قسمت دقیقی را نشان می دهم که جایگزین مثال If-Else خواهد شد.اگر علاقه مند به نحوه کامل این پیاده سازی هستید به این لینک رجوع کنید.برگرفته شده از مدیوم Nicklas Millard</description>
                <category>Amir Mokarchi</category>
                <author>Amir Mokarchi</author>
                <pubDate>Mon, 19 Apr 2021 23:03:21 +0430</pubDate>
            </item>
                    <item>
                <title>ایجاد کد با قابلیت پیکربندی مجدد در سه مرحله ساده</title>
                <link>https://virgool.io/@mokarchi/%D8%A7%DB%8C%D8%AC%D8%A7%D8%AF-%DA%A9%D8%AF-%D8%A8%D8%A7-%D9%82%D8%A7%D8%A8%D9%84%DB%8C%D8%AA-%D9%BE%DB%8C%DA%A9%D8%B1%D8%A8%D9%86%D8%AF%DB%8C-%D9%85%D8%AC%D8%AF%D8%AF-%D8%AF%D8%B1-%D8%B3%D9%87-%D9%85%D8%B1%D8%AD%D9%84%D9%87-%D8%B3%D8%A7%D8%AF%D9%87-cl9otnfc5mzg</link>
                <description>صادقانه، نوشتن کلاسهای عالی که قابل پیکربندی مجدد هم باشند خیلی دشوار و سخت نیست. اما اگر در کد نویسی به روش‌های خاصی عادت کردین، ممکنه که اینطور نباشه.بهترین راه برای تبدیل یک کلاس موجود به یک کلاس قابل تنظیم، اینه که ابتدا منطق رو به کلاسهای جداگانه منتقل کنیم و سپس قسمت Hardcode شده برنامه رو به سازنده یا آرگومان های متد منتقل کنیم.در این مقاله از GitHub Gist استفاده شده است و لود شدن قسمت مربوط به کد ها ممکن است کمی زمانبر باشدقبل از اینکه وارد کار بشیم و یه نمونه انجام بدیم بیاید ببینیم درباره چی داریم صحبت میکنیم.چه چیزی در مورد یک کلاس قابل پیکربندی عالی است؟قبل از اینکه وقت خودتون رو صرف refactoring کلاس موجود به کلاس قابل پیکربندی بکنید لازمه که بدونید با این کار چه چیزی بدست میارید.استفاده از کلاسی که قابلیت پیکربندی داشته باشه خیلی آسونه و قابل توسعه است.به شکل احمقانه ای ساده است. و بزرگترین نقطه عطف اون اینه که قابل تست هم هست.در اینجا خلاصه ای از کلاس هایی که با آنها سرو کار داریم ، آورده شده است.شما یک کلاس OrderProcessor با یک متد ProcessOrder دارید.بعد، یک کلاس پایه Order و سه زیر کلاسVirtualOrder ، ServiceOrder ، ShippingOrder وجود دارد.درک کلاس Order کاملا غیر ضروری است. با فکر کردن در مورد نحوه اجرای اون منحرف نشید. فقط همین اندازه بدونید که دو تا properties به نام های Name و Price دارد. https://gist.github.com/mokarchi/d0bfa2621393b574fab613155a352f9d زمان اجرای اون یک دقیقه طول کشید. کار هم می‌کنه. مسلما تو خوشحالی. مدیرت هم خوشحاله. مشتری شما  هم خوشحاله.چی از این بهتر!اما این خیلی داغونه.این به نظرم میتونه یک Switch باشه. اگر این اولین فکر شماست، شما بر جنبه های کاملاً بی ربط توسعه نرم افزار تمرکز کردید.بذار بهت نشون بدم چطور اینو بهترش کنیبهتر البته یک مفهوم ذهنی است. اگر مطمئن باشید (که نیستید) این کلاس هرگز تغییر نخواهد کرد (که تغییر خواهد کرد) ، این ممکن است یک پیاده سازی عالی باشد (که اینگونه نیست).من و شما در حال بازسازی این آشفتگی به یک کلاس منطقی و قابل تنظیم هستیم. بدون هیچ گونه تلاش زیادی.ما این کلاس رو با با این سه ویژگی بهترش میکنیم.خوانایی (Readability):خوانایی متد های این کلاس به طرز وحشتناکی است.نگهداشت پذیری (Maintainability): اگر نیاز دارید که بخش &quot;ServiceOrder&quot; را اصلاح کنید، این کار را در جایی انجام خواهید داد که توسط کد غیر مرتبط احاطه شده‌است. همچنین، اگر برنامه نویسان دیگر روی همان کلاس مشغول به کار باشند، احتمالا با اختلافات ادغام مواجه می شوید.انعطاف پذیری (Flexibility): سفارش جدیدی اضافه می شود؟ اگر نیاز دارید ، باید چیز دیگری اضافه کنید. من مطمئن هستم که شما قبلاً می دانید که این کار بد و نقض آشکار Open / Closed است.۱ - بهبود خواناییمعمولا چند تکرار برای refactor یک کلاس شلوغ و نامرتب طول می‌کشد. اول، ما در حال بهبود خوانایی هستیم. اگر غیرقابل خواندن باشد، دستیابی به یک کلاس بسیار خوب و انعطاف‌پذیر دشوار است.خلاص شدن از شر if-else اولین قدم عالی است. https://gist.github.com/mokarchi/bef0edf70fcad4c76c86f54218628592 خواندن متد ProcessOrder بسیار ساده تر شده است و اکنون فقط یک کار واحد انجام می دهد.ما if-else نامطبوع را گرفته و آن را با یک dictionary جایگزین کرده ایم. همچنین اگر نوع سفارش جدیدی ارائه شود ، نیازی نیست که آن را به صورت دستی در دو مکان اضافه کنیم.2 ایجاد کلاسهای جداگانه قابلیت نگهداری را بهبود می بخشدما به راحتی می توانیم در این نقطه متوقف شویم. شما قبلاً کلاس را خیلی ساده تر کرده اید. اما هنوز دقیقاً به &quot;ساده احمقانه&quot; نرسیده اید. این هدف نهایی ما است.در حال حاضر، کلاس ما هنوز درباره نحوه پردازش هر نوع آگاهی دارد.در این حالت ، دستیابی به قابلیت نگهداری عبارت است از تجزیه مجدد پیاده سازی های عملکرد خارج از کلاس پردازنده و در کلاس های خود. https://gist.github.com/mokarchi/4edc512b090c62fba7da3e33e6dd91df این بازسازی مجدد فوق العاده ساده به ما امکان می دهد تا هر پردازش را به صورت دقیق انجام دهیم. دیگر نیازی نیست که کل OrderProcessor را &quot;new&quot; کنیم تا ببینیم مثلاً یک سفارش به درستی پردازش می شود. https://gist.github.com/mokarchi/70f84c19a70b9976172b5f826f97c4a5 ۳ یک refactoring نهایی برای حداکثر انعطاف‌پذیریمطمئناً ، آزمایش واحد در این مرحله آسان است. اما هنوز لازم است که سه بار متد ProcessOrder را امتحان کنید ، فقط مطمئن شوید که به درستی کار می کند. برای هر نوع سفارش جدید، باید همان متد را با یک مورد دیگر تست کنید. این مطمئنا یک code smell است.آخرین refactoring شما قصد دارد که این کلاس processor را به طرز شگفت آوری ساده کند. شما به سادگی این dictionary را به یک وابستگی صریح تبدیل می‌کنید. https://gist.github.com/mokarchi/1b57845d88797132d54b6da9e2b36a6a خیلی سبک خیلی ساده. بسیار ساده برای تست. هنگامی که کد شما به طور ناگهانی ساده احمقانه می شود ، می دانید که به سطح انتزاع درستی رسیده اید. این یکی از آن مواقع است. تبریک می گویماما، باز هم برای اندازه‌گیری خوب، من یک آزمایش ساده انجام دادم. ۱ میلیون تکرار در کلاس non-refactored - نسبت به کلاس انعطاف‌پذیر، فراخوانی متد سفارش فرآیند برای هر نوع سفارش.خودت تصمیم بگیر که اون شماره‌ها چقدر وحشتناکهمنبع : Nicklas Millard </description>
                <category>Amir Mokarchi</category>
                <author>Amir Mokarchi</author>
                <pubDate>Tue, 13 Apr 2021 16:52:08 +0430</pubDate>
            </item>
                    <item>
                <title>چگونگی طراحی یک برنامه وب: معماری نرم‌افزار</title>
                <link>https://virgool.io/coderlife/%DA%86%DA%AF%D9%88%D9%86%DA%AF%DB%8C-%D8%B7%D8%B1%D8%A7%D8%AD%DB%8C-%DB%8C%DA%A9-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87-%D9%88%D8%A8-%D9%85%D8%B9%D9%85%D8%A7%D8%B1%DB%8C-%D9%86%D8%B1%D9%85-%D8%A7%D9%81%D8%B2%D8%A7%D8%B1-gxfspvtypgup</link>
                <description>در این پست به بررسی این موارد خواهیم پرداخت:معماری نرم‌افزار چیست؟چرا معماری نرم‌افزار مهم است؟تفاوت بین معماری نرم‌افزار و طراحی نرم‌افزارالگوهای معماری نرم‌افزارنحوه تصمیم‌گیری در مورد تعداد سطح هایی(tier) که برنامه شما باید داشته باشدمقیاس بندی افقی یا عمودی … کدامیک برای برنامه من مناسب است؟کدامیک Monolith یا Microservice؟چه زمانی باید از NoSQL و یا SQL استفاده کنید؟چگونگی تبدیل شدن به یک معمار نرم‌افزارمعماری نرم افزار چیست؟معماری نرم‌افزار در واقع انتخاب یک ساختار کلی برای پیاده‌سازی یک پروژه  نرم‌افزاری بر مبنای مجموعه‌ای از نیازهای کاربری و تجاری یک سیستم  نرم‌افزاری است تا هم بتوان کاربردهای مورد نظر را پیاده‌سازی کرد و هم  بتوان کیفیت نرم‌افزار، تولید آن و نگهداری آن را نیز بهینه کرد و سرعت  بخشید.معماری نرم‌افزار، اجزای اصلی، روابط آن‌ها و نحوه تعامل آن‌ها با یکدیگر را در یک سیستم توصیف می‌کند. اساسا به عنوان یک طرح کلی(blueprint) عمل می‌کند. این روش یک انتزاع برای مدیریت پیچیدگی سیستم(complexity) و ایجاد ارتباط(communication) و هماهنگی(coordination) میان اجزا(components) فراهم می‌کند.به عبارتی دیگر: معماری نرم‌افزار یک برنامه یا سیستم محاسباتی، ساختار یا ساختارهای آن  سیستم محاسباتی است که خصوصیات قابل رویت از بیرون، عناصر و ارتباطات بین  آن‌ها را نشان می‌دهد.در اینجا چند نکته کلیدی وجود دارد:معماری به تعریف راه‌حلی برای برآورده کردن تمام الزامات فنی و اجرایی، با هدف مشترک بهینه‌سازی عملکرد و امنیت کمک می‌کند.طراحی معماری شامل تقاطع نیازهای سازمان و همچنین نیازهای تیم توسعه است. هر تصمیم می تواند تأثیر قابل توجهی بر کیفیت(quality) ، قابلیت نگهداری(maintainability) ، عملکرد(performance) و غیره داشته باشد.تعریف Ralph Johnson نویسنده کتاب Design Patterns: Elements of Reusable Object-Oriented Software از معماری نرم افزار:این تصمیماتی است که شما می‌خواهید و آرزو میکنید در ابتدا در یک پروژه به دست آورید.چرا معماری نرم‌افزار مهم است؟عنصر کلیدی در ایجاد موفقیت در ایجاد هر چیزی درست ساختن پایه است. حالا خواه که ساختن یک ساختمان یا ساخت پیتزا باشد. اگر پایه را درست دریافت نکنیم، باید از ابتدا شروع کنیم؛ هیچ راه دیگری برای این کار وجود ندارد.ساخت یک برنامه وب متفاوت نیست. معماری پایه و اساس آن است و باید دقیقا مورد بررسی قرار گرفته شود تا از تغییرات عمده در طراحی و تغییر شکل کد(code refactoring) در زمان بعدی اجتناب شود. بنابراین ، قبل از اینکه حتی کد را لمس کنیم و دستمان را کثیف کنیم ، باید معماری اساسی را درست کنیم.اگر چه توسعه نرم‌افزار یک فرآیند تکراری و تکاملی است، اما ما همیشه در ابتدا همه چیز را کامل نمی‌کنیم. با این حال، این نمی‌تواند بهانه‌ای برای انجام ندادن تکالیف ما باشد.تفاوت بین معماری نرم‌افزار و طراحی نرم‌افزاراغلب بین طراحی نرم افزار و معماری سردرگمی وجود دارد ، بنابراین ما این مورد را برطرف خواهیم کرد.از معماری نرم افزار برای تعریف اسکلت و اجزای سطح بالای یک سیستم و نحوه کار همه آنها با هم استفاده می شود. به عنوان مثال ، آیا شما به معماری serverless نیاز دارید که برنامه را به دو جز BaaS و FaaS  تقسیم کند؟ یا آیا شما به چیزی مانند معماری microservice نیاز دارید که در آن ویژگی ها / وظایف مختلف به واحدهای مربوطه مجزا تقسیم می شوند؟انتخاب یک معماری نحوه برخورد شما با عملکرد(performance)، تحمل خطا(fault tolerance) ، مقیاس پذیری(scalability) و قابلیت اطمینان(reliability) را مشخص می‌کند.الگوهای معماری نرم‌افزارالگوی Client-serverاین معماری یک مدل request-response  را ارائه می کند. مشتری درخواست را برای اطلاعات به سرور ارسال می کند و سرور با آن پاسخ می دهد.کامپوننت سرور برای چند مؤلفۀ کلاینت سرویسی را ارائه می‌دهد؛ کلاینت‌ها هم  می‌توانند برای دستیابی به سرویس مد نظر خود، ریکوئستی را به سرور ارسال  کنند که سرور نیز در پاسخ به این ریکوئست، سرویس درخواستی را برای آن  کلاینت‌ها فراهم می‌کند. علاوه بر این، سرور همواره در آمادگی کامل برای  دریافت ریکوئست از سمت کلاینت و ارائۀ سرویس به آن‌ها است.هر وب سایتی که شما مرور می‌کنید، یک وبلاگ wordpress یا یک برنامه وب مانند Facebook، Twitter یا برنامه بانکداری شخصی شما در معماری Client-server ساخته شده‌است. الگوی Peer-to-Peerشبکه P2P شبکه ای است که در آن رایانه هایی که به آنها گره نیز می گویند می توانند بدون نیاز به سرور مرکزی با یکدیگر ارتباط برقرار کنند. فقدان سرور مرکزی احتمال خرابی یک نقطه را منتفی می داند. تمام رایانه های موجود در شبکه از حقوق برابر برخوردارند. یک گره به طور همزمان به عنوان seeder و leecher بازی می کند. بنابراین ، حتی اگر بعضی از رایانه ها / گره ها خراب شوند ، شبکه و ارتباطات همچنان برقرار است.شبکه P2P پایه فناوری بلاکچین است.الگوی Model-View-Controller (MVC)معماری MVC یک الگوی معماری نرم‌افزاری است که در آنمعماری اپلیکیشن را به سه مولفه براساس کارکرد تقسیم میکند. این مولفه‌ها عبارتند از: Models - نشان می‌دهند که چگونه داده‌ها در پایگاه‌داده ذخیره می‌شوند. View- اجزایی که برای کاربر قابل‌رویت هستند، مانند خروجی یا کنترل‌کننده‌های واسط گرافیکی. Controller- اجزایی که به عنوان یک رابط بین Models و Views عمل می‌کنند.از معماری MVC نه تنها برای برنامه های دسکتاپ بلکه برای برنامه های موبایل و وب نیز استفاده می شود.Microservicesدر معماری microservice، ویژگی‌ها / وظایف مختلف به ماژول های مربوطه مجزا تقسیم می‌شوند که در ارتباط با یکدیگر کار می کنند و تشکیل یک سرویس بزرگ به عنوان یک کل را می دهند.الگوی Event drivenمعماری Non-blocking به عنوان معماری Reactive یا Event-based نیز شناخته می شود. معماری های مبتنی بر رویداد در توسعه برنامه های وب مدرن بسیار محبوب هستند.آنها قادر به مدیریت تعداد زیادی از اتصالات همزمان با حداقل مصرف منابع هستند. برنامه های مدرن برای مقیاس گذاری به یک مدل کاملاً ناهمزمان نیاز دارند. این چارچوب های مدرن وب رفتار قابل اعتماد تری را در یک محیط توزیع شده ارائه می دهند.الگوی Layeredاین الگو را می توان برای ساخت برنامه‌هایی بکار برد که می‌توانند به گروه‌هایی از وظایف فرعی تجزیه شوند، که هر کدام در یک سطح خاص از انتزاع قرار دارند. هر لایه خدمات را به لایه بالاتر بعدی ارایه می‌دهد.اینها رایج‌ترین لایه‌ها هستند:لایه Presentation لایه Application لایه Business logic لایه Data access الگوی Hexagonalالگوی Hexagonal در واقع یک روش تصور  شده برای توصیف هسته‌ی یک اپلیکیشن است که توسط دامین آبجکت‌ها،  usecase هایی که آن‌ها را عملیاتی می‌کنند و پورت‌های ‌input و output که یک  رابط برای دستیابی به دنیای بیرون می‌باشند، است.این معماری از سه جز زیر تشکیل شده است:ساختن Portsساختن لایه Adaptersساختن یک Domain Objectنحوه تصمیم‌گیری در مورد تعداد سطح هایی(tier) که برنامه شما باید داشته باشداپلیکیشن های Single tier مزایا:تاخیر در شبکه وجود نداردداده‌ها به سرعت و به راحتی در دسترس هستندمعایب:کنترل کمی بر روی برنامه وجود دارد؛ پیاده سازی ویژگی های جدید یا تغییرات کد پس از ارسال سخت است.تست باید بسیار دقیق و با کمترین جای اشتباه باشد.برنامه های تک لایه در برابر اصلاح یا مهندسی معکوس آسیب پذیر هستند.اپلیکیشن های  Two-tier مزایا:فراخوانی شبکه کم‌تر از زمانی است که کد و رابط کاربر در همان ماشین هستندسرور پایگاه‌داده و منطق تجاری از نظر فیزیکی نزدیک هستند، که عملکرد بالاتری را ارایه می‌دهد.معایب:از آنجا که مشتری بیشتر منطق برنامه را در اختیار دارد ، در کنترل نسخه نرم افزار و توزیع مجدد نسخه های جدید مشکلاتی بوجود می آید.فاقد مقیاس پذیری است زیرا فقط تعداد محدودی از کاربران را پشتیبانی می کند. هنگامی که چندین درخواست مشتری افزایش می یابد ، عملکرد برنامه می تواند کاهش یابد ، زیرا مشتری برای ادامه کار نیاز به اتصالات جداگانه و حافظه CPU دارد.از آنجا که منطق برنامه با مشتری همراه است ، استفاده مجدد از منطق دشوار است.اپلیکیشن های Three-tierمزایا:خرابی داده ها از طریق برنامه های مشتری می تواند برطرف شود زیرا داده های ارائه شده در سطح میانی برای بروزرسانی پایگاه داده ، اعتبار آن را تضمین می کندقرار دادن منطق کسب و کار در یک سرور متمرکز باعث امنیت بیشتر داده ها می شود.با توجه به استقرار توزیع شده سرورهای برنامه ، مقیاس پذیری سیستم افزایش می یابد زیرا اتصال جداگانه ای از هر سرویس گیرنده مورد نیاز نیست در حالی که اتصالات از چند سرور برنامه کافی است.معایب:معمولاً هنگام ایجاد برنامه های three-tier باید تلاش بیشتری انجام شود زیرا نقاط ارتباطی افزایش می یابد.اپلیکیشن های N-Tierمزایا:تمام مزایا و معایب معماری three-tierعملکرد به دلیل حذف بار از database tier و client tier افزایش می‌یابد، که آن را قادر می‌سازد تا متناسب با صنایع متوسط تا حجیم باشد.معایب:به دلیل پیچیدگی tier ، پیاده‌سازی یا حفظ ساختار پیچیده مشکل است.نتیجه‌گیریهنگامی که تأخیری در شبکه ندارید ، باید یک معماری تک tier انتخاب کنیدهنگامی که نیاز دارید تاخیر شبکه را به حداقل برسانید و به کنترل بیشتری بر داده ها در برنامه خود نیاز دارید ، یک برنامه two tier را انتخاب کنیدهنگامی که به کنترل کد / منطق تجاری برنامه خود نیاز دارید و می خواهید از امنیت برخوردار باشد ، باید معماری three tier را انتخاب کنید.هنگامی که به برنامه خود برای مقیاس بندی و مدیریت مقادیر زیادی از داده ها نیاز دارید ، باید یک معماری  N tier انتخاب کنید.مقیاس بندی افقی یا عمودی … کدامیک برای برنامه من مناسب است؟اگر برنامه شما یک برنامه یا ابزار است که انتظار می‌رود حداقل ترافیک هماهنگ را دریافت کند، ممکن است برای ماموریت مهم نباشد. به عنوان مثال ، یک ابزار داخلی یک سازمان یا چیزی مشابه آن. مقیاس گذاری عمودی با بهبود کارایی هر یک از تراکنش ها انجام می شود، بنابراین می توانید مقیاس گذاری عمودی را انجام دهید وقتی می دانید بار ترافیک به طور قابل توجهی افزایش نمی یابد.مقیاس گذاری عمودی مستلزم گسترش شبکه با اضافه کردن توان و حافظه ی بیشتر به واحد پردازش هسته ای سیستم استاگر برنامه شما یک برنامه اجتماعی عمومی مانند شبکه اجتماعی ، برنامه تناسب اندام یا موارد مشابه است ، انتظار می رود که در آینده نزدیک میزان بازدید به طور چشمگیری افزایش یابد. در این حالت هم قابلیت دسترسی بالا و هم مقیاس پذیری افقی برای شما مهم است.مقیاس پذیری افقی شامل اضافه کردن گره های بیشتر (یعنی دستگاه ها) به چارچوب یک سیستم موجود است.هنگام پرداختن به موضوع قابلیت مقیاس پذیری ، مهم است که درک کنیم وقتی  کسی به دنبال افزایش ظرفیت معاملات یک پلتفرم خاص است ، معمولاً از این  مفهوم استفاده می شود.کدام گزینه Monolith or Microserviceبیایید بررسی کنیم که چه زمانی باید یکی از آن‌ها را انتخاب کنیدچه موقع باید از معماری Monolithic استفاده کردبرنامه های Monolithic در مواردی که نیازها کاملاً ساده است ، مناسب است و انتظار می رود این برنامه میزان محدودی از ترافیک را کنترل کند. یک نمونه از این موارد ، یک برنامه محاسبه مالیات داخلی یک سازمان است.اینها مواردی هستند که در آن کسب‌وکار اطمینان دارد که رشد نمایی در پایه کاربر و ترافیک در طول زمان وجود نخواهد داشت.همچنین مواردی وجود دارند که در آن تیم‌های توسعه دهنده تصمیم می‌گیرند با یک معماری Monolithic شروع کنند و بعد از آن به یک معماری Microservices توزیعی تبدیل شوند.این امر به آنها کمک می کند مرحله به مرحله با پیچیدگی برنامه کنار بیایند. این دقیقاً همان کاری است که LinkedIn انجام داد.فواید Monolithنگرانی کمتر در رابطه با قطعی‌ها: بیشتر اپلیکیشن‌ها دارای تعدادی  قطعی‌ها و قسمت‌های متفاوت از یکدیگر هستند. به عنوان مثال عملیات وارد  شدن، ویژگی‌های امنیتی، محافظت‌ها و... . یکی از بزرگ‌ترین مزیت‌های این  معماری آن است که به دلیل وجود تمام این نکات در یک اپلیکیشن، مشاهده کردن  اختلالات در این زمینه‌ها بسیار ساده‌تر خواهد بود.وجود عملیات‌های کمتر: داشتن یک اپلیکیشن بزرگ بدان معناست که تنها یک  اپلیکیشن برای تست کردن، نظارت و وارد شدن وجود دارد. به همین دلیل  عملیات‌های کمتری انجام می‌شود. نگه‌داری از این سیستم‌ها پیچیده‌گی کمتری  نیز دارد.کارایی: از آنجایی که دسترسی به حافظه اشتراکی سریع‌تر از ارتباطات  داخل پردازش سریع‌تر است، بنابراین کارایی در این معماری نیز بیشتر است.معایب Monolithمحکم به هم بسته بودن: در این سیستم معماری همه چیز به شدت با همدیگر  ارتباط دارند و به همین دلیل جدا کردن آن‌ها کار سختی است. بنابراین وقتی  بخواهید قسمتی را به صورت مستقل توسعه و یا نگه‌داری کنید کار سختی است.درک سخت‌تر: معماری Monolithic درک‌پذیری سخت‌تری دارد، به این دلیل  که وقتی مشکلی اتفاق می‌افتد ممکن است پیدا کردن آن در یک قسمت سخت باشد.چه موقع باید از معماری Microservice استفاده کردمعماری Microservice برای موارد استفاده پیچیده مناسب است و برای برنامه‌هایی که انتظار می‌رود ترافیک در آینده به صورت نمایی افزایش یابد مانند یک برنامه کاربردی شبکه اجتماعی مناسب است.یک شبکه اجتماعی معمولی دارای  اجزای مختلفی مثل پیام گذاری، real-time chat، پخش ویدیویی زنده، بارگذاری تصویر، Like و ... را است.در این سناریو، پیشنهاد می‌کنم که هر بخش را به طور جداگانه در نظر بگیریم که Single Responsibility و جداسازی قابلیت ها یا رفتارها(Separation of Concerns principle) را در ذهن داشته باشیم.واقعیت این است که در مهندسی نرم‌افزار هیچ راه حل طلایی‌ای وجود ندارد!  میکروسرویس‌ها به صورت جادویی تمام مشکلات scaling را حل نمی‌کنند و حتی  بعضی وقت‌ها مشکلات جدیدی را هم به وجود می‌آورندفواید Microservicesسازمان‌دهی بهتر: معماری میکروسرویس‌ها معمولا بهتر دسته‌بندی و  سازمان‌دهی می‌شوند. این بدان دلیل است که هر میکروسرویس یک کار منحصر به  فرد را انجام می‌دهد و کاری به دیگر اجزا ندارد.جداسازی شده: سرویس‌های از هم جداشده برای برآورده کردن نیازهای مربوط  به اپلیکیشن‌های دیگر قابلیت تغییر و پیکربندی مجدد ساده‌تری را ارائه  می‌دهند. آن‌ها همچنین در یک سیستم یکپارچه بزرگ‌تر قابلیت تحویل قسمت‌های  منحصر به فرد را به صورت سریع‌تری ارائه می‌دهند.کارایی: بسته به موقعیت درست میکروسرویس‌ها همچنین می‌توانند مزیت‌های  خوبی را در زمینه کارایی ارائه دهند. برای مثال وقتی قرار است از یک قسمت  منحصر به فرد باری دیگر در اپلیکیشن استفاده کرد، جدا کردن آن قسمت از دیگر  اجزا کار ساده‌ای خواهد بود.اشتباهات کمتر: میکروسرویس‌ها به شما قابلیت توسعه موازی را می‌دهند. به همین دلیل احتمال انجام اشتباهات در این حالت کمتر می‌شود.معایب Microservicesنگرانی قطع شدن در ارتباط با هر سرویس: همانطور که شما یک معماری  میکروسرویس جدید را ایجاد می‌کنید، ممکن است با قطع‌ شدن‌های مختلفی مواجه  شوید که در زمان طراحی سیستم با آن‌ها برخورد نکرده‌اید. شما یا مجبور  هستید که تمام این موارد را دوباره بررسی کنید و یا اینکه می‌توانید در یک  لایه دیگر از سرویس‌ها با آن‌ها تعامل داشته باشید.انجام عملیات‌های بیشتر: میکروسرویس‌ها به صورت مکرر روی ماشین مجازی  یا کانتینر خودشان اجرا می‌شوند. به همین دلیل میزان بیشتری را اشغال کرده و  نیاز به کارهای بیشتری برای انجام دادن هستند. این وظایف معمولا توسط یک  ابزار مدیریت خودکارسازی می‌شوند.چه زمانی باید از NoSQL و یا SQL استفاده کنید؟چه موقع می توان پایگاه داده SQL را انتخاب کرد؟اگر در حال نوشتن معاملات سهام ، بانکداری یا برنامه ای مبتنی بر امور مالی هستید یا باید روابط زیادی را ذخیره کنید ، به عنوان مثال ، هنگام نوشتن یک برنامه شبکه های اجتماعی مانند فیس بوک ، باید یک پایگاه داده رابطه ای انتخاب کنید. به همین دلیل است:Transactions &amp; Data Consistencyاگر در حال نوشتن نرم افزاری هستید که ارتباطی با پول یا شماره دارد ، باعث می شود تراکنش ها و سازگاری داده ها برای شما بسیار مهم باشد. DB های رابطه ای وقتی صحبت از سازگاری داده ها و داده ها می شود ، می درخشند. آنها مطابق با قانون ACID هستند ، از دیرباز وجود داشته و مورد آزمایش قرار گرفته اند.همه دیتابیس‌های SQL، خواص ACID را دارا هستند. ACID مخففی  برای (Atomicity, Consistency, Isolation, Durability) است که در زیر  هرکدام را مختصراً توضیح می‌دهیم:تجزیه ناپذیری Atomicity: این ویژگی تضمین می‌کند  که با هر تراکنش، چه با شکست روبه‌رو شود و چه موفق باشد،‌ به‌عنوان یک  واحد تکی و غیرقابل تقسیم رفتار می‌شود. از این رو هیچ حالت میانه‌ای وجود  ندارد.استحکام Consistency: اطمینان حاصل می‌کند  که هر تراکنش، دیتابیس را از یک حالت معتبر به حالت معتبر دیگر می‌برد. به  عبارت بهتر هر داده‌ی افزوده شده به دیتابیس باید از قوانین تعریف شده  پیروی کند.ایزوله سازی Isolation: این خاصیت کنترل می‌کند  اجرای همزمان تراکنش‌ها دیتابیس را در حالتی قرار دهد که اگر تراکنش‌ها یکی  یکی انجام می‌شدند، قرار می‌گرفت.پایداری Durability: وقتی یک تراکنش انجام شود، حتی اگر سیستم با شکست رو‌به‌رو شود به روند خود ادامه می‌دهد؛ این وظیفه‌ی خاصیت Durability است.Storing Relationships اگر داده های شما روابط زیادی داشته باشد مانند اینکه کدام یک از دوستان شما در یک شهر خاص زندگی می کنند؟ کدام یک از دوستان شما قبلاً در رستورانی که امروز قصد بازدید از آن را دارید غذا خورده است؟ و غیره هیچ چیز بهتر از یک پایگاه داده رابطه ای برای ذخیره این نوع داده ها نیست.محبوب ترین پایگاه های داده رابطه ای:MySQLMicrosoft SQL ServerPostgreSQLMariaDBچه موقع می توان پایگاه داده NoSQL را انتخاب کرد؟مدیریت تعداد زیادی از عملیات خواندن/نوشتنزمانی که تعداد زیادی از عملیات خوانش در وب سایت شما وجود دارد و زمانی که با مقدار زیادی از داده‌ها سروکار داشته باشد، پایگاه‌های داده NoSQL در این سناریوها بهترین جا هستند. از آنجا که آن‌ها توانایی اضافه کردن گره‌ها را دارند، می‌توانند ترافیک همزمان و مقادیر زیاد داده را با حداقل تاخیر کنترل کنند.اجرای تجزیه و تحلیل داده‌هاپایگاه داده های NoSQL همچنین برای موارد استفاده از تجزیه و تحلیل داده ها ، جایی که ما باید با هجوم مقادیر گسترده ای از داده ها مقابله کنیم ، مناسب ترین است.محبوب ترین پایگاه های داده NoSQL :MongoDBRedisCassandraHBASEچگونگی تبدیل شدن به یک معمار نرم‌افزارممکن است آرزو داشته باشید یک معمار نرم افزار باشید. اما شما از کجا شروع می کنید؟ خوب ، بسیار غیرمعمول است که کسی به عنوان یک معمار نرم افزار شروع به کار کند ، بنابراین بیشتر مهندسان نرم افزار قبل از اینکه طراحی معماری را شروع کنند ، چند سال کار می کنند.یکی از بهترین راه های آشنایی با معماری نرم افزار ، طراحی برنامه های وب خاص خودتان است. این شما را مجبور خواهد کرد که از جنبه های مختلف برنامه خود  از load balancing ، message queueing ، stream processing ، caching و موارد دیگر فکر کنید زمانی که شروع به درک این موضوع می‌کنید. به محض اینکه بفهمید این مفاهیم چگونه در برنامه شما جای می گیرند ، می توانید یک معمار نرم افزار شوید.شما به عنوان یک معمار مشتاق نرم افزار ، باید دائماً دانش خود را گسترش داده و در بالای آخرین روند صنعت باقی بمانید. شما ممکن است با یادگیری یک یا چند زبان برنامه نویسی شروع کنید ، به عنوان یک توسعه دهنده نرم افزار کار کنید و کم کم راه خود را باز کنید.</description>
                <category>Amir Mokarchi</category>
                <author>Amir Mokarchi</author>
                <pubDate>Fri, 19 Mar 2021 10:08:46 +0330</pubDate>
            </item>
                    <item>
                <title>refactor یک برنامه sync به async در ASP.NET - بخش دوم</title>
                <link>https://virgool.io/@mokarchi/refactor-%DB%8C%DA%A9-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87-sync-%D8%A8%D9%87-async-%D8%AF%D8%B1-aspnet-%D8%A8%D8%AE%D8%B4-%D8%AF%D9%88%D9%85-x8izcvtcemft</link>
                <description>در این پست ، فرایند refactoring یک برنامه وب همزمان(synchronous) ASP.NET را به یک برنامه غیر همزمان (asynchronous) شروع می کنیم و نشان می دهیم چه نوع مشکلی ممکن است درانجام این کار بوجود آید.برنامه وب که می خواهیم آنرا refactor کنیم یک برنامه نسبتاً ساده است. این سیستم یک سرویس خارجی را فراخوانی می کند تا داده های برگشتی توسط این سرویس را نمایش دهد.داده هایی که بازگشت داده می شود مربوط به یکی از چهار objects زیر است:Users, Posts, Albums, Photosاگر بخش اول این مطلب رو مطالعه کرده باشید شما می دانید که برای اینکه یک برنامه synchronous را asynchronous کنیم و همه چیز را خراب نکنیم ، به طور کلی می خواهیم از پایین ترین سطح سلسله مراتب داده شروع کنیم که در اینجا مقصود object تصویر می باشد.بنابراین ، بدون هیچ حرف بیشتری ، بیایید شی فوق رو refactor کنیم!Refactoring the PhotoRepository and PhotoControllerکد فوق مربوط است برای PhotoRepository :من می‌خواهم تا آنجا که ممکن است کمترین کار ممکن را انجام دهم، بنابراین بلوک های کد را با استفاده از متد  Task.Run به صورت asynchronous میکنم. من تصمیم گرفتم که فقط این کار را انجام دهم:نکته جالب در مورد این راه حل این است که من حتی نیازی به تغییر اینترفیس  IPhotoRepository نداشتم ، بنابراین کار بسیار کمی انجام شد. و اگر کد را اجرا کنیم ، می بینیم که به طرز شگفت انگیزی ، در واقع کار می کند! Problem #1: Async-Over-Syncآنچه ما انجام داده ایم یک ضد الگویی است که به عنوان async-over-sync شناخته شده استهنگام اجرای این متد:1- یک thread  برای اجرای GetAll فراخوانده می‌شود.2- یک thread کاملا متفاوت برای اجرای محتوای Task.Run فراخوانده می‌شود.3- در این مرحله، thread  اصلی بلاک شده و منتظر میماند  که photoTask.Result نتیجه را بازگرداند.سیستم‌های ما اکنون قادر به رسیدگی به درخواست‌های همزمان کمتری نسبت به یک سیستم synchronous می باشد.بنابراین اکنون این سؤال مطرح می شود: چگونه این مسئله را برطرف کنیم؟ برای پاسخ به آن ، باید دو مشکل را حل کنیم.Finishing the PhotoRepositoryاولین مشکل کلاس WebClient  است. یک جانشین جدید و مناسب تر برای فراخوانی API هایی که ما انجام می دهیم کلاس HttpClient است. من به عنوان مالک پروژه می خواهم کل پروژه خود را از استفاده از WebClient به HttpClient تغییر دهم. با این حال، زمانی که سعی می‌کنم این کار را انجام دهم، فورا به یک مشکل می‌رسم:HttpClient does not expose synchronous methods!مشکل دوم این است که ، همانطور که در بالا دیدیم ، wrap کردن کد synchronous در Task ایده بدی است. بنابراین در حال حاضر من &quot;مجبور&quot; شده ام تا دوباره refactor به سمت برنامه‌نویسی asynchronous انجام دهم.بنابراین در اینجا کاری که می خواهم انجام دهم: من فقط قصد دارم تا Repository را به asynchronous تبدیل(refactor) کنم و نه PhotoController که درسطح بالاترقرار دارد.PhotoRepositoryPhotoControllerبه استفاده از .Result توجه کنید. معنی این امر این است که وقتی کنترلر repository را صدا می کند ، منتظر می ماند تا نتیجه متد  برگردد ، سپس از آن نتیجه استفاده می کند. اما آیا واقعاً این اتفاق می افتد؟ نه. آنچه واقعاً اتفاق می افتد بسیار بدتر است ، و کاملاً واضح نیست.Problem #2: Deadlockبه دلایلی که احتمالاً در حال حاضر مشخص نیست ، کد بالا منجر به deadlock خواهد شد. برای فهمیدن دلیل آن ، ابتدا باید چیزی را بدانیم که در هنگام فراخوان یک asynchronous task در پشت صحنه اتفاق می افتد.هر زمان که یک asynchronous task ایجاد شود ، اگر thread  اجرای آن کار باید منتظر بماند تا اتفاقی بیفتد ، می‌تواند محیط اجرایی را ترک کند و کار دیگری انجام دهداما قبل از این که آن را ترک کند، چیزی به نام SynchronizationContext ایجاد می‌کند، که context پیرامون اجرای task را ذخیره می‌کند و برای از سرگیری اجرای این برنامه در آینده مورد نیاز است.توجه: پاراگراف فوق فقط مربوط به ASP.NET Framework است ، نه ASP.NET Core.می‌دانم که این تصویر خیلی شلوغ و گیج‌کننده است، اما خوشبختانه یک دقیقه طول می‌کشد. برای توضیح دادن که چرا deadlock در حال رخ دادن است:1- اکشن کنترلر Index متد GetAll را از Repository فراخوانی می کند2- GetAll درخواست async برای GetStringAsync را شروع می کند3- GetStringAsync یک task uncompleted را باز می‌گرداند.4- اکنون منتظر نتیجهGetStringAsync  هستیم. Context در این مرحله گرفته می شود و در آینده برای بازگرداندن task استفاده می شود.5- اکنون متد controller به طور همزمان result از GetAll را مسدود می کند که این امر مانع احیای Context  می‌شود.6- از طرفی دیگر ، GetStringAsync پایان می یابد. این کار سبب می شود GetStringAsync  پیام completes را برگشت دهد7- اکنون این task برای اجرا آماده است، اما باید منتظر بماند تا Context در دسترس باشد تا این کار را انجام دهد.8- به دلیل 5 و 7 ، هیچگاه Context فراهم نمی شود ، بنابراین ما DeadLock داریم.به عبارتی، کدهای async منتظر پایان کار Result هستند تا نتیجه را  بازگردانند. در همین لحظه کدهای همزمان برنامه نیز منتظر کدهای async هستند  تا خاتمه یابند. نتیجه‌ی کار یک deadlock است.بنابراین ما در این باره چه کار کنیم؟ شما ممکن است از پست قبلی به خاطر داشته باشید که async تمایل دارد مثل یک ویروس پخش شود. راه‌حل در اینجا این است که اجازه دهید این کار را انجام دهد وکنترلر را refactor کنید تا  از async / await استفاده کند.مخزن سورس پروژه فوق و همچنین مطالب بررسی شده در مقاله فوق در این لینک قابل دسترس می باشد</description>
                <category>Amir Mokarchi</category>
                <author>Amir Mokarchi</author>
                <pubDate>Tue, 01 Sep 2020 11:09:48 +0430</pubDate>
            </item>
            </channel>
</rss>