
هذه المقالة هي جزء من
Chronicle of Software Architecture ، وهي سلسلة من المقالات حول هندسة البرمجيات. فيها أكتب عن ما تعلمته عن هندسة البرمجيات ، وما أفكر فيه وكيف أستخدم المعرفة. قد يكون محتوى هذه المقالة أكثر منطقية إذا قرأت المقالات السابقة في السلسلة.
بعد التخرج من الجامعة ، بدأت العمل كمدرس في المدرسة الثانوية ، ولكن قبل بضع سنوات تركت العمل وذهبت إلى مطوري البرمجيات بدوام كامل.
منذ ذلك الحين ، لطالما شعرت أنني بحاجة إلى استعادة الوقت "الضائع" واكتشاف أكبر قدر ممكن ، في أسرع وقت ممكن. لذلك ، بدأت في المشاركة في التجارب قليلاً ، وقراءة وكتابة الكثير ، مع إيلاء اهتمام خاص لتصميم وهندسة البرنامج. لذلك أكتب هذه المقالات لأساعد نفسي في دراستي.
تحدثت في المقالات الأخيرة عن العديد من المفاهيم والمبادئ التي تعلمتها ، وقليلاً عن كيفية تفكيري فيها. لكني أتخيلها على أنها أجزاء من لغز كبير واحد.
تتناول هذه المقالة كيفية تجميع كل هذه الأجزاء. أعتقد أنني يجب أن أعطيهم اسمًا ، لذلك سأطلق عليهم
هندسة صريحة . بالإضافة إلى ذلك ، يتم
اختبار جميع هذه المفاهيم
في المعركة ويتم استخدامها في الإنتاج على منصات موثوقة للغاية. أحدهما هو منصة SaaS للتجارة الإلكترونية مع الآلاف من المتاجر عبر الإنترنت حول العالم ، والآخر هو منصة تداول تعمل في دولتين مع ناقل رسائل يعالج أكثر من 20 مليون رسالة شهريًا.
الكتل الأساسية للنظام
لنبدأ
باستدعاء بنيات EBI و
Ports & Adapters . كلاهما يفصلان بوضوح الكود الداخلي والخارجي للتطبيق ، وكذلك المحولات لتوصيل الكود الداخلي والخارجي.
بالإضافة إلى ذلك ، تحدد بنية
الموانئ والمحولات بشكل صريح الكتل الأساسية الثلاثة للكود في النظام:
- يتيح لك ذلك تشغيل واجهة المستخدم ، بغض النظر عن نوعها.
- منطق عمل النظام أو نواة التطبيق . يتم استخدامه من قبل واجهة المستخدم لإجراء معاملات حقيقية.
- رمز البنية التحتية الذي يربط جوهر تطبيقنا بأدوات مثل قاعدة البيانات أو محرك البحث أو واجهات برمجة التطبيقات التابعة لجهات خارجية.

جوهر التطبيق هو أهم شيء يجب التفكير فيه. يسمح لك هذا الرمز بتنفيذ إجراءات حقيقية في النظام ، وهذا هو تطبيقنا. العديد من واجهات المستخدم (تطبيق ويب تقدمي ، تطبيق جوال ، CLI ، API ، إلخ) يمكن أن تعمل معها ، كل شيء يعمل على قلب واحد.
كما يمكنك أن تتخيل ، ينتقل تدفق التنفيذ النموذجي من الرمز في واجهة المستخدم من خلال قلب التطبيق إلى رمز البنية التحتية ، ثم يعود إلى جوهر التطبيق ، وأخيرًا ، يتم تسليم الاستجابة إلى واجهة المستخدم.

الأدوات
بعيدًا عن رمز النواة الأكثر أهمية ، لا تزال هناك أدوات يستخدمها التطبيق. على سبيل المثال ، محرك قاعدة البيانات ، ومحرك البحث ، وخادم الويب ، ووحدة تحكم CLI (على الرغم من أن الأخيرين هما أيضًا آليات تسليم).

