Thursday, March 1, 2018

هندسة البرمجيات بالهجايص (7): قانون ديميتر

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

* مقدمة

كان فيه مشروع برمجي اسمه مشروع ديميتر، الناس اللي شغالة فيه عملوا بعض القواعد للمبرمجين اللي شغالين على المشروع عشان يكتبوا كود OOP نضيف، و بعدين لقوا إن القواعد دي ينفع تعمم فنشروها بالاسم ده = قانون ديميتر Law Of Demeter. وديميتر دي إلهة النبات والطبيعة عند الإغريق. وطبعا دول ناس كفار مالناش دعوة بيهم، ومايهمناش دلوقتي ليه سموه بالاسم ده. اللي يهمنا الفكرة اللي وراه.

* إيه الفكرة؟ 

لما بييجوا يشرحوا الفكرة بالهجايص كده بيقولوا نفس الكلام اللي أمك كانت بتقوله لك وأنت صغير: اتكلم مع أصحابك بس، ما تتكلمش مع حد ما تعرفوش 
Only talk to your friends; don't talk to strangers.
لكن لما بييجوا يشرحوها كفنيين، بيشرحوها كالآتي:
لما بيكون عندك method/function ما، مسموح للmethod دي إنها تنده لـ5 أنواع فقط من الmethods:
1- أي method تانية معاها في نفس الclass
2- لو الmethod دي داخل لها parameters، مسموح لها تنده لأي method في أي parameter من اللي داخلين لها
3- لو الmethod دي أنشأت instantiates أي كائن object، مسموح لها تنده لأي method فيه
4- لو فيه field/attribute في نفس الclass معاها، مسموح لها تنده للmethods اللي فيه
5- لو فيه أي global object، تقدر تنده للmethods اللي فيه.

* طيب إيه علاقة الشرح اللي بالهجايص بالشرح الفني؟
بالهجايص: لو أنت رايح تقابل واحد صاحبك و لقيته جايب واحد صاحبه معاه، اتكلم مع صاحبك بس، وماتتكلمش مع صاحبه عشان أمك ما تزعلش منك!
في البرمجة: لو ندهت لmethod من اللي مسموح لك تنده لهم بحسب قانون ديميتر، فرجعت لك object، ما ينفعش تنده لأي method في الobject ده عشان اللي حطوا قانون ديميتر ما يزعلوش منك، يعني ما ينفعش تكتب كود زي كده:

GetObjectA().GetObjectB().DoSomething();

أو بعبارة أخرى:في اللغات اللي بتستخدم النقطة للوصول للبيانات fields/attributes أو العمليات methods/functions المسموحة على الobject، زي الjava و الC#، استخدم نقطة واحدة بس في الإجراء الواحد. use only one dot.
أي مبرمج مصري فهلوي أصيل، هايقول لك خلاص، لو الكود اللي فات ده بيخالف القانون، احنا ممكن نكتبه على أكثر من سطر، كده مثلا:

Var b = GetObjectA().GetObjectB();
b.DoSomething();

بس الحقيقة ده مخالف للقانون برضو، لأن الفكرة مش في تقليل عدد النقاط المستخدمة للوصول لتفاصيل الobjects، بل في تقليل الاعتمادية بين أجزاء البرنامج وتحسين الencapsulation، عشان كده هاتلاقي أي حاجة بتستخدم Fluent API (إنك تفضل تنده لmethods على نفس الobject) - زي jQuery مثلا - مش بتخالف القانون ده ولا حاجة.
مثال من jQuery:

$('<p></p>').html("Blah, blah, blah").addClass("foobar").appendTo("body");

ليه المثال ده مش بيخالف قانون ديميتر؟ لأ كل function من دول بترجع this، وبالتالي الإجراء اللي فات ملتزم بالنوع الأول المسوح في القانون.
ونفس الكلام للناس اللي شغال LINQ، لما بكتب كود زي المثال التالي مش بخالف قانون ديميتر:

employees.Where(x => x.IsActive).Select(x => x.JoinDate).ToList();

* مميزات تطبيق قانون ديميتر

تطبيق القانون ده بيخلي البرنامج مرن وسهل التعديل،عشان بيقلل الاعتمادية بين أجزاء البرنامج. بل إن فيه دراسة اتعملت على الموضوع ده سنة 1996 وطلعوا بنتيجة إن تقليل تسلسل نده الmethods ممكن يؤدي إلى تقليل الأخطاء البرمجية bugs.

