كتاب الطبخ المطور: وصفات DDD (الجزء 3 ، بنية التطبيق)

مقدمة


في المقالات السابقة ، حددنا نطاق النهج وفحصنا المبادئ المنهجية الأساسية للتصميم القائم على المجال .


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


WM


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


هندسة مرنة


في المقالة الأخيرة ، ركزنا على حقيقة أن DDD يشمل ممارسة التنفيذ من خلال النموذج. يجب وصف مجال الموضوع من خلال التعليمات البرمجية الخاصة بك. دعونا نحاول معرفة كيفية القيام بذلك.


في كتابه ، يقدم إريك إيفانز سلسلة من أنماط التصميم الموصى بها ويصف هذا النهج بأنه مرن:


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

إريك إيفانز ، التصميم المستند إلى المجال: معالجة التعقيد في قلب البرمجيات

مجموعة أنماط التصميم المعروضة ليست بنية صارمة أو حل جاهز ، بل غذاء للتفكير.


العمارة المبهرجة


ظهرت أفكار مماثلة في أذهان العديد من مطوري ومصممي الأنظمة المعقدة.


في عام 2011 ، تم نشر مقالة بقلم روبرت مارتن - هندسة الصراخ ، والتي تنص على أن التعليمات البرمجية الخاصة بك لا يجب أن تصف مجال الموضوع فحسب ، بل تصيح حوله ، ويفضل أن تكون فاحشة.


فماذا تصرخ بنية التطبيق الخاص بك؟ عندما تنظر إلى بنية دليل المستوى الأعلى ، وملفات المصدر في حزمة المستوى الأعلى ؛ هل تصرخ: نظام الرعاية الصحية أو نظام المحاسبة أو نظام إدارة المخزون؟ أم أنها تصرخ: القضبان أم الربيع / السبات أو ASP؟

روبرت سي مارتن ، 30 سبتمبر 2011

يقول روبرت أن رمز التطبيق الخاص بك يجب أن يعكس نشاط التطبيق ، بدلاً من التكيف مع قواعد الإطار. يجب ألا يحد هيكل الإطار من بنيتك. التطبيق ، بدوره ، لا ينبغي إرفاقه بقاعدة البيانات أو بروتوكول http ، فهذه مجرد آليات تخزين وتسليم. المربع المحيط هو أداة. لا يجب أن تصبح من أتباع الإطار. اختبارات التطبيق الخاص بك هي اختبارات لمنطق تشغيله ، وليس اختبار بروتوكول http.


العمارة النظيفة


بعد عام ، المقالة التالية بقلم روبرت مارتن - العمارة النظيفة . في ذلك ، يخبر المؤلف كيفية جعل الشفرة تصرخ. بعد دراسة العديد من البنى ، حدد المبادئ الأساسية:


  1. استقلال الإطار. العمارة لا تعتمد على أي مكتبة موجودة. هذا يسمح لك باستخدام الأطر كأدوات ، بدلاً من القيود التي تربط يديك.
  2. قابلية الاختبار. يمكن اختبار قواعد العمل بدون واجهة مستخدم أو قاعدة بيانات أو خادم ويب أو أي وسيلة تقنية أخرى.
  3. استقلالية واجهة المستخدم. يمكن تغيير واجهة المستخدم بسهولة دون تغيير بقية النظام. على سبيل المثال ، يمكن استبدال واجهة الويب بواجهة وحدة التحكم دون تغيير منطق الأعمال.
  4. استقلالية قاعدة البيانات. يمكنك استبدال Oracle أو SQL Server بـ Mongo أو BigTable أو CouchDB أو أي شيء آخر. لا يجب أن يكون منطق التطبيق الخاص بك مرتبطًا بقاعدة البيانات.
  5. الاستقلال عن التأثيرات البيئية. في الواقع ، قواعد عملك ببساطة لا تعرف أي شيء عن العالم الخارجي.

على habr نشرت بالفعل مقال جيد جدا Misconceptions Clean Architecture . مضغ مؤلفها ، Jeevuz بشكل جيد للغاية تعقيدات فهم هذا النهج. أوصي بشدة أن تتعرف على ذلك والمواد الأصلية.


هندسة متغيرة


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


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


  1. إنشاء المستند
  2. معالجة المستندات
  3. العمل مع أرشيف الوثائق
  4. تقديم الوثيقة

وثيقة - تسجيل المعلومات حول الأنشطة الاقتصادية لعنصر تجاري حقيقي معين.

يرجى ملاحظة أن الوثيقة نفسها ليست كائنًا تجاريًا حقيقيًا ، ولكنها فقط نموذجها. حاليا ، يتم استبدال الوثائق الورقية بأخرى إلكترونية. يمكن أن يكون المستند سجلاً في جدول أو صورة أو ملف أو رسالة مرسلة أو أي معلومة أخرى.
لا أرغب في استخدام كلمة word في المستقبل ، لأنها ستكون أكثر إرباكًا ، وسوف نستخدم مفهوم الكيان من مصطلحات DDD. ولكن يمكنك أن تتخيل أن نظامك بالكامل الآن هو نظام إلكتروني لإدارة المستندات يقوم بأربعة إجراءات بسيطة.


  1. الجمع
  2. جارٍ المعالجة
  3. التخزين
  4. التمثيل التمثيلي

العمل - وحدة هيكلية لنشاط نموذج الأعمال ؛ فعل منفصل مكتمل نسبيًا لهدف واعي ، التعسف والقصد للنشاط الفردي لعنصر تجاري ، يتميز به المستخدم النهائي.

مثال جيد على العمل هو عمل مسرحي. يعرض المسرح الأحداث من واقع الحياة. الفعل هو جزء ذو مغزى من المسرحية. ولكن ، لإكمال القصة ، تحتاج إلى لعب العديد من الأعمال بترتيب معين بدقة. مثل هذا الأمر في هندستنا سوف نسمي الوضع .


