-
المساهمات
164 -
تاريخ الانضمام
-
تاريخ آخر زيارة
نوع المحتوى
ريادة الأعمال
البرمجة
التصميم
DevOps
التسويق والمبيعات
العمل الحر
البرامج والتطبيقات
آخر التحديثات
قصص نجاح
أسئلة وأجوبة
كتب
دورات
كل منشورات العضو ابراهيم الخضور
-
تعرفنا في المقال السابق على طريقة ضبط اﻹعدادات البسيطة لشبكات الاتصال المختلفة، كما تعلمنا ضبط إعدادات مظهر سطح المكتب والمواضيع المتعلقة به. نتابع في هذا المقال استكشاف بقية اﻹعدادات التي تختص بإدارة التطبيقات المثبتة وإدارة حسابات المستخدمين. إعدادات خاصة بالتطبيقات افتح تطبيق "اﻹعدادات"، وانتقل منه إلى خيار "التطبيقات". عند النقر على هذا الخيار، سيعرض لك الشريط الجانبي لنافذة اﻹعدادات جميع التطبيقات المثبتة على حاسوبك. انقر اﻵن على أي تطبيق، وستظهر لك نافذة مشابهة للنافذ التالية: تتكون النافذة من قسمين رئيسيين: التكامل: وتعرض مجموعة موارد النظام التي يمكن لهذا التطبيق الوصول إليها. نلاحظ أن أغلب التطبيقات يمكنها فقط عرض تنبيهاتها ورسائلها للمستخدم. وإن أردت إلغاء التنبيهات التي يعرضها تطبيق ما، فانقر على الزالقة المجاور لحقل التنبيهات. المناولات المبدئية: يعرض هذا القسم مجموعة الملفات التي يمكن لهذا التطبيق فتحها، باﻹضافة إلى الروابط التي يمكنه الاتصال بها وتنزيل البيانات منها. تعرض الصورة التالية الملفات المبدئية لتطبيق "الملفات": لاحظ أن التطبيق قادر على فتح المجلدات العادية و 19 نوعًا من الأرشيفات (المجلدات المضغوطة). وﻹزالة أي نوع من هذه اﻷنواع لأسباب تتعلق بك (كأن تفضل أن تُفتح من قبل تطبيق آخر)، انقر على الزر" أزل" إلى جوار نوع الملفات أو اﻷرشيفات الذي لا تريد لهذا التطبيق فتحه. ولكي تطلع على تفاصيل أكثر عن التطبيق الذي اخترته، انقر على زر "افتح في البرمجيات" أعلى النافذة ضمن شريط المهام ليفتح بدوره تطبيق "برمجيات" الذي يعرض لمحةً عن التطبيق، ويتيح تشغيل التطبيق أو إزالته كليًا من حاسوبك. للخروج من قائمة التطبيقات، انقر على أيقونة التراجع الموجودة أقصى يسار شريط مهام النافذة. إعدادات الخصوصية ويُقصد بها اﻹعدادات التي تساعد المستخدم في منع تجاوز خصوصيته من خلال الاطلاع على موقعه أو مراقبة نشاطه على شبكات الاتصال أو الوصول إلى معلومات حساسة عنه. يتيح لك تطبيق "اﻹعدادات"، إمكانية ضبط بعض اﻹعدادات التي تسهم في المحافظة على خصوصية ما تقوم به على حاسوبك، وسيعرض لك التطبيق هذه الخيارات بمجرد النقر على "الخصوصية": الموصولية يتيح لك هذا الخيار إمكانية تشغيل تطبيق "التحقق من الموصولية connectivity checking"، الذي يتفقد تلقائيًا إعدادات شبكة الاتصال التي تستخدمها ويعالج المشاكل التي تظهر ليبقى اتصالك مستقرًا دائمًا؛ كما يساعد هذا التطبيق في الحصول على معلومات عن أي جهاز ضمن الشبكة يحاول مراقبة اتصالك. لتفعيل هذا التطبيق، انقر على الزالقة المجاورة، فتتحول إلى اللون البنفسجي. وانقر مجددًا ﻹلغاء تفعيله. خدمات التموضع يسمح لك هذا الخيار بإلغاء أو تفعيل تحديد مكانك الحقيقي، إذ تطلب بعض التطبيقات اﻹذن للوصول إلى موقعك الجغرافي الحقيقي لتقديم خدمات معينة. لتفعيل خدمة تحديد الموضع، انقر على الزالقة في شريط أدوات النافذة، وعندها ستظهر لك قائمة بالتطبيقات التي تطلب إذنًا في الوصول إلى موقعك الجغرافي. تاريخ الملفات وسلة المهملات تضم هذه اﻹعدادات قسمين من الخيارات: تاريخ الملفات عندما تعمل على ملف معين، سيسجل النظام ذلك ويحدد موقع هذا الملف في منظومة الملفات، كما يحدد التطبيق الذي أنشأه والتطبيق الذي تستخدمه في تحرير هذا الملف. يشارك النظام هذه السجلات بين جميع التطبيقات لكي يسهل وصولك إلى آخر الملفات التي عملت عليها، والتي قد ترغب في إعادة فتحها. قد يحمل هذا اﻷمر تهديدًا ممكنًا للخصوصية، ولذلك يتيح لك النظام القدرة على ضبط الفترة الزمنية التي يحتفظ فيها بتلك السجلات. وبافتراض أنك الوحيد الذي يستثمر هذا الحاسوب مستخدمًا الحساب الذي ولجت فيه، فإن الخيار الافتراضي هو "أبدًا". أي أن هذه السجلات ستبقى محفوظة إن لم يطرأ خلل ما ولن يجري مسحها. في المقابل ترك لك النظام عدة خيارات أخرى هي: يوم واحد 7 أيام 30 يومًا كما يعطيك خيار الحذف الفوري للسجلات من خلال النقر على زر "مسح السجلات clear history". سلة المهملات والملفات المؤقتة يضبط هذا القسم الفترة الزمنية التي تحتفظ بها سلة المهملات أو مخازن الملفات المؤقتة بمحتوياتها. قد تضم هذه اﻷماكن بعض المعلومات الحساسة التي يمكن استرجاعها من قِبل جهات غير مخولة بالاطلاع عليها، لذلك يعطيك النظام إمكانية الحذف التلقائي لهذه الملفات. ستلاحظ وجود ثلاثة خيارات: الحذف التلقائي لمحتويات سلة المهملات ِAutomaticaaly delete trash content: بالنقر على هذا الخيار ستفعل عملية الحذف التلقائي لمحتويات سلة المهملات. الحذف التلقائي للملفات المؤقتة Automatically delete temporary files: بالنقر على هذا الخيار تفعل عملية الحذف التلقائي للملفات المؤقتة. فترة تنفيذ الحذف التلقائي Automatically delete period: ويحدد الفترة الزمنية التي تبقى فيها الملفات المؤقتة ومحتويات سلة المهملات موجودة قبل أن تحذف تلقائيًا. ستجد أيضًا أسفل النافذة زرين: اﻷول "أفرغ المهملات" لحذف محتويات سلة المهملات مباشرةً، واﻵخر "delete temporary files"، لحذف الملفات المؤقتة مباشرةً. إقفال شاشة المستخدم تُستخدم هذه الميزة عادةً لمنع أيٍّ كان من استخدام حسابك على الجهاز إن غادرت مكان عملك لبرهة وتركته مفتوحًا. إذ تُقفل شاشة سطح المكتب في هذه الحالة ويُطلب إليك إدخال كلمة المرور من جديد حتى يسمح لك بمتابعة العمل. يتيح لك هذا القسم من اﻹعدادات أن تضبط مايلي: زمن تعتيم الشاشة blank screen delay: وهي الفترة الزمنية التي يختفي بعدها سطح المكتب عند ترك العمل، ويمكنك ضبط هذه الفترة "من دقيقة واحدة" إلى "أبدًا" وتعني أن يبقى سطح المكتب ظاهرًا دائمًا. إيصاد تلقائي للشاشة: يقفل النظام الشاشة تلقائيًا إن تركت العمل على حاسوبك فترةً من الزمن. الفترة الزمنية للقفل التلقائي للشاشة Automatic screen lock delay: إن اخترت أن تُقفل الشاشة تلقائيًا، فسيحدد لك هذا الخيار الفترة الذي ينتظرها النظام قبل اﻹيصاد التقائي لها. وتتراوح الخيارات بين 30 ثانية حتى ساعة؛ كما يتيح خيار اﻹيصاد بمجرد أن تنطفئ الشاشة. قفل الشاشة عند تعليق العمل lock screen on suspend: عند تفعيل هذا الخيار سيقفل النظام شاشة سطح المكتب عندما تعلّق العمل على الجهاز (النقر على خيار "علّق" ضمن خيارات اﻹطفاء في شريط المهام الرئيسي)، وبالتالي ستضطر إلى كتابة كلمة السر عندما تعيد تشغيل الجهاز. أظهر التنبيهات على شاشة القفل show notifications on lock screen: يمكن لأي تطبيق عند تفعيل هذا الخيار عرض تنبيهاته ورسائله على الشاشة حتى إن كانت موصدة. إدارة المستخدمين انقر على خيار "المستخدمين" الموجود في الشريط الجانبي لنافذة تطبيق "الإعدادات"، وستظهر النافذة التالية: يتطلب اﻷمر عادةً فك الحظر عن تغيير هذه الإعدادات، وذلك بالنقر على الزر "فك unlock" الموجود في الشريط السماوي أعلى النافذة، ثم يطلب إليك النظام عندها إدخال كلمة السر للاستيثاق منك، وستكون بعدها جاهزًا للتحكم بخيارات مثل: تغيير اسم المستخدم: بالنقر على أيقونة القلم بجانب اسم المستخدم. تغيير كلمة السر: يطلب إليك عندها تزويده بالكلمة القديمة ثم الجديدة وتأكيدها. خيار الولوج التلقائي: سينقلك النظام إلى سطح المكتب مباشرةً عند تشغيل الحاسوب دون المرور بشاشة تسجيل الدخول إن فعّلت هذا الخيار. نشاطات الحساب account activity: ويعرض لك قائمةً بوقتي بداية ونهاية كل جلسة على حاسوبك خلال أسبوع. إضافة مستخدم جديد: انقر على زر "أضف مستخدمًا" في شريط مهام النافذة، وسيعرض لك النظام مربع الحوار التالي: اختر نوع الحساب: عادي أو إداري (إن لم ترغب بإعطاء المستخدم صلاحيات واسعة اختر "عادي"). اكتب اسمك. اكتب اسم المستخدم الذي سيكون نفسه اسم مجلد "المنزل" ولا يمكن تغييره لاحقًا. اختر كلمة سر، ثم أكدها. انقر الزر "أضف". اقرأ أيضًا المقال السابق: إعدادات أوبونتو 20.04: الاتصالات وسطح المكتب تعرّف على سطح مكتب أوبونتو 20.04 التعامل مع المجلدات والملفات في أوبونتو 20.04 تغيير اللغة في نظام لينكس أوبنتو إلى العربية
-
لغات البرمجة هو مفهوم واسع كبير يحتوي على أسماء عدة شتى قد يحتار فيها الداخل الجديد إلى مجال علوم الحاسوب لتعلم البرمجة، فقد يتساءل أي لغة برمجة يجب أن أتعلم أولًا، وما هي أشهر لغة برمجة تُستعمل على نطاق واسع استفيد منها، وما هي أسهل لغة برمجة ابدأ بها وغيرها من الأسئلة المحيرة، فإن فتحت مثلًا قائمة لغات البرمجة على ويكيبيديا فستجد عشرات لغات البرمجة المذكورة وهو ما يزيد المشكلة وهنا لابد من الاستعانة بدليل. يقودك هذا المقال تدريجيًا في جولة سريعة في عالم لغات البرمجة كي تتكون لديك صورة عامة موسّعة عن لغات البرمجة لتكون عونًا لك إن كنت ستتعلم إحداها، وسينتقل بك المقال من شروحات مبسطة لمفهوم لغات البرمجة ومستويات لغة البرمجة وأقسامها إلى أنواعها واستخداماتها سواء لبرمجة الحواسيب أو الأجهزة الذكية أو الأجهزة الإلكترونية وحتى الروبوتات، ثم سنجاوب على بعض الأسئلة الشائعة المتعلقة بلغات البرمجة مثل التي أشرنا إليها قبل قليل في نهاية المقال. ينبغي أن تكوّن في نهاية المقال فكرة واضحة عن ما يُدعى لغة برمجة ولغات البرمجة عمومًا تكون ركيزة صلبة تعتمد عليها في اختيار لغة البرمجة التي تناسب المجال الذي تخطط الدخول له إن أردت تطوير مسارك المهني ودخول عالم البرمجة. إليك فهرس المقال لكي يسهل عليك التنقل بين أقسامه: تعريف البرمجة ما هي لغات البرمجة لغة البرمجة واللغات البشرية أنواع لغات البرمجة لغات برمجة السكربت Scripting Languages اللغات التوصيفية Markup Languages أسئلة شائعة عن لغات البرمجة تعريف البرمجة البرمجة هي العملية التي تستطيع بواسطتها إنجاز فكرة معينة أو حل مشكلة ما عن طريق تقسيم الفكرة أو المشكلة إلى خطوات متتالية قابلة لإعادة التكرار وصولًا إلى النتيجة المطلوبة. فلو سألت أحدهم ما هو ناتج العملية الرياضية التالية 5*(2-3) فقد يعطيك مباشرة الجواب 5 لكن ما فعله الدماغ هو عملية تحليل للمسألة ووضع طريقة لحلها وهذا ما يُدعى بوضع خوارزمية Algorithm. فخوارزمية حل المسألة البسيطة السابقة هي: اطرح 2 من 3 وسجل الجواب: 1 =2-3. احسب جداء الناتج مع العدد 5: 5x1. قل الجواب: 5. وخلاصة القول أن البرمجة هي طريقة لترتيب وتنظيم مسألة ما للحصول على النتيجة بالمعنى العام، أما في عالم الحواسيب فهي وسيلة للتخاطب مع هذه الأجهزة. أما الأسلوب المقترح لتنفيذ هذه الخطوات فهي الخوارزمية، وستكون عندها لغة البرمجة هي الوسيلة التي نخبر فيها الحاسوب أو التجهيزة كيفية تنفيذ الخوارزمية لحل المشكلة المعروضة. ما هي لغات البرمجة؟ لغات البرمجة تشير ببساطة على أنها وسيلة للتواصل بين البشر والحواسب أو بعض التجهيزات أو الآلات المهيأة لتنفيذ برامج متغيرة والتي تُدعى تجهيزات قابلة للبرمجة. ونظرًا للتقدم التكنولوجي الهائل ودخول تقنيات المعلومات إلى مختلف نواحي الحياة، ازداد توجه الصانعين إلى إنتاج تجهيزات قادرة على التخاطب والتفاعل مع المستخدم لتنفيذ وظائف متعددة كالصرافات الآلية ونقاط الخدمة الذاتية والهواتف الذكية وحتى التجهيزات المنزلية والسيارات، وكلما زاد تعقيد هذه التجهيزات وتعددت مهامها احتاجت إلى طريقة فعّالة لتخبرها بما هو مطلوب منها. وهنا تأتي أهمية لغات البرمجة وضرورة وجود أنواع مختلفة من لغات البرمجة وفق سويات مختلفة لتأمين إدارة تلك التجهيزات والتواصل الأمثل معها. إذًا فلغة البرمجة هي مجموعة من التعليمات والتوجيهات التي تكتب أو تُجمّع أو تُركّب ضمن سياق معين كي تنقل بعد معالجتها إلى الجهاز الهدف بغية تنفيذها. ويُقصد بمعالجة لغات البرمجة هو تحويلها من تعليمات مقروءة -في لغات البرمجة المكتوبة Written Programming Languages- أو مرئية بالنسبة للبشر -في لغات البرمجة المرئية Visual programing languages- إلى توجيهات تفهمها الآلة المستهدفة سواء حاسوب أو أية أنظمة إلكترونية أخرى. فما يفهمه الحاسوب هو برنامج مكوّن من الواحدات 1 والأصفار 0 التي تخبره وفقًا لتسلسلها بطريقة محددة سلفًا ما عليه فعله، وتعرف لغة البرمجة التي تُكتب برنامجًا بهذه الطريقة "لغة الآلة" machine language. ونظرًا لصعوبة فهمها للبشر، ظهرت الحاجة إلى لغات برمجة أكثر قربًا من البشر وهنا بدأت الحكاية. تتكون لغة البرمجة -مثلها مثل أي لغة- عمومًا من الأقسام التالية: صياغة لغة البرمجة Syntax هي الطريقة التي نصيغ فيها تعليمات لغة البرمجة ونربطها مع بعضها لإنتاج عبارات صحيحة الصياغة يمكن استخدامها في تنفيذ البرنامج وقد تكون الصياغة: نصية: وتمثل تعليمات اللغة وكلماتها المفتاحية keywords وعباراتها ومتنها. رسومية أو كتلية: تُنظَّم فيها التعليمات التي تؤدي عملًا محددًا ضمن كتلة واحدة، ثم تُمثَّل هذه الكتلة بطريقة مرئية كمربع أو دائرة تُعطى لونا واسمًا يدل على طبيعة العمل الذي تنفذه. ويبنى البرنامج عندها بضم هذه الكتل إلى بعضها لإنجاز الوظيفة المنوطة بالبرنامج. تعطي الصياغة إذًا الشكل العام الصحيح لطريقة كتابة التعليمات بناء على معايير خاصة خارج نطاق مقالنا، وإن أردنا تقريب الأمر فهي بمثابة القواعد النحوية للغات البشر أو اللغات الطبيعية. إذ تُعد مثلًا الجملة "إن المبرمجون مبدعون." في اللغة العربية خاطئة الصياغة لمخالفتها قواعد اللغة ومن المفترض أن نقول" إن المبرمجين مبدعون.". دلالة لغة البرمجة Semantic هي مجموعة قواعد تحدد ما إن كانت طريقة صياغة التعليمات ستعطي النتيجة المرجوة أم لا، وتضع بعض القيود على الصياغة الصحيحة التي قد لا تؤدي إلى نتيجة. لن نخوض كثيرًا في هذه الفكرة لكن سنسهل الأمر عليك عزيزي القارئ: لن تمنعنا أية قاعدة نحوية في اللغة العربية من القول بأنني "أتناول برتقالًا حامضًا لا طعم له" لكن كيف يكون حامضًا ولا طعم له في نفس الوقت! صياغة صحيحة ومدلول لا معنى له. تحديد الأنواع في لغة البرمجة Types وهي الطريقة التي تصنّف فيها لغة البرمجة القيم والتعابير ضمن أنواع مختلفة وكيفية التعامل مع هذه الأنواع والتحويل فيما بينها. فهنالك مثلًا قيم نصية كأن استخدم القيمة "انقر هنا" وقيم عددية كأن استخدم الرقم 5 وقيم منطقية كأن استخدم القيمة "صحيح" true. وقد تكون نتيجة تنفيذ العملية نوعًا محددًا من البيانات كأن تُنتج العملية الحسابية عددًا أو تنتج نصًا. لهذا تحاول معظم اللغات وضع أنواع للقيم التي تتعامل معها. لكن في المقابل ستجد عدة لغات لا تعتمد على الأنواع مثل جافاسكربت JavaScript وماتلاب MatLab. إن وجدت هذا الفكرة غامضة قليلًا لا تكترث وتابع القراءة فستبدو هذه الفكرة غاية الوضوح ما أن تكتب برنامجك الأول في لغة تختارها. المكتبات المعيارية Standard Libraries وهي مجموعة من التعليمات أو العمليات الجاهزة التي توفرها لغة البرمجة لعمل مختلف أجزائها مع بعضها ولتنفيذ المهام الأساسية المنوطة بلغة البرمجة تلك مثل التعامل مع النصوص والأعداد والتواصل مع نظام التشغيل ونظام الملفات وغيرها، وتوضع عادة في ملفات منفصلة وتضاف إلى البرنامج الذي تُنفّذه. إذ تساعدك بعض المكتبات مثلًا على إضافة نصٍ إلى نص آخر مباشرة باستخدام إشارة الجمع + على الرغم من كونها عملية حسابية تجري على الأعداد. إذ تضم تلك المكتبات القدرة على فهم أن هذه العملية هنا ليست لجمع عددين بل لضم نصين. تصنّف لغات البرمجة في فئات ومجموعات وفقًا لصياغتها وطريقة معالجتها للمعلومات وطريقة تنفيذ تعليمات لغة البرمجة وهذا ما سنتوسع فيه بعد قليل. لغة البرمجة واللغات البشرية إنّ اللغات البشرية هي الطريقة الطبيعية للتواصل بين البشر وتتكون من حروف تكوّن كلمات ومن ثم تشكل جملًا وفق مجموعة من القواعد التي ندعوها في العربية "نحوًا" ومن ثم نستخدم هذه الجمل بعناية لإيصال المعنى المطلوب. ويُفترض بالإنسان أن يُلم بأساسيات لغة الشخص الذي يحاوره كي لا تقع مشاكل في التواصل. الأمر مشابه في لغات البرمجة كونها لغة للتخاطب بين البشر والحواسيب أو الآلات التي تقبل البرمجة عمومًا. إضافة إلى ذلك، للغات الطبيعية ولغات البرمجة نوع من الهيكلية أو البنية التي تنتظم وفقها تلك اللغات، فالكلمات في اللغات الطبيعية قد تشابه التعليمات في لغة البرمجة والجمل sentences قد تشابه التعابير البرمجية Expressions، وتستخدم لغات البرمجة ما تستخدمه اللغات الطبيعية من علامات للترقيم لكن لأغراض خاصة بوظيفتها، وتستخدم عوامل تشابه حروف العطف والاختيار والموازنة في اللغات الطبيعية للربط بين التعابير البرمجية واستخلاص المعنى، فلهذه اللغات جميعها أساليب في الصياغة والمدلول. ومن أوجه الشبه أيضًا ما يُدعى بالعائلات، فاللغات الطبيعية تنحدر من عائلات تتشابه اللغات فيها كاللغات السامية أو اللغات الجرمانية أو السلافية. كذلك الأمر في لغات البرمجة التي تنحدر جميعها من لغات ظهرت في البداية مثل Fortran التي انحدرت منها Algol ثم C و ++C إذ تتشابه هاتين الأخيرتين كثيرًا. أما الاختلافات فتأتي من كون التعليمات في لغات البرمجة معدة سلفًا وقابلة للحصر حتى إن تطورت سيكون التطور بإلغاء تعليمة ووضع أخرى بينما تتطور اللغات الطبيعية وفقًا للحاجة ويظهر ذلك تلقائيًا. كذلك يظهر الاختلاف في عدم قدرة لغات البرمجة على التعبير بطرح أسئلة أو استخدام الإيحاءات بل تعتمد على مجموعة قواعد صارمة فيما يخص الصياغة وطريقة استخدام اللغة. تأتي أهمية هذا النقاش من ضرورة الفهم الأصيل للغات البشرية ولغات البرمجة لما سيقود ذلك من تطور في مجال البرمجيات التي تتعرف على الكلام أو المترجمات الآلية أو الذكاء الاصطناعي وغيرها الكثير. دورة الذكاء الاصطناعي احترف برمجة الذكاء الاصطناعي AI وتحليل البيانات وتعلم كافة المعلومات التي تحتاجها لبناء نماذج ذكاء اصطناعي متخصصة. اشترك الآن أنواع لغات البرمجة هنالك المئات من لغات البرمجة وجدت لتحقيق أهداف مختلفة وحتى هذه اللحظة تظهر لغات برمجة جديدة باستمرار، لذا تصنف هذه اللغات إلى أنواع عدة بالاعتماد على وظائف كل لغة وتطبيقاتها وطريقة معالجتها وغيرها من المقاييس ونوضح في الصورة التالية بعض الأنواع أو الفئات التي تنضوي تحتها لغات البرمجة. أنواع لغات البرمجة الشائعة هي تنقسم إلى الأنواع التالية: أنواع لغات البرمجة وفق مستوى الترميز لغات البرمجة منخفضة المستوى Low level Programming Languages لغة الآلة Machine language لغات التجميع Assembly languages لغات البرمجة عالية المستوى High level languages أنواع لغات البرمجة وفق طريقة معالجة التعليمات اللغات المُصرَّفة Compiled Languages اللغات المُفسَّرة Interpreted languages اللغات الهجينة المصرّفة المفسّرة أنواع لغات البرمجة وفق أسلوب تنظيم الشيفرة لغات البرمجة الوظيفية Functional Programming لغات البرمجة الإجرائية Procedural Programming لغات البرمجة الكائنية Object-oriented Programming أنواع لغات البرمجة وفق مجالات الاستخدام لغات البرمجة عامة الغرض General Purpose programming Languages لغات البرمجة خاصة الغرض Special Programming Languages شرح كل الأنواع السابقة سيطيل المقال وهو خارج موضوع التعريف بلغات البرمجة ويكفي أن تأخذ فكرة على أنواع لغات البرمجة وتتعرف على أشهر أصنافها لأنك عادة عندما تتعلم لغة برمجة يفترض أن تعرف نوعها والصنف الذي تتبع له لأن الأنواع الواحدة تشترك بمفاهيم واحدة تقريبًا يمكن تعلمها بشكل منفصل. ويمكنك الرجوع إلى مقال أنواع لغات البرمجة لتكتشف المزيد من التفاصيل حول معايير وطرق تصنيف وتنظيم لغات البرمجة وشرح مفصل لكل الأنواع التي ذكرناها بالأعلى. لغات برمجة السكربت تُعد لغة برمجة ما أنها لغة سكربت إن كانت: تستخدم مجموعة من التعليمات النصية المكتوبة لتنفيذ أي نوع من العمليات. تعتمد على مضيف: إذ لا يمكن أن تُنتج برامجًا تنفيذية قائمة بحد ذاتها بل ترتبط بنظام تشغيل مثل (سكربتات الطرفيات) أو بيئة عمل (سكربت ويب على الخادم) أو برنامج ( سكربت كتابة ماكرو أو موسّع) أو لغة برمجة أخرى لتنفيذ مجموعة من العمليات التي تهدف إلى تعديل أو تطوير أو زيادة القدرة الوظيفية للمضيف أو تتوسط بينها وبين منظومات أخرى ليشار إليها عندها إلى أنها لغات صمغية glue code. أن تكون لغة مفسّرة وليست مُصرَّفة. تتميز لغات السكربت بكونها، مفتوحة المصدر غالبًا، وسهلة التعليم نسبيًا ولا ضرورة لوجودها ضمن ملف خاص كي تُفسّر، ولا يمكن كتابة تطبيقات أو برامج باستخدامها مباشرة بل تحتاج إلى مضيف لذلك يُقال أنها محمولة. أضف إلى ذلك أنها سريعة التنفيذ كونها تستطيع تنفيذ الطلبات مباشرة (تنفيذ أمر مباشرة) دون الحاجة إلى تعليمات أخرى لتفعيل الطلب كما يزيد سرعتها كونها لغة برمجة مفسّرة. يمكنك مثلًا أن تُنفّذ الأمر ('مرحبًا')window.alert مباشرة في جافاسكربت وهي لغة سكربت مشهورة جدًا، لكنك لن تستطيع فعل ذلك باستخدام لغة ++C. لاحظ ماذا سيتطلب الأمر: // لنقول مرحبًا C++ برنامج بلغة #include <iostream> using namespace std; int main(){ cout<<"مرحبًا"; return 0; } تُصنف لغات برمجة السكربت إلى: سكربتات تطوير الويب: وتستخدم لكتابة صفحات ويب ديناميكية وتطوير مواقع وتطبيقات الويب، ويمكن أن نميز بين نوعين من السكربتات في هذه الصدد سكربتات تعمل من جانب العميل (أي تُستخدم في بناء الواجهة الأمامية للتطبيق أو الموقع) نجد: JavaScript React Next.js سكربتات تعمل من جانب الخادم (أي تستخدم لبناء الواجهة الخلفية للتطبيق، وهي ما يستعرضه المتصفح) نجد منها: JavaScript PHP Node.js ASP.net Ruby Perl Python سكربتات تعمل مع طرفيات أنظمة التشغيل: وتستخدم لتنفيذ الأوامر ضمن واجهات سطر الأوامر في أنظمة التشغيل المختلفة مثل ويندوز ولينكس. من الأمثلة عليها: BASH: في طرفيات لينكس، وتنفذ طيفًا واسعًا من التعليمات مثل الكتابة والقراءة من وإلى الملفات وتنزيل البرمجيات من الإنترنت وتثبيتها وتشغيل البرمجيات وغيرها الكثير. Windows powerShell: في ويندوز، وتنفذ مهامًا مشابهة لما تنفذه طرفية لينكس. سكربتات للأغراض العامة: يمكن أن تُنفذ تقريبًا أي شيء نذكر منها: Ruby Python يمكن استخدام السكربتات في كل المجالات تقريبًا مثل تطبيقات الويب وتطبيقات الهواتف المحمولة وسطح المكتب والتعامل مع الأنظمة وأتمتة المهام على المنظومات السحابية والتنقيب عن البيانات وبرمجة الموّسعات والإضافات إلى البرامج وغيرها الكثير. نفذ مشاريعك البرمجية باللغة التي تحتاجها استعن بأفضل المبرمجين في كتابة وتصحيح الأكواد البرمجية على خمسات اطلب خدمتك الآن اللغات التوصيفية Markup Languages يشير مصطلح اللغات التوصيفية markup languages إلى آلية لترميز النصوص عن طريق إضافة مجموعة من الرموز إلى النص تتحكم بتنسيقه أو بإيجاد علاقات بين أقسامه وتسهل عملية أتمتته. إذ تضم اللغات التوصيفية مجموعة من الوسوم أو القواعد التي يشير كل منها إلى دلالة معينة وتستخدم لتنظيم البيانات النصية وعرضها بطريقة يسهل تمييزها بالنسبة للإنسان أو الحاسوب كأن تشير إلى عبارة على أنها عنوان وتبرز عبارة أخرى بكتابتها بخط ثخين وهكذا. لا تُعرض تلك القواعد أو الوسوم ولا تُضاف إلى المحتوى الفعلي بل وظيفتها وصف البيانات فقط وترتيبها. تتطلب هذه اللغات فقط برنامجًا ليحلل الوسوم ويعرض المحتوى وفقًا لمدلول كل وسم وغالبًا ما تحلل المتصفحات أكواد HTML وأكواد XML ثم تعرض النتائج بينما تحلل برمجيات أخرى مخصصة لغات توصيفية أخرى مثل Markdown و DocBook اللتان تستخدمان في المحررات النصية ولاتخ LaTex لكتابة الأوراق البحثية الأكاديمية وغيرها الكثير. لا تحتاج اللغات التوصيفية كلغات البرمجة إلى تصريف Compilation أو تفسير Interpretation كي تحول الشيفرة المكتوبة إلى مجموعة أخرى من التعليمات التي يفهمها الحاسوب، فهي لا تنفذ أية عمليات أو إجرائيات لذلك لا تُعد اللغات التوصيفية لغات برمجة. فكل ما تفعله محللات اللغات التوصيفية هو قراءة الوسوم ومعرفة بدايتها ونهايتها ثم عرض هذه الوسوم بالطريقة الصحيحة تبعًا لدلالة تلك الوسوم. يمكن استخدام هذه اللغات لتصميم صفحات ويب مثل HTML أو لتنسيق صفحات الويب مثل CSS أو لتخزين البيانات مثل XML أو لتنسيق النصوص مثل Markdown وغيرها الكثير. تشرح دورة تطوير واجهات المستخدم من أكاديمية حسوب كل من لغات تطوير واجهات المستخدم الأمامية وهي HTML و CSS وجافاسكربت شرحًا شاملًا بعدد ساعات يزيد عن 50 ساعة فيديو بتطبيقات عملية تطبيقية تناسب سوق العمل. يمكنك الرجوع في هذا الصدد إلى مقال تعلم لغة HTML الذي يتحدث عن اللغات التوصيفية عمومًا ولغة HTML خصوصًا. أسئلة شائعة عن لغات البرمجة إليك بعض الإجابات عن أكثر الأسئلة شيوعًا حول لغات البرمجة. كم عدد لغات البرمجة الموجودة حاليًا؟ عدد لغات البرمجة وفقًا لموقع ويكيبيديا يقارب 700 لغة برمجة مستخدمة أو توقف استخدامها باستثناء اللغات التوصيفية. لكن يرى البعض أنها قد تصل بجميع تصنيفاتها إلى 8000-9000 وهذا رقم مبالغ فيه قليلًا. ما السبب في وجود عدد كبير من لغات البرمجة؟ التنوع نابع عن الحاجة، فلن تتمتع لغة برمجة واحدة بجميع المزايا التي تسهّل العمل في جميع المجالات بفعالية ودقة. قد يكون الأمر مشابهًا لوجود أنواع عدة من المركبات منها السيارة والطائرة والدراجة الهوائية والنارية فلكل استخدامه، إذ يولّد التطور التقني المتسارع الحاجة إلى وجود لغات أكثر مرونة وفعالية في مجالات مختلفة مما يدفع إلى تطوير لغات جديدة تلبي هذه الحاجة. ما هي أحدث لغات البرمجة؟ إذا استثنينا الإصدارات الجديدة من اللغات القديمة مثل الإصدار 3 من لغة Python يمكن أن نجد: لغات البرمجة بالدوال: ELIXIR ELM PURESCRIPT SWIFT لغات البرمجة الإجرائية: Go لغات البرمجة بالكائنات: DART PONY CARBON لغات أغراض عامة: HACK Kotlin NIM RUST ما هي لغات البرمجة السائدة (أشهر لغات البرمجة)؟ إليك أكثر لغات البرمجة استخدامًا وأشهر لغات البرمجة لكن دون نسب مئوية للاستخدام ودون أفضلية لعدم وجود إحصائيات دقيقة وموثوقة. Python JavaScript JAVA C++/C GO Ruby #C PHP أشهر لغة من بينها تُستعمل في بناء تطبيقات سطح مكتب تعمل على مختلف أنظمة التشغيل الحاسوبية هي لغة جافا Java وبايثون Python والأخيرة تستعمل في مجال الذكاء الاصطناعي وتعلم الآلة والتعامل مع البيانات وغيرها، أما في مجال الويب، فأشهر لغة فيه حاليًا هي لغة جافاسكربت JavaScript فيمكنك باستعمالها تطوير الواجهات الأمامية Frontend وأصبح بإمكانك أيضًا تطوير الواجهات الخلفية Backend عبر بيئة Node.js وكما يمكنك باستعمال تقنيات الويب تطوير تطبيقات لسطح المكتب تعمل على كل أنظمة التشغيل باستعمال إطار العمل Electron.js، وتعد دورة تطوير التطبيقات باستخدام لغة JavaScript أفضل مرجع عربي يشرح لغة جافاسكربت وكافة تطبيقاتها لبناء تطبيقات الويب وتطبيقات سطح المكتب شرحًا عمليًا. ما هي أسهل لغات البرمجة من حيث التعلم والاستخدام؟ لا يمكن أن نجد إجابة محددة عن سؤال أسهل لغات البرمجة فالغرض من استخدامك للغة البرمجة وتآلفك معها مسألة حاجة ورغبة: PHP Python JavaScript Ruby C/C++/JAVA Kotlin Swift عمومًا، يقال عن لغة بايثون أنها أسهل لغة برمجة يمكن البدء بتعلمها والسبب أنها صياغة اللغة قريبة جدًا من صياغة اللغة الإنجليزية فعندما تكتب شيفرة برمجية كأنك تصيغ فقرة من لغة إنجليزية وهذا ما يميزها عن بقية اللغات التي تكثر فيها الأحرف والكلمات الغامضة وعلامات الترقيم والأقواس المتناثرة هنا وهناك، ولهذا السبب تبدأ أغلب الجامعات بشرح هذه اللغة كأول لغة برمجة لطلاب علوم الحاسوب وتبدأ أغلب الدورات والكورسات البرمجة بشرحها لمن يريد تعلم البرمجة بمفرده، وأفضل مرجع عربي شامل متكامل من تلك الدورات هي دورة تطوير التطبيقات باستخدام لغة Python من أكاديمية حسوب. هل عليَّ تعلم لغة برمجة؟ إن كنت تنوي تطوير مهنتك الهندسية أو العلمية أو التسويقية أو الاقتصادية أو التحليلية فالجواب نعم بكل تأكيد. ما الفائدة من تعلم لغة برمجة؟ تطوير مسيرتك المهنية، فكل الدلائل تشير إلى أننا مقبلون وبشدة على عصر الآلات الذكية. الاطلاع على الطريقة التي تعمل بها الآلات المبرمجة مما قد يساعدك على استخدامها بالشكل الصحيح. تحسين قدراتك العقلية على التحليل وترتيب الأفكار. إضافة إلى تلك الأسباب العامة، ستجد من مهنة المبرمج أو مطور ويب مهنة ممتعة ومجزية ماديًا فالطلب يزداد بشكل كبير على المنتجات الرقمية وتتنوع مجالات استخداماتها لما تقدمه من فوائد على جميع الأصعدة مثل أتمتة المهام المختلفة وتحليل البيانات والحسابات الرياضية والتقنية المتقدمة وإدارة المتاجر الإلكترونية والأعمال وغير ذلك الكثير. فالبرمجة هي مهنة المستقبل بامتياز، وأيًا كانت مهنتك الأصلية ستجد البرمجة سبيلًا إليها، وهكذا ستجني فائدة مضاعفة بتعلمك إحدى لغات البرمجة. هل من الصعب تعلم لغة برمجة؟ الجواب لا إن كنت تمتلك الإرادة والمثابرة. تعلم البرمجة شبيه بركوب الدراجة ما أن تُصِرَّ على تعلمها ثم تتعلم كيف تستخدمها لن تنسى أبدًا كيف ستقودها وكذلك لن تنسى كيف تفكر برمجيًا. لكن إن أردت أن تصبح محترفًا، فهذا طريق طويل تعترضك فيه بعض الصعوبات. ما هي مجالات استخدام لغات البرمجة؟ من كتابة كلمة "مرحبًا" على شاشة حاسوبك إلى التحكم بمسبار فضائي يحط على كوكب آخر. فكل ما تعرضه لك الأجهزة الإلكترونية من بسيطها إلى أعقدها هي نتاج عملية برمجة لهذه الأجهزة. ويمكن تلخيص استخدامات لغات البرمجة وفق الخطوط العريضة التالية: تطوير تطبيقات للحواسب تطوير تطبيقات للويب تطوير تطبيقات للهواتف الذكية برمجة الآلات والتجهيزات القابلة للبرمجة تطوير وإدارة الخدمات السحابية تطوير أنظمة تشغيل تطوير أنظمة وآلات ذاتية التعلم مجالات الذكاء الاصطناعي والروبوتات أنشئ موقع إلكتروني لأعمالك بدون خبرة برمجية صمم موقع احترافي لأعمالك بالسحب والإفلات مع أكثر من 70 قالب جاهز وقابل للتخصيص ليناسب هويتك التجارية جرب سنديان الآن خاتمة تعرفنا في هذه المقال على لغات البرمجة التي نستخدمها في برمجة الحواسب والأجهزة الإلكترونية الذكية أو القابلة للبرمجة واستعرضنا الخطوط العامة لمكوّنات أي لغة برمجة ثم فصلنا في أنواعها وقلنا أنها قد تكون عامة الغرض أو مخصصة من ناحية الاستخدام أو لغات مكتوبة أو مرئية من ناحية إظهار الشيفرة وأنها مفسّرة أو مصرّفة من ناحية معالجة المعلومات. كما ذكرنا أن لغات البرمجة التي تقترب تعليماتها وظيفيًا من التعليمات التي يفهمها الحاسوب هي لغات منخفضة المستوى ويزداد مستواها باستخدامها تعليمات تنفذ وظائف أكبر من تعليمات الحاسوب الأساسية. ومررنا أخيرًا على مفهوم لغات السكربت واستخداماتها بشيء من التفصيل، وعلى مفهوم اللغات التوصيفية واختلافها عن لغات البرمجة. وبهذا الشكل نكون قد أحطنا ولو بالشيء اليسير بمفاهيم هذا العالم الواسع لتكون خطوتك الأولى في الإنطلاق إلى عالم البرمجة. اقرأ أيضًا المدخل الشامل لتعلم علوم الحاسوب كيف تتعلم البرمجة فوائد تعلم البرمجة دليلك إلى: لغات برمجة الألعاب المدخل الشامل لتعلم تطوير الويب وبرمجة المواقع المرجع الشامل إلى تعلم لغة بايثون البرمجة بلغة جافاسكربت مقارنة بين JavaScript و TypeScript مقارنة بين PHP و NodeJS
-
تُعَدّ HTML أو لغة توصيف النصوص التشعبية بأنها الشيفرة التي تُستخدَم في هيكلة صفحات ويب ومحتوياتها، فقد تُنظَّم الصفحة مثلًا على هيئة مجموعة من المقاطع النصية أو قائمة من النقاط أو أن تعرض الصور أو جداول البيانات، وسنقدِّم لك في هذا المقال مجموعة معارف أساسية لفهم لغة HTML ووظائفها. ما هي HTML؟ تُعَدّ HTML بأنها لغة توصيفية تُعرِّف هيكلية المحتوى الذي تقدِّمه الصفحة، وتتألف اللغة من سلسلة من العناصر التي تستخدِمها لتضمين أو تغليف الأجزاء المختلفة من المحتوى لتظهر بطريقة محددة أو لتعمل بطريقة محددة، كما يمكن أن تربط الوسوم المغلقة enclosing tags كلمةً أو صورةً بمكان آخر، أو يمكنها عرض الكلمات عرضًا مائلًا أو تكبّر خط الكتابة أو تصغّره وهكذا، وإليك على سبيل المثال المحتوى التالي الذي لا يتعدى السطر: My cat is very grumpy إذا أردنا أن يظهر السطر كما هو، فيمكننا أن نجعله فقرةً نصيةً بتضمينه داخل وسمَي فقرة، أي <p> </p>: <p>My cat is very grumpy</p> تشريح عنصر HTML دعونا نستكشف عنصر الفقرة السابق بصورة أعمق: إن الأجزاء الرئيسية من العنصر هي: وسم البداية Opening tag: يشير هذا الوسم إلى النقطة التي يبدأ عندها العنصر أو التي يبدأ تأثيره عندها (بداية الفقرة النصية في حالتنا)، ويتكوّن من اسم العنصر (p في حالتنا) محاطًا بقوسَي زاوية. وسم النهاية Closing tag: يشير هذا الوسم إلى نهاية العنصر (نهاية الفقرة في حالتنا)، ويشبه وسم البداية لكنه يبدأ بشرطة أمامية / قبل اسم العنصر، كما يُعَدّ إغفال وسم النهاية من أكثر الأخطاء التي يرتكبها المبتدئون، وقد تفضي إلى نتائج غريبة بالفعل. المحتوى Content: يشير إلى المحتوى الفعلي للعنصر، وهو في حالتنا مجرد نص. العنصر Element: ويتكون من وسمَي البداية والنهاية والمحتوى معًا. يمكن أن تمتلك العناصر سمات attributes تبدو شبيهةً كما يلي: تتضمن السمات معلومات إضافية عن العنصر لا تريدها أنت أن تظهر مثل جزء من المحتوى الفعلي، فالكلمة class في الشكل السابق هي اسم السمة وقيمتها هي editor-note، إذ تسمح لك السمة class بإعطاء العنصر معرِّفًا عامًا يمكن استخدامه لتطبيق معلومات تنسيق على هذا العنصر أو أي عنصر تحمل السمة class فيه القيمة نفسها أو غيرها. لكتابة السمة لا بد من: مسافة فارغة بينها وبين اسم العنصر، أو بينها وبين السمة التي تسبقها في حال امتلك العنصر سمتَين أو أكثر. اسم السمة تليها إشارة المساواة =. قيمة السمة بين إشارتَي تنصيص. ملاحظة: يمكنك عدم وضع قيمة السمة بين إشارتي تنصيص إذا لم تتضمن رمز ASCII الخاص بالمسافة الفارغة أو أيّ من المحارف " أو ' أو ` أو = أو < أو >، لكن يفضَّل وضع قيمة السمة دائمًا داخل إشارتَي التنصيص لأنها تجعل الشيفرة واضحةً ومفهومةً. دورة تطوير واجهات المستخدم ابدأ عملك الحر بتطوير واجهات المواقع والمتاجر الإلكترونية فور انتهائك من الدورة اشترك الآن العناصر المتداخلة يمكن وضع عناصر داخل عناصرأخرى أيضًا وهذا ما يُعرف بالتداخل nesting، فإذا أردنا أن تظهر الكلمة "very" في الفقرة "My cat is very grumpy" بخط سميك، فيمكن تغليف هذه الكلمة داخل العنصر <strong></strong> كما يلي: <p>My cat is <strong>very</strong> grumpy.</p> لكن عليك التأكد دومًا من أنّ العناصر متداخلة بصورة صحيحة، فقد فتحنا في المثال السابق العنصر <p> أولًا ثم <strong>، وبالتالي توجَّب إغلاق العنصر الثاني آخر من فتح على الشكل <strong/> ثم إغلاق الأول <p/>، أي أنّ التداخل التالي غير صحيح: <p>My cat is <strong>very grumpy.</p></strong> لا بد من فتح وإغلاق العناصر بالصورة الصحيحة لكي تظهر بوضوح داخل أو خارج عنصر آخر، فإذا تداخلت بالشكل الذي عرضناه في الشيفرة السابقة، فسيحاول المتصفح أن يخمّن بأفضل شكل ما تحاول قوله، مما قد يتسبب بظهور نتائج غير متوقعة، فلا تفعل ذلك. العناصر الفارغة تُدعى بعض العناصر التي لا تحمل أيّ محتوى بالعناصر الفارغة Empty elements مثل العنصر <img> الذي استخدمناه سابقًا: <img src="images/firefox-icon.png" alt="My test image"> إذ يمتلك العنصر سمتَين ولا يمتلك وسم نهاية <img/> أو محتوى، والسبب أن عنصر الصورة لا يغلِّف محتوًى لكي يتأثر بوجود أو عدم وجود وسم النهاية، فوظيفته هي إدراج صورة في صفحة HTML في المكان الذي يظهر فيه. تشريح مستند HTML سنشرح الآن الطريقة التي نجمّع بها عناصر HTML المفردة لنشكِّل صفحةً كاملةً، فلنعُد قليلًا إلى الشيفرة التي وضعناها في الملف index.html والذي رأيناه أول مرة في المقال السابق: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>My test page</title> </head> <body> <img src="images/firefox-icon.png" alt="My test image"> </body> </html> لدينا هنا الأشياء التالية: <DOCTYPE html!>: وهو عنصر تمهيدي مطلوب، فقد كانت الغاية من هذا العنصر في الأيام الأولى (1991/1992) أن يعمل على أساس رابط إلى مجموعة من القواعد التي ينبغي أن تحققها صفحة HTML لكي تُعَدّ صفحةً جيدةً بما في ذلك الاكتشاف التلقائي للأخطاء وغيرها من النقاط المفيدة، وليس لهذا العنصر في أيامنا هذه وظيفةً سوى التأكد من سلوك المستند للسلوك المطلوب، وهذا كل ما عليك معرفته حاليًا. <html></html>: يضم هذا العنصر كامل محتوى الصفحة، ويُدعى أحيانًا بالعنصر الجذري root element. <head></head>: يعمل على أساس حاوية لتضع فيها كل الأشياء التي تريدها في صفحتك ولكنها لا تمثِّل محتوًى تريد إظهاره لمتابعيك مثل الكلمات المفتاحية ووصف الصفحة الذي تريد إظهاره عندما يعرضها محرك البحث على أساس نتيجة وقواعد CSS لتنسيق محتوى الصفحة ونوع المحارف التي تستخدمها في الصفحة وغيرها الكثير. <"meta charset="utf-8>: يضبط هذا العنصر مجموعة المحارف التي تستخدِمها في الصفحة، وهنا اخترنا المجموعة UTF-8 التي تضم محارف الأغلبية الساحقة من اللغات المكتوبة، إذ تستطيع هذا المحارف أن تعرض الآن أيّ محتوى نصي بأيّ لغة قد تضعه في صفحتك، ولا مبرر لعدم ضبط مجموعة المحارف المستخدَمة، كما ستساعدك على تحاشي الكثير من الأخطاء لاحقًا. <title></title>: يضبط هذا العنصر عنوان صفحتك الذي يظهر أعلى المتصفح عند تحميل الصفحة، كما يُستخدم لوصف الصفحة عندما تضيفها إلى قائمة الصفحات المفضلة. <body></body>: يضم المحتوى الذي تريد عرضه على زائري صفحتك بأكمله، سواءً كان نصًا أو صورًا أو فيديو أو ألعاب أو أيّ شيء آخر. الصور لنعُد إلى العنصر <img> مجددًا: <img src="images/firefox-icon.png" alt="My test image"> يُدرِج هذا العنصر صورةً ضمن الصفحة في المكان الذي تضعه فيه، إذ نحدِّد الصورة المعروضة بكتابة عنوانها على أساس قيمة للسمة src -أي مصدر source-، كما يمتلك عنصر الصورة أيضًا سمةً أخرى تُدعى alt -أي بديل alternative-، إذ تُستخدَم هذه السمة لعرض نص بديل عن الصورة للأشخاص الذين لا يستطيعون رؤيتها لأسباب عديدة منها: المشاكل البصرية: إذ يستخدِم الكثيرون من فاقدي البصر أدوات تُدعى قارئات الشاشة تستطيع قراءة النص البديل. أخطاء في عرض الصورة: حاول مثلًا تغيير المسار الموجود داخل السمة في مثالنا السابق ثم احفظ الملف وأعد تحميله ضمن المتصفح، إذ لن تظهر الصورة، وإنما نص كما يلي: ما يهم فعلًا في النص البديل هو أن يكون وصفيًا تمامًا لمحتوى الصورة، إذ ينبغي أن يزوِّد النص القارئ بمعلومات كافية ليكوِّن فكرةً جيدةً عن محتوى الصورة، فالنص البديل "My test image" في مثالنا غير جيد على الإطلاق، وسيكون الأنسب لشعار فايرفوكس هو "Firefox logo: a flaming fox surrounding the Earth" وبالعربية "شعار فايرفوكس: ثعلب ملتهب يحيط بالكرة الأرضية"، أي حاول إذًا ابتكار نصوص بديلة جيدة تصف الصورة. توصيف محتوى صفحات HTML يغطي هذا القسم من المقال عناصر HTML الأساسية لتوصيف محتوى الصفحات. العناوين تساعدك العناوين Headings على عرض أجزاء من محتوى الصفحة على أساس عناوين رئيسية أو فرعية، وكما هو حال الكتب التي تحمل عنوانًا رئيسيًا وعناوين للفصول وعناوين فرعية في كل فصل، تحمل صفحة HTML الميزة ذاتها، إذ تضم اللغة عناوين تتدرج إلى مستويات ستة من <h1> إلى <h6>، وغالبًا ما ستستخدِم ثلاث إلى أربع مستويات كحد أقصى. <!-- 4 heading levels: --> <h1>My main title</h1> <h2>My top level heading</h2> <h3>My subheading</h3> <h4>My sub-subheading</h4> ملاحظة: كل ما يرد بين الوسمين <-- و --!> في صفحة HTML هو تعليق سيتجاهل المتصفح محتواه عندما يصيّر الشيفرة ولن يُعرَض على الشاشة، إذ تساعدك التعليقات في وضع ملاحظات مفيدة عن مقطع محدَّد من الشيفرة أو عن منطق معيّن اعتمدته. حاول الآن وضع عنوان فرعي في صفحة HTML التي نبنيها فوق العنصر <img> مباشرةً. ملاحظة: تملك العناوين من المستوى الأول تنسيقًا ضمنيًا خاصًا، لذلك لا تستخدِمها لتكبير النص أو جعله سميكًا Bold لأنها تُستخدَم لغايات أخرى مثل سهولة الوصول أو لأسباب أخرى مثل تحسين محركات البحث، لذا حاول أن تعطي تدرجًا منطقيًا للعناوين في صفحتك دون تجاوز أيّ مستوى إلى ما دونه مثل الانتقال من 4 إلى 2 مباشرةً دون المرور بالمستوى 3. الفقرات النصية يحتوي العنصر <p> كما شرحنا سابقًا مقطعًا نصيًا، وستستخدمه بكثرة عندما ترمز المحتوى النصي في الصفحة: <p>This is a single paragraph</p> يمكنك على سبيل التجربة إضافة عينة من نص ما على هيئة فقرة نصية أو أكثر تحت العنصر <img> في الصفحة التجريبية التي نبنيها. القوائم تُصنَّف كمية لا بأس بها من محتوى ويب على صورة قوائم Lists وتمتلك HTML القدرة على ذلك، إذ تتضمن القائمة عنصرين على الأقل، وأكثر القوائم شيوعًا هي القوائم المرتبة Ordered وغير المرتبة Unordered: القوائم المرتبة: توضع بنود هذه القائمة ضمن العنصر <ol>، وتُستخدَم لعرض القوائم التي يهمنا فيها ترتيب العناصر مثل وصفات تحضير الطعام أو ترتيب فِرق دوري لكرة القدم وغيرها. القوائم غير المرتبة: توضع بنود هذه القائمة ضمن العنصر <ul>، وتُستخدَم لعرض القوائم التي لا نهتم فيها لترتيب العناصر مثل قائمة التسوق. يوضع كل بند من بنود القائمة ضمن العنصر <li> -أي بند من قائمة list item-، فإذا أردنا مثلًا تحويل جزء من الفقرة النصية التالية إلى قائمة: <p>At Mozilla, we’re a global community of technologists, thinkers, and builders working together ... </p> فيمكننا تعديل توصيف محتوى الفقرة ليصبح كما يلي: <p>At Mozilla, we’re a global community of</p> <ul> <li>technologists</li> <li>thinkers</li> <li>builders</li> </ul> <p>working together ... </p> الروابط تُعَدّ الروابط العنصر الأكثر أهميةً، فهي ما تجعل من الويب شبكةً حقيقيةً، إذ نستخدِم العنصر البسيط <a> لإنشاء رابط، وهو اختصار للكلمة "anchor"، ولتجعل جزءًا من الفقرة النصية السابقة رابطًا اتبع الخطوات التالية: اختر جزءًا من النص وليكن "Mozilla Manifesto". ضَع هذا الجزء ضمن الوسمَين <a></a> كما يلي: <a>Mozilla Manifesto</a> زوّد الرابط بعنوان للانتقال إليه من خلال السمة href كما يلي: <a href="">Mozilla Manifesto</a> اكتب العنوان المطلوب بين علامَتي تنصيص السمة href كما يلي: <a href="https://www.mozilla.org/en-US/about/manifesto/">Mozilla Manifesto</a> قد تصل إلى نتيجة غير متوقعة إذا حذفت بداية العنوان الذي يُدعى بروتوكول، أي //:https أو ://http، لذلك تحقق من وصولك إلى المكان المطلوب عند النقر على الرابط. ملاحظة: قد يبدو اختيار اسم السمة href غامضًا في البداية، فإذا صعُب عليك الأمر، تذكر أنه مشتق من كلمتَي "مرجع إلى نص تشعبي hypertext reference" خلاصة إذا اتبعت التوجيهات التي أشرنا إليها خلال اطلاعك على هذا المقال، فستبدو صفحة الويب التي نبنيها بالشكل التالي تقريبًا إذا لم تغير في العناوين أو النصوص. إذا لم تجد عملك صحيحًا، فيمكنك دائمًا موازنة ما فعلته مع النسخة الجاهزة على جيت-هاب. ترجمة -وبتصرف- للمقال HTML Basics. اقرأ أيضًا المقال السابق: التعامل مع الملفات في عملية تطوير موقع الويب توثيق لغة HTML العربي مكونات الويب: عناصر HTML المخصصة وقوالبها دليل: تعلم لغة HTML
-
تتمتع البرمجيات بدورة حياة كاملة ابتداءً من التصورات الأولية وانتقالًا إلى البرمجة ومنها إلى إصدار البرنامج إلى المستخدم النهائي وصيانته. سنتعرف في هذا المقال على مفهوم الحاويات Containers، وهي أداةٌ عصرية تُستخدم في المراحل النهائية من دورة حياة البرنامج. تُغلّف الحاويات تطبيقك ضمن حزمةٍ واحدة تتضمن كل الاعتماديات التي يحتاجها التطبيق، وتكون النتيجة حاويةً يمكن أن تعمل بصورةٍ مستقل عن غيرها من الحاويات. تمنع الحاويات التطبيق من الوصول واستخدام ملفات وموارد الأجهزة، وقد يعطي مطورو التطبيقات بعض الأذونات للبرنامج الذي تضمه الحاوية في الوصول إلى ملفات محددة وتخصيص موارد محددة أيضًا. ولنكون أكثر دقة، تُعدّ الحاويات بمثابة بيئات عمل افتراضية على مستوى نظام التشغيل، وأكثر ما يشابهها من الناحية التقنية هي الآلات الافتراضية Virtual machines التي تساعد على تشغيل عدة أنظمة تشغيل على جهاز فيزيائي واحد. وينبغي على الآلات الافتراضية تشغيل النظام بأكمله، بينما تُشغّل الحاوية التطبيق بالاستفادة من نظام التشغيل الذي يستضيفها. وهكذا سيكون الاختلاف بين الحاويات والآلات الافتراضية هي أنك لن تلاحظ إلا نادرًا جدًا زيادة في تحميل النظام عند استخدام الحاويات، فهي عادةً ما تحتاج إلى تنفيذ عملية واحدة. يمكن للحاويات أن تكون سريعةً وقابلةً للتوسع لكونها خفيفة الوزن موازنةً بالآلات الافتراضية على الأقل، وطالما أنها تعزل التطبيق الذي يُنفَّذ ضمنها، سيساعد ذلك في الحصول على نفس الأداء تمامًا وفي أي مكان. وبالنتيجة، تُعد الحاويات خيارًا ممتازًا في أي بيئة تشغيل سحابية أو للتطبيقات التي يكثر مُستخدميها. تدعم معظم الخدمات السحابية، مثل AWS و Google Cloud و Microsoft Azure الحاويات وبأشكال متعددة، بما في ذلك AWS Fargate و Google Cloud Run وهما خدمتان لتشغيل الحاويات دون خادم serverless إذ لا حاجة مطلقًا لتنفيذ الحاوية إن لم تُستخدم. يمكن أيضًا تثبيت مقومات تشغيل البيئة على أغلب الأجهزة وتشغيل الحاويات بنفسك، بما في ذلك حاسوبك الخاص. طالما أن الحاويات تعمل في البيئات السحابية وحتى أثناء تطوير التطبيقات، فما الفائدة من الفعلية منها إذًا؟ إليك حالتي الاستخدام التاليتين: الحالة الأولى: عندما تحاول أن تطور تطبيقًا من المفترض أن يعمل على نفس الجهاز لدعم إصدار أقدم، فكلاهما يحتاج إلى تثبيت نسخ مختلفة من Node.js. بإمكانك استخدام nvm أو آلة افتراضية أو حتى اختراع طريقة سحرية لجعل النسختين تعملان معًا، لكن تبقى الحاويات حلًا ممتازًا لأنك تستطيع تشغيل كلا التطبيقين كلًا ضمن حاويته الخاصة، فهما معزولان عن بعضهما ولا يتداخلان. الحالة الثانية: عندما يعمل تطبيقك على حاسوبك وتحاول نقله إلى خادم، فمن الأمور الشائعة ألا يعمل التطبيق على الخادم علمًا أنه يعمل جيدًا على حاسوبك. قد يكون الأمر اعتماديات مفقودة، أو اختلافات أخرى في بيئات التشغيل. في حالة كهذه، تظهر الحاويات مثل حل رائع، لأنها قادرة على تنفيذ التطبيق في نفس بيئة التنفيذ على حاسوبك أو على الخادم. وقد لا يكون حلًا مثاليًا نظرًا لاختلاف العتاد الصلب، لكن يمكنك أن تجعل الاختلافات في بيئات التنفيذ محدودةً جدًا. قد تسمع أحيانًا عبارات من قبيل "يعمل ضمن حاويتي"، إذ تصف هذه العبارة الحالة التي يعمل فيها التطبيق جيدًا ضمن حاوية على جهازك لكنها تُخفق في تنفيذ التطبيق عندما تنقلها إلى الخادم. هذه العبارة هي تلاعب في العبارة "يعمل على جهازي"، فالحاويات مصممةٌ لتعمل، وغالبًا ما تكون هذه الحالة خطأ في الاستخدام. حول هذا القسم لن نركز اهتمامنا في هذا القسم على شيفرة جافاسكربت JavaScript، بل تهيئة البيئة التي سيُنفَّذ فيها التطبيق. لهذا قد لا تحتوي التمارين أية شيفرات. كما ستجد التطبيق جاهزًا على غيت هب GitHub ويحتاج فقط إلى التهيئة. ينبغي رفع التمارين إلى مستودع GitHub واحد يضم كل الشيفرات المصدرية وإعدادات التهيئة التي نفّذتها في هذا القسم. لا بد أن تمتلك معرفة مبدئية بالتعامل مع Node و Express و React، وعليك إكمال الأقسام الجوهرية من 1 إلى 5 للمتابعة في هذا القسم. التمرين 12.1 تنبيه سنخرج في هذا القسم من دائرة الراحة الخاصة بمطوري JavaScript، وقد يتطلب منك ذلك جولةً لتتآلف مع أوامر الصدفة shell أو سطر الأوامر command line أو محث الأوامر command prompt أو الطرفية terminal قبل أن تبدأ؛ فإذا كنت تستخدم واجهة مستخدم رسومية ولم تلمس أبدًا طرفية لينوكس Linux أو ماك Mac، وشعرت بأنك تائه لا تعرف كيف تبدأ حل التمرين، ننصحك بالاطلاع على القسم الأول من كتاب "Computing tools for CS studies"، فهو يضم كل ما تحتاجه لمتابعة العمل هنا. التمرين 12.1: استخدام الحاسوب دون واجهة مستخدم رسومية الخطوة الأولى: اقرأ النص الذي يلي التنبيه. الخطوة الثانية: نزّل مستودع التمرين واجعله مستودع تسليم التمارين لهذا القسم. الخطوة الثالثة: انتقل إلى العنوان "http://helsinki.fi" واحفظ الخرج ضمن ملف، ثم احفظ الملف ضمن مستودعك بالاسم "script-answers/exercise12_1.txt". وتذكر أنك أنشأت بالفعل المجلد "script-answers" في الخطوة السابقة. أدوات العمل تحتاج إلى بعض الأدوات الأساسية التي تختلف وفقًا لنظام التشغيل. ستحتاج WSL 2 terminal على نظام ويندوز. الطرفية على نظام ماك. سطر الأوامر على نظام لينوكس. تثبيت كل ما تحتاجه للعمل سنبدأ بتثبيت البرامج التي نحتاجها، وقد تشكل هذه الخطوة إحدى العقبات المحتملة، إذ لا بد من أذونات واسعة النطاق على جهازك طالما أننا نتحدث عن شكلٍ من البيئات الافتراضية على مستوى نظام التشغيل، وهذا ما يتطلب الولوج إلى نواته. تتركز مادة القسم حول دوكر Docker، وهو يمثّل مجموعةً من المنتجات التي سنستخدمها في تشكيل وإدارة الحاويات، لكن إن لم تستطع تثبيته فلن تتمكن لسوء الحظ من متابعة العمل في هذا القسم. ستختلف إرشادات عملية تثبيت المنتجات على حاسوبك وفقًا لنظام التشغيل، لذلك عليك أن تجد الإرشادات الصحيحة لتثبيت المنتج من خلال صفحة Docker المخصصة للغرض، وتذكر وجود خيارات عدة للتثبيت على نفس نظام التشغيل. لنفترض أن كل شيء جرى على ما يُرام، لهذا سنتأكد من تطابق الإصدارات، إذ لا بُد أن يكون إصدار نسختك أعلى من هذا الإصدار: $ docker -v Docker version 20.10.5, build 55c4c88 الحاويات والصور هناك مفهومان جوهريان فيما يتعلق بالحاويات، ومن السهل الخلط بينهما: الحاوية والصورة؛ إذ أن الحاوية هي نسخة التشغيل من الصورة، لهذا فكلا العبارتين التاليتين صحيحة: تضم الصور الشيفرات والاعتماديات والإرشادات اللازمة لتشغيل التطبيق. تُحزّم الحاويات البرنامج ضمن وحدات معيارية. وبالتالي لا عجب من سهولة الخلط بينهما. للمساعدة في تجاوز الأمر، تُستخدم كلمة "حاوية" للإشارة إلى كلا المفهومين. لكنك لن تتمكن أبدًا من بناء حاوية أو تنزيلها لأنها موجودةٌ فقط أثناء التشغيل؛ أما الصورة فهي ملفاتٌ غير قابلة للتغيير، وبالتالي لن تكون قادرًا على تعديل صورة بعد إنشائها. لكن يمكنك استخدام صورة موجودة لإنشاء صورة جديدة بإضافة طبقات جديدة فوق القديمة. وبعبارات مجازية مستوردة من عالم الطبخ: الصورة هي وجبة مطبوخة مسبقًا ومجمّدة. الحاويات هي تلك الوجبة اللذيذة الجاهزة للأكل. يُعد دوكر Docker أكثر تقنيات إنشاء الحاويات شهرةً وقد أبدع المعايير التي تستخدمها معظم تقنيات إنشاء الحاويات حاليًا. هذا المنتج تقنيًا هو مجموعة منتجات تساعد في إدارة الصور والحاويات وتمنحنا القدرة على العمل مع كل ميزاتها، إذ سيتولى Docker مثلًا مهمة تحويل الصور إلى حاويات. هناك أداةٌ تُدعى Docker Compose لإدارة حاويات دوكر، إذ تسمح لك بتنسيق العمل على عدة حاويات في نفس الوقت، لهذا سنستخدمها في هذا القسم لبناء بيئة تطوير محلية مركّبة، ولم يعد هناك حاجةٌ لنثبت Node عند الانتهاء من إعداد بيئة التطوير هذه. يبقى هناك مجموعةٌ من المصطلحات التي علينا أن نعرّج عليها، لكننا سنتجاهل ذلك مؤقتًا لنتعلم أكثر عن دوكر. لنبدأ من الأمر docker container run الذي يُستخدم لتشغيل الصور ضمن حاوية. لهذا الأمر الهيكلية التالية: container run *IMAGE-NAME* التي تخبر دوكر بإنشاء حاويةٍ من الصورة. ومن الميزات الجيدة لهذا الأمر هو إمكانية تشغيل حاوية حتى لو لم تُنزّل الحاوية على الجهاز بعد. لننفِّذ الأمر: § docker container run hello-world ستكون النتيجة العديد من المُخرجات، لهذا سنحاول فصلها إلى عدة أقسام كي نفسر هذه المخرجات معًا. رقمنا الأسطر لسهولة شرح ما فيها، فلن تجد أية أرقام لأسطر الخرج في الواقع: 1. Unable to find image 'hello-world:latest' locally 2. latest: Pulling from library/hello-world 3. b8dfde127a29: Pull complete 4. Digest: sha256:5122f6204b6a3596e048758cabba3c46b1c937a46b5be6225b835d091b90e46c 5. Status: Downloaded newer image for hello-world:latest لم يعثُر الأمر على الصورة في جهازك، لذلك نزّلها من مُسجّل مجاني يُدعى Docker Hub. بإمكانك الاطلاع على صفحة الويب الخاصة بهذا المسجّل باستخدام المتصفح. تنص الرسالة الأولى أن الصورة "hello-world:latest" غير موجودة بعد، وهذا ما يكشف بعض التفاصيل عن الصور بحد ذاتها، إذ تتألف أسماء الصور من عدة أجزاء بصورةٍ مشابهة لعناوين URL وهي على الشكل: registry/organisation/image:tag في حالتنا يعوَّض عن الحقول الثلاثة المفقودة بالقيم الافتراضية: index.docker.io/library/hello-world:latest يعرض السطر الثاني اسم المنظمة والمكتبة التي تحصل على الصورة منها، ويُختصر عنوان المكتبة في Docker Hub إلى _. يعرض السطران الثالث والخامس الحالة فقط، لكن ما يضمه السطر الرابع هو المهم. لكل صورة معرّف تعمية مختزل وفريد digest بناءً على الطبقات التي بُنيت منها الصورة. وفي واقع الأمر تُنشئ كل تعليمة أو خطوة استُخدمت في بناء الصورة طبقةً فريدة، لهذا يستخدم دوكر معرّف التعمية المختزل لتمييز أن الصورة بقيت كما هي. وهكذا نرى أن خرج الأمر السابق هو سحب ثم إخراج معلومات عن الصورة. تخبرنا الحالة بعد ذلك أن نسخةً جديدةً من الصورة "hello-world:latest" قد نُزّلت بالفعل. بإمكانك سحب الصورة باستخدام الأمر docker image pull hello-world ومتابعة ما سيحدث. يمثل التالي خرجًا ناتجًا عن حاوية، ويشرح ما يجري عند تنفيذ الأمر docker container run hello-world: Hello from Docker! This message shows that your installation appears to be working correctly. To generate this message, Docker took the following steps: 1. The Docker client contacted the Docker daemon. 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. (amd64) 3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading. 4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal. To try something more ambitious, you can run an Ubuntu container with: $ docker container run -it ubuntu bash Share images, automate workflows, and more with a free Docker ID: https://hub.docker.com/ For more examples and ideas, visit: https://docs.docker.com/get-started/ يتضمن الخرج بعض الأشياء الجديدة التي يجب تعلّمها مثل: Docker daemon: وهي خدمة في الخلفية تتحقق من عمل الحاوية. Docker client: واجهة للتفاعل مع الخدمة السابقة. لقد تفاعلنا مع الصورة الأولى وأنشأنا حاوية من هذه الصورة، وتلقينا الخرج أثناء تنفيذ الحاوية. التمرين 12.2 لا تتطلب منك بعض هذه التمارين كتابة أية شيفرات أو إعدادات تهيئة في ملف. عليك أن تستخدم في هذا التمرين الأمر script لتسجيل الأوامر التي استخدمتها. جرّب ذلك بتنفيذ التعليمة script لتبدأ التسجيل ثم الأمر "echo "hello لتوليد خرج ما، ومن ثم التعليمة exit لإيقاف التسجيل. تُسجِّل تلك التعليمات أفعالك في ملف اسمه "typescript". يمكنك أيضًا نسخ ولصق جميع الأوامر التي استخدمتها في ملف نصي إن لم تستطع استخدام script. التمرين 12.2 تشغيل حاويتك الثانية استخدم script لتسجيل ما تفعله واحفظ الملف بالاسم "script-answers/exercise12_2.txt". نفّذ ما يلي: الخطوة الأولى: شغّل حاوية بنفس أسلوب تشغيل الحاوية، إذ ستربطك هذه الخطوة مباشرةً مع الحاوية عبر تعليمات bash وستكون قادرًا على الوصول إلى كل الملفات والأدوات الموجودة ضمن الحاوية. لهذا نفذ الخطوات التالية ضمن الحاوية. الخطوة الثانية: أنشئ المجلد "usr/src/app/". الخطوة الثالثة: أنشئ الملف "usr/src/app/index.js/". الخطوة الرابعة: نفّذ التعليمة exit للخروج من الحاوية. ابحث عن طريقة إنشاء الملفات أو المجلدات بمساعدة محركات البحث إن لزم الأمر. صورة Ubuntu يحتوي الأمر التالي المُستخدم في تشغيل حاوية "ubuntu": docker container run -it ubuntu bash بعض الإضافات عن أمر تشغيل الحاوية "hello-world". سنستخدم التعليمة help-- لفهم الموضوع أكثر، وسنجتزئ بعض المعلومات التي تتعلق بحديثنا مما يرد في خرج العملية: $ docker container run --help Usage: docker container run [OPTIONS] IMAGE [COMMAND] [ARG...] Run a command in a new container Options: ... -i, --interactive Keep STDIN open even if not attached -t, --tty Allocate a pseudo-TTY ... تتحقق الرايتان أو الخياران it- من قدرتنا على التفاعل مع الحاوية، ثم نحدد بعد ذلك أن الصورة التي نشغلها هي "ubuntu"، ثم لدينا الأمر bash الذي يُنفَّذ داخل الحاوية عندما نشغلها. يمكنك تجريب أوامر أخرى يمكن للصورة أن تُنفذها، مثل: docker container run --rm ubuntu ls إذ يرتب الأمر ls كل الملفات في المجلد ضمن قائمة، بينما يُزيل الأمر rm-- الحاوية بعد التنفيذ، فلا تُحذف الحاويات تلقائيًا عادةً. لنتابع الآن مع أول حاوية "ubuntu" من خلال الملف "index.js" داخلها. لقد توقفت الحاوية عن العمل في اللحظة التي خرجنا منها. ولاستعراض جميع الحاويات، نستخدم الأمر container ls -a. إذ تستعرض الراية a- أو all-- كل الحاويات التي خرجنا منها توًا. $ docker container ls -a CONTAINER ID IMAGE COMMAND CREATED STATUS NAMES b8548b9faec3 ubuntu "bash" 3 minutes ago Exited (0) 6 seconds ago hopeful_clarke أمامنا خياران يتعلقان بالتخاطب مع الحاوية: المعرّف في العمود الأول الذي يمكن استخدامه للتفاعل مع الحاوية في أي وقت، كما تقبل معظم الأوامر تمرير اسم الحاوية إليها. لاحظ أن الحاوية في مثالنا قد ولّدت تلقائيًا باسم "hopeful_clarke". تُظهر حالة الحاوية أننا خرجنا منها منذ 6 ثوان ويمكنك تشغيلها مجددًا باستخدام الأمر start الذي يقبل معرّف الحاوية id أو اسمها: $ docker start hopeful_clarke hopeful_clarke يشغّل الأمر الحاوية نفسها التي عملنا عليها سابقًا، لكن انتبه إلى أننا أغفلنا لسوء الحظ استخدام الراية interactive-- وبالتالي لن نتمكن من التفاعل معها. مع ذلك فالحاوية تعمل فعلًا، ويُظهر تنفيذ الأمر container ls -a ذلك، إلا أننا لا نستطيع التواصل معها: $ docker container ls -a CONTAINER ID IMAGE COMMAND CREATED STATUS NAMES b8548b9faec3 ubuntu "bash" 7 minutes ago Up (0) 15 seconds ago hopeful_clarke يمكنك أيضًا تجاهل الراية a- في الأمر السابق لعرض الحاويات التي تعمل فقط: $ docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS NAMES 8f5abc55242a ubuntu "bash" 8 minutes ago Up 1 minutes hopeful_clarke لنُنهي عمل الحاوية باستخدام الأمر kill يليه اسم الحاوية أو معرّفها ثم نحاول ثانية: $ docker kill hopeful_clarke hopeful_clarke يُرسل الأمر الإشارة SIGKILL إلى العملية ليجبرها على التوقف، ونستطيع التأكد من حالتها بتنفيذ الأمر container ls -a: $ docker container ls -a CONTAINER ID IMAGE COMMAND CREATED STATUS NAMES b8548b9faec3 ubuntu "bash" 26 minutes ago Exited 2 seconds ago hopeful_clarke لنشغل الحاوية الآن في وضع التفاعل: $ docker start -i hopeful_clarke root@b8548b9faec3:/# سنجري بعض التعديلات على الملف"index.js" بإضافة شيفرة جافا سكربت، لكن تنقصنا الأداة اللازمة لذلك. سيكون المحرر Nano خيارًا جيدًا حاليًا، لذلك سننزّله ونشغله. يمكنك الاطلاع على طريقة استخدام هذا المحرر بإجراء بحث بسيط ضمن أي محرك بحث. انتبه أنه لا حاجة لاستخدام التعليمة sudo فنحن فعليًا داخل المجلد الجذري: root@b8548b9faec3:/# apt-get update root@b8548b9faec3:/# apt-get -y install nano root@b8548b9faec3:/# nano /usr/src/app/index.js وهكذا يكون Nano جاهزًا للاستخدام. التمرينان 12.3 - 12.4 حاول أن تحل التمرينين التاليين: التمرين 12.3: 101 Ubuntu استخدم script لتسجيل ما تفعله واحفظ الملف بالاسم "script-answers/exercise12_3.txt" واستخدم المحرر النصي Nano لتعديل الملف "usr/src/app/index.js/" ضمن الحاوية بإضافة السطر التالي: console.log('Hello World') يمكنك الاطلاع على طريقة استخدام محرر Nano بإجراء بحث بسيط ضمن أي محرك بحث. التمرين 12.4: 102 Ubuntu استخدم script لتسجيل ما تفعله واحفظ الملف بالاسم "script-answers/exercise12_4.txt" ثم ثبّت Node طالما أنك ضمن الحاوية، ثم شغِّل الملف "index" باستخدام الأمر node /usr/src/app/index.js. من الصعب أحيانًا إيجاد تعليمات واضحة لتثبيت Node لهذا إليك بعض الأوامر التي يمكنك نسخها ولصقها: curl -sL https://deb.nodesource.com/setup_16.x | bash apt install -y nodejs لا بد أيضًا من تثبيت curl ضمن الحاوية بطريقة مشابهة لتثبيت Nano، وتأكد بعد اكتمال التثبيت من قدرتك على تنفيذ شيفرتك داخل الحاوية. root@b8548b9faec3:/# node /usr/src/app/index.js Hello World أوامر دوكر أخرى بعد أن ثبتنا Node ضمن الحاوية يمكننا تنفيذ شيفرة جافاسكريبت JavaScript داخلها. لنحاول الآن إنشاء صورة جديدة من الحاوية بعد التعديلات التي أجريناها. للأمر الصيغة التالية: "commit" + اسم أو معرف الحاوية + اسم الصورة الجديدة. يمكنك استخدام الأمر container diff للتحقق من التغييرات بين الصورة الأصلية والجديدة. $ docker commit hopeful_clarke hello-node-world كما يمكنك عرض قائمة بالصور الموجودة باستخدام image Is على النحو التالي: $ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE hello-node-world latest eef776183732 9 minutes ago 252MB ubuntu latest 1318b700e415 2 weeks ago 72.8MB hello-world latest d1165f221234 5 months ago 13.3kB وستتمكن من تشغيل الصورة الجديدة على النحو التالي: docker run -it hello-node-world bash root@4d1b322e1aff:/# node /usr/src/app/index.js هناك عدة طرق لتحقيق النتيجة نفسها. لهذا دعونا نتحوّل إلى حل أفضل، وسنبدأ أولًا بإزالة الحاوية القديمة باستخدام الأمر container rm: $ docker container ls -a CONTAINER ID IMAGE COMMAND CREATED STATUS NAMES b8548b9faec3 ubuntu "bash" 31 minutes ago Exited (0) 9 seconds ago hopeful_clarke $ docker container rm hopeful_clarke hopeful_clarke أنشئ الملف "index.js" في المجلد الحالي واكتب التعليمة ('console.log('Hello, World ضمنها. لا حاجة للحاويات بعد، ولنتفادى أيضًا تثبيت Node. هناك العديد من الصور المفيدة الجاهزة للاستخدام يقدمها Docker Hub، لهذا سنستخدم الصورة " https://hub.docker.com/_/Node" التي تضم Node، وعلينا فقط اختيار الإصدار المناسب. كما تساعد الراية name-- في الأمر container run على تسمية الحاوية: $ docker container run -it --name hello-node node:16 bash سننشئ الآن مجلدًا للشيفرة ضمن الحاوية: root@77d1023af893:/# mkdir /usr/src/app وطالما أننا ضمن الحاوية، شغّل نسخة جديدة من الطرفية ونفّذ الأمر container cp لنسخ الملف من مكان وجوده في جهازك إلى الحاوية: $ docker container cp ./index.js hello-node:/usr/src/app/index.js يمكنك الآن تنفيذ الأمر ضمن الحاوية، كما يمكن تحضيرها على هيئة صورة جديدة، لكن هناك حل أفضل أيضًا. وهذا ما سنتابع البحث فيه لاحقًا. ترجمة -وبتصرف- للفصل Introduction to Containers من سلسلة Deep Dive Into Modern Web Development اقرأ أيضًا أبرز المفاهيم التي يجب عليك الإلمام بها عن الحاويات حاوية دوكر Docker ومخزن APCu في PHP كيفية تثبيت دوكر Docker على فيدورا لينكس
-
سنعرض في هذا المقال طريقة التعامل مع اﻹعدادات اﻷساسية لنظام التشغيل لينكس أوبونتو، من خلال تطبيق "اﻹعدادات" الذي يسمح لك من خلال واجهة رسومية بسيطة وقوية، بضبط معظم ما تحتاجه بصفتك مستثمرًا للنظام، وذلك من إعدادات تتعلق بالعتاد الصلب والاتصال والتطبيقات والخصوصية والحماية واﻹنترنت وإعدادات اللغة وسهولة الوصول أو (اﻹتاحة)، وغيرها من اﻹعدادات. ننصحك قبل قراءة المقال أن تطلع على طريقة التعامل مع سطح مكتب أوبونتو وكذلك طريقة التعامل مع المجلدات والملفات. للوصول إلى هذا التطبيق، انقر على زر "أظهر التطبيقات" ضمن شريط التطبيقات لتظهر لك نافذة التطبيقات، ثم انقر على تطبيق "اﻹعدادات"؛ كما يمكنك الوصول إلى التطبيق مباشرةً من شريط المهام، أو بالنقر على سطح المكتب بالزر اﻷيمن لمؤشر الفأرة، واختيار "إعدادات settings". يعرض الشريط الجانبي للنافذة قوائم منفصلة من اﻹعدادات، تتعلق كل قائمة منها بمجموعة محددة، مثل الاتصالات والمظهر والتنسيقات المحلية واﻹقليمية، وغير ذلك، وسنناقش كل منها بشيء من التفصيل. ملاحظة: قد يتغير شريط المهام في نافذة التطبيق وفقًا للموضوع الذي نضبط إعداداته، إذ تظهر أحيانًا أشرطة مهام إضافية أو أزرار قوائم إضافية لتطبيق التغييرات التي نريدها بسرعة. إعدادات شبكات الاتصال يتيح لك أبونتو الاتصال مع معظم شبكات الاتصالات السلكية واللاسلكية، وحزم الاتصال العريضة عبر شبكات الهاتف المحمول وغيرها الكثير، لذلك سنطلع في الفقرات القادمة على طريقة إعداد وضبط بعض أنواعها. 1. إعداد واي فاي WiFi بالنقر على هذا الخيار، يبدأ معالج اﻹعدادات بالبحث عن الشبكات المرئية المتوفرة في الجوار ويضعها في قائمة على رأسها الشبكة اللاسلكية التي تتصل معها حاليًا. وفي حال لم تتصل بعد بأي شبكة لكنك تعرف معلومات الاستيثاق الخاصة بالولوج إليها (كأن تكون شبكتك الشخصية أو شبكة الشركة التي تعمل فيها)، انقر على هذه الشبكة، وستظهر لك نافذة تطلب إليك كتابة عبارة الوصول المشتركة: بعد كتابة كلمة السر أو عبارة الاستيثاق، انقر على الزر "اتصل"، وستصبح الشبكة جاهزةً للاستخدام؛ كما سيظهر إلى جوارها إشارة (صح)، باﻹضافة إلى أيقونة تشير إلى قوة اﻹشارة المستقبلة. قد يظهر إلى جوار الشبكة التي تتصل بها أيضًا أيقونة على شكل قفل لتدلّك أنّ هذه الشبكة محمية بآلية تشفير محددة. تفحص تفاصيل الاتصال لتفحص إعدادات الشبكة التي اتصلت بها، انقر على أيقونة اﻹعدادات في آخر السطر الذي يعرض اسم الشبكة. تعرض نافذة التفاصيل بعض النقاط العامة، مثل قوة اﻹشارة المستقبلة، وسرعة الاتصال، وعناوين بروتوكول الإنترنت IP، وعنوان بروتوكول وصول الوسائط (ماك MAC)، وذلك تحت مسمى "عنوان العتاد". وما يهمنا فعلًا في هذه النافذة هما الخياران: اتصل تلقائيًا: باختياره سيتصل الحاسوب بهذه الشبكة تلقائيًا بمجرد التقاط إشارتها في الجوار لتصبح الشبكة المبدئية. اجعله متاحًا للمستخدمين اﻵخرين: بتفعيل هذا الخيار يمكن لأي مستخدم مسجَّلٍ في نظامك أن يصل إلى هذه الشبكة، وإن لم يكن مفعلًا ستستخدمه أنت فقط. تشاهد أسفل النافذة زرًا باللون اﻷحمر عنوانه "انسَ الاتصال". انقر عليه لحذف الشبكة الحالية من قائمة الشبكات التي وجدها النظام في الجوار، وذلك إن أردت إعادة ضبط معلومات الاتصال من جديد. لن نتابع في تفصيل بقية النوافذ لأن مواضيعها خارج نطاق سلسلة المقالات هذه، لكن تجدر اﻹشارة إلى أنّ نافذة "أمان"، ستعرض لك كلمة السر التي أدخلتها عند تأسيس اتصالك مع الشبكة، ويمكنك العودة إليها دائمًا إن أردت تذكر الكلمة، وذلك بعد تفعيل خيار "أظهر كلمة السر". لتطبيق أية تغييرات أجريتها على تفاصيل شبكة الاتصال، انقر الزر "طبّق" أعلى يسار النافذة أو "ألغِ" للخروج دون أن تحفظ أية تغييرات. الاتصال بشبكة لاسلكية مخفية الشبكة اللاسلكية المخفية هي شبكة لا تبث هويتها SSID، ويُعَد ذلك عاملًا من عوامل اﻷمان. إن كنت تعرف بوجود شبكة لاسلكية خفية في الجوار وتريد الاتصال بها، فعليك أولًا أن تعرف هويتها تمامًا، وأن تعرف نظام التشفير الذي تستخدمه. وعند توفر هاتين المعلومتين، انقر على زر قائمة الاتصال اللاسلكي في شريط مهام نافذة اﻹعدادات (يبدو على شكل ثلاث نقاط متعامدة)، ثم اختر بعد ذلك اﻷمر "اتصل بشبكة مخفية" من القائمة المنسدلة، وستظهر لك الشاشة التالية: عليك كتابة اسم الشبكة في حقل "اسم الشبكة network name"، واختيار نظام اﻷمان من الحقل "أمان واي-فاي wifi security". انقر بعد ذلك على زر "اتصل" لتتمكن من استخدام الشبكة إن كان ما أدخلته صحيحًا. تفعيل نقطة بث شبكة لاسلكية إن أردت مشاركة اتصالك باﻹنترنت مع مجموعة من المستخدمين اﻵخرين عن طريق إنشاء شبكة لا سلكية خاصة بك، فاﻷمر بسيط جدًا، وذلك من خلال الخيار "شغل نقطة بث واي فاي" المتواجد ضمن قائمة الاتصال اللاسلكي التي أشرنا إليها سابقًا. اختر اسمًا لشبكتك ثم ضع كلمة السر التي ينبغي على المشتركين استخدامها لولوج الشبكة، ثم انقر على الأمر "شغّل". 2. إعداد الشبكة يعرض هذا اﻹعداد بقية أنواع شبكات الاتصال التي يدعمها حاسوبك، مثل الاتصال السلكي عبر محول الشبكة السلكية ethernet، أو اتصالات الحزمة العريضة عن طريق الشبكات الخلوية، أو الشبكات الافتراضية الخاصة VPN، وغيرها. تعرض لقطة الشاشة السابقة وجود محوّل شبكة سلكي تحت القسم "سلكي Wired" لكنه معطل لأن كابل الشبكة غير موصول بالمحوّل؛ بينما يشير القسم الثاني "حزمة خلوية عريضة Mobile Broadband" إلى وجود اتصال فعّال باﻹنترنت عن طريق الاتصال بالهاتف المحمول، ويعرض لك تفاصيل هذا الاتصال. يدل القسم الثالث "VPN" على وجود شبكة افتراضية اسمها "VPN1" لكنها معطلة؛ أما القسم اﻷخير، فهو مخصص لحالات وجود "وسيط الشبكة proxy"، وهو خادم وسيط بين حاسوبك وبقية الحواسيب على الشبكة؛ أو بين حاسوبك وشبكة اﻹنترنت. لا يوجد وسيط شبكة كما تدل اﻹعدادات، فهو معطل؛ لكن إن كان موجودًا، فانقر على زر اﻹعدادات في حقل "وسيط الشبكة"، ثم اختر اﻷمر "تلقائي" للكشف عن اﻹعدادات تلقائيًا أو "يدويًا" ﻹدخالها بنفسك. تظهر لك عند النقر على زر اﻹعدادات إلى جوار كل نوع من أنواع الاتصالات المعروضة نافذة تفاصيل الاتصال، وهي مشابهة من ناحية الخيارات لتفاصيل اتصال واي-فاي، ولن نخوض فيها أيضًا. 3. إعداد البلوتوث يتيح لك هذا الإعداد القدرة على البحث عن أية أجهزة تدعم اتصال بلوتوث إن كان حاسوبك يدعم هذا الخيار، وسيظهر حاسوبك عند اﻵخرين بنفس الاسم الذي اخترته أثناء تثبيت النظام. يبحث حاسوبك باستمرار عن اﻷجهزة الموجودة في النطاق ويعرضها في قائمة. للإتصال بأي جهاز مجاور موجود ضمن قائمة اﻷجهزة التي وجدها النظام، انقر على اسم الجهاز، وستظهر لك نافذة تحتوي على رمز التحقق الذي ينبغي على الجهاز المستهدف إدخاله لتأكيد قبول الاتصال مع حاسوبك. عندما يقبل الطرف اﻵخر الاقتران مع حاسوبك، سيكون كل شيء جاهزًا ﻹرسال الملفات واستقبالها. إرسال ملف من حاسوبك إلى جهاز مقترن به عبر بلوتوث عندما يقترن حاسوبك بجهاز ما، وتظهر عبارة "متصل" إلى جوار هذا الجهاز، فانقر عندها على هذا الجهاز، وستظهر لك النافذة التالية. انقر على الزر "إرسال ملفات"، ثم اختر الملف الذي تريد إرساله من النافذة التي ستظهر. ستبدأ بعدها مباشرةً عملية النقل وتدلك نافذة اﻹرسال على تقدم العملية. استقبال ملف من جهاز مقترن بحاسوبك عبر بلوتوث تتم عملية الاستقبال آليًا من الجهاز المقترن بالحاسوب، ويخبرك النظام بأنه استقبل ملفًا من هذا الجهاز وخزّنه في التنزيلات عندما تنتهي العملية. إعدادات مظهر سطح المكتب ومحتوياته يتيح لك سطح مكتب جنوم خيارات متعددة للتحكم بمظهر سطح المكتب وموقع شريط التطبيقات وسماته اللونية وحجم أيقوناته وغيرها. سنتعرف في هذه الفقرة على أهم اﻹعدادات التي يمكن التحكم بها من خلال تطبيق "إعدادات". اختيار خلفية سطح المكتب افتح تطبيق اﻹعدادات، ثم انتقل إلى الخيار "خلفية"، وستظهر لك الشاشة التالية: يمكنك اختيار أية صورة من الصور الموجودة أصلًا مع هذه النسخة من أوبونتو، وذلك بالنقر عليها لتتحول مباشرةً إلى خلفية لسطح المكتب؛ كما يمكن النقر على زر "أضف صورة" لاختيار صورة أخرى من اختيارك. اختيار سمة وضبط خصائص شريط التطبيقات يتيح لك أوبونتو مجموعة إعدادات لضبط المظهر العام لسطح المكتب والنوافذ من ناحية الشكل واللون، وهذا ما سنناقشه تاليًا. اختيار السمة اللونية انتقل إلى خيار "مظهر" في الشريط الجانبي لنافذة اﻹعدادات، وستظهر لك النافذة التالية: يتيح لك سطح مكتب جنوم إمكانية استخدام ثلاث سمات لسطح المكتب وهي: سمة اﻷلوان الفاتحة light: وتتميز النوافذ بخلفيتها البيضاء وشريط المهام الرمادي الفاتح. السمة القياسية standard: وتتميز النوافذ فيها بالخلفية البيضاء وشريط المهام الأسود. سمة اﻷلوان الداكنة dark: وتتميز النوافذ فيها بالخلفية الرمادية الداكنة وشريط المهام اﻷسود. بالنقر على أي من هذه السمات نقرةً واحدة، سيُطبّق النظام التغيرات مباشرةً. التحكم بإعدادات عرض شريط التطبيقات يتيح لك سطح مكتب جنوم الخيارات التالية: اﻹخفاء التلقائي Auto-hide the dock: بالنقر على الزالقة المجاورة لهذا الخيار، ستتحول إلى اللون البنفسجي ويختفي شريط التطبيقات عن سطح المكتب لكن بمجرد اﻹقتراب من مكانه يظهر مجددًا. التحكم بحجم اﻷيقونات Icon size: يمكنك جعل اﻷيقونات كبيرة بحجم 64 بكسل أو صغيرة بحجم 16 بكسل، أو أن تختار أي قيمة بينهما بما يناسبك عن طريق الزالقة المجاورة لهذا الخيار. وتجدر اﻹشارة إلى أنّ القيمة الافتراضية لحجم اﻷيقونات هي 48 بكسل. شاشة عرض الشريط show on screen: يُمكِّنك هذا الخيار من إظهار الشريط على الشاشة الحالية فقط، أو إظهاره على كل الشاشات المتصلة بحاسوبك، أو ما يُعرف باسم توسعة سطح المكتب. تغيير موقع شريط التطبيقات position on screen: يقع شريط التطبيقات في النسخة العربية عموديًا على يمين الشاشة، لكن إن أردته أن يكون إلى اﻷسفل كما هي حال أشرطة المهام في ويندوز أو ماك، فاختر القيمة "أسفل button"، أو اختر القيمة "يسار left" إن أردته أن يظهر يسارًا. ضبط التنبيهات التنبيهات هي مجموعة من الرسائل النصية أو الصوتية التي يصدرها النظام أو أحد التطبيقات المثبتة ﻹبلاغ المستخدم بوجود مشكلة أو اﻹشارة إلى تنفيذ عمل ما. وتُعَدّ التنبيهات إحدى موارد النظام التي يمكن للبرمجيات الوصول إليها، فعندما يكتمل تحميل برنامج مثلًا، سيعرض لك النظام تنبيهًا على شكل رسالة منبثقة أعلى ومنتصف شريط المهام يخبرك فيها باكتمال التحميل، أو عندما يتصل النظام بشبكة أو ينقطع الاتصال تعرض لك رسائل وتنبيهات صوتية مناسبة. ولضبط التنبيهات التي تريدها أن تظهر أو إهمال تنبيهات لا تعتقد أنها مهمة، فافتح تطبيق "إعدادات"، وانتقل إلى الخيار "التنبيهات": تتيح لك هذه النافذة مجموعتين من الخيارات، اﻷولى تتعلق بالنظام واﻷخرى بالتطبيقات: تنبيهات النظام يمكن التحكم بميزتين تتعلقان بتنبيهات النظام وهما: عدم اﻹزعاج Do not disturb: عند تفعيل هذا الخيار بالنقر على الزالقة المجاورة، سيمنع النظام ظهور أية تنبيهات أيًا كان مصدرها، ويعرض أيقونة عدم اﻹزعاج إلى جوار الساعة وسط شريط المهام. تنبيهات شاشة القفل: سيعرض النظام عند تفعيل هذا الخيار التنبيهات حتى لو كانت شاشة سطح المكتب مقفلة؛ بينما لن يعرض التنبيهات عند تقفل الشاشة في حال لم يكن هذا الخيار مفعلًا (الزالقة إلى اليسار ورمادية اللون). تنبيهات التطبيقات يعرض هذا القسم من النافذة جميع التطبيقات التي تستخدم تنبيهات النظام لعرض رسائل حالة التطبيق. وبالنقر على أيٍ من هذه التطبيقات، ستنبثق نافذة تضم مجموعة من الخيارات هي: التنبيهات: لعرض تنبيهات التطبيق عمومًا أو إبطالها. التنبيهات الصوتية: تفعيل أو إسكات التنبيهات الصوتية. نوافذ التنبيهات المنبثقة: يعرض النظام تنبيهات التطبيق على شكل نوافذ منبثقة عند تفعيل الخيار، ولن يعرضها ضمن قائمة منبثقة، بل ضمن قائمة التنبيهات فقط (تظهر القائمة بالنقر على الساعة في شريط المهام) إن لم يكن مفعلًا. أظهر محتوى الرسائل في نافذة منبثقة: يعرض النظام رسائل التطبيق عند تفعيل الخيار في نوافذ منبثقة مستقلة بدلًا من عرضها في شريط المهام أو في قائمة التنبيهات. تنبيهات شاشة القفل: يعرض تنبيهات التطبيق في شريط المهام أو في قائمة التنبيهات حتى لو كانت الشاشة مقفلة. أظهر محتوى الرسالة في شاشة القفل: عند تمكين هذا الخيار، سيعرض النظام رسالة التطبيق على الشاشة حتى لو كانت مقفلة. البحث في سطح المكتب والتطبيقات سيعرض لك النظام عند النقر على خيار "البحث" ضمن الشريط الجانبي لتطبيق "اﻹعدادات" قائمةً باﻷماكن التي سيبحث فيها النظام عن مدخلاتك عندما تحاول البحث عن شيء ما. تُرتب هذه اﻷماكن وفقًا لأولوية ظهور نتائج البحث المتعلقة بها، فالمكان الموجود أعلى القائمة، ستظهر نتائجه أولًا وهكذا. يمكنك أيضًا تغيير اﻷولوية بالنقر على زر النقاط الثلاث المتعامدة آخر كل حقل واختيار "انقل لأعلى" أو "انقل لأسفل" لرفع ترتيب الحقل أو تخفيضه؛ كما يمكنك النقر على الزالقة المجاورة لكل حقل ﻹلغاء البحث في هذا المكان، أو يمكنك النقر أيضًا على الزالقة الموجودة في شريط مهام النافذة لتعطيل البحث في هذه اﻷماكن. اقرأ أيضًا تعرّف على سطح مكتب أوبونتو 20.04 التعامل مع المجلدات والملفات في أوبونتو 20.04 تغيير اللغة في نظام لينكس أوبنتو إلى العربية
-
يتألف موقع ويب من ملفات عدة منها ملفات المحتوى وملفات الشيفرة وملفات التنسيق والوسائط المتعددة وغيرها، فعندما تبني موقعك، عليك تجميع هذه الملفات ضمن هيكلية معقولة على حاسوبك، والتأكد من أنها قادرة على التواصل مع بعضها وأنّ كل شيء يبدو على ما يرام قبل أن ترفع هذه الملفات إلى الخادم، إذ سيناقش هذا المقال بعض الأمور التي ينبغي الانتباه إليها لكي تنظم ملفاتك ضمن هيكلية واضحة لتكوين موقعك. مكان تجميع موقع ويب على حاسوبك عندما تشرع في بناء موقع ويب على حاسوبك، لا بد أن تُبقي كل الملفات المرتبطة به ضمن مجلد واحد يحاكي في تنظيمه تنظيم الملفات ضمن موقع الويب عندما تنشره، كما يمكنك اختيار أيّ مكان ضمن حاسوبك لوضع هذا المجلد شرط أن يكون إيجاده سهلًا مثل سطح المكتب أو في المجلد الرئيسي Home أو ضمن المجلد الجذري للقرص الصلب. اختر مكانًا لتخزِّن ضمنه مشروع موقع الويب، ثم انشئ مجلدًا جديدًا في هذا المكان وسمِّه web-projects أو ما شابه، إذ سيكون هذا المجلد المكان الذي تخزّن فيه جميع مواقع الويب التي تصممها. انشئ ضمن هذا المجلد مجلدًا جديدًا لتخزين موقعك الأول، وسمِّه test-site أو ما شابه. تسمية الملفات والمجلدات ستلاحظ خلال هذا المقال أننا نسمي المجلدات والملفات بأحرف صغيرة ودون فراغات وذلك لأن: تُعَدّ الكثير من الحواسب وخاصةً الخوادم حساسةً لحالة الأحرف، فإذا وضعت مثلًا صورةً على موقعك عنوانها test-site/MyImage.jpg وأردت تشغيلها من ملف آخر وكتبت العنوان test-site/myimage.jpg، فربما لا تعمل. لا تعامِل خوادم ويب والمتصفحات ولغات البرمجة الفراغات بالطريقة نفسها، فإذا وضعت فراغات في اسم الملف مثلًا، فستعامِل بعض الأنظمة اسم الملف هذا على أساس ملفين منفصلين، إذ تملأ بعض خوادم ويب الفراغات في أسماء الملفات بالرمز "%20" (وهو رمز المسافة الفارغة في عناوين URL)، وتكون النتيجة أخطاءً في جميع الروابط، ومن الأفضل أيضًا فصل الكلمات بشرطة hyphen مثل my-file.html بدلًا من الشرطة السفلية مثل my_file.html، والسبب في ذلك أنّ محرك بحث جوجل يعامل الشرطات على أساس فواصل بين الكلمات بينما لا يعامل الشرطات السفلية بالطريقة ذاتها. خلاصة الأمر أنه عليك اعتياد استخدام الأحرف الصغيرة دون فراغات، واستخدام الشرطات للفصل بين الكلمات حتى تدرك ما تفعل على الأقل، فإنّ تقيدك بذلك يريحك من بعض المشاكل التي قد تنبثق أمامك هنا وهناك. الهيكلية التي ينبغي أن يبنى عليها موقع ويب لنلق نظرةً فيما سيأتي على هيكلية الموقع البسيط الذي نبنيه، إذ يُعَدّ الشيء المشترك بين معظم مشاريع مواقع ويب هو إنشاء ملف HTML يعمل تلقائيًا عند استدعاء الموقع ويُدعى عادة "index"، بالإضافة إلى مجلد يحتوي على الصور وملفات التنسيق وملفات الشيفرة، فلنبن هذه الأشياء إذًا: index.html: استخدم محرر النصوص الذي تملكه لإنشاء ملف جديد يُدعى index.html، ثم احفظه ضمن المجلد test-site، إذ يحتوي هذا الملف عمومًا على محتويات الصفحة الرئيسية للموقع مثل النصوص والصور التي يراها الزائر عند دخول موقعك. المجلد images: أنشئ مجلدًا بهذا الاسم داخل المجلد test-site، إذ يضم كل الصور التي تستخدمها في موقعك. المجلد styles: أنشئ مجلدًا بهذا الاسم ثم احفظه ضمن المجلد test-site، إذ يضم كل الملفات التي تحتوي على شيفرة التنسيقات المورثة CSS والتي تتحكم بمظهر الصفحة مثل لون النصوص والخلفية. المجلد scripts: أنشئ مجلدًا بهذا الاسم ثم احفظه في المجلد test-site، إذ يضم شيفرة جافاسكربت التي تُستخدَم لإضافة وظائف تفاعلية إلى صفحتك مثل الأزرار التي تعرض بيانات عند نقرها. ملاحظة: قد تجد صعوبةً في رؤية أسماء الملفات كاملة على الحواسب التي تشغل النظام ويندوز لأنه يقدِّم خيارًا بإخفاء امتدادات الملفات معروفة النوع، وهذا الخيار مفعَّل افتراضيًا، إذ يمكنك عادةً إيقاف هذا الخيار بالانتقال إلى مستكشف ويندوز Windows Explorer ثم خيارات المجلد Folder Options وبعدها ألغ تفعيل خيار "إخفاء الامتدادات للملفات معروفة النوع Hide extensions for known file types"، كما يمكنك دومًا البحث عبر الويب لإيجاد التفاصيل الخاصة بنسختك من ويندوز. مسارات الملفات لا بد من تحديد مسار الملف بطريقة صحيحة حتى تتمكن الملفات في الموقع من التخاطب مع بعضها بعضًا، ومبدئيًا لا بد من تحديد وجهة ليتمكن أيّ ملف من معرفة مكان الآخر، ولتوضيح الأمر سنكتب بعض الشيفرة في الملف index.html لكي يعرض الصورة التي اخترتها لموقعك البسيط أو أية صورة مناسبة قد تجدها على حاسوبك أو على الويب: انسخ الصورة التي اخترتها إلى المجلد images. افتح الملف index.html وانقل الشيفرة التالية إليه كما هي تمامًا، ولا تكترث حاليًا بمعنى هذه الشيفرة، إذ سنهتم بالتفاصيل لاحقًا: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>My test page</title> </head> <body> <img src="" alt="My test image"> </body> </html> يُدرِج سطر شيفرة HTML التالي الصورة ضمن صفحتك: <img src="" alt="My test image"> لابد من إخبار HTML بمكان وجود الصورة، إذ تتواجد الصورة ضمن مجلد الصور وهذا المجلد موجود في المجلد نفسه الذي يحوي الملف index.html، وبالتالي سنحتاج إلى المسار images/your-image-filename للوصول من هذا الملف إلى الصورة، فإذا كان اسم الصورة firefox-icon.png، لكان المسار images/firefox-icon.png. ضع اسم المسار في شيفرة إدراج الصورة بين علامتي إقتباس بالشكل ""=src، ثم احفظ الملف ثم افتحه باستخدام المتصفح بالنقر المزدوج على أيقونة الملف، إذ ستظهر الآن الصورة المطلوبة. إليك بعض القواعد العامة في تحديد مسارات الملفات: لاستدعاء ملف يقع في المجلد نفسه الذي يقع فيه الملف الذي يستدعي، استخدم فقط اسم هذا الملف مثل my-image.jpg. للإشارة إلى ملف في مجلد فرعي مجاور للملف الذي يستدعي، اكتب اسم المجلد الفرعي متبوعًا بالمحرف "/" ثم اسم الملف المطلوب مثل subdirectory/my-image.jpg. للإشارة إلى ملف يقع في المجلد الأب للمجلد الذي يقع فيه الملف الذي يستدعيه، اكتب نقطتين .. ثم المحرف "/" ثم اسم الملف مثل my-image.jpg/... يمكنك الدمج بين القواعد السابقة كما تشاء مثل ../subdirectory/another-subdirectory/my-image.jpg، وهذا كل شيء تحتاجه إلى الآن. ملاحظة: يستخدِم نظام التشغيل ويندوز الشرطة الخلفية \ وليست الأمامية / لتحديد المسارات مثل C:\Windows، ولكن عليك استخدام الشرطة الأمامية دائمًا عند تطوير مواقع ويب حتى لو عملت على ويندوز. ما الذي يجب فعله أيضا لا شيء الآن، إذ يجب أن تبدو هيكلية موقعك مشابهةً للهيكلية التي تعرضها الصورة التالية: ترجمة -وبتصرف- للمقال Dealing with files اقرأ أيضًا التعامل مع الملفات في البرمجة رفع ملفات موقع الويب إلى خادم على الإنترنت الأدوات المستخدمة في بناء مواقع ويب
-
لقد حان الوقت لتوسيع مشروعنا بعد أن أسسنا له قاعدةً معرفيةً جيدة، وسنسخّر لهذه المهمة كل إمكانيات React Native التي تعلمناها حتى الآن. سنغطي بالإضافة إلى توسيع المشروع نواحٍ جديدة، مثل الاختبارات والموارد الإضافية. اختبار تطبيقات React Native سنحتاج إلى إطار عمل للاختبارات عند البدء باختبار أي نوع من الشيفرة، لتنفيذ مجموعة من الحالات المختبرة، والتدقيق في نتائجها. فلاختبار تطبيق جافا سكربت JavaScript سنجد أن إطار العمل Jest هو الأكثر شعبية لأداء المهمة. ولاختبار تطبيقات React Native المبنية على المنصة Expo باستخدام Jest، ستزودنا Expo بمجموعة من إعدادات تهيئة على هيئة مجموعة جاهزة تدعى jest-expo. ولكي نستخدم المدقق ESLint في ملف اختبار Jest، سنحتاج إلى الإضافة eslint-plugin-jest الخاصة به. لنبدأ إذًا بتثبيت الحزم: npm install --save-dev jest jest-expo eslint-plugin-jest لاستخدام المجموعة jest-expo في Jest، لا بدّ من إضافة إعدادات التهيئة التالية في الملف "package.json"، مع سكربت الاختبار: { // ... "scripts": { // other scripts... "test": "jest" }, "jest": { "preset": "jest-expo", "transform": { "^.+\\.jsx?$": "babel-jest" }, "transformIgnorePatterns": [ "node_modules/(?!((jest-)?react-native|@react-native(-community)?)|expo(nent)?|@expo(nent)?/.*|@expo-google-fonts/.*|react-navigation|@react-navigation/.*|@unimodules/.*|unimodules|sentry-expo|native-base|react-native-svg|react-router-native)" ] }, // ... } يطلب الخيار transform من Jest تحويل شيفرة الملفين "js." و"jsx." باستخدام مصرّف Babel. بينما يُستخدم الخيار transformIgnorePatterns لتجاهل مجلدات محددة ضمن المجلد "node_modules" أثناء تحويل الملفات. وتتطابق تقريبًا إعدادات Jest هذه مع تلك المقترحة في توثيق Expo. لاستخدام الإضافة eslint-plugin-jest، لا بدّ من وضعها ضمن مصفوفة الإضافات والموسِّعات في الملف "eslintrc.". { "plugins": ["react", "react-native"], "settings": { "react": { "version": "detect" } }, "extends": ["eslint:recommended", "plugin:react/recommended", "plugin:jest/recommended"], "parser": "@babel/eslint-parser", "env": { "react-native/react-native": true }, "rules": { "react/prop-types": "off", "react/react-in-jsx-scope": "off" } } وللتأكد من نجاح التهيئة، أنشئ المجلد "tests" في المجلد "src"، ثم أنشئ ضمنه الملف "example.js" وضع فيه الشيفرة التالية: describe('Example', () => { it('works', () => { expect(1).toBe(1); }); }); لننفذ الآن هذا المثال من خلال الأمر: npm test. ينبغي أن يشير خرج العملية إلى نجاح الاختبار المتواجد في الملف "src/tests/example.js". تنظيم الاختبارات تقتضي إحدى طرق تنظيم ملفات الاختبارات بوضعها في مجلد وحيد يُدعى "tests". ويفضّل عند استخدام هذه الطريقة وضع ملفات الاختبار ضمن المجلدات الفرعية الملائمة كما نفعل مع ملفات الشيفرة، إذ ستُوضع الاختبارات التي تتعلق بالمكوّنات مثلًا في المجلّد "components"، وتلك التي تتعلق بالخدمات ستُوضع في المجلّد "utils"، وهكذا. سينتج عن هذا التنظيم الهيكلية التالية: src/ __tests__/ components/ AppBar.js RepositoryList.js ... utils/ authStorage.js ... ... أما الطريقة الأخرى فهي وضع ملف الاختبار بجانب ملف الشيفرة الذي سيستخدمه. ويعني ذلك أننا سنضع الملف الذي يتضمن اختبارات للمكوّن AppBar مثلًا في نفس المجلد الذي يحتوي شيفرة هذا المكوّن. وستنتج عن هذه الطريقة في التنظيم الهيكلية التالية: src/ components/ AppBar/ AppBar.test.jsx index.jsx ... ... شيفرة المكوّن في المثال السابق موجودةٌ في الملف "index.jsx"، بينما ستجد الاختبارات في الملف "AppBar.test.jsx". ولكي تجد بسهولة الملفات التي تحتوي الاختبارات، عليك أن تضعها في المجلد "tests" أو في ملفات تحمل إحدى اللاحقتين "test." أو "spec."، أو أن تهيئ يدويًا الأنماط العامة global patterns. اختبار المكونات بعد أن ضبطنا إعدادات Jest وجربناها بتنفيذ مثال بسيط، حان الوقت لنتعرف على كيفية اختبار المكوّنات. يتطلب اختبار المكوّنات، كما نعلم، طريقة لتفسير الخرج الناتج عن تصيير المكوّن ومحاكاة عملية معالجة الأحداث المختلفة مثل الضغط على زر. ولحسن الحظ تتوافر عائلة من مكتبات الاختبار تؤمن مكتبات لاختبار مكوًنات واجهة المكوّن في منصات عدة. وتتشارك جميع هذه المكتبات بواجهة برمجية واحدة API لاختبار مكونات واجهة المستخدم بأسلوب يركّز على المستخدم. تعرّفنا في القسم 5 على إحدى هذه المكتبات وهي React Testing Library. لكن لسوء الحظ فهذه المكتبة مخصصة فقط لاختبار تطبيقات الويب المبنية باستخدام React. لكن بالطبع هناك مقابل لها في React Native وهي المكتبة React Native Testing Library التي سنستخدمها في اختبار مكوّنات تطبيقات React Native. وكما ذكرنا فإن جميع هذه المكتبات تتشارك بنفس الواجهة البرمجية، ولن تضطر إلى تعلّم الكثير من المفاهيم الجديدة. بالإضافة إلى هذه المكتبة، سنحتاج إلى مجموعة من مُطابقات Jest مخصصة للمكتبة مثل toHaveTextContent و toHaveProp. تزوّدنا المكتبة jest-native بهذه المُطابقات، لذلك لا بدّ أولًا من تثبيت هذه الحزم: npm install --save-dev react-test-renderer@17.0.1 @testing-library/react-native @testing-library/jest-native ملاحظة: إذا واجهت مشاكل في اعتمادية النظير peer، فتأكد من مطابقة إصدار react-test-renderer مع نسخة react للمشروع في أمر npm install المذكور أعلاه. يمكنك التحقق من إصدار react من خلال تنفيذ الأمر: npm list react --depth=0 وفي حال فشل التثبيت بسبب مشكلات اعتمادية النظير، فحاول مرةً أخرى باستخدام الراية --legacy-peer-deps في الأمر npm install. لنتمكن من استخدام هذه المُطابقات، علينا توسيع الكائن expect العائد للمكتبة Jest. ويجري تنفيذ ذلك باستخدام ملف إعداد عام. لذلك أنشئ الملف "setupTests.js" في المجلد الجذري لمشروعك، وهو نفسه المجلد الذ++ي يحتوي الملف "package.json". أضف الشيفرة التالية إلى هذا الملف: import '@testing-library/jest-native/extend-expect'; هيئ الملف السابق على انه ملف إعداد ضمن أوامر تهيئة Jest الموجودة في الملف "package.json": { // ... "jest": { "preset": "jest-expo", "transform": { "^.+\\.jsx?$": "babel-jest" }, "transformIgnorePatterns": [ "node_modules/(?!(jest-)?react-native|react-clone-referenced-element|@react-native-community|expo(nent)?|@expo(nent)?/.*|react-navigation|@react-navigation/.*|@unimodules/.*|unimodules|sentry-expo|native-base|@sentry/.*|react-router-native)" ], "setupFilesAfterEnv": ["<rootDir>/setupTests.js"] } // ... } تعتمد المكتبة على مفهومين أساسيين هما الاستعلامات (query) وإطلاق الأحداث (fire event)؛ إذ تُستخدم الاستعلامات لاستخلاص مجموعة من العقد من المكوّن الذي يُصيّر بواسطة الدالة render، ونستفيد منها في اختبار وجود عنصر أو كائن ما، مثل نص معين، ضمن المكوّن المُصيَّر. يمكنك تحديد العقد باستخدام الخاصية testID ثم الاستعلام عنها باستخدام الدالة getByTestId. تقبل جميع المكوّنات البنيوية في الخاصية testID. وإليك مثالًا عن كيفية استخدام الاستعلامات: import { Text, View } from 'react-native'; import { render } from '@testing-library/react-native'; const Greeting = ({ name }) => { return ( <View> <Text>Hello {name}!</Text> </View> ); }; describe('Greeting', () => { it('renders a greeting message based on the name prop', () => { const { debug, getByText } = render(<Greeting name="Kalle" />); debug(); expect(getByText('Hello Kalle!')).toBeDefined(); }); }); تعيد الدالة render الاستعلامات ودوال مساعدة أخرى مثل الدالة debug التي تطبع شجرة React بطريقة واضحة بالنسبة للمستخدم. استخدم هذه الدالة إن كنت غير متأكد من شكل المكوّن الذي صيَّرته الدالة render. يمكننا أن نحصل على العقدة Text التي تحتوي نصًا محددًا عن طريق الدالة getByText. وللاطلاع على كل الاستعلامات المتاحة، راجع توثيق المكتبة React Native Testing. يُستخدم المُطابق toHaveTextContent للتأكد من أن المحتوى النصي للعقدة صحيح. وللاطلاع كذلك على كل المُطابقات الخاصة بالمكتبة React Native، راجع توثيق jest-native. وتذكر أنك ستجد معلومات عن كل مُطابقٍ عام في توثيق Jest. أما المفهوم الثاني الذي ترتكز عليه المكتبة React Native Testing في عملها هو إطلاق الأحداث firing events، إذ يمكننا إطلاق حدث ضمن عقدة معينة باستخدام توابع الكائن fireEvent. سنستفيد من ذلك على سبيل المثال في طباعة نص ضمن حقل نصي أو على زر. وإليك مثال عن اختبار تسليم نموذج بسيط: import { useState } from 'react'; import { Text, TextInput, Pressable, View } from 'react-native'; import { render, fireEvent } from '@testing-library/react-native'; const Form = ({ onSubmit }) => { const [username, setUsername] = useState(''); const [password, setPassword] = useState(''); const handleSubmit = () => { onSubmit({ username, password }); }; return ( <View> <View> <TextInput value={username} onChangeText={(text) => setUsername(text)} placeholder="Username" /> </View> <View> <TextInput value={password} onChangeText={(text) => setPassword(text)} placeholder="Password" /> </View> <View> <Pressable onPress={handleSubmit}> <Text>Submit</Text> </Pressable> </View> </View> ); }; describe('Form', () => { it('calls function provided by onSubmit prop after pressing the submit button', () => { const onSubmit = jest.fn(); const { getByPlaceholderText, getByText } = render(<Form onSubmit={onSubmit} />); fireEvent.changeText(getByPlaceholderText('Username'), 'kalle'); fireEvent.changeText(getByPlaceholderText('Password'), 'password'); fireEvent.press(getByText('Submit')); expect(onSubmit).toHaveBeenCalledTimes(1); // تحوي أول وسيط من أول استدعاء onSubmit.mock.calls[0][0] expect(onSubmit.mock.calls[0][0]).toEqual({ username: 'kalle', password: 'password', }); }); }); نريد في هذا الاختبار أن نتأكد من أنّ الدالة onSubmit ستُستدعى على نحوٍ صحيح بعد أن تُملأ حقول النموذج باستخدام التابع fireEvent.changeText ويُضغط على الزر باستخدام التابع fireEvent.press. ولتحري إذا ما استُدعيت الدالة onSubmit وبأية وسطاء، يمكن استخدام الدالة المقلّدة mock function؛ والدوال المقلدة هي دوال ذات سلوك مبرمج مسبقًا كأن تعيد قيمةً محددة. كما يمكننا تحديد توقّعات expectations لهذه الدوال، فمثلًا "توقّع أن الدالة المقلّدة قد استدعيت مرةً واحدة". يمكنك الاطلاع على قائمة بكل التوقعات المتاحة في توثيق توقعات Jest. عدّل وجرّب في تلك الأمثلة السابقة، وأضف اختبارات جديدة في المجلد "tests "، بحيث تتأكد من فهمك للأفكار السابقة قبل الغوص أعمق في موضوع الاختبارات. التعامل مع الاعتماديات أثناء الاختبارات يُعد اختبار المكوّنات سهلًا نوعًا ما لأنها صرفة بشكلٍ أو بآخر. فلا تعتمد المكوّنات الصرّفة على التأثيرات الجانبية side effects، مثل طلبات الشبكة أو استخدام واجهات برمجية أصيلة، مثل AsyncStorage. فالمكوّن Form ليس صرفًا بقدر المكون Greeting، لأن تغيرات حالته قد تُعد أثرًا جانبيًا. لكن الاختبارات تبقى سهلةً مع ذلك. لنلقِ الآن نظرةً على استراتيجية لاختبار المكوّنات مع الآثار الجانبية، وسنختار على سبيل المثال المكوّن RepositoryList من تطبيقنا. لهذا المكوّن حاليًا أثر جانبي واحد وهو استعلام GraphQl الذي يحضر قائمة بالمستودعات المقيّمة. يُستخدم المكوّن حاليًا كالتالي: const RepositoryList = () => { const { repositories } = useRepositories(); const repositoryNodes = repositories ? repositories.edges.map((edge) => edge.node) : []; return ( <FlatList data={repositoryNodes} // ... /> ); }; export default RepositoryList; ينتج التأثير الجانبي عن استخدام الخطاف useRepositories الذي يرسل استعلام GraphQL. هناك عدة طرق لاختبار المكوّن، إحدى هذه الطرق هي تقليد استجابات المكتبة Apollo Client كما هو مشروح في توثيقها. أما الطريقة الأبسط هي افتراض أن المكوّن يعمل كما نتوقع (ويُفضل من خلال اختباره)، ثم استخلاص الشيفرة "الصرفة" له ووضعها في مكوّن آخر مثل RepositoryListContainer: export const RepositoryListContainer = ({ repositories }) => { const repositoryNodes = repositories ? repositories.edges.map((edge) => edge.node) : []; return ( <FlatList data={repositoryNodes} // ... /> ); }; const RepositoryList = () => { const { repositories } = useRepositories(); return <RepositoryListContainer repositories={repositories} />; }; export default RepositoryList; يحتوي المكوّن الآن التأثيرات الجانبية فقط وتنفيذه سهل. يمكن اختبار المكوّن RepositoryListContainer بتمرير بيانات عن مستودع من القائمة من خلال الخاصية repositories، والتأكد أنّ معلومات المحتوى المُصيَّر صحيحة. التمرينان 10.17 - 10.18 10.17 اختبار قائمة المستودعات المقيمة أنجز اختبارًا يتأكد أن المكوّن RepositoryListContainer سيصيِّر بصورةٍ صحيحة كلًا من: اسم المستودع ووصفه واللغة وعدد التشعبات وعدد النجوم ومعدل التقييم وعدد التقييمات. تذكر أنه بالإمكان الاستفادة من المطابق toHaveTextContent في التحقق من احتواء العقدة على سلسلة نصية محددة. const RepositoryItem = (/* ... */) => { // ... return ( <View testID="repositoryItem" {/* ... */}> {/* ... */} </View> ) }; كما يمكنك استخدام الاستعلام getAllByTestId للحصول على كل العقد التي تمتلك قيمة محددة للخاصية testID على هيئة مصفوفة، وإن كنت غير متأكد من المكوّن الذي صُيَّر، استفد من الدالة debug في تفكيك نتيجة التصيير. const repositoryItems = getAllByTestId('repositoryItem'); const [firstRepositoryItem, secondRepositoryItem] = repositoryItems; // توقع شيئًا من عنصر المستودع الأول والثاني استخدم الشيفرة التالية أساسًا لاختبارك: describe('RepositoryList', () => { describe('RepositoryListContainer', () => { it('renders repository information correctly', () => { const repositories = { pageInfo: { totalCount: 8, hasNextPage: true, endCursor: 'WyJhc3luYy1saWJyYXJ5LnJlYWN0LWFzeW5jIiwxNTg4NjU2NzUwMDc2XQ==', startCursor: 'WyJqYXJlZHBhbG1lci5mb3JtaWsiLDE1ODg2NjAzNTAwNzZd', }, edges: [ { node: { id: 'jaredpalmer.formik', fullName: 'jaredpalmer/formik', description: 'Build forms in React, without the tears', language: 'TypeScript', forksCount: 1619, stargazersCount: 21856, ratingAverage: 88, reviewCount: 3, ownerAvatarUrl: 'https://avatars2.githubusercontent.com/u/4060187?v=4', }, cursor: 'WyJqYXJlZHBhbG1lci5mb3JtaWsiLDE1ODg2NjAzNTAwNzZd', }, { node: { id: 'async-library.react-async', fullName: 'async-library/react-async', description: 'Flexible promise-based React data loader', language: 'JavaScript', forksCount: 69, stargazersCount: 1760, ratingAverage: 72, reviewCount: 3, ownerAvatarUrl: 'https://avatars1.githubusercontent.com/u/54310907?v=4', }, cursor: 'WyJhc3luYy1saWJyYXJ5LnJlYWN0LWFzeW5jIiwxNTg4NjU2NzUwMDc2XQ==', }, ], }; // أضف شيفرة اختبارك هنا }); }); }); يمكن أن تضع ملف الاختبار أينما تشاء، لكن من الأفضل أن تتبع إحدى الطرق التي ذكرناها في تنظيم ملفات الاختبار. استخدم المتغير repositories مثل مصدر للبيانات في الاختبار، ولا حاجة لتغيير قيمته. تحتوي البيانات على مستودعين، فعليك بالتالي التحقق من وجود المعلومات في كليهما. 10.18 اختبار نموذج تسجيل الدخول أنجز اختبارًا يتحقق أن الدالة onSubmit ستُستدعى بوسطاء مناسبين عندما يُملأ حقلي اسم المستخدم وكلمة المرور في النموذج ويُضغط على زر الإرسال. ينبغي أن يكون الوسيط الأول كائنًا يمثّل قيم النموذج، ويمكنك إهمال بقية وسطاء الدالة. تذكر أنك قد تستعمل توابع fireEvent لتنفيذ أحداث ودوال مقلِّدة للتحقق من استدعاء معالج الحدث onSubmit أو لا. لا حاجة لاختبار أي شيفرة متعلقة بالمكتبة Apollo Client أو AsyncStorage والموجودة في الخطاف useSignIn. وكما فعلنا في التمرين السابق، استخلص الشيفرة الصرفة وضعها في مكوّن خاص واختبره. انتبه إلى إرسالات نماذج Formik فهي غير متزامنة، فلا تتوقع استدعاء الدالة onSubmit مباشرة بعد الضغط على زر الإرسال. يمكنك الالتفاف على المشكلة بجعل دالة الاختبار دالة غير متزامنة باستخدام التعليمة Async واستخدام الدالة المساعدة waitFor العائدة للمكتبة React Native Testing. كما يمكنك يمكن أن تستخدم الدالة waitFor لانتظار تحقق التوقعات. فإن لم يتحقق التوقع خلال فترة محددة، سترمي الدالة خطأً. إليك مثالًا يشير إلى أسلوب استخدام هذه الدالة: import { render, fireEvent, waitFor } from '@testing-library/react-native'; // ... describe('SignIn', () => { describe('SignInContainer', () => { it('calls onSubmit function with correct arguments when a valid form is submitted', async () => { //صيّر المكوّن ثم املأ الحقول النصية ثم اضغط زر الإرسال await waitFor(() => { // توقع أن تُستدعى دالة الإرسال مرة واحد وأن يكون الوسيط الأول صحيحًا }); }); }); }); توسيع التطبيق سنبدأ باستخدام كل ما تعلمناه في توسيع تطبيقنا، فلا يزال التطبيق يفتقر لبعض النواحي، مثل عرض معلومات مستودع وتسجيل مستخدمين جدد. سنركز في التمارين القادمة على هذه النقاط. التمرينات 10.19 - 10.24 10.19: واجهة لعرض مستودع واحد أنجز واجهةً لعرض معلومات عن مستودع واحد، تتضمن نفس المعلومات التي تُعرض في قائمة المستودعات بالإضافة إلى زر لفتح المستودع في غيت هب Github. من الجيد أن تجد طريقةً لإعادة استخدام المكونين RepositoryItem و RepositoryList وأن تعرض الزر الذي أشرنا إليه بناء على خاصية محددة تعيد قيمة منطقية مثلًا. ستجد عنوان المستودع ضمن الحقلurl العائد للنوع "Repository" في تخطيط GraphQL. تستطيع إحضار مستودع واحد من خادم Apollo بإجراء الاستعلام repository. يُمرَّر إلى هذا الاستعلام وسيط واحد وهو المعرّف المميز id للمستودع. إليك مثالًا عن استخدام الاستعلام repository. { repository(id: "jaredpalmer.formik") { id fullName url } } اختبر استعلامك كما هو معتاد في أرضية عمل Apollo قبل استخدامه في التطبيق. إن لم تكن على دراية بتخطيط GrapQL أو الاستعلامات التي يتيحها، افتح النافذة "docs" أو النافذة "schema" في أرضية عمل GraphQL. وإن واجهتك صعوبة في استخدام المعرف id مثل متغير في الاستعلام، توقف قليلًا لتطلع على توثيق Apollo Client بما يخص الاستعلامات. لتطلع على طريقة التوجه إلى عنوان URL في المتصفح، اقرأ توثيق Expo حول واجهة الربط البرمجية Linking API، لأنك ستحتاج ذلك عند تنفيذك للزر الذي يفتح المستودع في GitHub. ينبغي أن تمتلك واجهة العرض عنوانًا خاصًا بها، ومن الجيد أن تحدد المعرّف المميز id للمستودع ضمن المسار الذي يوجهك نحو هذا العنوان مثل معامل مسار، كي تستطيع الوصول إليه باستخدام الخطاف useParams. ينبغي أن يكون المستخدم قادرًا على الوصول إلى واجهة العرض بالضغط على المستودع ضمن قائمة المستودعات. ومن الممكن تنفيذ ذلك بتغليف المكوّن RepositoryItem داخل المكّون البنيوي Pressable في المكوّن RepositoryList، ثم استخدام الدالة navigate لتغيير العنوان من خلال معالج الحدث onPress. استخدم الخطاف useNavigate أيضًا للوصول إلى الكائن دالة navigate. ستبدو النسخة النهائية لواجهة عرض مستودع واحد قريبة من الشكل التالي: 10.20: قائمة بالآراء حول مستودع بعد أن أنجزنا واجهة عرض لمستودع وحيد، سنعرض تقييمات المستخدمين ضمن هذه الواجهة. ستجد التقييمات في الحقل reviews العائد للنوع "Repository" في تخطيط GraphQL. تشكل التقييمات قائمةً صغيرةً مرقمةً يمكن الحصول عليها باستخدام الاستعلام repositories. وإليك مثالًا عن طريقة إحضار قائمة التقييمات لمستودع واحد: { repository(id: "jaredpalmer.formik") { id fullName reviews { edges { node { id text rating createdAt user { id username } } } } } } يحتوي الحقل text لكل تقييم على رأي المستخدم للنص، ويحتوي الحقل rating على قيمة عددية بين 0 و100، أما الحقل craetedAt فيحتوي على بيانات إنشاء هذا التقييم، وأخيرًا يحتوي الحقل user معلومات عن مُنشئ التقييم ويحمل النوع "User". نريد أن نعرض التقييمات على شكل شريط تمرير، مما يجعل المكوّن البنيوي FlatList ملائمًا لأداء المهمة. ولكي تعرض معلومات مستودع محدد في أعلى الواجهة، استخدم الخاصية ListHeaderComponent للمكون FlatList. يمكنك أيضًا استخدام المكوّن البنيوي ItemSeparatorComponent لإضافة مساحة بيضاء بين العناصر المعروضة كما هو الحال بين عناصر المكوّن RepositoryList مثلًا. إليك مثالًا عن هيكلية التنفيذ: const RepositoryInfo = ({ repository }) => { // Repository's information implemented in the previous exercise }; const ReviewItem = ({ review }) => { // Single review item }; const SingleRepository = () => { // ... return ( <FlatList data={reviews} renderItem={({ item }) => <ReviewItem review={item} />} keyExtractor={({ id }) => id} ListHeaderComponent={() => <RepositoryInfo repository={repository} />} // ... /> ); }; export default SingleRepository; ستبدو النسخة النهائية عن تطبيق قائمة المستودعات مشابهة للشكل التالي: البيانات التي تراها تحت اسم المستخدم لمنشئ التقييم هي تاريخ الإنشاء الذي نجده في الحقل createdAt وهو من النوع "Review"، وينبغي أن يكون تنسيق البيانات مريحًا للمستخدم مثل الصيغة "يوم.شهر.سنة". قد يساعدك تثبيت المكتبة date-fns على تنسيق تاريخ الإنشاء بالاستفادة من الدالة format. يمكن إنجاز الحاوية ذات الشكل الدائري باستخدام خاصية التنسيق borderRadius. ولتفعل هذا عليك تثبيت قيمتي الخاصيتين width و height، ثم ضبط خاصية التنسيق border-radius عند القيمة "width/2". 10.21: نموذج التقييم أنجز نموذجًا لإنشاء تقييم جديد لمستودع مستخدمًا المكتبة Formik. ينبغي أن يضم النموذج أربعة حقول هي: اسم دخول مالك المستودع. اسم المستودع. التقييم على هيئة قيمة عددية. رأي المستخدم على هيئة نص. تحقق من الحقول مستخدمًا تخطيط Yup، بحيث تتأكد أن: اسم المستخدم لمالك المستودع هو قيمة نصية إجبارية. اسم المستودع هو قيمة نصية إجبارية. التقييم هو قيمة عددية إجبارية بين 0 و100. رأي المستخدم هو قيمة نصية اختيارية. اطلع على توثيق Yup لإيجاد المُقيَّمات validators المناسبة، واستخدم رسائل خطأ مناسبة عند استخدامك لهذه المُقيِّمات، إذ يمكنك تعريف رسالة الخطأ مثل وسيط للتابع message العائد للمقيّم. يمكنك أيضًا توسيع نص الحقل ليمتد على عدة أسطر باستعمال الخاصية multiline العائدة للمكون TextInput. استخدم الطفرة createReview لإنشاء تقييم جديد، واطلع على وسطاء الطفرة بفتح إحدى النافذتين "docs" أو "schema " في أرضية عمل GraphQL. ويمكنك استخدام الخطاف useMutation لإرسال الطفرة إلى خادم Apollo. بعد نجاح عمل الطفرة createReview، حوّل المستخدم إلى واجهة عرض المستودع التي أنجزناها في التمرين السابق. نفّذ ذلك باستخدام التابع navigate بعد أن تستخرج كائن التاريخ باستخدام الخطاف useNavigate. يمتلك التقييم الذي أنشأته حقلًا باسم "repositoryId" يمكنك استخدامه لتأسيس مسار لعنوان التقييم. استخدم سياسة الإحضار "cache-and-network" لتمنع جلب بيانات الذاكرة المؤقتة مع الاستعلام repository في واجهة عرض مستودع وحيد. يمكنك استخدامها مع الخطاف على النحو التالي: useQuery(GET_REPOSITORY, { fetchPolicy: 'cache-and-network', // خيارات أخرى }); انتبه إلى أن التقييم سيكون فقط لمستودعات GitHub العامة الموجودة فعلًا، وأن المستخدم سيقيَّم مستودعًا محددًا مرة واحدة فقط. ليس عليك الآن التعامل مع حالات الخطأ هذه، بل فقط إظهار الخطأ مع الرمز المحدد والرسالة المناسبة. جرّب ما نفّذته على أحد المستودعات العامة التي تملكها، أو أية مستودعات عامة أخرى. ينبغي أن يتمكن المستخدم من الوصول إلى واجهة التقييم من خلال شريط التطبيق. لذلك أنشئ نافذة جديدة عنوانها "Create a review". ينبغي أن تكون النافذة مرئية للمستخدم الذي سجل دخوله فقط. وعليك أن تحدد أيضًا عنوانًا لواجهة التقييم. ستبدو النسخة النهائية للتطبيق مشابهة للشكل التالي: التُقطت شاشة التطبيق هذه بعد إخفاق إرسال بيانات نموذج لإظهار شكله في هذه الحالة. 10.22: نموذج تسجيل مستخدم جديد أنجز نموذجًا لتسجيل مستخدم جديد مستخدمًا Formik. ينبغي أن يضم النموذج ثلاثة حقول: اسم مستخدم، كلمة مرور، وتأكيدًا لكلمة المرور. تحقق من صحة البيانات في النموذج مستخدمًا تخطيط Yup ومتبعًا مايلي: اسم المستخدم هو سلسلة نصية إجبارية طولها بين 1 و 30. كلمة المرور هي سلسلة نصية إجبارية طولها بين 1 و 5. تأكيد كلمة المرور يتطابق تمامًا مع كلمة المرور. قد يربكك قليلًا تأكيد كلمة المرور، لكن يمكن إنجاز الأمر بالاستفادة من التابعين oneOf وref كما هو مبين في إرشادات هذا المشروع. يمكنك إنشاء مستخدم جديدة باستخدام الطفرة createUser، ويمكنك الإطلاع على كيفية استخدامها من خلال توثيق أرضية عمل Apollo. سجّل دخول المستخدم الجديد بعد إنشاء حسابه الخاص مستخدمًا الخطاف useSignIn كما فعلنا في نموذج تسجيل الدخول. وجِّه المستخدم الجديد بعد تسجيل دخوله إلى واجهة عرض المستودعات المقيّمة. ينبغي أن يكون المستخدم قادرًا على الوصول إلى واجهة تسجيل مستخدم جديد من خلال شريط التطبيق، وذلك بالضغط على نافذة "Sign up" التي ستظهر فقط للمستخدم قبل أن يسجّل دخوله. ستبدو النسخة النهائية لواجهة تسجيل مستخدم جديد مشابهة للصورة التالية: التُقطت شاشة التطبيق هذه بعد إخفاق إرسال بيانات نموذج لإظهار شكله في هذه الحالة. 10.23: ترتيب بيانات تطبيق قائمة المستودعات المقّيمة تُرتّب المستودعات حتى هذه اللحظة وفقًا لتاريخ تقييم المستودع. أنجز آلية تسمح للمستخدم أن يختار أساسًا لترتيب هذه المستودعات وفقًا لما يلي: المستودعات الأخيرة: سيكون المستودع الذي قُيَّم آخيرًا وللمرة الأولى في أعلى القائمة. هذا الترتيب هو المتبع حاليًا، وينبغي أن يكون الخيار الإفتراضي. المستودعات الأعلى تقييمًا: سيكون المستودع الذي يحمل أعلى قيمة لمعدّل التقييم في أعلى القائمة. المستودعات الأدنى تقييمًا: سيكون المستودع الذي يحمل أدنى قيمة لمعدّل التقييم في أعلى القائمة. يمتلك الاستعلام repositories الذي يحضر قائمة المستودعات وسيطًا يدعى orderby يمكنك استخدامه لتحديد أسلوب الترتيب المتبع، إذ يمتلك هذه الوسيط قيمتين فقط هما: CREATED_AT: الترتيب وفق تاريخ التقييم لأول مرة. RATING_AVERAGE: الترتيب على أساس معدل التقييم. كما يمتلك الاستعلام وسيطًا يدعى orderDirection ويستخدم لتغيير جهة الترتيب. يملك الوسيط الأخير قيمتين، هما: ASC (تصاعدي، من التقييم الأدنى إلى الأعلى) و DESC (تنازلي، من التقييم الأعلى إلى الأدنى). يمكن المحافظة على خيار الترتيب باستخدام الخطاف useState على سبيل المثال، كما يمكن تمرير المتغيرات التي يستخدمها الاستعلام repositories إلى الخطاف useRepositories مثل وسطاء. يمكنك أيضًا استخدام المكتبة react-native-picker أو المكوّن Menu العائد للمكتبة React Native Paper لإنجاز شيفرة ترتيب القائمة، كما يمكنك استخدام الخاصية ListHeaderComponent العائدة للمكوّن FlatList لتزويدك بترويسة تحتوي على مكوّن الاختيار. ستبدو النسخة النهائية لهذه الميزة، وبناء على مكوَّن الاختيار الذي اعتمدته، قريبةً من الصورة التالية: 10.24: انتقاء مستودعات محددة من القائمة يتيح خادم Apollo ترشيح المستودعات بناءً على اسمها أو اسم مالكها، ويمكن إنجاز ذلك باستخدام الوسيط searchKeyword العائد للاستعلام repositories. إليك مثالًا عن كيفية استخدام الوسيط مع الاستعلام: { repositories(searchKeyword: "ze") { edges { node { id fullName } } } } أنجز ميزةً في التطبيق لترشيح قائمة المستودعات المقيّمة بناءً على كلمة محددة. ينبغي أن يكون المستخدم قادرًا على الكتابة ضمن مربع إدخال نصي وستظهر نتائج الفلترة وفقًا للكلمة المكتوبة مباشرة أثناء الكتابة. يمكنك استخدام المكوّن البسيط TextInput، أو استخدام مكوّن أكثر عصرية مثل المكوّن Searchbar العائد للمكتبة React Native Paper على أنه مربع إدخال نصي. ضع مكوّن الإدخال النصي ضمن ترويسة المكوّن FlatList. ولتفادي تنفيذ عدد كبير من الاستعلامات أثناء كتابة المستخدم للكلمة بسرعة، اختر آخر سلسة كتبها بعد تأخير بسيط. تدعى هذه التقنية بالتريّث debouncing. تمثّل المكتبة use-debounce حلًا جيدًا لتأخير متغيّر الحالة، بعد أن تستخدم زمن انتظار معقول مثل 500 ميلي ثانية. خزّن قيمة النص الذي يُكتب في مربع الإدخال مستخدمًا الخطاف useState، ومرر القيمة المُؤخَّرة إلى الاستعلام كقيمة للوسيط searchKeyword. قد تعترضك مشكلة فقدان مكون الإدخال النصي تركيز الدخل بعد كتابة كل حرف، وذلك لأن المحتوى الذي تقدّمه الخاصية ListHeaderComponent سيُلغى باستمرار. يمكن حل المشكلة بتحويل المكوّن المسؤول عن تصيير المكوّن FlatList إلى مكوّن صنف class component ومن ثم تعريف دالة تصيير الترويسة إلى خاصية للصنف على النحو التالي: export class RepositoryListContainer extends React.Component { renderHeader = () => { // يحوي خاصيات المكون this.props const props = this.props; // ... return ( <RepositoryListHeader // ... /> ); }; render() { return ( <FlatList // ... ListHeaderComponent={this.renderHeader} /> ); } } ستبدو النسخة النهائية لميزة انتقاء المستودعات قريبةً من الصورة التالية: الترقيم بطريقة المؤشرات عندما تعيد الواجهة البرمجية قائمةً مرتبةً من العناصر من مجموعةٍ ما، فإنها ستعيد مجموعةً جزئيةً من العناصر من أصل المجموعة الكاملة لتقليل عرض حزمة الاتصال مع الخادم وتقليل الذاكرة المستخدمة لتخزين القائمة في تطبيق المستخدم. يمكن أن نطلب تلك المجموعة الجزئية لتوافق معاملات محددة لكي يستطيع المستخدم أن يطلب مثلًا أول عشرين عنصرًا منها ابتداءًا من عنصر محدد. تدعى هذه التقنية عادة بالترقيم pagination. وعندما نستطيع الحصول على قائمة بعد عنصر محدد بمؤشر معيّن، سنكون أمام الترقيم المبني على المؤشرات cursor-based pagination. فالمؤشر إذًا هو تحديدٌ لعنصر في قائمة مرتبة. لنلقي نظرةً على قائمة المستودعات المرقمة التي يعيدها الاستعلام repositories باستخدام الاستعلام التالي: { repositories(first: 2) { totalCount edges { node { id fullName createdAt } cursor } pageInfo { endCursor startCursor hasNextPage } } } يبلِّغ الوسيط first الواجهة البرمجية ان تعيد فقط أول مستودعين. وإليك مثالًا عن الاستجابة لهذا الاستعلام: { "data": { "repositories": { "totalCount": 10, "edges": [ { "node": { "id": "zeit.next.js", "fullName": "zeit/next.js", "createdAt": "2020-05-15T11:59:57.557Z" }, "cursor": "WyJ6ZWl0Lm5leHQuanMiLDE1ODk1NDM5OTc1NTdd" }, { "node": { "id": "zeit.swr", "fullName": "zeit/swr", "createdAt": "2020-05-15T11:58:53.867Z" }, "cursor": "WyJ6ZWl0LnN3ciIsMTU4OTU0MzkzMzg2N10=" } ], "pageInfo": { "endCursor": "WyJ6ZWl0LnN3ciIsMTU4OTU0MzkzMzg2N10=", "startCursor": "WyJ6ZWl0Lm5leHQuanMiLDE1ODk1NDM5OTc1NTdd", "hasNextPage": true } } } } يعتمد تنسيق الكائن الناتج والوسطاء على مواصفات اتصالات مؤشر أرضية عمل GraphQL للترحيل، والتي أصبحت مواصفات ترقيم صفحات شائعة جدًا واعتُمدت على نطاقٍ واسع في واجهة برمجة تطبيقات GitHub's GraphQL API. سيحتوي الكائن الذي يحمل النتيجة مصفوفةً باسم edges تحتوي بدورها على عناصر لها سمتين الأولى هي العقدة node والأخرى هي المؤشر cursor؛ إذ تحتوي العقدة على المستودع بحد ذاته كما نعرف؛ أما المؤشر فهو تمثيلٌ مشفّر للعقدة بأسلوب "Base64". ويحتوي المؤشر على المعرّف id للمستودع بالإضافة إلى تاريخ إنشائه. هذه هي كل المعلومات التي نريدها لكي نشير إلى العنصر عندما تُرتَّب العناصر وفق تاريخ إنشاء المستودع. يحتوي الكائن pageInfoعلى معلومات مثل المؤشرات على بداية ونهاية المصفوفة. دعونا نتأمل الحالة التي نريد فيها مجموعة العناصر التي تلي آخر عنصر من المجموعة الحالية وهو العنصر "zeit/swr". يمكننا إسناد قيمة الحقل endCursor إلى الوسيط after للاستعلام على النحو التالي: { repositories(first: 2, after: "WyJ6ZWl0LnN3ciIsMTU4OTU0MzkzMzg2N10=") { totalCount edges { node { id fullName createdAt } cursor } pageInfo { endCursor startCursor hasNextPage } } } والآن سنحصل على العنصرين التاليين، وسنستمر في هذه العملية حتى يأخذ الحقل hasNextPage القيمة false، وهذا يعني أننا وصلنا آخر القائمة، ولتتعمق أكثر في الترقيم المتعلق بالمؤشرات، إقرأ المقالة التي عنوانها Pagination with Relative Cursors على موقع Shopify، حيث تقدم المقالة الكثير من التفاصيل عن طريقة كتابة الشيفرة بالإضافة إلى الفوائد من استخدام الترقيم بالمؤشرات مقارنةً بالترقيم وفق ترتيب العنصر index-based. التمرير اللانهائي تُصمّم القوائم المرتبة عموديًا في تطبيقات سطح المكتب أو تطبيقات الهواتف الذكية بتقنية تدعى التمرير اللانهائي - infinite scrolling. ويعتمد مبدأ هذه التقنية على النقاط التالية: إحضار المجموعة الأولية من العناصر. عند وصول المستخدم إلى آخر عنصر من هذه المجموعة، يجري إحضار المجموعة التالية من العناصر التي تبدأ من العنصر الذي يلي آخر عنصر من المجموعة السابقة. تتكرر الخطوة الثانية حتى يتوقف المستخدم عن تمرير شريط القائمة أو عندما يتجاوز حدًا معينًا من مرات التمرير. ويشير الاسم "تمرير لانهائي" إلى أن القائمة ستبدو لانهائية، فسيبقى المستخدم قادرًا على تمرير العناصر ضمن الشريط وستُعرض العناصر بصورةٍ مستمرة أيضًا. لنرى كيف سننفذ ذلك عمليًا من خلال خطاف Apollo Client الذي يُدعى useQuery. يضم توثيق Apollo Client تفاصيل كثيرة عن طريقة تنفيذ الترقيم باستخدام المؤشرات. لننجز إذًا ميزة التمرير اللانهائي لعرض قائمة المستودعات المقيّمة. علينا أولًا أن نحدد متى يصل المستخدم إلى آخر عنصر في القائمة. ولحسن الحظ، يمتلك المكون FlatList الخاصية onEndReached التي تستدعى الدالة التي ستنفذ العملية عندما يصل المستخدم إلى آخر عنصر من القائمة. يمكنك التحكم بوقت استدعاء الدالة onEndReach باستخدام الخاصية onEndReachedThreshold. غيِّر شيفرة المكوّن FlatList الموجود ضمن المكوّن RepositoryList لكي يستدعي الدالة حالما يصل المستخدم إلى العنصر الأخير: export const RepositoryListContainer = ({ repositories, onEndReach, /* ... */, }) => { const repositoryNodes = repositories ? repositories.edges.map((edge) => edge.node) : []; return ( <FlatList data={repositoryNodes} // ... onEndReached={onEndReach} onEndReachedThreshold={0.5} /> ); }; const RepositoryList = () => { // ... const { repositories } = useRepositories(/* ... */); const onEndReach = () => { console.log('You have reached the end of the list'); }; return ( <RepositoryListContainer repositories={repositories} onEndReach={onEndReach} // ... /> ); }; export default RepositoryList; جرّب عملية التمرير إلى نهاية قائمة المستودعات، وستظهر رسالةً في سجل العمل مفادها أنك وصلت إلى العنصر الأخير. علينا الآن أن نحضر مزيدًا من المستودعات في اللحظة التي نصل فيها إلى نهاية العناصر. يمكن إنجاز ذلك باستخدام الدالة fetchMore التي يؤمنها الخطاف useQuery. يمكننا استخدام سياسة الحقل field policy لوصف عميل Apollo وكيفية دمج المستودعات الموجودة في ذاكرة التخزين المؤقت مع المجموعة التالية من المستودعات، إذ تُستخدم سياسات الحقول عمومًا لتخصيص سلوك ذاكرة التخزين المؤقت أثناء عمليات القراءة والكتابة باستخدام دوال القراءة والدمج. دعنا نضيف سياسة حقل للاستعلام repositories في ملف "apolloClient.js" على النحو التالي: import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client'; import { setContext } from '@apollo/client/link/context'; import Constants from 'expo-constants'; import { relayStylePagination } from '@apollo/client/utilities'; const { apolloUri } = Constants.manifest.extra; const httpLink = createHttpLink({ uri: apolloUri, }); const cache = new InMemoryCache({ typePolicies: { Query: { fields: { repositories: relayStylePagination(), }, }, }, }); const createApolloClient = (authStorage) => { const authLink = setContext(async (_, { headers }) => { try { const accessToken = await authStorage.getAccessToken(); return { headers: { ...headers, authorization: accessToken ? `Bearer ${accessToken}` : '', }, }; } catch (e) { console.log(e); return { headers, }; } }); return new ApolloClient({ link: authLink.concat(httpLink), cache, }); }; export default createApolloClient; كما ذكرنا سابقًا، يعتمد تنسيق كائن نتيجة ترقيم الصفحات والوسطاء على مواصفات ترقيم الصفحات الخاصة بالترحيل Relay، ولحسن الحظ، يوفر Apollo Client سياسة حقل محددة مسبقًا، relayStylePagination، والتي يمكن استخدامها في هذه الحالة. غيّر في شيفرة الخطاف useRepositories بحيث يعيد الدالة fetchMore بعد فَكِّ تشفيرها، بحيث تستدعي الدالة fetchMore الفعلية مع الحقل endCursor، ثم يُحدّث بعدها الاستعلام بصورة صحيحة وفقًا للبيانات المُحضرة: const useRepositories = (variables) => { const { data, loading, fetchMore, ...result } = useQuery(GET_REPOSITORIES, { variables, // ... }); const handleFetchMore = () => { const canFetchMore = !loading && data?.repositories.pageInfo.hasNextPage; if (!canFetchMore) { return; } fetchMore({ variables: { after: data.repositories.pageInfo.endCursor, ...variables, }, }); }; return { repositories: data?.repositories, fetchMore: handleFetchMore, loading, ...result, }; }; تأكد من وجود الحقلين pageInfo و cursor في الاستعلام repositories كما هو موضح في مثال الترقيم. كما ينبغي عليك أن تضيف الوسيطين first و after إلى الاستعلام. ستستدعي الدالة handleFetchMore الدالة fetchMore العائدة إلى Apollo client إن كان هناك المزيد من العناصر التي ينبغي إحضارها، وذلك بناء على قيمة الخاصية hasNextPage، ومن المفترض أن نمنع إحضار عناصر جديدة طالما أن عملية الإحضار سابقةً لا تزال قيد التنفيذ، إذ ستكون قيمة الحقل loading في هذه الحالة true. سنزود الاستعلام في الدالة fetchMore بالمتغير after الذي يتلقى آخر قيمة endCursor للحقل. وتكون الخطوة الأخيرة استدعاء الدالة fetchMore ضمن دالة معالجة الحدث onEndReach: const RepositoryList = () => { // ... const { repositories, fetchMore } = useRepositories({ first: 8, // ... }); const onEndReach = () => { fetchMore(); }; return ( <RepositoryListContainer repositories={repositories} onEndReach={onEndReach} // ... /> ); }; export default RepositoryList; استخدم قيمة صغيرة نسبيًا (8 مثًلا) للوسيط first عندما تجرب التمرير اللانهائي، وهكذا لن تضطر إلى عرض كثيرٍ من المستودعات، وقد تواجهك أيضًا مشكلة الاستدعاء المباشر لمعالج الحدث onEndReach بعد تحميل واجهة العرض، والسبب على الأرجح، هو العدد الكبير للمستودعات في القائمة، وبالتالي ستصل إلى نهاية القائمة مباشرةً. يمكنك الالتفاف على هذه المشكلة بزيادة قيمة الوسيط first. وبمجرد أن ترى أن قائمة التمرير اللانهائي تعمل جيدًا، يمكنك تجريب قيم كبيرة للوسيط first. التمرينات 10.25- 10.27 10.15: شريط تمرير لانهائي لقائمة المستودعات المقيّمة نفذ شريط تمرير لانهائي لقائمة المستودعات المقيّمة. يمتلك الحقل reviews العائد للنوع "Repository" الوسيطينafter و first كما في الاستعلام repositories. ويمتلك النوع "ReviewConnection" الحقل pageInfo كما يمتلكه النوع "RepositoryConnection". إليك مثالًا عن استعلام: { repository(id: "jaredpalmer.formik") { id fullName reviews(first: 2, after: "WyIxYjEwZTRkOC01N2VlLTRkMDAtODg4Ni1lNGEwNDlkN2ZmOGYuamFyZWRwYWxtZXIuZm9ybWlrIiwxNTg4NjU2NzUwMDgwXQ==") { totalCount edges { node { id text rating createdAt repositoryId user { id username } } cursor } pageInfo { endCursor startCursor hasNextPage } } } } يمكن أن تتشابه سياسة حقل ذاكرة التخزين المؤقت مع استعلام repositories: const cache = new InMemoryCache({ typePolicies: { Query: { fields: { repositories: relayStylePagination(), }, }, Repository: { fields: { reviews: relayStylePagination(), }, }, }, }); استخدم قيمةً صغيرةً نسبيًا للوسيط first عندما تحاول إنجاز قائمة التمرير اللانهائي، وربما ستضطر إلى إنشاء عدة مستخدمين جدد لكي تُقيّم عددًا من المستودعات، وبذلك تصبح قائمة المستودعات المقيّمة طويلة بما يكفي لتجرّب شريط التمرير. اجعل قيمة الوسيط كبيرةً بما يكفي لعدم استدعاء معالج الحدث onEndReach مباشرةً عند عرض الواجهة، وصغيرةً في نفس الوقت بحيث يعرض الشريط المستودعات من جديد عند الوصول إلى نهاية القائمة. وبمجرد أن ترى أن قائمة التمرير اللانهائي تعمل جيدًا، يمكنك تجريب قيم كبيرة للوسيط first. 10.26: واجهة عرض لتقييمات المستخدم أنجز واجهة تُمكِّن المستخدم من عرض ما قيّمه. ينبغي أن يكون المستخدم قادرًا على الوصول إلى هذه الواجهة من خلال الضغط على النافذة "My reviews" في شريط التطبيق بمجرد أن يسّجل دخوله. يمكنك تطبيق أسلوب التمرير اللانهائي إن أردت في هذا التمرين. وإليك الشكل الذي يمكن أن تظهر عليه هذه الواجهة: تذكر أنه بإمكانك الحصول على المستخدم الذي سجّل دخول من خادم Apollo مستعينًا بالاستعلام me. سيعيد الاستعلام النوع "User" الذي يمتلك الحقل review. إن كنت قد أنجزت مسبقًا الاستعلام me يمكنك إعادة استخدامه بعد جعله قادرًا على إحضار الحقل review شرطيWh، وذلك بالاستفادة من توجيه GraphQL الذي يُدعى include. لنفترض أن الاستعلام الحالي قد أنجز بصورةٍ قريبة من التالي: const GET_CURRENT_USER = gql` query { me { # user fields... } } `; يمكنك تزويد الاستعلام بالوسيط includeReviewواستخدام ذلك مع التوجيه include: const GET_CURRENT_USER = gql` query getCurrentUser($includeReviews: Boolean = false) { me { # user fields... reviews @include(if: $includeReviews) { edges { node { # review fields... } cursor } pageInfo { # page info fields... } } } } `; يمتلك الوسيط includeReview القيمة الافتراضية false، لأننا لا نريد أن نسبب حملًا زائدًا على الخادم ما لم نرد صراحةً إحضار المستودعات التي قيّمها المستخدم. إن مبدأ هذا التوجيه بسيط على النحو التالي: إن كانت قيم الوسيط if هي true، أحضر الحقل، وإلا احذفه. 10.27: إضافة أفعال إلى واجهة عرض التقييمات بعد أن أصبح المستخدم قادرًا على استعراض ما قيّمه، لنضف إلى الواجهة بعض الأفعال. ضع أسفل كل تقيم زرين، أحدهما لعرض المستودع، بحيث ينتقل المستخدم بالضغط عليه إلى واجهة عرض مستودع واحد، والآخر لحذف تقييم هذا المستودع. إليك ما قد يبدو عليه الوضع بعد إضافة الزرين: ينبغي أن يلي الضغط على زر الحذف رسالة تأكيد للحذف، فإن أكد المستخدم أمر الحذف ستُنفّذ العملية، وإلا سيُهمل الأمر. يمكنك إنجاز ذلك باستخدام الوحدة البرمجية Alert. وانتبه إلى أن استدعاء التابع Alert.alert لن يفتح رسالة التأكيد في واجهة عرض المنصة Expo، بل عليك استخدام تطبيق جوّال Expo أو المقلّد لترى كيف ستبدو هذه الرسالة. إليك الرسالة التي ينبغي أن تظهر عند الضغط على زر الحذف: يمكنك حذف التقييم باستخدام الطفرة deleteReview. تمتلك هذه الطفرة وسيطًا واحدًا وهو المعرّف id للتقييم الذي سيُحذف. ومن السهل بعد تنفيذ الطفرة تحديث استعلام قائمة المستودعات باستدعاء الدالة refetch. هكذا نكون قد وصلنا إلى التمرين الأخير في هذا المقال، وقد حان وقت تسليم الإجابات إلى GitHub والإشارة إلى التمارين التي أكملتها في منظومة تسيم التمارين. انتبه إلى وضع تمارين هذا المقال في القسم 4 من منظومة التسليم. مصادر إضافية طالما أننا وصلنا إلى نهاية هذا القسم، دعونا نلقي نظرةً على بعض المصادر الهامة للتطوير باستخدام React Native. سنبدأ من توثيق React Native باللغة العربية الذي تقدمه أكاديمية حسوب، والتي تقدم أيضًا توثيق React باللغة العربية، بالإضافة إلى القسم المتخصص باللغة React على موقع الأكاديمية، كما نشير إلى الموقع Awesome React Native الذي يقدم قائمةً مهمةً جدًا من المصادر مثل المكتبات والدورات التعليمية. وبما أن القائمة طويلة جدًا، لنطلع على بعض النقاط. المكتبة React Native Paper المكتبة Paper هي مجموعةٌ من المكوّنات المخصصة والجاهزة للاستخدام في React Native، مبنيةٌ على معايير تصميم Material التي وضعتها غوغل Google. صُممت React Native Paper من أجل لتقدم وظيفة تماثل وظائف المكتبة Material-UI، إذ تقدم مجموعةً واسعةً من مكوّنات واجهة المستخدم UI عالية الجودة التي تدعم إنشاء سمات مخصصة للتطبيق. وتتميز إعدادات استخدام React Native Paper مع تطبيقات React Native المبنية على منصة Expo بالسهولة، حيث يمكنك تجربتها مباشرة في التمارين القادمة إن أردت. المكتبة Styled-components سيعطيك استخدام القوالب المعرّفة المجرّدة tagged template literal -وهي إضافةٌ جديدة في JavaScript-، مع المكتبة styled-components إمكانية كتابة شيفرة CSS فعلية لتنسيق المكوّنات، كما يلغي استخدام هذه المكتبة الحاجة إلى الربط بين المكوّنات والتنسيق، وسيكون استخدام المكوّنات مثل وحدات بناءً تنسيقات على المستوى البرمجي المنخفض سهلًا جدًا. تستخدم المكتبة Styled-components لتنسيق مكوّنات React Native باستخدام تقنية CSS-in-JS. لقد اعتدنا على تعريف تنسيق المكوّنات في React Native باستخدام كائنات JavaScript، وبالتالي لن يكون استخدام CSS-in-JS غريبًا. لكن مقاربة المكتبة Styled-components ستختلف تمامًا عن استخدام التابع StyleSheet.createو الخاصية style. يُعرّف تسيق المكوّن في Styled-components باستخدام ميزة تُدعى القوالب المعرّفة المجرّدة tagged template literal أو كائنات جافا سكربت JavaScript الصِّرفة، التي تُمكننا من تعريف خصائص تنسيق جديدة للمكونات بناءً على خصائص تلك المكوّنات في زمن التنفيذ. سيتيح ذلك الكثير من الإمكانات مثل الانتقال بين السمات القاتمة والمضيئة، كما أنها تدعم كليًا موضوع السمات. إليك مثالًا عن إنشاء المكوّن Text مع إمكانية تغيير تنسيقه بناءً على خصائصه: import styled from 'styled-components/native'; import { css } from 'styled-components'; const FancyText = styled.Text` color: grey; font-size: 14px; ${({ isBlue }) => isBlue && css` color: blue; `} ${({ isBig }) => isBig && css` font-size: 24px; font-weight: 700; `} `; const Main = () => { return ( <> <FancyText>Simple text</FancyText> <FancyText isBlue>Blue text</FancyText> <FancyText isBig>Big text</FancyText> <FancyText isBig isBlue> Big blue text </FancyText> </> ); }; وطالما أن المكتبة styled-components ستعالج تعريف التنسيق، يمكننا استخدام أسلوب كتابة الأفعى snake case المشابه لطريقة كتابة CSS لتسمية الخصائص والواحدات (مثل % أو px)، لكن لا أهمية في الواقع للواحدات، لأن قيم خصائص التنسيق لا تقبل ذلك. للاطلاع على مزيدٍ من المعلومات عن استخدام هذه المكتبة، اقرأ التوثيق الخاص بها. المكتبة React-spring react-spring هي مكتبة رسوم متحركة أساسها المكتبة spring-physics، تغطي معظم احتياجاتك لواجهات مزودة برسوم متحركة، إذ تؤمن لك هذه المكتبة أدوات بالمرونة الكافية لتحويل جميع أفكارك إلى واجهات متحركة. تؤمن لك المكتبة React-spring واجهة برمجية ذات خطافات hook API واضحة الاستخدام لتحريك مكونات React Native. المكتبة React Navigation تؤمن مكتبة React Navigation التنقل والتوجه في تطبيقات React Native هي مكتبةٌ للتحكم بالتنقلات بين وجهات مختلفة في تطبيقات React Native. تتشابه في بعض النواحي مع المكتبة React Router. لكن وعلى خلاف React Router، تقدم مميزات أكثر قربًا للمنصة الأصيلة مثل الإيماءات الأصيلة والرسوميات الانتقالية التي تظهر عند التنقل بين الواجهات المختلفة للتطبيق. كلمة ختامية وهكذا نكون قد أكملنا تطبيقنا وأصبح جاهزًا. لقد تعلمنا خلال هذه الرحلة العديد من المفاهيم الجديدة، مثل إعداد تطبيقات React Native باستخدام المنصة Expo، وطريقة العمل مع مكوّنات React Native البنيوية، وتنسيق مظهر هذه المكوّنات، إضافةً إلى الاتصال مع الخادم واختبار التطبيقات. ستكون الخطوة الأخيرة هي نشر التطبيق على متجر Apple App أو متجر Google Play. يبقى موضوع نشر التطبيق خيارًا شخصيًا وليس أمرًا مُلحًّا، لأنك ستحتاج أيضًا إلى نشر وتوزيع الخادم rate-repository-api، أما من أجل تطبيق React Native بحد ذاته، فعليك أن تُنشئ نسخة بناء لمنصة iOS أو لمنصة أندرويد باتباع الإرشادات في توثيق Expo. وبعد ذلك ستتمكن من توزيع هذه النسخ على متجري Apple App أو Google Play، وستجد تفاصيل عن هذه الخطوة أيضًا في توثيق Expo. ترجمة -وبتصرف- للفصل Testing and extending our application من سلسلة [Deep Dive Into Modern Web Development اقرأ أيضًا المقال السابق: تواصل تطبيق React Native مع الخادم أساسيات React Native مدخل إلى التحريك في React Native
-
إن أهم ما يميز أنظمة التشغيل من ناحية سهولة الاستخدام (وخاصةً للمبتدئين والمستخدمين العاديين)، هي طريقة إدارة النظام للمجلدات والملفات مثل طريقة عرضها وإنشائها والتحكم بموقعها وخصائصها وطريقة الوصول إليها. لهذا تُعد اﻷنظمة التي تُقدّم واجهة رسومية GUI مثل أوبونتو وويندوز وماك أكثرها انتشارًا واستخدامًا؛ وإن كانت هناك اختلافات بينها، وميزات إيجابية وسلبية تتفاوت بين نظام وآخر. نقدم في مقالنا هذا اﻷفكار اﻷساسية المتعلقة بنظام إدارة المجلدات والملفات في أوبونتو، وذلك لكي تتمكن من التعامل بحرية مع الملفات التي تُنشئها وتنظيمها بالطريقة التي تراها مناسبة؛ كما سنلقي نظرةً على وسائط التخزين الداخلية والخارجية، وفكرة تثبيتها Mounting وإزالتها. ستكون قادرًا في نهاية هذا المقال على استثمار حاسوبك بطريقة مريحة ومثمرة، ومتمكنًا من تنظيم ملفاتك والعمل معها بكل ثقة. النافذة الرئيسية "منزل" وفكرة المجلد الجذري تُبنى هيكلية تنظيم المجلدات والملفات في أوبونتو على فكرة وجود مجلد جذري root folder تتفرع عنه بقية المجلدات. يُعرف هذا المجلد باسم "home/"، ولايوجد ضمنه سوى مجلد وحيد يحمل اسم مستخدم الجهاز، كما يُعرف باسم "المنزل". لا يمكن أن تضع في المجلد الجذري أي مجلدات أخرى أو أية ملفات؛ وبالتالي سيبدأ مجال عملك من "المنزل" وما داخله. ولكي ننتقل مباشرةً إلى النافذة الرئيسية "منزل"، يمكنك النقر نقرةً مزدوجةً على المجلد الذي يحمل اسم المستخدم ضمن نافذة سطح المكتب، أو النقر على تطبيق "الملفات" من شريط التطبيقات. أقسام النافذة "منزل" كمثال عن نوافذ واجهة جنوم الرسومية توضح لقطة الشاشة التالية النافذة الرئيسية "منزل"، واﻷقسام التي تتألف منها عمومًا: تتكون النافذة من: الشريط الجانبي: يقع على يمين النافذة في النسخة العربية ويضم اختصارات للوصول إلى المجلدات اﻷساسية إين ما كنت، باﻹضافة إلى اختصارات للوصول إلى سواقات الأقراص المدمجة وأجهزة التخزين الخارجية وأماكن أخرى كالمجلدات المشتركة على الشبكات. فضاءالعمل: وهي المساحة البيضاء التي تشغل معظم مساحة النافذة، وتُعرض فيها المجلدات والملفات الموجودة في المجلد الحالي. يمكنك العمل مع المجلدات الموجودة ضمن هذه النافذة من نسخ ولصق وتغيير تسمية وغيرها؛ وبالنقر على فضاء العمل نقرةً واحدةً بالزر اليميني، ستظهر لك قائمة مختصرة تتيح بعض خيارات التعامل مع المجلدات. شريط اﻷدوات: شريط أسود يقع أعلى النافذة ويضم مجموعةً من اﻷزرار التي تؤدي وظائف متنوعة. تصنف أزرار شريط الأدوات ضمن مجموعات هي: أزرار التنقل: وتضم زري "أمام" و"خلف" للانتقال إلى الملجد اﻷعلى أو اﻷدنى مستوىً من المجلد الحالي، وإلى جوارها موقع المجلد الحالي بالنسبة لمجلد "المنزل". أزرار التحكم الرئيسية بالنافذة: تقع على يمين شريط المهام وتضم على التسلسل من أقصى اليسار إلى اليمين أزرار اﻹغلاق، وتكبير أو تصغير النافذة وإخفاء النافذة. أزرار تنظيم فضاء العمل: قد يختلف عدد هذه اﻷزرار من نافذة إلى أخرى باختلاف التطبيق الذي يفتحها، لكنها تضم افتراضيًا اﻷزرار التالية مرتبة من اليسار إلى اليمين: زر البحث: بالنقر عليه، يظهر إلى يساره مربع حوار لكتابة ما تريد البحث عنه في هذا المجلد. زر تغيير المنظور: بالنقر عليه، يتبدّل تنظيم اﻷيقونات في فضاء العمل بين عرض القائمة والعرض الحر. زر خيارات المنظور: بالنقر عليه، تظهر قائمة تتيح لك مجموعة إضافية من الخيارات تتعلق بحجم اﻷيقونات المعروضة وطريقة ترتيبها وعمليات التراجع أو إعادة فعل سابق. زر القائمة: يعرض هذا الزر مجموعةً من الخيارات الهامة للعمل ضمن المجلد نستعرضها تاليًا بالتفصيل: أيقونات فتح النوافذ والمجلدات: تقع أعلى القائمة وهي بالترتيب: فتح نافذة جديدة، وفتح نافذة فرعية أخرى ضمن النافذة الواحدة، وإضافة مجلد جديد. أيقونات التحرير: وهي على الترتيب من اليسار إلى اليمين: قص ونسخ ولصق. اختيار الكل: لاختيار جميع محتويات المجلد. أظهر الملفات المخفية: ﻹظهار أية ملفات جرى إخفاؤها ضمن المجلد. أظهر الشريط الجانبي show sidebar: ﻹخفاء وإظهار الشريط الجانبي للنافذة. التفضيلات: تظهر عند النقر على هذا الخيار نافذة التفضيلات التي تضم أدوات تتحكم في طريقة عرض وفتح الملفات والبحث عنها وغيرها. اختصارات لوحة المفاتيح: وتعرض لك نافذةً تضم معظم اختصارات لوحة المفاتيح التي تحتاجها ﻷداء المهام في النوافذ. مساعدة: سيحمّل هذا الخيار تطبيق "مساعدة". عن الملفات: يعرض لمحة عن تطبيق "ملفات". أساسيات التعامل مع المجلدات والملفات بعد أن أخذنا فكرةً واضحةً عن أقسام النافذة، سننتقل مباشرةً إلى العمل مع المجلدات والملفات. إنشاء مجلد جديد وحذف مجلد وتغيير اسمه ﻹشاء مجلد جديد في نافذة، انقر بالزر الأيمن للفأرة ضمن فضاء العمل، واختر مجلد جديد أو اضغط المفاتيح Shift + Ctrl + N؛ كما يمكنك النقر على قائمة النافذة في شريط اﻷدوات، ثم النقر على أيقونة المجلد الجديد. وأيما اخترت من الطرق، ستظهر لك نافذة إنشاء مجلد جديد تضم مربح حوار يطلب إليك اختيار اسم للمجلد الجديد. انقر على الزر "أنشئ" ﻹنشاء المجلد بالاسم الذي اخترته، أو "إلغ" ﻹلغاء اﻷمر. لحذف مجلد ما، انقر على المجلد ثم اضغط على المفتاح Delete، أو انقر بالزر الأيمن للفأرة على المجلد لتظهر قائمة خيارات المجلد. انتقل بعدها إلى الخيار "انقل إلى المهملات"، وانقر عليه. في كلتا الطريقتين سيُحذف المجلد، لكن بعد أن تتم العملية، ستعرض عليك النافذة رسالةً تخبرك فيها أن المجلد قد حُذف وتعطيك خيار "تراجع" إن فعلت ذلك عن طريق الخطأ، فستختفي الرسالة إن أهملتها الرسالة تلقائيًا بعد عدة ثوان. لإعادة تسمية مجلد، انقر عليه، ثم اضغط على المفتاح F2؛ أو انقر عليه بالزر الأيمن للفأرة واختر اﻷمر "غيّر الاسم" من قائمة الخيارات المتاحة. تعرض النافذة في كلتا الطريقتين رسالةً تضم مربع حوار لكتابة الاسم الجديد، وإلى جواره زر "غيّر الاسم". إن غيرت اسم المجلد ولم تنقر على زر "غيّر الاسم"، فلن يحدث شيء. تحريك المجلدات والملفات ونقلها نسخ مجلد ولصقه: لتنشئ نسخةً جديدةً عن مجلدك، انقر على المجلد بالزر الأيمن، ثم اختر اﻷمر "انسخ"؛ كما يمكنك استخدام الاختصار Ctrl + C. عندها يخزن النظام نسخةً من مجلدك أو ملفك في ذاكرته، ويبقيها حتى تُلصق هذه النسخة في المكان المطلوب. إن أردت إنشاء نسخة في نفس النافذة، فانقر بالزر الأيمن للفأرة ضمن فضاء عمل النافذة، واختر اﻷمر "ألصق"، أو استخدم الاختصار Ctrl + V. سيظهر مجلد يحمل اسم المجلد السابق وإلى جواره عبارة "(نسخة)" إن كانت النسخة اﻷولى وعبارة "(نسخة أخرى)" إن كانت الثانية و"(3 نسخ)" إن كانت الثالثة وهكذا!؛ أما إن أردت إنشاء نسخة في نافذة أخرى، فافتح هذه النافذة وكرر خطوات اللصق السابقة. قص مجلد ولصقه: تماثل هذه العملية عملية النسخ، إلا أن النسخة اﻷصلية التي جرى قصها من مكانها ستختفي عند لصقها في مكان آخر، ولن تبقى أيضًا نسخة عنها في الحافظة، إذ لن يتفعّل الخيار "ألصق" في قائمة الخيارات. لقص ملف أو مجلد، انقر عليه بالزر الأيمن للفأرة ثم اختر اﻷمر "قص"، أو اضغط على المفتاحين Ctrl + X، ثم انتقل إلى النافذة الهدف واختر اﻷمر "ألصق". ضغط المجلدات والملفات يقدم لك نظام التشغيل أوبونتو ميزة ضغط الملفات وذلك لغرضين أساسيين: تصغير حجم المجلد أو الملف. سهولة مشاركة المجلد على اﻹنترنت نظرًا لامتناع الكثير من الخدمات عن تحميل أو تنزيل ملفات بامتدادات معينة، ونلجأ إلى تحويلها إلى صيغة ملف مضغوط. لضغط مجلد (أو كما يُعرف بإنشاء أرشيف)، انقر عليه بالزر الأيمن للفأرة، ثم اختر اﻷمر "اضغط"، وستظهر لك النافذة التالية: لاحظ وجود ثلاثة أنواع من أرشيفات الضغط هي: zip: وهو أرشيف عالي الدعم من قِبل معظم أنظمة التشغيل، ويتميز بسرعة إنشائه وفكّه. tar.xz: أرشيف تدعمه معظم توزيعات لينكس، كما توجد برامج تدعمه في ويندوز، لكنه أبطأ في اﻹنشاء والفك مقارنةً بالسابق، ويتميز بحجم أصغر. 7z.: يماثل السابق من حيث سرعة اﻹنشاء والفك والحجم الصغير، وتدعمه توزيعات لينكس؛ كما تجد مجموعة برمجيات تدعمه على ويندوز وماك. اكتب اسم اﻷرشيف الذي ستضغط فيه مجلداتك أو ملفاتك واختر نوعه ثم انقر الزر "أنشئ". خصائص الملفات والمجلدات للاطلاع على خصائص مجلد أو ملف، انقر عليه بالزر الأيمن للفأرة، ثم اختر "خصائص"؛ أو اضغط المفتاحين Ctrl + I معًا. تختلف نافذة الخصائص الظاهرة في حالتي المجلد والملف، وسنستعرض كل منهما سريعًا. خصائص المجلدات تتكون النافذة من النوافذ الفرعية التالية: أساسي: وتقدم معلومات عن نوع وموقع المجلد والمساحة الفارغة ضمن المجلد الجذري. التصاريح: وتقدم خيارات للتحكم بأذونات فتح المجلد للقراءة فقط أو للقراءة والكتابة، وهو موضوع سنتحدث فيه لاحقًا. المشاركة على الشبكة المحلية: إن كان حاسوبك متصلًا بشبكة محلية، فيمكنك عندها مشاركة المجلد مع مستخدمي الشبكة؛ وهذا موضوع خارج نطاق مقالنا. خصائص الملفات تتكون النافذة من نفس النوافذ الفرعية الموجودة في نافذة خصائص المجلد، ويضاف إليها نافذة أخرى هي "افتح باستخدام" تعرضها كما تعرضها لقطة الشاشة السابقة. وكما هو واضح، سيفتح التطبيق المبدئي هذا الملف لعرض محتواه؛ كما يقدم النظام عدة تطبيقات مُزكّاة لفتح هذا الملف، أي التطبيقات القادرة على فتحه والتعامل معه؛ وبإمكانك اختيار أيّ من التطبيقات المزكاة ليكون التطبيق المبدئي بالنقر عليه، ثم النقر على زر "اجعله المبدئي". وإن أردت العودة إلى اﻹعدادات الافتراضية، فانقر الزر"صفِّر". قد تظهر في نافذة الخصائص نافذة فرعية جديدة في بعض أنواع الملفات مثل ملفات الصورة لتقدم معلومات إضافية. ملاحظة: يمكنك النقر على الملف بالزر الأيمن للفأرة، ثم اختيار اﻷمر "افتح بتطبيق آخر" لاختيار تطبيق آخر غير التطبيق المبدئي. لمحة عن إنشاء الملفات وفتحها ما يُنشئ الملفات هي التطبيقات، لهذا عليك أولًا معرفة ما تريد عمله بمساعدة حاسوبك، ثم الاطلاع على التطبيقات التي تتيح لك تنفيذ ما تريده (أو برمجتها إن كنت محبًا للمغامرة والتحدي ومستعدًا لخسارة الشعر أحيانًا!). سنفترض حاليًا أن لديك خلفيةً محدودةً في مبادئ عمل الحاسوب، كما سنفترض أيضًا أنك تريد ببساطة كتابة بعض الملاحظات وبعض التقارير أو إجراء بعض الحسابات وتصفح اﻹنترنت. سنَدُلّك هنا على بعض التطبيقات المثبتة افتراضيًا مع أوبونتو والتي قد تفيدك: LibreOffice Writer: وهو محرر نصوص يمتلك الكثير من الميزات المتقدمة. LiberOffice Calc: تطبيق جداول إلكترونية بميزات متقدمة. Libreoffice Impress: تطبيق إنشاء عروض تقديمية كامل الميزات. LibreOffice Draw: تطبيق ﻹنشاء الرسوميات مع الكثير من الميزات الرائعة. متصفح الويب فايرفوكس: متصفح الويب الغني عن التعريف بكامل إمكاناته. محرر النصوص: تطبيق بسيط لكتابة الملاحظات والنصوص، لكنه شديد اﻷهمية، وخاصةً إن فكرت في البدء بتعلم البرمجة أو تصميم صفحات الويب. تتواجد هذه التطبيقات في قائمة التطبيقات المثبتة، ويمكن فتحها بالنقر على أي منها بالزر الأيسر للفأرة. سيخبرك النظام أن التطبيق جاهز للعمل عندما ينهي تحميله. تطبيق عملي: افتح برنامج "محرر النصوص" ونفذ مايلي: اكتب العبارة "مرحبًا أوبونتو" وانقر الزر "احفظ"، ثم احفظه باسم "test-txt" في مجلد مناسب. احذف اﻵن العبارة السابقة وانسخ والصق ما يلي: <html> <body> <h1> مرحبًا أوبونتو </h1> </body> انقر على زر القائمة بجانب زر "احفظ"، واختر "احفظ باسم"، ثم اجعل اسم هذه النسخة "test-web"، وضعها في نفس المجلد السابق. ستكون النتيجة ظهور الملفين التاليين في المجلد الذي اخترته: لماذا ظهرت أيقونتي الملفين بشكلين مختلفين علمًا أننا استخدمنا نفس البرنامج في إنشائهما؟ الجواب هو: لأن نظام لينكس يقرأ ويفهم محتوى هذا الملف بغض النظر عن التطبيق الذي أنشأه، ومن ثم يبحث عن التطبيق اﻷنسب لتشغيله. إن الملف "test-txt" هو ملف نصي بحت وسيُسند النظام مهمة فتحه إلى محرر النصوص نفسه، لكن اﻵخر يحتوي على معلومات تُدعى شيفرة HTML التي تُستخدم في بناء صفحات ويب، لذلك يسند النظام مهمة فتحه إلى متصفح الويب. جرب بنفسك! تثبيت وإزالة وسائط التخزين كأي نظام تشغيل آخر، تستطيع إضافة وسائط تخزين داخلية أو خارجية إلى جهازك، والعمل معها بكل سهولة ويسر، ماعدا بعض الاستثناءات التقنية البسيطة. سواءً أردت تثبيت قرص صلب خارجي أو بطاقة ذاكرة أو قرص DVD، سيستشعر النظام ما وصلته إلى الحاسب، ويحدد نوعه وينفَّذ ما يُسمى تثبيت للقرص mounting تلقائيًا، ويصبح جاهزًا للاستخدام عندما تظهر أيقونته ضمن شريط التطبيقات. يظهر في لقطة الشاشة السابقة اكتمال تثبيت ذاكرة عبر مدخل USB وقرص مدمج؛ حيث أنه عند النقر على أيقونة أي منهماـ سيفتح النظام هذا الوسيط باستخدام تطبيق "الملفات"، وستكون قادرًا على نقل البيانات منه وإليه. تجدر اﻹشارة أن سواقات اﻷقراص المدمجة لا تُعرض تلقائيًا في شريط التطبيقات أو في أية أماكن أخرى ما لم تضع فيها القرص المدمج؛ وكذلك اﻷمر بالنسبة إلى أقسام القرص الصلب الداخلي أو اﻷقراص الصلبة الداخلية اﻷخرى. فلكي تصل إليها، افتح تطبيق "ملفات"، وانتقل إلى الخيار" أماكن أخرى" أسفل الشريط الجانبي؛ ومن ثم انقر على هذه اﻷقراص نقرًا مزودجًا، وعندها تُثبَّت للاستخدام من قبل مستثمر النظام وتُعرض في شريط التطبيقات. اقرأ أيضًا المقال السابق: تعرّف على سطح مكتب أوبونتو 20.04 تغيير اللغة في نظام لينكس أوبنتو إلى العربية في ماذا يختلف Ubuntu عن Debian؟
-
ينبغي أن يبقى الفرع الرئيسي دائمًا في المنطقة الخضراء، ويعني ذلك تنفيذ كل خطوات بناء خط الإنتاج بنجاح، إذ يجب أن يُبنى المشروع بنجاح، وأن تُنفَّذ الاختبارات دون أخطاء، ولا يجب أن يعترض المدقق على أي شيء. ما أهمية هذا الأمر؟ من المرجح أنك ستنشر شيفرتك إلى العالم الخارجي من الفرع الرئيسي تحديدًا، وأي إخفاق في هذا الفرع سيعني أنّ الميزات الجديدة لن تُنشر حتى تُحل المشكلة؛ فقد تكتشف أحيانًا ثغرات في نسخة الإنتاج لم يلتقطها خط الإنتاج لمنظومة التكامل المستمر CI/CD، وفي حالات كهذه، سترغب في التراجع إلى النسخة السابقة بطريقة آمنة. كيف ستُبقي فرعك الرئيسي في المنطقة الخضراء إذًا؟ تحاشى دفع أية تغييرات إلى الفرع الرئيسي مباشرةً، بل ادفع شيفرتك إلى فرع آخر يمثّل أحدث نسخة ممكنة للفرع الرئيسي، وعندما ترى أن هذا الفرع جاهزٌ للدمج مع الرئيسي، أنشئ طلب سحب Pull Request -أو اختصارًا PR- على غيت هب GitHub. العمل مع طلبات السحب تمثل طلبات السحب جزءًا جوهريًا من عملية التعاون في تطوير أي مشروع برمجي يُنفَّذه مساهمَين على الأقل، فعندما تُجري أية تعديلات على مشروعك، ستختبرها على جهازك أولًا، ثم تعتمد هذه التغييرات وتدفعها إلى مستودع على الإنترنت -وهو غيت هب GitHub في حالتنا-، ثم تقدم طلب سحب لكي يراجع أحدٌ ما هذه التغييرات قبل أن تُدمج مع الفرع الرئيسي. هناك عدة أسباب تدفعنا لاستخدام طلبات السحب، كما أنّ مراجعة الشيفرة من قبل شخص آخر على الأقل فكرةٌ جيدةٌ دائمًا. قد تتواجد بعض الثغرات حتى في شيفرة المطورين الخبراء، وهذا مشابهٌ لمشكلة الرؤية النفقية tunnel، إذ لا يستطيع المصاب بها سوى رؤية ما أمامه مباشرة وكأنه ينظر من خلال نفق. يمتلك المراجع منظورًا مختلفًا، فقد يقدم وجهة نظر مختلفة. سيكون هناك مطورٌ واحد على الأقل على دراية بالتغيرات التي أجريتها بعد قراءتها. ستسمح لك طلبات السحب أن تُنفِّذ تلقائيًا كل المهام في خط الإنتاج لمنظومة CI قبل أن تصل الشيفرة إلى الفرع الرئيسي، وستزودك GitHub Actions بآلية لتنفيذ طلبات السحب. يمكنك تهيئة مستودع GitHub بطريقة تمنع دمج الشيفرة المرتبطة بطلب سحب إلى أن يُوافق عليها. لتقديم طلب سحب جديد، افتح فرعك في GitHub بالضغط على الزر الأخضر "Compare & pull request" في الأعلى، وسيظهر لك نموذج لتعبئته بوصفٍ لطلب السحب الذي تقدمه. تقدم لك واجهة طلبات السحب في GitHub إمكانية وصف الطلب ومناقشته، حيث تَظهر لك في الأسفل جميع علامات التحقق من منظومة CI (وهي في حالتنا كل فعل من أفعال GitHub Actions التي نستخدمها) التي هُيِّئت للعمل عند كل طلب سحب وحالة هذه العلامات. وما نهدف إليه فعلًا هو لوحة خضراء. يمكنك النقر على تفاصيل "Details" كل علامة تحقق للاطلاع عليها وتشغيل السجلات. تُنفَّذ جميع مخططات العمل التي واجهناها حتى الآن عند دفع الشيفرة إلى الفرع الرئيسي، ولجعلها تعمل عند كل طلب سحب، لا بدّ من تحديث الجزء المسؤول عن مسببات triggers إقلاع المخطط. سنستخدم المسبب "pull_request" للفرع الرئيسي ونربط هذا المسبب بالحدثين "opened"و "synchronize"؛ ويعني هذا مبدئيًا أن المخطط سيُنفَّذ عندما يُقدَّم طلب سحب إلى الفرع الرئيسي، أو عندما يُحدّث. لنغيّر إذًا الأحداث التي تسبب تشغيل مخطط العمل على النحو التالي: on: push: branches: - master pull_request: branches: [master] types: [opened, synchronize] سنمنع قريبًا دفع الشيفرة مباشرةً إلى الفرع الرئيسي، لكننا سننفذ حاليًا مخطط العمل لكل عمليات دفع الشيفرة المباشر إلى الفرع الرئيسي. التمرينان 11.13 - 11.14 يعمل مخطط العمل على النحو المطلوب للحفاظ على نوعية جيدة لشيفرتنا، لكن طالما أنه يُقلع عند دفع الشيفرة إلى الفرع الرئيسي، فسيلتقط الأخطاء متأخرًا. 11.13: طلب سحب حَدِّث مسببات إقلاع مخطط العمل كما اقترحنا سابقًا ليعمل عند تقديم طلب سحب جديد إلى الفرع الرئيسي. أنشئ فرعًا جديدًا وادفع بشيفرتك إليه، ثم افتح طلب سحب إلى الفرع الرئيسي. إذا لم تكن قد تعاملت مع الفروع سابقًا اطلع على المقالات التالية: مقدمة عن التفريع Branching في Git إدارة التفريعات (branches) في Git واستخدامها لتخطيط سير العمل إعادة تأسيس تفريعات طلب السحب وتحديثه في git تنبيه: تأكد عندما تفتح طلب سحب جديد أنك اخترت مستودعك الخاص واجهةً أساسية، إذ سيكون الاختيار افتراضيًا للمستودع الأصلي ولا يجب أن تفعل هذا: سترى في النافذة "Conversation" ضمن واجهة فتح طلب سحب آخر عملية (أو عمليات) دفع للشيفرة، كما سترى الحالة الصفراء لعلامات التحقق الذي يجري تنفيذه: ينبغي أن تكون العلامات باللون الأخضر بعد أن تنتهي عمليات التحقق. تأكد من نجاح كل اختبارات التحقق، ولا تدمج فرعك الآن، فهناك نقاط ينبغي تحسينها في خط الإنتاج. 11.14: تشغيل خطوة النشر للفرع الرئيسي فقط كل شيء يبدو على ما يرام، لكن هناك مشكلةٌ حقيقية في مخطط العمل الحالي، إذ ستُنفَّذ جميع الخطوات بما فيها خطوة النشر عندما نفتح طلب سحب، وبالتأكيد لا نريد حدوث هذا الأمر. ولحسن الحظ، هناك حلٌ بسيط لهذه المشكلة، إذ يمكننا استخدام العبارة الشرطية if في خطوة النشر لكي تضمن عدم تنفيذ هذه الخطوة إن لم تُدمج الشيفرة أو تُدفع إلى الفرع الرئيسي. يتضمن سياق context شتى أنواع المعلومات حول الشيفرة التي ينفذها مخطط العمل. ستجد المعلومات المتعلقة بالموضوع في GitHub context، إذ يمثل الحقل event_name اسم الحدث الذي يسبب تنفيذ المخطط. عندما يُدمج طلب سحب، سيظهر اسم الحدث على أنه "push"، وهو نفسه الحدث الذي يقع عندما تُدفع الشيفرة إلى المستودع، لذلك سنحصل على السلوك المطلوب بإضافة العبارة الشرطية التالية إلى خطوة النشر: if: ${{ github.event_name == 'push' }} ادفع بشيفرة إضافية إلى فرعك، وتأكد من عدم تنفيذ خطوة النشر. ادمج بعد ذلك فرعك مع الفرع الرئيسي وتأكد من حدوث خطوة النشر. إدارة إصدار نسخ البرمجيات الغاية الرئيسية من تحديد الإصدار هي التعريف الفريد للبرمجية التي تعمل والشيفرة المتعلقة بها. يشكّل ترتيب الإصدارات أيضًا جزءًا مهمًا من المعلومات، فلو احتوى الإصدار الحالي لبرنامج ما، على سبيل المثال وظيفةً حيويةً معطلة، سيلزمنا تحديد النسخة السابقة المستقرة من البرنامج لكي نتمكن من التراجع إليها. إدارة الإصدار بطريقة Semantic وبطريقة Hash تُدعى الطريقة التي يُدار بها إصدار برنامج في بعض الأحيان باستراتيجية إدارة الإصدار Versioning strategy. سنطلّع ونوازن استراتيجيتين في هذا المجال، تدعى الأولى الإدارة الدلالية لنُسخ البرمجيات Semantic، إذ يُكتب الإصدار بالشكل التالي: {major}.{minor}.{patch}. فلو كان إصدار نسخة من البرنامج 1.2.3، سيكون 1 هو رقم الإصدار الرئيسي الجذري major و 2 رقم الإصدار الثانوي (البسيط) minor و 3 هو رقم الإصدار الترميمي (الترقيع) patch. وعمومًا، فأية تغييرات تهدف لمعالجة الوظيفة المخفقة في إصدار دون المساس بالطريقة التي يعمل بها التطبيق من الخارج ستكون تغييرات ترميمية؛ أما التغييرات التي تؤدي إلى تغييرات بسيطة في الوظيفة (كما تبدو من الخارج) فستكون تغييرات ثانوية، وندعو تلك التغيرات التي ستؤثر كليًا على التطبيق (أو تغيير وظائفه بصورةٍ كبيرة) بالتغييرات الرئيسية، وقد يختلف تعريف هذه المصطلحات من مشروع لآخر. تتبع على سبيل المثال مكتبات npm ترميز semantic، ففي وقت كتابة هذه السطر (الثالث من آذار 2022)، يُعد الإصدار 17.0.2 هو الأحدث للمكتبة React إذ أن رقم الإصدار الرئيسي هو 17 والثانوي 0 والترميمي 1. أما الإصدار بترميز Hash (أو الترميز SHA) فهو مختلفٌ تمامًا، فرقم الإصدار هو سلسلة نصية عشوائية مشتقة من محتويات المستودع والتغيرات التي اعتمدت فيه. يُنفّذ ذلك في git تلقائيًا مثل رمز Hash معتمد وفريد لأي مجموعة من التغييرات. يستخدم الإصدار برمز غالبًا في الحالات المؤتمتة، فعملية نقل رمز Hash مكون من 32 محرف للتأكد من نشر كل شيء على النحو الصحيح عمليةٌ مضنية وتولّد الكثير من الأخطاء. إلى ماذا يشير الإصدار؟ تحديد الشيفرة الموجودة في كل إصدار أمرٌ مهمٌ جدًا، ويختلف أسلوبي الترميز السابقين في طريقة فعل ذلك؛ فالعملية في Hash (على الأقل في غيت هب GitHub) بسيطة ببساطة البحث عن تغييرات معتمدة للشيفرة commit لها رمز Hash معرّف ومحدد، إذ سيمنحنا ذلك إمكانية معرفة الشيفرة التي نُشرت في كل إصدار. سيتعقد الوضع قليلُا في semantic، فهناك ثلاث طرق لمقاربة الموضوع: الأولى تتعلق بالشيفرة نفسها، والثانية تتعلق بالمستودع أو البيانات الوصفية له، والثالثة تتعلق بأشياء خارج المستودع كليًا. طالما أننا لن نتطرق إلى المقاربة الثالثة (لأنها متشعبة مثل حجر الأرنب)، فستلاحظ أن العملية بسيطة أيضًا وكأنها جدول بيانات يربط بين الإصدار والشيفرة المعتمدة التي يدل عليها. تتلخص المقاربة المتعلقة بالشيفرة برقم إصدار النسخة في ملف، بينما تعتمد مقاربة المستودع وبياناته الوصفية على الوسوم tags أو في حالة GitHub على الإصدارات، إذ يشير الوسم أو الإصدار في هذه المقاربة إلى شيفرة مُعتمدة هي نفسها الموجودة في الإصدار. ترتيب إصدارات النسخ من السهل في semantic ترتيب الإصدارات حتى لو كانت مختلفة (رئيسي، ثانوي، ترميمي)، فسيأتي الإصدار 1.3.7 قبل 2.0.0 والذي سيأتي قبل 2.1.5 وهذا الأخير سيكون قبل 2.2.0. لكننا سنحتاج إلى قائمة بالإصدارت أو الوسوم ( يؤمنها مدير حزم GitHub بصورةٍ ملائمة) لمعرفة الإصدار الأخير، فمن الأسهل الاطلاع على هذه القائمة ومناقشتها، أي من الأسهل أن نقول أننا سنتراجع إلى الإصدار 3.2.4 بدلًا من التعامل بأنفسنا مع رموز hash التي تشير إلى رقم الإصدار. وطبعًا لا نعني إطلاقًا أنّ رموز hash غير ملائمة؛ فلو عرفت أي شيفرة معتمدة سببت مشكلة بعينها، فمن السهل البحث من خلال تاريخ عمليات GitHub والحصول على رموز hash للإصدار السابق؛ لكن لو كانت لديك سلسلتين من رموز Hash على النحو التالي مثلًا: d052aa41edfb4a7671c974c5901f4abe1c2db071 12c6f6738a18154cb1cef7cf0607a681f72eaff3 فلن تستطيع التمييز أيهما قبل الأخرى، وستحتاج إلى مساعدة إضافية مثل سجل عمل GitHub لكشف الترتيب الصحيح. الموازنة بين أسلوبي إدارة الإصدار لقد لمسنا بالمناقشة السابقة بعض إيجابيات وسلبيات كل أسلوب، لكن من الأفضل التطرق إلى مجال استعمال كل منهما. يعمل أسلوب semantic جيدًا عندما يكون لرقم الإصدار أهميةً خاصة أو عندما تكون هناك حاجة للبحث عنه. فكر مثلًا بمكتبات جافا سكربت JavaScript التي تستخدمها؛ فلو كنت تستخدم الإصدار 3.4.6 من مكتبة محددة وظهر تحديث لها يحمل الرقم 3.4.8، فيمكنك أن تأمل بأن انتقالك إلى الإصدار الأحدث سيكون آمنًا؛ لكن لو حمل الإصدار الجديد الرقم 4.0.1 فلن تضمن انتقالًا آمنًا إليه. يُناسب hash الحالات التي تُبنى فيها الشيفرة داخل أدوات برمجية artifact (مثل الملفات الثنائية القابلة للتنفيذ أو قوالب منصة Docker) قابلة بحد ذاتها للرفع أو التخزين، فإذا تطلبت اختباراتك على سبيل المثال بناء حزمتك داخل أداة برمجية، ثم رفعها إلى الخادم واختبارها، فمن الملائم عندها استخدام أسلوب Hash في تحديد الإصدار لأنه سيمنع وقوع الحوادث. تخيل على سبيل المثال أنك تعمل على الإصدار 3.2.2 وفشل أحد الاختبارات، أصلحت بعد ذلك الخلل ودفعت بشيفرتك إلى مستودعك، لكن طالما أنك تعمل ضمن مستودعك فلن تستطيع تحديث رقم الإصدار. لن يتغير اسم الأداة البرمجية دون تحديد إصدار hash. وإن كان هناك خطأ في رفع الأداة البرمجية، فقد يُنفَّذ الاختبار على الأداة الأقدم (طالما أنها لا تزال موجودة وبنفس الاسم). بينما لو أُعطيت الأداة رقم إصدار بأسلوب hash، ينبغي أن يتغير رقم الإصدار عند كل محاولة لدفع شيفرة معتمدة، ويعني هذا أنه في حال أخفق رفع الأداة، سيظهر خطأ لأن الأداة التي ستُنفَّذ عليها الاختبارات غير موجودة. يُعد ظهور الخطأ عندما يحدث شيء ما أفضل غالبًا من مشكلة تهملها منظومة CI بصمت. أفضل ما في الأسلوبين يمكن أن نستشف من المقارنة السابقة أن استخدام أسلوب semantic مناسب لإصدار برمجيات، بينما استخدام أسلوب hash أكثر منطقية أثناء نشر البرمجيات ولن يسبب هذا الأمر تعارضًا بالضرورة. فكر في ذلك على النحو التالي: تتلخص إدارة الإصدارات بأنها تقنية تشير إلى كمية معتمدة من الشيفرة وتعطيها اسمًا فليكن 3.5.5 لن يمنع ذلك طبعًا من إعطاء الشيفرة نفسها رمز hash. هناك أمر ما، فقد ذكرنا في بداية هذا القسم أنه علينا معرفة ما يحدث تمامًا في شيفرتنا، فعلينا أن نكون واثقين مثلًا بأننا اختبرنا الشيفرة التي نريد نشرها. سيعقد وجود أسلوبين متوازيين لإدارة الإصدار (أو تسميته) الأمور قليلًا. فعندما يكون هناك مشروع يستخدم نسخًا من أداة برمجية بحيث يُدار إصدار هذه النسخ بأسلوب hash أثناء اختبارها، يمكننا دائمًا تعقب نتيجة خطوات البناء والتدقيق والاختبار، وبالتالي سيعلم المطورون حالة هذه النسخ. ويحدث ذلك آليًا وبصورةٍ واضحة بالنسبة للمطور، فليس على المطور الاهتمام بما تفعله منظومة CI في الخفاء من حيث استخدام ترميز hash لتسمية النسخة واختبارها. عندما يدمج المطور شيفرته ضمن الفرع الرئيسي، تتولى منظومة CI الأمر من جديد، إذ ستبني هذه المرة وتختبر كل الشيفرة ومن ثم تمنحها رقم إصدار بأسلوب semantic، وتربط هذا الرقم بآخر شيفرة معتمدة ومختبرة وتحمل وسم git. سيكون البرنامج الذي سنصدره في الحالة السابقة مُختبرًا لأن منظومة CI ستتأكد أنّ الاختبارات قد نجحت على الشيفرة الموسومة بوسم git المحدد، وليس خطأً أن نقول أن المشروع سيستخدم أسلوب semantic في إدارة الإصدار ويتجاهل ببساطة فكرة أن منظومة CI ستختبر الفروع الخاصة بكل مطور أو طلبات السحب الخاصة بكل منهم بأسماء مبنية على أسلوب hash في إدارة الإصدار. نقول ذلك لأن النسخة التي تعنينا (التي سنصدرها) ستُمنح رقم إصدار semantic. التمرينان 11.15 - 11.16 لنوسّع مخطط العمل الذي نبنيه لكي يزيد تلقائيًا رقم الإصدار عندما تجري الموافقة على طلب سحب وتنفيذ عملية الدمج ضمن الفرع الرئيسي وأن يوسم النسخة المصّدرة برقم الإصدار. سنستخدم anothrNick/github-tag-action وهو فعل GitHub Actions مفتوح المصدر طوره أحدهم. 11.15: إضافة رقم إصدار سنوّسع مخطط العمل بإضافة خطوة واحدة: - name: Bump version and push tag uses: anothrNick/github-tag-action@1.36.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} سنمرر متغير البيئة environment variable التالي secrets.GITHUB_TOKEN إلى الفعل، وطالما أنّ مصدر الفعل طرف ثالث، سنحتاج إلى شهادة استيثاق token في مستودعك. يمكن الاطلاع أكثر عن الاستيثاق في توثيق GitHub. يمكن أن نمرر عدة متحولات بيئة إلى الفعل anothrNick/github-tag-action. تعدّل هذه المتغيرات الطريقة التي يُعرِّف بها الفعل الإصدارات. يمكنك الاطلاع على تفاصيل أكثر ضمن ملف README الخاص بالفعل على GitHub واستخدام ما يناسبك. وكما سترى في التوثيق سيزداد الرقم الثانوي لرقم الإصدار تلقائيًا minor bump. عدّل التهيئة في الشيفرة السابقة لكي يكون هناك زيادةٌ تلقائية في رقم الترميم patch bump لرقم الإصدار، أي سيزداد الرقم الأخير تلقائيًا. تذكر أننا نريد فقط زيادة رقم الإصدار عندما تطرأ تغييرات على الفرع الرئيسي. لذلك أضف العبارة الشرطية "if" لمنع زيادة رقم الإصدار عند فتح طلب سحب كما فعلنا في التمرين 11.14. أكمل مخطط العمل وحاول تجربته، ولا تضفه مثل خطوة إضافية فقط، وإنما أجري إعداده على أنه عمل منفصل يعتمد على العمل المهتم بتدقيق وكشف الأخطاء والفحص والنشر. أجرِ التغييرات التالية على تعريف مخطط العمل: name: Deployment pipeline on: push: branches: - master pull_request: branches: [master] types: [opened, synchronize] jobs: simple_deployment_pipeline: runs-on: ubuntu-20.04 steps: // steps here tag_release: needs: [simple_deployment_pipeline] runs-on: ubuntu-20.04 steps: // steps here تُنفَّذ أعمال مخطط العمل على التوازي كما ذكرنا سابقًا، لكن طالما أننا نريد إجراء التدقيق والاختبار والنشر أولاً، سنحتاج لضبط اعتمادية tag_release بحيث تنتظر عملًا آخر ليُنفّذ أولًا نظرًا لأننا لا نريد وضع علامة على الإصدار ما لم يجتاز الاختبارات ويُنشر. إذا لم تكن متأكدًا من إعدادات التهيئة، يمكنك ضبط قيمة DRY_RUN على true، وبالتالي سيعطي الفعل رقم الإصدار التالي دون إنشاء وسم للإصدار. حالما يعمل مخطط العمل على نحوٍ صحيح، سيشير المستودع إلى وجود بعض الوسوم: وبالنقر على هذه الوسوم ستُعرض ضمن قائمة بكل الوسوم (والتي تمثل آلية لتعريف الإصدار ووسمه): 11.16: تجاوز إنشاء وسوم لحزمة شيفرة معتمدة ونشرها من الأفضل في أغلب الأوقات نشر الفرع الرئيسي إلى وضع الإنتاج.، لكن قد تكون هناك بعض الأسباب المقنعة لتجاوز إنشاء وسم شيفرة معتمدة أو طلب سحب جرى الموافقة على دمجه أو نشرهما. عدّل إعداداتك لكي لا تُنشر إلى وضع الإنتاج أية شيفرة جرى دمجها إن احتوت رسالة طلب السحب الكلمة "skip#"، ولا توسم برقم الإصدار. تلميح: أسهل طريقة لإنجاز ذلك هو تبديل العبارة الشرطية "if" للخطوة المناسبة. ويمكنك كما فعلنا في التمرين 11.14 الحصول على المعلومات المطلوبة من سياق GitHub لمخطط العمل: يمكنك الإستعانة بالشيفرة التالية مثل نقطة انطلاق: name: Testing stuff on: push: branches: - main jobs: a_test_job: runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 - name: gihub context env: GITHUB_CONTEXT: ${{ toJson(github) }} run: echo "$GITHUB_CONTEXT" - name: commits env: COMMITS: ${{ toJson(github.event.commits) }} run: echo "$COMMITS" - name: commit messages env: COMMIT_MESSAGES: ${{ toJson(github.event.commits.*.message) }} run: echo "$COMMIT_MESSAGES" لاحظ ما الذي طُبع في سجل مخطط العمل. ملاحظة: يمكنك الوصول إلى الشيفرة المعتمدة أو رسائلها عند الدفع أو الدمج مع الفرع الرئيسي فقط، وبالتالي لن تحمل الخاصية github.event.commits أية قيمة. لا حاجة لهذه القيمة على أية حال طالما أننا نرغب في تجاوز هذه الخطوة. ستحتاج غالبًا إلى الدالتين contains و join ضمن عبارة if الشرطية. لا يُعد نشر مخطط العمل أمرًا سهلًا، وغالبًا ما يكون الخيار المتاح هو المحاولة والخطأ، وينصح أحيانًا بوجود مستودع منفصل للتأكد من صحة تهيئة الإعدادات، ثم تُنقل هذه الإعدادات إلى المستودع الفعلي إن كانت صحيحة. كما يمكن أيضًا تثبيت أداة مثل act، التي تساعدك على تشغيل مخطط العمل على جهازك. وعندما تواجهك حالات مختلفة عن التي ناقشناها، كأن تنشئ أفعال خاصة بك، فإن اقتحام غمار أدوات مثل act وتجربتها سيستحق العناء. ملاحظة لاستخدام الأفعال التي يطورها طرف ثالث عندما تستخدم فعل يؤمنه طرف ثالث مثل github-tag-action، من الأفضل أن تحدد أسلوب hash لإدارة الإصدار بدلًا من رقم الإصدار. والسبب في ذلك أن رقم الإصدار الذي أنجز بوسم git قد يكون عرضة للتغيير، فالإصدار الذي يحمل الرقم 1.33.0 هذا اليوم على سبيل المثال، قد يشير إلى شيفرة مختلفة عن تلك الموجودة في نفس الإصدار لكن في الأسبوع القادم. مع ذلك، فالشيفرة المعتمدة على ترميز hash محددة لا تتغير أيًا كانت الظروف، لذا فإن أردنا التيقن 100% من الشيفرة التي نستخدمها، سيكون الخيار الأكثر أمانًا hash. إنّ الإصدار 1.33.0 من الفعل السابق يتوافق مع شيفرة ترميز hash لها هو الإصدار: eca2b69f9e2c24be7decccd0f15fdb1ea5906598، لذلك من الأفضل أن نغير إعدادات التهيئة على النحو التالي: - name: Bump version and push tag uses: anothrNick/github-tag-action@eca2b69f9e2c24be7decccd0f15fdb1ea5906598 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} وعلينا أن نثق عند استخدام أفعال تزودنا بها GitHub بأنها لن تعبث بوسوم الإصدار version tags وأن نختبر شيفرتها بدّقة. وقد ينتهي بك المطاف عند استخدام أفعال من طرف ثالث أمام أفعال تحتوي ثغرات أو حتى مثيرة للشبهة، وحتى لو لم تكن نية المطور الذي كتب الشيفرة سيئة، فقد ينس معلومات الاستيثاق الخاصة به في ركن إنترنت عام، ومن يدري ما قد يحدث بعدها. سنتأكد عند استخدام أسلوب hash أن هذه شيفرة التي نستخدمها لتشغيل مخطط العمل لن تتغير، لأن تغيير الشيفرة المعتمدة المسؤولة عن تنفيذ المخطط سيؤدي إلى تغيير hash. أبق الفرع الرئيسي آمنا سيسمح لك غيت هب أن تهيئ فروعًا محمية، فمن المهم حماية الفرع الأكثر أهمية الذي يجب ألا يخفق أبدًا وهو الفرع الرئيسي. يمكنك أن تختار بين عدة مستويات حماية عبر إعدادات المستودع. لن نغطي كل هذه الخيارات، لكن يمكنك طبعًا الاطلاع عليها من خلال توثيق GitHub. ومن وجهة نظر منظومة CI، ستتمثل الحماية الأكثر أهمية في نجاح خطوات التحقق من الحالة قبل أن يدمج طلب السحب ضمن الفرع الرئيسي. فلو أعددت أفعال GitHub لتنفذ مهام التدقيق والاختبار، فلن يُدمج طلب السحب قبل تصحيح جميع أخطاء التدقيق وقبل أن تنجح جميع الاختبارات. ونظرًا لكونك مدير مستودعك، ستجد خيارًا لتخطي التقييدات هذه. لن يظهر هذا الخيار لغير المدراء. لتهيئ إعدادات الحماية للفرع الرئيسي، توجه إلى إعدادات "Settings" المستودع من القائمة العليا ضمن المستودع. اختر من قائمة الجهة اليسرى فروع "Branches" ثم انقر زر أضف قاعدة "Add rule" بجوار العنصر قواعد حماية الفروع "Branches protection rules". اكتب نموذج لاسم الفرع ("master" سيكون مناسبًا)، ثم اختر طريقة الحماية التي تريد إعدادها. اختر على الأقل "يجب التحقق من نجاح خطوات التحقق من الحالة قبل الدمج Require status checks to pass before merging" لتضمن تسخير الإمكانات الكاملة لاستضافة GitHub Actions. وتحت هذا الخيار عليك اختيار "يجب أن تكون الفروع محدّثة قبل الدمج Require branches to be up to date before merging"، وفعّل جميع الخيارات التي تتحقق من الحالة قبل دمج أية طلبات سحب. التمرين 11.17 إضافة حماية إلى الفرع الرئيسي أضف حماية لفرعك الرئيسي. إذ عليك حمايته بضمان التالي: الموافقة على جميع طلبات السحب قبل دمجها. نجاح جميع خطوات التحقق من الحالة قبل الدمج. لا تفعِّل الخيار "Include administrators" حاليًا، لأنك لو فعلت ذلك فعليك الانتظار حتى يراجع شخص ما طلب السحب الذي قدمته قبل نشر الشيفرة. ترجمة -وبتصرف- للفصل Keeping Green من سلسلة Deep Dive Into Modern Web Development. اقرأ أيضًا المقال السابق: نشر التطبيقات وتوزيعها وفق نهج التسليم المستمر نشر تطبيقات الويب الموجهة لبيئة الإنتاج نشر تطبيقات iOS على متجر Apple Store
-
سنلقي نظرةً في مقالنا على اﻷجزاء التي يتكون منها سطح المكتب في نظام التشغيل لينكس أوبنتو Ubuntu في إصدارته 20.04؛ وهي النافذة الذي تظهر مباشرةً عند انتهاء تحميل نظام التشغيل. لن أتطرق بالطبع إلى أية مقارنات مع نسخ أقدم، أو إلى التغييرات التي تجري باستمرار على تنظيم سطح المكتب، بل سأعُدُّك مستخدمًا عاديًا دون أية خبرة مسبقة؛ على أساس أنك أردت أن تجرب نظام تشغيل مفتوح المصدر لمجرد الفضول، أو لأنك سمعت عن بعض ميزاته من أحد معارفك، فوجدت نفسك قد تورّطت وثبتت هذا النظام بمساعدة أو دون مساعدة. دعنا نبدأ إذًا هذه الرحلة السريعة التي تقودك بكل بساطة إلى فهم المكونات اﻷساسية لسطح المكتب وكيفية الوصول إلى بعض المعلومات المتعلقة بحاسوبك. اﻷجزاء الرئيسية لسطح مكتب جنوم يتكون سطح المكتب من عدة أقسام أساسية هي: شريط التطبيقات Applications Panel: يقع افتراضيًا في النسخة العربية على يمين الشاشة وفي النسخة اﻹنكليزية على يسارها. يعرض هذا الشريط اختصارات إلى التطبيقات التي ترغب في الوصول إليها بسرعة، ويمكنك دائمًا إضافة او إزالة الاختصارات كما تراه ملائمًا لاحتياجاتك. يدل ظهور نقطة حمراء بجوار التطبيق على أنه نشط؛ في حين تدل النقطتين على وجود نافذتين تعودان لهذا التطبيق وهكذا. زر إظهار التطبيقات Show Applications: يقع هذا الزر على طرف شريط التطبيقات وينتقل بك عند النقر إليه إلى نافذة التطبيقات المثبتة على حاسوبك. ستجد دائمًا مجموعةً من التطبيقات اﻷساسية التي تُثبّت افتراضيًا مع نظام التشغيل، كما ستُعرض فيه أية تطبيقات ستعمل على تثبيتها بنفسك لاحقًا. شريط المهام Taskbar: يقع الشريط أعلى يمين الشاشة في النسخة العربية ويضم اختصارات لأدوات تحكم ومؤشرات على حالة النظام. قد يختلف عدد هذه الاختصارات وفقًا للإعدادات التي نضبطها ( سنرى ذلك لاحقًا في مقالات أخرى)، لكن الاختصارات الموضحة في الصورة التالية موجودة افتراضيًا: شريط اﻷنشطة Activity Bar: يقع هذا الشريط أعلى يمين الشاشة في النسخة العربية ويضم اختصارًا إلى البرنامج الذي يجري تحميله. وبعد إنتهاء التحميل، يختفي الاختصار من شريط اﻷنشطة وتظهر أيقونة البرنامج ضمن شريط التطبيقات. وعندها يكون دور شريط اﻷنشطة لإظهار اختصار إلى التطبيق الذي نعمل عليه حاليًا، إذ يعرض بالنقر عليه مجموعةً من التعليمات المتعلقة ببعض تفاصيل التطبيق أو بإنهائه. يعرض لك سطح المكتب عند النقر على زر "أنشطة" نوافذ جميع البرامج التي حمّلتها. نافذة سطح المكتب Desktop Window: تشغل هذه النافذة المساحة اﻷكبر من الشاشة وتضم افتراضيًا المجلد اﻷساسي "المنزل" ويعنون باسم مستخدم النظام؛ كما يضم سلة المهملات. ويمكنك إضافة مجلدات جديدة أو نسخ ولصق ملفات من وإلى نافذة سطح المكتب. التوقيت والتاريخ Time and Date: يظهران بين شريطي اﻷدوات واﻷنشطة ويعطي بالنقر عليهما تقويمًا بسيطًا يعرض اليوم والشهر والعام، مع إمكانية عرض الأحداث والتنبيهات المرتبطة بأيام معينة. يمكنك أيضًا تفعيل خيار "بلا إزعاج" لإسكات التنبيهات. تفاصيل سطح مكتب جنوم بعد أن عرضنا اختصار تنظيم سطح المكتب وأقسامه الرئيسية، سنغوص فيها الآن بشيء من التفصيل. استكشاف شريط التطبيقات يضم شريط التطبيقات أيقونات مجموعة من التطبيقات، والتي يظهر بعضها افتراضيًا عند تثبيت النظام مثل "متصفح الويب فايرفوكس" وتطبيق "الملفات" وتطبيق البريد اﻹلكتروني "ثندربيرد ميل Thunderbird Mail"؛ وبعضها قد تضعه بنفسك كما سنرى لاحقًا. سيُحمّل التطبيق بمجرد النقر عليه بالزر اليساري للفارة ويختفي عن سطح المكتب بالنقر على زر التصغير في النافذة مجددًا. تظهر عند النقر بالزر اليميني على أي تطبيق ضمن شريط التطبيقات نافذة مهام تُقدم مجموعةً من الخيارات، ويتعلق نوعها وعددها بالتطبيق ذاته. تحوي هذه القائمة عمومًا على تعليمات مثل: نافذة جديدة: وتفتح نافذة أخرى للتطبيق. لهذا اﻷمر أهميته الخاصة في التطبيقات التي يجري فيها سحب وإفلات العناصر من نافذة لأخرى مثل تطبيق "الملفات". أزل من المفضلة: ويستخدم لإزالة أيقونة التطبيق من شريط التطبيقات. أظهر التفاصيل: تنتقل بك هذه التعليمة إلى نافذة توصيف التطبيق، وهي نافذة من نوافذ تطبيق "برمجيات"، الذي يسمح بإضافة أو إزالة التطبيقات من نظامك. تقدم لك هذه النافذة معلومات عن آلية عمل التطبيق ومؤلفه ورخصة استخدامه وآخر إصداراته وتحديثاته وقائمة باﻹضافات المتوفرة التي تدعم وظائف هذا التطبيق. أنهِ: ﻹغلاق التطبيق إن كان مُحمّلًا، حيث لا يظهر هذا الخيار إن لم يكن كذلك. استكشاف نافذة التطبيقات بالنقر على زر التطبيقات الموجود أسفل شريط التطبيقات، ينتقل بك النظام إلى نافذة تعرض أيقونات التطبيقات المثبتة على حاسوبك. تضم هذه النافذة مجموعةً خدميةً متنوعةً من التطبيقات التي تأتي افتراضيًا مع نظام التشغيل أوبونتو، منها برامج التحديث وضبط اﻹعدادات ودعم اللغات واﻷلعاب. لتشغيل أي تطبيق، انقر عليه بزر الفأرة اليساري مرةً واحدة، وسيظهر اختصاره في شريط اﻷنشطة أثناء التحميل، ثم تظهر أيقونته في شريط التطبيقات عندما يكتمل التحميل. ملاحظة 1: إن اختفى اختصار التطبيق من شريط اﻷنشطة ولم تظهر أيقونته في شريط التطبيقات خلال فترة قصيرة، فهنالك مشكلة في تشغيل التطبيق وقد أنهى النظام تشغيله دون إنذار مسبق. ملاحظة 2: لإضافة أي تطبيق إلى قائمة التطبيقات، انقر بالزر اليميني للفأرة على التطبيق واختر "أضف إلى المفضلة". يتواجد في أسفل نافذة التطبيقات خياران هما: "الكل" و "شائعة". بالنقر على الخيار اﻷول، سيعرض لك سطح المكتب جميع البرامج المثبتة على حاسوبك، بينما سيعرض فقط التطبيقات اﻷكثر استخدامًا إن نقرت على "شائعة". تقدم لك هذه النافذة أيضًا ميزة البحث عن أية تطبيقات أو ملفات أو إعدادات من خلال صندوق البحث في أعلاها. ويمكنك كتابة حرف أو أكثر من الاسم حتى يعرض لك كل ما هو موجود بأسلوب منظم وسهل الفهم. تعرض الصورة التالية محاولة البحث عن محرر نصوص، لذلك كتبنا أول حرفين "مح". لاحظ النتائج المتوفرة: لمغادرة نافذة التطبيقات، اضغط على المفتاح "Esc"؛ أو انقر مجدًا على زر التطبيقات. من أهم التطبيقات التي تعرضها القائمة نشير إلى ما يلي: اﻹعدادات: يتيح لك التطبيق واجهةً للتحكم بإعدادات العتاد الصلب والتطبيقات والخدمات المختلفة، وسنفرد لهذا التطبيق مقالات خاصة لأهميته الكبيرة. مُحدّث البرمجيات: يتيح لك التطبيق إمكانية ضبط إعدادات آليات تحديث النظام والبرمجيات المثبتة عليه، وإمكانية تحديد ما تريد تحديثه وما لاتريده واختيار الخوادم التي ستنزّل منها هذه التحدثيات. لهذا البرنامج أهمية كبيرة جدًا في صيانة تطبيقاتك والتحقق من جودة اعتمادياتها Dependencies. برمجيات: وهو تطبيق شديد اﻷهمية يسمح لك بالوصول إلى مخازن أوبنتو سواءً "جنوم-ستور" أو سناب-ستور" لتثبيت البرمجيات اللازمة في عملك. وقد تجده أحيانًا باسم "أوبنتو سوفتوير Ubuntu Software" وفقًا ﻵخر تحديث مثبت على حاسوبك. يعرض لك التطبيق البرمجيات المتوفرة مصنفةً وفقًا لنوعها وطبيعة عملها وتقييم المستخدمين لها. وسنفرد لاحقًا مقالًا خاصًا عن استخدام هذا التطبيق لتثبيت وإزالة البرمجيات. LibreOffice: وهو مجموعة برامج مكتبية Office مفتوحة المصدر تشابه مجموعة برامج مايكروسوفت أوفيس، تساعدك في كتابة وتنسيق الملفات النصية والعروض التقديمية وتصميم جداول البيانات بإمكانات متقدمة ومتميزة. ستجد من هذه السلسة تطبيقات LibreOffice Writer و LibreOffice Calc و LibreOffice Impress و LibreOffice Draw. تعرف على شريط المهام يضم شريط المهام مجموعةً من الاختصارات لبعض اﻹعدادات، وبعض مؤشرات أداء الجهاز والتطبيقات. تظهر ضمن الشريط مجموعات من القوائم تبدأ كلّ منها بسهم صغير نحو اﻷسفل يفتح بالنقر عليه ما تضمه القائمة من خيارات. يظهر افتراضيًا الشريط الرئيسي الموجود في أقصى اليسار ويضم إعدادات الصوت وشبكات الاتصال وأوامر إنهاء التشغيل وتسجيل الخروج. يعرض القسم اﻷول من قائمة الشريط الرئيسي مستوى الصوت، ويليها قسم شبكات الاتصال بأنواعها. تُظهر القائمة وجود شبكة واي-فاي WiFi جاهزة للعمل وشبكة افتراضية VPN مطفأة وشبكة لاسلكية بتقنية بلوتوث جاهزة للعمل أيضَا، وسيظهر بالطبع أي اتصال ضمن هذه القائمة. وبالنقر على زر القائمة المنسدلة بجوار كل اتصال، ستظهر مجموعة الخيارات للتحكم بالاتصال، مثل اختيار شبكة أو إيقافها أو الانتقال إلى إعدادات الاتصال. يلي هذا القسم التالي خيارات الانتقال إلى لوحة إعدادات النظام وأوامر قفل سطح المكتب "أوصد" وأوامر اﻹطفاء الكامل والخروج. يظهر أيضًا شريط اللغة الذي يضم قائمًةً بمجموعة اللغات المثبتة كمصدر دخل Input Source، أي اللغات التي يمكن الكتابة بها عند استخدام لوحة المفاتيح. ويعرض الشريط أيضًا خيار "أظهر تخطيط لوحة المفاتيح" الذي يعطي تسمية المفاتيح وفقًا لنظام التشغيل أوبنتو. لا تتفاجئ بظهور أشرطة مهام أخرى، فقد تعرض بعض البرمجيات والتطبيقات أشرطة مهام خاصة بها لتساعدك في التعامل مع إعداداتها. تعرف على نافذة سطح المكتب وهي الواجهة الرئيسية لنظام أوبنتو وتمثل في الواقع مجلدًا لا يختلف عن بقية المجلدات عمومًا من الناحية الوظيفية إلا أنه لا يقبل عمليات السحب واﻹفلات. إذ لا يمكن جر وإفلات أي مجلد أو ملف من نافذة ما إلى سطح المكتب، إلا أن عمليات النسخ واللصق متاحة. تظهر قائمة سطح المكتب بالنقر على أي نقطة من نافذة سطح المكتب بالزر اليميني وتعرض الخيارات التالية: "مجلد جديد New Folder": ﻹنشاء مجلد جديد على سطح المكتب. "لصق Paste": لصق المجلدات أو الملفات الموجودة في الحافظة. "اعرض سطح المكتب باستخدام تطبيق الملفات Show Desktop in Files": يفتح تطبيق "الملفات" سطح المكتب ويعرضه كأي مجلد آخر. "افتح باستخدام الطرفية Open in Terminal": يفتح سطح المكتب باستخدام برنامج الطرفية. "غير الخلفية Change Background": يفتح إعدادات تغيير صورة الخلفية. "إعدادت العرض Display Settings": يفتح إعدادات ضبط شاشة العرض المستخدمة. "اﻹعداداتSettings": يفتح تطبيق اﻹعدادات. إطفاء الحاسوب انقر على شريط المهام الرئيسي في أقصى يسار شريط اﻷدوات، ثم اختر اﻷمر " إطفاء \ خروج" لتظهر لك النافذة التالية: اختر اﻷمر "أطفئ" ﻹيقاف التشغيل أو "أعد التشغيل"، كما يمكنك إلغاء العملية بالنقر على زر "ألغِ" إن وصلت إلى هذا المكان بطريق الخطأ. سيُطفأ النظام تلقائيًا بعد 60 ثانية إن لم تتخذ قرارك كما توضح لقطة الشاشة السابقة. خلاصة تعرفنا في هذا المقال على البنية التنظيمية لسطح مكتب جنوم، وهي الواجهة الرسومية الرئيسية لنظام لينكس أوبونتو؛ كما تحدثنا بشيء من التفصيل عن أقسام سطح المكتب وأهم المؤشرات والاختصارات التي يحويها كل قسم، ثم عرضنا آلية إطفاء الحاسوب بالطريقة الصحيحة. لقد أصبحنا اﻵن مستعدين للانتقال إلى المرحلة الثانية من مراحل استثمار نظام أوبنتو، وهي التعامل مع المجلدات والملفات. إقرأ أيضًا ما هو نظام التشغيل لينكس؟ تغيير اللغة في نظام لينكس أوبنتو إلى العربية في ماذا يختلف Ubuntu عن Debian؟
-
لقد أضفنا حتى الآن عدة ميزات إلى تطبيقنا لكن دون أي اتصال بالخادم، إذ يستخدم تطبيق قائمة المستودعات المقيَّمة الذي نفذناه في المقال السابق أساسيات React Native -على سبيل المثال- بيانات وهمية، ولا يرسل نموذج تسجيل الدخول بيانات التحقق من المستخدم إلى أية وصلة تخديم endpoint مفوَّضة باستقبال هذه البيانات، لذا سنتعلم في هذا المقال كيف سنتصل بالخادم مستخدمين طلبات HTTP، وكيف سنستخدم المكتبة Apollo Client ضمن تطبيقات React Native، وكذلك طريقة تخزين البيانات في جهاز المستخدم. سنحتاج قبل الشروع بتعلم تلك النقاط إلى خادم لنتواصل معه، لذلك فقد أنجزنا خادمًا كاملًا ووضعناه في المستودع rate-repository-api. سيلبي الخادم "rate-repository-api" كل ما تحتاجه الواجهة البرمجية لتطبيقنا خلال هذا القسم، إذ يستخدم "rate-repository-api" قاعدة بيانات SQLite والتي لا تحتاج إلى إعدادات، كما يؤمن واجهة برمجية خاصة بالمكتبة Apollo GraphQL، إضافةً إلى بعض وصلات التخديم التي تؤمن واجهة برمجية متوافقة مع REST. قبل أن تغوص أعمق في مادة هذا المقال، عليك أن تُعدَّ الخادم "rate-repository-api" باتباع الإرشادات الموجودة في ملف README الخاص بالمستودع. ننصحك إن كنت ستستخدم المقلّد emulator لتطوير التطبيق، أن تشغله على نفس الحاسوب الذي يشغّل الخادم، فسيسهل ذلك طلبات الاتصال عبر الشبكة على نحوٍ واضح. طلبات HTTP تزودنا React Native بالواجهة البرمجية Fetch API لتنفيذ طلبات HTTP الخاصة بتطبيقنا، كما تدعم أيضًا الواجهة البرمجية القديمة XMLHttpRequest API والتي ستمكننا من استخدام مكتبات خارجية مصدرها طرف ثالث مثل Axios. وهذه الواجهات هي نفسها التي استخدمناها في بيئة المتصفح، كما أنها متاحة لكامل التطبيق ولا حاجة لإدراجها. قد يتفق المطورون الذين تعاملوا مع الواجهتين البرمجيتين السابقتين، أن Fetch API أسهل استخدامًا وأكثر عصرية، لكن للواجهة XMLHttpRequest API استعمالاتها أيضًا، ولأجل تبسيط الموضوع سنتعامل فقط مع Fetch API في أمثلتنا. يمكن استخدام Fetch API لإرسال طلبات HTTP باستخدام الدالة fetch وسيكون الوسيط الأول لهذه الدالة عنوان المورد URL وطلب HTTP الافتراضي لها هو GET: fetch('https://my-api.com/get-end-point'); أما الوسيط الثاني للدالة فهو كائن خيارات يمكنك استعماله لإنشاء طلب HTTP آخر، أو ترويسة طلب، أو متن body طلب: fetch('https://my-api.com/post-end-point', { method: 'POST', headers: { Accept: 'application/json', 'Content-Type': 'application/json', }, body: JSON.stringify({ firstParam: 'firstValue', secondParam: 'secondValue', }), }); انتبه إلى أنّ العناوين "URL's" مصطنعة ولن تستجيب لطلباتك غالبًا. تعمل Fetch API موازنةً بالمكتبة Axios في مستوى أدنى قليلًا، فلا توجد مثلًا أية عمليات تحويل أو تفسير لمتن الطلب أو الاستجابة، فعليك مثلًا أن تحدد نوع المحتوى content-type بنفسك وأن تستخدم التابع JSON.stringify لتحويل متن الطلب إلى نص. تعيد الدالة fetch وعدًا (promise) يُحَل resolves إلى كائن الاستجابة Response، وانتبه إلى أنّ رموز الحالة للأخطاء التي تحصل مثل 400 أو 500 لن تُرفض كما هو الوضع في Axios مثلًا. يمكن أن نفسّر متن الاستجابة المنسقة بأسلوب JSON باستخدام التابع Response.json: const fetchMovies = async () => { const response = await fetch('https://reactnative.dev/movies.json'); const json = await response.json(); return json; }; وللاطلاع على أساسيات Fetch API بشيء من التفصيل، اقرأ مقال الواجهة البرمجية fetch في JavaScript ومقال استعمالات متقدمة للواجهة البرمجية Fetch في جافاسكربت وأضف إليهما مقال تتبع تقدم عملية تنزيل البيانات عبر Fetch ومقاطعتها في جافاسكربت. لنبدأ بالاستخدام التطبيقي للمكتبة Fetch API، إذ يؤمن الخادم rate-repository-api وصلة تخديم تعيد قائمةً مرقمةً من المستودعات المقيَّمة. ستتمكن من الولوج إلى وصلة التخديم الموجودة على العنوان "http://localhost:5000/api/repositories" بمجرد أن يعمل الخادم. تُرقّم البيانات بأسلوب الترقيم المعتمد على المؤشرات cursor based pagination format، وستجد البيانات الفعلية خلف المفتاح "node" في المصفوفة "edges". لا يمكن، لسوء الحظ، الوصول إلى الخادم rate-repository-api مباشرةً من خلال تطبيقنا بطلب العنوان "http://localhost:5000/api/repositories"، إذ نحتاج لإرسال طلب إلى وصلة التخديم هذه عبر التطبيق الوصول إلى الخادم باستخدام عنوان IP الخاص به في الشبكة المحلية التي ينتمي إليها. ولإيجاد هذا العنوان، افتح أدوات تطوير Expo بتنفيذ الأمر npm start. سترى في أدوات التطوير عنوانًا له بالبادئة "//:exp" فوق شيفرة QR: انسخ عنوان IP الموجود بين البادئة "//:exp" والنهاية ":"، وسيكون في مثالنا 192.168.100.16. أنشئ بعد ذلك عنوان URL بالتنسيق التالي "http://:5000/api/repositories" ثم توجه إليه من خلال المتصفح، وستحصل على نفس الاستجابة التي حصلت عليها باستخدام عنوان الخادم المحلي "localhost". بعد أن حددنا عنوان وصل التخديم، سنستخدم البيانات الفعلية التي يزودنا بها الخادم في تطبيق قائمة المستودعات المقيَّمة. أشرنا سابقًا أننا نستخدم بيانات وهمية مخزّنة في المتغير repositories. اِحذف هذا المتغير واستعض عن البيانات الوهمية في الملف "RepositoryList.jsx" الموجود في المجلد "components" بهذه الشيفرة: import { useState, useEffect } from 'react'; // ... const RepositoryList = () => { const [repositories, setRepositories] = useState(); const fetchRepositories = async () => { // صحح عنوان IP إن كان مختلفًا لديك const response = await fetch('http://192.168.100.16:5000/api/repositories'); const json = await response.json(); console.log(json); setRepositories(json); }; useEffect(() => { fetchRepositories(); }, []); // Get the nodes from the edges array const repositoryNodes = repositories ? repositories.edges.map(edge => edge.node) : []; return ( <FlatList data={repositoryNodes} // Other props /> ); }; export default RepositoryList; استخدمنا الخطاف useState للحفاظ على حالة قائمة المستودعات، كما استخدمنا الخطاف useEffect لاستدعاء الدالة fetchRepositoriesعندما يُثبّت المكوّن RepositoryList ضمن شجرة المكوّنات. استخلصنا المستودعات الفعلية ووضعناها في المتغير repositoryNode واستبدلنا به المتغير السابق repositories الموجود في الخاصية data العائدة للمكوّن FlatList، وبذلك يمكننا أن نرى البيانات الفعلية التي يعطيها الخادم ضمن التطبيق. من الجيد عادةً تسجيل استجابة الخادم لتتمكن من تحرّيها كما فعلنا في الدالة fetchRepositories. ينبغي أن تكون قادرًا على الاطلاع على السجلات في أدوات تطوير Expo عن طريق الوصول إلى سجلات جهازك كما تعلمنا في المقال السابق (فقرة عرض سجلات العمل). إن استخدمت تطبيق جوّال Expo وأخفق طلب HTTP، تأكد أن هاتفك وحاسوبك الذي يشغّل الخادم ينتميان إلى نفس الشبكة اللاسلكية. وإن لم تستطع ذلك، استخدم المقلّد على نفس الحاسوب الذي يعمل عليه الخادم أو هيئ نفق توصيل tunnel إلى الخادم المحلي. يمكنك استخدام المكتبة Ngrok مثلًا لإنجاز ذلك. يمكن إعادة كتابة شيفرة إحضار البيانات الموجودة في المكوّن RepositoryList، إذ يعرف المكوّن مثلًا تفاصيل الطلبات عبر الشبكة كعنوان وصلة التخديم، وبالإضافة إلى ذلك، تحمل شيفرة إحضار البيانات إمكانية لإعادة استخدامها. لنعد إذًا كتابة شيفرة المكوّن بنقل شيفرة إحضار البيانات إلى خطاف خاص بها. سننشئ أولًا مجلدًا باسم "hooks" ضمن المجلد "src" ومن ثم سنضع فيه الملف "useRepositories.js" الذي يحتوي الشيفرة التالية: import { useState, useEffect } from 'react'; const useRepositories = () => { const [repositories, setRepositories] = useState(); const [loading, setLoading] = useState(false); const fetchRepositories = async () => { setLoading(true); // صحح عنوان IP إن كان مختلفًا لديك const response = await fetch('http://192.168.100.16:5000/api/repositories'); const json = await response.json(); setLoading(false); setRepositories(json); }; useEffect(() => { fetchRepositories(); }, []); return { repositories, loading, refetch: fetchRepositories }; }; export default useRepositories; لنستخدم الآن الخطاف الجديد useRepositories في المكوّن RepositoryList: // ... import useRepositories from '../hooks/useRepositories'; const RepositoryList = () => { const { repositories } = useRepositories(); const repositoryNodes = repositories ? repositories.edges.map(edge => edge.node) : []; return ( <FlatList data={repositoryNodes} // Other props /> ); }; export default RepositoryList; وهكذا لن يكون لدى المكوّن RepositoryList أية فكرة عن طريقة الحصول على مستودعات القائمة، وربما سنطلب هذه المستودعات مستقبلًا باستخدام الواجهة البرمجية للمكتبة GraphQL بدلًا من واجهة REST، ونرى ما الذي سيحدث. العمل مع المكتبتين GraphQL و Apollo client تعرفنا في القسم 8 على GraphQL وكيفية إرسال استعلامات إلى خادم Apollo في تطبيقات React بالاستفادة من المكتبة Apollo Client. ولحسن الحظ، يمكنك استخدام Apollo client في تطبيقات React Native بنفس الطريقة التي استخدمناها في بناء تطبيقات React الخاصة بالويب. وكما أشرنا سابقًا، سيزودنا الخادم "rate-repository-api" بواجهة برمجية للمكتبة GraphQL نُفِّذت باستخدام Apollo client، وبالتالي ستتمكن من الولوج إلى أرضية عمل GraphQL بالتوجه إلى العنوان http://localhost:5000/graphq. تمثل أرضية عمل GraphQL أداة تطوير لإرسال استعلامات GraphQL، وتفقد تخطيط الواجهة البرمجية للمكتبة GraphQL، وعرض توثيق هذه المكتبة. ويفضل أن تجرب دائمًا أية استعلامات سيرسلها تطبيقك من خلال أرضية عمل GraphQL قبل تضمينها في الشيفرة. ومن الأسهل أيضًا تنقيح الأخطاء المحتملة في الاستعلامات ضمن أرضية عمل GraphQL موازنةً مع تنقيحها باستخدام التطبيق. وإن لم تكن متأكدًا من الاستعلامات المتاحة أو كيفية استخدامها، انقر على النافذة "docs" لفتح التوثيق: سنستعمل في تطبيقات React Native المكتبة Apollo Boost، وهو أسلوب لا يتطلب أية قواعد للتهيئة zero-config للبدء باستخدام Apollo client. وللتكامل مع React، سنستخدم المكتبة apollo/react-hooks@ والتي تؤمن خطافات مثل useQuery و useMutation تساعدنا في العمل مع المكتبة Apollo client. لنبدأ بتثبيت الاعتماديات اللازمة: npm install @apollo/client graphql سنحتاج قبل البدء باستخدام عميل Apollo إلى إعدادٍ جزئي لمجمّع Metro لمعالجة الملفات ذات الامتداد "cjs." التي يستخدمها عميل Apollo. لنثبّت أولًا الحزمة "expo/metro-config@" التي تحتوي على إعدادات Metro الافتراضية: npm install @expo/metro-config يمكننا بعد ذلك إضافة الإعداد التالي إلى الملف "metro.config.js" في المجلد الجذري للمشروع: const { getDefaultConfig } = require('@expo/metro-config'); const defaultConfig = getDefaultConfig(__dirname); defaultConfig.resolver.sourceExts.push('cjs'); module.exports = defaultConfig; أعِد تشغيل أدوات تطوير Expo لتطبيق الإعدادات المُجراة. لننشئ الآن دالةً خدميّة utility function لتكوين عميل Apollo وتهيئته على النحو المطلوب. أنشئ بدايةً المجلد "utils" ضمن المجلد "src"، وأنشئ ضمنه الملف "apolloClient.js"، ثم هيئ عميل Apollo ضمن هذا الملف ليتصل مع خادم Apollo: import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client'; const httpLink = createHttpLink({ // صحح عنوان IP إن كان مختلفًا لديك uri: 'http://192.168.100.16:4000/graphql', }); const createApolloClient = () => { return new ApolloClient({ link: httpLink, cache: new InMemoryCache(), }); }; export default createApolloClient; يستخدم عميل Apollo للاتصال بخادم Apollo العنوان URL ذاته الذي استخدمناه مع Fetch API ونفس رقم المنفذ 4000، ما عدا أنّ المسار هو "graphql/". وأخيرًا علينا تزويد التطبيق بعميل Apollo وذلك باستخدام سياق العمل ApolloProvider. سنضيفه إذًا إلى المكوّن App في الملف "App.js": import { NativeRouter } from 'react-router-native'; import { ApolloProvider } from '@apollo/client'; import Main from './src/components/Main'; import createApolloClient from './src/utils/apolloClient'; const apolloClient = createApolloClient(); const App = () => { return ( <NativeRouter> <ApolloProvider client={apolloClient}> <Main /> </ApolloProvider> </NativeRouter> ); }; export default App; تنظيم الشيفرة المتعلقة بالمكتبة GraphQL سيعود الأمر إليك دائمًا في تنظيم الشيفرة المتعلقة بالمكتبة GraphQL ضمن تطبيقك. لكن ولأجل الحصول على هيكلية مرجعية، لنلق نظرةً على طريقة بسيطة لكنها فعالة في تنظيم هذه الشيفرة. عرّفنا في هذه الهيكلية كلًا من الاستعلامات والطفرات mutations والاجتزاءات fragments وغيرها من الكيانات التي قد نستخدمها في ملفات خاصة بها وتتواجد في نفس المجلد. إليك صورة توضح هيكلية يمكنك اعتمادها: يمكنك استيراد معرّف القالب المجرّد gql المُستخدم في تعريف استعلامات من مكتبة "apollo/client@". وإن اتبعنا الهيكلية التي اقترحناها منذ قليل، فمن الأفضل إنشاء الملف "queries.js" في المجلد "graphql" ليحتوي الشيفرة اللازمة لتنفيذ استعلامات GraphQL في تطبيقنا. يمكن أن نخزّن كل استعلام ضمن متغّير خاص ثم نصدّره كالتالي: import { gql } from '@apollo/client'; export const GET_REPOSITORIES = gql` query { repositories { ${/* ... */} } } `; // other queries... يمكن إدراج تلك المتغيرات واستخدامها بالاستفادة من الخطاف useQuery على النحو التالي: import { useQuery } from '@apollo/client'; import { GET_REPOSITORIES } from '../graphql/queries'; const Component = () => { const { data, error, loading } = useQuery(GET_REPOSITORIES); // ... }; وينطبق على الطفرات ما ينطبق على الاستعلامات. طبعًا لا بدّ من تعريف الطفرات في ملف منفصل مثل "mutations.js"، ويُفضّل استخدام الاجتزاءات (fragments) في الاستعلامات لتفادي تكرار كتابة الحقول نفسها عدة مرات. تطوير هيكلية التطبيق عندما يأخذ التطبيق في النمو، سيزداد حجم بعض الملفات لتصبح ربما كبيرة جدًا لإدارتها بصورةٍ صحيحة. لنفترض أنه لدينا مكوّن A سيصيّر مكونين B و C. ستُعرّف جميع هذه المكونات ضمن الملف "A.jsx" والذي سيوضع في المجلد"components". نريد الآن أن ننقل المكونين A و B إلى ملفين مستقلين "B.jsx" و "C.jsx" دون أن نجري تغييرًا كبيرُا في تنظيم الشيفرة. سيكون أمامنا في هذه الحالة خيارين: الأول، إنشاء الملفين "B.jsx" و"C.jsx" في المجلد "components". وستكون هيكلية التطبيق على النحو التالي: components/ A.jsx B.jsx C.jsx ... الثاني، إنشاء مجلد A في المجلد "components" ثم إنشاء الملفين "B.jsx"و"C.jsx" ضمنه. ولتفادي إخفاق المكونات التي تُدرِج الملف "A.jsx" في شيفرتها، انقل الملف "A.jsx" إلى المجلد "A" وغيّر اسمه إلى "index.jsx". سينتج عن هذا الأسلوب الهيكلية التالية: components/ A/ B.jsx C.jsx index.jsx ... يُعد الخيار الأول مناسبًا تمامًا إن لم يكن المكونين C وB قابلين للاستخدام خارج حدود المكوّن A، فلا فائدة من وضعهما في ملفات منفصلة في المجلد "components"؛ أما الخيار الثاني فهو مناسبٌ لأسلوب الوحدات المستقلة، إذ أنه لا يسبب أية مشاكل في إدراج المكونات، لأن إدراج مسار مثل "A/." سيطابق إدراج كلا الملفين "A.jsx" و"A/index.jsx". التمرين 10.11 إحضار المستودعات باستخدام Apollo client نريد استبدال ما نفذناه ضمن الخطاف useRepositories مستخدمين المكتبة Fetch API باستعلام GraphQL. شغّل أرضية عمل Apollo على العنوان "http://localhost:4000"، ثم افتح توثيق المكتبة بالنقر على النافذة "docs". يستخدم الاستعلام عدة وسطاء اختيارية، فلا حاجة لتحديدها الآن. كوّن استعلامًا ضمن أرضية عمل Apollo لإحضار المستودعات بالاستفادة من قيم الحقول التي تعرضها حاليًا في واجهة التطبيق. ستُرقّم النتائج التي تضم قرابة 30 نتيجة افتراضيًا. يمكنك تجاهل موضوع الترقيم حاليًا. عندما يعمل الاستعلام ضمن أرضية عمل Apollo، اِستخدمه ليحل مكان شيفرة المكتبة FetchAPI في الخطاف useRepositories. يمكن أن تنفِّذ ذلك باستخدام الخطاف useQuery. أدرج بعدها معّرف القالب المجرّد gql من المكتبة بالطريقة التي شرحناها سابقًا. حاول أن تستخدم الهيكلية التي اقترحناها سابقًا لتنظيم الشيفرة المتعلقة بالمكتبة GraphQL. ولتجنب مشاكل الذاكرة الخبيئة مستقبلًا، استخدم سياسة الإحضار (fetch policy) "cache-and-network"، التي يمكن استخدامها مع الخطاف useQuery على النحو التالي: useQuery(MY_QUERY, { fetchPolicy: 'cache-and-network', // خيارات أخرى }); يجب أن لا تؤثر التغييرات في شيفرة الخطاف useRepositories على أداء المكوّن RepositoryList بأي شكل من الأشكال. متغيرات البيئة سيعمل كل تطبيق على الأرجح في أكثر من بيئة، ومن الواضح أن بيئتي التطوير والإنتاج أقرب مثالين عن الفكرة، لكن خارج هاتين البيئتين، هناك البيئة التي نشغّل عليها التطبيق حاليًا. تحتاج البيئات المختلفة عادةً اعتماديات مختلفة، فقد يستخدم الخادم المحلي الذي نتعامل معه قاعدة بيانات محليّة، بينما سيتعامل الخادم الذي سيُنشَر في بيئة الإنتاج مع قاعدة بيانات بيئة الإنتاج. ولكي نجعل شيفرتنا مستقلة عن بيئة التشغيل، لا بد من ربط هذه الاعتماديات بمعاملات أو متغيرات. لاحظ مثلًا أننا نستخدم في تطبيقنا قيمة جاهزة تعتمد بشدة على بيئة التشغيل وهي عنوان الخادم. تعلمنا سابقًا أنه بالإمكان تزويد البرامج قيد التشغيل بمتغيرات بيئة، إذ يمكن تعريف هذه المتغيرات من خلال سطر الأوامر أو من خلال ملف تهيئة بيئة التشغيل الذي ينتهي بلاحقة مثل "env." ومكتبات يؤمنها طرف ثالث مثل Dotenv. لكن ولسوء الحظ لا تدعم React Native الاستخدام المباشر لمتغيرات البيئة، لكن يمكننا الوصول إلى إعدادت تهيئة Expo الموجودة في الملف "app.json" في زمن التشغيل من خلال شيفرة JavaScript. وبالتالي يمكن استخدام هذه الإعدادات لتعريف المتغيرات المتعلقة بالبيئة والوصول إليها. نستطيع الوصول إلى إعدادات التهيئة بإدراج الثابت Constants من الوحدة "expo-constants" كما فعلنا ذلك عدة مرات مسبقًا. وبإدراج هذا الثابت، ستزودنا الخاصية Constants.manifest بكل الإعدادات. لنجرب ذلك بكتابة شيفرة ضمن المكوّن App وظيفتها طباعة محتويات هذه الخاصية في سجل العمل: import { NativeRouter } from 'react-router-native'; import { ApolloProvider } from '@apollo/client'; import Constants from 'expo-constants'; import Main from './src/components/Main'; import createApolloClient from './src/utils/apolloClient'; const apolloClient = createApolloClient(); const App = () => { console.log(Constants.manifest); return ( <NativeRouter> <ApolloProvider client={apolloClient}> <Main /> </ApolloProvider> </NativeRouter> ); }; export default App; ستجد الآن كل إعدادات التهيئة في سجل العمل. تقتضي الخطوة الثانية استخدام الإعدادات لتعريف متغيّرات تعتمد على بيئة التشغيل. لنبدأ المهمة بتغير اسم الملف "app.json" إلى "app.config.json". بهذا التغيير سنصبح قادرين على استخدام شيفرة جافا سكريبت داخل ملف التهيئة. غير محتوى الملف بحيث يتحوّل الكائن: { "expo": { "name": "rate-repository-app", // … بقية الضبط } } إلى كائن قابل للتصدير، يحتوي على الخاصية expo: export default { name: 'rate-repository-app', // … بقية الضبط }; يتلقى الكائن expo الخاصية extra ضمن إعدادات التهيئة، وذلك لتمرير أية إعدادات خاصة بالتطبيق. ولنرى كيف يعمل هذا الأمر، سنضيف المتغير env إلى إعدادات تهيئة تطبيقنا: export default { name: 'rate-repository-app', // … بقية الضبط extra: { env: 'development' }, }; أعد تشغيل أدوات تطوير Expo لتطبيق التغييرات. من المفترض أن تتغير قيمة الخاصية Constans.manifest بحيث تضم الخاصية extra التي تحتوي على إعدادات التهيئة الخاصة بتطبيقنا. يمكننا الآن الوصول إلى المتغير env من خلال الخاصية Constants.manifest.extra.env ولأن وضع القيم الجاهزة في الشيفرة أمر طائش، سنستخدم متغير بيئة بديلًا لذلك: export default { name: 'rate-repository-app', // rest of the configuration... extra: { env: process.env.ENV, }, }; تعلمنا سابقًا كيفية إسناد قيمة لمتغير البيئة من خلال سطر الأوامر، وذلك بتحديد اسم المتغيّر وقيمته قبل الأمر الفعلي. فعلى سبيل المثال، شغل أدوات تطوير Expo، ثم أسند القيمة "test" إلى متغير البيئة ENV: ENV=test npm start لو ألقيت نظرةً على سجل العمل، فستجد أن الخاصية Constants.manifest.extra.env قد تغيرت. يمكننا كذلك تحميل متغيرات البيئة من الملف "env." كما تعلمنا في الأقسام السابقة. لكن علينا أولًا تثبيت المكتبة Dotenv: npm install dotenv لنضف الآن الملف "env." إلى المجلد الجذري للمشروع على أن يحتوي ما يلي: ENV=development سندرج أخيرًا المكتبة ضمن الملف "app.config.js": import 'dotenv/config'; export default { name: 'rate-repository-app', // … بقية الضبط extra: { env: process.env.ENV, }, }; أعد تشغيل أدوات تطوير Expo لتطبيق التغييرات التي أجريتها على الملف "env". ملاحظة: لا تضع بيانات حساسة ضمن إعدادات التطبيق، لأن المستخدم بعد تنزيل التطبيق قد يكون قادرًا من الناحية النظرية على تحليل شيفرتك وسيحصل بالتالي على هذه البيانات الحساسة. التمرين 10.12 متغيرات البيئة استخدم متغير بيئة ضمن ملف "env." لتحديد عنوان خادم Apollo بدلًا من كتابته ضمن الشيفرة، وذلك عند تهيئة عميل Apollo. يمكنك تسمية هذا المتغير "APOLLO_URI" مثلًا. لا تحاول الوصول إلى متغير البيئة على النحو التالي: process.env.APOLLO_URI خارج الملف "app.config.js"، بل استخدم الكائن Constants.manifest.extra كما فعلنا في المثال السابق. كذلك لا تدرج المكتبة Dotenv خارج الملف "app.config.js" وإلا قد تواجهك المشاكل. تخزين البيانات في جهاز المستخدم قد تحتاج في بعض الأحيان إلى تخزين بعض البيانات في جهاز المستخدم. ومن أبرز السيناريوهات التي تضطرك إلى ذلك هو تخزين شهادة التحقق من المستخدم token لكي تكون قادرًا على الحصول عليها عندما يغلق المستخدم التطبيق ثم يعيد فتحه. لقد استخدمنا عند تطوير تطبيقات الويب الذاكرة المحلية للمتصفح من خلال الكائن localStorage. تؤمن Recat Native بالمقابل ذاكرة تخزين مقيمة هي الذاكرة غير المتزامنة (AsyncStorage). يمكن استخدام أمر التثبيت في Expo لتثبيت نسخة من الحزمة reactnativecommunity/async-storage@ متوافقة مع نسخة Expo SDK المستخدمة: expo install @react-native-async-storage/async-storage تتشابه الواجهة البرمجية للحزمة AsyncStorage مع الواجهة البرمجية للذاكرة المحلية localStorage بعدة نواحٍ، فكلاهما ذاكرة تعتمد مبدأ "مفتاح-قيمة". ويكمن الاختلاف الكبير بينهما، كما يوحي الاسم، أنّ عمليات AsyncStorage غير متزامنة. من المفيد أن نُجري تجريدًا بسيطًا لشيفرة العمليات، طالما أن AsyncStorage ستعمل مع مفاتيح نصية ضمن فضاء الأسماء العام global namespace. يمكن إنجاز هذا التجريد باستخدام الأصناف class. إذ يمكن، على سبيل المثال، إنشاء صنف لبطاقة تسوق، نخزّن فيها المنتجات التي يريد أن يشتريها مستخدم: import AsyncStorage from '@react-native-async-storage/async-storage'; class ShoppingCartStorage { constructor(namespace = 'shoppingCart') { this.namespace = namespace; } async getProducts() { const rawProducts = await AsyncStorage.getItem( `${this.namespace}:products`, ); return rawProducts ? JSON.parse(rawProducts) : []; } async addProduct(productId) { const currentProducts = await this.getProducts(); const newProducts = [...currentProducts, productId]; await AsyncStorage.setItem( `${this.namespace}:products`, JSON.stringify(newProducts), ); } async clearProducts() { await AsyncStorage.removeItem(`${this.namespace}:products`); } } const doShopping = async () => { const shoppingCartA = new ShoppingCartStorage('shoppingCartA'); const shoppingCartB = new ShoppingCartStorage('shoppingCartB'); await shoppingCartA.addProduct('chips'); await shoppingCartA.addProduct('soda'); await shoppingCartB.addProduct('milk'); const productsA = await shoppingCartA.getProducts(); const productsB = await shoppingCartB.getProducts(); console.log(productsA, productsB); await shoppingCartA.clearProducts(); await shoppingCartB.clearProducts(); }; doShopping(); ومن الجيد أيضًا أن نحدد فضاء أسماء للمفاتيح في AsyncStorage، ذلك أنها قيم نصيّة. وفي هذا السياق، سنجد أن فضاء الأسماء هو بادئة نزوّد بها مفاتيح التخزين، إذ سيمنع استخدام فضاء الأسماء مفاتيح التخزين من التصادم مع مفاتيح أخرى للمكتبة AsyncStorage. عرّفنا فضاء الأسماء في المثال السابق على شكل وسيط للدالة البانية، كما استخدمنا التنسيق "namespace:key مفتاح: فضاء أسماء" من أجل مفاتيح التخزين. يمكن إضافة عنصر إلى ذاكرة التخزين مستخدمين التابع AsyncStorage.setItem. سيكون مفتاح العنصر هو الوسيط الأول للتابع بينما ستكون قيمة المفتاح هي المعامل الثاني. وطالما أن قيمة المفتاح هي قيمة نصية، فلا بد من تحويل القيم غير النصية إلى نصية باستخدام التابع JSON.stringify. يُستخدَم التابع AsyncStorage.getItem للحصول على عنصر محدد من ذاكرة التخزين، ووسيط هذا التابع هو مفتاح العنصر. أما التابع AsyncStorage.removeItem فيُستخدم لحذف عنصر من ذاكرة التخزين بتحديد مفتاحه. التمرينان 10.13 - 10.14 10.13: استخدام الطفرات في نموذج تسجيل الدخول لا يستطيع نموذج تسجيل الدخول حاليًا فعل أي شيء حيال معلومات توثيق المستخدم التي يرسلها، لذلك سنحاول تحسين الوضع قليلًا في هذا التمرين. اطلع أولًا على توثيق الاستيثاق authentication documentation الخاص بالخادم "rate-repository-api"، ثم اختبر الاستعلامات التي تُزوَّد بها ضمن أرضية عمل Apollo. إن لم تحتوي قاعدة البيانات على أي مستخدمين يمكن وضع بعض البيانات فيها، وستجد إرشاداتٍ لذلك في الفقرة "getting started"من الملف "README" الموجود في المستودع "rate-repository-ap". عندما تتفهم الطريقة التي تعمل بها استعلامات الاستيثاق، أنشئ الملف "useSignIn.js" في المجلد "hooks" وضع فيه شيفرة الخطافuseSignIn الذي يرسل الطفرة باستخدام الخطاف useMutation. تقبل الطفرة authenticate وسيطًا وحيدًا هو credentials من النوع "AuthenticateInput". يحتوي نوع عنصر الإدخال (input type) حقلين لاسم المستخدم وكلمة المرور. ستكون القيمة التي يعيدها الخطاف على الشكل [signIn, result]، إذ يمثل الوسيط result نتيجة الطفرات كما يعيدها الخطاف useMutation، ويمثل الوسيط signIn دالة تنفيذ الطفرة باستخدام وسيط هو كائن من الشكل {username, password}. تلميح: لا تمرر دالة الطفرة إلى القيمة المعادة مباشرةً، بل أعد دالة تستدعي دالة الطفرة على النحو التالي: const useSignIn = () => { const [mutate, result] = useMutation(/* mutation arguments */); const signIn = async ({ username, password }) => { // استدعي دالة الطفرة بالوسطاء المناسبين }; return [signIn, result]; }; بعد إنجاز الخطاف، استخدمه في دالة الاستدعاء onSubmit العائدة للمكوّن SignIn على النحو التالي مثلًا: const SignIn = () => { const [signIn] = useSignIn(); const onSubmit = async (values) => { const { username, password } = values; try { const { data } = await signIn({ username, password }); console.log(data); } catch (e) { console.log(e); } }; // ... }; يمكنك عدُّ التمرين مكتملًا عندما تُسجَّل نتيجة طفرات authenticate في سجل عمل التطبيق بعد إرسال بيانات النموذج. وينبغي أن تتضمن نتيجة الطفرة شهادة التحقق من المستخدم. 10.14: تخزين شهادة التحقق- الخطوة 1 بعد أن حصلنا على شهادة التحقق لا بدّ من تخزينها. أنشئ الملف "authStorage.js" في المجلد "utils" بحيث يحتوي الشيفرة التالية: import AsyncStorage from '@react-native-async-storage/async-storage'; class AuthStorage { constructor(namespace = 'auth') { this.namespace = namespace; } getAccessToken() { // احصل على شهادة التحقق } setAccessToken(accessToken) { // أضف الشهادة إلى ذاكرة التخزين } removeAccessToken() { // احذف شهادة التحقق من ذاكرة التخزين } } export default AuthStorage; أنجز شيفرة التوابع التالية: AuthStorage.getAccessToken و AuthStorage.setAccessToken و AuthStorage.removeAccessToken. استخدم المتغير namespace لمنح المفاتيح فضاء أسماء كما فعلنا في المثال السابق. تحسين طلبات المكتبة Apollo Client بعد أن أنجزنا آلية لتخزين شهادة التحقق من المستخدم، حان الوقت لاستخدامها. هيئ ذاكرة التخزين في المكوّن App: import { NativeRouter } from 'react-router-native'; import { ApolloProvider } from '@apollo/client'; import Main from './src/components/Main'; import createApolloClient from './src/utils/apolloClient'; import AuthStorage from './src/utils/authStorage'; const authStorage = new AuthStorage(); const apolloClient = createApolloClient(authStorage); const App = () => { return ( <NativeRouter> <ApolloProvider client={apolloClient}> <Main /> </ApolloProvider> </NativeRouter> ); }; export default App; مررنا نسخةً من الصنف الذي يتعامل مع ذاكرة التخزين AuthStorage إلى الدالة createApolloClient مثل وسيط، لأننا سنرسل لاحقًا شهادة التحقق إلى خادم Apollo مع كل طلب. يتوقع خادم Apollo أن تكون شهادة التحقق ضمن ترويسة الاستيثاق وبنفس تنسيق حامل الشهادة <ACCESS_TOKEN>. يمكن تحسين طلب Apollo Client باستخدام الدالة setContext. لنرسل شهادة التحقق إلى خادم Apollo من خلال عميل Apollo بتعديل الدالة createApolloClientفي الملف "apolloClient.js": import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client'; import Constants from 'expo-constants'; import { setContext } from '@apollo/client/link/context'; // قد تحتاج إلى تغيير هذا بناءً على كيفية تكوين URI لخادم Apollo const { apolloUri } = Constants.manifest.extra; const httpLink = createHttpLink({ uri: apolloUri, }); const createApolloClient = (authStorage) => { const authLink = setContext(async (_, { headers }) => { try { const accessToken = await authStorage.getAccessToken(); return { headers: { ...headers, authorization: accessToken ? `Bearer ${accessToken}` : '', }, }; } catch (e) { console.log(e); return { headers, }; } }); return new ApolloClient({ link: authLink.concat(httpLink), cache: new InMemoryCache(), }); }; export default createApolloClient; استخدام React Context لتوزيع البيانات يبقى علينا في النهاية إجراء تكامل بين ذاكرة التخزين والخطاف useSignIn. ولكي ننجز ذلك لا بدّ من السماح للخطاف بولوج شهادة التحقق التي هيئنا نسخة منها في المكوّن App. سنستخدم الواجهة Context التي تزودنا بها React لأداء هذه المهمة. أنشئ المجلد "contexts" ضمن المجلد "src"، ثم أنشئ ضمنه الملف "AuthStorageContext.js" وضع فيه الشيفرة التالية: import React from 'react'; const AuthStorageContext = React.createContext(); export default AuthStorageContext; ستتمكن الآن من استخدام المكوّن AuthStorageContext.Provider لتوزيع نسخة من ذاكرة التخزين على المكوّنات الأبناء ضمن سياق التنفيذ context. لنضفه إلى المكوّن App: import { NativeRouter } from 'react-router-native'; import { ApolloProvider } from '@apollo/client'; import Main from './src/components/Main'; import createApolloClient from './src/utils/apolloClient'; import AuthStorage from './src/utils/authStorage'; import AuthStorageContext from './src/contexts/AuthStorageContext'; const authStorage = new AuthStorage(); const apolloClient = createApolloClient(authStorage); const App = () => { return ( <NativeRouter> <ApolloProvider client={apolloClient}> <AuthStorageContext.Provider value={authStorage}> <Main /> </AuthStorageContext.Provider> </ApolloProvider> </NativeRouter> ); }; export default App; يمكن الوصول إلى نسخة ذاكرة التخزين في دالة الخطاف useSignIn باستخدام الخطاف useContext العائد للمكتبة React على النحو التالي: // ... import { useContext } from 'react'; import AuthStorageContext from '../contexts/AuthStorageContext'; const useSignIn = () => { const authStorage = useContext(AuthStorageContext); // ... }; انتبه إلى أنه من غير الممكن الولوج إلى القيمة التي يعيدها سياق العمل باستخدام الخطاف useContext مالم يُستخدم هذا الخطاف في مكوّن ابن للمكون Context.Provider. يُعد الوصول إلى نسخة ذاكرة التخزين باستخدام (useContext(AuthStorageContext مطولًا تمامًا ويكشف عن تفاصيل التنفيذ. دعنا نحسن هذا من خلال تنفيذ خطاف useAuthStorage في ملف "useAuthStorage.js" في مجلد "hooks": import { useContext } from 'react'; import AuthStorageContext from '../contexts/AuthStorageContext'; const useAuthStorage = () => { return useContext(AuthStorageContext); }; export default useAuthStorage; يعد تنفيذ الخطاف بسيطًا جدًا ولكنه يحسن إمكانية قراءة الخطافات والمكونات التي تستخدمها وصيانتها. يمكننا استخدام الخطاف لإعادة تشكيل خطاف useSignIn كما يلي: // ... import useAuthStorage from '../hooks/useAuthStorage'; const useSignIn = () => { const authStorage = useAuthStorage(); // ... }; ستجعل إمكانية توزيع البيانات على المكونات الأبناء من React Context مفتاحًا لحل عدد هائل من الحالات. لتطلع أكثر على هذه الحالات، اقرأ المقالة How to use React Context effectively للمؤلف "Kent C. Dodd"، لتعرف كيف توافق بين استخدام الخطاف useReducer وReact context لتنفيذ آلية لإدارة الحالة. وربما ستجد هذا مفيدًا لحل التمارين القادمة. التمرينان 10.15 و 10.16 10.15: تخزين شهادة التحقق- الخطوة 2 حسّن شيفرة الخطاف useSignIn لكي يخزّن شهادة التحقق التي تنتج عن الطفرة authenticate، بحيث لا تتغير القيمة التي يعيدها الخطاف. ينبغي أن يكون التغيير الوحيد في المكوّن SignIn هو تحويل المستخدم إلى واجهة عرض قائمة المستودعات بعد أن يسجل دخوله بنجاح. يمكنك إنجاز ذلك باستخدام الخطاف useNavigate. عليك أن تعيد ضبط مخزن عميل Apollo بعد تنفيذ الطفرة authenticate وتخزين شهادة التحقق في ذاكرة التخزين. سيسبب ذلك مسح الذاكرة المؤقتة وإعادة تنفيذ كل الطلبات النشطة. يمكن إنجاز ذلك باستخدام التابع resetStore العائد للمكتبة Apollo Client. يمكن الوصول إلى عميل Apollo عبر الخطاف useSignIn باستخدام الخطاف useApolloClient. وانتبه إلى أنّ ترتيب خطوات التنفيذ مهم جدًا وينبغي أن يكون على النحو التالي: const { data } = await mutate(/* خيارات */); await authStorage.setAccessToken(/* شهادة التحقق مأخوذة من البيانات */); apolloClient.resetStore(); 10.16: تسجيل الخروج ستكون الخطوة الأخيرة هي تنفيذ ميزة تسجيل الخروج. يمكن استخدام الاستعلام me للتحقق من بيانات الشخص الذي سجّل دخوله. فإن كانت نتيجة الاستعلام "null" فلن يكون الشخص مخوّلًا بالوصول. شغّل أرضية عمل Apollo، ثم نفّذ الاستعلام التالي: { me { id username } } ستكون النتيجة غالبًا "null"، والسبب في ذلك أنّ أرضية عمل Apollo غير مفوّضة بالوصول. ويعني ذلك أنها لم ترسل شهادة تحقق مع الطلب. راجع توثيق الاستيثاق لتفهم آلية استخلاص شهادة تحقق من الطفرة authenticate. استخدم هذه الشهادة في ترويسة الاستيثاق كما هو موّضح في التوثيق. نفّذ بعد ذلك الاستعلام me من جديد وسترى معلومات المستخدم الذي سجّل دخوله. افتح الملف "AppBar.jsx" الذي يحتوي على المكوّنAppBar والذي يحتوي بدوره على النافذتين "Sign in" و"Repositories". عدّل النوافذ بحيث تظهر النافذة "Sign out" إن سجل المستخدم دخوله، والنافذة "Sign in" إن سجّل خروجه. يمكنك إنجاز ذلك باستخدام الاستعلام me مع الخطاف useQuery. من المفترض أن تُحذف شهادة التحقق من ذاكرة التخزين عند الضغط على النافذة "Sign out"، وأن يُعاد ضبط مخزن عميل Apollo باستخدام التابع resetStore، إذ سيُعاد تنفيذ كل الاستعلامات النشطة تلقائيًا عند استدعاء التابع resetStore، ويعني ذلك إعادة تنفيذ الاستعلام me. تذكّر أن ترتيب خطوات التنفيذ مهم جدًا، ويجب إزالة شهادة التحقق من ذاكرة التخزين قبل إعادة ضبط مخزن عميل Apollo. ترجمة -وبتصرف- للفصل Communicating with server من سلسلة Deep Dive Into Modern Web Development. اقرأ أيضًا المقال السابق: أساسيات React Native مدخل إلى React Native مدخل إلى التحريك في React Native الاتصال مع الخادم في تطبيق React معتمد على Redux
-
الآن وبعد أن كتبنا تطبيقًا جيدًا، قد حان الوقت لنشره وتوزيعه على المستخدمين الفعليين. لقد فعلنا ذلك في القسم 3 بدفع مستودع git إلى خوادم الاستضافة السحابية Heroku بكل بساطة. تُعد عملية إصدار برمجيات على منصة هيروكو Heroku أمرًا بسيطًا موازنةً بغيرها من الاستضافات، لكن لا تزال هناك طبعًا بعض المخاطر، فلا شيء سيمنعنا من الدفع بشيفرة لا تعمل إلى وضع الإنتاج عن طريق الخطأ. سنتعرف في الفقرات القادمة على مبادئ النشر الآمن للتطبيقات، ومبادئ نشر البرمجيات بالمقاييس الصغيرة والواسعة. يمكن لأي شيء أن يحدث خطأ نريد تحديد بعض القواعد التي تضبط عملية نشرنا للتطبيقات، لكن علينا بداية إلقاء نظرةٍ على بعض المحدوديات الواقعية: "إن أمكن لشيءٍ ما أن يخفق، فسيخفق": هي عبارة يتضمنها قانون مورفي، ومن المهم تذكرها دائمًا عند التخطيط لمنظومة النشر التي سنتبعها، ومن الأشياء التي ينبغي أخذها بالحسبان أيضًا: ماذا لو توقف الحاسوب عن العمل أثناء نشر التطبيق؟ ماذا سيحدث إن انقطع الاتصال بالإنترنت أثناء نشر التطبيق؟ ماذا سيحدث إن أخفقت أية تعليمات من سكربت أو منظومة النشر؟ ماذا سيحدث إن لم يعمل تطبيقي، لسببٍ أو لآخر، على الخادم بعد نشره؟ هل يمكنني التراجع rollback إلى النسخة السابقة؟ ماذا سيحدث إذ أرسل مستخدم ما طلب HTTP إلى التطبيق قبل أن يكتمل نشره (لا يوجد وقتٌ لإرسال استجابة له)؟ هذه عينة صغيرة من المشاكل التي قد تواجهك أثناء النشر أو بالأحرى عينة من الأمور التي ينبغي التخطيط لها. لا ينبغي لمنظومة النشر التي نعتمدها أن تترك البرنامج في حالة إخفاق أيًا كان سببه، كما ينبغي علينا أن نعرف (أو أن نجد بسهولة) حالة منظومة النشر. وطالما نتحدث عن النشر وعن التكامل المستمر CI عمومًا، هناك قاعدةٌ مهمةٌ أخرى عليك تذكرها: "الأخطاء الصامتة قاتلة". لا يعني هذا طبعًا عرض الأخطاء على مستخدم البرنامج، بل يعني أنه يجب علينا الانتباه إلى أي شيء قد يخفق. فلو كنا على دراية بمشكلة محتملة الوقوع، يمكننا إصلاحها. فإن لم تعطي منظومة النشر أية أخطاء لكنها فشلت، سنصل إلى المرحلة التي نعتقد فيها أننا أصلحنا كل الأخطاء الحرجة ومع ذلك تخفق المنظومة، وبالتالي سنترك الثغرة في بيئة الإنتاج غير مدركين لخطورة الوضع. ما الذي تمنحه منظومة النشر الجيدة؟ من الصعب وضع قواعد محددة أو متطلبات خاصة بمنظومة النشر، لكننا سنحاول ذلك: عندما تخفق المنظومة في أية خطوة، يجب أن تخفق دون أية آثار جانبية. لا ينبغي أبدًا أن تترك المنظومة البرنامج في حالة فشل. ينبغي أن تخبرنا المنظومة عن أية حالات إخفاق، فمن الأفضل تنبيهنا إلى حالات الإخفاق عوضًا عن النجاح. ينبغي على المنظومة أن تسمح لنا بالتراجع إلى النسخة المنشورة سابقًا. يفضل أن نتراجع بسهولة إلى نسخة أقل عرضة للإخفاق بالموازنة مع النسخة المنشورة كاملةً. يبقى الخيار الأفضل لنا هو التراجع الآلي في حال أخفق النشر. ينبغي أن تكون المنظومة قادرةً على التعامل مع طلبات HTTP قبل انتهاء أو أثناء عملية النشر. ينبغي أن تتأكد المنظومة أنّ البرنامج الذي ننشره سيلبّي المتطلبات التي وضعناها لعملية النشر (لا تنشر مثلًا برنامج أخفق في أحد الاختبارات). لنحدد أيضًا بعض الأشياء التي نريدها في منظومة النشر الافتراضية التي نقترحها: نريدها أن تكون سريعة. لا نريد وقتًا يتوقف فيه البرنامج عن العمل downtime أثناء النشر (هذا أمر مختلف عن معالجة طلبات المستخدمين قبل انتهاء أو أثناء النشر). التمارين 11.10 - 11.12 قبل أن نبدأ بالتمارين عليك إعداد تطبيقك لبيئة عمل هيروكو Heroku. وهنا لن ندفع الشيفرة بأنفسنا، إذ سينفِّذ مخطط عمل GitHub Actions المهمة من أجلنا. تأكد من تثبيت Heroku CLI ثم سجِّل دخولك مستخدمًا واجهة سطر الأوامر CLI عن طريق heroku login. أنشئ تطبيقًا على هيروكو HeroKu باستخدام الأمر: heroku create --region eu {your-app-name} وانتق منطقةً قريبةً من موقعك الجغرافي. ولِّد شهادة تحقق Token لملفك على Heroku باستخدام الأمر: heroku authorizations:create ثم خزّن معلومات الاستيثاق على ملف ضمن حاسوبك لكن لا تدفعه إلى GitHub. ستحتاج إلى شهادة التحقق من أجل مخطط عمل نشر التطبيق. اطلع أكثر على شهادة تحقق هيروكو عبر الإنترنت. 11.10: نشر تطبيقك على منصة هيروكو Heroku وسّع مخطط العمل بخطوة لنشر تطبيقك على منصة هيروكو Heroku. نفترض فيما سيأتي أنك ستستخدم AkhileshNS/heroku-deploy وهو فعل GitHub Actions الخاص بالنشر على هيروكو والذي طوره مجتمع GitHub Actions. تحتاج إلى شهادة التفويض التي حصلت عليها سابقًا من أجل نشر تطبيقك. ومن الأفضل تمرير قيمتها إلى GitHub Actions باستخدام أسرار المستودع repository secrets: يمكنك الآن الوصول إلى قيمة الشهادة على النحو التالي: ${{secrets.HEROKU_API_KEY}} إذا جرى كل شيء على ما يرام، سيبدو مخطط العمل على الشكل التالي: جرِّب تطبيقك عبر متصفح، لكن الأخطاء ستظهر غالبًا. سنجد أنّ منصة هيروكو تفترض وجود الملف "Procfile" في المستودع والذي يوجّهه لطريقة تشغيل البرنامج. أضف إذًا ملف "Procfile" مناسب إلى المستودع وتأكد أنّ التطبيق سيعمل جيدًا. تذكرة: راقب باستمرار ما يحدث عبر سِجِل الخادم عندما تجرب عملية النشر. استخدم لذلك الأمر heroku logs دائمًا. 11.11: التحقق من عمل التطبيق قبل التوسّع أكثر في التطبيق، تحقق أن التطبيق يعمل جيدًا بعد النشر. لا نحتاج في الواقع لخطوة جديدة في مخطط العمل، إذ يحتوي الفعل deploy-to-heroku على خيار يفي بالغرض. أضف وصلة تخديم end point بسيطة مهمتها التحقق من عمل التطبيق في الواجهة الخلفية. ويمكنك أيضًا نسخ الشيفرة التالية: app.get('/health', (req, res) => { res.send('ok') }) من الجيد أيضًا وجود وصلة تخديم اختبارية في التطبيق، لكي يمتلك إمكانية إجراء بعض التعديلات في الشيفرة ويتأكد من أن التغيرات قد ظهرت أيضًا في النسخة المنشورة: app.get('/version', (req, res) => { res.send('1') // غير هذه القيمة للتأكد من أنها نُشرت في النسخة الجديدة }) راجع التوثيق لتعرف كيف ستضم آلية التحقق من عمل التطبيق إلى خطوة النشر، واستخدم عنوان وصلة التخديم التي أنشأتها للتحقق من عمل التطبيق، وقد تحتاج غالبًا إلى الخيار "checkstring" حتى يُنفَّذ الأمر. تأكد من أنّ GitHub Actions سينتبه إذا ما سبب النشر إخفاق التطبيق. استخدم لاختبار ذلك أمر إقلاع خاطئ مثلًا في الملف "Procfile". قبل الانتقال إلى التمرين التالي، أصلح مشاكل خطوة النشر وتأكد أن التطبيق سيعمل بالشكل المطلوب مجددًا. 11.12: التراجع من الأفضل إذا أخفق التطبيق بعد النشر أن تتراجع إلى الإصدار السابق. ولحسن الحظ، يجعل هيروكو Heroku هذا الأمر بسيطًا جدًا. ينتج عن كل عملية نشر على Heroku إصدار، ويمكنك معرفة الإصدارات الموجودة لتطبيق بتنفيذ الأمر heroku releases: $ heroku releases === calm-wildwood-40210 Releases - Current: v8 v8 Deploy de15fc2b mluukkai@iki.fi 2022/03/02 19:14:22 +0200 (~ 8m ago) v7 Deploy 8748a04e mluukkai@iki.fi 2022/03/02 19:06:28 +0200 (~ 16m ago) v6 Deploy a617a93d mluukkai@iki.fi 2022/03/02 19:00:02 +0200 (~ 23m ago) v5 Deploy 70f9b219 mluukkai@iki.fi 2022/03/02 18:48:47 +0200 (~ 34m ago) v4 Deploy 0b2db00d mluukkai@iki.fi 2022/03/02 17:53:24 +0200 (~ 1h ago) v3 Deploy f1cd250b mluukkai@iki.fi 2022/03/02 17:44:32 +0200 (~ 1h ago) v2 Enable Logplex mluukkai@iki.fi 2022/03/02 17:00:26 +0200 (~ 2h ago) v1 Initial release mluukkai@iki.fi 2022/03/02 17:00:25 +0200 (~ 2h ago) يمكن التراجع إلى إصدار محدد بكتابة أمر واحد ضمن سطر الأوامر، والأفضل من ذلك سيتولى الفعل deploy-to-heroku مهمة التراجع نيابةً عنا. اقرأ توثيق GitHub Actions مجددًا وعدّل مخطط العمل لتمنع إخفاق التطبيق عند النشر. يمكنك محاكاة الأمر أيضًا بكتابة أمر خاطئ في الملف "Procfile" والتجربة: تحقق أنّ التطبيق سيستمر في العمل حتى لو أخفق النشر. تنبيه: على الرغم من إمكانية التراجع التلقائي، قد يخفق البناء في العالم الحقيقي. لذلك يُعد إيجاد سبب المشكلة وإصلاحها بسرعة أمرًا جوهريًا. ويبقى سجل هيروكو Heroku عادةً هو المكان الأنسب للبحث والتقصي عن المسببات: ترجمة -وبتصرف- للفصل Deployment من سلسلة Deep Dive Into Modern Web Development. اقرأ أيضًا المقال السابق: استخدام GitHub Actions لتحقيق التكامل المستمر والنشر المستمر نشر تطبيقات الويب الموجهة لبيئة الإنتاج نشر تطبيقات iOS على متجر Apple Store
-
كيف سيبدو موقع الويب الذي تبنيه؟ يناقش هذا المقال أعمال التخطيط والتصميم التي تجري قبل كتابة الشيفرة بما في ذلك المعلومات التي سيقدّمها الموقع وخطوط الكتابة والألوان والوظيفة التي ينجزها الموقع. التخطيط قبل كل شيء لا بد من تجميع بعض الأفكار قبل أن تبدأ بأيّ شيء، أي ما الذي سيقدِّمه موقعك؟ فبإمكانك برمجة موقع الويب ليفعل أيّ شيء تقريبًا، لكن وطالما أنها تجربتك الأولى، فلا بد أن تُبقي الأمور بسيطةً قدر المستطاع، لذلك سنبدأ ببناء صفحة ويب بسيطة بعنوان وصورة وبعض المقاطع النصية، وقبل أن نبدأ لا بد من الإجابة على الأسئلة التالية: ما الموضوع الذي يدور حوله هذا الموقع؟ هل يدور حول الحيوانات الأليفة أو حول مدينة محددة أو شخصية ما. ما المعلومات التي ستقدِّمها حول هذا الموضوع؟ اكتب عنوانًا وبعض الفقرات ثم فكّر بصورة مناسبة لتعرضها على الصفحة. كيف يبدو موقعك؟ ماهو لون الخلفية؟ ما هي أنواع خطوط الكتابة المناسبة؟ ملاحظة: تحتاج المشاريع الأكثر تعقيدًا إلى تفاصيل أكثر تتعلق بالألوان وخطوط الكتابة والفراغات ما بين العناصر في الصفحة وأسلوب الكتابة الملائم وهكذا، إذ تُدعى هذه التفاصيل عادةً بدليل التصميم design guide أو نظام التصميم أو دليل المنتج، كما يمكنك الاطلاع على أمثلة عن ذلك في معرض فايرفوكس للتصاميم. رسم الخطوط الأولى لتصميمك أمسك ورقةً وقلمًا وحاول رسم شكل الموقع الذي تريده، إذ لن تجد الكثير لرسمه في الصفحة البسيطة التي سنبنيها، لكن من الأفضل أن تعتاد الأمر منذ اللحظة، إذ سيساعدك ذلك كثيرًا، ولا حاجة بالطبع إلى رسم متقن. ملاحظة: يبدأ المصممون برسم تصوراتهم عن الموقع رسمًا تقريبيًا على ورقة مهما كان معقدًا، ثم يبنون نسخةً رقميةً باستخدام محرر رسومي أو تقنيات ويب أخرى، وغالبًا ما يضم فريق ويب مصممي رسوميات ومصممي تجربة المستخدِم، إذ يضع مصممي الرسوميات (الغرافيك) التصور المرئي للموقع، بينما تقتصر مهمة مصممي تجربة المستخدِم على تصوّر تجربة المستخدِم لهذا الموقع وطبيعة تفاعله معه وتوجيه التصميم لتحقيق التجربة الأفضل. اختيار المواد المساعدة من الأفضل أن تبدأ بتجميع المحتوى الذي ستعرضه على موقعك في هذه المرحلة. النصوص لا بد أن يكون عنوان الصفحة والمقاطع النصية التي ستعرضها محضرة مسبقًا، لذا تأكد من ذلك. السمة اللونية للصفحة انتق لونًا مناسبًا باستخدام أيّ أداة لانتقاء الألوان، فعندما تنقر على اللون المطلوب، فسترى ستة محارف تشبه الرمز التالي 6600AB# عادةً، إذ يُعَدّ هذا الرمز رمزًا ست عشريًا يمثل اللون، وبعدها انسخ هذا الرمز واحفظه في مكان يسهل عليك العودة له لاحقًا. الصور استخدم محرك البحث الذي تراه مناسبًا لإيجاد الصور المناسبة لموقعك. انقر على الصورة حين تجدها لعرضها بأبعاد أكبر. انقر بالزر اليميني على الصورة (أو انقر عليها مع ضغط زر Ctrl في ماك) ثم اختر "حفظ الصورة باسم Save Image As" وانتق مكانًا مناسبًا على جهازك لحفظها فيه، كما يمكنك نسخ عنوان الصورة من شريط عنوان المتصفح وحفظه لاستخدامات لاحقة. انتبه إلى أنّ معظم الصور الموجودة على ويب محمية بحقوق نشر معيّنة، ولكن يمكنك استخدام مرشّح رخص الاستخدام من جوجل Google's license filter مثلًا إذا كنت تستخدم "صور جوجل Google Images" في البحث وذلك للتقليل من مشاكل خرق هذه الحقوق، ثم انقر على زر "أدوات Tools" ثم اختر "التراخيص الإبداعية العامة Creative Commons licenses" من قائمة "حقوق الاستخدام Usage Rights". خطوط الكتابة لاختيار خط كتابة معيّن: انتقل إلى خطوط الكتابة من جوجل Google Fonts" واعثر على الخط المناسب. انسخ أسطر الشيفرة التي يزوّدك بها جوجل إلى المحرر النصي لديك واحفظها لاستخدامات لاحقة. ترجمة -وبتصرف- للمقال ?What will your website look like. اقرأ أيضًا المقال السابق: تثبيت البرمجيات الأساسية للانطلاق في تطوير الويب أفضل 12 أداة انتقاء للألوان لمصممي الويب الألوان في تصميم الرسوميات ونظرية الألوان الحركات في تصميم الويب: لماذا نستخدمها ومتى؟ فلسفة تصميم الويب المتجاوب
-
سنلقي نظرةً قبل أن نبدأ التعامل مع GitHub Actions على ماهيته والطريقة التي يعمل بها. يعمل GitHub Actions على مبدأ مخططات العمل workflows؛ ومخطط العمل هو سلسلة من الأعمال التي تُنفَّذ عندما يقع حدثٌ معين، وتتضمن هذه الأعمال بحد ذاتها التعليمات التي يجب أن يُنفّذها GitHub Actions. سيبدو تنفيذ مخطط عمل نموذجي على النحو التالي: وقوع حدثٌ ما، مثل دفع push شيفرة إلى الفرع الرئيسي. البدء بتنفيذ مخطط العمل. الإنهاء والتنظيف. الاحتياجات الأساسية نحتاج عمومًا إلى المتطلبات التالية لتشغيل منظومة التكامل المتواصل Continuous Integration -أو اختصارًا CI- ضمن مستودع: مستودع. بعض التعريفات بالمهام التي ستنفذها منظومة CI، وقد يكون ذلك على هيئة ملف ضمن المستودع، أو يمكن أن يُعرَّف ضمن منظومة CI. يجب أن تعرف المنظومة أنّ المستودع (والملف في داخله) موجودٌ فعلًا. تحتاج المنظومة إلى الأذونات اللازمة لتنفيذ الأفعال التي يفترض أن تُنفذها، فلو أردنا من المنظومة أن تكون قادرةً على النشر في بيئة الإنتاج مثلًا، فستحتاج إلى بيانات الاستيثاق الخاصة بهذه البيئة. سنحتاج ما ذكرناه على الأقل في النموذج التقليدي للمنظومة. سنرى لاحقًا كيفية اختصار بعض الخطوات أو تنفيذها بطريقة مريحة لا تسبب لك أية مشاكل تقلق منها. لاستضافة GitHub Actions إيجابياتٌ عظيمة بالموازنة مع الاستضافة الذاتية؛ إذ سيُستضاف المستودع مع مزوِّد لمنظومة CI، أي سيؤمن لك GitHub Actions المستودع ومنظومة CI معًا، ويعني ذلك أننا عندما نُمكِّن الأفعال ضمن المستودع، سيكون GitHub Actions على علم مسبقًا بأنه لدينا مخططات عمل مُعرًّفة، وبما تعنيه هذه التعريفات. التمرين 11.2 سننفذ في معظم تمرينات هذا القسم خط إنتاج لمنظومة CI/CD من أجل المشروع الصغير الموجود على غيت هب GitHub. تنبيه: قد لا تعمل الشيفرة مع الإصدار 15 من Node، وإذا حدث ذلك ولم يُقلع المشروع، انتقل للعمل على الإصدار 14 وإلا عليك حل مشاكلك بنفسك. المشروع النموذجي عليك أولًا إنشاء نسخةٍ من مستودع المشروع ضمن حسابك الخاص ولاستخدامك الشخصي. لاشتقاق المستودع، انقر على الزر "Fork" في أعلى ويمين واجهة المستودع بجانب الزر "Star": سيبدأ بعد ذلك بإنشاء مستودع جديد يُدعى "github_username}/full-stack-open-pokedex}"، وستُنقل بعد انتهاء العملية إلى مستودعك الجديد تلقائيًا: انسخ المشروع الآن إلى جهازك، وكما جرت العادة إبدأ بتفقد الملف "package.json" فهو المكان الأنسب للاطلاع على تفاصيل مشروع جديد. حاول أن تنفّذ ما يلي: تثبيت الاعتماديات باستخدام الأمر npm install. تشغيل الشيفرة في وضع التطوير. إجراء الاختبارات. تدقيق lint الشيفرة. قد تلاحظ وجود بعض أخطاء التدقيق والاختبارات المخفقة في المشروع، دعها كما هي حاليًا، إذ سنتكفل بحلها في التمارين القادمة. وكما ذكرنا في القسم 3، لا ينبغي تشغيل شيفرة React في وضع التطوير بعد نشرها في وضع الإنتاج، لذلك حاول أن تُنفِّذ ما يلي: أنشئ نسخة إنتاج من المشروع. شغل نسخة الإنتاج على جهازك محليًا. ستجد سكربتًا خاصًا لتنفيذ المهمتين السابقتين في المشروع. خذ وقتًا لدراسة هيكيلية المشروع. وكما ستلاحظ، فإن الواجهتين الأمامية والخلفية موجودتان في نفس المستودع، وقد اعتدنا في الأقسام الأولى على وجودهما في مستودعين منفصلين. لكن هذا الأمر سيبسط الأمور عند إعداد بيئة CI. ستجد بالمقابل أنّ الواجهة الأمامية في معظم مشاريع منهاجنا لم تُنفّذ باستخدام "create-react-app"، لكنها تمتلك إعدادات تهيئة بسيطة باستخدام webpack تتكفل بإنشاء بيئة التطوير وبإنشاء حزمة الإنتاج. التعامل مع مخططات العمل تُعد مخططات العمل الأساس الذي تبنى عليه منظومات CI في غيت هب GitHub، فهي مساراتٌ لعملية يمكنك إعدادها لتنفيذ مهام تلقائيًا، مثل بناء التطبيقات واختبارها وتدقيقها وإصدارها ونشرها. تبدو عادةً هيكلية مخططات العمل على النحو التالي: مخطط العمل مهمة خطوة خطوة مهمة خطوة ينبغي أن يحدد كل مخطط مهمةً واحدةً على الأقل تحتوي على خطوات لتنفيذ إجراءات مستقلة. ستُشغّل هذه المهمات على التوازي بينما تُنفًّذ الخطوات في كل مهمة على التتالي. تتنوع الخطوات من تنفيذ سطر أوامر محدد إلى الأفعال المعرَّفة مسبقًا، لهذا تحمل الاستضافة اسم أفعال غيت هب "GitHub Actions". يمكنك إنشاء الأفعال الخاصة بك أو أن تستخدم أفعالُا نشرها آخرون، وهي في الواقع كثيرة، وسنعود إليها لاحقًا. ينبغي أن تُحدِّد مخططات العمل الخاصة بك ضمن المجلد "github/workflows." في مستودعك كي يميزها غيت هب، ولكل مخطط عمل ملفٌ مستقلٌ خاصٌ به والذي يجب تهيئته باستخدام لغة تقسيم البيانات YAML. يُشتق الاسم YAML من العبارة "YAML Ain't Markup Language" والتي تعني "ليست لغة توصيف"؛ فكما تُلمّح إليه التسمية، فالهدف منها أن تكون مفهومةً للبشر. تُستخدم هذه اللغة في كتابة ملفات التهيئة، وستجد أنها سهلة الفهم فعلًا. عليك الانتباه إلى أهمية الانزياحات Indentation في بداية الأسطر البرمجية في YAML، وللاطلاع أكثر حول قواعد اللغة يمكنك الرجوع إلى شبكة الإنترنت. يتضمن مخطط العمل في مستند YAML هذه العناصر الثلاث: name الاسم: ويشير إلى اسم المخطط. triggers المُسبب: الأحداث التي تؤدي إلى تنفيذ المخطط. jobs المهام: المهام المختلفة التي سيُنفّذها المخطط، وقد يحتوي المخطط البسيط مهمةً واحدةً فقط. سيبدو تعريف مخطط بسيط على النحو التالي: name: Hello World! on: push: branches: - master jobs: hello_world_job: runs-on: ubuntu-20.04 steps: - name: Say hello run: | echo "Hello World!" وكما هو واضح، سيكون المُسبب هو عملية دفع الشيفرة إلى الفرع الرئيسي. يحتوي المخطط أيضًا على مهمة واحدة اسمها hello_world_job سيجري تنفيذها ضمن بيئة افتراضية تعمل على نظام التشغيل أوبنتو Ubuntu 20.04، وتتضمن هذه المهمة خطوة واحدة اسمها Say hello ستُنفِّذ الأمر "!echo "Hello World ضمن الصدفة shell. ربما تتساءل، متى يبدأ غيت هب بتنفيذ مخطط معين؟ هناك العديد من الخيارات المتاحة، لكن وبصراحة، يمكنك أن تهيئ المخطط ليعمل حالما: يقع حدث ما، مثل الحالة التي يدفع فيها أحدهم اعتمادًا commit إلى مستودع، أو عندما تحدث مشكلة أو يقدم أحدهم طلب سحب pull request. تُنفَّذ مهمةٌ مجدولةٌ مسبقًا ومحددة باستخدام تعابير cron. يقع حدث خارجي، كأن يُنفَّذ أمر ضمن تطبيق خارجي، مثل تطبيق الرسائل Slack. وللاطلاع على مزيدٍ من الأحداث المسببة لبدء تنفيذ مخطط عمل، عُد إلى توثيق GitHub Actions. التمرينان 11.3- 11.4 لنربط كل ما خلصنا إليه، دعونا نشغِّل GitHub Actions ضمن المشروع النموذجي. 11.3: تطبيق Hello world أنشئ مخططًا يُظهر العبارة "!Hello World" للمستخدم. عليك أن تنشئ المجلد "github/workflows."، والملف "hello.yml" الذي سيحتوي الإعدادات ضمن مستودعك. ولتطلع على ما أنجزه مخطط عمل GitHub Actions الخاص بك، يمكن التوجه إلى النافذة Action ضمن واجهة غيت هب GitHub، حيث من المفترض أن ترى مخطط العمل في مستودعك والخطوات التي أنجزها. ستبدو نتيجة تنفيذ مخططك على النحو التالي إن كانت تهيئة المخطط صحيحة: يُفترض أن ترى الرسالة "!Hello World" نتيجةً لتنفيذ المخطط، وإذا حدث ذلك، ستكون جميع الخطوات قد نُفِّذت بنجاح، وسيكون أول مخططات عمل GitHub Actions الخاصة بك قيد العمل. سيعطيك أيضًا GitHub Actions معلومات عن البيئة (نظام التشغيل، وإعداداته) التي يعمل ضمنها مخطط العمل. وتظهر أهمية ذلك أثناء حدوث أمر طارئ، إذ سيسهل هذا الأمر تنقيح الأخطاء إن استطعت تكرار كل الخطوات على جهازك. 11.4: التاريخ ومحتويات المجلد وسًع مخطط العمل لإضافة خطوات لطباعة التاريخ ومحتويات المجلد الحالي بالصياغة الطويلة long format. يمكن تنفيذ هاتين الخطوتين باستخدام الأمرين date و ls بكل بساطة. سيبدو مخطط عملك الآن على النحو التالي: وطالما أن الأمر ls -l سيُظهر افتراضيًا البيئة الافتراضية التي يعمل عليها مخطط العمل، ستلاحظ أنها لا تحتوي على أية شيفرات. إعداد وتجهيز خطوات التدقيق والاختبار والبناء بعد إنجاز التمارين الأولى، سيكون لدينا مخطط عمل بسيط لكنه لن يفيدنا في عملية الإعداد. لنجعل مخطط العمل قادرًا على فعل مهمة حقيقية. سننجز فعلًا action قادرًا على تدقيق الشيفرة. فإذا أخفق التدقيق، سيُظهر Github Actions الحالة الحمراء. سيبدو المخطط الذي سنخزنه ضمن الملف "pipeline.yml" مبدئيًا على النحو التالي: name: Deployment pipeline on: push: branches: - master jobs: قبل أن نتمكن من تنفيذ الأمر الذي سيبدأ خطوة التدقيق، لا بدّ من تنفيذ فعلين لإعداد البيئة الملائمة للمهمة. إعداد بيئة العمل إعداد بيئة العمل أمرٌ ضروري لتهيئة خط الإنتاج Pipeline، لذلك سنستخدم بيئة العمل الافتراضية Ubuntu 20.04 لأنها ستكون البيئة التي ستعمل عليها نسخة الإنتاج. ولا بدّ من تطابق البيئة نفسها في منظومة CI وفي وضع الإنتاج قدر المستطاع، لتحاشي الحالات التي تعمل فيها الشيفرة نفسها بصورةٍ مختلفة في كليهما، وبالتالي لن تتحقق الغاية من استخدام CI. سنوضح تاليًا الخطوات في مهمة "البناء" لكي تستطيع منظومة CI تنفيذها. وكما لاحظنا في التمارين السابقة، لن تحتوي بيئة العمل افتراضيًا أية شيفرات، لذلك لا بدّ من التحقق من الشيفرة من المستودع. هذه الخطوة سهلة وهي على النحو التالي: name: Deployment pipeline on: push: branches: - master jobs: simple_deployment_pipeline: runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v3 تُستخدم التعليمة uses لإخبار المخطط أن يُنفِّذ فعلًا محددًا. ويُعرَّف الفعل بأنه قطعة من الشيفرة قابلة لإعادة الاستخدام مثل الدوال، ويمكن تعريف الأفعال داخل المستودع ضمن ملف مستقل، أو استخدام الأفعال الموجودة في المستودعات العامة. سنستخدم هنا الفعل العام actions/checkout وبنسخة محددة هي "v3@" لتلافي فشل التعديلات إن جرى تحديث الفعل. ويُنفِّذ الفعل checkout ما يوحي به اسمه، إذ يتحقق من شيفرة المشروع المصدرية من git. وطالما أنّ التطبيق قد كتب باستخدام جافا سكربت، فلا بدّ من تهيئة "Node.js" لكي نتمكن من استخدام الأوامر الموجودة في الملف "package.json". ولإعداد "Node.js" يمكن استخدام الفعل actions/setup-node. سنختار الإصدار "16" لأنه الإصدار الذي تستخدمه بيئة الإنتاج. # name and trigger not shown anymore... jobs: simple_deployment_pipeline: runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v2 with: node-version: '16' تُستخدم التعليمة with لإسناد معامل parameter إلى الفعل، إذ يحدد المعامل هنا نسخة Node.js التي ننوي استخدامها. أخيرًا، لا بُد من تثبيت الاعتماديات اللازمة. وكما تفعل عادةً على جهازك، نفِّذ الأمر npm install. ستبدو خطوات المهمة على النحو التالي: jobs: simple_deployment_pipeline: runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v2 with: node-version: '16' - name: npm install run: npm install وهكذا ستكون البيئة الآن جاهزةً لأداء مهمة حقيقية ومهمة. التدقيق Lint يمكنك الآن تنفيذ السكربتات التي يحتويها الملف "package.json" كما لو أنك تنفذها على حاسوبك الشخصي، فكل ما عليك فعله لتدقيق الشيفرة، هو إضافة إعدادٍ لتشغيل الأمر npm run eslint: jobs: simple_deployment_pipeline: runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v2 with: node-version: '16' - name: npm install run: npm install - name: lint run: npm run eslint التمرينات 11.5 - 11.9 11.5: تدقيق مخطط عمل نفّذ أو انسخ والصق مخطط العمل "Lint" واعتمد شيفرته في مستودعك، ثم أنشئ ملف yml جديد لهذا المخطط، يمكنك تسميته "pipeline.yml". ادفع بشيفرتك إلى الفرع الرئيسي ثم توجه إلى النافذة "ِActions" وانقر على المخطط الذي أنشأته على اليسار. ستجد أن هذا المخطط سيفشل في الإقلاع: 11.6: إصلاح الشيفرة ستجد بعض المشاكل في الشيفرة تتطلب الإصلاح. افتح سِجِل مخطط العمل وتحقق من وجود أخطاء. إليك تليمحين مهمين: من الأفضل أن تصلح أحد الأخطاء بتحديد ملف مناسب لعملية التدقيق (راجع القسم الثالث لمزيد من المعلومات عن كيفية تنفيذ ذلك)؛ كما يمكن إيقاف أحد الاعتراضات التي تخص تنفيذ الأمر console.log بإيقاف القاعدة التي تسببه في السطر الذي توجد به. أجرِ التعديلات اللازمة على الشيفرة المصدرية لكي ينجح مخطط العمل في الإقلاع، وحالما تعتمد الشيفرة الجديدة سيعمل المخطط وستجد خرجًا مُحدَّثًا باللون الأخضر من جديد. 11.7: البناء والاختبار لنوسِّع مخطط العمل الذي يُنفِّذ حاليًا مهمة التدقيق. أضف أوامر البناء والاختبار إلى مخطط العمل، وستبدو النتيجة قريبةً من التالي: ستلاحظ أيضًا وجود بعض المشاكل. 11.8: العودة إلى الوضع الصحيح تحقق من الاختبارات التي أخفقت وأصلح المشكلة في الشيفرة (لا تُغيّر الاختبارات). سيعمل المخطط ويظهر الخرج باللون الأخضر مجددًا عند إصلاح المشاكل. 11.9: اختبار مشترك بسيط للواجهتين تستخدم مجموعة الاختبارات الحالية jest لتتأكد من عمل مكونات React بالطريقة المطلوبة، وهذا تمامًا ما فعلناه في فصل "اختبار تطبيقات React" من القسم 5. يُعد اختبار كل مكوًن بصورةٍ منفصلة أمرًا مفيدًا لكنه لا يضمن عمل كل النظام بالطريقة المطلوبة. وللتأكد أكثر، سنكتب اختبارًا بسيطًا مشتركًا بين الواجهتين الأمامية والخلفية end to end testing، مستخدمين المكتبة Cypress وعلى نحوٍ مشابه للعمل الذي أنجزناه في الفصل الذي يحمل العنوان "الاختبار المشترك للواجهتين" في القسم 5. سنهيئ cypress (ستجد الطريقة في الفصل الذي أشرنا إليه)، ثم سننفذ الاختبار التالي: describe('Pokedex', function() { it('front page can be opened', function() { cy.visit('http://localhost:5000') cy.contains('ivysaur') cy.contains('Pokémon and Pokémon character names are trademarks of Nintendo.') }) }) عرِّف سكربت npm التالي: test:e2e لتشغيل الاختبار المشترك للواجهتين "e2e" باستخدام سطر الأوامر. تنبيه: لا تستخدم الكلمة "spec" في تسمية ملف اختبار cypress، لأنها ستجعل jest ينفذ شيفرة الملف أيضًا، وقد يسبب ذلك عدة مشاكل. تنبيه آخر: على الرغم من قدرة الصفحة على تصيير أسماء "مخلوقات البوكيمون Pokemon" لتبدأ بأحرف كبيرة، إلا أنها مكتوبةٌ بأحرف صغيرة في المصدر، فاسم البوكيمون "Ivysaur" هو أصلًا "ivysaur" تحقق من نجاح الاختبار على جهازك، وتذكر أن الاختبارات ستفترض أن تطبيقك يعمل عندما تُنفِّذ الاختبار. وإن كنت قد نسيت بعض التفاصيل، راجع القسم 5. حالما يعمل الاختبار المشترك للواجهتين على جهازك، ضعه في مخطط عمل GitHub Action، وأسهل الطرق لتنفيذ ذلك هو استخدام الفعل الجاهز cypress-io/github-action، وستكون الخطوة المناسبة لحالتنا على النحو التالي: - name: e2e tests uses: cypress-io/github-action@v2 with: command: npm run test:e2e start: npm run start-prod wait-on: http://localhost:5000 لقد استخدمنا ثلاثة خيارات: command: ويحدد كيف سنشغل اختبار cypress. start: يزودنا بسكربت npm الذي يُشغِّل الخادم. wait-on: يمنع الاختبار من العمل قبل أن يقلع الخادم على العنوان http://localhost:5000. عندما تتأكد من عمل خط الإنتاج، اكتب اختبارًا آخر للتأكد أنّ المستخدم قادرٌ على الانتقال من الصفحة الرئيسية إلى صفحة "بوكيمون" محدد مثل "ivysaur". لا حاجة لتعقيد الاختبار، بل تأكد فقط أن الصفحة التي تنتقل إليها بنقر الرابط، ستحتوي بعض المعلومات الصحيحة مثل النص "chlorophyll" في حالة البوكيمون "ivysaur". ملاحظة: تُكتب أسماء البوكيمون بالأحرف الصغيرة، ويمكن الكتابة بالأحرف الكبيرة في CSS، لذلك لا تكتب أثناء البحث الاسم "Chlorophyll"، بل اكتب "chlorophyll". ملاحظة: لا تحاول الانتقال إلى صفحة البوكيمون "bulbasaur"، فربما لسببٍ ما لن تعمل صفحة هذا البوكيمون. ستبدو النتيجة النهائية على الشكل التالي: إن الأمر الجيد المتعلق بالاختبار المشترك للواجهتين هو الثقة بأنّ البرنامج سيعمل على نحوٍ جيد من وجهة نظر المستخدم النهائي. لكن سيكون الثمن الذي تدفعه بالمقابل هو الاستجابة البطيئة، إذ سيستغرق تنفيذ مخطط العمل بالكامل وقتًا أطول بكثير. ترجمة -وبتصرف- للفصل Getting started with GitHub Actions من سلسلة Deep Dive Into Modern Web Development. اقرأ أيضًا المقال السابق: مدخل إلى التكامل المستمر والنشر المستمر CI/CD التكامل المستمر: تثبيت Concourse CI على أوبنتو إعداد التكامل المستمر والنشر المستمر باستخدام الخدمتين CircleCI وCoveralls إعادة تأسيس تفريعات طلب السحب وتحديثه في git
-
سنعرض في هذا المقال الأدوات التي تلزم في عملية تطوير موقع ويب بسيط وكيفية تثبيتها تثبيتًا صحيحًا. الأدوات التي يستخدمها المحترفون حاسوب: قد يبدو الأمر بديهيًا للبعض، لكن البعض الآخر لا يستخدِمه فعليًا، فهو يقرأ هذا المقال عن طريق الهاتف الجوال أو عبر حاسوب مكتبة عامة، أي لا بد من امتلاك حاسوب مكتبي أو محمول يعمل على ويندوز أو ماك أو لينوكس إذا قررت أن تكون مطور ويب حقيقي. محرر نصي: يساعدك في كتابة الشيفرة، وقد يكون نصيًا تمامًا مثل فجيوال ستديو كود Visual Studio Code أو نوت باد بلس بلس ++Notepad، أو هجينًا مثل دريم ويفر Dreamweaver وويب ستورم WebStorm، ولن تناسبك محررات النصوص المكتبية لأنها تعتمد على عناصر خفية تتداخل مع محركات التصيير التي تستخدِمها المتصفحات لتنفيذ الشيفرة. متصفح ويب: لتخابر شيفرتك من خلاله، وستجد الكثير من المتصفحات لكن أكثرها استخدامًا فايرفوكس وكروم وأوبِرا وسفاري وإنترنت إكسبلورر ومايكروسوفت إيدج، ولا بد أيضًا من اختبار أداء صفحاتك على متصفحات الهواتف الجوّالة وعلى المتصفحات القديمة التي لاتزال جمهورك يستخدِمها مثل إنترنت إكسبلورر 8 و 10، كما سيساعدك لينكس linux - وهو متصفح يعتمد على طرفية تُقاد بالأوامر النصية- في اختبار تجربة المستخدِمين ذوي المشاكل البصرية لموقعك. محرر صور: لإعداد الصور والرسوم البيانية لموقعك. نظام لإدارة الإصدارات version control system: لإدارة الملفات على الخوادم أو التعاون مع فريق من المطورين على مشروع ومشاركة الشيفرة والدعم وتحاشي التضارب في عملية تحرير الشيفرة، تُعد حاليًا غت Git أكثر هذه الأنظمة شعبية مع خدمتي الاستضافة جيت هاب GitHub وجيت لاب GitLab. برنامج لنقل الملفات عبر بروتوكول FTP: ويُستخدَم للتعامل مع حسابات خوادم الاستضافة القديمة لإدارة الملفات عليها، لهذا تستبدل جيت هذا البروتوكول بوتيرة متزايدة، كما توجد هناك مجموعة أخرى من البرامج التي تعتمد FTP و FTPS مثل سايبر دك Cyberduck أو فيتش Fetch أو فايلزيلا FileZilla. برنامج أتمتة المهام automation system: مثل Webpack و Grunt و Gulp لتنفيذ المهام المتكررة مثل اختزال أو تصغير الشيفرة وإجراء الاختبارات. مكتبات وأطر عمل وغيرها لتسريع كتابة شيفرات المهام الشائعة، فعادةً ما تكون المكتبات على هيئة ملفات جافاسكربت أو CSS جاهزة لتأمين وظائف جاهزة لاستخدامها في الشيفرات، في حين يمثِّل إطار العمل منظومةً متكاملةً نوعًا، إذ يقدِّم الوظائفية السابقة مع بعض الصيغ المخصصة لكتابة تطبيقات ويب بناءً عليها. أدوات إضافية أخرى. الأدوات التي يحتاجها المطور المبتدئ قد تبدو هذه القائمة مخيفةً، لكنك في الواقع قادر على البدء دون استخدام أيٍّ منها، إذ تحتاج في الحد الأدنى إلى محرر نصي ومتصفح حديث. تثبيت المحرر النصي قد يكون المحرر مثبتًا أصلًا على حاسوبك مع نظام التشغيل مثل "نوتباد" Notepad في ويندوز و"تيكست إديت" TextEdit مع ماك أو إس macOS، كما تختلف المحررات النصية التي تأتي مع لينكس حسب النسخة، فيأتي مثلًا "غيت إديت" gedit مع أوبونتو، وقد تستفيد أكثر من محررات أفضل من المحررات السابقة لتطوير ويب، إذ ننصحك البدء بالمحرر "فيجوال استوديو كود" Visual Studio Code، وهو محرر مجاني يزودك بعروض مباشرة لنتائج شيفرتك وبعض التلميحات المتعلقة بكتابتها. تثبيت متصفح ويب حديث حاول تثبيت متصفحين مما سنعرض في هذه القائمة وفقًا لنظام التشغيل لديك، وجهزهما للاختبار: لينكس: فايرفوكس Firefox أو كروم Chrome، أو أوبرا Opera أو بريف Brave. ويندوز: فايرفوكس أو كروم أو أوبرا أو إنترنت إكسبلورر أو مايكروسوفت إيدج أو بريف، علمًا أنه يأتي إيدج افتراضيًا مع ويندوز 10، كما يمكنك تثبيت هذا المتصفح أو إكسبلورر 11 لنسخ ويندوز 7 وما بعد. ماك أو إس: فايرفوكس أو كروم أو أوبرا أو سفاري أو بريف، علمًا أنه يأتي سفاري افتراضيًا مع ماك أو إس أو نظام آي أو إس. ملاحظة: لا يتوافق إنترنت إكسبلورر مع بعض الميزات الحديثة لويب، وقد لا يتمكن من تنفيذ مشروعك، فلا داعي لأن تقلق بهذا الشأن أو أن تجعل مشروعك متوافقًا معه وخاصةً وأنت في مرحلة التعلم، لأن قلة قليلة من الأشخاص فقط هم من يستخدموه، وقد يتطلب التوافق مع هذا المتصفح في بعض المشاريع دعمًا خاصًا. تثبيت خادم ويب محلي لتجريب بعض المشاريع ستحتاج إلى خادم ويب لتحصل على النتيجة الصحيحة، اطلع على مقال "إعداد خادم اختبار محلي" لتفاصيل أكثر. ترجمة -وبتصرف- للمقال Installing basic software. اقرأ أيضًا المقال السابق: عالم الويب ومعاييره مدخل إلى خادم الويب دليل إعداد خادم ويب محلي خطوة بخطوة
-
يقدِّم لك هذا المقال خلفيةً مفيدةً حول عالم الويب وظهوره والتقنيات المعيارية له وكيف تعمل معًا، كما يطلعك على تمّيز مهنة مطوري الويب وعن الممارسات العملية الأفضل التي عليك تعلّمها. موجز عن تاريخ ويب سنختصر الأمر قدر المستطاع لوجود الكثير من المعلومات المفصّلة عن تاريخ ويب خارج إطار هذا المقال والتي سنشير إليها لاحقًا، ويمكنك أيضًا البحث باستخدام أحد محركات البحث المفضلة لديك إذا كنت مهتمًا بتفاصيل أكثر. طوّر الجيش الأميريكي في ستينيات القرن الماضي شبكة اتصال دُعيت آربانت ARPANET، إذ يمكن عدّ هذه الشبكة هي البداية المبكرة لويب، وقد استخدمت تقنية تحويل أو تبديل حزم البيانات وشهدت أول تنفيذ لمجموعة بروتوكولات TCP/IP، كما تُشكِّل التقنيتين السابقتين البنية التحتية التي قامت عليها شبكة الإنترنت. كتب تيم برنرز-لي Tim Berners-Lee -ويشار إليه عادةً بالاسم TimBL- عام 1980 برنامجًا نصيًا دُعي "ENQUIRE" والذي مهَّد لمفهوم الربط بين العقد المختلفة، أيبدو مألوفًا؟ وبتسريع الوقت حتى عام 1989، إذ كتب تيم عملَين أحدهما بعنوان "مقترح لإدارة المعلومات Information Management: A Proposal" والآخر بعنوان النص التشعبي HyperText خلال عمله مستشارًا في المنظمة الأوروبية للطاقة النووية CERN، وقد قدّم هذان العملان خلفيةً معرفيةً عن الكيفية التي يفُتَرض أن تعمل بها ويب، كما وتلقى العملان كمًا لا بأس به من الاهتمام، وكان هذا كافيًا ليسمح له مديروه بمتابعة العمل نحو إنشاء منظومة نصوص تشعبية عالمية؛ أما بحلول عام 1990، فقد كان تيم قد أنشأ كل الأشياء الضرورية اللازمة لتشغيل النسخة الأولى لويب.بروتوكول HTTP ولغة HTML، بالإضافة إلى متصفح ويب الأول والذي دُعيَ حينها WorldWideWeb وخادم HTTP وبعض صفحات ويب لاستعراضها. توسّع عالم الويب بشدة في السنوات التي تلت مع ظهور عدد من المتصفحات الجديدة وإعداد آلاف خوادم ويب وكتابة ملايين الصفحات، ولا بد من الإشارة في هذه العجالة إلى تأسيس تيم لمجمّع World Wide Web Consortium واختصارًا W3C، وهي منظمة تجمع ممثلين عن شركات تقنية عالمية مختلفة للعمل معًا لوضع مواصفات ومعايير للويب، وبعد ذلك ظهرت تقنيات مثل CSS ومن ثم جافاسكربت وأخذت تبدو الويب بعدها شبيهةً بما هي عليه اليوم. معايير ويب تُعَدّ معايير ويب Web standards التقنيات التي نستخدِمها لبناء مواقع الويب، إذ تظهر هذه المعايير على هيئة مستندات تقنية طويلة تُدعى التوصيفات specifications والتي تفصّل تمامًا الطريقة التي ينبغي لتقنية ما العمل وفقها، كما لا تقدِّم هذه المستندات فائدةً كبيرةً في تعلّم استخدام التقنية التي تصفها ولذلك وُجِدت مواقع مثل موسوعة حسوب وتوثيق MDN التي تعرض التوثيقات بطريقة مختصرة ومبسطة، وإنما هي موجَّهة إلى مهندسِي البرمجيات لتطبيق هذه التقنيات، إذ يصف المستند HTML Living Standard على سبيل المثال كيفية تطبيق شيفرة HTML تمامًا، أي جميع عناصر اللغة، والواجهات البرمجية المرتبطة بها، وغير ذلك من التقنيات المحيطة بها. تُنشَأ معايير ويب من قِبَل هيئات قياسية مثل المنظمات والمعاهد التي تدعو تِقنيين من شركات مختلفة للاتفاق على أفضل الطرائق التي ينبغي أن تعمل وفقها التقنيات لتلبي احتياجاتهم، إذ تُعَدّ W3C من أهم هذه الهيئات، ونجد أيضًا WHATWG التي تصون وتطوِّر المعايير المستخدم للغة HTML، و ECMA التي تنشر معايير ECMAScript التي تُبنى عليها جافاسكربت، و Khronos التي تنشر تقنيات الرسوميات ثلاثية الأبعاد مثل WebGL وغيرها من الهيئات. المعايير مفتوحة المصدر لا بد أن تبقى الويب وتقنياتها مجانيةً للمساهمين في بنائها ومستخدِميها وغير خاضعة لبراءات الاختراع أو رخص الاستخدام، وهذا الموضوع هو الميزة الأساسية لمعايير ويب والتي وافق عليها تيم-لي ومجمّع W3C منذ البداية، لذلك يمكن لأيّ كان كتابة الشيفرات مجانًا لبناء موقع ويب، كما يمكن لأيّ كان المساهمة في عملية تطوير وإنشاء معايير ويب. لا يمكن لأي شركة التحكم بتقنيات الويب لأنها بُنيَت لتكون مفتوحة المصدر بالتعاون بين شركات مختلفة، وهذا أمر جيد حقًا، فلن ترغب مطلقًا أن تضع أيّ شركة قيودًا ماليةً على تقنيات ويب فجأة، أو أن تصدر نسخةً مدفوعةً من HTML عليك شرائها لتستمر في استخدامها، أو أن تقرر الشركة -في أسوأ سيناريو- أنّ الموضوع لم يَعُد يهمها ثم توقف العمل به، وبالتالي يسمح هذا الأمر ببقاء الويب وتقنياتها متاحةً مجانًا للجميع. لا تفكك الويب قد تسمع بمصطلح آخر يتعلق بمعايير ويب هو "لا تفكك الويب"، ويعني ذلك أنّ أيّ تقنية جديدة في عالم الويب لا بد وأن تكون متوافقةً مع ما بُني سابقًا -أي يجب استمرار مواقع الويب القديمة بالعمل-، ومع ما سيُبنى لاحقًا -أي أن التقنيات التي ستظهر لاحقًا لا بد أن تبقى متوافقة مع التقنيات الحالية-، ومع تقدمك في مسيرتك في التعلم ستعرف كيف يتحقق ذلك من خلال التصميم والتنفيذ الذكي لهذه المفاهيم. من الجيد أن تكون مطور ويب تُعَدّ صناعة الويب سوقًا ملفتًا ومهمًا إذا كنت تبحث عن عمل، وتشير الأرقام الحالية إلى وجود أكثر من 19 مليون مطور ويب في العالم، وسيتضاعف هذا العدد في العقد القادم، وفي الوقت ذاته، هناك نقص في الخبرات ضمن هذه الصناعة، لذلك فالوقت الآن مناسب جدًا من أجل تعلم تطوير مواقع ويب. لا تتعلق صناعة الويب فقط بأمور الترفيه والألعاب، وإنما يزداد تعقيد بناء مواقع الويب عما كان عليه، إذ عليك قضاء المزيد من الوقت في دراسة التقنيات المختلفة التي ستستخدِمها، وجميع الأساليب والممارسات العملية التي يجب تعلمها، والنماذج التقليدية التي سيطلب منك إنجازها، فقد تحتاج أشهرًا عدة لتبدأ باستيعابها، وبعد ذلك عليك الاستمرار في تعلم المزيد لكي تبقى معلوماتك مواكبةً لآخر التطورات بما في ذلك الأدوات والميزات الجديدة التي تظهر على منصات عمل ويب، كما عليك التمرن أكثر لصقل مهاراتك في هذه المهنة. هل يبدو الأمر صعبًا؟ نسعى في هذا السياق إلى منحك كل الإمكانات لتنطلق ومن ثم ستسهل بقية الأمور عليك، فحالما تعتنق مفهومَي التغيُّر والشك في عالم ويب، فستستمتع بما تفعله، وعلى أساس أنك فرد في مجتمع ويب، فستجد شبكةً كاملةً من المعارف والمواد القيّمة التي ستساعدك وسترى الإمكانات الإبداعية التي يوفّرها هذا العمل، كما ستغدو مبدعًا في العالم الرقمي، فاستمتع إذًا بهذه التجربة وبالمكاسب المحتملة التي ستحققها في تجربتك في تطوير الويب. نظرة على بعض تقنيات ويب العصرية لا بد أن تتعلم عددًا من التقنيات إذا قررت أن تصبح مطورًا للواجهات الأمامية، لذلك سنصف في هذه الفقرة هذه التقنيات باختصار. المتصفحات ربما تستخدِم الآن متصفحًا لقراءة هذا المقال، فالمتصفحات هي برمجيات يستخدِمها الناس ليستعرضوا محتويات الويب ويتفاعلوا معها مثل فايرفوكس وكروم وأوبرا وسفاري وإيدج. بروتوكول HTTP يُعَدّ بروتوكول نقل النص التشعبي Hypertext Transfer Protocol واختصارًا HTTP بروتوكولًا لنقل الرسائل التي تسمح للمتصفح بالتواصل مع خوادم ويب (المكان الذي تُثبت عليه مواقع الويب)، إذ تجري المحادثة النمطية بين المتصفح والخادم بصورة تشبه التالي: "Hello web server. Can you give me the files I need to render bbc.co.uk"? "Sure thing web browser — here you go" [Downloads files and renders web page] لا يمكن للبشر بالطبع قراءة الصيغة الفعلية لرسائل التواصل والتي تُدعى طلبات واستجابات، لكن قد يعطيك مثالنا السابق تصوّرًا عن العملية. HTML و CSS وجافاسكربت وهي التقنيات الرئيسية الثلاث التي سنستخدِمها لبناء مواقع ويب: HTML لغة ترميز النصوص التشعبية Hypertext markup language: وهي لغة ترميزية تتكون من عناصر مختلفة يمكن أن تُغلِّف محتوى ويب ضمنها وتوضِّح معناها وهيكليتها، إذ تبدو شيفرة HTML البسيطة قريبة من التالي: <h1>This is a top-level heading</h1> <p>This is a paragraph of text.</p> <img src="cat.jpg" alt="A picture of my cat"> يمكنك تشبيه اللغة إذا وازنتها مع بناء سكني بأساسات وجدران المنزل التي تعطيه شكله وتجعله متماسكًا. CSS التنسيقات المورثة Cascading Style Sheets: وهي لغة مبنية على قواعد مخصصة لتطبيق تنسيقات معينة على عناصر HTML مثل ضبط ألوان النصوص والخلفيات وإضافة الأطر وتحريك الأشياء أو تخطيط الصفحة بطريقة معينة، وإليك مثالًا بسيطًا يحوِّل نصوص الفقرات <p> في HTML إلى اللون الأحمر: p { color: red; } ووفقًا لتشبيه المنزل السكني، فستكون CSS بمثابة الطلاء وورق الجدران والسجاد واللوحات التي تضعها داخل المنزل. جافاسكربت JavaScript: هي لغة البرمجة التي تستخدِمها لإضافة التفاعل في مواقع الويب، ابتداءً بالتغيير الديناميكي للتنسيق إلى إحضار البيانات من الخادم مرورًا بتنفيذ الرسوميات ثلاثية الأبعاد، إذ ستخزِّن شيفرة جافاسكربت التالية على سبيل المثال مرجعًا إلى عنصر الفقرة <p> ومن ثم تغيّر النص الموجود ضمنه: let pElem = document.querySelector('p'); pElem.textContent = 'We changed the text!'; وبالعودة لتشبيه المنزل السكني، فستكون جافاسكربت بمثابة الطباخ أو التلفاز أو مجفف الشعر، أي الأشياء التي تزيد من إمكانات منزلك. الأدوات حالما تتعلم التقنيات الأساسية التي تُستخدم في بناء صفحات الويب، فستبدأ بالتعرف على أدوات عديدة تُسهِّل عملية بناء الصفحات وتجعلها أكثر فاعليةً، وإليك بعض الأمثلة: أدوات مطوري ويب الموجودة في المتصفحات العصرية والتي تُستخدم في تنقيح شيفرتك. أدوات الاختبار التي تُستخدم في تنفيذ اختبارات تظهر سلوك شيفرتك إذا حققت المطلوب أم لا. المكتبات وأطر العمل frameworks المبنية على أساس جافاسكربت والتي تسمح بتطوير أنواعًا مختلفةً من مواقع الويب بطرق أسرع وأكثر فاعليةً. المنقِّحات Linters التي تحدِّد مجموعةً من القواعد وتدقق شيفرتك بحثًا عن أيّ خرق لهذه القواعد. المُصغِّرات Minifiers التي تزيل المساحات الفارغة من الشيفرة لتبدو أقل حجمًا، وبالتالي ستزداد سرعة تنزيلها من خوادم الويب. اللغات التي تنفذ ضمن الخوادم وأطر العمل المتعلقة بها تُعَدّ HTML و CSS وجافاسكربت لغات تعمل في الواجهة الأمامية (من جهة العميل)، أي أنها تُنفَّذ باستخدام المتصفحات لتظهر صفحة الويب كما يراها المستخدِم. هناك أيضًا مجموعة أخرى من لغات البرمجة تُدعى لغات الواجهة الخلفية (من جهة الخادم) أي أنها تُنفّذ على الخادم قبل أن تًرسل نتيجة التنفيذ إلى المتصفح لعرضها، إذ يقتصر الاستخدام النمطي لهذه اللغات على الحصول على بعض البيانات من قواعد البيانات ومن ثم توليد شيفرة HTML لاحتواء هذه البيانات وإرسالها إلى المتصفح ليعرضها للمستخدِم، ونذكر من هذه اللغات ASP.NET و Python و PHP و NodeJS. أفضل الممارسات عند تطوير مواقع الويب تحدثنا بإيجاز عن التقنيات التي ستستخدِمها في بناء مواقع الويب، وسنتحدث الآن عن أفضل الممارسات العملية التي عليك تبنيها لتتأكد من استخدام تلك التقنيات بأفضل طريقة ممكنة. سيأتي المصدر الأساسي لعدم الثقة عندما نتحدث عن تصميم مواقع ويب من عدم معرفتك بمجموعة التقنيات التي يعتمد عليها المستخدِمين في تصفح موقعك: قد يستخدِم أحدهم جهاز آيفون بشاشة صغيرة وضيقة. قد يستخدِم آخر حاسوبًا محمولًا بنظام ويندوز له شاشة عرض واسعة. أما الثالث فقد يكون ضريرًا ويستخدم قارئًا آليًا لمحتوى الشاشة. وقد يستخدم الرابع حاسوبًا مكتبيًا قديمًا لا يستطيع تشغيل أية متصفحات حديثة. عليك تصميم موقعك وفق الآلية الدفاعية بما أنك لا تعرف ببساطة كيف سيتصفحه المستخدِم، ف، لذا اجعل موقعك مرنًا قدر الإمكان لكي يتمكن جميع المستخدِمين من الوصول إلى محتواه بصرف النظر عن اختلاف تجربتهم له، أي عليك باختصار إفادة الجميع من الويب قدر المستطاع، كما ستصادف في مرحلة ما من رحلتك التعليمية المفاهيم التالية: التوافق مع متصفحات مختلفة Cross-browser compatibility: وهو أسلوب يحاول التأكد من عمل صفحة الويب بالصورة المطلوبة ضمن أكبر عدد ممكن من المتصفحات، ويتضمن ذلك استخدام تقنيات تدعمها معظم المتصفحات، وتقديم تجربة تصفح أفضل في المتصفحات القادرة على التعامل مع هذه التقنيات (تحسين مستمر)، وكتابة شيفرة يمكن اختزالها بسهولة إلى صيغة أبسط تستطيع المتصفحات القديمة عرضها لإعطاء تجربة تصفح مفيدة (تراجع رشيق graceful degradation)، كما يتضمن الأمر الكثير من الاختبارات لمتابعة أي مشاكل على متصفح محدد، ومن ثم العمل أكثر على إصلاح تلك المشاكل. تصميم متجاوب للصفحات Responsive web design: وهو أسلوب لخلق مرونة من الناحية الوظيفية والتخطيطية للصفحات بحيث تتلاءم تلقائيًا مع المتصفحات المختلفة، ومثالنا على ذلك صفحة ويب تُعرَض بتخطيط معيّن على شاشة واسعة لمتصفح حاسوب ومن ثم تأخذ تخطيطًا متجاوبًا مع حجم الشاشة مثل تخطيط العمود الواحد على متصفح هاتف محمول، إذ يمكنك تجريب أيّ موقع على الأحجام الصغيرة بتصغير حجم نافذة المتصفح وملاحظة سلوكه المتجاوب مع الأحجام الصغيرة الأداء Performance: ويستهدف تحميل صفحة ويب بالسرعة الممكنة مع المحافظة على وضوحها وسهولة استخدامها لكي لا يشعر المستخدِم بالإحباط ويغادرها. سهولة الوصول Accessibility: ويعني إمكانية استخدام الموقع من قِبَل أكبر عدد ممكن من الأشخاص المختلفين من جميع النواحي وترتبط بمفاهيم مثل التنوع، والشمولية، والتصميم الشمولي، كما يتضمن ذلك أشخاصًا ذوي إعاقة بصرية أو سمعية أو إدراكية أو حركية، ويتعدى الأمر مفهوم الإعاقة إلى السن والثقافة والتجهيزات المستخدَمة والمحدودية التقنية مثل الاتصال البطيء بالإنترنت. التدويل Internationalization: ويعني ذلك إمكانية استخدام موقع الويب من قِبَل أشخاص ينتمون إلى ثقافات مختلفة أو يتكلمون لغات مختلفة عن لغتك، وهنالك اعتبارات تقنية للموضوع مثل تبديل تخطيط الصفحات ليتلاءم مع اللغات التي تُكتَب من اليمين إلى اليسار أو مع اللغات التي تكتب عموديًا، واعتبارات إنسانية مثل استخدام لغة بسيطة وواضحة بعيدة عن اللهجات، ليزداد احتمال فهم الأشخاص الذين يتكلمون لغتك على أساس لغة ثانية أو ثالثة لما تعرضه. الخصوصية والأمان Privacy & Security: يرتبط المفهومان ببعضهما لكنهما مختلفان، إذ تعني الخصوصية السماح للأشخاص بتنفيذ ما يريدونه دون أن تتجسس على نشاطاتهم أو تجمع أية بيانات أكثر مما تحتاجه فعلًا، بينما يعني الأمان بناء موقعك بطريقة لا تُمكّن المستخدِمين المشبوهين من سرقة المعلومات التي يضمها الموقع عنك أو عن عملائك. الانطلاق في عالم ويب سنعرض في هذا المقال بعض المهارات العملية اللازمة لتنطلق في عالم تطوير ويب مثل اختيار البرمجيات التي تعمل عليها والأدوات اللازمة لبناء صفحات ويب بسيطة ونشرها وكتابة شيفرتها، كما سنفرد لاحقًا لكل العناوين التي نمر عليها مقالات خاصةً لشرح مستفيض أكثر. عليك الكثير لتتعلمه وتفعله حتى تصل إلى مرحلة تطوير موقع ويب احترافي، فإذا كنت حديث العهد في هذا المجال، فسنشجِّعك على البدء بموقع بسيط، ولن تكون جاهزًا مباشرةً لتبني موقع فيسبوك جديد، لكنك ستكون قادرًا على بناء مواقع بسيطة ونشرها، وبالاطلاع على المقالات التي سنشير إليها باختصار والعمل بمضمونها، ستنتقل من الصفر إلى نشر أول موقع بسيط لك على الإنترنت، فلنبدأ جولتنا. تثبيت البرمجيات الأساسية هناك الكثير من الأدوات والبرمجيات التي تُستخدَم في بناء وتطوير مواقع ويب، وقد تربكك بالفعل كثرة محررات الشيفرة وإطارات العمل وأدوات الاختيار، إذ سنرشدك في مقال تثبيت البرمجيات الأساسية خطوةً بخطوة إلى تثبيت البرمجيات التي تحتاجها لتبدأ عملية بناء مواقع ويب بسيطة. التفكير بالمظهر العام لموقع الويب الذي تبنيه عليك التخطيط لمظهر ومحتوى موقعك قبل الشروع في كتابة الشيفرة، فما هي المعلومات التي سيعرضها؟ وما هي خطوط الكتابة والألوان التي ستستخدِمها؟ التعامل مع الملفات يتكون موقع ويب من ملفات عدة: نصية وشيفرات وأوراق تنسيق ووسائط متعددة وغيرها. لا بد إذًا من تنظيم هذه الملفات وفق هيكلية منطقية عندما تبدأ بناء موقعك وأن تتأكد من ترابط هذه الملفات مع بعضها. أساسيات HTML تُستخدَم شيفرة HTML في هيكلة محتوى ويب وتعطيه المعنى والغاية، أي هل المحتوى الذي تقدِّمه على سبيل المثال سيكون مقطعًا نصيًا أم قائمة نقطية؟ هل ستزوِّد صفحتك بالصور؟ هل ستعرض جداول تضم بيانات؟ أساسيات CSS تُعَدّ التنسيقات المورثة Cascading Style Sheets واختصارًا CSS شيفرةً خاصةً بتنسيق صفحات ويب، فهل سيكون نص ما مثلًا أسود أم أحمر؟ في أيّ مكان من الصفحة ستعرض محتوًى معينًا؟ ما الصورة التي ستضعها في خلفية الصفحة؟ أو ما الألوان التي ستختارها لموقعك؟ أساسيات جافا سكربت جافا سكريبت هي لغة البرمجة التي تستخدمها لإضافة ميزات تفاعلية إلى موقعك مثل الألعاب أو الأشياء التي تحدث عند النقر على زر أو عندما تُدخل نصًا في نموذج أو عندما تُحدث تأثيرات حركية في تنسيق العناصر أو عند تصميم الرسوميات المتحركة وغيرها الكثير. نشر موقعك على شبكة الإنترنت عندما تُنهي كتابة شيفرة موقعك وتنظيم جميع الملفات التي يضمها، سيحين الوقت لنشره على شبكة الإنترنت ليطَّلع عليه الناس. كيف يعمل الويب قد لا تكون لديك فكرة عن الأشياء المعقدة التي تجري خلف الستار عندما تتصفح مواقعك المفضلة، لكننا سنختصر ما يحدث في جزئية لاحقة من هذه السلسلة عندما تستعرض صفحة ويب في متصفح حاسوبك. ختامًا، قد يهمك مقال آلية عمل شبكة الإنترنت؟، وقد ترغب بالاطلاع أكثر على تاريخ الشبكة العنكبوتية العالمية، وننصحك أيضًا بالرجوع إلى مقالة المدخل الشامل لتعلم تطوير الويب ترجمة -وبتصرف- للمقال The web and webstandards. اقرأ أيضًا الفرق بين صفحة الويب وموقع الويب وخادم الويب ومحرك البحث الحماية من مواقع الإنترنت في العالم الرقمي التأثير النفسي للألوان في تصميم الويب
-
سنبني خلال هذا المقال خط إنتاج Pipeline لنشر المشروع النموذجي الذي بدأناه في التمرين 11.2. إذ سننشئ نسخة خاصةً بنا من مستودع المشروع لكي نتعامل معها، ثم سنبني في آخر تمرينين خط إنتاج آخر لنشر بعض التطبيقات الخاصة بنا والتي بنيناها سابقًا. يضم القسم 21 تمرينًا من المفترض إكمالها جميعًا حتى تنهي هذا المنهاج، وعليك أن تسلم حلول هذه التمرينات إلى منظومة تسليم التمارين بنفس الأسلوب المُتبع في القسم السابق، إذ تُسلَّم التمرينات إلى نسخة مختلفة من المنهاج. ستعتمد المعلومات في هذا القسم على مفاهيم اطلعنا عليها سابقًا، لذلك ننصحك بإكمال الأقسام 0-5 قبل البدء بهذا القسم. لن تكتب الكثير من أسطر الشيفرة في هذا القسم، فهو يغطي في معظم الأوقات مواضيع عن التهيئة. وعلى الرغم من أن تنقيح الشيفرة صعب، لكن تنقيح أوامر التهيئة أصعب بكثير، فعليك إذًا التحلي بالصبر والمثابرة في هذا القسم. تجهيز التطبيقات لمرحلة الإنتاج ستضطر بعد الانتهاء من كتابة الشيفرة عاجلًا أم آجلًا إلى نقل تطبيقك إلى مرحلة الإنتاج، أي إلى مستخدميه الحقيقيين، ثم ستضطر بعدها إلى صيانة هذا التطبيق باستمرار وإصدار نسخٍ جديدة منه والعمل مع مطورين آخرين لتوسيعه. لقد استخدمنا حاليًا غيت هب GitHub لتخزين الشيفرة المصدرية، لكن ما الحل عندما نعمل ضمن فريق من المطورين؟ ستظهر عدة مشاكل عند تعاون عدة مطورين، فقد يعمل التطبيق جيدًا على حاسوبي، لكن قد يخفق على حواسيب مطورين آخرين يعملون على أنظمة تشغيل مختلفة، أو يستخدمون نسخًا مختلفة من المكتبات التي أدرجناها في التطبيق. يُشار إلى هذه المشكلة بالعبارة "التطبيق يعمل على جهازي works on my machine". هناك مشكلة أخرى، فلو أجرى مطورين تعديلات على شيفرة التطبيق ولم يتفقا من سينشر التعديلات التي أنجزها، من سيمنع أحدهما من محي تعديلات الآخر وكتابة تعديلاته مكانها؟ سنغطي في هذا القسم أساليب العمل المشترك لبناء ونشر التطبيقات بطريقة منضبطة ومحددة جيدًا، يظهر فيها بكل وضوح ما الذي سيحدث وتحت أية ظروف. بعض المصطلحات المفيدة نستخدم في هذا القسم مصطلحات قد لا تعرفها أو لم تفهمها جيدًا، سنناقش هذه المصطلحات تاليًا، وحتى لو كنت على دراية بهذه المصطلحات، اطلع على هذه الفقرة لنكون على وفاق في فهم المصطلح عند وروده. الفروع Branches يسمح نظام غيت Git بوجود نسخ، أو مسارات streams، أو إصدارات مختلفة من الشيفرة تتعايش معًا دون الحاجة لإلغاء بعضها بعضًا؛ فعندما تُنشئ مستودعًا سيكون هذا المستودع بمثابة الفرع الرئيسي (ندعوه في غيت بالاسم "main" أو "master"، لكن الأمر مختلف في المشاريع القديمة). لا بأس بهذا الأسلوب إذا كان هناك مطور واحد يستخدم هذا الفرع، ويعمل على تطوير ميزة واحدة للتطبيق كل مرة. سيكون استخدام الفروع مفيدًا عندما تتعقد بيئة التطوير، إذ سيعمل كل مطور على فرع أو أكثر، وسيمثل كل فرع نسخةً مختلفةً قليلًا عن نسخة الفرع الرئيسي. وعندما تكتمل الميزة التي يجري تطويرها في أحد الفروع ستُدمج مع الفرع الرئيسيٍ، وبالتالي ستصبح هذه التغييرات أو الميزات الجديدة جزءًا من التطبيق الرئيسي. وهكذا سيتمكن كل مطور من العمل على مجموعة من التعديلات بحيث لا يعيق بقية المطورين من العمل على أفكارهم الخاصة قبل إكمال هذه التعديلات. لكن ما الذي سيحدث لبقية الفروع الخاصة بالمطورين الآخرين عندما يدمج أحد المطورين تعديلاته ضمن الفرع الرئيسي؟ إذ سيبتعد بقية المطورين عن النسخة القديمة التي يعملون عليها. وكيف سيعرف المطورون أن تعديلاتهم التي يجرونها على النسخة السابقة ستكون متوافقةً مع الحالة الجديدة التي يفرضها دمج التعديلات ضمن الفرع الرئيسي؟ سنحاول الإجابة عن هذا السؤال الجوهري في هذا القسم. يمكنك الاطلاع على مزيدٍ من المعلومات حول الفروع من خلال قراءة المقالة "أساسيات التفريع (Branching) والدمج (Merging) في Git". طلبات السحب Pull requests يجري عادةً دمج فرع ضمن الفرع الرئيسي وفق آلية تُعرف بطلب السحب، أو كما يُعرف أحيانًا بالاختصار "PR"، إذ يطلب المطور الذي أجرى بعض التعديلات أن تُدمج التعديلات التي أجراها ضمن الفرع الرئيسي، وحالما يُقبل هذا الطلب أو يُفتتح للمراجعة، يمكن لمطور آخر أن يتحقق من أن كل شيء سيجري على مايرام بعد الدمج. لو اقترحت مثلًا تعديلًا على مادة منهجنا، فقد قدمت فعلًا طلب سحب. بناء التطبيق Build لهذا المصطلح معانٍ مختلفة في لغات البرمجة المختلفة. فلا حاجة في بعض اللغات المترجمة، مثل روبي Ruby، أو بايثون Python إلى خطوة بناء فعلية إطلاقًا. عندما نتكلم عن البناء عمومًا، فإننا نعني بذلك إعداد التطبيق ليعمل على المنصة التي صُمِّم لأجلها، وقد يعني ذلك، على سبيل المثال، أننا لو أردنا كتابة التطبيق بلغة TypeScript ثم تنفيذه على Node، فستكون خطوة البناء هي عملية نقل شيفرة TypeScript إلى جافا سكربت JavaScript. ستغدو هذه الخطوة إجبارية وأكثر تعقيدًا في اللغات المُصرَّفة، مثل C و Rust، إذ تتطلب شيفرتها التصريف إلى شيفرة قابلة للتنفيذ. وكنا قد اطلعنا في القسم 7 على برنامج webpack، وهو أداةٌ رائدة حاليًا في بناء نسخ إنتاج من تطبيقات React أو تطبيقات واجهة أمامية مكتوبة بلغة جافاسكربت JavaScript أو TypeScript. نشر التطبيقات Deploy يشير مصطلح "النشر" إلى وضع التطبيق في المكان الذي يمكن للمستخدم النهائي الوصول إليه واستخدامه؛ فقد يعني هذا المصطلح بالنسبة للمكتبات مثلًا وضعها ضمن حزم ثم دفعها إلى أرشيف للحزم (مثل npmjs.com) بحيث يمكن للمستخدمين إيجادها وتضمينها في مشاريعهم. تختلف صعوبة نشر خدمة (مثل تطبيق ويب) حسب تعقيدها، فقد اشتمل مخططنا لنشر التطبيق في القسم 3 مثلًا على تنفيذ بعض السكربتات يدويًا ثم دفع شيفرة المستودع إلى خدمة استضافة Heroku. سنطور في هذا القسم "خط إنتاج" لنشر كل جزء من شيفرتك آليًا إلى Heroku إن لم تسبب هذه الشيفرة أية مشاكل. وقد يكون النشر أحيانًا على درجة عالية من التعقيد خاصةً إذا تطلب التطبيق احتياجات خاصة، كأن يكون متاحًا دائمًا للعمل أثناء تطويره "لا إيقاف من أجل النشر zero downtime deployment"، أو كان علينا أن نأخذ في الحسبان بعض الأمور مثل نقل قواعد البيانات. لن نغطي النقاط المتعلقة بالنشر الذي يحمل تعقيدات مثل التي ذكرناها، لكن من المهم أن تدرك وجودها. ما هو التكامل المتواصل؟ يختلف المفهوم الدقيق لمصطلح التكامل المتواصل Continuous Integration -أو اختصارًا "CI"- عن كيفية استخدامه في مجال التطوير. ستجد نقاشًا قديمًا لكنه يحمل أثرًا كبيرًا عن استخدام هذا المصطلح في مدونة "مارتن فلور". وإذا أردنا التحديد الدقيق للمصطلح CI سنقول أنه يعني غالبًا "دمج التغييرات التي نفذها المطور مع الفرع الرئيسي" ثم أضافت ويكيبيديا Wikipedia العبارة "عدة مرات في اليوم" إلى المصطلح. وهذا الأمر صحيح عادةً، لكن عندما نشير إلى CI في مجال البرمجيات، فنحن نتحدث غالبًا عما سيحدث بعد عملية الدمج الفعلية للتغيرات، إذ قد نحتاج إلى إنجاز بعضٍ من هذه الخطوات: التدقيق lint: للحفاظ على الشيفرة واضحة وقابلة للصيانة. البناء build: وضع كل الشيفرة المُنجزة في برنامج واحد. الاختبار test: لضمان عدم إخفاق أية ميزات موجودة مسبقًا. التحزيم packaging: وضع كل ما نحتاجه في حزمة سهل الحمل والنقل. التحميل/ النشر deploy: لجعل البرنامج متاحًا للاستخدام. سنناقش كل خطوة من تلك الخطوات (عندما نجد فائدةً من ذلك) بشيء من التفصيل لاحقًا. وعلينا أن نتذكر دائمًا أنّ هذه العملية ستكون محددةً بدقة. يعيق التحديد الدقيق strict definition عادةً سرعة التطوير أو الإبداع في إيجاد الحلول، لكن من المفترض أن لا يكون هذا صحيحًا بالنسبة للتكامل المتواصل، إذ يجب وضع هذه القيود بطريقة مرنة تسمح بالتطوير والعمل المشترك. سيسمح استخدام أنظمة CI جيدة، مثل GitHub Actions الذي سنغطيه في هذا القسم بتنفيذ كل ما ذكرناه آليًا وبصورة سحرية. التحزيم والنشر مثل جزء من نظام التكامل المتواصل CI ينبغي التذكير من حين إلى آخر، أنّ عملية التحزيم وعملية النشر خاصة لا تُعدان أحيانًا جزءًا من نظام CI، لكننا سنعدّهما جزءًا من النظام، لأنه من المنطقي في العالم الحقيقي أن نضع كل الخطوات التي أشرنا إليها معًا. ويعود جزءٌ من ذلك للحفاظ على التسلسل في سياق العمل وخط إنتاج البرنامج (الطريق إلى إيصال المنتج إلى المستخدم النهائي)، بينما يعود الأمر في شقه الآخر إلى حقيقة أنّ هذه النقطة هي ما يسبب إخفاق العملية ككل. ستظهر المشاكل غالبًا في مرحلة التحزيم من نظام CI كونها مرحلةٌ لا تختبر محليًا، فمن المنطقي إذًا اختبار عملية تحزيم المشروع خلال سير العمل في CI حتى لو لم نضع هذه الحزمة موضع العمل، كما يمكن في بعض مسارات العمل أن نختبر حزمةً قد بُنيت فعلًا مسبقًا. سيؤكد ذلك أننا اختبرنا الشيفرة بنفس الشكل الذي سننشرها فيه خلال مرحلة الإنتاج. إذًا ما هو وضع عملية النشر؟ سنتحدث عن الاستمرارية وإمكانية التكرار مطولًا في الفصول القادمة، لكن تجدر الإشارة هنا إلى أننا نحتاج إلى عملية تبدو متماثلةً دائمًا، سواءٌ أجرينا الاختبارات في فرع تطوير أو في الفرع الرئيسي. نحتاج في الواقع إلى العملية نفسها "حرفيًا" بحيث يظهر الاختلاف فقط في نهايتها، وذلك عند تحديد ما إذا كنا في الفرع الرئيسي أم لا، وإن كنا نريد النشر أم لا. وفي هذا السياق من المنطقي تضمين خطوة النشر في سير عمل CI طالما أنها ستخضع للصيانة في نفس الوقت الذي نطورها فيه. يشير المصطلحان: "التسليم المتواصل Continuous Delivery" و"النشر المتواصل Continuous Deployment" -أو اختصارًا CD- إلى منظومة CI عندما تتضمن مرحلة النشر. لن نزعجك بالتعريف الدقيق، إذ يمكنك الاطلاع عليه من خلال Wikipedia، أو منشورات مدونة "مارتن فلور"، أو من خلال أكاديمية حسوب، لكننا نستخدم الاختصار CD ليشير إلى أسلوب ممارسة عملي يقتضي إبقاء الفرع الرئيسي متاحًا للنشر والتطوير في أي وقت. لكن ماذا عن المنطقة الغامضة بين مصطلحي CI وCD؟ فلو كان علينا مثلًا أن نجري بعض الاختبارات قبل أن ندمج أية شيفرات جديدة ضمن الفرع الرئيسي، هل نعد ذلك شكلًا من أشكال CI لأننا سنجري دمجًا متواصلًا مع الفرع الرئيسي؟ أم شكلًا من أشكال CD لأننا نتحقق بذلك أن الفرع الرئيسي قابلًا للنشر باستمرار؟ تقع بعض المفاهيم إذًا على الخط الفاصل بين المصطلحين، فمن المنطقي كما أشرنا سابقًا، أن نعد CD جزءًا من CI. لهذا السبب، سيُستخدم غالبًا المصطلح CI/CD للدلالة على العملية برمتها. وانتبه إلى أننا سنستخدم المصطلحين CI و CI/CD بالتناوب طوال الوقت في هذا القسم. أين تكمن أهمية استخدام نظام CI؟ لقد ذكرنا سابقًا مشكلة "يعمل على جهازي" ومشكلة نشر تغييرات متعددة المصادر، لكن ماذا عن بقية المشاكل؟ ماذا لو حملّت "سارة" الشيفرة مباشرةً إلى الفرع الرئيسي؟ ماذا لو استخدم "أحمد" فرعًا ولم يكلف نفسه عناء إجراء بعض الاختبارات قبل دمج ما عدّله ضمن الفرع الرئيسي؟ ماذا لو حاول "عبد الله" بناء نسخة إنتاج من التطبيق لكن بمعاملات خاطئة؟ سيمكِّننا استخدام التكامل المتواصل وفق طريقة منهجية في العمل في: منع رفع الشيفرات مباشرةً إلى الفرع الرئيسي. تنفيذ عملية CI لكل طلبات السحب إلى الفرع الرئيسي وتمكينها من دمج التغييرات. بناء حزم إنتاج للبرامج التي نطورها في بيئة معروفة تمتلك نظام CI. وهنالك أيضًا بعض الإيجابيات لتوسيع هذه الإعدادات: إذا استخدمنا CD في كل مرةٍ ننفذ فيها عملية دمج مع الفرع الرئيسي، سنكون واثقين من عمل الفرع الرئيسي وفق نظام الإنتاج. إذا سمحنا بإتمام عملية الدمج فقط في الحالة التي يكون فيها الفرع الرئيسي محدّثًا، سنضمن أن لا يلغي المطورون التغييرات التي نفذها غيرهم. تنبيه: سنفترض في هذا القسم أن الشيفرة الموجودة في الفرع الرئيسي ("mian" أو "master") ستعمل وفق نظام الإنتاج. ونظرًا لوجود عدد هائل من مخططات العمل (workflows) على git، قد يكون هناك على سبيل المثال حالات يظهر فيها فرع خاص للإصدار release branch يحتوي على الشيفرة التي تعمل وفق نظام الإنتاج. مبادئ هامة من المهم أن نتذكر أنّ CI/CD ليس هدفًا بحد ذاته، لكن الهدف هو تطوير أسرع وأفضل للتطبيقات بأقل عددٍ من الثغرات، وتحقيق أفضل تعاون بين المطورين. ولهذا لا بدّ من تهيئة نظام CI بما يلبّي المهمة التي ننفذها والمشروع بحد ذاته، كما ينبغي أن نبقي الهدف الرئيسي من استخدامه في حساباتنا دائمًا. يمكننا التفكير بنظام CI بمثابة جوابٍ على الأسئلة التالية: كيف سنتأكد أنّ جميع الاختبارات ستُطبّق على كامل الشيفرة التي ستُنشر؟ كيف سنضمن جاهزية الفرع الرئيسي للنشر في كل الأوقات؟ كيف سنتأكد أنّ النسخ التي تُبنى ستكون متوافقة، وستعمل دائمًا على المنصات التي صُمِّمت للنشر عليها؟ كيف سنضمن أن التغييرات الجديدة لن تلغي التغييرات الأقدم؟ كيف سننجز عملية النشر بضغطة زر أو بطريقة آلية، عندما يدمج مطور التغييرات التي أجراها مع الفرع الرئيسي؟ وهناك أيضًا دلائل علمية على الفائدة الهائلة التي يقدمها نظام CI/CD، فبناءً على دراسة واسعة في كتاب ": Building and Scaling High Performing Technology Organizations"، يقترن استخدام CI/CD بشدة مع النجاحات على صعيد المؤسسات (تحسين الأرباح وجودة المنتج وزيادة الحصة السوقية وتقليل زمن التسويق)، وكذلك من ناحية المطورين، فقد جعلتهم أكثر سعادةً وأقل إرهاقًا. سلوك موثق تشيع في أوساط المبرمجين طرفةٌ مفادها أنّ الثغرات هي "ميزات غير موثقة". لكن يجب علينا تفادي أية حالات لا نعلم تمامًا نتيجتها. فلو اعتمدنا مثلًا على عنوان طلب السحب لنحدد ما إذا كان إصدار البرنامج رئيسيًا major، أو ثانويًا minor، أو ترميميًا patch (سنتحدث عن معنى كل إصدار لاحقًا)، سيكون علينا الانتباه إلى الحالة التي يُغفل فيها المطور من وضع عنوانٍ لطلب السحب الذي قدمه. وماذا لو وضع هذا العنوان بعد بدء عملية البناء أو الاختبار؟ أو أنه غيَّر العنوان خلال مرحلةٍ ما، فما الذي سيكون عليه هذا الإصدار؟ من الممكن أن تغطي جميع الحالات التي قد تتوقعها، ومع ذلك، قد تظهر بعض الثغرات عندما يُنفّذ المطور شيئًا "إبداعيًا" لم تتوقعه إطلاقًا، فمن الجيد إذًا أن تنتهي العملية التي ستخفق بأمان في هذه الحالة. فلو عدنا إلى المثال السابق عندما يغير المطور عنوان الطلب أثناء تنفيذ عملية البناء. إذا لم نتمكن من توقع سيناريو مثل هذا مسبقًا، فمن الأفضل ربما أن تتوقف عملية البناء، وأن نبلِّغ المستخدم بأنّ شيئًا غير متوقع قد حدث، فنشر إصدار خاطئ سينتج حتمًا مشاكلًا أكبر، وسيكون إيقاف العملية وإخطار المستخدم هو الحل الأكثر أمانًا. يحدث الشيء ذاته في كل مرة قد نملك أفضل اختبارات لبرمجياتنا يمكن تخيلها، وقد تكون قادرةً على اصطياد أية مشكلة محتملة، لكنها ستبقى عديمة الجدوى إن لم ننفذها على الشيفرة قبل نشرها. علينا أن نضمن أنّ الاختبارات قابلةً للتنفيذ، كما نريد أن نضمن أنها ستعمل مع الشيفرة التي سننشرها فعليًا. فلن يفيدنا الاختبار الذي ينجح مثلًا ضمن فرع "سارة" ويفشل عند دمجه مع الفرع الرئيسي. وطالما أننا سننشر محتويات الفرع الرئيسي، لذا علينا أن نتأكد من نجاح الاختبارات على نسخة من الفرع الرئيسي بعد أن ندمج معه فرع "سارة". ستوصلنا المناقشة السابقة إلى مبدأ جوهري وهو التأكد أنّ السلوك نفسه سيحدث كل مرة، أو أنّ المهام المطلوبة ستُنفَّذ جميعها وبالترتيب الصحيح. يجب أن تبقى الشيفرة قابلة للنشر دائما إنّ وجود شيفرة قابلة للتوزيع والنشر دائمًا أمر مريح جدًا وخاصةً عندما يحتوي الفرع الرئيسي على شيفرة تعمل في وضع الإنتاج؛ فإذا ظهرت ثغرةٌ مثلًا وتطلب الأمر معالجتها، يمكنك سحب نسخة من الفرع الرئيسي (وهي الشيفرة التي تُنفًّذ في وضع الإنتاج) وحل المشكلة، ثم تقديم طلب سحب لإعادة الشيفرة إلى الفرع الرئيسي (دمج من جديد). ويجري هذا الأمر عادةً مباشرةً دون أية مشاكل. إذا اختلفت الشيفرة الموجودة في الفرع الرئيسي عن شيفرة الإنتاج ولم يكن الفرع الرئيسي قابلًا للنشر، سيكون عليك البحث عن الشيفرة التي تعمل في وضع الإنتاج وسحب نسخة عنها، ثم إيجاد الثغرة ومعالجتها، كما عليك إيجاد طريقة لإعادة الشيفرة إلى الفرع الرئيسي والعمل على نشر الجزء المحدد الذي أصلحته. لن يكون هذا الأمر مريحًا وستكون طريقة تنفيذه مختلفةً كليًا عن مخطط نشر التطبيقات الاعتيادي. معرفة أجزاء الشيفرة المنشورة- مجموع SHA/الإصدار من المهم غالبًا تحديد الشيفرة التي تعمل فعليًا في وضع الإنتاج. ولقد ناقشنا سابقًا أن شيفرة الفرع الرئيسي هي من تعمل في هذا الوضع في الحالة النموذجية، لكن هذا الأمر ليس ممكنًا دائمًا؛ فقد تتعرض عملية البناء للإخفاق عندما نحاول تشغيل شيفرة الفرع الرئيسي في وضع الإنتاج، وقد نجري عدة تغييرات على الشيفرة ونريدها أن تُنشر جميعها مباشرةً. ما نحتاج إليه في حالات مثل هذه (وهي فكرة جيدة عمومًا)، هو معرفة الشيفرة التي تعمل في وضع الإنتاج بالضبط؛ إذ يمكن معرفة ذلك أحيانًا عن طريق رقم الإصدار version، وأحيانًا بمجموع SHA sum (وهو جدول HASH يعرِّف بصورةٍ فريدة اعتماد git) متصل بالشيفرة. سنناقش موضوع تحديد رقم الإصدار لاحقًا في هذا القسم. الآلية الأكثر فائدةً هي ربط معلومات الإصدار مع تاريخ جميع الإصدارات، فلو اكتشفنا مثلًا وجود ثغرة في اعتماد محدد، يمكننا أن نعرف متى أُصدر هذا الاعتماد وكم عدد المستخدمين الذين تأثروا بالثغرة. وتظهر فائدة هذه المقاربة عندما تسبب الثغرة أخطاءً في بيانات قواعد البيانات، وهكذا من الممكن تقفي أثر البيانات الخاطئة بناءً على تاريخ إنشائها. أنماط إعدادات منظومة CI علينا تخصيص خادم منفصل لتشغيل مهام منظومة التكامل المتواصل CI لكي نلبي بعضًا من المتطلبات التي ذكرناها سابقًا، إذ سيقلل وجود خادم منفصل المخاطر الناتجة عن اختلاط عمليات أخرى بعملية منظومة CI/CD جاعلةً نتيجتها غير متوقعة. هنالك خياران: استضافة خادم خاص بنا أو الخدمة السحابية cloud service. استضافة Jenkins وإعدادات بيئة الاستضافة الذاتية self-host تُعد استضافة Jenkins الخيار الأكثر شعبيةً من بين خيارات الاستضافة الذاتية، فهي مرنةٌ جدًا وتمتلك عدة إضافات plugin لكل شيء تقريبًا (ماعدا الشئ الوحيد الذي تريده). تمثل هذه الاستضافة خيارًا جيدًا للعديد من التطبيقات. يعني استخدام الاستضافة الذاتية أن تكون بيئة الاستضافة تحت سيطرتك بالكامل، وكذلك جميع الموارد، ولن تكون أسرارك عرضةً للكشف من قبل الآخرين، كما ستتمكن من فعل ما تشاء بالعتاد الصلب. لكن ولسوء الحظ هناك جانبٌ مظلم لاستضافة Jenkins فهي صعبة الإعداد، إذ تتطلب المرونة الكبيرة في الإعداد وجود العديد من قوالب template الشيفرة التي تتطلب الإعداد ليعمل كل شيء، ويتطلب استخدام Jenkins بالتحديد إعداد منظومة CI/CD باستخدام لغة Jenkins الخاصة بالنطاق domain-specific. ولا ننس مخاطر إخفاق العتاد الصلب والذي قد يسبب مشكلةً في حالات الازدحام. تعتمد فاتورة الاستضافة الذاتية على العتاد الصلب الذي تختاره غالبًا، فأنت تدفع مقابل الخادم وما ستفعله على الخادم لن يغير من فاتورتك. استخدام GitHub Actions وحلول أخرى معتمدة على الاستضافة السحابية لن تضطر للتفكير كثيرًا عند إعداد بيئة الاستضافة في الاستضافة السحابية، فكل ما عليك فعله هو أن تطلب من الاستضافة ما تريده، ويتضمن ذلك عادةً وضع ملف في مستودعك (ثم إخبار منظومة CI بقراءته)، أو التحقق من وجود ملف كهذا في المستودع. سيكون ملف تهيئة CI في الاستضافة السحابية أبسط قليلًا، وخاصةً إن لم تتعدّى الحدود "الطبيعية" للاستخدام، لكن قد تغدو خيارات هذه الإستضافة محدودةً قليلًا إن أردت فعل أشياء خاصة بين الفينة والأخرى، أو قد تجد صعوبةً في ذلك، خاصةً في إنجاز مهام محددة لم تُبنى المنصة السحابية لكي تنجزها. سنركز في هذا القسم على الاستخدامات التي تعد "طبيعية"، فقد تتطلب إعدادات بعض المهام الخاصة عتادًا صلبًا خاصًا على سبيل المثال. وبعيدًا عن إعدادات التهيئة التي ذكرناها سابقًا، قد تواجهنا مشاكلًا تتعلق بمحدودية الموارد على الاستضافة السحابية، فلو بدت النسخة بطيئة على الاستضافة الذاتية، يمكنك ببساطة حجز خادم أقوى وتضع ما تحتاجه من الموارد ضمنه، لكن هذا الأمر قد يكون مستحيلًا في الاستضافة السحابية. ستعمل العقد التي تبنيها في GitHub Actions مثلًا على معالجين افتراضيين (vCPU) و8 جيجابايت من ذواكر الوصول العشوائي. ستعتمد فاتورتك في الاستضافة السحابية على الوقت المستغرق في بناء تطبيقك، وهذا أمر يجدر أخذه بالحسبان. لماذا نفضل خيارا على آخر؟ إن كان مشروعك صغيرًا إلى متوسط الحجم ولن يحتاج أية متطلبات خاصة (مثل الحاجة إلى بطاقة رسومية لتنفيذ الاختبارات)، ستكون الاستضافة السحابية الحل المناسب غالبًا، إذ ستكون الإعدادات بسيطةً ولن تدخل دوامة إعدادات النظام الخاص بك، كما ستكون الكلفة أقل للمشاريع الصغيرة خاصة؛ أما بالنسبة للمشاريع الأضخم والتي تحتاج إلى موارد أكبر أو بالنسبة للشركات الكبيرة التي تضم عدة فرق للتطوير وعدة مشاريع، قد يكون اختيار منظومة استضافة ذاتية هو الخيار الأنسب. لماذا استخدمنا GitHub Actions في هذه السلسلة؟ يُعدّ GitHub Actions الخيار الأنسب كوننا نستخدم غيت هب GitHub، إذ سيؤمن لنا منظومة CI قوية تعمل مباشرةً دون الحاجة إلى إعداد خادم أو خدمة سحابية يؤمنها طرف ثالث. إضافةً إلى سهولة استخدامه، يُعد GitHub Actions خيارًا جيدًا من عدة جوانب، فقد يكون أفضل خدمة سحابية موجودة حتى اللحظة، إذ يحظى بشعبية كبيرة منذ إصدار النسخة الأساسية منه في نوفمبر (تشرين الثاني) عام 2019. التمرين 11.1 قبل أن ننغمس في إعداد خطوط إنتاج لأنظمة CI/CD، لا بدّ من مراجعة ما قرأناه. لنتهيأ للانطلاق فكر بحالة افتراضية نكون فيها أمام تطبيق يجري تطويره من قِبل فريق من 6 مطورين وسيصدر قريبًا. لنفترض أنّ اللغة المستخدمة في تطوير التطبيق ليست JavaScript/TypeScript فلنقل Python، أو Java، أو Ruby، أو أية لغات قد تفكر بها. اكتب موضوعُا بسيطًا من 200-300 كلمة تجيب فيه أو تناقش النقاط التي سنطرحها تاليًا. يمكنك التحقق من عدد الكلمات التي تكتبها عبر موقع wordcounter. خزّن إجابتك في ملف اسمه "exercise1.md" في جذر المستودع الذي ستنشئه في التمرين 11.2 ناقش النقاط التالية: بعض الخطوات الشائعة في إعداد CI بما فيها التدقيق والاختبار والبناء، وكذلك الأدوات اللازمة لتنفيذ هذه الخطوات في بيئة عمل اللغة التي تختارها. يمكنك البحث عن الأجوبة عبر غوغل Google. ما هي بدائل إعداد منظومات CI عن GitHub Actions أو Jenkins؟ يمكنك الاستعانة بمحرك البحث غوغل. أين سيكون تطبيق هذه الإعدادات أفضل، على استضافة ذاتية أو استضافة سحابية؟ لماذا؟ ما هي المعلومات التي ستحتاجها لاتخاذ قرارك؟ تذكر أنه لا توجد إجابات صحيحة أو خاطئة لجواب هذا السؤال. ترجمة -وبتصرف- للفصل Introduction to CICD من سلسلة Deep Dive Into Modern Web Development اقرأ أيضًا ما هو Git إعادة تأسيس تفريعات طلب السحب وتحديثه في git إعداد التكامل المستمر والنشر المستمر باستخدام الخدمتين CircleCI وCoveralls التكامل المستمر: تثبيت Concourse CI على أوبنتو
-
يشرح هذا المقال مفاهيم تصميمية أساسية تتمثل بسهولة أو إمكانية الوصول accessibility إلى محتوى مواقع ويب وكيفية تصميم مواقع ويب يستطيع معظم زائريها الحصول على محتواها بسهولة ومتعة. تسهيل وصول جميع المستخدمين إلى مواقع ويب لن يتمكن بعض الزائرين من تجربة موقعك بالطريقة التي تأملها نظرًا لمعوقات فيزيائية أو تقنية قد تعترضهم. لذلك سنناقش في هذا المقال المبادئ العامة لسهولة الوصول accessibility (تترجم أحيانًا إلى شمولية أي شمولية التصميم لكل المستخدمين) وسنشرح بعض القواعد المتعلقة بها. المبادئ العامة لسهولة الوصول قد نربط إمكانية الوصول في البداية بالمعوقات السلبية مثل قولنا بأنّ الوصول إلى هذا البناء ممكن عندما تُعتمد مجموعة قواعد ناظمة مثل عرض الباب أو حجم المرافق الصحية أو موقع المصعد، وهذه مقاربة ضيقة لمفهوم إمكانية أو سهولة الوصول، وفكِّر بالأمر على أساس طريقة مميزة لدعم الآخرين ولخدمة العملاء، فما الذي قد يستفيده الناس في البرازيل من موقعك الذي يعتمد اللغة الإنكليزية؟ هل يمكن لمستخدِمي الهواتف الذكية تصفح مواقع ويب مزدحمة ومخصصة لشاشات الحواسب المكتبية الواسعة والتي تستخدِم حزمة استهلاك بيانات غير محدودة؟ بالطبع سيغادر الزوار موقعك في حالات مثل هذه، إذ ينبغي التفكير عمومًا بالمنتج الذي تقدِّمه انطلاقًا من وجهات النظر المختلفة لجميع العملاء المستهدَفين ومن ثم التكيف معها، فهذه هي سهولة الوصول. سهولة الوصول في عالم ويب تعني سهولة الوصول في سياق عالم ويب قدرة الجميع على الوصول إلى المحتوى الذي تقدِّمه دون النظر إلى الإعاقة التي يعانيها الزائر أو مكانه أو أية محدودية تقنية قد يواجهها أو أية ظروف أخرى. لنتأمل مقطع فيديو: حالة ضعف السمع: كيف يمكن لشخص لديه تدهور في حاسة السمع الاستفادة من مقطع الفيديو؟ لا بدّ إذًا من تزويد الفيديو بالكلمات أو تقدّم نص الفيديو بأكمله، وتأكد أيضًا من قدرة المستخدِم على ضبط مستوى الصوت بما يلبي احتياجاته الخاصة. حالة ضعف البصر: قدّم أيضًا نص الفيديو بأكمله لكي يطَّلع المستخدِم على المضمون دون أن يشغِّله، كما يمكنك تقديم وصفًا صوتيًا لما يحدث في الفيديو. إمكانية التوقف المؤقت: قد لا يفهم المستخدِم ما تقوله إحدى الشخصيات في الفيديو، لذلك من الأفضل تقديم إمكانية إيقاف المقطع مؤقتًا ليتسنى له قراءة كلماته أو إدراك ما يجري. إمكانية استعمال لوحة المفاتيح: لكي يتمكن المستخدِم من الوصول إلى الفيديو أو الخروج منه وتشغيله وإيقافه دون أن يعلق داخله. تتضمن أساسيات سهولة الوصول في ويب أشياءً مثل: ضع دائمًا نصًا بديلًا للصورة للمستخدِمين الذين يعانون من مشاكل بصرية أو لمن لديه اتصال ضعيف بالإنترنت عندما يحتاج الموقع إلى صورة لنقل معنى معين. تأكد من إمكانية تشغيل جميع المستخدِمين لبعض الواجهات الرسومية مثل عرض القوائم بنقرة زر واحدة أي لمسة أو ضغطة على زر "Return" مثلًا. حدِّد بصراحة لغة المحتوى الذي تعرضه لكي تتمكن البرمجيات التي تقرأ محتوى الشاشة من قراءة النصوص بصورة صحيحة. تأكد من قدرة المستخدِم على التنقل بين الأدوات التي تعرضها الصفحة من خلال لوحة المفاتيح فقط دون أن يعلق ضمنها، أي القدرة على الدخول والخروج على الأقل. وهذه النقاط هي البداية فقط. أدارت منظمة W3C منذ عام 1999 مجموعة عمل تُدعى "مبادرة سهولة الوصول على الويب Web Accessibility Initiative" لتطوير معايير إمكانية الوصول من خلال الإرشادات والمواد الداعمة والموارد على المستوى العالمي، ويمكنك الاطلاع على المزيد من خلال موقع المبادرة WAI، كما قد تجد بعض الأفكار في مقالات أكاديمية حسوب. تصميمات موجهة لجميع المستخدمين عندما تشرع في تصميم موقع ويب ينبغي علينا التفكير أولًا بتصميم شمولي Universal Design للموقع يلائم جميع مستخدِميه بغض النظر عن أية إعاقات قد يعانونها أو أية قيود تقنية أو ثقافية أو مكانية. يناقش هذا المقال بعض الأفكار السريعة والناجحة في تصميم أكثر شمولية لمواقع ويب، ولكن لا بدّ أن تكون أولًا على دراية بمفهوم التصميم الشمولي Universal design. التلاؤم اللوني من الأمور المهمة التي تجعل النصوص في مواقع ويب مقروءة هو استخدام خلفية ذات لون ملائم تسهل متابعة النص، إذ سيساعد ذلك مَن يعاني من إعاقة بصرية أو من يستخدِم هاتفه الذكي للقراءة في الخارج وعلى الطرقات. تُحدِّد منظمة W3C التلاؤم اللوني من خلال خوارزمية تحسب نسبة السطوع luminosity ratio بين الخلفية والواجهة، وقد تكون هذه الحسابات معقدةً، لكن بعض الأدوات الجاهزة قد تساعدنا في إنجاز الأمر. اختُبر التلاؤم اللوني لصفحة المقال الأصلي في الصورة السابقة وأعطى نتيجة 8.30:1 وهذا الرقم أعلى بكثير من الحد الأدنى المقبول الذي يقدَّر بالنسبة 4.5:1 وبالتالي لا بد أن يساعد التلاؤم اللوني للصفحة الكثيرين من ذوي الإعاقة البصرية في قراءتها. حجم خط الكتابة يمكنك تحديد حجم خط الكتابة في موقع ويب بوحدات قياس نسبية relative أو مطلقة absolute. وحدات القياس المطلقة لا تُحسَب هذه الوحدات حسابًا تناسبيًا، وإنما تعتمد على حجم محدد بصورة أساسية في الحساب، إذ تُقدَّر وحدة القياس المطلقة غالبًا بالبيكسل px، فإذا وضعت الشيفرة التالية مثلًا في ملف تنسيق CSS: body { font-size:16px; } فأنت تطلب من المتصفح أن يكون حجم الخط 16 بيكسل دائمًا، وقد تلتف بعض المتصفحات الحديثة على هذه القاعدة متظاهرةً أن حجم الخط سيكون 16 بكسل عندما يكون معامل تكبير الصفحة 100%، أي الحجم الطبيعي، ومع هذا وعلى امتداد سنوات عدة فقد عرض إنترنت إكسبلورر عمدًا الخطوط التي ضُبط حجمها على 16 بكسل مثلًا بالحجم 16 بكسل تمامًا بغض النظر عن معامل التكبير وصولًا إلى النسخة 8 التي لا بد من الانتباه لها لأنها لاتزال مستخدَمة. وحدات القياس النسبية تُحسَب هذه الأحجام نسبةً إلى العنصر الأب، وهي أكثر وضوحًا فيما يخص سهولة الوصول لأنها تحترم الإعدادات الخاصة بنظام المستخدِم، كما يُعبَّر عن الوحدات النسبية بالرموز em و% وrem: الحجم المبني على النسبة المئوية %: تخبر هذه الوحدة المتصفح أنّ حجم الخط في العنصر هو نسبة مئوية من حجم الخط في العنصر الأب الذي حُدِّد فيه حجم الخط، فإذا لم يكن للعنصر أب، فستجري الحسابات بالنسبة إلى حجم الخط الافتراضي للمتصفح (16 بكسل عادةً). الحجم المبني على الوحدة Em: تُحسَب اعتمادًا على أسلوب النسبة المئوية ذاته لكن على أساس أجزاء من 1 وليس 100، كما يُقال أن "em" هو عرض الحرف الأبجدي "M" على أساس حرف كبير (إذ يمكن وضعه ضمن مربع بصورة تقريبية). الحجم المبني على الوحدة rem: تُحسَب على أساس نسبة من حجم الخط للعنصر الجذري، ويعبَّر عنها على أساس أجزاء من 1 كما هو حال Em. لنفترض أننا نريد حجمًا أساسيًا للخط مقداره 16 بكسل وحجمًا مقداره 32 بكسل لعنصر العنوان الرئيسي h1، فإذا وجدنا ضمن العنصر h1 الوسم span الذي يطبق تنسيق الصنف subheading، فيجب تصيير ما داخل span أيضًا بالنسبة إلى حجم الخط الافتراضي (16 بكسل عادة)، وإليك شيفرة HTML لتوضيح الفكرة: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Font size experiment</title> </head> <body> <h1>This is our main heading <span class="subheading">This is our subheading</span> </h1> </body> </html> أما شيفرة CSS المبنية على النسبة المئوية: /* 100% من حجم الخط الأساسي للمتصفح والذي يكون عادة 16 بكسل */ body { font-size:100%; } /* أي حوالي 32 بكسل body ضعفي حجم المحدد */ h1 { font-size:200%; } /* أي العودة إلى القياس 16 بكسل h1 نصف */ span.subheading { font-size:50%; } سنواجه المشكلة نفسها عند استخدام وحدة القياس Em: /* 1em = 100% من قياس الخط الأساسي الذي يكون عادة 16 بكسل*/ body { font-size:1em; } /*أي حوالي 32 بكسل body ضعفي حجم المحدد */ h1 { font-size:2em; } /* أي العودة إلى القياس 16 بكسل h1 نصف */ span.subheading { font-size:0.5em; } لاحظ كيف ستغدو الحسابات مزعجةً إذا أردت ملاحقة العنصر الأب ثم أب الأب وهكذا، كما تُنفّذ معظم التصاميم على برمجيات تستخدِم البكسل، لذلك من الأفضل أن تجري الحسابات من قِبَل الشخص الذي كتب شيفرة CSS تقاس الوحدة rem بالنسبة إلى حجم العنصر الجذري وليس لأيّ عنصر أب، لذلك يمكن كتابة تنسيق CSS كما يلي: /* 1em = 100% من قياس الخط الأساسي الذي يكون عادة 16 بكسل*/ body { font-size:1em; } /*أي حوالي 32 بكسل body ضعفي حجم المحدد */ h1 { font-size:2rem; } /*الحجم الأصلي*/ span.subheading { font-size:1rem; } يبدو الأمر أسهل، أليس كذلك؟ يعمل هذا التنسيق على إنترنت أكسبلورر 9 وغيره من المتصفحات الحالية، لذلك يعود اختيار وحدة القياس لك بالمطلق. لماذا قد أستخدم وحدات القياس النسبية لأنك لا تعرف متى سيرفض المتصفح تكبير أو تصغير حجم النص الذي يعتمد البيكسل على أساس وحدة قياس، كما أنّ موقعك قد يتلقى زيارات ممن يستخدِمون متصفحات قديمةً، لذلك سنقدِّم لك النصائح التالية: استخدم وحدة القياس rem وستكون النتائج مرضيةً في جميع المتصفحات. دع مهمة عرض الخطوط في المتصفحات القديمة لمحركاتها الداخلية، إذ تتجاهل هذه المحركات أيّ خاصية أو قيمة لتنسيقات CSS لا تتوافق معها، وهكذا ستبقى قادرًا على عرض صفحتك على تلك المتصفحات، وعلى أية حال، ستختفي المتصفحات القديمة مع الوقت حتى لو لم يتفق ذلك مع رؤية المصمم. حجم السطر هنالك جدل طويل قائم حول طول الأسطر في ويب، وإليك القصة كاملةً. لقد أدرك العاملون في مجال الطباعة مع ظهور المجلات المطبوعة أن أعين القراء ستعاني عند الانتقال من سطر لآخر إذا كان السطر طويلًا جدًا، وكان الحل هو ظهور الأعمدة، ولم يتغير الأمر كثيرًا عندما انتقلنا إلى عالم الويب، ولا تزال أعين القراء تلاحق الأسطر، لذلك كان الحل بتحديد حجم السطر ليضم ما بين 60 إلى 70 محرفًا فقط لتسهيل الأمر على القارئ، إذ يمكنك لإنجاز الأمر تحديد حجم العنصر الذي يحتوي على النص، وإليك شيفرة HTML: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Font size experiment</title> </head> <body> <div class="container"> <h1>This is our main heading <span class="subheading">This is our subheading</span> </h1> <p>[lengthy text that spans many lines]</p> </div> </body> </html> لدينا عنصر div له صنف التنسيق container، إذ يمكننا تنسيق div بضبط عرضه باستخدام الخاصية width أو من خلال ضبط عرضه الأعظمي لكي لا يزداد كثيرًا باستخدام الخاصية max-width، فإذا أردت موقعًا مرنًا أو متجاوبًا ولم تكن تعرف العرض الافتراضي الذي يأخذه المتصفح، فيمكنك استخدام الخاصية max-width لكي تضبط عدد المحارف في السطر بحدود 70 محرفًا لا أكثر: div.container { max-width:70em; } النصوص البديلة عن الصور والمقاطع الصوتية ومقاطع الفيديو تضم مواقع الويب أشياء أخرى غير النصوص، ولا بد من الانتباه إليها: الصور قد تكون الصور لمجرد العرض وتدعى بالصور الاستعراضية أو قد تحتوي على معلومات، لكن لا ضمانة بأن يراها المستخدِم لأسباب منها: استخدام ذوي الإعاقة البصرية قارئات الشاشة التي تتعامل مع النصوص فقط. استخدام شبكات إنترانت محلية تفرض قيودًا على عرض الصور من مصادر خارجية أو شبكات توريد محتوى CDN. تعطيل المستخدِم عرض الصور لتوفير حزمة البيانات المتاحة وخاصةً عند استخدام الهواتف الجوالة. أما الصور الاستعراضية Decorative، فتُستخدَم لتزيين الصفحات ولا توصل أية معلومات حقيقة، كما يمكن استبدالها في معظم الحالات بصورة خلفية، وتأكد من وضع نص فارغ على أساس قيمة للسمة alt في عنصر الصورة كي لا يتجاهل المتصفح عرض النص البديل. <img src="deco.gif" alt=""> وأما الصور التي تحتوي على معلومات Informative، فتُستخدَم لإيصال معلومات محددة، مثل عرض رسم بياني أو وجه أحد ما أو أية معلومات أخرى، إذ عليك أن تقدِّم على الأقل نصًا بديلًا في هذه الحالة (السمة alt)، فإذا أمكن وصف الصورة جيدًا، فيكفي استخدام النص البديل، وإلا عليك تقديم محتوى الصورة تقديمًا آخرًا في الصفحة نفسها مثل أن تعرض بالإضافة إلى الرسم البياني جدولًا يضم المعلومات نفسها، أو الجأ إلى السمة longdesc التي تحمل عنوان URL يشير إلى مصدر يشرح صراحةً محتوى الصورة. الصوت والصورة لابد أن تقدِّم بديًلا عن الوسائط السمعية والبصرية أيضًا. ترجمة الفيديو أو عرض كلماته: لا بد من إضافة كلمات الفيديو لمساعدة الزوار ذوي الإعاقة السمعية أو الذين لا يمتلكون مكبرات صوتية أو من يعمل في بيئات صاخبة. تقديم نص الفيديو أو الملف الصوتي كاملًا: سيكون عرض الكلمات أثناء تشغيل الفيديو ممتازًا لمن لديه الوقت لمتابعته، لكن قد لا يتمكن العديد من الزوار من ذلك، بالإضافة إلى اعتماد محركات البحث على النصوص لفهرسة المحتوى، لذلك من الأجدى تقديم نصوص كاملة توضِّح ما يقال في الفيديو أو في المقطع الصوتي. ضغط الصور عندما يرغب الزائر في عرض الصور على المتصفح لكنه يعاني من محدودية في حزمة تراسل البيانات وخاصةً في البلدان النامية وعلى أجهزة الهاتف المحمول، لذلك اضغط الصور على موقعك إذا كنت تريده ناجحًا، وستجد العديد من الأدوات التي تساعدك في ذلك: برمجيات تُثبَّت على جهازك: ستجد ImageOptim على ماك، وستجد PNGcrush على دوس ولينوكس ويونكس، بينما يعمل OptiPNG على كل المنصَّات. أدوات على الإنترنت: مثل smushit! من ياهو Yahoo و Online Image Optimizer من Dynamic Drive، إذ يحوِّل هذا الأخير الصور تلقائيًا من تنسيق إلى آخر إذا كان أكثر فعاليةً فيما يخص تخفيض استهلاك حزمة تراسل البيانات. نظرة إلى ميزات HTML التي تدعم سهول الوصول هنالك مجموعة من الميزات الخاصة في HTML قد تسهل وصول الأشخاص ذوي الإعاقة إلى محتوى صفحة ويب، وسنستعرض بعضها في هذه الفقرة. التنقل عبر المفتاح TAB يمكن للزائرين الذين لا يمتلكون أجهزة تأشير مثل الفأرة، أو لا يستطيعون استخدامها التنقل عبر الروابط من خلال استخدام المفتاح TAB، إذ ينبغي أن تكون الروابط مرتبةً بطريقة منطقية لاستخدام هذه الميزة، لذلك تقدِّم HTML السمة tabindex التي تحدِّد الترتيب، فإذا كانت شيفرة HTML المكتوبة خطيةً ومتتابعةً كما ينبغي، فستظهر الروابط وفق الترتيب المنطقي تلقائيًا. <ul> <li><a href="here.html" tabindex="1">Here</a></li> <li><a href="there.html" tabindex="3">There</a></li> <li><a href="anywhere.html" tabindex="2">Anywhere</a></li> </ul> تعرض الشيفرة السابقة التي قدمناها لمجرد توضيح الفكرة ترتيب استخدام TAB من "Here" إلى "Anywhere" إلى "There". عناوين الروابط إذا لم يشرح الرابط نفسه بنفسه، أو كان من الأفضل شرح وجهة الرابط بتفاصيل أكثر، فيمكنك إضافة معلومات عن الرابط باستخدام السمة title. <p>I'm really bad at writing link text. <a href="inept.html" title="Why I'm rubbish at writing link text: An explanation and an apology.">Click here</a> to find out more.</p> مفاتيح الوصول تزوِّد مفاتيح الوصول Access keys المستخدِم بطريقة سهلة للتنقل بتعيين اختصار إلى الرابط عبر لوحة المفاتيح، إذ يتلقى الرابط التركيز عندما يضغط المستخدِم Ctrl أو Alt مع مفتاح الوصول، وتختلف مجموعة الأزرار التي تُضغَط معًا من نظام لآخر. <a href="somepage.html" accesskey="s">Some page</a> روابط التجاوز تعمل روابط التجاوز Skip Links على أساس رديف للتنقل عبر المفتاح TAB، إذ تسمح بالقفز إلى جزء محدَّد من الصفحة، فقد يرغب أحد الزوار بتجاوز الكثير من الروابط إلى المحتوى الرئيسي بدلًا من التنقل من رابط لآخر حتى الوصول إلى المطلوب. <header> <h1>The Heading</h1> <a href="#content">Skip to content</a> </header> <nav> <!-- navigation stuff --> </nav> <section id="content"> <!--your content --> </section> ترجمة -وبتصرف- للمقال ?What is accessibility، والمقال ?How can we design for all types of users، والمقال ?What HTML features promote accessibility. اقرأ أيضا الفرق بين إمكانية الوصول والشمولية في تصميم تجربة المستخدم سهولة وصول جميع الزوار لمواقع وتطبيقات الويب التحقق من سهولة الوصول لصفحات الويب المبادئ الخمسة الأساسية في قابلية الاستخدام إعداد صور متجاوبة في صفحات الويب
-
انصب تركيزنا في هذا القسم على بناء منظومة تكامل مستمر CI بسيطة وفعالة ومحكمة، تساعد المطورين على العمل معًا والحفاظ على جودة الشيفرة ومن ثم نشرها بأمان. ما الذي يمكننا فعله أكثر؟ لنتذكر أنه في العالم الحقيقي ستمتد أيادٍ إلى الكعكة غير أياد المطورين والمستخدمين. حتى وإن لم يكن ذلك صحيحًا، وخاصة بالنسبة للمطورين، إلا أنّ هناك الكثير الذي تقدمه منظومة CI غير ما اطلعنا عليه. مجال الرؤية والفهم في جميع الشركات ما عدا الصغيرة منها، لا تُتخذ القرارات حول تطوير المنتجات حصرًا من طرف المطورين. يشير مصطلح أصحاب الشأن "stakeholder" إلى الأشخاص داخل وخارج فريق التطوير، الذين لديهم مصلحة في مراقبة تقدم عملية التطوير.عند هذا المستوى، هناك غالبًا تكاملٌ بين git وأي برنامج لإدارة المشاريع أو تتبع الثغرات قد يستخدمه الفريق. يُعد امتلاك مرجع إلى نظام التتبع في طلبات السحب أو في الشيفرة المعتمدة أكثر الطرق شيوعًا لتنفيذ ذلك. وهكذا، عندما تعمل على النقطة رقم 123 مثلًا، بإمكانك عندها تسمية طلب السحب الخاص بك BUG-123: Fix user copy issue، وسيلاحظ نظام تتبع الثغرات عندها الجزء الأول من اسم طلب السحب، وسينقل النقطة إلى قائمة النقاط المنفَّذة Done عندما يُدمج الطلب. تنبيهات عندما تنتهي عملية CI بسرعة، فمن المناسب أن نراقب العملية فقط وننتظر النتائج، لكن مع ازدياد حجم المشاريع ستزداد أيضًا فترة تنفيذ عمليات بناء واختبار الشيفرة. سيقودنا ذلك إلى الحالة التي تستغرق فيها ظهور نتائج بناء الشيفرة وقتًا طويلًا، مما يدفع المطور للتفكير في العمل على مهمة أخرى، وهذا سيقود بدوره إلى نسيان عملية البناء. ستظهر المشكلة في طرحنا هذا خاصة عندما نتحدث عن دمج طلبات السحب التي قد تؤثر على عمل مطور آخر، إما بالتسبب بمشاكل في عمله أو تأخير هذا العمل. وقد يقودنا ذلك أيضًا إلى الحالة التي تعتقد فيها أنك نشرت شيئًا، لكنك في الواقع لم تنهي عملية النشر، وسيؤدي ذلك إلى سوء التواصل مع أعضاء فريقك أو مع الزبائن (كأن تقول: "جرب من جديد، لا بدّ أنّ المشكلة قد حُلَّت"). هناك عدة أساليب لحل هذه المشكلة، تتدرج من إنشاء تنبيهات بسيطة إلى عمليات أكثر تعقيدًا تدمج ببساطة الشيفرة التي تمرر إليها إن تحققت جملةٌ من الشروط الموضوعة مسبقًا. سنناقش حاليًا التنبيهات مثل حل بسيط، كونها الوحيدة التي تتعلق بسير مخطط عمل الفريق. يرسل غيت هب افتراضيًا بريدًا إلكترونيًا عند إخفاق البناء. يمكن تغيير ذلك لإرسال تنبيهات بغض النظر عن حالة البناء، كما يمكن تهيئته لإنذارك على واجهة ويب غيت هب GitHub. طبعًا هذا الأمر رائع، لكن ماذا لو أردنا أكثر من ذلك؟ ماذا لو لم يعمل هذا الحل لسببٍ ما مع حالتنا؟ يمكن أن يتكامل غيت هب GitHub مع عدة تطبيقات رسائل مثل Slack لإرسال التنبيهات، وستكون هذه التطبيقات قادرةً على تحديد متى ترسل هذه التنبيهات بناءً على منطق يفرضه غيت هب GitHub. التمرين 11.18 أعددنا قناة fullstack_webhookعلى مجموعة Discord على العنوان "https://study.cs.helsinki.fi/discord/join/fullstack" لاختبار تكامل منظومة الرسائل. ستحتاج طبعًا إلى بريد إلكتروني للتسجيل، وانتبه إلى ضرورة استخدام عنوان خطاف الويب webhook الخاص بالتطبيق Discord لتنفيذ هذا التمرين. ستجد هذا الخطاف في الرسالة المنبثقة القناة "fullstack_webhook". ويُستحسن عدم الالتزام بالخطاف على غيت هب GitHub. أفعال لتنبيه المستخدم إلى نجاح أو فشل البناء ستجد العشرات من أفعال GitHub Actions التي طورها مطورون مستقلون على GitHub Action Marketplace بمجرد أن تبحث عن العبارة discord. اختر واحدًا لتستخدمه في هذا التمرين. وقد اخترنا discord-webhook-notify لأنه حصل على تقييم مرتفع وله توثيق جيد. هيئ الفعل بحيث يعطي نوعين من التنبيهات: مؤشر على النجاح إن نُشرت النسخة. مؤشر على الفشل إن أخفق البناء. في حال وقوع خطأ، لا بدّ أن تكون رسالة الخطأ مسهبة لمساعدة المطور على إيجاد الخطأ بسرعة وإيجاد الشيفرة المعتمدة التي سببت هذا الخطأ. ابحث في توثيق GitHub عن كيفية التحقق من حالة المهمة. يمكن أن تبدو التنبيهات على النحو التالي: المقاييس Metrics لقد أشرنا في الفقرة السابقة أنه عندما ينمو المشروع ستزداد مدة إنجاز خطوات البناء والاختبار، وهذا ليس بالأمر المثالي، فكلما طالت حلقة وصول النتائج ستصبح دورة التطوير بطيئة. وعلى الرغم من إمكانية القيام بأشياء لتقليل الوقت اللازم للبناء، من المفيد أيضًا أن ننظر جيدًا إلى الصورة الكلية للوضع. فمن الجيد أن نعرف كم استغرقت عملية البناء قبل أشهر عدة موازنةً مع ما تستغرقه الآن. هل يسلك الاختلاف منحًى خطيًا أم يظهر على هيئة قفزات فجائية؟ كما أنّ معرفة السبب الكامن خلف زيادة زمن البناء سيساعدنا جدًا في حل المشكلة؛ فإذا زاد زمن التنفيذ على نحوٍ خطي من 5 إلى 10 دقائق خلال سنة، فيمكننا أن نتوقع بأنه سيزداد أيضًا بضع دقائق خلال عدة أشهر قادمة ليصل إلى 15 دقيقة، وستكون لدينا فكرةً عن قيمة ما ننفقه من وقت لتسريع عمل منظومة CI. يمكن أن تكون المقاييس ذاتية- التسجيل self-reported وتدعى أيضًا مقاييس "دفع-Push"، إذ تسجل كل عملية بناء الوقت الذي تستغرقه، أو أن نحضر البيانات من واجهة برمجية بعد انتهاء العملية وتدعى أحيانًا مقاييس "سحب-Pull". يتمثل خطر التسجيل الذاتي في الوقت الذي ستستغرقه عملية التسجيل بحد ذاتها، والتي قد يكون لها أثر على الوقت الكلي المستغرق للبناء. يمكن أن تُرسل هذه البيانات إلى قاعدة بيانات تعمل وفق سلاسل زمنية time-series DB، أو إلى سِجِل من نوع آخر. هناك عدة خدمات سحابية لتجميع قياساتك بكل سهولة، ومن الخيارات الجيدة الخدمة Datadog. المهام الدورية هناك بعض المهام الدورية التي يجب تنفيذها ضمن فرق تطوير البرمجيات، إذ يمكن أتمتة بعضها من خلال بعض الأدوات المتوفرة، وعليك أتمتة بعضها الآخر. تتضمن الفئة الأولى من المهام الدورية التحقق من الحزم لتفادي الاختراقات الأمنية، وقد تساعدك في ذلك العديد من الأدوات الجاهزة. سيكون بعض هذه الأدوات مجانيًا لمشاريع محددة (مفتوحة المصدر مثلًا) مثل الأداة Dependabot التي يقدمها GitHub. وإليك النصيحة التالية: من الأفضل دائمًا استخدام أدوات جاهزة لأداء هذه المهام، إن سمحت بذلك ميزانيتك، بدلًا من الاعتماد على حلولك الخاصة، فإن لم تكن مهتمًا بتطوير أدوات تتعلق بأمور الأمن مثلًا، استخدم Dependabot للتحقق من الثغرات الأمنية بدلًا من تطوير الأداة بنفسك. لكن ماذا عن المهام التي لا تتوفر لها أدوات مساعدة؟ يمكنك أتمتة هذه المهام بنفسك عن طريق GitHub Actions أيضًا، إذ يزودك GitHub Actions بمُطلِقات أحداث المجدولة scheduled trigger التي يمكن استخدامها لتنفيذ مهمة محددة في وقت محدد. التمارين 11.19 -11.21 11.19: التحقق الدوري من سلامة البرمجيات لدينا الثقة الآن بأنّ خط الإنتاج الذي عملنا عليه سيمنع نشر الشيفرة المخفقة، لكن مع ذلك هناك مصادر عديدة للأخطاء؛ فعندما يعتمد تطبيقنا مثلًا على قاعدة بيانات قد لا تكون متوفرة دائمًا، سيتوقف التطبيق عن العمل في لحظةٍ ما. لهذا من المفيد جدًا التحقق دوريًا من سلامة عمل التطبيق عن طريق إرسال طلب HTTP-GET إلى الخادم. ندعو هذه العملية عادة بعملية التحقق من الاتصال "ping". من الممكن أن نجدول أفعال GitHub لتُحدّث دوريًا وبصورة منتظمة. استخدم الفعل url-health-check أو أي بديل له وجدول عملية التحقق من الخادم الذي تنشر عليه التطبيق. حاول محاكاة الحالة التي يخفق فيها تطبيقك، تأكد حينها أن عملية التحقق ستكتشف الخطأ. اكتب مخطط العمل الدوري الذي أوجدته على ملف خاص. تنبيه: سيستغرق GitHub Actions وقتًا طويلًا حتى يبدأ بتنفيذ مخطط العمل الذي جدولته للمرة الأولى، فقد تطلب منا الأمر قرابة الساعة، لذلك تُعد فكرة إطلاق مخطط العمل مباشرةً بتنفيذ عملية دفع للشيفرة إلى الاستضافة فكرةً جيدة. انتقل بعد ذلك لتنفيذ المخطط المجدول بعد أن تنجح معك هذه الحيلة. تنبيه: عندما تنجح في تنفيذ ما طلبناه، من الأفضل أن تقلل مرات التحقق من الاتصال مع الخادم إلى مرة كل 24 ساعة أو عطل القاعدة، وإلا ستكلفك عملية التحقق المستمرة ساعاتك المجانية المتاحة خلال الشهر. 11.20: خط إنتاج خاص بك ابنِ خط إنتاج CI/CD لبعض التطبيقات التي أنجزتها سابقًا. من التطبيقات المرشحة للعمل عليها تطبيق دليل الهاتف الذي طورناه في القسمين 2 و3 من المنهاج، أو تطبيق المدونة الذي طورناه في القسم 4 والقسم 5، أو تطبيق الطرائف الذي بنيناه بالاستعانة بالمكتبة Redux في القسم 6. ستضطر غالبًا إلى إعادة هيكلية التطبيق لتجمع قطع الشيفرة المتفرقة، وعليك في الخطوة الأولى وضع الواجهتين الأمامية والخلفية في مستودع واحد. لست مجبرًا على ذلك طبعًا، لكنه سيسهل عليك الأمر كثيرًا. إحدى الهيكليات المقترحة هي وضع الواجهة الخلفية في جذر المستودع وأن تضع الواجهة الخلفية ضمن مجلد فرعي، ويمكنك أيضًا نسخ ولصق بنية التطبيق النموذجي الذي نفذناه في هذا القسم، أو أن تحاول الاستفادة من التطبيق النموذجي الذي اطلعنا عليه في القسم 7. ربما من الأفضل أن تنشئ مستودعًا جديدًا لهذا التمرين، ومن ثم تنسخ وتلصق الشيفرة ضمنه. قد تضطر غالبًا في العمل الواقعي إلى تنفيذ ذلك ضمن المستودع القديم، لكن الإنطلاقة الجديدة الآن ستسهل علينا الأمر. سيستغرق منك هذا التمرين وقتًا وجهدًا، لكن الحالة التي تواجهها هنا، وهي بناء خط إنتاج لنشر شيفرة قديمة، شائعة جدًا في الحياة العملية. لن يُنفّذ هذا التمرين في نفس المستودع الذي نفذت فيه التمارين السابقة، لأنك لا تستطيع أن تعيد سوى مستودع واحد إلى منظومة تسليم التمارين، ضع رابطًا إذًا للمستودع الآخر ضمن المستودع الذي أشرت إليه في نموذج التسليم. 11.21: حماية الفرع الرئيسي وتقديم طلب سحب احمِ الفرع الرئيسي للمستودع الذي أنجزت فيه التمرين السابق، وامنع المدراء أيضًا هذه المرة من دمج الشيفرة مع الفرع الرئيسي دون مراجعتها. قدم طلب سحب، واطلب من أحد مستخدمي GitHub التالية أسماؤهم mluukkai و/ أو kaltsoon أن يراجع شيفرتك، وبعد أن تنتهي المراجعة، ادمج الشيفرة مع الفرع الرئيسي، وانتبه إلى أن يكون المراجع من المتعاونين معك في المستودع. اتصل بنا على Discord لكي نراجع شيفرتك، ومن الأفضل إرسال رسالة خاصة تتضمن رابط دعوة. بعدها يكون العمل قد أُنجز. ترجمة -وبتصرف- للفصل Expanding further من سلسلة Deep Dive Into Modern Web Development اقرأ أيضًا المقال التالي: مدخل إلى الحاويات المقال السابق: نشر إصدارات التطبيق بأمان في منظومة التكامل والتسليم المستمر نشر التطبيقات وتوزيعها وفق نهج التسليم المستمر إعداد التكامل المستمر والنشر المستمر باستخدام الخدمتين CircleCI وCoveralls
-
من الجيد الاطلاع على التخطيطات layouts الأكثر استخدامًا لصفحات الويب قبل البدء بتصميمها، وهناك سبب يدفعنا في الواقع للخوض في تصميم الصفحات، إذ ستبدأ العمل عادةً انطلاقًا من صفحة فارغة، ومن ثم يأخذك العمل إلى نواحٍ عدة، فإذا لم تمتلك بعض الخبرة، فستشعر بالقلق عندما تبدأ من نقطة الصفر، ولهذا السبب سنرشدك في هذا المقال إلى قواعد عامة وجوهرية تساعدك في تصميم موقعك بناءً على خبرة طويلة تمتد 25 عامًا. حتى وإن كان التركيز حاليًا على تصميم المواقع المخصصة للهواتف الذكية، لكن المكوّنات الأساسية لبناء صفحات الويب بقيت كما يلي: الترويسة Header: وهي الجزء الذي يظهر أعلى الصفحة ويحتوي على معلومات مكررة في كل الصفحات مثل اسم الموقع وشعاره بالإضافة إلى منظومة سهلة الاستخدام لأغراض التنقل بين الصفحات. المحتوى الرئيسي Main Content: وهي المنطقة الأوسع من الصفحة، وتحتوي على المعلومات الخاصة التي ينبغي عرضها في هذه الصفحة تحديدًا. إضافات ولوحات على الجوانب Stuff on the side: وتضم أيّ شيء لا يجب أن يتواجد في القسم الرئيسي، أي ما يلي: معلومات مشتركة بين مجموعة فرعية من الصفحات. معلومات مكملة لما ورد في المحتوى الرئيسي. منظومة تنقل بديلة. التذييل Footer: يُشاهَد في أسفل الصفحة ويتضمن كما الترويسة معلومات عامة تتعلق بالموقع لكنها أقل أهمية. تشترك الكثير من الصفحات بهذه الأقسام، لكن قد تختلف بطريقة توضعها، وإليك بعض الأمثلة، إذ يمثل 1 الترويسة، ويمثل 2 التذييل، في حين يمثل A المحتوى الرئيسي؛ أما B1 و B2 فهما بعض الأقسام على جانبي الصفحة: تخطيط أحادي العمود: وهو تخطيط مفيد جدًا لمتصفحات الهواتف الجوّالة لتجنب الفوضى في الشاشات الصغيرة. تخطيط ثنائي الأعمدة: ويستهدف عادةً الأجهزة اللوحية لأن شاشاتها أكثر عرضًا من الهواتف الجوالة. تخطيط ثلاثي الأعمدة: ويناسب متصفحات الحواسب المكتبية التي تتميز بشاشات كبيرة على الرغم من أنّ عرض المحتوى ضمن شاشات أصغر هو ما يفضله العديد من مستخدمي الحواسب المكتبية. لكن المتعة الحقيقية ستبدأ عندما تمزج بين التخطيطات الثلاث السابقة في الصفحة نفسها، ويبقى ما عرضناه مجرد أمثلة قد تأخذ بها أو لا. قد تلاحظ كيف يمكن أن يتغير موقع المحتوى الرئيسي في الصفحة إلا أنّ الترويسة (1) تبقى في الأعلى، كما يبقى التذييل (2) في الأسفل، وطالما أنّ المحتوى الرئيسي (A) هو الأكثر أهميةً، فامنحه المساحة الأكبر من الصفحة. إذًا سنعرف في مقالنا على أقسام صفحة الويب والمكان الأفضل لوضعها، وننصحك قبل إكمال قراءة المقال أن تعرف تمامًا ما تريد إنجازه عندما تفكر في تصميم موقع ويب، وسنناقش في مقالات أخرى التصميم المتجاوب للمواقع أي المواقع التي تتغير تخطيطات صفحاتها بناءً على حجم الشاشة. تخطيط أحادي العمود يقدم التخطيط وحيد العمود جميع محتويات الصفحة تقديمًا متتابعًا ومباشرًا، وتذكَّر أنّ الكثير من متابعيك يستعرضون موقعك من خلال الحواسب المكتبية، فاحرص أن يكون المحتوى مقروءًا وسهل الاستعمال على تلك الأجهزة أيضًا. تخطيط ثنائي الأعمدة تُصمَّم المدونات عادةً وفق تخطيط العمودين، إذ يُستخدَم العمود العريض لنشر المحتوى الرئيسي والآخر الضيق لعرض بقية الأشياء مثل بعض المكوّنات الخاصة وأدوات التنقل الإضافية والروابط الإعلانية. انظر إلى الصورة (B1) في الشكل السابق تحت الترويسة مباشرةً، إذ تتعلق هذه الصورة بالمحتوى الرئيسي، لكن المحتوى يبدو معقولًا أكثر دونها، لذلك بالإمكان أن تعدها جزءًا من المحتوى الرئيسي أو من المحتوى الجانبي، وليس الأمر بهذه الأهمية، لأن ما يهم فعلًا هو وضع المحتوى الرئيسي فقط أو ما يتعلق به مباشرةً تحت الترويسة. حالة قد تخدعك إليك هذه الصفحة من موقع MICA التي تبدو وكأنها تستخدِم ثلاثة أعمدة لكنها ليست كذلك: تعوم Float اللوحتين B1 و B2 حول المحتوى الرئيسي، وتذكر المصطلح "يعوم" عندما تبدأ بتعلم التنسيقات المورثة CSS. لِمَ قد نظن أنّ الصفحة منسقة في ثلاثة أعمدة؟ لأن الصورة في أعلى يمين الصفحة لها شكل الحرف "L" ولأن القسم B1 يبدو وكأنه عمود يدعم المحتوى الرئيسي المنزاح، ولأن حرفي "M" و"I" للشعار "MICA" يُشكِّلان خطان عموديان يعطيان انطباعًا قويًا بوجود ثلاث أعمدة، وهذا مثال جيد عن تخطيط كلاسيكي لصفحة ويب مع لمسة إبداعية، فالتخطيط البسيط أسهل تنفيذًا، لكن امنح نفسك مع ذلك فرصةً للاستكشاف والتعبير عن إبداعاتك في هذا المجال. حالة أخرى ستخدعك أكثر تعتمد هذه الصفحة من موقع The Opera de Paris على تخطيط العمودين، لكنك ستلاحظ العديد من الحيل هنا وهناك قد تشوش نظرتك إلى تخطيطها، فالترويسة تحديدًا تتداخل مع صورة المحتوى الرئيسي، وطريقة انحناء قائمة الترويسة التي تتماشى مع الانحناء أسفل الصورة تجعلنا نتوقع أنهما شيء واحد علمًا أنهما تقنيًا مختلفان تمامًا، كما تبدو الصورة السابقة المأخوذة لموقع "Opera" أكثر تعقيدًا من الصورة التي تسبقها من موقع "MICA"، لكنها أسهل تنفيذًا مع الانتباه إلى نسبية الكلمة "سهل". وهكذا نرى إمكانية إبداع مواقع ويب رائعة بتخطيطات بسيطة، وألق نظرةً إذًا على مواقع الويب التي تفضِّلها ثم اسأل نفسك أين الترويسة؟ أين المحتوى الرئيسي والجانبي والتذييل؟ سيلهمك ذلك إلى تصاميم خاصة بك ويمنحك تلميحات عما يفيدك في عملك وعما لا يفيد. ترجمة -وبتصرف- للمقال ?What do common web layouts contain. اقرأ أيضًا المقال السابق: البدء بتصميم موقع ويب التحكم في تخطيط الصفحة وضبط محاذاة العناصر في CSS
-
يغطي هذا المقال الخطوة الأولى والأهم للانطلاق في أيّ مشروع، وهي تحديد ما نريده من مشروعنا وخصوصًا مواقع الويب، إذ يركِّز الكثيرون في هذا المضمار على الجانب التقني من المشروع، لكن ما يهم فعلًا -وعلى الرغم من أهمية التقنية التي يستخدِمها المرء في حرفته- هي الغاية التي ينشد الوصول إليها، فالكثير من المشاريع التي أخفقت لم يكن سبب إخفاقها هو الناحية التقنية أو المعرفية، وإنما ضبابية أهدافها ورؤيتها، لهذا السبب، عندما تخطر في بالك فكرةً وتريد نقلها لتصبح موقع ويب، لا بد لك من الإجابة على بعض الأسئلة قبل أيّ شيء آخر: ما الذي أريد إنجازه بدقة؟ كيف سيساعدني موقع الويب في الوصول إلى أهدافي؟ ما الذي يتوجب علي فعله وبأي ترتيب للوصول إلى أهدافي؟ تُدعى هذه الخطوات فكرة المشروع أو التصور الأولي للمشروع project ideation، وهي ضرورية للوصول إلى هدفك سواءً كنت مبتدئًا أم مطوّرًا محترفًا. لا يبدأ المشروع عادةً بالالتفات إلى نواحيه التقنية، فلا يؤلف الموسيقيون مقطوعاتهم حتى يتكون لديهم تصوّر أولي لما يرغبون في عزفه، ولا الرسامون ولا الكتَّاب ولا مطورو مواقع الويب، إذ تأتي التقنية ثانيًا، كما لا ينفي ذلك اطلاقًا الدور الحيوي للتقنية، فلا بد أن يتقن الموسيقيون العزف على الآلات، لكنهم لا يقدِّمون أعمالًا دون تصوّر لما سيقدِّمونه، لهذا عليك التروِّي والعودة إلى التفاصيل لتقرِّر ما تريده قبل القفز إلى كتابة الشيفرة واستخدام أدوات البناء. سيساعدك الجلوس ومناقشة أفكارك مع أصدقائك، لكن لا تتوقع فائدةً كبيرةً، إذ عليك الجلوس وتنظيم أفكارك لتصل إلى رؤية واضحة للطريق الذي ستمشيه لتحويل أفكارك إلى واقع، فجُلّ ما تحتاجه في هذه المرحلة قلم وورقة وبعض الوقت للإجابة على الأسئلة التي سنطرحها تباعًا في مقالنا. ما الذي أريد إنجازه بالتحديد؟ يبدو أنّ هذا السؤال هو الأهم لأنه يقود كل شيء آخر، لذا ضع قائمةً بكل الأهداف التي تريد تحقيقها مثل بيع البضائع لكسب المال أو التعبير عن آراء سياسية أو التعرف على أصدقاء جدد، أو أيّ شيء تريده. افترض أنك موسيقي وقد ترغب بأن: يستمع الناس إلى موسيقاك. تبيع بعض المنتجات. تتعرف على موسيقيين آخرين. تناقش الآخرين بموسيقاك. تعلم الموسيقى من خلال الفيديوهات. تنشر صورًا لقططك. تتعرف على أصدقاء جدد. عندما تنتهي من وضع قائمة الأهداف، فلا بدّ من ترتيبها حسب الأولوية التي تراها من الأكثر إلى الأقل أهمية والتي قد تكون بالصورة التالية: التعرف على أصدقاء جدد. استماع الناس إلى موسيقاك. مناقشة الآخرين بموسيقاك. التعرف على موسيقيين جدد. بيع بعض المنتجات. تعليم الموسيقى من خلال الفيديوهات. نشر صور لقططك. سيساعدك التمرّن على كتابة أهدافك بهذه الصورة على اتخاذ القرارات (هل عليّ تنفيذ هذه الميزات أو استخدام هذه الخدمات أو اعتماد تصاميم معينة)، وبعد ترتيبنا لقائمة الأهداف، فلننتقل إلى السؤال الثاني. كيف سيقربني موقع الويب من أهدافي؟ وضعتَ قائمةً بأهداف وترى أنك بحاجة إلى موقع ويب لتحقيق هذه القائمة، ولنعد قليلًا إلى عناصر القائمة، سنجد أنها تضم خمسة أهداف تتعلق بالموسيقى، وهدف يتعلق بالعلاقات الشخصية، وأخيرًا هدف ليس له علاقة إطلاقًا بالموسيقى وإنما بصور القطط، فهل من المنطقي بناء موقع ويب يحقق كل هذه الأهداف؟ هل الأمر ضروري؟ فقد تجد أن خدمات الويب الموجودة قد تحقق أهدافك دون عناء بناء موقع ويب جديد، فالتعرف على أصدقاء جدد مثلًا هي حالة واضحة للاستفادة من تلك الخدمات، إذ ستمُضي وقتك في تصميم وبناء وصيانة موقع بدلًا من البحث جديًا على أصدقاء جدد. طالما أنّ أهم ما في الأمر هو الوصول إلى أهدافنا، فمن الأفضل استغلال إمكانياتنا في تجريب الأدوات الموجودة بدلًا من البدء من الصفر، وكذلك الأمر بالنسبة إلى نشر الصور، إذ توجد فعلًا خدمات كثيرة لهذه الغاية، ولا مبرر أبدًا لإهدار الوقت في بناء موقع ويب لنشر صور القطط، كما ترتبط الأهداف الخمسة الأخرى بالموسيقى، وستجد الكثير من خدمات الويب التي تغطي هذه الأهداف، لكن من المنطقي في هذه الحالة التفكير في بناء موقع ويب خاص بك لهذه الغايات، فقد يساعدك موقع الويب في تجميع كل الأشياء التي تحتاجها في مكان واحد (وهذا أمر مفيد في تحقيق الأهداف 3 و5 و6) ويعزز العلاقات بينك وبين العامة (تكمن فائدته في تحقيق الهدفين 2 و4). باختصار، وطالما أن الأهداف تحوم حول الموضوع نفسه، فقد يساعدنا تجميع كل شيء في المكان نفسه على تحقيق أهدافنا، كما يساعد متابعينا في التواصل معنا، وبالتالي ستجد الطريق الأفضل لبلوغ أهدافك دون أن تبدد جهودك سدًى عند الإجابة على السؤال "كيف يساعدني موقع الويب في الوصول إلى أهدافي؟". ما الذي يتوجب علي فعله وبأي ترتيب للوصول إلى أهدافي؟ الآن وقد حددت أهدافك، فقد حان الوقت لتحويل هذه الأهداف إلى خطوات قابلة للإنجاز، وعليك التذكُّر دائمًا بأنّ الأهداف تتطور مع الوقت حتى عند تنفيذ المشروع وليست جامدةً، وخاصةً عندما تصادف عقبات غير متوقعة أو عندما ستغير رأيك بمسألة ما. لنعد إلى مثالنا السابق بدلًا من الإسهاب في التفسيرات ولنوضح الأمر: ليستمع الناس إلى موسيقاك عليك ما يلي: تسجيل بعض الألحان. تحضير بعض الملفات الصوتية التي يمكن استخدامها على الويب (هل يمكن الاستفادة من خدمة موجودة؟). امنح الآخرين إمكانية الوصول إلى موسيقاك في بعض أقسام موقعك. لمناقشة الآخرين بموسيقاك عليك ما يلي: كتابة بعض المقالات لبدء الحوار. حدِّد الطريقة التي ستظهر عليها مقالاتك. انشر هذه المقالات على الويب. للتعرف على موسيقيين جدد عليك ما يلي: زوّد متابعيك بقنوات للتواصل معك (بريد إلكتروني، فيس بوك، هاتف، بريد). حدد الطريقة التي سيصل فيها الآخرون إلى قنوات الاتصال التي توفرها عبر موقعك. لبيع بعض المنتجات عليك ما يلي: حضِّر منتجاتك وخزّنها. جِد طريقةً مناسبةً لشحنها. جِد طريقةً مناسبةً للدفع. جِد آليةً مناسبةً على موقعك تسهِّل على الناس طلب منتجاتك. لتعليم الموسيقى من خلال الفيديوهات عليك ما يلي: سجِّل مقاطع فيديو لدروسك. اجعل فيديوهاتك مناسبةً للاستعراض عبر الويب (مجددًا، هل يمكن الاستفادة من خدمة موجودة؟). امنح الآخرين إمكانية الوصول إلى فيديوهاتك في بعض أقسام موقعك. تجدر الإشارة هنا إلى نقطتين: الأولى: وهي أنّ بعض الأعمال لا تتعلق بالويب مثل تسجيل الموسيقى وكتابة المقالات، ولهذه النشاطات التي تجري دون اتصال بالإنترنت أهمية كبيرة قد تفوق الجانب المرتبط بالويب في مشروعك، فعندما تهتم ببيع منتجات على سبيل المثال، فمن الأجدى والأوفر من ناحية الوقت إيجاد حلول لتأمين المنتجات وطريقة للدفع والشحن قبل الشروع في بناء الموقع الذي سيستخدِمه الآخرون في طلب تلك المنتجات. الثانية: تحضير خطوات قابلة للتنفيذ سيقودك غالبًا إلى أسئلة جديدة عليك البحث عن إجابة لها. إذ ستجد عادةً مزيدًا من الأسئلة أكثر مما قد تتوقع مثل هل عليَّ تعلّم كل هذه الأمور بنفسي؟ هل أطلب من شخص آخر ذلك؟ هل استخدم خدمات تؤمنها أطراف أخرى؟ الخلاصة كما رأينا، قد تقودك فكرة بسيطة مثل "أريد بناء موقع ويب" إلى قائمة طويلة من الخطوات التي ينبغي تنفيذها والتي تنمو أكثر كلما فكرت بتفاصيلها أكثر، وقد يطغى الأمر على تفكيرك بسرعة، فلا حاجة للإجابة على كل الأسئلة، ولن تضطر إلى تنفيذ كل ما وضعته على قائمتك، فالأهم هنا أن يكون لديك تصوّر عما تريد وكيف ستصل إلى مبتغاك، وحالما تتوضَّح الرؤية، عليك أن تقرِّر متى وكيف تبدأ، وجزِّء المهام الضخمة إلى خطوات أصغر قابلة للتنفيذ بحيث تصل بك في النهاية إلى الإنجاز الذي تنتظر. نأمل أن ترشدك هذه المقالة إلى رسم ملامح خطتك لبناء موقع ويب، وربما سيكون مناسبًا الاطلاع على الطريقة التي تعمل بها شبكة الإنترنت على أساس خطوة ثانية. ترجمة -وبتصرف- للمقال ?How do I start to design my website. اقرأ أيضًا الفرق بين مصمم الويب ومطور الويب وكيفية معرفة الأنسب بينهما أدوات ضرورية لتصميم مواقع الويب HTML و CSS للمبتدئين: كيف تصمم أول صفحة ويب لك 50 تصميمًا مميزًا لمواقع إلكترونية نموذجية يحتذى بها
-
تُعد أداة التهيئة في راسبيري باي حزمةً برمجيةً فعالةً لضبط كثيرٍ من الإعدادات على جهاز راسبيري باي، ابتداءً من الواجهات المتوفرة في الجهاز وصولًا إلى البرامج والتحكُّم بها عبر الشبكات الحاسوبية. قد يصعُب ضبط الإعدادات المختلفة على المستخدمين الجدد، لذلك سيأخذ هذا الملحق بيدك خطوةً خطوة في كل شرح كل إعداد وبيان الغاية منه. تستطيع تحميل الأداة من قائمة راسبيري باي ضمن فئة "التفضيلات Preferences"، أو من خلال واجهة سطر الأوامر بكتابة الأمر التالي في نافذة برنامج "الطرفية Terminal": raspi-config ستجد اختلافًا بين طريقتي عرض النسخة الرسومية لأداة التهيئة ونسخة واجهة سطر الأوامر، إذ ستظهر الخيارات في فئات مختلفة. سيعتمد هذا الملحق على النسخة الرسومية. نافذة النظام تضم نافذة النظام System tab خيارات تتحكم بمجموعة الإعدادات التالية: كلمة المرور Password: انقر على الزر "تغيير كلمة المرور Change Password" لاختيار كلمة مرور جديدة للمستخدم الحالي (المستخدم 'pi' هو المستخدم الافتراضي). اسم المضيف Hostname: وهو الاسم الذي يعرِّف به باي نفسه على الشبكات، إذ ينبغي أن يمتلك كل جهاز باي اسمًا فريدًا إن كان هناك عدة أجهزة على نفس الشبكة. واجهة الإقلاع Boot: سيقلع باي وصولًا إلى "سطح المكتب Desktop" بالوضع الافتراضي للإعداد، ويمكن اختيار "To CLI" للإقلاع وصولًا إلى واجهة سطر الأوامر التي شرحناها في الملحق "C". تسجيل دخول تلقائي Auto Login: عندما يكون الخيار "مثل مستخدم حالي As current user" مفعلًا (وهو مفعلٌ افتراضيًا)، سيحمّل راسبيان سطح المكتب دون طلب اسم المستخدم وكلمة المرور. التحقق من الاتصال بالشبكة عند الإقلاع Network Boot: إذا كان الخيار "انتظار شبكة الاتصال wait for network" مفعلًا، فلن يُحمّل راسبيان سطح المكتب حتى يضمن وجود اتصال بالشبكة. شاشة مؤقتة Splash Screen: عندما يُفعَّل هذا الخيار، تختفي رسائل إقلاع راسبيان خلف شاشة رسومية مؤقتة. فيديو باي 4 Pi 4 Video: يُتاح هذا الإعداد في النموذج Pi 4 ويعطيك القدرة على تبديل مخرج الفيديو، إذ يمكِّنك الخيار "4K HDMI" من بث الفيديوهات بدقة "4K" عبر أحد منفذي micro أو HDMI أو كلاهما؛ بينما يمكِّن الخيار "تماثلي Analog" عرض الفيديوهات المركبة composite video عبر منفذ الفيديو 3.5 مم، ويُعد هذا الخيار جيدًا إذا كان لديك شاشة أو تلفاز قديم ليس له منفذ HDMI. لا يُفعّل افتراضيًا أيًا من الخيارين السابقين وتُعرض الفيديوهات بدقة 1080p عبر منافذ micro أو HDMI. انتبه إلى أنّ تفعيل الخيار "4K" سيزيد من استهلاك الطاقة والحمل على وحدة المعالجة المركزية CPU ووحدة معالجة الرسوميات GPU، لذلك من الأفضل إلغاء تفعيل هذا الخيار إذا لم تكن بحاجته حاجةً ماسةً لتوجيه موارد الجهاز لمهامٍ أخرى. نافذة الواجهات وتضم الإعدادات التي تتحكم بواجهات العتاد الصلب المتوفرة على باي، وهي: الكاميرا Camera: يمكّن أو يعطّل واجهة الكاميرا التسلسلية Camera Serial Interface -أو اختصارًا CSI-، للتعامل مع تجهيزة كاميرا راسبيري باي. SSH: يمكّن أو يعطّل واجهة المفسر المؤمّنة Secure Shell Interface، والتي تسمح بتشغيل واجهة سطر الأوامر على باي من حاسوب آخر على الشبكة باستخدام عميل SSH. VCN: يمكّن أو يعطّل واجهة الشبكة الافتراضية Virtual Network Computing، والتي تسمح لك باستعراض الواجهة الرسومية لسطح مكتب باي من حاسوب آخر على الشبكة باستخدام عميل VCN. SPI: يمكّن أو يعطّل واجهة الطرفيات التسلسلية Serial Peripheral Interface، التي تُستخدم للتحكم ببعض التجهيزات المتصلة بالمنصة GPIO. I2C: يمكّن أو يعطّل الممر الناقل بين الدارات المتكاملة Inter-Integrated Circuit التي تُستخدم للتحكم ببعض التجهيزات المتصلة بمنصة GPIO. المنفذ التسلسلي Serial Port: يمكّن أو يعطّل المنفذ التسلسلي Serial port الخاص براسبيري باي والمُتاح عبر المنصة GPIO. واجهة سطر الأوامر التسلسلية Serial Console: تمكّن أو تعطّل واجهة الأوامر التسلسلية المتاحة للمنفذ التسلسلي، ويمكن تعديل هذا الإعداد عند تمكين الإعداد Serial Port. 1-Wire: يمكّن أو يعطّل الواجهة 1-Wire التي تُستخدم للتحكم ببعض التجهيزات المتصلة بمنصة GPIO. Remote GPIO: تمكّن أو تعطّل خدمة شبكة تسمح بالتحكم بمنصة GPIO لحاسوب باي من حاسوب آخر على الشبكة باستخدام المكتبة GPIO Zero. نافذة الأداء وتضم الإعدادات التي تتحكم بحجم الذاكرة المتاحة وسرعة عمل المعالج. رفع تردد التشغيل Overclock: يتيح لك هذا الإعداد جملةً من الخيارات التي تزيد أداء باي لكنه بالمقابل يزيد من استهلاك الطاقة والحرارة واحتمال قصر عمر التجهيزة؛ وهو غير متاح في كل نماذج باي. ذاكرة وحدة المعالجة الرسومية GPU Memory: وتتيح لك ضبط حجم الذاكرة المخصص للاستخدام من قبل معالج رسوميات باي. قد تزيد الذاكرة التي تزيد عن 128 ميغا بايت (افتراضية) الأداء أثناء تصيير الرسوميات ثلاثية الأبعاد والمهام الإعتيادية لوحدة معالجة الرسوميات للأغراض العامة general-purpose GPU -أو اختصارًا GPGPU-، على حساب الذاكرة المخصصة لنظام التشغيل راسبيان؛ بينما يحسِّن تخفيض الذاكرة المخصصة للرسوميات أداء بعض المهام الحساسة للذاكرة على حساب انخفاض أداء تصيير الرسوميات ثلاثية الأبعاد والكاميرا وبعض ميزات عرض الفيديوهات التي قد تصبح غير متاحة. نافذة إعدادات الموقع الجغرافي وتضم الإعدادات التي تتحكم بالمنطقة الجغرافية التي صّممت باي لتعمل ضمنها بما في ذلك إعدادات لوحة المفاتيح. محلي Locale: يسمح لك باختيار موقعك، وهو إعدادٌ يتعلق بالنظام نفسه ويضبط اللغة والبلد ومجموعات المحارف. انتبه إلى أنّ تغيير اللغة في هذا الإعداد سيؤثر فقط على لغة التطبيقات التي تتوفر ترجمةً لها إلى اللغة المختارة. المنطقة الزمنية TimeZone: ويتيح لك اختيار منطقتك الزمنية وذلك بانتقاء منطقة من العالم يليها اختيار أقرب مدينة إليك. إذا اتصلت باي بالانترنت وعرضت الساعة توقيتًا خاطئًا، يكون السبب عادةً اختيار منطقة زمنية خاطئة. لوحة المفاتيح Keyboard: يتيح لك اختيار نمط لوحة المفاتيح ولغتها ومخطط محارفها؛ فإذا لاحظت أن لوحة المفاتيح تطبع حروفًا أو رموزًا خاطئةً، يمكن تصحيحها من خلال هذا الإعداد. البلد الذي تستخدم فيه WIFI: ويسمح لك باختيار البلد لأغراض تنظيم استخدام أمواج الراديو للاتصال اللاسلكي. احرص على اختيار البلد الذي تستخدم فيه باي، فاختيارك لبلد آخر قد يُفقدك القدرة على الاتصال بنقاط الوصول اللاسلكية المجاورة التي قد تخضع لقوانين البث اللاسلكي. إذًا، من الأفضل اختيار البلد قبل محاولة الاتصال بالشبكات اللاسلكية. ترجمة -وبتصرف- للملحق The Raspberry Pi Configuration Tool من كتاب The Official Raspberry Pi Beginner's Guide اقرأ أيضًا المقال السابق: واجهة سطر أوامر راسبيان في راسبيري باي تجميع راسبيري باي والتحضير لاستعماله إعداد Raspberry Pi للعمل
-
تستطيع الوصول إلى معظم برامج راسبيري باي عبر سطح المكتب، إلا أنك تحتاج واجهةً لكتابة تعليمات نصية تُعرف بواجهة سطر الأوامر Command-line interface -أواختصارًا CLI- للوصول إلى بعض البرامج. يؤمن هذه الواجهة في راسبيان تطبيقٌ يُدعى "الطرفية Terminal". لن يحتاج معظم المستخدمين إلى تعلُّم العمل عبر واجهة سطر الأوامر CLI، لكن ما سيقدمه هذا الملحق هو مدخلٌ بسيط لمن يرغب بتعلم مزيدٍ عنها. فتح تطبيق الطرفية يصل المستخدم إلى CLI عبر برنامجٍ يُدعى "الطرفية Terminal"، وهو برنامج يُحمِّل ما يُعرف تقنيًا بواجة الطباعة الافتراضية عن بُعد Virtual teletype terminal؛ إذ تعود هذه التسمية إلى الفترة الزمنية التي أعطى فيها مستخدمي الحاسوب الأوامر عبر آلة كاتبة كهروميكانيكية بدلًا من استخدام لوحة المفاتيح والشاشة. يمكنك فتح الطرفية عن طريق النقر على أيقونة راسبيري لفتح القائمة والانتقال إلى فئة "برامج ملحقة Accessories"، ثم النقر على "الطرفية Terminal". يمكن سحب نافذة الطرفية إلى سطح المكتب كما يمكن تكبيرها وتصغيرها وتغيير حجم خط الكتابة إن كان من الصعب قراءته، أو ليناسب حجم النافذة وذلك بالنقر على القائمة "تحرير Edit" ثم اختيار "تكبير Zoom in"، أو "تصغير Zoom out"K أو بالضغط على المفتاح "CTRL" ثم أحد الزرين "+" أو "-". محث الطرفية أول ما تراه في الطرفية هو المحث Prompt الذي يكون منتظرًا تعليماتك. يظهر المحث في راسبيان على الشكل التالي: pi@raspberrypi:~ $ يشير الاسم ما قبل "@" إلى اسم المستخدم وما بعده إلى اسم الحاسوب الذي تستخدمه وهو افتراضيًا "raspberrypi". بعد الرمز ":" ستشاهد الرمز "~" وهو اختصارٌ يشير إلى المجلد الرئيسي Home directory ويمثِّل مجلد العمل الذي تعمل ضمنه حاليًا current working directory -أواختصارًا CWD-؛ أما الرمز "$" فيشير إلى أن المستخدم الحالي غير مفوّض unprivileged، أي يحتاج إلى كلمة مرور ليُنفّذ مهامًا، مثل إضافة أو إزالة البرامج. الانطلاق في العمل اكتب التعليمة التالية ثم اضغط المفتاح "Enter": cd Desktop سيتغير المُحِث إلى: pi@raspberrypi:~/Desktop $ أصبح سطح المكتب الآن هو مجلد العمل الحالي الذي يقع مباشرةً تحت المجلد الرئيسي، والذي يشير إليه الرمز "~"، ونُفِّذ ذلك من خلال تعليمة تغيير مجلد العمل cd. يمكنك العودة إلى المجلد الرئيسي بأربعة طرق، حاول أن تجرب كل منها على حدى، ثم جرّب استخدامها للعودة إلى مجلد فرعي لسطح المكتب. الطريقة الأولى- باستخدام الأمر التالي: cd .. إذ يُعد الرمز ".." اختصارًا للمجلد الذي يقع مباشرةً فوق مجلد العمل الحالي أو المجلد الأب، وطالما أنّ المجلد الرئيسي هو الأب المباشر لمجلد سطح المكتب فستصل إليه. عُد إلى سطح المكتب وحاول تجريب الأمر التالي. الطريقة الثانية- باستخدام الأمر التالي: cd ~ ويعني الأمر حرفيًا "توجَّه إلى المجلد الرئيسي"، إذ يمكنك الانتقال بهذه التعليمة إلى المجلد الرئيسي من أي مجلد تعمل عليه، على خلاف الطريقة الأولى التي تنقلك إلى المجلد الأب الأعلى مباشرةً من مجلد العمل الحالي. عُد إلى سطح المكتب وحاول تجريب الطريقة الثالثة التالية. الطريقة الثالثة- باستخدام الأمر التالي: cd إذا لم تضع عنوان المجلد الذي ستنتقل إليه بعد التعليمة cd سيقودك افتراضيًا إلى المجلد الرئيسي. عُد إلى سطح المكتب وحاول تجريب الأمر الأخير التالي. الطريقة الرابعة- باستخدام الأمر التالي: cd /home/pi إذ يمثِّل المسار ما بعد التعليمة cd المسار المطلق absolute path والذي سيعمل بغض النظر عن المجلد الحالي، وينقلك إلى المجلد الرئيسي من أي مجلد تعمل عليه كما هو حال التعليمتين السابقتين، لكن عليك ذكر اسم المستخدم (pi في حالتنا هذه). التعامل مع الملفات لكي تتمرن على أساليب التعامل مع الملفات، انتقل إلى سطح المكتب واكتب الأمر: touch Test سيظهر على سطح المكتب عند تنفيذ التعليمة السابقة ملفٌ اسمه "Test"، إذ تُستخدم التعليمة touch عادةً لتحديث معلومات الوقت والتاريخ لملف، لكن في الحالة التي لا يكون فيها هذا الملف موجودًا (مثل حالتنا) تُنشئ التعليمة هذا الملف. جرّب التعليمة التالية: cp Test Test2 سيظهر على سطح المكتب ملفٌ آخر باسم "Test2" ويمثّل نسخةً مطابقةً للملف الأصلي. لنحذف هذه النسخة على النحو التالي: rm Test2 لن يظهر الملف على سطح المكتب بعد الآن. حاول أن تجرّب الآن التعليمة التالية: mv Test Test2 تنقل هذه التعليمة الملف "Test"، إذ سيختفي عن سطح المكتب ليحل محله الملف "Test2"، الذي يعد نسخةً مطابقةً أيضًا عن الملف الأصلي، وتُستخدم هذه الطريقة في تغيير اسم ملف مثلًا. إذا لم يكن سطح المكتب هو مجلد العمل الحالي، قد تحتاج إلى معرفة ما يحتويه هذا المجلد من مجلدات وملفات لذلك اكتب التعليمة: ls إذ تًظهر هذه التعليمة قائمةً بمحتويات المجلد الحالي أو محتويات أي مجلد آخر تحدده لهذه التعليمة. أضِف بعض الخيارات إلى تعليمتك لتتمكن من عرض تفاصيل أكثر، مثل الملفات المخفية وحجم الملفات: ls -larth تتحكم الخيارات التالية بتعليمة ls: l: يعرض النتائج في قائمة عمودية طويلة. a: يعرض جميع الملفات والمجلدات. r: يعكس الترتيب الاعتيادي للمعروضات. t: يعرض المحتويات وفقًا لتاريخ أخر تعديل، ومع r سيعرض لك الملفات الأقدم في بداية القائمة. h: يُظهر حجم الملف بطريقة مقروءة للبشر ليسهل فهمه. تشغيل البرامج لا يمكن تشغيل بعض البرامج إلا باستخدام سطر الأوامر، بينما يمتلك البعض الآخر واجهات رسومية وواجهة لسطر الأوامر؛ إذ تُعد "أداة تهيئة البرمجيات Pi software configuration tool" مثالًا عن الحالة الأخيرة، والتي تُشغَّل عادةً من قائمة راسبيري باي. لنجرّب طريقة سطر الأوامر بكتابة التعليمة: raspi-config ستكون نتيجة التعليمة رسالة خطأ مفادها أنه لا يمكن تشغيل البرنامج إلا في حالة كان مستخدم جذر رئيسي root user، لذلك حاول تغيير التعليمة إلى: sudo raspi-config التوجيه sudo هو اختصار لعبارة "switch-user do"، وهي تجبر راسبيان على تنفيذ الأمر كأنه مستخدمٌ رئيسي. لا تستخدم هذا التوجيه ما لم يتطلب البرنامج الذي تشغله امتيازات عالية مثل حالة تثبيت أو إزالة برامج أو ضبط إعدادات النظام، فلا يجب أن تُشغّل لعبة مثلًا باستخدام sudo. اضغط على المفتاح "TAB" مرتين، ثم اختر "إنهاء Finish" واضغط على المفتاح "Enter" لإغلاق أداة التهيئة والعودة إلى واجهة سطر الأوامر. نفذ أخيرًا التعليمة التالية: exit التي ستنهي جلسة العمل وتغلق برنامج الطرفية. استخدام الطرفيات TTYs لا يمثِّل برنامج "الطرفية Terminal" الواجهة الوحيدة لسطر الأوامر، بل بالإمكان الانتقال إلى أية طرفيات قيد العمل، والتي تُعرف بواجهات الأوامر البعيدة teletype -أو اختصارًا TTYs-. للانتقال إلى tty2 اضغط على المفتاحين "CTRL" + "ALT" معًا واضغط معهما الزر "F2". لا بدّ من تسجيل دخولك باستخدام كلمة المرور واسم المستخدم، وستتمكن بعد ذلك من التعامل مع هذه الطرفية كما فعلنا سابقًا. هذه الطرفيات مفيدةٌ خاصةً عندما لا تكون قادرًا على الوصول إلى سطح المكتب لسببٍ أو لآخر. لمغادرة tty2 اضغط على المفتاحين "CTRL" + "ALT" معًا واضغط معهما الزر "F7". عند العودة إلى tty2 مجددًا سترى كل ما أنجزته سابقًا قبل مغادرتها. اكتب التعليمة exit ثم اضغط على المفاتيح "CTRL+ALT+F7" للعودة إلى سطح المكتب، وتأتي أهمية تنفيذ هذه التعليمة قبل مغادرة TTY في تسجيل خروجك تلقائيًا، إذ سيتمكن أي شخصٍ قادرٍ على الوصول إلى TTY من العبث بحسابك دون الحاجة لكتابة كلمة المرور. تهانينا، لقد اجتزت خطوتك الأولى في احتراف واجهة سطر الأوامر الخاصة بالنظام راسبيان. ترجمة -وبتصرف- للملحق The command-line interface من كتاب The Official Raspberry Pi Beginner's Guide اقرأ أيضًا المقال التالي: أداة التهيئة في راسبيري باي المقال السابق: تثبيت أنظمة التشغيل والبرامج على راسبيري باي إنشاء أمر جديد في بيئة سطر الأوامر في راسبيري باي التعامل مع بيئة سطر الأوامر في راسبيري باي
-
لابد من نشر الموقع على شبكة الإنترنت حالما تنتهي من كتابة الشيفرة وتنظيم الملفات التي تكوّنه ليتمكن الجميع من الوصول إليه، إذ سنشرح في هذا المقال كيف تنشر موقعك التجريبي البسيط على الإنترنت بأقل جهد ممكن. ماهي الخيارات المتاحة يُعَدّ نشر موقع ويب موضوعًا معقّدًا لوجود طرق وأساليب كثيرة لتنفيذه، ولن نحاول في هذا المقال توثيق كل الطرق الممكنة، وإنما سنصف إيجابيات وسلبيات ثلاثة نهج مناسبة للمبتدئين، ثم نفصّل إحداها والتي تُعَدّ الأفضل للكثير من القراء. الحصول على استضافة واسم نطاق يفضِّل الكثيرون الدفع مقابل الحصول على استضافة واسم نطاق وذلك لتحكّم أفضل في محتوى ومظهر موقع الويب: الاستضافة Hosting: هي مساحة تخزين مُستأجَرة على خادم ويب تابع لشركة الاستضافة، إذ توضَع ملفات الموقع على هذا الخادم الذي يتيح محتواه للزائرين. اسم النطاق Domain name: هو العنوان الفريد الذي ستجد عليه موقع ويب محدَّد مثل /hsoub أو /google، ويمكنك استئجار اسم النطاق لعام أو أكثر من شركة مُسجّلة Domain Registrar. تستخدِم معظم مواقع ويب الاحترافية الطريقة السابقة لتنشر محتواها على شبكة الإنترنت، وبالإضافة إلى ذلك، سيتطلب الأمر برنامجًا يستخدِم بروتوكول نقل الملفات FTP لنقل ملفاتك إلى الخادم، ويمكنك الاطلاع على مقال أساسيات تحديد الكلفة المادية الكاملة لبناء موقع ويب، كما تتنوع برامج FTP كثيرًا، لكن وظيفتها بالمجمل هي استخدام المعلومات التي تزودك بها شركة الاستضافة وهي اسم المستخدِم وكلمة المرور واسم المضيف عادةً، وذلك لتأمين الاتصال مع خادم الاستضافة ونقل الملفات إليه، ثم يُظهِر البرنامج بعد الاتصال ملفاتك المحلية وملفات خادم الويب في نافذتين متجاورتين ليسهل نقل الملفات بين المكانين. نصائح لإيجاد استضافة ونطاق لا نرشح في هذا المقال أيّ شركة استضافة أو شركة مسجِّلة، فعليك البحث بنفسك عما يناسبك، إذ تتيح لك كل المسجلات وسيلةً للتحقق من توفر اسم نطاق معين وحجزه. تمنحك بعض مزودات الخدمة الموجودة على حاسوبك الشخصي أو ضمن شبكة مكتبك إمكانية استضافة محدودة لموقعك، إذ لن تكون الميزات المتاحة كثيرةً، لكنها ممتازة لتجربته الموقع. ستجد أيضًا خدمات استضافة مجانية مثل Neocities و Google sites و Blogger و Wordpress، وقد تجني فائدة ما تدفع، لكن موارد مجانية مثل هذه قد تكوِّن خيارًا تجريبيًا ممتازًا أيضًا. تزوّدك بعض الشركات بخدمتي الاستضافة وحجز أسماء نطاقات معًا. استخدام أدوات على شبكة الإنترنت مثل جيت-هاب و جوجل آب تساعدك بعض الأدوات في نشر موقعك مثل: جيت-هاب GitHub: وهو موقع كتابة شيفرة تشاركي يسمح لك برفع ملفات الشيفرة إلى مستودعات تخزين على منظومة التحكم بالإصدار Git، إذ تستطيع بعد ذلك مشاركة شيفرة المشاريع المختلفة والتعاون في العمل عليها، وطالما أنّ المنظومة مفتوحة المصدر، فيمكن لأيّ كان الوصول إلى الشيفرة على جيت-هاب واستخدامها والتعلم منها وتطويرها، كما تقدِّم جيت-هاب أيضًا ميزةً مفيدةً هي صفحات جيت-هاب GitHub Pages التي تسمح لك باستضافة شيفرة موقعك على ويب. محرّك جوجل آب Google App Engine: وهي منصة قوية تسمح لك ببناء وتشغيل التطبيقات بالاستفادة من البنية التحتية لجوجل، سواءً أردت بناء تطبيق ويب من الصفر أو استضافة موقع ويب ساكن، ولمزيد من المعلومات راجع مقال رفع موقع ويب إلى شبكة الإنترنت. هناك عدة خيارات أخرى مجانية، لكنك قد تتخطى بسهولة حدود الميزات المتاحة. استخدام بيئة عمل متكاملة مبنية على ويب هناك العديد من تطبيقات الويب التي تحاكي بيئة تطوير مواقع ويب وتسمح لك بإدخال شيفرة HTML و CSS وجافاسكربت واستعراض نتيجة تنفيذ الشيفرة على أساس موقع ويب حقيقي داخل نافذة المتصفح، وتُعَدّ هذه الأدوات عمومًا سهلة الاستخدام نسبيًا وممتازةً لأغراض التعلّم ومشاركة الشيفرة، إذ بإمكانك إذا أردت مشاركة أسلوب برمجي أو طلب مساعدة في تنقيح شيفرة من زميل في مكتب مجاور، كما أنها مجانية لبعض الميزات الأساسية، لكنها لا تزوّدك عادةً بمساحة لتخزين ملفات الدعم أو ملفات المساعدة والتي تدعى بالأصول assets مثل الصور، وحاول أن تجرب بعضها مثل JSFiddle و Glitch و JS Bin و CodePen g لتجد ما يناسبك. النشر باستخدام جيت-هاب سنناقش الآن كيف تنشر موقعك على صفحات جيت-هاب بسهولة: سجّل في موقع جيت-هاب أولًا وأكِّد امتلاكك عنوان البريد الإلكتروني الذي استخدمته في التسجيل. أنشئ مستودعًا لتخزين الملفات. أدخِل في الصندوق Repository name الظاهر في الصفحة الموضحة في الشكل التالي العبارة username.github.io، إذ يمثل username اسم المستخدم، فقد يُدخِل "مازن" الاسم "mazen.github.io" مثلًا، ثم فعِّل بعد ذلك الخيار Initialize this repository with a README وانقر بعدها زر أنشئ مستودعًا create repository. اسحب وأفلت محتوى الموقع ضمن المستودع واحفظ التغييرات. انتقل باستخدام متصفحك إلى الموقع "username.github.io -وفقًا لما اخترته-، وسيعرض محتوى موقعك. ترجمة -وبتصرف- للمقال Publishing your website. اقرأ أيضًا مدخل إلى خادم ويب. مدخل إلى أسماء النطاقات على شبكة الإنترنت. أساسيات تحديد الكلفة المادية الكاملة لبناء موقع ويب
-
صُمم البرنامج "نوبس NOOBS" لتسهيل عملية تثبيت أنظمة التشغيل على راسبيري باي ما أمكن، إذ يمكنك شراء بطاقة ذاكرة microSD ثُبت عليها نوبس مسبقًا من أي موزّع لتجهيزات باي، أو اتباع التعليمات التالية لتثبيت البرنامج على بطاقة ذاكرة خاصة بك. تنزيل نوبس NOOBS لتثبيت نوبس على بطاقة ذاكرة فارغة، عليك تنزيل البرنامج من موقع ويب راسبيري باي على حاسوب قادر على قراءة بطاقة الذاكرة microSD و full-size SD مع محوِّل لبطاقة microSD، ويمكنك استخدام قارئ بطاقات ذاكرة بواجهة USB كذلك. استخدم المتصفح في الوصول إلى موقع التنزيلات الخاص براسبيري باي وانقر على برنامج نوبس المُعلّم بأيقونة راسبيري باي في الصفحة التي يحملها المتصفح، ثم انقر "تنزيل ملف مضغوط Download ZIP" ضمن الفئة "تنزيل نوبس دون اتصال أو عبر الشبكة NOOBS Offline and network install". يستغرق تنزيل نوبس وقتًا وخاصة إن كان الاتصال بالإنترنت بطيئًا. عند انتهاء التنزيل أدخل بطاقة الذاكرة في الحاسوب، وستظهر على شكل سواقة مفردة قابلة للإزالة، وقد تُضطرإلى تهيئتها format أولًا إن لم تظهر بهذا الشكل. خياري تنزيل: لاحظ وجود نسختين قابلتين للتنزيل على صفحة تنزيلات نوبس، هما: NOOBS و NOOBS Lite. تنزِّل النسخة الأولى نوبس ونسخة عن آخر إصدار لنظام التشغيل راسبيان في حزمة واحدة؛ بينما تنزِّل النسخة الثانية نوبس فقط. ما يحتاجه معظم المستخدمين هي النسخة الأولى، فلا تنزل النسخة الثانية إلا إذا كنت تخطط لتثبيت نظام تشغيل آخر غير راسبيان. تُثبَّت النسختان بالطريقة ذاتها كما نشرحها في هذا الملحق. تهيئة بطاقة الذاكرة microSD لتهيئة بطاقة ذاكرة مستخدمة سابقًا لتثبيت نوبس، ينبغي لمستخدمي ويندوز أو ماك أو إس تنزيل أداة تهيئة بطاقة الذاكرة "SD Card Association SD Memory Card Formatter"، ثم تثبيتها، أما بالنسبة لمستخدمي لينوكس، فالأداة "disk management tool" هي المستخدمة في حذف أية تقسيمات على البطاقة، ثم إنشاء جزء وحيد single partition وتهيئته وفق نظام الملفات VFAT، ثم إكمال هذا الدليل. أدخل بطاقة الذاكرة في الحاسوب إن لم تكن قد فعلت ذلك، ثم شغِّل الأداة "SD Card Formatter". ابحث عن بطاقة الذاكرة ضمن القائمة "اختر بطاقةً Select card"، إذ قد تجد أكثر من بطاقة لها نفس اسم بطاقتك إن كنت قد استخدمتها سابقًا مع راسبيري باي، لذلك اختر واحدةً منها في هذه الحالة وتحقق من اختيارك للقرص الصحيح (بطاقة الذاكرة) بالاطلاع على معلومات القرص في قسم "معلومات البطاقة card information" الذي يعرض حجم ونوع بطاقة الذاكرة microSD التي أدخلتها. حاول أن تختار الآخرى إن كانت المعلومات المعروضة ليست صحيحة (ليست معلومات بطاقتك)، وتحقق من صحة المعلومات من جديد حتى تتأكد تمامًا بأنها البطاقة الصحيحة. تحقق كذلك من عمل نسخة احتياطية لأية ملفات مخزنة عليها قد تحتاجها لاحقًا، ثم سمِّ البطاقة "NOOBS" من خلال الصندوق "عنوان وحدة التخزين volume label" وانقر زر "تهيئة format" وأكّد -عندما يُطلب منك ذلك- رغبتك في تهيئة القرص. لن يستغرق خيار التهيئة السريعة "quick format" سوى ثوانٍ معدودة ليكتمل. أغلق بعد ذلك أداة التهيئة. تثبيت نوبس وهي عمليةٌ بسيطة مثل عملية سحب وإفلات. ابحث عن ملف نوبس الذي نزلته مسبقًا وستجده عادةً في مجلد " التنزيلات Downloads". يُدعى هذا الملف "ملف أرشيف Archive file"، ويحتوي نسخًا عن كثيرٍ من الملفات التي ضُغطت ضمنه لتقليل حجمها وتسريع تنزيلها. انقر على الأرشيف نقرًا مزدوجًا لفتحه، ثم اضغط على المفتاحين "CTRL+ A" في نظام ويندوز، أو "⌘+A" في نظام ماك أو إس لاختيار جميع ملفات الأرشيف، ثم اسحب هذه الملفات إلى بطاقة الذاكرة microSD ثم أفلتها وانتظر حتى تكتمل عملية النسخ والتي قد تستمر عدة دقائق. أخرج بطاقة الذاكرة عندما ينتهي نسخ الملفات من الحاسوب وضعها في راسبيري باي. عندما تُقلع باي مرةً أخرى سيُحمّل برنامج نوبس وسيطلب منك اختيار نظام التشغيل الذي تود تثبيته. تثبيت البرامج وإزالتها يأتي مع نظام التشغيل راسيبان Raspbian مجموعةً من البرامج المُختارة من قبل مؤسسة راسبيري باي لكنها طبعًا ليست الوحيدة التي تعمل على راسبيان. سترشدك الأفكار التالية إلى طريقة تصفُّح برامج إضافية وتثبيتها أو إزالتها لتوسيع إمكانيات باي. بُنيت الإرشادات في هذا الملحق على ما شرحناه في المقال الثالث "نظام تشغيل راسبيري باي (راسبيان)" من هذه السلسلة دليل راسبيري باي حول استخدام بعض البرمجيات الأساسية، لذلك من الأفضل العودة إلى هذا الفصل -إن لم تفعل بعد- قبل استخدام الطرق التي سنشرحها في هذا الملحق. سعة بطاقة الذاكرة: تستهلك البرامج الإضافية التي تثبتها مساحةً أكبر على بطاقة الذاكرة. تسمح لك مثلًا بطاقات الذاكرة بحجم 16 جيجابايت أو أكثر بتثبيت برامج أكثر، ويمكنك التحقق من أن بطاقة الذاكرة التي تنوي استخدامها مناسبةٌ لراسبيري باي من خلال موقع دعم راسبيري. تصفح البرامج الموجودة يمكن تصفُّح قائمة البرمجيات المُتاحة لراسبيان، والتي تُعرف باسم مستودعات البرمجيات software repositories من خلال النقر على أيقونة راسبيري والانتقال إلى فئة "تفضيلات Preferences"، ثم النقر على "إضافة/ إزالة البرامج Add/Remove Software". ستظهر نافذة الأداة بعد عدة ثوانٍ. يتضمن الجانب الأيسر للنافذة قائمةً بالفئات تشبه تلك التي تراها في قائمة راسبيري باي. ستعرض لك نافذة إضافة / إزالة البرامج جميع البرمجيات التي تندرج تحت فئة معينة عند النقر عليها؛ ويمكنك أيضًا البحث عن برنامج أو توصيف برنامج بكتابته في صندوق البحث في أعلى يسار النافذة، مثل "محرر نصوص text editor"، أو "ألعاب games"، وستجد نتيجة البحث على هيئة قائمة من البرامج التي حققت معيار البحث من كل الفئات. لمزيدٍ من المعلومات حول أي برنامج منها، انقر عليه ضمن القائمة وستُعرض المعلومات في الفراغ أسفل النافذة. في حال ضمّت فئةٌ من الفئات كثيرًا من البرمجيات المتاحة للتثبيت، سيستغرق ذلك وقتًا أطول من نافذة إضافة/إزالة البرامج لعرضها. تثبيت برنامج فعّل مربع التحقق بجوار البرنامج الذي تريد تثبيته بالنقر عليه. ويمكنك طبعًا النقر على مربعات التحقق قبل مجموعة البرامج التي تحتاجها لكي تثبتها الأداة في نفس الوقت. ستتحول الأيقونة إلى جانب البرنامج الذي تختاره إلى أيقونة صندوق مفتوح وعليه الرمز "+" للإشارة إلى أنه جاهزٌ للتثبيت؛ وعندما تكتمل قائمة البرامج التي تحتاجها انقر على أحد الزرين "OK" أو "Apply"، إذ لا فرق بين الزرين السابقين سوى أنّ الأول يغلق النافذة عند الانتهاء من التثبيت بينما يبقيها الثاني مفتوحة. سيُطلب منك إدخال كلمة المرور للتأكد من هويتك، فلن ترغب بالتأكيد أن يعبث أحد بالبرامج التي تثبتها على باي قد تلاحظ أحيانًا أنّ مجموعة حزم قد جرى تثبيتها مع البرنامج الذي ثبته، إذ تُعرف هذه الحزم بالاعتماديات dependencies ويحتاجها برنامجك للعمل بصورةٍ جيدة، مثل حزمة المؤثرات الصوتية التي تحتاجها الألعاب، أو قاعدة بيانات للعمل مع مخدم ويب. يمكنك الوصول إلى برنامجك بعد اكتمال التثبيت ضمن الفئة التي ينتمي إليها في قائمة راسبيري باي. تذَكر أن الفئات في قائمة راسبيري باي قد تختلف عن الفئات في أداة إضافة / إزالة البرامج، وقد لا تجد اختصارًا لبعض البرامج التي ثبتّها في قائمة راسبيري إطلاقًا والتي تعرف ببرامج سطر الأوامر Command-line software، إذ ينبغي تشغيلها من برنامج الطرفية "Terminal". لمزيدٍ من المعلومات حول سطر الأوامر والطرفية راجع الملحق "C" (واجهة سطر الأوامر). إلغاء تثبيت برنامج لإزالة أو إلغاء تثبيت برنامج، افتح أداة إضافة / إزالة البرامج، ثم ابحث عن البرنامج الذي تريد إلغاء تثبيته وألغِ تفعيل مربع التحقق إلى جواره بالنقر عليه؛ كما يمكنك استخدام صندوق البحث لإيجاد البرنامج المطلوب؛ وتستطيع كذلك إلغاء تثبيت عدة برامج معًا بالنقر على مربع التحقق بجوار كل منها وإلغاء تفعيله، وسيتغير عندها شكل الأيقونة إلى صندوق مفتوح بجواره سلة محذوفات للإشارة بأن هذا البرنامج سيُحذف أو يُلغى تثبيته. انقر بعد ذلك على أحد الزرين "OK" أو "Apply" لتبدأ العملية، وسيطلب منك إدخال كلمة المرور إن لم تكن قد أدخلتها لسببٍ ما خلال الدقائق القليلة الماضية، كما قد يُطلب منك تأكيد عملية إلغاء تثبيت البرنامج وأية اعتماديات مرتبطة به أيضًا. سيختفي البرنامج من قائمة باي عند اكتمال عملية إلغاء التثبيت، ولن تُحذف طبعًا أية ملفات كنت قد أنشأتها بهذا البرنامج، مثل الرسوميات أو الصور أو المستندات وغيرها. ترجمة -وبتصرف- للملحقين Installing NOOBS to a microSD card و Installing and uninstalling software من كتاب The Official Raspberry Pi Beginner's Guide اقرأ أيضًا المقال السابق: ربط كاميرا مع لوحة راسبيري باي وتشغيلها تجميع راسبيري باي والتحضير لاستعماله ما هو حاسوب راسبيري باي Raspberry Pi؟