ویرگول
ورودثبت نام
آرش رستمی
آرش رستمیPassionate software developer building complex systems and efficient databases. Led projects end-to-end, write clean scalable code, solve real problems, mentor juniors, and co-found tech ventures.
آرش رستمی
آرش رستمی
خواندن ۳ دقیقه·۱۲ روز پیش

اگه سیستم‌ت بزرگ شده، وقتشه CQRS رو بشناسی

CQRS Pattern
CQRS Pattern

من چرا باید CQRS رو بلد باشم؟!

یه زمانی یه «مدل واحد» برای نوشتن و خوندن دیتا کافی بود…
ولی الان دیگه واقعاً نه 😄
وقتی سیستم بزرگ می‌شه، همزمانی زیاد می‌شه، و نیاز به سرعتِ خوندن و گزارش‌گیری میاد وسط، اون مدل واحد کم‌کم کند و پیچیده می‌شه. (و تازه دردِ مقیاس‌پذیری هم اضافه می‌شه.)

پس حداقل باید CQRS رو بفهمیم.

CQRS یعنی چی، خیلی ساده؟

CQRS مخففِ Command Query Responsibility Segregation ـه.
یعنی:

  • Command (فرمان) = هر چیزی که «وضعیت رو تغییر می‌ده»

  • Query (پرس‌وجو) = هر چیزی که «فقط می‌خونه و نمایش می‌ده»

ایده‌ی اصلی اینه که مدلی که باهاش می‌نویسی، لزوماً همون مدلی نیست که باهاش می‌خونی.

این جدا کردن، تو بعضی سیستم‌ها خیلی ارزش داره…
ولی حواست باشه: برای خیلی از پروژه‌های کوچیک، CQRS می‌تونه «پیچیدگی اضافه» بیاره. (martinfowler.com)

چرا اصلاً این جدا کردن به درد می‌خوره؟

چون می‌تونی هر سمت رو جداگانه بهینه کنی:

  • سمت نوشتن: قوانین کسب‌وکار، اعتبارسنجی، همزمانی، جلوگیری از خرابکاری

  • سمت خوندن: سرعت، سرچ، گزارش، مدل ساده برای UI

مایکروسافت هم دقیقاً همین رو می‌گه: با جدا کردن مدلِ خواندن/نوشتن، می‌تونی کارایی و مقیاس‌پذیری رو بهتر کنی.

یه نکته خیلی مهم: «همون لحظه نمی‌بینی»

توی خیلی از پیاده‌سازی‌های CQRS، نوشتن که انجام شد، مدلِ خواندن با کمی تأخیر آپدیت می‌شه.
یعنی ممکنه کاربر «ثبت کرد»، ولی «لیست» یک لحظه بعد آپدیت شه.

این طبیعی‌ـه… ولی باید تو طراحی UI و تجربه کاربر حواست باشه.

حالا Axon این وسط چیه؟

Axon Framework یه فریمورک جاوا/اسپرینگ برای ساخت سیستم‌های رویدادمحور (event-driven) با محوریتِ DDD + CQRS + Event Sourcing ـه. (GitHub)

به زبان خودمونی:
Axon خیلی از «سیم‌کشی‌های تکراری» رو برات انجام می‌ده تا تو روی مدلِ دامنه و قوانین تمرکز کنی.

چیزهایی که معمولاً تو Axon زیاد می‌بینی:

  • Aggregate (هسته‌ی دامنه برای نوشتن)

  • Command Handler (جایی که فرمان رو می‌گیره)

  • Event (خروجیِ تغییر)

  • Event Sourcing Handler (بازسازی وضعیت با رویدادها)

  • Projection / Read Model (مدلِ خواندن)

Axon وقتی Event Sourcing استفاده می‌کنی، وضعیتِ Aggregate رو با ریپلی کردن رویدادها بازسازی می‌کنه.

نمونه‌ی خیلی ساده: «ثبت سفارش» و «دیدن سفارش‌ها»

سناریو:
کاربر سفارش ثبت می‌کنه.
بعد می‌خواد لیست سفارش‌هاشو ببینه.

