Thursday, January 25, 2018

أسئلة المعلم رفاعي الدسوقي في البرمجة: (2) المراهقة في البرمجة


المقالة اللي فاتت اتكلمنا عن الفرق في المهارات الشخصية اللي بيكتسبها المبرمج كل ما خبرته بتزيد. (الرابط في أول تعليق) خلونا بقى نتكلم المرة دي كفنيين 
قبل ما أبدأ عاوز أقول إن فيه مبرمجين بزعل عليهم جدا. أكتر من مرة تقابلني حالة واحد خبرة أكتر من 8 أو 10 سنين و آجي أسأله مثلا عمرك استخدمت الpolymorphism؟ اللي يقولي لأ! و اللي يقولي ما احتجتهاش!!! طبعا ده مؤشر إنهم وقع منهم أساسيات كتير في البرمجة ومحتاجين يشتغلوا عليها. و المقالة دي مش للمبرمجين دول. المقالة دي للمبرمجين اللي ماشيين في المسار الطبيعي و اللي بيشتغلوا على نفسهم عشان يتطوروا.
في المقالة دي - إن شاء الله - هانتكلم عن حاجات المبرمجين بيقعوا فيها وهما صغيرين و كل ما بيكبروا و بتزداد خبرتهم الحاجات دي بتقل. أنا سميت الحاجات دي "مظاهر المراهقة البرمجية". و بما إني واحد من المبرمجين دول فالحاجات دي أنا وقعت - وبقع فيها - بصفة شخصية، فحبيت ألخصها من باب النصيحة لنفسي و لزملائي المبرمجين، يمكن تختصر الطريق على حد.
1- ثقة المبتدئين
فيه ناس في طبعها حدة في النقاش واعتداد بالرأي مهما كانت خبرتهم، بس بصفة عامة لما باجي أدخل في نقاش تقني مع حد، لما بلاقيه متواضع و بيسمع وبيتفهم وجهة النظر المختلفة بعرف إنه عنده خبرة غالبا. على العكس من ده بلاحظ كتير من الناس اللي خبرتهم قليلة بيكون عندهم ثقة عالية جدا في إطلاقهم للأحكام على آراء و أكود غيرهم وتقييمهم للمبرمجين والتكنولوجيا، وغالبا بيعانوا من مشكلة البعد الواحد: هو شاف حل واحد لمشكلة ما وفاكر إن هو ده الحل الوحيد الصحيح لكل المشاكل اللي في الدنيا!
فربما تسمع بقى منهم كلام من نوعية:
المبرمج ده كبر و خرف
اللي اشتغلوا في البرنامج دول بقالين
التكنولوجيا س أحسن من ص قولا واحدا
..إلخ.
فيه مقولة جميلة عجبتني بتقول: "العلْمُ ثلاثةُ أَشبارٍ ، مَن دَخَلَ في الشبْرِ الأَوَّلِ ؛ تَكَبَّرَ ؛ وَمَنْ دَخَلَ في الشبْرِ الثاني ؛ تَواضَعَ ، ومَن دَخَلَ في الشبْرِ الثالثِ ؛ عَلِمَ أنه ما يَعْلَمُ". فالله يكرمك بلاش تكون أبو شبر 
و طبعا صاحبنا المبتديء لما بيشوف برنامج مش عاجبه فيه بعض الحاجات بيقع في الظاهرة التانية:
2- إعادة اختراع العجلة
أي حاجة ما تعجبوش بيبقى عاوز يهدها ويبنيها من أول وجديد، بغض النظر عن الحاجة دي اتعملت كده ليه وعن خبرات الناس اللي اشتغلوا فيها. اتكلمت عن النقطة دي في مقالة مستقلة فمفيش داعي لإعادة الكلام عليها هنا تاني، يمكن الاطلاع عليها من الرابط في أول تعليق.
لما بيكبر شوية بقى ويبدأ يتعلم أنماط التصميم Design Patterns بيعاني من ظاهرة غريبة جدا، وهي:
3- متلازمة أنماط التصميم Design Patterns Syndrome
و دي بتحصل كالآتي: كل مشكلة بيشوفها بيقى عاوز يحلها بdesign pattern وبيتعسف عشان يطبقها، حتى لو الحل ممكن يكون أبسط من كده بكتير!
الdesign patterns حاجة عبقرية، و هي من المهارات الأساسية اللي لازم أي مبرمج يكون ملم بيها، بس تطبيقها بالطريقة دي غلط. لو المشكلة واضحة وأنت عارف الpattern اللي بيحلها على طول توكل على الله وطبقه، لكن لو مش واضحة حلها بأي طريقة و بعدين لو اكتشفت بعد كده إن فيه pattern بيحل نفس المشكلة، عدل الكود للpattern ده. والطريقة دي بيسموها refactoring to patterns.
إن شاء الله هانتكلم في سلسلة منفصلة عن الdesign patterns و إمتى نطبقها، بس يكفينا في السياق ده اللي قلته.
4- لو المبرمج مش شغال مع فريق محترفين بيراجعوا على شغله، هاتلاقيه بيعاني من ظاهرة الفهلوة في البرمجة، و دي ليها كذا اسم عند المبرمجين. فمثلا بيسموها البرمجة بطريقة القص و اللصق Copy/Paste Driven Development
و طبعا أشهر مكان بيتعمل منه كوبي بيست دلوقتي هو stackoverflow عشان كده فيه ناس بيسموها Stackoverflow-Driven Development 
الفكرة إن الحلول السريعة اللي بتكون موجودة على المواقع دي أحيانا كتيرة بتكون مبسطة عشان تحل المشكلة مباشرة، و أحيانا بتكون فيها مشاكل ربما مش هاتاخد بالك منها. و لو فضلت كل ما تقابلك مشكلة تحلها بطريقة النسخ و اللصق هاتلاقي البرنامج بتاعك في النهاية مش متماسك خالص و بعد فترة هاتلاقيه عبارة عن مكرونة اسباجيتي، أو كرة طين كبيرة Big Ball of Mud، و دي اتكلمنا عنها في مقالة سابقة، الرابط بتاعها في أول تعليق. و عشان البرنامج في الحالة دي بيكون مبني كله بحلول مش متماسكة فبيسموا الطريقة دي Hack-Driven Development 
المشكلة دي بتبقى وحشة قوي لو المبرمج كبر و اتعود على الطريقة دي في البرمجة، عشان لما بيكبر مسؤولياته بتكبر، و ممكن يكون قائد فريق فينقل لهم طرق سيئة في البرمجة و المشكلة تتفاقم في الأجيال اللي بعد كده 
طبعا stackoverflow موقع جامد تنين، و مفيش حد اعرفه مش بيستفيد منه، بس المطلوب منك بس تفكر في الكود شوية قبل ما تلطعه في البرنامج بتاعك.
كان فيه واحد جميل اشتغلت معاه، وهو م. عصام عبد العال Essam، قال لي حكمة لسه فاكرها من ربما من أكتر من 12 سنة، قال: فيه كوبي بيست بتصرف و فيه كوبي بيست بتسرع 
بلاش التسرع ده، و تصرف شوية في اللي بتنقشه الله يكرمك 
5- بعد شوية المبرمج ده عاوز يغير الشركة، و بالتالي عاوز يظبط السي في بتاعه عشان يعرف يقدم في الشركات، فيبتدي يستخدم تقنيات في البرامج عشان يحطها في السي في بتاعه! ودي بيسموها Resume-Driven Development
طبعا المشكلة الأساسية هنا إنه بيستخدم التكنولوجيا لغرض استخدامها فقط، بغض النظر هل هي أحسن حل للمشكلة اللي بيواجهها و لا لأ، و هل هي تقنية ناضجة بما فيه الكفاية و لا لأ. و اللي بيحصل بعد كده إنه بيلبس في الحيطة و ربما ده بيتسبب إن المشروع بتاعه يفشل!
فيه نوع تاني من الظواهر مرتبط بالظاهرة اللي فاتت، بس لاحظت إنه بيحصل أكتر لما المبرمج بيكبر شوية كمان، و ربما لما بياخد مناصب إدارية أو فنية عالية بدون التدرج الوظيفي:
6- البرمجة حسب الموضة Hype-Driven Development و في رواية Design By Fad
فتلاقيه عاوز يطبق الagile و DevOps و يشتغل المبرمجين TDD و يستخدم DDD و microservices وCQRS، وعاوز يعمل CI/CD وعاوز يطلع على الكلاود،….إلخ. و العجيب إنه ممكن يكون عاوز يعمل كل ده و هو ذات نفسه ما جربهاش قبل كده، و ولا هو و لا المبرمجين اللي معاه طبقوا أكثر الحاجات دي! لقد هرمنا يا جماعة، اعقلوا شوية!

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