يبدو من الغريب وضع وحدة التحكم في واجهة سطر الأوامر (CLI) في نفس القسم الموضوعي مثل نظام إدارة قواعد البيانات (DBMS) ، لأن لديهم غرضًا مختلفًا. ولكن في الواقع ، كلاهما أدوات يستخدمها التطبيق. الفرق الرئيسي هو أن وحدة تحكم CLI وخادم الويب
يطلبان من التطبيق القيام بشيء ما ، فإن نواة DBMS ، على العكس من ذلك ،
تتلقى أوامر من التطبيق . هذا اختلاف مهم جدًا ، لأنه يؤثر بشكل كبير على كيفية كتابة التعليمات البرمجية لربط هذه الأدوات بنواة التطبيق.
ربط أدوات وآليات التسليم إلى جوهر التطبيق
تسمى كتل أدوات توصيل الكود إلى قلب التطبيق محولات (
بنية الموانئ والمحولات ). إنها تسمح لمنطق الأعمال بالتفاعل مع أداة معينة ، والعكس صحيح.
تسمى المحولات التي تخبر التطبيق بفعل شيء ما
محولات أساسية أو محولات تحكم ، بينما تسمى المحولات التي تطلب من التطبيق القيام بشيء ما
محولات ثانوية أو مدارة .
الموانئ
ومع ذلك ، لا يتم إنشاء هذه
المحولات عن طريق الصدفة ، ولكن لتتوافق مع نقطة دخول محددة في قلب التطبيق ،
المنفذ . المنفذ
ليس أكثر من تحديد لكيفية استخدام الأداة لب التطبيق أو العكس. في معظم اللغات وبأبسط أشكاله ، سيكون هذا المنفذ واجهة ، ولكن في الواقع يمكن أن يتكون من عدة واجهات و DTO.
من المهم ملاحظة أن
المنافذ (الواجهات) موجودة داخل منطق الأعمال ، والمحولات في الخارج. لكي يعمل هذا القالب بشكل صحيح ، من المهم للغاية إنشاء منافذ وفقًا لاحتياجات قلب التطبيق ، وليس فقط محاكاة واجهات برمجة التطبيقات للأداة.
محولات أولية أو تحكم
تلتف المحولات الأساسية أو وحدات التحكم
حول المنفذ وتستخدمه لإخبار نواة التطبيق بما يجب القيام به.
يقومون بتحويل جميع البيانات من آلية التسليم إلى استدعاءات الطريقة في جوهر التطبيق.
بمعنى آخر ، محولات التحكم لدينا هي وحدات تحكم أو أوامر وحدة تحكم ، يتم تضمينها في مُنشئها مع بعض الكائنات التي تقوم فئتها بتنفيذ الواجهة (المنفذ) التي يتطلبها أمر وحدة التحكم أو وحدة التحكم.
في مثال أكثر تحديدًا ، قد يكون المنفذ هو واجهة الخدمة أو واجهة المستودع التي تتطلبها وحدة التحكم. يتم بعد ذلك تنفيذ تطبيق محدد لخدمة أو مستودع أو طلب واستخدامها في وحدة التحكم.
بالإضافة إلى ذلك ، يمكن أن يكون المنفذ ناقل أوامر أو واجهة ناقل استعلام. في هذه الحالة ، يتم إدخال تطبيق محدد لأمر ناقل أو طلب في وحدة التحكم ، والتي تقوم بعد ذلك بإنشاء أمر أو طلب وتمريره إلى الناقل المقابل.
محولات ثانوية أو مدارة
على عكس محولات التحكم التي تلتف حول منفذ ، تقوم
المحولات المدارة بتطبيق منفذ وواجهة ، ثم أدخل جوهر التطبيق حيث يكون المنفذ مطلوبًا (مع النوع).

على سبيل المثال ، لدينا تطبيق أصلي يحتاج إلى حفظ البيانات. نقوم بإنشاء واجهة استمرار باستخدام طريقة
حفظ مصفوفة بيانات وطريقة
حذف صف في جدول بمعرفه. من الآن فصاعدًا ، حيثما يحتاج التطبيق إلى حفظ البيانات أو حذفها ، سنطلب في المنشئ كائنًا يقوم بتنفيذ واجهة الثبات التي حددناها.
الآن قم بإنشاء محول خاص بـ MySQL يقوم بتنفيذ هذه الواجهة. سيكون لديه طرق لحفظ الصفيف وحذف الصف في الجدول ، وسوف نقدمه حيثما كان مطلوبًا واجهة المثابرة.
إذا قررنا في مرحلة ما تغيير موفر قاعدة البيانات ، على سبيل المثال ، إلى PostgreSQL أو MongoDB ، فنحن بحاجة فقط إلى إنشاء محول جديد يطبق واجهة الثبات الخاصة بـ PostgreSQL وإدخال محول جديد بدلاً من المحول القديم.
انقلاب التحكم
السمة المميزة لهذا القالب هي أن المحولات تعتمد على أداة معينة ومنفذ معين (من خلال تنفيذ واجهة). لكن منطق أعمالنا يعتمد فقط على المنفذ (الواجهة) ، المصمم لتلبية احتياجات منطق الأعمال ولا يعتمد على محول أو أداة معينة.

