العمارة الواقعية البحتة. العصف الذهني

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

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

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

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

من يريد الحصول على حبوب منع الحمل السحرية التي تساعد على التوقف عن الاهتزاز والبدء في إعادة التصنيع - مرحبًا في تقرير الفيديو أو تحت القط.





اسمي فيكتور ، أنا من رومانيا. رسميا ، أنا مستشار وخبير تقني ومهندس رئيسي في شركة IBM الرومانية. ولكن إذا طُلب مني تقديم تعريف لنشاطي بنفسي ، فأنا مُبشِّر عن الكود الخالص. أحب إنشاء رمز جميل ونظيف ومدعوم - كقاعدة عامة ، أتحدث عن هذا في التقارير. والأكثر من ذلك ، أنا مستوحى من التعليم: تدريب المطورين في مجالات Java EE ، Spring ، Dojo ، Test Driven Development ، Java Performance ، وكذلك في مجال التبشير - مبادئ أنماط الشفرة النظيفة وتطورها.

الخبرة التي تستند إليها نظريتي هي بشكل رئيسي تطوير تطبيقات المؤسسة لأكبر عميل IBM في رومانيا - القطاع المصرفي.

خطة هذه المقالة كما يلي:

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


ولكن أولاً ، لنتذكر المبادئ الرئيسية التي يجب علينا دائمًا ، كمطورين ، أن نتذكرها.

مبدأ المسؤولية الوحيدة





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

ملزمة وحدة ضعيفة





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

لا تكرر





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

البساطة والإيجاز





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

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

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



كما ترى ، لا يتطلب التنفيذ سوى سطرين من التعليمات البرمجية. بعد كتابة الطلب في التعليق التوضيحي المطلوب (ليس من الصعب القيام بذلك إذا كنت تستخدم Spring أو CDI) ، فسوف تحرر نفسك من الحاجة إلى تمرير تسجيل دخول المستخدم إلى الأساليب وأيًا كان: البيانات الوصفية للطلب المخزنة داخل السياق ستنتقل التطبيق بشفافية. سيسمح لك الوكيل المحدد النطاق بالوصول إلى البيانات الوصفية للطلب الحالي في أي وقت.

اختبارات الانحدار





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

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

أين تنفذ منطق الأعمال؟





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

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

بالنسبة لتطوري ، اخترت دائمًا النهج الأول. يمكنني أن أؤكد لكم أنه في حالتي عملت بشكل مثالي.

نمذجة البيانات



الكيانات



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



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



دعنا نرى ما قدمته لكيان العميل. أولاً ، قمت بتطبيق getFullName() الاصطناعية getFullName() والتي ستعيد لي تسلسل firstName و lastName. قمت أيضًا بتطبيق طريقة activate() - لرصد حالة كياني ، وبالتالي تغليفها. في هذه الطريقة ، قمت أولاً بإجراء عملية التحقق من الصحة ، وثانيًا ، تعيين القيم للحالة والحقول التي تم تنشيطها ، لذلك ليست هناك حاجة إلى تعيينهم. أضفت أيضًا إلى كيان العميل isActive() و canPlaceOrders() ، التي تنفذ التحقق من صحة لامدا داخل نفسي. وهذا ما يسمى التغليف الأصلي. هذه المسندات تكون مفيدة إذا كنت تستخدم مرشحات Java 8: يمكنك تمريرها كوسيطة للمرشحات. أنصحك باستخدام هؤلاء المساعدين.

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



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

كائنات القيمة



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

يجب أن يكون كائن القيمة:

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




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

الفرق بين كيان وكائن القيمة



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

كائنات نقل البيانات (DTOs)





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

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

المبدأ الأول المهم: يجب أن يحتوي DTO على الحد الأدنى من المنطق.
هنا مثال على تنفيذ CustomerDto .



المحتوى: المجالات الخاصة والخطابات العامة والمستوطنون لهم. يبدو أن كل شيء رائع. OOP بكل مجده. لكن هناك شيء واحد سيئ: في شكل مراسلين ومستوطنين قمت بتطبيق العديد من الأساليب. في DTO ، يجب أن يكون هناك أقل قدر ممكن من المنطق. ثم ما هو طريقي؟ أجعل الحقول عامة! ستقول أن هذا يعمل بشكل سيئ مع مراجع الطريقة من Java 8 ، وأنه ستكون هناك قيود ، وما إلى ذلك. ولكن صدق أو لا تصدق ، لقد فعلت كل مشاريعي (10-11 قطعة) مع DTOs من هذا القبيل. أخي على قيد الحياة. الآن ، بما أن الحقول الخاصة بي عامة ، يمكنني بسهولة تعيين القيمة إلى dto.fullName ببساطة عن طريق وضع علامة المساواة. ما الذي يمكن أن يكون أكثر جمالا وبساطة؟

منظمة المنطق



رسم الخرائط



لذا ، لدينا مهمة: نحن بحاجة إلى تحويل كياناتنا إلى DTO. نقوم بتنفيذ التحول على النحو التالي:



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

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

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

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

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

سأوضح مع مثال. بناءً على DTO الحالي ، نقوم بإنشاء كيان Customer .



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

لكن المشكلة لا تنتظرنا هنا ، ولكن بالطريقة التي تؤدي العملية العكسية - تحويل الكيان إلى DTO.



باستخدام حلقة ، نراجع جميع العناوين المرتبطة بالعميل الحالي ونترجمها إلى عناوين DTO. إذا كنت تستخدم ORM ، فربما ، عند استدعاء طريقة getAddresses() ، سيتم تنفيذ التحميل getAddresses() . إذا كنت لا تستخدم ORM ، فسيكون هذا طلبًا مفتوحًا لجميع أطفال هذا الوالد. وهنا تتعرض لخطر الانغماس في "مشكلة N + 1". لماذا؟