الوضع (التوصيل) - مجموعة من الإجراءات بترتيب معين ، لها معنى كامل ، مفيدة للمستخدم النهائي.

توصيل


لمثل هذه الأساليب من العمليات ، اخترع موصل انتقائي أو محدد. بتعبير أدق ، "آلية توقيت لإجراء واحدة مختارة من تعدد تسلسل العملية" ، والتي تم الحصول على براءة الاختراع US2870278A . نحن نعرف هذا الجهاز على أنه "تطور" الغسالة. يتم إعطاء تطور معماري في بداية المقال.


يتجلى تنوع النهج في حقيقة أنه باستخدام هذه البنية ، يمكنك اختيار أي من الأوضاع الأربعة ، والتي تمر لن تقوم بتنفيذ إجراءات غير ضرورية.


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


التمثيل


إذا تحدثنا عن عرض تقديمي خالص دون اللجوء إلى قاعدة بيانات أو مصدر خارجي ، فإننا نقدم بعض المعلومات الثابتة: صفحة html ، ملف ، دليل في شكل json. يمكننا حتى إعطاء استجابة الرمز فقط - 200:


لنكتب أبسط "مدقق للصحة"


module Health class Endpoints < Sinatra::Base get '/check' do; end end end 

في شكله الأكثر بدائية ، سيبدو مخططنا كما يلي:


التمثيل التمثيلي


الاستطراد الغنائي

أطلب منك ملاحظة أنه في إطار Sinatra ، تجمع فئة Endpoints بين كل من جهاز التوجيه وجهاز التحكم في فئة واحدة. هل هذا ينتهك مبدأ المسؤولية وحدها؟ في الواقع ، نقاط النهاية ليست فئة ، بل طبقة يتم التعبير عنها من خلال فئة ، ومسؤوليتها على مستوى أعلى.


حسنًا ، ماذا عن جهاز التوجيه والتحكم ؟ ولا يمثلها مجموعة من الفئات ، ولكن باسم وظيفة وتنفيذها. الملف الثابت هو بشكل عام ملف. الفصل الواحد مسؤول عن مسؤولية واحدة ، لكن لا تحاول التعبير عن كل مسؤولية من خلال الفصل. استخدم التطبيق العملي ، وليس العقيدة.


العمل بنظام التخزين


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


لاسترداد كائن من التخزين لا يتطلب الوصول إلى منطق الأعمال. تخيل أننا نقوم بأتمتة أنشطة سلسلة الفنادق ولدينا مجلة ضيف في مكتب الاستقبال. قررنا أن نرى معلومات حول الزائر.


  module Reception class Endpoints < Sinatra::Base # Show item get '/residents/:id', provides: :json do resident = Repository::Residents.find params[:id] status 200 serialize(resident) end end end 

العمل مع نظام التخزين في شكل رسم بياني:


التخزين


كما نرى ، يتم تنفيذ التواصل بين الطبقة المسؤولة عن التخزين والطبقة المسؤولة عن تقديم البيانات من خلال نموذج الاستجابة. لا ينتمي هذا النموذج إلى أي من هذه الطبقات. في الواقع ، هذا كائن أعمال ويقع على الطبقة المسؤولة عن منطق الأعمال.


جارٍ المعالجة


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


ضع في اعتبارك حالة الاستخدام هذه. الزائر مسجل بالفعل في فندقنا ، لكننا نحتفل بكل وصول أو مغادرة.


  module Reception class Endpoints < Sinatra::Base # Register resident arrival post '/residents/:uid/arrival', provides: :json do result = Interactors::Arrival.call(resident_id: params[:id]) check!(result) do status 201 serialize result.data end end # Register resident departure post '/residents/:uid/departure', provides: :json do result = Interactors::Departure.call(resident_id: params[:id]) check!(result) do status 201 serialize result.data end end end end 

دعونا نتوقف قليلاً. لماذا لا تجعل التنفيذ طريقة واحدة مع معلمة status ؟ يختلف Arrival Departure بشكل أساسي. إذا وصل إلينا ضيف ، فيجب علينا التحقق مما إذا كان التنظيف قد انتهى ، وما إذا كانت هناك رسائل جديدة له ، وما إلى ذلك. بمغادرته ، يجب علينا ، على العكس ، أن نبدأ التنظيف إذا لزم الأمر. في المقابل ، لا نتذكر حتى الرسائل ، لأنه لو كان في فندق ، لكنا اتصلنا به على الفور. كل منطق الأعمال هذا الذي نصفه على طبقة Interactor .


جارٍ المعالجة


ولكن ماذا نفعل إذا كانت لدينا بيانات من الخارج؟ هنا يتم توصيل عمل جمع البيانات .


جمع البيانات


أثناء التسجيل الأولي لضيف في الفندق ، يملأ نموذج التسجيل. يتم التحقق من هذا النموذج. إذا كانت البيانات صحيحة ، فستتم عملية تسجيل الأعمال. تعيد العملية البيانات - نموذج الأعمال "المستأجر" الذي تم إنشاؤه. نقدم هذا النموذج للضيف في شكل مقروء:


 module Reception class Endpoints < Sinatra::Base # Register new resident post '/residents', provides: [:json] do form = Forms::Registration.new(params) complete! form do check! form.result do status 201 serialize form.result.data end end end end end 

من الناحية التخطيطية ، يبدو هذا:


الجمع


قواعد اللعبة (القواعد)


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

الشجرة


مخطط عام


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


خريطة عالية الدقة




مصادر الإلهام

Source: https://habr.com/ru/post/ar429750/


All Articles