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

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