الگوی CQRS مخفف Command Query Responsibility Segregation است. این الگویی است که برای اولین بار توسط Greg Young مطرح شد. در قلب آن این تصور وجود دارد که شما می توانید از مدلی متفاوت برای به روز رسانی اطلاعات نسبت به مدلی که برای خواندن اطلاعات استفاده می کنید، بهره ببرید. برای برخی موقعیتها، این جداسازی میتواند بسیار ارزشمند باشد، اما مراقب باشید که برای اکثر سیستمها CQRS پیچیدگی خطرناکی را به سیستم اضافه میکند.
رویکرد اصلی که مردم برای تعامل با یک سیستم اطلاعاتی استفاده می کنند، این است که آن را به عنوان یک CRUD در نظر بگیرند. منظور این است که ما یک مدل ذهنی از ساختار رکورد داریم که در آن میتوانیم رکوردهای جدید ایجاد کنیم، رکوردها را بخوانیم، رکوردهای موجود را به روز کنیم، و پس از اتمام کار رکوردها را حذف کنیم. در سادهترین حالت، تعاملات ما همه در مورد "ذخیره" و "بازیابی" این رکوردها است.
همانطور که نیازهای ما پیچیده تر می شوند، به طور پیوسته از مدل سنتی تعامل با داده ها دور می شویم. ممکن است بخواهیم اطلاعات را به گونهای متفاوت استفاده کنیم، شاید چندین رکورد را در یک رکورد جمع کنیم، یا با ترکیب اطلاعات برای مکانهای مختلف، رکوردهای مجازی تشکیل دهیم. در سمت بهروزرسانی، ممکن است قوانین اعتبارسنجی را تغییر دهیم تا فقط ترکیبهای خاصی از دادهها ذخیره شوند، یا حتی ممکن است بخواهیم دادههایی متفاوت از آنچه ارائه میدهیم ذخیره شوند.
با رخ دادن این اتفاق، ما شروع به دیدن بازنماییهای متعدد از اطلاعات می کنیم. هنگامی که کاربران با اطلاعات تعامل برقرار می کنند، از ارائه های مختلفی از این اطلاعات استفاده می کنند که هر یک استفاده متفاوتی دارد. توسعه دهندگان معمولاً مدل مفهومی خود را می سازند که از آن برای دستکاری عناصر اصلی مدل استفاده میشود. اگر از مدلی در این دامنه استفاده میکنید، این مدل معمولا بازنمایی مفهومی در آن دامنه است. پس منطقی است که شما مکان ذخیره سازی دائمی (Storage) را تا جایی که می توانید به مدل مفهومی نزدیک کنید.
این ساختار تشکیل شده از چندین لایه ارائه دهنده میتواند بسیار پیچیده شود. اما هنوز هم میتوان این پیچیدگی را با استفاده از یک نقطه ادراکی واحد رفع کرد، این نقطه به عنوان یک نقطه ادغام مفهومی بین همه ارائه ها عمل میکند.
تغییری که الگوی CQRS معرفی میکند این است که مدل مفهومی را به مدلهای جداگانه برای بهروزرسانی و نمایش (نوشتن و خواندن) اطلاعات تقسیم کنیم، که به ترتیب به عنوان Command و Query در این الگو شناخته میشوند. در اینجا منطق این است که برای بسیاری از مسائل، به ویژه در حوزه های پیچیده تر، داشتن مدل های مفهومی یکسان برای اجرای دستورات و کوئری ها منجر به پدید آمدن مدل های پیچیده تری می شود.
منظور ما از مدلهای جداگانه معمولاً اشیاء متفاوتی است که احتمالاً در فرآیندهای منطقی متفاوتی اجرا میشوند، و حتی شاید روی سختافزار جداگانه اجرا شوند. مثال تجت وب زیر را در نظر بگیرید:
کاربر صفحه وبی را میبیند که با استفاده از مدل کوئری رِندر شده است. حال اگر کاربر تغییری را اعمال کند، آن تغییر برای پردازش به مدل جداگانه کامند هدایت میشود. در نهایت تغییر حاصل شده به مدل کوئری ارسال می شود تا اطلاعات قابل نمایش به روز رسانی شوند.
در اینجا با انتخاب های قابل توجهی روبرو هستیم;
مدل های تعریفشده درون حافظه میتوانند از یک دیتابیس مشترک استفاده کنند، که در این صورت دیتابیس به عنوان یک پل ارتباط بین دو مدل عمل میکند.
همچنین مدل ها میتوانند از دیتابیس های جداگانه استفاده کنند، که به شکل موثری دیتابیس کوئری ها را به یک دیتابیس گزارشی بلادرنگ تبدیل میکند. که در این حالت باید مکانیزم ارتباطی بین دو مدل یا دیتابیس آنها وجود داشته باشد.
این مدل ها ممکن است اشیاء مجزا نباشند، ممکن است به این دلیل باشد که به جای ویوهای موجود در پایگاههای داده رابطهای، اشیاء یکسان دارای اینترفیس های متفاوتی برای سمت فرمان و سمت کوئری خود هستند، پس وقتی در مورد CQRS صحبت می کنیم، معمولاً به مدل های جداگانه ای اشاره میکنیم.
الگوی CQRS به طور طبیعی با برخی دیگر از الگوهای معماری مطابقت دارد:
با دور شدن از یک ارائه واحد که از طریق CRUD با آن تعامل داریم، به راحتی میتوانیم به سمت یک UI مبتنی بر وظیفه (Tasked-Base) برویم.
الگوی CQRS به خوبی با مدلهای برنامه نویسی مبتنی بر رویداد (Event-Based) مطابقت دارد. پس تقسیم شدن سیستم به سرویس های جداگانه که از طریق همکاری رویدادها (Event Collaboration) ارتباط برقرار میکنند، امری بدیهی است; که به سرویس ها اجازه میدهد به راحتی از مزایای Event Sourcing بهره ببرند.
داشتن مدل های جداگانه سوال دیگری را نیز مطرح میکند: چقدر سخت است تا داده ها را به صورت یکسان و بدون تناقض در اختیار داشت؟ که احتمال استفاده از Event Sourcing را بسیار افزایش می دهد.
الگوی CQRS برای دامنه های پیچیده مناسب است، و در عین حال از طراحی دامنه محور (Domain-Driven Design) نیز بهره می برد.
مانند هر الگویی، CQRS در برخی جا ها مفید ، و در برخی دیگر مفید نیست.
بسیاری از سیستمها با یک مدل ذهنی CRUD مطابقت دارند، بنابراین باید در آن سبک انجام شوند. پیاده سازی الگوی CQRS یک جهش ذهنی قابل توجه میطلبد. پس بهتر است تا زمانی که مزایای آن واقعا مورد نیاز نیست، با آن درگیر نشوید.
مارتین فولر در این باره میگوید:
1. الگوی CQRS باید فقط در بخشهای خاصی از یک سیستم (BoundedContext) و نه در کل سیستم استفاده شود..
2. استفاده از الگوی CQRS می توان از پیچیدگی چند دامنه مختلف مقابله کرد، اما چنین مورد استفادهای برای CQRS به ندرت پیش میآید. معمولاً همپوشانی کافی بین دو طرف کامند و کوئری آن قدری وجود دارد که به اشتراک گذاری یک مدل گزینه آسان تری است. در نتیجه استفاده از CQRS در دامنهای که با آن مطابقت ندارد، پیچیدگی را به شدت افزایش میدهد، بنابراین بهرهوری کاهش پیدا کرده و ریسک افزایش مییابد.
3. مزیت اصلی دیگر مدیریت برنامه های کاربردی با پرفرمنس بالا است. CQRS به شما امکان می دهد بار سیستم را در حیطه های خواندن و نوشتن جدا کرده و مقیاس پذیری در هر لایه را به شکل جداگانه ممکن میسازد... اگر اختلاف زیادی در خواندن و نوشتن داده ها در اپلیکیشن شما وجود دارد، این الگو بسیار کاربردی است; اگر چنین موردی هم وجود ندارد، هنوز هم میتوانید از اعمال کردن استراتژیهای بهینهسازی متفاوت در هر دو لایه سود ببرید. یک مثال واضح آن استفاده از تکنیک های مختلف دسترسی به دیتابیس برای خواندن و به روز رسانی است.
4. اگر دامنه شما برای الگوی CQRS مناسب نیست، اما کوئری هایی دارید که باعث ایجاد پیچیدگی یا مشکلات پرفرمنسی میشوند... به یاد داشته باشید که همواره میتوانید از یک Reporting Database استفاده کنید. الگوی CQRS از یک مدل جدا برای همه کوئری ها استفاده میکند. با یک Reporting Database، شما همچنان از سیستم اصلی خود برای اکثر کوئری ها استفاده می کنید، اما کوئری های پیچیده را به Reporting Database واگذار می کنید.
با وجود این مزایا، باید در استفاده از CQRS بسیار محتاط باشید. بسیاری از سیستمهای اطلاعاتی با مفهوم به روزرسانی داده ها به همان روشی که خوانده میشوند، به خوبی مطابقت دارند، پس افزودن CQRS به چنین سیستمی میتواند پیچیدگی قابل توجهی را اضافه کند. که این موضوع، حتی در یک تیم توانا، تأثیر قابل توجهی بر بهرهوری میگذارد، و ریسک غیرقابل توجیهی را به پروژه اضافه میکند.
هر چند داشتن این الگو در جعبه ابزارتان گزینه خوبی است.. اما پیاده سازی صحیح آن دشوار است. و در انتخاب آن معیارهای زیادی برای سنجش وجود دارد.
منبع: «مارتین فولر»