تطبيقات الصفحة الواحدة SPA. ماذا, لماذا و كيف.
رغم أننا لا ننكر أن مجتمع التطوير العربي يشهد نمواً متسارعاً, إلا أنه بين الحين و الآخر تحدث قفزات في عالم التطوير, تأخذ منا وقتاً طويلاً حتى نتداركها. خاصة تلك التي تتعلق بعالم الجافا سكربت, حيث أننا لا نزال نفتقد إلى المطور المتخصص بها, أو الوظائف التي تطلبها وحدها كمهارة أساسية.
و كذلك نظراً لكبر مساحة الإبداع في السنوات الأخيرة, و بعد أن صار المستخدم العربي نفسه يحتك بالمستوى العالمي من تطبيقات الويب, و صار يبتغ أمثله متطوره في طلباته, فقد صار أمراً لزاماً على المطورين العرب أن يولوا أهتمام أكبر للغة الجافا سكربت, خاصة أن التطور الحادث بها خلال السنوات الأخيرة, صار مما لا يمكن مجاراته بمعنى الكلمة. فالواجهةFront End تقريباً صارت لا تقل أهمية, بل تزيد في أحيان كثيرة عن البنية الأساسية Back End.
واحدة من تلك النماذج الإحترافية التي صار يبحث عنها المستخدم العربي في الفترة الأخيرة, هي تقنيات “تطبيقات الصفحة الواحدة Single Page Applications”, أو ما يعرف إختصاراً بـ SPA. و لنا هنا أن نوضح أن الـ SPA يختلف كليا عن صفحات الـ Squeeze التي قد تجد مثال لها هنا.
براءة الأختراع
ربما لا تعلم أن تقنية SPA هي براءة إختراع أمريكية مسجلة تحت الكود (8,136,109). حيث كانت الفكرة عن تقديم نموذج لمواقع ويب ديناميكية, تشبه تطبيقات سطح المكتب. تلك التي تفتح فيها نافذة واحدة, و تستمر بالتنقل بين الخصائص و الخيارت المختلفة, دون أن تبتعد عن نفس النافذة. و كذلك الأمر هنا, عليك أن تتصفح الموقع المكون من أكثر من صفحة, و تنتقل بينهم دون أن يحدث أي تحديث reload للصفحة التي أنت عليها.
الأمر تجده في مواقع مشهورة حالياً, ربما من أشهرهم GitHub و SoundCloud. فالتطبيقان تفتحهم لأول مرة, و تستمر تتنقل بين صفحات كثيرة دون أن يحدث أي تحديث أو انتقال من الصفحة أغلب الوقت. يمكنك أن تستطلع الصورة التالية لتطبيق SoundCloud و تعتبر أن جميع الصفحات قد تم تحميلها مسبقاً مرة واحدة, و لكن هناك صفحة تظهر لك في المقدمة, و باق الصفحات في الخلفية و تنتظر كل واحدة دورها, و هو تشبيه غير دقيق أعرف, لكنه فقط للتوضيح.
هل الـ SPA بهذه البساطة
مما لا شك فيه أنك هنا تصنع من البساطة عنوان للمستخدم, تخيل مثلاً ما ربحه SoundCloud و هو يمنحك ميزة أن يظل المشغل مستمر بالعمل, و أنت تتنقل بين الصفحات. و لكن مما لا شك فيه, فإنه بالنسبة للمطور, فأن الأمر ليس إلا طاقة من الجحيم قد فتحها في وجهه, إذا ما أراد تنفيذ تطبيق SPA, و خاصة إذا كان متعدد الوظائف.
في التالي, سنناقش أكبر مشاكل تطبيقاتSPA و كيف نحاول تفاديها على قدر المستطاع. علماً أن كل ما يطرح هنا من حلول, سيأتي عليها الزمن حتماً و تكون قديمة, أو حتى لربما في الوقت الحاضر يكون لدى البعض الأفضل منها. لذا لا تستمر بتحديث معلوماتك و مناقشتها معنا في التعليقاتك دوماً.
الصفحات
ببساطة, أن تبني تطبيق SPA بنفس مفهومك عن التطبيقات التقليدية, هو أمر سئ حقاً. فبالفعل دائماً هناك صفحات كثيرة تظهر للمستخدم و هو يتنقل بين الروابط, و لكن الأمر مختلف عن ذلك.
الأسلوب الأشهر المستخدم هنا هو أن تقسم موقعك بالكامل من ناحية العرض View, الى مكونات صغيرة جداً, كما قطع الـ Puzzle, و تحاول أن تخطط كيف تعيد إستخدام هذه القطع أكثر من مرة لصنع كل تلك الصفحات. و كلما زادت تلك القطع التي تستخدمها أكثر من مرة, وفرت على نفسك العناء الكثير.
حاول مثلاً أن تتصفح GitHub, و في كل مرة سجل العناصر التي تراها من القوائم و الأزرار و رسائل التحذير و ما الى ذلك. و حاول أن تكتشف كيف يتم إعادة استخدام الكثير منهم في كل مشهد مختلف. إذن الأمر لا يتعلق بصفحات كاملة كثيرة, بل بمكونات قابلة لإعادة الإستخدام.
يمكنك أيضاً – وذلك أفضل في رأيي– أن تستخدم إطار عمل أو مكتبة تنظم لك عرض المشاهد و العناصر ببساطة, كـ AngularJS أو Ember أو Backbone أو React أو غيرهم الكثير.
البيانات
حسناً, قمنا بتكوين كل صفحة و مشهد. إذن كيف سنتعامل مع البيانات التي ستملأ تلك المشاهد, و لا ننسى أننا هنا بصدد بناء موقعاً ديناميكياً.
عادة بعد أول تحميل للموقع, فإنك تبدأ من بعدها بالتعامل مع الخادم Server كمستودع لجلب البيانات فقط. و تستمر رسائل التواصل كـ Ajax بينك و بين الخادم لإحضار كل ما يلزم. و لكن إن لم تنظم سير هذه البيانات جيداً, ستصنع لنفسك مشكلة بنهاية المطاف.
الحل يأتي بإستخدام أحد إطارات العمل الشهيرة التي تحاول صنع من الجافا سكربت التقليدية شيئاً أفضل. ربما بشأن هذه النقطة يمكننا ذكر AngularJS, حيث يأتي ببناء من نوع MVC (كأسلوب أحدث, حالياً تم تحديث الـ C الى حرفW , أو ما يعني Whatever) و يطرح لك نموذج تنظيم البيانات في هيئة models كما مستودعات للبيانات. و تحدد أنت ببساطة أين تريد أن تظهر هذه البيانات و كيف. و كلما حدث تغيير في هذه المستودعات, سيحدث التغيير في الصفحات تلقائياً. و هذا بالتأكيد سيوفر عليك عناء أن تضع البيانات في أماكنها يدوياً, أو تضطر لمراقبة التحديثات يدوياً كذلك.
الذاكرة
ماذا لو إستخدمت حدث Event يتم تنفيذه كلما قمت بتغيير قيمة حقل نصي معين. هنا ستنشأ عملية من النوع Listener تقوم على الدوام بمراقبة القيمة في الحقل. و لكن ماذا لو أنك حذفت هذا الحقل بالكامل من الصفحة ؟!. هل فكرت ماذا سيحدث حينها ؟.
الأمر ببساطة أنك ستترك حيزاً مشغولاً في الذاكرة, و الألعن أنك ستترك Zombie Task او عملية غير مسيطر عليها. هذا الأمر كان لربما يواجه الكثير منا في التطبيقات التقليدية, و لكن لا يلق له بالاً. فحيز الذاكرة عادة لا يكون كبيراً, و كذلك تلك العمليات الـ Zombies ستنتهي بالكامل فور إنتقال المستخدم لصفحة أخرى, حيث يتم إزاله كل القديم, و إعادة بناء الأمر من جديد لصفحة جديدة. و لكن في تطبيقات SPA, فإن ميزة كإعادة تحميل الصفحة, من المفترض أنها ليست موجودة. فما الحل ؟.
الحل يأتي في صورة صعبة قليلة, و هو أن تستمر بالتأكد بأنه كلما أحضرت مشهد جديد, قمت بإزالة كل متعلقات القديم من events و متغيرات غير مستخدمة و ما إلى ذلك. فمثلاً يمكنك في jQuery دوماً أن تستخدم الدوال كـ empty و unbind و غيرهم, للتأكد أنك أزلت كل متعلقات العنصر قبل إخفاءه (فأنت فعلياً ربما لا تقوم دائماً بحذف العناصر, بل إخفائها من المشهد). و يمكنك أن تستخدم مكتبة كـ CanJS التي تضمن لك أن تحذف تلقائياً أي عمليات متعلقة بأي عنصر تم إزالته من الـ DOM. أو أنصحك بقراءة هذه الإجابة الجميلة على سؤال متعلق بهذه المشكلة.
ملفات كثيرة, مشاكل أكثر
بالتأكيد بنهاية المطاف في بنائك لتطبيق SPA ستكون على موعد مع عدد كبير من ملفات الجافا سكربت التي تحتاج لترتيب. و لكن الأسوأ من الترتيب هو الاعتمادية بين الملفات. حيث يحتاج كل ملف لعدد من الملفات, أو تلك المكتبة تعتمد على أخرى, و هكذا.
الحل لتنظيم ملفاتك, و كذلك تنظيم الإعتمادية, يأتي مثلاً مع الـ AngularJS في صورة ضمانته لأن ينظم هو بنفسه تلك المشكلة. لكن ذلك يحدث في التطبيقات ربما الصغيرة. و لكن إن كانت الملفات أكبر و أضخم, إذن أنت تحتاج لحل مستقل خاص بهذه المشكلة.
و لذلك, يمكنك إستخدام مكتبة الـ Require.js التي تعني بتنظيم ملفات الجافا سكربت. لتضمن أن تخرج في صورة ملف واحد في النهاية, يتغير طبقاً لما تحتاج من أكواد. فتظل دائماً تستخدم فقط الاكواد التي تحتاجها كل لحظة.
جدير بالإشارة أن SoundCloud كان يعتمد على هذه المكتبة لفترة طويلة, ثم قرر أخيراً أن يستغني عنها لمشاكل متعلقة ببنيته الضخمة. لذلك إستخدم المكتبة Almond.js كبديل.
أول لحظة, هي الأهم
بالتأكيد لأنك تريد توفير الوقت فيما بعد على المستخدم, فإنك تجلب العديد من العناصر الإضافية للصفحة الأولى, و العديد من ملفات الجافا سكربت و ملفات التنسيق CSS و غيرذلك. ثم تظل تنتقل بينهم طوال الوقت. و لكن أكبر مشكلة هنا هي أن كل زوارك لا يمتلكون سرعة الإنترنت المطلوبة لتحميل كل ذلك سريعاً. لذلك لا تنس أن تتفقد وقت تحميل موقعك على مختلف السرعات من وقت لآخر. يمكنك أن تستخدم برامج تساعدك على محاكاة مختلف السرعات لتحميل موقعك مثل slowyapp أو charlesproxy أو غيرهم.
إحترس من الوحش
لا تنس دوماً, أنك تتعامل مع الجافا سكربت, التي يعتبرها الكثير صداع الويب الأكبر. و لذا فكلما زاد تطبيقك تعقيداً, ستظهر حتماً المشاكل و الأخطاء. و الأخطاء هنا في الجافا سكربت أسوأ من أن تكشف عن نفسها ببساطة كما في باقي اللغات الأكثر إحتراماً. فيمكنك فجأة تجد كلمات من نوع undefined و null و unexpected فقط لتوصيف المشكلة. و ستكون ممتناً لو حدد لك سطر المشكلة, و كثيراً لا تكون المشكلة من هذا السطر أصلاً !. و عليك أن تدور حولك دائماً لتكتشف ماذا حدث, و تقضي الساعات لإصلاح مشكلة بسيطة. فقط لأنك لا تعرف ماذا حدث بالضبط !.
لذلك, تأتي ميزة إستخدامك لإطارات العمل الشهيرة. حيث أنها تضع دائماً تعريف واضح للمشاكل التي تتعلق بدوالها, و لكن ماذا عن أكوادك أنت ؟. ربما يجب عليك أيضاً أن لا تهمل فكرة أن تستخدم تقنيات مثل Try, Catch,Final, Throw دوماً, لتعرف أنت عن مشاكلك بشكل أدق.
إياك و التطبيقات الضخمة
كثيراً ما قرأت أن الخبراء يحذرون من تطبيقات SPA الضخمة. و في الحقيقة أنا لم أتعرض لها, و لكن الأغلب يوافق على أن صنع التطبيقات الضخمة يؤدي الى فشل ذريع في النهاية.
و هؤلاء يطرحون دوماً أن تقسم تطبيقك SPA الكبير الى مجموعة من التطبيقات الأصغر. كأن تقسم موقعك الى مكونات Components و تحاول أن تصنع SPA لكل واحد (مثال: أن تحصر عمليات العضوية في مكون, و عمليات التدوينات في مكون, و هكذا … ), و لا ضرر أن يحدث تحديث للصفحة إذا انتقل المستخدم من مكون لآخر, و لكن هذا سيوفر عليك تعقيد أكبر.
محركات البحث لا تع هذا الهراء
واحدة من المشاكل التي يمكن أن تقض تماماً على مشروعك, هي أن تنسى أن محركات البحث لا تفهم الجافا سكربت. فلو أن رابط موقعك واحد دائماً (و هو الأمر البديهي), فهذا سيؤدي إلى غياب موقعك تقريباً عن الإشهار و المشاركة.
لنأخذ مثالاً في موقع SoundCloud, كلما إنتقلت لصفحة, فأنه أي نعم لا يقوم بتحديث للصفحة, و لكنك ستلاحظ أن الرابط في حقل العنوان في المتصفح, قد تم تغييره. و هذا مفيد لأمرين مهمين.
أولاً أنه يمكن أن أدلف مثلاً لصفحة ملف صوتي, فأجد رابط جديد قد تم توليده بحقل العنوان بالمتصفح, و منها يمكنني أن أنسخه و أشاركه مع الجميع. و حين يستخدم صديقي هذا الرابط المخصص, فالأمر لا يؤثر إطلاقاً على سير التطبيق SPA, و لكنه فقط يحدد بأي مشهد يبدأ بالضبط. فقط تغيير في ترتيب سيناريو المشاهد. لذلك من المهم أن تضع في الحسبان أن تحدد سير المشاهد بناء على الرابط.
و الأمر الثاني, هو أن تبقى هناك دوماً روابط مفصلة لكل شئ, لتساعد محركات البحث أن تقوم بأرشفتك. رغم أن الأمر ربما سيحتاج منك أن تبني ملف خريطة موقع sitemap تسجل فيه كل تلك الراوبط المولدة, لتسهل على محرك البحث المهمة.
هل انتهى الأمر
لا بالطبع, فكلما تعمقت أكثر, ستكتشف مشاكل أكثر, و لكننا هنا سردنا أكبر التحديات. و يمكنك مثلاً متابعة ذلك المقال الشيق الذي يشرح فيه مطورو الـ SoundCloud ما هي منهجيتهم في بناء تطبيقهم و تحديثه و كيف يفعلون ذلك و ماذا يستخدمون.
و نتمنى أن نكون ساعدنا في توضيح الصورة, من أجل تطبيقات SPA بجودة عالية. و كلما إكتسبت خبرة جديد, شاركها من حولك دوماً. و لا تترد أن تشاركنا تعليقاتك و خبراتك حول الأمر, فبالتأكيد هناك من الحديث بقية.
بارك الله فيك … مقال شيق و ممتاز
Great Post
You are professional