* حالات استثنائية

- الحقيقة كلمة "قانون" دي مش مهضومة قوي في البرمجة، لأنها تحمل معنى إني ما ينفعش أكسره، وده مش الواقع، فمثلا لو طبقت القانون ده بحذافيره، هاتلاقي إنك عشان تفضل محافظ على استخدام نقطة واحدة في كل عملية، هاتضطر تعمل wrapper methods كتيرة، وده مش بس ممل وبيستهلك وقت، لأ ده بيزود احتمالية حدوث أخطاء برمجية بسبب كثرة الmethods اللي هاتكون في الclass (زي ما الدراسة اللي اتكلمنا عليها فوق قالت برضو).
- فيه حالات تانية برضو بنبقى عاوزين "نخالف" القانون ده عن عمد مش نطبقه! زي ما قلنا فوق، المقصود من المبدأ ده تحسين الencapsulation، عن طريق إخفاء المعلومات، بس فيه حالات ببقى عاوز "أظهر" فيها المعلومات مش أخفيها، وبالتالي تطبيق القانون ده بيبقى مش مناسب، زي مثلا لما يكون عندي View Model متقسم لمجموعات من الobjects، ونفس الكلام في حالة إني باستخدم Data Transfer Object متقسم لمجموعات من الobjects، الشاهد هنا لما بيكون عندي data objects مافيهاش behavior كتير، القانون ده مش بيبقى مش مناسب قوي.
- مثال ثالث لو هيكلية البيانات data structure مهمة بالنسبة لي، زي مثلا إني أكون بتعامل مع ملف إكسيل، وتقسيم البيانات في الملف (ورقة > جدول > حقل..إلخ) مهم بالنسبة لي لتسهيل الوصول للمعلومات وفهمها، ففي الحالة دي مخالفة القانون مافيهاش حاجة.
- كمان مثال، زي ما قلنا إن هدفنا تقليل الاعتمادية و تحسين الencapsulation، بحيث إن لو حاجة اتغيرت ما اضطرش أغير في حاجات تانية، طيب لو الحاجات دي ما بتتغيرش؟ قشطة مفيش مشكلة من "ترك" الاعتمادية في الحالة دي ومخالفة القانون.

* روح القانون

الحقيقة الحالات الاستثنائية للقانون ده كثيرة، وعشان كده فيه ناس اعترضت على تسميته قانون، وفيه ناس اقترحت تغيير اسمه، زي مارتن فاولر Martin Fowler، اقترح تسميته: اقتراح ديميتر المفيد أحيانا Occasionally Useful Suggestion of Demeter. بل إن فيه ناس قالت عليه مالوش أي تلاتة لازمة، زي ديفيد هانيمر هانسن David Heinemeier Hansson (اللي عمل Ruby On Rails)، قال بالنص:
I think the Law of Demeter is shit and never follow it.
بس خروجا من الخلاف، ممكن نستخدم الاسم الثاني - الأقل شهرة - للقانون ده: مبدأ المعرفة على قدر الحاجة Principle of least knowledge [محدش يقول لي الترجمة غلط، عشان أنا مترجمها بالمعنى مش ترجمة حرفية:)] وده حتى أكثر تعبيرا عن"روح القانون"، فمش لازم الobjects تعرف حاجات كتير بتفاصيل التفاصيل عن الobjects الثانية عشان تعرف تشتغل، إنما الأفضل إنها تعرف اللي هي محتاجاه بس.

* إزاي نطبق القانون ده؟

زي ما قلنا فوق، لو جيت تطبق القانون بحذافيره، هاتلاقي إنك بتعمل wrapper methods كتيرة، ودي حاجة مش ظريفة خالص، والحل هنا ممكن يكون إني أسأل السؤال التالي: هو ليه الobject ده عاوز يعرف تفاصيل الobjects التانية دي؟ ماذا لو طبقنا مبدأ "أؤمر، ما تسألش Tell, Don't Ask" اللي اتكلمنا عنه الحلقة اللي فاتت؟ مش كده نبقى طبقنا القانون واستفدنا من "روحه"؟ فضلا اقرأوا المقالة.

* الالتزام بالقانون على مستوى الarchitecture

فيه حالة واحدة تحضرني دلوقتي، أنا شايف إنه "قانون" ولازم ألتزم بيه مهما حصل، وهو على مستوى الarchitecture مش على مستوى الclasses، ففي حالة إنك مستخدم طبقات layers، كل طبقة مسموح لها تتعامل مع الطبقة اللي تحتها مباشرة بس، ومش مسموح إنها تتجاوز الطبقة اللي تحتها لطبقات أدنى، وده بيخلي الarchitecture بتاعك نظيف وسهل الصيانة نسبيا.

ماتنسوش تشيروا المقالة لو حسيتوا إنها مفيدة 
* مصادر اللي استفدت منها

https://en.wikipedia.org/wiki/Law_of_Demeter
https://dzone.com/articles/the-genius-of-the-law-of-demeter
https://haacked.com/archive/2009/07/14/law-of-demeter-dot-counting.aspx/

Thursday, February 15, 2018

تأثير تقسيم الفرق على المشروع

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

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

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

سنة 1967 فيه واحد اسمه ملفن كونواي Melvin Conway قال -ما معناه - إن المؤسسات لما بتيجي تصمم أي نظام، بيطلع التصميم بتاعهم مطابق لهيكل تقسيم الفرق و إزاي بيتواصلوا مع بعض. وده نص كلامه:
Any organization that designs a system (defined broadly) will produce a design whose structure is a copy of the organization's communication structure.
سنة 1975 فريدريك بروكس Frederick Brooks في كتابه الشهير The Mythical Man-Month خد الكلام ده وسماه قانون كونواي Conway's Law وبعد كده الكلام ده انتشر بالاسم ده.

فيه دراسات اتعملت بعد كده على الفكرة دي، منها دراسة عملتها مدرسة هارفارد للأعمال Harvard Business School سنة 2007، وقارنوا في الدراسة دي بين أكواد بعض المشاريع بتقوم بنفس الوظيفة، واكتشفوا إن البرامج مفتوحة المصدر اللي طورها مبرمجون متفرقون تميل لتكون أحسن تقسيما و أقل اعتمادية فيما بين أجزائها loosely-coupled وعلى العكس من ذلك البرامج اللي طورها فريق واحد متفرغ للمشروع أقرب ما تكون لوحدة واحدة monolith والاعتمادية فيما بين أجزائها كبيرة tightly-coupled. واكتشوفوا برضو إن جودة أو سوء التواصل بين الفرق بينعكس على جودة أو سوء التكامل بين أجزاء المشروع اللي هما شغالين عليها.

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

القانون ده بيشتغل بالعكس برضو، فزي ما تصميم البرنامج بيتأثر بالهيكل الإداري في المؤسسة، بيأثر فيها برضو، وده بيظهر قوي في الأنظمة القديمة، فمثلا لو كان البرنامج متقسم ل3 طبقات tiers: قاعدة بيانات، و إجراءات الأعمال Business Logic و واجهة المستخدم، وكل طبقة من دول كان عاملها ناس متخصصة في الحتة دي بس، يعني مثلا طبقة قاعدة البيانات مليانة stored procedures و وطبقة واجهة الاستخدام فيها شغل javascript عملاق و حاجات متقدمة جدا في التفاعل مع المستخدم، هاتلاقي إن بعد فترة المؤسسة مضطرة تستمر في تشغيل ناس متخصصة في كل طبقة من ال3 دول عشان البرنامج يفضل عايش.

طيب إزاي بقى نخلي القانون ده يعمل لمصلحتنا مش ضدنا؟- لازمة القانون ده إنه لو تم توزيع الفريق اللي بدأ المشروع إلى فرق مستقلة، فبنية المشروع الأساسية Application Architecture ستعمل "ضد" المشروع ما لم يتم تغييرها. فريديريك بروكس - اللي نشر الفكرة، زي ما قلنا فوق - قال إن تصميم أول نسخة من المشروع غالبا بيكون مش أفضل حاجة، و فيه احتمال كبير إنك تضطر تغير فيه حاجات كتير، ولذلك فمرونة المؤسسة في تقسيم وإعادة تقسيم الفرق مهم جدا في تصميم المشروع. بعبارة أخرى: تأكد أن بنية المشروع Application Architecture متوافقة دائما مع التقسيم الإداري للمؤسسة و إلا هاتلبس في الحيطة يا معلم!
- الكود الواحد محتاج تواصل على مستوى التفاصيل الدقيقة fine-grained communication، لا تستطيع الفرق الموزعة القيام به، في الحالة دي أحسن حاجة تعملها إنك يا إما تجمع الفرق الموزعة في فريق واحد أو إنك تفصل الكود الواحد بحسب تقسيم الفرق، والتواصل في الحالة الثانية دي هايكون عند الضرورة فقط.
- حاول تخلي تقسيم الفرق ييجي *بعد* وضع الarchitecture اللي أنت شايف إنه مناسب من الناحية الفنية للمشروع.
- الفريق اللي بيشتغل على كود واحد خليه بقدر الإمكان قريب من بعضه، يعني لو في نفس المكتب يبقى مية مية، أقل من كده شوية لو في نفس الدور، وكل ما بيبعد أعضاء الفريق عن بعضهم بيبقى أوحش.

