Showing posts with label OOP. Show all posts
Showing posts with label OOP. Show all posts

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/

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 - من وجهة نظري - هي مقالة نفسي أكتبها من زمان قوي، ربنا ييسر وتيجي قريب.

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

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

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

Saturday, December 30, 2017

هندسة البرمجيات بالهجايص -- (2) أحط الحاجة فين؟

أصل المقالة دي كانت بوست كتبته على الفيسبوك، فحبيت أعيد نشره لتعم الفائدة...
وده رابط الحلقة الأولى في السلسلة لمن أراد..
"جيت ألم البنطلون الجاكتة ضربت...جيت ألم الجاكتة البنطلون ضرب!" -- سمير غانم 
- الحقيقة احنا بنشوف المرار في البرمجة، تيجي تعدل في حتة في البرنامج ولا تحل bug تلاقي جحيم اتفتح عليك و عمال تعدل في حتة تانية ورا حتة تالتة ورا حتة رابعة. وبيبقى فيه حتت كده في كل برنامج عبارة عن كهف مظلم محدش يجرؤ يقرب له بسبب موضوع تسلسل التعديلات ده. النوع ده من البرامج بيبقى مقاوم للتغيير، بيبقى عامل زي الزجاج كده فيه صلابة rigidity بس فيه هشاشة في نفس الوقت fragility. الوضع ده لما بيكون صفة ملازمة للبرنامج غالبا هاتفكر تهده وتبنيه من أول وجديد، إوعى، وراجع مقالة "إعادة اختراع العجلة في البرمجيات

- فيه برامج تانية بتبقى حلوة وظريفة وشغالة لكن لما بنحب نعيد استخدام الكود ده - حتى لو بعمله copy/paste بلاقيه مش بيشتغل. ممكن يكون لأنه مش مصمم إنه يعاد استخدامه - وده مش عيب بالمناسبة - وممكن يكون بسبب اعتماد أجزاء الكود على بعضها dependencies. برضو فكرة الاعتمادية في حد ذاتها مش مشكلة، المشكلة في كثرة عدد الحاجات اللي معتمدة على بعضها وعمق درجة الاعتمادية دي يعني بتعتمد على حاجات كتير اللي هي بدورها بتعتمد على حاجات كتير برضو..وهكذا. النوعية دي من التصميمات البرمجية بتتسم بصفة الجمود immobility.

- فيه نوعية تالتة من البرامج لما تحب تعدل فيها أو تحل مشكلة تلاقي الطريقة الصحيحة لعمل ده صعبة بسبب اعتمادية أجزاء الكود على بعضها، و تلاقيك بتكتب hacks و workarounds أكتر ما بتكتب كود كويس. الكود اللي من النوعية دي بيتصف باللزوجة viscosity يعني بيبقى ملزق كده زي الزيت لما يكون في الطاسة، لما تيجي تنظفه تلاقيه مش راضي يطلع.

البرامج اللي بيجتمع فيها البلاوي اللي فوق دي فيه مصطلح ظريف بيعبر عنها اسمه Big Ball Of Mud يعني كرة الطين الكبيرة!
لو تلاحظ المشاكل اللي فوق دي هاتلاقي إن الاعتمادية dependencies هي جزء أساسي في المشكلة، مش الاعتمادية في حد ذاتها، لكن كثرة الاعتمادية و عمقها - زي ما اتكلمنا فوق - و جزء أساسي في شغلك لما تيجي تظبط برنامج مطين أو تصمم برنامج جديد إنك تكسر الاعتمادية دي، و ده موضوع المقالة دي...أحط الحاجة فين؟

- أول مبدأ معانا هو مبدأ الفصل بين المسئوليات Separation of Concerns [الترجمة متصرفة أنا عارف].

تعالوا نضرب أمثلة توضح المقصود على طول:
= لما بيكون المشروع بتاعك مقسم لطبقات layers ما تخليش مسئوليات الطبقات تدخل في بعضها، يعني مثلا الطبقة بتاعت الواجهة front-end/presentation layer تكون مسئولة بس عن واجهة المستخدم user interface ومافيهاش قرارات ليها علاقة بقواعد النظام business rules و طبعا مش بتوصل لقاعدة البيانات! ده على مستوى بنية النظام application architecture.
= في كل طبقة layer ما تجيش تخلط برضو بين المسئوليات في أجزاء الطبقة دي، يعني مثلا يفضل إنك ما تكتبش html و css و javascript في نفس الملف لأن كل حاجة من دول مسئولة عن حاجة مختلفة. و نفس الكلام لما يكون عندك مثلا class مسئولة عن إدارة حسابات المستخدمين ما تحطش فيها كود له علاقة بإدارة الكتب (لو أنت عامل برنامج لمكتبة مثلا).
= نفس الكلام في قاعدة البيانات، ما تجيش تحط حقول columns مالهاش ارتباط الprimary key (و دي اسمها database normalization بس مش هانتكلم عنها عشان دي قصة لوحدها)
...وهكذا في كل مناحي البرنامج.