لديك مجموعة من الآباء ، لكل منهم أطفال. لكل هذا ، تحتاج إلى إنشاء نظائرك الخاصة داخل DTO. ستحتاج إلى تنفيذ استعلام SELECT واحد لاجتياز الكيانات الأم N ثم استعلامات N SELECT للتنقل بين الأطفال في كل منها. إجمالي طلب N + 1. بالنسبة إلى 1000 كيان من Customer الرئيسيين ، ستستغرق هذه العملية 5-10 ثوانٍ ، والتي تستغرق بالطبع وقتًا طويلاً.

افترض ، مع ذلك ، أن طريقة CustomerDto() تسمى داخل الحلقة ، وتحويل قائمة كائنات العميل إلى قائمة CustomerDto.



تحتوي مشكلة استعلامات N + 1 على حلول قياسية بسيطة: في JPQL يمكنك استخدام FETCH by customer.addresses لاسترداد الأطفال ثم توصيلهم باستخدام JOIN ، وفي SQL يمكنك استخدام تجاوز IN و WHERE .

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

حول التحسين



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

هل أنت متأكد من أنك مؤهل لأنك خبير حقيقي؟ كن متواضعا في تقييم نفسك. لا تعتقد أنك تفهم JVM حتى تقرأ على الأقل كتابين عن تجميع JIT. يحدث أن يأتي أفضل المبرمجين من فريقنا لي ويقولون أنهم يعتقدون أنهم وجدوا تنفيذًا أكثر كفاءة. اتضح أنهم اخترعوا مرة أخرى شيئًا يعقد فقط الشفرة. لذا أجيب مرارًا وتكرارًا: YAGNI. لا نحتاجها.

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

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

يفضل التكوين على الميراث



العودة إلى DTO لدينا. لنفترض أننا نحدد DTO مثل هذا:



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

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

يمكنك اللجوء إلى مبدأ الميراث المعروف في نظرية OOP: ما عليك سوى تحديد DTO أساسي وإنشاء وريث لكل حالة استخدام.



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

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



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

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



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

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

الواجهات





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



ما هو الغرض من الواجهة؟

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


تحلل الكثير من التعليمات البرمجية





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

مثال:



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

مثال آخر:



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

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

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

إقران البرمجة





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

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

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

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



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

"أنا مهندس معماري. بحكم التعريف ، أنا دائمًا على حق ".



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

العمارة البصل



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



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

الانتباه إلى هذا الاعتماد:



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

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

أولاً: تخطي العدو داخل الوحدة.



من الواضح أن هذا خيار سيئ: من المحتمل ألا يتم ترقية الخدمة الخارجية غدًا إلى الإصدار 2.0 ، وعلينا إعادة رسم نطاقنا. لا تدع العدو داخل المجال!

أقترح نهجًا مختلفًا: سنقوم بإنشاء محول خاص للتفاعل .



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

على سبيل المثال ، قد نحتاج إلى تنفيذ استعلامات LDAP من أحد المجالات. للقيام بذلك ، نقوم بتنفيذ "وحدة مكافحة الفساد" LDAPUserServiceAdapter.



في المحول يمكننا:

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


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


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

مبدأ انعكاس التبعية





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

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



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

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

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

بحسب العم بوب ، فإن مبدأ انعكاس التحكم (أو ، كما يسميه "بنية التوصيل") ربما يكون أفضل ما يقدمه نموذج OOP بشكل عام.



يمكن استخدام هذه الإستراتيجية للتكامل مع أي أنظمة ، للمكالمات والرسائل المتزامنة وغير المتزامنة ، لإرسال الملفات ، إلخ.

نظرة عامة على اللمبة





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

تبدو البنية كما يلي:



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

وحدة المستودع



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



يمكنك أيضًا استخدام Spring و JdbcTemplate:



أو MyBatis DataMapper:



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

تطبيق JPA / Hibernate:



في حالة Spring Data JPA:



يمكن لـ Spring Data JPA إنشاء طرق تلقائيًا في وقت التشغيل ، على سبيل المثال ، getById () و getByName (). كما يسمح لك بتنفيذ استعلامات JPQL إذا لزم الأمر - وليس لقاعدة البيانات ، ولكن لنموذج الكيان الخاص بك.

يبدو رمز JPA Hibernate و Spring Data JPA جيدًا حقًا. هل نحن بحاجة لاستخراجها من المجال على الإطلاق؟ في رأيي ، هذا ليس ضروريًا وضروريًا. على الأرجح ، سيكون الرمز أنظف حتى إذا تركت هذا الجزء داخل المجال. لذا التصرف على الوضع.



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

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

API





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

لمبة براغماتية



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


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

الاختبارات



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

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

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

اختبارات الوحدة





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



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

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



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

نصائح



تلخيصًا لكل ما قيل اليوم ، أود أن أوجه إليك النصائح التالية:

  • اجعله بسيطًا لأطول فترة ممكنة (وبغض النظر عن التكلفة) : تجنب "إعادة هندسة" التحسين المتأخر ، لا تفرط في تحميل التطبيق ؛
  • , , ;
  • «» — ;
  • , — : ;
  • «», , — ;
  • لا تخف من الاختبارات : امنحهم الفرصة لإسقاط نظامك ، ويشعرون بكل فوائدهم - في النهاية ، هم أصدقاؤك لأنهم قادرون على الإشارة بصدق إلى المشاكل.


من خلال القيام بهذه الأشياء ، سوف تساعد كلاً من فريقك ونفسك. وبعد ذلك ، عندما يأتي يوم تسليم المنتج ، ستكون جاهزًا لذلك.

ماذا تقرأ







. JPoint — , 19-20 - Joker 2018 — Java-. . .

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


All Articles