آخر حاجة، اعتبروا الكلام ده مدخل للmicroservices و الdistributed systems ...أي خدعة 

ما تنسوش تنشروا المقالة لو حسيتوا إنها مفيدة 




-------------------
مصادر استفدت منها:
http://www.melconway.com/Home/Conways_Law.html
https://en.m.wikipedia.org/wiki/Conway%27s_law
https://www.thoughtworks.com/insights/blog/demystifying-conways-law
https://haacked.com/archive/2013/05/13/applying-conways-law.aspx/
http://whatis.techtarget.com/definition/Conways-law
http://www.hbs.edu/faculty/Publication%20Files/08-039_1861e507-1dc1-4602-85b8-90d71559d85b.pdf


Monday, February 12, 2018

هندسة البرمجيات بالهجايص (6): أؤمر، ما تسألش


[الصورة من مقالة لمارتن فاولر استفدت منها في كتابة المقالة دي]

في عصر ما قبل الObject Oriented Programming، البرامج كانت بتتقسم بحيث إن البيانات بتبقى في حتة و العمليات اللي بتعالج البيانات دي في حتة تانية خالص. الOOP قالت لك لأ احنا هانرتب الدنيا بطريقة مختلفة، احنا نحطهم الاتنين مع بعض، وسموا الحركة دي (اللي هي جمع البيانات مع العمليات) encapsulation (الترجمة الحرفية ليها = تغليف، تضمين).
لما بحط البيانات و العمليات مع بعض بزود في التماسك cohesion لأن العمليات مرتبطة بالبيانات اللي موجودة معاها بالفعل، ودي حاجة كويسة. و لما بفصلهم بزود في الاقتران coupling لأن الclass اللي فيها العمليات هاتحتاج تعتمد على الclass اللي فيها البيانات، و دي حاجة وحشة. [اتكلمت عن الموضوع ده بالتفصيل في مقالة: أحط الحاجة فين]
عارفين الناس اللي بيدخلوا على الجروبات ويقولوا لو حد يعرف كذا يقول، و عادة الناس بترد عليه وتقول له: قول سؤالك على طول. اللي بيعرف هايرد عليك. وفيه جروبات بتمنع النوع ده من المشاركات من الأساس.
أهم هما دول اللي مش بيطبقوا الencapsulation كويس 
تعالوا نشوف القصة إيه...

فيه مبدأ عندنا بيقول: ما تسألش عن البيانات، وبعدين تقرر أنت هاتعمل بيها إيه. خلي المسئول عن تنفيذ اللي أنت عاوز تعمله بالبيانات دي هي الclass نفسها اللي فيها البيانات دي. و قل للclass دي تجيب من الآخر وتنفذ اللي أنت عاوزه على طول.المبدأ ده بيسموه Tell, Don't Ask. يعني إيه الكلام ده؟

- تعالوا ناخد مثال من ال.NET Framework، فيه class اسمها File دي بنستخدمها لما نيجي نتعامل مع الملفات على الهارد ديسك، الclass دي فيها method اسمها Exists. ودي بنستخدمها عشان نتأكد الملف موجود ولا لأ قبل ما نعمل عليه أي عمليات (قراءةRead أو كتابة Write أو حذف Delete) و إلا هايضرب Exception لو جيت اعمل العمليات دي على ملف مش موجود مثلا. بس لو ندهت للExists عشان أشوف الملف موجود ولا لأ قبل ما اعمل عليه أي عملية هاخالف المبدأ اللي معانا: Tell, Don't Ask، عشان أنا سألت الأول عن حالة الملف وبعدين أخدت القرار بناء على الحالة اللي عرفتها.

