من مترجم: نشر سيفيرين بيريز مقالاً عن استخدام مبادئ سوليد في البرمجة من أجلك. المعلومات الواردة في المقالة ستكون مفيدة لكل من المبتدئين والمبرمجين ذوي الخبرة.إذا كنت مطورًا ، فمن المحتمل أنك سمعت عن مبادئ SOLID. إنها تمكن المبرمج من كتابة رمز نظيف جيد التنظيم وسهل الصيانة. تجدر الإشارة إلى أنه في البرمجة هناك عدة طرق لكيفية القيام بهذا العمل أو ذاك بشكل صحيح. لدى المختصين المختلفين أفكارًا وفهمًا مختلفين لـ "الطريق الصحيح" ، كل هذا يتوقف على تجربة كل شخص. ومع ذلك ، فإن الأفكار المعلنة في SOLID مقبولة من قبل جميع ممثلي مجتمع تكنولوجيا المعلومات تقريبًا. أصبحت نقطة الانطلاق لظهور وتطوير العديد من الممارسات الجيدة لإدارة التنمية.
دعونا نرى ماهية مبادئ سوليد وكيف تساعدنا.
توصي Skillbox بما يلي: دورة عملية "Mobile Developer PRO" .
نذكرك: لجميع قراء "Habr" - خصم بقيمة 10،000 روبل عند التسجيل في أي دورة تدريبية في Skillbox باستخدام الرمز "Habr" الترويجي.
ما هو الصلبة؟
هذا المصطلح هو اختصار ، كل حرف من المصطلح هو بداية اسم مبدأ معين:
- مبدأ المسؤولية. يمكن أن يكون للوحدة سبب واحد فقط للتغيير.
- يا قلم / مبدأ مغلق . يجب أن تكون الفئات والعناصر الأخرى مفتوحة للتوسع ، لكن يتم إغلاقها للتعديل.
- مبدأ الاستبدال L iskov . يجب أن تكون الوظائف التي تستخدم النوع الأساسي قادرة على استخدام أنواع فرعية من النوع الأساسي دون معرفة ذلك.
- أنا مبدأ الفصل nterface . لا ينبغي أن تعتمد كيانات البرامج على الأساليب التي لا تستخدمها.
- مبدأ الانقلاب د . يجب ألا تعتمد وحدات المستوى العلوي على وحدات المستوى الأدنى.
مبدأ المسؤولية الوحيدة
ينص مبدأ المسؤولية الفردية (SRP) على أن كل فئة أو وحدة نمطية في البرنامج يجب أن تكون مسؤولة عن جزء واحد فقط من وظائف هذا البرنامج. بالإضافة إلى ذلك ، يجب تعيين عناصر من هذه المسؤولية إلى الفصل الخاص بهم ، وعدم توزيعها بين الطبقات غير ذات الصلة. يصف روبرت س. مارتن ، مطور برنامج التقويم الإقليمي والإنجيلي الرئيسي ، المسؤولية بأنها سبب التغيير. في البداية ، اقترح هذا المصطلح كواحد من عناصر عمله ، "مبادئ التصميم الموجه للكائنات". تضمن المفهوم الكثير من نمط الاتصال الذي تم تعريفه مسبقًا بواسطة Tom Demarco.
تضمن المفهوم أيضًا العديد من المفاهيم التي صاغها ديفيد بارناسوس. أهمها هما التغليف وإخفاء المعلومات. جادل بارناسوس بأن تقسيم النظام إلى وحدات منفصلة لا ينبغي أن يستند إلى تحليل لمخططات التدفق أو تدفقات التنفيذ. يجب أن تحتوي أي من الوحدات النمطية على حل محدد يوفر الحد الأدنى من المعلومات للعملاء.
بالمناسبة ، أعطى مارتن مثالًا مثيرًا للاهتمام مع كبار المديرين في الشركة (COO ، CTO ، CFO) ، كل منهم يستخدم برنامجًا محددًا للعمل لأغراض مختلفة. ونتيجة لذلك ، يمكن لأي منهم تنفيذ تغييرات في البرنامج دون التأثير على مصالح المديرين الآخرين.
كائن إلهي
كالعادة ، فإن أفضل طريقة لتعلم برنامج التقويم الاستراتيجي هي رؤية كل شيء في العمل. لنلقِ نظرة على قسم من البرنامج لا يتوافق مع مبدأ المسؤولية المشتركة. هذا هو رمز روبي الذي يصف سلوك وسمات المحطة الفضائية.
تحقق من المثال وحاول تحديد ما يلي:
مسؤوليات تلك الكائنات التي تم الإعلان عنها في فئة SpaceStation.
أولئك الذين قد تكون مهتمة في عمل المحطة الفضائية.
class SpaceStation def initialize @supplies = {} @fuel = 0 end def run_sensors puts "----- Sensor Action -----" puts "Running sensors!" end def load_supplies(type, quantity) puts "----- Supply Action -----" puts "Loading
في الواقع ، فإن محطتنا الفضائية غير فعالة (أعتقد أنني لن أتلقى مكالمة من وكالة ناسا في المستقبل المنظور القريب) ، ولكن هناك شيء لتحليله.
لذلك ، فإن فئة SpaceStation لديها العديد من المسؤوليات (أو المهام) المختلفة. كل منهم يمكن تقسيمها إلى أنواع:
- مجسات
- العرض (المواد الاستهلاكية) ؛
- الوقود
- المعجلات.
على الرغم من حقيقة أنه لم يتم تعريف أي من موظفي المحطة في الفصل ، يمكننا بسهولة تخيل من المسؤول عن ماذا. على الأرجح ، يتحكم العالم في المستشعرات ، فاللوجستي مسؤول عن توفير الموارد ، والمهندس مسؤول عن إمدادات الوقود ، والطيار يتحكم في المعجلات.
هل يمكن القول أن هذا البرنامج غير متوافق مع SRP؟ نعم بالطبع. لكن فئة SpaceStation هي "كائن إلهي" نموذجي يعرف كل شيء ويفعل كل شيء. هذا هو النمط الرئيسي المضاد للنمط في البرمجة الموجهة للكائنات. للمبتدئين ، من الصعب للغاية الحفاظ على هذه الأشياء. حتى الآن ، البرنامج بسيط جدًا ، نعم ، لكن تخيل ما سيحدث إذا أضفنا ميزات جديدة. ربما ستحتاج محطة الفضاء لدينا إلى مركز طبي أو غرفة اجتماعات. وكلما زاد عدد الميزات ، زاد عدد SpaceStation. حسنًا ، نظرًا لأن هذا الكائن سيتم توصيله بالآخرين ، ستصبح صيانة المجمع بالكامل أكثر تعقيدًا. نتيجة لذلك ، يمكننا تعطيل عمل المعجلات ، على سبيل المثال. إذا طلب الباحث تغييرات في العمل مع أجهزة الاستشعار ، فإن هذا قد يؤثر بشكل جيد على أنظمة الاتصالات في المحطة.
يمكن أن يؤدي انتهاك مبدأ SRP إلى تحقيق انتصار تكتيكي قصير الأجل ، ولكن في النهاية "سنخسر الحرب" ، ستكون خدمة مثل هذا الوحش في المستقبل صعبة للغاية. من الأفضل تقسيم البرنامج إلى أقسام منفصلة من التعليمات البرمجية ، يكون كل منها مسؤولاً عن إجراء عملية محددة. مع وضع ذلك في الاعتبار ، دعونا نغير فئة SpaceStation.
تقاسم المسؤوليةأعلاه ، حددنا أربعة أنواع من العمليات التي يتم التحكم فيها بواسطة فئة SpaceStation. عند إعادة بيع المساكن ، سنضعها في الاعتبار. رمز محدث يطابق برنامج التقويم الاستراتيجي بشكل أفضل.
class SpaceStation attr_reader :sensors, :supply_hold, :fuel_tank, :thrusters def initialize @supply_hold = SupplyHold.new @sensors = Sensors.new @fuel_tank = FuelTank.new @thrusters = Thrusters.new(@fuel_tank) end end class Sensors def run_sensors puts "----- Sensor Action -----" puts "Running sensors!" end end class SupplyHold attr_accessor :supplies def initialize @supplies = {} end def load_supplies(type, quantity) puts "----- Supply Action -----" puts "Loading
هناك العديد من التغييرات ، البرنامج يبدو الآن أفضل بالتأكيد. الآن أصبحت فئة SpaceStation الخاصة بنا ، بدلاً من ذلك ، حاوية يتم فيها بدء العمليات المتعلقة بالأجزاء التابعة ، بما في ذلك مجموعة من المستشعرات ، ونظام تزويد للمستهلكات ، وخزان وقود ، وأجهزة التعزيز.
لأي من المتغيرات الآن هناك فئة المقابلة: Sensors؛ العرضمولد FuelTank الدفاعات.
هناك العديد من التغييرات المهمة على هذا الإصدار من الكود. والحقيقة هي أن الوظائف الفردية لا يتم تغليفها في فصولها فقط ، بل يتم تنظيمها بطريقة تصبح متوقعة ومتسقة. نقوم بتجميع عناصر متشابهة في الوظيفة لاتباع مبدأ الاتصال. الآن ، إذا كنا بحاجة إلى تغيير مبدأ النظام عن طريق التبديل من بنية التجزئة إلى صفيف ، فما عليك سوى استخدام فئة SupplyHold ، ولن نضطر إلى لمس الوحدات النمطية الأخرى. وبالتالي ، إذا غير الضابط المسؤول عن الخدمات اللوجستية شيئًا ما في قسمه ، فستظل العناصر المتبقية في المحطة على حالها. ومع ذلك ، فإن فئة SpaceStation لن تكون على علم بالتغييرات.
من المحتمل أن يكون مسؤولو المحطة الفضائية لدينا سعداء بالتغييرات ، حيث يمكنهم طلب التغييرات التي يحتاجون إليها. لاحظ أن الرمز يحتوي على أساليب مثل report_supplies و report_fuel المضمنة في فصول SupplyHold و FuelTank. ماذا يحدث إذا طلبت الأرض تغيير طريقة إنشاء التقارير؟ ستحتاج إلى تغيير كلتا الفئتين ، SupplyHold و FuelTank. ولكن ماذا لو كنت بحاجة إلى تغيير الطريقة التي توفر بها الوقود والمواد الاستهلاكية؟ قد تضطر إلى تغيير كل الطبقات مرة أخرى. وهذا انتهاك لمبدأ SRP. دعونا إصلاحه.
class SpaceStation attr_reader :sensors, :supply_hold, :supply_reporter, :fuel_tank, :fuel_reporter, :thrusters def initialize @sensors = Sensors.new @supply_hold = SupplyHold.new @supply_reporter = SupplyReporter.new(@supply_hold) @fuel_tank = FuelTank.new @fuel_reporter = FuelReporter.new(@fuel_tank) @thrusters = Thrusters.new(@fuel_tank) end end class Sensors def run_sensors puts "----- Sensor Action -----" puts "Running sensors!" end end class SupplyHold attr_accessor :supplies attr_reader :reporter def initialize @supplies = {} end def get_supplies @supplies end def load_supplies(type, quantity) puts "----- Supply Action -----" puts "Loading
في هذا الإصدار الأخير من البرنامج ، تم تقسيم المسؤوليات إلى فئتين جديدتين ، FuelReporter و SupplyReporter. كلاهما من أبناء فئة المراسل. بالإضافة إلى ذلك ، أضفنا متغيرات المثيل إلى فئة SpaceStation من أجل تهيئة الفئة الفرعية اللازمة إذا لزم الأمر. الآن ، إذا قررت الأرض تغيير شيء آخر ، فسنقوم بإجراء تغييرات على الفئات الفرعية ، وليس على الفئة الرئيسية.
بالطبع ، لا تزال بعض الفصول هنا تعتمد على بعضها البعض. لذلك ، يعتمد كائن SupplyReporter على SupplyHold ، ويعتمد FuelReporter على FuelTank. بالطبع ، يجب أن تكون مرتبطة التعزيز إلى خزان الوقود. ولكن هنا يبدو كل شيء منطقيًا ، وإجراء تغييرات لن يكون أمرًا صعبًا بشكل خاص - لن يؤثر تحرير رمز كائن واحد على الآخر كثيرًا.
وبالتالي ، أنشأنا رمزًا معياريًا يتم فيه تحديد مسؤوليات كل كائن / فئة بدقة. العمل مع مثل هذا الكود ليس مشكلة ؛ صيانته ستكون مهمة بسيطة. كامل "كائن إلهي" قمنا بتحويلها إلى SRP.
توصي Skillbox بما يلي: