<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های مهدی فلامرزی</title>
        <link>https://virgool.io/feed/@m_22983838</link>
        <description>مشاور و معمار نرم افزار در شرکت SmartMed</description>
        <language>fa</language>
        <pubDate>2026-06-18 08:32:51</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/541908/avatar/ZY41fP.png?height=120&amp;width=120</url>
            <title>مهدی فلامرزی</title>
            <link>https://virgool.io/@m_22983838</link>
        </image>

                    <item>
                <title>مسیر تفکر در طراحی Model Driven (قسمت دوم)</title>
                <link>https://virgool.io/@m_22983838/model-driven-implementation-xdzrjqf072zg</link>
                <description>در این مقاله سعی داریم که با انجام مثالی، کاربرد معیارهایی که در قسمت اول مقاله گفته شده را به تصویر بکشیم و در مسیری که مشخص شده است قدم برداریم. در حقیقت بخش عملی این مسیر، در این قسمت از مقاله است. مثالی که قرار است پیاده سازی شود، یک نیازمندی واقعی از محصولی است که در همین مثال کوچک، تقریبا تمام معیارهای طراحی را شامل میشود.قبل از انجام طراحی، گفتن این نکته الزامی است که، به چند دلیل پیاده سازی انجام شده صحیح نیست:1- طراحی و پیاده سازی انجام شده، بدون همفکری تیمی انجام شده است. تجارب کاری نشان میدهد که در یک تیم نرم افزاری، هر طراحی ایی حتی اگر در بهترین و بی نقص ترین شکل ممکن باشد، بدون مقبولیت جمعی، چندان دوام نخواهد آورد. چون اصولا در طراحی نرم افزار تداوم و تکامل یکی از مهمترین ویژگی ها باید باشد، این نکته بسیار حایز اهمیت است. یک طراحی با دوام در تیم نرم افزاری، همیشه در حد متوسط مهارت ها و قابلیت های آن تیم است. هرگز سطح مهارتی یک تیم نرم افزاری تغییر نمیکند، مگر اینکه متوسط آن تغییر کند و هر تغییری از  تحصیل (تفکر و مطالعه) شروع میشود.2- پیاده سازی مد نظر تنها قرار است مسیر تفکر در طراحی Model Driven را بر ما آشکار کند. این پیاده سازی قصد برآورده کردن ارزش بیزینسی ندارد.3- طراحی بدون تست انجام شده و در مقاله بعدی، به منظور بررسی آثار رعایت معیار ها و نکات، بصورت Test After در میاید. یک طراحی خوب بصورت Test First است و از اصول TDD پیروی میکند.بعد از بیان و متوجه شدن مواردی که در بالا گفته شد، میتوانیم به سراغ پیاده سازی برویم. پیاده سازی انجام شده تنها به لایه Domain و Application مربوط میشود و وارد جزییات استفاده از Library های زیرساختی نمی شود. همچنین از پیاده سازی الگوریتم ها نیز اجتناب شده است.شرح نیازمندی: یک محصول E-Commerce را در نظر بگیرید که کاربران آن با توجه به خرید هایی که میکنند، امتیازاتی دریافت میکنند. داستان کاربری این نیازمندی از این قرار است: مالک محصول میخواهد امکان ثبت نام کاربر با کد معرف را داشته باشد. این کد معرف یک رشته 8 کارکتری است که توسط بازاریاب تولید میشود. همچنین بازاریاب میتواند مشخص کند هنگام ثبت نام کاربر، چه امتیاز اولیه ایی به کاربر اختصاص داده شود.قبل از اینکه به سراغ شرح بیشتر نیازمندی برویم، در مورد کد 8 رقمی معرف، تامل میکنیم. از Feature خواسته شده مشخص است که یک سیستم کدینک برای کد معرف، باید طراحی شود. در این مثال، این سیستم کدینگ را بصورت بسیار ساده یک رشته 8 کارکتری میبینیم که 3 کارکتر اول، کد ارجاع بازاریاب خواهد بود، 4 کارکتر بعدی کد ارجاع مشتری و کارکتر آخر یک شماره به عنوان کدینگ استفاده شده، برای ساخت کد معرف، قرار داده میشود. با توجه به اینکه در این سیستم کدینگ، هم از حروف هم از اعداد میتوان استفاده کرد، کد معرف یک عدد در مبنای 36 خواهد بود. بدین صورت سیستم کدینگ مد نظر، توانایی پوشش 46,656 بازاریاب را خواهد داشت. همچنین هر بازاریاب قابلیت تولید 1,679,616 کد یکتا را خواهد داشت که در مجموع 78,364,164,096 کد معرف یکتا وجود خواهد داشت.برای اینکه در سیستم کدینگ 0 جلو عدد نداشته باشیم اعداد را بصورت برعکس در کد میگذاریم. برای مثال در صورتی که شماره ارجاع بازاریاب 2 و شماره ارجاع مشتری 1 باشد، کد معرف 2001000C خواهد بود. حرف C در کارکتر آخر نشان دهنده سیستم کدینگ پیش فرض است که برای تولید کد معرف استفاده میشود. به عنوان یک مثال دیگر شماره ارجاع بازاریاب 457 و شماره ارجاع مشتری 7865 را در نظر بگیرید. کد  معرف معادل آن PC0H260C خواهد بود.حال به منظور روشن ساختن نیازمندی، بعضی از سناریو های ممکن را بصورت Happy Path مورد بررسی قرار میدهیم.Scenario: Registering customer without referral codeGiven a customer with descriptions below:name: &quot;mehdi,&quot; family: &quot;falamarzi&quot;, referral code: &quot;&quot;When the customer registered in the systemThen the customer registered with &quot;0&quot; initial pointsScenario: Creating referral code for customers by marketerGiven a marketer with referral number: &quot;457&quot;And the marketer created &quot;7864&quot; referral code so farWhen the marketer created another referral code with &quot;30&quot; initial points for registering customersThen referral code &quot;PC0H260C&quot; created with &quot;30&quot; initial points for registering customersScenario: Registering customers with referral codeGiven a referral code &quot;PC0H260C&quot; with &quot;30&quot; initial points for registering customersAnd a customer with descriptions below:name: &quot;mehdi,&quot; family: &quot;falamarzi&quot;, referral code: &quot;PC0H260C&quot;When the customer registered in the systemThen the customer registered with &quot;30&quot; initial pointsحال پس از تفهیم و انتقال نیازمندی، اقدام به طراحی و پیاده سازی آن میکنیم. اول به سراغ marketer میرویم و آن را مدل میکنیم:مدل Marketerدر طراحی مدل Marketer، نکات زیر در نظر گرفته شده است:1- در طراحی Marketer از معیار اول استفاده شده است. به همین سبب کد های معرف دیگر بصورت Entity درون مدل Marketer قرار نخواهند گرفت بلکه بصورت AggregateRoot درآمده. این طراحی منطبق بر طراحی سیستم های OLTP باعث میشود که با ID به Model ها دسترسی پیدا کنیم. همچنین مدل Marketer با این طراحی، هر تعداد ReferralCode که درست شود، همچنان برای فراخوانی از دیتابیس سبک خواهد بود.(در اینجا گفتن این نکته شاید خالی از لطف نباشد، که در مدل REST بازاریاب، ممکن است برای سادگی کار Client، کد معرف، یک Entity از Marketer باشد. علی رغم اینکه در Domain، مدل Marketer چیز دیگری است، اما چون دغدغه سرویس های RESTful از مسایل Domain جدا هستند، آن لایه بخصوص میتواند مدل و نمایش Resource مستقل خودش را داشته باشد. شرح سرویس های RESTful خارج از قاموس این مقاله هست به این دلیل تا همین جا به مطالب مربوط به REST بسنده میکنیم) 2- بجای آن که درون ReferralCode برای چک شدن Unique بودن کد معرف از Domain Service استفاده شود، مدل Marketer را Factory برای Referral Code قرار میدهیم. این کار علاوه بر اینکه مدل ما را Rich میکند، از عریض و طویل شدن مدل ها نیز جلوگیری میکند. این نکته را در نظر داشته باشید که حضور ReferralCode در Marketer به هیچ عنوان ناقض قوانین طراحی Model Driven نیست بلکه به عنوان یک Trade Off در طراحی در نظر گرفته شده است. برای متوجه شدن این مورد میتوان به اولین جواب در سوال مطرح شده در Stackoverflow رجوع کرد: DDD: How to check invariant with multiple aggregate3- شماره ارجاع بازاریاب، تنها در زمان ایجاد کد معرف کاربرد دارد و در زمان ساخته شدن مدل Marketer کاربردی ندارد. به همین دلیل از Sequenceهای دیتابیس برای تخصیص شماره استفاده شده است. شماره ارجاع بازاریاب را همیشه میتوان در زمان ایجاد کد معرف در اختیار داشت و اطلاعات کامل را از طریق Event به اطلاع سیستم های دیگر از جمله سیستم Query رساند.4- بدلیل اینکه تعداد کدهای معرف تولید شده توسط Application افزایش میابد، استفاده از Timestamp الزامی است تا از مشکلات همزمانی ذخیره در دیتابیس جلوگیری به عمل آید. (البته Timestamp میتواند بصورت Shadow Property با استفاده از قابلیت های ORM پیاده سازی شود)پس از اینکه مدل Marketer توضیح داده شد، میتوانیم به سراغ طراحی و پیاده سازی مدل ReferralCode برویم:مدل ReferralCodeدر طراحی مدل  نکات زیر در نظر گرفته شده است:1- سازنده این مدل بصورت internal قرار داده شده است تا تنها Factory آن که همان Marketer هست قادر به ساختن ReferralCode باشد. این عمل دقیقا نشان دهنده نیازمندی سیستم است که تنها بازاریاب قادر به ساختن کد معرف است. امروزه ORM های موجود نظیر EFCore قابلیت پشتیبانی از سازنده های internal همراه با پارامتر یا قابلیت استفاده از Factory برای مدل ها را دارا میباشند بنابراین مشکلی از لحاظ Mapping و بازخوانی مدل از دیتابیس پیش نخواهد آمد.2- در طراحی این مدل از چهارمین معیار طراحی استفاده شده است. بجای استفاده از Domain Service در مدل Customer برای تخصیص امتیاز اولیه، مدل های ReferralCode و Customer به هم ارتباط داده شده است. در این طراحی از Anemic شدن Customer اجتناب شده است. همچنین بیزینس مربوط به ReferralCode درون خودش قرار گرفته و این مدل را Rich کرده است.3- متد SetInitialRegisteringPoints بصورت internal قرار گرفته شده تا تنها مورد استفاده مدل های Domain قرار گیرد.پس از اینکه مدل ReferralCode توضیح داده شد، میتوانیم به سراغ طراحی و پیاده سازی مدل Customer برویم:مدل Customerدر طراحی مدل Customer این نکته در نظر گرفته شده است، که در زمان ساخته شدن مدل، امتیاز اولیه آن توسط ReferralCode تخصیص داده میشود. به همین دلیل ReferralCode در سازنده Customer آمده و همچنین Setter امتیاز مشتری نیز بصورت internal است.حال که مدل ها مشخص شدند، میتوانیم به سراغ Command و CommandHandlerی برویم که نیازمندی پروژه را پاسخ میدهند. طراحی آن ها به اینصورت خواهد بود:CreateCustomerCommandHandlerیک نکته در این طراحی وجود دارد. زمانی که مشتری کد معرف ندارد، ReferralCode آن Null است. اما این مورد در CommandHandler لحاظ نشده است. در حقیقت با استفاده از معیار شماره 3 طراحی سعی شده است که لایه های پایینی (درونی) بصورت هرچه Abstractتر طراحی شوند و Implemetation ها و احینا Cyclomatic های حاصله، به لایه های بالایی (بیرونی) انتقال داده شوند. برای اینکه این معیار را در طراحی در نظر بگیریم، با الهام گیری از الگوی طراحی Null Object، پیاده سازی ReferralCodeRepository را بدین صورت انجام میدهیم:(پیاده سازی ارتباط با دیتابیس انجام نشده است)ReferralCodeRepositoryNoReferralCodeبا استفاده از این طراحی، بجای آن که دو Command برای ثبت نام مشتری داشته باشیم یا برای پیاده سازی اینکار در لایه Application پیچیدگی Cyclomatic ایجاد کنیم، با رعایت معیار شماره 3 طراحی، یک دستی و سطح Abstraction لایه های پایینی (درونی) را حفظ خواهیم کرد.در طراحی های انجام شده، تمامی مدل ها Rich میباشند و حتی یک Domain Service استفاده نشده است. این در حالی است که تمامی مدل ها تنها فقط با  ID آن ها قابل دستیابی هستند. همچنین از ایجاد Aggregate های سنگین نیز اجتناب شده است. این طراحی ساده،  سبک و سریع مناسب سیستم های OLTP و متناظر با آن ها قسمت Write پروژه های DDD است.(نکته مهم حایز اهمیت آن است که، در قسمت Write، هیچ چیز اضافه ایی که برای انجام شدن Command ها مورد نیاز نیست، در State مدل ها نباید ذخیره شود. بسیاری از اطلاعات مورد نیاز در سیستم های مختلف، میتواند توسط  Integration Eventها فراهم شود. همچنین سیستم Query که توسط Event ها دیتای آن فراهم میشود، یک سیستم خبره OLAP است که برای ذخیره و بازیابی اطلاعات تنها نیاز به Event های ذخیره شده دارد. همشکل کردن Write و Read از اشتباهات معمول برنامه نویسان در پیاده سازی CQRS است.)جمع بندی:برای اینکه بتوان معیارهای طراحی را رعایت کرد و یک پیاده سازی مطابق با آن ها انجام داد، نیاز است که در به کار بردن الگوهای طراحی شی گرایی تفکر کرد و از آن ها در مسیر درست کمک گرفت. به کارگیری از الگوهای طراحی برای تطابق پیاده سازی با معیار ها، همان مسیر تفکر در Model Driven  است. تیم های نرم افزاری میتوانند در جلسات همفکری طراحی، پیشنهادات بیان شده را با معیارهای گفته شده تطابق دهند. هرکجا که طراحی مطابق با معیار ها نبود، مشکل را شناسایی و با استفاده از به کار گیری الگوهای طراحی شی گرایی، به یک طراحی مطابق با معیار های طراحی خوب Model Driven دست یابند.</description>
                <category>مهدی فلامرزی</category>
                <author>مهدی فلامرزی</author>
                <pubDate>Tue, 25 Oct 2022 01:35:20 +0330</pubDate>
            </item>
                    <item>
                <title>مسیر تفکر در طراحی Model Driven (قسمت اول)</title>
                <link>https://virgool.io/@m_22983838/modeldrivenpathofthinking-xt8cq0ggkoy0</link>
                <description>در پارادایم Model Driven سعی میشود با کمک طراحی شی گرایی، مدل کردن اعضا و رفتارهای یک سیستم انجام شود. از این طریق نیازمندی های نرم افزاری یک کسب کار، پیاده سازی و پاسخ داده میشود. در پروژه هایی که از تفکر و رویکرد DDD استفاده میشود، میتوان تلاش های بکارگیری این پارادایم طراحی را به وضوح مشاهده کرد.زمانی که پروژهای DDD از معماری CQRS بهره میبرند، بدلیل اینکه به کارگیری و طراحی Domain Model ها بصورت انحصاری، تنها برای Command ها انجام میشود، استفاده از الگوها و قواعد Model Driven به اوج خود میرسد. در چنین شرایطی، غایت طراحی بوجود آوردن مدل هایی است که رفتارهای سیستم مطلوب را به خوبی Encapsulate کرده اند. این پیاده سازی به گونه ایی است که برای اجرای Use Case های مربوط به یک مدل، آن مدل در Scope خود نیازمند ارتباط با بیرون از خود نیست. اصطلاحا به چنین مدل هایی Rich میگویند.در تیم های توسعه اغلب بخشی از طراحی بصورت گروهی در جلسات انجام میشود. از این طریق علاوه بر انتقال دانش و پیشبرد توسعه محصول، تیم نرم افزاری اقدام به کشف Domain و روشن ساختن مسیر پیش رو میکند. علی رغم وجود سینرژی در کارهای گروهی و همچنین مهارت های فردی در رویکرد DDD، طراحی مدل ها اغلب بصورت Anemic ظاهر میشود. این موضوع تا آنجا پیش میرود که مباحث طراحی در جلسات، اغلب به مناقشه کشیده میشوند و از منظر توسعه محصول، به غیر از سختی و پیچیدگی الگو های Model Driven، چیز دیگری در پیاده سازی ها باقی نمی ماند.زمانی که چنین پدیده هایی رخ میدهند، از نظر تحلیل سیستمی، اغلب نشان از این دارند که یک مسیر یا دیسیپلین مشخصی، برای انجام آن کار، یا شروع به انجام آن کار وجود ندارد. در این مقاله سه قسمتی سعی میشود با کمک مشخص کردن معیارهایی برای طراحی در پارادایم Model Driven، یک مسیر تفکر ایجاد شود. کاربرد این مسیر در یکسو سازی انرژی است که تیم توسعه، آن را برای طراحی بصورت گروهی، صرف میکند. همچنین میتوان از معیارهای مشخص شده به منظور سنجش کیفیت طراحی ها نیز استفاده کرد تا با بازبینی و بازنویسی های صورت گرفته بتوان به مدل های Rich دست پیدا کرد.در قسمت اول این مقاله، به معرفی معیارهای طراحی و همچنین القا تفکرات به گونه ایی که طراحی منطبق بر معیارها باشند پرداخته میشود. در قسمت دوم، طراحی بصورت عملی بر روی یک مثال کاربردی انجام میشود تا معیارهای طراحی را در  این مسیر، به نمایش بگذارد. در قسمت سوم آثار و فواید رعایت نکات بر روی طراحی بحث میشود. هر سه مقاله در شرایطی که یک محصول سازمانی، با رویکرد DDD و معماری CQRS پیاده سازی شده اند به بررسی نکات و بیان مطالب میپردازد.برای هر طراحی در وهله اول نیاز هست که مشخص کنیم چه سیستمی را میخواهیم طراحی کنیم. برای این منظور نگاه به طراحی سیستم از نظر نوع پردازش آنها بسیار سودمند است. از نظر پردازشی میتوان سیستم ها را به دو گروه OLTP و OLAP طبقه بندی کرد. در ادامه به معرفی و بیان تفاوت های آنها میپردازیم:سیستم های OLTP (Online Transaction Processing):هدف از طراحی این سیستم ها پاسخ دهی، پردازش و ذخیره درخواست های Transactional بصورت Real Time هست. این نوع سیستم ها به سبب تقسیم بندی انجام شده، به گونه ایی طراحی میشوند که حجم بسیار بالایی از اطلاعات Transactional را پشتیبانی کنند.این ویژگی در سیستم های OLTP سبب میشود که عملا از کوئری های پیچیده استفاده ایی نشود. در این سیستم ها ذخیره و بازیابی اطلاعات به ساده ترین شکل انجام میشود. به همین دلیل طراحی مدل ها در اینگونه سیستم ها اغلب بصورتی انجام میشود که به ساده ترین شکل به مدل ها دست پیدا کرد و از پایگاه داده، اطلاعات مربوط به آن مدل را استخراج کرد.سیستم های OLAP (Online Analytical Processing):هدف از طراحی این سیستم ها پردازش حجم بالای اطلاعاتی است که از سمت سیستم های OLTP تغذیه شده است. این سیستم ها به گونه ایی طراحی میشوند که توانایی بسیار زیادی برای کار بر روی داده ها را دارا باشند. همچنین این سیستم ها قابلیت اجرای سریع کوئری های پیچیده و بررسی سریع اطلاعات از ابعاد مختلف را دارا میباشند. اغلب از این سیستم ها به عنوان دریافت اطلاعات تصمیم گیری، برای ارسال درخواست به سیستم های OLTP استفاده میشود.این ویژگی در سیستم های OLAP سبب میشود که از پایگاه های داده با امکانات گزارش گیری پیشرفته استفاده شود.به همین دلیل طراحی مدل ها بصورت Data Driven در این سیستم ها بسیار متداول است.دستیابی به مدل ها از طریق ID:بعد از معرفی این دو سیستم از دید پردازش اطلاعات، می توان در رابطه با این موضوع بحث کرد، در یک پروژه سازمانی که با رویکرد DDD توسعه می یابد و از معماری CQRS بهره می برد، تیم توسعه در حال ساخت چه سیستم هایی است؟ با تطبیق ویژگی های سیستمی که در بخش های قبل بحث شد، با مرزهای مشخص شده از نظر کارایی فنی در چنین محصولی، به وضوح میتوان به این نتیجه رسید که قسمت Write سیستم منطبق بر OLTP و قسمت Read سیستم منطبق بر OLAP خواهد  بود.بنابراین در اینجا میتوان نتیجه گرفت که تفکر طراحی Model Driven باید بیشتر منطبق بر OLTP باشد. به بیان دیگر در یک طراحی Model Driven خوب، دستیابی به Aggregate ها بیشتر توسط ID آن ها صورت خواهد گرفت تا توصیف و یا ویژگی ایی از آن ها. میتوان اینگونه تصور کرد که برای قسمت Write تنها یک پایگاه داده key:value در اختیار است و برای انجام این مهم از الگو های طراحی شی گرایی در سطح پیشرفته استفاده میشود. این مورد را میتوان به عنوان اولین معیار در طراحی خوب Model Driven در نظر گرفت.اجتناب از Down Casting برای مشتق شده های یک Aggregate:معمولا در پروژه های DDD شرایطی پیش میاید که رفتارهای مشترک با پیاده سازی های مختلف شناسایی میشوند. یکی از راه حل ها استفاده از Inheritance هست. زمانی که از این تکنیک بصورت صحیح استفاده میشود هیچ وقت نیاز نیست در فلو های اصلی عمل Down Casting صورت گیرد. این قضیه هنگام فراخوانی Aggregate ها از Repository نیز صادق است. به بیان دیگر یک Aggregate اگر مشتق شده باشد در همه جای Domain بغیر از زمان new شدن باید با phase کلاس base آن دیده شود. این موضوع در زمان فراخوانی یک Aggregate مشتق شده بسیار حائز اهمیت است. این مورد را میتوان به عنوان دومین معیار در طراحی خوب Model Driven در نظر گرفت.جداسازی Use Case ها در لایه های پایینی:برای مشخص کردن این موضوع خیلی کوتاه در مورد اینکه کدام لایه ها پایینی یا بالایی هستند بحث میکنیم. عموما پروژه های DDD از معماری های Domain Centric بهره میبرند. بصورت عمومی لایه هایی که اغلب Bootstrapper هستند و یا پیاده سازی Abstract های مختلف را شامل میشوند، لایه های پایینی اطلاق میشوند. در معماری های Domain Centric نظیر Onion بیرونی ترین لایه، قسمت های لایه هایی پایینی محسوب میشوند.روند Abstraction در یک طراحی خوب Model Driven بصورت کاهشی از لایه های بالایی به لایه های پایینی است. به عبارت دیگر همیشه سعی بر آن است که لایه های بالایی همیشه بصورت همگن و Abstract قرار گیرند. این روند با استفاده از الگوهای طراحی بصورت کاهشی به سمت لایه های پایینی انجام میشود. تلاش در همگن سازی و نگهداری سطح Abstraction در لایه های بالایی را میتوان به عنوان سومین معیار در طراحی خوب Model Driven در نظر گرفت.ارتباط دادن Aggregate Root ها بجای استفاده از Domain Service:در پروژه های DDD معمولا طراحی به اینصورت دیده میشود که Aggregate ها باهم در ارتباط نیستند و این عمل اغلب با این توجیه انجام میشود که Granularity باید در حدی باشد که بتوان به راحتی یک Aggregate را در BCیی به BC دیگر انتقال داد. اما این در حالی است که در سال های اخیر بسیار تاکید بر آن شده که طراحی مرزهای Sub Domain ها و به طبع آن BC ها باید بصورتی دقیق انجام شود که در ادامه پروژه دستخوش تغییرات بزرگی نشوند. البته پیش از این تجارب تاکید لزوم تفکر و تحلیل صحیح در قسمت Strategic طراحی DDD گواه این واقعیت بوده است که این قسمت از پروژه های نرم افزاری، عموما یک تصمیم معماری غیر قابل بازگشت است. بنابراین میتوان توجیه Granularity برای طراحی Aggregate ها را عملا ناکارآمد دانست.همچنین برای بحث در مورد این موضوع، بسیار مفید است که به بیان یک اصل درمورد پیچیدگی نیز پرداخت: &quot;در یک سیستم بسته پیچیدگی هیچگاه از بین نمیرود بلکه ممکن است از جایی به جای دیگر منتقل میشود&quot;. این جمله در بعضی از مطالب به قانون پایستگی پیچیدگی و یا قانون Tesler معروف است. در Model Driven سعی شده است با ابداع و یا جمع آوری الگو های طراحی نظیر Aggregate Root ، ارتباطات بین کلاس ها و یا در اصطلاح Coupling بین آن ها را کنترل کرد. چون ارتباطات و Coupling بین اجزا قسمتی از ویژگی های یک پدیده پیچیده است، میتوان این بخش را با استفاده از پیچیدگی تحلیل کرد.برای استفاده از الگو طراحی Aggregate Root انجام Classification و Fragmentation بر روی بیزینس لاجیک ها غیر قابل اجتناب است. این در حالی است که در همه Use Case ها این امکان وجود ندارد که یک بیزینس لاجیک Classify شده بصورت تنها به کار گرفته شود. عدم توجه به این نکته غالبا خود را بصورت Aggregate هایی با Hierarchy عریض و طویل نمایش میدهد. این در حالی است که قانون پایستگی پیچیدگی سبب میشود زمانی که Use Caseی به یک Fragment از لاجیک دیگر نیاز داشت، این نیاز ارتباطی با استفاده از Domain Service انجام شود. در اینصورت طراحی Aggregate ها هرچه بیشتر به سمت Anemic شدن پیش خواهد رفت. رعایت اصل پایستگی پیچیدگی و استفاده از الگو های طراحی شی گرا، در زمانی که به Fragment های مختلف از بیزینس لاجیک ها نیاز باشد را میتوان به عنوان چهارمین معیار طراحی خوب Model Driven در نظر گرفت.تا به اینجا معیارهای بیان شد که ارتباط مستقیمی با طراحی Model Driven داشتند. در ادامه به دو معیار فرعی برای طراحی اشاره میکنیم که بصورت غیر مستقیم بر Model Driven تاثیر گذار هستند.جداسازی Process های Sync و Async:در پیاده سازی Use Case ها اغلب شرایطی دیده میشود که یک Use Case شامل چندین عدد زیر مجموعه اجرایی در قالب Use Case های دیگر باشد. در پروژه های DDD با بهره گیری از CQRS، این موضوع بصورت Dispatch شدن یک Sequence از Commandها پیاده سازی میشود. عموما مشاهده میشود که حتی Use Case هایی که بصورت Side Effect هستند نیز در پروسه اصلی قرار میگیرند. در حالی که Use Case های Side Effect عموما میتوانند بصورت Async در پروسه دیگر قرار بگیرند. با استفاده از Event ها میتوان پردازش این مدل Use Case ها را در پروسه دیگر انجام داد. این موضوع حتی اگر Handler ها در یک مرز  سیستم نیز باشند صادق است. بنابراین میتوان جداسازی Process های Sync و Async را پنجمین معیار طراحی خوب Model Driven در نظر گرفت.استفاده از Saga Choreography در زمان ارتباطات برون مرزی سیستمی: ارتباطات بین مرزی سیستمی همیشه یک بحث چالش برانگیزی در مهندسی نرم افزار بوده است. بیان این نکته بسیار حائز اهمیت است که الگوهای معماری ایی مانند Bounded Context اساسا تاکید بر استقلال مرزها دارند. بنابر این ارتباطات و وابستگی های برون مرزی بیش از اندازه، مخل موضوع استقلال مرز ها هستند. در نتیجه در پروژه های DDD انتظار میرود که اکثر Use Case های Sync بصورت درون مرزی پاسخ داده شوند و نیاز چندانی به ارتباطات برون مرزی نداشته باشند. تقابل این موضوع در طراحی ماکروسرویس ها، سو تفاهمی است که بخشی از آن باید در مقاله دیگر بررسی شود و بخش دیگر آن در مقاله تفاوت دیدگاه در طراحی های کلاسیک و DDD بررسی شده است.در نتیجه در پروژه های DDD باید به دید یک استثنا به ارتباطات برون مرزی درون سیستمی نگریست. از این رو لازم است که برای حفظ Loose Coupling سیستم ها و همچنین Deploy شدن آنها بصورت مستقل، از  Saga Choreography استفاده کرد. این موضوع استفاده از Stateهای میانی برای بعضی از Aggregate ها را نتیجه میدهد. بنابراین استفاده از Choreography و همچنین Stateهای میانی برای بعضی از Aggregate ها را میتوان به عنوان ششمین معیار طراحی Model Driven خوب مطرح کرد.جمع بندی:پروژه های DDD اغلب با بهره گیری از تکنیک Model Driven و الگوهای طراحی آن پیاده سازی میشوند. درصورتی که کتاب ها و مطالب در این موضوع فراوان در مورد قواعد و الگوها صحبت میکنند اما معیارهایی بصورت مشخص برای سنجش و هدایت طراحی ها در اختیار نیست. در این مقاله سعی شده است معیارهایی برای طراحی Model Driven خوب مطرح شوند که عبارتند از:دستیابی به مدل ها از طریق IDاجتناب از Down Casting برای مشتق شده های یک Aggregateجداسازی Use Case ها در لایه های پایینیارتباط دادن Aggregate Root ها بجای استفاده از Domain Serviceجداسازی Process های Sync و Asyncاستفاده از Saga Choreography در زمان ارتباطات برون مرزی سیستمی</description>
                <category>مهدی فلامرزی</category>
                <author>مهدی فلامرزی</author>
                <pubDate>Sun, 23 Oct 2022 02:19:21 +0330</pubDate>
            </item>
                    <item>
                <title>تفاوت دیدگاه در طراحی های کلاسیک و DDD</title>
                <link>https://virgool.io/@m_22983838/%D8%AA%D9%81%D8%A7%D9%88%D8%AA-%D8%AF%DB%8C%D8%AF%DA%AF%D8%A7%D9%87-%D8%AF%D8%B1-%D8%B7%D8%B1%D8%A7%D8%AD%DB%8C-%D9%87%D8%A7%DB%8C-%DA%A9%D9%84%D8%A7%D8%B3%DB%8C%DA%A9-%D9%88-ddd-u8fdajovwm25</link>
                <description>در این مقاله به بررسی تفاوت تفکر طراحی سطح بالای کلاسیک و DDD پرداخته میشود.برای پیش بردن این مقاله، طراحی ها بر روی یک مثال کاربردی محدود صورت میگیرند. تلاش شده است که مثال طراحی شده نزدیک به حالت واقعی فرایندهای سازمانی بزرگ باشد تا ابعاد مورد نظر را بصورت کاملی شامل شود. همچنین تلاش شده است طراحی های انجام شده، درگیر با اصطلاحات تخصصی و الگوهای متداول مربوط به حوزه DDD نباشند، تا انتقال پیام به درستی بدون پرداختن به حاشیه های این موضوع، صورت گیرد. دراین طراحی سطح بالا به ارتباطات بخش های مختلف نرم افزار در سطح Solution توجه شده است. طراحی و تحلیل مدل های سطوح پایین مورد موضوع این مقاله نیست.مثالی که طراحی روی آن صورت میگیرد شامل بخش های فروش، انبار، حسابداری و لجستیک یک فروش آنلاین میباشد. در این مثال طراحی، تنها سعی شده است دید تحلیلی خوانندگان در طراحی سیستم ها و ارتباطات بین سیستمی مورد موضوع قرارگیرد. بدیهی است که طراحی سیستم ها و معماری آنها مستلزم در نظر گرفتن نکات و ظرافت های بسیار زیادی است که گاهی حتی روش های بسیار خاصی محدود به همان شرایط را میطلبد.شرح این فرایند بدین صورت است، که ابتدا تحویل کالاهای مورد نیاز توسط انبار صورت می گیرد، سپس بخش فروش اقدام به ارائه و فروش آن کالا ها میکند. پس از آن بخش لجستیک اقدام به تحویل و برنامه ریزی آن برای مرسولات میکند و با محاسبات هزینه و دریافتی ها در بخش حسابداری، فرایند ها کامل میشوند.دیاگرام USE CASE زیر، سیستم های مورد بحث را نشان میدهد:دیاگرام USE CASE زیر فرایندها سیستم هادر این مثال در قسمت انبارداری به منظور کارهای ثبتی حسابداری، بعد از تحویل گیری کالاها و گرفتن موجودی در انبار، باید اسناد معادل آن ثبت شود. همچنین در قسمت های فروش و لجستیک نیز به ترتیب برای ثبت مبلغ فروش و هزینه ارسال کالا، نیاز به قسمت حسابداری است. همچنین در قسمت فروش پس از اینکه پرداختی کالای خریداری شده توسط مشتری انجام شد، باید از موجودی آن در انبار کم شود.این مثال از این جهت که نیازمند ارتباط بین قسمت ها و سیستم های مختلف هست، دارای پیچیدگی میباشد که برای این منظور باید در سطح بالا، نوعی طراحی را انجام داد تا ارتباطات بین قسمت های مختلف را تامین و تسهیل کند.طراحی ارتباطات بین سیستمی در دیدگاه کلاسیک:در دیدگاه کلاسیک توسعه نرم افزار اساسا اهمیت خیلی زیادی به ساختارهای جدولی و نرمالیزه شده است. طبیعی است که در این حالت جداول شامل اطلاعاتی خواهند شد که تنها برای استفاده از یک قسمت نرم افزار نخواهد بود، بلکه ماژول های زیادی از اطلاعات داخل جداول استفاده میکنند. هرچند دیدگاه کلاسیک در چالش هایی مانند گرفتن گزارشات سریع ممکن است بخشی از اطلاعات جداول را از حالت نرمال خارج کند، اما توسعه ابزارها و امکانات پایگاه داده ایی در این جهت است که امکان گزارش گیری سریع را برای اطلاعات هرچه بیشتر نرمالیزه شده فراهم آورد.با توجه به توضیحات داده شده، میتوان طراحی زیر را برای مثال گفته شده تصور کرد:مدل نرمالیزه شده مثال در طراحی کلاسیکدر این طراحی ارتباط بین ماژول ها و سیستم ها از طریق جداول واسط تعبیه میشود. همانطور که از جداول مشخص است به دلیل نرمالیزه شدن اطلاعات، هر قسمت برای انجام فرایند مخصوص به خود، نیازمند اطلاعات مربوط به قسمت های دیگر نیز هست. برای مثال  قسمت لجستیک برای اینکه بتواند برای تحویل سفارشات یک روز، برنامه ریزی پیک ها را داشته باشد، به جدول آدرس های ثبت شده مشتریان برای یک سفارش نیازمند است. بنابراین در این طراحی، وابستگی فیزیکی و معنایی در اطلاعات اجتناب ناپذیر است و اطلاعاتی که در جداول نگهداری می شوند، بیشتر برحسب نرمالیزیشن و ماهیت آن ها طبقه بندی می شوند تا کاربرد و یا درک ماژول ها از آن ها.معایب طراحی کلاسیک:1- به دلیل رعایت نرمالیزیشن به عنوان یک اصل در طراحی مدل های اطلاعاتی، با گذشت زمان و طراحی نیازمندی های جدید، اضافه شدن ستون های جداول منجر به بیشتر و پیچیده تر شدن  اطلاعات جداول خواهد شد. به بیان دیگر رشد اطلاعات در جداول بیشتر بصورت عمودی خواهد بود. همینطور با بزرگتر شدن سیستم ها، سطوح نرمالیزیشن بیشتری نیز مورد نیاز است که ارتباطات جداول را پیچیده تر میکند.2- وابستگی ایجاد شده باعث میشود که تغییرات در هر ماژولی بدون در نظر گرفتن تاثیرات آن در فرایند های دیگر ماژول ها، امکان پذیر نباشد.3- نیازمندی ماژول ها به اطلاعات و نحوه ذخیره سازی اطلاعات در ماژول ها دیگر، باعث میشود عملا تیم های مستقل نرم افزاری شکل نگیرند. اغلب محصولات سازمانی ایی که به اینصورت توسعه داده و طراحی شده اند، بیشتر شبیه به یک تیم بسیار بزرگی هستند که تحت نظر یکی از افراد قدیمی و با سابقه آن جا هدایت می شوند. این ساختار تیمی و سازمانی، با تیم های کوچک و چابک مستقل نرم افزاری بسیار تفاوت دارد.4- پیچیدگی و وابستگی های ایجاد شده مانع از پیشرفت طراحی به سمت معماری های مدرن نرم افزاری میشود.5- در این بینش طراحی اساسا مدل های اطلاعات حول قوانین ثابتی همچون ارتباطات جدولی و نرمالیزیشن انجام میپذیرد. این رویکرد به دلیل ثابت بودن اصول و قوانین، عملا طراحی مدل های بهینه صورت نمی گیرد و به جای آن خلاقیت و تلاش ها در واکشی بهینه اطلاعات انجام می پذیرد. این روند موجب میشود که روز به روز وابستگی فرایندهای نرم افزار به امکانات و محدودیت های از پیش تعیین شده پایگاه داده بیشتر شود. این وابستگی گاهی آن چنان پیش میرود که برای طراحی فرایندهای نرم افزاری، ابتدا محدودیت های پایگاه داده مد نظر گرفته میشود و سپس طراحی انجام میپذیرد.6- با اضافه شدن ماژول ها و امکانات دیگر، تعدد در جداول و ارتباطات بین آن ها به گونه ایی پیچیده میشود که عملا ذهن یک نفر برای بخاطر سپردن آن ها کافی نیست، یا به بیان دیگر در یک ذهن جا نمیشود. این در حالی است که یک سیستم مستقل با فرایند های مشخص نباید به چنین حد از پیچیدگی برسد.7- در چنین محصولاتی تلاش توسعه دهندگان عملا به یادگیری هرچه بیشتر دیتابیس منتهی میشود تا اصول طراحی و بکارگیری آن ها در طراحی مدل های نرم افزاری و اطلاعاتی.طراحی ارتباطات بین سیستمی در دیدگاه DDD:در مقایسه با دید کلاسیک در طراحی ارتباطات بین سیستمی، نرمالیزشن در این سطح اعمال نمیشود و مبنای ارتباطی بین آنها قراردادهای بین سیستمی است. این قراردادهای بین سیستمی بعد از انجام عملیات خاصی در یک سیستم، به دیگر سیستم ها اعلان میشود که هر کدام بصورت رویدادی خاص معرفی میشوند. یک سیستم پس از دریافت رویدادی، به میزان مورد نیازش از اطلاعات رویداد، در سیستم خود استفاده میکند. این استفاده می تواند همراه با پردازش روی اطلاعات نیز باشد.سیستم ها برای مشخص کردن نیاز اطلاعاتی خود از یک مفهوم، به نقطه نظری که از آن مفهوم دارند رجوع میکنند. قبل از طراحی ارتباطات بین سیستمی لازم است با مفهوم نقطه نظر در دیدگاه DDD آشنا شویم.مفهوم نقطه (Point Of View) در نظر در دیدگاه  DDD : نقطه نظر یک سیستم بیانگر ادراک آن سیستم از یک مفهوم است. برای روشن شدن این تعریف، اول به بررسی نوع فرایند های مد نظر در مثال، برای هر سیستم می پردازیم، سپس نقطه نظرات سیستم های مختلف را برای مفاهیم معرفی شده ، تحلیل و بررسی میکنیم.تحلیل و بررسی سیستم انبار:در سیستم انبار فوکوس کار بر روی دریافت، انبار داری و تحویل دهی کالاها است. در این سیستم عمده فرایند های مهم عبارتند از: انبارداری، انبارگردانی و نقل و انتقالات درون سیستمی. سیستم انبار برای انجام فرایند های خود نیازمند کالا و مشخصات آن است. مشخصات مورد نیاز یک کالا برای انبار میتواند ابعاد، وزن، نوع، بسته بندی، رده ارزشی و تعداد کالا باشد.تحلیل و بررس سیستم فروش:در این سیستم تمرکز فرایند ها بر روی فروش و مسائل مربوط به آن است. بنابراین در این سیستم توجه اصلی بیشتر برروی ارزش، موجودی، مشخصات محتوایی کالا ها است. این سیستم بوسیله این اطلاعات میتواند فرایند های مربوط به فروش را انجام دهد.تحلیل و بررسی سیستم لجستیک:در این سیستم برنامه ریزی و انجام فرایند های ارسال، بر اساس زمان مرسولات، مشخصات و اولویت های برنامه ریزی شده برای آن ها انجام میشوند. در این سیستم مشخصات وزنی، ابعادی، نوع  کالاها، گیرنده و آدرس گیرنده اهمیت دارد.تحلیل و بررسی سیستم حسابداری:در این سیستم تمرکز بر روی حساب و مشخصات مالی فرایند ها است. به بیان دیگر برای این سیستم تنها هزینه رد و بدل شده، طرفین حساب، تاریخ، و دلیل فرایند مالی مورد توجه هستند.با توجه به تحلیل های بالا، نقطه نظرات و روند اطلاعات کالا در سیستم های مورد بحث به قرار زیر خواهد بود:روند اطلاعات کالا در سیستم هاتصویر بالا نشان میدهد که نقطه نظر سیستم انبارداری از کالا، یک چیز قابل انبار کردن است بدین ترتیب تنها مشخصاتی از آن برایش اهمیت دارد که در فرایند های انبارداری به آن نیاز دارد. همچنین نقطه نظر سیستم فروش یک چیز فروختنی است. هرچند موجودی کالا در انبار برای این بخش مهم است، اما بدیهی است که اطلاعات انباری آن برای این بخش کافی نیست. این بخش باید برای فرایند های خود اطلاعات مورد نیاز برای کالاها، نظیر قیمت، تخفیفات و محتوا را در مرز سیستم خود تهیه و نگهداری کند. در سیستم لجستیک کالا معنای مستقلی ندارد و با مفهوم سفارش تعریف میشود. در این سیستم هر سفارش یک بسته برای تحویل است که کالا ها، محتویات بسته ایی هستند که باید به دست گیرنده برسد.با توجه به توضیحات بالا، روند اطلاعات برای کالاها به صورت زیر خواهد بود:1- پذیرش Stuff در سیستم انبار و اعلان رویداد پذیرش کالا2- دریافت رویداد پذیرش کالا در سیستم فروش و تعریف Good برای فروش3- تکمیل اطلاعات Good برای فرایند فروش و مشخص شدن آن برای موارد قابل فروش4- فروش Good ها در یک سفارش و اعلان رویداد سفارش5- دریافت رویداد سفارش توسط سیستم انبار و کثر موجودی Stuff های معادل در انبار6- انتقال Stuff های کسر شده به بخش لجستیک7- دریافت اعلان رویداد سفارش توسط سیستم لجستیک و تعریف Package آن به همراه Package Item های معادل8- برنامه ریزی Package ها در سیستم انبار برای ارسال آن ها9- ارسال یک Package توسط سیستم لجستیک و اعلان رویداد ارسالبا توجه به تحلیل های بالا نقطه نظرات و روند اطلاعات Party در سیستم های مورد بحث به قرار زیر خواهد بود:روند اطلاعات Party در سیستم هاتصویر بالا نشان میدهد که نقطه نظر سیستم فروش از یک Party یک مشتری است. همچنین در سیستم لجستیک مفهوم Party به معنی راننده است. این قضیه برای سیستم حسابداری اینگونه است که Party هرچیزی که باشد در این سیستم تنها میتواند یک طرف حساب مالی تلقی شود.با توجه به توضیحات بالا، روند اطلاعات برای Party به صورت زیر خواهد بود:1- تعریف مشتری در سیستم فروش و اعلان رویداد تعریف مشتری2- دریافت رویداد تعریف مشتری توسط سیستم حسابداری و ایجاد حساب مربوط به آن1- تعریف راننده در سیستم لجستیک و اعلان رویداد تعریف راننده2- دریافت رویداد تعریف راننده توسط سیستم حسابداری و ایجاد حساب مربوط به آنبا توجه به بررسی نقطه نظرهای سیستم ها، طراحی سیسام ها و ارتباطات آنها در دیدگاه DDD به صورت زیر خواهد بود: طراحی سیسام ها و ارتباطات در دیدگاه DDDچند نکته در طراحی بالا قابل توجه است:1- برای مفاهیم Party وکالا دیگر جداولی وجود ندارند و بجای آن، اطلاعات مورد نیاز از این مفاهیم بصورت Redundant درون هر سیستم ذخیره شده است. در این طراحی گرچه در سطح ارتباطی بین سیستم ها، نرمالیزشن انجام نشده، اما Redundancy ایجاد شده باعث این میشود که استقلال سیستم های اطلاعاتی محفوظ بماند. به عنوان مثال می توانیم سیستم فروش و انبار را مد نظر بگیریم. در طراحی جدید، جدا شدن ذخیره اطلاعات انباری کالا از فروش آن سبب میشود که فرآیند فروش کالا از فرایند های انبار مجزا شود، به گونه ایی که سبب میشود حتی بتوان از این سیستم فروش بصورت مستقل استفاده کرد. تا آن جا که سیستم فروش حتی میتواند بدون انبار نیز فرایند های خود را انجام دهد. این ویژگی در نرم افزارهای سازمانی بسیار اهمیت دارد که یک سیستم بتواند به صورت مستقل از دیگر سیستم ها کار کند و به راحتی قابل یکپارچه سازی با دیگر سیستم ها (حتی سیستم هایی که توسط دیگر شرکت ها عرضه شده اند) باشد.2- ارتباطات بین سیستمی تنها بوسیله رویداد ها انجام میشود و تنها در موارد خیلی خاص، ارتباط مستقیم صورت می پذیرد.3- در هیچ سیستمی در سطح معماری نرم افزار دسترسی مستقیم به زیرساخت های ذخیره و بازیابی اطلاعات دیگر سیستم ها وجود ندارد.4- به خاطر وجود نقطه نظرهای هر سیستم از مفاهیم، هر کدام از سیستم ها میتوانند اصطلاحات و تعبیرهای مخصوص به خود را داشته باشد. این اسقلال معنایی و مفهومی در تمامی سطوح فنی و تحلیلی مرز یک سیستم وجود خواهد داشت. از این جهت به این استقلال معنایی و مفهومی، زبان فراگیر آن سیستم نیز گفته میشود.جمع بندی:تفاوت بسیار اساسی در طراحی های کلاسیک و DDD وجود دارد که اساسا بدون تغییر در بینش و تفکر به هیچ عنوان مزایای استفاده از DDD یا بوجود نمی آید و یا اینکه برای بهره بردن از آن ها به صرفه نیست. از مهمترین تفاوت های نگرش در این دو بینش نگاه به نرمالیزیشن و ارتباطات بین سیستمی است. در دیدگاه DDD ارتباطات بین سیستمی در ذخیره سازی اطلاعات محدود به نقطه نظر سیستم است. بازه ی ذخیره سازی و بازیابی این اطلاعات محدود به مرز کاربردی سیستم از اطلاعات است و به هیچ وجه دیگر سیستم ها را شامل نمیشود.</description>
                <category>مهدی فلامرزی</category>
                <author>مهدی فلامرزی</author>
                <pubDate>Sun, 15 Aug 2021 03:58:03 +0430</pubDate>
            </item>
                    <item>
                <title>(حداقل) از MediatR چگونه استفاده کنیم</title>
                <link>https://virgool.io/@m_22983838/mediatr-part1-xsmcywto2ur7</link>
                <description>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 باید از مدل های متنوع و حتی پایگاه های داده متفاوت استفاده کنیم.اما این پیچیدگی زمانی باید به پروژه اعمال شود که دستاورد قابل توجهی از نظر طراحی و کارایی سیستم داشته باشد.</description>
                <category>مهدی فلامرزی</category>
                <author>مهدی فلامرزی</author>
                <pubDate>Thu, 07 Jan 2021 14:29:42 +0330</pubDate>
            </item>
            </channel>
</rss>