Friday, March 10, 2017

ما أهمية تقسيم المشروع لطبقات layers and tiers؟

من فترة كان فيه سؤال على المجموعة Egpytian Geeks على الفيسبوك عن أهمية إني أقسم المشروع بتاعي لlayers و tiers, و هل ده هايأثر على سرعة و أداء التطبيق و لا إيه اللي هايحصل؟
ساعتها كنت كتبت كلام كتير و افتكرته دلوقتي، فقلت أظبطته شوية و أعيد نشره على صفحتي على الفيسبوك لتعم الفائدة، ثم نصحني بعض الأصدقاء بإعادة نشره المدونة دي, و عشان كده مكتوب بالعامية...
و أصل النقاش كان هنا لمن أراد الاطلاع عليه.

الفرق بين الlayers و الtiers

خلينا الأول نبين الفرق بين الtier و الlayer. الاتنين طبقات, بس لو الطبقات بيشتغلوا على نفس الكمبيوتر يبقى اسمهم layers, لو انفصلوا يبقى اسمهم tiers. بعبارة أخرى, الlayers هي logical separation أما ال tiers فهي physical separation.

هل الطبقات دي هاتأثر على طريقة أداء المشروع؟

آه طبعا...
- هاتبطأه (و لو قليلا في حالة الlayers (فيمكن إهماله) و كثيرا في حالة الtiers)
- هاتخليه أصعب في الفهم و الdebugging: تخيل إنت عمال تتنط بين الlayers عشان توصل للbug أسهل و لا لو هي ف نفس المكان معاك أسهل؟
- هاتكبر المشروع: هاتزود tier يعني هاتعمل project منفصل لكل tier و هاتحتاج تزود  web services...إلخ, و ده طبعا هايصعب الدنيا أكتر
- فيه ناس هاتقول لك هاتقدر تعيد استخدام الطبقات دي في مشاريع تانية، و الفكرة دي تسمى  reusability ، و دي انساها خالص مش هاتحصل!!! -- هاتيجي بالتفصيل تحت - إن شاء الله -
أمال ليه وجع القلب ده؟!!!
 خلينا ناخد شوية تفاصيل عشان نعرف الفايدة الحقيقية...

ليه بقسم المشروع لطبقات؟ 

 - فيه نظرية عامة في هندسة البرمجيات بتقول: إن أي مشكلة في تصميم البرامج ممكن أحلها بإضافة طبقة غير مباشرة - و الاستثناء الوحيد هو مشكلة كثرة الطبقات غير المباشرة -
 We can solve any problem by introducing an extra level of indirection....except for the problem of too many levels of indirection
ممكن تقرأ المزيد عن النظرية دي هنا

يعني إيه الكلام ده؟

 يعني أنا عندي فورمة عليها شوية كونترولز, و عندي قاعدة بيانات, ليه ما بندهش لقاعدة البيانات على طول و أريح دماغي؟
 عشان أنا عندي مشكلة (أو عدة مشاكل) عاوز أحلها, و بتطبيق النظرية السابقة, رحت عامل طبقة حطيت فيها شغل الداتابيز, و طبقة حطيت فيها البزنس بتاعي, و خليت الطبقة اللي فيها الUI بسيطة لا بتهش و لا بتنش!

طب إيه هي المشاكل اللي عاوز أحلها دي؟

تخيل الآتي:
إني لو جبت الكود بتاع البزنس + الكود بتاع الداتبيز + الكود بتاع الuii و حطيتهم في حتة واحدة, فكر معايا إيه اللي هايحصل في السيناريوهات دي:
1- كنا شغالين ال UI بasp.net web forms بس مايكروسوفت عملت حاجة جديدة اسمها asp.net mvc بس لما جيت أطبقها ما عرفتش عشان الكود ملخفن!
2- البرنامج كان صغير, و كنا شغالبن أكسس, بس لما كبر البرنامج أكسس ما استحملتش, فقلنا لازم نستخدم sql server بس ما عرفناش عشان الكود بتاع الداتابيز معتمد على أكسس, و ملخفن جوة الكود بتاع الui و محتاج تعديلات في حتت كتيرة!
3- البرنامج كان شغال desktop بس برامج الdesktop بقت ميتة, و كل الناس متجهة نحو الويب و الموبايل, و أنا كاتب كود بقالي سنين كتيرة و حرام أرميه, و أبدأه من أول و جديد, و مش عارف أسلكه من الكود الملخفن!
 .. الأمثلة من دي كتيرة, الشاهد: إن فكرة تقسيم البرنامج لطبقات فوق بعض بتديني ميزة تسهيل استبدال أي طبقة (نوعا ما) , و ده اللي بنسميه design for replacement not reusability!
لاحظ هنا إني حصلت على ميزة سهولة الاستبدال replacement مش سهولة إعادة الاستخدام reusability، طب إيه الفرق بينهم؟
الأولى تعني *إعادة الاستخدام* يعني عندي layer هاستخدمها ف حتة تانية
أما الثانية فتعني *الاستبدال*, يعني عندي layer هارميها و أجيب واحدة بدالها
اسأل أي واحد عمل كام مشروع وييب, كام مرة أخد Layer ك dlll و أعاد استخدامها في مشروع تاني؟ عمر ده ما حصل معايا أنا - على الأقل -! أقصى ما فعلته إني أخدت شوية كود copy/paste و استخدمتهم في مشروع تاني. و ده ما اسمهوش reusability ده اسمه code duplication و ده ربما يكون مصدر كل الشرور في البرمجة - كما قال روبرت مارتن!
لكن كام مرة احتجت إني استبدل layer فيها مشاكل بlayer تانية لسبب أو لآخر؟ ده حصل معايا كتيييير. عشان كده بقول لك design for replacement not reusability و ده بيفرق على فكرة في طريقة التصميم نفسها, بس ده مش مجاله دلوقتي.

