(حداقل) از MediatR چگونه استفاده کنیم

CQRSدر این مقاله چهار قسمتی به بررسی فنی استفاده از کتابخانه MediatR با توجه به پیچیدگی و گستردگی پروژه ها پرداخته میشود و در قسمت پایانی مقاله راهنمای طبقه بندی شده برای استفاده از این کتابخانه ارائه خواهد شد.زمانی که بحث از MediatR میشود بخاطر مباحث پیرامون آن که روند های حوزه مهندسی نرم افزار هستند، ناخودآگاه ذهن به سمت موضوعاتی مثل CQRSو الگوی Mediator کشیده میشود.قسمت اول: چگونه CQRS را به یک کودک 5 ساله تفهیم کنیم.تعریف CQRS چیست و چرا مورد نیاز است:فرض کنید که تنهایی در خانه هستید و هوس خوردن لوبیا پلو کرده ایید. در این موقعیت پس از پخت غذا برای کشیدن آن به بشقاب مطمئنا از دیس و یا حتی کفگیر استفاده نمی کنیم. برای کشیدن یک پرس غذا برای یک نفر احتمال زیاد همان پای اجاق گاز با قاشق غذا را به بشقاب میریزیم و سر میز میل میکنیم. در این حالت تنها یک قاشق، هم برای آوردن غذا به سر سفره و هم برای خوردن آن از بشقاب کفایت میکند و نیازی به کثیف شدن کفگیر نیست.اما همین لوبیا پلو خوردن در موقعیتی که یک خانواده می خواهند از خوردن آن لذت ببرند شرایط متفاوتی را دارد. در این موقعیت یک قاشق برای کشیدن غذا و خوردن آن دیگر کافی نیست. پس از پخت غذا برای آوردن آن سر سفره مطمئنا از کفگیر و دیس استفاده میکنیم. در اینجا چون تعداد افراد بیشتر از موقعیت اول است، در صورت استفاده از قاشق تعداد کارها و رفت آمد در آشپزخانه بسیار زیاد میشود. با آوردن غذا در دیس به سر میز یا سفره، رفت آمد به آشپزخانه کمتر و رسیدن به غذا ساده تر می‌شود. همچنین برای کشیدن غذا از کفگیر استفاده میکنیم که با دفعات کمتر غذا سریع تر به بشقاب کشیده شود.همین شرایطی که در خوردن لوبیا پلو در موقعیت های مختلف می‌توانیم داشته باشیم، در IT و کار با Dataهم داریم.در حوزه IT در مورد Dataنیز موقعیت های مشابه بالا بوجود می آید. در پروژه های کوچک و یا بخش هایی از یک پروژه بزرگ، که عموما Data-Driven هستند و Request زیادی روی آن ها نیست، ثبت Data روی چند جدول Normalizedشده و خواندن اطلاعات از آن ها پاسخگوی شرایط خواهد بود. در شرایطی که وضعیت کمی بحرانی شود میتوان همین مدل را بوسیله Indexingویا تکنیک های دیگر بهینه کرد. به عبارت دیگر همان یک قاشق و بشقاب برای این شرایط کافی است و انتظارات را برآورده میکند.اما زمانی که کار با اطلاعات پیچیده تر می شود و یا Requestهای زیادی در خواندن، ثبت و ویرایش Dataپیش می آید، ذخیره اطلاعات و خواندن آن به یک شکل مشترک دیگر جوابگوی شرایط نیست. به عبارتی، دیگر یک قاشق و بشقاب برای کشیدن غذا و خوردن آن مناسب موقعیت ما نیست.اگر در چنین شرایطی بخواهیم از یک مدل استفاده کنیم، دقیقا مانند زمانی است که در یک مهمانی بزرگ بخواهیم فقط با استفاده از قاشق و بشقاب، غذا ها را بکشیم و صرف کنیم. به بیان دیگر مشقت و سختی بسیار زیادی را به خود تحمیل می کنیم.برای این موقعیت اگر مدل های ثبت و ویرایش Data با مدل های خواندن آن متفاوت و مجزا باشد، درواقع CQRS پیاده سازی شده است. پس شرط لازم برای پیاده سازی CQRS مدل های مختلف مجزا و تک منظوره Data برای ذخیره و یا بازیابی اطلاعات است.مثال طراحی CQRS در Application ها:مدیریت دسترسی کاربران را در محصولات نرم افزاری در نظر بگیرید. عموما مدل RBAC برای این منظور استفاده میشود. در مدل RBAC یک کاربر میتواند نقش های مختلفی داشته باشد که برای هر نقش میتوان چندین دسترسی را انتساب کرد.پیاده سازی این مدل در دیتابیس های رابطه ایی معمولا به این شکل است که سه جدول برای ماهیت های کاربران، نقش ها و دسترسی ها در نظر گرفته میشود و برای مشخص شدن ارتباطات آن ها دو جدول دیگر به منظور انتساب کاربران به گروه ها و دسترسی ها به گروه ها در نظر گرفته میشود. هر زمان که در برنامه بخواهیم دسترسی کاربری را برای انجام کاری بسنجیم، در این مدل باید 5 جدول را به همدیگر Join کنیم. این مدل Dataدر صورتی کارآمد است که تعداد Requestها روی برنامه و همچنین تعداد کاربران، نقش ها و دسترسی ها در حد قابل قبولی باشد که عمل Join شدن Record ها در بازه زمانی کوتاهی انجام شود.مدل دسترسی RBACزمانی که تعداد Request ها و یا تعداد کاربران، گروه ها و دسترسی ها زیاد شود یا بطور کلی مدل های انتساب دسترسی پیچیده تر شوند (برای مثال سیاست بازه زمانی محدود برای دسترسی کاربران) Query سنجش دسترسی که برای هر درخواست باید اجرا شود، روز به روز کند تر خواهد شد تا آنجا که حدود نصف بار اعمالی بر روی دیتابیس را از آن خود خواهد کرد.این در حالی است که برای سنجش دسترسی کاربر، تنها کافیست بدانیم که آیا کاربر، آن دسترسی را دارد یا خیر. در این حالت می توان مدل ثبت اطلاعات دسترسی و انتسابات را از مدل سنجش دسترسی کاربران مجزا کرد. به این گونه که برای ثبت اطلاعات و جستجوی آن ها (که این اقدامات در مقابل عمل سنجش دسترسی کاربر در سیستم بسیار کمتر انجام میشود) از همان مدل Normalized استفاده کرد ولی برای سنجش دسترسی کاربران از مدل Denormalized(کاربر – دسترسی) استفاده شود. برای مثال میتوان برای سنجش دسترسی، یک کلید (دائمی یا زمان دار) با ترکیب (نام کاربری – نام دسترسی) را در دیتابیس Redis بوجود آورد. در این حالت برای سنجش دسترسی یک کاربر، تنها کافیست، وجود داشتن کلید (نام کاربری - نام دسترسی) را در Redis چک کرد، که این عمل در دیتابیس بسیار سریع اتفاق می افتد و کاملا این مدل قابلیت مقیاس پذیری با ازدیاد کاربران، دسترسی ها و یا گروه ها و حتی سیاست های مختلف انتساب دسترسی را دارا میباشد.مدل های مختلف Data دسترسی و Sync شدن آن هاپیچیدگی ایی که CQRS به پروژه می افزاید Sync نگه داشتن اطلاعات بین مدل های مختلف است که طبیعتا این عمل Sync شدن موجب بوجود آمدن مدت زمان تاخیر بین یکپارچگی Data در مدلهای مختلف می شود. این پیچیدگی فقط باید زمانی به پروژه اعمال شود که دستاورد قابل توجهی از لحاظ طراحی و کارایی سیستم داشته باشد. برای نمونه در مثال قبل پیچیدگی ایی که در مقابل سنجش سریع دسترسی کاربران به پروژه اعمال میشود، استخراج و اعمال کلید های کاربر – دسترسی ایی است که با هر اقدام روی مدل Normalized باید انجام میشود که به موجب آن باید کدهای Sync کننده بین مدل های مختلف Data به پروژه اضافه شود.در حقیقت ما در CQRS تلاشمان این است که برای شرایط خاصی (مانند تعداد Client ها و یا تعداد Requestهای مشخص) مدل Data طراحی کنیم و آن مدل را در بهترین حد بهینه قرار دهیم. وقتی آن شرایط تغییر کرد(برای مثال تعداد Request ها بیشتر شد و یا نوع اطلاعات تغییر کرد) یک مدل جدید متناسب با آن شرایط طراحی میکنیم و Dataقبلی را به آن انتقال می دهیم.اما در مدل کلاسیک ما تلاشمان این است که مدل طراحی Dataطبق قواعدی از پیش تعیین شده مانند Normalization در سطوح مختلف انجام شود.این مدل بر حسب شرایط مختلف بوجود آمده بهینه سازی میشود و حتی Query آن نیز دچار تغییر و تحول خواهد شد، اما مدل Data کماکان برای هر عملیاتی تغییر نخواهد کرد. به عبارتی دیگر ما در این حالت تلاشمان این است که قابلمه را دور مجلس بگردانیم و اگر یک قاشق کفاف کار را نداد با چندین قاشق و سرعت دست بالاتر غذا را بکشیم.نتیجه:زمانی که پیچیدگی کار با دیتا بیشتر و یا شرایط بازخوانی اطلاعات از ثبت آن متفاوت می شود، برای طراحی و کار بهینه با Data باید از مدل های متنوع و حتی پایگاه های داده متفاوت استفاده کنیم.اما این پیچیدگی زمانی باید به پروژه اعمال شود که دستاورد قابل توجهی از نظر طراحی و کارایی سیستم داشته باشد.