التحوّل التالي للويب - كيف سيتغير شكل الويب الذي نعرفه كمبرمجين!
- التطبيقات متعددة الصفحات (MPAs)
- السلوكيات المعمارية لهذه التطبيقات متعددة الصفحات
- إيجابيات وسلبيات التطبيقات متعددة الصفحات
- تطبيقات متعددة الصفحات محسّنة تدريجيًا (PEMPAs)
- السلوكيات المعمارية لهذه التطبيقات متعددة الصفحات المحسنة تدريجيًا
- إيجابيات وسلبيات التطبيقات متعددة الصفحات المحسنة تدريجيًا
- تطبيقات الصفحة الواحدة (SPAs)
- السلوكيات المعمارية لتطبيقات الصفحة الواحدة
- إيجابيات وسلبيات تطبيقات الصفحة الواحدة
- تطبيقات الصفحة الواحدة المحسنة تدريجيًا (PESPAs)
- السلوكيات المعمارية لتطبيقات الصفحة الواحدة المحسنة تدريجيًا
- إيجابيات وسلبيات تطبيقات الصفحة الواحدة المحسنة تدريجيًا
- تطبيق عملي للتطبيقات الصفحة الواحدة المحسّنة تدريجيًا: Remix
- خاتمة
السلام عليكم ورحمة الله، أسعد الله صباحكم والمساء أحبتي الكرام.
يتكون الويب من مجموعة تقنيات ظهرت منذ أكثر من 25 عامًا. وُحِّدَت ووضعت لها المعايير (standardized) لكل من HTTP و HTML و CSS و JavaScript بمنتصف التسعينيات.
منذ ذلك الحين، نَمى الويب ليصبح منصة تطبيقات حاضرة في كل مكان، ورافق ذلك تقدمًا في معماريات التطوير المتّبعة.
تتوافر هذه الأيام معماريات أساسية عديدة لبناء تطبيقات الويب. أكثرها شيوعًا بين المطورين هي تطبيقات الصفحة الواحدة (SPA)، ولكنّنا في قيد التحوّل إلى معمارية جديدة مُحسّنة لإنشاء تطبيقات ويب مختلفة.
ببداية عصر الويب وُجدت عناصر الروابط <a>
وعناصر النماذج <form>
في المتصفحات. أما الروابط فنحصل منها على معلومات من الخادوم، وأما النماذج فنرسل بها الطلبات إلى الخادوم ونحصل على معلومات أخرى في المقابل.
من خلال هذا الاتصال ثنائي الاتجاه (two-way communication) الذي أنشئ كجزء من العملية منذ بداية الويب، ساهم في إنشاء تطبيقات قوية.
فيما يلي نسرد المِعماريات الرئيسية مرتبةً زمنيًا حسب شيوعها:
- التطبيقات متعددة الصفحات (MPAs).
- التطبيقات متعددة الصفحات المحسنة تدريجيًا (PEMPAs) والتي تضاف إليها JavaScript كملح الطعام "JavaScript Sprinkles".
- تطبيقات الصفحة الواحدة (SPAs).
- التحوّل التالي (The next transition).
كل معمارية لتطوير الويب لها مزايا وعيوب. في نهاية المطاف، أصبحت العيوب والمشاكل محفزّة للانتقال إلى المعمارية التالية بإيجابياتها وسلبياتها.
بغض النظر عن كيفية إنشاء تطبيقاتنا، سنحتاج في غالب الحالات إلى كود يعمل على الخادوم.
أحد الأشياء التي تميّز هذه المعماريات هو مكان وجود الكود. فلنستكشف هذه المعماريات ونشاهد كيف تَغَيّر موقع الكود بمرور الوقت.
أثناء تغطيتنا لكل معمارية سننظر بالأخص إلى حالات استعمال الكود التالية:
- التخزين: حفظ البيانات وقراءتها من قاعدة البيانات.
- التوجيه (routing): توجيه تدفّق البيانات بحسب الرابط (URL).
- جلب البيانات (Data fetching): استرجاع البيانات من التخزين.
- تغيير البيانات (Data mutation): تغير البيانات في التخزين.
- منطق العرض (Rendering logic): عرض البيانات للمستخدم.
- استجابة واجهة الاستخدام (UI Feedback): الاستجابة لتفاعل المستخدم.
من الطبيعي أن مكونات تطبيق الويب أكثر من هذه الأجزاء الصغيرة المذكورة آنفًا. ولكنّها الأجزاء التي يُنبنى عليها تطبيقنا ونقضي فيها وقتا أكبر كمطورين.
اعتمادًا على حجم المشروع وهيكل الفريق، إما أن نعمل في جميع الفئات هذه أو قد نعمل على جزء واحد فقط.
التطبيقات متعددة الصفحات (MPAs)
أو (Multi-Page Apps) في أيّام الويب الأولى، كانت هذه المعمارية الأكثر ملائمةً بناءً على إمكانات متصفحات الويب في ذلك الوقت.
بالتطبيقات مُتعددة الصفحات يكون الكود الذي نكتبه في الخادوم فقط، وأما كود الاستجابة لواجهة المستخدم فيعالجه متصفح المستخدم.
"لـتفهم أكثر ركّز على فهم الصُور المُرفقة لتتضح ليسهل فهم المقالة"
السلوكيات المعمارية للتطبيقات متعددة الصفحات (MPA Architectural)
طلب المستند (Document Request): عندما يُدخل المستخدم رابط URL في شريط العناوين، يرسل المتصفح طلبًا إلى خادومنا.
بعدها سيستدعي منطق التوجيه (routing logic) دالة لجلب البيانات التي تتواصل مع كود التخزين لاسترجاع البيانات.
ثم تُستخدم هذه البيانات بواسطة منطق العرض (Rendering logic) لتحديد كود HTML الذي سيُرسل استجابة للعميل. طوال هذا الوقت، يقدم المتصفح أول تفاعل أثناء الحالة المعلّقة (عادةً يكون الأيقونة المفضلة "favicon").
طلب التغيير (Mutation Request): عندما يُرسِل المستخدم نموذجًا (submit form)، يسلسل (serialization) المتصفح النموذج جاعلاً منه طلباً يُرسل إلى الخادوم.
بعدها سيستدعي منطق التوجيه (route logic) دالة لتغيير البيانات التي بدورها تتواصل مع كود التخزين لتحديث قاعدة البيانات.
بعدها، سيستجيب بإعادة توجيه (redirect) بحيث يشغّل المتصفح طلب GET للحصول على واجهة مستخدم جديدة، والتي ستؤدي إلى نفس الأمر الذي حدث عندما أدخل المستخدم رابط URL أول مرة.
مرة أخرى، سيعطي المتصفح تفاعلًا للمستخدم مع واجهة المستخدم المعلّقة.
ملاحظة: من المهم أن التغييرات الناجحة أُرسِلَت على هيئة استجابة إعادة توجيه (redirect) بدلًا من مجرد محتوى HTML الجديد.
بدون ذلك، سيتراكم طلب POST في مكدس السجل (history stack) وسيؤدي النقر على زر الرجوع إلى تشغيل طلب POST مرة أخرى.
هل تساءلت عن سبب قول التطبيقات أحيانًا "هل تود العودة وارسال الطلب؟" نعم، هذا هو السبب. تَوَجَّبَ الاستجابة بطلب إعادة توجيه.
إيجابيات وسلبيات التطبيقات متعددة الصفحات
النموذج الذهني للتطبيقات متعددة الصفحات سهل الاستيعاب. لم نُقدّر ذلك حينها. على الرغم من وجود بعض مسارات معقدة التي يُتعامل معها بشكل أساسي من خلال ملفات الكوكيز (cookies) في الطلبات، فقد حدث كل شيء في معظم الأحيان خلال دورة الطلب/الاستجابة.
أين يظهر قصور هذه المعمارية:
- تحديث الصفحة كليًا: يجعل بعض الأشياء صعبة مشتتة للتركيز، وتحيل أمورًا لتكون غير عملية بالمرة. تخيل التحديث الكامل للصفحة في كل مرة نفضّل فيها تغريدة! وبعض الأشياء تصبح مستحيلة كانتقالات الصفحة المتحركة.
- التحكم في تفاعل واجهة المستخدم: من الجيد أن تتحول أيقونة favicon إلى قرص دوار (spinner)، ولكن غالبًا ما تكون تجربة المستخدم الأفضل هي التفاعلات التي تكون بصريًا أقرب إلى الواجهات التي تفاعل معها المستخدم. وهو بالتأكيد شيء يحب المصممون تخصيصه لكي يناسب العلامة التجارية.
وماذا عن واجهة المستخدم المتفائلة؟
من الجدير بالذكر أن النظام الأساسي للويب يتحسن باستمرار باستخدام الواجهة البرمجية القادمة لانتقالات الويب والذي يجعل التطبيقات متعددة الصفحات (MPAs) خيارًا أكثر قابلية للتطبيق لمزيد من حالات الاستخدام. لكن بالنسبة لغالبية تطبيقات الويب، ما يزال هذا غير كافٍ. على أي حال، في ذلك الوقت كانت هذه المشكلة بعيدة عن أذهان لِجان المعايير ويريد المستخدمون المزيد حاليًا!
التطبيقات متعددة الصفحات محسّنة تدريجيًا (PEMPAs)
التحسين التدريجي أو Progressively Enhanced Multi-Page Apps.
هو فكرة أن تطبيقات الويب يجب أن تعمل وأن تتاح لجميع متصفحات الويب، ومن ثم الاستفادة من أي إمكانات إضافية يمتلكها المتصفح لتحسين التجربة. صِيغَ المصطلح في عام 2003 بواسطة Nick Finck وSteve Champeon.
بالحديث عن إمكانات المتصفح، فقد طُوّرت تقنية XMLHttpRequest في البداية بواسطة فريق Microsoft Outlook Web Access في عام 1998 ولكنه لم يكن معيارًا حتى عام 2016 (هل تصدق ذلك؟!). بالطبع هذا لم يوقف مزودي المتصفحات ولا مطوري الويب قبلهم من استخدام التقنية.
انتشر مصطلح AJAX في عام 2005 وبدأ الكثير من الأشخاص في تقديم طلبات HTTP في المتصفح. بُنيت الشركات على فكرة أننا لسنا مضطرين للعودة إلى الخادوم لأكثر من أجزاء صغيرة من البيانات لتحديث واجهة المستخدم في مكانها. باستخدام ذلك، يمكننا إنشاء التطبيقات متعددة الصفحات مُحسّنة تدريجيًا:
"لحظة!" قد تفكر، "انتظر دقيقة ... من أين تأتي كل هذه الأكواد؟" لذلك لم نتحمل الآن مسؤولية تفاعلات واجهة المستخدم من المتصفح فحسب، بل لدينا أيضًا التوجيه (routing) وجلب البيانات (data fetching) وتغيير البيانات (data mutation) ومنطق العرض للعميل بالإضافة إلى ما لدينا بالفعل على الخادوم. "ما يعطي؟"
حسنًا. تكمن الفكرة وراء التحسين التدريجي في أن الأساس الذي نوفره يجب أن يكون تطبيقًا يعمل. خاصة في أوائل العقد الأول من القرن الحادي والعشرين، لم نتمكن من ضمان أن مستخدمنا سيستخدم متصفحًا قادرًا على تشغيل عناصر AJAX الجديدة الرائعة، أو أنه سيكون على شبكة سريعة بدرجة كافية لتنزيل JavaScript قبل التفاعل مع تطبيقنا. لذلك احتجنا إلى الحفاظ على معمارية التطبيقات متعددة الصفحات (MPA) الحالية في مكانها واستخدام JavaScript فقط لتحسين التجربة.
ومع ذلك، اعتمادًا على مستوى التحسين الذي نتحدث عنه، قد نضطر بالفعل إلى كتابة الأكواد في جميع فئاتنا تقريبًا، والتخزين هو الاستثناء (ما لم نرغب في دعم الوضع غير المتصل (offline) وهو أمر رائع حقًا، ولكن ليس مطبقًا وفق معايير الصناعة، لذلك لم تُضمّن في الرسم البياني).
زيادة على ذلك، اضطررنا إلى إضافة المزيد من الأكواد إلى الواجهة الخلفية (backend) لدعم طلبات AJAX التي سيقدمها عميلنا. وهذا يعني المزيد من الأكواد على جانبي الشبكة.
هذا هو عصر jQuery و MooTools وغيرها.
السلوكيات المعمارية للتطبيقات المتعددة الصفحات المحسنة تدريجيًا (PEMPA)
طلب المستند: عندما يطلب المستخدم المستند لأول مرة، يحدث نفس الذي يحدث في مثال التطبيقات متعددة الصفحات (MPA). ومع ذلك، سيقوم التطبيقات المتعددة الصفحات المحسنة تدريجيًا (PEMPA) أيضًا بتحميل JavaScript من جانب العميل عن طريق تضمين علامات <script>
التي ستُستخدم لمزيد من التحسين.
التنقل من جانب العميل (Client-side Navigation): عندما ينقر المستخدم على عنصر رابط يحتوي "href" داخل تطبيقنا، يمنع كود جلب البيانات (data fetching) من جانب العميل سلوك تحديث الصفحة الكاملة الافتراضي وتستخدم JavaScript لتحديث عنوان URL.
ثم يحدد منطق توجيه العميل (client routing logic) التحديثات التي يجب أن تحدث لواجهة المستخدم ويحدّثها يدويًا، بما في ذلك عرض أي حالات معلّقة (تفاعلات واجهة المستخدم) أثناء تقديم مكتبة جلب البيانات طلب شبكة (network request) إلى نقطة وصول الخادوم.
يستدعي منطق توجيه الخادوم كود جلب البيانات لاسترداد البيانات من كود التخزين ويرسل ذلك على صورة استجابة (مثل XML أو JSON، والذي علينا اختيار من بينها) وهو الذي يستخدمه العميل بعد ذلك لتحديثات واجهة المستخدم النهائية باستخدام منطق العرض خاصته.
طلبات التغيير: عندما يرسل المستخدم نموذجًا (submit form)، يمنع منطق تغيير البيانات من جانب العميل التحديث الافتراضي للصفحة كاملة وسلوك النشر (post behavior)، ويستخدم JavaScript لسَلْسَلَة النموذج وإرسال البيانات إلى نقطة وصول الخادوم.
ثم يستدعي منطق توجيه الخادوم دالة تعديل البيانات، والتي تتفاعل مع كود التخزين للتعديل، وتستجيب بالبيانات المحدثة للعميل.
سيستخدم منطق تقديم العميل تلك البيانات المحدثة لتحديث واجهة المستخدم المحتاجة. في بعض الحالات سيرسل منطق التوجيه من جانب العميل المستخدمَ إلى مكان آخر يؤدي إلى تدفق بيانات مماثل لتدفق التنقل من جانب العميل.
إيجابيات وسلبيات التطبيقات متعددة الصفحات المحسنة تدريجيًا
لقد حللنا بالتأكيد مشكلات التطبيقات متعددة الصفحات من خلال جلب كود من جانب العميل وتحمّل مسؤولية تفاعل واجهة المستخدم على عاتقنا. لدينا قدر أكبر من التحكم ويمكننا أن نمنح المستخدمين إحساسًا أكثر قربًا من تجربة التطبيقات.
لسوء الحظ، لمنح المستخدمين أفضل تجربة يبحثون عنها، يجب أن نكون مسؤولين عن التوجيه (routing) وجلب البيانات (data fetching) والتعديلات (mutations)، ومنطق العرض (rendering logic). هناك بعض المشاكل مع هذا الأسلوب:
- المنع الافتراضي (Prevent default): نحن لا نصل لمستوى جودة المتصفح فيما يتعلق بالتوجيه وتقديم النموذج (form submission). لم يكن تحديث البيانات على الصفحة مصدر اهتمام من قبل، ولكنه الآن يمثل أكثر من نصف الأكواد من جانب العميل. أيضًا، تعد حالات التعارض (race conditions) وإعادة إرسال النماذج (form resubmissions) ومعالجة الأخطاء أماكن تعشعش تحتها الأخطاء.
- كود مخصص: هناك الكثير من الأكواد التي يجب إدارتها والتي لم يكن علينا كتابتها من قبل. أعلم أن الارتباط لا يعني السببية، لكنني لاحظت أنه عمومًا كلما زاد عدد الأكواد، زادت الأخطاء.
- تكرار الكود: يوجد الكثير من تكرار الكود فيما يتعلق بمنطق التقديم (rendering logic). يحتاج كود العميل إلى تحديث واجهة المستخدم بالطريقة نفسها التي يعرض بها كود الواجهة الخلفية كل حالة ممكنة بعد حدوث تعديل أو انتقال للمستخدم.
لذلك يجب أن تكون واجهة المستخدم نفسها المتوفرة في الواجهة الخلفية متاحة أيضًا في الواجهة الأمامية. وفي معظم الأوقات، تكون هذه اللغات البرمجية مختلفة تمامًا، مما يجعل مشاركة الكود غير ممكن.
ولا يتعلق الأمر بالقوالب فحسب، بل بالمنطق أيضًا. التحدي هو: "إجرِ تفاعلًا من جانب العميل، ثم تأكد من أن واجهة المستخدم التي حُدّثت من قبل كود العميل هي نفس ما كان سيحدث لو حُدُثت الصفحة كاملة." من الصعب جدًا القيام بذلك (هناك موقع يستخدمه مطورو البرامج بشكل منتظم وهو تطبيق متعدد الصفحات المحسنة تدريجيًا وغالبًا لا يفعل ذلك كما يجب).
- تنظيم الكود: يصعب تنظيم الكود للغاية مع التطبيقات متعددة الصفحات المحسنة تدريجيًا. مع عدم وجود مكان مركزي لتخزين البيانات أو عرض واجهة المستخدم، كان الأشخاص يحدّثون يدويًا DOM في أي مكان تقريبًا، وكان من الصعب جدًا تتبع الكود، مما أدى إلى بطء التطوير
- المراوغة بين الخادوم/العميل: هناك انتقالات غير مباشرة بين مسارات واجهة برمجة التطبيقات (API) وجلب البيانات من جانب العميل، وكود تغيير البيانات الذي يستخدمها.
يتطلب التغيير على جانب واحد من الشبكة تغييرًا على الجانب الآخر، وهذه المراوغة تجعل من الصعب الاطمئنان أننا لم نفسد أي شيء لأن مسارات الأكواد التالية تتضمن الخوض في سلسلة من الملفات.
أصبحت الشبكة حاجزًا تسبب في هذا المراوغة بنفس الطريقة التي يستخدم بها الثعلب النهر للتخلص من رائحة كلب الصيد.
من الناحية الشخصية، كان هذا هو الوقت الذي دخلت فيه إلى عالم تطوير الويب. أتذكره هذه المَرّة بمزيج من الحنين إلى الماضي والخوف.
تطبيقات الصفحة الواحدة (SPAs)
لم يستغرق الأمر وقتًا طويلاً قبل أن ندرك أنه يمكننا إزالة مشكلات الازدواج إذا قمنا بحذف كود واجهة المستخدم من الواجهة الخلفية. إذ هذا فعلًا ما فعلناه
ستلاحظ أن هذا الرسم مطابق تقريبًا لرسم التطبيقات المتعددة الصفحات المحسنة تدريجيًا. الاختلاف الوحيد هو أن اختفاء منطق التقديم ( rendering logic). اختفى بعض أكواد التوجيه أيضًا لأننا لم نعد بحاجة إلى مسارات لواجهة المستخدم.
كل ما تبقى لنا هو مسارات واجهة التطبيقات (API). هذا هو عصر تقنيات Backbone و Knockout و Angular و Ember و React و Vue و Svelte وما إلى ذلك. هذه هي الاستراتيجية السائدة في عالم البرمجيات اليوم.
السلوكيات المعمارية لتطبيقات الصفحة الواحدة
نظرًا لأن الواجهة الخلفية لم تعد تحتوي على منطق عرض، تُقّدم جميع طلبات المستندات (أول طلب يقدمه المستخدم عند إدخال رابط URL) بواسطة خادوم ملفات ثابت، والذي عادةً ما يكون عبر شبكات توزيع المحتوى (CDN).
في الأيام الأولى لتطبيقات الصفحة الواحدة (SPAs)، كان مستند HTML دائمًا عبارة عن ملف HTML فارغ مع وسم <div id ="root"> </div>
في وسم <body>
والذي سيستخدم لـ "ربط" الطلب. ومع ذلك، تسمح لنا الأطر هذه الأيام بتقديم أكبر قدر ممكن من الصفحة كما نعرفه في وقت الإنشاء باستخدام تقنية تُعرف باسم "توليد المواقع الساكنة" (SSG).
السلوكيات الأخرى في هذه الاستراتيجية هي نفسها كما هي مع التطبيقات متعددة الصفحات المحسّنة تدريجيًا. الآن فقط نستخدم في الغالب fetch
بدلاً من XMLHttpRequest
.
إيجابيات وسلبيات تطبيقات الصفحة الواحدة
المثير للاهتمام هو أن الاختلاف الوحيد عن التطبيقات متعددة الصفحات المحسّنة تدريجيًا (PEMPAs) في السلوكيات المعمارية أعلاه هو أن طلب المستند أسوأ! فلماذا فعلنا هذا!؟
إلى حد بعيد فإنّ أكبر إيجابية هنا هي تجربة المطوّر. كانت هذه هي الدافع الأصلي للانتقال من التطبيقات متعددة الصفحات المحسنة تدريجيًا إلى تطبيقات الصفحة الواحدة في المقام الأول.
كان عدم وجود ازدواجية في الأكواد فائدة كبيرة. لقد برّرنا هذا التغيير بوسائل مختلفة، فإن تجربة المطور (DX) هي مدخل إلى تجربة المستخدم (UX) بعد كل شيء. لسوء الحظ، فإن تحسين تجربة المطور (DX) هو كل ما فعلته لنا تطبيقات الصفحة الواحدة بالفعل.
أتذكر أنني كنت مقتنعًا بأن معمارية تطبيقات الصفحة الواحدة (SPA) ساعدت في الأداء المتصور لأن شبكات توزيع المحتوى (CDN) يمكن أن تستجيب بمستند HTML أسرع مما يمكن للخادوم أن يولده، ولكن في السيناريوهات الواقعية لا يبدو أنها تحدث فرقًا (وهذا أقل صحة بفضل البنية التحتية الحديثة). الحقيقة المحزنة هي أن تطبيقات الصفحة الواحدة (SPAs) ما تزال لديها نفس المشكلات الأخرى مثل التطبيقات المتعددة الصفحات المحسنة تدريجيًا (PEMPAs)، وإن كان ذلك باستخدام أدوات أكثر حداثة تجعل التعامل مع الأمور أسهل بكثير.
ومما زاد الطين بِلَّة، تسببّت تطبيقات الصفحة الواحدة (SPA) أيضًا بعدة مشاكل جديدة:
- حجم الحزمة: ازدادت ازديادًا هائلًا. اقرأ المزيد حول تأثير JavaScript على أداء صفحة الويب في هذه المقالة الشاملة على Web Almanac.
- أسلوب الشلالات: نظرًا لأن جميع الأكواد لجلب البيانات موجودة الآن داخل حزمة JavaScript، يتعيّن علينا الانتظار حتى يكتمل تنزيلها قبل أن نتمكن من جلب البيانات.
وهذا يفاقم الحاجة إلى الاستفادة من تقسيم الكود والتحميل البطيء (lazy-loading) لهذه الحزم، والآن لدينا حالة تبعية حرجة مثل هذا: document
→ app.js
→ page.js
→ component.js
→ data.json
→ image.png
. هذا ليس جيدًا ويؤدي في النهاية إلى تجربة مستخدم أسوأ بكثير.
بالنسبة للمحتوى الساكن، يمكننا تجنّب الكثير من هذا، ولكن هناك مجموعة كاملة من المشكلات والقيود مع تلك التي يعمل عليها مقدمو استراتيجيات توليد المواقع الساكنة (SSG) ويسعدهم بيع حلولهم المخصصة.
- أداء وقت التشغيل: مع وجود الكثير من JavaScript من جانب العميل يجب تشغيله، فإن بعض الأجهزة منخفضة الطاقة تكافح من أجل مواكبة ذلك. اقرأ: The Cost Of JavaScript. ما كان يعمل على خواديمنا القوية من المتوقع الآن أن يعمل على أجهزة الكمبيوتر المصغرة للأشخاص في أيديهم. أعلم أننا أرسلنا أشخاصًا إلى القمر بقوة حاسوبية أقل، لكن ما تزال هذه مشكلة.
- إدارة الحالة (state management): أصبحت هذه مشكلة كبيرة. دليلًا على ذلك، فأنا أعرض عدد المكتبات المتاحة لحل هذه المشكلة 😩.
من قبل، كانت التطبيقات متعددة الصفحات (MPA) تعرض حالتنا في DOM وسنقوم فقط بالإشارة/تغيير ذلك. نحن الآن نحصل للتو على JSON وعلينا ألا نسمح فقط للواجهة الخلفية بمعرفة متى يحصل تحديث البيانات، ولكن أيضًا نحافظ على التمثيل في الذاكرة لتلك الحالة محدثًا.
يحتوي هذا على جميع علامات تحديات التخزين المؤقت (caching)؛ لأن هذا هو ما هو عليه، والتي تعد واحدة من أصعب المشكلات في البرمجيات.
في تطبيقات الصفحة الواحدة النموذجية، تمثل إدارة الحالة 30-50٪ من الكود الذي يعمل عليها الأشخاص (يحتاج هذا الإحصاء إلى ذكر مصدر الإحصائية، لكنك تعلم أنه صحيح).
أنشئت مكتبات للمساعدة في معالجة هذه المشاكل وتقليل تأثيرها. لقد كان هذا مفيدًا إلى درجة كبيرة، لكن البعض قد يسمي هذا بالإعياء. أصبحت هذه الطريقة القياسية الفعلية لإنشاء تطبيقات الويب منذ منتصف العقد الأول من القرن الحادي والعشرين. نحن في عام 2020 (في وقت كتابة المقال) وهناك بعض الأفكار الجديدة في الأفق.
تطبيقات الصفحة الواحدة المحسنة تدريجيًا (PESPAs)
لدى التطبيقات متعددة الصفحات نموذج ذهني بسيط. تمتلك تطبيقات الصفحة الواحدة (SPA) قدرات أكثر قوة. الناس الذين مروا بمرحلة التطبيقات متعددة الصفحات (MPA) ويعملون في تطبيقات الصفحة الواحدة (SPA) يأسفون حقًا على البساطة التي فقدناها في المرحلة الماضية. هذا مثير للاهتمام بشكل خاص إذا كنت تفكر في حقيقة أن الدافع وراء معمارية التطبيقات ذات الصفحة الواحدة (SPA) كان في المقام الأول تحسين تجربة المطور عن التطبيقات متعددة الصفحات المحسنة تدريجيًا (PEMPAs).
إذا تمكنا بطريقة ما من دمج التطبيقات ذات الصفحة الواحدة (SPA) والتطبيقات متعددة الصفحات (MPAs) في معمارية واحدة للحصول على أفضل ما في كليهما، فإننا نأمل أن يكون لدينا شيء بسيط وأكثر قدرة. هذا هو المقصود بتطبيقات الصفحة الواحدة المحسنة تدريجيًا.
ضع في اعتبارك أنه باستخدام التحسين التدريجي، فإن الأساس هو تطبيق يعمل، حتى بدون JavaScript من جانب العميل. لذلك إذا كان إطار العمل يمكّن ويشجع على التحسين التدريجي بوصفه مبدأ أساسيًا، فإن أساس تطبيقنا يأتي مع الأساس المتين للنموذج الذهني البسيط للتطبيقات متعددة الصفحات. على وجه التحديد، النموذج الذهني للتفكير في الأشياء في سياق دورة الطلب/الاستجابة. هذا يسمح لنا بالتخلص إلى حد كبير من مشاكل تطبيقات الصفحة الواحدة (SPA).
هذا يشدد التركيز أن: الفائدة الأساسية للتحسين التدريجي ليس أن "تطبيقك يعمل بدون JavaScript" (على الرغم من أن هذه ميزة جانبية جيدة) ولكن النموذج الذهني أسهل كثيرًا. فلنكمل القراءة..
للقيام بذلك، تحتاج تطبيقات الصفحة الواحدة المحسنة تدريجيًا (PESPAs) إلى "محاكاة المتصفح" عندما تمنع التعامل الافتراضي. لذا، يعمل كود الخادوم بنفس الطريقة بغض النظر عما إذا كان المتصفح يرسل طلبًا أو طلب جلب (fetch) مبني على JavaScript.
لذلك بينما لا نزال نمتلك هذا الكود، يمكننا الاحتفاظ بالنموذج الذهني السهل في بقية أكوادنا. جزء مهم من هذا هو أن تطبيقات الصفحة الواحدة المحسنة تدريجيًا (PESPAs) تحاكي سلوك المتصفح لإعادة التحقق من البيانات على الصفحة عند إجراء تعديلات للحفاظ على البيانات الموجودة على الصفحة محدثة.
مع التطبيقات متعددة الصفحات (MPAs)، حصلنا للتو على إعادة تحميل صفحة كاملة. مع تطبيقات الصفحة الواحدة المحسّنة تدريجيًا (PESPAs)، تحدث إعادة التحقق هذه مع طلبات الجلب (fetch requests).
تذكر أننا واجهنا مشكلة كبيرة مع التطبيقات متعددة الصفحات المحسنة تدريجيًا (PEMPA) كذلك: تكرار الكود. تحل تطبيقات الصفحة الواحدة المحسنة تدريجيًا (PESPAs) هذه المشكلة عن طريق جعل الكود لواجهة المستخدم الخلفية وكود واجهة المستخدم الأمامية هي نفسها تمامًا. باستخدام مكتبة واجهة مستخدم قادرة على العرض على الخادوم والتفاعل مع التحديثات على العميل، فلن نواجه مشكلات تكرار الكود.
ستلاحظ في الشكل أعلاه وجود مربعات صغيرة لجلب البيانات والتعديل والعرض. هذه الأجزاء وُجدت من أجل التحسين. مثلًا، الحالات المعلّقة (pending states) وواجهة المستخدم المتفائلة (optimistic UI) وما إلى ذلك ليس لها مكان على الخادوم، لذلك سيكون لدينا بعض الأكواد التي تعمل فقط على جانب العميل. ولكن حتى مع ذلك، مع مكتبات واجهة المستخدم الحديثة، فإن الموقع المشترك الذي نحصل عليه يجعله قابلاً للاستمرار.
السلوكيات المعمارية لتطبيقات الصفحة الواحدة المحسنة تدريجيًا (PESPA)
طلبات المستندات مع التطبيقات متعددة الصفحات المحسنة تدريجيًا (PEMPAs) متطابقة تطابقًا فعّالًا مع تطبيقات الصفحة الواحدة المحسّنة تدريجيًا (PEMPAs). يُرسل الـ HTML الأولي المطلوب للتطبيق مباشرة من الخادوم وتُحمّل JavaScript لتحسين تجربة تفاعلات المستخدم.
التنقل من جانب العميل: عندما ينقر المستخدم على رابط، سنمنع السلوك الافتراضي. سيحدد الموجّه (router) البيانات وواجهة المستخدم اللازمة للمسار الجديد ويطلق جلب البيانات لأي بيانات يحتاجها المسار التالي ويعرض واجهة المستخدم التي تُعرض لهذا المسار.
*طلبات التغيير:** هل لاحظت أن هذين المخطّطَيْن متماثلان؟ نعم! هذا ليس صدفة! يجري التعديل باستخدام تطبيقات الصفحة الواحدة المحسنة تدريجيًا (PESPAs) عبر عمليات إرسال النماذج (form submissions). لا مزيد من هذا الهراء "onClick" \ + `fetch" (ومع ذلك ، فإن التعديلات الحتمية جيدة للتحسين التدريجي مثل إعادة التوجيه إلى شاشة تسجيل الدخول عند انتهاء مهلة جلسة المستخدم).
عندما يرسل المستخدم نموذجًا، سنمنع السلوك الافتراضي. يقوم كود التعديل بسَلْسَلَة النموذج وإرساله بوصفه طلبًا إلى المسار المرتبط بـ "الإجراء" الخاص بالنموذج (والذي يُعيّن افتراضيًا على رابط URL الحالي).
يستدعي منطق التوجيه الموجود على الواجهة الخلفية كود الإجراء الذي يتواصل مع كود التخزين لإجراء التحديث ويرسل استجابة ناجحة (على سبيل المثال: إعجاب بتغريدة) أو إعادة التوجيه (على سبيل المثال: إنشاء مستودع GitHub جديد) إذا كانت إعادة توجيه، يقوم منطق التوجيه بتحميل الأكواد/البيانات/الملفات المساعدة لهذا المسار (بالتوازي) ثم يُشغّل منطق العرض.
أما إذا لم تكن إعادة توجيه، فإن منطق التوجيه يعيد التحقق من البيانات لواجهة المستخدم الحالية ويطلق منطق العرض لتحديث واجهة المستخدم. من المثير للاهتمام، بغض النظر عمّا إذا كان تعديلًا مضمّنًا أو إعادة توجيه، فإن منطق التوجيه مشارك فيه، مما يمنحنا نفس النموذج الذهني لكلا النوعين من التعديلات.
إيجابيات وسلبيات تطبيقات الصفحة الواحدة المحسنة تدريجيًا (PESPA)
تقضي تطبيقات الصفحة الواحدة المحسنة تدريجيًا (PESPAs) على الكثير من المشاكل من المعماريات السابقة. دعونا نلقي نظرة عليها واحدة تلو الأخرى:
مشاكل التطبيقات متعددة الصفحات (MPA):
- التحديثات الكاملة للصفحة (full-page refreshes): تمنع تطبيقات الصفحة الواحدة المحسنة تدريجيًا (PESPAs) السلوك الافتراضي وبدلاً من ذلك تستخدم JavaScript من جانب العميل لمحاكاة المتصفح. من منظور الكود الذي نكتبه، لا يبدو هذا مختلفًا عن التطبيقات متعددة الصفحات (MPA)، ولكن من وجهة نظر المستخدم، إنها تجربة محسّنة كثيرًا.
- التحكم في تفاعل واجهة المستخدم: تسمح لنا تطبيقات الصفحة الواحدة المحسنة تدريجيًا (PESPA) بالتحكم الكامل في طلبات الشبكة لأننا نمنع السلوك الافتراضي ونقدم طلبات الجلب (fetch requests)، وبالتالي يمكننا تزويد المستخدمين بالتفاعل بأي طريقة تكون أكثر منطقية لواجهة المستخدم.
مشاكل التطبيقات متعددة الصفحات المحسنة تدريجيًا:
- منع السلوك الافتراضي: يتمثل أحد الجوانب الأساسية لتطبيقات الصفحة الواحدة المحسنة تدريجيًا (PESPAs) في أنها يجب أن تتصرف بنفس الطريقة التي يتصرف بها المتصفح فيما يتعلق بالتوجيه (routing) والنماذج (forms). هذه هي الطريقة التي ينجزون بها إعطائنا النموذج الذهني للتطبيقات متعددة الصفحات (MPA).
يُعد إلغاء الطلبات من عمليات إعادة إرسال النماذج، والتعامل مع الاستجابات خارج الترتيب بشكل صحيح لتجنّب مشكلات حالة التعارض، وظهور الأخطاء لتجنب الأقراص الدوارة (spinners) التي لا تختفي أبدًا جزءًا مما يجعل تطبيقات الصفحة الواحدة (PESPA) جزءًا أصيلًا من تكوينها. هذا هو المكان الذي يساعد فيه إطار العمل حقًا.
- كود مخصص: من خلال مشاركة الكود بين العميل والخادوم والحصول على التجريد الصحيح التي يحاكي سلوك المتصفح، ينتهي بنا الأمر إلى تقليل مقدار الأكواد التي يتعين علينا كتابتها بأنفسنا بشكل كبير.
- تكرار الكود: جزء من فكرة تطبيقات الصفحة الواحدة المحسنة تدريجيًا (PESPA) هو أن الخادوم والعميل يستخدمان الكود نفسه لتقديم المنطق. لذلك ليس هناك ازدواجية يمكن الحديث عنها. لا تنس التحدي: "اجرِ تفاعلًا من جانب العميل، ثم تأكد من أن واجهة المستخدم المحدثة تلقائيًا بواسطة العميل هي نفسها التي نحصل عليها إذا حدّثنا الصفحة". مع تطبيقات الصفحة الواحدة المحسنة تدريجيًا (PESPA)، يجب أن تُمرّر دائمًا دون جهد أو اعتبار من جانب المطورين.
- تنظيم الكود: نظرًا للنموذج الذهني الذي توفره تطبيقات الصفحة الواحدة المحسنة (PESPAs) فيما يتعلّق بمحاكاة المتصفح، فإن إدارة حالة التطبيق ليست في الحسبان. ويتم التعامل مع متحكّم العرض بالطريقة نفسها على جانبي الشبكة، لذلك لا توجد تعديلات عشوائية في الـ DOM أيضًا.
- المراوغة بين الخادوم/العميل: إن محاكاة تطبيقات الصفحة الواحدة المحسّنة (PESPA) للمتصفح تعني أن كود الواجهة الأمامية وكود الواجهة الخلفية متلازمان مما يلغي المراوغة ويرفع إنتاجيتنا.
مشاكل تطبيقات الصفحة الواحدة (SPA)
- حجم الحزمة: يتطلب الانتقال إلى تطبيقات الصفحة الواحدة المحسّنة تدريجيًا (PESPA) خادومًا مما يعني أنه يمكننا نقل طنًا من الكود البرمجية إلى الواجهة الخلفية. كل ما تحتاجه واجهة المستخدم هو مكتبة واجهة مستخدم صغيرة يمكن تشغيلها على كل من الخادوم والعميل، وبعض الأكواد للتعامل مع تفاعلات واجهة المستخدم ومردودها، والأكواد للمكونات.
وبفضل تقسيم الأكواد للـ URL (المستند إلى المسار)، يمكننا أخيرًا أن نقول وداعًا لصفحات الويب التي تحتوي على مئات الكيلوبايتات من JavaScript. وفوق ذلك، وبسبب التحسين التدريجي، يجب أن يعمل معظم التطبيق قبل انتهاء تحميل JavaScript على أي حال.
علاوة على ذلك، هناك جهود الآن في أطر JavaScript لتقليص كمية الـ JavaScript المطلوبة في جانب العميل.
- الشلالات (Waterfalls): جزء مهم من تطبيقات الصفحة الواحدة المحسنة تدريجيًا (PESPAs) هو أنها يمكن أن تكون على دراية بالأكواد والبيانات وبمتطلبات الملفات المساعدة لعنوان URL معين دون الحاجة إلى تشغيل أي من الأكواد.
هذا يعني أنه بالإضافة إلى تقسيم الكود، يمكن لـتطبيقات الصفحة الواحدة المحسنة تدريجيًا (PESPAs) تشغيل عملية جلب للكود والبيانات والملفات المساعدة دفعة واحدة بدلاً من انتظار واحد في كل مرة على التوالي. هذا يعني أيضًا أنه يمكنها جلب هذه الأشياء مسبقًا قبل أن يشغّل التنقل بحيث عندما تكون هناك حاجة إلى ذلك، يمكن للمتصفح أن يعيدها على الفور، مما
يجعل تجربة استخدام التطبيق بأكملها فورية.
أداء وقت التشغيل: تمتلك تطبيقات الصفحة الواحدة المحسنة تدريجيًا (PESPA) شيئين في هذا القسم:
- تنقل الكثير من الأكواد إلى الخادوم لذلك هناك كود أقل للأجهزة التي يجب تنفيذها في المقام الأول.
- بفضل التحسين التدريجي، فإن واجهة المستخدم جاهزة للاستخدام قبل انتهاء تحميل JavaScript وتنفيذه.
- إدارة الحالة: بسبب محاكاة المتصفح التي تعطينا نموذج MPA الذهني، فإن إدارة حالة التطبيق ليست مصدر قلق في تطبيقات الصفحة الواحدة المحسنة تدريجيًا (PESPA). والدليل على ذلك هو حقيقة أن التطبيق يجب أن يعمل في الغالب بدون JavaScript على الإطلاق. تقوم هذه التطبيقات المحسنة تلقائيًا بإعادة التحقق من البيانات الموجودة على الصفحة عند اكتمال التعديلات (حصلت التطبيقات متعددة الصفحات (MPAs) على ذلك مجانًا بفضل إعادة تحميل الصفحة كاملة).
من المهم الإشارة إلى أن تطبيقات الصفحة الواحدة المحسنة تدريجيًا (PESPAs) لن تعمل بالطريقة نفسها مع وبدون JavaScript من جانب العميل. هذا ليس هدف التحسين التدريجي على أي حال. فقط أن معظم التطبيق يجب أن يعمل بدون JavaScript. وهذا ليس فقط لأننا نهتم بتجربة مستخدم sans-JavaScript.
يرجع السبب في ذلك إلى أننا من خلال استهداف التحسين التدريجي، قمنا بتبسيط كود واجهة المستخدم تبسيطًا كبيرًا. ستندهش من المدى الذي يمكننا الوصول إليه بدون JavaScript، ولكن بالنسبة لبعض التطبيقات، ليس من الضروري أو العملي أن يعمل كل شيء بدون JavaScript من جانب العميل. ولكن لا يزال بإمكاننا جني الفوائد الأساسية لتطبيقات الصفحة الواحدة المحسنة تدريجيًا (PESPAs) حتى لو كانت بعض عناصر واجهة المستخدم تتطلب بعض JavaScript للعمل.
ما الذي يميّز تطبيقات الصفحة الواحدة المحسّنة تدريجيًا (PESPA):
- أداء العمل هو الأساس، أما الـ JavaScript المستخدمة هي للتحسين لا التمكين.
- التحميل البطيئ (lazy loading) + الجلب المسبق الذكي (أكثر من مجرد كود JavaScript).
- يدفع الكود إلى الخادوم.
- لا يوجد تكرار يدوي لكود المستخدم، عكس ما هو الحال في التطبيقات متعددة الصفحات المحسنة تدريجيًا (PEMPAs).
- محاكاة متصفح شفافة (#useThePlatform)
أما بالنسبة للسلبيات. ما زلنا نكتشف ماهي. لكن إليك بعض الأفكار وردود الفعل الأولية:
كثير من المعتادين على تطبيقات الصفحة الواحدة (SPA) ومولّدات المواقع الساكنة (SSG) سوف يأسفون لأن لدينا الآن كود من جانب الخادوم يشغّل تطبيقنا. ومع ذلك، بالنسبة إلى أي تطبيق في العالم الحقيقي، لا يمكننا تجنب الكود من جانب الخادوم.
هناك بالتأكيد بعض حالات الاستخدام حيث يمكننا إنشاء الموقع بالكامل مرة واحدة ووضعه على شبكة توزيع المحتوى (CDN)، لكن معظم التطبيقات التي نعمل عليها في وظائفنا اليومية لا تندرج ضمن هذه الفئة.
يرتبط بهذا الأشخاص القلقون بشأن تكلفة الخادوم. الفكرة هي أن مولدات المواقع الساكنة (SSG) تسمح لنا ببناء تطبيقنا مرة واحدة ثم تقديمه عبر شبكة توصيل المحتوى (CDN) إلى عدد لا حصر له من المستخدمين بتكلفة منخفضة جدًا.
هناك عيبان في هذا النقد:
- من المحتمل أننا نصل إلى واجهات برمجة التطبيقات (API) في تطبيقنا، لذلك سيستمر هؤلاء المستخدمون في تشغيل الكثير من الأكواد الأكثر تكلفة من جانب الخادوم في زياراتهم على أي حال.
- تدعم شبكات توصيل المحتوى (CDN) آليات التخزين المؤقت لـ HTTP، لذلك إذا كنا قادرين حقًا على استخدام مولدات المواقع الساكنة (SSG)، فيمكننا بالتأكيد الاستفادة من ذلك لتقديم استجابات سريعة، والحد من حجم العمل الذي يتعامل معه خادوم العرض.
هناك مشكلة أخرى شائعة لدى الأشخاص مع مغادرة تطبيقات الصفحة الواحدة (SPAs) وهي أنه يتعين علينا الآن التعامل مع تحديات العرض على الخادوم.
يعد هذا بالتأكيد نموذجًا مختلفًا للذين اعتادوا تشغيل أكوادهم على جانب العميل فقط، ولكن إذا كنا نستخدم الأدوات التي أخذت هذا في الحسبان، فلن يمثّل ذلك تحديًا. إذا لم نكن كذلك، فيمكن أن يمثّل ذلك تحديًا بالتأكيد، ولكن هناك حلول معقولة لإجبار كود معين على تشغيل جانب العميل فقط أثناء الترحيل (migrate)
كما قلت، ما زلنا نكتشف سلبيات تطبيقات الصفحة الواحدة المحسّنة تدريجيًا، لكنني أعتقد أن الفوائد تستحق المقايضات التي يمكننا إدراكها حتى الآن.
يجب أن أذكر أيضًا أنه على الرغم من أن لدينا إمكانات معمارية تطبيقات الصفحة الواحدة المحسنة تدريجيًا (PESPA) لبعض الوقت مع الأدوات الحالية، إلا أن التركيز على التحسين التدريجي مع مشاركة كود منطقي للتقديم يعد أمرًا جديدًا. يهتم هذا المنشور اهتمامًا أساسيًا بإظهار المعماريات القياسية الواقعية، وليس فقط إمكانات النظام الأساسي.
تطبيق عملي لتطبيقات الصفحة الواحدة المحسنة تدريجيًا: Remix
تقود تكلفة تطبيقات الصفحة الواحدة المحسنة تدريجيًا PESPAs Remix، وهو إطار ويب يركز تركيزًا على أساسيات الويب وتجربة المستخدم الحديثة. Remix هو أول إطار عمل ويب مُعد ومجهّز بكل ما وصفته في عرض تطبيقات الصفحة الواحدة المحسنة تدريجيًا (PESPA). يمكن لأطر العمل الأخرى أن تتكيف وقد صارت تتكيف لتتبع قيادة Remix في هذا الشأن. أنا على دراية بكل من SvelteKit و SolidStart التي تُعمِل مبادئ تطبيقات الصفحة الواحدة المحسنة تدريجيًا (PESPA) في تطبيقاتها. أتخيل أن المزيد سيتبع ذلك.. (مرة أخرى، كانت الأطر الوصفية قادرة على هندسة تطبيقات الصفحة الواحدة المحسنة تدريجيًا (PESPA) لبعض الوقت، ومع ذلك فقد وضع Remix هذه المعمارية في المقدمة والبعض الآخر يتبع المجموعة). إليك كيف تبدو الأمور عندما يكون لدينا إطار عمل ويب لتطبيقات الصفحة الواحدة المحسنة تدريجيًا (PESPA):
في هذه الحالة، تعمل Remix جسرًا عبر الشبكة. بدون Remix سيتعين علينا تنفيذ هذا بأنفسنا للحصول على تطبيقات الصفحة الواحدة المحسّنة تدريجيًا (PESPA) بصورة كاملة.
تتعامل Remix أيضًا مع التوجيه عبر مجموعة من التوجيه القائم على الاتفاقية والقائم على التكوين. ستساعد Remix أيضًا في البتات (bits) المحسّنة تدريجيًا في جلب البيانات والتعديلات (مثل زر الإعجاب في تويتر) وتفاعل واجهة المستخدم لتنفيذ أشياء مثل الحالات المعلقة وواجهة المستخدم المتفائلة (optimistic UI).
بفضل التوجيه المتداخل المضمن في Remix، لدينا تنظيم أفضل للكود أيضًا (شيء تسعى له Next.js أيضًا). في حين أن التوجيه المتداخل ليس مطلوبًا لمعمارية تطبيقات الصفحة الواحدة المحسّنة تدريجيًا (PESPA) على وجه التحديد، فإن تقسيم الكود المستند إلى المسار يعد جزءًا مهمًا. أيضًا، لدينا تقسيم أكثر دقة للكود باستخدام التوجيه المتداخل، لذا فهو جانب مهم.
تعرض Remix أنه يمكننا الاستمتاع أكثر ببناء تجارب أفضل بشكل أسرع باستخدام معمارية تطبيقات الصفحة الواحدة المحسّنة تدريجيًا (PESPA). وانتهى بنا الأمر بمواقف مثل هذه:
نتيجة مثالية لمعيار lighthouse دون محاولة؟ أشركني!
خاتمة
أنا شخصياً متطلع هنا من أجل هذا التحوّل. يعد الحصول على تجربة استخدام (UX) وتجربة تطوير (DX) أفضل في نفس الوقت فوزًا قويًا. أعتقد أنه أمر مهم وأنا متحمّس لما يخبئه المستقبل لنا.
مكافأة لك لإنهاء منشور المدونة هذا، فقد أنشأت مستودعًا يوضّح كل هذه الأكواد التي تتحرك عبر الزمن باستخدام تطبيق مهام TodoMVC! يمكنك العثور عليها هنا: kentcdodds/the-webs-next-transform. نأمل أن تساعد في جعل بعض الأفكار أكثر واقعية.
وهذا ما يسعدني أن أعلمك إياه هنا على EpicWeb.dev. إذا كنت ترغب في متابعة تقدمي هنا، يرجى وضع بريدك الإلكتروني في النموذج أدناه. لنجعل الويب أفضل 🎉
Cheers!
تحياتي!
ترجمة -وبتصرف- للمقال The Web’s Next Transition لصاحبه Kent C. Dodds بـمساعدة الأخ واثق الشويطر.
شكرا وامتنان لكل من راجع الترجمة (القائمة أبجدية):
- د. طه زروقي
- عبداللطيف الشريف
- عمر شريف
- فراس طامش
- محمد عبدالكريم