هذا يعني أن التبعيات موجهة نحو المركز ، أي أن هناك
انعكاسًا لمبدأ التحكم على المستوى المعماري .
على الرغم من
أنه من الضروري ، مرة أخرى ،
إنشاء المنافذ وفقًا لاحتياجات قلب التطبيق ، وليس فقط محاكاة واجهات برمجة التطبيقات للأداة .
تنظيم جوهر التطبيق
تلتقط
بنية Onion طبقات DDD وتدمجها في
بنية المنفذ والمحول . تم تصميم هذه المستويات لإضفاء بعض الترتيب على منطق الأعمال ، داخل "السداسي" للمنافذ والمحولات. كما كان من قبل ، يكون اتجاه التبعيات نحو المركز.
طبقة التطبيق (طبقة التطبيق)
حالات الاستخدام هي عمليات يمكن إطلاقها في النواة من خلال واجهة مستخدم واحدة أو أكثر. على سبيل المثال ، قد تحتوي CMS على واجهة مستخدم واحدة للمستخدمين المنتظمين وواجهة مستخدم مستقلة أخرى لمسؤولي CMS و CLI أخرى وواجهة برمجة تطبيقات الويب. يمكن أن تؤدي واجهات المستخدم (التطبيقات) هذه إلى حالات استخدام فريدة أو شائعة.
يتم تعريف حالات الاستخدام على مستوى التطبيق - المستوى الأول من DDD وبنية البصل.

تحتوي هذه الطبقة على خدمات التطبيق (وواجهاتها) ككائنات من الدرجة الأولى ، وتحتوي أيضًا على واجهات المنفذ والمحول (المنافذ) ، والتي تشمل واجهات ORM ، وواجهات محرك البحث ، وواجهات المراسلة ، وما إلى ذلك. في حالة استخدامنا ناقل الأوامر و / أو ناقل الطلب ، في هذا المستوى هما الأمر المقابل ومعالجات الطلب.
تحتوي خدمات التطبيق و / أو معالجات الأوامر على منطق النشر لحالة الاستخدام ، وهي عملية تجارية. كقاعدة ، يكون دورهم كما يلي:
- استخدام المستودع للبحث عن كيان واحد أو أكثر ؛
- اطلب من هذه الكيانات تنفيذ بعض منطق المجال ؛
- واستخدام التخزين لإعادة حفظ الكيانات ، وتوفير تغييرات البيانات بشكل فعال.
يمكن استخدام معالجات الأوامر بطريقتين:
- قد تحتوي على منطق لتنفيذ حالة استخدام ؛
- يمكن استخدامها كأجزاء بسيطة من الاتصال في هندستنا التي تتلقى أمرًا وتستدعي المنطق الموجود في خدمة التطبيق.
يعتمد أي نهج للاستخدام على السياق ، على سبيل المثال:
- لدينا بالفعل خدمات التطبيق والآن يتم إضافة ناقل القيادة؟
- هل يسمح لك ناقل الأوامر بتحديد فئة / أسلوب كمعالج ، أم أنك بحاجة إلى توسيع أو تنفيذ فئات أو واجهات موجودة؟
تحتوي هذه الطبقة أيضًا على
تشغيل أحداث التطبيق التي تمثل بعض نتائج حالة الاستخدام. تؤدي هذه الأحداث إلى تشغيل المنطق الذي يعد أحد الآثار الجانبية لحالة الاستخدام ، مثل إرسال رسائل البريد الإلكتروني ، أو إخطار واجهة برمجة تطبيقات تابعة لجهة خارجية ، أو إرسال إشعار دفع ، أو حتى إطلاق حالة استخدام أخرى تنتمي إلى مكون آخر من التطبيق.
مستوى المجال
مزيد من الداخل هناك مستوى المجال. تحتوي الكائنات على هذا المستوى على بيانات ومنطق لإدارة هذه البيانات ، وهي خاصة بالمجال نفسه ومستقلة عن عمليات الأعمال التي تؤدي إلى هذا المنطق. هم مستقلون وغير مدركين تمامًا لمستوى التطبيق.