- تعالوا نشوف مثال تاني من ال.NET Framework برضو: لما تيجي تحول نص string لرقم، فيه عندك method في الint struct اسمها Parse و دي هاتضرب exception لو النص لا يمكن تحويله لرقم، يعني هاينطبق عليها نفس الكلام اللي قلناه في المثال اللي فات عند التعامل مع الملفات. بس الحقيقة الstruct دي فيها method تانية اسمها TryParse ودي "بتحاول" تحول النص لرقم، لو فشلت مش بتضرب exception. ودي متسقة جدا مع المبدأ اللي بنتكلم عليه، ومش محتاج هنا try-catch عشان أتفادى مشاكل فشل التحويل.
تعالوا نرجع للمثال الأول: لو كانت الFile class فيها methods اسمها: TryRead، TryDelete، TryWrite، مش هايكون أفضل؟
أظن هايكون أفضل.

- المبدأ ده مفيد جدا لما تيجي تصمم خدمة ويب web service. الفكرة إنك عاوز تقلل المشاوير اللي ما بينك و بين الخدمة عشان تتفادى مشاكل الشبكة. فلما تطبق المبدأ ده هاتلاقي إنك بتطلب من الخدمة تنفذ لك المهمة اللي أنت عاوزها دوغري، ودي بيسموها coarse grained، على عكس لو فضلت رايح جاي على الخدمة تسأل عن البيانات و بعدين تقرر و بعد كده بترجع تعيط إن الخدمة بطيئة. و دي بيسموها fine grained أو chatty.

المبدأ ده كويس جدا، بس أحيانا مش بيكون مناسب للسياق اللي أنا شغال فيه، أو لو طبقته هاضيع على نفسي مميزات أخرى، تعالوا نشوف أمثلة:
- تعالوا نرجع لأول مثال ذكرته فوق، لغاية لما مايكروسوفت تعمل TryDelete، استخدم Exists الأول وبعدين Delete و لا أحط الDelete في try-catch؟
لأ طبعا استخدم الExists وبعدين الDelete، و لا تستخدم الtry-catch في التحكم في مسارات البرنامج control flow أبدا. هنا مش أنا اللي عامل الFile class و مضطر استخدمها كما هي، وده مش عيب.

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

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

- أحيانا بفصل العمليات عن البيانات لأن العمليات دي ممكن تتغير، ودي هاتيجي معانا بالتفصيل إن شاء الله لما نتكلم على المبدأ Encapsulate what varies أو عند تطبيق ال strategy pattern.

- أحيانا بفصل العمليات عن البيانات عشان أقسم الدنيا لطبقات layers فتديني مرونة أعلى في التصميم، زي مثلا إني بفصل العمليات اللي بتتعامل مباشرة مع قاعدة البيانات (اللي هي CRUD Operations = إنشاء Create وقراءة Retrieve وتعديل Update وحذف Delete البيانات) عن العمليات اللي بتعالج البيانات دي، وتطبق عليها إجراءات العمل business rules مثلا.

- أحيانا بنفضل إننا نفصل العمليات الاستعلامية Queries (زي التقارير و لوحات المعلومات dashboards مثلا) عن العمليات الإجرائية Commands (زي إنشاء و تعديل وحذف البيانات) عشان نقدر نحسن كل واحدة على حدة، وفيه architecture style معروف في التقسيمة دي اسمه Command and Query Responsibility Segregation، أو اختصارا CQRS.

حابب أختم المقالة دي بكلمة لعم الأركتكتس، مارتن فاولر Martin Fowler، قال: التصميم الجيد عبارة عن شوية موازنات، وجمع البيانات مع العمليات يعتبر عامل واحد فقط نأخذه في حسباننا بجانب العوامل الأخرى.
Good design is all about trade-offs, and co-locating data and behavior is just one factor to bear in mind.

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

Sunday, February 4, 2018

هندسة البرمجيات بالهجايص (5): تسرب تفاصيل التتنفيذ



أحد أركان الOOP هو ما يسمى abstraction، وترجمتها الحرفية تعني التجريد بس معناها في السياق بتاعنا: إخفاء تفاصيل التنفيذ hiding implementation. التفاصيل دي ممكن تكون صعوبة في التنفيذ complexity أو قصور limitations في التفاصيل المخفية دي بيتم عزلها عشان ما تحسش إنها موجودة.

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

