لماذا يجب علي عزل كيانات المجال الخاص بي عن طبقة العرض التقديمي الخاصة بي؟

StackOverflow https://stackoverflow.com/questions/821276

سؤال

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

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

لذلك أبحث عن بعض الأسباب الملموسة التي يمكنني استخدامها لدعم هذا الأمر.خاصة:

  1. لماذا لا نستخدم كائنات المجال في طبقة العرض التقديمي لدينا؟
    (إذا كانت الإجابة واضحة، "الفصل"، فيرجى توضيح سبب أهمية ذلك في هذا السياق)
  2. هل يجب علينا استخدام كائنات أو بنيات إضافية لعزل كائنات المجال الخاصة بنا عن الواجهة؟
هل كانت مفيدة؟

المحلول

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

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

نصائح أخرى

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

حسنًا، بدلاً من تحميل CompanyObject الذي قد يحتوي على إشارات إلى الاشتراكات أو من يعرف ماذا أيضًا، يمكنني إرسال DTO بالاسم والمعرف.وهذا هو الاستخدام الجيد IMHO.

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

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

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

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

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

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

أنت تفعل ذلك لنفس السبب الذي يجعلك تبقي SQL خارج صفحات ASP/JSP الخاصة بك.

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

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

أنا أعترض.

أعتقد أن أفضل طريقة للبدء هي البدء بكائنات المجال في طبقة العرض التقديمي الخاص بك حتى يكون من المنطقي القيام بخلاف ذلك.

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

نحن نستخدم نفس النموذج في الخادم وعلى واجهة المستخدم.وهذا ألم.علينا أن نعيد تشكيلها في يوم من الأيام.

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

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

في النهاية، أعتقد أن الأمر يتعلق فقط بأي طريقة أسهل.قد يكون هناك مشاريع حيث تعمل بشكل جيد وحيث لا توجد حاجة لكتابة نموذج DTO آخر.

تعتمد الإجابة على حجم طلبك.


تطبيق بسيط CRUD (إنشاء، قراءة، تحديث، حذف).

بالنسبة للتطبيقات الخام الأساسية، ليس لديك أي وظيفة.إن إضافة DTO فوق الكيانات سيكون مضيعة للوقت.سيزيد من التعقيد دون زيادة قابلية التوسع.

enter image description here


تطبيق غير معقد إلى حد ما

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

تعد إضافة DTOs في هذه الحالة فكرة جيدة لعدة أسباب:

  • يمكن لطبقة العرض التقديمي رؤية مجموعة فرعية فقط من الحقول التي يمتلكها الكيان.تقوم بتغليف الكيانات
  • لا يوجد اقتران بين الواجهة الخلفية والأمامية
  • إذا كانت لديك أساليب عمل داخل الكيانات، ولكن ليس في DTO، فإن إضافة DTOs يعني أن الكود الخارجي لا يمكنه تدمير حالة كيانك.

enter image description here


تطبيق المؤسسة المعقدة

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

enter image description here

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

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

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

تتعلق الواجهات بالمدخلات وطرق العرض المقدمة للنواة الوظيفية الثابتة والمصممة بشكل صحيح.

اللعنة، أنا يُقسم وقال هذا الثبات.

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

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

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

لنفترض الآن أن محرك الكلام الخاص بنظام الاتصال الهاتفي يعمل على نوع مختلف تمامًا من أجهزة الكمبيوتر (نظام التشغيل Mac على سبيل المثال) عن جهاز الكمبيوتر الذي يقوم بتشغيل موقع الويب (ربما يعمل بنظام Windows).

بالطبع من السهل الوقوع في الفخ "حسنًا، في شركتي، نهتم باللغة الإنجليزية فقط، ونقوم بتشغيل موقعنا على LAMP (Linux وApache وMySQL وPHP) ويستخدم الجميع نفس الإصدار من Firefox".ولكن ماذا بعد 5 أو 10 سنوات؟

راجع أيضًا قسم "انتشار البيانات بين الطبقات" في ما يلي، والذي أعتقد أنه يقدم حججًا مقنعة:

http://galaxy.andromda.org/docs/andromda-documentation/andromda-getting-started-java/Java/index.html

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

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

فيما يلي مثال حقيقي عن السبب الذي يجعلني أجد أنه من الممارسات الجيدة فصل كيانات المجال عن طريقة العرض.

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

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

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

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

السبب المعقول الوحيد لإضافة تعيين إضافي بين الدلالات المعممة والمجالات المحددة هو أن لديك (الوصول إلى) مجموعة موجودة من التعليمات البرمجية (والأدوات) التي تعتمد على دلالات معممة (ولكن قابلة للتعيين) تختلف عن دلالات المجال الخاص بك.

تعمل التصميمات المعتمدة على المجال بشكل أفضل عند استخدامها مع مجموعة متعامدة من أطر عمل المجال الوظيفي (مثل ORM وGUI وسير العمل وما إلى ذلك).تذكر دائمًا أنه فقط في الطبقة الخارجية المجاورة يجب كشف دلالات المجال.عادةً ما تكون هذه هي الواجهة الأمامية (GUI) والواجهة الخلفية المستمرة (RDBM، ORM).يمكن لأي طبقات متداخلة مصممة بشكل فعال أن تكون ثابتة في المجال.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top