تخطَّ إلى المحتوى

CQRS

CQRS — فصل القراءة عن الكتابة CQRS

يفصل نموذج البيانات المستخدم للكتابة (Commands) عن نموذج القراءة (Queries)، فيمكن تحسين كل جانب بشكل مستقل.

في النموذج التقليدي، نفس بنية البيانات تُستخدم للكتابة والقراءة معاً — رغم أن احتياجاتهما مختلفة غالباً: الكتابة تحتاج تحقق صارم من قواعد العمل، بينما القراءة تحتاج غالباً شكلاً مُجمَّعاً جاهزاً للعرض مباشرة.

CQRS (Command Query Responsibility Segregation) يفصلهما لنموذجين: نموذج Write محسَّن للتحقق والاتساق، ونموذج Read مُجمَّع مسبقاً (غالباً محدَّث عبر أحداث من جانب الكتابة) ومحسَّن للاستعلام السريع دون Joins معقدة بين خدمات متعددة.

الصياغة

Command → Write Model → Event → Read Model (denormalized) → Query

📄 مثال

// جانب الكتابة
async function createOrder(cmd) {
  const order = await writeDb.orders.save(cmd);
  await eventBus.publish('order.created', order);
}

// جانب القراءة — يبني عرضاً مُجمَّعاً عند وصول الحدث
eventBus.on('order.created', async (order) => {
  await readDb.orderSummaries.insert({
    orderId: order.id, customerName: order.customerName, total: order.total,
  });
});

أهم النقاط

العنصرالوظيفة
Write Modelمحسَّن للتحقق من قواعد العمل والاتساق
Read Modelنسخة مُجمَّعة مسبقاً محسَّنة للاستعلام السريع، غالباً محدَّثة عبر أحداث

💡 نصائح عملية

  • لا تطبّق CQRS على كل الخدمات افتراضياً — يستحق تعقيده الإضافي فقط عند اختلاف واضح بين احتياجات القراءة والكتابة
  • تقبّل أن نموذج القراءة يتأخر قليلاً عن الكتابة (Eventual Consistency) عبر الأحداث

⚠️ أخطاء شائعة

  • استخدام CQRS كنمط افتراضي لكل خدمة بسيطة — تعقيد بلا فائدة حقيقية
  • افتراض أن نموذج القراءة يتحدث فوراً بلا أي تأخير بعد كل كتابة

خصائص ذات صلة

🎓 تريد فهم الصورة الكاملة خطوة بخطوة؟ ابدأ من مسار MICROSERVICES الكامل بالعربي.