خدمات المجال
كما ذكرت أعلاه ، دور خدمة التطبيق:
- استخدام المستودع للبحث عن كيان واحد أو أكثر ؛
- اطلب من هذه الكيانات تنفيذ بعض منطق المجال ؛
- واستخدام التخزين لإعادة حفظ الكيانات ، وتوفير تغييرات البيانات بشكل فعال.
ولكن في بعض الأحيان نواجه بعض منطق النطاق ، والذي يتضمن كيانات مختلفة من نفس النوع أو أنواع مختلفة ، ولا ينتمي منطق النطاق هذا إلى الكيانات نفسها ، أي أن المنطق ليس مسؤوليتها المباشرة.
لذلك ، قد يكون رد فعلنا الأول وضع هذا المنطق خارج الكيانات في خدمة التطبيق. ومع ذلك ، هذا يعني أنه في حالات أخرى لن يتم إعادة استخدام منطق المجال: يجب أن يبقى منطق المجال خارج مستوى التطبيق!
الحل هو إنشاء خدمة مجال ، يتمثل دورها في الحصول على مجموعة من الكيانات وتنفيذ بعض منطق الأعمال عليها. تنتمي خدمة المجال إلى مستوى المجال وبالتالي لا تعرف أي شيء عن الفئات على مستوى التطبيق ، مثل خدمات التطبيق أو المستودعات. من ناحية أخرى ، يمكنه استخدام خدمات المجال الأخرى ، وبالطبع ، كائنات نموذج المجال.
نموذج المجال
في الأساس هو نموذج المجال. لا يعتمد على أي شيء خارج هذه الدائرة ويحتوي على كائنات أعمال تمثل شيئًا في المجال. أمثلة على هذه الكائنات هي ، أولاً وقبل كل شيء ، كيانات ، وكذلك كائنات القيمة ، والتعدادات ، وأي كائنات مستخدمة في نموذج المجال.
تعيش أحداث المجال أيضًا في نموذج المجال. عندما تتغير مجموعة بيانات محددة ، يتم تشغيل هذه الأحداث ، والتي تحتوي على قيم جديدة للخصائص المتغيرة. هذه الأحداث مثالية ، على سبيل المثال ، للاستخدام في وحدة مصادر الأحداث.
مكونات
حتى الآن ، لدينا كود معزول في طبقات ، ولكن هذا عزل رمز مفصل للغاية. من المهم بنفس القدر أن ننظر إلى الصورة بمظهر أكثر عمومية. نحن نتحدث عن تقسيم الشفرة إلى نطاقات فرعية
وسياقات ذات صلة وفقًا لأفكار روبرت مارتن التي تم التعبير عنها في
هندسة الصراخ [أي ، يجب على الهندسة المعمارية "الصراخ" حول التطبيق نفسه ، وليس حول الأطر التي تستخدمها - تقريبًا. العابرة.]. يتحدثون عن تنظيم الحزم حسب الوظيفة أو المكون ، وليس حسب الطبقة ، وأوضح سايمون براون ذلك جيدًا في مقالة
"حزم المكونات واختبار الهندسة المعمارية" على مدونته:

أنا مؤيد لتنظيم حزم المكونات وأريد تغيير مخطط سيمون براون دون خجل على النحو التالي:

هذه الأقسام من الشفرة متداخلة لجميع الطبقات الموصوفة سابقًا ، وهذه هي
مكونات تطبيقنا. من أمثلة المكونات الفوترة أو المستخدم أو التحقق أو الحساب ، ولكنها ترتبط دائمًا بنطاق. يجب اعتبار السياقات المحدودة ، مثل التفويض و / أو المصادقة ، أدوات خارجية نقوم من أجلها بإنشاء محول وإخفائه خلف منفذ.

