# الگوی CQRS (تفکیک فرمان و پرس‌وجو)

## 🎯 هدف
CQRS پیشنهاد می‌کند **دستورات (نوشتن)** و **پرس‌وجوها (خواندن)** را از هم جدا کنیم تا هر کدام بهینه و مستقل توسعه یابند. این جداسازی به ما اجازه می‌دهد مدل خواندن را بر اساس نیاز گزارش‌گیری و مدل نوشتن را بر اساس منطق دامنه طراحی کنیم.

## 💻 مثال کد (C#)

```csharp
// فرمان‌ها (Write Model)
public record CreateOrderCommand(Guid Id, string Customer);

public interface ICommandHandler<TCommand>
{
    Task Handle(TCommand command);
}

public class CreateOrderHandler : ICommandHandler<CreateOrderCommand>
{
    private readonly IOrderRepository _orders;
    private readonly IEventBus _bus; // برای انتشار رویدادها

    public CreateOrderHandler(IOrderRepository orders, IEventBus bus)
    {
        _orders = orders;
        _bus = bus;
    }

    public async Task Handle(CreateOrderCommand command)
    {
        var order = new Order(command.Id, command.Customer);
        await _orders.Save(order);
        await _bus.Publish(new OrderCreatedEvent(order.Id, order.Customer)); // به Outbox یا پیام‌رسان
    }
}

// پرس‌وجوها (Read Model)
public record GetOrderDto(Guid Id, string Customer, string Status);
public record GetOrderQuery(Guid Id);

public interface IQueryHandler<TQuery, TResult>
{
    Task<TResult> Handle(TQuery query);
}

public class GetOrderHandler : IQueryHandler<GetOrderQuery, GetOrderDto?>
{
    private readonly IReadOnlyOrderView _view; // جدول نمای خواندن

    public GetOrderHandler(IReadOnlyOrderView view) => _view = view;

    public Task<GetOrderDto?> Handle(GetOrderQuery query)
        => _view.Find(query.Id); // مستقیماً از پایگاه داده خواندن
}
```

## 🔍 چه زمانی استفاده کنیم؟
1. سیستم‌هایی با **خواندن بسیار بیشتر از نوشتن** یا نیازهای متفاوت عملکردی برای هرکدام
2. زمانی که **مدل دامنه پیچیده** است و می‌خواهید ساده‌سازی نمای خواندن را جداگانه انجام دهید
3. زمانی که به **Event Sourcing / Outbox / پیام‌رسانی** نیاز دارید و می‌خواهید جریان نوشتن ایزوله باشد
4. برای **مقیاس‌پذیری مستقل** لایه‌های خواندن و نوشتن (بانک اطلاعاتی/کش متفاوت)

## ✅ مزایا
- **بهینه‌سازی مستقل** خواندن و نوشتن
- **کاهش کوپلینگ** بین منطق دامنه و نیازهای گزارش‌گیری
- **مقیاس‌پذیری مجزا** و امکان استفاده از ذخیره‌سازی متفاوت
- سازگاری خوب با **Event Driven** و **Outbox**

## ❌ معایب
- **پیچیدگی بیشتر** در معماری و استقرار
- نیاز به **همگام‌سازی داده‌ها** بین مدل نوشتن و مدل خواندن (lag)
- مناسب نبودن برای **اپلیکیشن‌های ساده** با دامنه کوچک

## 🔑 نکات کلیدی
- دستورها باید **Side Effect** داشته باشند اما خروجی ندهند؛ پرس‌وجوها **فقط خواندنی** باشند.
- مدل خواندن را می‌توان روی **Viewهای بهینه** یا کش نگه داشت.
- معمولاً همراه با **Event Sourcing** یا **Outbox** استفاده می‌شود تا پایداری و همگام‌سازی تضمین شود.
- حداقل‌گرایی: فقط زمانی به سراغ CQRS بروید که **درد فعلی** (گزارش‌های سنگین، مقیاس‌پذیری) آن را توجیه کند.