أي حد اشتغل على ال WIN32 API يعرف قد إيه حاجة زي Visual C++ سهلت الدنيا عن طريق عزل الصعوبات اللي كانت موجودة قبلها في برمجة الويندوز. و نفس الكلام الناس اللي اشتغلت .NET Framework بعد ما كانت شغالة win32 أو visual c++. السهولة دي (اللي جت من عزل التفاصيل الرخمة) خلتنا نقدر نعمل برامج ما كانش متاح عملها قبل كده. لكن أحيانا الabstraction ده بيبقى غير كافي و كنا بنضطر نتجاوزه و نفهم التفاصيل أكتر و نشتغل على الwin32 api مباشرة.

الORMs زي Hibernate أو Entity Framework عظيمة جدا، خاصة لما بيكون معاها Object Query Language زي الLinq تخليك مش محتاج تفهم sql كويس عشان تتعامل مع قاعدة البيانات، و بتديك مميزات بقى وأنت بتكتب استعلاماتك زي الstatic type checking و code auto-completion و حاجة آخر شياكة. عزل التفاصيل بتاعت التعامل مع قاعدة البيانات خلى حياة المبرمجين أسهل كتير و خلاهم يركزوا أكتر على البزنس بتاع البرنامج بتاعهم وما يشغلوش بالهم كتير بكيفية التعامل مع قاعدة البيانات. الدنيا بتفضل حلوة وجميلة لغاية لما تلبس في الحيطة في سرعة أداء performance الاستعلامات الناتجة عن الORMs. في الحالة دي بتضطر آسفا ترجع للsql عشان تكتب استعلامات ذات كفاءة.

طول ما أنت مش بتحتاج تعرف تفاصيل التنفيذ ولا بتحاول تتجاوز العزل اللي معمول عشان يخفيها عنك، فالabstraction بتاعك زي الفل. أول ما بتحتاج تفهم التفاصيل فالعزل بتاعك ابتدى يسرسب، أو ما أسماه جول سبولسكي (أحد مؤسسي stackoverflow):
Leaky Abstraction.
الحقيقة هو ما سماهوش بس، ده حط له قاعدة بتقول: إن أي عزل لتفاصيل التنفيذ، لو كان بيعزل حاجة مهمة يعني، فهو غالبا هايبقى مسرسب بدرجة أو بأخرى!
All non-trivial abstractions, to some degree, are leaky.

طيب إزاي أستفيد من القاعدة دي؟
- لما تيجي تتعلم تقنية جديدة بتعزل تفاصيل تقنية أقدم منها تؤدي نفس الغرض، تأكد إنك هاتحتاج تفهم التقنية القديمة في يوم من الأيام عشان التقنية الجديدة أكيد هاييجي اليوم اللي تسرسب فيه و تحتاج تفهم هي شغالة إزاي عشان تعالج السرسبة دي. ونفس الكلام عن الحاجات اللي بتعمل code generation عشان توفر عليك وقت التطوير، حاول تتعلم الشغل بيتعمل بلدي إزاي من غير الcode generation عشان لما الcode generation يسرسب تعرف تتعامل و ما تلبسش في الحيطة.
- لو العزل بتاعك سرسب غصب عنك ماشي هانعديهالك، لكن ما تجيش أنت تسمح بتسرب تفاصيل التنفيذ بمزاجك، تعالوا ناخد مثال شهير: لما الناس بينفذوا الrepository pattern أشهر طريقة لتنفيذه هي عن طريق إنه يعمل واحد generic و يرجع فيه IQueryable أو يقبل في Expression عام يسمح لمستخدم الrepository إنه يكتب الquery كيفما شاء. الطريقة دي في التنفيذ مسرسبة وش! كده أنت ما عزلتش تفاصيل الوصول للبيانات و خليت مستخدم الrepository عارف تفاصيل عمله. الrepository كده هايبقى سهل جدا في الاستخدام لكن بييجي من وراه مصايب كتيرة قوي. تخيل مثلا إنك لقيت query بطيء وعاوز تحسنه، في حالة الgeneric repository هاتحتاس عشان توصل للquery ده جاي منين، و بعدين هاتحتاس تاني لما تكتشف إنه متكرر في أكتر من مكان في البرنامج و محتاج تصلحه في كل الأماكن اللي هاتقعد تكتشفها بالصدفة!
أفضل طريقة لتنفيذ الrepository pattern - من وجهة نظري - هي مقالة نفسي أكتبها من زمان قوي، ربنا ييسر وتيجي قريب.

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

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

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