قطع اتصال المكون
تمامًا كما هو الحال في وحدات الكود الدقيقة (الفئات ، والواجهات ، والسمات ، والمزج ، وما إلى ذلك) ، تستفيد الوحدات (المكونات) الكبيرة من الاقتران الضعيف والاتصال الضيق.
لفصل الطبقات ، نستخدم حقن التبعية ، وإدخال التبعيات في الفصل ، بدلاً من إنشائها داخل الفصل ، وعكس التبعيات أيضًا ، مما يجعل الفصل يعتمد على التجريد (واجهات و / أو فئات مجردة) بدلاً من فئات محددة. وهذا يعني أن الفئة التابعة لا تعرف أي شيء عن الفئة المحددة التي ستستخدمها ، ولا تحتوي على إشارة إلى الاسم الكامل للفئات التي تعتمد عليها.
وبالمثل ، في المكونات المنفصلة تمامًا ، لا يعرف كل مكون شيئًا عن أي مكون آخر. بمعنى آخر ، لا يوجد رابط لأي كتلة تعليمات برمجية دقيقة من مكون آخر ، حتى إلى الواجهة! هذا يعني أن حقن التبعية وانقلاب التبعية ليست كافية لفصل المكونات ، سنحتاج إلى نوع من البناء المعماري. قد تكون هناك حاجة إلى الأحداث ، ونواة مشتركة ، والاتساق النهائي ، وحتى خدمة الاكتشاف!