1) سمت نوشتن: فرمان و رویداد

فرمان (Command):
«سفارش بساز»

رویداد (Event):
«سفارش ساخته شد»

اینجا حداقل یک قانون داریم:
سفارش بدون شناسه و آیتم‌ها معنی نداره.

2) Aggregate: جایی که قوانین اصلی می‌شینن

این‌جا تصمیم می‌گیریم آیا فرمان مجازه یا نه.
اگر مجازه، رویداد تولید می‌کنیم.

نکته‌ی Axon: خیلی وقت‌ها عمر Aggregate با یه «سازنده‌ی هندلرِ فرمان» شروع می‌شه.

یک شبه‌کد خیلی خلاصه (جاوا/اسپرینگ + Axon)، فقط برای اینکه تصویر بسازه:

@Aggregate public class OrderAggregate { @AggregateIdentifier private String orderId; private boolean created; public OrderAggregate() {} @CommandHandler public OrderAggregate(CreateOrderCommand cmd) { // اعتبارسنجی خیلی ساده if (cmd.items().isEmpty()) throw new IllegalArgumentException("سفارش خالیه"); AggregateLifecycle.apply(new OrderCreatedEvent(cmd.orderId(), cmd.items())); } @EventSourcingHandler public void on(OrderCreatedEvent evt) { this.orderId = evt.orderId(); this.created = true; } }

ایده‌ی اصلی:

  • Command میاد.

  • اگر معتبر بود، Event صادر می‌شه.

  • با EventSourcingHandler وضعیت ذخیره/بازسازی می‌شه.

3) سمت خواندن: Projection (مدلِ مخصوص نمایش)

اینجا دیگه دنبال قوانین سخت نیستیم.
دنبال یه جدول/مدل ساده‌ایم که UI راحت بخونه.

پس رویداد OrderCreatedEvent رو می‌گیریم و یه رکورد تو دیتابیسِ خواندن می‌نویسیم:

@Component public class OrderProjection { private final OrderViewRepository repo; public OrderProjection(OrderViewRepository repo) { this.repo = repo; } @EventHandler public void on(OrderCreatedEvent evt) { repo.save(new OrderView(evt.orderId(), evt.items())); } @QueryHandler public List<OrderView> handle(GetOrdersQuery q) { return repo.findByUserId(q.userId()); } }

این‌جا دقیقاً همون جداسازی اتفاق افتاده:

  • Aggregate = نوشتن و قوانین

  • Projection = خواندن و نمایش

و چون این دو جدا هستن، می‌تونی Read Model رو برای سرچ و سرعت، خیلی راحت‌تر بهینه کنی.

کی CQRS + Axon انتخاب خوبیه؟

حداقل وقتی که این‌ها رو داری:

  • دامنه‌ی پیچیده و قانون زیاد

  • نیاز جدی به گزارش و خواندن سریع

  • مقیاس‌پذیری و رویدادمحور بودن برات مهمه

  • «ردپا» و تاریخچه‌ی تغییرات ارزش داره (اینجا Event Sourcing هم میاد وسط)

ولی اگر پروژه‌ت کوچیکه و CRUD ساده جواب می‌ده، خیلی وقت‌ها CQRS فقط هزینه‌ی ذهنی می‌ذاره.

جمع‌بندی خودمونی

CQRS می‌گه:
«نوشتن و خوندن رو قاطی نکن.»

Axon کمک می‌کنه این جداسازی رو تمیزتر بسازی:
Aggregate برای نوشتن، Projection برای خوندن، و اگر خواستی Event Sourcing برای تاریخچه و بازسازی.

پ.ن: لینک پروژه گیت هاب که یک سمپل خوب برای شروع هست:
https://github.com/a-rostami/CQRS-Axon-Implementation

event sourcingcqrsmicroservices
۱
۰
آرش رستمی
آرش رستمی
Passionate software developer building complex systems and efficient databases. Led projects end-to-end, write clean scalable code, solve real problems, mentor juniors, and co-found tech ventures.
شاید از این پست‌ها خوشتان بیاید