- المبدأ ده يقودنا لمبدأ تاني هو التخصص الدقيق Single Responsibility Principle [الترجمة متصرفة جدا المرة دي أنا عارف].

المبدأ بيقولك أي جزء برمجي لازم يكون بيعمل حاجة واحدة بس، و بيعملها كويس. و تقدر تقيس الموضوع ده بإن ما يكونش عندك أكتر من سبب لتغييرالجزء البرمجي ده. تعالوا نخش في الأمثلة:
= عندي method اسمها ParseAndCalculate لاحظ وجود الAnd في الاسم ده دليل على إن الmethod بتعمل حاجتين. طبعا الاسم مش دليل كافي، ممكن يكون مسميها بلحة وبتعمل 5 حاجات. الشاهد إن لما أحب أغير في الParse هاعدل في الmethod ولما أحب أغير في الcalculate هاغير فيها برضو، و ده يتنافى مع مبدأ التخصص الدقيق.
= شفت كود الmethod فيت تتجاوز ال3000 سطر بدون أي مبالغة، بس الحقيقة المبرمج حاطط comments كتير وعامل regions جوه الmethod مبين فيها كل حتة بتعمل إيه. ده مؤشر ظريف إن ممكن الregions دي تتقسم لmethods منفصلة.
= الكلام ده لا يسري على الmethods بس، طبقه بقى على كل حاجة من أول بنية النظام و طبقاته، مرورا بالclasses و الmethods و وصولا لقاعدة البيانات.

- فيه مبدأ تالت مرتبط بالمباديء اللي فاتت دي، ألا و هو مبدأ الاقتران Coupling و التماسك Cohesion [بتتنطق كده كوهيجن، بتعطيش الجيم]. يعني إيه الكلام ده؟

= الاقتران coupling معناه قد إيه الحاجات اللي أصلا مالهاش علاقة ببعض في اعتمادية بينها، و دي قصة الdependencies اللي عمالين نهري فيها فوق، فده بيتكلم عن علاقة الحاجات ببعضها من بره.
= أما التماسك cohesion فبيتكلم عن علاقة الحاجات ببعضها من جوة، يعني لما تشوف حاجة في الclass كده و تقول: "إيه اللي جاب القلعة جنب البحر؟" تعرف إن الclass مش متماسكة و بتعمل حاجات مش بتاعتها.
المبدأ ده تقدر تعتبره معيار لقياس هل تغيير الكود بتاعي سهل و لا صعب، إزاي؟
= الحاجات اللي مقترنة ببعضها tightly coupled بتبقى صعبة التعديل، يعني فيه اعتمادية بينها بحيث لو عدلت في جزء محتاج أعدل في جزء تاني. و أنا مش عاوز كده أنا عاوز الارتباط بينها يكون في حده الأدنى loosely coupled.
= الحاجات اللي مش بتطبق مبدأ التخصص الدقيق بتكون غير متماسكة loosely cohesive ودي برضو بتبقى صعبة في التعديل، يعني فيه أكتر من سبب لتعديل الجزء البرمجي ده. و أنا مش عاوز كده برضو، أنا عاوز التماسك يكون عالي جدا tightly cohesive.
= طيب تعالوا نعيد صياغة المبدأ تاني: حاول توصل لأعلى تماسك و أقل ارتبط strive for tight cohesion and loose coupling عشان الكود بتاعك مايبقاش big ball of mud.

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

Wednesday, December 6, 2017

هندسة البرمجيات بالهجايص: (1) أسمي الحاجة إيه؟

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

* مقدمة:

بقالي كتير عاوز أكتب سلسلة مقالات أو أعمل سيشنز عن بعض المفاهيم المهمة في تصميم البرمجيات، و بالذات المفاهيم المتعلقة بال Object Oriented Design و ما يتبعها من Design Patterns، بس كالعادة الوقت ما بيبقاش متاح، فقلت أعمل سلسلة على الفيسبوك أتكلم فيها عن المفاهيم دي بالهجايص كده، و أهو أحسن من مفيش.

* مين هايستفيد من الهري ده؟

عشان يكون الكلام مفيد لازم اللي هايقراه يكون عنده خلفية جيدة عن الObject Oriented Programming و إلا هايحس في معظم الأحيان إننا بنتكلم هيروغليفي.

* أول قاعدة:

خلونا نبدأ في الأول بمفاهيم عامة في تصميم البرمجيات و نخش في التفاصيل واحدة واحدة مع الوقت إن شاء الله.
من أهم الحاجات اللي محتاجين ناخد بالنا منها لما نعوز نكتب كود نظيف:
1- نسمي الحاجة إيه؟
2- نحط الحاجة دي فين؟
[الحقيقية اللي اتعلمت منه القاعدة دي واحد ابن حلال اسمه أمير جعفر عامل سلسلة يتيمة على اليوتيوب عن الTest Driven Development (ابقوا بصوا عليها)]
نرجع لشرح المفهوم...

*** نسمي الحاجة إيه؟

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

* إزاي بقى تختار اسم مناسب؟

