يعرض هذا المستند تفاصيل Foodtruacker، وهو مشروع ينفذ التصميم المستند إلى المجال (DDD)، وCQRS، ومصادر الأحداث. يستخدم ASP.NET Core ويركز على تحسين قابلية الصيانة في مجالات الأعمال المعقدة. يستخدم المشروع حالة عمل خيالية مبسطة لأغراض توضيحية. يغطي هذا الشرح التفصيلي الدوافع والميزات وتفاصيل التنفيذ والتقنيات ذات الصلة.
Foodtruacker - تنفيذ DDD وCQRS ومصادر الأحداث
يستخدم هذا المشروع القائم على الأحداث المبادئ والأطر والبنيات - وكلها تتمحور حول فكرة تعزيز قابلية الصيانة عند التعامل مع الأنظمة التي تعكس مجالات الأعمال المعقدة. تم بناء واجهة برمجة تطبيقات الويب الخاصة بالتطبيق على إطار عمل Microsoft ASP.NET Core وتنفذ التصميم المستند إلى المجال، بالإضافة إلى أنماط CQRS ومصادر الأحداث. تضع حالة عمل خيالية أساس هذا المشروع وهي نتيجة ورشة عمل عاصفة للحدث.
يرجى ملاحظة: تم تبسيط نطاق الأعمال الخيالي المقدم لهذا المشروع إلى حد كبير ويجب أن يُنظر إليه فقط على أنه مزود لحالات الاستخدام ذات الصلة.
تحفيز
نظرًا لأنه ليس من الأفضل دائمًا استخدام عمليات CRUD وكائنات POCO في المشاريع ذات مجالات الأعمال المعقدة إلى حد ما، فقد قررت إنشاء هذا المشروع كتنفيذ عملي لبحثي حول التصميم المستند إلى المجال (DDD) والاهتمام به. نهج تطوير البرمجيات.
نظرًا لأن حالة العمل الخيالية المقدمة لهذا المشروع تعتمد بشكل كبير على الأحداث، فقد قررت أيضًا تنفيذ أنماط CQRS ومصادر الأحداث. كلاهما لفت انتباهي أثناء إجراء البحث لهذا المشروع وكانا يسيران بشكل جيد مع DDD.
سمات
ملخص
يتكون هذا المشروع من تطبيق Web API واحد قابل للتنفيذ والعديد من المكونات الوظيفية، يتم توفير كل منها عبر مكتبات الفئات. يتم تنظيم الكود حسب مساحات الأسماء. في تطبيقات ASP.NET Core التي تم إنشاؤها في Visual Studio، يتم إنشاء مساحات الأسماء، افتراضيًا، تلقائيًا من بنية مجلد المشروعات. انظر الرسم البياني أدناه للحصول على نظرة عامة على بنية المجلد (ومساحة الاسم) لهذا المشروع:
مقدمة
عاصفة الحدث
صيغة ورشة عمل مرنة للاستكشاف التعاوني لمجالات الأعمال المعقدة، ابتكرها ألبرتو براندوليني. إنها منهجية خفيفة الوزن للغاية لتحسين وتصور واستكشاف وتصميم تدفقات الأعمال والعمليات داخل مؤسستك بسرعة.
تتكون ورشة العمل من مجموعة من الأشخاص ذوي خبرات مختلفة يستخدمون الملاحظات اللاصقة الملونة لتخطيط العمليات التجارية ذات الصلة بشكل تعاوني. من الضروري أن تضم ورشة عمل EventStorming الأشخاص المناسبين وأن يكون لديها مساحة كافية لوضع الملاحظات اللاصقة عليها. يشمل الأشخاص المطلوبون عادةً أولئك الذين يعرفون الأسئلة التي يجب طرحها (عادةً المطورين) وأولئك الذين يعرفون الإجابات (خبراء المجال، وأصحاب المنتجات).
الهدف من ورشة العمل هذه هو جعل المشاركين يتعلمون من بعضهم البعض، والكشف عن المفاهيم الخاطئة ودحضها، وعلى سبيل المثال، في مشروع GitHub هذا، القيام بالأساس لتطوير حل برمجي قائم على الحدث يعكس مجال الأعمال المرتبط.
التصميم القائم على المجال (DDD)
نهج لتطوير البرمجيات يركز التطوير على برمجة نموذج المجال الذي يتمتع بفهم غني للعمليات والقواعد الخاصة بمجال الأعمال المرتبط. مصطلح "التصميم الموجه بالمجال" صاغه إريك إيفانز في كتابه الذي يحمل نفس العنوان.
يهدف DDD إلى تسهيل إنشاء التطبيقات المعقدة ويركز على ثلاثة مبادئ أساسية:
يحدد كتاب إريك إيفانز بعض المصطلحات الشائعة للتصميم المبني على المجال:
نموذج المجال
نظام تجريد يصف العمليات والسياسات الخاصة بمجال الأعمال ويستخدم للتعامل مع المهام المطلوبة المرتبطة بهذا المجال.
لغة في كل مكان
كلمات وبيانات لعناصر معينة من مجال الأعمال. من أجل حماية المفاهيم الخاطئة مرة أخرى، يجب على جميع أعضاء الفريق اعتماد مصطلحات معينة، عادة تلك التي يستخدمها خبراء المجال.
السياق المحدود
حدود مفاهيمية يتم من خلالها تحديد نموذج مجال معين وقابل للتطبيق. يمثل هذا عادةً نظامًا فرعيًا أو مجال عمل. إنه في الأساس ترسيم حدود لغوية، حيث يكون لكل سياق محدد لغته المنتشرة في كل مكان.
على سبيل المثال: إدارة العملاء حيث يُطلق على المستخدم اسم "العميل".
يميز كتاب إريك إيفانز أيضًا أجزاء معينة من نموذج المجال. على سبيل المثال لا الحصر:
كيان
كائن يتم تعريفه بهويته بدلاً من سماته.
على سبيل المثال: سيظل الشخص دائمًا هو نفسه، بغض النظر عن اختيار السترة أو لون الشعر أو اللغة التي يتحدث بها في لحظة معينة.
كائن القيمة
كائن يتم تعريفه فقط من خلال قيمة سماته. كائنات القيمة غير قابلة للتغيير وليس لها هوية فريدة. يمكن استبدال كائنات القيمة بكائنات قيمة أخرى لها نفس السمات.
على سبيل المثال: عند التركيز على شخص ما، يمكن بسهولة استبدال زوج من النظارات الشمسية المكسورة بزوج جديد من النظارات الشمسية بنفس المظهر.
إجمالي
مجموعة مكونة من كيان واحد أو أكثر وكائنات قيمة اختيارية، موحدة لتكون وحدة معاملات واحدة. سيشكل كيان واحد قاعدة التجميع وبالتالي يتم إعلانه كجذر إجمالي. لا يجوز الوصول إلى جميع خصائص الكيانات المتعاونة وكائنات القيمة إلا من خلال هذا الكيان الأساسي الوحيد. يجب أن يكون التجميع دائمًا في حالة متسقة. في البرمجة الموجهة للكائنات، يتم ذلك عادةً باستخدام أدوات ضبط خاصة وحروف محمية.
على سبيل المثال: في سياق مبيعات السيارات، يتم تعريف سيارة واحدة (الكيان) من خلال رقم تعريف السيارة الخاص بها. قد تحتوي هذه السيارة على أربع عجلات (كائنات ذات قيمة)، والتي قد تحتاج إلى استبدالها بعد فترة زمنية معينة.
حدث المجال
كائن تم إنشاؤه كنتيجة للنشاط داخل نموذج المجال. يتم استخدامه للاحتفاظ بالمعلومات المتعلقة بهذا النشاط وإعادة توجيهها. يتم عادةً إنشاء أحداث النطاق لتلك الأنشطة التي يعتبرها خبراء المجال ذات صلة.
بنية سداسية (المنافذ والمحولات)
نمط معماري يستخدم في تصميم البرمجيات، اقترحه أليستير كوكبيرن في عام 2005. يهدف هذا النمط إلى تحقيق درجة عالية من قابلية الصيانة ويصف التطبيق في ثلاث طبقات. تتواصل كل طبقة مع الطبقة (الطبقات) المجاورة باستخدام الواجهات (المنافذ) والتطبيقات (المحولات):
القاعدة الأساسية في نمط البنية هذا هي أن التبعيات يمكن أن تشير إلى الداخل فقط. لا يمكن لأي شيء في الدائرة الداخلية أن يعرف أي شيء على الإطلاق عن شيء ما في الدائرة الخارجية. أي تبعيات ترغب في الإشارة إلى الخارج، على سبيل المثال، استدعاء قاعدة بيانات من طبقة التطبيق، تحتاج إلى إنشاء مثيل لها عبر عكس التحكم (IoC) أو حقن التبعية (DI).
CQRS باستخدام MediatR (إطار مراسلة مُعد مسبقًا)
يرمز CQRS إلى فصل مسؤولية الأوامر/الاستعلام وقد تم وصفه لأول مرة بواسطة جريج يونج في عام 2010. وهو يعتمد على مبدأ فصل استعلام الأوامر (CQS) ويسمح بفصل عمليات القراءة والكتابة. تنص CQS على ما يلي:
التحسين من CQRS على CQS هو أن تلك الأوامر والاستعلامات يتم التعامل معها كنماذج وليس كأساليب. يمكن إرسال هذه النماذج ككائنات عند نقطة واحدة، ليتم التعامل معها بعد ذلك بواسطة معالجيها المطلوبين في نقطة أخرى في النظام، حيث يقوم كل منهم بإرجاع نماذج الاستجابة الخاصة به من أجل الفصل الواضح بين كل إجراء.
يسمح نمط الوسيط بتنفيذ الأوامر/الاستعلامات والمعالجات مقترنة بشكل غير محكم باستخدام كائن الوسيط. لم تعد الكائنات تتواصل مباشرة مع بعضها البعض، بل تتواصل عبر الوسيط.
إطار عمل MediatR هو تطبيق مفتوح المصدر لنمط الوسيط، أنشأه جيمي بوجارد. سيتم استخدامه في هذا المشروع للتواصل بين طبقة الإطار وطبقة التطبيق. سيتم استخدامه أيضًا لإسقاط البيانات من قاعدة بيانات الأوامر إلى قاعدة بيانات الاستعلام.
مصادر الحدث
نمط تصميم معماري لتخزين كل تغيير في حالة التطبيق، بدلاً من تخزين الحالة الحالية للبيانات في المجال فقط. تم تقديم هذا النمط بواسطة جريج يونج وشهد منذ ذلك الحين العديد من عمليات التبني.
يهدف النمط إلى التقاط كل تغيير في حالة التطبيق ككائن حدث. يتم بعد ذلك تخزين كائنات الحدث هذه، في تسلسل حدوثها، بطريقة الإلحاق فقط. لا يسمح هذا فقط بإعادة إنشاء الحالة الحالية للكائن عبر تسلسل الأحداث التي حدثت حتى الآن، ولكنه يسمح في النهاية بالعودة بالزمن وإعادة إنشاء حالة الكائن في أي وقت محدد.
يمكن أن يكون الحساب البنكي مثالاً جيدًا لمبدأ تحديد مصادر الأحداث. في كل مرة يتم فيها سحب الأموال أو إيداعها، بدلاً من مجرد تحديث الرصيد الحالي، يتم تسجيل مبلغ التغيير. يتم بعد ذلك حساب الرصيد الحالي من خلال مراجعة تسلسل الأحداث، مع المعلومات المقابلة لها حول مقدار الأموال التي تم سحبها أو إيداعها في كل مرة.
يعمل تحديد مصادر الأحداث بشكل جيد مع التصميم المستند إلى المجال، نظرًا لأنه مناسب تمامًا لتخزين أحداث المجال، التي يتم تشغيلها بواسطة نموذج المجال مع كل طلب تغيير.
يستفيد تحديد مصادر الأحداث أيضًا بشكل كبير من CQRS. بدلاً من الاضطرار إلى إجراء استعلام مقابل قاعدة بيانات مصادر الأحداث، والتي يجب أن تمر بجميع الأحداث المسجلة المتعلقة بالكائن المطلوب لإعادة إنشاء الحالة الحالية، يمكن إجراء هذا الاستعلام مقابل قاعدة بيانات استعلام مخصصة. يتم تحديث قاعدة بيانات الاستعلام هذه بواسطة معالجات الأحداث الخاصة بها، والاستماع إلى نفس الأحداث التي يتم إرسالها مباشرة بعد إلحاقها بقاعدة بيانات مصادر الأحداث. تسمى عمليات التحديث هذه الإسقاطات.
ويمهد هذا الفصل بين قواعد البيانات أيضًا الطريق لإمكانات هائلة في قابلية التوسع وتحسين الأداء. يمكن إنشاء مثيلات متعددة لقاعدة بيانات الاستعلام ومزامنتها ببساطة عن طريق جعل معالجات الأحداث الخاصة بها تستمع للأحداث التي يتم إرسالها من Event Sourcing Database Client مباشرة بعد حدوث تغيير ذي صلة في حالة التطبيق. يمكن أن يؤدي اختيار نوع قاعدة البيانات بالإضافة إلى درجة عدم تسوية البيانات، التي يتم تحسينها لكل استعلام، إلى تحسين الأداء بشكل كبير.
يمكن أن يحدث هذا التحديث المستمر لنموذج القراءة بشكل متزامن أو غير متزامن. يأتي الأخير على حساب الاتساق النهائي، حيث يكون نموذج القراءة غير متزامن مع نموذج الكتابة لفجوة زمنية صغيرة (عادةً ميلي ثانية).
النواة المشتركة
مكتبة مشتركة لطبقة المجال، والتي تحتوي على فئات أساسية محددة للتصميم المعتمد على المجال، وكيانات المجال، وكائنات القيمة، وما إلى ذلك والتي يتم مشاركتها عبر السياقات المحدودة.
ابدء
لبدء هذا المشروع وتشغيله كما هو، لا تتردد في اتباع الخطوات التالية:
المتطلبات الأساسية
يثبت
قم بتشغيل https://localhost:5001/swagger/index.html في متصفحك لعرض وثائق Swagger الخاصة بواجهة برمجة التطبيقات (API) الخاصة بك.
استخدم Swagger أو Postman أو أي تطبيق آخر لإرسال طلب POST إلى https://localhost:5001/api/Administration/Register لتسجيل حساب المسؤول الأولي الخاص بك. أرسل الكائن التالي:
ابحث في تطبيق وحدة التحكم أو أي مخرج تمت إعادة تكوينه لسجلات التطبيق. بعد أي تسجيل ناجح للمستخدم، يجب أن يكون هناك رابط للتحقق من البريد الإلكتروني - مقدم من EmailService - مكتوب في السجلات. انسخ عنوان URL والصقه في متصفحك واضغط على زر الإدخال لإكمال التسجيل. لا تتردد في تغيير أو البناء على هذا التنفيذ غير السليم لخدمة البريد الإلكتروني؛-)
أنت جاهز تمامًا. تسجيل الدخول التالي.
قم بتشغيل http://localhost:2113/ في متصفحك لعرض واجهة المستخدم الرسومية لـ EventStoreDB. افتح علامة التبويب "متصفح البث" لرؤية جميع الأحداث المخزنة.
يمكن تنفيذ الاختبارات عن طريق تشغيل:
التقنيات
يستخدم هذا المشروع حزم التقنيات / NuGet التالية:
الموارد / القراءة الموصى بها
ألبرتو براندوليني:
https://www.eventstorming.com
فون فيرنون:
https://dddcommunity.org/wp-content/uploads/files/pdfarticles/Vernon2011_1.pdf
https://dddcommunity.org/wp-content/uploads/files/pdfarticles/Vernon2011_2.pdf
https://dddcommunity.org/wp-content/uploads/files/pdfarticles/Vernon2011_3.pdf
أليستير كوكبيرن:
https://web.archive.org/web/20180822100852/http://aliستير.cockburn.us/Hexagonal+architecture
روبرت سي مارتن (العم بوب):
https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html
سيزار دي لا توري، بيل واجنر، مايك روسوس:
https://docs.microsoft.com/en-us/dotnet/architecture/microservices/
جريج يونج
https://cqrs.files.wordpress.com/2010/11/cqrs_documents.pdf
https://cqrs.wordpress.com/documents/building-event-storage/
https://msdn.microsoft.com/en-us/library/jj591559.aspx
مارتن فاولر:
https://www.martinfowler.com/bliki/CQRS.html
جيمي بوجارد:
https://github.com/jbogard/MediatR
https://www.youtube.com/watch?v=SUiWfhAhgQw
التصميم القائم على المجال:
https://dddcommunity.org
https://thedomaindrivendesign.io
https://dotnetcodr.com/2013/09/12/a-model-net-web-service-based-on-domain-driven-design-part-1-introduction/
https://dotnetcodr.com/2015/10/22/domain-driven-design-with-web-api-extensions-part-1-notifications/
العمارة السداسية:
https://fideloper.com/hexagonal-architecture
https://herbertograca.com/2017/09/14/ports-adapters-architecture/
الاعتمادات
http://www.andreavallotti.tech/en/2018/01/event-sourcing-and-cqrs-in-c/
https://www.exceptionnotfound.net/real-world-cqrs-es-with-asp-net-and-redis-part-1-overview/
https://buildplease.com/pages/fpc-1/
https://dotnetcoretutorials.com/2019/04/30/the-mediator-pattern-in-net-core-part-1-whats-a-mediator/
https://itnext.io/why-and-how-i-implemented-cqrs-and-mediator-patterns-in-a-microservice-b07034592b6d