طب إزاي حصلت على ميزة القابلية للاستبدال دي؟

بإني خليت كل طبقة تعمل حاجة واحدة بس, و بالتالي بقى فيه سبب واحد للعب في الطبقة دي.
مثلا: طبقة الpresentation بقت مش هالعب فيها إلا لما عاوز أعدل حاجة في طريقة العرض أو استبدلها كليا, و ده من غير ما قاعدة البيانات تتأثر. و نفس الكلام بينطبق على الطبيقات التانية.
و ده اللي بنسميه separation of concerns و فيه رواية أخرى  single responsibility principle

مشكلة كمان...

 دلوقتي أنا حاطط كل الطبقات بتاعتي على كمبيوتر واحد, بس أنا خايف إن حد يقدر يخترق الكمبيوتر ده و يحصل على البيانات اللي متسجلة في قاعدة البيانات, إيه الحل؟
Add layers of indirection!
بس الطبقات اللي هاضيفها هنا هاتكون في الحقيقة tiers مش layers بحيث لو أي tier فيهم اتضربت compromised هايكون لسه عندي خطوط دفاع تانية (الtiers اللي ورا)!
و بمجرد ما أقسم البرنامج بتاعي لtiers هاتتفتح لي آفاق تانية مثيرة جدا!!!

نرجع لمشكلة البطء...

زي ما قلنا، إن أول حاجة هاتحصل لما أقسم البرنامج على أكتر من كمبيوتر tiers إن البرنامج هايبطأ شوية!
أيوة... عشان فيه وقت هايستهلك في إن الدااتا تتنقل من كمبيوتر للتاني عبر الشبكة.
 لو الكمبيوترين دول بعاد عن بعض, و عملية نقل البيانات هاتتم عبر الإنترنت فالدنيا هاتكون أبطأ مما لو كانوا على شبكة داخلية.
 بس عشان أتغلب على مشكلات البطء دي محتاج أظبط حتت كتير في البرنامج, يعني مثلا أعتمد كتير على client = javascript و الajax calls و في السيرفر أعتمد كتير على الasync calls و هاحتاج اعمل optimization للdatabase queries و أعمل caching للبيانات...إلخ و في الآخر الدنيا هاتظبط بصورة كبيرة.
بالرغم من إن سرعة البرنامج قلت (نوعا ما) إلا إني لما عملت tiers هاقدر دلوقتي أحسن اللscalability بتاعت البرنامج, وده هايحسن السرعة جدا!
 طب إزاي؟
الscalability قصة طويلة مش ده وقتها, بس خلينا نقول إن معناها قد إيه البرنامج بتاعي هايستحمل زيادة عدد المستخدمين؟
في حالة الكمبيوتر الواحد one tier قدرة البرنامج مرتبط بقدرة الكمبيوتر اللي هو شغال عليه. البرنامج هايفضل شغال معايا كويس و زي الفل لغاية لما عدد المستخدمين يوصل لحد معين بعده البرنامج سرعته هاتقل بصورة دراماتيكية (حلوة دراماتيكية دي :)
و الحل إما تزويد إمكانات الكمبيوتر أو تزويد الكمبيوترات.
فيه كلام هنا كتير web farms - web gardens ...إلخ, بس اختصارا, توزيع البرنامج هايسمح لي إني أعمل optimization لأجزاء معينة في البرنامج تحسن الscalability بتاعته.
طب السرعة هاتزيد و لا هاتقل, آخر كلام؟ :)
لو البرنامج بتاعك صغير و عدد المستخدمين صغير, هاتحس إنها بطيئة.
لو البرنامج بتاعك كبر, و عدد المستخدمين زاد هاتحس إنها أسرع.
 ---
و ده يقودنا إن للهدف الرئيسي من كل الحوارات دي: المرونة!
لما بقسم الدنيا لأجزاء أو طبقات بيبقى عندي المرونة اللي تخيني أعمل optimizations على كل جزء على حدة.
----
و كما يظهر من كل الهري ده, إني زودت الcomplexity بتاعت البرنامج بس في المقابل حصلت على مرونة: مرونة إني أستبدل بأجزاء تعبانة في البرنامج أجزاء كويسة , مرونة إني أظبط أجزاء في البرنامج من غير ما أؤثر على أجزاء تانية..إلخ.
 ---

طيب إمتى أعقد الدنيا كده؟

لازم أختم الكلام بإن إضافة الcomplexity دي على المشروع لازم تكون مبررة, يعني المشروع طول ما هو صغير (يتعمل في أيام) مفيش داعي إني أعمل الفصلة في الكود, أي عجن في الcontroller هايكون كويس
لو المشروع كبر شوية (يتعمل في أسابيع) هنا الlayers هاتكون مناسبة
لو كبر أكتر (يتعمل في شهور) هنا الtiers هاتكون مناسبة أكتر
... و هكذا
 أو بعبارة أخرى: الفائدة من الحوارات دي بتبان لما البرنامج يكبر, لكن طول ما هو صغير فهاتفضل تحس إنه صعبة و رخمة و مالهاش فايدة كبيرة!

No comments:

Post a Comment