Sunday, January 14, 2018

هندسة البرمجيات بالهجايص -- (3) تفكيك التعلق/الاعتمادية

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

إِذا اِكتَحَلَت عَيني بِعَينِكِ لَم تَزَل *** بِخَيرٍ وَجَلَّت غَمرَةٌ عَن فُؤادِيا
فَأَنتِ الَّتي إِن شِئتِ أَشقَيتِ عِيشَتي *** وَأَنتِ الَّتي إِن شِئتِ أَنعَمتِ بالِيا
وَأَنتِ الَّتي ما مِن صَديقٍ وَلا عِداً *** يَرى نِضوَ ما أَبقَيتِ إِلّا رَثى لِيا
-- قيس بن الملوح (مجنون ليلى)
في الأبيات اللي فاتت دي بيصف قيس شدة تعلقه بليلى، و لأن التعلق ده (أو الاعتمادية) هو موضوع المقالة دي، فقلت أبدأها بشعر غزل، زي ما كان العرب بيعلموا في قصائدهم، حتى لو كانت لأغراض تانية غير الغزل:) بالمناسبة، القصيدة جميلة قوي ابقوا بصوا عليها:)

نخش بقى في الموضوع… يعني إيه تعلق أو اعتمادية dependency؟

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

صدق أو لا تصدق: أغلس تعلق أو اعتمادية بيكون في الوراثة inheritance! 

لأن أي تعديل في الbase class غالبا بيأثر على كل الderived classes، وهو ده التعلق أو الاعتمادية اللي بنتكلم عنها! مش بس كده، الclass الوارثة بتكون عارفة كل حاجة تقريبا عن الbase class. مش عارف أجيبهالكم إزاي… بس ده معناه إني ببوظ الencapsulation اللي هي أحد الأعمدة الرئيسية في الObject Oriented Programming!
وده مش كلامي - عشان محدش يقول إني بهذي - ده كلام عصابة الأربعة Gang of Four (GoF) قالوا بالنص في كتابهم عن الDesign Patterns:
“Because inheritance exposes a subclass to details of its parent’s implementation, it’s often said that ‘inheritance breaks encapsulation’”

* طيب نعمل إيه؟ 

- أول مبدأ معانا هو تفضيل التجميع أو التركيب على الوراثة favor composition over inheritance يعني بالبلدي ما تعملش وراثة inheritance واعمل تجميع/تركيب compostion.

يعني إيه تركيب composition؟ بتبسيط مخل: يعني اعمل class منفصلة و خد منها reference في الclass الأولى.
مثال: لو عندك class اسمها أسد الغابة وناوي تخليها ترث inherits من class تانية اسمها الأسد، فكر تاني، يمكن يكون هو هو نفس الأسد بس شغال في الغابة بدوام كامل fulltime و خليها attribute/field/property للأسد، فلما يجيبلك أسد السيرك هاتلاقيها هاتسد معاك من غير ما تحتاج تعمل class جديدة ترث من الأولى. طبعا الclass الجديدة بتاعت الوظيفة دي ممكن تزود فيها بيانات مفصلة عن طبيعة العمل، وأوقات الدوام، و مكان الغابة...إلخ.

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

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

- هاتقول لي: بس أنا عندي كود مشترك كتير، و محتاج أطبق الوراثة عشان أستفيد من القابلية لإعادة الاستخدام reusability اللي بتتيحها الObject Oriented Programming.أقولك صح كلامك (مؤقتا)، فيه عندنا قاعدة فعلا بتقول: امنع تكرار الكود Don't Repeat Yourself(DRY)
و البرنس أونكل بوب بيقول -بتصرف- إن تكرار الكود ربما يكون مصدر كل الشرور في البرمجيات!
وحيث إننا ما عرفناش نتخلص من الوراثة، فتعالوا نقلل من آثارها الجانبية.

- المبدأ اللي بعد كده بيقول: الوراثة على قدر الحاجة Interface Segregation Principle.(الترجمة متصرفة جدا أنا عارف عشان Segregation معناها الفصل). بس المعنى المقصود هو إنك ما تعملش base class أو Interface فيها كل حاجة و بالتالي كل اللي هايورثها أو هاينفذها هاياخدها بسلاطاتها ببابا غنوجها، وده هايزود الاعتمادية جدا و هايؤدي لكسر المبدأ التالي:

- مبدأ تقليل المفاجآت Principle of least surprise!

لو خالفت المبدأ اللي فات هاتلاقي فيه كود كتير أنت مش محتاجه من الbase class متاح للاستخدام عن طريق الinherited classes، وبالتالي سهل جدا يساء استخدامه من قبل المبرمجين، وهاتلاقي برضو abstract methods أنت مش محتاجها بس مضطر تكتب لها implementation عشان هي abstract فهاترمي exceptions أو تحط أي كود مالوش أي لازمة، وكل ده هايؤدي لمفاجآت غير سارة للمبرمجين اللي هايكون من سوء حظهم إنهم يتعاملوا مع الكود بتاعك، و مفاجآت غير سارة برضو للمستخدمين اللي هايستخدموا البرنامج بتاعك!
المبدأ ده مهم و هانرجع له تاني - إن شاء الله - كتير.

سامع واحد مركز معايا بيقول الاعتراضات التالية:
- أول حاجة: أنا ليه قلت على الكلام على القابلية لإعادة الاستخدام reusability إنها صح (مؤقتا)؟
- تاني حاجة: لو ما عملتش inheritance إزاي هاستفيد من الpolymorphism؟
- تالت حاجة: أونكل بوب (روبرت مارتن) مأكد لي إن الوراثة حلوة مفيش كلام، ده حتى عامل مبدأ في الObject Oriented Design اسمه Open/Closed Principle! إيه الكلام بقى؟

والإجابة هاتكون معانا - إن شاء الله - في الحلقات القادمة، فابقوا معنا 

No comments:

Post a Comment