تحفيز المنطق في المكونات الأخرى
عندما يحتاج أحد مكوناتنا (المكون B) إلى القيام بشيء ما عندما يحدث شيء آخر في مكون آخر (المكون A) ، لا يمكننا إجراء مكالمة مباشرة من المكون A إلى فئة / طريقة المكون B ، لأن ثم سيتم توصيل A بـ B.
ومع ذلك ، يمكننا استخدام مدير الأحداث لإرسال حدث التطبيق ، والذي سيتم تسليمه إلى أي مكون يستمع إليه ، بما في ذلك B ، وسيؤدي مستمع الأحداث في B إلى تشغيل الإجراء المطلوب. هذا يعني أن المكون أ سيعتمد على مدير الحدث ، ولكنه سيكون منفصلًا عن المكون ب.
ومع ذلك ، إذا كان الحدث نفسه "يعيش" في A ، فهذا يعني أن B يعرف عن وجود A ويرتبط به. لإزالة هذه التبعية ، يمكننا إنشاء مكتبة بمجموعة من الوظائف الأساسية للتطبيق والتي سيتم مشاركتها من قبل جميع المكونات -
جوهر مشترك . هذا يعني أن كلا المكونين سيعتمدان على النواة المشتركة ، ولكن سيتم فصلهما عن بعضهما البعض. يحتوي النواة المشتركة على وظائف مثل أحداث التطبيق والنطاق ، ولكن يمكن أن تحتوي أيضًا على كائنات المواصفات وأي شيء منطقي للمشاركة. في الوقت نفسه ، يجب أن يكون حجمه الأدنى ، لأن أي تغييرات في النواة المشتركة ستؤثر على جميع مكونات التطبيق. بالإضافة إلى ذلك ، إذا كان لدينا نظام متعدد اللغات ، على سبيل المثال ، نظام بيئي من الخدمات الدقيقة بلغات مختلفة ، فيجب ألا يعتمد النواة المشتركة على اللغة حتى تفهمها جميع المكونات. على سبيل المثال ، بدلاً من نواة مشتركة مع فئة حدث ، ستحتوي على وصف للحدث (أي اسم وخصائص وربما حتى طرق ، على الرغم من أنها ستكون أكثر فائدة في كائن المواصفات) في لغة عالمية مثل JSON بحيث يمكن لجميع المكونات / الخدمات الصغيرة تفسيره و ربما تقوم تلقائيًا بإنشاء تطبيقات خاصة بها.
يعمل هذا النهج في كل من التطبيقات المتجانسة والموزعة ، مثل النظم البيئية للخدمات الصغيرة. ولكن إذا كان من الممكن تسليم الأحداث بشكل غير متزامن فقط ، فإن هذا النهج لا يكفي للسياقات التي يجب أن يعمل فيها منطق الزناد في المكونات الأخرى على الفور! هنا ، سيحتاج المكون A إلى إجراء مكالمة HTTP مباشرة إلى المكون B. في هذه الحالة ، لفصل المكونات ، نحتاج إلى خدمة اكتشاف. سيطلب منها المكون "أ" إرسال الطلب لبدء الإجراء المطلوب. وبدلاً من ذلك ، قم بتقديم طلب إلى خدمة الاكتشاف ، والتي ستعيد توجيهها إلى الخدمة المناسبة وستعيد في النهاية ردًا إلى الطالب.
يربط هذا النهج بين المكونات وخدمة الاكتشاف ، ولكنه لا يربطها ببعضها البعض.استرجاع البيانات من المكونات الأخرى
كما أراه ، لا يُسمح للمكون بتعديل البيانات التي لا يمتلكها ، ولكن يمكنه طلب أي بيانات واستخدامها.تخزين البيانات المشتركة للمكونات
إذا كان يجب أن يستخدم المكون بيانات تنتمي إلى مكون آخر (على سبيل المثال ، يجب أن يستخدم مكون الفوترة اسم العميل الذي ينتمي إلى مكون الحسابات) ، فإنه يحتوي على كائن الطلب لتخزين البيانات. أي أن عنصر الفوترة يمكنه معرفة أي مجموعة بيانات ، ولكن يجب أن يستخدم بيانات للقراءة فقط من بلدان أخرى.تخزين بيانات منفصل للمكون
في هذه الحالة ، يتم تطبيق نفس القالب ، ولكن مستوى تخزين البيانات يصبح أكثر تعقيدًا. يعني وجود المكونات بمستودع البيانات الخاص بها أن كل مستودع بيانات يحتوي على:- مجموعة من البيانات يمتلكها أحد المكونات ويمكنه تغييرها ، مما يجعله المصدر الوحيد للحقيقة ؛
- مجموعة بيانات عبارة عن نسخة من بيانات المكونات الأخرى التي لا يمكن تغييرها بمفردها ، ولكنها ضرورية لوظيفة المكون. يجب تحديث هذه البيانات كلما تغيرت في مكون المالك.
سيقوم كل مكون بإنشاء نسخة محلية من البيانات التي يحتاجها من المكونات الأخرى ، والتي سيتم استخدامها حسب الحاجة. عندما تتغير البيانات في المكون الذي تنتمي إليه ، يقوم مكون المالك هذا بتشغيل حدث مجال يحمل تغييرات البيانات. ستستمع المكونات التي تحتوي على نسخة من هذه البيانات إلى حدث النطاق هذا وستقوم بتحديث نسختها المحلية وفقًا لذلك.تدفق التحكم
كما قلت أعلاه ، ينتقل تدفق التحكم من المستخدم إلى جوهر التطبيق ، إلى أدوات البنية التحتية ، ثم مرة أخرى إلى قلب التطبيق - ثم يعود إلى المستخدم. ولكن كيف تعمل الفصول معًا بالضبط؟ من يعتمد على من؟ كيف نؤلفهم؟مثل العم بوب ، في مقالتي عن الهندسة المعمارية النظيفة ، سأحاول شرح تدفق إدارة مخطط UMLish ...بدون قيادة / طلب ناقل
إذا لم نستخدم ناقل الأوامر ، فسوف تعتمد وحدات التحكم على خدمة التطبيق أو كائن الاستعلام.[الملحق 11/18/2017] تخطيت تمامًا DTO ، الذي أستخدمه لإرجاع البيانات من الطلب ، لذلك أضفتها الآن. بفضل MorphineAdministered ، الذي أشار إلى مسافة. في الرسم البياني أعلاه ، نستخدم الواجهة لخدمة التطبيق ، على الرغم من أنه يمكننا القول أنها ليست ضرورية حقًا ، لأن خدمة التطبيق هي جزء من رمز التطبيق الخاص بنا. لكننا لا نريد تغيير التنفيذ ، على الرغم من أنه يمكننا إجراء إعادة هيكلة كاملة.
يحتوي كائن الاستعلام على استعلام محسّن يقوم ببساطة بإرجاع بعض البيانات الأولية التي سيتم عرضها للمستخدم. يتم إرجاع هذه البيانات إلى DTO المضمنة في ViewModel. قد يكون لدى ViewModel نوعًا من منطق العرض وسيتم استخدامه لملء العرض.من ناحية أخرى ، تحتوي خدمة التطبيق على منطق حالة الاستخدام الذي ينطلق عندما نريد القيام بشيء ما على النظام ، وليس فقط عرض بعض البيانات. تعتمد خدمة التطبيق على المستودعات التي تعيد الكيانات التي تحتوي على المنطق الذي يحتاج إلى البدء. قد تعتمد أيضًا على خدمة النطاق لتنسيق عملية النطاق عبر كيانات متعددة ، ولكن هذه حالة نادرة.بعد تحليل حالة الاستخدام ، يمكن لخدمة التطبيق إخطار النظام بالكامل بحدوث حالة استخدام ، ثم تعتمد على مرسل الحدث لتشغيل الحدث.من المثير للاهتمام ملاحظة أننا نستضيف واجهات على كل من محرك المثابرة والمستودعات. قد يبدو هذا زائدة عن الحاجة ، لكنهم يخدمون أغراضًا مختلفة:- واجهة المثابرة هي طبقة تجريد عبر ORM ، حتى نتمكن من تبديل ORM دون تغيير جوهر التطبيق.
- persistence-. , MySQL MongoDB. persistence- , ORM, . , , , , , , MongoDB SQL.
C /
إذا كان تطبيقنا يستخدم ناقل الأوامر / الطلب ، فسيظل الرسم البياني كما هو تقريبًا ، باستثناء أن وحدة التحكم تعتمد الآن على الناقل ، وكذلك الأوامر أو الطلبات. يتم إنشاء مثيل لأمر أو طلب هنا وتمريره إلى الناقل ، والذي سيجد المعالج المناسب لاستلام الأمر ومعالجته.في الرسم البياني أدناه ، يستخدم معالج الأوامر خدمة التطبيق. ولكن هذا ليس ضروريًا دائمًا ، لأنه في معظم الحالات ، سيحتوي المعالج على كل منطق حالة الاستخدام. كل ما نحتاجه هو استخراج المنطق من المعالج إلى خدمة تطبيق منفصلة إذا كنا بحاجة إلى إعادة استخدام نفس المنطق في معالج آخر.[الملحق 11/18/2017] تخطيت تمامًا DTO ، الذي أستخدمه لإرجاع البيانات من الطلب ، لذلك أضفتها الآن. شكرا لكالمورفين ، الذي يشير إلى مسافة. ربما لاحظت عدم وجود تبعيات بين الناقل والأمر والطلب والمعالجات. في الواقع ، لا يحتاجون إلى معرفة بعضهم البعض من أجل ضمان الانفصال الجيد. يتم تكوين طريقة توجيه الناقل إلى معالج معين لمعالجة أمر أو طلب في تكوين بسيط. في كلتا الحالتين ، تشير جميع الأسهم - التبعيات التي تعبر حدود kernel للتطبيق - إلى الداخل. كما هو موضح سابقًا ، هذه هي القاعدة الأساسية للمنافذ والمحولات والبصل والهندسة النظيفة.