- الاسم لازم يعبرعن الحاجة اللي بيمثلها، يعني مثلا لو بتختار اسم لclass فالمفروض تفهم من اسمها الكلاس دي بتهبب إيه بالضبط، لو اسم method فالمفروض الاسم يعرفك هي بتعمل إيه بالضبط من غير ما تبص على الكود اللي جواها...إلخ. و خدها قاعدة كده، لو الاسم اللي اخترته محتاج تكتب جنبه comment عشان يشرح معناه إيه، فده مؤشر إن الاسم اللي أنت مختاره وحش.
- بلاش الأسماء المضللة عشان بتتعبنا و الله، يعني مثلا ماتجيش تسمي variable: productList و هو مش list مش جايين نحل فوازير احنا...لقد هرمنا 
- الفرق بين المفاهيم لازم ينعكس في الأسماء، يعني مثلا لو بنعمل method بتنقل ملف من source إلى destination، ما تسميش الvariables:
a1 & a2
لأ سميهم source & destination
- تجنب التلوث البصري في اختيار الأسماء، يعني مثلا لو عندك class اسمها company، ما تجيش بقى في كل الfields اللي فيها و تلزق في اسمها company، فماتقولش companyName، companyId، companyAddress..إلخ. قل لي إيه الإضافة اللي ضفتها لما عملت كده؟ و الأنيل بقى لما تلاقي واحد كاتب لك nameString كأن الاسم ممكن يكون float مثلا.....لقد هرمنا بجد 
- الاسم اللي هاتختاره لازم تكون هاتعرف تقراه، و بالتالي لما تيجي تدور عليه تعرف تلاقيه. بلاش اختصارات في الأسماء، و استخدام الأسماء الطويلة مش عيب و لا حرام على فكرة.
- استخدام الفرانكو في الفيسبوك وحش قوي، و أوحش في الكود. دونت يوز فرانكو إن يور كود بلييييييزززز.
- بلاش أرقام سحرية في الكود، أرقام مستخدمة في كل الكود كده محدش عارف معناها إيه. في اختراعات ظريفة في لغات البرمجة دلوقتي زي الenums و الconstants، المبرمجين الكويسين بيستخدموها...كن مبرمجا كويسا زيهم.
- ما تستخدمش variables من حرف واحد إلا في الloops، عشان دي من الحالات القليلة اللي المبرمجين تلقوها بالقبول.
- أسماء الclasses و الobjects تكون أسماء مش أفعال، مثال: company، account، FileParse. و أسماء الmethods تكون أفعال و أسئلة مش أسماء، مثال: DoSomething، IsValid، HasChildren..إلخ.
- بلاش استظراف في الكود، ما تجيش مثلا تستخدم قفشات من فيلم بتحبه في أسماء الvariables عشان أنت أكيد عارف إن مش كل الناس بتلقط قفشات الأفلام.
- حاول تكون متسق مع ذاتك و تستخدم نفس الاسم للتعبير عن نفس المفهوم في كل حتة، يعني مثلا لو بتحب اسم get لما تعوز تجيب حاجة، افضل استخدمه في كل حته، مش مرة تستخدم get ومرة retrieve و مرة fetch... كمان مرة، خليك متسق مع ذاتك.
- لو مطبق design pattern معين حاول تستخدم اسمه كجزء من اسم الclass أو الmethod بتاعتك، و نفس الكلام لو فيه algorithm أو أي مصطلح يفهمه بتوع البرمجة برضو استخدم اسمه برضو. تذكر إن اللي بيقروا الكود مبرمجين فارفق بهم و ساعدهم يفهوا الكود عشان يدعولك.
- لو ما لقيتش اسم برمجي مناسب بس كان فيه اسم في البزنس اللي أنت شغال عليه ممكن تستخدمه، توكل على الله و استخدم اسم البزنس.
- و لو ما لقيتش اسم مناسب لا للمبرمجين و لا في البزنس، هاتضطر تطلع مهارات الفتي اللي جواك، بس حاول تقلل من استخدام الأسماء المستهلكة زي Manager، Controller، Data، Info بقدر المستطاع عشان كتر استخدامها عمال على بطال بقى مضلل شوية.
- لو اخترت اسم وبعد كده حسيت إنه مش مناسب غيره عادي خالص، مش عيب و الله، خاصة إن التولز دلوقتي بتسهل لك التعديل في كل الأماكن مرة واحدة. و لو غيرته 10 مرات و لسه مش مناسب افضل غير فيه ولا يهمك.
- حاول تقرأ كتاب clean code، أنا نقشت منه حاجات كتير في البوست ده. و دايما بقول لو المبرمج مش هايقرأ غير كتاب واحد في حياته في البرمجة فليكن الكتاب ده.

-------
طيب بقية المفهوم الأول: أحط الحاجة فين؟
مش هاجيب صورة عادل إمام الشهيرة للإجابة على السؤال ده عشان هي قبيحة، بس هاقول لكم نخليها المرة الجاية إن شاء الله 
و لا تنسونا من لايكاتكم و شيراتكم و نصائحكم