عند التعامل مع SOLID ، غالبًا ما صادفت حقيقة أن عدم اتباع هذه المبادئ يمكن أن يؤدي إلى مشاكل. المشاكل معروفة ، لكنها غير رسمية. تمت كتابة هذه المقالة بهدف إضفاء الطابع الرسمي على المواقف النموذجية التي تنشأ في عملية كتابة التعليمات البرمجية والحلول الممكنة والعواقب الناشئة عن ذلك. سنتحدث عن سبب مواجهة الرموز السيئة وكيف تنمو المشاكل مع نمو البرنامج.
لسوء الحظ ، في معظم الحالات ، يأتي التقييم إلى خيارات "متعددة" و "واحد" ، والتي تشير إلى إعسار O-notation ، ولكن حتى هذا التحليل سيجعل من الممكن فهم الشفرة الأكثر خطورة حقًا لمزيد من تطوير النظام وأي رمز متسامح.
التعريف
نقول أن التغيير في البرنامج يتطلب "O" من إجراءات f (n) إذا كان المبرمج بحاجة إلى إجراء ما لا يزيد عن f (n) من التغييرات المنفصلة في البرنامج لتنفيذ التغيير بدقة لعامل ثابت ، حيث n تعني حجم البرنامج.
المقاييس
فكر في بعض ميزات تصميم روبرت مارتن وقم بتقييمها من حيث الترميز O.
التصميم صعب إذا تسبب تغيير واحد في سلسلة من التغييرات الأخرى في الوحدات التابعة. كلما زاد عدد الوحدات التي يتعين عليك تغييرها ، زاد صلابة التصميم.
الفرق الكبير هو التغييرات O (1) و O (n). على سبيل المثال يسمح تصميمنا بعدد ثابت من التغييرات ، أو مع نمو البرنامج ، سيزداد عدد التغييرات. بعد ذلك ، يجب أن نفكر في التغييرات نفسها - فقد تتحول أيضًا إلى صرامة مع بعض السلوك المقارب. وبالتالي ، يمكن أن تكون الصلابة معقدة حتى O (نانومتر). سيتم استدعاء المعلمة m عمق الصلابة. حتى التقدير التقريبي لعمق الصلابة في التصميم الذي يسمح بالصلابة O (n) معقد للغاية بالنسبة للشخص ، حيث يجب التحقق من كل تغيير حتى التغييرات الأعمق.
الهشاشة هي خاصية برنامج للتلف في العديد من الأماكن عند إجراء تغيير واحد. غالبًا ما تنشأ مشاكل جديدة في الأجزاء التي ليس لها اتصال مفاهيمي مع تلك التي تم تغييرها.
لن ننظر في مسألة الاتصال المنطقي للوحدات التي تحدث فيها التغييرات. لذلك ، من وجهة نظر التدوين ، لا يوجد فرق بين الهشاشة والصلابة ، والحجج الصالحة للصلابة تنطبق على الهشاشة.
التصميم خامل إذا كان يحتوي على أجزاء قد تكون مفيدة في أنظمة أخرى ، لكن الجهود والمخاطر المرتبطة بمحاولة فصل هذه الأجزاء عن النظام الأصلي كبيرة جدًا.
يمكن تفسير المخاطر والجهود المبذولة في هذا التعريف على أنها عدد التغييرات التي تحدث في الوحدة عند محاولة استخلاصها من النظام الأصلي على أنها غير ثابتة مع نمو حجم الوحدة. ومع ذلك ، كما تظهر الممارسة ، لا يزال الأمر يستحق التجريد ، حيث أن هذا يجلب النظام للوحدة نفسها ويسمح بنقلها إلى مشاريع أخرى. في كثير من الأحيان ، بعد الحاجة الأولى لنقل الوحدة إلى مشروع آخر ، تظهر مشاريع أخرى مماثلة.
اللزوجة
في مواجهة الحاجة إلى إجراء تغيير ، عادة ما يجد المطور عدة طرق للقيام بذلك. يحافظ البعض على التصميم ، والبعض الآخر لا يفعل ذلك (أي أنهم في الأساس "اختراق"). إذا كان تنفيذ أساليب الحفاظ على التصميم أصعب من الاختراق ، فإن لزوجة التصميم عالية. حل المشكلة أمر سهل ، ولكن الحق صعب. نريد تصميم برامجنا بحيث يكون من السهل إجراء تغييرات تحافظ على التصميم.
يمكن أن تسمى اللزوجة التالية قصر النظر من حيث ترميز O. نعم ، يتمتع المطور في البداية بفرصة لإجراء تغيير في O (1) بدلاً من O (n) (بسبب الصلابة أو الهشاشة) ، ولكن غالبًا ما تؤدي هذه التغييرات إلى مزيد من الصلابة والهشاشة ، أي زيادة عمق الصلابة. إذا تجاهلت مثل هذا "الجرس" ، فقد لا يكون من الممكن حل التغييرات اللاحقة باستخدام "الاختراق" وسيتعين عليك إجراء تغييرات في ظروف الصلابة (ربما أكثر من قبل "الجرس") أو إدخال النظام في حالة جيدة. أي أنه عند اكتشاف اللزوجة ، من الأفضل إعادة كتابة النظام بشكل صحيح.
يحدث مثل هذا: يحتاج إيفان إلى كتابة بعض التعليمات البرمجية التي تجعد قدمه الصغيرة. التسلق إلى أجزاء مختلفة من البرنامج ، حيث يعتقد أنه تم تدخين البوكرياد أكثر من مرة ، حيث وجد قطعة مناسبة. تقوم بنسخها ولصقها في وحدتها وإجراء التغييرات اللازمة.
لكن إيفان لا يعرف أن الشفرة التي استخرجها باستخدام الماوس وضعت بيتر هناك ، وأخذه من الوحدة التي كتبها Sveta. كانت Sveta أول من دخن كبح صغير ، لكنها عرفت أن هذه العملية تشبه إلى حد كبير تدخين الغواصين. وجدت في مكان ما رمزًا قام karmyachit karmaglot بنسخه في وحدتها وتعديله. عندما يظهر الرمز نفسه في أشكال مختلفة قليلاً مرارًا وتكرارًا ، يفقد المطورون فكرة التجريد.
في هذه الحالة ، يصبح من الواضح أنه عندما تكون هناك حاجة لتغيير أساس العمل المحفور ، يجب إجراء هذا التغيير في n n. بالنظر إلى إمكانية إجراء تعديلات فريدة في كل نسخة نسخ ، يمكن أن يؤدي هذا أيضًا إلى تغييرات غير ذات صلة منطقيًا. في هذه الحالة ، هناك فرصة لنسيان التغيير ببساطة في مكان آخر ، حيث لا توجد حماية في مرحلة التجميع. لذلك يمكن أن يتحول هذا أيضًا إلى تكرارات اختبار O (n).
تطبيق حول تدوين SOLID
SRP (مبدأ المسؤولية الفردية). يجب أن يكون لدى الكيان البرمجي سبب واحد فقط للتغيير (المسؤولية). وبعبارة أخرى ، على سبيل المثال ، لا يجب أن يتبع الفصل منطق الأعمال ورسم الخرائط ، لأن عند تغيير مسؤولية واحدة ، يجب أن نتأكد من أننا لم نلحق أي مسؤولية أخرى. أي أن التضارب مع مبدأ SRP يؤدي إلى الصلابة والهشاشة. يساعد اتباع هذا المبدأ أيضًا على التخلص من القصور الذاتي ونقل الوحدات من برنامج إلى آخر مع عدد أقل من التبعيات.
يظل السلوك المقارب للتغييرات بشكل أساسي كما هو دون اتباع المبدأ ، ولكن العامل الثابت ينخفض بشكل كبير. في كلتا الحالتين ، يجب علينا التحقق من محتويات الفصل بالكامل ، وفي حالة تغيير واجهة الكيان ، الأماكن التي يتفاعلون فيها مع هذا الكيان. يساعد اتباع SRP فقط على تقليل الواجهة واحتمال تغييرها ، بالإضافة إلى مقدار التنفيذ الداخلي ، والذي قد يتبين بعد التغيير أنه معيب. الاستدلال المشابه ، الذي تم اقتطاعه لمناقشة الواجهات ، صالح لـ ISP (مبدأ الفصل بين الواجهات).
OCP (مبدأ الإغلاق المفتوح). يجب أن تكون كيانات البرامج (الفئات والوحدات والوظائف وما إلى ذلك) مفتوحة للتوسيع ومغلقة للتعديل. يجب أن يتم فهم ذلك بطريقة تمكننا من تعديل سلوك الوحدة النمطية دون التأثير على التعليمات البرمجية المصدر الخاصة بها. عادة ، يتم تحقيق ذلك من خلال الميراث وتعدد الأشكال. بما أن انتهاك مبدأ LSP هو انتهاك لـ OCP ، و DIP وسيلة للحفاظ على OCP ، يمكن تطبيق ما يلي على كل من LSP و DIP. عدم الامتثال لمبدأ الانفتاح والانسجام لإجراء تغييرات في جميع الكيانات غير المغلقة فيما يتعلق بهذا التغيير.
حالة تافهة إلى حد ما ، على سبيل المثال ، وجود سلسلة من ifs التي تحدد نوع المتغير بين قائمة الفئات الفرعية. قد تظهر مثل هذه الهياكل في البرنامج أكثر من مرة. وكلما أضفت فئة فرعية جديدة ، يجب عليك إجراء التغييرات المناسبة في كل سلسلة. يمكن أن تنشأ حالات مماثلة ليس فقط مع صفوف الأطفال ، ولكن أيضًا مع أي اعتبار لجميع الحالات الخاصة الممكنة [يشير هذا إلى الحالات ليس في وقت كتابة هذا التقرير ، ولكن بشكل عام. قد تظهر الحالات لاحقًا].
الآن فكر في الوضع عندما نقوم بإجراء تغييرات m من نفس النوع ، والتي ، بسبب التعارض مع مبدأ الانفتاح ، تتطلب n عمليات منا. ثم ، إذا تركنا كل شيء كما هو ، ودعم البنية للنظر في الحالات الخاصة ، وعدم التعميم ، فسوف نحصل على التعقيد العام لجميع التغييرات O (مليون). إذا أغلقنا جميع الأماكن m فيما يتعلق بهذا التغيير ، فستتخذ التغييرات اللاحقة O (1) بدلاً من O (m). وبالتالي ، يتم تقليل التعقيد الكلي إلى O (m + n). وهذا يعني أن بدء عملية OCP لم يفت الأوان.
يقول مارتن عن هذا الموقف الذي لا يجب أن تخمنه (إذا كنت لا تعرف بالتأكيد ، بالطبع) كيفية الإغلاق من التغيير الأول ، ولكن بعد التغيير الأول يستحق الإغلاق ، لأن التغيير الأول كان علامة على أن النظام لن يبقى بالضرورة في الحالة الحالية. هذا أمر منطقي ، لأننا نقوم بإجراءات O (1 * n) بسبب عدم التقارب ، ثم إجراءات O (m) لإغلاق أنفسنا من التغييرات اللاحقة. في المجموع ، نحصل على التعقيد الكلي O (n + m) ، ولكن في نفس الوقت نقوم بكل الإجراءات بالضبط عندما تصبح ضرورية ولا نفعل شيئًا مقدمًا ، دون معرفة ما إذا كانت هناك حاجة إليها.
الأنماط والتدوين- O
يمكن استخلاص تشبيه آخر بين الترميز O في الترميز الحسابي والترميز O في التصميم. وهو يتألف من حقيقة أننا نخفض عدد العمليات الحسابية باستخدام الخوارزميات وهياكل البيانات ، مثل أشجار البحث والأكوام ، والتي تحل المشكلات النموذجية بشكل أسرع من الحلول "المباشرة" ، وعدد عمليات المبرمج ذات التصميم الجيد ، حيث يمكنه أيضًا استخدام حلول نموذجية جيدة تسمى أنماط التصميم. يمكنك تقييم تأثير الأنماط في سياق مبادئ SOLID ، ونتيجة لذلك ، في سياق تدوين O.
على سبيل المثال ، يلغي قالب الوسيط إمكانية كسر شيء ما في البرنامج عند تغيير منطق التفاعل بين كائنين ، لأنه يغلفه تمامًا ويضمن التعقيد المستمر لمثل هذا التغيير.
يسمح لنا قالب المحول باستخدام كيانات (قراءة إضافة) مع واجهات مختلفة ، والتي سنستخدمها لغرض مشترك. باستخدام هذا القالب ، يمكنك تضمين كائن جديد بواجهة غير متوافقة في النظام لعدد العمليات التي لا تعتمد على حجم النظام.
نظرًا لأن هياكل البيانات يمكن أن تدعم بعض العمليات ذات الخطوط المقاربة الجيدة ، وبعضها مع العمليات السيئة ، لذلك فإن الأنماط تتصرف بمرونة فيما يتعلق ببعض التغييرات وبشكل صارم فيما يتعلق بالآخرين.
حدود معقولة
عند التعامل مع الترميز O ، والعمل على مشكلة التحسين ، يجب أن نتذكر أنه ليس دائمًا الخوارزمية مع أفضل الخطوط المقاربة هي الأنسب لحل المشكلة. يجب أن يكون مفهوما أن الفرز بواسطة فقاعة لمجموعة من 3 عناصر سيعمل بشكل أسرع من الهرمي ، على الرغم من حقيقة أن الفرز الهرمي له خطوط مقاربة أفضل. بالنسبة للقيم الصغيرة لـ n ، يلعب العامل الثابت دورًا مهمًا ، والذي يخفيه الترميز O. O- التدوين في التصميم يعمل بنفس الطريقة. بالنسبة للمشاريع الصغيرة ، لا معنى لتسييج الكثير من القوالب ، نظرًا لأن تكاليف تنفيذها تتجاوز عدد التغييرات التي يجب إجراؤها من "التصميم الضعيف".