الخلاصة
كما هو الحال دائمًا ، يتمثل الهدف في الحصول على قاعدة تعليمات برمجية غير متصلة مع اتصال عالي ، حيث يمكنك إجراء أي تغييرات بسهولة وسرعة وأمان.الخطط غير مجدية ، لكن التخطيط هو كل شيء. - أيزنهاور
هذه الرسوم البيانية هي خريطة مفاهيم. تساعدك معرفة وفهم كل هذه المفاهيم على تخطيط بنية صحية وتطبيق عملي.ومع ذلك:الخريطة ليست منطقة. - الفريد كورزيبسكي
وبعبارة أخرى ، هذه مجرد توصيات! التطبيق عبارة عن منطقة وواقعية وحالة استخدام محددة حيث نحتاج إلى تطبيق معرفتنا ، ويحدد الشكل الذي ستبدو عليه الهندسة الحقيقية!يجب أن نفهم كل هذه الأنماط ، ولكننا نحتاج أيضًا دائمًا إلى التفكير وفهم ما يحتاجه تطبيقنا ، وإلى أي مدى يمكننا الذهاب من أجل الانفصال والترابط. يعتمد هذا القرار على العديد من العوامل ، بدءًا من المتطلبات الوظيفية للمشروع ، إلى توقيت تطوير التطبيق ، وفترة خدمته ، وتجربة فريق التطوير وما إلى ذلك.هكذا أتخيل كل هذا بنفسي.تتم مناقشة هذه الأفكار بمزيد من التفصيل في المقالة التالية: "أكثر من مجرد طبقات متحدة المركز" .