Tuesday, January 23, 2018

أسئلة المعلم رفاعي الدسوقي في البرمجة: (1) خبرة السنين


إلا قل لي ياض يا عصام، هو إيه الفرق بين المبرمج الخبرة 5 سنين و المبرمج الخبرة 7 أو 8 سنين غير الفرق اللي كل الناس عارفاه؟
-- المعلم رفاعي الدسوقي لما عمل كارير شيفت واشتغل مبرمج
دي سلسلة جديدة هاتكلم فيها إن شاء الله عن بعض الفروق اللي المبرمج بيتعرض لها أو بيحتاج ياخد قرار فيها. السلسة التانية بتاعت "حبة Software Engineering بالهجايص" لازالت مستمرة - إن شاء الله - بس السلسلة دي هاكتب فيها من حين لآخر - إن شاء الله حسب التساهيل - .
أول سؤال معانا في المقالة دي اللي سأله المعلم رفاعي الدسوقي عن الفرق اللي بيبان في سنين خبرة المبرمج.
الحقيقة مش ناوي أكتب المبرمج حديث التخرج fresh graduate المفروض يعرف كذا وكذا، و المبرمج الjunior المفروض يعرف كذا وكذا، والمبرمج الأول الsenior المفروض يعرف كذا وكذا. الحاجات دي مهمة جدا الحقيقة بس مش ناوي اتكلم فيها عشان سهل الوصول ليها، إنما ناوي اتكلم عن حاجات تانية ناس كتير مش بتاخد بالها منها.
- بنسبة كبيرة، أي مبرمج عنده 5 سنين خبرة يقدر يعمل أي حاجة فنية يقدر المبرمج اللي عنده 7 أو 8 سنين خبرة يعملها، بس الفرق بينهم الحقيقي بيبان في مهاراتهم في "تخليص الشغل"، يعني إزاي بيخلوا الناس التانية تشتغل؟ إمتى يرخموا؟ و إمتى يزنّوا؟ و إمتى يهزروا؟ و إمتى يسايسوا؟ و إمتى يرازوا؟ إلخ. اللي علمني الحتة دي صديقي العزيز م محمد عاطف  (وهو مهندس اتصالات بالمناسبة مش مبرمج 
- إيه بقى الفرق بين المبرمج الخبرة 7 سنين و المبرمج الخبرة 10 سنين؟ نفس الكلام، فنيا الفرق قليل قوي، بس المبرمج الخبرة 10 سنين بيبتدي يغير طريقة تفكيره من البرمجة المعتمدة على المنطق و تسلسل الأسباب و النتائج و الحلول المباشرة للمشكلات إلخ، إلى طريقة التفكير الإدارية - حتى لو فضل مبرمج - إزي يدير مديره؟ إزاي يحقق نجاحات في بيئات عمل سيئة؟ إزاي يواجه الهجوم عليه؟ إزاي يقنع ناس مش فنية بأمور فنية؟ إزاي يوصل لحلول وسط؟ إزاي يخطط بطريقة استراتيجية؟ إمتى يتنازل عن رأيه وإمتى يصر عليه؟ إلخ. أكتر واحد استفدت منه في الحتة دي وعلى طول بينصحني فيها هو مديري م أحمد عبد الحميد، ربنا يصبره عليّ 
- الحقيقة فيه فروق تانية - غير اللي الناس عارفاها -  أنا بسميها "النضج الفني"، أو بعبارة أخرى: بيبطل يعمل حاجات أنا بعتبرها من المراهقة البرمجية. ودي هاتكون موضوع المقالة اللي جاية إن شاء الله، فابقوا معنا 

Wednesday, January 17, 2018

هندسة البرمجيات بالهجايص (4): مبدأ لسكوف للاستبدال

[مش عارف مصدر الصورة إيه، بس هي منتشرة على النت، عموما أنا جبتها من هنا]

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

أَبَا هِنْـدٍ فَلاَ تَعْجَـلْ عَلَيْنَـا *** وَأَنْظِـرْنَا نُخَبِّـرْكَ اليَقِيْنَــا
بِأَنَّا نُـوْرِدُ الـرَّايَاتِ بِيْضـاً *** وَنُصْـدِرُهُنَّ حُمْراً قَدْ رُوِيْنَـا
وَرِثْنَـا المَجْدَ قَدْ عَلِمَتْ مَعَـدٌّ *** نُطَـاعِنُ دُوْنَهُ حَـتَّى يَبِيْنَـا
-- عمرو بن كلثوم

اتكلمنا المقالة اللي فاتت عن تفكيك التعلق أو الاعتمادية في حالة الوراثة inheritance و قلنا الأفضل ما نروحش لسكة الوراثة - بقدر المستطاع - لكن لو لقينا إن الوراثة فعلا مفيدة عشان نعمل polymorphism على سبيل المثال، فعاوزين نقلل من آثارها الجانبية بقدر المستطاع، و ده موضوعنا في المقالة دي.

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

- أول مبدأ معانا في المقالة دي هو مبدأ البرمجة بالاتفاق Design By Contract
سنة 1986 في واحد برنس اسمه برتراند ماير Bertrand Meyer كان بيتكلم على طريقة في البرمجة سماها "البرمجة بالاتفاق" Design By Contract، المهم يعني كان بيقول عشان أجزاء البرنامج تتكلم مع بعضها لازم يحطوا اتفاق فيما بينهم، الاتفاق ده بيتكون من 3 بنود:
1- الشروط المسبقة preconditions: يعني مثلا عشان تنده method اسمها ConvertDocToPdf فالشروط المسبقة في الحالة دي ممكن تكون إن لازم يتبعت لها ملف doc سليم (يعني بيتبع التنسيق format القياسي standard المعتمد من مايكروسوفت) و الملف يكون موجود بالفعل مش null. تمام؟
2- الشروط اللاحقة postconditions: يعني مثلا في المثال السابق بتاع ConvertDocToPdf لازم نتيجة تنفيذ الmethod دي إن يكون عندي ملف Pdf سليم (يعني بالتنسيق format القياسي standard المعتمد من شركة أدوبي) يرجع من الmethod و يكون موجود بالفعل مش null. حلو؟
3- آخر حاجة بقى هي إن الثوابت invariants اللي في الclass ما ينفعش تتغير لكل الinstances بتاعت الclass اللي احنا شغالين عليها. مثال: لو عندنا class بتسهل لنا عمليات على التواريخ، و ليكن اسمها DateUtils. الحاجات اللي عمرها ما هاتتغير هاتكون مثلا إن الأيام هاتكون أي رقم ما بين 1 و 31، و الشهور هاتكون أي رقم ما بين 1 و 12،..إلخ. مثال تاني، لو عندي list: من الحاجات اللي عمرها ما هاتتغير فيها إن عدد العناصر فيها لازم يكون أكبر أو يساوي صفر...إلخ. الشاهد إن دي حاجة بتتحدد في كل class على حدة حسب هي بتعمل إيه، و مش شرط تكون موجودة في كل الclasses.

طيب هانعمل إيه بالمبدأ ده؟
ولا حاجة، ده بس مقدمة عشان نعرف نفهم المبدأ الرخم اللي جاي 
- المبدأ اللي بعد كده هو مبدأ لسكوف للاستبدال Liskov Substitution Principle (لسكوف دي واحدة ست بالمناسبة، واسمها بالكامل باربارا لسكوف Barbara Liskov)
ركز معايا بقى الله يكرمك عشان تفهم…
لو عندك class فيها virtual method و خليت class تانية تورث منها و تعمل override للvirtual method اللي في الbase class دي (يعني هاتعمل polymorphism) انتبه بقى لل3 حاجات اللي جايين دول:
1- الشروط المسبقة preconditions ما ينفعش تزيد في الderived class. خلونا ناخد نفس مثال ConvertDocToPdf اللي ذكرناه في المبدأ السابق، زي ما ضربنا أمثلة على الشروط المسبقة بإن الملف يكون doc سليم و مش null، لو جيت أعمل لها override في derived class ما ينفعش أقول إن حجم الملف ما يزيدش عن 3 ميجا مثلا، كده أنا زودت الشروط المسبقة. و ده هايزعل مدام لسكوف مننا. إنما لو غيرت طريقة التحويل، خليتها أسرع مثلا، أو حتى قبلت إن تنسيق الملف format ما يكونش قياسي standard فكده أنا قللت الشروط المسبقة وما خالفتش المبدأ.
2- الشروط اللاحقة postconditions ما ينفعش تقل في الderived class. خلونا ناخد نفس مثال ConvertDocToPdf اللي ذكرناه في المبدأ السابق، زي ما ضربنا أمثلة على الشروط اللاحقة بإن نتيجة تنفيذ الmethod إن يكون عندي ملف Pdf سليم (يعني بالformat القياسي المعتمد من شركة أدوبي) و مش null، لو حبيت أعمل لها override في derived class ما ينفعش أخلي الmethod تتساهل في الformat بتاع الملف الpdf اللي راجع بحيث يتكتب فيه حاجات مش قياسية مثلا، كده أنا قللت الشروط اللاحقة، و ده هايخلي مدام لسكوف تعيط. إنما لو غيرت في طريقة التنفيذ بحيث إني خليت التحويل أسرع أو قللت حجم الملف اللي راجع فكده أنا زودت الشروط اللاحقة وما خالفتش المبدأ.
3- الثوابت invariants اللي في الbase class - لو موجودة - ما ينفعش تتغير في الderived classes أبدا.خلونا ناخد نفس المثال بتاع DateUtils اللي ذكرناه في المبدأ اللي فات، الثوابت invariants اللي كانت عندنا إن مثلا الأيام لازم تكون رقم بين 1 و 31، لو عملت class بترث من الDateUtils دي لازم أحافظ على نفس الثوابت، ماينفعش بقى آجي ألاقي الأيام رقم بالسالب أو أكتر من 31، لأني بكده هاكون غيرت في الثوابت و أنت عارف الستات بتزعل قوي من الحاجات دي، ومدام لسكوف كده ممكن تنكد علينا.

لو وصلت مدام لسكوف للنقطة دي و جيت تسألها عن فايدة الكلام ده هاتقولك: لو كنت مهتم كنت عرفت لواحدك 
تعالوا نتكلم جد... بص يا سيدي، إنت كده تقدر تستخدم الobjects بتاعت الderived classes مكان الobjects بتاعت الbase classes و أنت مغمض عينك عشان هاتكون مطمئن إن سلوك البرنامج program behavior مش هايتغير. و عمرك ما هاتحتاج تعمل casting أو type checking عشان تعرف نوع الobject اللي أنت شغال عليه.
خد بالك إن مجرد إني أغير طريقة التنفيذ في الderived classes هذا لا يعد مخالفة لمبدأ لسكوف، طالما أنا ملتزم بال3 شروط بتوع البرمجة حسب الاتفاق. وفي الحالة دي أنا الحقيقة شايف إن المبدأ ده قريب جدا من مبدأ Open/Closed Principle الشهير، و ده هانتكلم عنه بالتفصيل في حلقة لاحقة - إن شاء الله -

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

المهم، إزاي أنا بستفيد من المبدأ ده - على المستوى الشخصي-؟
1- وأنا بكتب المقالة دي فكرت شوية لقيت إني بقالي كتير قوي بستخدم الوراثة inheritance في أضيق الحدود، و بعتمد بصورة كبيرة على الinterfaces لتحقيق الpolymorphism أو بطبق مبدأ تفضيل التركيب على الوراثة favor composition over inheritance - اللي اتكلمنا عنه في مقالة سابقة - وفي الحالات دي المبدأ ده مالوش لازمة.
2- روح المبدأ ده بتتكلم عن إنك لما تيجي تعمل وراثة تعملها صح، و الحقيقة فكرة إنك تسأل نفسك عن العلاقة بين الclasses هل يمكن اعتبارها is-a؟ بلاقيها أسهل كتير في تحديد القرار الصحيح. خلونا ناخد المثال العبيط اللي دايما بيستخدموه عشان يشرحوا مبدأ لسكوف، وهو مثال المربع و المستطيل: هل ينفع المربع يورث من المستطيل؟ بتطبيق مباديء البرمجة بالاتفاق - اللي اتكلمنا عليها فوق - هاتلاقي نفسك محتاج تراجع ال3 حاجات (الشروط السابقة، و الشروط اللاحقة، و الثوابت) عشان في الآخر تلاقيها ما تنفعش عشان هاتلاقي إنك محتاج في المربع تغير الطول مع العرض دايما، و ده بيخالف الشروط اللاحقة و/أو الثوابت للclass بتاعت المستطيل. سكة طويلة عشان تفكر فيها كده، خاصة لو المشكلة أعقد شوية من المثال العبيط اللي أنا ذكرته، صح؟ لكن لو سألت نفسك ببساطة: هل المربع يعتبر (=is-a) مستطيل؟ ولا هما الاتنين ممكن نعتبرهم (=is-a) شكل Shape، و يبقى هما الاتنين ليهم base class واحدة؟ أظن السؤال كده أسهل والإجابة واضحة.
3- آخر حاجة، الصراحة لو خالفت المبدأ ده مش بزعل ولا بحس بأي تأنيب ضمير عشان أنا غالبا مش بعمل inheritance إلا لما بكون مضطر ليها، و في الحالة دي بضحي بالمبدأ عشان البرنامج يعيش 
معلش طولت عليكم في المقالة دي عشان أصلا موضوعها رخم و كنت عاوز أشرحه بالتفصيل الممل، فلو فيه حاجة مش واضحة يا ريت تكتبوا في التعليقات.

شير في الخير بقى...سلام.

شوية مقالات بقى استفدت منهم
https://hackernoon.com/liskov-substitution-principle-a982551d584a
http://wiki.c2.com/?LiskovSubstitutionPrinciple

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! إيه الكلام بقى؟

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