اذهب إلى المحتوى

أسامة دمراني

الأعضاء
  • المساهمات

    244
  • تاريخ الانضمام

  • تاريخ آخر زيارة

  • عدد الأيام التي تصدر بها

    24

كل منشورات العضو أسامة دمراني

  1. يُطلق مصطلح الشبكة الحاسوبية على مجموعة من الأجهزة الإلكترونية -غالبًا حواسيب بصورة أو أخرى- المتصلة ببعضها سلكيًا أو لاسلكيًا، ويتحكم في قواعد الاتصال بين تلك الأجهزة بروتوكولات (قواعد) لنقل البيانات وتخزينها والوصول إليها، وقد تكون صغيرة للغاية مثل حاسوب منزلي متصل بطابعة مثلًا، أو قد تكون كبيرة للغاية ومترامية الأطراف مثل شبكة الإنترنت. ونتيجة لهذا المقياس الرهيب الذي قد تصل إليه شبكات الحاسوب فإن لها أنواعًا كثيرة، لكل منها غرض أو استخدام مختلف، وخصائص كذلك ومزايا وعيوب، وقد تطورت عدة معماريات للشبكات توجه تصميمها وتنفيذها، وهي عبارة عن مخططات أنشئت بسبب طبيعة الشبكات المعقدة التي تتغير فيها التقنيات التي تُبنى عليها من ناحية، والمتطلبات التي تحتاج إليها البرمجيات التي تستخدم الشبكات نفسها. أنواع شبكات الحاسوب ونستعرض فيما يلي أشهر أنواع شبكات الحاسوب وهي: الشبكة الشخصية PAN الشبكة المحلية LAN شبكات الشركات CAN الشبكات الإقليمية MAN الشبكة واسعة النطاق WAN الشبكة الشخصية PAN الشبكات الشخصية Personal Area Network وتختصر إلى PAN هي أصغر أنواع شبكات الحاسب حجمًا وأقلها تعقيدًا، وكما يوحي اسمها فهي تدور حول شخص واحد في الغالب حيث تربط أجهزته ببعضها أو بشبكة خارجية، سواء كانت تلك الأجهزة كلها حواسيب عامة الأغراض -مثل الحواسيب المكتبية desktop أو المحمولة laptop- أو أجهزة تقنية أخرى تتصل بتلك الشبكة، مثل الطابعة أو الأجهزة المنزلية الذكية أو أجهزة إنترنت الأشياء IoT أو الهاتف. من أهم مزايا الشبكات الشخصية ما يلي: تتميز بالأمان ومستوى الحماية الجيد نسبيًا نظرًا لأنها محدودة في عدد الأجهزة المتصلة، ويكون مالك تلك الأجهزة هو نفس الشخص في الغالب. نطاق عمل هذه الشبكة يكون صغيرًا جدًا في الحيز الجغرافي حيث لا يتجاوز أمتارًا معدودة. أما عيوب الشبكات الشخصية فهي: تفتقر الشبكات الشخصية إلى إمكانية الانتشار على نطاق متوسط إلى واسع، فإذا كان المنزل كبيرًا أو يتكون من عدة مباني متجاورة أو عدة طوابق مثلًا فقد لا تكون كافية وسيحتاج المستخدم إلى إنشاء شبكة محلية صغيرة أو إضافة أجهزة تقوية وأسلاك وربما هوائيات أيضًا لنقل الإشارة لاسلكيًا. قد تتداخل إشارات الشبكة مع إشارات شبكات أخرى تعمل على نفس التردد أو النطاق. دورة علوم الحاسوب دورة تدريبية متكاملة تضعك على بوابة الاحتراف في تعلم أساسيات البرمجة وعلوم الحاسوب اشترك الآن الشبكة المحلية LAN الشبكات المحلية Local Area Network وتختصر إلى LAN هي ثاني أنواع شبكات الحاسوب من حيث الحجم، وتمتد على مساحات صغيرة نسبيًا، مثل مبنى واحد أو طابق في ذلك المبني، وقد يكون منزلًا أيضًا، وتُشارك الموارد الموجودة في ذلك المبنى مع الحواسيب والأجهزة المتصلة بتلك الشبكة، والغالب على تلك الموارد أن تكون طابعات أو ملفات مخزنة في أرشيف أو أقراص صلبة. من أهم مزايا الشبكات المحلية ما يلي: شبكة خاصة لا يستطيع أحد من خارجها أن يصل إليها. تقليل تكلفة الموارد المخصصة لكل حاسوب أو جهاز في تلك الشبكة، بما أننا نستطيع الوصول إلى أي من الموارد الموجودة في أي حاسوب في الشبكة -طالما يمتلك الحاسوب صلاحيات الوصول إلى تلك الموارد-، مثل البرمجيات غالية الثمن التي يمكن استخدامها عبر الشبكة دون الحاجة إلى شراء نسخة لكل حاسوب، أو الاتصال بالإنترنت مثلًا، إذ يمكن استخدام اتصال واحد لكل الحواسيب الموجودة في الشبكة. أما عيوب الشبكات المحلية فهي: التكلفة الابتدائية لإنشاء الشبكات المحلية تكون عالية، وإن كانت ستوفر لاحقًا في تكاليف التشغيل نفسها. تحتاج إلى إدارة ومتابعة مستمرة لإصلاح مشاكل العتاد والبرمجيات التي قد تطرأ. يستطيع مدير الشبكة أن يصل إلى جميع الملفات الموجودة على حواسيب الشبكة، فإن كانت تحمي الشبكة من الاتصالات الخارجية، إلا أن المتصلين بالشبكة أنفسهم ليس لديهم خصوصية كبيرة على الملفات الموجودة في حواسيبهم. شبكات المؤسسات CAN ثالث أنواع شبكات الحاسوب هي شبكات الشركات Corporate Area Network وتُسمى أحيانًا بشبكات الحرم Campus Networks لأنها تُستخدم عادة في الحُرُم الجامعية، وهذا يعني أنها تمتد على نطاق مباني الجامعة كلها بمكتباتها ومبانيها الأكاديمية والإدارية وغيرها، وكذلك في شأن الشركات إذ تُستخدم لتوصيل مباني الشركة ببعضها، فهي أكبر من الشبكات المحلية إذن في نطاقها الجغرافي، لكنها أصغر من الشبكات الواسعة WAN والإقليمية MAN. من أهم مزايا شبكات الشركات: تمتد على نطاق بين 1-5 كم. سرعة نقل البيانات، إذ تستخدم مزيجًا من كابلات الإيثرنت السلكية وكابلات الألياف الضوئية فائقة السرعة. مستويات الحماية العالية، نظرًا لطبيعة البيانات الحساسة الخاصة بالشركات والجامعات، فتوضع إجراءات حماية مشددة على العتاد الخاص بالشبكة، عن طريق الجدر النارية Firewalls وخوادم الوكلاء Proxy Servers، إضافة إلى مستويات الصلاحيات المخصصة لكل موظف أو فرد داخل الشبكة، وإجراءات الحماية الأخرى للعتاد من أقفال وحراسة وغيرها. أما عيوب شبكات الشركات فهي: عدد العُقد -الحواسيب أو الأجهزة اﻷخرى- المسموح به في الشبكة محدود، كما أن مدى الشبكة محدود بمسافة أيضًا. التكلفة العالية للصيانة والإدارة موازنة بالشبكات المحلية LAN والشبكات الواسعة WAN مثلًا. هل ترغب في إدارة شبكتك وحمايتها وتحديثها باستمرار؟ وظّف مهندس شبكات خبير من مستقل أضف مشروعك الآن الشبكات الإقليمية MAN تمتد الشبكات الإقليمية Metropolitan Area Network أو شبكات المدن على نطاق أكبر حيث تصل المساحات التي تغطيها إلى خمسين أو مئة كيلومتر مثلًا، وهذه الشبكات تمثل أحد أنواع شبكات الحاسب المعقدة، فقد تتألف من عدة شبكات محلية LAN عبر توصيلهم معًا بكابلات الألياف الضوئية. من أهم مزايا الشبكات الإقليمية: سرعات نقل البيانات العالية موازنة بالشبكات المحلية، حيث تكون بين 34-159 ميجابت/ث، أما الشبكات المحلية فتكون من 1-100 ميجابت/ث فقط. تستخدم خاصية المسار المزدوج dual bus لنقل البيانات في كلا اتجاهي وسيلة النقل (الكابل مثلًا) في نفس الوقت. الدعم التقني المتقدم بما أنها تتبع شركات في الغالب أو جهات حكومية. أما عيوب الشبكات الإقليمية فهي: التكلفة العالية للإنشاء والتشغيل، حيث تتطلب بنية تحتية باهظة التكلفة، وكذلك فرق صيانة وإدارة متخصصة. صعوبة تأمينها من الهجمات الأمنية التي ينفذها المخترقون بسبب انتشارها الجغرافي الواسع. الشبكة واسعة النطاق WAN تمتد الشبكات واسعة النطاق Wide Area Network وتختصر إلى WAN على نطاق أوسع من الشبكات السابقة، فيمكن إنشاؤها بين عدة مباني إلى أحجام أكبر تصل إلى العالم كله، فشبكة الإنترنت التي تصل بين مليارات الحواسيب والأجهزة التقنية في القارات المختلفة وفي أعالي البحار وفي الفضاء أيضًا -كما في حالة محطة الفضاء الدولية- ما هي إلا مثال على الشبكات واسعة النطاق WAN، وعلى ذلك يكون هذا النوع من الشبكات هو أكثر أنواع شبكات الحاسوب مرونة في زيادة حجمه. لكن الأمثلة الأشهر لها هي استخدامها في الشركات أو المؤسسات الكبيرة، وقد تتكون الشبكات واسعة النطاق من مجرد عدة شبكات محلية متصلة معًا. من أهم مزايا الشبكات واسعة النطاق ما يلي: إمكانية تغطية مساحات جغرافية كبيرة، مما يعني إمكانية ربط فروع الشركة ببعضها وإن كانت بعيدة. تشمل الشبكات واسعة النطاق نفس المزايا التي للشبكات المحلية، من مشاركة الموارد وتقليل التكلفة وغيرها. أما عيوب الشبكات واسعة النطاق فما يلي: تكلفة الإنشاء الابتدائية تكون عالية للغاية بما أنها قد تشمل تثبيت بنية تحتية على نطاق جغرافي كبير. صعوبة صيانتها للأيدي غير المدربة، فيجب توظيف متخصصين في الشبكات. طول المدة اللازمة لإصلاح الأعطال بما أن الفني المسؤول عليه أن يفحص كثيرًا من الأجزاء التي قد تكون فيها المشكلة، وقد يكون ذلك في عدة مباني مختلفة وعبر عدة وسائل لنقل البيانات. امتلك شبكة حاسوب اعتمادية وآمنة لأعمالك احصل على حلول شبكات متقدمة وسريعة بالاستعانة بأفضل خدمات الشبكات على خمسات اطلب خدمتك الآن أنواع الشبكات الأخرى توجد بعض الأنواع الأكثر تخصصًا في شبكات الحاسوب تخدم أغراضًا بعينها أو تكون لها طبيعة خاصة، وإن كانت جزءًا من واحدة أو أكثر من الشبكات السابقة، وأهم تلك الأنواع ما يلي: الشبكات المحلية اللاسلكية WLAN تتيح شبكات WLAN إمكانية الاتصال اللاسلكي لجهاز أو أكثر بشبكة محدودة النطاق، كما في حالة الراوتر اللاسلكي (الموجِّه) أو نقطة الاتصال Access Point أو المكرر Repeater الذين قد تستخدمهم في المنزل أو العمل، فيستطيع المستخدمون التحرك بأجهزتهم في نطاق تغطية الشبكة دون الحاجة إلى الاتصال السلكي. شبكات التخزين SAN تتكون شبكات التخزين Storage-Area Networks وتختصر إلى SAN من وحدات تخزينية قد تكون مجرد أقراص صلبة صغيرة أو قد تكون خوادم كاملة مخصصة لتخزين، ويمكن تصور كيفية عمل هذه الشبكة على أنها مجموعة من أقراص التخزين، يمكن الوصول إليها عبر شبكة من الخوادم. وتتميز هذه الشبكة بسرعة الوصول إلى بياناتها بسبب أن وحدات التخزين تظهر كأقراص صلبة في الحواسيب المتصلة بتلك الشبكة. الشبكات الخاصة بالمؤسسات EPN قد تبني الشركات أو المؤسسات شبكات خاصة بها Enterprise Private Networks لا يمكن الوصول إليها من خارجها، وذلك في حالة الشركات التي تريد توصيل عدة مواقع تتبعها توصيلًا آمنًا لضمان سلامة بياناتها الحساسة. الشبكات الافتراضية الخاصة VPN الشبكات الافتراضية الخاصة Virtual Private Networks تكون خاصة أيضًا -من الخصوصية- لكنها تستخدم شبكة عامة للاتصال بالمواقع البعيدة أو توصيل عدة مستخدمين معًا، وتستخدم اتصالات افتراضية أو وهمية virtual توجَّه داخل الإنترنت من شبكة المؤسسة إلى طرف ثالث يقدم خدمات VPN، ومنها إلى الموقع البعيد الخاص بالشركة. قد يكون استخدام تلك الشبكات مدفوعًا أو مجانيًا وفقًا لمقدم الخدمة، وتختلف عن النوع السابق للشبكات الخاصة في أنها يمكن الوصول منها إلى الإنترنت، على عكس شبكات المؤسسات التي تكون مقصورة على موارد الشبكة فقط بما أنها تستخدم خطوطًا خاصة بها لنقل البيانات. خاتمة تعرفنا في هذه المقالة على أشهر أنواع شبكات الحاسب المنتشرة، واستخدامات كل منها ومزايا بعضها، وعرفنا أنها تُصنف وفقًا لحجمها والغرض الذي تُستخدم له، ولا شك أنه توجد أنواع أخرى من الشبكات مثل الشبكات المنزلية Home Area Networks (HAN)‎ وغيرها ولكن حرصنا أن يكون المقال تعريفًا بسيطًا بأشهر أنواع شبكات الحاسوب ببساطة ودون تعقيد أو تطويل، ويمكنك أن تنتقل بعد هذا المقال إلى مواضيع أوسع عن شبكات الحاسوب. وتوفر أكاديمية حسوب مساقًا كاملًا لتعلم علوم الحاسوب الأساسية، وفهم أساسيات أنظمة التشغيل المختلفة التي تعمل بها الحواسيب والأجهزة الإلكترونية والخوادم، وكذلك المفاهيم الأساسية في الشبكات، وطبيعة عمل الخوادم من حيث استقبال الطلبات فيها والرد عليها، ومفاهيم الحماية والأمان في تلك الشبكات وفي الويب خاصة. اقرأ أيضًا المتطلبات اللازمة لبناء شبكة حاسوبية البرمجيات المستخدمة في بناء الشبكات الحاسوبية أمثلة عن أنظمة أمن الشبكات الحاسوبية
  2. يتعامل الإنسان مع الحاسب من خلال واجهة رسومية يتفاعل معها بمؤشر الفأرة أو باللمس، ليستخدم برامج وتطبيقات مثبتة عليه لإنجاز مهامه اليومية، وتصل طلباته عن طريق تلك التطبيقات إلى المكونات المادية للحاسب من خلال طبقة وسيطة أخرى هي المسؤولة عن التحكم في هذه المكونات المادية، وتلك الطبقة الوسيطة تسمى بنظام التشغيل. تعريف نظام التشغيل ببساطة، يكون لدينا نحن المستخدمين مجموعة من الطلبات التي نريدها من الحاسب، مثل التقاط صورة أو كتابة رسالة أو إجراء عملية حسابية مثلًا، فنستخدم تطبيقًا مخصصًا لتلك المهمة نستطيع التفاعل معه، مثل الكاميرا أو معالج النصوص أو الآلة الحاسبة، ويرسل التطبيق تلك البيانات التي نُدخلها إليه، سواء ضغطنا على زر التقاط الصورة أو كتابتنا لنص الرسالة أو لأطراف العملية الحسابية، يرسلها التطبيق إلى مجموعة من البرمجيات تسمى في مجملها بنظام التشغيل. يعالج نظام التشغيل تلك البيانات التي التقطها من التطبيقات ثم يترجمها في صورة إشارات كهربية يرسلها إلى المكونات المادية للحاسب لتنفيذ ما يلزم لتحقيق المهمة التي نريدها، فيرسل إشارات إلى الكاميرا لتلتقط الضوء المحيط بحساس الصورة ثم يعالج تلك البيانات فيكون الصورة التي التقطناها. وبالمثل في حالة الرسالة والعملية الحسابية، حيث يرسل إشارات إلى المعالج والذاكرة ليخزن الرسالة في القرص الصلب إن كنا نريد حفظها، وإلى المعالج ليحسب ناتج العملية الحسابية التي أدخلناها إليه، ثم يعيد إلينا هذا الناتج. وهكذا فإن نظام التشغيل عبارة عن مجموعة من البرمجيات التي تدير مكونات الحاسب المادية على الوجه الأمثل الذي يضمن سلامة عمل تلك المكونات مع تنفيذ المهام التي نريدها من الحاسب في نفس الوقت. لكن هذه الصورة المبسطة لدور نظام التشغيل يدخل تحتها كثير من المفاهيم الأكثر تعقيدًا، والتي قد نتعرض لبعضها بعد قليل. أمثلة لأنظمة التشغيل المشهورة قبل أن ننظر في أنواع أنظمة التشغيل نريد أولًا أن نقدم بعض الأمثلة على أنظمة التشغيل المشهورة التي بين أيدينا، كي نضع تصورًا لما سيأتي في العناوين التالية أدناه عند تفصيل أنواعها. نظام التشغيل مايكروسوفت ويندوز نظام التشغيل ويندوز Windows من شركة مايكروسوفت هو أشهر أنظمة التشغيل على الإطلاق والمتصدر في نسب الاستخدام على مستوى العالم، وهو نظام تشغيل للحواسيب المكتبية والمحمولة، متعدد المهام وعام الأغراض، وهو غني عن التعريف، ولا يقتصر استخدامه على حواسيب شركة معينة، وإنما يمكن تثبيته على أي حاسب مكتبي أو محمول. نظام ويندوز هو نظام مغلق واحتكاري لشركة مايكروسوفت المالكة له، وآخر نسخة منه وقت كتابة هذه الكلمات هي ويندوز 11. لا يمكن التعديل في النظام والبناء عليه ليوافق احتياجات متخصصة، بل يُستخدم كما تقدمه الشركة دون تعديل، وهذا يقودنا إلى المثال التالي لأنظمة التشغيل. أنظمة تشغيل لينكس تُسمى أحيانًا توزيعات لينكس، وهي أنظمة تشغيل مفتوحة المصدر، أي يستطيع أي أحد أن يطلع على شيفراتها المصدري ويعدّل فيها ويبني عليها أنظمة تشغيل جديدة لتناسب احتياجاته أو احتياجات فئة معينة من المستخدمين، وهي أنظمة كذلك موجهة للحواسيب عامة الأغراض والحواسيب المحمولة مثل ويندوز، لكن تختلف هنا في أنها تزيد على ذلك قليلًا. وذلك أن جميع الحواسيب الخارقة في العالم تقريبًا تعمل بأنظمة لينكس، وهي حواسيب عملاقة تستخدمها الشركات الكبرى والدول لإجراء تجارب المحاكاة العلمية واختبار النظريات الفيزيائية وحساب مسارات الأجرام السماوية وغيرها. كذلك فإن نظام تشغيل أندرويد الشهير الخاص بالهواتف هو نسخة من نسخ لينكس معدّلة لتناسب موارد الهاتف المحدودة. وبسبب تلك الإمكانية الكبيرة في تعديل أنظمة تشغيل لينكس فإنه يدخل في أنواع كثيرة من الحواسيب غير التي يعمل عليها ويندوز، وقد كانت تجربة أحد أنظمة لينكس قبل أعوام تجربة صعبة على من اعتاد نظامي ويندوز أو ماك، لكن الآن صارت أسهل كثيرًا لما تطورت معه التوزيعات (الإصدارات) لتناسب المستخدمين الجدد. دورة علوم الحاسوب دورة تدريبية متكاملة تضعك على بوابة الاحتراف في تعلم أساسيات البرمجة وعلوم الحاسوب اشترك الآن نظام تشغيل ماك MacOS على عكس الأمثلة السابقة فإن نظام تشغيل ماك أو إس MacOS، الخاص بشركة أبل، لا يعمل إلا على حواسيبها فقط، وهو نظام مغلق كما في حالة ويندوز. وتوجه شركة أبل نظام ماك ليتوافق مع بقية الأجهزة التي تنتجها مثل هواتف ايفون وساعاتها الذكية وأنظمة البيت الذكية مثل السماعات وغيرها، من حيث تجانس تجربة الاستخدام على تلك الأجهزة جميعًا. أنظمة التشغيل الأخرى لا شك أن العالم فيه مئات أنظمة التشغيل الأخرى التي تناسب شتى الاحتياجات والأغراض، لكننا ذكرنا الأمثلة الأشهر لتقريب الصورة، وبدلًا من ذكر أسماء أخرى لمنتجات قد تكون غير معروفة للمستخدم، فإننا سنذكر الأنواع التي بُنيت عليها تلك الأنظمة والاستخدامات التي تخصص لها. أنواع أنظمة التشغيل تتنوع أقسام أنظمة التشغيل وفقًا لنوع العتاد الذي ستعمل عليه، ووفقًا للغرض من استخدام ذلك العتاد، وفيما يلي أهم أنواعها: أنظمة التشغيل متعددة المهام لا تستطيع أنظمة التشغيل وحيدة المهام تشغيل أكثر من برنامج واحد في نفس الوقت، كما يوحي اسمها، على عكس نظام التشغيل متعدد المهام الذي ينفذ أكثر من برنامج في نفس الوقت من خلال توزيع وقت التنفيذ على المهام والبرامج التي ينفذها، لكن هذا التوزيع يكون على فترات زمنية متقاربة للغاية بحيث يبدو للمستخدم أن جميع البرامج تعمل معًا في نفس الوقت. أنظمة التشغيل متعددة المستخدمين بناء على نفس مفهوم تعدد المهام في الفقرة أعلاه، فإن أنظمة التشغيل متعددة المستخدمين تسمح لعدة مستخدمين بالتفاعل مع موارد الحاسب -مثل مساحة التخزين ومعالجة العمليات والذاكرة- في نفس الوقت. أنظمة التشغيل المدمجة يمثل نظام التشغيل المدمج embedded system حاسوبًا يوضع في آلة أكبر مثل تلفاز ذكي أو ذراع روبوت، وتكون مهام نظام التشغيل هنا محددة للغاية، مثل تحريك ذراع الروبوت في سلسلة حركات معينة، أو التحكم في التلفاز ووصوله إلى الإنترنت، وهكذا. وتُستخدم أنظمة التشغيل المدمجة في أجهزة إنترنت الأشياء Internet of Things مثل المصابيح الذكية وحساسات الحرارة وغيرها، وفي صيانة السيارات والتحكم في حرارتها، وأنظمة الملاحة في الطائرات، ومتعقبات الموقع GPS trackers والأساور الرياضية fitness trackers. وقد يكون نظام التشغيل المدمج أحد الأنظمة المشهورة مثل لينكس، لكن توجد حالات تُستخدم فيها أنظمة تشغيل في الوقت الحقيقي تكون أكثر دقة وأقل سماحية بالخطأ، في استخدامات مثل أنظمة المكابح في السيارات مثلًا. أنظمة التشغيل في الوقت الحقيقي يختلف نظام التشغيل في الوقت الحقيقي عن أنظمة تشغيل الحاسب أو أنظمة تشغيل الهواتف التي يعتادها المستخدم، فبينما يكون حجم نظام التشغيل المعتاد 4-20 جيجابايت أحيانًا، وفيه الكثير من التطبيقات ويقبل تثبيت التطبيقات التي يحتاج إليها المستخدم، فإن نظام التشغيل في الوقت الحقيقي Realtime Operating System يكون حجمه صغيرًا -20 ميجابايت مثلًا-. ويُستخدم نظام التشغيل في الوقت الحقيقي في البيئات الحرجة مثل التي يؤدي الفشل فيها إلى كوارث، مثل متحكمات الطيران flight controlers والروبوتات وأجهزة تنظيم ضربات القلب، وكذلك في الآلات التي تتكرر مهامها، أي إذا كلما وقع نفس حدث الإدخال فإننا نحصل على نفس الخرج، إضافة إلى الأداء العالي والأمان، وجدولة المهام وفقًا لأهميتها وليس ترتيبها. لماذا توجد أنظمة تشغيل كثيرة للحواسيب؟ قد يتبادر سؤال إلى الذهن بعد هذا الشرح أعلاه لأمثلة أنظمة التشغيل وأنواعها، وهو أليس من الأفضل لو كان هناك نظام تشغيل واحد فقط لكل تلك الأجهزة؟ الواقع أن ذلك سيكون أمرًا رائعًا ومريحًا لكل من المستخدمين والشركات على حد سواء، لكن لأن أي أحد يستطيع تطوير نظام تشغيل خاص به إذا كان لديه المعرفة الكافية بالبرمجة وعلوم الحاسب، ولأن احتياجات الناس تختلف عن بعضها، فإن كل شركة أو مجموعة قد تحتاج إلى نظام تشغيل يناسب طبيعة عملها. وبالمثل فإن بعض البرمجيات التي تعمل على الحاسبات المكتبية قد لا تناسب العمل على الهواتف الذكية مثلًا، كبرامج التصميم الهندسي والإخراج الفني مثلًا، فنحتاج إلى أجهزة مختلفة أيضًا لتناسب هذه، وكما رأينا فإن بعض أنظمة التشغيل قد يتجاوز حجمها 20 جيجا بايت، وهي مساحة كبيرة للغاية على الهاتف أن يتحملها، إضافة إلى أن واجهة الاستخدام الخاصة بنظام ويندوز مثلًا قد لا تناسب شاشات الهاتف الصغيرة، فينبغي تطوير واجهات مختلفة للعمل معها. وهذا يظهر في مثال نظام التشغيل أندرويد المبني على نظام لينكس، حيث عُدِّل فيه كثيرًا ليوافق شاشات الهواتف ومعالجاتها الصغيرة وبطاريتها المحدودة السعة كذلك، وليستطيع استخدام الرقائق الموجودة في الهاتف والخاصة بالاتصال اللاسلكي والاتصالات الخليوية. تعريفات العتاد في أنظمة التشغيل بما أن بعض أنظمة التشغيل تكون عامة الأغراض -مثل نظام ويندوز- فلماذا لا تعمل بعض قطع العتاد عليها بالصورة المثلى؟ قد يلاحظ المستخدم بعد تثبيت نظام التشغيل على الحاسب مباشرة أن العناصر والأيقونات على الشاشة تبدو كبيرة الحجم، أو أن لوحة اللمس في الحاسب المحمول laptop لا تعمل كل وظائف التمرير فيها، رغم أن الشاشة سليمة وأن لوحة اللمس متصلة وتعمل بكفاءة، وهذا يكون بسبب برمجيات تسمى تعريفات العتاد، وهي تعرِّف نظام التشغيل على هذه القطعة الموصولة بالحاسب ليستطيع تفعيل كل وظائفها. ورغم أن أنظمة التشغيل المشهورة الآن تكاد تتعرف على جميع القطع المشهورة مثل لوحات المفاتيح والفأرة والشاشات وغيرها، إلا أن بعض القطع التي لا يستخدمها إلا فئات محدودة من المستخدمين قد تحتاج إلى تعريفات خاصة قبل استخدامها، مثل بطاقات المداخل الإضافية Express Cards -وهي بطاقات خاصة فيها مداخل USB مثلًا أو قارئات بطاقات بنكية أو غيرها، تُوصل بالحاسب- والطابعات والكاميرات الرقمية وغيرها، وتأتي مع تلك الأجهزة والقطع في الغالب برمجيات تعريف خاصة بها. هل تعمل البرامج على جميع أنظمة التشغيل؟ تظهر هذه المشكلة للذين ينتقلون من نظام تشغيل إلى آخر إما لأسباب تقنية كما في حالة الذين ينتقلون من نظام ويندوز إلى أحد أنظمة لينكس بسبب طبيعة عمله أو بسبب مزايا في أنظمة لينكس غير موجودة في ويندوز، خاصة للعاملين في البرمجة وإدارة الخوادم مثلًا، أو بسبب شرائه لحاسب من شركة مختلفة، كما في حالة من يشتري أحد حواسيب شركة أبل. وتتلخص في أنه قد يكون من المستخدمين لحزمة برامج مثل طقم المكتب في مايكروسوفت مثلًا Office، ثم ينتقل إلى لينكس فلا يستطيع استخدامه أو تشغيل نفس البرنامج على نظام التشغيل الجديد، فلماذا لا يعمل البرنامج رغم أنه نفس الحاسب، وما تغير إلا نظام التشغيل فقط؟ الواقع أن نظام التشغيل كُتب بواسطة لغات برمجية، وينبغي كتابة البرامج بلغات برمجية تتوافق مع هذه اللغات التي يقبلها نظام التشغيل ويستطيع تفسيرها، فإذا أردنا تشغيل برنامج مثل معالج النصوص Word مثلًا على نظام تشغيل ماك، فيجب كتابة نفس البرنامج بلغة يستطيع نظام ماك أن يفسرها ويتعامل معها، وبنفس المنطق فإن التطبيقات المخصصة للهواتف مثلًا لا تعمل على الحواسيب المكتبية. على أنه توجد طرق أخرى لتشغيل البرامج على أنظمة تشغيل غير التي كُتبت من أجلها، من خلال آلات التشغيل الوهمية Virtual Machines، وهي برامج تحاكي إنشاء حواسيب افتراضية داخل الحاسب تُخصص لها مساحة من القرص الصلب والذاكرة ليعمل عليها نظام تشغيل مختلف بالكلية داخل النظام الأساسي، لكنها تحتاج إلى أن يكون الحاسب نفسه قويًا بما يكفي لتشغيل نظامين معًا. أو في صورة أقل من هذا، بيئات التشغيل البرمجية، وهي برمجيات توفر قاعدة برمجية تعمل عليها البرامج التي لا يمكن تشغيلها على نظام التشغيل مباشرة، مثل بيئات تشغيل جافا التي يجب تثبيتها قبل تثبيت أي برنامج مكتوب بلغة جافا. خاتمة رأينا في هذه المقالة لمحة مختصرة عن أنظمة التشغيل الخاصة بالحواسيب، وتعرفنا على أنواعها ومهامها ونظرنا في أمثلة عليها، وهي أساس أي عمل أو وظيفة أو مهمة نريد تنفيذها هذه الأيام سواء للبيت أو العمل، فينبغي أن تكون لدينا معرفة أساسية بها وبكيفية عملها، فهي مما لا يسع المرء جهله. فإذا أردت الاطلاع على مدخل شامل لعلوم الحاسب وأنظمة التشغيل فإننا ننصحك بدورة علوم الحاسوب، أو إذا كانت لديك معرفة أساسية وتريد التعمق قليلًا في أنظمة التشغيل فربما تود النظر في كتاب أنظمة التشغيل للمبرمجين. كذلك من المهم أن يتعلم المستخدم كيفية حماية بياناته الشخصية وحاسبه وتأمين تصفحه على الإنترنت، وهنا لا نجد أفضل من كتاب دليل الأمان الرقمي الذي يأخذك خطوة بخطوة إلى تأمين نفسك وتوعيتها بالمخاطر المحيطة ببياناتك على الويب وعلى أجهزتك الشخصية. اقرأ أيضًا العمليات وعناصرها في نظام تشغيل الحاسوب ما هو نظام لينكس ولماذا توجد 100 توزيعة منه؟
  3. شبكة الحاسب ببساطة هي مجموعة من أجهزة الحاسب التي تتصل ببعضها وتستخدم موارد مشتركة بينها، وتكون تلك الموارد المشتركة إما بيانات أو أجهزة حقيقية مثل الطابعات وأجهزة العرض والتسجيل أو الماكينات والآلات التي تحمل رقاقات حاسوبية بداخلها متصلة بنفس الشبكة. وصحيح أن مصطلح شبكة الحاسب على إطلاقه يشير إلى الشبكة العالمية التي نعرفها بالإنترنت، إلا أن مفهوم الشبكات أوسع من ذلك بكثير، كما سنرى في الفقرات التالية. تعريف شبكة الحاسب شبكة الحاسب computer network مؤلفة من كلمتين، الأولى شبكة ومعناها لا يخفى على أي قارئ عربي وهي بحسب قاموس صخر المعاصر ربط بين شيئين أو عدة أشياء أو يطلق على كل متداخل متشابك وتحصر كلمة الحاسب الثانية بربط الحواسيب مع بعضها بعضًا. ظهرت أول صورة من صور الحواسيب المتصلة ببعضها في أواخر الخمسينات من القرن الماضي في صورة شبكة من الحواسيب التي استُخدمت في أحد أنظمة الرادار في الجيش الأمريكي، وقد استُخدمت خطوط الهاتف العادية في نقل البيانات بواسطة جهاز مودم تجاري من شركة AT&T. تبع هذه المحاولة في تنظيم الاتصال بين الحواسيب البعيدة عن بعضها عدة محاولات أخرى في الشركات الكبرى والجامعات، وكان أغلب تلك المحاولات يحاول تنظيم الموارد المتاحة للشركة أو المؤسسة وتسهيل تطوير البيانات واتخاذ القرار من خلال تنظيم حركة تدفق البيانات بين تلك الحواسيب البعيدة. دورة علوم الحاسوب دورة تدريبية متكاملة تضعك على بوابة الاحتراف في تعلم أساسيات البرمجة وعلوم الحاسوب اشترك الآن فوائد شبكات الحاسب لعل فوائد الشبكات بدأت تتضح مما لنا نحن كمستخدمين عاديين أو كشركات، وبدت أهمية شبكات الحاسب في نقل البيانات والمعلومات بين الدول والمؤسسات والأفراد، وكذلك في التحكم في الأجهزة والآلات عن بعد لتسهيل مراقبتها، وفيما يلي أهم تلك الفوائد: مشاركة الملفات: كما في حالة الشركات والمؤسسات، بل وفرق العمل التي تعمل عن بعد. مشاركة الموارد: كما في حالة مشاركة الطابعات، والحواسيب القوية لإجراء عمليات محاكاة أو إخراج للتصاميم الهندسية أو الإبداعية، أو العمل على برامج عمل سحابية مثل مستندات جوجل أو برامج تصميم مشترك سحابية. التواصل: حيث يستطيع المستخدمون للشبكة أن يرسلوا الرسائل والبيانات والوسائط فورًا ويستقبلون بيانات وردودًا مشابهة من غيرهم من المستخدمين في نفس الوقت. تقليل التكلفة: كما رأينا في حالة الموارد المشتركة مثل الطابعات أو الحواسيب الكبيرة أو توفير أجهزة وهمية للموظفين للعمل عليها أو خوادم وهمية لاستضافة المواقع. زيادة كفاءة المعدات وسلامة البيانات: بما أن العتاد المستخدم للشبكات يكون في الغالب ذا جودة عالية ويقوم عليه فريق صيانة متخصص، فتقل احتمالات تعطل العتاد أو خسارة البيانات نتيجة النسخ الاحتياطية المنظمة التي تُنفذ للبيانات، على عكس الحواسيب الشخصية للمستخدمين. عيوب شبكات الحاسوب رغم المنافع التي تطغى على بيئة الشبكات إلا أنها تأتي بعيوب قد يكون بعضها خطيرة وقد يكون بعضها الآخر مجرد أعباء إدارية، وفيما يلي بعض تلك العيوب لشبكات الحاسب: تحتاج شبكات الحاسب إلى الاستثمار في بنى تحتية باهظة التكلفة عند بداية إنشائها، وكلما زاد حجم الشبكة زادت التكاليف كثيرًا. تحتاج شبكات الحاسب إلى مراقبة على مدار الساعة لتجنب تعطل أجزائها أو فشل عمليات توصيل الطاقة إليها أو تبريد مراكز البيانات، أو اختراقها داخليًا من العاملين فيها أو خارجيًا من مخربين أو مخترقين عن بعد. سهولة انتقال الفيروسات والبرامج الضارة لكل الأجهزة المتصلة بالشبكة إن أصيب أحدها. المخاطر الأمنية التي قد تحصل نتيجة هجمات قد تأتي داخليًا من أحد الأجهزة المتصلة بالشبكة أو خارجيًا عبر اختراق الشبكة والأجهزة المتصلة بها. مكونات شبكات الحاسب الرئيسية صحيح أننا ذكرنا أن الشبكات الحاسوبية عبارة عن حواسيب متصلة ببعضها، لكن الأمر فيه تفصيل أكثر من هذا، فليست كل تلك الحواسيب عامة الأغراض وتشبه الحاسوب الذي لدى المستخدم العادي، بل يكون بعضها مخصصًا لوظيفة أو أكثر داخل تلك الشبكة بحيث يخدم بقية مكونات الشبكة دون أن يُستخدم هو نفسه لأي غرض آخر، بل قد يُحظر الوصول إليه أحيانًا إلا لفئات محدودة من الأشخاص لعدة أسباب أهمها الحفاظ على أمان الشبكة، وهكذا فإن المتطلبات اللازمة لإنشاء شبكة حاسوبية قد تكون أكثر تعقيدًا من مجرد توصيل بعض الأجهزة ببعضها. الخوادم Servers: أساس شبكات الحاسب لعل أجهزة الخوادم servers هي القلب النابض لشبكات الحاسوب، وهي حواسيب توضع فيها الموارد التي يراد الوصول إليها عن بعد من بقية مكونات الشبكة، وهي حواسيب أقوى من الحواسيب العادية بعشرات المرات من حيث قوة المعالجة وعدد المعالجات ومساحات التخزين والذواكر العشوائية، وتوجد في العادة في غرف مخصصة آمنة تسمى مراكز بيانات data centers. فحين تدخل إلى موقع تتصفحه مثلًا (والموقع هو جزء من شبكة الإنترنت العالمية) وليكن يوتيوب، فإنك تكتب عنوان الموقع في المتصفح، فيذهب بك إلى يوتيوب لتتصفح مقطعًا تريد مشاهدته، فهذا المقطع مخزن على خوادم شركة يوتيوب، وكذلك موقع يوتيوب نفسه مخزّن على خوادم سريعة بالغة القوة لتتحمل آلاف المقاطع التي تُرفع إليه وملايين المستخدمين الذين يتصفحونه في نفس الوقت. وتوجد أنواع عديدة من الخوادم يختص كل منها بمهمة أو عدة مهام، وأشهر تلك الأنواع ما يلي: خوادم أسماء النطاقات Domain Name Servers خوادم التطبيقات Application Servers خوادم الويب Web Servers خوادم الملفات File Servers خوادم البريد Mail Servers خوادم أسماء النطاقات Domain Name Servers وهي الخوادم التي تحتوي على عناوين المواقع التي تتصفحها، فإذا استخدمنا مثال يوتيوب السابق، فإنك تكتب Youtube.com مثلًا ثم تضغط زر الإدخال Enter ليرسل المتصفح الطلب إلى الشبكة، فيمر على خادم DNS الذي يمثل دفتر جهات الاتصال للشبكة وهي هنا شبكة الإنترنت، فيرسل بدوره الطلب إلى العنوان المقابل لهذا النطاق أو الموقع -youtube.com-، ويكون في الغالب مجموعة من الأرقام مثل 192.0.2.44. خوادم التطبيقات Application Servers تُحفظ بعض التطبيقات البرمجية على خوادم بعيدة ليتصل بها المستخدمون من حواسيبهم أينما كانوا، وتسمى الخوادم التي تُحفظ عليها باسم خوادم التطبيقات Application Servers، وتُستخدم مثل تلك التطبيقات في الغالب داخل الشركات التي تريد للموظفين أن يستفيدوا من تلك التطبيقات المركزية دون الحاجة إلى تثبيت التطبيق على حاسوب كل موظف، وهذا مفيد في تجميع بيانات العمل للموظفين في فريق واحد مثلًا ومشاركتها والتعديل عليها مباشرة دون الانتظار لرفع تلك البيانات من حاسوب كل موظف. كذلك تُستخدم في حالة الشركات التي تقدم خدمات بعيدة لمستخدميها بحيث يتصل المستخدم بالتطبيق الموجود بخوادم الشركة من أي جهاز متصل بالإنترنت دون أن يكون التطبيق مثبتًا على حاسوبه الشخصي، ومثل تلك التطبيقات تسمى تطبيقات ويب web apps لأنها تعمل في بيئة الويب في الغالب ويصل المستخدم إليها عن طريق المتصفح. خوادم الويب Web Servers خوادم الويب هي أشهر أنواع الخوادم التي تُستخدم في الوصول إلى الإنترنت، وهي المسؤولة عن نقل البيانات المخزنة في مواقع الإنترنت إلى حاسوبك أو جهازك الذي تتصفح منه، عن طريق بروتوكولات نقل بيانات مثل HTTP. خوادم الملفات File Servers تُستخدم خوادم الملفات في تخزين البيانات والملفات والبرامج داخل المؤسسات مثلًا للسماح بنقل تلك الملفات ومشاركتها بسرعة وأمان بين العاملين في تلك المؤسسة. خوادم البريد Mail Servers يخزن خادم البريد الرسائل البريدية الخاصة بالمستخدمين الذين يستخدمون خدمات بريدية مثل Gmail مثلًا، كي يتمكنوا من الوصول إليها دون الحاجة إلى استخدام برمجيات خاصة على أجهزتهم، حيث تكون تلك البرمجيات في خوادم البريد نفسها. توجد أنواع أخرى من الخوادم غير التي ذكرناها أعلاه، لكن هذه هي الأشهر والتي قد يتعامل المستخدم معها بشكل أو بآخر أثناء حياته اليومية داخل العمل وخارجه. المبدِّل Switches المبدِّل switch هو جهاز يربط أجزاء الشبكة ببعضها بواسطة أسلاك إيثرنت Ethernet أو فايبر في الغالب، فتتصل به الحواسيب الموجودة داخل مبنى مثلًا بالشبكة الموجودة داخل ذلك المبنى، ويكون هو المسؤول عن تنظيم التواصل بين تلك الحواسيب، ولمزيد من التفاصيل حول المبدل ووصله بالشبكة، يمكنك الرجوع إلى مقال شبكة الإيثرنت المبدلة Switched Ethernet. الموجِّه Router لعل هذا الجهاز الصغير هو أكثر مكونات الشبكات التي يتعامل معها المستخدم وإن كان تعاملًا غير مباشر، يليه جهاز نقطة الاتصال Access Point. يُستخدم الموجِّه أو الراوتر في الاتصال بشبكات متعددة، كما يُستخدم لمشاركة اتصال إنترنت واحد مع عدة حواسيب وأجهزة أخرى لتقليل تكلفة اتصال كل منها على حدة بالشبكة، سواء عن طريق أسلاك أو هوائيًا، ولا يكاد يخلو منزل في يومنا هذا من وجود راوتر فيه للاتصال بشبكة الإنترنت عبر مزود خدمة الإنترنت. نقطة الاتصال Access Point تُستخدم نقاط الاتصال، وهي أجهزة شبيهة بأجهزة الراوتر- لتوصيل الحواسيب والهواتف والأجهزة الأخرى بالشبكة اتصالًا لاسلكيًا، عن طريق الاتصال سلكيًا بالراوتر ثم بث إشارة الشبكة لاسلكيًا عن طريق هوائي صغير متصل بها. يمكن لتلك الأجهزة وكذلك أجهزة الراوتر أن تهيأ لتُستخدم كمكررات لإشارات الشبكات repeaters، بحيث تلتقط إشارة الشبكة لاسلكيًا وتنقيها من التشويش ثم تعيد توليدها وبثها مرة أخرى بقوة أكبر، وذلك من أجل توسيع نطاق البث للشبكة. العملاء/الأجهزة العميلة Clients الأجهزة العميلة أو الوكيلة في بيئة الشبكات هي الحواسيب والأجهزة الأخرى التي تتصل بالشبكة ومواردها المختلفة من خوادم وغيرها، وتلك الأجهزة العميلة تمثل مستخدمي الشبكات، حيث تستطيع إرسال واستقبال الطلبات من الخوادم. هل ترغب في بناء شبكة موثوقة وآمنة لشركتك؟ احصل على شبكة عالية الأداء مع مهندس شبكات خبير من مستقل أضف مشروعك الآن مكونات أخرى لشبكات الحاسب إضافة إلى ما سبق، توجد مكونات وأجهزة أخرى تمثل أجزاء لا غنى عنها للشبكة، وقد لا تكون بالضرورة أجهزة مادية، لكن المستخدم العادي قد لا يحتك بها مباشرة أو ليس له وصول إليها، وبعض تلك المكونات ما يلي: بروتوكولات شبكات الحاسب البروتوكول Protocol هو مجموعة من القواعد التي تحكم التواصل بين جهتين في الشبكة، وتكون بعض تلك البروتوكولات قياسية مثل بروتوكولات IP و TCP و FTP وغيرها. عنوان الوصول للجهاز Mac Address يمثل عنوان الماك -عنوان التحكم في الوصول إلى الوسائط Media Access Control Address- معرِّفًا وعنوانًا فريدًا لكل جهاز يتصل بالشبكة. المنفذ Port المنافذ هي قنوات منطقية يرسل المستخدمون البيانات من خلالها إلى التطبيقات أو يستقبلون بيانات منها، ويُعرَّف كل تطبيق من تلك التطبيقات باستخدام رقم المنفذ الذي يعمل من خلاله. وسائل نقل البيانات في شبكة الحاسب إذا كانت بيانات التطبيقات والمواقع والشركات تُخزَّن على خوادم وحواسيب بعيدة، وكان المستخدمون يصلون إلى تلك الخوادم من خلال حواسيبهم وهواتفهم وغيرها من الأجهزة، فكيف تُنقل تلك البيانات؟ تُرسل البيانات بطريقتين أساسيتين، إما نقلًا سلكيًا أو غير سلكي، والنقل السلكي يكون دومًا أسرع وأفضل، لكنه يحتاج إلى بنى تحتية أكثر كلفة، ويتم النقل فيه عبر كابلات من الألياف الزجاجية Fiber glass، خاصة في حالة الكابلات العابرة للمحيطات التي تربط بين القارات المختلفة، وكذلك باستخدام كابلات نحاسية مؤمنة ضد التشويش على الإشارات، تكون في صورة كابلات الإيثرنت التي نعرفها ذات الثمانية أطراف، أو الكابلات المحورية Coaxial، أو أسلاك الهاتف العادية كما كان يحدث قديمًا في اتصال Dialup. أما الاتصالات اللاسلكية فتكون باستخدام هوائيات Antennas لبث الاتصال بالشبكة المراد الاتصال بها، وتختلف المسافة التي يمكن الاتصال بالشبكة من خلالها وكذلك عدد المستخدمين الذين يمكنهم الاتصال بتلك الشبكة على نوع الهوائي المستخدم وسعة الشبكة نفسها. الجدار الناري Firewall الجدار الناري قد يكون جهازًا ماديًا أو برنامجيًا يُستخدم في التحكم في الشبكة وأمانها وقواعد الوصول إليها، وتوضع كحماية للحاسوب وما يتصل به من الشبكات الآمنة -مثل شبكات المنازل والشركات- من الاتصالات الخارجية غير المأمونة مثل الإنترنت، وتهيأ لحظر الطلبات من المصادر غير المعرَّفة للشبكة الآمنة، فهو مثل الباب الذي يفصل المنزل الداخلي الخاص عن المحيط الخارجي العام. زادت أهمية الجدر النارية كثيرًا بعد تطور الإنترنت ووصوله إلى يد كل مستخدم من خلال الهواتف الذكية وأجهزة إنترنت الأشياء، حيث زادت خطورة الهجمات السيبرانية التي قد تستهدف أولئك المستخدمين بحيث يمكن التلاعب بأجهزتهم وسرقة بياناتهم وإغلاق تلك الأجهزة لطلب فدية، كما يحدث كل مدة في حالة فيروسات الفدية التي تصيب أجهزة المستشفيات والمؤسسات المهمة والشركات الكبرى. أو حتى على مستوى الشبكات الموجودة في المنازل العادية حيث انتشرت أنظمة البيوت الذكية التي يُمكن التحكم فيها عن بعد، فيستطيع المخرب تنفيذ هجمة على المنزل بتغيير درجات الحرارة أو قطع الكهرباء أو الاتصالات أو التلاعب بالأجهزة المنزلية المتصلة بالشبكة. أنواع شبكات الحاسوب توجد عدة أنواع من الشبكات تُصنف وفقًا للحيز الجغرافي الذي تخدمه وعدد الحواسيب المتصلة فيها، وفيما يلي بعض أشهر أنواع هذه الشبكات: الشبكة الشخصية PAN‎ الشبكة المحلية LAN الشبكات واسعة النطاق WAN الشبكات الإقليمية MAN 1. الشبكة الشخصية PAN‎ الشبكات الشخصية Personal Area Network وتختصر إلى PAN هي الشبكات التي تتكون من أجهزة تتبع شخصًا واحدًا، مثل الحاسب الخاص به وهاتفه وأجهزته اللاسلكية المتصلة عبر البلوتوث، ويكون نطاقها محدودًا بالتبعية، وقد تتصل بالإنترنت لاسلكيًا. 2. الشبكة المحلية LAN الشبكات المحلية Local Area Network وتختصر إلى LAN تتكون الشبكات المحلية من مجموعة من الحواسيب والأجهزة الأخرى التي تتصل بشبكة واحدة على نطاق مبنى أو عدة مباني متجاورة تمثل مؤسسة واحدة مثل شركة أو مستشفى أو منزل أو غيره، وتكون الشبكة مقصورة على الأجهزة التي داخل تلك المباني، أي لا يمكن الوصول إليها من خارج الأجهزة المتصلة بها أو من خارج نطاق تلك الشبكة. تُستخدم تلك الشبكات في أغراض نقل الملفات واستخدام الأجهزة عن بعد مثل الطابعات والماسحات الضوئية وغيرها، ولعل أبسط صورها هو حاسوب متصل بطابعة مثلًا. لا يزيد عدد الأجهزة المتصلة في الشبكات المحلية عن 5000 جهاز. 3. الشبكات واسعة النطاق WAN الشبكات واسعة النطاق Wide Area Network وتختصر إلى WAN تمثل عدة شبكات محلية متصلة معًا، لكنها تمتد على نطاق جغرافي أكبر، كما في حالة الشركات الكبرى. تُعد شبكة الإنترنت أحد أمثلة الشبكات واسعة النطاق WAN العامة، أي التي يصل إليها كل أحد، على عكس الشبكات الواسعة التي تكون مقصورة على المؤسسات والشركات. 4. الشبكات الإقليمية MAN تنتشر الشبكات الإقليمية Metropolitan Area Network وتختصر إلى MAN على نطاق أوسع من سابقتها، حيث تمتد خلال المدن الكبيرة، وتمتد على نطاق يصل إلى خمسين كيلومترًا مثلًا، وقد تشمل شبكات LAN أو WAN، إضافة إلى شبكات أخرى متصلة عبر تقنيات الاتصال اللاسلكية الهوائية، مثل شبكات الهواتف الخليوية المتصلة عبر تقنيات الجيل الثاني والثالث. تتصل الشبكات الإقليمية في الغالب عبر كابلات ألياف زجاجية بسبب حاجتها إلى نقل البيانات بسرعات عالية. امتلك شبكة حاسوب اعتمادية وآمنة لأعمالك احصل على حلول شبكات متقدمة وسريعة بالاستعانة بأفضل خدمات الشبكات على خمسات اطلب خدمتك الآن خاتمة تُبنى التقنيات الحديثة الآن من حواسيب وشركات وبنى تحتية أحيانًا وأنظمة حكومية باستخدام شبكات الحاسب كقواعد أساسية لها، فصارت جزءًا لا يتجزأ من حياتنا اليومية سواء استخدمناها استخدامًا مباشرًا أم استفدنا من أحد تطبيقاتها. ولا يسع أحدنا اﻵن أن يجهل أبسط مبادئ علوم الحاسب التي بُنيت عليها تلك الشبكات من أجل فهم طبيعة عملها والاستفادة المثلى منها سواء في بيئة العمل أو المنزل، وكذلك تجنب مخاطرها وإغلاق ثغراتها التي قد يدخل المخربون منها. اقرأ أيضًا أمثلة عن أنظمة أمن الشبكات الحاسوبية مدخل إلى شبكات الحواسيب: مصطلحات وفهم طبقات الشبكة المتطلبات اللازمة لبناء شبكة حاسوبية أنواع شبكات الحاسب
  4. نحتاج الآن أكثر من أي وقت مضى إلى مطوري البرمجيات الذين يكتبون برامج تقوم بأغلب المهام التي يحتاجها كل من الشركات والأفراد على السواء، لتقليل الجهد البشري المبذول في تلك المهام من ناحية، ولتقليل نسب الخطأ والمخاطر كذلك، وهو اﻷمر الذي تتفوق فيه البرمجيات على الإنسان فيه بما أنها تعمل في بيئات لا تتأثر بالمخاطر التي يتأثر بها الإنسان، ولا تتعرض إلى السهو والنسيان الذي يعرض للإنسان أثناء تنفيذ المهام. وقد توسع مجال تطوير البرمجيات كثيرًا منذ الثمانينات ليفتح الباب على مصراعيه لوظائف ما كانت موجودة من قبل إما في تطوير البرمجيات نفسها مباشرة أو في وظائف ظهرت بعد تطور تقنيات وأدوات برمجية أو تغير سوق العمل، وصار العامل في تطوير البرمجيات بنفس أهمية اليد العاملة في المصانع إبان الثورة الصناعية قديمًا. ما هو تطوير البرمجيات؟ عملية تطوير البرمجيات software development تشمل الخطوات والمناهج المتبعة في بناء وتصميم البرمجيات وكتابتها واختبارها وتجميعها، وتنطوي هذه العمليات على تفاصيل وأقسام كثيرة بداخلها سيأتي بيانها أدناه. تُصمم البرمجيات أولًا وفقًا لمتطلبات العميل الذي يحتاج إلى حل مشكلة لديه، ويضع المبرمج إن كان يعمل مستقلًا أو فريق التطوير داخل الشركة مخططًا لحل هذه المشكلة، ومنهجية لتنفيذ ذلك الحل، ثم ينطلق في الخطوات التقنية لتنفيذ ذلك الحل باستخدام أدوات تطوير البرمجيات ولغات البرمجة وأطر العمل اللازمة. بعد ذلك، يُختبر البرنامج الناتج ليُرى إن كان يحقق المعايير التي طلبها العميل أم لا، إلى أن نصل إلى النسخة النهائية التي تدخل بيئة العمل مباشرة بعد تمام التأكد من خلوها من الزلات البرمجية والمشاكل التي قد تعطل عملها فيما بعد، خاصة إن كانت البرمجيات توضع في آلات مثل السيارات أو الماكينات في المصانع وغيرها. يشار أحيانًا إلى تطوير البرمجيات بأسماء متبادلة مثل تطوير التطبيقات أو يتعدى أحيانًا مفهوم التطبيقات إلى برمجة أنظمة تحكم لعتاد مخصص مثل أنظمة إنترنت الأشياء ويمتد حتى أنظمة التشغيل. أنواع البرمجيات وبيئات عملها البرمجيات كثيرة الأنواع ولكنها كلها في النهاية تعمل على عتاد حوسبي، ويكون هو البيئة التي تُنفذ فيها التعليمات البرمجية التي تحل المشكلة التي لدى العميل، وتتعدد تلك البيئات تعددًا لا يكاد يُحصر، لكنه يقع تحت فئات عامة يمكن حصرها وفقًا لنظام التشغيل كما يلي: الحواسيب المكتبية: وتشمل كل البرمجيات التي تعمل على الحاسوب سواء حاسوب مكتبي أو محمول الهواتف الذكية والأجهزة اللوحية: وتشمل البرمجيات التي تعمل على الأجهزة المحمولة من تطبيقات عامة وحتى تطبيقات مخصصة تدير العتاد مثل برمجيات الكاميرا وتسجيل الصوت وقياس الحرارة والضغط وغيرها. أجهزة إنترنت الأشياء: مثل برمجيات الأجهزة المنزلية التي يمكن ربطها بالإنترنت. الماكينات والآلات: والتي تكون الحواسيب فيها مدمجة وغير مرئية للمستخدم، أو يتفاعل معها من خلال أوامر محددة وقليلة. دورة علوم الحاسوب دورة تدريبية متكاملة تضعك على بوابة الاحتراف في تعلم أساسيات البرمجة وعلوم الحاسوب اشترك الآن أنواع تطوير البرمجيات يندرج تحت مظلة تطوير البرمجيات أقسام كثيرة تمثل مجالات ووظائف يمكن للمرء أن يعمل فيها، وتتنوع بتنوع مجال العمل وطبيعة المشاكل التي يجب حلها، والأدوات المتاحة للعمل. تطوير الويب Web Development مصطلح تطوير الويب فيه إيجاز قليلًا من حيث أنه يشير إلى تطوير تطبيقات الويب، وهي أي تطبيق يمكن استخدامه داخل متصفح ويب مثل جوجل كروم أو فاير فوكس، وهو يختلف عن التطبيقات المصممة للهواتف أو سطح المكتب، كما سيلي بيانه أدناه. وهذا المجال بدوره مظلة جديدة تدخل تحتها العديد من الوظائف الأخرى المتعلقة به. تطوير الواجهات الأمامية يعمل مطور الواجهات الأمامية Front End Developer في الغالب على تطوير الأجزاء التي سيراها المستخدم ويتفاعل معها من البرامج والتطبيقات، وإن كان هذا المجال يدخل في أي نوع من أنواع التطوير البرمجي التي تنتج برامج رسومية يتفاعل المستخدم معها باللمس أو المؤشر أو غيرها، إلا أنه يُستخدم في الغالب للإشارة إلى تطوير الواجهات الأمامية لتطبيقات الويب، ما لم يُذكر خلاف ذلك لتخصيصه لمجال آخر. تطوير الواجهات الخلفية يعمل مطور الواجهات الخلفية Back End Developer مثل زميله السابق في بيئة الويب في الغالب، ما لم يُذكر تخصيص يشير إلى غير ذلك، وهو يختص بتطوير التطبيقات التي تعمل على الخوادم التي تُخزن فيها تطبيقات الويب والمواقع، والتي تمثل البنى التحتية لتلك المواقع، ولا يركز على واجهات مرئية، وإنما يهتم بقواعد البيانات ومنطق التطبيق وكفاءة عمله واستهلاكه للموارد وسرعة تنفيذه، ومستوى أمانه. تطوير التطبيقات المكتبية يُقصد بها التطبيقات التي تعمل على الحواسيب المكتبية والحواسيب المحمولة Laptops، والتي تكون في الغالب على أنظمة تشغيل مثل ويندوز ولينكس وماك، وهي البرامج المعتادة للأعمال المكتبية للأفراد والشركات، مثل أطقم المكتب وبرامج البريد والتقويم ومتصفحات الويب وبرامج الحسابات وغيرها. وكذلك البرامج المتخصصة الموجهة للعاملين في تطوير البرمجيات أنفسهم، مثل بيئات التطوير المتكاملة IDEs والمحررات النصية والمصرِّفات، وبرامج التصميم المرئي للعاملين في تطوير الواجهات الأمامية والمصممين، وكذلك برامج التصميم الهندسي للمهندسين، وبرامج تحرير الصوتيات والفيديو، فمثل تلك البرمجيات تحتاج إلى الموارد القوية للحواسيب المكتبية، ولا تصلح في الغالب أن تعمل بنفس الكفاءة على الهواتف مثلًا ذات الإمكانيات المحدودة. تطوير تطبيقات الهواتف لعل هذا المجال هو أكثر ما يتعرض إليه أغلب طوائف المستخدمين على اختلاف مجالاتهم وأعمارهم بسبب الاستخدام اليومي للهواتف المحمولة الذكية في حياتنا، ويُقصد به تطوير التطبيقات والبرامج للهواتف المحمولة والأجهزة اللوحية. هذا المجال كبير واسع فكما أشرنا نظرًا لازدياد الأجهزة المحمولة حولنا والتي أصبحت تتعدى الهاتف المحمول إلى أجهزة ملبوسة وأجهزة مساعدة ذكية وغيرها وكلها تحتاج إلى برمجة وتحتاج إلى تطبيقات لتؤدي الغرض المطلوب منها، ويطول المقال إن أردنا التفصيل فيه، ويمكنك الرجوع إلى مقال برمجة تطبيقات الجوال ففيه تفصيل أكبر. تطوير التطبيقات السحابية زاد انتشار هذا المجال مؤخرًا مع ازدياد القوة الحوسبية للخوادم وإتاحة العمل المشترك بين الفرق العاملة عن بعد، أو لمن يرغب في الوصول إلى إمكانيات هائلة القوة لفترة محدودة من أجل إجراء عمليات حسابية معقدة أو إخراج تصميمات كبيرة. التطبيقات السحابية هي تطبيقات وخدمات تعمل على خوادم وحواسيب بعيدة -السحابة- تتبع الشركات المالكة لتلك البرمجيات والتطبيقات، أو تتبع شركات استضافة تحجز تلك الحواسيب لمن يرغب في استضافة تطبيقه عليها سواء كان فردًا أو شركة. ويستطيع المستخدم أو فريق العمل الوصول إلى تلك التطبيقات من أي جهاز متصل بالإنترنت، وتنفيذ المهام المطلوبة دون الحاجة إلى امتلاك المستخدم لحاسوب بنفس القوة المطلوبة لتنفيذ المهمة، فما هو إلا منصة وواجهة أو طرفية يصل منها إلى الحاسوب البعيد القوي، وتُنفذ العمليات بالكامل على الحاسوب البعيد. أدوات تطوير البرمجيات بعد أن عرفنا أشهر الأنواع الموجودة في مجالات تطوير البرمجيات، نأتي الآن إلى الأدوات التي يستخدمها أولئك المبرمجون في تنفيذ أعمالهم وتطوير برمجياتهم. حاسوب يحتاج مطور البرمجيات إلى حاسوب لتطوير البرمجيات عليه، لذا إن كنت تفكر في تعلم تطوير البرمجيات ودخول هذا المجال فلابد من اقتناء حاسوب فهو أول وأهم أداة في هذه المهنة وهو بمثابة ماكينة الخياطة للخياط. قد تتساءل عن مواصفات الحاسوب المناسب، وهذا يعتمد على مجال تطوير البرمجيات الذي تريد التخصص فيه، وعمومًا إن كانت عملية التطوير لا تحتاج إلى تعامل مع رسوميات، فمعظم الحواسيب الجديدة حاليًا تفي بالغرض، وارجع إلى سؤال مواصفات الحاسوب الخاص بالبرمجة وسؤال الحاسوب المناسب لتعلم البرمجة ففيهما تفصيل في هذا الموضوع. لغة برمجة على عكس الاعتقاد الشائع أن المبرمج حين تأتيه فكرة برمجية فإنه يجلس ليكتب شيفرات برمجية وطلاسم على شاشة سوداء، فإن الواقع هو أن البرمجة في جوهرها حل لمشكلة تواجه المبرمج أو يطلب منه عميله أو شركته أن يحلها مستخدمًا أدوات التطوير البرمجي، وأشهر تلك الأدوات لا شك هو لغات البرمجة. وعلى كثرة اللغات البرمجية الموجودة إلا أن أكثرها يبنى على منهج معين أو منطق للغة بعينها وتشترك كلها بمفاهيم وقواعد واحدة وقد شرحنا معظمها في مقال قواعد البرمجة ببساطة للمبتدئين، لذا على المتعلم الجديد تعلم الأساسيات والمفاهيم والقواعد قبل البدء مباشرة بتعلم لغة برمجة. وكما في حالة أنواع مجالات التطوير البرمجي والبرمجيات التي تختلف أنواعها باختلاف بيئة التشغيل التي ستعمل عليها، فإن لغات البرمجة كذلك تختلف وفقًا لنفس بيئات التشغيل ومتطلبات العمل والمشكلة التي تحلها، وفيما يلي موجز يقسم لغات البرمجة وفقًا للمنصة التي تعمل عليها. عدة تطوير البرمجيات Development Kit يحتاج النجار إلى عدة نجارة فيها مفك ومطرقة ومسامير وغيرها، وكذلك مطور البرمجيات، فهو يحتاج إلى عدة لتطوير البرمجيات وقد تكون هذه العدة ملموسة مثل لوحة إلكترونية ومعالجات (راسبيري باي أو أردوينو مثلًا) لبناء برمجيات لأنظمة تحكم وقد تكون عدة برمجية أيضًا وهي مجموعة برمجيات يحتاج إليها المطور مثل محرر الشيفرات البرمجية أو بيئة التطوير البرمجية وأدوات تشغيل الشيفرة واختبارها. تختلف العدة باختلاف تخصص تطوير البرمجيات الذي تحدده لذا لا تشغل بالك حاليًا بها، وستتعرف عليها بمجرد اختيار التخصص المناسب لك. خطوات تطوير البرمجيات يبدأ العمل على تطوير التطبيقات بتحليل المشكلة أولًا التي تكون لدى العميل ويحتاج إلى تطبيق برمجي لحلها، ثم تمر بعدة خطوات ومراحل إلى أن تصل إلى المنتج النهائي. تحليل المشكلة يجمع المطور أو فريق العمل البيانات اللازمة عن المشكلة إما من المعطيات المتاحة التي يمكن جمعها أو من العميل مباشرة، ثم يحللها ليصل إلى سبب المشكلة وطرق معالجتها منطقيًا، وأفضل الأساليب والخوارزميات التي يمكن استخدامها لحل تلك المشكلة، وعلى ذلك يمكن اختيار الأدوات المناسبة ومنصات التشغيل التي سيعمل عليها التطبيق البرمجي. اختيار منهجية العمل لعل هذه لا تتغير من مشروع إلى آخر أو من تطبيق إلى آخر، وإنما تظل ثابتة لنفس فريق العمل أو نفس الشركة، وذلك لأنها تتعلق بنمط عمل الفريق نفسه وليس طريقة عمل التطبيق، وأشهر منهجيات العمل ما يلي: منهج الشلال Waterfall: تُكتب البرامج وفقًا لهذا المنهج على مراحل متتالية، بحيث لا يبدأ العمل في مرحلة إلا بعد تمام التي قبلها. المنهج المرن Agile: وهذا المنهج يقسم فريق التطوير إلى مجموعات يوكل إلى كل منها جزء من العمل، ويعملون في نفس الوقت لتقليل الوقت اللازم لإتمام المشروع، ويغلب على هذا المنهج أن يتبع العاملون فيه أسلوب Scrum، الذي يضع بعض القواعد لإدارة فريق العمل لضمان إتمام المشروع على أكمل وجه في أقصر مدة ممكنة. الجدير بالذكر هنا أن أسلوب العمل المرن وكذلك أسلوب Scrum لا يقتصران على تطوير التطبيقات البرمجية فقط، وإنما يتعديانها إلى كثير من المجالات الصناعية بما أنهما أسلوبين لإدارة المشاريع أصلًا وليسا مقتصرين على تطوير برمجيات، وارجع إلى مقال المراسم الأربعة لمنهجية أجايل Agile ceremonies لمزيد من التفصيل. النموذج الأولي Prototype بعد وضع أسلوب الحل الأمثل للمشكلة وتخطيط التفاصيل والخطوات العامة لحلها، وإسناد المهام إلى أعضاء الفريق البرمجي، يبدأ العمل على تنفيذ الشيفرات البرمجية والتصاميم المرئية وغيرها من العناصر المكونة للتطبيق النهائي. ثم يلتقي الفريق -أو المستقل مع العميل- في كل صباح أو كل فترة محددة لمناقشة ما تم إنجازه، وحل المشاكل التي طرأت، وتعديل سير العمل وفق المعطيات الجديدة. مرحلة الاختبار قد يبدأ العمل على اختبار البرمجية في بيئة التشغيل التي ستعمل عليها النسخة النهائية منه إما بعد الانتهاء من كتابة الشيفرات البرمجية والتصميم، أو أثناء العمل عليها إن احتاج الاختبار إلى العتاد الحقيقي وبيئة تشغيل حقيقية -الآلة أو الجهاز الذي سيعمل عليه التطبيق-، أو إلى بيئة تشغيل وهمية مثل المحاكيات، كما في حالة محاكيات نظم التشغيل والأجهزة المختلفة. يعود التطبيق أو البرمجية إلى مراحل سابقة من مراحل العمل وفقًا للمشاكل التي قد تظهر أثناء الاختبارات، وتُكرر دورة العمل مرة أخرى إلى أن ينجح التطبيق في تجاوز جميع مراحل التطوير. وقد يتطلب الاختبار أحيانًا عرضه على المستخدمين المحتملين لاختبار قابلية الاستخدام الشخصي للتطبيق، فقد يكون مكتوبًا بأفضل التقنيات البرمجية لكن المستخدم لا يستطيع استخدامه بسهولة، فحينئذ يكون الخلل في مرحلة تصميم تجربة الاستخدام، فيعود إليها من أجل تصميم تجربة استخدام سهلة للمستخدم النهائي. الإطلاق الأولي Soft Launch قد لا تظهر بعض المشاكل في بيئات الاختبار والمحاكاة مهما طالت، وقد يتعذر الوصول إلى مستخدمين محتملين، فيلجأ المطور إلى الإطلاق المرن التجريبي للتطبيق في بيئة التشغيل، مع مراقبة الأداء عن كثب، ومتابعة سلوك المستخدمين للتطبيق وسؤالهم ومراسلتهم إن تطلب الأمر لجمع البيانات اللازمة لتطوير بقية المزايا والخدمات في التطبيق، ولتصحيح الأخطاء التي قد تظهر مع الإطلاق الأولي. الإطلاق النهائي Hard launch في هذه المرحلة يكون التطبيق قد نضج، وتختلف المدة اللازمة لنضج التطبيق ووصوله إلى مرحلة الإطلاق النهائي وفقًا للتطبيق نفسه وحجم المزايا التي فيه، وبيئة العمل التي سيعمل فيها، فبعض البيئات لا تحتمل نسب الخطأ أو تكراره، كما في حالة الآلات التي سيحمَّل عليها التطبيق ولا سبيل للوصول إليه بعدها إلا بصعوبة بالغة، مثل السيارات والأجهزة المنزلية، أو لا يمكن السماح بنسبة خطأ كبيرة غير محسوبة، كما في حالة آلات المصانع والسيارات، وهكذا. لكن قد لا يكون هذا ضروريًا أو يمثل مشكلة في حالات تطبيقات الهواتف وأسطح المكتب وتطبيقات الويب المخصصة للمهام العادية، وهي ولله الحمد أغلب الحالات التي يطلبها العملاء في السوق، وتتراوح مدة العمل على التطبيقات فيها من أسبوعين إلى بضعة أشهر في الغالب. كيف تصبح مطور برمجيات؟ بعد أن تعرضنا إلى تفصيل مجال تطوير التطبيقات ينبغي أن تعلم أن السوق متعطش للغاية إلى العاملين المهرة في هذا المجال، وربما أكثر في العالم العربي بسبب ازدياد الشركات والعملاء وتطور الخدمات التي تعتمد على التقنيات البرمجية والبنى التحتية الرقمية في الأعوام الأخيرة، إضافة إلى إمكانية العمل عملاً حرًا كمستقل على منصات العمل الحر مثل مستقل وخمسات. وتحتاج إلى بعض المهارات الشخصية أولًا لتتميز في مجال تطوير التطبيقات، ثم إلى معرفة بالتقنيات والأدوات المطلوبة للعمل نفسه. المهارات الشخصية لمطور البرمجيات سنركز هنا على المهارات التي يحتاج إليها المطور خاصة والتي تفيده مباشرة في مسيرته المهنية كمطور، وليس المهارات العامة لأي عامل مستقل أو موظف. الطلب المستمر للعلم إن كان ثمة شيء ثابت في مجال تطوير البرمجيات لا يتغير، فهو أنه مجال دائم التطور والتجدد، فتخرج تقنيات جديدة كل يوم، وأساليب أفضل لتطوير البرمجيات، وربما أدوات جديدة أيضًا، وعلى المطور أن يكون مطلعًا على أحدث تلك الأدوات والوسائل لئلا يجد نفسه ابتعد عن المطالب التي يحتاج إليها العملاء أو يجد حصيلة المهارات التي لديه قد صارت لا قيمة لها بعد بضع سنين. وليهتم بدراسة علوم الحاسوب اﻷساسية التي تُبنى عليها التقنيات والأدوات الجديدة، ليسهل عليه استيعاب تلك التقنيات في بضعة أيام ثم بدء العمل بها مباشرة، فكم رأيت من مبرمج درس القواعد والأساسات الخاصة بعلم الحاسوب، فلما احتاج إلى تطوير تطبيق للهواتف مثلًا عكف على تعلم لغة البرمجة Swift فدرس أساسياتها ثم عمل مباشرة على التطبيق بعد أسبوع من دراستها، لأنه يعلم منطقها والأساسات التي بنيت عليها كما بينا من قبل في هذا المقال. وكذلك قد يتعرض المطور لمشروع يحتاج إلى تعلم تقنية جديدة عليه أو خارجة عن مجاله بالكلية، كأن يتعلم تقنيات تهيئة المحتوى مثلًا وهو يعمل مطورًا في الواجهات الأمامية أو الخلفية لتطبيقات الويب، وذلك لتصميم الموقع أو التطبيق وفق أحدث إرشادات محركات البحث وقواعدها التي تصنف المواقع وفقًا لها. التفكير المنطقي ذكرنا من قبل أن البرمجة في جوهرها هي حل للمشاكل، وما لغات البرمجة إلا أدوات تخرج تلك الحلول إلى النور، فإذا كنا نحتاج إلى معالجة معطيات تدخل إلينا بسرعة عالية، وبكميات كبيرة، واختيار المعطيات التي تحمل أسماء معينة أو خصائص س وص، فكيف نحل هذه المشكلة؟ الأمر الجميل في البرمجة أن أغلب المشاكل التي ستواجه المطور قد واجهت غيره من قبل، ووُضعت لها الحلول وصُنفت فيها الكتب والتوثيقات، لهذا كانت مهارة حب العلم لازمة للمطور، فسيجد أغلب وقته يقرأ مبحرًا في التوثيقات البرمجية ومناهج حل المشاكل المنطقية للبرمجيات. فمثلًا، ينبغي أن يكون مطلعًا على أنماط التصميم البرمجية التي تحل أغلب المشاكل في البرمجيات بمناهج تمثل قواعد يمكن تطبيقها على نفس نوعية المشاكل بغض النظر عن بيئة تطبيقها، وعلى أفضل الخوارزميات المستخدمة في تصنيف المعطيات واتخاذ القرار بشأنها، وهكذا. وقد فصلنا كثيرًا حول هذه النقطة في مقال حل المشكلات وأهميتها في احتراف البرمجة فارجع إليه لمزيد من الفائدة. المهارات التقنية ذكرنا أن المطور عليه أن يكون ملمًا بأساسيات علوم الحاسوب، ثم ينتقل بعدها إلى الأدوات التي سيستخدمها في بيئة عمله التي يختارها سواء كانت تطويرًا لتطبيقات الويب أو الهواتف أو تطبيقات أسطح المكتب أو غيرها، ليتعلم اللغات البرمجية وأطر العمل التي يحتاج إليها. يمكن كسب المهارات التقنية وتعلمها من عدة مصادر منها الدراسة الجامعية والدورات التعليمية، وعادة تكون الدراسة الجامعية طويلة أربع سنوات على الأقل ومليئة بالمواد النظرية البعيدة عن سوق العمل، أما الدورات التعليمية المتخصصة فقد أصبحت الأسلوب الشائع لدخول مجال هندسة وتطوير البرمجيات لأنها تعطي المتعلم ما ينفعه لبناء البرمجيات ودخول سوق العمل وأجمل ما في الأمر أن الشهادات التي تُعطى فيها معترفة وتغني عن الشهادة الجامعية. وقدمت أكاديمية حسوب الكثير من تلك الدورات التعليمية المتخصصة الاحترافية لتعلم تطوير البرمجيات ودخول سوق العمل مباشرةً، مثل دورة علوم الحاسوب لتعليم أساسيات ومفاهيم مجال علوم الحاسوب بالكامل ودورة تطوير التطبيقات باستخدام لغة Python لتعلم تطوير تطبيقات للويب أو لسطح المكتب أو دورة تطوير التطبيقات باستخدام لغة JavaScript وغيرها وارجع إلى صفحة الدورات التعليمية للاطلاع على كافة الدورات الموجودة. سوق العمل كمطور برمجيات بعد أن يتعلم المطور التقنيات التي يحتاج إليها والمهارات اللازمة لشق طريقه في سوق العمل، يستطيع أن ينطلق مباشرة إلى السوق إما في صورة عمل حر من خلال تقديمه لخدمات تقنية وبرمجية على منصة خمسات، أو تقديمه لعروض على المشاريع التقنية في منصة مستقل، ومزية العمل الحر هنا أنه يوفر للمطور فرصة لإنشاء معرض أعمال متميز من سوابق الأعمال، وكذلك الاحتكاك المباشر بالعملاء لاكتساب الخبرات والمهارات اللازمة للتفاوض وإدارة المشاريع، وهي المهارة التي يستطيع تعلمها من دورة إدارة تطوير المنتجات أيضًا ليتعرف على كيفية دراسة السوق وتحليل المنافسين ومتطلبات العملاء، ومراحل الإدارة المختلفة للمشاريع التقنية. أو إذا أراد، يمكنه التقديم على الوظائف البعيدة التقنية لمطوري التطبيقات عبر منصة بعيد، لتكون عملًا نظاميًا بدوام جزئي أو كلي، على عكس العمل الحر كما في منصتي مستقل وخمسات. خاتمة رأينا في هذا المقال مرورًا سريعًا على مجال تطوير التطبيقات البرمجية، وحاجة السوق إليه، وأنواع تطوير التطبيقات ومنصاتها، والمهارات التي يحتاج إليه المطور في عمله. وربما لا توجد عبارات تصف مدى حاجة السوق العالمي عمومًا والعربي خاصة إلى مطوري التطبيقات المهرة هذه الأيام، والأفضلية التي تكون لهؤلاء في السوق إذ لا تحدّهم حدود جغرافية، ولا أزمات محلية، بل تُفتح لهم فرص العمل بأجور تنافسية عالية موازنة ببقية الوظائف، مع عملاء من مختلف الدول. اقرأ أيضًا تعلم البرمجة تعرف على تخصص هندسة البرمجيات دليلك الشامل إلى برمجة التطبيقات مقال دليلك الشامل إلى تعلم البرمجة دليل المبتدئين لمنهجية أجايل Agile
  5. سنتحدث عن تصميم موقع إلكتروني بشكل عام في هذا المقال، ولكن يجب أن نوضح أن مجال بناء المواقع الإلكترونية يتفرع إلى فرعين أساسيين هما تصميم المواقع وتطويرها، فتصميم المواقع يختص بترتيب العناصر المرئية واختيارها وتخطيط سلوك المستخدم وتجربته من حيث طريقة تفاعله مع الموقع وكيفية استقباله لرسالته التي أنشئ من أجلها، أما تطوير المواقع فيختص بتحويل تلك التصاميم المرئية إلى أكواد وشيفرات برمجية يخرج منها منتجات جاهزة للإطلاق. ورغم تشعبات هذا المجال التي تتزايد كل حين إلا أن أغلب حديث العملاء عند الرغبة في تصميم مواقع لهم سيدور حول التصميم المرئي للعناصر والنماذج وترتيبها على الشاشة، وكيفية ظهور الموقع على الشاشات المختلفة سواء كانت حواسيب أو هواتف أو غيرها، وطريقة تفاعل المستخدم مع عناصر الموقع. خطوات تصميم موقع إلكتروني وبنائه نلاحظ أننا ذكرنا نوعين من أنواع تصميم المواقع في الفقرة السابقة، وهما التصميم المرئي وتصميم تجربة الاستخدام، وهما يشبهان الهندسة المعمارية للمباني حيث يرى المستخدم آثارهما مباشرة عند تفاعله مع الموقع من حيث تنسيق الواجهة وترتيب العناصر وتناسق الألوان والتفاعلات الموجودة فيها. كذلك فإن هذين النوعين من التصميم هما أول مرحلتين من مراحل تصميم مواقع الإنترنت أو التطبيقات الموجهة للهواتف أو غيرها من الأجهزة، ثم يأتي بعدهما تطوير الواجهات سواء الأمامية أو الخلفية. 1. تصميم تجربة الاستخدام يختص مصمم تجربة الاستخدام User Experience (UX) بدراسة الفئات المستهدفة من الموقع، وحالاتهم الصحية والنفسية وأعمارهم وجنسياتهم، وذلك من خلال بحوث عميقة لطبيعة نشاط العميل والموقع والأهداف التي يجب أن يحققها الموقع أو التطبيق المراد إنشاؤه، من أجل توجيه انتباه المستخدم إلى العناصر التي يريد له صاحب الموقع أن يهتم بها أو يراها، إضافة إلى تخطيط تجربة استخدامه عمومًا داخل الموقع. وتظهر أهمية هذا المجال عند تصميم مواقع طبية مثلَا لا تراعي فئات المستخدمين التي لديها مشاكل في النظر أو القراءة أو السمع، فلا يراعي تهيئة الموقع لتلك الفئات من المستخدمين، فهل تتخيل موقعًا لمستشفى للأطراف الصناعية فيه الكثير من الحقول التي على المستخدم ملؤها في استمارة حجز موعد في مستشفى؟ ويضع مصمم تجربة الاستخدام الخريطة التأسيسية للموقع، وكيف يجب أن يكون التصميم المرئي للواجهة، وترتيب كل قسم رئيسي وفرعي فيه، وعدد النقرات التي ينقر عليها المستخدم للوصول إلى العناصر الهامة في الموقع، والألوان التي يجب استخدامها، وأحجام الأزرار والعناصر، وهكذا. 2. تصميم واجهة المستخدم يأتي مصمم واجهة المستخدم User Interface (UI)‎ ليعمل على هذه النسخة التي أخرجها مصمم تجربة الاستخدام مسترشدًا بها، فيصمم الواجهة النهائية التي يراها المستخدم من قوائم وأزرار وألوان وغيرها وفق مبادئ تصميمية تحقق أهداف تجربة الاستخدام. قد يتخصص مصمم الواجهات المرئية في تصميم العناصر المرئية فقط إذا كان يعمل في شركة كبيرة وفي فريق تصميم كبير، لكن الغالب أنه يتجاوز هذه المرحلة إلى تصميم مواقع الإنترنت بحيث تكون تفاعلية، تستطيع بقية الفرق أن يتفاعلوا معها ليعرفوا الأثر المطلوب تنفيذه عند النقر على أحد الأزرار، أو كي يستطيع العميل أن يرى نسخة شبه حية من الموقع قبل البدء في تطويره وبنائه. 3. تطوير واجهة المستخدم بعد تمام مرحلة تصميم المواقع أو التطبيقات بحيث يكون لدينا نسخة مرئية جاهزة منها، ينتقل العمل إلى مطور الواجهات الأمامية Front End Development الذي يعمل على برمجة هذه الواجهات لتتحول من مجرد تصميمات إلى نسخة حية من الموقع يستطيع العميل أن يتفاعل معها بنفس كيفية تفاعل المستخدم النهائي معها. ويستخدم لغات وصفية مثل HTML وبرمجية مثل جافاسكربت لإتمام عمله، إضافة إلى أطر عمل Frameworks لئلا يعيد اختراع العجلة من الصفر في المهام المكررة. ومطور الواجهات الأمامية هو المسؤول عن إنشاء التأثيرات المرئية للأزرار والقوائم والانتقالات في الصفحة الواحدة وبين الصفحات. 4. تطوير الواجهة الخلفية ينشئ مطور الواجهة الخلفية قواعد البيانات التي تلتقط بيانات المستخدم من نماذج التسجيل وبيانات وصور وغيرها لتخزينها وتصنيفها ثم جلبها للمستخدم عند الحاجة، وكذلك الخوادم التي تكون عليها المواقع نفسها وقواعد بياناتها. وتختلف أهداف المطورين عن المصممين في أنهم يولون أهمية كبيرة لسرعة تحميل الموقع والعناصر التي فيه، وكذلك كفاءة التشغيل للخوادم لئلا تكون عرضة للاختراق أو التعطل، على عكس المصممين الذين يهتمون بتفاعلات المستخدم مع الواجهة اﻷمامية، وسهولة فهمه للمطلوب من الموقع أو التطبيق، وسرعة وصوله للمعلومات التي يحتاج إليها بأقل عدد من النقرات والإجراءات. الأدوات المستخدمة في تصميم موقع يشترك مصمم تجربة الاستخدام ومصمم الواجهات المرئية في بعض البرامج التي يستخدمونها في تصميم المواقع، لكن توجد بعض البرامج والأدوات التي ينفرد بها كل منهما، وفيما يلي أشهر تلك البرامج. Adobe XD يُستخدم برنامج Adobe XD من حزمة أدوبي لإنشاء نماذج أولية للمواقع والتطبيقات إما ثابتة أو تفاعلية، إضافة إلى مزية التعاون بين المصممين على نفس التصميم. Figma يسمح برنامج Figma ببناء نماذج أولية أيضًا للمواقع والتطبيقات واختبار قابلية استخدامها -وهو أمر ضروري لمصممي تجربة الاستخدام-، وهو أيضًا بيئة تفاعلية يستطيع فيها المصممون التعاون في العمل على نفس المشروع في نفس الوقت -مثل العمل المشترك على تطبيقات جوجل السحابية-، مما يعني أنه ليس تطبيقًا مستقلًا وإنما يعمل داخل المتصفح. ‎FlowMapp - Octopus‎ هذان التطبيقان يعملان في المتصفح أيضًا، ويُستخدمان في إنشاء خريطة تدفق Flow map لسلوك المستخدمين في التطبيقات، وكذلك مخططات التطبيقات وخرائط المواقع، كي تكون واضحة لبقية فرق العمل من مصممي الواجهات المرئية والمطورين، مما يعني أن هاتين اﻷداتين لمصممي تجربة الاستخدام خاصة. ‎Balsamiq‎ تُستخدم هذه الأداة لإنشاء إطارات سلكية Wireframes للموقع أو التطبيق، وهي كذلك لمصممي تجربة الاستخدام، حيث يستخدمونها لإنشاء تصميمات بسيطة لعناصر وتقسيمات الموقع أو التطبيق دون تشتيت بقية فرق العمل بتفاصيل العناصر من نصوص وأيقونات وألوان وغيرها. Adobe Ai أبقينا هذا البرنامج إلى نهاية القائمة ربما لإمكانياته الكبيرة، حيث يمكن تنفيذ أغلب مهام البرامج والأدوات السابقة فيه، وهو أقدم هذه الأدوات في سوق التصميم وأشملها، وكذلك أشهرها بين مصممي تجربة الاستخدام والواجهات المرئية على حد سواء. اللغات المستخدمة في تطوير المواقع نأتي إلى اللغات التي يستخدمها المطورون لتحويل التصميمات المرئية إلى تطبيقات حية جاهزة للإطلاق في السوق، وسنبدأ بمطوري الواجهات الأمامية أولًا ثم ننتقل إلى الواجهة الخلفية. HTML لا تُعد لغة HTML لغة برمجة وإنما هي لغة توصيفية تُستخدم لإنشاء هيكل واضح لصفحات الويب، فهي التي تحدد أن هذا النص عنوان وذاك نص عادي، وهذه قائمة غير مرتبة، وبالمثل تحدد بقية العناصر من روابط تشعبية وصور وأقسام في الصفحة وغيرها. لعل HTML هي أبسط اللغات في تعلمها إذ قد لا تستغرق بضعة أيام لفهم أساسياتها ومن ثم البناء بها أو الانتقال إلى بقية اللغات. CSS لغة CSS هي لغة تنسيق تضفي بعض مظاهر الحياة على صفحات الويب مع توحيد مظهر تلك الصفحات في نفس الوقت، وكذلك تُستخدم لإنشاء تصميمات متجاوبة responsive للمستخدمين لتناسب الأجهزة التي يتصفحون منها سواء كانت هواتف محمولة أو حواسيب لوحية أو حتى أجهزة سطح المكتب. تكمن فائدتها الأساسية في أن شيفرتها توضع في ملف منفصل عن HTML، ثم تُكتب فيها القوانين العامة لتصميم الموقع، مثل تنسيق العناوين الرئيسية وألوانها وحجم خطوطها، حتى إذا أردنا تغيير ذلك التنسيق لجميع العناوين غيرناه مرة واحدة في ملف CSS، بدلًا من تغييره في كل صفحة على حدة، وهكذا في بقية عناصر الصفحات من تنسيق الأزرار والألوان ومحاذاة النصوص مثلًا. جافاسكربت Javascript تأتي لغة جافاسكربت لتكمل أغلب الجوانب التي تبقى في عملية تطوير الويب سواء للواجهة الأمامية أو الخلفية، سواء باللغة نفسها أو بأطر العمل frameworks التي بُنيت عليها، فهي لغة برمجة أصيلة -ليست وصفية مثل HTML- تُستخدم لإنشاء تفاعلات من الموقع مع إجراءات المستخدم، إما باستخدام جافاسكربت نفسها أو أحد أطر العمل المشهورة التي بُنيت عليها، مثل أنجولر Angular و jQuery و Vue.js. وتُستخدم بعض أطر العمل تلك لبناء خدمات وتطبيقات تعمل في الواجهة الخلفية أيضًا للمواقع، مثل أنجولر Angular و Vue.js، إضافة إلى أطر عمل مثل Next.js. لغات أخرى يمكن استخدام العديد من لغات البرمجة وأطر العمل لتصميم مواقع الإنترنت وتطويرها، فمثلًا يُستخدم إطار العمل جانغو Django المكتوب بلغة بايثون لكتابة تطبيقات للويب، وكذلك إطار العمل Ruby-on-rails المكتوب بلغة روبي Ruby، وهكذا، فلم يعد الأمر مقصورًا على لغة جافاسكربت وحدها لإتمام عملية بناء الموقع. ويتوقف قرار اللغة المستخدمة في بناء الموقع وكذلك إطار العمل على طبيعة المشروع المطلوب والعميل والبيئة التي سيعمل فيها والتطورات المستقبلية له، لكن تظل جافاسكربت هي اللغة اﻷشهر المستخدمة في تطوير واجهات الويب أو الواجهات الأمامية لمواقع الإنترنت. الأدوات المستخدمة في تطوير الواجهات الأمامية يحتاج مطورو المواقع الإلكترونية إلى بيئات أو أدوات يستخدمونها لكتابة شيفراتهم البرمجية، وبيئات أخرى لاختبارها، وفيما يلي أمثلة لأهم هذه الأدوات. المحررات النصية Text Editors وهي برامج كتابة نصوص بسيطة مثل Notepad، لكنها تكون موجهة للمبرمجين والمطورين، فتتميز بتمييز النصوص بصريًا وفقًا لنوعها ليسهل قراءتها، وكذلك الإكمال التلقائي للنصوص، وغيرها من المزايا المخصصة لتطوير المواقع والتطبيقات، وأشهر هذه المحررات ما يلي: ‎Vim‎ ‎Emacs‎ ‎Notepad++‎‎ ‎Sublime Text‎ بيئات التطوير المتكاملة IDEs تختلف بيئة التطوير عن المحرر النصي العادي في أنها أشمل وأكثر تكاملًا، فإضافة إلى المحرر النصي فإنها تحتوي على مصرِّف compiler و منقِّح debugger وأداة لبناء واجهات المستخدم المرئية، كما تدعم عدة لغات أحيانًا مثل بايثون و PHP وروبي Ruby و جافاسكربت وغيرها. فيما يلي أهم بيئات التطوير المستخدمة في تطوير المواقع: ‎Visual Studio Code‎ ‎IntelliJ IDEA‎ ‎Aptana Studio 3‎ ‎Eclipse‎ ‎NetBeans‎ ‎Webstorm‎ خاتمة مواقع الإنترنت هي المقرات الافتراضية للشركات والمؤسسات، وهي عنصر لابد منه في العلامة التجارية لأي كيان له نشاط على الويب أو على الأرض، سواء كان ذلك شركة أو مؤسسة أو حتى فردًا مستقلًا. وترغب هذه الكيانات بإنشاء مواقع لها لبيع منتجاتها أو الترويج لأنشطتها والتعريف بها، أو توجيه جمهورها إلى استخدام تطبيقات مخصصة للهواتف، أو حتى لمجرد حجز خدماتها والتواصل من خلالها، إضافة إلى أن وجود موقع إنترنت يرفع كثيرًا من سمعتها لدى محركات البحث، مما يعني تصدرًا لنتائج البحث وشهرة أكثر. وقد ذكرنا في بداية المقال أن العملاء يولون أهمية خاصة لتصميم الموقع الذي يريدون له أن يعكس هويتهم التي تمثلهم، وتحمل روح المؤسسة أو الشركة من حيث جدية التصميم أو حداثته أو غير ذلك، وكذلك مناسبته للفئات المستهدفة منه. وعلى ذلك ينبغي أن يطلع المصمم -إلى جانب إلمامه بالجوانب الفنية الخاصة بعمله- على أصول إدارة المنتجات الرقمية، خاصة إن كان يوظف مطورين آخرين للعمل معه أو كان يدير فريق تصميم، وكذلك على أسس التعامل مع العملاء ليفهم احتياجاتهم ويوصل لهم رأيه المهني بالطريقة المثلى. إقرأ أيضا تعلم أساسيات البرمجة تعلم البرمجة كيف تتعلم البرمجة: نصائح وأدوات لرحلتك في عالم البرمجة برمجة مواقع الويب: دليلك المختصر مبادئ تصميم واجهة المستخدم UI الجيدة قواعد تصميم واجهة المستخدم
  6. تمثل المتاجر الإلكترونية واجهات بيع رقمية للشركة أو فروع جديدة لها، وتتفوق على مثيلاتها التي تكون على الأرض في أن تكلفة إنشائها لا تكاد تُذكر مقارنةً بتكاليف تجهيز فرع حقيقي، وتكون أغلب عمليات البيع فيها آلية لا تحتاج إلى نفس العمالة المطلوبة للمتاجر الحقيقية. لذلك بات من الضروري العمل على تصميم متجر إلكتروني لمواكبة هذا التطور والاستفادة منه. ويمثل متجرك الإلكتروني المتاح في دولة ما للتصفح والشراء وتوصيل المنتجات فرعًا لك في تلك الدولة، وتلك مزية عظيمة لمن يرغب في زيادة معدلات البيع والربح والتوسع لأسواق جديدة، وعلى ذلك ينبغي الاهتمام بتصميم المتاجر الإلكترونية وتنسيق تجربة الاستخدام فيها لتكون سلسة ومريحة لمن يتصفحها بغض النظر عن المنصة التي يدخل منها، سواء في طريقة تصميم المنتجات وترتيبها، أو وسائل الدفع المتاحة، أو تصميم المتجر البصري من حيث الألوان المستخدمة وإمكانية التصفح من الهاتف. وأن تكون عملية إدارة المتجر نفسها سهلة ليس فيها تعقيد تقني بحيث يعيق المعاملات اليومية، وذلك باستخدام أنظمة التجارة الإلكترونية المشهورة مثل ووكومرس Woocommerce وشوبيفاي Shopify على سبيل المثال لا الحصر، وأنظمة إدارة الموارد للشركات Enterprise resource planning (ERP) مثل أودو Odoo. مراحل تصميم المتجر الإلكتروني قبل البدء في بناء المتجر الإلكتروني نفسه ينبغي أن ننظر أولًا في عدة عوامل للاعتبار بها أثناء التصميم، وهي توجه قرارات التصميم والبناء التقنية لاحقًا مثل اللغات البرمجية وأطر العمل التي يجب استخدامها، ووسائل الدفع الممكنة وفقًا للمستخدمين والدولة التي يتصفحون منها، وطبيعة المنتجات المعروضة على المتجر نفسه. دراسة السوق المستهدف للمتجر الإلكتروني يجب معرفة النموذج التجاري الخاص بالشركة لتحديد تجربة الاستخدام المناسبة ونموذج الربح الخاص بالمتجر إن كان ربحًا مباشرًا أم وساطة فقط بين طرفين، ويغلب على المتاجر الإلكترونية أن تكون أحد الأنواع التالية: متاجر تبيع من الشركات للشركات Business to Business (B2B). متاجر تبيع من الشركات للأفراد Business to Consumers (B2C). لكن توجد أنواع أخرى أقل شهرة، مثل المتاجر التي يبيع فيها الأفراد للأفراد C2C، ويكون الموقع مجرد وسيط يضمن المعاملة فقط، أو متاجر تبيع من الأفراد إلى الشركات C2B. تحديد فئات المستخدمين ثم ننظر بعدها في فئات الجمهور المستهدف من المتجر أولًا قبل بنائه لتحديد وسائل الدفع المناسبة لهم، وتجربة الاستخدام المناسبة إن كانوا يتصفحون من هواتف ذكية أم حواسيب مكتبية. وتؤثر تلك العوامل في كيفية تصميم تجربة الاستخدام للمتجر ككل، وينبغي هنا إدارج سلوك الشركة صاحبة المتجر في الحسبان إن كان لها متاجر حقيقية على الأرض، إذ يغلب أن يكون المتجر الإلكتروني انعكاسًا للهوية البصرية على الأرض. كذلك فإن معرفة الخبرة التقنية المتاحة لمن سيدير المتجر الإلكتروني توجه قرار اختيار نظام المتجر الإلكتروني، سواء كان شوبيفاي Shopify أو ووكومرس Woocommerce أو ماجنتو Magento أو غيرها من أنظمة إدارة المتاجر الإلكترونية، ونظام إدارة المحتوى مثل ووردبريس. كما أن قرار تصميم الواجهة الأمامية للمتجر الإلكتروني يتحكم فيه نوع العميل نفسه إن كان المتجر يبيع لمستهلكين أفراد أم لشركات، وإن كان يبيع منتجاته أم منتجات لشركات أخرى. اختيار منصة التجارة الإلكترونية المناسبة تفضل المتاجر الصغيرة أو الناشئة استخدام أنظمة إدارة جاهزة مثل شوبيفاي Shopify و ووكومرس Woocommerce، خاصة الثانية التي يمكن تثبيتها من خلال لوحة التحكم في نظام إدارة المحتوى الشهير ووردبريس Wordpress لموقعك، وهذا يعني أنها ستكون أقل تكلفة من الخيارات الأخرى مثل Shopify أو أنظمة الإدارة الكبيرة مثل Odoo. وتلك الأنظمة الجاهزة تدخل تحت نطاق البرمجيات الخدمية Saas، التي لا تحتاج إلى خبرة برمجية متخصصة أو توظيف مبرمجين، لكن في حالة المتاجر التي تحتاج إلى إعدادات مخصصة تكون الخيارات المتقدمة مثل أودو Odoo هي الأفضل، لكنها تحتاج إلى مبرمجين متخصصين في أنظمة إدارة الأعمال، حيث يمكن بناء تطبيقات وإضافات خاصة بمتجر الشركة. تصميم متجر إلكتروني احترافي تتعدد التقنيات المستخدمة في تصميم تطبيق متجر إلكتروني احترافي وفقًا لطبيعة المتجر الإلكتروني والجمهور المستهدف وقرار الشركة صاحبة المتجر وفقًا للأدوات التي تفضلها. اختيار التقنيات المناسبة لبناء المتجر قد يُستخدم إطار العمل Django مثلًا في بنائه ويُربط مع بوابات دفع مثل باي بال PayPal و سترايب Stripe، وهذا يعني أن لغة بايثون هي التي ستُستخدم، كذلك يمكن استخدامها لتطوير إضافات برمجية لاستخدامها مع نظام أودو Odoo لإدارة الأعمال. أو قد يُبنى المتجر باستخدام ووكومرس WooCommerce كما ذكرنا في شأن مواقع ووردبريس، فيحتاج إلى تطوير قوالب وإضافات له وفقًا لحاجة العميل أو الشركة صاحبة المتجر، وحينئذ تُستخدم لغة مثل PHP. دورة تطوير تطبيقات الويب باستخدام لغة PHP احترف تطوير النظم الخلفية وتطبيقات الويب من الألف إلى الياء دون الحاجة لخبرة برمجية مسبقة اشترك الآن تصميم تجربة الاستخدام للمتجر بعد أن تقرر التقنية المناسبة لبناء المتجر الإلكتروني باستخدامها، ينبغي النظر في عدة عوامل تدور بين تجربة المستخدم والتسويق للمتجر، وذلك من أجل إنجاح تجربة الشراء والاستخدام للعميل الذي يتصفح الموقع، ومن أجل تقليل فترة التسويق التي تسبق بدء تحقيق الأرباح الحقيقية. الواجهة البسيطة المرتبة لا تستقبل العميل بالرسائل المنبثقة، والأقسام غير المرتبة والخطوط المزعجة، فإن هذا يشتت العميل أولًا ويزيد من فرصة خروجه من الموقع دون إتمام عملية الشراء ثانيًا، فهذا يشبه دخوله إلى متجر حقيقي سيء التصميم والديكور، والمنتجات غير مرتبة، ويقفز الموظفون في المتجر في وجه العميل ليقاطعوا تجربة الشراء. كذلك ينبغي الاهتمام بتسهيل خطوات تصفح المنتجات إلى إتمام عملية الشراء، ذلك أن أي تأجيل فيها أو تعطيل قد يؤدي إلى ترك العميل للمتجر بالكلية، وهذا يشبه دخول متجر أرففه خالية من المنتجات إلا قليلًا، وموظف التحصيل غير موجود! التصفح من الهاتف صار من البداهة الآن أن يبدأ التصميم لمن يتصفح من الهاتف أولًا، سواء كان للمتجر تطبيق مخصص للهواتف أم كان التصفح من نسخة الويب، فينبغي تحسين تجربة الاستخدام من الهاتف لتكون مماثلة لتجربة الاستخدام الخاصة بسطح المكتب، وكذلك لتكون واحدة بين الأجهزة المختلفة. فنتجنب الاهتمام بمنصة على حساب الأخرى، كالاهتمام بتطبيق المتجر على هواتف أيفون مثلًا وإهمال تجربة الاستخدام على أندرويد إن كان للمتجر تطبيق مخصص، أو إهمال تجربة الاستخدام من متصفح الويب للهاتف إن كان التصميم متجاوبًا وموجه لسطح المكتب والهاتف معًا. وهذه النقطة غاية في الأهمية، إذ يجب توحيد عناصر تجربة الاستخدام بين تلك المنصات من سرعة التصفح والأيقونات وطريقة استخدام المتجر لئلا يختلف سلوك المستخدم بينها فيتشتت أو يصاب بالحيرة، فهذا قد يصرفه عن استخدام المتجر بالكلية. خاتمة لا شك أن التطور الطبيعي لبيئة مثل الإنترنت أن تنتقل المعاملات الحقيقية أو أغلبها إليه، وعمليات البيع والشراء ودخول الأسواق الجديدة للشركات والمتاجر عبر الإنترنت من أهم تلك المعاملات، إذ سمحت للشركات والمتاجر بالوصول إلى أسواق بعيدة عنها دون الحاجة إلى الذهاب إليها وافتتاح فروع حقيقية فيها، فقد سهلت الخدمات اللوجستية كثيرًا من عمليات الشحن الدولية، وبقي أن يكون لدى الشركة واجهة رقمية في صورة متجر إلكتروني تعرض فيه منتجاتها. وإذا كنت تريد تصميم متجر إلكتروني لموقع ووردبريس قائم بالفعل وتريد استخدام ووكومرس له فربما تود النظر في دورة تطوير تطبيقات الويب بلغة PHP، حيث ستتعلم كيفية إنشاء المتاجر الإلكترونية وبناء نظم إدارة المحتوى وقوالب ووردبريس. كذلك فإن دورة تطوير واجهات المستخدم تحتوي على قسم كامل لتطوير واجهة استخدام حقيقية من الصفر لمتجر إلكتروني، وهي مناسبة لمن ليس له خبرة مسبقة في تطوير المواقع وواجهات المستخدم ويريد أن يبدأ فيها. أما إذا كنت تريد تطوير متجر إلكتروني مخصص وتطوير قوالب وإضافات له، أو حتى العمل على نظم إدارة الأعمال الكبيرة ERP مثل Odoo، فربما تود الاطلاع على دورة تطوير التطبيقات بلغة بايثون، حيث ستتعلم تطوير متجر إلكتروني باستخدام جانغو Django، وتطوير متجر إلكتروني وبناء إضافات برمجية لاستخدامها مع نظام أودو Odoo لإدارة الأعمال. إقرأ أيضا الدليل الشامل لأشهر أنظمة إنشاء وإدارة المتاجر الإلكترونية المدخل الشامل لتعلم تطوير الويب وبرمجة المواقع دليلك لتصميم متجر وموقع تجارة إلكترونية على شبكة الإنترنت الخطوات الابتدائية لإنشاء متجرك الإلكتروني: عنوان المتجر وحجز النطاق (Domain) دليلك لتصميم موقع لمتجر إلكتروني إنشاء متجر إلكتروني باستخدام نظام أودو Odoo
  7. يدرك البشر أهمية المراقبة الدقيقة لمن يصل إلى الموارد المهمة فيقيدون ذلك بشروط وحدود واضحة، ولا ريب أن المعلومات والبيانات من أهم تلك الموارد، فيضع صاحبها قيودًا لتحديد من يستطيع الوصول إلى تلك المعلومات وكيفية وصوله إليها، من أجل ضمان أمن المعلومات التي يريد حفظها، سواء ذلك في قديم تاريخ البشرية أو حديثها، وإن كنا نركز هنا على المعنى المشهور الحديث لأمن المعلومات، وهو الأمان الرقمي للمعلومات المتداولة عبر الإنترنت. أهمية أمن المعلومات الرقمية وقد برزت الحاجة الملحة إلى تطوير أمن المعلومات مع التقدم التقني الواضح في كل من العتاد الحوسبي والبرمجيات التي تعمل عليها، والاعتماد المتزايد للأفراد والشركات على تقنيات المعلومات في تنفيذ عملياتها اليومية من معاملات مالية وحسابات وتوثيقات ونقل لملفات ومتابعة لسير العمليات في الشركات وغيرها، فضلًا عن المجالات الحساسة مثل المجالات العسكرية والطبية التي تتأثر أبلغ الأثر بالتلاعب فيها أو الوصول إليها لمن لا ينبغي لهم ذلك. أمن المعلومات ما قبل شبكة الإنترنت كانت البيانات قبل عصر الإنترنت حبيسة الغرف والبيوت والمباني، فتكون بيانات المواطنين مثلًا محفوظة في سجلات داخل مباني الدولة في المدينة أو البلدية، ولا يستطيع أحد أن يصل إليها ما لم يدخل المبنى ويطلع على السجلات، أو إلى وسائل نقل تلك البيانات من مركبات وطائرات وغيرها، أو من يستطيع التجسس على وسائل الاتصال الهاتفية أو الاجتماعات ونقل ما يجري فيها، وكان يكفي لضمان أمن المعلومات تحصين مباني السجلات وحجب تلك الاجتماعات عن الأنظار أو تقييد من يحضرها أو تمويه وسائل نقل البيانات من سيارات أو مركبات أو أفراد، أو تشفير الاتصالات الهاتفية واتصالات الراديو لحجب محتوياتها عمن يتجسس عليها. وهذا المثال لأمن المعلومات الخاصة بالدولة ينطبق على أمن المعلومات الخاص بالأفراد أيضًا، حيث لم يكن يستطيع أحد أن يطلع على محادثة بين اثنين إلا إن كان هو ثالثهما أو يتجسس عليهما، ولم يكن لأحد أن يصل إلى وثائق وصور وأموال الأفراد إلا أن استطاع دخول بيته أو اقتحامه. أمن المعلومات بعد شبكة الإنترنت أما مع نقل بيئة تلك المعلومات إلى فضاء الإنترنت الواسع، فقد اتسعت دائرة التهديدات اتساعًا رهيبًا بحيث صارت وسائل الحماية التقليدية غاية في السذاجة، ووجب استحداث تقنيات تشفير للبيانات وتحقق من سلامتها، ومن يصل إليها، وتوفير سجلات ترصد تغير البيانات والتعديل فيها لمعرفة من عدَّل عليها ومتى وطبيعة التعديل الذي حدث. وباستخدام مثال سجلات الدولة في النقطة السابقة، فقد أصبحت تلك السجلات موجودة في حواسيب متصلة بالإنترنت، وعلى خوادم قد توجد داخل حدود الدولة أو خارجها -تشترط بعض الدول من شركات الحوسبة السحابية التي تستضيف سجلاتها أن تكون بيانات مواطنيها داخل حدود الدولة- فإن استطاع شخص اختراق الوسائل الموضوعة لحماية أمن المعلومات هنا فسيصل إليها بسهولة تامة وينسخها إلى حاسوبه، حتى لو لم يكن هو نفسه داخل الدولة أو القارة حتى الموجودة فيها تلك المعلومات، على عكس ما كان يحدث من قبل إذ كان يضطر المخترق إلى التواجد في مكان تخزين تلك البيانات وتحميلها في شاحنة مثلًا. وقد يتسبب تغيير تعليمة برمجية واحدة في تهديد خطير لأمن المعلومات في الشركة أو المؤسسة يؤدي إلى تسريب بيانات العاملين في الشركة أو عملائها إلى أيدي المنافسين أو الأعداء لتلك المؤسسة، ويزيد خطر تلك الثغرات في حالة الشركات الكبرى أو التي تتعامل مع بيانات حساسة للمستخدمين كالحسابات البنكية أو البيانات الطبية. خطورة تهديدات أمن المعلومات يكمن خطر تهديد أمن المعلومات حاليًا في سهولة الوصول إلى كميات ضخمة منها بثغرات بسيطة من ناحية، وتوفر أدوات المعالجة القوية لتلك البيانات من ناحية أخرى لاستخراج الظواهر العامة لتلك البيانات أو استقراء نتائج معينة منها، ذلك أننا أصبحنا في قرية صغيرة جدًا ويمكننا معرفة خبر حيوان انقرض في قارة أخرى تبعد عنا آلاف الكيلومترات مثلًا. وبالمثل، يمكن معرفة التوجه العام لسكان مدينة أو دولة بعينها من خلال النظر في المحادثات النصية بين أفرادها والمنشورات النصية والمرئية والمسموعة التي ينشرونها على الويب، ومن ثم استغلال تلك المعلومات في توجيههم ثقافيًا أو التأثير على الرأي العام، وخطورة مثل هذه الأساليب يكمن في سهولة الحصول على تلك البيانات وسرعة معالجتها، واستخدام أساليب مختلفة للتأثير قد لا تدركها الضحية نفسها. التجسس على المستخدمين وتكون أخف الأضرار هنا هو استخدام تلك البيانات في الترويج لسلعة ما من قِبل شركة، وهو ما تفعله شركات التقنية وغيرها مع بيانات مستخدميها من خلال بيع نتائج تلك البيانات للشركات التي ترغب في بيع منتجاتها إلى مستخدمي جوجل مثلًا، لكن في تلك الحالات يكون استغلالًا غير قانوني إما بالسرقة أو بالتجسس غير القانوني على بيانات لا يريد المستخدمون استغلالها من قِبل الشركات. التأثير على الرأي العام أما أسوأ الحالات ضررًا فيتمثل في التأثير على الرأي العام، مثل استخدام مزارع المستخدمين user-farms وهي مجموعات كبيرة من المستخدمين يُوظفون لكتابة آراء ذات توجه معين عن عمد بحيث يخدم من يوظفهم وذلك من أجل كتابة آراء زائفة لمنتجات على أمازون كأبسط مثال ويمتد حتى تأييد اتجاه سياسي أو رفضه بما يُحدث زخمًا في سير الأحداث في منطقة ما، وهكذا. استهداف المنشآت الحساسة أو باستغلال الثغرات الأمنية الرقمية أو البشرية للمعلومات في الوصول إلى نقاط حساسة في المؤسسات ومن ثم استهدافها من خلالها، كالوصول إلى حواسيب مفاعلات نووية مثلًا أو أجهزة طبية في مستشفيات أو إلى مولدات الطاقة في تلك المنشآت الطبية أو النووية، ومن ثم تعطيلها أو تخريبها أو إيقاف عملها، أو حجب الوصول إليها مقابل فدية مادية أو معنوية، ويزيد الخطر في حالة الوصول إلى منشآت عسكرية أو أنظمة دفاعية، خاصة مع ازدياد الاعتماد على الأنظمة الرقمية في الطائرات المسيرة أو أنظمة الدفاع الجوي. سرقة الأموال وإن كانت الحالات المذكورة في الفقرة أعلاه نادرة الحدوث إلا أنها شديدة الخطر حال حدوثها، وتتسبب في كوارث حقيقية، لكن الحالات الأكثر شيوعًا منها تكون في استغلال ثغرات في أنظمة المعلومات البنكية التي تكون تحت سيطرة البنوك أو الشركات التي تضع يدها على وسائل دفع للمستخدمين، ومن ثم سرقة الأموال الموجودة في تلك الحسابات إما بتحويلها إلى حسابات تابعة للصوص أو استخدامها في شراء منتجات مباشرة بانتحال شخصية صاحب الحساب الأصلي. وحتى لو كانت أنظمة البنوك نفسها من التعقيد بحيث لا تسمح للمخترقين بالوصول إلى أموال المستخدمين بسهولة، إلا أن نقطة الضعف الكبرى تكمن دومًا في المستخدمين أنفسهم. استهداف الضحايا الأفراد تشكل المعلومات المتوفرة حول الأفراد مصدرًا غنيًا لاستهدافهم شخصيًا إما بالسرقة أو الابتزاز أو حتى تهديد سلامتهم، من خلال الأجهزة التقنية التي يستخدمونها من حواسيب وهواتف، سواء ببيانات مباشرة مثل الصور والعناوين والبيانات المالية، أو بيانات وصفية metadata تجمعها الحواسيب والتطبيقات التي يستخدمونها، مثل المواقع الجغرافية ومواعيد الاتصالات وسجل تحركاتهم، بل وحتى تحديد وسائل تلك التحركات إن كانت باستخدام سيارات أو مشيًا على الأقدام، ومن يتعاملون معهم من أفراد أو خدمات. وتكون تلك الحالة أشد خطورة بسبب استغلال إحدى أسوأ الثغرات وأضعفها، وهي الثغرة البشرية، ذلك أن المنشآت والشركات يكون لديها أقسام وإدارات خاصة بالتعامل مع الأخطار الرقمية والأمنية، أما الأفراد ففي الغالب يغلب عليهم الجهل شبه التام بالأخطار المحيطة بهم فيما يستخدمونه من وسائل وأدوات تحمل بياناتهم ومعلوماتهم. والواقع أن العنصر البشري يمثل نقطة الضعف الكبرى في أي منظومة أمنية، لهذا تضع المؤسسات ميزانيات كبيرة للتوعية الأمنية لأفرادها تكاد تقارب الميزانيات المخصصة للأنظمة الأمنية مثل الكاميرات وبرامج مكافحة الاختراق وغيرها، وتوظف أحيانًا من يختبر كفاءة تلك المنظومات الأمنية من خلال تنفيذ اختبارات اختراق على أنظمة الشركة تحت إشرافها، أو محاكاة عمليات الاحتيال على الموظفين لاكتشاف المشاكل المحتملة ونقاط الضعف التي قد تكون لدى بعضهم من أجل معالجتها وتوعيتهم. عناصر أمن المعلومات احتاجت المؤسسات الأمنية إلى وضع عناصر تمثل معايير لأمن المعلومات تُستخدم في تصنيف المعلومات الواردة إليها أو الخارجة منها، ومن ثم تحديد الأسلوب الأمثل للتعامل معها. وقد اشتهر ثلاثي عناصر الأمان الذي تستخدمه وكالة الاستخبارات الأمريكية في وسط المهتمين بأمن المعلومات وحماية البيانات منذ السبعينات من القرن الماضي، والذي يتكون من ثلاثة عناصر هي السرية confidentiality، وسلامة البيانات integrity، ومدى إتاحتها availability. لكن خرجت لاحقًا في التسعينات عدة إرشادات أخرى تزيد على تلك العناصر الثلاثة، وهذه العناصر مفيدة حتى للأفراد العاديين ليعلموا ما الذي يجب النظر إليه عند التعامل مع بياناتهم، ومن ثم تحديد مدى تأثير تلك البيانات إن وقعت في يد غير أمينة. فمثلًا، اقترح الباحث الأمني دون باركر Donn Parker في 1998 نموذجًا بديلًا للثلاثي السابق مكونًا من ستة عناصر هي: سرية البيانات Confidentiality حيازة البيانات Possession أو التحكم فيها Control سلامة البيانات وصحتها Integrity موثوقية البيانات Authenticity إتاحة البيانات Availability قيمة البيانات أو أثرها Utility والعلم بعناصر أمن المعلومات هذه مفيد حتى للأفراد العاديين، من أجل معرفة ما يجب النظر إليه في المعلومات الخاصة من صور ومستندات وجهات اتصال وغيرها، ومن ثم النظر في أوجه التعامل معها، فهل نثق في رسالة أرسلها شخص غريب إلينا أم لا -لا إلا إن كنا نعرف ذلك الشخص حقًا ورقم هاتفه أو بريده- وهل نشارك جهة اتصال مع تطبيق ثبتناه على الهاتف أم لا -لا، إلا إن كان التطبيق ذو سمعة جيدة ويحتاج حقًا إلى استخدام جهة الاتصال- وهل نأمن أن نترك الهاتف في حيازة غيرنا أم لا -لا قطعًا-، وهكذا. وسائل حماية البيانات تتعدد الوسائل المتاحة لحماية أمن المعلومات والبيانات وحفظها من السرقة أو التخريب، بين الأنظمة المادية والبرمجية، والتوعية المعرفية للأفراد. الحماية المادية للمعلومات لا شك أن أكثر مكان آمن لتخزين البيانات هو الذي لا يمكن الوصول إليه، وعلى ذلك توضع الخوادم والحواسيب التي تحتوي على بيانات حساسة في منشآت شديدة الحراسة، وتكون الحواسيب نفسها داخل غرف محصنة من الوصول غير المصرح به، وكذلك ينبغي اختيار العتاد الخاص بالحواسيب من شركات مشهورة لضمان الحصول على عتاد آمن قدر الإمكان، وتجنب شراء العتاد الرخيص إلى درجة تثير الشك، ذلك أن كثيرًا من الشركات التي تبيع عتادًا رخيصًا سواء في سوق الحواسيب أو الهواتف يتبين لاحقًا إما بتحقيقات أو بفضيحة مسربة أنها تجمع بيانات المستخدمين وتبيعها. أما على الصعيد الشخصي، فينبغي حفظ الأجهزة المنزلية التي عليها بياناتنا (الراوتر - الهاتف - الحاسوب …إلخ.) في مأمن من العبث بها، سواء من الأطفال أو من اللصوص، واختيار كلمات مرور قوية لها، وتغييرها دوريًا كل مدة، والنسخ الاحتياطي لبياناتها لتجنب ضياعها في حالة التلف أو السرقة أو غيرها. التوعية المعرفية للأفراد يجب على المؤسسة أن تنظم برامج لتوعية العاملين فيها بوسائل اختراق المؤسسة وأنظمتها للحصول على البيانات، إما باستغلال ثغرات أمنية للمؤسسة أو باستغلال الأفراد أنفسهم، حيث تتعدد وسائل اختراق المؤسسات من خلال الأفراد باستغلال جهل العنصر البشري أو بابتزازه ماديًا أو نفسيًا من خلال تهديده بفضيحة أو سرقة أو غيرها. فهنا يجب أن يُرشد اﻷفراد إلى كيفية الاستخدام الآمن للهواتف والحواسيب الخاصة بالعمل وكذلك الأجهزة الشخصية، لئلا يصل المخترق إلى بيانات خاصة بالموظف يستغلها في ابتزازه من أجل الحصول على معلومات خاصة بالشركة. وهذا مفيد حتى خارج نطاق المؤسسات، فمن المهم أن يكون الوعي الرقمي منتشرًا بين أفراد المجتمع لئلا تحدث تلك الحالات على المستوى الفردي، من ابتزاز أو سرقة أو اختطاف أو غيرها، وقد نشرت حسوب في هذا كتابًا من خمسة عشر فصلًا في الأمان الرقمي، يشرح أهميته ومفاهيمه، وكيفية تأمين الأدوات المحيطة بالمستخدم من أجهزة أو برمجيات، والسلوكيات الصحيحة الواجب اتباعها عند تنفيذ المعاملات المالية عبر الإنترنت وعند الشعور بتهديد أو حدوث اختراق أمني. كذلك ينبغي توعية المستخدمين بأهمية البيانات الخاصة بهم، ذلك أن كثيرًا من الشركات والبرامج هذه الأيام تستخدم حيلًا نفسية للتلاعب بالمستخدمين ودفعهم إلى مشاركة بياناتهم بمحض إرادتهم، كما يحدث في كثير من التطبيقات التي تستخدم الذكاء الصناعي في محاكاة مظاهر الشيخوخة على الصور الشخصية، أو التي تطلب بيانات خاصة بالمستخدمين في صورة ألعاب بسيطة. ومن تلك الحيل أيضًا ترك بطاقات الذاكرة أو أصابع flash محملة ببرمجيات خبيثة عمدًا حول مواقع تواجد الضحايا من المستخدمين، حتى يلتقطونها ويضعونها في حواسيبهم أو حواسيب شركاتهم، فتنتقل البرمجيات الخبيثة مباشرة إلى تلك الحواسيب ويستخدمها المخترق في الحصول على بيانات المستخدم أو شركته، فانتبه إذا كنت تفكر في شراء إصبع فلاش أو بطاقة ذاكرة إلى اختيار نوع موثوق فيه، وكذلك إذا رأيتها ملقاة على الأرض فلا تأخذها وتضعها في حاسوبك! وانتبه أيضًا إلى المواضع التي تترك فيها حواسيبك وهواتفك، فنحن نضطر في مرحلة ما إلى اللجوء إلى محلات الصيانة لإصلاح عطل ما، فإن استطعت أن تجد محلًا تثق فيه وتعرف العاملين فيه معرفة شخصية تضمن أنهم لن يستبدلوا القطع الموجودة في جهازك أو لن يتعرضوا لبياناتك فافعل، وإلا احرص أن تكون موجودًا أثناء الإصلاح، أو أن يُسجل الإصلاح بالفيديو لتطلع عليه -توفر بعض المحلات تلك الخدمة، بل تبثها عبر يوتيوب أحيانًا مع حجب بيانات العميل وبيانات عتاد الهاتف- أو أن يكون الإصلاح أثناء وجودك. ولا تعط تلك المحلات كلمات مرورك إلا عند الضرورة القصوى، فإصلاح الشاشة للهاتف مثلًا لا يحتاج إلى كلمة المرور إلا لتجربتها، وفي تلك الحالة تخبر الفنيين أن يتصلوا بك للحضور لتقديم كلمة المرور ومن ثم تجربة الشاشة الجديدة قبل تثبيتها واستلام الهاتف، ويُفضل تغيير كلمة المرور العامة للهاتف وكلمات المرور للحسابات المستخدمة فيه بعد عملية الصيانة تلك. الحماية البرمجية في أمن المعلومات يُفضل اختيار البرمجيات ذات السمعة الجيدة في حماية البيانات، كالتي تستخدم تشفيرًا متقدمًا واستيثاقًا ثنائيًا للمستخدمين، والتي تنفذ نسخًا احتياطية مشفرة للبيانات بشكل دوري، إضافة إلى استخدام برمجيات الحماية من الفيروسات والبرمجيات الخبيثة وبرمجيات الفدية. كذلك يُفضل اختيار البرمجيات المفتوحة المصدر ما أمكن إذا تساوت إمكانياتها مع البرمجيات مغلقة المصدر، ولا نشير هنا إلى أن مجانية البرامج المفتوحة، فبعضها يكون أغلى من البرامج مغلقة المصدر، لكن لإمكانية الاطلاع على شيفراتها المصدرية والتأكد أنها لا تحمل برمجيات خبيثة تضر بأمان المستخدم وبياناته. وهذا يُطبَّق على البرمجيات بدءًا من نظام التشغيل نفسه وحتى البرمجيات والأدوات البسيطة التي تستخدمها على الهاتف أو الحاسوب، فبرنامج بسيط للمهام ToDo List لا ينبغي أن يُسمح له بتصريح الوصول إلى موقع الهاتف أو إلى الكاميرا أو بيانات المستخدم على الهاتف وجهات الاتصال مثلًا. كما ينبغي إجراء التحديثات للعتاد الرقمي دوريًا، إذ أن الأنظمة البشرية لا تكون كاملة، وتُكتشف الثغرات كل يوم فيها فيعمل مطورو تلك الأنظمة على سدها، ثم يرسلون تحديثات أمنية إلى المستخدمين تسد تلك الثغرات لديهم كذلك. خاتمة اعلم أن أمن المعلومات في هذه الأيام من أخطر الأسلحة وأشدها فتكًا إذا أسيء استخدامها كما تبين مما ذكرنا في هذا المقال، فيكفي الوصول إلى حواسيب منظومة صحية لإحداث خسائر في الأرواح والممتلكات، والمرء لا يقبل أن يترك باب بيته مفتوحًا لمن شاء أن يدخل ويرى ويسمع ما يجري فيه، لكن ذلك يحدث وأكثر للأسف بسبب ما في الهواتف من إمكانيات تجعله أداة تجسس ممتازة إن تعرض للاختراق إذ تظل أغلب الأجهزة متصلة بالإنترنت ليل نهار، فتخيل فداحة الخطر إن رأى المخترق ما تراه كاميرا جوالك، وسمع ما يسمعه الهاتف. فنحن بحاجة إلى نشر ثقافة الوعي الرقمي بيننا أكثر من أي وقت مضى، إما بمجرد الوعي والمعرفة أو بدراسة ذلك المجال للحفاظ على أمان الأفراد والمؤسسات في المجتمع. اقرأ أيضًا ما هو الأمن السيبراني؟ إدارة كلمات المرور عبر برنامج Bitwarden أمان الحاسوب وأداؤه وحمايته وخيارات الرقابة الأبوية في تطبيق أمن ويندوز الهجمات الأمنية Security Attacks في الشبكات الحاسوبية أمثلة عن أنظمة أمن الشبكات الحاسوبية
  8. تمثل مواقع الويب بوابات ومنافذ للجهات المالكة لها، فالموقع الإلكتروني لشركة أجهزة منزلية ما هو إلا فرع إضافي لمتاجر تلك الشركة على الأرض، أو قد يكون هو المتجر الوحيد الذي تبيع من خلاله أجهزتها وتشحنها إلى عملائها، وقد يكون موقع الكاتب/المترجم/المبرمج الفلاني هو مقر شركته الرقمي الذي يحصل منه على العملاء ويتواصل معهم من خلاله. وهكذا تكون المواقع على الإنترنت سوقًا موازية للسوق الحقيقي على الأرض، بل تكون أحيانًا هي النسخة الوحيدة من السوق في مجالات قد لا يكون من السهل تحقيق انتشار على الأرض فيها لسبب أو لآخر، ومن هنا تظهر أهمية بناء وبرمجة مواقع الويب وحجم السوق النشط لذلك المجال. ونقدم في هذه المقالة مدخلًا لغير المتخصصين لشق طريقهم في مجال برمجة المواقع، فنذكر فيها أنواع المواقع الإلكترونية وكيفية تصميمها، ومن ثم بناءها وبرمجتها، واللغات المستخدمة في برمجة مواقع الويب وتطبيقاته، والقسمين الأشهر في هذا المجال، وهما مجال الواجهات الأمامية Front-End والواجهات الخلفية Back-End، وما يكون تحتهما من أقسام فرعية. مدخل إلى برمجة مواقع الويب من الجميل في مجال برمجة مواقع الويب أنه من أسهل مجالات البرمجة في تعلمه، وأسرعه في الحصول على منتجات حقيقية -أي مواقع أو تطبيقات كاملة- ولا يحتاج إلى تعلم رياضيات متقدمة أو خوارزميات معقدة من أجل العمل فيه. وتنقسم برمجة مواقع الويب إلى عدة أقسام رئيسية تمثل وظائف مستقلة، وإن كان السوق فيه تخصصات كثيرة إلا أن تلك الوظائف هي الأشهر، ومنها يستطيع المطور التخصص لاحقًا إن شاء: مصمم واجهة الاستخدام UI Designer: يختص بتصميم الواجهة المرئية التي يتفاعل معها المستخدم ويراها، بما فيها من أزرار وأيقونات وقوائم وغيرها، ويختار الألوان المناسبة لطبيعة الموقع، ويستخدم برامج عدة لتصميم تلك المواقع والأيقونات التي يحتاج إليها. مصمم تجربة الاستخدام UX Designer: يختص بدراسة المستخدمين النهائيين للموقع لفهم احتياجاتهم ومن ثم تصميم تجربة استخدام مناسبة، فيختار أحجام الأزرار وترتيب القوائم والعناصر فيها وعدد النقرات اللازمة للوصول إلى كل عنصر في الصفحة، والتأثيرات السمعية والبصرية المصاحبة لكل نقرة أو إجراء من المستخدم، ومواضع النصوص والوسائط المتعددة وأحجامها وغير هذا، ويجب أن يكون لديه فهم جيد لنظرية الألوان وتأثيرها النفسي على المستخدم. قد يجمع المصمم بين هذا التخصص والتخصص السابق. مبرمج الواجهات الأمامية Front-End Developer: يستلم مبرمج الواجهة الأمامية ملفات التصميم من المصممين ليحولها إلى نسخة حية يتفاعل معها المستخدم، ويستخدم لغات برمجية تعمل في المتصفح مباشرة. مبرمج الواجهات الخلفية Back-End Developer: يكون مسؤولًا عن معالجة البيانات الخاصة بالموقع وتنفيذ الإجراءات التي يتخذها المستخدم عليه (مثل عمليات الشراء والدفع وتسجيل الدخول وكتابة المنشورات وغيرها)، وضمان أمان الموقع وسلامة الخوادم التي تحمل بياناته، وكذلك كفاءة وسرعة عمل الموقع. متطلبات العمل في برمجة المواقع الإلكترونية يحتاج من يتعلم كيفية برمجة مواقع الويب -وكذلك أي مجال برمجي آخر- معرفةً جيدة بالإنجليزية بحيث يستطيع قراءتها وكتابتها على الأقل، ذلك أن البنية اللغوية نفسها بالإنجليزية، وأغلب توثيقات اللغات البرمجية والمجتمعات الموجودة حولها تكون بالإنجليزية. لكن الجميل هنا في حالة المتعلم العربي أن شركة حسوب سعت في الأعوام الماضية لتوفير مصادر عربية لأشهر التوثيقات المتاحة للتقنيات واللغات المستخدمة في تطوير وبرمجة الويب عبر موسوعة حسوب، إضافة إلى الشروح والمقالات والكتب والدورات في أكاديمية حسوب، لتقرب الطريق على من يرغب بالدخول إلى المجالات البرمجية والعمل فيها، فهذا يسهّل كثيرًا على من يرغب بالعمل البرمجي من العرب عما كان الأمر عليه من قبل. أما ما يحتاجه مبرمج الويب من عتاد فلا يعدو أكثر من حاسوب جيد المواصفات متصل بالإنترنت، فلا تحتاج برمجة مواقع الويب إلى عتاد خاص بها، وأما البرمجيات فتختلف وفقًا للتخصص الذي يريد المبرمج أن يعمل فيه، فمصممو المواقع يستخدمون برمجيات تصميم مرئية ساكنة مثل Adobe Illustrator أو تفاعلية مثل Adobe XD، في حين يستخدم مبرمجو الواجهات الأمامية أو الخلفية لغات برمجية يكتبون شيفراتها في محررات نصية وبيئات برمجة، إضافة إلى متصفحات الويب لا ريب التي يكون لديهم أشهر إصداراتها وأحدثها لاختبار الموقع عليها. اللغات والأدوات المستخدمة في برمجة مواقع الويب تنقسم الأدوات المستخدمة في برمجة المواقع إلى قسمين أساسيين هما البرامج واللغات، والغالب على البرامج أن من يستخدمها المصممون، في حين يستخدم المبرمجون اللغات البرمجية المختلفة لبناء المواقع. أشهر البرامج التي يستخدمها مصمم الويب لا يوجد برنامج واحد يجمع كل ما يحتاجه مصمم الويب، بل يستخدم عدة برامج وفقًا لما يحتاج إليه المشروع أو الموقع الذي يعمل عليه، ووفقًا كذلك للميزانية المتاحة، ولبيئة العمل التي يعمل فيها، فقد يستخدم برامج مغلقة المصدر من شركة أدوبي Adobe، أو أدوات تصميم تشاركية مثل Figma، أو حتى برامج مفتوحة المصدر مثل Gimp و Inkscape، وفيما يلي أشهر تلك البرامج: أدوبي إكس دي XD: أحد برامج التصميم في حزمة أدوبي Adobe، يُستخدم لإنشاء التصاميم المرئية للمواقع والتطبيقات وحتى الألعاب في صورة قريبة للشكل النهائي لها، بحيث تعطي كلًا من العميل والمطور فكرة عن النموذج النهائي للموقع. قد تُستخدم بعض الأدوات الأخرى لهذا الغرض مثل Figma، والتي تتميز عن برامج أدوبي في أنها تطبيقات للعمل المشترك بين المصممين، بنفس مبدأ تطبيقات جوجل السحابية مثلًا. أدوبي إليستوريتور Adobe Illustrator: برنامج آخر للتصميم يعتمد على التصاميم المتجهية Vector Graphics التي لا تتأثر جودتها بتكبيرها، يُنشأ به عناصر الموقع من أزرار وقوائم وصفحات وغيرها. قد يُستخدم برنامج Inkscape مفتوح المصدر لذلك الغرض أيضًا، وذلك يتبع بيئة العمل التي يفضلها المصمم، والميزانية المتاحة للمشروع. أدوبي فوتوشوب: قد يُستخدم برنامج فوتوشوب PhotoShop الشهير لإنشاء تصميمات المواقع أيضًا، لكن إليستوريتور أفضل بسبب جودة التصميمات التي يخرجها، رغم احتياج مصمم الويب إلى برنامج مثل فوتوشوب -أو Gimp في حالة البرامج مفتوحة المصدر- لمعالجة بعض التصميمات التي يخرجها وإضافة تأثيرات عليها. دورة تطوير واجهات المستخدم ابدأ عملك الحر بتطوير واجهات المواقع والمتاجر الإلكترونية فور انتهائك من الدورة اشترك الآن أبرز لغات برمجة مواقع الويب تنقسم اللغات المستخدمة في برمجة الويب إلى قسمين رئيسيين، هما لغات الواجهة الأمامية واللغات المستخدمة لبرمجة الواجهات الخلفية، وفيما يلي أشهر تلك اللغات ووظائفها. لغات برمجة الواجهة الأمامية Front End HTML: لا تُصنف لغة HTML على أنها لغة برمجية، وإنما هي لغة تصف هيكل صفحة الويب ومواضع العناصر فيها، فهي لغة وصفية تتكون من وسوم بسيطة لكل عنصر من عناصر الصفحة، ولا يستغرق تعلمها بضعة أيام لإتقانها. CSS: تُستخدم لغة CSS في تخصيص مظهر عناصر الموقع من ألوان الخطوط وأحجامها وتأثيرات الانتقال وغيرها، وعليه فهي من لغات برمجة الواجهة الأمامية، وهي سهلة التعلم ويكفي أسبوع مثلًا لإتقانها، ويمكن إنشاء مواقع كاملة باستخدام HTML و CSS فقط. JavaScript: تُستخدم لغة جافاسكربت في إضفاء الحياة على عناصر الموقع، والاستجابة لتفاعلات المستخدم أثناء استخدام الموقع أو التطبيق، ولها الكثير من المكتبات وأطر العمل المبنية عليها والتي يستطيع مبرمج الواجهات الأمامية استخدامها لتسريع عملية إنشاء الموقع، وهي اللغة الأشهر في برمجة مواقع الويب. لغات برمجة الواجهة الخلفية Back End PHP: من أشهر لغات برمجة مواقع الويب وأكثرها استخدامًا، وتُستخدم لبرمجة تطبيقات الويب التي تعمل على الخوادم، أي في الواجهات الخلفية، كما تُبنى بها أنظمة إدارة المحتوى مثل ووردبريس. Ruby: لغة برمجة عامة الأغراض يمكن بناء الخوادم ومعالجة البيانات بها وكذلك بناء تطبيقات ويب باستخدام إطار العمل Ruby on Rails. Python: لغة برمجة عامة الأغراض كذلك يُستخدم فيها إطار العمل Django أو Flask لبناء تطبيقات الويب. JavaScript: كما تُستخدم لغة جافاسكربت في برمجة الواجهات الأمامية فهي كذلك تُستخدم في برمجة الواجهات الخلفية باستخدام إطار العمل Node.js. تُستخدم لغات برمجة غير هذه التي ذكرناها قطعًا في برمجة مواقع الويب مثل جافا وغيرها، وتخرج أطر عمل جديدة كل فترة مبنية على تلك اللغات، وإنما ذكرنا الأشهر فقط، ويكفي اختيار لغة واحدة في كل قسم وتعلمها ومن ثم تعلم أطر العمل المبنية عليها لاستخدامها، ويتحكم في هذا الاختيار تفضيل المبرمج نفسه وطبيعة المشاريع التي يريد العمل عليها، لكن بأي حال من السهل على من تعلم إحدى اللغات البرمجية أن ينتقل إلى غيرها في خلال بضعة أسابيع، انظر مقال مقدمة إلى أطر عمل تطوير الويب من طرف العميل للاطلاع على أشهر تلك الأطر. خطوات برمجة مواقع الويب يبدأ العمل على موقع الويب لعميلك بالاجتماع معه لمعرفة الهدف الذي يريده من الموقع والأقسام والعناصر التي ستكون فيه من أجل تحديد ميزانية للمشروع، وطبيعة المستخدمين النهائيين للموقع لمعرفة الألوان والتصاميم التي يجب استخدامها، ثم تأتي المراحل التالية: التصميم: ينشئ مصمم تجربة الاستخدام ومصمم الواجهات المرئية التصميم المرئي للموقع لعرضه على العميل، وعند اعتماده تبدأ مرحلة برمجته. برمجة الواجهة الأمامية Front End: يعمل مبرمج الواجهات الأمامية على تحويل التصميمات المرئية إلى موقع حي يتفاعل معه المستخدم ويتنقل بين صفحاته وقوائمه وعناصره، مستخدمًا لغات برمجة الواجهة الأمامية التي ذكرناها. برمجة الواجهة الخلفية Back End: ينشئ مبرمج الواجهة الخلفية الخوادم وقواعد البيانات وآليات معالجتها، ويضمن أمان حركة البيانات -خاصة في حالة إجراء معاملات مالية على الموقع-، وسرعة استجابة الموقع لإجراءات المستخدم وكفاءة التشغيل وضمان عمل الموقع لأقصى حد ممكن دون انقطاع، وقد تيسر هذا في الأعوام الأخيرة بعد خدمات الاستضافة السحابية مثل Azure من مايكروسوفت و AWS من أمازون، والتي يستخدمها مبرمج الواجهة الخلفية في تخزين بيانات الموقع عليها مستخدمًا إحدى الحلول التي توفرها تلك الخدمات، وفقًا لحجم الموقع والميزانية المتاحة. حجز النطاق والخوادم: يتولى مبرمج الواجهة الخلفية -أو مهندس العمليات DevOps Engineer- في الغالب مهمة حجز النطاق -وهو اسم الموقع مثل google.com- الذي سيستخدمه الموقع وشراؤه من إحدى الشركات التي تقدم هذه الخدمة وكذلك تأجير الخوادم التي سيكون عليها الموقع من Azure أو AWS كما ذكرنا أعلاه. مصادر تعلم برمجة مواقع الويب من مزايا العمل في تطوير الويب أنه لا يحتاج إلى شهادة جامعية متخصصة، وأن مصادر تعلمه متاحة عبر الويب بأشكال شتى، ويكفي بناء معرض أعمال جيد بعد تعلم اللغات والأدوات المطلوبة للبدء في العمل فيه عملًا مستقلًا أو عملًا منتظمًا في وظيفة مع شركة. وتوفر حسوب دورات باللغة العربية الفصحى عالية الجودة، لبرمجة الواجهات الأمامية باستخدام HTML و CSS ولغة JavaScript، وكذلك دورات لبناء تطبيقات الويب باستخدام لغة Ruby و PHP و Python و JavaScript وغيرها، وتحدَّث تلك الدورات كل فترة لتواكب التغيرات في السوق. ويكون معك في هذه الدورات مدربون محترفون للإجابة على أسئلتك، كما تضمن استرداد قيمة الدورة في خلال ستة أشهر، إضافة إلى معين زاخر بالمقالات والشروح والكتب عالية الجودة في أكاديمية حسوب لنفس المجالات، وتوثيقات اللغات البرمجية نفسها في موسوعة حسوب. إضافة إلى ما سبق، يزخر الإنترنت بمصادر تعلم أطر العمل ولغات البرمجة، سواء كانت المصادر مجانية أو مدفوعة، ومن المواقع الرسمية لتلك اللغات البرمجية أو من غيرها، ويبقى على المتعلم الجِد في الطلب وتطبيق ما يتعلمه في مشاريع وتطبيقات لصقل خبرته، ويُرجع إلى مقالة المدخل الشامل لتعلم تطوير الويب وبرمجة المواقع للاطلاع على مسارات التعلم والتخصصات المتاحة في مجال تطوير الويب كي تستطيع اختيار المسار المناسب لك، وانظر أيضًا مقال الدليل الشامل لتعلم البرمجة باستخدام المصادر العربية. خاتمة صحيح أن تعلم أي مهارة جديدة قد يستغرق بعض الوقت والجهد والمال أحيانًا، إلا أن الاستثمار في مهارة يكثر الطلب عليها مثل البرمجة عمومًا وتطوير مواقع الويب وتطبيقاته خاصة قرار غاية في الحكمة، خاصة في ظل التقلبات الحادثة في السوق وازدياد الطلب على اﻷيدي العاملة التقنية وأتمتة المهام وانتقال السوق إلى فضاء الإنترنت، كما يوفر مصدرًا لكسب الرزق بعملة صعبة مع حرية العمل من المكان الذي تريده في الغالب إذ أن كثيرًا من شركات برمجة المواقع تتيح العمل من المنزل لموظفيها. اقرأ أيضًا كيفية التعامل مع الويب تعلم البرمجة المدخل الشامل لتعلم علوم الحاسوب كيف يعمل الويب Web مدخل إلى خادم الويب
  9. إذا أمكننا اختيار مجال واحد ليكون أهم مجال علمي وعملي في السوق الحديث فسيكون ذلك المجال هو تقنية المعلومات Information Technology -يُطلق عليه تقانة المعلومات أحيانًا- ذلك أنه مجال واسع ومتشعب يستطيع أن يستوعب أغلب مجالات العمل والعلم الأخرى بشكل أو بآخر إن لم يكن يستطيع استيعابها جميعًا. ما هي تقنية المعلومات ربما يجب أن نبدأ بتعريف هذا المجال أولًا كي يتضح نطاق تأثيره على واقعنا الحالي -وربما الماضي والمستقبل أيضًا- فتقنية المعلومات تمثل النظم التي نضعها باستخدام الحواسيب من أجل إنشاء البيانات وإجراء العمليات المختلفة عليها، مثل التحليل والحساب واستقراء النتائج والظواهر، وكذلك تحقيق عمليات اتصال بين تلك الحواسيب وإن كانت بعيدة عن بعضها، من أجل نقل البيانات بينها لتسهيل تنفيذ عمليات المعالجة عليها. أهمية تقنية المعلومات قد يكون التعريف أعلاه عامًا أو يحصر مجال تقنية المعلومات بين الحواسيب والأسلاك والأقراص الصلبة فقط، والواقع أن أهمية هذا المجال الكبرى تنبع من سبب استخدامنا للحواسيب ابتداءً، حيث نغذيها بالمعلومات والبيانات للمشاكل والحالات التي تكون لدينا، ثم نعطي تلك الحواسيب المعادلات والإجراءات التي يجب عليها اتباعها للنظر في تلك المشاكل والحالات -وهو ما نعرفه بالبرامج والنظم- كي تخرج لنا باستقراء أفضل للواقع ومن ثم اقتراحات أو حلول أفضل، بسرعة تفوق سرعة المعالجة البشرية كثيرًا لنفس المشكلات. ربما تتضح تلك الأهمية إن ذكرنا لها أمثلة من الواقع. أمثلة لتطبيقات تقنية المعلومات نحن نستخدم الهواتف مثلًا لتحقيق اتصالات بيننا وبين أحبابنا رغم بعد المسافة، وما أصواتنا وصورتنا والرسائل التي نرسلها إلا بيانات التقطتها هواتفنا -التي هي حواسيب أيضًا- لتحولها إلى بيانات وإشارات كهربية ترسلها عبر تقنيات اتصال إلى الطرف الثاني الذي نحدثه، فتُحوَّل تلك الإشارات مرة أخرى إلى صور ونصوص وأصوات. وكذلك حين نستخدم برنامجًا لمتابعة سير العمل على المهام في شركة ما، بحيث نسجل فيه مواعيد الحضور والانصراف ومواعيد بداية ونهاية عمل كل موظف على المهام التي لديه، أو حين نسجل عمليات الشراء التي تتم في متجر مثلًا من أجل تيسير إجراء العمليات المحاسبية لصاحب المتجر. وتأتي ثمرة مجال تقنية المعلومات هنا في إمكانية تخزين تلك البيانات جميعًا، سواء المحادثات والاتصالات أو الرسائل أو مواعيد الحضور وسجلات العمل على المهام وعمليات البيع، ثم استخدام تقنيات مثل الذكاء الصناعي والخوارزميات المتقدمة من خلال لغات برمجية في تحليل تلك البيانات واستخراج ظواهر Trends بارزة فيها تُستخدم في صناعة القرار فيما بعد. فمثلًا، إذا تبين من بيانات عمليات الشراء في متجر ما أن أغلب عمليات الشراء تكون في المساء وأن عمليات البيع في الصباح لا تكاد تُذكر، فيمكن حينها إجراء مفاضلة للنظر في إغلاق المتجر في ساعات الصباح توفيرًا للتكاليف. وكذلك في مواعيد العمل على المهام بالنسبة للموظفين، إذ تفيد إجراء تحليلات مراقبة الأداء في معرفة سلوك الموظفين في أعمالهم اليومية، ومن ثم تعديل سياسات العمل أو تغيير ترتيب المهام أو غيرها. ومثل ذلك يُمكن تطبيقه على أي مجال تقريبًا، من تحليل ساعات الطيران لطائرة جديدة يراد اختبارها من أجل الإصلاح المبكر لمشاكلها، إلى تخزين البيانات الكبيرة للمؤسسات والدول في صور رقمية يمكن فهرستها وأرشفتها ومعالجتها بسهولة، على عكس الأساليب الورقية القديمة، بل حتى على عكس الأساليب التقنية القديمة التي كانت تستخدم البطاقات المثقبة Punched Cards مثلًا في تخزين البيانات في القرن الماضي، التي كان تعديل خطأ فيها مكلفًا ومستهلكًا للوقت والجهد، بل كان مجرد تخزينها يحتاج إلى مستودعات ضخمة جدًا. وتمكننا تلك التقنيات من توفير أعوام وأعوام من عمليات المعالجة التي كانت تتم يدويًا، من خلال استخدام المعالجات الحاسوبية التي تستطيع تنفيذ ملايين العمليات الحسابية في الثانية الواحدة، بل عشرات المليارات من العمليات في الثانية الواحدة، وذلك للحواسيب المكتبية، أما الحواسيب الخارقة الكبيرة فتكون أكثر من هذا بكثير. تُستخدم تلك الإمكانيات الهائلة في إجراء عمليات محاكاة للتجارب العلمية الكبيرة مثلًا وحسابات مسارات الأجرام السماوية التي يُحتمل أن ترتطم بالأرض، أو توقعات الطقس والمناخ مثلًا. دورة علوم الحاسوب دورة تدريبية متكاملة تضعك على بوابة الاحتراف في تعلم أساسيات البرمجة وعلوم الحاسوب اشترك الآن عناصر تقنية المعلومات تشتمل تقنية المعلومات على عنصرين أساسيين هما العتاد المادي من أبراج اتصالات وهوائيات وأسلاك لنقل البيانات ومستقبِلات وغيرها من البنى التحتية اللازمة لإنشاء الشبكات، والحواسيب بأنواعها من الحواسيب المدمجة الصغيرة في الأجهزة إلى الحواسيب الخارقة التي تُخصص لها منشآت مستقلة، وما يتبع ذلك من عتاد إلكتروني من معالجات وأقراص تخزين وغيرها. ويندرج تحت هذا العنصر قسمان فرعيان هما قواعد البيانات Databases وأنظمة الاتصالات Telecommunications، وقد زادت أهمية قواعد البيانات مؤخرًا بعد تطور تقنيات الذكاء الصناعي وتحليل البيانات، أما أنظمة الاتصالات فهي المعدات اللازمة لربط الحواسيب البعيدة ببعضها لتكوين شبكات فيما بينها باستخدام أسلاك الإيثرنت أو الألياف البصرية، أو باستخدام الاتصالات اللاسلكية مثل الواي فاي. والعنصر الثاني هو البرمجيات التي تعمل بها تلك الحواسيب، وما تقوم عليه من نظريات فيزيائية ومفاهيم رياضية. تختلف المؤسسات فيما بينها في مدى قرب أو بعد كل عنصر منهما عن صُلب مفهوم تقنية المعلومات، حيث ترى بضعها أن دراسة مجال تقنية المعلومات يجب أن تركز على تهيئة الطالب لاختيار العتاد المناسب للشركة أو المؤسسة واستخدامه وصيانته وتطويره، وبعضها -كما في حالة شهادة الهندسة في تقنية المعلومات في الهند- يرى أن طالب تقنية المعلومات يجب أن يدرس المفاهيم النظرية الرياضية، فيقضي عامين في دراسة التفاضل والجبر الخطي وغيرها. الفرق بين نظم المعلومات وتقنية المعلومات تختص تقنية المعلومات بالأنظمة المادية من إلكترونيات وبرمجيات ونظريات رياضية وغيرها كما رأينا، أما نظم المعلومات فتمثل حلقة تصل تلك الأنظمة بالمستخدمين أنفسهم، وتختص بتوظيف تقنية المعلومات ونظرياتها لخدمة مجالات العمل الأخرى، فنستغل تقنية المعلومات في إنشاء نظم معلومات تخدم المؤسسات أو الأفراد، مستفيدين من عناصرها المادية والنظرية وغيرها. تخصصات تقنية المعلومات تتعدد مجالات العمل التي تندرج تحت تقنية المعلومات تعددًا كبيرًا، غير سنركز على الوظائف التي تكون في صلب المجال التقني والحاسوبي نفسه، بحيث يمكن تشكيل صورة واضحة عن طبيعة وظائف تقنية المعلومات من تلك الأمثلة أدناه: متخصص الدعم الفني: يكون مسؤولًا عن مراجعة شبكات الحاسوب ومشاكل العتاد وحلها في الشركات. متخصص الأمن التقني: يصمم أنظمة وقائية للبيانات الخاصة بشركته أو مؤسسته لإنشاء خطط احتياطية لحالات اختراق البيانات وسرقتها من الشبكة أو الخوادم الخاصة بالشركة، وكذلك إجراءات التعامل مع المشاكل التي تطرأ على ذلك العتاد. مهندس الشبكات: يصمم الشبكات الحاسوبية ويقوم على صيانتها الدورية لضمان عملها بكفاءة ودون انقطاع. محلل النظم: يراجع عناصر النظم المصممة في الشركة ويستخرج الطرق التي يمكن تطوير البنى التحتية بها لتسهيل عمل الفرق التقنية. مهندس البرمجيات: يصمم البرمجيات ويطورها، سواء كانت تلك البرمجيات نظم تشغيل أم أنظمة تحكم أم برمجيات غيرها تعمل على منصات مختلفة، وهو مجال واسع بحد ذاته يحتاج من صاحبه كثيرًا من الدراسة المستمرة كلما أراد الانتقال إلى مستوى أعلى فيه. عالم البيانات: يحلل البيانات لاستخراج الظواهر والمؤشرات التي تؤثر على صناعة القرار في المؤسسة أو الشركة، مستخدمًا تقنيات تعلم الآلة والإحصاءات لمعالجة بيانات مثل السجلات المالية والمبيعات وغيرها. مصمم تجربة الاستخدام/مصمم الواجهة المرئية: هذا التخصص وإن ابتعد عن بيئة العتاد والبنية التحتية وعن الجانب البرمجي من مجال تقنية المعلومات إلا أنه لازم له من أجل إنشاء واجهات يسهل التعامل معها من المستخدمين للنظم الحاسوبية والبرمجية. تتفرع كثير من الوظائف الأخرى من كل نقطة من النقاط السابقة، وتختلف مهام كل منها باختلاف الصناعة التي تكون فيها، لكن تلك هي الصورة العامة للوظائف في مجال تقنية المعلومات. هل تواجه مشكلات تقنية وتحتاج لمساعدة؟ احصل على أفضل خدمات الدعم الفني والتقني من خمسات اطلب خدمتك الآن خاتمة تعرفنا في هذا المقال على مدخل بسيط إلى مجال تقنية المعلومات، يغطي رؤوس عناصره الأساسية، وإلا فهو مجال متشعب واسع، لا يكاد يخلو مجال أو صناعة من أثره، ولا يُتصور أن تنجح مؤسسة أو تقوم دولة حديثة تفتقر إلى أرضية صلبة من تقنية المعلومات سواء من حيث العتاد أو البرمجيات. اقرأ أيضًا التوجهات الحديثة في مجال تقنية المعلومات التي تحتاج الشركات إلى معرفتها إدارة التقنية وتخطيطها في الشركات المدخل الشامل لتعلم علوم الحاسوب
  10. سنتحدث في هذا المقال عن أشهر علماء الحاسب أولئك الذين تغير علم الحاسوب بعدهم وتركوا بصمة فيه لنسلط الضوء على إنجازاتهم ونفتخر بهم وبأن قسم كبير منهم كانوا من العلماء العرب، فهل أنت جاهز للتعرف عليهم؟ لنبدأ! من هو عالم الحاسب؟ لم يصل علم الحاسوب إلى ما وصل عليه الآن ولم يبلغ التطور الرقمي مبلغه الآن إلا بفضل علماء ساهموا به وقدموا له الإنجازات وبذلوا فيه التضحيات لتتراكم تلك الإنجازات فوق بعضها ويصل العالم اليوم إلى تطور رقمي لم يصله من قبل حتى بات الشخص يسافر أبعد المسافات، ويتحدث أحدهم من أقصى الشرق مع آخر من أقصى الغرب، ويرسل آخر حوالة مالية من أقصى الشمال لتصل إلى أقصى الجنوب بمدة زمن خيالية وغير ذلك ما لو كان أجدادنا الأولون هنا لتعجبوا أشد العجب، وربما تعجبنا مثله نحن مستقبلًا على تطورات لم نكن نتخيلها الآن أو ربما جرى تأليف فلم خيال علمي عنها. وعمومًا، عالم الحاسب هو من أفنى عمره في مجال علوم الحاسوب وما يتصل به ولم يعمل به فقط، بل ساهم فيه وقدم إنجازات معتبرة بها يدرج ضمن الخط الزمني التاريخي حيث التاريخ ما قبله ليس كما بعده، وستجد اسمه مدرجًا في المراجع والمقالات التاريخية أو يُذكر في أروقة الجامعات مقرونًا بإنجازه في المجال. أهم علماء الحاسب نتعرف الآن على مجموعة من أشهر علماء الحاسب الذين تركوا علامات فارقة وإنجازات تركت أثرًا على حياتنا الآن إما بنظريات جديدة أو بمنتجات وخدمات تقوم هي أيضًا على نظريات أحدثوها أو طوروها. تيم بيرنرز-لي Tim Berners-Lee الصورة بواسطة Paul Clarke، منشورة برخصة CC BY-SA 4.0 أحد أشهر علماء الحاسب البريطانيين، أنشأ أول نسخة من الشبكة العالمية WWW (شبكة الإنترنت) عام 1989. عمل كمهندس في شركة اتصالات ثم انضم إلى المنظمة الأوروبية للبحث النووي CERN في عام 1980 ثم مرة أخرى في 1984 وقرر اختبار نموذج الربط التشعبي فيه إذ كان أكبر شبكة إنترنت في أوروبا وقتها، وهو ما شكل الأساس فيما بعد لشبكة الويب التي تقوم على الروابط المتشعبة Hyper Links باستخدام بروتوكول نقل النصوص الفائقة Hyper Text Transfer Protocol أو HTTP. فينتون سيرف Venton Cerf الصورة بواسطة Duncan.Hull منشورة برخصة CC BY-SA 4.0 أحد علماء الحاسب الأمريكيين، يُعد أحد آباء الإنترنت الذين أنشأوه حيث كتب أول بروتوكول TCP بالاشتراك مع يوجين دلال Yogen Dalal وكارل صنشاين Carl Sunshine. عمل كذلك كأستاذ مساعد في جامعة ستانفورد في عام 1972 لأربعة سنوات أجرى فيها أبحاثًا حول بروتوكولات الاتصالات الشبكية، وصمم حزمة DoD TCP/IP بالاشتراك مع بوب خان Bob Kahn. آلان تيورنج Alan Turing رياضي بريطاني وأحد أهم علماء الحاسب البريطانيين الذين عملوا أثناء الحرب العالمية الثانية في المدرسة الحكومية البريطانية للتشفير والتعمية Government Code and Cypher School على فك تشفير آلة إنيجما الألمانية التي استُخدمت في تشفير الرسائل الألمانية العسكرية، وكتب ورقتين حول استخدام التحليل الرياضي لتحديد الإعدادات الأقرب التي يمكن استخدامها بسرعة لفك الشيفرة المستخدمة، ولم تُنشر هاتان الورقتان للعلن إلا في عام 2012. يُعزى إليه الفضل مع جوردون ويلشمَن Gordon Welchman في إنشاء أول آلة كهروميكانيكية استُخدمت في فك تشفير آلة إنيجما، ثم عمل بعد الحرب على تصميم محرك حوسبة آلي نشر ورقته في 1946، يصف فيه برنامج مخزَّن على الحاسب، ثم عمل بعده على كتابة برامج لأحد أوائل الحواسيب ذات الذاكرة، وهو حاسب مانشيستر مارك1. كذلك اقترح في عام 1950 ما عُرف بعدها باختبار تيورنج الذي يعرِّف فيه الآلة على أنها ذكية إذا لم يدرك الإنسان الذي يتعامل معها أنها آلة آنذاك. طاهر الجمل الصورة بواسطة Alexander Klink منشورة برخصة CC BY 3.0 أحد أشهر علماء الحاسب العرب من الحاصلين على الجنسية الأمريكية إذ هو مصري الأصل، يُعزى إليه الفضل في إنشاء بروتوكول SSL أثناء عمله في شركة Netscape، إضافة إلى نظام تعمية عُرف باسمه ElGamal encryption system عبارة عن خوارزمية تعمية باستخدام المفتاح العام، حيث يكون للمستخدم مفتاحان واحد عام يمكن نشره للعامة وآخر سري، ويرتبطان معًا بعملية حسابية تختلف وفقًا للخوارزمية المستخدمة، ورغم ارتباطهما فلا يمكن الوصول إلى أحد المفتاحين عن طريق الآخر. تُستخدم هذه التقنية بكثرة في تعمية الرسائل وتستخدمها البنوك لضمان سرية معاملاتها المالية. دورة علوم الحاسوب دورة تدريبية متكاملة تضعك على بوابة الاحتراف في تعلم أساسيات البرمجة وعلوم الحاسوب اشترك الآن عباس الجمل أحد علماء الحاسب العرب من الحاصلين على الجنسية الأمريكية إذ هو مصري الأصل كذلك، وهو أخو الدكتور طاهر الجمل الذي ذكرناه أعلاه. شغل عدة مناصب أكاديمية في جامعة ستانفورد، وطور نوعًا من الدوائر الإلكترونية يمكن برمجته بعد مرحلة التصنيع ليوافق احتياجات المستخدم، وله عدة براءات اختراعات وأوراق علمية في هذا المجال. وقد عمل أيضًا على تطوير مستشعرات CMOS المستخدمة حاليًا في الكاميرات الرقمية والهواتف المحمولة، ثم أنشأ العديد من الشركات مثل Actel التي تعمل على تصنيع الدوائر الإلكترونية التي طورها، وشركة Pixim لتطوير رقاقات في كاميرات المراقبة تستخدم تقنية حساس البكسل الرقمي Digital Pixel Sensor التي طورتها مجموعته في ستانفورد. لينوس تورفالدز Linus Torvalds الصورة بواسطة kuvaaja - Linuxmag.com منشورة برخصة CC BY-SA 3.0 أحد أشهر علماء الحاسب في مجال هندسة البرمجيات، وهو أمريكي فنلندي، حيث يُنسب إليه اختراع نواة نظام التشغيل لينكس في 1991، وقد تطور نظام لينكس وتوسع انتشاره ليصبح من أهم نظم التشغيل حاليًا، إذ تعمل به جميع الحواسيب الخارقة في العالم، ويُبنى عليه نظام أندرويد الذي تعمل به أكثر الهواتف. يتميز نظام لينكس والتوزيعات المبنية عليه بمستويات الأمان المتقدم ونظام الصلاحيات الذي لا يسمح للمستخدمين ولا الملفات بإحداث ضرر غير مقصود أو تلقائي في النظام، كما يتميز أيضًا بمجانيته وأنه مفتوح المصدر في نفس الوقت، مما يقلل من تكلفة استخدام الحواسيب إلى حد كبير، خاصة في حالة المؤسسات الكبرى التي لديها أعداد كبيرة من الأجهزة، إلا أن بعض التوزيعات المبنية عليه تقدم خدمة الدعم الفني للشركات الكبيرة التي تحتاج إلى ذلك بمقابل مادي. ثم طور في 2005 نظام Git للتحكم في إصدارات البرمجيات، وهو النظام الأشهر الأكثر استخدامًا الآن من قبل المطورين والمبرمجين في العالم. ريتشارد ستولمان Richard Stallman أحد أهم علماء الحاسب الأمريكيين، اشتهر في الثمانينات من القرن الماضي حين بدأ في تطوير نظام تشغيل مفتوح المصدر من الصفر على إثر إغلاق نظام يونكس الذي كان منتشرًا وقتها، إضافة إلى بعض البرامج الأساسية للنظام مثل محرر النصوص Emacs والمصرِّف الخاص بنظام جنو Gnu Compiler Collection GCC، وغيرهما، وسُمي هذا النظام باسم جنو GNU، وأصدر له رخصة حرة خاصة به وأدوات تطوير تنشر مبدأ حرية البرمجيات وتعديلها بشرط أن يُعاد نشرها بنفس الرخصة. وقد بُني على هذا النظام أول نواة لينكس التي طورها لينوس تورفالدز الذي ذكرناه قبل قليل. دورة الذكاء الاصطناعي احترف برمجة الذكاء الاصطناعي AI وتحليل البيانات وتعلم كافة المعلومات التي تحتاجها لبناء نماذج ذكاء اصطناعي متخصصة. اشترك الآن دينيس ريتشي Dennis Ritchie الصورة بواسطة Denise Panyik-Dale - منشورة برخصة CC BY 2.0 أحد أهم علماء الحاسب الأمريكيين، ساهم في إنشاء نظام يونكس UNIX الذي كان يعمل على تطويره مع كين ثومبسون Ken Thompson، وهو أول نظام تشغيل للحواسيب متعدد المهام، وقد استُخدم بكثرة منذ إصداره في 1971، ثم صار الاسم يُطلق على أي نظام تشغيل يحقق عدة معايير مجموعة في واجهة POSIX التي أُصدرت في الثمانينات. كذلك يُنسب إليه الفضل في إنشاء لغة البرمجة C، مع بريان كيرنيهان Brian Kernighan، وهي اللغة الأشهر منذ إصدارها في السبعينات إلى الآن، وتُستخدم في برمجة أنظمة التشغيل وتعريفات العتاد والبرامج والتطبيقات، رغم تراجع استخدامها في التطبيقات مؤخرًا، ولا يزال كتابهما الذي أصدر كدليل للغة في 1972 صالحًا للتطبيق حتى الآن، مما يشهد بمدى تقدم تلك اللغة وقت إصدارها والنقلة النوعية التي أحدثتها في الوسط التقني. كين تومبسون Ken Thompson الصورة بواسطة National Inventors Hall of Fame منشورة برخصة CC BY-SA 3.0 أحد علماء الحاسب الأمريكيين الأوائل، عمل في مختبرات بل Bell Labs حقبة من الزمن وقد ساهم في تصميم نظام التشغيل يونكس UNIX وتشييده وقد ساهم في اختراع لغة B مع دينيس ريتشي اللغة التي تسبق مباشرةً لغة سي C، وقد ساهم أيضًا في اختراع نظام التشغيل Plan 9 وتطويره. انتقل كين للعمل في شركة غوغل Google منذ عام 2006 حيث أضاف إلى سجل إنجازاته المساهمة في تطوير لغة جو Go، ونذكر أيضًا من تلك الإنجازات العمل على التعابير النمطية RegEx وتعريف الترميز UTF-8. حصد كين تسعة جوائز معتبرة منها جائزة تيورنج Turing Award مع شريكه دينيس ريتشي عام 1983 وآخرها جاهزة Japan Prize عام 2011 تقديرًا لإنجازاته وجهوده المبذولة. جيمس غوسلينغ James Gosling الصورة بواسطة Eugene Zelenko منشورة برخصة CC BY-SA 4.0 عالم حاسوب كندي الأصل اشتهر شهرة كبيرة في تأسيسه للغة جافا Java الشهيرة وتصميمه لها ولمعماريتها المتمثلة في آلة جافا الافتراضية Java VM، كما له مساهمات معتبرة في اختراع النوافذ windows ضمن أنظمة التشغيل، إذ كان من أوائل من اخترع نظام النافذة في نظام التشغيل يونيكس تحت مظلة شركة Sun Microsystems. محمد عطا الله فيزيائي ومهندس أمريكي مصري وأحد علماء الحاسب الذين لهم أثر كبير في مجال أشباه الموصلات حيث اخترع أحد أشكال الترانزستور المسمى MOSFET في عام 1959، وهو ترانزستور به قناة نقل من أشباه الموصلات، يُستخدم في الدوائر المتكاملة -مثل المعالجات الدقيقة- ومحولات الطاقة في السيارات الكهربائية وأنظمة الاتصالات. حاتم زغلول أحد أشهر علماء الحاسب العرب حيث نستخدم اختراعه كل يوم، وهو كندي مصري، سجل براءة اختراع لتقنية هي أساس تقنيات الواي فاي الحديثة التي نستخدمها اليوم، مع ميشيل فتوش، أحد زملائه من علماء الحاسب المصريين أيضًا، وقد أنشأ معه عدة شركات لتسويق اختراعاتهما، حيث بُنيت عليها تقنيات الاتصالات الحديثة من الجيل الرابع، مثل CDMA، كما أسس عدة شركات في مجال التكنولوجيا والاتصالات. محمد بن موسى الخوارزمي الصورة بواسطة ميشيل بكني مشتقة من 1983 CPA 5426.jpg و CC BY-SA 4.0 وهو أحد علماء المسلمين الأغنياء عن التعريف لما اشتهر به من كتب ومؤلفات في الرياضيات والجبر والمثلثات والفلك، حيث اعتمد العلماء المسلمون في زمانه -القرن الثاني الهجري- على ترجمة أعمال الأمم التي سبقت بالعلوم والمعرفة وتعلمها ثم البناء عليها. وقد بنى علماء الحاسب في العصر الحديث أغلب تقنياتهم الحوسبية على المفاهيم التي أسسها الخوارزمي في الجبر وحساب المثلثات والمعادلات الخطية والتربيعية، وكذلك الخوارزميات التي سميت باسمه. يعقوب بن إسحاق الكِندي هو أحد العلماء المسلمين في القرن الثاني الهجري، برع في الفلسفة والرياضة والفلك والطب، لكننا سنركز على أعماله في التشفير والتعمية cryptography هنا، حيث كان له الفضل في تطوير أسلوب في التعمية لتحليل الاختلاف في وتيرة حدوث الحروف في الرسائل بالتحليل الإحصائي، ومن ثم فك الشفرات التي كُتبت بها، وقد فصّل ذلك في مخطوطة وُجدت في الأرشيف العثماني في اسطنبول بعنوان "مخطوط في فك رسائل التشفير". الخليل بن أحمد الفراهيدي أحد علماء المسلمين في القرن الثاني الهجري كذلك، وله إسهاماته في اللغة والأدب والعروض، وقد أثرت دراسته تلك في أعماله في علم التعمية إذ كان أول عالم لغوي يضع كتابًا في التعمية والتشفير، ذكر فيه استخدام التراكيب اللغوية والتباديل التي تسرد الكلمات العربية الممكنة بحروف العلة ومن غيرها، وأثرت أعماله في علم التعمية على الكِندي الذي ذكرناه قبل قليل. ويُنسب إليه كذلك علامات التشكيل العربية التي نستخدمها الآن والتي حلت محل النظام النقطي الذي كان قبلها، وقد كان ينوي استخدامها في الشعر فقط بادئ الأمر، إلا أنها صارت تُستخدم في كل مكان أيضًا. خاتمة تعرفنا في هذا المقال على أهم علماء الحاسب الذين كانت لهم بصمات مؤثرة في التقنيات التي نستخدمها اليوم، إما مباشرة أو بطريق غير مباشر، ونرجو بذكرنا للعلماء العرب أن نقدم قدوة للشباب ولأولادهم من بعدهم يحتذوا بها ويزيدوا عليها أيضًا، فمن كان يظن أن من اخترع الواي فاي وتقنيات الجيل الرابع وتقنيات التشفير والتعمية وبعض أشهر أنواع الرقائق الإلكترونية هم عرب تعلموا في مدارسنا وبيننا؟! ويبقى هنالك من علماء حاسوب لم نذكرهم في المقالة ليس لصغر إنجازاتهم ولكن لأن القائمة لن تنتهي وستتعرف عليهم تباعًا إن دخلت إلى مجال علوم الحاسوب. اقرأ أيضًا المدخل الشامل إلى علوم الحاسوب تعلم البرمجة دليلك إلى لغات البرمجة
  11. رأينا في المقالات السابقة من هذه السلسلة أن إدارة القوى العاملة عن بعد تأتي بتحديات فريدة بما في ذلك حاجة أصحاب العمل إلى توفير الأدوات والخدمات المناسبة للموظفين وإيجاد طرق مرنة وتشاركية للتواصل، ورأينا أهمية إحسان إدارة تلك العناصر العاملة عن بعد، خاصة بالنسبة لأولئك الذين اعتادوا العمل مع فريق في موقع العمل، وهذا ما سنناقشه ونركز عليه في هذا المقال. تحديات العمل عن بعد للمديرين لا يعدو المدير كونه أحد الموظفين في الشركة في الغالب، وعليه ما على الموظف من مسؤوليات والتزامات تجاه الشركة وإن اختلفت، فما يصلح للموظف من نصائح لمواجهة تحديات العمل عن بعد يصلح للمدير أيضًا، مع بعض الفروقات التي يختص بها المدراء لطبيعة عملهم الذي يديرون فيه بقية الموظفين أو يتابعون تحقيق المقاييس المطلوبة منهم، وقد يكون له نسبة في الشركة أو يكون هو مالكها. وقد يرتاح الموظف لعدم وجود إشراف مباشر من مديره في حين يزداد الضغط على المدير لحاجته إلى متابعة الموظف في عمله، وهو ما تعرضنا له في المقال السابق، آليات الإدارة والتطوير لشركة تعمل عن بعد، وبينا كيفية معالجته بأدوات مراقبة العمل وقياس أداء العاملين، كذلك قد تُسجل الاجتماعات الصوتية بين الموظفين وبعضهم أو بين الموظفين والعملاء، ويتم ذلك في الغالب بداعي مراقبة الجودة أكثر منه لمراجعته ممن لم يتمكن من حضور الاجتماع، بل الأولى أن يحضر الموظف الاجتماع الذي يراد منه حضوره، وذلك أنه قد يستفيد من النقاش الجاري أثناء الاجتماع أكثر من المادة نفسها، فإن كان المطلوب اطلاعًا على مادة مقروءة أو مسموعة فيكفي توفيرها للموظف دون الحاجة إلى تسجيل اجتماع، فتسجيل الاجتماعات المرئية أو الصوتية تشغل مساحة تخزين كبيرة، وتكون مكلفة في حالة الشركات التي تشتريها ضمن حزمة برامج الاجتماعات المرئية. الطائرة ليست سيارة بأجنحة عند انتقال الشركة إلى نمط العمل عن بعد أو تأسيس شركة وإدارتها عن بعد، يظن المدير أنه سيديرها أو يدير الفريق المسؤول عنه بنفس طرق الإدارة التقليدية بما أنه عمل مديرًا من قبل على الأرجح، وهو نفس الظن الذي يكون لدى من يظن أن التحليق بالطائرة يشبه قيادة السيارة بما أن الاختلاف الأبرز بينهما هو وجود أجنحة وذيل في الطائرة! وكما أن الفرق بين هذين كبير للغاية ولا وجه للشبه فيهما إلا أن تشغيلهما يتطلب إنسانًا خلف عجلة القيادة، وأن كليهما يحتوي على إطارات، فإن إدارة الفريق البعيد يتطلب عقلية تختلف عن عقلية الإدارة التقليدية في محل العمل. ويمكن إسقاط مثال الطائرة والسيارة هنا على كثير من مواقف العمل البعيد للاستفادة منها ولتكون مرجعًا سهل التذكر للمدير، فالشرخ الصغير على زجاج السيارة قد يظل شهورًا دون أن تسوء حالته أو يؤثر على سلامة القيادة، لكن ذلك الشرخ في زجاج قمرة القيادة يعني خطرًا وشيكًا ونهاية كارثية إذا لم يعالج على الفور. وكذلك لا يحدث شيء في الغالب حين يأخذ الركاب حواسيبهم المحمولة وبطاريات إضافية أيضًا داخل السيارة، لكن هذا له شروط وقواعد عند السفر بالطائرة، تصل إلى حد حظر نقل بعض تلك البطاريات أحيانًا، وقس على ذلك ما شابهها من أمثلة. التواجد الدائم كنت أظن أن كوني مديرًا في شركتي أو على فريقي يعني تواجدي الدائم للرد على أي استفسار أو سؤال حتى لو كان تافهًا، ويعزز هذا المقطع الذي انتشر لإيلون ماسك يقول فيه أنه متاح 24/7 لأي أحد في شركته، وكان مكتبه في إحدى شركاته ضمن المكاتب المفتوحة مع الموظفين لتقليل المراحل التي يمر بها الموظف حتى يصل إليه، وكذا كان يفعل مؤسس تويتر الذي كان يتبنى سياسة المكتب المفتوح لتسريع توارد الأفكار ومعالجتها وتطويرها، وذلك كله كان قبل انتشار العمل عن بعد قطعًا. غير أني وجدت -كما وجد مؤسسو 37Signals في كتبهم التي أشرنا إليها في هذه السلسلة- أن ذلك قد يكون نافعًا في حالات وضارًا في حالات أخرى، فليس عليك كمدير أن ترد على كل رسالة وكل بريد وإشعار وتعليق وملاحظة وغيرها، بل اجعل لنفسك مواعيد عمل محددة واحرص على بيانها للعاملين معك كتابة ولفظًا، خاصة إن كان فريق العمل البعيد الذي لديك أو تريد إنشاءه فيه أفراد من مناطق زمنية مختلفة. وهذا له فائدتان، الأولى أنك تضبط وقتك وتخصص فيه مدة محددة للرد على تلك الرسائل وإجراء اجتماعات إن لزم الأمر، ويفسح لك وقتًا تصرفه في أعمال الشركة الأخرى الإدارية أو لشخصك خارج العمل. والثانية أن الموظفين يتعودون على البحث وأخذ زمام الأمر بأنفسهم واستنفاذ الجهد في حل المشكلة التي بين أيديهم، فتتطور مهاراتهم في العمل من ناحية وفي الإدارة من ناحية أخرى، ولا يصل إليك إلا المشاكل التي تحتاج حقًا إلى تدخلك فيها. الردود الفورية حين تذهب إلى مكتب أحد الموظفين لتناقشه في أمر ما أو تستدعيه إلى مكتبك، فلن يستغرق هذا أكثر من بضعة دقائق للوصول إلى قرار أو التعمق في تفاصيل أكثر، أما عندما ترسل نفس الأمر في رسالة إليه فقد لا يرد إلا في اليوم الثاني مثلًا، وقد يرسل المدير الرسالة في البريد، ثم يرسل إليه على واتس اب بعدها بدقيقتين يخبره أن يتفقد البريد، ثم يتصل بعدها بعشر دقائق ليسأله هل رأى الرسالة بعد؟ وهذا يقضي على الفائدة التي يمكن تحقيقها من العمل عن بعد، ويسبب توترًا للعاملين يقلل إنتاجهم ويزيد تشتتهم، وعليه ينبغي تخصيص وسائل الاتصال الخاصة بالعمل، وتحديد غرض واضح لكل منها، وفترات سماح للرد على الرسائل البريدية وغيرها كي يتمكن العاملون من إنهاء مهامهم التي بأيديهم قبل النظر في الرسائل، وأن تُخصص قناة للأمور الطارئة التي لا تحتمل التأخير حقًا، كأن تكون على قناة دردشة أو متاح للاتصال الهاتفي، بينما تخصص برامج الاتصال المرئي أو المؤتمرات للاجتماعات المجدولة فقط، وهكذا. نموذج الإدارة البعيدة يقودنا هذا إلى نقطة أدوات الإدارة البعيدة نفسها، والتي سيأتي ذكرها عدة مرات في هذا الكتاب، وتكمن أهميتها عند النظر إلى نموذج الإدارة البعيدة كثلاثة تروس: أسلوب الإدارة. الأدوات التقنية والبرمجية التي تستخدمها الإدارة في التواصل مع العاملين. النتيجة النهائية من تطور مهارات العاملين وأثر قرارات الإدارة على منتجات الشركة. وترتبط تلك التروس الثلاثة ببعضها بحيث يكون ترس الأدوات في المنتصف، فإذا استُخدمت أدوات غير مناسبة فلن يدور الترس الثالث "ترس النتيجة النهائية" والذي هو المراد من تلك العملية كلها. وحل ذلك هو ما ذكرناه في النقطة السابقة وغيرها، من تخصيص قنوات التواصل بحيث يكون لكل منها غرض محدد، وذلك خطأ يقع فيه المدراء كما قلنا بسبب اعتمادهم على الوسائل التقليدية مثل البريد الإلكتروني والهاتف أثناء إدارة العاملين في مقر الشركة. التعقب الدقيق يحضر العاملون إلى مقر الشركة التقليدي ويسجلون حضورهم ببصماتهم أو توقيعاتهم، وتراهم كاميرات الشركة أثناء تواجدهم فيعلم المدير كيف يقضون أوقاتهم، وكذلك عند خروجهم بعد نهاية يوم العمل، أما عند العمل عن بعد، كيف يعرف المدير أنهم يعملون حقًا؟ هذا الأمر له جانبان، فبعض الوظائف تحتاج إلى تلك المراقبة الدقيقة كوظائف خدمة العملاء في القطاعات التي ترتبط بمواعيد مناسبة للعملاء أنفسهم، إما بمراقبة أوقات الحضور أو مراقبة مقاييس الأداء لتقديم أفضل خدمة ممكنة مع تقليل الوقت اللازم للتعامل مع كل عميل، انظر مثلًا مقال عشرة مقاييس تنتبه إليها أثناء مراقبة نشاط الموظفين في الشركة. أما في القطاعات اﻷخرى مثل الأعمال التقنية والإدارية وغيرها من الوظائف فلا تُشترط تلك المراقبة الدقيقة إلا في تحقيق مقاييس الأداء مثلًا، وتلك تقيسها أدوات وبرامج بالفعل فلا حاجة لتتبع تسجيلها، وفي تلك الحالة يُفضل إعطاء العاملين فسحة يعملون فيها من غير أن يتدخل المدير في كل صغيرة وكبيرة، ويؤدي سوء إدارة هذه النقطة إلى ما سنذكره أدناه من تظاهر الموظفين بالعمل ليريحوا أنفسهم من لوم المدير. فقر التواصل غير الرسمي يقابل المدير العاملين في الشركة وأفراد فريقه أثناء السير في أروقة الشركة ومكاتبها، ويتخلل هذا المحادثات العارضة بين الحين والآخر من السؤال عن الحال واﻷهل وآخر المشاريع التي يعملون عليها، وقد يخبره أحدهم بمشروع أو فكرة يود طرحها على الإدارة أو يظن أنها قد تحل المشكلة التي تعيق تقدم المشروع، فيتناقشان فيها لبضع دقائق ويقرر المدير أن يرشح هذا الموظف في الاجتماع التالي، خاصة إن كان من الموظفين الأحدث الذين قد يخشون الحديث في اجتماعات الشركة أو إبداء آرائهم بسهولة. وذلك الترشيح وتبادل الأفكار في المحادثات الجانبية وغير الرسمية يفتح الباب أمام الموظفين المميزين للظهور ويعزز فرصهم في الترقيات والمكافآت، وهو ما ليس متاحًا عند العمل عن بعد، أو على الأقل ليس بتلك السهولة وذلك التواتر، فقد يخشى الموظف أن يراسل غيره في أمر غير العمل أو المهمة التي يعملون عليها خشية تشتيت غيره أو إلهائه عن المهمة التي بيده، ظنًا منه أن زميله أو مديره لا شك يعمل الآن. فعلى المدير هنا أن يفسح الطريق لمحاكاة مثل هذه المحادثات، بتخصيص قناة للحديث غير الرسمي أو المتعلق بالعمل، وبمبادرته بالتواصل مع كل موظف على حدة كل يوم أو في الأسبوع عدة مرات على الأقل، ليتجاذب معه أطراف الحديث دون أن يكون ذلك بدافع العمل بالضرورة. وتكون قناة التواصل غير الرسمي محاكية لردهة المكتب الحقيقي التي يلتقي فيها العاملون لتجاذب أطراف الحديث، ويجب أن يشدد المدير المسؤول عن قنوات التواصل تلك على خصوصية الأحاديث التي تجري فيها، فلا يُنقل حديث من أحد العاملين فيها ليساءل عنه إلا بإذنه كونها قناة تواصل خاصة ولا تتعلق بالعمل، مع التنبيه على الموظفين من الناحية الأخرى بالتزام أعلى درجات المهنية والأخلاق العالية أثناء التواصل في تلك القنوات، وسيأتي الحديث مرة أخرى عن أمثلة النشاطات التي يمكن تنفيذها للتغلب على عزلة العمل عن بعد، ولا تُهمل فرص اللقاءات الافتراضية غير الرسمية والجوائز التي تُرسل إلى المتميزين في العمل شهريًا أو أسبوعيًا، سواء كانوا من المكتب أو كانوا عن بعد، فذلك يزيد الترابط بين العاملين عن بعد ويوحد لديهم الشعور بالزمان والمكان الذي يعملون فيه. انتهى يوم الموظف يتعاقد المدير مع الموظف على ساعات محددة في اليوم، فإذا قضاها ترك الشركة وذهب إلى بيته، فلا يكون بينهما وسيلة تواصل إلا في اليوم التالي، ثم ظهر الهاتف فصار المدير يستطيع إزعاج الموظف في بيته ليلًا إن شاء، ثم ظهرت الأدوات التي بين أيدينا الآن، فما عاد للموظف بيت ولا سكن! وتلك مشكلة تعاني كثير من الشركات منها سواء العاملة منها عن بعد أو من المكتب، وتتسبب في إرهاق نفسي لأكثر الموظفين وقد تؤدي إلى مشاكل أسرية بسبب انزعاج زوجاتهم من انشغالهم الدائم بالعمل، على أنه توجد شركات تمنع التواصل مع الموظفين في شؤون العمل خارج ساعات العمل الرسمية. وتظهر هذه المشكلة جلية في العمل عن بعد، بما أن مكتب الشركة هو الحاسوب الذي بين يدي المدير أو برامج إدارة المشاريع التي يستخدمها، ولا يبعد التواصل مع الموظف إلا بضع نقرات فقط على لوحة المفاتيح أو شاشة الهاتف، فكلما تذكر أمرًا أرسل به للموظفين. محمد، تذكرت اليوم أني لم يعجبني تصميم التطبيق، هلا عدلت قالب الألوان غدًا إن شاء الله ليبدو رسميًا أكثر؟ أبو أحمد، كيف الحال؟ هلا نظرت في العقد الذي سنوقع عليه غدًا؟ أظن أني رأيت بعض البنود التي قد تسبب مشاكل في الصفحة الرابعة أو الخامسة. بانتظار ردك. حسن، لماذا يتعطل التطبيق كلما أدرت شاشة الهاتف، لقد كان يعمل البارحة، ما التعديلات التي أجريتها عليه؟ ولماذا لم ترد إلى الآن؟ أعلم أنها الواحدة ليلًا، لكن هذه مشكلة طارئة وأريد ردًا عليها لو سمحت! إن مثل هذه الرسائل مؤذية للغاية وتخرب نمط عمل الموظفين وروتينهم اليومي، وإني أعلم من يغلق وسائل التواصل الخاصة بالعمل ولا يفتحها بعد انتهاء يوم العمل أو في الإجازات الأسبوعية، وكذلك يفعل أحد أقربائي في شركته إذ يغلق هاتفه بعد العشاء مباشرة ولا يفتحه إلا في اليوم التالي، وهو المدير نفسه في هذه الحالة، وشركته لا تعمل عن بعد، بل هي مواقع عمل موزعة في الصحراء وأعالي البحار، فمجرد التفكير في أن لي شركة كهذه يصيبني بالقلق من مقدار المشاكل المحتملة في كل موقع منها كل يوم! ورغم هذا فهو لا يتواصل مع أحد البتة بعد العمل. فاحرص على إرجاء إرسال تلك الرسائل، أو إن خشيت نسيانها، جدول إرسالها لتكون في صباح اليوم التالي، وذلك متاح في أغلب التطبيقات المستخدمة في العمل عن بعد. أولويات المشروع صحيح أن العمل عن بعد يوفر مرونة كبيرة في الجدول الزمني للعمل، سواء كان عملًا حرًا أو منتظمًا، غير أن تلك المرونة تعني أن الموظف معرض أكثر للتشتت من زميله الذي يعمل من المكتب، وهذا بدوره معرض أكثر لذلك الذي يعمل من حاسوب الشركة الذي تمنع الوصول فيه إلى شيء غير العمل. وهنا يجب وضع أساسيات لأولويات العمل عن بعد لضمان إنجاز الموظفين للمهام في مواقيتها دون تأخير في تنفيذها أو إرهاق للعاملين، والأسهل أن تهيأ بيئة تضمن حدوث تلك التدابير بدلًا من الاعتماد على قوة الإرادة لكل موظف، بدءًا من إضافات المتصفحات التي تحظر مواقع التواصل الاجتماعي خلال ساعات العمل مثلًا وصولًا إلى أدوات إدارة جداول العمل اليومية ومتابعة الأداء وتوزيعها الأسبوعي على الفرق العاملة، ونحيلك هنا إلى مقال رفع أداء الموظفين عبر تحديد أهدافهم. والشائع في إدارة تلك الأولويات والمهام هي أدوات مثل "أنا" التي عملت شركة حسوب على تطويرها مدة لتلبي احتياجاتها الخاصة ابتداءً من إدارة للمشاريع والعمل المشترك، لكن يجب التنبيه هنا على الموظفين أن يسجلوا الدخول إلى أدوات العمل تلك من أجهزة مخصصة للعمل، فلا يسجلوا الدخول إلى صناديق بريد العمل أو لوحات متابعة المهام من حواسيب شخصية أو هواتف خاصة، لتجنب ما نذكره في غير موضع من هذا الكتاب من إرهاق الموظف العامل عن بعد من ناحية، وللحفاظ على أمان بيانات الشركة من ناحية أخرى. وتلك نقطة يغفل كثير من الموظفين عنها ويقعون فيها رغبة في تسهيل الوصول إلى أدوات وبيانات العمل، دون وعي بمشاكلها، وهي تسجيل الدخول إلى أدوات العمل من الأجهزة الشخصية، فتأتي بالعمل إلى جيب الموظف ليل نهار، ولا يكون عنده فصل حقيقي لا جسدي ولا نفسي عن العمل، وهو أحد أسباب الإرهاق الذهني والجسدي للموظفين سواء العاملين من المكتب أو عن بعد، وأحد أسباب تراجع أدائهم في العمل كذلك على المدى المتوسط والبعيد. ويفضل تحديد التوقعات المطلوبة من الموظفين في بداية كل مهمة أو أسبوع عمل أو حتى يوم عمل، خاصة إن كان ذلك في بداية عمل الموظفين، أما العاملون الأقدم والأكثر خبرة فلن يحتاجوا إلى كثير متابعة من المدراء، وعلى هذا يبدو الكتاب موجهًا في أغلبه للمدراء الذين يتعاملون مع الموظفين الجدد، أو المنتقلين إلى نمط العمل عن بعد حديثًا، وفي الواقع هذا قريب من هدف الكتاب الذي وُضع له، إذ استهدفنا به المدراء الذين يفكرون في اعتماد العمل عن بعد أو التوظيف عن بعد، إما توظيفًا دائمًا أو تعهيدًا خارجيًا، أو إدارة لمستقلين عبر خدمة مثل مستقل للمؤسسات كما رأينا في الفصول السابقة. إدارة فريق هجين قد يعمل بعض أعضاء الفريق من المكتب والبعض الآخر عن بعد، وهنا ينبغي أن ينتبه المدراء انتباهًا شديدً إلى كيفية معاملة الفريق العامل من المكتب. فقد أتت إحدى المديرات التي لدينا في الشركة ذات صباح ومعها قطع حلوى توزعها على العاملين بالمكتب، ثم أرسلت هي أو أحد الموظفين من المكتب صور الحلوى وهي مع الموظفين إلى العاملين عن بعد، يمازحونهم أن لو أتوا إلى المكتب لحصلوا على الحلوى. وقد يقف القارئ المدير هنا قائلًا، هذا أمر سخيف، فهل تريدني أن أعدل في مثل هذا؟! والإجابة التي لدينا هي نعم، لا ريب! لكن دعنا نوضح الأمر قليلًا … هذا المثال البسيط قد يكون في صور أخرى، تتمثل في المكاتب التي توفرها الشركة للعاملين من المكتب والمكاتب التي لدى العاملين من منازلهم، أليس من العدل أن توفر الشركة نفس المعدات المكتبية للعاملين لديها؟ إن المفاضلة في هذا لصالح مكتب الشركة يرسل رسالةً مفادها أن لو أردت راحة العمل تعال إلى المكتب، فماذا لو كانت امرأة لا تستطيع ترك أولادها أو تعول بيتها لمرض زوجها أو وفاته؟ بل ماذا لو كانت شركتك موزعة في أكثر من دولة؟ وقل مثل هذا على أي شيء قد يحصل عليه العاملون في مقر الشركة ويراه العاملون من المنزل لكنه ليس لديهم أو عليهم توفيره بأنفسهم، ثم يتعدى هذا إلى فرص الترقيات التي ستكون أسهل للعاملين من المكتب بما أنهم يحتكون بالمدراء أكثر. وهذه الحالة للفرق الهجينة تحتاج إلى رعاية دقيقة من المدراء، إذ يقول فِل جولد Phil Gold صاحب دورة إدارة الفرق البعيدة على موقع LinkedIn Learning أنه قابل من الموظفين في الشركات من يخبره أن مثل تلك الأمور أثرت فيه سلبًا، هذه الأمور التي قد تبدو تافهة مثل الطعام أو الحلوى أو غيرها، وهو أمر غاية في الدقة ينبغي أن ينتبه إليه من يسوس الناس في شركة أو بيت أو غيرها، وإن كان الولد أو الموظف لا يقولها صراحة أحيانًا إلا أنها تبني في النفس غيرة يمكن تجنبها بقليل من الحكمة. فمثلًا، هناك حل لطيف يبدو سهل التنفيذ وقد حدثني به أحد العاملين في شركة عاملة عن بعد، كما ذكره فِل أيضًا ضمن الأمثلة التي ذكرها في إدارة الفرق الهجينة أن أحد المدراء نفذه أيضًا، وهو ترتيب مع بعض المطاعم لإرسال طعام إلى الحاضرين في الاجتماع في نفس الوقت أثناء الاجتماع. العدل في المكافآت وفقًا لأداء الموظفين من المهم عن مكافأة الموظف العامل عن بعد أن يكون ثمة عدل أيضًا، فأولًا ينبغي أن تكون المكافأة أمام الفريق كله سواء العامل عن بعد أو من المكتب، في رسالة بريدية أو أثناء اجتماع أو غير ذلك. وإن أرسلت هدية إلى رامي أو أظهرت إنجازه كمكافأة فيجب أن تفعل هذا أيضًا لمحمد وسلمى وعمر، بنفس الأسلوب، في كل مرة، أما في حالة الأداء الضعيف، فهذه تكون محادثة على انفراد، فالتوبيخ على العلن أمر ليس محمود العقبى في الفريق، لا للذي توبخه ولا لباقي الفريق الذي لا محالة سيكون في نفس موقفه يومًا ما. توفيق مواعيد اللقاءات والاجتماعات المهمة ذكرنا من قبل أن الشركات البعيدة قد تعتمد أسلوب الساعات المتراكبة، وأن هذا له عدة منافع، لكن من ناحية أخرى، كيف تنسق اجتماعًا بين أشخاص في مناطق زمنية مختلفة؟ لنفترض أن لدينا اجتماعًا مهمًا والفريق يعمل عبر عدة دول، من البرازيل إلى الهند مثلًا، فنختار حينها موعدًا مناسبًا لأكثر الفريق، وسيكون لدينا بعض أعضاء الفريق عندها حاضرين للاجتماع في وقت غير مناسب لهم، لكن هذا أفضل ما يمكن فعله، وينبغي عليك كمدير أن تتحمل أنت ذلك الموعد بين الحين والآخر، ليكون أكثر فريقك في مواعيد مناسبة لهم، بينما أنت الذي تحضر في موعد غير مناسب لمنطقتك الزمنية. الحفاظ على العلاقات قوية مع الموظفين من السهل التواصل مع أعضاء الفريق كل يوم أكثر من مرة أثناء العمل من المكتب، والدخول إلى تفاصيل عائلية للاطمئنان عليهم دون أن يشعر من يُسأل بالحرج أو الغرابة، لكن هذا مختلف قليلًا حين تأتيك رسالة أثناء العمل تقول "كيف أبلى أحمد في الاختبار اليوم"! لكن مرة أخرى مثل هذا التواصل ضروري بين أفراد الفريق، فكيف نوفقه؟ لتحرص كمدير على تحديد مواعيد ثابتة كاجتماعات دورية قصيرة للاطمئنان على أعضاء الفريق، والسؤال عن حال كل واحد فيهم كل يوم على حدة، سؤالًا يتعدى "كيف الحال" الذي ستكون إجابته لا شك "الحمد لله"، فتسأله أسئلة تجعله يجيبك بما يجري معه في حاله، كأن تسأله ما أخبار ابنتك سلوى اليوم، أو كيف حال القطة التي كانت مريضة بالأمس، أو هل ذهبت إلى الشاطئ في عطلتك الفائتة؟ وهكذا. بناء الثقة في الموظفين على بداهة أمر مثل الثقة بين أي جهتين تتعاملان معًا، إلا أن الثقة تُكتسب في العادة ولا توهب، وتُبنى أهم معايير استحقاقها على عوامل سمعية وبصرية يراها الطرفان المتعاملان، فكيف وقد تعذر ذلك بسبب التواصل البعيد؟ وبناء عليه سيحتاج المدير إلى المبادرة بمنح هذه الثقة للموظفين مع توضيح الأهداف المشتركة والمطلوبة منهم، والحرص على توفير الدعم والمساعدة التي يحتاجون إليها ولو لم يطلبونها، فذلك جزء من تلك الثقة الممنوحة. وتشمل صور الدعم تلك معاملة الفريق بالاحترام الذي يستحقونه لو كانوا اكتسبوه بالمعاملة، ما لم يثبت ما يقتضي خلاف هذا الاستحقاق، ومطابقة الفعل بالقول وإنجاز الوعود التي تعطيها للفريق. كذلك ستجد تجاوزات في حق تلك الثقة الممنوحة ينبغي أن تُقابل بالحِلم والنصيحة الحسنة، لئلا تستفز ردود فعل دفاعية بداعي الكِبر وحفظ ماء الوجه فتُحدث شرخًا يصعب التئامه، فيصير التزام الفريق بالعمل دافعه كراهية مساءتك، وليس خشية المساءلة. وتمامًا على هذه النقطة، وبما أن الدليل موجه للمدراء بالأساس، وقد ذكرنا مرة بعد مرة أهمية النشاطات الاجتماعية غير الرسمية بين أعضاء الفريق، فيجب أن ننبه إلى ألا ينخرط المدير في أحد تلك النشاطات وهو يعلم أنه يخرج فائزًا، خاصة إن كان ذلك الفوز يعني الحصول على جائزة مادية أو امتياز في العمل. كذلك من صور بناء الثقة ما ذكرناه في موضع آخر في هذا الدليل من إرشاد الموظفين لتحين فرصة ليعملوا معًا في جلسة افتراضية وإن لم يكن العمل على مشروع واحد، أو ضبط موعد راحة أثناء العمل لكوب قهوة أو وجبة خفيفة في تلك الجلسة الافتراضية. العمل والحياة الشخصية ذكرنا أن المدير ما هو إلا عامل عن بعد أيضًا كباقي الموظفين الذين تحته، غير أنه يختلف عنهم في أن المدير ينزع كثيرًا إلى العمل أكثر من الموظفين، لمتابعة أدائهم، ومراجعة التقارير التي رفعوها إليه، وحل المشاكل التي تطرأ لبعضهم، والنظر في كيفية سد العجز الذي سببه غياب هذا الموظف أو ذاك، وهكذا، لا تكاد مهام المدير تنتهي إن حملها على كاهله وحده. ويكاد يبرر لنفسه كل ما يفعله إذا كان يمت للعمل بصلة، فهو يبرر متابعته لبريد الشركة على هاتفه بحرصه على متابعة سير العمل، ودخوله بعد وقت العمل إلى مكتب الشركة الافتراضي أو مراجعة المهام المنجزة أو التي يُخطط لها بأنه يريد اكتشاف أي مشكلة قد تطرأ ليحلها مبكرًا، وليتأكد من كفاءة الخطط الموضوعة والمهام المنجزة. وهذا واقع مشاهد في حياة أغلب المدراء سواء العاملين عن بعد أو في مقرات الشركات، ويزيد عدد ساعات العمل ومقدار الإجهاد النفسي والجسدي على المدير طرديًا مع زيادة مسؤولياته، فترى المديرين التنفيذيين للشركات الكبرى يعملون سبعين ساعة وثمانين وتسعين أحيانًا كل أسبوع، وقلما يقتطعون من أوقاتهم إجازات سنوية، ولربما تأثرت حياتهم الاجتماعية سلبًا فلم تتحمل زوجاتهم تلك الحياة -غير الموجودة- فيطلبن الطلاق. ولا أتوقع أن يكون حل تلك المشاكل في هذه الفقرات البسيطة التي نكتبها، فهذا سيكون تسطيحًا فجًا لهذه المشكلة العميقة، وإنما نترك بين يدي القارئ المفاتيح التي عثرنا عليها أثناء بحثنا لحلول تلك المشاكل لنا أنفسنا حين كنا ندير الموظفين سواء عن بعد أو من مقرات أعمالنا. تحديد الأولويات قبل أن تقرر عدد ساعات العمل الأسبوعية والمهام التي تريد العمل عليها، يجب أن تنظر أولًا في أي تلك المهام يجب أن تعمل عليها في هذا الأسبوع، وأيها لا يمكن لغيرك أن ينفذها كي تفوض تنفيذ الباقي إلى غيرك من العاملين معك. الدنيا "لن تطير" كنت أحاول استغلال وقتي إلى آخر ذرة فيه كل أسبوع في الأعوام الماضية، ما بين تفقد سير العمل في فروع تجارتي إلى ممارسة الرياضة أحيانًا إلى القراءة إلى الترجمة والكتابة، إلى تعلم دورات ومساقات جديدة، واجتماعات العمل التي لا تبدأ في الأوقات التي خططنا لها، ولا تُناقش فيها البنود التي جُدولت لها، ولا تنتهي إلا بعد ساعة على الأقل من الوقت الذي أردنا إنهاءها فيه! وكان ذلك كله يضعني في دوامة الإجهاد التي ذكرتها أعلاه للمدراء، وكنت كلما نظرت إلى المهام التي بين يدي لا أرى مهمة يمكن تأجيلها أو إلغاؤها، فلم يكن لدي حل إلا التفويض، فبدأت في هذا رويدًا أحيانًا وبسرعة أحيانًا أخرى، مع تقديم الدعم اللازم للقائم بتلك المهمة حتى يتقنها، وظللت هكذا بضعة أشهر حتى تركت إدارة تجارتي بالكلية إلى أحد شركائي! والغالب في مثل هذه السلوكيات هو رغبة المدير في إنجاز أكبر قدر من المهام في أقل وقت ممكن، غير أن المرء لو ذكر حديث الحض على غرس الفسيلة ولو قامت القيامة لعلم أن أغلب الطوارئ يمكن التعامل معها بضبط نفس، وبتفويض لها إلى بعض الموظفين، ليحافظ المدير على جدول عمله مناسبًا بما يضمن كفاءة عمله من ناحية، وسعادته العائلية من ناحية أخرى، فأي طارئ أعظم من قيام الساعة! ومع هذا لا يترك العامل ما بيده يأسًا أو جزعًا لينظر هذا الطارئ الجديد، فلكلٍ وقته. العمل للعمل والبيت للبيت لعل المديرين يتعلمون هذا الأمر من العاملين معهم، فأغلب الموظفين يفصلون هواتف العمل بعد انتهاء ساعات العمل، ويغلقون حواسيب العمل، ولا يردون على الرسائل البريدية الخاصة به، وذلك كله من حقهم، بل من الحقوق التي صارت تكفلها الدول في التشريعات الجديدة للعمل عن بعد. غير أن المدير يكون على عكس ذلك في الغالب، خاصة إن كان يدير فرق عمل تعمل بساعات متراكبة، فيلجأ إلى استخدام هاتفه الشخصي لمتابعة أداء العاملين، وحاسوبه الشخصي، بل وربما حاسوب أحد الموجودين معه في المنزل إن تطلب الأمر! وقد يكون في اجتماع أثناء عودته من مكتبه إلى البيت إن كان يعمل من مساحة عمل مشتركة، فيدخل البيت وهو بعد في الاجتماع، ثم بعد العشاء يعود إلى البحث في مجريات ذلك الاجتماع إلى منتصف الليل، ويرد على رسائل بعض العملاء والموظفين وغيرهم، ولا يجد إلا بضع ساعات قبل بدء يوم عمله التالي. وهذا -على أثره الضار- أتفهمه لطبيعة عمل المدير، غير أنه إن كان ديدنه فيجب أن ينظر جديًا في المهام التي يمكن لغيره تنفيذها فيفوضها إليه، ولجدول عمله مرة أخرى فيحاول تأجيل بعض المهام إلى أسابيع لاحقة إن كانت تؤثر على حياته العائلية، فبعض الشركات مثل 37Signals تتبنى مبدأ النمو البطيء الهادئ، فتقلل ساعات العمل الأسبوعية، وتقلل أيام العمل في الصيف، كي يحظى العاملون بأوقات كافية مع ذويهم، وقد ثبت بتجارب تلك الشركة وغيرها بل وبعض الدول أيضًا أن ست ساعات كل يوم أكثر من كافية لإتمام العمل، وتكون الساعات الباقية هدرًا كان يجب استغلاله في أمور غير العمل، وهذا واضح في غير مجال، كما في حالة مجال التعليم في فنلندا والولايات المتحدة مثلًا، حيث تزيد كفاءة التعليم في فنلندا عن الولايات المتحدة كثيرًا، رغم قلة الساعات التي يقضيها المعلمون في فنلندا عن الولايات المتحدة في التدريس. ونعيد التذكير بألا يستخدم أجهزته الشخصية لأغراض العمل، فإن كان هذا صحيحًا في حالة الموظفين فإنه في حالة المدير أشد ضرورة، وألا يدخل إلى مكتبه بعد مواعيد العمل أيضًا، فقد ذكرنا مثال مدير الشركة كثيرة العمال والمواقع التابعة لها الذي يغلق هاتفه عند عودته من العمل، وهو رأس الشركة، وكنت أتعجب غاية العجب وقتها من فعله، فماذا لو حدث كذا، وماذا لو وقع كذا، غير أنه فوض إدارة تلك المهام إلى غيره في حال حدوث طارئ أثناء تلك الأوقات، ويحيل مدير كل موقع مشاكل موقعه في ورديات العمل الليلية إلى يوم العمل التالي في الصباح حين يُبلَّغ ذلك إلى إدارة الشركة في مقرها الأم. العمل من مكتب خارجي أم من المنزل يختلف تفضيل المدير في عمله من منزله أو من مكتب خاص أو من مساحة عمل مشتركة وفقًا لطبيعة المدير نفسه، ولكل مزاياه وعيوبه، فالبيت يفتقر إلى الخصوصية إلا إذا وضعت قواعد لتنظيم عمله فيه وفصله عن سائر مهام البيت، شأنه في هذا شأن الموظف العامل عن بعد، والمكتب الخاص قد يكون مكلفًا لكنه مفيد في حال إجراء اجتماعات مع عملاء أو موظفين آخرين، سواء عن بعد أو في المكتب نفسه، وكذلك مساحات العمل المشتركة -وإن كان مكتبًا خاصًا فيها- توفر فرصة الوصول إلى عقول جديدة وتقلل عزلة العمل عن بعد. والواقع أن الغالب سيكون عملًا من المنزل، لتوفير نفقات الإيجار ولباقي المزايا التي ذكرناها في أول السسلسلة وفي كتاب دليل المستقل والعامل عن بعد، خاصة إن كان يتولى المدير رعاية بعض أهله، فإن لم يستطع العمل من المنزل فليتخذ مكتبًا خاصًا به منفصلًا عن المنزل، وإن كان هذا يزيد في تكاليف العمل إلا أنه جد مفيد للتركيز على العمل كما ذكرنا في سياق الكتاب في فصول سابقة وفي هذا المقال، وقد جربته بنفسي لفترات طويلة ورأيت أثره، وكيف أن تكلفة ذلك المكتب لا تعدو كونها بضعة ساعات عمل، ثم يكون كل ما وراءها ربح وزيادة تركيز في العمل، إلى حد أني كدت أن أقلب الغاية التي استأجرت المكتب من أجلها بأن كنت أبيت بعض الليالي فيه لشدة إعجابي بالنتائج التي رأيتها منه! وهذا الخيار على ندرة ما رأيت اتباع المدراء له إلا أني الآن أنصح به لمن يستطيع، فهو يحقق نقطة "البيت للبيت" التي ذكرناها من قبل، ويحقق فائدة نفسية عظيمة للمدير ولمن يسكن معه في نفس البيت، وهي نقطة لا ينتبه المرء إليها، فالزوجة والأولاد ينتظرون اليوم كله حتى يقضي الرجل من عمله ليجلس إليهم، وكذلك بقية العائلة التي لها حق صلة الرحم، وقد شهدت بنفسي شكاوى زوجات بعض العاملين معنا من استيلاء العمل على وقت زوجها في الليل والنهار، وفي أيام العمل والإجازات، إلى حد أننا كنا نتحايل عليه بشتى الحيل ليقضي إجازة مع أهله، ثم لا نلبث أن نراه عاد إلى مقر العمل مرة أخرى في يوم إجازته لفكرة أراد إخبارنا بها أو لمهمة تذكرها، وذلك قبل عدة أعوام، أي قبل وباء كوفيد وازدهار العمل عن بعد. أما العمل من مساحات العمل المشتركة، فهو على وجهين بالنسبة للمدراء الذين يديرون فرق عمل عن بعد، فإما أن تكون مساحة العمل تابعة للشركة نفسها، غير أنها تخصصها لمن يرغب في العمل منها أو للموظفين الجدد أو لغير ذلك مما يوافق احتياجات الشركة، وقد رأيت شركات كبيرة تعامل مقراتها على أنها مساحات عمل مشتركة حقًا بعد اعتمادها نظام العمل عن بعد، بل وعلى عكس ما جرى للشركات والمصانع التي كانت تغلق فروعها وتبيعها لعدم حاجتها إليها بعد اعتماد العمل عن بعد، فإن تلك الشركات استثمرت في مقرات أفضل وأكبر وأحدث تجهيزًا وملائمة للعمل عن بعد، وأنشأت تطبيقًا للهاتف فيه تخطيط جميع مقراتها في الدول العاملة فيها، بمواقع المكاتب الموجودة في كل طابق وكل مبنى منها، مع رمز خاص بكل مكتب، وما على الموظف الراغب في العمل من أحد تلك المقرات سوى الدخول إلى التطبيق وحجز المكتب الذي يريده في الأيام التي سيعمل فيها من المكتب، ويوضح كذلك عدد الساعات التي سيشغل فيها مكتبه. وأما الوجه الثاني فهو أن تدفع الشركة اشتراكات في مساحات العمل القريبة من مواقع عمل موظفيها عن بعد، ليلتقي فيها الفريق في أيام العمل العادية أو في الاجتماعات الهامة ليستفيد من الموارد المتاحة في مساحة العمل المشتركة، أو حتى تدفع ذلك الاشتراك للموظفين الراغبين في ذلك ولا يرغبون في العمل من المنزل لأي سبب كان، ولا يريدون استئجار مكتب خاص أيضًا. شحن النفس وتخليتها بعد انتهاء ساعات العمل ينبغي صرف الوقت فيما ينفع لا ريب، ومما ينفع النفس هنا تخليتها مما شغلها سائر يومها في العمل، بممارسة الرياضة أو قضاء الوقت مع الأهل أو القراءة أو حتى مجرد التفكر في الكون أثناء المشي أو الجلوس في المنزل أو في الحديقة، فمطاردة حلول مشاكل العمل في كل وقت يرهق الذهن ويقعده عن تحصيل تلك الحلول، والأولى إعطاؤه فسحة يتنفس فيها من تلك الحلقات المتعاودة للعمل والمهام والمشاكل. ومنه أيضًا إمتاع العين والنفس بالطبيعة المحيطة بصاحبها، بالنزهات القصيرة في الحدائق أو المناطق ذات الطبيعة الخلابة، أو التخطيط للنزهات المتوسطة أو الطويلة في العطلات كذلك. الروتين الثمين وفوائده السبعين نعيد ذكر هذه النصيحة التي نكاد نشير إليها في كل مناسبة تقريبًا، لعلمنا أن العاملين عن بعد يميلون إلى المرونة في العمل، وتنفيذ المهام في الأوقات التي يرغبون فيها، غير أن هذا النمط لا تستقيم الحياة به، خاصة مع إدارة موظفين آخرين. وعلى ذلك ينبغي تحديد المهام المتكررة كل يوم، وتخصيص وقت ثابت لها ما أمكن، فوقت للقهوة ووقت لمراجعة البريد ووقت للرياضة وأيام أو أوقات للاجتماعات، هذا خلاف الأيام المحددة للإجازات الأسبوعية. فهذا الروتين سيضع كل جزء في حياتك في موضعه الصحيح تلقائيًا، ويعلم الموظفون معك متى تكون متاحًا ومتى لا تفضل الاتصال بك. وكذلك تخصيص مساحة فارغة من المهام ما أمكن في كل يوم أو كل أسبوع، وتخصيصها للطوارئ أو للراحة في غير الطوارئ، لئلا يبدو جدولك مزدحمًا طوال الوقت بالمهام، حتى إذا جاءت مهمة طارئة لم تستطع تنفيذها. اليوم الهادئ يفضل أن تبدأ يوم العمل قبله بساعتين إلى أربع ساعات مثلًا، يتهيأ فيها جسدك لليوم الجديد رويدًا، فتبدأ بالصلاة والرياضة والإفطار مثلًا، فتكون قد غذيت جسدك وروحك معًا، ورفعت مستويات طاقة جسدك إلى أقصاها، وذلك كله ولم تبدأ العمل بعد. ثم بما أنك المدير هنا ولست الموظف، فلا شك أن مهامك ستكون متغيرة من يوم لآخر وإن تشابهت القوالب العامة لها، لذا أفضل للمدراء أن يراجعوا صناديق بريدهم في بداية اليوم، ثم تنسيق اليوم وفقًا لها، ما لم يكن ثمة طارئ أو مهمة أولى يجب تنفيذها. وذلك من خبرتي المتواضعة في السنوات الماضية كمدير، إذ لم أكن منخرطًا في المهام اليومية بقدر بقية من معي من الذين كانوا ينظرون في المهام العالقة مباشرةً في أول اليوم، أو يكملون ما كانوا يعملون عليه في اليوم السابق، أما أنا فكنت أتلقى في الغالب الملاحظات والرسائل التي تركوها لي من اليوم السابق لأرى ما يجب فعله بشأنها وتنسيق الموارد البشرية أو المادية وفقًا لها. لماذا نذكر هذا النمط وكأنه دعوة إلى التراخي في العمل؟! في الواقع، تكون مهمة المدير في الغالب إدارة أفراد العمل لا العمل نفسه، وعلى ذلك تكون أغلب الأمور التي يفعلها في اليوم تؤدي إلى قرارات بالنهاية، فهو في الاجتماع يشرح فكرة أو يستمع إليها، وفي الرسائل يكتب قرارًا أو يقرأ ليتخذ قرارًا، ويوافق على تعديل ما أو يرفضه، وهكذا. ومثل تلك الأمور كلها تحتاج إلى شخص هادئ النفس رائق البال، ليستطيع الوصول إلى أفضل القرارات المناسبة لشركته، فمثله كمثل القاضي الذي يجب ألا يحكم بين اثنين وهو جائع أو غضبان أو غير ذلك. تحديات العمل عن بعد للموظفين تختلف شخصيات العاملين وتفضيلاتهم في العمل، وكذلك تختلف ظروف الشركات التي تسمح بالعمل عن بعد أو تفرضه، ونذكر هنا بعض التحديات التي يواجهها الموظفون أثناء العمل عن بعد، إما التحديات التي ليس لهم يد فيها أو التي تنتج عن سلوك مباشر منهم. العزلة في العمل لا شك أن كل موظف يطمح في مكتب خاص به في الشركة، لكنه في الغالب يعمل في مكتب مفتوح فيه غيره من أعضاء فريقه، وسيمر خلال اليوم لا محالة على زملائه وأفراد الأمن وربما بعض أطقم الصيانة للمبنى، هذا غير من يقابلهم في طريقه من البيت إلى العمل والعكس. أما عند العمل من المنزل، فسيقصر الطريق إلى العمل من بضعة كيلومترات إلى بضعة خطوات، ولن يرى فيها سوى زوجه أو ابنه مثلًا، ثم يدخل إلى مكتبه ويعمل وحيدًا فيه حتى نهاية اليوم. وقد يمثل هذا بيئة العمل المثلى للبعض، وكابوسًا مخيفًا للبعض الآخر، فالناس تختلف في طبائعها وبيئة العمل التي تكون مريحة لها، وكذلك تختلف باختلاف نوع العمل نفسه، فبعض الوظائف تتطلب هدوءًا وقلة مشتتات، وبعضها يصلحه اجتماع العاملين معًا في مكان واحد. التظاهر بالعمل يسمح العمل عن بعد للموظف بحرية أكبر بما أنه في الغالب ليس عليه رقيب في محل العمل، وهذا الأمر فيه بعض أوجه القصور كما أن فيه مزايا عظيمة. فقد ذكرنا في مقال مدخل إلى العمل عن بعد، أن فيه فوائد اجتماعية للعاملين عن بعد في تمكينهم من تنفيذ مهام لم يكن باستطاعتهم تنفيذها من قبل أو كانوا يقتطعون إجازات من أجلها، كصلة الأرحام وزيارات الطبيب وتوصيل الأولاد إلى المدارس، ومثل الشؤون اليومية التي لا بد منها مثل صلاة الجماعة والذهاب إلى صالات الرياضة في الأوقات التي لا تكون مزدحمة فيها، وهكذا، فتلك من المزايا الكبيرة التي يوفرها العمل عن بعد في كثير من الشركات. أما وجه القصور هنا فهو شعور المدير أن الموظف يتظاهر بالعمل أو يريد التفلت منه، وشعور الموظف أن عليه المبالغة في إظهار عمله، فتحدث بعض السلوكيات من المدراء والموظفين على حد سواء تجعل بيئة العمل عن بعد غير صحية. فقد يتهم المدير موظفيه بأنهم كسالى أو مراوغون في أعمالهم، وقد ذكرنا أن إيلون ماسك يريد العاملين في شركة تيسلا أن يعودوا للعمل من مقر الشركة، وأن من يريد العمل من بيته فليذهب إلى شركة أخرى "ليتظاهر" بالعمل فيها. غير أنه في نفس الوقت كان ينوي السماح للعاملين في شركة تويتر التي أراد شراءها بالعمل من المنزل، فكيف ننظر إلى هذين الموقفين من نفس المدير؟ نقول هنا أن الشركة الأولى في فترة صعبة في إنتاجها، وهي شركة تصنع منتجات حقيقية في مصانع، فإذا أخرج أحد الموظفين تصميمًا جديدًا يقلل معامل السحب Drag coefficient للسيارة بحيث تقل مقاومة الهواء لها فيقل استهلاك البطارية، أو تحديثًا جديدًا لنظام تشغيل السيارة، فهذا يحتاج إلى التواجد على أرض المصنع لاختبار هذا التصميم أو ذلك التحديث مع من سيصنعه ويختبره. أما في مثال الشركة الأخرى، وهي تويتر، فهي شركة برمجية لا تحتاج من أحد أن يجرب محركًا جديدًا أو يراقب سبائك الصلب أثناء خروجها من الفرن، بل لا تحتاج إلى تزامن عمل أغلب الموظفين حتى أو التصاقهم بالحواسيب طول اليوم، وعلى ذلك فهي تعتمد نفس النهج الذي تعتمده حسوب و 37Signals و Buffer مما ذكرناه في المقال السابق في شأن التواصل غير المتزامن. وفي تلك البيئات البرمجية التي يكون أغلب العمل التقني فيها هندسيًا ويحتاج إلى كثير من التركيز والتحليل المنطقي، وحتى الأعمال غير الهندسية مثل الترجمة والتصميم المرئي والكتابة وغيرها تحتاج إلى كثير من التفكير والبحث والترتيب، فيغلب على العاملين فيها فترات نشاط وفتور في العمل، فقد يظل الموظف في عصف ذهني واختبار للأفكار والحلول والتصاميم المقترحة وحده أو مع فريقه أسبوعًا أو أسبوعين، دون كتابة سطر برمجي واحد، ثم يصلون إلى نتيجة فينطلق في العمل عدة أيام متواصلة مثلًا، على أنه توجد أنظمة مثل Scrum تعالج مثل تلك العيوب في سير العمل. وعلى ذلك يخشى الموظف أن مديره في العمل يلاحظ سكونه في أيام العمل أو يظن أنه ترك العمل مبكرًا أو تكاسل فيه، فيلجأ إلى سلوكيات تشبه ما يفعله الموظفون في مقرات الشركة التقليدية من بقاء في المكتب بعد ساعات العمل أو قبله حتى لو لم يكن ينفذ مهامًا حقًا لمجرد أن يراه المدير فيظن أنه مجتهد في العمل. وأمثلة تلك السلوكيات أن يترك الموظف آثارًا وبصمات إلكترونية في مستندات العمل المشتركة أو ملفات المشروع الذي يعمل عليه لمجرد أن يعرف المدير وزملاؤه أنه كان موجودًا في ذلك الوقت، حتى لو لم تكن تلك المساهمات ذات أهمية، أو يظل متاحًا بعد ساعات العمل مدة أطول لئلا يظن أحد أنه ترك العمل مبكرًا بما أنه لا يراه أحد، وغيرها من السلوكيات التي تزيد من الضغط النفسي على العامل عن بعد ليثبت جدارته في العمل أمام مديره. ويحضرني في هذا مثال شهير يحدث بين الطلاب في دراستهم، ولا شك أنه ينتقل معهم إلى بيئة العمل، وهو بين الطالب الذي يفكر بيده فيكتب المسوّدات وينشئ نماذج أولية ويجرب الحلول التي يراها للمسائل على الورق فإذا تبين له خطؤها ألقى الأوراق وجلب أوراقًا جديدة، وبين الطالب الذي يظل مطرقًا محدقًا في المسألة دون أن يحرك ساكنًا، ثم إذا وصل إلى الحل السليم أخرج الأوراق وبدأ يكتب. وباعتبار أن كلا الطالبين مجتهد وعالم بالمسألة التي يحلها، فإن ما يبدو للمعلم أن الطالب الأول هو المجتهد الذي يستحق المكافأة، وأن الثاني إذا جاء بالحل صحيحًا فإنه لا بد قد غشه من غيره بما أنه لم يذكر كيف وصل إليه. وتلك حالة حقيقية رأيتها وتحدث في بيئتي التعليم والعمل كثيرًا، فيُرفض حل الطالب الثاني لأنه لم يذكر كيف وصل إليه، وهو درس للمدراء الذين لديهم موظفين من ذلك النوع الثاني والذي يُعرف بنمط عمله، فتراه يكتم إشعارات قنوات التواصل أثناء العمل، ويرد على الرسائل البريدية في وقت محدد في اليوم، ويفضل نمط العمل غير المتزامن لأنه يحتاج إلى فترات هدوء للتركيز على إخراج الحل المناسب بما أنه يعالج المشكلة داخل عقله وليس على ورق مفصل بين يديه أو على شاشة الحاسوب. وإن كنت أنا من النوع الثاني إلا أني أشهد بالكفاءة الشديدة لإخراج الأفكار والحلول على الأوراق أو الحاسوب أو أي وسيط آخر لاختبارها فيه، غير أني أشير بهذا إلى المدير كي لا يسارع بالحكم على الموظف الهادئ الذي لا يترك فوضى خلفه قبل معرفة حقيقة مجريات العمل، وتوضع مقاييس أخرى لقياس الأداء كما ذكرنا تقيس تحقيق خطوات العمل، وليس تحقيق النتائج فقط. العمل المفرط وإرهاق العمل قد تكون هذه النقطة مخالفة للمنطق بادي الرأي، فكيف يشعر الموظف الذي يعمل من بيته بالإرهاق؟ والواقع أن الإرهاق هنا يحدث نتيجة خلل في ضبط منظومة العمل من المنزل أو عن بعد، ويمكن سداد ذلك الخلل بوضع قواعد دقيقة للعمل ومتابعته، بحيث لا يختلف العمل من المكتب عن العمل من المنزل. وهذه مشكلة تمتد جذورها إلى ما قبل العمل عن بعد ووباء كوفيد الذي فرض نظام العمل عن بعد من قبل على العالم، فالمعتاد في اليابان مثلًا أن الموظفين يعملون ساعات كثيرة كل يوم، وليس غريبًا أن ترى موظفًا عائدًا من عمله في الثالثة فجرًا، بل تشكلت حول تلك الثقافة مظاهر بدت خالصة لتلك الأمة، مثل برج ناكاجين Nakagin الذي أنشئ في السبعينات من القرن الماضي إبان ثورة اليابان الصناعية، والمكوّن من كبسولات يمكن فكها وتركيبها، والذي كان أحد أبرز الفئات التي استخدمته هي فئة الموظفين الذين يعملون على مشاريع مهمة وحرجة لكن مساكنهم بعيدة عن الشركة، حيث كانوا يستأجرون كبسولة أو يشترونها ليعودوا إليها آخر النهار للراحة إذ هو أقرب من منازلهم، أو لمتابعة العمل فيها إذا كان يصعب متابعته في المنزل! فكانت إحدى نتائج تلك الثقافة للعمل المضني وتشجيعه أن ظهرت حالة الموت نتيجة العمل الزائد Overwork death أو التي تُعرف باسم كاروشي Karoshi. وهذه المشكلة لم تكن مقصورة على اليابان وحدها وإن برزت فيها، وباتت الشركات تعلم التأثير السلبي للعمل الزائد دون إجازة على الصحة النفسية والجسدية للموظف، فشرعت شركات كثيرة في وضع قواعد وشروط للعمل الذي يضمن تجنب تلك المشاكل في بيئاتها إذا لم تكن قوانين الدولة العاملة فيها الشركة كافية، خاصة إذا كانت المجالات مستحدثة ولم تواكبها القوانين بعد أو تُرى آثارها بوضوح، كما في المجالات التقنية أو الحوسبية، فإما تمنع الشركة الوصول إلى خوادمها بعد ساعات العمل إلا بتصريح مسبق، أو تضع قواعد صريحة للتعامل مع العمل الزائد برفضه صراحة عند طلب الموظف له أو مساءلته إذا تم من غير إذن وحاجة ملحة، كذلك تشجع الشركات العاملين فيها على قضاء الإجازات الأسبوعية مع ذويهم وبعيدًا عن حواسيب العمل وصناديقه البريدية ما لم تكن ثمة ضرورة لواحد أو أكثر من الموظفين. خاتمة تطرقنا في هذا المقال إلى أبرز التحديات التي تواجه المدير العامل عن بعد في تنظيم يوم عمله، وأفضل الاستراتيجيات التي يمكن لكل شركة استخدامها للتغلب على هذه المشكلات والاستمتاع بالمزايا الكاملة التي يقدمها العمل عن بُعد. بالإضافة لعرض أساليب حول التوازن بين العمل والحياة الشخصية للمديرين، وحاولنا الإجابة عن تساؤل حول خيار المكان المناسب للعمل عن بُعد، وأخيرًا تحدثنا حول عادات لصياغة يوم عمل مثالي لك عن بُعد كمدير. ونكون بهذا قد شرحنا ماهية العمل البعيد من منظور مدير الفريق أو الشركة، وكيفية تأسيس بيئة العمل المناسبة للعمل عن بعد، ثم توظيف العاملين وإدارتهم، وها نحن في تحديات الإدارة البعيدة، ويبقى لنا المقال الأخير الذي نتحدث فيه عن استقرار الشركة البعيدة وتطورها. كتبت فاطمة أحمد المسودة الأولية لهذا المقال. اقرأ أيضًا المقال السابق: آليات الإدارة والتطوير لشركة تعمل عن بعد الفن السري للتفويض لماذا يجب أﻻ نعمل في السرير؟ كيف يبدأ الأشخاص الناجحون يومهم: أفضل نماذج للروتين الصباحي تجاوز التحديات العشرة التي تواجه المدراء الجدد استراتيجيات تعزيز مسؤولية الموظفين تجاه العمل 8 طرق لتحقيق الاستفادة القصوى من العمل في البيت
  12. يحتاج إعداد بيئة العمل البعيدة إلى تخطيط سليم لدراسة الأدوات وأساليب العمل التي يجب استخدامها واتباعها، ثم طرق مراقبة ذلك العمل لتقييمه وتصحيحه وقياس أداء العاملين، وتدريب العاملين الجدد على العمل أيضًا، ثم تأتي النشاطات المكملة للعمل نفسه، والتي تمثل حاشية العمل التي تكمل الجوانب الناقصة في علاقات الموظفين ببعضهم جراء العمل عن بعد، من لقاءات دورية وحوافز معنوية ومسابقات وغيرها. وقد عرفنا فوائد هذا النمط من العمل للشركات في المقال السابق، وعرفنا صوره المختلفة وعوامله التي تؤثر فيه ويجب النظر فيها عند تأسيس الشركة لتعمل عن بعد أو نقلها لهذا النمط إن كانت قائمة بالفعل، ولعلك عرفت الآن إن كان مناسبًا لك أم لا، وننطلق الآن لنتعرف كيف نؤسس بيئة العمل الجديدة لتكون مناسبة للعمل البعيد. ولتعلم أنك كمدير فريق أو مؤسسة ستراجع أدوار الموظفين ومهامهم عند النظر في تبني هذا النمط، وكذلك قد تعيد النظر في مخططات سير العمل لهؤلاء الموظفين لترى إن كنت تحتاج إلى برامج أو أدوات جديدة لمتابعة العمل ودمجه مع بقية الشركة التي تعمل من المكتب مثلًا في حالة تبني العمل عن بعد جزئيًا، وهل سيعمل الموظفون من حواسيبهم الخاصة فتحتاج إلى أدوات سحابية أو شبكية لضمان أمان البيانات وتوحيد منصات العمل، أم من حواسيب خاصة بالشركة، وكم سيحتاج ذلك من ميزانيات مادية، وتجهيزات لوجستية لتجهيز تلك الحواسيب وإرسالها إلى الموظفين ومتابعتها بعد توصيلها للدعم الفني والتحديثات وغيرها، وهل سيؤثر هذا على مستوى إنتاج العاملين أم لا. تأسيس بيئة عمل عن بعد مقابل الانتقال من بيئة عمل تقليدية سيكون الأمر أسهل في بعض الجوانب إن كانت الشركة قيد التأسيس وأصعب في جوانب أخرى، فمن ناحية لن تحتاج إلى إقناع العاملين بالانتقال إلى هذا النمط إذا وُجد منهم من يفضل العمل من المكتب بما أنك ستضع شرط العمل عن بعد في إعلانات التوظيف، وسيأتيك من هو مستعد نفسيًا وتقنيًا لهذا النمط من العمل، وقد يكون أصعب في جوانب التجهيز والإعداد من طرفك بما أنك ستخوض عملية إنشاء الشركة من ناحية مع مخاطرة التجارة الملازمة للشركات إلى أن تصل إلى نقطة التعادل على الأقل، ومن ناحية أخرى سيكون عليك تأسيس بيئة العمل الجديدة ومتابعة أداء الموظفين والشركة عن بعد، وهو الجانب الذي نريد تيسيره وشرحه في الكتاب. أما إذا كانت الشركة قائمة بالفعل فستحتاج إلى تنفيذ مرحلة تجريبية قليلة المخاطر لدراسة جدوى الانتقال إلى العمل عن بعد مع مراجعة العاملين ومتابعتهم في تلك الفترة التجريبية لتعرف ما الذي نجح من سياستك فتعتمده، كما ستحتاج إلى تحديث السياسات المتعلقة بالعمل عن بعد وإجراءات السلامة والصحة البدنية والنفسية في مكان العمل البعيد، وقد نشرت شركة حسوب دليلًا للعمل عن بعد لتوفر على الشركات كثيرًا من الخطوات اللازمة لإدارة العمل البعيد بكفاءة. وستعطيك تلك البيانات التي تجمعها من الفترة التجريبية فكرة عن الميزانية المطلوبة للاستثمار في بنية تحتية تقنية للفرق العاملة عن بعد من حواسيب وأدوات وبرامج كما تقدم بيانه، وهذا يعني بالضرورة توظيف مختصين بهذه البنية التحتية إن كانت الشركة متوسطة الحجم إلى كبيرة، خاصة إذا كنت تنوي إرسال حواسيب إلى الموظفين، لتلافي إرسال عتاد تالف أو غير مناسب، أو إرسال قطع مختلفة أو ناقصة، وهكذا، فإنك تريد الانتقال إلى النمط البعيد لتتخلص من بعض أوجه القصور في العمل المكتبي، لا أن تضيف إلى نفسك مشاكل جديدة! الأهلية التقنية للعاملين عن بعد تفترض الشركات في الغالب أثناء التوظيف معرفة الموظف التقنية في شأن التعامل مع الحواسيب وبرامج العمل، أو على الأقل تشترط ذلك، وقد يبدو الحديث عن هذا اﻷمر سخيفًا إذا كان مجال الشركة تقنيًا بالأساس، غير أني رأيت من العاملين من لا يعرف في تعامله مع الحاسوب أكثر من فتح بعض البرامج الأساسية، وقد كان ذلك في شركة تقنية، لذا يفضل أن تتأكد الشركة من أهلية الموظف ابتداءً وقدرته على التعامل الصحيح مع برامج العمل وأدواته، أو حتى توفير بعض التوجيه والإرشاد إذ قد يعلم الموظف كيف يستخدم أدوات العمل لكن ربما ليس الاستخدام الأمثل. وبما أننا ذكرنا هذه النقطة، فنعرّج على أمر آخر قد يغفل عنه المدراء، وهو تعلم المدراء أنفسهم للأدوات والتقنيات التي يستخدمونها، فإذا لم تكن للشركة سياسة محددة للبرامج والأدوات الخاصة بالعمل وأغراضها، أو كان المدير وصاحب الشركة من يسن قوانين العمل فيها، فقد ينزع إلى استخدام الأدوات والتطبيقات التي ألفها وتعود عليها، مثل البريد والهاتف والفاكس رغم بياننا لأهمية تخصيص قنوات التواصل وأدوات العمل بأغراض محددة تناسب العمل أولًا وآخرًا. تدريب العاملين عن بعد كذلك ينبغي أن يحتوي منهج تدريب العاملين عن بعد على سياسات الشركة وثقافتها، وطرق تنفيذ المهام والتدريب عليها، وتنفيذ محاكاة لتنفيذ بعض المهام إن لزم، مع محاضرات أو مواد تعليمية عن أمن المعلومات وإجراءات الاتصالات الآمنة والعلاقات بين أعضاء الفريق مما يجب قوله وما يجب تجنبه، والأدوات المستخدمة لمتابعة تنفيذ المهام والجداول الزمنية للعمل اليومي والأسبوعي. كذلك، توضع قواعد واضحة للتواصل النصي والمرئي، فلا يُنصح بالتواصل في غير أوقات العمل، لما يسببه ذلك من إحراج أو إرهاق للعاملين أمام أهليهم -خاصة في حالة الموظفات من النساء-، وذلك أن ثقافات التواصل بيننا تختلف عن ثقافات التواصل في الشعوب غير العربية أو المسلمة، وكنت أرى أكثر المواد التي تفصل في أساليب العمل عن بعد تكون إما باللغة الإنجليزية أو مترجمة منها، ولا تُعرَّب تلك الأساليب لتناسبنا نحن العرب. وعلى ذلك تضع الشركة قواعد للتواصل المرئي بألا تكون الاجتماعات في أوقات غير مناسبة ما أمكن، ويُتجنب قطعها لأوقات العبادة بأن تُجعل الاجتماعات قبلها أو بعدها بوقت كافي، لئلا تُقطع الاجتماعات في منتصفها، وإذا كان الاجتماع مرئيًا فيكون اللباس ومحل الاجتماع على قدر من المهنية والالتزام، فقد عملت مع فرق من قبل كانت تعقد كثيرًا من الاجتماعات المرئية، وكانت الشركة أجنبية تترك حرية السلوك مفتوحة إلى حد كبير، فصدرت مع الوقت تجاوزات مؤذية من بعض الأعضاء إلى زملائهم بقصد أو بغير قصد، ثم نسمع بعدها عن جلسات تأديبية وتحقيقات وغيرها، مما كان يمكن تجنبه إذا التزم العاملون ببعض الجدية والمهنية أثناء التعامل فيما بينهم. فإذا كان لا بد من الاجتماعات المرئية فليعاملها الموظفون كأنهم ذاهبون إلى مقر الشركة، من هندامهم الذي يظهرون به أمام الشاشة وأسلوب حديثهم، مع الحرص على مراعاة خصوصية منازلهم بألا تكون الكاميرا مواجهة لممر يظهر فيه أفراد المنزل إن كانوا يعملون من المنزل، وذلك أولى من التفكير في جودة صوت الاجتماع والإضاءة وغيرها، فتلك تأتي في المرتبة الثانية، وإن كانت مثل هذه النصائح تقال للعاملين عن بعد مطلقًا إما في شركات أو عملًا حرًا، لما ثبت من أثر نفسي على معاملة العمل من المنزل بنفس الجدية التي يُعامَل بها العمل التقليدي. كذلك تُحدد الألفاظ التي يجب استخدامها بين الموظفين في قنوات التواصل، وحدود المعاملات بين الجنسين خاصة لئلا تقع مشاكل من غير أن يشعر الواقع فيها أنه يؤذي زميله. وإذا كانت الشركة تدرب الموظفين الجدد في مقر الشركة ليعملوا عن بعد، فينبغي أن تعودهم على العمل عن بعد وهم في مقرها، بأن تُدرب الشركة العاملين فيها على استخدام برنامج اجتماعات مرئية من أجل الاجتماعات، وبرنامج محادثات نصية للنقاشات السريعة، وكذلك البريد الإلكتروني للرسائل المهمة ونشرات الشركة ووثائقها، مع استخدام خدمة تخزين سحابية لمستندات الشركة وأدلة استخدام البرامج وتنفيذ المهام وغيرها، وكل ذلك تمهيدًا لنقل بيئة العمل التقليدية لتكون عن بعد. وعندئذ قد يأتي أحد المتدربين بحاسوبه إلى جوار المدرب أو أحد زملائه على مكتبه ليسأله عن أمر ما، فينبغي للمدرب أن يوجهه إلى قناة التواصل الصحيحة في هذا، وهذا مثال لواقعة حقيقية من عاملين في شركة تقنية كانت تدرب العاملين فيها على العمل عن بعد، فرغم أنه أتى يمشي إلى مكتبه، ومكتبه لا يبعد عنه بضع خطوات، إلا أنه يدرَّب ليعمل عن بعد في غضون أيام، وعلى هذا ينبغي أن يوطن نفسه على استخدام قنوات الاتصال المناسبة. وهو تمام على ما سنذكره أدناه من توفير أدوات المساعدة والدعم في صورة يسهل الوصول إليها والاستفادة منها وإلا فسيلجأ الموظفون إلى سؤال بعضهم بعضًا أو سؤال من هم أكثر خبرة منهم، ومن ثم تضييع مزيد من أوقاتهم وأوقات زملائهم. دور مجال الشركة في صلاحية العمل عن بعد قد تحكم طبيعة العمل لديك مقاييس زمنية ترتبط بعوامل خارجة عن الشركة نفسها، مثل العمل في الدعم الفني أو الاستقبال أو غيرها، فتلك الوظائف ترتبط بعملاء الشركة وليس بالشركة نفسها، وتتعلق مواقيت العمل فيها بالأوقات المناسبة للعملاء وليس للشركة، فقد تعمل الشركة من دولة تختلف مواقيتها الزمنية عن مواقيت العملاء، وحينئذ تضطر الفرق العاملة في الدعم الفني إلى التواجد أو العمل في مواقيت تختلف عن مواقيت عمل الشركة، لكن هل هذا يعني أن العمل عن بعد لا يصلح هنا؟ في الواقع، كلا، وليس لهذا علاقة البتة بصلاحية العمل عن بعد في الشركة، فكل ما تحتاج المؤسسة إليه في هذه الحالة هو توظيف مدراء يعملون في نفس مواقيت عمل الدعم الفني وحسب، وهذا هو واقع مراكز الدعم الفني وخدمة العملاء في الشركات الكبرى التي تعمل في أسواق عدة مثل أمريكا الشمالية وأوروبا وغيرها، فتلك الشركات تنقل خدمة العملاء إلى مراكز تابعة لها في دول أخرى مثل ألبانيا والهند ومصر وباكستان والمجر لتخفيف الالتزامات المالية والقانونية عليها، أو ربما تعهد إلى شركات خارجية في تلك الدول تنوب عنها في هذه العملية، ولا تحتاج عندئذ إلا لتوظيف من يدير تلك العملية كأنها عملية مستقلة بذاتها، وتسجيل مجرياتها في نظام رقمي سحابي أو على خوادم الشركة بما يكون من تحديث لبيانات العملاء، أو نقل ذلك لأقسام أخرى من الشركة إن كانت طلبات العملاء تتطلب نقلًا إلى أقسام مثل البيع أو الشحن أو الإدارة العليا أو غيرها. ولن تكون عملية التواصل المباشر بين العاملين مشكلة في بيئات خدمة العملاء، وهي البيئة التي تشبه في عملها خطوط الإنتاج في المصانع من حيث وتيرتها السريعة وحاجتها الشديدة للتواصل الفوري، ذلك أن الموظفين يستطيعون التواصل في قنوات اتصال في الوقت الحقيقي مثل التي توفرها برامج الاجتماعات أو المحادثات الفورية، ومراجعة المشاكل التي سبق التعرض لها في قاعدة بيانات يسجلها الموظفون أنفسهم مع كل حالة أو تسجلها الشركة وتوفرها للموظفين كدليل يُرجع إليه لتوفير وقت الرجوع إلى المدراء. فإذا كان العمل عن بعد يصلح في مثل تلك الحالات فإنه ولا شك يصلح لما هو أقل منها في الحاجة إلى التواصل، والتي يكفيها وجود عدة موظفين تتقاطع ساعات أو أيام عملهم مع بعضهم بحيث لا تسقط بيانات مهمة أثناء العمل. الانتقال إلى بيئة عمل عن بعد لا شك أن الشركات تستفيد عند الانتقال إلى العمل عن بُعد استفادة كبيرة، خاصة في شأن توظيف أفضل المواهب وإسعاد موظفيها كما ذكرنا، غير أن الاستغناء عن المكتب ثم إدارة العاملين عن بعد ليست مهمة سهلة لمن لم يعتادها، وتحتاج إلى تخطيط وتحضير إذا تم تنفذها الشركة من قبل أو تكن لها خبرة بها، وهناك عدة طرق تحول بها شركتك من مكتب تقليدي إلى شركة عاملة عن بُعد. تطوير معايير ومبادئ توجيهية جديدة ينبغي أن تراجع الشركة البيانات التي تحصل عليها من العاملين لديها قبل الانتقال إلى العمل عن بعد، وكذلك لوائح العمل التنظيمية، من أجل معرفة إن كانت تحتاج إلى تعديلات للوضع الجديد، ثم يبلَّغ العاملون المتأثرون بتلك اللوائح بالإرشادات والتعديلات الجديدة من خلال الوسائل التي توثق تلك الإرشادات، ومن خلال جلسات مرئية تطول أو تقصر وفقًا لحجم التعديلات على تلك الإرشادات من قِبل مدربين من الشركة للتأكد أن جميع الموظفين قد فهموا الوضع الجديد. تحديد لوائح العمل عن بعد تحمل سياسات العمل عن بُعد أهمية لكل من الموظفين وأصحاب العمل، ويجب أن تغطي جميع الجوانب الهامة للعمل عن بُعد ليصبح من السهل على أعضاء الفريق فهم كيفية التصرف بأنفسهم. على سبيل المثال، يجب أن تذكر سياسة العمل عن بُعد بوضوح إذا كان مسموحًا للموظفين تثبيت برامج غير برامج العمل على أنظمة الحواسيب التي توفرها لهم الشركة أم لا، وذلك للأسباب التي ذكرناها من قبل في شأن حماية أمن البيانات مثلًا. وصحيح أن هذه السياسات تتوقف على عدد الموظفين وحجم الشركة واحتياجاتها، لكنها في العموم تدور حول ما يلي: هل يجب أن يكون الفريق متصلًا بالإنترنت خلال ساعات عمل محددة أم أن جداول العمل مرنة؟ وما هي ساعات العمل في تلك الحالة؟ وهل يحتاج العاملون إلى مراعاة المناطق الزمنية المختلفة في عمليات التواصل؟ ما هي الأدوات التي يستخدمها الفريق للتواصل والتعاون بفعالية؟ كيف يتتبع الفريق التقدم المحرز في المشاريع ويقيس النتائج؟ على سبيل المثال، تحدد سياسة العمل عن بُعد في Google التدريب الافتراضي والفصول الدراسية التي عُقدت من التي ستساعد الموظفين في عملية الانتقال، ويرجع الموظفون إلى هذا المستند متى احتاجوا إليه، مما سيوفر لهم الوقت في التواصل مع مديريهم. وبالمثل، توضح سياسة العمل عن بُعد Shopify أفضل أدوات الاتصال، ولماذا يطلبون من الموظفين استخدامها، وكيف سيؤثر اختيارهم في برنامج العمل عن بُعد بشكل إيجابي على الفرق البعيدة. وفي العموم، توضع المراحل التالية في الحسبان عند كتابة سياسة العمل عن بُعد ومشاركتها من أجل تحقيق الاستفادة المثلى منها نسردها بالتفصيل. 1. وضع جداول العمل الرسمية ينبغي ذكر الساعات التي يتعين على الموظفين التواجد فيها عبر الهاتف أو البريد الإلكتروني أو برامج المراسلة، وتحديد الوقت الذي يجب أن يبدأ فيه الموظفون العمل وينتهون العمل كل يوم، وتستخدم الشركات وسائل شتى لذلك، من المتابعة اليدوية إلى رسائل البريد إلى تطبيقات المكاتب الافتراضية التي يسجل العاملون الدخول إليها عند بدء العمل ويسجلون الخروج عند الانتهاء منه، وصولًا إلى أدوات تستخدمها الشركات الكبرى مثل Avaya و Cisco. 2. تقييم كفاءة العمل عن بعد حدد كيفية تقييم جودة عمل الموظف عن بُعد وما هي عمليات المراجعة التي سيتم تنفيذها للتأكد من أن الجميع لا يزال يبذل قصارى جهده، واطلب من رؤساء الأقسام تزويدك بتعليقات حول مسودة سياسة العمل عن بعد لأنك قد تفوتك الفروق الدقيقة في بعض المناصب التي تحتاج إلى تغطيتها. 3. إجراء مراجعات منتظمة للسياسة راجع سياسة العمل عن بعد كل ثلاثة أشهر أو عند وقوع أحداث كبيرة داخل مؤسستك أو خارجها للتأكد من أنها لا تزال ذات صلة. ويمكنك الاستفادة في هذا الصدد من دليل العمل عن بعد لشركة حسوب، وكذلك دليل حسوب للموظفين. إنشاء قاعدة معرفية داخلية يعد برنامج إدارة المعرفة الداخلية عاملًا آخر يجب عليك مراعاته عند نقل مكتبك التقليدي إلى نظام العمل عن بعد، وسيكون هذا بمثابة مركز التعليمات بين العاملين في الفريق، ويجب أن تكون قاعدة المعرفة تلك جيدة التوثيق وقابلة للبحث فيها بالكلمات المفتاحية، وإلا فسيلجأ الموظفون إلى الدوران حولها وسؤال زملائهم الأقدم منهم أو مدراؤهم، إما مباشرة أو من خلال وسائل الاتصال والمحادثة الأخرى، وذلك في أحسن الحالات، أو يتوقفون لا يدرون كيف ينفذون المهمة التي بين أيديهم، مما يزيد وقت التشغيل لتلك المهمة. وأما إن كان لدى الشركة قاعدة معرفية مسبقًا، فتضاف اللوائح والإرشادات الجديدة الخاصة بالعمل عن بعد فقط. إنشاء مقاييس للأداء كما أن الشركة في الوضع العادي لها لديها مؤشرات للأداء مثل الالتزام بالمواعيد وجودة الأعمال المسلمة ورضا العملاء وحجم المبيعات وغيرها، فيجب اعتماد تلك المقاييس في العمل عن بعد، مع الحرص على استخراج بيانات العمل قدر الإمكان لتحديد إنتاج الموظف وكفاءته في أداء مهامه من جهة لإدارة شؤونه الوظيفية من حوافز وجزاءات وإجازات وغيرها، وكفاءته في التواصل مع زملائه وفهمه لتفاصيل العمل وإدارته للمشاكل التي تواجهه أو تواجه فريقه، من أجل تقييم فرص ترقيته من جهة أخرى. وتزيد أهمية مقاييس الأداء هنا في العمل البعيد بما أن كثيرًا من جوانب التواصل المرئي وتحليل أداء الموظفين بمجرد المراقبة قد تعذر بسبب عمل الموظف عن بعد، فقد كانت تتحكم عوامل الحكم البدهي من قِبل المديرين والمسؤولين عن التوظيف في جزء كبير من ترقية الموظف أو مكافأة أو توقيع الجزاء عليه، بمجرد مراقبة سلوكه في المواقف العارضة والاجتماعات ومعاملته لأفراد الشركة وعملائها وغيرهم. أما في العمل البعيد فلا يرى المدير إلا أداء الموظف في مهامه فقط، وقد يقال أن هذا يكفي للحكم على عمله، وهذا صحيح إن كانت الترقية لوظيفة فنية أخرى فيمكن إهمال الجوانب الشخصية حينها إلى حد ما، أما إن كانت الترقية لإدارة مشروع أو فريق فمن السذاجة إغفال سلوك الموظف هنا وأسلوب تفكيره وقناعاته الشخصية وتغير مزاجه في المشاكل الطارئة. تحديد الغرض من الفريق البعيد يقترب التأسيس الناجح للعمل عن بعد من الهندسة والفن على حد سواء، شأنه في ذلك كأي نمط أو نهج للعمل، لذا ستحتاج إلى تهيئة الظروف المناسبة وتنفيذ أفضل الممارسات لضمان أن يكون فريقك البعيد منتجًا وفعالًا وناجحًا. يجيب ذلك الغرض على "سبب" إنشاء الفريق من الأساس، فيرسم المسار الذي يجب أن يكون عليه الفريق في هيكلته وأدوات عمله وغير هذا، ونعده ضروريًا قبل بناء فريقك البعيد لأنه سيرشدك في المرحلة التي تسبق التشغيل، فتعرف من تريد توظيفه وما الذي تبحث عنه في المرشحين. اختيار مدير الفريق أما توظيف مدير الفريق فيختلف ميقاته وفقًا لحالة الفريق نفسه والمشروع الذي يعمل عليه، فالمشاريع ذات المتطلبات الدقيقة والمتغيرة تحتاج إلى توظيف مدير الفريق أولًا، ويكون أدرى الناس بالغاية من ذلك المشروع وإن لم يكن أتقنهم لأدوات تنفيذه، ثم يُختار أعضاء الفريق بعد ذلك، وتُعطى صلاحية ذلك للمدير نفسه إن أمكن. أما في حالة الفرق ذات المهام الروتينية أو المتكررة أو التي عُرفت أبعادها فلا بأس من اختيار أعضاء الفريق قبل مدير المشروع، بل قد يعمل الفريق دون مدير فترة من الزمن لتوفر دليل العمل للمهام التي يعملون عليها في الغالب. وضع أطر العمل ثم نأتي بعدها لإعداد أطر العمل المناسبة، وتبرز أهميتها عند العمل مع فرق افتراضية يكون فيها موظفين ذوي ثقافات مختلفة ومن مناطق زمنية متباينة، حيث تعمل هذه الأطر على تناغم سير العمل وتحديد المسؤوليات، فيجب إنشاء مخطط تنظيمي لذلك الإطار وفق الإرشادات التي نوردها في هذا المقال والتي سنوضحها في الفصول التالية. مخططات سير العمل Workflow Charts يكون لكل مشروع أو مهمة مخطط لسير العمل يختص به، ويكون الغرض منه ضمان كفاءة تنفيذ العمل، فعلى سبيل المثال، يمكن أن يبدو سير العمل لمشروع محاسبة كما يلي: وهكذا تختلف مخططات سير العمل باختلاف المشاريع والمهام، ومن المهم كتابة تلك المخططات في بداية كل عمل سواء كان عن بعد أم من الشركة، ووضعه في دليل عمل للموظفين، غير أنه في حالة العمل عن بعد يكون آكَد وأوجَب لأن الموظف -خاصة الجديد- يحتاج إلى دعم أسرع في البداية، فيمثل مخطط سير العمل طريقًا مختصرًا لتنفيذ المهام دون تخبط أو مشاكل في التواصل. توظيف المواهب المناسبة تولي الشركات عناية كبيرة باختيار الموظفين لديها، فلا حاجة هنا إلى إسهاب في الشرح حول هذا الأمر، فأقسام الموارد البشرية تتولاه بكفاءة، لكن ربما يجب أن نشير إلى أن المهارات المطلوبة في العاملين عن بعد هي التي تنشئ برامج تأهيلية ليتعلمها الموظفون الحاليون لديك. فيفضَّل توجيه أسئلة المقابلات لدراسة نفسية الموظف من تلك الجوانب، فيُسأل مثلًا عن سلوكه عند مواجهة مهمة صعبة أو عند تعذر الدعم المناسب، أو عند رغبته في اقتراح فكرة جديدة على باقي فريقه عن بعد، وهواياته التي يقضي فيها وقته لترى مدى جديته في العمل وانضباطه، ومدى حاجته إلى التوجيه أو المتابعة في فترة عمله الأولى على الأقل، ومدى صبره على العمل بمفرده ونمط شخصيته فهنالك شخصيات إجتماعية بنسبة كبيرة قد لا تحتمل العمل خلف الحاسوب دون وجود زملاء حولها. ويمكن سبر نفسية المرشح للعمل عن بعد بأسئلة على النحو التالي: كيف تتصرف في حال انقطاع وسائل التواصل أو الطاقة عن حاسوب العمل؟ لقياس حسن تصرف الموظف بالإبلاغ عن المشاكل التي قد لا تراها الشركة من طرفها إلا في وقت متأخر. كيف تقضي وقت فراغك خارج نطاق العمل؟ لقياس تأثير العمل عليه ومدى تحمله لإجهاده، وطبيعة شخصيته من حيث الانطوائية أو الانبساطية في سلوكه خارج نطاق العمل. ما المكان الذي تفضل العمل فيه في المنزل أو مساحة العمل؟ لقياس قدرته على العمل في بيئة هادئة أو تحتوي على مشتتات من حوله، وتحديد مواضع الخلل إن طرأت لاحقًا أثناء العمل. وغيرها من الأسئلة التي تخبر الشركة بسلوك الموظف أثناء مواجهة المشاكل أو المهام المملة أو العمل مع فريق من عدمه وفقًا لحاجة المهمة أو المشروع الذي سيعمل عليه، فقد تتطلب بعض المشاريع أن يستطيع الموظف العمل ضمن فريق مفرط النشاط، وربما لا يهم ذلك لأن المشروع الذي سيعمل عليه يتطلب الكثير من البحث والتركيز أو ليس فيه أفراد إلا قليلًا. تعزيز التواصل بين الموظفين العاملين عن بعد لا شك أن طباع الناس تختلف في تفضيلات بيئة العمل، فبعضهم لا يريد أن يسمع همسًا أثناء تركيزه على ما بيده، وغيرهم لا يستطيعون العمل إلا وسط جماعات أو في بيئة تفاعلية. ولعل تلك المشكلة لم تكن تظهر كثيرًا بين العاملين عن بعد قبل انتشار العمل عن بعد نفسه، ربما لأنه يكثر في الأوساط التقنية والبرمجية التي يفضل العاملون فيها بيئات العمل الهادئة، وقد وجدوا في العمل عن بعد بيئة مثالية للتفكير العميق في المهام التي بين أيديهم، فلما أن جاء الحظر إبان جائحة كورونا وفُرض العمل عن بعد على أكثر المؤسسات وجد بعض العاملين أنفسهم في بيئة غريبة عليهم، وصعُب عليهم التعامل معها في البداية وتسيير يومهم تسييرًا طبيعيًا في البداية. وتزيد حساسية العاملين عن بعد لمشاكل التواصل عن زملائهم من العاملين في المكتب، فقد يخشى الموظف من التجاهل إذا تُرك طلبه دون رد مدة يسيرة لم يكن ليلقي لها بالًا إذا كان يعمل من المكتب، فيسارع إلى محاولة التواصل مع نفس الجهة أو غيرها من خلال عدة وسائل تواصل، خاصة إذا كانت المسألة طارئة ولا تحتمل تأخيرًا. وعلى ذلك ينبغي التفكير في قواعد محددة للتواصل بين العاملين عن بعد وبقية الشركة من الموظفين والإدارة، ويكون ذلك أسهل إذا كان الفريق كله يعمل عن بعد، وقد ذكرنا ذلك في المقال السابق، في شأن تخصيص قنوات التواصل لتكون كل منها لغرض معين، وهذا النظام مفيد للمؤسسة إذ يقلل الوقت الضائع في دوران الموظفين في حلقات تواصل مفرغة لحل مشاكل كان يمكن حلها بسهولة أو تجنب تكرار حدوثها إذا استُخدمت أدوات مناسبة، خاصة قنوات التواصل النصية إذ تسهّل استخراج حلول المشاكل المكررة ووضعها في توثيق أو قاعدة بيانات يبحث فيها الموظف عند مواجهته لمشكلة ما. كذلك يجب وضع قواعد واضحة لتدريب الموظفين الجدد وتعريفهم بثقافة الشركة والموظفين العاملين بها، بداية من نطاق عمل الشركة وتاريخها إلى كيفية التواصل بين العاملين بعضهم بعضًا والألفاظ التي تُعد غير لائقة مثلًا، ويزيد أثر هذا في البيئات ذات الالتزام الديني أو العرفي مثل دولنا العربية أو الإسلامية، فرغم أن الشركات الأجنبية تسن قواعد للتعامل بين الموظفين لتجنب المشاكل الناتجة عن العنصرية أو الكلمات غير اللائقة، إلا أن قوانينها في المجمل أكثر تساهلًا من التي تصلح للعمل في بيئاتنا، وقد رأيت أثناء عملي في بعض الشركات الأجنبية تفريطًا وتساهلًا كثيرًا في شأن هذه القواعد أو في تطبيقها، أدى إلى عواقب وخيمة على من تساهل في شأنها وصلت إلى الفصل من العمل، مما يدعو إلى الوقاية الاستباقية لهذا بتوضيح تلك القواعد للعاملين الجدد توضيحًا بيّنًا، وتطبيقها بصرامة على من يخالفها. ذلك أني رأيت أكثر المتضررين من مخالفة تلك القوانين يكن من النساء في الغالب، إما لحياء المرأة عن طلب حقها أو لعجزها إثبات حالتها في حال التعرض لها، وقد سبق أن وضحنا كيف يتعامل المرء مع مثل تلك المضايقات في كتاب دليل المستقل والعامل عن بعد، غير أن هذا كان مع العملاء في المشاريع المستقلة، حيث يتحكم العامل المستقل في قوانينه بشكل كبير، أما هنا فيختلف الوضع إذ يدخل فيه عوامل أخرى مثل قوانين العمل في الشركة والدولة العاملة فيها أو التابعة لها، وسيأتي بيان مثل تلك القواعد في فصول تالية. الخصوصية وحماية أمن البيانات تمثل معالجة الانتهاكات الأمنية تحديًا خاصًا عندما ترتبط بموقع عمل بعيد، إذ يستطيع طرف ثالث -الأزواج مثلًا والأطفال والزائرين، والمارين أمام معدات العمل- أن يصل إلى أنظمة الحاسوب والوثائق الورقية واستخدام مزود خدمة الإنترنت الخارجي للوصول إلى بيانات الشركة أو العميل ونقلها، فيجب عليك التشاور مع فرق تقنية المعلومات الخاصة بك حول إمكانية ضمان تأمين مواقع العمل عن بُعد بجدران الحماية المناسبة وغيرها من التدابير الأمنية، مثل الشبكات الخاصة VPNs وأدوات مراقبة الحواسيب عن بعد إن كان الحاسوب يتبع الشركة، وهو الخيار الذي يجدر بالشركة اللجوء إليه في حالة مخاوف سرقة البيانات أو وقوعها في أيدي غير أمينة، وكذلك إعداد تدريبات ووسائل تعليمية تشرح كيفية تجنب الوقوع في تلك المشاكل الأمنية، وحظر تثبيت برامج من مصادر غير معروفة أو غير متفق عليها داخل الشركة على حواسيبها، وهكذا. وتختلف الشركات في أساليب تأمينها لتلك البيانات، خاصة مع زيادة عدد الموظفين فيها وصعوبة التحكم في سلوكياتهم، فتلجأ ابتداءً إلى إحكام سيطرتها على معدات العمل، فتوفر حواسيب خاصة بالعمل، وشبكات VPN خاصة بها، وتجهز الحواسيب بحيث تكون مراقبة من طرف الشركة، وبحيث يُمنع إمكانية التعديل على مكوناتها البرمجية أو عتادها إلا بموافقة الشركة ومن خلال الفرق المختصة بذلك. ويكون دافع هذا أحيانًا إما رغبة الشركة في الحفاظ على سرية البيانات الخاصة بها، أو بسبب القوانين المفروضة عليها من الدول العاملة فيها، فالدول الواقعة في الاتحاد الأوروبي مثلًا تفرض قوانين مشددة على التعامل مع بيانات العملاء، وعلى ذلك تتبع الشركات التي تتعامل مع تلك البيانات أساليب صارمة في هذا، فلا يُسمح بالدخول إلى مكاتب العمل إلا الأفراد المصرح لهم فقط، وبعد التأكد من عدم حمل أية أوراق وأقلام أو هواتف داخل مكتب العمل لمنع تسجيل بيانات العملاء على وسائل خارجية. وكذلك التحكم في حواسيب العمل وبرامجه نفسها، فلا يُسمح باستخدام برمجيات إلا التي تصرح بها الشركة وتعتمدها، ويُعطى العاملون عن بعد في تلك الشركات توجيهات أمنية في شأن ترك الحواسيب مفتوحة دون رقابة عليها، أو في شأن من يرى شاشة العمل الخاصة بالموظف، فيُنصح العاملون بجعل ظهورهم إلى حائط إن كانوا يعملون في مساحات مفتوحة أو مساحات عمل مشتركة، أو في مكاتب خاصة في منازلهم مثلًا. وفيما يلي بعض الأمثلة للاحتياطات الأمنية التي يجب النظر فيها عند الانتقال إلى بيئة عمل بعيدة، وإن كان يجب تطبيقها عند الحاجة إليها حتى في المقرات العادية للشركة. العتاد توفر كثير من الشركات العاملة عن بعد عتاد العمل للموظفين، إما بإرسال العتاد نفسه أو تغطية نفقات شرائه، أو على الأقل نفقات إصلاحه وتحديثه كل عام، فقد تعطي الشركة للموظف حاسوبًا للعمل عليه، وربما هواتف أو أجهزة لوحية أو غيرها من المعدات الإلكترونية إن كانت تعمل على تطوير برمجيات لتلك الأجهزة وتريد اختبارها مثلًا، وهنا قد تسمح الشركة للموظف باستخدام تلك الأجهزة لأغراضه الشخصية أو لا، ويختلف هذا بحسب كل شركة وبحسب طبيعة البيانات التي تتعامل معها الشركة كما ذكرنا من قبل. فمن ناحية أخرى، قد توفر الشركة عتاد العمل ولكن بشرط ألا يغير الموظف فيه قطعًا من تلقاء نفسه، أو لا يغير نظام التشغيل مثلًا، أو لا يثبت برمجيات غير برامج العمل أو البرامج المتفق عليها داخل الشركة، بل قد تمنعه الشركة من نسخ ملفات إلى خارج حاسوب العمل، أو إدخال ملفات إليه، وقد يكون للشركة مستودع آمن للبرامج التي تحتاج إليها أقسامها، يصل إليها الموظفون ويثبتوا البرامج التي يحتاجون إليها، أو قد تخصص الشركة فرقًا تقنية مختصة بتلك العملية تتولى تلك المهام كلها. وهنا قد تحدث مشكلة للشركات التي ترسل عتادها إلى الموظفين عن بعد، إذ قد يصل إلى الموظف قطعًا مكررة أو تالفة أو ناقصة، ثم يستغرق تصحيح ذلك الخطأ أيامًا أو حتى أسابيع، وتكاليف إضافية للشحن من أجل حل مشكلة بسيطة كهذه. ونحن نذكر هنا حل هذه المشكلة لأني رأيتها تحدث في شركة كبيرة تقنية يصعب أن يُتصور معها ذلك الخطأ التافه، وهو أن يُجهز خط تجميع صغير لإرسال ذلك العتاد -خاصة إن كان يتكون من أكثر من قطعة لكل موظف-، ويُعطى رمزًا أو رقم تعقب لكل قطعة مع اختبار كفاءة عملها، ويُسجل نجاح عملها من عدمه مع رمزها، ويوضع كل صنف من القطع في أرفف أو صناديق مرتبة ترتيبًا متتابعًا حول صف في المنتصف -ولو حتى على طاولة أو أكثر تُصف مع بعضها-، ثم تؤخذ القطع من صناديقها أو أرففها إلى طاولة التجميع، وتُسجل أكواد القطع المرسلة إلى الموظف في حزمة واحدة. فهكذا نتجنب إرسال لوحتي مفاتيح مثلًا إلى الموظف دون الفأرة، أو إرسال أسلاك ومقابس غير متوافقة، وهكذا، ويُفضل في هذا إرسال حواسيب محمولة أو التي تكون أجزاؤها مجتمعة في الشاشة All-In-One لتجنب هذه المشكلة من الأساس، مع اختبارها قطعًا. البرمجيات لعل هذه النقطة أسهل في بيانها بما أن الشركات معتادة عليها، فهي تدفع اشتراكات البرمجيات المطلوبة أو أثمانها للموظفين على أي حال، غير أننا نشير إلى جزء آخر هنا، وهو المتعلق بأمان البرمجيات. فإذا كانت الشركة تستخدم شبكات خاصة VPN، فيمكن أن تربطها بتطبيقات استيثاق ثنائي مثل تطبيق Authenticator من مايكروسوفت، بحيث لا يستطيع الموظف الدخول إلى الحاسوب أو إلى الشبكة الخاصة أو تطبيقات الشركة دون كتابة الرمز الظاهر على شاشة الحاسوب في التطبيق، وذلك لضمان التحقق من أن الموظف المصرّح له فقط هو الذي يستخدم عتاد العمل. كذلك قد تحتاج الشركة في الحالات التي يعمل فيها الموظف على بيانات حساسة أن تستخدم برمجيات لمراقبة حاسوب العمل، مثل SecureDesk و InterGuard و Hubstaff، التي تراقب عمل الموظف على الحاسوب وتسجل نقرات لوحة المفاتيح، ويكون في بعضها خاصية التقاط صورة من كاميرا الحاسوب في أوقات عشوائية للتأكد من عدم تواجد شخص غير مصرح له أمام الحاسوب، وهكذا. على أن هذه النقطة شائكة جدًا بالنسبة للموظفين، فإننا نرى المبرر الوحيد للجوء إليها هو التعامل مع بيانات حساسة لا يجوز لغير الموظف الاطلاع عليها، لما فيها من مراقبة زائدة قد تتجاوز كثيرًا المراقبة الحقيقية في المكتب، وأما في غير تلك الحالة، فإن الثقة أفضل في التعامل بين أفراد الشركة، وقد بيّن عالم الاقتصاد الأمريكي فرانسيس فوكوياما أثر الثقة في تحقيق الرخاء والرفاهية في كتاب "الثقة: الفضائل الاجتماعية وتحقيق الرخاء Trust: The Social Virtues and The Creation of Prosperity". وتستخدم الفرق العاملة عن بعد مزيجًا منظمًا من الحزم البرمجية في تواصلها أثناء العمل، وإدارتها للمشاريع التي تعمل عليها، ويختلف المقدار المطلوب للتشغيل من شركة لأخرى وفق احتياجات الشركة ومجال عملها، وعدد أفرادها كذلك، ولكنها تشترك جميعًا في حزم أساسية لا غنى عنها ولا غنى لصاحب الشركة عن معرفتها نسردها فيما يأتي. برامج إدارة المشاريع والمكاتب الافتراضية تتبع الشركات العاملة عن بعد نهجين أساسيين في البرامج التي تعتمدها لإدارة مشاريعها، ويختلف سلوك الشركة وفقًا للنهج الذي تتبعه. فالنوع الأول يحاول قدر الإمكان نقل المحتوى الحقيقي لمقر الشركة بسلوكياته ولوائحه إلى البيئة الافتراضية، ولا بأس بنقل الملفات والأرشيفات ومواد العمل وملفاته والمواد التدريبية من كتب ودورات إلى بيئة افتراضية يسهل الوصول إليها لمن له حق الوصول، بل هذا من ضروريات الانتقال إلى العمل عن بعد. لكنها تجمع إلى هذا نفس السلوك الإداري الذي كانت تتبعه في العمل من المكتب، فتظل الاجتماعات في نفس مواعيدها ولكن عبر تطبيقات الاجتماع الافتراضي عن بعد وكذلك مواعيد الحضور والانصراف والتحركات الدقيقة لكل موظف أثناء اليوم، والاستجابات الفورية لرسائل العمل. أما النوع الثاني من الشركات فيسلك نهجًا مختلفًا يوظف فيه خصائص العمل البعيد في معالجة بعض أوجه القصور في العمل المكتبي، ذلك أن بُعد العاملين عن بعضهم يؤثر تأثيرًا مباشرًا على العلاقة بينهم كأشخاص، وعلى أداء العمل نفسه إن لم تحكمه قواعد سليمة، غير أنه من ناحية أخرى أتى بفائدة عظيمة يعاني منها الموظفون في المكاتب، وهي الحاجة إلى التركيز التام دون ملهيات أو مشتتات، وهذا يندر حدوثه لأغلب الموظفين إلا من له مكتب خاص به داخل الشركة، وحتى هذا لا يسلم من طارق يطرق عليه أو اتصال يأتيه. فيلجأ بعض الموظفين إلى البقاء بعد مواعيد العمل ليلًا أو الذهاب إلى مقر الشركة مبكرًا عند الحاجة إلى إنجاز مهام كبيرة أو مشاريع مهمة، وأكاد أجزم أن كل من عمل في شركة من مقرها قد لجأ إلى هذا بغض النظر عن مجال عمله، وقد فعلت هذا بنفسي كثيرًا لتأثري بالمشتتات من حولي ثم المعاناة لاستجماع انتباهي وتركيزي على ما كنت أعمل عليه. أما في حالة العمل عن بعد، فإن الموظف يستطيع الخلوة بنفسه وإنهاء المهام التي بين يديه دون إزعاج من أحد، فلا أحد يدخل عليه في بيته إلا بإذنه، ويستطيع إخبارهم أنه لا يريد مداخلات في وقت كذا وكذا، ويكون أفضل من هذا إذا كان يتخذ مكانًا مستقلًا له يعمل منه كغرفة مستقلة في البيت أو مكتبًا خاصًا به، ففي تلك الحالات لا يضطر إلى القدوم مبكرًا أو المكث ليلًا إذا أراد وقتًا يركز فيه على العمل. وقد عالجت الشركات التي اتبعت النهج الثاني هذه المشكلة باستغلال خصائص العمل البعيد، فقللت من وقت الاجتماعات وجعلتها للضرورة فقط، وتبنت التواصل غير المتزامن Asynchronous -والذي سنشرحه بتفصيل لاحقًا في الكتاب إن شاء الله- مع الحفاظ على ساعات عمل متراكبة بين العاملين في الفريق الواحد على الأقل، وبين العاملين في الشركة إن تيسر، بحيث تسمح تلك الساعات المتراكبة أن يتلاقى الزملاء ويجتمعون ويتناقشون في العمل والمهام التي بينهم، وكذلك تسمح بالنقاش خارج نطاق العمل إن أرادوا، فهي لا تؤثر على سير العمل بحيث يشعر العاملون أنهم يعملون وحدهم في عزلة، مع ضمان إنجاز المهام على أكفأ وجه ممكن بسبب فرصة العمل الهادئة التي يحظى بها كل موظف. أما الأمثلة على برامج إدارة المشاريع تلك والمكاتب الافتراضية فهي ما يلي: تطبيق "أنا" من شركة حسوب. سلاك Slack تطبيق Basecamp من شركة 37Signals أسانا Asana تريلو Trello وغيرها من البرامج واﻷدوات التي تُستخدم وحدها أو تُستخدم بعضها معًا بحيث يكون لكل منها وظيفة محددة أو أكثر. برامج التواصل المرئي والاجتماعات يفضَّل نقل كل ما لا يمكن شرحه في أقل من ثلاثة أسطر إلى اجتماع صوتي أو مرئي بحسب الحاجة، على أن الاجتماعات الصوتية تكون أفضل في حالات العصف الذهني لأن أعضاء الاجتماع يركزون على الأفكار المطروحة فقط دون إضافة عوامل أخرى مثل التواصل البصري ولغة الجسد وغيرها، وفيما يلي أمثلة على برامج التواصل والاجتماعات التي تستخدمها أغلب الشركات الآن: برنامج زوم Zoom Microsoft Teams Google Meets وتُستخدم البرامج أعلاه في الغالب في حالة الشركات التي تتعاقد مع الشركة المقدمة للتطبيق، من أجل الحصول على المزايا الإضافية التي تحصل عليها الشركات، مثل السبورة البيضاء للشرح ومساحات التخزين الكبيرة والأعداد الكبيرة لأعضاء الاجتماع. لكن مما رأيناه فإن كثيرًا من الشركات التي لا يتجاوز عدد موظفيها خمسين إلى مئة موظف تكتفي بوسائل اتصال أخف مثل تليجرام أو واتس اب مثلًا، وقد تحدثت إلى العديد من العاملين عن بعد في شركات -أغلبها برمجية- وأخبروني أنهم يستخدمون تليجرام للتواصل في رسائل العمل، وكذلك لاجتماعاتهم الصوتية أيضًا. فالأمر فيه مرونة وفق احتياج الشركة وتعود موظفيها على ما يحقق لهم النتائج المطلوبة من التواصل، فالشركات الكبيرة التي توقع عقودًا لاستخدام زوم أو تيمز Teams تريد بعض المزايا الإضافية من وراء ذلك كما ذكرنا، والتي قد لا تحتاج إليها الشركات الأصغر أو لا تهتم لها. خدمات التخزين والحوسبة السحابية تقدم شركات مثل أمازون ومايكروسوفت خدمات حوسبة سحابية للشركات والمؤسسات، خاصة الصغيرة منها، لتحمل عنها مهام إدارة الخوادم وقواعد البيانات والوصول لعملاء في دول بعيدة ومساحات التخزين وخدمات التحليل ونشر التطبيقات وأدوات التطوير والإدارة وغيرها، وهي خدمتي AWS و Microsoft Azure على التوالي. وقد سهلت تلك الخدمات على الشركات أن تعمل عن بعد بأريحية لأنها لم تعد مضطرة إلى إنشاء مقرات مركزية تجمع العاملين وقواعد البيانات معًا، إضافة إلى تجهيزات الأمان والحماية الخاصة بملفات الشركة وأرشيفاتها وبياناتها، حيث كان من الصعب قبل تلك الخدمات أن يستطيع العامل الوصول إلى ملفات كبيرة الحجم أو حساسة إلا بالذهاب شخصيًا إلى مقر العمل وتقديم ما يثبت أهليته للاطلاع على تلك المواد، وكذلك لم يكن ممكنًا أن يعمل فريق على مشروع كبير الحجم -وإن كان تقنيًا- إلا بالتواجد في مقر الشركة لأن ملفات المشروع والحواسيب اللازمة للتعامل معه تكون غالية الثمن في العادة ولا يمكن الوصول إليها إلا محليًا. أما بعد أن نقلت الشركات خدماتها وملفاتها إلى خدمات الحوسبة السحابية تلك، يستطيع العاملون أن يصلوا إلى ملفات المشروع الذي يعملون عليه، ويديروا المهام التي يجب تنفيذها في كل مرحلة منه، ويعدلوا على أجزائه ويعتمدوا تلك التعديلات، كل ذلك وأكثر منه عن بعد! صلاحيات الوصول تخصص الشركة حواسيب للعاملين فيها، أو تشترط عليهم تخصيص حواسيب خاصة بهم، أو حتى ترسل إليهم أصابع عليها نظم تشغيل تُدخلهم إلى خوادم عليها أنظمة وهمية Virtual Machines للعمل عليها في بيئة الشركة الآمنة، أو غير ذلك من الأساليب التي تضمن الشركة بها أمان نظام التشغيل كما ذكرنا في النقطة السابقة. ثم يأتي بعدها عناوين البريد وعناوين IP التي يجب أن يستخدمها العاملون في الشركة، فتخصص الشركة نطاقات domains خاصة بها موسومة باسم الشركة مثل name@company.com غير خدمات البريد المعتادة التي تكون فيها أسماء تلك الشركات مثل name@gmail.com، ولا تُستخدم في المراسلات الشخصية أو المراسلات إلى جهات اتصال خارج العمل. ويُحدد صلاحيات وصول للعاملين على حواسيب العمل أو ملفات الشركة، فلا يُعطى أحد الموظفين صلاحية لا يحتاج إليها بداعي الثقة، فإن كان الموظف نفسه لا غبار عليه، إلا أنه معرض للاختراق أو الإهمال أو غيرها من العوارض التي تضع البيانات التي يصل إليها في خطر، لذا يجب تضييق أمر صلاحيات الوصول إلى حدود آمنة، فيُطبَّق هنا مبدأ "المعرفة على قدر الحاجة"، مع استبدال صلاحية الوصول بالمعرفة. وماذا عن مستندات الشركة الداخلية أو التي ينشئها الموظفون؟ توجد خيارات تخصص مستوى الأمان الخاص بالمستند داخل طقم برامج المكتب، كما في قائمة Protect في برنامج MS Word، التي تحدد صلاحيات الوصول للمستند، إضافة إلى مستويات الأمان التي تحددها لشركتك، والتي ينبغي أن يستخدمها الموظفون في كل مستند ينشئونه، مع وضع ذلك كخيار افتراضي داخل البرامج المستخدمة الوعي الرقمي قد لا يكون مجال الشركة تقنيًا بالضرورة بحيث يكون أفرادها على علم بالهجمات الرقمية والاختراقات الأمنية واستخدام الهندسة الاجتماعية فيها، بل ثَم كثير من العاملين في التقنية ينقصهم وعي كافي في هذه الأمور، فيفضَّل هنا تنظيم توعيات دورية للعاملين في الشركة بالمخاطر الرقمية وحدود العالم الافتراضي وما يجب اتباعه فيه، واستخدام المواد المناسبة للتوعية سواء كانت مرئية أو غيرها. وقد أصدرت حسوب كتاب دليل الأمان الرقمي في 2021، وهو موجه إلى عموم من يستخدم الحواسيب والأجهزة الذكية، ويهدف إلى توعيتهم بالمسائل المتعلقة بالأمن الرقمي، إضافة إلى مواد متقدمة مفيدة حتى للمتخصصين في المجال، ومن الجيد ترشيح مثل هذه المواد للموظفين لقراءتها ضمن برامج التطوير والتدريب. الشروط القانونية للعمل عن بعد وضعت الكثير من الدول تشريعات جديدة خاصة بالعمل عن بعد والعمل عبر الدول Multi-State Remote Work لحماية مواطنيها العاملين في شركات أجنبية أو حتى العاملين في شركات محلية لكنها تعمل عن بعد، ويجب قراءة تلك التشريعات بعناية شديدة للدولة التي توظف منها لتوافق العقود مع الموظفين تلك القوانين واللوائح، ويمكن الاطلاع على نسخة شبه كاملة منها في تقرير التشريعات الجديدة للعمل عن بعد من وكالة Lockton، أو من جمعية إدارة الموارد البشرية في الولايات المتحدة SHRM. تدور تشريعات الدول في العمل عن بعد حول حق الموظفين عن بعد في بدلات لصيانة المعدات التقنية ونفقات الاتصال بالإنترنت، والحد الأدنى للأجور، والاشتراكات الشهرية التي يحصل عليها زملاؤهم من العاملين في مقرات الشركة، وكيفية التصرف في حالة فصل الموظفين أو توقيع الجزاءات عليهم إن كانوا يخضعون لدول مختلفة، وقد لا تختلف تلك التشريعات كثيرًا في حالة الشركات التي تعمل عبر عدة دول منذ بدايتها، لكنها ستكون دليلًا خصبًا للشركات القادمة إلى نمط العمل عن بعد حديثًا ولم تعتده من قبل. فمثلًا، تدفع الغالبية العظمى من العاملين عن بُعد مقابل اتصالها بالإنترنت، ويدفع معظم أصحاب العمل مقابل البرامج والأدوات السحابية المستخدمة، ولكن في حالة تزويد الشركة للعاملين بمعدات العمل، إما لطبيعة عمل الشركة أو امتثالًا لقوانين العمل عن بعد في دولة الموظف أو لغيرها من الأسباب، فيجب تفصيل بنود الميزانية المخصصة للفرق البعيدة. وذلك قد لا يكون فيه اختلاف كبير عن البنود المخصصة للفرق العاملة من المكتب في شأن معدات العمل، فستدفع الشركة لا محالة تكاليف تلك المعدات إن كانت ستوفرها، أو على الأقل تدفع بدلًا لصيانة وتحديث المعدات إن كان الموظف يستخدم أجهزته الخاصة، إضافة إلى قيمة الاتصال بالإنترنت. وكذلك في شأن بعض البنود المادية الأخرى مثل اشتراكات الدورات التعليمية أو صالات الرياضة أو مساحات العمل وغيرها، فالموظف البعيد يشترك في هذا مع زميله العامل من المكتب، باستثناء قيمة مساحات ركن السيارات مثلًا، بل يفضُل التوظيف عن بعد هنا في أنه يوفر بعض التكاليف التي تُدفع للموظفين من المكتب، عدا بعض التكاليف الهامشية مثل إرسال الهدايا إلى الموظفين عن بعد عند إعطاء مثيلها للموظفين في المكتب، فستزيد هنا تكلفة الشحن فقط إلى الموظفين عن بعد. خاتمة تعرفنا في هذا المقال على كيفية التأسيس لبيئة عمل عن بعد، والأخطاء الشائعة التي يقع فيها الموظفون والمدراء أثناء العمل البعيد، والبنود التي يجب مراعاتها في لوائح العمل الجديدة والاختلافات التي تكون في بيئة العمل البعيدة عن التقليدية، وننظر في المقال القادم في كيفية التوظيف عن بعد وحالاته وأنواعه المختلفة، وما يتعلق به من إجراءات. واعلم أن الأدوات التي ذكرناها في هذا المقال وبقية السلسلة ما هي إلا أمثلة لتلك الخدمات، وليست حصرًا لها، فللشركة أن تنظر في الأداة التي تناسبها، فقد تكون تعاقدت مع شركة تقدم لها الخدمات التي تستخدمها، فتضيف فقط ما ذكرنا ها هنا إن كانت تلك الشركة تقدمها، وهكذا فلا تقيد الشركة نفسها بالأمثلة المذكورة. كتبت فاطمة أحمد المسودة الأولية لهذا المقال. اقرأ أيضًا المقال السابق: مدخل إلى العمل عن بعد دليل مدير المنتجات لاختيار مقاييس أداء صحيحة أفضل أدوات التواصل للعمل عن بعد العمل عن بعد عندما يكون الجميع ضمن مناطق زمنية مختلفة التواصل غير المتزامن: السر وراء نجاح الفرق العاملة عن بعد لقاءات فريق العمل البعيد: إليك بعض التجارب
  13. كثر العاملون عن بعد في اﻷعوام الأخيرة إما عملًا حرًا أو نظاميًا، وقفز هذا النمط قفزات كبيرة وتغير كذلك عدة مرات في تلك الأعوام، وربما نشهد استقرارًا نسبيًا لتقلباته على المدى القريب، وإن كانت الطبعة الأولى من هذه السلسلة التوظيف عن بعد، تبشر به وتدعو الناس إليه وإلى مزايا التعامل مع الموظفين عن بعد، فقد كان لزامًا علينا تحديث السلسلة والتوسع فيها وعرض المشاكل التي تواجه الذين يوظِّفون عن بعد، فقد طرأت مشاكل جديدة لم تكن موجودة من قبل استحداث هذا النمط من العمل، وسنذكر بعض الحلول لتلك المشاكل مما رأيناه في السوق أو جربناه بأنفسنا. وكانت الوظائف التي تسمح بالعمل عن بعد في الغالب في المجال التقني أو المجالات التي تعتمد على التقنية في مهامها اليومية، حيث يكون المنتج مادة تُنشأ وتعالَج وتُخرَج على الحواسيب، إما برمجيات أو تصاميم أو نصوص أو مرئيات أو مواد مالية أو غيرها، على عكس المجالات التي تكون المنتجات فيها حقيقية مثل المصانع والمتاجر التي لا بد من تواجد حقيقي للموظفين في محل الإنتاج أو البيع. ولم يتمتع برفاهية العمل عن بعد إلا قلة ممن اضطروا إليه أو كانت شركاتهم تسمح بهذا، إلا أن التطورات التي حدثت في الأعوام الأخيرة -خاصة وباء كوفيد- أجبرت المؤسسات قاطبة على تبني هذا النمط من العمل، وتبع ذلك تغيير للبنية التحتية التقنية، وتدريب الموظفين الحاليين أو الجدد على أداء المهام عن بعد والتنسيق بين العاملين وبعضهم، وكذلك تغير في لوائح العمل التنظيمية بين الموظفين والشركات. وفي هذا نشر كل من جوناثان دِنجل Johnathan Dingel وبرِنت نيمَن Brint Neiman من جامعة شيكاغو دراسة حول مجالات العمل التي يمكن إتمامها عن بعد، خلصت إلى أن 37% من الوظائف التي في الولايات المتحدة الأمريكية يمكن تنفيذها عن بعد، وأن الوظائف التي يمكن إتمامها عن بعد يحصل أصحابها على أجور أعلى في الغالب من نظرائهم، مع الاستثناءات التي تدخل في حساب الأجور لبعض الشركات، مثل محل إقامة الموظف وسياسة الشركة في العمل عن بعد، فقد يحصل بعض الموظفين عن بعد على رواتب أقل من زملائهم إذا كانوا يعملون من مدن أرخص في تكاليف المعيشة، أو يحصلون على مكافآت إضافية إذا كانت الشركة تريد من موظفيها أن يعملوا عن بعد. وقد تصدرت في تلك الدراسة وظائف مجالات الحوسبة والتعليم والتدريب قائمة الوظائف التي يمكن إتمامها عن بعد، تليها الوظائف القانونية والإدارية ووظائف التصميم والهندسة المعمارية، في حين أتت الوظائف التي لا بد لها من حضور في أسفل القائمة، مثل الوظائف التي في مجال تجهيز الطعام وتقديمه، والبناء والتنظيف والصيانة، وكذلك الوظائف الإنتاجية والزراعية والصيد وغيرها. وتلجأ الشركات الآن إلى التوظيف عن بعد بطرق مختلفة، غير أن الأسباب تكاد تكون نفسها في كل حالة، وهي أن التوظيف عن بعد يوفر كفاءات غير موجودة محليًا، ويوفر على الشركة بعض نفقات التوظيف المحلي، فقد رأت الشركات تلك النتائج في الأعوام الماضية بعد فرض نمط العمل عن بعد طوعًا أو كرهًا على أغلب المؤسسات الخاصة والحكومية، وربما يحسن بنا شرح بعض المصطلحات التي سيرد ذكرها في هذه السلسلة قبل أن نشرع في مادته. العمل عن بعد واختلافه عن أنواع العمل الأخرى يحدث أحيانًا خلط بين العمل عن بعد والعمل المستقل أو الحر، فصحيح أن كلاهما يعمل بعيدًا عن مقر العمل أو الشركة، ولكن هنالك فرق كبير في تبعية العامل لصاحب العمل أو الشركة التي يعمل معها أي تحديدًا في عقد العمل، ومن ذلك تنبثق مفاهيم أخرى تأخذ تسميات تبعًا لعقد العمل ولكن كلها تصب كما ذكرنا في مفهوم العمل بعيدًا عن مقر الشركة أو صاحب العمل، ولن نتطرق بالطبع إلى مفهوم العمل التقليدي الذي يحضر فيه العامل إلى مقر العمل فهو خارج نطاق هذه السلسلة. العمل البعيد أو العمل عن بعد نقول أن وظيفة ما تدخل تحت مظلة العمل عن بعد إذا كان الموظف يعمل من موقع غير تابع للشركة، فهو بعيد عنها أثناء وقت العمل وبعده، فيعمل من بيته أو من مساحة عمل مشتركة أو أي مكان آخر، وهو يتبع الشركة إداريًا وتنطبق عليه لوائحها التنظيمية، وتكون الشركة مسؤولة عنه أمام قانون العمل في الدولة التابعة لها الشركة -تدخل فيها غالبًا التأمينات والضرائب- وفق الشروط المتفق عليها بينها وبينه، فهو جزء من الشركة غير أنه لا يعمل في مكتبها المعتاد ولا يذهب إليها في أيام العمل. أود التنبيه على أمر، وهو أنه عندما نذكر العامل عن بعد فإننا نشير إلى المفهوم السابق تمامًا، ولكن قد يُطلق مجازًا على عامل مستقل على أنه عامل عن بعد إشارةً إلى أنه يعمل بعيدًا من منزله مثلًا. العمل الحر أو المستقل يختلف نظام العمل الحر أو المستقل على الإنترنت عن العمل النظامي عن بعد في أن العامل به لا يكون تابعًا للشركة أو العميل الذي ينفذ له العمل، بل يتعاقد مع الشركة في كل مشروع ينفذه لها، وهذا يعطيه حرية التعاقد مع غيرها في نفس الوقت، وهو الأمر الذي قد لا يكون مسموحًا به في العمل النظامي، وإن سمحت به الشركة فيجب أن يكون في غير أوقات العمل التي تخصصها. وهذا اختلاف آخر للعمل الحر، فالعامل المستقل أو الحر يعمل في الأوقات التي يختارها وتناسبه، وفي الأيام التي يختارها كذلك، ولا نعني بهذا أنه لا يعمل بنظام لنفسه، وإنما نقصد أنه لا يتقيد بمواعيد عمل العملاء والشركات التي يتعاقد معها. كذلك فإنه يعمل لحسابه الخاص، وهذا يعني أنه مسؤول عن تأميناته الاجتماعية والصحية وضرائبه وغيرها أمام الدولة التي يعمل منها إن كان لديها تشريعات للعمل الحر، وهنا قد يعهد بتلك الأمور إلى متخصصين ينظمونها له أو قد يقوم بها بنفسه إن كان يستطيع أو كان لديه وقت. يختلف هذا في حالة العمل البعيد المنتظم في أن الشركة تتولى تلك المسؤوليات عن الموظف، لكن هذا يعني أنه يخضع للوائحها التنظيمية أيضًا فيما يخص المكافآت والجزاءات وغيرها. التوظيف النظامي والتعاقد الحر تعرضنا في النقطتين السابقتين لنموذجين من العمل، هما التعاقد المنتظم، وذلك في حالة العمل البعيد، والتعاقد الحر في حالة العمل المستقل، وعرفنا أن التعاقد المنتظم هو نفسه التعاقد مع الموظف على العمل للشركة، ولكن دون الحاجة إلى الذهاب إلى مقر الشركة، فلا يختلف عن العمل المعتاد إلا في مكان العمل ليس إلا. وتظهر الحاجة للتفريق بين النظامين لأن كليهما عمل عن بعد، غير أن المتعاقد الحر أو المستقل يعمل لحسابه، ولا يتبع الشركات التي يتعاقد معها إداريًا، وقد يمثل نفسه أو يمثل شركة يملكها أو فريق عمل ينفذون جميعًا المهام المتفق عليها مع الشركة أو العميل. التعهيد الخارجي تلجأ الشركات إلى التعهيد الخارجي لبعض المهام التي لا تريد إدراجها ضمن نشاطاتها لسبب أو لآخر، فقد تكون خارجة عن تخصص الشركة أو لا تحتاج إليها بالقدر الذي يتطلب معها توظيف عمالة دائمة، أو تعهد الشركة بعملية توظيف العمالة في بعض الوظائف إلى شركات توظيف خارجية إلى حين مدة معينة أو إلى حين تحقيق نتائج معينة، ينتقل بعدها الموظفون -إداريًا- من شركة التوظيف إلى الشركة الأساسية. كذلك يلجأ بعض المستقلين إلى تعهيد بعض مهامهم إلى مستقلين آخرين أو شركات أخرى توفيرًا للوقت ولضمان جودة التنفيذ إذا كانت المهام تخرج عن تخصصهم، لكن هذا يكون في حالة المستقل الذي له عملاء كثر بحيث لا يستطيع متابعة المهام الإدارية بنفسه، فقد يعهد حينئذ بمهام المحاسبة والضرائب إلى شركة محاسبية، ويوظف مساعدًا افتراضيًا لتنظيم مهامه الإدارية، وهكذا، وإن كان يعمل على مشاريع كبيرة فقد يوظف بعض المستقلين ليحملوا عنه بعض المهام، مثل الترجمة الأولية أو المراجعة اللغوية أو تصميم تطبيقات الويب أو برمجة الواجهات الخلفية، أو اختبار التطبيقات، وغيرها مما يخرج عن صلب تخصصه. وتعاقد الشركة مع شركة التوظيف هو تعهيد خارجي، وتعاقدها مع مستقلين هو تعهيد خارجي كذلك، فكل تعاقد حر لا تنطبق عليه اللوائح التنظيمية للعميل يُعد تعهيدًا خارجيًا، وإن كان المصطلح يُستخدم في المهام التي يُعهد بها بانتظام كالأمثلة التي ذكرناها. فوائد العمل عن بعد للشركات تبرز عند الحديث عن فوائد العمل الحر فائدتان عظيمتان تكادان تتفردان بأغلب الحديث، وهما توظيف الخبرات وترشيد التكاليف، إضافة إلى فوائد أخرى نتناولها تباعًا. الوصول إلى أفضل الكوادر يعني اعتماد الشركة للعمل عن بعد أنها لم تعد مقيدة بالكفاءات المحلية، ولا مضطرة لافتتاح فرع في المدينة التي توجد فيها الكفاءات المطلوبة فضلًا عن تأسيس الشركة في تلك المدينة، وهو ما كان يمثل عقبة في طريق الكثير من الشركات ويضطرها للانتقال إلى العاصمة أو إلى دولة أخرى حتى من التي توجد فيها تلك الكفاءات والكوادر. وهذا الاتصال الجديد يقرب بين رؤوس الأموال والشركات وأصحاب الأفكار بالكوادر المهنية والتي قد لا تجد مجالًا للعمل بتخصصها في محيطها المحلي، تقاربًا عظيمًا يحقق فوائد لأي طرف تمسه هذه العملية، فهي توفر بيئة خصبة لرؤوس الأموال والشركات أن تزدهر وبسرعة، مع استخدام أفضل الكوادر المتاحة للعمل بغض النظر عن الموقع الجغرافي لتلك الكوادر، وهذا بدوره يحل مشكلة البطالة من جهة، ومشكلة المدن الطاردة للسكان أو تكدس السكان في المدن الصناعية والعواصم المالية، فلا يضطر العاملون لترك أهليهم للعمل في تلك المدن، أو حتى الهجرة بهم إلى تلك المدن، بما أنهم صاروا يعملون عن بعد. ويؤدي اجتماع تلك الكوادر متعددة الخلفيات العلمية والثقافية إلى تطور سريع للمؤسسة أو الشركة لم تكن لتشهده لو كان العاملون من مدينة واحدة، وهذا معلوم بالمشاهدة في الحضارات التي ازدهرت من قبل، أيام الخلافة العباسية، وفي الأندلس، وفي العصر الحديث في الشركات الكبرى التي توظف من جنسيات متعددة مثل جوجل وإنتل وفيس بوك وغيرها. وقد كان لشركة حسوب باع سابق في هذا إذ اعتمدت العمل عن بعد منذ بدئها، واستفادت منه في جمع كوادر نابغة عربية من شتى بلدان الوطن العربي، فاجتمع من في المغرب مع من في العراق وسوريا ليعملوا معًا دون عوائق جغرافية أو سياسية، أو حتى زمنية. ترشيد التكاليف كذلك يحقق العمل عن بعد فائدة أخرى لأصحاب الشركات، وهي ترشيد النفقات وتقليل مصارفها، مما يسمح بإعادة توجيهها مرة أخرى في صورة استثمارات أو تطوير للشركة نفسها، ولكن كيف هذا؟ تحتاج الشركة في حالة التوظيف المحلي إلى الانتقال إلى العواصم المالية أو المراكز الصناعية ابتداءً، وهذا وحده يعني زيادة في تكاليف التشغيل، ثم توظيف الكفاءات الموجودة محليًا، والتي ستنفق نصيبًا لا بأس به من الراتب في الانتقالات وتكاليف المعيشة الغالية في تلك المدن الكبيرة، مما يضطر الشركة إلى رفع متوسط الرواتب لتعادل غلاء المعيشة، وهذا يزيد مرة أخرى من تكاليف التشغيل للشركة. أما عند اعتماد نفس الشركة للعمل عن بعد، فلا تحتاج إلى الانتقال لتلك المراكز المالية في الغالب، وإن احتاجت لأسباب قانونية أو إدارية فإنها ستكون على الأقل انتهجت سبيلًا أقل كلفة من التوظيف المحلي، ذلك أنها ستوظف كفاءات عن بعد، مما يعني أن العاملين يكونون في الغالب من مدن تكلفة المعيشة فيها أقل من تلك المراكز الصناعية والمدن الكبيرة، وهو ما تفعله بعض الشركات التقنية الكبرى الآن من حث لموظفيها على الانتقال إلى مدن أقل تكلفة في المعيشة. وهنا تنقسم الشركات في سياساتها المالية بين من يعتمد على متوسط الراتب للمدينة أو الدولة التي فيها الموظف، وبين من يرفض تلك السياسة جزئيًا، مثل شركة ريديت Reddit التي ألغت سياسة الدفع الجغرافي في 2020 للموظفين الأمريكيين فيها، واعتمدت بدلًا من هذا على نطاقات للرواتب للمدن عالية التكلفة مثل نيويورك وسان فرانسيسكو، وتبعتها في هذا كل من شركتي زيلّو Zillow وأُكتا Okta في العامين التاليين. وكذلك تبعتهم شركة بافر Buffer بنهج مشابه، إذ حددت نطاقين للرواتب فيها، هما النطاق العالمي، والنطاق الخاص بالمدن عالية التكلفة، إذ تقول جيني تيري Jenny Terry مديرة العمليات فيها أن الشركة تريد نقل جميع الموظفين إلى النطاق العالي، لكن هذا قد يكلف الشركة نحو مليون دولار، لذا تنتهج أسلوبًا مرحليًا للوصول إلى هذه النقطة، ويقول مدير الشركة أنه يهدف بالنهاية إلى تقديم نفس الراتب للوظيفة الواحدة بغض النظر عن موقع العامل فيها، غير أن هذا سيكلف الشركة أموالًا كثيرة، لذا يؤجل هذا القرار إلى حين توفر القدرة المادية على ذلك. ثم إن الشركات وفرت أموالًا طائلة كانت تدفعها في نفقات المكاتب الخاصة بالموظفين وتشغيلها، وإن كانت لا تزال تدفع تكاليف برامج الاجتماعات والعمل المشترك عن بعد، وقد استغلت بعض الشركات نمط العمل عن بعد في تخصيص مقراتها لتدريب الموظفين الجدد تحت إشراف من موظفين أقدم منه وأكثر خبرة، ثم ينتقلون بعدها إلى العمل عن بعد كليًا أو جزئيًا وفق سياسة الشركة، وهكذا وفرت الشركات على نفسها تكلفة زيادة سعة المقرات الحالية لها، ولم تخسر تلك المقرات بتركها فارغة عند عمل الموظفين عن بعد. فوائد العمل عن بعد للموظفين تنقسم الفوائد التي يجنيها الموظفون عند العمل عن بعد إلى قسمين رئيسيين أحدهما اجتماعي والآخر مادي، مع بعض الفوائد الأخرى التي قد لا تندرج بالضرورة تحت أي منهما. الفوائد المادية تظهر الفائدة المادية بداهة في توفير نفقات الانتقال من العمل وإليه إن كان الموظف في نفس المدينة، وتكلفة السكن في المدينة التي فيها الشركة إن كانت في مدينة مختلفة فضلًا أن تكون في دولة مختلفة، كما تظهر في جانب آخر كان موجودًا من قبل ثم برز بعد ازدهار العمل عن بعد مؤخرًا. ذلك أن بعض الدول والشركات تقدم مكافآت للعاملين الذين ينتقلون إلى مدن بعينها شهرية أو سنوية، أو تُدفع مرة واحدة عند الانتقال إليها، وذلك كانت تفعله مصر في بعض المدن الساحلية النائية لتشجيع الانتقال إليها، فيزيد راتب العامل فيها إلى قرابة الضعف، وكذلك تفعل بعض الولايات في أمريكا إما لقلة عدد سكانها أو لأسباب أخرى، مثل ولاية ألاسكا. ثم برز هذا الأمر في السنوات الأخيرة لتقدم بعض تلك الولايات تسهيلات أخرى خاصة بالعمل الحر والعمل عن بعد، سواء للمقيمين في الولايات المتحدة أو الراغبين في الانتقال إليها، فيما صار يُعرف بمدن زووم Zoom Towns إشارة إلى برنامج الاجتماعات المرئي الذي يُستخدم بكثرة في العمل عن بعد، وأُطلقت مبادرات قبل عدة أعوام -كمبادرة تولسا ريموت Tulsa Remote في 2018 لمدينة تولسا الأمريكية- لتدشين حركة الانتقالات تلك رسميًا، كما توفر بعض الولايات مثل مينيسوتا تسهيلات أخرى غير الحوافز المادية، مثل مساحات العمل المشتركة المجانية. وكذا في بعض الدول الأخرى مثل إسبانيا وتشيلي وسويسرا وإيطاليا واليونان وكرواتيا وغيرها، والجامع فيما يظهر من تلك المدن والدول أنها جميعًا تسعى لجذب مجموعة متنوعة من الكوادر العاملة إليها لتنويع مجتمعاتها، خاصة النائية قليلة السكان منها والتي ليس فيها محفزات للانتقال إليها والاستقرار بها كأن تكون بها موانئ أو مصانع أو مساحات زراعية أو غير ذلك. الفوائد الاجتماعية أما الفائدة الأخرى، وهي الفائدة الاجتماعية، فتظهر في قرب العاملين من ذويهم والقدرة على صلة أرحامهم في الأوقات التي كانت تضيع في الانتقالات أو الإجازات الأسبوعية التي كانت في مدن غريبة عليهم ليس فيها أحد من عوائلهم. كذلك يستطيع العاملون تنفيذ بعض المهام المنزلية التي لم يكونوا يجدوا لها وقتًا في العادة، أو كانوا يضطرون لاقتطاع إجازة من العمل من أجلها، مثل إيصال الأولاد إلى المدارس أو زيارة الطبيب، وتزيد أهمية هذه الأمور في حالة المرأة العاملة، خاصة التي لها أولاد، فليست مضطرة إلى السفر والاغتراب في هذا النمط، كما تستطيع العناية بأولادها مع تنفيذ مهام العمل دون تعارض بينهما. كما يوفر نمط العمل البعيد فرصة لمن يريد قضاء بعض الوقت في مدن أو قرى هادئة لكنه لا يستطيع بسبب انشغاله بعمله، حيث يستطيع العامل عن بعد أن يحمل معه مكتبه حيث شاء بما أنه لا يحتاج إلا إلى حاسوب محمول في الغالب، ويعمل من تلك المدن دون الحاجة إلى اقتطاع إجازة مخصصة لهذا الغرض. عوامل ازدهار العمل عن بعد سار العمل عن بعد بوتيرة بطيئة منذ نشأته، ولم تكن المؤسسات مقتنعة بجدواه ولا تملك رفاهية تجربته في الغالب أو ليست مضطرة إلى تجربته فالإنسان عدو ما يجهل، وبدأ بالصورة التي نعرفها الآن منذ سبعينيات القرن الماضي في شكل تجربة داخل شركة IBM لخمسة موظفين زاد عددهم بعدها إلى ألفين، ثم بدأت بعض الشركات الناشئة في التسعينيات بتبنيه رويدًا بسبب قلة الموارد المتاحة لها في نشأتها، ثم أتت الألفية الجديدة. العوامل التقنية مع دخول هذه الألفية أتى التطور المتسارع في البنى التحتية للسوق البرمجي، بداية من تقنيات الاتصال الإلكتروني والإنترنت فائق السرعة، إلى البرمجيات التشاركية collaborative software وبرامج الاتصال المرئي والصوتي والحوسبة السحابية، ومرورًا بالقفزات الكبيرة التي حدثت في تصنيع الرقاقات الإلكترونية والمعالجات الدقيقة للحواسيب، وقد اجتمعت تلك العوامل كلها في خدمة الشركات التقنية الراغبة في تطوير أعمالها. ثم أتت طبقة الشركات التي تخدم تلك الأولى بتوفير برمجيات تسهل أعمالها، وهي شركات البرمجيات الخدمية Software as a Service أو SaaS‎ التي وجدت في نمط العمل عن بعد خيارًا ممتازًا لها مثل شركة 37Signals التي كانت من أبرز المتبنين لثقافة العمل عن بعد حيث لم تكتف به فقط، بل دعت إليه في عدة كتب ألفها مديرو الشركة إضافة إلى الكثير من المقالات التي تحث العاملين في التقنية ابتداءً ومن يستطيع تبعًا على الانتقال إلى هذا النمط الجديد. وقد استفادت الشركات العاملة عن بعد كليًا أو جزئيًا من التطور المذهل في تقنيات الاتصال والعمل المشترك عن بعد أيما فائدة، فانتقلت المشاريع من خوادم الشركة وحواسيبها المحلية إلى الخوادم السحابية، ليتمكن أفراد الشركة من متابعة العمل من أي مكان وفي أي وقت، كما استفادت من هذا التطور في أوجه أخرى كما سنرى أدناه. تطور البنية التحتية للإنترنت لم يكن العمل عن بعد متاحًا بالصورة التي عليها الآن لو عدنا بالزمن عشرين أو خمسًا وعشرين سنة إلى الوراء مثلًا، ذلك أن البنى التحتية للاتصالات لم تكن تتحمل النقل السريع للبيانات والملفات الكبيرة، ولا العمل المشترك عن بعد، فضلًا عن جمع هذا إلى أمر بسيط مثل الاجتماعات المرئية، وقد سمح تطور البنى التحتية الإلكترونية من معالجات وتقنيات لنقل البيانات عبر الألياف الضوئية وغيرها، سمح ذلك بإنشاء شركات لخدمات برمجية ما كان يمكن إنشاؤها على البنية القديمة التي كانت سرعات الإنترنت فيها بطيئة للغاية. العوامل الاقتصادية لازدهار العمل عن بعد تتأثر الشركات بالتغيرات الاقتصادية في الدولة العاملة بها تأثرًا مباشرًا، وقد تفقد حصة كبيرة من سوقها في ظرف مفاجئ، أو تفقد بعض العاملين فيها لظروف خارجة عنها أو حتى اختيارًا من العاملين أنفسهم كما حدث في الولايات المتحدة إبان وباء كوفيد-19، فتلجأ إلى التوظيف عن بعد لحل تلك المشاكل، هذا غير الشركات التي اختارت هذا النمط ابتداءً كما ذكرنا سابقًا دون عوامل تضطرها إلى ذلك. وقد اتجه كثير من العاملين إلى نمط العمل البعيد اختيارًا لما وجدوا فيه من حرية أكبر للعمل بما أنهم ينجزون مهامهم دون الحاجة إلى التواجد الفعلي في المكتب، وهذا التفضيل يفيد الشركات في الغالب ولا يضرها بما أنه يفتح فرصة للشركة أن توظف كفاءات بعيدة دون الحاجة إلى استجلابها محليًا وتقنين وضعها داخل الدولة. والناظر إلى الواقع في الأعوام العشرة الماضية يجد كل حدث كبير وقع حول العالم يزيد التوجه إلى العمل عن بعد ولا يقل منه، وما يجده العاملون في نمط العمل عن بعد من فوائد مما ذكرناه من قبل، وقد ساعد في هذا التطور التقني الذي لا يهدأ في سوق الخدمات الرقمية المُقدَّمة للشركات فيما يخص التحول الرقمي أو العمل عن بعد، فشكل هذا مخرجًا لأي أزمة تؤثر على سوق العمل في أي دولة، فبدلًا من زيادة البطالة وما يتبعها، يبحث العاملون عن فرص متاحة للعمل عن بعد إما في مدينة أخرى أو دولة أخرى. ومن ناحية أخرى، فإن العمل عن بعد يوفر لصاحب الشركة فرصة تسجيل الشركة في المكان الذي يريده ويناسبه بغية الحصول على مزايا بعينها جراء التسجيل في تلك الدولة، مع الحفاظ على إمكانية توظيف من يشاء من أي مكان يريد، وهو الأمر الذي لم يكن متاحًا من قبل بتلك السهولة، إذ كان عليه معالجة الإجراءات القانونية الخاصة بكل دولة سيعمل فيها أو يوظف منها. العوامل الاجتماعية لازدهار العمل عن بعد استغل كثير من الموظفين فترة العمل عن بعد في الانتقال إلى جوار عوائلهم إن كانوا يعملون في مدن بعيدة، وإيلائهم مزيدًا من الاهتمام والرعاية، فالعامل عن بعد يوفر وقتًا بين ساعة إلى أربع ساعات كل يوم كانت تضيع في الذهاب إلى العمل والعودة منه. كذلك ظهرت حالات هجرة إما فردية أو جماعية أحيانًا إلى مدن هادئة أو ذات مناظر طبيعية جذابة من أجل العمل منها بما أن العمل سيكون عن بعد على أي حال، وقد ذكرنا أن بعض المدن والدول تشجع العاملين على الانتقال إليها، خاصة أولئك العاملين عن بعد، وهنا نضيف أنهم قد يفعلون ذلك اختيارًا من أنفسهم، غير أن هذا التنقل العشوائي قد يتسبب في بعض المشاكل لأهل المدن الصغيرة، كما حدث في مدينة كريستد بَت Crested Butte في ولاية كولورادو الأمريكية، وهي مدينة صغيرة بالكاد تتعدى مساحتها 2 كم مربع، إذ شهدت حالات هجرة إليها منذ بداية العمل عن بعد في ظل وباء كورونا. وإن كانت تلك الحرية في الانتقال عاملًا في ازدهار العمل عن بعد ومثلًا عليه إلا أنها من ناحية أخرى خلقت مشاكل لم تكن موجودة من قبل، فتلك المدينة السابقة شهدت زيادات خيالية في تكلفة المعيشة بسبب حركة الهجرة الجديدة إليها إلى حد اضطرار المدينة إلى إعلان حالة طوارئ لندرة المنازل المتاحة للسكنى. وإن كان هذا المثال بعيدًا عن العالم العربي إلى الآن على الأقل، إذ أن زيادة العمل عن بعد تعني ازدهاره في الوطن العربي لازدياد فرص توظيف الكفاءات العربية بين الدول العربية نفسها، كما هو الحال في شركة حسوب وغيرها من الشركات العاملة في الوطن العربي، وبين كافة الدول التي كان يصعب عليها جلب الكفاءات العاملة من الوطن العربي إليها. بل قد يشكل هذا فيما رأيت فرصة كبيرة على النقيض مما حدث في تلك المدينة الأمريكية، فالعديد من البلاد العربية تتسم بالمركزية الشديدة التي تكثف فرص العمل والتعليم والصحة وغيرها في العاصمة الإدارية أو الاقتصادية للدولة وما جاورها، مما يثقل كاهل العاصمة نفسها ابتداءً، فتعداد السكان في منطقة مثل القاهرة الكبرى في مصر يزيد على بعض الدول العربية مثل تونس والإمارات مجتمعتين، ويساوي ضعف تعداد سكان الأردن، وأربعة أمثال تعداد سلطنة عمان، وأكثر من نصف تعداد المملكة العربية السعودية! ومن ناحية أخرى يشبه تأثير المركزية في تلك الدول تأثير الهجرة تمامًا، فكما يهاجر الموظفون إلى دول أجنبية للعمل فيها ابتغاء فرص أفضل للحياة فإنهم ينتقلون انتقالًا شبه دائم إن لم تكن هجرة حقيقية إلى تلك المدن المركزية للاستقرار فيها لذات السبب، وقد حدثني كثير منهم أنه قد لا يرى بعض أفراد عائلته القريبين منه إلا كل عام أو اثنين! وذلك لغلاء تكلفة المعيشة في تلك المدن إلى حد اضطرارهم إلى العمل في وظيفتين أو أكثر. وهنا يأتي دور العمل عن بعد إذ شهدنا عودة كثير من أولئك العاملين في المدن المركزية إلى أقاليمهم وقراهم التي فيها عوائلهم، بل وفيها بيوتهم التي تركوها من أجل العمل في المدينة، بعد أن صاروا يعملون عن بعد إما بسبب جائحة كوفيد أو بعدها لما قررت شركاتهم بقاء نمط العمل عن بعد على ما هو عليه، وحدثني بعضهم عن التوفير في النفقات وعودة صلة الأرحام وراحة النفس مما كانوا قد فقدوه بالعمل لسنوات في المدن الكبرى. ثم ظهرت فرص جديدة لم تكن موجودة من قبل أو متاحة، إذ قرر بعض أولئك العاملين الانتقال إلى دول أخرى تمامًا للعمل فيها لأسباب أو ظروف طرأت عليهم ولم يكن بأيديهم حل لها من قبل، إذ رأينا سفر بعض العاملين عن بعد في مصر وعمان مثلًا إلى دول مثل تركيا للسياحة -أثناء العمل عن بعد!- أو طلبًا لتعليم أفضل لأولادهم، ومن الأردن والسودان إلى مصر لحضور دورات أو تعلم مهارة جديدة لم يكونوا يستطيعون ترك أعمالهم والسفر لها من قبل. تحديات العمل عن بعد والتغلب عليها يشكل العمل عن بعد نقلة نوعية للشركات قد تكون غير جاهزة لها لا تقنيًا ولا إداريًا، ومن ثم جاءت هذه السلسلة وأمثالها ليمهد الطريق لها، لتجنب الأخطاء التي قد تؤدي إلى عواقب قد يصعب إصلاحها، وتدور أغلب التحديات التي تواجهها الشركات هنا حول ما يلي: انضباط العاملين عن بعد. ضمان تنفيذ العمل على أكمل وجه. كفاءة التواصل بين العاملين والإدارة وبين العاملين وبعضهم. حل مشكلة رواتب العاملين عن بعد وضرائبها، وبقية البنود المالية من تأمينات اجتماعية وصحية وغيرها. هذا إضافة إلى الآثار الجانبية للتقنيات التي تُستخدم في العمل البعيد، كأن تتسبب أدوات متابعة العمل في تشتت العاملين عن بعد إذا كثرت قنوات العمل، كأن يرسل المدير رسالة على بريد العمل ثم يخبر العاملين أنه أرسلها في قناة محادثات أخرى مثل واتس اب أو سلاك أو تليجرام أو كامب فاير وغيرها، وإن كان من يفعل هذا يتعذر بقلة وعي العاملين باستخدام الأدوات التقنية أو بمحاولة ضمان وصول أخبار العمل ورسائله إلى العاملين، إلا أن هذا يؤدي إلى آثار عكسية أحيانًا كما سنبين لاحقًا. انضباط العاملين عن بعد يريد المدير وصاحب العمل أن يضمن عمل الموظف عن بعد بكفاءة تضاهي العمل من المكتب، وهذا حقه بما أنه يدفع المال كل شهر في صورة رواتب وضرائب ومنافع أخرى للموظف، وقد أظهر العديد من مدراء الشركات الكبرى عدم رضاهم بنمط العمل البعيد لأنه يشجع على الكسل وقلة الإنتاج، وقد كان أبرزهم في هذا إدارات شركة جوجل وتيسلا وأبل، حيث صرحت الأولى أنها تريد إعادة العاملين إلى المكتب تدريجيًا مع استثناءات، وكذلك شركة أبل التي استقال منها إيان جودفيلو Ian Goodfellow، وهو أحد مدراء الذكاء الصناعي بعد رفضه للسياسة الجديدة التي تريد فيها الشركة أن يعود العاملون إلى الشركة ثلاثة أيام على الأقل في الأسبوع. وكذلك كان إيلون ماسك يصرح بين الحين واﻵخر إما علنًا على تويتر أو داخليًا في رسائل شركة تيسلا البريدية أنه يريد للعاملين أن يعودوا للعمل من الشركة، ولا يُحسب للعامل حضوره إلا إذا كان من فرع الشركة الذي يتبع له العامل، في حين أنه وافق على سياسة العمل عن بعد للعاملين في شركة تويتر التي دخل في مفاوضات لشرائها. فالأمر بين الشركات يدور وفق الحاجة، بحيث تحتاج الشركات التي تصدر منتجات حقيقية مثل السيارات والطائرات أن يتواجد المدراء والمهندسون على أرض المصنع جنبًا إلى جنب مع الفنيين الذين يعملون في الغالب ساعات طويلة، وهو ما صرح به ماسك أن من يريد العمل عن بعد في تيسلا يجب أن يعمل 40 ساعة على الأقل كل أسبوع من الفرع التابع لها. أما الشركات التي تكون منتجاتها تقنية وبرمجية، فلا يُشترط العمل من المكتب بنفس القدر المطلوب في النوع السابق. ولا شك أن لكل نظام عمل مزايا وأوجه قصور تعتريه، ويفاضل صاحب العمل بين هذا وذاك لتحقيق أفضل النتائج، فإن كان العمل من المكتب يسهل على صاحب العمل "حصر الرؤوس" أو "Headcount" ليطمئن إلى سير العمل وأنه لا يدفع مالًا لغائب، وأن الأفكار تتلاقى في المكتب فقط، والحق أن هذه دعاوى مردها إلى أن صاحب العمل أو المدير لا يعرف كيف يدير الفرق البعيدة، وأنه يجب وضع المهام والأعمال التي تحتاج إلى تواجد حقيقي في حسابات العمل الحر، كما رأينا في مثال تويتر وتيسلا أعلاه. ويُضمن انضباط العمل البعيد بأوجه كثيرة تكاد تنفي الحاجة إلى التواجد في المكتب إلا في أضيق الحدود، فتفضل بعض الشركات التواصل غير المتزامن مثل حسوب و 37Signals وغيرهما، وتعتمد شركات أخرى من التي تتعامل مع بيانات أكثر حساسية طرقًا مختلفة لضمان تواجد الموظف في أوقات العمل الرسمية، بل ولضمان عدم جلوس غيره على الحاسوب كذلك، بأن تثبت برمجيات تلتقط صورًا للشاشة مع لقطة من كاميرا الحاسوب، وتوجد صورة أخف من هذا في بعض منصات العمل الحر التي تعتمد نظام العمل بالساعة مثل Freelancer، إذ توفر تطبيقًا يثبته المستقل على حاسوبه ليلتقط صورة من شاشة الحاسوب أثناء ساعات العمل التي يحددها المستقل، تُرسل إلى العميل على موقع المنصة ليطمئن العميل أنه يدفع حقًا مقابل ساعات عمل حقيقية. ضمان تنفيذ العمل سيقول بعض المدراء أنهم يريدون ضمان تنفيذ العمل على الوجه الأمثل، وهذه حجة يسهل تفنيدها ودحضها، ذلك أن الموظفين في الغالب يعملون على حواسيب ولا يتأكد المدير من عمل الموظف إلا من نتائجه التي يحصل عليها دوريًا أو من ملفات العمل المشتركة، وسواء هذا أو ذاك يتم تنفيذه رقميًا ويمكن تنفيذه عن بعد. فإن قال بأنه يريد ضمان عمل الموظف في ساعات العمل عدنا إلى النقطة السابقة التي نستخدم فيها البرمجيات اللازمة لضمان تواجد الموظف في ساعات عمله، واستخدام الساعات المتراكبة لضمان تفاعل الموظفين معًا، وهكذا. كفاءة التواصل هنا لا نقول أن التواصل الحقيقي في المكتب يضاهيه شيء، ولكن نحاول إثبات أنه غير ضروري في أغلب الوقت، بل ويأتي بنتائج عكسية أحيانًا! فكر في الأمر قليلًا، هل تقضي يوم العمل تتحدث مع الموظف في اجتماع يحتاج إلى تواجدك معه شخصيًا، أو يفعل الموظفون هذا مع بعضهم بعضًا؟ كلا، بل ينقضي أغلب الوقت في مهام يحتاج الموظف إلى التركيز الشديد فيها دون مشتتات، ألم يكن هذا الغرض من مقرات الشركات بالأساس؟ أن يستطيع العامل التركيز دون مشتتات من أهله أو غيرهم؟ بل يظل الموظف يطمح أن يكون له مكتب مستقل خاص به لئلا يزعجه أحد أثناء العمل، ويرى أن من يحصل على هذا المكتب فاز بحظ وافر، فكيف ونحن نقول أن العمل عن بعد يوفر ذلك المكتب الخاص لكل موظف! أما الاجتماعات وما يحدث فيها من تواصل، فقد حلت محلها الاجتماعات الافتراضية وجربتها مؤسسات العالم كله في فترة وباء كوفيد-19 دون مشاكل، بل ونحن نفعلها كل يوم في اتصالاتنا بأحبابنا، غير أننا نفضل الاجتماع الشخصي بهم لما يجمع بيننا من أرحام وعلاقات شخصية، فالإنسان يأنس بوجوده مع أناس آخرين وهو اجتماعي في نهاية المطاف، أما في العمل فهو كما يقول مؤسسو 37Signals، أن "الشركات ليست عائلات، وإنما تحالف بين عائلات"، ويقصدون بها تحالف بين عوائل الموظفين. وكذلك كثرت قنوات التواصل الخاصة بالعمل وما يتبعه من احتياجات من سبورة للشرح أو تواصل مرئي أو رفع لليدين لطلب الحديث أو كتم أصوات غير المتحدثين للتركيز على المتحدث، وغيرها مما لم يعد معه حاجة للاجتماعات الحقيقية، بل تذكر مراجعات هارفارد للأعمال Harvard Business Review أن الاجتماعات الافتراضية تفضُل هنا في جلسات العصف الذهني لابتكار الحلول للمشاكل وتمثل خيارًا أفضل للشخصيات الانطوائية أو الموظفين الأحدث. وعلى المدراء هنا أن يتخلوا عن الحاجة للرد الفوري على الرسائل، فهذا يقلل إنتاج الموظفين ويزعجهم بسبب التشتت على أي حال، ثم يصعب عليهم العودة للتركيز على المهمة التي كانوا يعملون عليها، بل بما أن الرسالة أُرسلت في بريد أو قناة تواصل، فينظر الموظف في الرد عليها حال إنهائه للمهمة التي بين يديه، وحينئذ يكون رده عليها أفضل بما أن ذهنه خلا للتفكير فيها. الأثر العكسي لبرامج العمل المشترك تحتاج هذه النقطة إلى كتب مطولة لبيانها بتفاصيلها، وقد كُتبت حقًا فيها كتب عظيمة النفع مثل كتاب العمل العميق Deep Work لكالفن نيوبورت Calvin Newport الأستاذ المساعد لعلوم الحاسوب في جامعة جورج تاون، وكتابي "It doesn't have to be crazy at work" و "Remote, Office Not required" اللذين ألفاهما جيسون فِريد Jason Fried وديفيد هانسون David Hansson، وهما مؤسسا شركة 37Signals، ذلك أن العاملين عن بعد يحاولون تعويض التواصل الحقيقي إلى أقصى قدر ممكن، فتجدهم على قنوات التواصل مثل تريللو وعلى البريد الإلكتروني الخاص بالعمل، إضافة إلى برنامج للتواصل المرئي مثل زوم أو تيمز Teams، فضلًا عن المجموعات الخاصة بين العاملين وبعضهم أو بينهم وبين مدرائهم على برامج المحادثة مثل تليجرام أو واتس اب! وتلك فوضى حقيقية، فكأن لدى كل موظف خمس نسخ من مديره في العمل، تخرج عليه كل واحدة من باب مختلف بنفس الرسالة كي يضمن أنها وصلته، وكذلك في حال زملائه في العمل، ويكثر هذا في حالة الموظفين الأصغر سنًا ممن ولدوا في الألفية مثلًا إذ لم يتعودوا على العمل العميق أو بدون مشتتات، أو استخدام قناة واحدة للتواصل مثلًا كالبريد الإلكتروني، إذ أخبرني بعض المدراء أنه يلجأ لاستخدام برامج المحادثة النصية مثل واتس اب في أغراض العمل لأن الموظفين الذين هم دون الخامسة والعشرين لا يعرفون كيف يستخدمون البريد الإلكتروني! ولم أصدقه حتى رأيت بنفسي عينات عشوائية لأولئك الموظفين، وهم حقًا يبدو أنهم لم يتعرضوا للبريد في حياتهم لاستغنائهم عنه بوسائل التواصل الأحدث مثل برامج المحادثة. وتُحل تلك المشكلة بالاتفاق على أغراض لوسائل الاتصال المختلفة، فلا تُستخدم برامج الاجتماعات المرئية إلا لذلك الغرض، ولا تُرسل رسائل أطول من ثلاثة أسطر مثلًا في البريد الإلكتروني، وإنما تُحول إلى اجتماعات صوتية أو مرئية، وتُخصص قنوات للإشعارات اللازم الاطلاع عليها بحيث تبقى لدى الموظف مفعّلة إشعاراتها إذا ما أراد كتم بقية وسائل الاتصال. ويعود هنا أسلوب التواصل غير المتزامن لتظهر فائدته، ففيه يحظى كل موظف ببضع ساعات من العمل العميق دون مشتتات أو إشعارات لأن بقية زملائه في العمل لم يبدأ يوم عملهم بعد أو قد انتهى بالفعل، فحتى لو ترك إشعارات وسائل التواصل الخاصة بالعمل مفعلة فلن يسمع منها شيئًا لأنه لا يحدث فيها شيء ذا بال في الغالب، ولو حدث فسيكون مهمًا على الأرجح. وتلك النقطة مهمة للمدراء خاصة بما أنهم يريدون ردودًا فورية على أغلب ما يرسلونه إلى الموظفين، وينزعجون من تأخر الموظف لانشغاله بمهمة أو اجتماع، والأولى ترك فترة زمنية كافية لكل موظف حتى ينتهي من عمله أو المهمة التي بين يديه، أو تخصيص وقت كل يوم يُنظر فيه في رسائل البريد، قبل أن يُحاسَب الموظف على تحديث في شروط العمل أو لوائحه لم يلتزم به لأنه لم يقرأ الرسالة البريدية الخاصة به، ويفضّل الاتفاق على قناة تواصل ما للأخبار التي لا يمكن تأجيل الاطلاع عليها. البنود المادية قد يظن بعض المدراء أن أمر الرواتب سهل بغض النظر عن محل عمل الموظف، وينظر البعض إلى التفاصيل والخطوات والشروط الواجب تحقيقها لكل دولة من الدول التي لديه أيدي عاملة فيها فيحجم عن التوظيف عن بعد، ويقتصر على التوظيف المحلي فقط. ولا تمثل هذه الأمور مشكلة في حالة التعاقد وفق المشروع مثل حالات العمل على منصات العمل الحر، كمنصة مستقل أو خمسات أو غيرها، حيث لا يتحمل صاحب الشركة أي تكاليف أو التزامات من طرفه، وإنما يتحمل المستقل تلك التكاليف ويقتطعها من قيمة مشروعه، أما في حالة التوظيف المنتظم، فإن صاحب العمل في الغالب هو من يحمل عبئها، وتنتهج الشركات عدة أساليب لحل هذه الأمور ننظر فيها في مقال لاحق. الآثار الاجتماعية للعمل البعيد قد تواجه الشركة مشكلة في بناء تواصل فعال بين العاملين عن بعد، لغياب التواصل البصري ولغة الجسد المعبرة عن مزاج المتحدث ومدى جديته في طرح الحديث، مما يوصل قصده إلى السامع وصولًا واضحًا لا يشوبه لبس ولا سوء فهم، فيُنظر في حل تلك المشكلة إن وجدت أو تلافيها عن طريق التواصل المرئي باجتماعات الفيديو مثلًا. كذلك سيعاني العديد من العاملين عن بعد من العزلة أثناء العمل وانخفاض معدل الإنتاج والتركيز في العمل، وهو ما كان العمل في المكتب التقليدي يعالجه بسبب بيئة العمل التي تحفز على الإنتاج، وتُحل تلك المشكلة بتوجيه الشركة للعاملين لتصميم بيئة عمل مناسبة من حيث التصميم المكتبي نفسه وصولًا إلى قواعد العمل عن بعد لكل من الموظف والمحيطين به إن كان يعمل من المنزل، وبتنظيم اللقاءات الدورية ووسائل التواصل غير الرسمي لتشجيع انسياب التواصل غير المتكلف بين العاملين. وتمامًا على تلك النقطة الأخيرة، فلعل أحد أكثر الأمور التي يصعب تنفيذها في نمط العمل عن بعد هو بناء روابط تتعدى حاجز علاقات العمل بين الموظفين في الشركة الواحدة، وتحل الشركات التي تنتهج العمل عن بعد تلك المشكلة بعدة طرق. فشركة حسوب على سبيل المثال تنظم اجتماعات سنوية يلتقي فيها الزملاء ببعضهم وجهًا لوجه، وتنظم بعض الشركات الأخرى رحلات سنوية لأحد فرقها في دولة ما ليعمل مع فريق آخر تابع للشركة في دولة أخرى لمدة أسبوع مثلًا في مكتب مشترك، من أجل تعزيز التواصل والعلاقات البشرية بين الزملاء، فيتعرفوا على شخصيات بعضهم بعضًا. تقييم مزايا وتحديات العمل عن بعد ذكرنا المزايا والتحديات هنا لنستطيع المفاضلة بينهما، كي يقيم المدير موقفه من نمط العمل عن بعد ويرى إن كان يصلح له أم لا، فقد يوفر تكاليف كبيرة في تكاليف المساحات المكتبية مثلًا وما يلحقها من تجهيزات، لكن قد يواجه صعوبة في تدريب الموظفين الجدد عن بعد، وتحل بعض الشركات تلك المشكلة بتخصيص مقراتها كلها أو جزء منها للموظفين الجدد، وتعيين موظفين قدامى لتدريبهم يعملون معهم لفترات مؤقتة من مقر الشركة لتسريع عملية التدريب، وإن كان يمكن تنفيذ نفس الأمر عن بعد دون الحاجة إلى مقرات الشركات ابتداءً، بإرسال الحواسيب إلى الموظفين عن بعد وتنفيذ التدريب افتراضيًا كعملية تعليمية بحتة باستخدام برامج التواصل المرئي وأدوات العمل المشترك الأخرى. لكن من الناحية الأخرى، قد تجد بعض الشركات أن العمل عن بعد يقلل من فرص التعاون المباشر الذي يُستغل في فترة تدريب الموظفين الجدد، أو قد يرى العاملون أنهم يرتاحون للعمل من المنزل أكثر، خاصة في حالة النساء اللاتي لا يردن الإهمال في حق بيوتهن وأولادهن. ومثل تلك البيانات التي تجمعها المؤسسة أو المدير المسؤول عن الفرق العاملة عن بعد توجه قرار اعتماد المؤسسة على هذا النمط إما كليًا أو جزئيًا، أو تقرر أنه لا يصلح لها أصلًا. الصور المختلفة للعمل عن بعد في الشركات تختلف الشركات عن النهج الذي تتبعه في العمل عن بعد إذ يعتمد هذا على إمكانيات الشركة نفسها واحتياجاتها، فقد تعمل بعض الفرق فيها عن بعد كليًا أو جزئيًا، أو قد تقيد الشركة العاملين فيها بالعمل ضمن نطاق جغرافي معين، وهكذا. شركات تعمل عن بعد كليا هي شركات تعمل بالكامل عن بُعد، ومنها نوع يعمل في نطاق زمني أو جغرافي محدد، وتلك الشركات قد يكون لها مكاتب أو مساحات عمل مشتركة أو لا يكون، فإن كان لها تلك المكاتب فإنها تخصصها لتدريب الموظفين الجدد، أو لمن لا يستطيعون العمل من منازلهم لسبب أو لآخر، وقد تخصص بعض تلك الشركات تطبيقات هاتفية لحجز المكاتب الموجودة في مقر الشركة لعدة ساعات أو أيام إذا كان الموظف ينوي الحضور إلى الشركة. وتفرض تلك الشركات على موظفيها أن يعملوا من حيز جغرافي -كدولة أو مدينة بعينها- أو زمني محدد مسبقًا، إما لأسباب قانونية تتعلق بالدولة التي تعمل فيها الشركة، أو لأسباب إدارية إذا كان العمل يعتمد على متغيرات زمنية أخرى، مثل مشاريع متزامنة أو عملاء في منطقة زمنية بعينها، أو لأسباب أمنية تتعلق ببيانات الشركة نفسها، وإن كانت هذه تندر لأن الشركات تعالجها باستخدام شبكات خاصة VPN أو حواسيب مخصصة للعمل تكون مراقبة ولا تسمح بالعبث بها. أما النوع الثاني منها فهي شركات أكثر مرونة حيث لا تشترط حيزًا جغرافيًا معينًا للعمل، وقد تسمح بالتواصل غير المتزامن بحيث يعمل الموظف من أي مكان شاء طالما يضمن تراكب ثلاث ساعات أو أكثر مع بقية زملائه أثناء ساعات عمله، وفي الغالب يحدد أيام العمل والإجازات بالتنسيق مع الموارد البشرية في الشركة، ويكثر هذا في الشركات التقنية. من أمثلة تلك الشركات شركة حسوب، وشركة 37Signals، و Buffer، وغيرها. شركات تعمل عن بعد جزئيا تسمح تلك الشركات لموظفيها بالعمل عن بعد بضعة أيام في الأسبوع، أما بقية الأيام فيجب أن تكون من المكتب، وينطبق عليها بقية الشروط التي ذكرناها في النوع السابق، ومن أمثلة تلك الشركات جوجل وأبل، بعد انتهاء فترة العمل عن بعد إثر جائحة كورونا. الجمع بين نوعي العمل عن بعد قد تجمع الشركة بين نوعي العمل عن بعد عند الحاجة، كأن تسمح بالعمل عن بعد كليًا لبعض الفرق التي لا تحتاج إلى الحضور إلى المكاتب، مثل فرق الدعم الفني والتطوير، وتسمح للبعض الآخر بالحضور عند الحاجة، ويكون ذلك بالتنسيق مع بقية أفراد الشركة إن كان العدد كبيرًا، فتستخدم بعض الشركات تطبيقات داخلية لحجز المكاتب الموجودة في مقرات الشركة مسبقًا لئلا يحدث زحام داخل الشركة في أحد الأيام دون غيره. وشركة جوجل مثلًا إحدى الشركات التي تريد للموظفين أن يعملوا من الشركة عدة أيام في الأسبوع، لكنها لم تمنع إلى الآن من يريد العمل عن بعد كليًا، خاصة إن كان من مدينة أخرى غير التي فيها مقرات الشركة، مع شروط معينة منها تخفيض الراتب إن كان يعمل من منطقة أقل في تكلفة المعيشة. فترات العمل عن بعد قد تعمل بعض الشركات عن بعد من بداية تعاقد الموظف فلا تعتمد لها مقرًا للموظفين أو مساحة عمل، وتترك حرية مكان العمل للموظف مطلقًا، غير أنها قد تعالج بعض تحديات العمل الحر التي تؤثر على أداء الموظفين بعدة طرق، فقد تخصص ميزانيات لتجهيز مكاتب منزلية للموظفين، أو اشتراكات في مساحات عمل قريبة ليعملوا منها، أو تخصص فترة كل عام يسافر فيها العاملون في إحدى الدول للعمل مع زملائهم من نفس الفريق في دولة أخرى في مقر للشركة أو مساحة عمل لمدة أسبوع أو أكثر، يلتقي فيها العاملون وجهًا لوجه، لتوطيد العلاقة بينهم وتقريب الثقافات المختلفة. ومن ناحية أخرى تختار بعض الشركات أن يعمل الموظفون عدة أيام فقط من المنزل، والبقية تكون في مقر الشركة، خاصة إن كان أغلب العاملين في مكان واحد قريب من الشركة، وسواء كان هذا أو ذاك فإن الأمر يعود إلى احتياجات الشركة نفسها وإمكانياتها المادية والإدارية، فليست كل الشركات يناسبها العمل عن بعد بنمط محدد دون غيره. تواصل الفرق العاملة عن بعد كما أن العمل عن بعد فيه عدة صور وأنواع، فإن له عدة أساليب مختلفة للتواصل كذلك لكنها تقع في الغالب تحت تصنيفين أساسيين، وهما التواصل المتزامن وغير المتزامن، هذا إضافة إلى التواصل الحقيقي إن كانت الشركة تعمل عن بعد جزئيًا، فحينئذ قد تخصص أوقاتًا من أيام العمل من المكتب للاجتماعات المهمة أو المكلفة إن كانت تتم عن بعد، ذلك أن اعتماد العمل عن بعد جزئيًا يعني أن الشركة لا زالت تدفع تكاليف لمكاتبها في كل شهر أو كل عام، فإضافة تكاليف الخدمات السحابية لاجتماعات الفيديو قد تكون عبئًا على الشركة إذا كان ممكنًا إجراء الاجتماع في مكتب الشركة. التواصل المتزامن يحدث الاتصال المتزامن في نفس الوقت ، مما يعني أن الاستجابات فورية في الغالب، وأكثر طرق التواصل اللحظي ذاك هي المكالمات الهاتفية ومؤتمرات الفيديو والاجتماعات الافتراضية، وهذا الأسلوب يناسب المواقف التي يُحتاج فيها إلى الرد المباشر والنقاش المثمر في جلسات العصف الذهني أو الاجتماعات أو الردود الفورية. لكن هذا يعني أن يعمل الموظفون في نفس التوقيت الزمني بغض النظر عن مواقعهم الجغرافية، وأن تكون احتمالات تعطل أدوات العمل أو معدات الاتصال نتيجة انقطاع للطاقة أو الاتصال بالإنترنت قليلة الحدوث، بل يُفترض وجود اتصال بالإنترنت لا تقل سرعته عن 5-10 ميجابت/ث من أجل التواصل المرئي البسيط. التواصل غير المتزامن أما في حالة التواصل غير المتزامن فلا يُشترط تواجد اﻷطراف المتواصلة في نفس الوقت من أجل تحقيق ذلك التواصل، فيُستخدم البريد الإلكتروني وتطبيقات إدارة الأعمال والبرمجيات التشاركية في تنفيذ المهام وتطبيقات المكتب السحابية وغيرها. وهنا لا تُشترط الاستجابة الفورية، بل يرد كل موظف في الوقت الذي يناسب جدول عمله، وتكفي ساعات عمل متراكبة لإجراء أي اجتماعات قد تكون طارئة أو لازمة، سواء صوتية أو مرئية أو حتى تواصلًا فوريًا في محادثة نصية من أجل الحصول على رد سريع، وهو لا يتأثر بتعطل تقنيات الاتصال أو انقطاع الطاقة كما يحدث في التواصل المتزامن، كما أن له مزية أخرى تصلح للأعمال التي تحتاج إلى تركيز كبير لعدة ساعات، وتظهر في طبيعة عمل الساعات المتراكبة، فتلك الساعات تعني وجود فترات زمنية لا يتحدث فيها الموظف مع باقي زملائه، فيصرفها في التركيز على المهام التي بيده وإنهائها كما ذكرنا من قبل، ثم تخصيص الأوقات التي يشترك معه زملاؤه فيها للنقاشات حول المهام والاجتماعات وغيرها. هل يصلح العمل البعيد لشركتي؟ يتبادر إلى الذهن سؤال هنا بعد الاطلاع على مفهوم العمل عن بُعد وفوائده وعيوبه، عن جدوى تبني هذا النظام إن لم يكن المدير أو المؤسسة قد تبنوه من قبل، فما هي الدوافع التي تجعلنا نختار تحويل الشركة إلى نظام العمل عن بعد، فهل نحتاج إلى إبقاء الموظفين في بيوتهم لظرف طارئ عام على الدولة التي فيها مقر الشركة أو خاص على مستوى الشركة نفسها، كأن تكون حالة صحية أو أمنية أو مناخية لا يمكن السماح فيها للعاملين بمخاطرة القدوم إلى مقر الشركة، أو يكون الأمر مجرد تغير بعض ظروف العمل في الشركة، كأن تحتاج مقر الشركة في تدريب موظفين جدد أو إخراج فرق عاملة على بعض المشاريع إلى أماكن منفصلة عن باقي الشركة لحاجة تلك الفرق إلى ذلك، ولعل القارئ تبادر إلى ذهنه الآن سبب أو مجموعة من الأسباب من بيئة عمله تدفعه لتبني ذلك النظام. من المقبول عقلًا أن العمل عن بعد لا يصلح لكل الشركات، بل لا يصلح لكل الفرق داخل الشركة الواحدة، وقد بدا هذا جليًا إذ أعلنت جوجل بعد تخفيف الإجراءات الاحترازية من جائحة كوفيد-19 عن نيتها لإعادة الموظفين إلى مقرات الشركة في خلال بضع سنين. ومن ناحية أخرى فقد يرغب بعض المدراء في تواجد الموظفين معهم تحت نفس السقف، فهذا أسهل في الإدارة من جانبهم عن الفرق البعيدة التي تتطلب أدوات وبرمجيات متابعة وغيرها، ويصعب هذا في الأعمال التي تحتاج إلى تركيز عميق واجتماعات قد لا تكون مجدولة مثل أعمال البرمجيات، خاصة في حالة المدراء الذين لم يتعودوا على الإدارة البعيدة. فعند تعذر تقييم العاملين عن بعد بسبب طبيعة عمل المؤسسة نفسها أو حاجتها إلى أنماط أعمال تتطلب وجودًا في مقر الشركة وتواصلًا أسرع من العمل عن بعد فحينئذ يكون العمل من مقرات الشركة هو الأنسب، فالعمل عن بعد ليس خيرًا محضًا ولا شرًا في نفسه، بل هو أسلوب للعمل قد يصلح لكثير من الشركات والمؤسسات العاملة في السوق ويوفر لها كفاءات لم تكن متاحة محليًا، ويوفر نفقات كانت لتُنفق في جلب تلك الكفاءات أو تجهيز بيئات العمل المحلية لها، غير أنها من الناحية الأخرى قد تعطل أداء بعض المؤسسات التي لا يصلح العمل عن بعد لها. أمثلة لشركات تعمل عن بعد قد ذكرنا أن العمل عن بعد ليس جديدًا في ذاته ولا مستحدثًا بظرف طارئ، وهنا نذكر أمثلة لبعض الشركات التي اعتمدت العمل عن بعد منذ بدئها أو بعده من غير اضطرار بسبب جائحة أو غيرها، وقد بدت نتائج العمل البعيد عليها في صور إيجابية. حسوب تعمل شركة حسوب عن بعد منذ نشأتها في 2011، وقد استفادت من العمل عن بعد في توظيف كفاءات من مختلف أنحاء الوطن العربي إن لم يكن من خارجه دون التقيد بمحل إقامتهم أو تكلف جلبهم إلى مقر الشركة نفسها، وهذا مفيد للشركات في بدئها لتقليل التكاليف والجهود الضائعة في إدارة الموارد البشرية والتركيز على المنتج نفسه. وقد أثمر هذا عن مجموعة من المنتجات التي صبت في نهر العمل البعيد أيضًا فقد أرادت تعميم الفائدة التي جنتها منه من توفير منصات للعمل الحر ومنصات للتوظيف والعمل عن بعد وخدمات أخرى مكملة لها تعلم العاملين العرب وتطور مهاراتهم التقنية والمهنية، إضافة إلى الكتب التي أصدرتها الشركة من خلال أكاديمية حسوب، والتي منها هذا الكتاب نفسه في طبعته الأولى، وكتاب دليل المستقل والعامل عن بعد، ودليل الأمان الرقمي، إضافة إلى الكتب المتخصصة في البرمجة والتسويق والتصميم وغيرها. مساق تأسست شركة مساق عن بعد كليًا عام 2020 واستفادت أكبر استفادة من ذلك بضم خبرات من كامل الوطن العربي الأمر الذي يساعدها على التوسع فيه بما أنها تستهدف العالم العربي في المقام الأول، وقد وصل فريقها الموزع عن بعد إلى 15 من السعودية والإمارات والبحرين ومصر وسوريا وفلسطين. وكان هدف مساق مساعدة المعلمين والمدارس والأكاديميات على إنشاء منصاتهم التعليمية على الإنترنت بسهولة ويسر دون الاهتمام بالجانب التقني والبرمجي، وبذلك ينصب التركيز على المحتوى التعليمي المقدم، وتستهدف كما ذكرنا العالم العربي بتوظيف الخبرات العربية أينما كانت في خدمة العالم العربي بنشر الأكاديميات التعليمية على الإنترنت ليستفيد منها أي متعلم عربي أينما كان. 37Signals شركة برمجيات أمريكية تأسست في 1999، كان تركيزها في البداية على تصميمات الويب، ثم انتقلت إلى بناء تطبيقات للويب، وقد طورت إطار العمل Ruby On Rails لاستخدامه داخليًا قبل نشره للعامة في 2004، وتعمل عن بعد بأسلوب التواصل غير المتزامن. لدى الشركة فلسفة في العمل تختلف عن أغلب الشركات الأمريكية التي تأثرت بصبغة شركات وادي السليكون، وتقوم على العمل الهادئ المنتظم، وعدم إرهاق العاملين بكثرة وسائل التواصل، والتشجيع على العمل العميق الذي لا يزيد عن 40 ساعة أسبوعيًا، وقد تعمقت في تفصيل تلك الفلسفة كثيرًا إلى حد أنها خرجت بعدة كتب تدعو إلى هذا النمط، مثل Rework و It doesn't have to be crazy at work و Remote: Office not required وغيرها. نماذج أخرى تكثر نماذج الشركات العاملة عن بعد إما كليًا أو جزئيًا في الواقع وقد يُخصص لها مقال طويل أو كتيب صغير يجمعها، لكننا جمعنا الفوائد التي تُستخرج من نمط عملها البعيد في هذه السلسلة، ويُنظر في بقية الأمثلة لمن أراد البحث عنها، فهي تتغير وفقًا لرغبات الشركة وحاجاتها، غير أن أهم الشركات التي تتبع هذا النهج وقت كتابة هذه الكلمات هي ما يلي: Buffer: شركة برمجية اشتهرت بتطبيقها الذي يحمل نفس الاسم لإدارة الحسابات في الشبكات الاجتماعية. Reddit: موقع النقاش وتقييم المحتوى. Google. شركة ميتا: وهي فيس بوك -قبل تغيير اسمها‎- الغنية عن التعريف. تويتر: صاحبة شبكة التواصل الاجتماعي الغنية عن التعريف. شركة SAP: شركة برمجيات ألمانية مختصة ببرمجيات إدارة العمليات في الشركات. شركة ليفت Lyft: شركة نقل الركاب المثيلة لشركة أوبر. 3M: شركة صناعية لها منتجات في طب الأسنان والمواد اللاصقة وأدوات الحماية وغيرها. خاتمة حاولنا في هذا المقال التمهيد للعمل عن بعد بإجمال ليعلم القائمون بالإدارة والتوظيف في الشركات أبعاده إن كانوا يفكرون في اعتماده بشكل أو بآخر، ثم نفصل في بقية السلسلة إن شاء الله ما ذُكر ها هنا، من آليات لمتابعة العمل عن بعد، وقياس أداء العاملين والحلول التي تتبعها أشهر الشركات العاملة عن بعد في العالم العربي لمتابعة الموظفين وتطويرهم وكذلك من الشركات العاملة في السوق الأجنبية، والأساليب المختلفة للتوظيف عن بعد، إما توظيفًا دائمًا أو تعهيدًا خارجيًا. ولا شك أننا سنفصل قبل كل هذا كيفية التأسيس الصحيح لبيئة العمل عن بعد في الشركة، كي يتلافي القارئ الأخطاء والتخبطات التي حدثت أثناء الانتقال السريع إلى العمل عن بعد من كثير من المؤسسات في السوق العربية والعالمية. كتبت فاطمة أحمد المسودة الأولية لهذا المقال. اقرأ أيضًا ما هو العمل عن بعد؟ دليلك لبناء فِرق عمل عن بعد والحصول على وظيفة أحلامك من المنزل 8 دروس يمكن تعلمها من أفضل الشركات التي تعمل عن بعد في العالم تعرف على منصات العمل الحر والعمل عن بعد كيف تبدأ – وتنجح في – خدمة العملاء عن بعد ما هو العمل المشترك الافتراضي؟ متى يحقق العمل عن بعد النجاح المطلوب في مشروعك الريادي
  14. سنغطي في هذا المقال من سلسلة تعلم البرمجة ما يلي: آلية ووقت استخدام التزامن concurrency والخيوط threads. مثال على تقسيم الحمل بين العمليات. الوصول إلى البيانات المشتركة باستخدام الخيوط. بعض الاحتمالات والمحاذير الأخرى. رأينا إضافة هذا المقال إلى شرحنا بعد تفكير طويل نظرًا لأهمية موضوعه، وسبب ترددنا في ذلك أن التزامن عمومًا -والخيوط على وجه الخصوص- موضوع يصعب فهمه، رغم مسارعة الكثيرين إليه ظنًا منهم أنه يحل مشاكلهم، لكنهم يزيدونها سوءًا لضعف فهمهم لمفاهيم التزامن والخيوط، واللتان هما أداتان قويتان عند استعمالهما في المواضع المناسبة عن فهم وإدراك، لكن نرى أن يكونا الملاذ الأخير، نلجأ إليهما بعد فشل جميع الحلول الأخرى، وقد عملنا -يقصد المؤلف نفسه- على عدة مشاريع تستخدم التزامن بصورة أو بأخرى في الأعوام الأربعين الماضية، لكننا لم نستخدمها في مشاريع شخصية من قبل، وربما يعطي هذا تصورًا عن توقيت استخدام هذه التقنية، ونوعية المشاريع التي تُستخدم فيها. مفهوم البرمجة التزامنية وتوقيت استخدامها تشير البرمجة التزامنية Concurrent programming ببساطة إلى برنامج يحوي عناصر تعمل على التوازي في نفس الوقت، وهو ما نطبقه على حواسيبنا كل يوم، لكننا نترك أمر إدارة تلك البرامج لنظام التشغيل، ليجدولها لتعمل بالترتيب، ويوزع حمل التشغيل على المعالجات والنوى kernels الموجودة فيها، فمفهوم تقسيم المهمة إلى عدة أجزاء والعمل على كل جزء على حدة ليس جديدًا، وهو يشبه إنشاء فرق مختلفة للتعامل مع مشكلة كبيرة تُقسم إلى عدة أجزاء، ليعمل كل فريق على جزء منها. وقد اتبعنا تلك الأساليب في علم الحواسيب على مدار العقود الماضية، خاصةً في الخوادم، فمثلًا يستقبل خادم الويب طلبات ويعالجها، لكن إذا كان الموقع كبيرًا وطلباته كثيرة ومتلاحقة، وكان الخادم يُعالج كل طلب قبل بدء الطلب الذي يليه؛ فستطفح قائمة انتظار المدخلات للخادم، لذلك يقرأ الخادم الطلب من قائمة الانتظار، فإذا كان الطلب ملف html بسيطًا فيعيده، أما إن كان أعقد من هذا فيشتق الخادم عمليةً فرعيةً للتعامل معه، ويعود هو لقراءة الطلب التالي. وقد رأينا من قبل كيفية إنشاء عمليات من شيفرة بايثون الخاصة بنا في مقال التواصل مع نظام التشغيل باستخدام وحدة subprocess، ورأينا منظورًا مختلفًا في مقال التواصل بين العمليات، حيث استخدمنا fork لإنشاء عملية فرعية تكون نسخةً من العملية الأصلية، وتعمل كلا التقنيتين بسلاسة إذا كنا نرغب في عمليات قليلة منمقالة تمامًا عن بعضها، لكنهما لا تناسبان الحالة التي نحتاج فيها إلى عمليات كثيرة، كما في حالة معالجة خادم الويب لآلاف الطلبات كل دقيقة، وإحدى المشاكل التي قد تحدث عند استخدامهما لحالة الطلبات الكثيرة هو ما ينتج عن بطء إنشاء العملية الجديدة -بمقياس سرعة الحواسيب-، كما تكلف كل عملية الكثير من الأحمال الزائدة من استهلاك الذاكرة وغيرها، وهنا يبرز دور الخيوط therads، وهي تشبه العمليات الدقيقة التي تعمل داخل العملية الأصل، فتتشارك جميعها نفس مساحة الذاكرة ونفس الشيفرة، وتأتي تسمية الخيوط من فكرة أن الشيفرة الخاصة بنا تعمل من الأعلى إلى الأسفل -مع قفزات وحلقات تكرارية في طريقها-، فهي مثل بكرة من القطن أمسكنا طرف خيطها وتركناها تسقط، فكل خيط جديد يشبَّه بكرة قطن جديدة نسقطها بالتوازي مع الخيط الأول، وكل خيط له مسار تنفيذ خاص به في نفس الشيفرة. لقد أشرنا أن التزامنية تتعلق بشكل ما بالأداء، خاصةً في حالة الأحمال الكبيرة من البيانات، والحق أن هذا هو السبب الوحيد لاستخدامها، فإذا واجهنا مشكلة عند زيادة البيانات ونكون قد بذلنا كل ما نستطيع من تعديلات على الأداء الأساسي -لعملية تبادل أو وحدة بيانات واحدة-، فحينئذ قد نحتاج إلى إعادة التفكير في شأن تقسيم الأحمال. اختيار أسلوب التزامن بعد أن أثبتنا فائدة التزامن في تحسين الأداء في حالة الأحمال الكبير، كيف نقرر التقنية التي سنستخدمها لمعالجة مهمة ما؟ أيهما أفضل لمهمتنا العمليات المتعددة أم الخيوط المتعددة؟ والجواب أننا ننظر في عدة عوامل، حيث: نستخدم الخيوط إذا كان في المهمة انتظار لنشاط الإدخال والإخراج، مثل رسائل الشبكة أو نتائج استعلامات قواعد البيانات. نستخدم الخيوط إذا تطلبت المهمة مشاركة البيانات بين عدة "خيوط"، لكن يجب تذكر قفل lock البيانات المشارَكة أثناء التحديثات. نستخدم العمليات الفرعية إذا كان في المهمة معالجة خالصة للبيانات data crunching، وقد صممت الوحدة multiprocessing في بايثون خصيصًا لهذه الحالة. إذا كانت المهمة الفرعية تعمل لوقت طويل، أو لا تُستدعى إلا لوقت قصير، فننشئ عملية خادم طويلة التشغيل long running server process، كما فعلنا في مقال التواصل بين العمليات، لنرسل البيانات إليها عند الحاجة. البدء بالبرمجة المتزامنة بما أننا قررنا استخدام التزامن فلننظر في الشيفرة المطلوبة لها، لدينا وحدتان في المكتبة القياسية تتعلقان بالخيوط، هما Thread وthreading، والوحدة الأخيرة هي وحدة عالية المستوى بُنيت فوق وحدة Thread، ولا نحتاج إلا إلى النظر فيها، أما في حالة العمليات المتعددة فنستخدم وحدة multiprocessing التي تعمل تقريبًا بنفس طريقة threading. تحديد المشكلة لننظر في مشروع بسيط نريد فيه حساب مضروب أول N عدد من مجموعة ما من الأعداد، فنكتب دالةً لحساب المضروب ثم نضعها في حلقة تكرارية ونخزن النتائج، وستبدو كما يلي: import time, sys factorials = [] def fact(n): if n < 2: return 1 result = 1.0 for x in range(2,n+1): result *= x return result def do_it(f,lo,hi): global factorials for n in range(lo,hi): factorials.append(f(n)) if __name__ == "__main__": hi = int(sys.argv[1]) + 1 start = time.time() do_it(fact, 1, hi) print('Time for %s: %s' % (hi, time.time() - start)) نلاحظ أننا أنشأنا دالة do_it التي تغلف الحلقة التكرارية الخارجية واستدعاءات المضروب، وهي ليست ضروريةً لكننا سنرى نفعها لاحقًا عندما ننظر في التزامن، وقد جعلنا عدد مرات التكرار وسيطًا في سطر الأوامر، وأضفنا مؤقتًا لإظهار الزمن الذي تستغرقه. احفظ ذلك في ملف باسم no_threads.py وشغله لأول 100 عدد كما يلي: $ python3 no_threads.py 100 إذا شغلنا هذا الأمر فسنجد أن الوقت المستغرق أقل من ثانية، نظرًا لسرعة الحواسيب هذه الأيام، لكن جرب ذلك مع أول ألف عدد مثلًا وانظر الوقت المستغرق، وقد جربناها لكل من أول 100 عدد، وأول 1000، وأول 10000، وخرجنا بالنتائج التالية: $ python3 no_threads.py 100 Time for 100: 0.0006973743438720703 $ python3 no_threads.py 1000 Time for 1000: 0.06539225578308105 $ python3 no_threads.py 10000 Time for 10000: 6.800917863845825 نلاحظ أن السرعة جيدة إلى أن نصل إلى الألف عدد، لكنها تسوء فجأةً مع زيادة العدد عن ذلك، ونريد تحسين هذا الأداء لتلك الأعداد الكبيرة، وهنا يأتي دور التزامن. إضافة التزامن إلى العملية باتباع الإرشادات التي شرحناها أعلاه، سنختار multiprocessing بدلًا من threading لهذه المهمة، ونريد أن نعرف مقدار العدد المُدخَل أولًا، فإذا كان أكثر من 1000، فسنقسم العملية إلى عدة فروع، وسيكون ذلك أبطأ في الأعداد الكبيرة، لذلك بدلًا من تقسيم البيانات بالتساوي بين العمليات سنقسمها عند 75% -عشوائيًا-. ستكون الشيفرة كما يلي: import time, sys import multiprocessing factorials = [] def fact(n): if n < 2: return 1 result = 1.0 for x in range(2,n+1): result *= x return result def do_it(f,lo,hi): global factorials for n in range(lo,hi): factorials.append(f(n)) if __name__ == "__main__": hi = int(sys.argv[1]) + 1 start = time.time() if hi > 1000: hi_1 = int(hi * 0.75) p1 = multiprocessing.Process(target=do_it, args=(fact,1,hi_1)) p2 = multiprocessing.Process(target=do_it, args=(fact,hi_1,hi+1)) p1.start() p2.start() p1.join() p2.join() else: do_it(fact, 1, hi) print('Time for %s: %s' % (hi, time.time() - start)) نلاحظ أننا أنشأنا كائنيْ Process، ومررنا الدالة التي نريد تشغيلها -وهي do_it- إضافةً إلى الوسائط اللازمة في صف tuple، ثم استدعينا start لتشغيل العمليات، أخيرًا استخدمنا التابع join لجعل البرنامج الرئيسي ينتظر انتهاء العمليات. $ python3 processes.py 100 Time for 100: 0.0006771087646484375 $ python3 processes.py 1000 Time for 1000: 0.06577491760253906 $ python3 processes.py 10000 Time for 10000: 3.690302610397339 نلاحظ أن الوقت المستغرق للعملية الكبيرة قد انخفض إلى النصف تقريبًا، لكن ما نفذناه لم يكن بسيطًا أو مباشرًا، فلم نقسم البيانات بالتساوي، فإذا جربت تقسيمها عند 50% فستجد أن الوقت المستغرق زاد مرةً أخرى. يبدو أن التزامن يعطينا تحسنًا كبيرًا في الأداء، لكن في الواقع لدينا خلل كبير في برنامجنا، فإذا طبعنا factorials -وهي قائمة النتائج- فسنجدها فارغةً! والسبب في هذا أن كل عملية فرعية هي نسخة من العملية الأصل، وبالتالي لها نسختها الخاصة من قائمة factorials، والتي نفقد بياناتها عند انتهاء العملية، لذلك نحتاج إلى طريقة لتمرير البيانات إلى العملية الأصل، مما يعني الكتابة إلى ذاكرة مشتركة -انظر وحدة mmap- أو إلى قاعدة بيانات أو إلى ملف. نستخدم في تلك الحالات كلها عمليات الإدخال والإخراج، لذا فلم لا نستخدم الخيوط بما أنها تتشارك الذاكرة! فنكون قد أنشأنا نسختنا الخاصة من معضلة Catch-22)! لكن لحسن الحظ نادرًا ما يكون لدينا عمليات نحتاج إلى تقسيمها بالتوازي دون أن يكون فيها عمليات إدخال وإخراج، لذا فإن الخيوط هنا حل يمكن تنفيذه، وسننظر في مثال "مفتعل" إلى حد ما لمجرد موازنة هيكل الشيفرة مع مثال تعدد العمليات السابق. استخدام الوحدة threading سننشئ في هذا المثال خيطًا مساعِدًا لتحديث المتغير theTime في كل ثانية، وسيتكرر البرنامج الرئيسي بلا نهاية ليطبع المتغير في كل مرة يتغير فيها، ولضمان تشغيل الخيوط بسلاسة سنضيف تأخيرًا زمنيًا باستخدام time.sleep، التي يعاملها المفسر على أنها عملية إدخال/إخراج. import time, threading theTime = 0 def getTime(): global theTime while True: theTime = time.time() time.sleep(1) def main(): global theTime current = theTime thrd = threading.Thread(target=getTime) thrd.start() while True: if current != theTime: current = theTime print(time.asctime(time.localtime(current))) time.sleep(0.01) if __name == "__main__": main() لقد أنشأنا في المثال أعلاه دالةً تغلف مهمة الخيوط، لضمان وجود عملية time.sleep فيها -أو أي دالة I/O أخرى-، ثم أنشأنا خيطًا نسند فيه دالتنا على أنها الهدف، كما فعلنا في العمليات أعلاه، ونبدأ تشغيل الخيط في الخلفية ثم ننتقل إلى الحلقة الأساسية التي تتحقق من المتغير في كل جزء من مئة من الثانية. عند الحاجة إلى إنهاء البرنامج نكتب Ctrl+C أو نستخدم مدير المهام في نظام التشغيل لإنهاء هذه العملية. إذا شغلنا الشيفرة السابقة فستكون النتيجة شبيهةً بما يلي: $ python3 clock.py Sat Dec 30 11:30:33 2017 Sat Dec 30 11:30:34 2017 Sat Dec 30 11:30:35 2017 Sat Dec 30 11:30:36 2017 ... كان من الممكن تحقيق ذلك بسهولة دون استخدام الخيوط، لكنها تعطينا فكرةً عما تبدو عليه أبسط شيفرة تحوي خيوطًا، فإذا وازنّاها مع شيفرة العمليات المتعددة فسنجد أنهما متطابقتان تقريبًا في بنيتيهما، والفرق بينهما أن شيفرة الخيوط تستطيع تحديث متغير getTime العام الذي تستطيع الدالة الرئيسية الموجودة في العملية الأصل أن تراه، نستطيع الآن أن نعود ونستبدل العمليات بالخيوط في المثال السابق ونوازن بين النتائج، وسنجد أن نسخة الخيوط لم تقدم مزيةً زمنيةً على نسخة العمليات. سنكتفي بهذا القدر من شرح التزامن لأنه موضوع معقد فيه الكثير من الفخاخ الدقيقة، وننصح بعدم استخدامه إلا عند الضرورة، وحتى في تلك الضرورة فالشرح الموجود هنا يمثل نقطة بداية فقط، يمكن الانتقال بعدها إلى شروح أكثر تفصيلًا وعمقًا. للمزيد من المعلومات، ننصحك بالإطلاع على دورة تطوير التطبيقات باستخدام لغة Python التي تشرح الكثير من المفاهيم الأساسية لبناء التطبيقات في بايثون. خاتمة نأمل في نهاية هذا المقال أن تكون تعلمت ما يلي: يُستخدم التزامن لتحسين الأداء. يُنفَّذ التزامن بتشغيل عمليات أو خيوط إضافية. تعمل العمليات بشكل مستقل عن بعضها، وتتواصل مع العملية الأصل باستخدام الأنابيب pipes. تعمل الخيوط افتراضيًا داخل العملية الأصل، وتتشارك الموارد -مثل الذاكرة وغيرها- فيما بينها. يجب إقفال الموارد المشتركة قبل تغيير الحالة لتجنب حدوث تعارضات. توجد طرق أخرى للتزامن، كما في وحدة asyncio في بايثون التي تستخدم منظورًا مختلفًا. ترجمة -بتصرف- للمقال الثاني والثلاثين: Concurrent Programming من كتاب Learn To Program لصاحبه Alan Gauld. اقرأ أيضًا المقال السابق: استخدام أطر العمل في برمجة تطبيقات الويب: فلاسك نموذجا برمجة عملاء ويب باستخدام بايثون كيفية كتابة تطبيقات الويب كيفية التعامل مع الويب استخدام أطر العمل في برمجة تطبيقات الويب: فلاسك نموذجًا
  15. سنغطي في هذا المقال من سلسلة تعلم البرمجة ما يلي: أساسيات أطر عمل الويب. استخدام إطار Flask في مثال Hello World. بناء برنامج دليل جهات الاتصال في تطبيق ويب. أطر عمل الويب Web Frameworks تُعد البرامج التي تعتمد على الواجهة CGI التي تحدثنا عنها في المقال السابق وسيلةً فعالةً لبناء مواقع ويب تفاعلية، إلا أن لها عدة مشاكل لا يمكن تجاهلها، لعل أخطرها بدء الخادم عمليةً جديدةً في كل طلب، مما يسبب بطءً واستهلاكًا للموارد، لذا لا يمكن استخدامها في التطبيقات ذات العمليات الكثيرة المتزامنة، والمشكلة الثانية وجود الشيفرة وتعليمات HTML والبيانات في ملف واحد، مما يصعّب عملية الصيانة ويعرّضها للأخطاء، فقد يتسبب تعديل بسيط في HTML بأخطاء تركيبية في شيفرة بايثون، وقد جُربت عدة أساليب مختلفة للتعامل مع هذه المشاكل، إلا أن الأسلوب الذي استمر والذي سننظر فيه هو إطار عمل الويب web framework، وأشهر هذه الأطر: صفحات خوادم مايكروسوفت النشطة Active Server Pages: واختصارًا ASP، يعمل هذا الإطار جنبًا إلى جنب مع خادم ويب مايكروسوفت IIS وبيئة "‎.NET" الخاصة بها، وهذا يعني إمكانية استخدام أي لغة مبنية على "‎".NET -بما في ذلك نسخة بايثون الخاصة بها- في إطار ASP. صفحات خوادم جافا Java Server Pages: واختصارًا JSP، هي إطار عمل جافا الخاص بتطوير الويب، و هي تقنية لتوليد تطبيقات الخوادم المصغرة Servlets، التي هي عمليات خفيفة تشبه برامج CGI، لكنها أسهل في التعامل معها. إطار عمل Ruby on Rails: يشبه إطار العمل ريلز rails الخاص بلغة روبي إطار عمل Flask الخاص ببايثون، والذي سندرسه قريبًا. إطار عمل جانغو Django: يُعد جانغو أكثر أطر عمل بايثون شهرةً، خاصةً في بناء المواقع الكبيرة، وله شروحات كثيرة في كتب وتوثيقات إلكترونية، وهو غني بوحدات الإضافات plug-in modules المتاحة لتوسيعه، إلا أنه صعب التعلم موازنةً بإطار Flask. إطار العمل Flask: وهو ما سندرسه في هذا المقال، إذ يوفر جميع العناصر الأساسية الموجودة في أطر العمل، وهو سهل التعلم نسبيًا، ويمكن استخدامه ببساطة دون كثير من التعقيد الذي يشتت الانتباه عن الأفكار الرئيسية. تتمثل الفكرة الأساسية في جميع أطر عمل الويب في أنها تقلل الحمل على الخادم، باستخدام تقنيات البرمجة المتزامنة، والتي سندرسها في المقال التالي، كما تمقال المنطق logic عن شيفرة العرض presentation code، لتسهيل صيانة الموقع، حيث تسعى أحدث المعايير الصادرة عن w3c في كل من HTML5 و CSS3 إلى تحقيق هذا المقال، إذ يجب أن تُستخدم HTML حصرًا في هيكلة بناء المستند، بينما تُستخدم التنسيقات المورَّثة CSS للمظهر، من خطوط وألوان ومواضع وتحكم في رؤية العناصر أو إخفائها وغير ذلك، وبهذا تصبح برمجة الويب عملًا منظمًا يمكن صيانته، من خلال الجمع بين تلك الممارسات في كل من CSS وHTML مع أطر عمل الويب، وذلك من خلال تقنيتين رئيسيتين: توجيه نقطة النهاية endpoint routing للروابط، والتي يشار إليها أحيانًا بالربط mapping، حيث يوجَّه الجزء الأخير من الرابط من ملف إلى دالة أو تابع في إطار العمل. توفر قوالب المستندات طريقةً لإنشاء ملفات HTML ساكنة، فيها محددات للمواضع place-markers لإدراج البيانات فيها، ويمكن لدوال إطار عمل الويب أن تجهز البيانات ثم تمررها إلى محرك القالب، الذي يجلب القالب المناسب، ويدرج البيانات في محددات مواضعها لتوليد خرج HTML النهائي الذي يُعاد إلى متصفح المستخدم. سنرى استخدام كلا التقنيتين في Flask، ولأطر عمل الويب غالبًا نفس المفاهيم، رغم اختلاف تفاصيل بنائها اللغوي syntax، واصطلاحات الاستدعاء المتبعة. تثبيت Flask لا يوجد إطار عمل Flask في مكتبة بايثون القياسية، لذا يجب تثبيته إما باستخدام أداة pip التي تأتي مع بايثون، أو استخدام حزمة تنفيذية خاصة، وهو ما يُنصح به مستخدمو لينكس، خاصةً عندما يُثبت على النظام أكثر من إصدار بايثون. عند استخدام pip نفتح طرفية النظام (وقد نضطر إلى تشغيل أمر pip بصلاحيات مدير النظام، خاصةً عند تثبيت بايثون لجميع المستخدمين على الحاسوب) ونكتب فيها ما يلي: $ pip install flask يمكن التحقق منها بتشغيل بايثون، واستيراد Flask بالأمر import flask، فإذا لم نحصل على أخطاء نكون قد نجحنا. استخدام Flask في مثال Hello World يوفر إطار عمل Flask وحدة خادم ويب بسيطةً، يمكن استخدامها للاختبار والتطوير قبل نقل الشيفرة إلى منصة استضافة ويب في شبكة تابعة لشركة أو على الإنترنت، وسندرس الآن كيفية تشغيله وتوفير صفحة ويب بسيطة. صفحة ويب بسيطة لن نحتاج هنا إلى إنشاء ملف HTML كما فعلنا في حالة CGI في المقال السابق، بل سنعيد شيفرة HTML من دالة Flask، كما يلي: import flask helloapp = flask.Flask(__name__) @helloapp.route("/") def index(): return """ <html><head><title>Hello</title></head> <body> <h1>Hello from Flask!</h1> </body></html>""" if __name__ == "__main__": helloapp.run() يجب أن نشير هنا إلى بضعة أمور، حيث يُسند أول سطر بعد import flask نسخةً من كائن تطبيق Flask إلى متغير helloapp، وهو اسم عشوائي رغم أنه نفس اسم تطبيقنا، ثم نمرر المتغير الخاص __name__، الذي رأيناه في فصول سابقة، إلى التطبيق الذي يستخدمه ليعرّف الموقع الرئيسي (الجذر) لموقع الويب. أما الأمر التالي فهو الدالة التي تعالج طلب http GET، والتي تسمى index اصطلاحًا لتوافق تسمية ملف index.htm، غير أن المثير للاهتمام هنا هو المزخرِف ‎@helloapp.route("/")‎ الذي يسبقها، والذي يخبر إطار Flask أن أي طلب إلى جذر الموقع / يجب توجيهه إلى التابع التالي المسمى index في حالتنا هذه، ويمكن توجيه عدة نقاط نهاية end points إلى نفس التابع بتكديس المزخرفات decorators فوق بعضها البعض، وقد ذكرنا من قبل أن توجيه نقاط النهاية هو إحدى التقنيات المستخدمة في أطر عمل الويب، وهذه هي طريقة إطار عمل Flask لتوجيهها. تشغيل خادم ويب Flask نبدأ تشغيل شيفرة Flask التي صارت جاهزةً الآن بالطريقة المعتادة، باستدعاء ما يلي من المجلد الذي يحوي التطبيق: $ python hello.py ينبغي أن نرى رسالةً تخبرنا أن الخادم يعمل وينتظر الطلبات: * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) نستطيع الآن العودة إلى المتصفح لندخل العنوان الموجود في الرسالة: http://127.0.0.1:5000/ ستظهر رسالة "Welcome from Flask"، وبهذا نكون قد بنينا أول تطبيق ويب بإطار عمل Flask. مقدمة في القوالب تتعامل شيفرة إطار Flask التي رأيناها حتى الآن مع مشاكل توسع التطبيقات، وزيادة حجمها، وبعض الفوضى التي تسببها برمجة CGI، إلا أنها لا تستطيع مقال الشيفرة عن HTML، فلا زلنا نكتب سلاسل HTML داخل شيفرة البرنامج، ولمعالجة تلك المشكلة نستخدم قوالب Flask. والقوالب في إطار Flask ما هي إلا ملفات HTML ساكنة فيها محددات markers أو مواضع خاصة لاستقبال البيانات من التطبيق، وهي تشبه سلاسل التنسيق format strings التي في بايثون، فمثلًا نريد قالبًا يستطيع استقبال رسالة الترحيب في سلسلة، ثم يدرجها في قالب، سيكون هذا القالب كما يلي: <!doctype html> <head><title>Hello from Flask</title></head> <body> <h1>{{message}}</h1> </body> </html> إذا نظرنا إلى {{message}} فسنجد المواضع التي ذكرناها، فتلك الأقواس المزدوجة هي مواضع استقبال البيانات، والمتغير message هو اسم المتغير الذي سيدخله محرك القالب إلى HTML. نحفظ المثال السابق في ملف باسم hello.htm داخل مجلد باسم templates في مجلد المشروع، واسم القالب مهم هنا لأنه المكان الذي يتوقع إطار Flask أن يجد فيه ملفات القوالب، يتبقى الآن بعض التعديلات على شيفرة بايثون الخاصة بنا لربطها بمحرك القوالب، وسنغير الشيفرة السابقة لتكون كما يلي: from flask import Flask, render_template helloapp = Flask(__name__) @helloapp.route("/") def index(): return render_template("hello.htm", message="Hello again from Flask") if __name__ == "__main__": helloapp.run() الاختلاف الأول في تعليمة import، حيث غيرنا النمط لنستطيع استيراد الأسماء التي نحتاجها مباشرةً. نلاحظ الآن اختفاء شيفرة HTML من ملف بايثون الخاص بنا، ونمرر الرسالة مثل سلسلة عادية إلى الدالة render_template مع اسم القالب، ونترك الباقي لإطار Flask، لكننا نريد أن نضمن مطابقة الوسائط المسماة في استدعاء هذه الدالة للأسماء التي في مواضع القالب، ثم نعرف كيف نقرأ البيانات الواردة من طلبات http لنستطيع تكرار نسخة CGI التي نفذناها من تطبيق "hello user". استخدام Flask في مثال Hello User نريد الآن تعديل التطبيق ليعمل مع استمارة HTML التي استخدمناها من قبل، فنبدأ بتحويل HTML إلى قالب نرسله عند تحديد المستخدم لنقطة نهاية "hello"، ولا نحتاج إلى إضافة أية محددات خاصة إلى HTML لأننا لا ندرج أي بيانات، لكن يجب تغيير الخاصية method للاستمارة إلى "POST"، وكذلك الخاصية action لتعكس منفذ إطار Flask -الذي هو 5000- ونقطة النهاية المطلوبة للرابط، والتي هي sayhello، ثم نحفظ ذلك في مجلد templates باسم helloform.htm ليستطيع إطار Flask العثور عليه، وسيبدو بعد تلك التعديلات كما يلي: <!doctype html> <html> <head> <title>Hello user page</title> </head> <body> <h1>Hello, welcome to our website!</h1>8000 <form name="hello" method="POST" action="http://localhost:5000/sayhello"> <p>Please tell us your name:</p> <input type="text" id="username" name="username" size="30" required autofocus/> <input type="submit" value="Submit" /> </form> </body> كتابة شيفرة Flask نحتاج الآن لإضافة تابعين جديدين إلى تطبيقنا، يعرض الأول منهما قالب helloform.htm، بينما يرد الثاني على طلب إرسال الاستمارة، ونلاحظ أن الدالة الثانية ستستخدم قالب hello.htm الأصلي، ولم نضف شيئًا سوى كتابة سلسلة رسالة جديدة: from flask import Flask, render_template, request helloapp = Flask(__name__) @helloapp.route("/") def index(): return render_template("hello.htm", message="Hello again from Flask") @helloapp.route("/hello") def hello(): return render_template("helloform.htm") @helloapp.route("/sayhello", methods=['POST']) def sayhello(): name=request.form['username'] return render_template("hello.htm", message="Hello %s" % name) if __name__ == "__main__": helloapp.run() لاحظ أننا اضطررنا إلى إضافة request إلى قائمة العناصر المستورَدة لأننا نستخدمه للوصول إلى بيانات طلب http، كما عدلنا مزخرف معالج sayhello ليشير إلى أنه يستطيع معالجة طلبات النوع POST -وقد كان الافتراضي طلبات GET- حيث نستخرج بيانات username داخل الدالة من الاستمارة، وندخلها في السلسلة التي نعيدها إلى قالب hello.htm. أما معالج hello فهو أبسط من ذلك، إذ يرسل قالب helloform.htm إلى المستخدم. إذا شغّلنا الشيفرة الآن فسيعمل الخادم، وإذا كتبنا العنوان التالي: http://localhost:5000/hello فسنرى نفس الاستمارة التي كانت لدينا في مثال CGI من قبل (لاحظ أن كلمة localhost هي اسم بديل لـ 127.0.0.1، ويمكن تذكرها بسهولة أكثر)، فإذا ملأنا الاستمارة وضغطنا زر Submit؛ فستظهر لنا رسالة ترحيبية. وبهذا نكون ألغينا الحاجة إلى بدء عملية منمقالة، وبالتالي جعلنا التطبيق قابلًا للتوسيع وزيادة الحجم، كما أزلنا أي أثر لتعليمات HTML من شيفرة البرنامج لتسهيل صيانته وتعديله، وهذا غيض من فيض إمكانيات Flask، إذ يحوي الكثير من المزايا التي لم نرها بعد، فمثلًا يستطيع الاتصال تلقائيًا بقاعدة بيانات عند بدئه، وإغلاقها عندما ينتهي، كما يستطيع التحقق من أن المستخدمين سجلوا الدخول قبل تنفيذ أي تغييرات على البيانات، وهناك العديد من مصطلحات الترميز التي لم نستخدمها، والتي تعيننا في صيانة وتشغيل موقع ويب كبير، وخاصةً في نظام القولبة الذي يحوي بدوره بعض المزايا الأخرى، وسننظر في بعضها إذ سننتقل الآن إلى إنشاء واجهة ويب أمامية لقاعدة بيانات دليل جهات الاتصال الخاص بنا. دليل جهات الاتصال كتبنا في مقال العمل مع قواعد البيانات في البرمجة تطبيقًا لدليل جهات اتصال يعمل من سطر الأوامر، وسنعيد استخدام قاعدة البيانات تلك لبناء نسخة ويب مبنية على إطار Flask، وسنضيف بعض عناصر برمجة الويب الأخرى أثناء ذلك، وسيكون تطبيق ويب بسيط رغم تلك العمليات التي سننفذها، غير أنه سيوفر أساسًا كافيًا لبناء تطبيقات ويب وفهم التوثيقات والتدريبات الأخرى. إعداد المشروع لمشاريع إطار Flask عادةً بنية محددة، فهي تأخذ صورة هرمية مجلد، حيث يكون اسم المشروع في الأعلى ، متبوعًا بمجلد static للملفات الساكنة مثل الصور وملفات CSS، ومجلد templates للقوالب، وحزمة بايثون اسمها في الغالب هو اسم المشروع، والتي هي مجلد يحوي ملفًا اسمه ‎__init__.py يتحكم في ما تصدره الحزمة، كما تحتوي عادةً على ملف setup.py يُستخدم لتثبيت الحزمة إذا كانت موزَّعةً من فهرس حزم بايثون Python Package Index أو PyPI اختصارًا، وتسهل هذه الهرمية توزيع التطبيق باستخدام أدوات بايثون القياسية مثل pip. لكننا لن نوزع التطبيق في حالة دليل جهات الاتصال، لذا سنكتفي بترتيب بسيط مبني على المجلدات القياسية الثلاثة، إضافةً إلى مجلد رابع لملف قاعدة البيانات: addressbook static templates db سننسخ ملف قاعدة البيانات من المقال السابق إلى مجلد db هنا. إنشاء قالب HTML سيكون لدينا صفحة ويب واحدة تتكون من استمارة بسيطة لإدخال البيانات، فيها ثلاثة أزرار هي Create وFind وList all، حيث سيستخدم زر Create البيانات التي في الاستمارة لإضافة مدخل جديد إلى قاعدة البيانات، ويعرض زر Find قائمةً بجميع العناوين المطابقة للبيانات التي في الاستمارة، بينما يعرض زر List all القائمة الكاملة للعناوين. سنستخدم مزيةً جديدةً لمحرك القوالب، وهي القدرة على تكرار صفوف HTML وفقًا لمجموعة بيانات الدخل، وسيُدمج هذا مع عنصر HTML جديد هو وسم الجدول <table> وعائلته التي سنستخدمها لعرض قائمة العناوين. وسيبدو القالب كما يلي: <!doctype html> <html> <head> <title>Flask Address Book</title> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1"> <style> h1 {text-align: center;} label { width: 20em; text-align: left; margin-top: 2px; margin-right: 2em; float: left;} input { margin-left: 1em; float: right; width: 12em;} input.button {width: 6em; text-align: center; float: left;} br {clear: all;} div.buttons {float: left; width:100%; padding: 1em;} </style> </head> <body> <header> <h1>Address Book Website</h1> </header> <div class="content"> <form name="hello" method="POST" action="http://localhost:5000/display"> <fieldset><legend>Address</legend> <label>First name: <input type="text" id="First" name="First" required autofocus/> </label> <label>Second Name: <input type="text" id="Last" name="Last" required /> </label> <br /> <label>House Number: <input type="text" id="House" name="House" /> </label> <label>Street: <input type="text" id="Street" name="Street" required /> </label> <br /> <label>District: <input type="text" id="District" name="District" /> </label> <label>Town: <input type="text" id="Town" name="Town" required /> </label> <br /> <label>Postcode: <input type="text" id="Postcode" name="Postcode" required /> </label> <label>Phone: <input type="text" id="Phone" name="Phone" /> </label> </fieldset> <div class="buttons"> <input class="button" type="submit" value="List All" /> <input class="button" type="submit" name="Filter" value="Filter" /> <input class="button" type="submit" name="Add" value="Add" /> <input class="button" type="reset" value="Clear" /> </div> </form> <br /> <div class="data"> <table id="addresses"> <tr> <th>First</th> <th>Second</th> <th>House#</th> <th>Street</th> <th>District</th> <th>Town</th> <th>Postcode</th> <th>Phone</th> </tr> {% for row in book %} <tr> <td>{{row.First}}</td> <td>{{row.Last}}</td> <td>{{row.House}}</td> <td>{{row.Street}}</td> <td>{{row.District}}</td> <td>{{row.Town}}</td> <td>{{row.PostCode}}</td> <td>{{row.Phone}}</td> </tr> {% endfor %} </table> </div> </div> </body> </html> يوجد عدد كبير من العناصر الجديدة هنا، بما في ذلك قسم <style> الذي يتحكم في تخطيط الاستمارة، ويمكن الرجوع إلى أي شرح للغة CSS -مثل توثيق CSS في موسوعة حسوب- لمعرفة ما تفعله الشيفرة هنا إذ لا يتسع المقام لشرحها بسبب بعدها عن الغرض من المقال. كما توجد بعض مزايا HTML الجديدة: يوضع ترميز المحارف في وسم meta داخل وسم head، وتجب إضافة هذا الوسم في صفحات الويب الحديثة خاصةً إذا كنا نستخدم محارف غير قياسية، وإلا فسيكون لدينا في الصفحة أجزاء غير قابلة للقراءة. الوسم meta هو منفذ للعرض viewport، وهو مصمم لتحسين عرض الصفحة على الأجهزة المحمولة، ويُفضل إضافة هذا الوسم إلى الصفحة. استخدمنا عددًا من وسوم div، وهي مجرد أدوات تنظيمية لا تظهر على الشاشة إلا إذا تعمدنا إظهارها باستخدام CSS، وهي تشبه ودجات Frame التي استخدمناها في برامج Tkinter الرسومية، وتفيدنا في التحكم في نطاق الأوامر لكل من CSS وجافاسكربت. تحتوي الاستمارة form على ثلاثة عناصر جديدة، يساهم كل منها في تحسين مظهرها، هي العنصر fieldset الذي يجمع عدة حقول داخل إطار مرئي يُدرج فيه العنصر legend، والعنصر label الذي يغلف حقول input ليجعلها معًا على الشاشة. نختم الاستمارة بثلاثة أزرار من النوع submit لها الخاصية name التي تُرسَل إلى الخادم، ونستطيع استخدام تلك البيانات لتحديد الدالة التي يجب تنفيذها، أما الزر الأخير فيكون من النوع reset، وهو يمسح حقول الاستمارة ولا يرسل شيئًا إلى الخادم. قسم <table> الذي يبدأ بصف من الترويسات <th> و<tr>. يوفر الجزء التالي ميزةً جديدةً لمحرك القوالب، وهي القدرة على تنفيذ حلقات تكرارية واستبدال عدة أجزاء من البيانات، وهي الحقول التي في كل صف في حالتنا، وتُحدَّد بنى التحكم هذه بمحارف {%...%}، ويدعم المحرك عدة بنىً مختلفة إضافةً إلى الحلقة الموضحة هنا. كتابة شيفرة إطار Flask لا نحتاج إلى إضافة الكثير من الشيفرات الجديدة في هذا المشروع، فعناصر إطار Flask مجرد توسيع طفيف من المثال السابق لتحديد أي زر من أزرار submit الثلاثة قد ضُغط، وبمجرد أن ننفذ ذلك نستدعي دوال بايثون العادية التي تعدل قاعدة البيانات باستخدام وحدة sqlite3 كما شرحنا في مقال قواعد البيانات، وتعيد تلك الدوال قائمةً من عناصر القواميس، بمقدار عنصر واحد لكل صف في قاعدة البيانات، وتمرَّر تلك القائمة إلى محرك عرض القوالب template rendering engine الذي ينفذ مهمة إدخال HTML إلى الصفحة التي أنشئت، وستبدو الشيفرة كما يلي: from flask import Flask, render_template, request, g import sqlite3, os addBook = Flask(__name__) addBook.config.update(dict( DATABASE=os.path.join(addBook.root_path,'static','address.db'), )) @addBook.route("/") def index(): data = findAddresses() return render_template("address.htm", book=data) @addBook.route("/display", methods=['POST']) def handleForm(): if 'Filter' in request.form: query= buildQueryString(request.form) return render_template('address.htm', book=findAddresses(query)) elif 'Add' in request.form: addAddress(request.form) # add a new entry return render_template("address.htm", book=findAddresses()) # Note: flask.g is the "global context" object # that lives for the life of the application. def get_db(): if not hasattr(g, 'sqlite_db'): try: file = addBook.config['DATABASE'] db = sqlite3.connect(file) db.row_factory = sqlite3.Row # return dicts instead of tuples except: print("failed to initialise sqlite") g.sqlite_db = db return g.sqlite_db @addBook.teardown_appcontext def close_db(error): if hasattr(g, 'sqlite_db'): db = g.sqlite_db db.commit() db.close def buildQueryString(aForm): base = "WHERE" test = " %s LIKE '%s' " fltr = '' for name in ('First','Last', 'House','Street', 'District','Town', 'PostCode','Phone'): field = aForm.get(name, '') if field: if not fltr: fltr = base + test % (name, field) else: fltr = fltr + ' AND ' + test % (name, field) return fltr def findAddresses(filter=None): base = """ SELECT First,Last,House,Street,District,Town,PostCode,Phone FROM address %s ORDER BY First;""" db = get_db() if not filter: filter = "" # empty -> get all query = base % filter cursor = db.execute(query) data = cursor.fetchall() return data def addAddress(aForm): db = get_db() cursor = db.cursor() first = aForm.get('First','') last = aForm.get('Last','') house = aForm.get('House','') street = aForm.get('Street','') district= aForm.get('District','') town = aForm.get('Town','') code = aForm.get('PostCode','') phone = aForm.get('Phone','') query = '''INSERT INTO Address (First,Last,House,Street,District,Town,PostCode,Phone) Values ("%s","%s","%s","%s","%s","%s","%s","%s;");''' %\ (first, last, house, street, district, town, code, phone) cursor.execute(query) if __name__ == "__main__": addBook.run() نلاحظ بعض النقاط المهمة هنا: نستورد الاسم g من إطار Flask، وهو كائن خاص يوفره Flask ليحمل قيم مستويات التطبيق، ونستفيد من المبدأ الذي يقوم عليه، رغم غرابة اسمه، وهو يشبه المعامِل self في البرمجة الكائنية لكنه ينطبق هنا على تعاملات الويب بدلًا من الكائن. نعِدّ موقع قاعدة البيانات في البنية الخاصة addbook.config، وهناك عدة عناصر أخرى يجب إعدادها هنا في الموقع الكامل، بما في ذلك اسم المستخدم وكلمة المرور للمدير admin، وتخزَّن هذه الأمور عادةً في ملف config، ويُستخدم أمر خاص لتحميلها. كما يجب الانتباه إلى خيار DEBUG الذي يؤدي لطبع معلومات كثيرة إلى الطرفية عند ضبطه على القيمة True، لأن هذه المعلومات مفيدة للغاية في حال حدوث المشاكل أثناء التطوير. تتحقق الدالة get_db من كون الخاصية sqlite_db مضبوطةً أو لا قبل أن تضبطها، وهذا يضمن وجود اتصال واحد فقط لقاعدة البيانات. كما تضبط هذه الدالة row_factory من sqlite3.Row، وفائدته أنه يجعل Sqlite تعيد قائمةً من كائنات Row بدلًا من صفوف tuple تحتوي على قيم، وتُعامَل كائنات Row تلك على أنها قواميس، وهو ما يبحث عنه Flask تحديدًا في محرك القوالب الخاص به، لذا يوفر سطر الشيفرة ذاك علينا كثيرًا من تنسيق البيانات. ينبغي أن توجد معالجات أخطاء try/except حول الكثير من التعليمات البرمجية، خاصةً أقسام قواعد البيانات، لكننا لم نشأ الإطالة أكثر من اللازم، وسنرى مثالًا في دالة get_db يوضح أننا نستطيع استخدام تعليمات print لعرض خرج التنقيح debug output في الطرفية. يُستخدم هنا مزخرِف جديد هو ‎@addBook.teardown_appcontext لرفع راية إلى إطار Flask بأنه يجب تشغيل الدالة close_db عند إغلاق التطبيق. تساعد الدالة buildQueryString في بناء شرط WHERE الخاص باستعلامنا ديناميكيًا، وقد تبدو معقدةً إلا أنها مجرد تعديل بسيط على سلسلة نصية، ويسمح لنا هذا الأسلوب باستخدام دالة واحدة لإيجاد جميع العناوين عند عدم استخدام مرشحات filters، أو العناوين المطلوبة فقط. تكون عمليات البحث أكثر مرونةً باستخدام عامل LIKE الخاص بـ SQL، بدلًا من اختبار التكافؤ equality test، بما في ذلك القدرة على استخدام علامة % محرف بدل في SQL. نستخدم تابع القاموس get لجلب القيم من الاستمارة، وهذا يضمن حصولنا على قيمة افتراضية عند عدم وجود المفتاح لسبب ما، وهي سلسلة فارغة في حالتنا. تشغيل دليل جهات الاتصال سنغير مجلد التطبيق ونشغل الملف address.py، ثم نستخدم المتصفح لزيارة localhost:5000، وبهذا تطابق عملية التشغيل هذه عملية التشغيل السابقة، ويجب أن نرى نفس الأسماء والعناوين التي أنشأناها في مقال قواعد البيانات في المتصفح. كما ينبغي أن نستطيع الآن إدخال القيم في الاستمارة، وترشيح النتائج لمطابقة كلمات البحث -نستخدم % محرف بدل wildcard- وكذلك نستطيع إضافة إدخالات جديدة، وبما أنه لا يوجد تحقق من الحقول أو الاستمارة فيجب أن نراعي إدخال قيم منطقية مناسبة، أو نتلافى أي أخطاء يدويًا باستخدام محث sqlite3. ينبغي أن يقدم هذا المقال فكرةً عن متطلبات إنشاء تطبيق ويب، وهناك المزيد لتعلمه بما في ذلك تقنيات برمجة المتصفحات، وأمور الأمان في جانب الخادم، وملفات تعريف الارتباط cookies، وإطلاق الموقع الحي في صورته النهائية على الإنترنت، وكل هذا خارج عن سياق شرحنا، لذا يُرجع فيه إلى تطوير التطبيقات باستخدام لغة Python من أكاديمية حسوب، أو دورة تطبيقات الويب باستخدام PHP، وغيرها من مقالات البرمجة والكتب البرمجية في الأكاديمية كما توفر شركات استضافة الويب توثيقات ممقالةً عن تحقيق الاستفادة القصوى من المواقع التي ننشئها. خاتمة نأمل في نهاية هذا المقال أن تكون تعلمت ما يلي: تحسّن أطر عمل الويب إمكانية توسيع المواقع وصيانتها. توجه أطر عمل الويب نقاط النهاية إلى الدوال. توجد عدة إطارات عمل للويب في السوق الآن. إطار Flask يمثل حلًا وسطًا بين البساطة والإمكانيات. يستخدم Flask مزخرفات decorators لتوجيه نقاط النهاية. كما يستخدم نظام قوالب لتمرير البيانات إلى صفحات الويب. ترجمة -بتصرف- للمقال الحادي والثلاثين: Using Web Apllication Frameworks من كتاب Learn To Program لصاحبه Alan Gauld. اقرأ أيضًا المقال التالي: البرمجة المتزامنة وفائدتها في برمجة التطبيقات المقال السابق: كيفية كتابة تطبيقات الويب برمجة عملاء ويب باستخدام بايثون كيفية كتابة تطبيقات الويب كيفية التعامل مع الويب تواصل البرامج والعمليات البرمجية عبر الشبكة
  16. سنغطي في هذا المقال من سلسلة تعلم البرمجة: تاريخ موجز لخوادم الويب. أساسيات CGI: واجهة البوابة المشتركة. مقدمة في برمجة خوادم الويب في بدايات الإنترنت كنا نطلب صفحات HTML من خوادم الويب فتعطينا صفحات ثابتةً أو ساكنةً، ليس للمستخدمين أي يد في تعديل محتواها أو التفاعل معها، باستثناء بعض عمليات باتش batch processes التي استخدمتها بعض المواقع لإنشاء صفحات HTML من مصادر البيانات، لضمان تحديث معلومات تلك الصفحات، وفي هذه الحالة أيضًا لم يكن للمستخدمين دور في ما يظهر أمامهم على صفحة الويب. ثم صرنا ندمج البرامج في خوادم الويب لتوليد الصفحات ديناميكيًا كلما طلبها المستخدم، وسميت الآلية المستخدمة في ذلك واجهة البوابة المشتركة Common Gateway Interface أو CGI اختصارًا، ولا يزال أثر تلك التقنية باقيًا في مواقع الويب التي نتصفحها حاليًا. ومع استغلال المبرمجين إمكانيات واجهة CGI -مع وسم <form> في HTML- صارت المواقع التي يبنونها أكثر تطورًا وتعقيدًا، وصار من الممكن بناء مواقع التسوق الإلكتروني، والألعاب، والدعم الفني، وغيرها من الخدمات التي صارت اليوم بدهيات. تُبنى واجهة CGI على مفهوم بسيط، هو أن بيانات الإدخال تُرسَل مثل جزء من رسالة http GET أو http POST، ويشير الرابط إلى مجلد خاص في خادم الويب، الذي يعرف أن عليه تنفيذ المورد resource بدلًا من إعادته، وهذا المورد هو برنامج يرسل الخرج الخاص به إلى مجرى الخرج القياسي stdout في صفحة HTML، فيقرأ الخادم مجرى الخرج القياسي، ويوجهه إلى العميل الذي طلب الصفحة. سندرس الآن جزءًا من تلك المرحلة المبكرة في تطور خوادم الويب، بأن ننشئ خادم ويب بسيط على حاسوبنا المحلي، ليعطينا صفحة HTML ثابتةً، ثم نوسّع الصفحة لتشمل استمارةً تلتقط اسم المستخدم وترسله إلى الخادم، ونختم بإنشاء برنامج CGI يقرأ اسم المستخدم ذاك، ويعيد رسالة ترحيب مخصصةً باسمه من الخادم. إنشاء صفحة ترحيب باستخدام واجهة CGI توفر بايثون وحدة خادم ويب بسيطةً نستطيع استخدامها للاختبار والتطوير، قبل نقل الشيفرة إلى منصة استضافة ويب حقيقية في شبكة ما أو على الإنترنت، وسنبدأ بالنظر في كيفية تشغيلها لإرسال صفحات ويب ساكنة static web pages. صفحة ويب بسيطة أول ما علينا فعله هو إنشاء صفحة الويب التي نريد إرسالها، ولن نشرح كيفية كتابة شيفرة HTML بالتفصيل هنا، وإنما سنشرح ما يكفي لتشغيل الأمثلة التي نكتبها، وستبدو صفحة "Hello World" بسيطةً كما يلي: <!doctype html> <html> <head> <title>Hello world web page</title> </head> <body> <h1>Hello World</h1> </body> </html> تتكون HTML من وسوم، وهي أسماء محددة مسبقًا في توصيف اللغة نفسها، تحيط بها علامتا < و>، وتأتي أغلب الوسوم في أزواج يكون وسم الإغلاق فيها مسبوقًا بشرطة مائلة /، كما قد تحتوي الوسوم على بيانات تُعرف بالخاصيات attributes، غير أن المثال أعلاه ليس فيه أي منها لأننا بدأنا به بسيطًا، لكننا سنراها لاحقًا. تجدر الإشارة هنا إلى أن بعض العناصر إجبارية في HTML، فيجب أن تحتوي كل صفحة HTML عليها على الأقل لتكون صالحةً، رغم أن أغلب المتصفحات الحالية ستعرض الصفحة حتى لو لم تكن هذه العناصر موجودةً، وتلك العناصر هي: التصريح doctype: يشير إلى أن هذا المستند هو مستند HTML، وقد كان هذا التصريح طويلًا ومفصلًا سابقًا، لكن -ومنذ صارت HTML5 قياسيةً ومعتمدةً- نكتفي بكتابة html في ذلك التصريح. لاحظ أن تنسيق الوسم في doctype مختلف عن وسوم HTML العادية، إذ توجد علامة تعجب مباشرةً بعد علامة ‎<‎. الوسم html: نستخدم زوجًا من الوسم <html> لتحديد بداية متن المستند نفسه ثم وسم إغلاق له، ويشكل هذا الوسم جذر المستند، وتمثَّل صفحات HTML في ذاكرة المتصفح في هيكل شجري، تكون قمته الوسم <html>. وتعدِّل شيفرة جافاسكربت التي في المتصفح ذلك الهيكل، لذا تؤثر طريقة كتابة HTML كثيرًا في كيفية كتابة شيفرة جافاسكربت، وكذلك في قراءة عملاء الويب web clients -مثل تلك التي كتبناها في المقال السابق- لتلك الصفحة. الوسم head: يحدد الوسم <head> جزءًا من الصفحة يحوي معلومات عن الصفحة نفسها، لكن المتصفح لا يعرضها، فمثلًا تعرَّف فيه بيانات أوراق الأنماط المتتالية أو التنسيقات الموروثة CSS، وقد يُستورد ملف CSS عند وجود عدة أنماط في الصفحة، كما تستورد ملفات جافاسكربت المستخدَمة في الصفحة. نلاحظ أننا أزحنا الوسوم في المثال أعلاه، لكن ذلك لا يؤثر على تنفيذ الشيفرة، وهو لتحسين قراءة الشيفرة وإظهار الهيكل الشجري المتشعب للمستند لا أكثر، ولا فرق بالنسبة للمتصفح سواء أزيحت الشيفرة أم لا، وقسم head غير إلزامي عند كتابة مستندات HTML نظريًا، لكن وجوده يرجع إلى حاجة أغلب المتصفحات الحديثة للمعلومات التي فيه. الوسم title: يحتوي هذا الوسم على عنوان الصفحة الذي سيعرضه المتصفح، وهو الجزء الوحيد المعروض من قسم الترويسة، رغم تأثير الأنماط وجافاسكربت في المظهر العام لمحتوى الصفحة الرئيسية. الوسم body: يغلف هذا الوسم المحتوى الأساسي للصفحة، والذي نراه في نافذة المتصفح. هذه هي العناصر الأساسية لصفحة الويب، وقد استخدمنا الوسم <h1> الذي يحتوي رسالة "Hello World"، وهو جزء من مجموعة عناصر h -التي تشير إلى كلمة ترويسة header- وتُرقَّم من 1 إلى 6 لتوضح ترتيب عناوين الفقرات، ويصغر حجم الخط المستخدم ومظهره كلما اقتربنا من العنوان السادس، رغم إمكانية تعديل ذلك باستخدام CSS. نحفظ شيفرة HTML في مستند باسم index.htm في مجلد باسم hello، ونتحقق من عمله بتحميله في متصفح ويب، فإذا عرض المتصفح الصفحة كما نريدها فنكون قد نجحنا في هذه المهمة البسيطة، وننتقل الآن إلى توفيره من خلال خادم الويب الخاص بنا. تشغيل خادم الويب يوجد خادم الويب الخاص ببايثون في وحدة http.server، ويمكن تشغيله دون أي تعديلات من خلال سطر أوامر نظام التشغيل، بتغيير المجلد العامل إلى مجلد hello الذي أنشأناه قبل قليل، كما يلي: $ python -m http.server --cgi 8000 يحدد الخيار ‎-m في الشيفرة أعلاه الوحدة التي يجب أن تشغلها بايثون، أما الراية ‎--cgi فتفعّل عمليات واجهة CGI التي سنحتاج إليها لاحقًا، ويشير العدد 8000 إلى منفذ الشبكة الذي ستستخدمه. تحميل صفحة الويب نستطيع الآن الوصول إلى الخادم من خلال تحميل الرابط التالي في شريط عنوان المتصفح: http://localhost:8000 إذا كان الخادم يعمل فستحمَّل تلك الصفحة وتُعرض كما فعلنا من قبل، إلا أنها الآن تُرسَل من قبل الخادم، كما يتضح من شريط العنوان في المتصفح، وبهذا نكون قد أرسلنا أول صفحة ويب لنا! والسبب الذي يجعل هذه العملية ناجحةً دون تحديد اسم الملف هو أن خوادم الويب تبحث عن ملف باسم index.htm تلقائيًا، فإذا كان موجودًا ولم نحدّد ملفًا مسبقًا فسيُعرض index.htm. كما يمكن إعداد الخادم ليبحث عن ملفات افتراضية أخرى، مثل index.html أو index.php. استخدام واجهة CGI لعرض رسالة ترحيب بالمستخدم نريد الآن أن نوسع صفحة الويب السابقة لتلتقط اسم المستخدم وترسله إلى الخادم، الذي يرد بإرسال رسالة ترحيب مخصصة باسم المستخدم. إنشاء استمارة HTML الخطوة الأولى لذلك هي تعديل ملف HTML ليتضمن حقل إدخال لاسم المستخدم، كما يلي: <!doctype html> <html> <head> <title>Hello user page</title> </head> <body> <h1>Hello, welcome to our website!</h1> <form name="hello" method="get" action="http://localhost:8000/cgi-bin/sayhello.py"> <p>Please tell us your name:</p> <input type="text" id="username" name="username" size="30" required autofocus/> <input type="submit" value="Submit" /> </form> </body> </html> نلاحظ هنا أن عناصر <form> تحتوي على خاصيات في وسومها، حيث تشكل الخاصية name جزءًا من البيانات المرسَلة إلى الخادم مع القيمة التي في صندوق الإدخال النصي، وتخبر الخاصية method الخاصة بوسم form المتصفح نوع رسالة http التي يجب إرسالها -وهي GET في هذه الحالة-، كما تخبره الخاصية action بالمكان الذي يجب أن يرسلها إليه. تخبر خاصيتا العنصر input الأخيرتان المتصفح ألا يرسل الاستمارة إلا إذا احتوى الحقل النصي على قيمة، وأن يضع المؤشر في ذلك الحقل ليكون مستعدًا لاستقبال الإدخال، كما تخبر القيمة submit الموجودة في نوع الإدخال type المتصفح أن يعرض هذا العنصر مثل زر تظهر عليه الكلمة الموجودة في قيمة الخاصية value -والتي هي submit أيضًا-، وسيرسل ذلك الزر الاستمارة عند الضغط عليه إلى الخاصية action الخاصة بالاستمارة. نحفظ هذا في نفس المجلد كما فعلنا من قبل، لكن نستدعي hello.htm في هذه المرة، ونتحقق من صحة عملها بكتابة ما يلي في شريط العنوان: http://localhost:8000/hello.htm ينبغي أن نرى رسالةً فيها حقل إدخال نصي يطلب منا إدخال الاسم مع زر تحته، إلا أنه لن يحدث شيء عند ضغطنا على الزر لأننا لم نكتب أي شيفرة تعالج تلك النقرة على الخادم، لذا نحتاج إلى إنشاء برنامج CGI يُستدعى عند إرسال الاستمارة إلى الخادم بالضغط على الزر. كتابة شيفرة CGI يشبه برنامج CGI برامج بايثون التي كتبناها من قبل، باستثناء أمرين هما: برنامج CGI يستورد وحدة CGI. يوجد في مجلد باسم cgi-bin، في جذر خادم الويب، ويكون هذا البرنامج تنفيذيًا executable، لنحقق الأمر الثاني ننشئ مجلد cgi-bin داخل مجلد html، ثم ننشئ ملفًا داخل ذلك المجلد الجديد ونسميه sayhello.py يحتوي على الشيفرة التالية: #!/usr/bin/env python3 import cgi # استخرج حقول البيانات data = cgi.FieldStorage() username = data["username"].value # \n\n الإجبارية مع اللاحقة http أرسل ترويسة: print("ContentType: text/html\n\n") # HTML والآن، أرسل محتوى print("<!doctype html>\n<html><head>") print("<title>Hello %s</title></head>" % username) print(''' <body> <h1>Welcome %s</h1> </body> </html>''' % username) تنفَّذ العمليات الخاصة بالبيانات داخل استدعاء FieldStorage، حيث تجمع وحدة cgi جميع البيانات من طلب http، وتضعها في قاموس لنستطيع الوصول إليها بسهولة باستخدام مفاتيح نصية هي خاصيات name من الاستمارة الخاصة بنا. نلاحظ كيف تمكننا علامات الاقتباس الثلاثية الخاصة ببايثون من هيكلة الخرج في HTML بصورة يمكن قراءتها -انظر قسم head و body. بعد أن نحفظ الصفحة، نتأكد من تغيير الصلاحيات ليكون الملف قابلًا للتنفيذ من جميع المستخدمين، فإذا أعدنا تحميل صفحة hello.htm، وملأنا الاستمارة فسنحصل على رسالة ترحيب من الخادم عند الضغط على الزر. تصلح هذه التقنية لمثل هذه التطبيقات البسيطة، وتمتاز بشفافية الخطوات، ومن ثم سهولة تصحيحها، غير أنه مع زيادة حجم المواقع وتعقيد البيانات لا تكون واجهة CGI مناسبةً للعمل معها، وهنا يأتي دور أطر عمل الويب frameworks، والتي سننظر فيها في المقال التالي. خاتمة نأمل في نهاية هذا المقال أن تكون تعلمت ما يلي: تُنشأ الطلبات إلى خوادم الويب باستخدام طلبات http GET. يرد خادم الويب بمستند HTML. تُمرَّر البيانات في رابط الطلب أو متغيرات البيئة. تعالج وحدة CGI البروتوكول الأساسي. تُجلب بيانات الاستمارة من خلال قاموس FieldStorage. واجهة CGI مناسبة لاستمارات الويب البسيطة، مثل شاشات تسجيل الدخول، إلا أنها لا تناسب التطبيقات الكبيرة. ترجمة -بتصرف- للفصل الثلاثين: Writing Web Applications من كتاب Learn To Program لصاحبه Alan Gauld. اقرأ أيضًا المقال التالي: استخدام أطر العمل في برمجة تطبيقات الويب: فلاسك نموذجا المقال السابق: برمجة عملاء ويب باستخدام بايثون أساسيات بناء تطبيقات الويب في ريآكت كيف تكتب أول برنامج لك في بايثون 3 البرمجة بلغة بايثون
  17. تعلمنا في الأجزاء السابقة من هذه السلسلة كيفية إنشاء مدونة وإضافة التدوينات وعرضها وحذف كل تدوينة والتعديل عليها وكذلك إضافة استيثاق جوجل وأضفنا صلاحيات للمستخدمين للوصول للمدونة، أما هذه المرة سنكمل ما بقي عمل على المدونة ونضيف اللمسات النهائية عليها مثل إضافة الملف الشخصي لكل كاتب ونشر التعليقات ومشاركة التدوينات على الشبكات الاجتماعية وغيرها ثم سننشر المدونة التي طورناها محليًا على الإنترنت باستعمال Firebase. هذا المقال جزء من سلسلة عن بناء مدونة باستخدام إطار العمل Angular وقاعدة بيانات Firestore مقدمة في بناء تطبيقات الويب باستخدام إطار العمل Angular وقاعدة بيانات Firestore بناء مدونة باستخدام إطار العمل Angular وقاعدة بيانات Firestore - إضافة التدوينات وعرضها بناء مدونة باستخدام إطار العمل Angular وقاعدة بيانات Firestore - تعديل التدوينات بناء مدونة باستخدام إطار العمل Angular وقاعدة بيانات Firestore - إضافة الاستثيثاق نشر مدونة مبنية عبر Angular على Firebase إضافة الملف الشخصي للكاتب سنعرض الملف الشخصي للكاتب على الصفحة الرئيسية، فنفِّذ الأمر التالي لإنشاء مكون author-profile: ng g c components/author-profile سنعرض صورة للكاتب مع روابط لحساباته الاجتماعية، وستأتي الصورة من التطبيق نفسه، ونضعها داخل مجلد src/assets. افتح الملف component.html وضع الشيفرة التالية فيه: <mat-card class="rightpanel-card mat-elevation-z2"> <mat-card-content> <h4 class="rightdivtext"> Author </h4> </mat-card-content> <mat-card-content> <div class="authorimagecontainer"> <img class="authorimage" mat-card-avatar src="../../../assets/ankit-sharma.jpg"> <h5>Ankit Sharma</h5> </div> </mat-card-content> <mat-divider></mat-divider> <mat-card-content> <h4 class="rightdivtext"> Follow Me </h4> </mat-card-content> <mat-card-content> <a href="https://www.facebook.com/Ankit.Sharma.0709" target="_blank"><i class="fa fa-facebook-square" aria-hidden="true"></i></a> <a href="https://twitter.com/ankitsharma_007" target="_blank"><i class="fa fa-twitter-square" aria-hidden="true"></i></a> <a href="https://www.linkedin.com/in/ankitsharma-007/" target="_blank"><i class="fa fa-linkedin-square" aria-hidden="true"></i></a> <a href="https://github.com/AnkitSharma-007" target="_blank"><i class="fa fa-github-square" aria-hidden="true"></i></a> </mat-card-content> </mat-card> افتح الملف component.scss وضع تعريفات التنسيق التالية فيه: .fa-twitter-square { color: #55acee; } .fa-facebook-square { color: #3b5998; } .fa-linkedin-square { color: #0976b4; } .fa-github-square { color: #333; } .fa { font-size: 3em; width: 1em; margin-top: 5px; cursor: pointer; } .mat-card-avatar { width: 100px; height: 100px; margin: auto padding: 5px; } .authorimagecontainer { text-align: center; } .rightdivtext { color: #636467; text-transform: uppercase; padding: 2px; } .rightpanel-card { margin-bottom: 15px; } إذا أردنا عرض الملف الشخصي للكاتب على الصفحة الرئيسية، نحتاج إلى إضافة AuthorProfileComponent إلى HomeComponent. افتح الملف home.component.html وحدِّث المحتوى الموجود فيه كما يلي: <div class="row left-panel"> <div class="col-md-9"> <app-blog-card></app-blog-card> </div> <div class="col-md-3"> <app-author-profile></app-author-profile> </div> </div> افتح المتصفح لترى الملف الشخصي للكاتب على الجانب الأيمن من الصفحة الرئيسية، وسيعرض الملف الشخصي صورة الكاتب مع روابط حساباته الاجتماعية: إضافة خيار تمرير إلى أعلى صفحة التدوينة سنضيف خيارًا للتمرير إلى أعلى صفحة التدوينة عندما يمرر المستخدم الصفحة إلى الأسفل، بحيث يعرض زر Scroll To top، وإذا نقر المستخدم عليه ينقله إلى أعلى الصفحة بتأثير انتقال ناعم وسلس. نفّذ الأمر التالي لإنشاء مكون التمرير: ng g c components/Scroller افتح الملف component.ts واستبدل الشيفرة التالية بالموجودة فيه: import { Component, HostListener } from '@angular/core'; @Component({ selector: 'app-scroller', templateUrl: './scroller.component.html', styleUrls: ['./scroller.component.scss'] }) export class ScrollerComponent { showScroller: boolean; showScrollerPosition = 100; @HostListener('window:scroll') checkScroll() { const scrollPosition = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0; if (scrollPosition >= this.showScrollerPosition) { this.showScroller = true; } else { this.showScroller = false; } } gotoTop() { window.scroll({ top: 0, left: 0, behavior: 'smooth' }); } } سنعيِّن قيمة المتغير showScrollerPosition لتكون 100، وهي تمثل عدد البكسلات التي يكون الممرِّر مرئيًا بعدها، وسيراقب التابع checkScroll أحداث التمرير باستخدام المزخرِف ‎@HostListener، ونحسب موضع التمرير الحالي للصفحة، فإن كان أكبر من showScrollerPosition فإننا نعرض زر التمرير إلى الأعلى على الصفحة، ويعيّن التابع gotoTop سلوك الممرِّر، بحيث يمرِّر الصفحة إلى الأعلى بتأثير ناعم. افتح الملف scroller.component.html واستبدل الشيفرة التالية بالموجود فيه: <div *ngIf="showScroller" (click)="gotoTop()" class="scroll-to-top"><i class="fa fa-angle-up"></i></div> افتح الملف scroller.component.scss وضع الشيفرة التالية فيه: .scroll-to-top { display: block; background: rgba(100, 100, 100, 0.4); color: #ffffff; bottom: 4%; cursor: pointer; position: fixed; right: 20px; z-index: 999; font-size: 24px; text-align: center; width: 45px; height: 45px; border-radius: 50%; .fa { font-weight: 900; } } .scroll-to-top:hover { background-color: #b2b2b2; } سنضيف الآن ScrollerComponent إلى BlogComponent، فافتح الملف blog.component.html وأضف السطر التالي في نهاية الملف: <app-scroller></app-scroller> وهكذا نكون قد أنشأنا ممرِّرًا لصفحة التدوينة بنجاح، وسنرى في القسم التالي عرضًا لذلك الممرِّر مع خاصية التعليقات. نشر التعليقات على التدوينة نضيف الآن خاصية أخرى إلى التدوينات، وهي إمكانية نشر التعليقات على كل تدوينة، بحيث يستطيع أي مستخدم سجل دخوله أن يعلِّق على التدوينات الموجودة، ويكون للمستخدم المدير صلاحية حذف أي تعليق. كذلك تُحذف التعليقات على تدوينة ما بمجرد حذف التدوينة نفسها. إنشاء نموذج التعليق أنشئ الملف comment.ts وضع الشيفرة التالية فيه: export class Comments { commentId: string; blogId: string; email: string; commentedBy: string; content: string; commentDate: any; } إنشاء خدمة التعليقات سننشئ خدمة تتولى معالجة العمليات المتعلقة بقاعدة البيانات فيما يخص التعليقات، فنفّذ الأمر التالي لإنشاء هذه الخدمة: ng g s services/Comment افتح الملف comment.service.ts وأضف تعليمات الاستيراد التالية في أعلاه: import { AngularFirestore } from '@angular/fire/firestore'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { Comments } from '../models/comment' والآن، أضف تعريفات التوابع التالية داخل الصنف CommentService: export class CommentService { constructor(private db: AngularFirestore) { } saveComment(comment: Comments) { const commentData = JSON.parse(JSON.stringify(comment)); return this.db.collection('comments').add(commentData); } getAllCommentsForBlog(blogId: string): Observable<Comments[]> { const comments = this.db.collection<Comments>('comments', ref => ref.where('blogId', '==', blogId).orderBy('commentDate', 'desc')).snapshotChanges().pipe( map(actions => { return actions.map( c => ({ commentId: c.payload.doc.id, ...c.payload.doc.data() })); })); return comments; } deleteAllCommentForBlog(blogId: string) { const commentsToDelete = this.db.collection('comments', ref => ref.where('blogId', '==', blogId)).snapshotChanges(); commentsToDelete.forEach( commentList => { commentList.forEach(comment => { this.db.doc('comments/' + comment.payload.doc.id).delete(); }); } ); } deleteSingleComment(commentId: string) { return this.db.doc('comments/' + commentId).delete(); } } سيقبل التابع saveComment كائنًا من النوع Comments كمعامِل، وسنحلل المعامِل إلى كائن JSON ونضيفه إلى تجميعة comments في قاعدة بياناتنا، فإذا كانت التجميعة موجودة مسبقًا فسيضاف كائن JSON إليها، أما إذا لم تكن موجودة في قاعدة البيانات فسينشئ تابع الإضافة تجميعة ويضيف الكائن الجديد إليها. سيقبل التابع getAllCommentsForBlog معرِّف التدوينة كمعامِل، وسيستعلم هذا التابع في تجميعة comments ويعيد قائمة بجميع التعليقات المتوافقة مع معرِّف التدوينة الممرر إليه. ويرتب commentDate قائمة التعليقات تنازليًا وفق التاريخ، لضمان عرض التعليق الأخير في قمة التعليقات. يقبل التابع deleteAllCommentForBlog معرِّف التدوينة كمعامِل له، ويحذف جميع التعليقات من تجميعة comments وفقًا لمعرِّف التدوينة الممرر إليه، أما التابع deleteSingleComment فسيأخذ معرِّف التعليق كمعامِل له، ويحذف تعليقًا واحدًا من تجميعة comments وفقًا لمعرِّف التعليق الذي مُرِّر إليه. إنشاء مكون التعليق نفِّذ الأمر التالي لإنشاء مكون التعليقات الذي يعالج التعليقات التي ينشرها المستخدم: ng g c components/Comments افتح الملف comments.component.ts وأضف تعليمات الاستيراد التالية في أعلاه: import { Input, OnDestroy } from '@angular/core'; import { DatePipe } from '@angular/common'; import { AppUser } from 'src/app/models/appuser'; import { Comments } from 'src/app/models/comment'; import { CommentService } from 'src/app/services/comment.service'; import { AuthService } from 'src/app/services/auth.service'; import { SnackbarService } from 'src/app/services/snackbar.service'; import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; أضف مزود DataPipe في قسم مزخرِف ‎@component كما يلي: @Component({ ... providers: [DatePipe] } سنحدِّث الآن صنف CommentsComponent كما يلي: export class CommentsComponent implements OnInit, OnDestroy { @Input() blogId; appUser: AppUser; public comments = new Comments(); commentList: Comments[] = []; private unsubscribe$ = new Subject<void>(); constructor(private datePipe: DatePipe, private commentService: CommentService, private authService: AuthService, private snackBarService: SnackbarService) { } } سيقبل هذا المكون معرِّف التدوينة blogId كمُدخَل له، وسنحقن الخدمات في منشئ الصنف، والآن، أضف تعريفات التوابع التالية داخل الصنف CommentsComponent: ngOnInit() { this.authService.appUser$.subscribe(appUser => this.appUser = appUser); this.getAllComments(); } onCommentPost(commentForm) { this.comments.commentDate = this.datePipe.transform(Date.now(), 'MMdd-yyyy HH:mm:ss'); this.comments.blogId = this.blogId; this.commentService.saveComment(this.comments).then( commentForm.resetForm() ); } getAllComments() { this.commentService.getAllCommentsForBlog(this.blogId) .pipe(takeUntil(this.unsubscribe$)) .subscribe(result => { this.commentList = result; }); } deleteComment(commentId) { if (confirm('Do you want to delete this comment!!!')) { this.commentService.deleteSingleComment(commentId).then( () => { this.snackBarService.showSnackBar('Comment Deleted successfully'); } ); } } login() { this.authService.login(); } ngOnDestroy() { this.unsubscribe$.next(); this.unsubscribe$.complete(); } سنعيّن commentDate داخل التابع onCommentPost ليكون التاريخ الحالي، ونعيّن خاصية blogId الخاصة بكائن التعليق لتكون معرِّف التدوينة التي نُشر عليها التعليق، وسنستدعي التابع saveComment الخاص بالخدمة CommentService ليخزن التعليق في قاعدة البيانات. كذلك فإن التابع getAllComments سيستدعي getAllCommentsForBlog من الخدمة CommentService ويستخدم blogId كمعامِل، وسيجلب هذا التابع قائمة التعليقات المنشورة على التدوينة. سيسمح التابع deleteComment لنا بحذف تعليق بعينه، وسيعرض صندوق تأكيد يستدعي التابع deleteSingleComment من الخدمة CommentService إذا أكد المستخدم خيار حذف ذلك التعليق. أما التابع login فسيسمح للمستخدم أن يسجل الدخول إلى التطبيق باستخدام حساب جوجل. افتح الملف comments.component.html واستبدل الشيفرة التالية بالموجودة فيه: <ng-template #anonymousUser> <mat-card class="comment-card mat-elevation-z2"> <a (click)="login()">Login with Google</a> to post comments </mat-card> </ng-template> <mat-card *ngIf="appUser; else anonymousUser" class="comment-card matelevation-z2"> <mat-card-title> LEAVE A REPLY </mat-card-title> <mat-card-subtitle> Your email address will not be published. Required fields are marked * </mat-card-subtitle> <mat-card-content> <form #commentForm="ngForm" (ngSubmit)="commentForm.form.valid && onCommentPost(commentForm)" novalidate> <mat-form-field class="full-width"> <input matInput placeholder="Name" name="commentedBy" [(ngModel)]="comments.commentedBy" #commentedBy="ngModel" required> <mat-error *ngIf="commentForm.submitted && commentedBy.errors?.required">Name is required</mat-error> </mat-form-field> <mat-form-field class="full-width"> <input matInput placeholder="Email" name="email" [(ngModel)]="comments.email" #email="ngModel" email required> <mat-error *ngIf="commentForm.submitted && email.errors?.required">Email is required</mat-error> <mat-error *ngIf="commentForm.submitted && email.errors?.email">Invalid email</mat-error> </mat-form-field> <mat-form-field class="full-width"> <textarea matInput placeholder="Comment" name="content" [(ngModel)]="comments.content" #content="ngModel" required></textarea> <mat-error *ngIf="commentForm.submitted && content.errors?.required">Comment is required</mat-error> </mat-form-field> <mat-card-actions> <button type=" submit" mat-raised-button color="primary">Post Comment</button> </mat-card-actions> </form> </mat-card-content> </mat-card> <mat-card *ngFor="let comment of commentList" class="comment-card matelevation-z2"> <mat-card-title> <div class="comment-card-title"> <div> {{comment.commentedBy}} </div> <div *ngIf="appUser?.isAdmin"> <button mat-icon-button matTooltip="Delete comment" matTooltipPosition="before" color="accent" (click)="deleteComment(comment.commentId)"> <mat-icon>delete</mat-icon> </button> </div> </div> </mat-card-title> <mat-card-subtitle>{{comment.commentDate | date:'medium'}}</matcard-subtitle> <mat-card-content> <p>{{comment.content}}</p> </mat-card-content> </mat-card> تتاح ميزة نشر التعليقات على التدوينة للمستخدمين الذين سجلوا دخولهم فقط، فإذا لم يكن المستخدم مسجلًا دخوله فنعرض رابط Login with Google لنطلب من المستخدم أن يسجل دخوله بحساب جوجل كي يترك تعليقًا. ونحن نستخدم استمارة قالبية template-driven لالتقاط تعليقات المستخدم، وهي تستدعي التابع onCommentPost عند الإرسال الناجح، وستحتوي الاستمارة على الحقول الثلاثة التالية: Name: هذا الحقل إجباري ويُستخدم لالتقاط اسم الشخص الذي ينشر التعليق. Email: هذا الحقل إجباري ويُستخدم لالتقاط بريد الشخص الذي ينشر التعليق. Comment: هذا الحقل إجباري أيضًا ويُستخدم لالتقاط نص التعليق. سنعرض التعليقات المنشورة على التدوينة في تخطيط بطاقة باستخدام العنصر <mat-card>، وسنعرض اسم الشخص الذي ينشر التعليق وتاريخ ذلك النشر ونص التعليق نفسه، وتُعرض قائمة التعليقات أسفل استمارة التعليق مباشرة. أما إذا كان المستخدم له صلاحية المدير فسنعرض أيقونة حذف في كل تعليق لتمكينه من حذف التعليق. افتح الملف comments.component.scss وانسخ الشيفرة التالية فيه: a:not([href]):not([tabindex]) { text-decoration: underline; cursor: pointer; color: #1565C0; } .comment-card-title{ display: flex; justify-content: space-between; } .comment-card { margin: 10px 0 15px 0; } .full-width { width: 100%; } سنضيف الآن المكون CommentsComponent إلى BlogComponent، فافتح الملف blog.component.html وأضف الشيفرة التالية في نهاية الملف، مباشرة قبل السطر الذي أضفنا فيه مكون الممرِّر من قبل ScrollerComponent: <mat-divider></mat-divider> <app-comments [blogId]="postId"></app-comments> تحديث مكون قائمة التدوينات سنضيف الآن خاصية حذف جميع التعليقات المرتبطة بتدوينة عند حذف تلك التدوينة، فافتح الملف blogcard.component.ts وأضف تعريفات الاستيراد الخاصة بالخدمة CommentService، وسنحقن الخدمة في المنشئ: import { CommentService } from 'src/app/services/comment.service'; ... constructor( // حقن خدمة private commentService: CommentService) { } نحدِّث الآن تابع الحذف داخل صنف BlogCardComponent، ونستدعي التابع deleteAllCommentForBlog المعرَّف في CommentService، فأضف سطر الشيفرة التالي داخل كتلة التابع delete، مباشرة قبل استدعاء التابع showSnackBar، وذلك لضمان أن جميع التعليقات المرتبطة بتدوينة تُحذف عند حذف التدوينة نفسها. this.commentService.deleteAllCommentForBlog(postId); إنشاء فهرس في قاعدة بيانات Firebase إذا فتحنا المتصفح الآن وانتقلنا إلى صفحة تفاصيل التدوينة سنحصل على خطأ في طرفية المتصفح يقول "ERROR FirebaseError: The query requires an index": بما أننا نستخدم شرط where مع معامل تساوي داخل التابع getAllCommentsForBlog، فنحتاج إلى إنشاء فهرس في قاعدة بياناتنا، وهذا الفهرس ضروري كي يعمل استعلامنا، ونستطيع أن نرى أن رسالة الخطأ توفر رابطًا لإنشاء الفهرس كذلك، فإذا نقرنا على ذلك الرابط سننتقل إلى طرفية firebase، كما نرى في لقطة الشاشة التالية: هنا نرى نافذة Create a composite index على الشاشة مع إعدادات الفهرس، فانقر على زر Create index لإنشاء الفهرس، وسيستغرق ذلك بضع دقائق لبنائه، ثم بمجرد تمام إنشائه تتغير حالة الفهرس إلى Enabled: اختبار التعليقات افتح المتصفح وسجل الخروج من التطبيق إذا كنت قد سجلت الدخول إليه، وانتقل إلى صفحة أي تدوينة، ثم مرر إلى أسفل الصفحة، يجب أن ترى زر scroll to top على الجانب الأيمن من الصفحة، فإذا نقرت على ذلك الزر ستعود الصفحة إلى الأعلى بتأثير انتقال ناعم، انظر الصورة أدناه: كذلك تستطيع أن ترى رسالة تطلب منك تسجيل الدخول بحساب جوجل لتتمكن من نشر التعليقات، فسجل الدخول به لترى نموذج نشر التعليق. اكتب تفاصيل التعليق واضغط على زر Post Comment ليُنشر التعليق ويُعرض في بطاقة تحت النموذج مباشرة. ستعرض بطاقة التعليق اسم الشخص الذي كتبه مع تاريخ ووقت نشر التعليق، فإذا سجلت الدخول كمستخدم مدير فسترى كذلك زر Delete Comment في الجانب العلوي الأيمن من بطاقة التعليق. إضافة خيار مشاركة للتدوينة سنضيف الآن خاصية مشاركة التدوينة بحيث نوفر خيار المشاركة من خلال الشبكات الاجتماعية والبريد الإلكتروني، ونستخدم لذلك مكتبة ngx-sharebuttons لإضافة خيار النشر، وهي مكتبة مفتوحة المصدر تزودنا بحل جاهز لإضافة أزرار النشر وأيقوناته لأغلب منصات الرسائل والشبكات الاجتماعية. تثبيت ngx-sharebuttons نفذ الأمر التالي لتثبيت حزم ngx-share: npm i -S @ngx-share/core @ngx-share/button @ngx-share/buttons @angular/cdk كما سنثبت حزم الأيقونات باستخدام الأمر التالي: npm i -S @fortawesome/fontawesome-svg-core @fortawesome/angularfontawesome @fortawesome/free-solid-svg-icons @fortawesome/free-brandssvg-icons استورد السمة الخاصة بأزرار المشاركة إلى التنسيق العام في الملف app/src/style.scss: @import '~@ngx-share/button/themes/circles/circles-dark-theme'; كذلك، استورد كلًا من ShareButtonsModule و ShareButtonsConfig و HttpClientModule إلى الملف src/app/app.module.ts. سننشئ إعدادات خاصة للوحدة ShareButtonsModule كما يظهر في الشيفرة التالية: import { ShareButtonsConfig, ShareModule } from '@ngx-share/core'; import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; import { HttpClientModule } from '@angular/common/http'; const customConfig: ShareButtonsConfig = { twitterAccount: 'ankitsharma_007' }; @NgModule({ ... imports: [ ... HttpClientModule, FontAwesomeModule, ShareModule.withConfig(customConfig), ], }) سنعيِّن اسم حساب تويتر twitterAccount الخاص بكاتب التدوينة في الإعدادات المخصصة، وذلك لضمان الإشارة إلى ذلك الحساب في كل مرة ننشر فيها تدوينة على موقع تويتر. إنشاء مكون social-share نفذ الأمر التالي لإنشاء مكون social-share: ng g c components\social-share افتح الملف social-share.component.html وضع الشيفرة التالية فيه: <p><strong>Found this article helpful!!! Share this with your Friends</strong></p> <button mat-fab shareButton="facebook" [style.backgroundColor]="share.prop.facebook.color"> <fa-icon [icon]="share.prop.facebook.icon" size="lg"></fa-icon> </button> <button mat-fab shareButton="twitter" [style.backgroundColor]="share.prop.twitter.color"> <fa-icon [icon]="share.prop.twitter.icon" size="lg"></fa-icon> </button> <button mat-fab shareButton="linkedin" [style.backgroundColor]="share.prop.linkedin.color"> <fa-icon [icon]="share.prop.linkedin.icon" size="lg"></fa-icon> </button> <button mat-fab shareButton="reddit" [style.backgroundColor]="share.prop.reddit.color"> <fa-icon [icon]="share.prop.reddit.icon" size="lg"></fa-icon> </button> <button mat-fab shareButton="whatsapp" [style.backgroundColor]="share.prop.whatsapp.color"> <fa-icon [icon]="share.prop.whatsapp.icon" size="lg"></fa-icon> </button> <button mat-fab shareButton="telegram" [style.backgroundColor]="share.prop.telegram.color"> <fa-icon [icon]="share.prop.telegram.icon" size="lg"></fa-icon> </button> <button mat-fab shareButton="print" [style.backgroundColor]="share.prop.print.color"> <fa-icon [icon]="share.prop.print.icon" size="lg"></fa-icon> </button> <button mat-fab shareButton="email" [style.backgroundColor]="share.prop.email.color"> <fa-icon [icon]="share.prop.email.icon" size="lg"></fa-icon> </button> سنضيف SocialShareComponent في BlogComponent، فافتح الملف blog.component.html وضع السطر التالي فيه، مباشرة قبل وسم <mat-divider>. <app-social-share></app-social-share> إعداد حزمة الأيقونات تستخدم مكتبة ngx-sharebuttons على المستوى الداخلي مكتبة FortAwesome/angularfontawesome لحزم أيقوناتها، لذا نحتاج إلى إعداد حزم أيقونات fontawesome في SocialShareComponent من أجل استخدام أيقوناتها لأزرار المشاركة. أنشئ ملفًا جديدًا باسم icons.ts داخل مجلد src، وضع فيه الشيفرة التالية: import { faTelegramPlane } from '@fortawesome/free-brands-svgicons/faTelegramPlane'; import { faFacebookF } from '@fortawesome/free-brands-svgicons/faFacebookF'; import { faTwitter } from '@fortawesome/free-brands-svgicons/faTwitter'; import { faRedditAlien } from '@fortawesome/free-brands-svgicons/faRedditAlien'; import { faLinkedinIn } from '@fortawesome/free-brands-svgicons/faLinkedinIn'; import { faWhatsapp } from '@fortawesome/free-brands-svgicons/faWhatsapp'; import { faPrint } from '@fortawesome/free-solid-svg-icons/faPrint'; import { faEnvelope } from '@fortawesome/free-solid-svgicons/faEnvelope'; export const iconpack = [ faFacebookF, faTwitter, faLinkedinIn, faRedditAlien, faTelegramPlane, faWhatsapp, faEnvelope, faPrint ]; لقد استوردنا جميع الأيقونات التي سنستخدمها في تطبيقنا من مكتبة fortawesome، وسنصدر تلك الحزمة الآن ليستخدمها المكون. افتح الملف social-share.component.ts وأضف تعليمة الاستيراد التالية في أعلاه: import { FaIconLibrary } from '@fortawesome/angular-fontawesome'; import { iconpack } from 'src/icons'; import { ShareService } from '@ngx-share/core'; حدِّث منشئ الصنف SocialShareComponent كما يلي: constructor(library: FaIconLibrary, public share: ShareService) { library.addIcons(...iconpack); } افتح الملف social-share.component.scss وأضف تعريفات التنسيق التالية: button{ margin: 5px; } اختبار أيقونات المشاركة افتح المتصفح وانتقل إلى صفحة أي تدوينة ومرِّر إلى الأسفل، سترى قائمة من أزرار النشر معروضة فيها، وستحصل على خيارات النشر التي أعددناها من قبل، انظر الصورة التالية: إذا نقرت على أي زر من أزرار النشر تلك فستفتح صفحة التطبيق الموافقة لها لتطلب منك تسجيل الدخول، وعند نجاح عملية تسجيل الدخول ستحصل على زر مشاركة للتدوينة، انظر الصورة التالية لترى خيار مشاركة تويتر. كما ترى فقد تمت الإشارة إلى حساب ‎@ankitsharma_007 (صاحب التدوينة) على تويتر، وخاصية الإشارة إلى الحساب تلك متاحة في تويتر فقط. نشر التطبيق على Firebase تتبقى آخر خطوة وهي نشر التطبيق على Firebase، من خلال الخطوات الموضحة أدناه: الخطوة الأولى، ثبّت أدوات firebase CLI من خلال npm، كما يلي: npm install -g firebase-tools الخطوة الثانية، شغّل الأمر التالي لبناء التطبيق بإعدادات الإنتاج: ng build --prod سيعين الخيار prod إعدادات البناء إلى هدف الإنتاج، وهو مُعد في إعدادات مساحة العمل بحيث تستفيد جميع عمليات البناء من الربط bundling، وعمليات الإزالة المحدودة للشيفرة الميتة Dead Code -وهي عملية تحذف الشيفرة التي لا تؤثر على نتيجة البرنامج-، وكذلك عمليات حت الأشجار المحدود tree shaking -وهو مصطلح في جافاسكربت لنفس مفهوم إزالة الشيفرة الميتة. الخطوة الثالثة، افتح نافذة الطرفية داخل مجلد ‎/blogsite/dist، وشغّل الأمر التالي لتسجيل الدخول إلى firebase: firebase login سيفتح ذلك نافذة متصفح تطلب تسجيل الدخول إلى firebase باستخدام حساب جوجل. بعد التسجيل، ارجع إلى الطرفية لتنفيذ الأمر التالي. الخطوة الرابعة، نفّذ الأمر التالي لتهيئة التطبيق: firebase init سيبدأ هذا الأمر مشروع firebase، وسيُطلب منك بضعة أسئلة، فأجب عليها كما يلي: Are you ready to proceed?‎ أدخل y ?Which Firebase CLI features do you want to set up for this folder اختر Hosting Please select an option اختر use an existing project Select a default Firebase project for this directory: اختر اسم مشروعك من القائمة. ?What do you want to use as your public directory اختر blogsite. ?Configure as a single-page app (rewrite all urls to /index.html) أدخل y ?File blogsite/index.html already exists. Overwrite أدخل N. ستحصل الآن على رسالة Firebase initialization complete. الخطوة الخامسة، انشر التطبيق على firebase، من خلال الأمر التالي: firebase deploy هذا الأمر سينشر التطبيق على Firebase، وسيعطيك رابط استضافة، فانتقل إليه لترى التطبيق منشورًا هناك، انظر الصورة التالية: كذلك تستطيع الوصول إلى رابط الاستضافة من لوحة تحكم firebase، فانتقل إلى صفحة Page Overview الخاصة بمشروع Firebase واختر Hosting من قائمة Develop. تستطيع رؤية أسماء النطاقات لتطبيق الويب الخاص بك على اليمين. خاتمة وهكذا نكون قد ختمنا في هذا الفصل عملية بناء مدونة متكاملة كتطبيق وحيد الصفحة باستخدام إطار العمل Angular للواجهة الأمامية، وقاعدة بيانات Firestore للواجهة الخلفية، وتصبح بإكمالك لكامل السلسلة قادرًا على بناء مدونتك الشخصية ونشرها على الإنترنت ومشاركة أصدقائك تدويناتك ويمكنك إضافة أي ميزات أو خصائص أخرى غير التي ذكرناها وهنا نترك الباب مفتوحًا لإبدعائك. ترجمة -وبتصرف- لفصول من كتاب Build a full stack web application using angular and firebase لصاحبه Ankit Sharma. اقرأ أيضًا بناء تطبيق ويب كامل باستخدام Angular ومنصة Firebase ما هي Angular؟ تهيئة بيئة تطبيقات Angular ونشرها على الويب
  18. سنغطي في هذا المقال من سلسلة تعلم البرمجة ما يلي: إرسال الطلبات إلى خادم الويب. إرسال البيانات إلى الخادم. معالجة HTML بواسطة html.parser. الخيارات الأخرى. برمجة عملاء الويب يمكن وصف برمجة عملاء الويب في تعريفين رئيسيين هما: استخدام جافاسكربت لتعديل محتوى صفحة الويب داخل المتصفح، بتغيير ألوان العناصر وتحريك اللوحات حولها، وإظهار العناصر أو إخفائها، وجلب أجزاء من البيانات الأولية من الخادم، مثل حالة البحث الحي live search مثلًا. وهي ليست معقدةً، لكنها تتطلب معرفةً عميقةً بكل من HTML و CSS، ومن ثم فهي خارج نطاق شرحنا، فإذا أردت معرفة المزيد عن مثل هذا النوع من برمجة عملاء الويب فانظر سلسلة مدخل إلى html5 مثلًا في أكاديمية حسوب، وكتاب نحو فهم أعمق لتقنيات HTML5، كما توجد عدة مكتبات وأطر عمل لجافاسكربت يجب البحث فيها وتعلمها، لعل أشهرها jQuery، والتي يمكن القراءة عنها في توثيق jQuery في موسوعة حسوب، وغيرها من السلاسل والمواد العلمية في الأكاديمية والموسوعة. إنشاء برنامج يعمل على حاسوب ويتصل بخادم ويب متظاهرًا بأنه برنامج متصفح ويب، حيث يجلب هذا البرنامج بعض البيانات للتحليل، وهو ما يسمى بالبوت bot -اختصار robot-، أو يتبع بعض الروابط من موقع لآخر بحثًا عن بيانات تتعلق بموضوع ما، وهو ما يسمى بعناكب الويب web spyders أو زاحفات الوب، وسندرس بعض هذه الأنواع من برامج عملاء الويب في هذا المقال. التعلم بالتطبيق سنخالف في هذا المقال النهج الذي كنا نتبعه في شرحنا، إذ سنستخدم مثالًا عمليًا لتوضيح كيفية كتابة برنامج عميل ويب، وسنبدأ ببساطة في البداية، ثم نضيف المزايا لإبراز بعض المشاكل المعقدة بالتدريج، لكنه سيظل برنامجًا بسيطًا للغاية عند تمامه، لكن القصد منه أن يعطيك فكرةً عما يمكن تنفيذه بمثل تلك البرامج. مهمة هذا التدريب هي بناء برنامج يولد صفحة ويب جديدةً، تحتوي على تجميعة من جميع محتويات قائمة "سنغطي في هذا المقال (What will we cover?‎)" ونحتاج إلى تنفيذ بضعة أمور لبناء ذلك البرنامج: قراءة محتوى HTML لملف الفهرس. تحليل محتويات الصفحة، واستخراج جميع الروابط الموجودة في الجزء الأيسر إلى قائمة. جلب محتوى HTML الخاص بكل رابط من روابط تلك القائمة. استخراج قائمة النقاط الموجودة في قسم "What will we cover" إلى قائمة جديدة. توليد صفحة HTML باستخدام البيانات التي جمعناها. جلب المحتوى رأينا سابقًا كيفية جلب صفحة HTML بسيطة من خادم باستخدام الوحدة urllib.request: import urllib.request as url site = url.urlopen('http://www.alan-g.me.uk/l2p2/index.htm') page = site.read() لدينا الآن سلسلة نصية تحتوي على شيفرة HTML الخاصة بالصفحة الرئيسية، أو صفحة المستوى الأعلى للنسخة الأجنبية من الفصول، وسنلاحظ صعوبة قراءة الخرج، لهذا نستخدم خيار عرض المصدر view source الموجود في المتصفح لننظر في شيفرة HTML، لنرى أن جدول المحتويات موجود في زوج من وسوم nav -اختصار للتنقل navigation- وأن كل قائمة من قوائم الفصول الموجودة في كل قسم تُجمع في قائمة غير مرتبة unordered list، تحمل الوسم ul، ونميز كل عنصر فيها بوجود وسم li فيه، وتمثل جميع عناصر القائمة روابط تشعبيةً إلى ملفات الفصول، لهذا نجدها محاطةً بوسم الرابط التشعبي <a>. مهمتنا التالية استخراج جميع عناصر <a> داخل لوحة nav من الصفحة. استخراج محتوى الوسوم ذكرنا في المقدمة أننا نستطيع استخدام عمليات البحث النصية البسيطة للعثور على الوسوم وغيرها في صفحات الويب، لكن يفضل استخدام محلل HTML مناسب، لذا سنستخدم الصنف HTMLParser الموجود في وحدة المكتبة القياسية html.parser، وهو محلل لغوي مجرَّد abstract، مدفوع بالأحداث أو حدَثي event-driven، ويجب أن نقسمه إلى أصناف فرعية subclasses لتوفير المزايا التي نريدها، مع ملاحظة أنه يستدعي تابعين، الأول هو handle_starttag()‎ عند كل وسم HTML افتتاحي، والثاني هو handle_endtag()‎ عند كل وسم إغلاق، ويجب أن نوفر النسخ الخاصة بنا من تلك التوابع لتنفذ الإجراءات المناسبة عند العثور على الوسوم التي نريدها، ونريد في حالتنا هذه أن نجد كل الروابط الموجودة في لوحة nav، لذا يجب تعيين راية flag نسميها in_nav في كل مرة نعثر فيها على وسم nav، فإذا وجدنا وسم a وكانت الراية True فسنحفظ خاصية href في قائمة، حيث تُمرَّر الخاصيات إلى التابع في صف tuple من ثنائيات المفتاح/القيمة، ونريد أخيرًا التقاط وسم الإغلاق ‎/nav، وإعادة تعيين الراية إلى False، لضمان أننا لا نجمع أي روابط من خارج لوحة المحتويات، وعليه سنعِدّ المحلل اللغوي، ونتأكد من قدرته على تعرّف الوسوم الثلاثة المطلوبة باستخدام تعليمات الطباعة كما يلي: import urllib.request as url import html.parser class LinkParser(html.parser.HTMLParser): def __init__(self): super().__init__() self.links = [] #list to store the links self.is_nav = False # the flag def handle_starttag(self, name, attributes): if name == 'nav': print("We found a <nav> tag") elif name == 'a': print("We found an <a> tag") def handle_endtag(self, name): if name == 'nav': print("We found a </nav> tag") site = url.urlopen('http://www.alan-g.me.uk/l2p2/index.htm') page = site.read().decode('utf8') # convert bytes to str parser = LinkParser() parser.feed(page) عند تشغيل الشيفرة السابقة ستجلب الصفحة، وتحللها، ثم تطبع الرسائل الموافقة لكل وسم تجده، وهي بهذا تثبت أن المحلل يعمل بكفاءة، وأننا بحاجة إلى راية is_nav لأن لدينا رابطًا خارج لوحة nav، نستطيع الآن أن نغير تعليمات الطباعة للشيفرة الحقيقية التي نريدها: import urllib.request as url import html.parser class LinkParser(html.parser.HTMLParser): def __init__(self): super().__init__() self.links = [] # قائمة لتخزين الروابط self.is_nav = False # الراية def handle_starttag(self, name, attributes): if name == 'nav': self.is_nav = True elif name == 'a' and self.is_nav: for key,val in attributes: if key == "href": self.links.append(val) def handle_endtag(self, name): if name == 'nav': self.is_nav = False site = url.urlopen('http://www.alan-g.me.uk/l2p2/index.htm') page = site.read().decode('utf8') # حوِّل سلسلة البايت إلى سلسلة نصية parser = LinkParser() parser.feed(page) print(parser.links) نلاحظ هنا أن التغييرات التي أجريناها كانت في التابعين handle_starttag()‎ وhandle_endtag()‎، إضافةً إلى السطر الأخير في الشيفرة print(parser.links)‎، ويجب أن تصبح النتيجة كما يلي: ['tutintro.htm', 'tutneeds.htm', 'tutwhat.htm', 'tutstart.htm', 'tutseq1.htm', 'tutdata.htm', 'tutseq2.htm', 'tutloops.htm', 'tutstyle.htm', 'tutinput.htm', 'tutbranch.htm', 'tutfunc.htm', 'tutfiles.htm', 'tuttext.htm', 'tuterrors.htm', 'tutname.htm', 'tutregex.htm', 'tutclass.htm', 'tutevent.htm', 'tutgui.htm', 'tutrecur.htm', 'tutfctnl.htm', 'tutcase.htm', 'tutpractice.htm', 'tutdbms.htm', 'tutos.htm', 'tutipc.htm', 'tutsocket.htm', 'tutweb.htm', 'tutwebc.htm', 'tutwebcgi.htm', 'tutflask.htm', 'tutrefs.htm'] استخراج النقاط من الفصول بعد أن حصلنا على قائمة الفصول نريد إنشاء دالة تستطيع استخراج النقاط التي في أول كل صفحة، لذا سنستخدم خاصية View Source الموجودة في المتصفح مرةً أخرى، إذ نفحص شيفرة HTML الخاصة بإطار الفصل، فنرى أننا ننظر في مجموعة من عناصر القائمة الموجودة داخل وسم div، مع تعيين الخاصية class على القيمة "todo"، وهذا يشبه تقريبًا ما فعلناه عند بحثنا عن الروابط، وسننشئ الآن دالةً تأخذ سلسلة HTML وتعيد قائمةً من سلاسل li، وسنضيف اسم الملف في الشيفرة ونثبته ليكون tutstart.htm. import urllib.request as url import html.parser class BulletParser(html.parser.HTMLParser): def __init__(self): super().__init__() self.in_todo = False self.is_bullet = False self.bullets = [] def handle_starttag(self, name, attributes): if name == 'div': for key, val in attributes: if key == 'class' and val == 'todo': self.in_todo = True elif name == 'li': if self.in_todo: self.is_bullet = True def handle_data(self, data): if self.is_bullet: self.bullets.append(data) self.is_bullet = False # أعد تعيين الراية def handle_endtag(self, name): if name == 'div': self.in_todo = False topic_url = "http://www.alan-g.me.uk/l2p2/tutstart.htm" def get_bullets(aTopic): site = url.urlopen(aTopic) topic = site.read().decode('utf8') topic_parser = BulletParser() topic_parser.feed(topic) return topic_parser.bullets print( get_bullets(topic_url) ) لاحظ أن لدينا تابع معالجة حدث إضافي سنعيد تعريفه، وهو handle_data()‎، لأننا نريد استخراج البيانات الموجودة في وسوم <li> بدلًا من الوسم نفسه أو خصائصه، وفيما عدا ذلك تشابه هذه الشيفرة المثال السابق، حيث نعين الراية in_todo لتوضيح متى نكون داخل صندوق المحتويات، وكذلك الراية is_bullet التي تشير إلى أننا وجدنا عنصر قائمة داخل الصندوق، ثم نعيد تعيين راية is_bullet بمجرد قراءتنا للبيانات، ونعيد تعيين is_todo عندما نترك الصندوق، أي عند ‎</div>‎. يمكن دمج البرنامجين معًا، بإضافة الصنف والدالة الجديدين إلى الملف السابق، ويتبقى أن نكتب حلقة for للتكرار على الروابط من المحلل الأول وإرسالها إلى دالة get_bullets()‎، ثم تُجمع النتائج في قاموس عام global dictionary مرتب وفق الفصول، كما سننظمها أكثر من خلال إنشاء دالة get_topics()‎ التي تشبه get_bullets()‎، يمكن أن نضيف شيئًا لمعالجة الأخطاء هنا، ونحوله إلى تنسيق وحدة في نفس الوقت، كما يلي: import urllib import urllib.request as url import html.parser ###### Link handling code #### class LinkParser(html.parser.HTMLParser): def __init__(self): super().__init__() self.links = [] #list to store the links self.is_nav = False # the flag def handle_starttag(self, name, attributes): if name == 'nav': self.is_nav = True elif name == 'a' and self.is_nav: for key,val in attributes: if key == "href": self.links.append(val) def handle_endtag(self, name): if name == 'nav': self.is_nav = False def get_topics(aSite): try: site = url.urlopen(aSite) page = site.read().decode('utf8') # convert bytestring to str link_parser = LinkParser() link_parser.feed(page) return link_parser.links except urllib.error.HTTPError: return [] ##### Bullet handling code class BulletParser(html.parser.HTMLParser): def __init__(self): super().__init__() self.in_todo = False self.is_bullet = False self.bullets = [] def handle_starttag(self, name, attributes): if name == 'div': for key, val in attributes: if key == 'class' and val == 'todo': self.in_todo = True elif name == 'li': if self.in_todo: self.is_bullet = True def handle_data(self, data): if self.is_bullet: self.bullets.append(data) self.is_bullet = False # reset the flag def handle_endtag(self, name): if name == 'div': self.in_todo = False def get_bullets(aTopic): try: site = url.urlopen(aTopic) topic = site.read().decode('utf8') topic_parser = BulletParser() topic_parser.feed(topic) return topic_parser.bullets except urllib.error.HTTPError: return [] #### driver code #### if __name__ == "__main__": summary = {} site_root = "http://www.alan-g.me.uk/l2p2/" the_topics = get_topics(site_root+'index.htm') for topic in the_topics: topic_url = site_root + topic summary[topic] = get_bullets(topic_url) print(summary['tutdata.htm']) لا زال بإمكاننا إجراء المزيد من التنظيم والترتيب، من خلال أخذ اثنين من أصناف المحلل والدوال المرتبطة بهما إلى وحدات منفصلة، لكن نترك هذا تدريبًا لك، لذا أنشئ الوحدتين linkparser.py و bulletparser.py، واستوردهما إلى الشيفرة المتبقية التي تستطيع حفظها باسم topic_summary.py، ويجب أن يبدو الملف الأخير أشبه بما يلي: import linkparser as LP import bulletparser as BP if __name__ == "__main__": summary = {} site_root = "http://www.alan-g.me.uk/l2p2/" the_topics = LP.get_topics(site_root+'index.htm') for topic in the_topics: topic_url = site_root + topic summary[topic] = BP.get_bullets(topic_url) print(summary['tutdata.htm']) إنشاء صفحة الملخص بقي لمشروعنا مهمة واحدة، وهي أخذ البيانات التي جمعناها وإنشاء صفحة ويب لعرضها فيها، وهي أكثر من مجرد إنشاء ملف بسيط ومعالجة نصوص، مثلما فعلنا في مثال القائمة الذي شرحناها في مقال التعامل مع الملفات في البرمجة، فالتعقيد الوحيد هنا هو الحاجة إلى استخدام وسوم HTML لتنسيق البيانات، والذي ننفذه بكتابة بعض ترويسات HTML الثابتة، ثم إنشاء حلقة تتكرر على بيانات الفصول لتطبع قائمةً من الفصول والنقاط bulletins، ثم نختم بوسم تذييل HTML ثابت أيضًا، ونغلق الملف، ثم نفتح الملف في المتصفح لرؤية الصفحة النهائية، كما يلي: import linkparser as LP import bulletparser as BP import time def create_summary(filename,data): with open(filename, 'w') as outf: # اكتب الترويسة outf.write('''<!Doctype htm> <html><body> <h1>Summary of tutor topics</h1> <dl>''') # اكتب اسم كل فصل... for topic in data: outf.write('<dt>%s</dt>' % topic) # ...and its bullets for bullet in data[topic]: outf.write("<dd>%s</dd>" % bullet) # اكتب التذييل outf.write(''' </dl> </body></html>''') if __name__ == "__main__": summary = {} site_root = "http://www.alan-g.me.uk/l2p2/" summary_file = './topic_summary.htm' the_topics = LP.get_topics(site_root+'index.htm') for topic in the_topics: topic_url = site_root + topic summary[topic] = BP.get_bullets(topic_url) time.sleep(1) # DOS تعطيل رؤية الخادم له على أنه هجمة create_summary(summary_file, summary) print('OK') يجب أن نحصل عند تشغيل الشيفرة على ملف اسمه topic_summary.htm نستطيع فتحه في المتصفح، ويجب أن يكون مثل هذه الصفحة. إرسال البيانات في الطلب نحتاج أحيانًا إلى تنفيذ أمور أكثر من مجرد جلب ملف ثابت من الخادم، فقد نرغب في تسجيل الدخول، ونحتاج إلى إرسال اسم المستخدم وكلمة المرور أو بيانات اعتماد أخرى، أو قد نستخدم وسيلة بحث لجلب بعض الروابط، وتوجد طريقتان لإرسال البيانات إلى الخادم وفقًا لنوع رسالة HTTP المتوقعة. رأينا من قبل أن HTTP تحتوي على العديد من الرسائل التي يمكن إرسالها، وقلنا إن أكثر تلك الرسائل استخدامًا هي GET وPOST، حيث ترسل GET جميع بياناتها في سطر العنوان، ونستطيع رؤية ذلك في المتصفح في صورة المحارف الغريبة التي تحتوي على الكثير من علامات الاستفهام وإشارات التساوي، فهي قيم البيانات التي في طلب GET. إرسال سلسلة بحث إلى GitHub تنقسم برمجة عملاء الويب web clients عمليًا إلى جزء علمي وفق قواعد معروفة مسبقًا ونتوقع نتائجها، وجزء يأتي بالتجربة والخطأ، ويمكن تعلم الكثير عن موقع ويب بزيارته من خلال متصفح ويب، وإلقاء نظرة متفحصة في كل من شريط العنوان ومصدر الصفحات، فإذا زرنا مستودع الشيفرات مفتوحة المصدر في GitHub مثلًا، وبحثنا عن كلمة "python" فسنرى أن عنوان الصفحة المعادة يكون أشبه بما يلي: https://github.com/search?utf8=%E2%9C%93&q=python&type= يشير الجزء utf8=%E2%9C%93 إلى محرف يونيكود -هو '- الذي يخبرنا أن البحث يستخدم UTF-8، ونستطيع تجاهل هذا التفصيل وكذلك type=‎ الفارغة في النهاية، ونرسل ما يلي: http://github.com/search?q=python وسنرى أنها تعطينا نفس النتيجة. نستطيع اكتشاف نوع هيكل HTML المُعاد من خلال عرض مصدر الصفحة، وخصائص العنصر element properties باستخدام أدوات الفحص الخاصة بالمتصفح inspection tools، ونستطيع إجراء البحث النصي لشاشة مصدر الصفحة في حالة GitHub ونحصل منه على أول نتيجة -والتي كانت geekcomputers/Python عند بحثنا-، والتي بدت كما يلي: <div class="repo-list-item d-flex flex-justify-start py-4 public source"> <div class="col-8 pr-3"> <h3> <a href="/geekcomputers/Python" class="v-align-middle">geekcomputers/<em>Python</em></a> </h3> ... نرى هنا كيفية استخراج الروابط، وصعوبته أكثر مما في مثال topic_summary.htm السابق. لا شك أن المشاكل لا حصر لها، وسنجد للمواقع آليات تمنع كل شيء -عدا المتصفحات- من الوصول إلى بياناتها، أو تستخدم تقنيات جافاسكربت متطورةً لعرض الصفحة، ولن تفلح تقنيات تحليل HTML البسيطة معها، لكن بنظرةً متفحصةً في تلك المواقع سنرى أنها توفر واجهة برمجة تطبيقات API يمكن استخدامها بديلًا، وهي أفضل من أدوات تحليل HTML، وقد يطلب الموقع مالًا لقاء رخصة استخدامها إن كان تجاريًا لأنها الطريقة التي يمول بها الموقع نفسه. وتوجد عدة مشاكل أخرى لا يتسع لها شرحنا، لكن نشير إلى أهمها والتي ينبغي البحث فيها، مثل معالجة محاولات تسجيل الدخول، واستخدام ملفات تعريف الارتباط cookies، ومعالجة اتصالات https المشفرة، فيمكن تنفيذ كل ذلك بقليل من الجهد، غير أنها خارج سياق شرحنا كما ذكرنا، ويمكن استخراج أغلب المعلومات من صفحة HTML باستخدام المحلل بدمج تباديل مختلفة من تلك التقنيات، إلا أننا قد نحصل على شيفرة HTML غير متقنة الكتابة أو التنسيق، وعندها سنحتاج إلى كتابة شيفرة خاصة لتصحيح الشيفرة، بل قد نضطر إلى كتابتها إلى ملف نصي واستخدام متحقق HTML خارجي -مثل HTMLtidy- لتصحيحها، إذا كان التشوه الحاصل فيها أكثر مما يمكن تعديله يدويًا، وذلك قبل أن نحللها، أو يمكن استخدام حزمة من طرف ثالث -مثل Beautiful Soup- التي تستطيع التعامل مع أغلب المشاكل الشائعة في HTML. اكتشاف رموز الخطأ يعيد الخادم أحيانًا أخطاءً بدلًا من صفحات الويب التي نتوقعها، ويجب أن نتمكن من التقاط تلك الأخطاء وقراءتها، والتي يعرضها المتصفح في صورة خطأ "Page Not Found" المشهور، أو صورة عبارات ألطف قليلًا، لكن إذا كنا نحن الذين نجلب البيانات بأنفسنا من الخادم فسنجد أن الخطأ يأتي في صورة رمز خطأ في ترويسة http، التي يحولها urllib.request إلى استثناء urllib.error.HTTPError، وبما أننا نعرف كيفية التقاط الاستثناءات باستخدام بنية try/except العادية، فنستطيع التقاط تلك الأخطاء بسهولة كما يلي: import urllib.request as url import urllib.error try: site = url.urlopen("http://some.nonexistent.address/foo.html") except urllib.error.HTTPError, e: print e.code تأتي القيمة الموجودة في urllib.error.HTTPError.code من أول سطر من رد HTTP الخاص بخادم الويب، مباشرةً قبل بداية الترويسات، مثل "HTTP/1.1 200 OK" أو "HTTP/1.1 404 Not Found"، ويتكون من رقم الخطأ، ويمكن الاطلاع على أشهر رموز الخطأ التي يعيدها خادم الويب في هذه الصفحة من موقع w3، وما يهمنا هي الأخطاء التي تبدأ بالرقم 4 أو 5، وأغلب تلك الأخطاء ستكون: 401: غير مصرح له Unauthorized. 404: الصفحة غير موجودة Page not found. 407: يُطلب توثيق الوكيل Proxy Authentication Required. 500: خطأ داخلي في الخادم Internal Server Error. 503: الخدمة غير متاحة Service Unavailable. 504: انتهت المهلة الزمنية للبوابة Gateway Timeout. قد يكون المطلوب في بعض تلك الأخطاء مثل -503 و504- مجرد إعادة المحاولة بعد بضعة دقائق، أما في الخطأ 407 فقد نحتاج إلى مزيد من العمل للوصول إلى صفحة الويب، ولمزيد من التفاصيل حول هذه الرموز انظر مقال رموز الإجابة في HTTP. لننظر الآن في الجانب الآخر، فما الذي يحدث عند وصول طلباتنا إلى خادم الويب؟ وكيف ننشئ خادم ويب خاص بنا؟ هذا هو موضوع المقال التالي. خاتمة في نهاية هذا المقال نأمل أن تكون تعلمت ما يلي: تُنشأ طلبات إلى خوادم الويب باستخدام طلبات http GET. يرد خادم الويب بمستند HTML. نحتاج إلى تحليل HTML لاستخراج البيانات المطلوبة. توفر بايثون عدة وحدات للتحليل، وأبسطها وحدة html.parser. توفر وحدات من طرف ثالث، مثل BeautifulSoup، وسائل تحليل أسهل وأفضل. ترجمة -بتصرف- للفصل التاسع والعشرين: Web Client Programming من كتاب Learn To Program لصاحبه Alan Gauld. اقرأ أيضًا المقال التالي: كيفية كتابة تطبيقات الويب المقال السابق: كيفية التعامل مع الويب المدخل الشامل لتعلم علوم الحاسوب دليلك الشامل إلى تعلم البرمجة البرمجة بلغة بايثون
  19. تعلمنا في الجزء الأول من هذا المقال كيفية بناء مدونة كتطبيق وحيد الصفحة باستخدام إطار العمل Angular للواجهة الأمامية، وقاعدة بيانات Firestore، وإضافة محرر للمدونة، ثم إضافة تدوينات جديدة وعرضها على الصفحة الرئيسية، ثم إضافة ميزات للتعديل على التدوينات وحذفها وتنسيق التدوينات في الصفحة الرئيسية وسنكمل في هذا الجزء العمل على المدونة وسنتعلم كيفية إضافة الاستيثاق authentication لتقييد وصول المستخدمين إلى المدونة وإعطاء كل مستخدم صلاحيات مناسبة لإضافة التدونيات والتعديل عليها. هذا المقال جزء من سلسلة عن بناء مدونة باستخدام إطار العمل Angular وقاعدة بيانات Firestore مقدمة في بناء تطبيقات الويب باستخدام إطار العمل Angular وقاعدة بيانات Firestore. بناء مدونة باستخدام إطار العمل Angular وقاعدة بيانات Firestore - إضافة التدوينات وعرضها. بناء مدونة باستخدام إطار العمل Angular وقاعدة بيانات Firestore - تعديل التدوينات. بناء مدونة باستخدام إطار العمل Angular وقاعدة بيانات Firestore - إضافة الاستثيثاق. نشر مدونة مبنية عبر Angular على Firebase إضافة استيثاق جوجل سنضيف الآن ميزة التسجيل بحساب جوجل إلى التطبيق الخاص بنا، ونحتاج هنا إلى تفعيل خاصية الاستيثاق authentication من طرفية Firebase كما يلي: انتقل إلى صفحة Project Overview الخاصة بمشروع Firebase. في القائمة اليسرى، تحت تبويب Develop، اختر Authentication. انتقل إلى التبويب Sign-in method. اختر Google من القائمة التي تظهر تحته. انقر على زر Enable المقابل لخيار Google، ثم انقر على Save للحفظ. سنهيئ التطبيق الآن ليستخدم استيثاق جوجل من Firebase. إنشاء نموذج AppUser أنشئ الملف appuser.ts وضع الشيفرة التالية فيه: export class AppUser { name: string; email: string; isAdmin: boolean; photoURL: string; } إنشاء خدمة الاستيثاق لإنشاء خدمة تعالج عملية الاستيثاق، نكتب الأمر التالي: ng g s services/auth افتح الملف auth.service.ts وضع تعريفات الاستيراد التالية فيه: import { AppUser } from '../models/appuser'; import { Observable, of } from 'rxjs'; import { AngularFireAuth } from '@angular/fire/auth'; import { ActivatedRoute, Router } from '@angular/router'; import { AngularFirestore } from '@angular/fire/firestore'; import { switchMap } from 'rxjs/operators'; import * as firebase from 'firebase/app'; صرِّح عن الكائن الملاحَظ observable الذي من النوع AppUser في الصنف AuthService كما يلي: appUser$: Observable<AppUser>; ثم احقن الخدمات في المنشئ: constructor( public afAuth: AngularFireAuth, private route: ActivatedRoute, private router: Router, private db: AngularFirestore ) يحصل الكائن الملاحَظ appUser$‎ على حالة الاستيثاق للمستخدم، فإذا كان قد سجل دخوله سيجلب بيانات المستخدم من قاعدة بيانات Firebase، وإلا يعيد قيمة غير معرَّفة null: this.appUser$ = this.afAuth.authState.pipe( switchMap(user => { if (user) { return this.db.doc<AppUser>(`appusers/${user.uid}`).valueChanges(); } else { return of(null); } }) ); كذلك، سنضيف التابع updateUserData لحفظ بيانات المستخدم في قاعدة بياناتنا عند نجاح تسجيل الدخول، فنخزن الاسم وعنوان البريد ورابط الصورة التي في حساب جوجل لكل مستخدم في قاعدة البيانات. نضيف التابع updateUserData كما يلي: private updateUserData(user) { const userRef = this.db.doc(`appusers/${user.uid}`); const data = { name: user.displayName, email: user.email, photoURL: user.photoURL }; return userRef.set(data, { merge: true }); } ونحن نخزن هذه البيانات لسببين: معرفة المستخدمين الذين سجلوا الدخول إلى تطبيقنا. عرض اسم المستخدم وصورته في شريط التنقل في حالة تسجيل الدخول الناجح. أضف تعريف التابع التالي لتسجيل الدخول والخروج في صنف AuthService كما يلي: async login() { const returnUrl = this.route.snapshot.queryParamMap.get('returnUrl') || this.router.url; localStorage.setItem('returnUrl', returnUrl); const credential = await this.afAuth.auth.signInWithPopup(new firebase.auth.GoogleAuthProvider()); return this.updateUserData(credential.user); } async logout() { await this.afAuth.auth.signOut().then(() => { this.router.navigate(['/']); }); } سنحصل على الرابط returnUrl من الموجه route ثم نخزن قيمته في الذاكرة المحلية، وذلك لضمان عدم فقد القيمة أثناء إعادة توجيه الصفحة أو تحديثها. سيستوثق التابع signInWithPopup من عميل Firebase باستخدام تدفق توثيق OAuth منبثق -popup-based OAuth authentication flow-، فإذا نجحت عملية تسجيل الدخول سيعيد مستخدمًا مسجَّلًا دخوله مع اعتماديات المزود، أما إذا فشل فسيعيد كائن خطأ يحتوي على معلومات حول هذا الخطأ، وسينفذ التابع logout عملية تسجيل الخروج للمستخدم الحالي ويوجهه إلى الصفحة الرئيسية. تحديث AppComponent افتح الملف app.component.ts وأضف تعريفات الاستيراد التالية في بدايته: import { AuthService } from './services/auth.service'; import { Router } from '@angular/router'; ثم احقن الخدمات في المنشئ كما يلي: constructor( private authService: AuthService, private router: Router ) { } سنشترك في الكائن الملاحَظ appUser$‎ داخل التابع ngOnInit الخاص بالصنف AppComponent كما يلي: this.authService.appUser$.subscribe(user => { if (!user) { return; } else { const returnUrl = localStorage.getItem('returnUrl'); if (!returnUrl) { return; } localStorage.removeItem('returnUrl'); this.router.navigateByUrl(returnUrl); } }); إذا كان المستخدم قد سجل دخوله فسنجلب قيمة الرابط المعاد من الذاكرة المحلية، فإذا كان ذلك الرابط متاحًا يُوجَّه المستخدم إليه، ثم نحذف الرابط من الذاكرة المحلية. إضافة زر تسجيل الدخول في شريط التنقل افتح الملف nav-bar.component.ts وأضف تعريفات الاستيراد التالية في بدايته: import { AuthService } from 'src/app/services/auth.service'; import { AppUser } from 'src/app/models/appuser'; سنصرِّح عن خاصية تحتفظ ببيانات المستخدم، كما سنحقن AuthService في المنشئ، انظر الشيفرة التالية: appUser: AppUser; constructor(private authService: AuthService) {} كما سنشترك في الكائن appUser$‎ الخاص بالخدمة AuthService ونعيِّن الخاصية appUser، فنفِّذ الواجهة OnInit على صنف NavBarComponent، وأضف السطر التالي إلى التابع ngOnInit: this.authService.appUser$.subscribe(appUser => this.appUser = appUser); كما سنضيف التابع من أجل معالجة تسجيل الدخول والخروج من تطبيقنا داخل الصنف NavBarComponent كما يلي: login() { this.authService.login(); } logout() { this.authService.logout(); } سنحدِّث الآن قالب شريط التنقل، فافتح الملف الملف nav-bar.component.html واستبدل الشيفرة التالية بالموجود فيه: <mat-toolbar class="nav-bar mat-elevation-z2"> <button mat-button [routerLink]='["/"]'> My blog </button> <ng-container *ngIf="appUser"> <button mat-button [routerLinkActive]='["link-active"]' [routerLink]='["/addpost"]'> Add Post </button> </ng-container> <span class="spacer"></span> <ng-template #anonymousUser> <button mat-button (click)="login()">Login with Google</button> </ng-template> <ng-container *ngIf="appUser; else anonymousUser"> <img mat-card-avatar class="user-avatar" src={{appUser.photoURL}}> <button mat-button [matMenuTriggerFor]="menu"> {{appUser.name}}<mat-icon>arrow_drop_down</mat-icon> </button> <mat-menu #menu="matMenu"> <button mat-menu-item (click)=logout()>Logout</button> </mat-menu> </ng-container> </mat-toolbar> إذا كان المستخدم قد سجل الدخول سنعرض كلا من الاسم والصورة اللذين في حساب جوجل له، أما إذا لم يسجل الدخول فسنعرض زر Login with Google على شريط التنقل. سنضيف تعريف التنسيق التالي في الملف nav-bar.component.scss: .user-avatar { height: 40px; width: 40px; border-radius: 50%; flex-shrink: 0; } تحديث نموذج التطبيق استورد AngularFireAuthModule إلى الملف app.module.ts كما يلي: import { AngularFireAuthModule } from '@angular/fire/auth'; @NgModule({ ... imports: [ ... AngularFireAuthModule, ], }) المستخدم ذو صلاحيات التحرير والحذف افتح الملف blog-card.component.ts وأضف تعريفي الاستيراد التاليين: import { AppUser } from 'src/app/models/appuser'; import { AuthService } from 'src/app/services/auth.service'; سنصرِّح عن خاصية في صنف BlogCardComponent -كما في مكون شريط التنقل-، ونحقن AuthService في المنشئ، انظر الشيفرة التالية: appUser: AppUser; constructor( // خدمات أخرى private authService: AuthService) {} سنشترك في الكائن الملاحَظ appUser$‎ من AuthService ونعيّن الخاصية appUser، فأضف السطر التالي إلى التابع ngOnInit الخاص بالصنف BlogCardComponent. this.authService.appUser$.subscribe(appUser => this.appUser = appUser); ثم افتح الملف blog-card.components.html وأضف توجيه ngIf إلى الوسم <ng-container>، وهو يحتوي أزرار Edit و Delete، وذلك لقصر استخدام هذين الزرين على المستخدمين الذين سجلوا دخولهم. <ng-container *ngIf="appUser"> نحن الآن نسمح بخاصية التعديل والحذف لأي مستخدم قد سجل دخوله، لكن في القسم التالي سنضيف خاصية الترخيص أو الإذن authorization، ثم نحدِّث الشيفرة لتقصر تلك المزايا على المستخدمين المدراء فقط. الحصول على اسم الكاتب بما أننا لا نسمح بإضافة تدوينات من المستخدمين الذين لم يسجلوا دخولهم، فنستطيع التقاط اسم الكاتب لكل تدوينة، ويكون هو نفس اسمه الذي في حساب جوجل الخاص به، فسنعرض هذا الاسم على صفحة التدوينة إلى جانب تاريخ إنشائها. أضف تعريفات الاستيراد التالية إلى الملف blog-card.components.ts: import { AuthService } from 'src/app/services/auth.service'; import { AppUser } from 'src/app/models/appuser'; سنصرِّح عن خاصية لتحتوي بيانات المستخدم، ثم نحقن AuthService في المنشئ الخاص بالمكون BlogEditorComponent. كذلك، سنشترك في الكائن الملاحَظ appUser$‎ من AuthService، ونعيّن الخاصية appUser، انظر الشيفرة أدناه: appUser: AppUser; constructor( // حقن آخر للخدمات private authService: AuthService) { } ngOnInit() { ... this.authService.appUser$.subscribe(appUser => this.appUser = appUser); } نعيّن خاصية الكاتب للكائن postData أثناء حفظ التدوينة الجديدة، فأضف السطر التالي داخل قسم else من التابع saveBlogPost، مباشرة قبل استدعاء التابع createPost الخاص بالصنف BlogService. this.postData.author = this.appUser.name; أضف السطر التالي في الملف blog.component.html، بعد السطر الذي نربط فيه createdDate داخل الوسم <mat-card-subtitle>. يُستخدم هذا لعرض اسم الكاتب إلى جانب تاريخ إنشاء التدوينة. <i class="fa fa-user" aria-hidden="true"></i> {{postData.author}} تأمين الوجهات سنضيف حاجز استيثاق auth guard إلى التطبيق لتقييد الوصول غير المصرح له إلى وجهات routes بعينها لا يجب على أي مستخدم الوصول لها خصوصًا المستخدم غير المسجل. شغِّل الأمر التالي لإضافة حاجز جديد: ng g g guards/auth --implements CanActivate افتح الملف src/app/guards/auth.guard.ts وأضف تعريفات الاستيراد التالية: import { Router } from '@angular/router'; import { AuthService } from '../services/auth.service'; import { map } from 'rxjs/operators'; أضف منشئًا في الصنف AuthGuard، واحقن Router و AuthService في المنشئ كما يلي: constructor( private router: Router, private authService: AuthService ) { } سنحدِّث التابع canActivate ليعالج الوصول غير المصدَّق له unauthenticated إلى الوجهات فأضف الشيفرة التالية إلى هذا التابع: return this.authService.appUser$.pipe(map(user => { if (user) { return true; } this.router.navigate(['/'], { queryParams: { returnUrl: state.url } }); return false; })); سنشترك في الكائن appUser$‎ لجلب حالة الاستيثاق authentication state للمستخدم، فإذا سجل المستخدم الدخول نعيد true، أما إذا لم يسجل الدخول فتحدث ثلاثة أشياء: نعيّن معامِل استعلام query parameter يسمى returnUrl على قيمة الرابط الحالي. ننقل المستخدم إلى الصفحة الرئيسية. نعيد false من التابع. إضافة حواجز الوجهة route guards في نموذج التطبيق إذا أردنا تفعيل حاجز الوجة لوجهة بعينها في التطبيق، نحتاج إلى إضافة الخاصية canActivate إلى الوجهة في الملف app.module.ts، وسنؤمن الوجهات الخاصة بإضافة تدوينة جديدة من خلال إضافة الخاصية canActivate. أضف تعريف الاستيراد التالي في الملف app.module.ts: import { AuthGuard } from './guards/auth.guard'; وحدِّث الاتجاه الخاص بالمكون addpost كما يلي: { path: 'addpost', component: BlogEditorComponent, canActivate:[AuthGuard] }, إذا حاول المستخدم أن يصل إلى الوجهة addpost فسيُستدعى الصنف AuthGuard، فإذا أعاد هذا الصنف true يُسمح للمستخدم أن يصل إلى تلك الوجهة لإضافة تدوينة جديدة، أما إذا أعاد false فلا يُسمح له بالوصول إلى تلك الوجهة ويُعاد إلى الصفحة الرئيسية. اختبار عملية الاستيثاق افتح المتصفح لترى أن بطاقة التدوينة لا تحتوي على زري التعديل والحذف، كذلك لا يظهر زر Add post في شريط التنقل، وذلك لأن المستخدم لم يسجل الدخول بعد، لهذا نرى زر Login with Google في الركن العلوي الأيمن من شريط التنقل. إذا ضغطنا على ذلك الزر ستظهر نافذة منبثقة تطلب منا تسجيل الدخول باستخدام حساب جوجل: ستحدِّث الصفحة نفسها بمجرد نجاح تصديق جوجل، ونرى أن الاتجاه الخاص بـ Add post قد ظهر على شريط التنقل، كما ظهر اسم المستخدم الذي سجل الدخول على الشريط، وسيظهر كل من زر Edit و Delete على بطاقة التدوينة، انظر: تطبيق التصاريح سنطبِّق الآن تصريحًا مبنيًا على قاعدة rule-based لموقعنا، وسنعرِّف دورًا -وهو دور المدير admin- بحيث يستطيع المستخدمون المدراء فقط أن يعدِّلوا ويحذفوا التدوينة، ثم سنضيف إمكانية نشر التعليقات على التدوينة لاحقًا، والتي يستطيع المدير حذفها هي أيضًا. إعداد قاعدة بيانات Firebase لدور المدير لقد عرَّفنا الخاصية البوليانية isAdmin في الصنف AppUser، وتُستخدم هذه الخاصية لتعريف دور المدير للمستخدم، وسنضيف -يدويًا- حقلًا جديدًا باسم isAdmin للمستخدمين الذين نريد منحهم صلاحية المدير، وسننفذ التغييرات في تجميعة appusers داخل قاعدة بيانات Firebase. انتقل إلى قاعدة بيانات Firebase وافتح تجميعة appusers التي تخزن سجلًا لجميع المستخدمين الذين سجلوا الدخول إلى تطبيقنا، انظر الصورة أدناه: انقر على زر Add field لتظهر نافذة تطلب تعريف حقل جديد، فاجعل اسم الحقل isAdmin، ونوعه boolean، وقيمته True، ثم انقر على زر Add لإضافته، انظر الصورة أدناه: سيضاف الحقل الجديد إلى التجميعة: عند نجاح عملية تسجيل الدخول سنجلب بيانات المستخدم من تجميعة appusers ونربطها بكائن يكون نوعه هو الصنف AppUser، ثم نستخدم الخاصية isAdmin بعدها لتقييد الدخول للمستخدم. وبما أننا ننشئ تطبيقًا للتوضيح والشرح فقط يحتوي على دور واحد، فإننا نعيّن خاصية isAdmin يدويًا، أما التطبيقات الكبيرة فلا يُنصح فيها بهذا إذ قد نحتاج إلى التعامل مع أدوار كثيرة مختلفة، ففي تلك الحالة ننشئ تطبيقًا منفصلًا لإدارة الأدوار لجميع المستخدمين. إنشاء حاجز admin-auth نفّذ الأمر التالي لإنشاء حاجز جديد باسم AdminAuthGuard: ng g g guards/admin-auth --implements CanActivate ثم افتح الملف src/app/guards/admin-auth.guard.ts وأضف تعليمات الاستيراد التالية في أعلاه: import { AuthService } from '../services/auth.service'; import { map } from 'rxjs/operators'; import { AppUser } from '../models/appuser'; أضف منشئًا واحقن الموجِّه Router والخدمة AuthService فيه كما يظهر في الشيفرة التالية: constructor( private router: Router, private authService: AuthService) { } سنحدِّث التابع canActivate لمعالجة الوصول غير المصرح له إلى الوجهات، وذلك بإضافة الشيفرة التالية: return this.authService.appUser$.pipe(map((user: AppUser) => { if (user && user.isAdmin) { return true; } this.router.navigate(['/'], { queryParams: { returnUrl: state.url } }); return false; })); سنشترك في الكائن appUser$‎ لجلب حالة التصديق/التصريح للمستخدم، فإذا كان قد سجل دخوله وكانت قيمة الخاصية isAdmin للمستخدم على القيمة true فإننا نعيد القيمة true أيضًا. بالمثل في سلوك الصنف AuthGuard فإذا لم يكن المستخدم قد سجل دخوله، فستحدث هذه الأشياء الثلاثة: نعين معامِل استعلام باسم returnUrl على قيمة الرابط الحالي. ننقل المستخدم إلى الصفحة الرئيسية. نعيد false من التابع. إضافة صلاحيات مدير للتطبيق لقد حدَّثنا المكون BlogCardComponent في القسم السابق ليقيد الوصول إلى أزرار Edit و Delete ويقصره على المستخدمين الذين سجلوا الدخول، أما الآن فسنحدِّث الشيفرة مرة أخرى لتقصر الوصول على المستخدمين المدراء فقط. افتح الملف src/app/components/blog-card.component.html، وحدِّث التوجيه ngIf الذي في الوسم <ng-container>، والذي بدوره يحتوي على الزر Edit والزر Delete -انظر الشيفرة أدناه- وهذا سيقصر إمكانية التعديل والحذف على المستخدمين الذين سجلوا الدخول فقط. <ng-container *ngIf="appUser?.isAdmin"> أضف تعليمة الاستيراد التالية في الملف app.module.ts: import { AdminAuthGuard } from './guards/admin-auth.guard'; حدِّث الاتجاه الخاص بالمكون editpost كما يلي: { path: 'editpost/:id', component: BlogEditorComponent, canActivate:[AdminAuthGuard] }, لقد قصرنا إمكانية التعديل على التدوينة هنا لتكن للمستخدمين المدراء فقط، فحين يحاول المستخدم الوصول إلى اتجاه editpost، فسيُستدعى الصنف AdminAuthGuard، فإذا أعاد هذا الصنف true يُسمح للمستخدم بالوصول إلى الوجهة editpost لتعديل التدوينة، أما إذا أعاد false فلا يُسمح له بالذهاب لتلك الوجهة لتعديل التدوينة. اختبار التصاريح افتح المتصفح وسجل الدخول إلى التطبيق بمستخدم غير مدير، سترى رابط AddPost في شريط التنقل، لكن بطاقة التدوينة لن يكون فيها زري Edit و Delete، وذلك يعني أن المستخدم يستطيع إضافة تدوينة جديدة لكنه لا يستطيع تعديل تدوينة موجودة أو أن يحذفها. انظر الصورة التالية: انتقل إلى قاعدة بيانات Firebase وأضف حقل isAdmin جديد للمستخدم كما سبق شرحه، أو يمكنك تسجيل الخروج وإعادة تسجيل الدخول بمستخدم آخر يكون فيه حقل isAdmin يحمل القيمة true، وهنا تستطيع أن ترى زري Edit و Delete على بطاقة التدوينة. انظر الصورة التالية: تحديث قواعد الأمان لقاعدة بيانات Firebase لقد أنشأنا قاعدة البيانات في وضع الاختبار، وسنحدِّث القاعدة الأمنية لقاعدة البيانات الآن لتسمح بعملية الكتابة للمستخدم المصرَّح له فقط. من القائمة التي على اليسار، اختر Database في قسم Develop، ثم اختر تبويب Rules، وحدِّث قواعد الأمان كما يلي: service cloud.firestore { match /databases/{database}/documents { match /{document=**} { allow read; allow write: if request.auth.uid != null; } } } ثم انقر على زر Publish لنشر القاعدة، انظر الصورة أدناه: الخاتمة تعلمنا في هذا الجزء من سلسلة بناء مدونة باستخدام إطار العمل Angular وقاعدة بيانات Firestore كيفية إضافة استيثاق جوجل للتأكد من تقييد وصول المستخدمين إلى مختلف أجزاء التطبيق وإعطاء كل مستخدم صلاحيات محددة بعد تسجيله في قاعدة بيانات التطبيق. أما في الجزء الخامس والأخير من هذه السلسلة، فسنكمل إضافة اللمسات النهائية على المدونة، مثل إضافة الملف الشخصي لكل كاتب ونشر التعليقات ومشاركة التدوينات على الشبكات الاجتماعية وغيرها ثم سنتعلم كيفية نشر المدونة على الإنترنت باستعمال Firebase. ترجمة -وبتصرف- لفصول من كتاب Build a full stack web application using angular and firebase لصاحبه Ankit Sharma. اقرأ أيضًا بناء تطبيق ويب كامل باستخدام Angular ومنصة Firebase تهيئة بيئة تطبيقات Angular ونشرها على الويب
  20. سنغطي في هذا المقال من سلسلة تعلم البرمجة: تاريخ موجز للويب. أساسيات بروتوكول HTTP. معماريات الويب وأطر العمل فيه. دور كل من HTML و CSS وجافاسكربت وبايثون. تاريخ موجز للويب ابتكر تِم برنرز-لي Tim Berners-Lee الشبكة العالمية -الوب- لحل مشكلة واجهته هو وزملاؤه في CERN، وهي مشكلة مشاركة المستندات فيما بينهم، فقد كان لديهم مستندات كثيرة في مواقع مختلفة وبصيغ مختلفة، ويحتاج كل منها إلى مفاهيم أو مواد موجودة في مستندات أخرى بعيدة، وكان الكثير من تلك المستندات مشاريع جاريةً يعمل عليها عدة أشخاص معًا. أدرك برنرز-لي أن هذه المشكلة قد تُحل باستخدام تقنية موجودة آنذاك اسمها النصوص الفائقة أو المتشعبة Hypertext، وهي تقنية قديمة يعود تاريخها إلى ما قبل الحواسيب الحديثة!، فعكف يدرس المشكلة وينظر في حلول النصوص الفائقة الممكنة، فوجدها غالية ومغلقة المصدر، أو لا تستطيع العمل إلا على حاسوب واحد، فكانت المساهمة التي قدمها لحل هذه المشكلة هي أخذ فكرة النصوص الفائقة وتطويرها لتعمل عبر شبكة، مما مكّن العاملين من التعاون على مشروع واحد في نفس الوقت، والوصول إلى نفس المستندات من أماكن متفرقة، من خلال السماح للمستخدم من الوصول إلى أي حاسوب متصل بالشبكة، فصارت المكتبة الكبيرة مثل مستند عملاق تتصل فيه جميع الملفات ببعضها وتتكامل فيما بينها، مثل شبكة عنكبوتية كبيرة من المعلومات. النصوص المتشعبة ولغة HTML والمحتوى الثابت بنى برنرز-لي شكلًا من أشكال نظم النصوص المتشعبة، وقد كانت لديه في نفس الوقت خبرة بالإنترنت الموجود آنذاك والمفاهيم التي بني عليها، لذا كانت الخطوة المنطقية التالية هي دمج الفكرتين معًا، فابتكر عدة أجزاء تشكل في مجموعها الويب الذي نعرفه اليوم. واحتاج مفهوم النص المتشعب إلى آلية لربط المستندات معًا، فابتكر لي صيغةً نصيةً أو لغةً توصيفيةً سماها لغة توصيف النصوص الفائقة Hypertext Markup Language أو HTML اختصارًا، مبنيةً على معيار موجود من قبل اسمه لغة التوصيف المعيارية العامة Standard Generalised Markup Language أو SGML اختصارًا، وتُكتب صفحات الويب الحالية في أبسط صورها بلغة HTML أو XHTML -وهي صورة أخرى تتوافق مع HTML-، يدويًا أو بواسطة برنامج حاسوبي، وتعرض المتصفحات صفحاتها من خلال تفسير وسوم HTML تلك وإخراج المحتوى المنسَّق بها على شاشة المستخدم، ويمكن الرجوع إلى توثيق موسوعة حسوب للغة HTML للمزيد عن هذه اللغة. استطاع لي بعد كتابة هذه اللغة أن ينشئ مستندات فائقةً -أو تشعبيةً وهو مصطلح آخر لوصف مستندات HTML- وإن كانت بسيطةً نسبةً إلى الموجود الآن، أتاحت تنسيق الصفحات، وإدراج الصور والروابط إلى مستندات أخرى، لاحظ أننا لم نتعرض حتى الآن لمفهوم الشبكات، فكانت الخطوة التالية هي تمكين الوصول إلى تلك المستندات من حواسيب أخرى عبر الشبكة، وقد تطلب ذلك تعريف صيغة قياسية لعناوين تلك المستندات وذلك المحتوى، وهو ما صار يُعرف فيما بعد باسم المحدد الموحد للموارد Uniform Resource Locator أو URL اختصارًا، يشير أول جزء منه إلى البروتوكول المستخدم، والذي يكون عادةً http أو https في حالة الويب، أما الجزء التالي فيستخدم تسميةً قياسيةً في الإنترنت لتحديد الخادم -ومنفذًا اختياريًا هو عادةً المنفذ 80 كما شرحنا في المقال السابق-، ثم يأتي الجزء الأخير وهو الموقع المنطقي logical للمحتوى على الخادم، ونستخدم كلمة المنطقي هنا لأن هذا الموقع قد لا يكون حقيقيًا أصلًا، وإنما متعلق بموقع ثابت ما يعرفه الخادم، وإن كان يبدو مثل مسار مطلق لمجلد في نظام يونكس، وقد يترجم الخادم الموقع إلى استدعاء تطبيق أو صورة أخرى من مصادر البيانات، لذا إذا نظرنا إلى الرابط الكامل للصفحة http://www.alan-g.me.uk/l2p2/tutweb.htm مثلًا، فسنجد أنه يتكون مما يلي: table { width: 100%; } thead { vertical-align: middle; text-align: center; } td, th { border: 1px solid #dddddd; text-align: right; padding: 8px; text-align: inherit; } tr:nth-child(even) { background-color: #dddddd; } البروتوكول عنوان IP المنفذ الموقع http://‎ www.alan-g.me.uk ‎:80 ‎/l2p2/tutweb.htm لكن المشكلة التي تأتي مع النصوص التشعبية الثابتة هي أن نمط تنسيق الصفحات هذا كان للقراءة فقط، فلا يمكن التعديل عليه أو التفاعل معه، وقد أراد لي طريقةً للتفاعل الديناميكي مع المحتوى. الصفحات الديناميكية وواجهة البوابة المشتركة CGI حُلّت مشكلة توفير المحتوى الديناميكي بإلحاق البيانات بنهاية الرابط فيما يعرف بالسلسلة المرمَّزة encoded string، أو السلسلة المهرَّبة escaped string، وهي تلك السلاسل الطويلة من الأحرف والأرقام ومحارف النسبة المئوية التي تكون في شريط عنوان المتصفح بعد الرابط، وتبدو للوهلة الأولى بلا معنى، وسندرسها بالتفصيل لأننا نحتاج إليها للاتصال بالمواقع الديناميكية. وتعطينا إمكانية التفاعل مع المحتوى هذه عدة مزايا، لعل أهمها توفير وصول آمن للصفحات من خلال مطالبة المستخدم بإدخال اسم مستخدم وكلمة مرور، أو الطلب من المستخدمين تسجيل الاهتمام بالصفحات قبل منحهم صلاحية الوصول إليها، وتُستخدم نفس المزية في التقاط أسماء المستخدمين، كما تُستخدم لاستلام بيانات بطاقات الائتمان والاختيار من قوائم المنتجات، وقد مهدت هذه المزايا الطريق لمجال التجارة الإلكترونية والتسوق عبر الإنترنت. أما التقنية المستخدمة في إنشاء المحتوى الديناميكي للويب فتسمى واجهة البوابة المشتركة CGI، وتمتاز بسهولة تنفيذها وحياديتها اللغوية بحيث لا تتعلق بلغة بعينها، فقد كُتبت تطبيقات الويب الأولى المبنية على CGI بلغات مثل C و C++‎ وملفات باتش لنظام DOS -أو batch files- وسكربتات صدفة يونكس، إلا أنها لم تلبث أن صارت تُكتب بلغة Perl وحدها بسبب القدرة الكبيرة لهذه اللغة على معالجة النصوص، ووجود وحدة CGI library لمعالجة طلبات الويب، وتحتوي بايثون أيضًا على وحدة cgi التي تُستخدم لبناء تطبيقات ويب ديناميكية، وإن كانت بسيطة، وسندرس ذلك في مقال لاحق. كل هذا العمل يضع إمكانيات التفاعل مع المستخدمين على عاتق الخادم، لذا صار جليًا أننا نحتاج إلى نوع من البرمجة داخل المتصفح، لأننا نريد سرعة الاستجابة في هذا التفاعل، وقد وفر متصفح Netscape ذلك في صورة جافاسكربت -و VBScript في متصفح إنترنت إكسبلورر-. وبهذه البرمجة النصية scripting languages -التي لا تحتاج إلى تصريف compiling قبل تشغيلها- صار المتصفح ينشئ نموذجًا برمجيًا للمستند داخل ذاكرته، فيما يسمى بنموذج كائن المستند Document Object Model أو DOM اختصارًا -وقد شاعت هذه التقنية إلى أن صارت معيارًا موحدًا على مستوى المتصفحات- ثم تستطيع اللغات النصية scripting languages أن تبحث في ذلك النموذج عن مكونات المستند، مثل الفقرات أو الجداول، وتعدلها، بتغيير لونها مثلًا أو موضعها في الصفحة، وقد كان ذلك مفيدًا في التحقق من صحة مدخَلات المستخدم مثلًا قبل إرسال البيانات إلى الخادم. غير أننا نواجه مشكلةً في البرمجة القياسية لواجهة البوابة المشتركة CGI، وهي إنشاء خادم الويب لعملية جديدة لكل طلب، مما يبطئ التنفيذ ويستهلك الموارد، خاصةً على الحواسيب التي تعمل بنظام تشغيل ويندوز، وكان من الطبيعي ظهور آليات أكثر تطورًا تستغل بروتوكول CGI، مع تمكينها لخوادم الويب من معالجة الطلبات بكفاءة أكبر في نفس الوقت. من النادر كتابة تطبيقات الويب باستخدام هذا البروتوكول حاليًا، وقد فقدت Perl موقعها في كونها لغةً مفضلةً للويب في ظل وجود تقنيات مثل صفحات الخوادم النشطة Active Server Pages أو ASP اختصارًا، وصفحات جافا للخوادم Java Server Pages أو JSP، وكذلك PHP وغيرها، وسنلقي نظرةً على تقنية من تلك التقنيات المبنية على بايثون في مقال لاحق. أما الآن فنسنلقي نظرةً على الهيكل العام لتطبيقات الويب، والتقنيات المستخدمة في كل مرحلة، قبل أن نكتب تطبيقات ويب على الخادم، وسنبدأ بإلقاء نظرة على البروتوكول الأساسي للشبكة، والذي طوره برنرز-لي لتمكين عملاء النصوص الفائقة من التواصل مع خوادم المستندات. بروتوكول النصوص التشعبية HTTP يجب أن نفهم آلية عمل الويب قبل أن نكتب برامج له، وبالتالي لا بد أن نعرف ما هو برتوكول النصوص الفائقة أو التشعبية، وهو بروتوكول ذو أساس نصي يتصل من خلال مقابس، بنفس الطريقة التي رأيناها في مقال برمجة الشبكات من قبل، ويوفر عدة رسائل: GET: لقراءة المستند من الخادم. POST: لإرسال البيانات إلى الخادم. PUT: لإنشاء مستند جديد على الخادم، أو بديل له. DELETE: لحذف المستند من الخادم. توجد رسائل أخرى غير التي ذكرناها، لكننا ذكرنا الرسائل الأساسية المستخدمة في بناء التطبيقات، ولعل أكثرها استخدامًا GET و POST، غير أننا نستطيع أن نرى أن لدينا أساسًا من نمط CRUD التقليدي هنا، والذي يعني إنشاء Create وقراءة Read وتعديل Update وحذف Delete. فإذا تتبعنا رابط http أعلاه فسنجد أننا نحتاج إلى تعلم الكثير لنكون خبراء في هذا البروتوكول، لكن لحسن الحظ فإن مستوى المعرفة المطلوب لاستخدامه بسيط، لأن وحدات المكتبات تنفذ أغلب العمل المبني عليه، إذ يرسل عميل الويب طلب http GET، ثم يرد الخادم برسالة خطأ فيها رمز من بضعة رموز قياسية لكل منها معنىً محدد، أو بمستند HTML. ورغم إمكانية تنفيذ كل ذلك يدويًا باستخدام المقابس و السلاسل المنسقة، إلا أن الأسهل استخدام حزمة urllib الموجودة في مكتبة بايثون القياسية، وتحديدًا وحدة urlliv.requests التي تعالج إرسال الطلبات إلى الخادم. استخدام الوحدة urllib.requests لجلب صفحة ويب بسيطة نستورد urllib.request، ثم نفتح رابطًا لقراءة النتيجة، كما يلي: >>> import urllib.request as url >>> site = url.urlopen('http://www.alan-g.me.uk/l2p2/index.htm') >>> page = site.read() >>> print( page ) هذا هو كل ما نحتاج إليه، فلدينا الآن سلسلة نصية تحتوي على شيفرة HTML للصفحة الرئيسية للنسخة الإنجليزية من هذه السلسلة، ونستطيع موازنتها إن شئنا مع نتيجة استخدام View>Source في المتصفح، حيث سنرى أن لهما نفس المحتوى تقريبًا، باستثناء أن المتصفح ينسق HTML لجعلها أسهل في القراءة. يبقى أن نسأل أنفسنا ماذا نفعل بالمحتوى الذي لدينا؟ والجواب أننا بلا شك نريد استخراج معلومات منه من خلال تحليله، ويتضمن هذا التحليل في أبسط صوره البحث عن سلسلة أو تعبير نمطي ما، إذ نستطيع أن نبحث في جميع وسوم الصور مثلًا في الصفحة من خلال البحث عن السلسلة ‎'<img'‎، أو ‎'<IMG'‎، أو التعبير النمطي ‎'<img'‎ مع تعيين الراية re.IGNORECASE. غير أننا سنواجه عقبات أخرى في الممارسة العملية كما سنرى في المقال التالي، لكن قبل أن نتعرف على تحليل ملفات HTML يجب أن ننظر إلى الصورة الكبيرة للكيفية التي تُبنى بها تطبيقات الويب، حيث توجد عدة طبقات تستخدم كل منها مجموعةً من التقنيات، وهذه أبرز الخصائص اللازمة لمن يكتب برامج للويب، وهي الحاجة إلى تعلم لغات كثيرة إذا أراد أن يبني تطبيقات تصلح للسوق، وتمثل بايثون هنا جزءًا واحدًا فقط من تلك اللغات. هيكل تطبيق الويب يبدأ تطبيق الويب التقليدي بمتصفح ويب يعمل على حاسوب عميل، يرسل طلبًا عبر الشبكة إلى خادم في مكان ما، ويشغّل الخادم جزءًا من البرنامج يسمى خادم الويب -أو مستمع الويب أحيانًا- ليلتقط الطلبات، ويرسلها -إذا كانت صالحةً- إلى خادم تطبيقات application server قد يكون -أو لا يكون- جزءًا من حزمة خادم الويب، بل قد يكون على حاسوب منفصل داخل مركز بيانات كبير، يفسر خادم التطبيقات الرسالة التي استلمها، ويعيد ملف HTML ساكنًا من نظام ملفاته، أو يعالج البيانات المستلَمة، ويولّد مستند HTML جديدًا حسب الطلب، بمساعدة البيانات المخزنة في قاعدة بيانات أحيانًا، وترسَل HTML في كلا الحالتين إلى المتصفح الذي يستقبلها، ويفسرها، ثم يعرضها على شاشة المستخدم في صورة صفحة ويب منسقة. تختلف التقنيات المستخدمة في كل مرحلة عن الأخرى، وسننظر الآن في تلك الوحدات بالترتيب. متصفح الويب Web Browser المتصفح غالبًا هو أحد المتصفحات الشهيرة، مثل كروم أو سفاري أو فاير فوكس، وسيحتوي على البرمجية اللازمة لتفسير HTML وجافاسكربت وعرض صفحة الويب على الشاشة، كما سيرسل طلبات http إلى خادم الويب، ويستلم الردود عليها. مستمع الويب Web Listener حزمة قياسية -مثل خادم Apache المعروف-، رغم وجود عدة حزم أخرى، ولا تحتوي هذه الحزمة على أي مزايا يمكن للمستخدم برمجتها، باستثناء بعض الإعدادات. خادم التطبيق Application Server تكون هذه الحزمة غالبًا حزمة خادم قياسيةً، إما متكاملةً مع مستمع الويب، أو مستقلةً بذاتها، كما في حالة حاوية Tomcat Java Server Container، أو قد تكون إطار عمل برمجي، مثل جانغو Django للغة بايثون، أو إطار فلاسك Flask الذي سندرسه لاحقًا. وخادم التطبيق -في كل من الحالات السابقة- هو المكان الذي سيكون فيه منطق التطبيق وشيفرته، ويمكن كتابته بأي لغة تقريبًا، لكننا سنكتبه ببايثون في شرحنا، وهو أيضًا المكان الذي ستخزَّن فيه موارد الويب الأخرى، مثل الصور وملفات الوسائط. ملفات HTML ملفات HTML هي ملفات نصية قياسية تُخزَّن على الخادم، وتُكتب بمزيج من لغات HTML وCSS وجافاسكربت، وربما VBScript إذا كانت في بيئة ويندوز، وسبب استخدام هذه اللغات الثلاثة مجموعةً؛ هو أن كلًا منها يؤدي دورًا مستقلًا في بناء الصفحة وجعلها قابلة للتعديل اللاحق، فتحدد لغة HTML بنية المستند، مثل العناوين والجداول والفقرات والصور وغيرها، وتوفر أوراق الأنماط المتتالية -أو التنسيقات الموروثة- CSS المظاهر الجمالية، مثل الألوان والمواضع على الصفحة والخطوط، وتتحكم في طريقة عرض عناصر HTML على الصفحة، بينما تتحكم جافاسكربت في السلوك الديناميكي للعناصر، مثل القوائم المنسدلة والعناصر القابلة للطي وغيرها، وقد استُخدمت في البداية للتحقق من البيانات، غير أن خيارات التحقق التي أتت في HTML5 حلت محلها في هذه الوظيفة. قاعدة البيانات حزمة قاعدة البيانات في الغالب حزمة قياسية مثل التي شرحناها في مقال العمل مع قواعد البيانات، وتتكون من جداول SQL واستعلاماتها وبعض الإجراءات المخزنة في أي لغة تدعمها قاعدة البيانات، ويكون الوصول إلى تلك البيانات غالبًا باستخدام واجهة برمجة التطبيقات API من شيفرة خادم التطبيق، كما رأينا في مقال قواعد البيانات سالف الذكر. ويتبين مما سبق أننا نحتاج إلى أن نتعلم HTML وCSS وجافاسكربت وبايثون وSQL أيضًا إذا أردنا بناء تطبيق ويب كامل، وكذلك كيفية إعداد الخوادم المختلفة وإدارتها، إلا أن مطوري الويب يتخصصون غالبًا إما في تطوير الواجهات الأمامية فقط، فيتعلمون اللغات التي تبني ما يراه المستخدم النهائي، مثل HTML و CSS وجافاسكربت ونحوها، أو تطوير الواجهات الخلفية فقط، فيتعلمون بايثون أو أي لغة تطوير أخرى مثل جافا و PHP وروبي Ruby وSQL (انظر مصادر التعلم وخارطة الطريق في مقال المدخل الشامل لتعلم تطوير الويب). وقد وُضعت آليات مختلفة لقولبة مهام التخصصات لتوضيح الفروق بينها، حيث يستطيع مصمم الواجهات مثلًا أن يصمم صفحات الويب، ويترك علامات markers في الشيفرة يستطيع مطور الواجهة الأمامية، وكذلك مطور الواجهة الخلفية، استخدامها لوضع بياناتهم فيها، ويفيد هذا التخصص في المهام أن مصممي الواجهات ليس عليهم تعلم التقنيات البرمجية، وبالمثل فليس على المطورين أن يشغلوا أنفسهم بأمور التصميم المرئية. سندرس في المقالين التاليين جانبًا من برمجة الويب من جانب العميل client side وجانب الخادم server side، فسنرى كيف نعالج HTML كما لو كانت في متصفح، وهذا ضروري إذا أردنا بناء قاعدة بيانات من المعلومات التي نحصل عليها من الويب، فقد نحصل على البيانات من موقعي ويب مختلفين، ونريد جمعهما معًا لتحليل الظواهر الشائعة trends، وهو ما يُعرف ببرمجة جانب العميل client side programming. أما برمجة جانب الخادم server side programming فهي التي ننشئ فيها موقع ويب فيه محتوىً ديناميكي، وسندرس تنفيذ ذلك باستخدام CGI التقليدية، إذ من الضروري فهم التقنيات الأساسية وراء هذه المهام عند العمل مع أطر العمل المتقدمة لاحقًا. ثم سندرس أحد أطر العمل الحديثة، وهو إطار فلاسك Flask، وهو إطار عمل خفيف ويسهل تعلمه، لكنه قوي بما يكفي لبناء تطبيقات عملية للبيئات التجارية، ثم نختم بنقل تطبيق دليل جهات الاتصال الذي نطوره ليكون تطبيق ويب هذه المرة. خاتمة نأمل في نهاية هذا المقال أن تكون تعلمت ما يلي: تُرسل الطلبات إلى خوادم الويب باستخدام طلبات http GET. يرد خادم الويب بمستند HTML. نحتاج إلى تحليل HTML لاستخراج البيانات التي نريدها. التعابير النمطية ليست أفضل أداة لتحليل HTML. توفر بايثون حزم browser وurllib وhtml لاستخدامها في برمجة جانب العميل. توفر بايثون كذلك عدة وحدات للتحليل، لعل أبرزها ElementTree. يُفضل التحكم في سلوك المتصفح من داخل صفحة الويب باستخدام جافاسكربت. ترجمة -بتصرف- للفصل الثامن والعشرين: Working With the Web من كتاب Learn To Program لصاحبه Alan Gauld. اقرأ أيضًا المقال التالي: برمجة عملاء ويب باستخدام بايثون المقال السابق: تواصل البرامج والعمليات البرمجية عبر الشبكة المدخل الشامل لتعلم تطوير الويب المدخل الشامل لتعلم علوم الحاسوب دليلك الشامل إلى تعلم البرمجة كيف تستخدم أدوات المطوِّر في المتصفحات الحديثة كيف تستخدم أدوات المطوِّر في المتصفحات الحديثة - جافاسكربت - أكاديمية حسوب (hsoub.com)
  21. نظرنا حتى الآن في سلسلة تعلم البرمجة في نظام التشغيل وقدرته على إدارة العمليات، وفي كيفية جعل السكربتات تنفذ برامج موجودةً من قبل، وكذلك استنساخ البرامج والتواصل بين تلك النسخ باستخدام الأنابيب pipes، وسندرس في هذا المقال الاتصال بالعمليات التي تعمل على حاسوب آخر عبر شبكة ما، أو بعمليات قد تكون جاريةً على نفس الحاسوب، حيث ستكون الشبكة هنا شبكةً منطقيةً logical network، وهذا النوع هو المثال الأول الذي سننظر فيه. وعلى ذلك سنشرح في هذا المقال ما يلي: مقدمةً بسيطةً عن الشبكات. أساسيات المقابس sockets. إنشاء عملية الخادم server process. إنشاء عملية العميل client process. التواصل من خلال المقابس. مقدمة في الشبكات يعمل خادم الويب web server على حاسوب في مكان ما في الشبكة، ونستطيع الوصول إليه من حاسوبنا إذا كان لدينا عنوان الويب Uniform Resource Locator واختصارًا URL، والذي هو نوع من عناوين الشبكات يحوي معلومات حول العنوان في الشبكة، واللغة التي يتحدث بها -أو البروتوكول protocol-، وكذلك مكانه على خادم الملفات التي نريد جلبها، وسنفترض أن للقارئ خلفيةً أساسيةً عن الإنترنت، ويعرف أن للحواسيب المتصلة بها عناوين. لكن كيف تتصل تلك الحواسيب ببعضها؟ طبعًا لا يتسع المقام هنا لشرح مفصل حول الشبكات، لذا يُرجع في هذا إلى أكاديمية حسوب التي فيها شرح ماتع في أساسيات الشبكات يمكن النظر فيه، وكذلك في هذا المصدر بالإنجليزية، وخلاصة ما نريد قوله في الشبكات هو أنه عند حاجة حاسوبين على شبكة ما للاتصال ببعضهما فإنها يتصلان من خلال إرسال حزمة بيانات من حاسوب لآخر، وتشبه تلك الحزمة إلى حد كبير مظروفًا يُرسل في طرد عبر البريد مع ورقة بداخله، حيث تمثل تلك الورقة البيانات، ويمثل المظروف ترويسة الطرد packet header التي تحوي عناوين المرسل والمستقبل، ويحدد جهاز التوجيه router أو المحول switch موقع الحاسوب المستقبِل على الشبكة، ثم يوجه الحزمة إلى جهاز توجيه أو راوتر في تلك المنطقة، وتصل الحزمة في النهاية إلى نفس الجزء من الشبكة الذي يحوي الحاسوب الهدف، ويتعرف الحاسوب الهدف على عنوانه ويفتح الطرد أو الحزمة، ثم يرسل حزمة تأكيد مرةً أخرى إلى المرسل ليخبره أن الرسالة قد وصلت. وللحزم قيمة عظمى لا تتعداها، فيما يتعلق بحجم البيانات التي ترسلها، خلافًا للخدمات البريدية التقليدية، ويمكن تشبيه ذلك بخدمة لإرسال خطاب يتكون من ورقة واحدة فقط، أما الرسائل الطويلة فنحتاج إلى إرسالها في عدة خطابات يحوي كل منها ورقةً واحدةً فقط، ويجب على الطرف المستقبل أن يجمع تلك الأجزاء بالترتيب، حيث يضاف رقم متسلسل إلى الورقة -مثل ترقيم الصفحات-، وذلك لتُرسَل رسالة خطأ من المستقبل إلى المرسل إذا لم تصل صفحة ما أو لم تظهر في الوقت المحدد لها، وعلى الرغم من انتفاء الحاجة إلى ذلك غالبًا، لأن الحاسوب يتكفل به وكذلك نظام التشغيل وبرمجيات الشبكات، لكن هذه الأمور تستحق أن نعلمها على أي حال، نظرًا لتعذر الاعتماد على موثوقية نقل البيانات أو استمراريته عند استخدام شبكة ما، إذ تقع الأخطاء العرضية بلا شك، ويجب أن نكون مستعدين لفقدان البيانات أو تلفها. الاتصال بالشبكة لنترك الكلام المجرد ولندرس التفاصيل العملية لكيفية كتابة تطبيق متصل بالشبكة، حيث نحتاج إلى إنشاء برنامج يعمل مثل خادم server ويكون على حاسوب ما، وبرنامج للعميل client على حاسوب أو عدة حواسيب أخرى متصلة بالشبكة التي يتصل بها الخادم، كما نحتاج إلى آلية تتيح التواصل بين البرنامجين وتعمل في كامل الشبكة، وقد رأينا أن لكل حاسوب عنوانًا، يتكون من عنوان IP الذي يحوي أربعة أرقام تفصل بينها نقاط، لا شك أننا رأيناها من قبل في عناوين الويب، ويضيف التطبيق المتصل بالشبكة عنصرًا آخر إلى ذلك العنوان، يُعرف باسم المنفذ port. المنافذ والبروتوكولات يُحدَّد المنفذ بنقطتين رأسيتين : متبوعتين برقم المنفذ، ويضاف ذلك إلى عنوان IP العادي، فنصل مثلًا إلى المنفذ 80 في العنوان 127.0.0.1 بالشكل 127.0.0.1:80، وتُحفظ بعض أرقام المنافذ لأغراض خاصة تكون في الغالب لبروتوكولات تطبيقات الإنترنت المختلفة، والبروتوكول -أو الميثاق- هو مجموعة من القواعد وتعريفات الرسائل التي تحدد كيفية عمل الخدمة، فالمنفذ 80 هو المنفذ القياسي المستخدم في خوادم الويب لطلبات http، أما المنفذ 25 فيُستخدم لبريد SMTP، وبناء عليه يتصرف الحاسوب مثل خادم لبعض الخدمات في نفس الوقت، بعرض تلك الخدمات من خلال منافذها المختلفة، ويمكن توضيح هذا بسهولة بإضافة رقم المنفذ 80 إلى عنوان خادم الويب مثل http://www.google.com:80، حيث ينبغي أن تفتح الصفحة بلا مشاكل لأن المتصفح يتصل بالمنفذ 80 افتراضيًا إن لم يتوفر منفذ آخر، لهذا يكثر استخدام المنفذ 8080 مثل منفذ اختبار للإصدارات الجديدة من مواقع الويب قبل إطلاقها. ورغم قلة عدد تلك المنافذ المحجوزة إلا أننا نستطيع استخدام أرقام المنافذ التي بين 1000 و60000 للتطبيقات المخصصة bespoke applications دون تعارض، لكن يفضل جعل رقم المنفذ قابلًا للإعداد من خلال متغير لبيئة النظام مثلًا، أو ملف إعدادات config file، أو بواسطة معامل سطر أوامر، نظرًا لوجود احتمال -ولو ضئيل- أن يختار برنامج آخر نفس المنفذ على الحاسوب، ولن نشرح ذلك هنا لكن يجب الانتباه إلى أنه وارد في التطبيقات الحقيقية، حين لا يكون لدينا تحكم كامل بحاسوب الخادم، لذا يجب اتخاذ مثل تلك الاحتياطات. بعد أن عرفنا الآلية، فإن السؤال التالي هو: كيف نصل الشيفرة بأحد تلك المنافذ؟ المقابس Sockets المقابس هي أبسط آلية اتصال يمكن استخدامها بين الشبكات، وفيها يُقدَّم المقبس للشبكة على أنه منفذ في عنوان IP، وتُنشأ المقابس في بايثون وتُستخدم من خلال استيراد وحدة socket، ويجب أن نكتب خادمًا لينشئ المقبس، ويربطه مع منفذ، لنتمكن بعدها من استخدامه، ونراقب ذلك المقبس منتظرين الطلبات الواردة إليه، ثم نكتب عميلًا ليتصل بالمقبس على ذلك المنفذ، ثم يتصل العميل بالمنفذ ويقبل الخادم ذلك الاتصال، ثم ينشئ الخادم منفذًا مؤقتًا جديدًا يُستخدم لعملية التواصل -أي عمليات الإرسال والاستقبال send/recv الفعلية- مع الخادم أثناء عملية النقل، مما يحرر المنفذ لمزيد من طلبات الاتصال. يمكن توضيح ما سبق في الصورة التالية: تظهر هنا مشكلة اختبار مثل تلك التطبيقات، إذ لا نستطيع أن نعرف إن كان الخادم يعمل أم لا بدون العميل، كذلك فإن العميل لا يستطيع فعل شيء دون الخادم، لذا ينبغي أن يكون لدينا كل من العميل والخادم. غير أنه يمكن إنشاء أي عدد من العملاء الآخرين بمجرد كتابة الخادم، شرط أن يتصلوا بمقبسه من خلال بروتوكول الرسائل المناسب، ونرى أمثلة ذلك في متصفحات الويب المختلفة التي تستطيع جميعها أن تتصل بأي خادم http، ويمكن بطريقة مماثلة كتابة العديد من الخوادم المختلفة بمجرد نشر البروتوكول، وينبغي هنا ألا توجد مشكلة في عمل أي عميل وأي خادم معًا، وهذا السلوك هو أحد أسباب انتشار تلك التطبيقات، فهو يشكل بيئةً مفتوحةً وقابلةً للتوسع، تكون فيها إحدى نهايات أي زوج من أزواج العميل/الخادم قابلةً للتحسين دون تعطيل النهاية الأخرى. إنشاء الخادم سننشئ خادمًا بسيطًا يستجيب للطلبات بأن يعيد رسالة ترحيب وعدد الطلبات التي عالجها من قبل. import socket # STREAMing و InterNET أنشئ مقبس # TCP/IP المعروف باسم serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # والمنفذ 2007 localhost استخدم serversocket.bind(('localhost', 2007)) # استعد لاستقبال الطلبات serversocket.listen(5) connections = 0 while True: # عالج الاتصالات من العملاء (clientSocket, address) = serversocket.accept() connections += 1 print( "Connection %d using port %d" % (connections, address[1]) ) # clientSocket افعل شيئًا باستخدام while True: req = clientSocket.recv(100) if not req: break # client closed connection message = 'Thankyou!, processed connection number %d' % connections clientSocket.send(message) clientSocket.close() نلاحظ هنا عدة أمور: يشير هذا المزيج من AF_INET وSOCK_STREAM إلى أننا سنستخدم بروتوكول TCP/IP، وكل بروتوكولات عناوين IP الأخرى متاحة من خلال استخدام تجميعات ثوابت أخرى، لكن TCP/IP هو الأشهر منها وهو ما سنستخدمه. مررنا القيمة 5 إلى listen()‎، وهي تمثل العدد الأقصى للاتصالات التي يمكن أن تنتظر في طابور المنفذ، لأننا نُعالج الطلب قبل أن تتجمع طلبات كثيرة في قائمة الانتظار تلك، ونشتق عمليةً مستقلةً لتنفيذ المعالجة الحقيقية إذا أردنا تحسين كفاءتها -انظر الملاحظة الخامسة أدناه-، مما يسمح للخادم أن يسحب الرسائل من قائمة الانتظار في أسرع وقت ممكن، ولا نحتاج زيادة عدد الاتصالات المسموح لها بالانتظار عن 5 اتصالات إلا في حالة الخوادم شديدة الزحام. ينشئ العملاء اتصالًا جديدًا لكل عملية تبادل بيانات، ولا تكون لدينا بيانات متاحة إذا انتهت عملية التبادل، وحينئذ ننهي حلقة while الداخلية ونعود إلى انتظار اتصال جديد. عالجنا طلب العميل في شيفرة الخادم، ولا بأس بهذا لأنها معالجة طفيفة، لكنها قد تستغرق وقتًا كبيرًا إذا كانت في أحد التطبيقات التجارية الكبيرة، عندها نشتق عمليةً أخرى في تلك الحالة لمعالجة تلك العملية خاصةً -ربما باستخدام وحدة subprocess التي ذكرناها في مقال نظم التشغيل-، ونترك الخادم يعود لسحب الطلبات من قائمة انتظاره. لا توجد طريقةً لإنهاء عملية الخادم، فهي تعمل بلا نهاية إلا إذا حدث خطأ، فإذا أردنا إنهاءها فسنستخدم أداةً من نظام التشغيل نفسه، من خلال برنامج TaskManager في ويندوز مثلًا، أو kill في يونكس. ينبغي أن يكون الخادم جاهزًا للعمل الآن وينتظر طلبات العملاء، لكن ليس لدينا عميل ليرسل تلك الطلبات، لذا سننشئه الآن. إنشاء العميل إنشاء العميل client هي عملية سهلة بقدر سهولة إنشاء الخادم، إذ يرسل طلبات متكررةً إلى الخادم بفواصل زمنية قدرها ثانية واحدة، ويطبع استجابة الخادم: import socket,time # أنشئ المقبس serverAddress = ('localhost',2007) # أرسل بعض الطلبات for n in range(5): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(serverAddress) try: sock.send('dummy request\n') data = sock.recv(100) if not data: break # لا توجد بيانات من الخادم print( data ) time.sleep(1) finally: # نرتب الآن ما سبق sock.close() لدينا بعض الملاحظات هنا: نستخدم connect للوصول إلى المقبس، ثم نستخدم نفس واجهة send/recv التي يستخدمها الخادم، لكن يكون التسلسل معكوسًا لأن العميل هو الذي يبدأ عملية تبادل البيانات. كان من الممكن إرسال أو استقبال بيانات أكثر في عملية واحدة، لكننا اخترنا هذه الطريقة ببساطة لإبراز أرقام الاتصال المختلفة القادمة من الخادم، فالعميل هو الذي يقرر متى ينهي عملية التبادل وليس الخادم، إلا إذا حدث خطأ ما. لاحظ استخدام try/finally لضمان إغلاق المقبس حتى في حالة رفع استثناء exception، وهذا مفيد لتقليل المراجعة والتصحيح لاحقًا، لأن بعض أنظمة التشغيل تترك المقابس مفتوحةً لفترة طويلة، مما يعني أنها ستستهلك موارد النظام. تشغيل البرامج نريد أن نتأكد أن الخادم يعمل أولًا قبل أن نستطيع تشغيل البرامج، ثم نبدأ برنامج عميل واحد أو أكثر ليتصل به، ولا نستطيع تشغيل هذه البرامج عبر الشبكة لأننا جعلنا الخادم على الحاسوب المحلي فقط localhost، لذا نحتاج إلى بدء عدد من جلسات الطرفية على حاسوبنا. توضح الصورة التالية الخادم وهو يعمل على يمين الصورة، واثنين من العملاء على يسارها: لاحظ أن خرج كلا العميلين يُظهر تسلسل الرسائل التي استلمت من الخادم، وتُظهر رسائل الخادم الاتصالات وأرقام المنافذ المؤقتة المسندة إلى الخادم. دليل جهات الاتصال الشبكي بنينا في المقال السابق: التواصل بين العمليات نسخةً تعمل على خادم من دليل جهات الاتصال الذي نطوره، وسميناها address_srv.py، وسنستخدمها في هذا المقال لبناء نسخة مبنية على المقابس، وسيكون الاختلاف الواضح بين نسخة IPC السابقة وبين هذه النسخة هو إمكانية وجود أكثر من عميل واحد يستطيع الوصول إلى دليل جهات الاتصال، وسيكون العملاء على حواسيب مختلفة قطعًا. وكانت الدوال التي المتاحة في address_srv هي: ‎readBook(filename)‎ ‎saveBook(book,filename)‎ ‎addEntry(book, name, data)‎ ‎removeEntry(book, name)‎ ‎findEntry(book, name)‎ برنامج الخادم لا زلنا بحاجة إلى كتابة برنامج خادم يعالج الطلبات الواردة من العملاء ويستدعي الدالة المناسبة، رغم أننا حولنا البرنامج إلى دوال مخدمات server style functions في المرة السابقة، وتسمى مثل تلك الآلية ببعث الرسائل dispatching messages، وستكون الشيفرة شبيهةً للغاية بالأمثلة البسيطة السابقة. سيكون البرنامج الرئيسي كما يلي: import socket, address_srv addresses = address_srv.readBook() # أعد المقبس serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) serversocket.bind(('localhost', 2007)) serversocket.listen(5) print( 'Server started and listening on port 2007...' ) # عالج الاتصالات من العملاء while True: (clientSocket, address) = serversocket.accept() # عالج أوامر دليل جهات الاتصال while True: s = clientSocket.recv(1024) try: cmd,data = s.split(':') except ValueError: break print( 'received request: ', cmd ) if cmd == "add": details = data.split(',') name = details[0] entry = ','.join(details[1:]) s = address_srv.addEntry(addresses, name, entry) address_srv.saveBook(addresses) elif cmd == "rem": s = address_srv.removeEntry(addresses, data) address_srv.saveBook(addresses) elif cmd == "fnd": s = address_srv.findEntry(addresses, data) else: s = "ERROR: Unrecognised command: " + cmd clientSocket.send(s) clientSocket.close() نلاحظ هنا أن شيفرة المعالجة الرئيسية للمقبس هي نفسها الشيفرة السابقة، بينما وضعنا معالجة بيانات الطلب في بنية try/except لالتقاط البيانات غير المكتملة من العميل، أما غير ذلك فإن هذه النسخة تكاد تطابق نسخة IPC في المقال السابق. برنامج العميل صار لدينا الآن خادم يعمل في الخلفية، ونريد كتابة برنامج عميل يتحدث إليه، وسيكون مشابهًا لنسخة IPC أيضًا، لكنه سيوجد في سكربت خاصة به، وسنتمكن من تشغيل أكثر من نسخة في نفس الوقت: import socket serverAddress = ('localhost', 2007) menu = ''' 1) Add Entry 2) Delete Entry 3) Find Entry 4) Quit ''' # اتصل بالخادم sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(serverAddress) while True: print( menu ) try: choice = int(input('Choose an option[1-4] ')) except: continue if choice == 1: name = input('Enter the name: ') num = input('Enter the House number: ') street= input('Enter the Street name: ') town = input('Enter the Town: ') phone = input('Enter the Phone number: ') data = "%s,%s %s, %s, %s" % (name,num,street,town,phone) cmd = "add:%s" % data elif choice == 2: name = input('Enter the name: ') cmd = 'rem:%s' % name elif choice == 3: name = input('Enter the name: ') cmd = 'fnd:%s' % name elif choice == 4: break else: print( "Invalid choice, must be between 1 and 4." ) continue # تحدث إلى الخادم try: sock.send(cmd) data = sock.recv(250) if not data: break # no data from server print( data ) finally: sock.close() نلاحظ هنا أن عملية معالجة القائمة هي نفسها في المثال السابق، وأن أوامر الاتصالات مجموعة في بضعة أسطر في الأسفل، وهذا أيضًا مشابه لمثال العميل الذي تقدم شرحه. الانتقال إلى الشبكة كانت مقابسنا إلى الآن على حاسوب محلي، ونريد أن ننقلها إلى شبكة حقيقية ويكون لدينا عمليات عميل/خادم حقيقية أيضًا، ويسهل تنفيذ ذلك بتغيير العناوين المستخدمة في استدعاء bind()‎ في الخادم واستدعاء connect()‎ في العميل، واستبدال عنوان IP -سواءً النسخة الرقمية أو الاسمية منه- للحاسوب الذي يعمل عليه الخادم بالمرجع المشير إلى 'localhost'، ويمكن تشغيل عدة نسخ من العميل على كل حاسوب في نفس الوقت إذا كان لدينا عدة أجهزة على نفس الشبكة، وسيعالج الخادم الطلبات من تلك النسخ. أما في الحياة العملية فقد نبذل مزيدًا من الجهد في التعامل مع تحليل أسماء DNS مثلًا، ونضيف اختبارات تتحقق من الأخطاء وآليات المهل الزمنية timeouts لكي لا يُعلِّق الخادم ويتأثر، لأن الشبكات الحقيقية أقل موثوقيةً وأكثر عرضةً للأخطاء، غير أننا لن نتحدث عن تلك الآليات والمهام، وإنما نذكرها فقط لوجوب حسابها عند حل مثل تلك المشكلات. المزيد من المعلومات كُتبت الكثير من الشروحات في برمجة المقابس، لعل أبرزها Socket How-To الذي كتبه جوردُن ماكمِلان Gordon McMillan، وهو يشرح كثيرًا من عيوب برمجة المقابس ويقدم الحلول المقترحة للتعامل معها، إضافةً إلى توثيق وحدة socket في بايثون، والذي لا غنى عن قراءته. كما تحتوي العديد من الكتب على أقسام عن البرمجة باستخدام المقابس، ونخص بالذكر منها كتاب Python Network Programming الذي كتبه جون جورزن John Goerzen، ويدور حول برمجة الشبكات مغطيًا كثيرًا من جوانب برمجة المقابس. والجميل في الأمر أنه يمكن تنفيذ أغلب مهام برمجة الشبكات بمستوىً أعلى إذا كنا نستخدم أحد بروتوكولات الإنترنت القياسية، مثل http و smtp و telnet وغيرها، ففي بايثون مثلًا وحدات تنفذ تلك البروتوكولات في طبقة المقابس لئلا نضطر نحن إلى ذلك، وسندرس في المقالات القادمة كيف نبسط برمجة الويب باستخدام http، من خلال وحدات المستوى الأعلى تلك، أما عند اختيار العمل في برمجة الشبكات ليكون تخصصًا مهنيًا فتُستخدم لغة rebol لأنها تولي أهميةً لخصوصية المهام، وفيها دعم للعديد من مهام الشبكة. وإن أردت التعمق أكثر في الشبكات، فقد ترجمت أكاديمية حسوب كتابًا مهمًا ونشرت مقالاته تحت وسم "أساسيات الشبكات " يمكنك الرجوع إليه. خاتمة نرجو في نهاية هذا المقال أن تكون تعلمت ما يلي: تمثَّل اتصالات شبكات الحواسيب بعناوين IP ومنافذ ports. تتصل المقابس بالمنافذ. تراقب مقابس الخوادم الاتصالات وتستمع لها عبر listen، وتقبلها إذا التقطتها بواسطة accept، وهذا يحدد منفذًا جديدًا ليستخدمه العميل الجديد. يجب أن تستقبل الخوادم رسائل العملاء على المنفذ الجديد من خلال recv، وترسل send الردود إلى العملاء. يتصل عملاء المقابس بمقبس الخادم من خلال connect، ويرسلون البيانات إليه من خلال send، ثم يستقبلون البيانات مرةً أخرى عبر recv في صورة ردود. يغلق العميل المقبس باستخدام close عند انتهاء عملية تبادل البيانات. ترجمة -بتصرف- للفصل السابع والعشرين: Network Communications من كتاب Learn To Program لصاحبه Alan Gauld. اقرأ أيضًا المقال التالي: كيفية التعامل مع الويب المقال السابق: التواصل بين العمليات في البرمجة المدخل الشامل لتعلم علوم الحاسوب مدخل إلى شبكات الحواسيب: مصطلحات وفهم طبقات الشبكة البرمجيات المستخدمة في بناء الشبكات الحاسوبية معمارية الشبكة الحاسوبية وشبكة الإنترنت (Network Architecture)
  22. سنستخدم في هذا المقال الدالة os.fork()‎ التي لا توجد في نظام ويندوز، لأنه بطيء جدًا -موازنةً بأنظمة يونكس- في إنشاء العمليات الجديدة، إلى درجة عدم استخدام fork()‎ حتى لو استطعنا ذلك، لكن يمكن حل هذه المشكلة باستخدام الخيوط threads، التي تعمل على كل من يونكس وويندوز، وسنشرحها في مقال لاحق، فإذا كنت تستخدم ويندوز فيفضّل أن تقرأ القسم الخاص بالمفاهيم هنا لأنها ستُستخدم في المقال التالي، لكن لا داعي لكتابة الأمثلة الموجودة هنا لأنها لن تعمل معك، أما إذا كنت تستخدم أحد أنظمة يونكس فلن تواجهك مشكلةً فيها. سنشرح في هذا المقال من سلسلة تعلم البرمجة: الحالات التي تستدعي IPC وأسبابها. أساسيات الأنابيب pipes. نسخ العمليات باستخدام os.fork()‎. التواصل من خلال الأنابيب. إنهاء العمليات باستخدام os.kill()‎. تعريف التواصل بين العمليات التواصل بين العمليات inter-process communication واختصارًا IPC، هو آلية تمكّن عمليةً ما من التواصل وتبادل البيانات مع عملية أخرى، وقد شرحنا في المقال السابق: استخدام نظام التشغيل أن العملية برنامج تنفيذي، وأنها تستطيع التواصل مع غيرها من العمليات باستخدام المزايا الموجودة في وحدة subprocess، وعلى الرغم من أن هذه التقنيات مفيدة في التواصل مع البرامج الأخرى، إلا أنها لا توفر التحكم الدقيق المطلوب أحيانًا للتطبيقات الكبيرة، فمن الشائع في تلك التطبيقات استخدام عدة عمليات في نفس الوقت، بحيث تنفذ كل منها مهمةً مستقلةً، وتطلب بقية العمليات خدمات منها، فمثلًا قد يكون لخادم الويب عملية تراقب طلبات الويب من المتصفحات وتخدمها في صفحات HTML بسيطة، لكنه يستخدم عمليةً أخرى لتوفير طلبات البيانات الأعقد، وربما عملية أخرى لمعالجة طلبات ftp، وتُصمم كل عملية بحيث تنفذ مهمةً واحدةً فقط بكفاءة عالية، ويسمح هذا التصميم للمدير بمشاركة حمل المعالجة مع عدة عمليات، فإذا كان لدينا طلبات ftp كثيرة مثلًا، فيمكن بدء عملية ftp جديدة، وتوزيع طلبات ftp على العمليتين. أهمية التواصل بين العمليات مع أننا قد لا نكتب مثل تلك التطبيقات الكبيرة، إلا أنها تقنية مفيدة، وسنحتاج المفاهيم التي فيها في مقالات لاحقة، مثل فصل برمجة الشبكات، وقد نستفيد منها في برامج يتشارك فيها عدة مستخدمين أحد الموارد، كقاعدة بيانات مثلًا، حتى لو كانت تلك البرامج صغيرةً، وكذلك عند قراءة البيانات من عدة منافذ اتصال، حيث سيكون من الأفضل وجود عملية لكل اتصال شبكي، كي لا يؤثر انقطاع إحدى الشبكات على قراءة بقية الشبكات. هل تشبه هذه التقنية تقنية العميل/الخادم؟ يكثر استخدام مصطلح العميل/الخادم في التطبيقات التجارية، وهو مصطلح خاص بمعمارية البرمجيات، ويشير إلى نوع محدد من إعدادات التواصل بين العمليات، ترسل فيه إحدى العمليات -وهي العميل client- طلبات إلى عملية أخرى -هي الخادم server-، لكن الخادم لا يطلب أي شيء أبدًا من العميل، وقد يكون لدينا عدة عمليات من نوع "العميل" تصل إلى خادم واحد، ويمكن لذلك الخادم نفسه أن يكون عميلًا لخوادم أخرى، فيما يعرف بحوسبة العميل/الخادم متعدد المستويات N-Tier Client/Server، التي تستخدم التواصل بين العمليات، إلا أنه لا يُشترط أن تكون تقنية التواصل بين العمليات مبنيةً على تقنية العميل/الخادم، ومن الممكن أن يكون لدينا شبكة من العمليات ترسل كل منها رسائل إلى بقية العمليات دون أي تخطيط ثابت بين العملاء والخوادم، ويُسمى هذا بحوسبة النِد للنِد peer-to-peer computing، وقد يبدو هذا نموذجًا جذابًا إلا أنه صعب الإدارة إذا زاد عدد العمليات، لذا يظل النموذج التقليدي للعميل/الخادم هو الأكثر استقرارًا والأسهل في تصميمه وتشغيله. هل لهذه التقنية علاقة بالعتاد؟ تكلمنا في وصفنا السابق للعميل والخادم عن البرمجيات والعمليات فقط، لكن ربما تكون قد سمعت هذه المصطلحات في العتاد أيضًا، خاصةً مصطلح الخادم server الذي يشير إلى الحواسيب القوية التي يتشاركها عدة مستخدمين، وهذه إساءة إلى المعنى الحقيقي لحوسبة العميل/الخادم التي هي معمارية برمجية خالصة، ومستقلة عن العتاد. تميل عمليات الخوادم في الواقع العملي إلى العمل على حواسيب مستقلة وقوية، ويُشار إلى الجمع بين العتاد وعمليات الخوادم باسم الخادم، ويأخذنا هذا الأسلوب من استخدام تقنية العميل/الخادم إلى عالم حوسبة الشبكات الذي ننظر فيه في المقال التالي. يمكن ملاحظة تشابه هذه المصطلحات مع تلك المستخدمة في البرمجة كائنية التوجه، لأن استخدام الرسائل بين العمليات يشبه إرسال الرسائل بين الكائنات في البرمجة الكائنية، وفعليًا توجد الكثير من الأمور المشتركة بين النموذج الكائني ونموذج التواصل بين العمليات، وقد طُورت بعض معماريات IPC لتستفيد من هذه الأوجه المشتركة، مثل معمارية وسيط طلب الكائن المشترك Common Object Request Broker أو COBRA اختصارًا، حيث نسجل الكائنات في تلك المعمارية مع وسيط طلب لكائن مركزي ORB، وتُوجَّه الرسائل المرسَلة إلى الكائن من أي مكان في الهيكل إلى العملية التي سجلت الكائن، ولن ننظر فيها هنا، ويمكن العودة إلى تطبيقات بايثون لوسطاء طلبات الكائنات المركزية ORB لمزيد من المعلومات. سنبدأ الآن كتابة بعض الشيفرات، لكن يجب أن ننظر أولًا في بعض آليات التواصل بين العمليات، وسندرس اثنتين منها، الأولى هي تقنية الأنبوب pipe المستخدمة لتبادل البيانات بين عمليتين. تعريف الأنبوب Pipe يمكن النظر إلى الأنبوب Pipe على أنه يشبه الخرطوم، حيث نسكب البيانات في أحد طرفيه ليخرج من الآخر، وهو يشبه الملف من حيث التعامل معه على أنه تدفق متسلسل للبيانات، لكنه يختلف عن الملف في أن له طرفين، لذا نحصل عند إنشائه على نقطتي نهاية، لنقرأ من إحداهما، ونكتب إلى الأخرى. وعلى عكس الملف لا تُخزّن البيانات حقيقةً عند إغلاق الأنبوب، لذا سنفقد كل ما كتبناه في أحد طرفي الأنبوب ولم نقرأه من الجانب الآخر. يمكن توضيح استخدام الأنابيب مثل قنوات بين العمليات كما يلي: نرى هنا عمليتين سميناهما Parent وChild، لأسباب ستبينها بعد قليل، وتستطيع عملية Parent أن تكتب في Pipe A، وتقرأ من Pipe B، أما عملية Child فتستطيع القراءة من Pipe A والكتابة في Pipe B، ويُستخدم كل أنبوب لإرسال طلب أو إعادة بيانات وفقًا للعملية التي بدأت عملية التبادل، ويعطينا ذلك تحديًا مثيرًا للاهتمام في سبب تسمية الأنابيب. سنكتب الآن بعض التعليمات البرمجية لنرى كيف يمكن بناء آلية IPC باستخدام بايثون، وسيكون المبدأ العام هو إنشاء عملية تكون أصلًا parent وتفتح أنبوبين، ثم نشتق نسخةً منها لتكون فرعًا فيه نفس الأنبوبين، ثم نستخدم الأنابيب للتواصل بين الأصل والفرع، وأول ما سنفعله هو معرفة كيفية استخدام الأنابيب لإرسال البيانات واستلامها، حيث سننشئ أنبوبًا باستخدام دالة os.pipe()‎ تعيد اثنين من واصفات الملفات، واحد لكل طرف من أطراف الأنبوب، ثم نستخدم دوال os.read/write لإرسال البيانات في الأنبوب: import os # أنشئ الأنبوب receive, transmit = os.pipe() data = 'Here is a data string' length = os.write(transmit, bytes(data, 'utf8')) print('Length of data sent: ', length) # 1024 مخزن مؤقت حجمه # لضمان استقبال جميع البيانات print( 'The pipe contains:', os.read(receive, 1024).decode('utf8') ) لاحظ أننا نحتاج إلى تحويل البيانات من وإلى مصفوفات البايتات byte arrays، تحويلًا مشتركًا مع معظم عمليات مستوى النظام، ويحدث كل ذلك في عملية واحدة، لذا لا يكون ذا فائدة كبيرة، لكننا نستطيع فصل شيفرة القراءة والكتابة والبدء في تنفيذ شيء ما، بمجرد استنساخ عمليتنا، فكيف ننشئ عملية الاستنساخ تلك؟ عمليات الاستنساخ إن الآلية المستخدمة في توليد الفروع spawning أو اشتقاقها forking هي استخدام استدعاء النظام os.fork()‎ الذي يعيد قيمًا مختلفةً وفقًا لمكاننا في العملية الأصل أو الفرع، وتكون قيمة الإعادة في العملية الأصلية هي معرِّف العملية أو pid للعملية الفرع، اما إذا كنا في العملية الفرع فستكون قيمة إعادة fork صفرًا، وهذا يعني أنه سيكون لدينا في الشيفرة تعليمة if تتحقق من قيمة إعادة fork()‎، فإن كانت صفرًا فستنفَّذ دوال العملية الفرع، وإن لم تكن كذلك فستنفَّذ دوال العملية الأصل، ويفضَّل وضع الدوال في وحدات منفصلة واستدعاؤها حسب الحاجة، للسيطرة على مجريات التنفيذ، إلا أننا لن نفعل ذلك هنا لأن الشيفرة قصيرة وستكفينا قائمة واحدة، ونعيد التذكير هنا أن ويندوز لا يفعل هذا، أي لا يدعم دالة fork()‎، لذا لن تعمل الشيفرة في ويندوز، وسيضطر مستخدم ويندوز إلى الانتظار إلى الفصل التالي ليعرف كيفية كتابة برامج العميل/الخادم. سننشئ الآن عمليةً فرعيةً تستطيع إجراء عملية بسيطة لتنسيق النصوص، وتعيد القيمة التي نمررها إليها مسبوقةً ومتبوعةً بالجملة Ni. import os,signal # أنشئ الأنابيب ServerReceive,ClientSend = os.pipe() ClientReceive, ServerSend = os.pipe() pid = os.fork() if pid == 0: # في الفرع while True: # قدمها بلا نهاية data = os.read(ServerReceive,1024) if data: # تحقق من استلام شيء ما! data = 'Ni!\n' + data + '\nNi!' else: data = "Error: received empty message" os.write(ServerSend,data) else: # في الأصل data = ['The Knights who say Ni!', 'Appear in the film "Monty Python and the Holy Grail" '] for line in data: os.write(ClientSend,line) print os.read(ClientReceive,1024) # والآن أنه العملية الفرع os.kill(pid,signal.SIGTERM) لاحظ أننا نستخدم pid الذي استلمناه من fork لإنهاء العملية الفرع، فإذا فشلنا في ذلك فستصبح العملية الفرع عمليةً خلفيةً أو خفيةً daemon، تعمل بصمت بلا نهاية بانتظار ظهور البيانات على أنبوب الدخل الخاص بها، أما الإنهاء الفعلي فيكون باستخدام دالة os.kill()‎، التي تُستخدم لإرسال أي رسالة إلى أي عملية -بغض النظر عن اسمها-، وتسمى إشارة الإنهاء هنا SIGTERM كما هو محدد في وحدة signal، وتختلف القائمة الكاملة وفقًا لكل منصة، وتكون موثقةً في مكتبة libc الخاصة بلغة C لمنصتك، لكن يمكن الحصول عليها بسهولة كما يلي في محث بايثون: >>> dir(signal) أو في سطر أوامر يونكس (لاحظ أن هذا حرف L وليس العدد 1): $ kill -l ونحصل في حالة يونكس على القيمة العددية التي يمكن استخدامها في أمر kill()‎ مباشرةً، لكن هذه القيمة لن تعمل في منصات مختلفة. أنشأنا الأنابيب ونقلنا البيانات عبرها، كما أنشأنا عمليةً فرعيةً وأرسلنا البيانات إليها، وعدلنا البيانات في العملية الفرعية وأرسلنا البيانات إلى العملية الأصل، وأخيرًا أنهينا العملية الفرع، وهذا كل ما نحتاج إليه في التواصل الأساسي بين العمليات، أما الآن فسنرى مثالًا حقيقيًا عمليًا، نعود فيه إلى برنامج دليل جهات الاتصال مرةً أخرى. دليل جهات الاتصال بتقنية العميل/الخادم بنينا نسخةً من دليل جهات الاتصال في فصل الملفات باستخدام قاموس، وسنعيد استخدام ذلك المثال لكننا سنبني هذه المرة نسخة العميل/الخادم. لاحظ أن الشيفرة الأصلية كسرت إحدى قواعد الممارسة السليمة التي ذكرناها من قبل، وهي أننا أدرجنا شيفرة واجهة المستخدم في دوالنا المساعِدة، فإذا كنا سنستخدم تلك الشيفرة مرةً أخرى فسنحصل على رسائل مختلطة من العملية الفرعية والعملية الأصل، ونريد أن نعدل الشيفرة قليلًا كي نحولها إلى نموذج يمكن استخدامه، والمهم هنا إزالة أي تعليمة print من الدوال، وتمرير البيانات وسطاء، كما نريد إعادة النتيجة من كل دالة، بمجرد إنهاء ذلك نستطيع استيراد الشيفرة والوصول إلى الدوال المساعدة دون تنفيذ دالة main()‎، وعلى ذلك تكون الدوال التي سنوفرها هي: readBook(filename)‎ saveBook(book, filename)‎ addEntry(book, name, data)‎ removeEntry(book, name)‎ findEntry(book, name)‎ وستبدو الشيفرة المعدلة كما يلي: def readBook(filename='addbook.dat'): import os book = {} if os.path.exists(filename): store = open(filename,'r') for line in store: name,entry = line.strip().split(':') book[name] = entry else: store = open(filename,'w') # أنشئ ملفًا فارغًا جديدًا store.close() return book def saveBook(book, filename = "addbook.dat"): store = open(filename,'w') for name,entry in book.items(): line = "%s:%s" % (name,entry) store.write(line + '\n') store.close() def addEntry(book, name, data): book[name] = data return 'Added entry for ' + name def removeEntry(book, name): del(book[name]) return 'Deleted entry for ' + name def findEntry(book, name): if name in book.keys(): result = "%s : %s" % (name, book[name]) else: result = "Sorry, no entry for: " + name return result لاحظ أننا تجاهلنا دوال واجهة المستخدم لأننا لا نحتاج إليها هنا، لكن قد نرغب في إجراء التعديلات المناسبة للسماح لها بالعمل مثل برنامج منفصل، يكون وحدةً لنسخة العميل/الخادم، ولتكتب ذلك ليكون تدريبًا عمليًا لك. بمجرد أن نصلح الشيفرة وتكون صالحةً للعمل في برنامج مستقل، أو بحفظ الشيفرة أعلاه في ملف address_srv.py، وهو ما فعلناه، نستطيع أن نتابع كتابة شيفرة العميل/الخادم، وستتكون من الهيكل القياسي لإنشاء الأنابيب واشتقاق العملية، حيث سنقرأ في العملية الفرعية الأنبوب الوارد، ونفسر البيانات على أنها أمر متبوع بالوسطاء التي توفرت، ثم نستدعي دالة قاعدة البيانات المناسبة، وسنعرض -سواء في العملية الأصل أو الفرع- على المستخدم قائمةً، ونطلب أي بيانات إضافية وفقًا لما اختير قبل إرسال سلسلة البيانات المدمجة إلى العملية الفرع أو الخادم، ثم يقرأ العميل الاستجابة ويقدمها إلى المستخدم، وسيبدو البرنامج الرئيسي كما يلي: import os, signal, address_srv fromClient,toServer = os.pipe() fromServer,toClient = os.pipe() pid = os.fork() if pid == 0: # نحن الخادم addresses = address_srv.readBook() while True: s = os.read(fromClient,1024) cmd,data = s.split(':') if cmd == "add": details = data.split(',') name = details[0] entry = ','.join(details[1:]) s = address_srv.addEntry(addresses, name, entry) address_srv.saveBook(addresses) elif cmd == "rem": s = address_srv.removeEntry(addresses, data) address_srv.saveBook(addresses) elif cmd == "fnd": s = address_srv.findEntry(addresses, data) else: s = "ERROR: Unrecognized command: " + cmd os.write(toClient,s) else: # We are the client menu = ''' 1) Add Entry 2) Delete Entry 3) Find Entry 4) Quit ''' while True: print( menu ) try: choice = int(input('Choose an option[1-4] ')) except: continue if choice == 1: name = input('Enter the name: ') num = input('Enter the House number: ') street= input('Enter the Street name: ') town = input('Enter the Town: ') phone = input('Enter the Phone number: ') data = "%s,%s,%s,%s,%s" % (name,num,street,town,phone) cmd = "add:%s" % data elif choice == 2: name = input('Enter the name: ') cmd = 'rem:%s' % name elif choice == 3: name = input('Enter the name: ') cmd = 'fnd:%s' % name elif choice == 4: break else: print( "Invalid choice, must be between 1 and 4." ) continue os.write(toServer, cmd) print( "\nRESULT: ", os.read(fromServer,1024) ) os.kill(pid, signal.SIGTERM) لا شك أننا نستطيع ترتيب تلك الشيفرة لتكون أفضل باستخدام بعض دوال سلاسل if/elif، لكن المثال أصغر من أن يستدعي ذلك، ويجب ملاحظة بعض النقاط هي: استخدام break لإيقاف الحلقة التكرارية. استخدام continue للعودة إلى قمة الحلقة مرةً أخرى. وقد شرحنا ذلك باختصار في فصل مقدمة في البرمجة الشرطية، ويُرجع إلى توثيق كل منها للمزيد من التفاصيل. من الممكن توسيع هذا التدريب ليستخدم نسخة قاعدة البيانات التي شرحناها من قبل لتكون هي الخادم بدلًا من نسخة القاموس، وسنترك ذلك تدريبًا للقارئ. تكمن العقبة في مثل هذا النموذج من برمجة العميل/الخادم في أن الخادم لا يستطيع التحدث إلا مع العميل الذي بدأه، مع أنه يسهل إنشاء آلية لإنتاج عمليات إضافية تدرك أنها يجب أن تتصرف مثل عملاء لا خوادم، وكان من الأفضل بدء تشغيل الخادم أولًا ثم إلحاق عدة عملاء به، وهو ما سنفعله في نهاية المقال التالي حيث نشرح الشبكات بمزيد من التفصيل. خاتمة في نهاية هذا المقال نأمل أن تكون تعلمت ما يلي: تستطيع العمليات أن تتواصل فيما بينها بواسطة الأنابيب. تستطيع العمليات الأصل أن تستنسخ نفسها باستخدام os.fork. يجب إنهاء العمليات الفرعية وإلا ستعمل بلا نهاية، وتستهلك موارد الحاسوب، وننهيها باستخدام دالة os.kill. ترجمة -بتصرف- للفصل السادس والعشرين: Inter-Process Communication من كتاب Learn To Program لصاحبه Alan Gauld. اقرأ أيضًا المقال التالي: تواصل البرامج والعمليات البرمجية عبر الشبكة المقال السابق: التواصل مع نظام التشغيل عبر بايثون المدخل الشامل لتعلم علوم الحاسوب التعامل مع الملفات في البرمجة مدخل إلى شبكات الحواسيب: مصطلحات وفهم طبقات الشبكة
  23. سننظر في هذا المقال من سلسلة تعلم البرمجة في دور نظام التشغيل وكيفية الوصول إليه من بايثون، وسنشرح فيه: دور نظام التشغيل ووظيفته. وصول بايثون إلى نظام التشغيل. العمل مع الملفات والمجلدات. التعامل مع العمليات. معرفة البيانات الخاصة بالمستخدمين. التعرف على نظام التشغيل يدرك أغلب مستخدمي الحواسيب أن حواسيبهم تعمل بنظم تشغيل، سواء كانت ويندوز أو لينكس أو ماك أو غير ذلك، لكنهم قد يجهلون الدور الذي تقوم به تلك النظم على وجه الدقة، خاصةً أن أغلب نظم التشغيل التجارية تأتي مع برامج كثيرة ليست جزءًا من نظام التشغيل، مثل برامج عرض الصور، وتصفح الويب، ومحررات النصوص، لكن الجهة المصدرة للنظام تحزمها معه لأن المستخدم لن يستطيع الاستفادة من نظام التشغيل وحده. مبدأ طبقات الكعكة إذا أردنا معرفة حقيقة نظام التشغيل فيجب أن ننظر أولًا في الطريقة التي بُنيت بها الحواسيب، والتي يمكن النظر إليها على أنها كعكة متعددة الطبقات multi-layer cake، حيث يكون عتاد الحاسوب والقطع الإلكترونية المختلفة فيه الطبقة الدنيا، بما في ذلك وحدة المعالجة المركزية CPU، والقرص الصلب، والذاكرة، ونظام الإدخال والإخراج الذي يحوي مداخل USB، وفتحات بطاقات الذاكرة، ووصلات الشبكة وغيرها. أما الطبقة التي فوقها فهي BIOS، أو نظام الإدخال والإخراج البسيط Basic Input Output System، وهي أول طبقة برمجية في تكوين الحاسوب، والمسؤولة عن إقلاع الحاسوب وتوفير أبسط واجهة ممكنة للعتاد، إذ تسمح بنقل رؤوس القرص الصلب من مسار لآخر، ومن قطاع لآخر داخل المسار الواحد، وبقراءة أو كتابة البايتات المنفردة في المخازن المؤقتة للبيانات data buffers المتصلة بكل منفذ، ومع هذا لا تعرف BIOS نفسها أي معلومات عن الملفات أو المجلدات أو أي من المفاهيم العليا الأخرى التي نتعامل معها نحن المستخدمون، وإنما تعرف كيفية التعامل مع الأجهزة الإلكترونية البسيطة التي يتكون منها الحاسوب، بل قد لا تتعامل معها مباشرةً، وإنما من خلال برمجيات يثبتها مزود العتاد نفسه في أماكن حساسة داخل BIOS، وهذا شائع في بطاقات الرسوم graphics cards على وجه الخصوص، إذ تثبت الشركات المصنعة لتلك البطاقات روابط إلى تعريفات الرسوم الخاصة بها في مكان معياري داخل شيفرة BIOS، لتستدعي BIOS واجهةً متفقًا عليها، مع توفير الشركة لبرنامجها الخاص بها، وتُخزَّن BIOS عادةً في نوع خاص من رقاقات الذاكرة ذات طبيعة شبه دائمة، أي أنها لا تحذَف عند قطع التيار الكهربي، لكن يمكن إعادة كتابتها عند الحاجة لتحديث BIOS. أما الطبقة التالية لطبقة BIOS فهي طبقة نظام التشغيل، ويختلف هيكل هذه الطبقة كثيرًا وفقًا لكل نظام تشغيل، غير أنها تتكون في الغالب من نواة kernel، أو مجموعة أساسية من الخدمات مع تعريفات للعتاد device drivers، وقد توضع تعريفات العتاد داخل النواة، أو تكون وحدات تحمّلها النواة عند الحاجة، وهذا شبيه بتحميل البرامج لوحدات بايثون عند الحاجة، أما وظيفة هذه الطبقة فهي الترجمة من العتاد منخفض المستوى إلى البُنى المنطقية التي نستطيع فهمها واستخدامها، مثل الملفات والمجلدات، ومن المهم هنا ملاحظة أن نفس العتاد والـ BIOS يستطيعان تشغيل عدة نظم تشغيل مختلفة معًا، فمن السهل إعداد النظام والقرص الصلب بحيث يمكن تثبيت عدة نظم تشغيل على نفس الحاسوب، ويختار المستخدم بينها عند الإقلاع. ننتقل إلى الطبقة قبل الأخيرة في هذه الكعكة، وهي الصدفة Shell أو بيئة المستخدم، وهي واجهة رسومية في أغلب أنظمة التشغيل الحديثة، رغم توفر واجهة سطرية لها بشكل أو بآخر. أما الطبقة الأخيرة، فهي طبقة برمجيات المستخدم، التي تتكون من حزمة من البرامج التي يثبتها المستخدم أو تأتي مثبتةً مع النظام، وفيها متصفحات الويب، وبرامج البريد، ومعالجات النصوص وغيرها، كما تحتوي على أدوات برمجية مثل بايثون. لندرس مثالًا نفهم من خلاله التفاعل بين هذه الطبقات، حيث سنرى ما الذي يحدث عند فتح ملف في بايثون وقراءته. نستخدم صدفة نظام التشغيل لبدء بايثون، وتحميل ملف سكربت أيضًا. تستدعي شيفرة بايثون الدالة open()‎ الخاصة ببايثون. تستدعي بايثون داخل هذه الدالة دالة نظام تشغيل لفتح نفس الملف. يبحث نظام التشغيل عن بعض البيانات الداخلية، ويترجم اسم الملف إلى مجموعة من المسارات والقطاعات على القرص الصلب. -ويكون قد عرف أي قرص يستخدم بداهةً!-، ويحدد ذلك الملف على أنه ملف مفتوح، ويمنع تعديلات المستخدمين الآخرين عليه إن دعت الحاجة إلى ذلك. يستدعي برنامج بايثون file.read()‎. تستدعي بايثون دالة القراءة الخاصة بنظام التشغيل. يستدعي نظام التشغيل عدة دوال من BIOS لوضع رؤوس القراءة في القرص الصلب عند المواضع المناسبة. يخبر نظام التشغيل BIOS أن تقرأ أعداد البايتات المناسبة من ذلك الموضع. يكرر نظام التشغيل عملية الموضعة والقراءة تلك حتى الانتهاء من قراءة جميع البيانات المطلوبة للملف. تعيد دالة النظام البيانات إلى بايثون. تعالج بايثون البيانات، وتعرض النتائج للمستخدم من خلال دوال أخرى لنظام التشغيل والبيوس BIOS. قد يبدو هذا معقدًا، ولن نقول إنه ليس كذلك، لكن هذا التعقيد نفسه هو سبب وجود نظم التشغيل، لتوفر على المستخدمين والمبرمجين تلك المهام، فما علينا نحن المبرمجون إلا استدعاء open()‎ وread()‎. التحكم في العمليات يوفر نظام التشغيل إمكانية بدء البرامج وتشغيلها، إضافةً إلى ما ذكرناه سابقًا من التحكم في الوصول إلى العتاد، كما يوفر الآليات اللازمة لإدارة تلك البرامج التي تعمل بالتوازي -أي في نفس الوقت– على الحاسوب، لأن عدد المعالجات الموجود على اللوحة الأم أقل بكثير من البرامج التي ستعمل على نظام التشغيل، لذا تنفذ نظم التشغيل عمليةً تسمى التقسيم الزمني time slicing، وهي إعطاء كل برنامج من البرامج العاملة حاليًا على الحاسوب حصةً صغيرةً من المعالج؛ ولفترة قصيرة من الزمن، قبل أن تنقل تلك الحصة بسرعة إلى عملية أخرى أو برنامج آخر، فتعطي ذلك الإحساس بأن جميع البرامج تعمل في نفس الوقت، وتختلف كفاءة نظم التشغيل في تنفيذ هذه العملية، فلم تكن الإصدارات الأولى من ويندوز وماك MacOS قادرةً على إجرائها وإدارتها إلا بمساعدة البرامج نفسها، فإذا فشل أحد البرامج في توفير نقطة توقف مناسبة فإن الحاسوب كله يتوقف عن الاستجابة، فيما يعرف بالتعليق Hanging. وتستخدم أغلب نظم التشغيل الحديثة نظامًا يسمى تعدد المهام الوقائي pre-emptive multi-tasking، حيث يقاطع نظام التشغيل البرامج بغض النظر عما تفعله تلك البرامج عند المقاطعة، ويعطي البرنامج التالي الوصول إلى المعالج تلقائيًا، وتُستخدم عدة خوارزميات هنا لتحسين كفاءة تلك العملية وفقًا لنظام التشغيل نفسه، مثل التبديل الحلَقي round robin، أو الأحدث استخدامًا most recently used، أو الأقدم استخدامًا least recently used، ولا تهمنا هذه الخوارزميات نحن المبرمجون، ولا بأس إن افترضنا أن تلك البرامج المتعددة تعمل بالتوازي. تأتي أغلب الحواسيب الحديثة بمعالجات متعددة قد تكون رقاقات متعددةً من السليكون، أو عدة نوى -عدة معالجات منفردة- على رقاقة واحدة، ووظيفة نظام التشغيل هنا أن يخصص العمليات الحالية إلى المعالجات والأنوية ليضمن الاستخدام الأمثل، ونعيد التذكير هنا أن ذلك لا يهمنا، ونترك هذه المهمة لنظام التشغيل نفسه. صلاحيات المستخدمين والأمان تسمح أغلب نظم التشغيل الحديثة بوجود عدة مستخدمين على نفس الحاسوب، لكل واحد منهم ملفاته الخاصة وإعدادات سطح مكتبه وغير ذلك، وتزيد بعض نظم التشغيل على ذلك بأن تسمح بولوج عدة مستخدمين إلى نفس النظام في نفس الوقت، فيما يعرف باسم الجلسات المتعددة multi-session، لكن تعدد المستخدمين هذا تأتي معه مشكلة الأمان، فمن المهم ألا يستطيع سعيد رؤية بيانات محمد، وكذلك العكس، إلا إذا أعطى محمد صلاحية الوصول إلى ملفاته إلى سعيد، ويكون نظام التشغيل مسؤولًا عن ضمان حماية ملفات كل مستخدم، عن طريق منع الوصول إليها إلا من الأشخاص المصرح لهم فقط. استخدام نظام التشغيل في البرامج قد نتساءل عن جدوى هذا الحديث عن أنظمة التشغيل لنا نحن المبرمجون، بما أن وظيفة ذلك النظام أن يجنبنا كل تلك التفاصيل التي ذكرناها، من التعامل مع العتاد وتنظيم عمليات تشغيل البرامج. والإجابة على ذلك أننا قد نحتاج أحيانًا إلى التعامل مع ذلك العتاد، ولا تستطيع الدوال البرمجية المعتادة تنفيذ ما نريده، أو ربما نحتاج إلى تشغيل برنامج آخر من داخل برنامجنا مثلًا، بل ربما نحتاج -من داخل برنامجنا- إلى التحكم في الحاسوب بنفس الطريقة التي يتحكم بها المستخدم فيه، وحل ذلك كله أن يكون لنا صلاحية الوصول إلى طبقة نظام التشغيل نفسه. وتوفر بايثون عددًا من الوحدات التي يمكن استخدامها للتفاعل مع نظام التشغيل، لعل أهمها وحدة os، التي توفر واجهةً مشتركةً لأي نظام تشغيل، من خلال تحميل وحدات منخفضة المستوى lower level، وستتصرف أنظمة التشغيل تصرفًا مختلفًا وفقًا للطريقة التي تنفذ بها تلك الدوال داخليًا، ولا ينتج عن هذا السلوك مشاكل غالبًا، لكن إذا واجهنا سلوكًا غريبًا من وحدة os فنرجع إلى التوثيق لنرى إن كان ثمة قيود على نظام التشغيل الخاص الذي نستخدمه. أما وحدات النظام الأخرى التي سندرسها فهي الوحدة shutil التي توفر للمبرمجين تحكمًا في الملفات والمجلدات على مستوى المستخدم، والوحدتان os.path وglob اللتان توفران أدوات للتنقل في نظام ملفات الحاسوب، وهذا هو الجزء الذي سننظر فيه أولًا. معالجة الملفات شرحنا كيفية التعامل مع الملفات في مقال التعامل مع الملفات في البرمجة فما الذي نريده من نظام التشغيل طالما نستطيع التعامل معها؟ والجواب أن ما ذكرناه في مقال التعامل مع الملفات في البرمجة هو أننا نستطيع إنشاء الملفات وتعديلها، لكننا لم نذكر حذفها لأننا لم نكن نستطيع ذلك بتوابع الملفات العادية، أما هنا فنستطيع استخدام نظام التشغيل في حذف الملفات، كما أن open()‎ ستكون كافيةً إذا علمنا مكان الملف، لكن كيف نجده إذا لم نعرف مكانه، بل ماذا لو أردنا معالجة مجموعات من الملفات؟ مثل ملفات الصور في مجلد ما، وكذلك التحكم الدقيق في القراءة من الملفات، حيث كانت التوابع القياسية التي شرحناها من قبل تقرأ سطرًا واحدًا فقط أو الملف كله، فماذا لو أردنا قراءة بضعة بايتات فقط؟ إن دوال نظام التشغيل هي الحل لتلك الحالات كلها. إيجاد الملفات أول وحدة سندرسها هي الوحدة glob التي نستخدمها للعثور على الملفات، والتي تجلب قوائم بأسماء الملفات، وتعود تسميتها إلى نظام يونكس، حيث استُخدم المصطلح لوصف عملية تحديد مجموعات من الملفات باستخدام محارف بدل wildcards، أما الاسم نفسه فيعود تاريخه إلى أمر قديم في نظم التشغيل استُخدم لإجراء عملية التوسع، وهو اختصار global، والوحدة سهلة الاستخدام، فبعد استيرادها نجد دالةً وحيدةً هي glob()‎، ونمرر إليها نمطًا pattern لتطابقه، فتعيد قائمةً بأسماء الملفات: import glob files = glob.glob("*.txt") print( files ) سنحصل على قائمة من الملفات النصية في المجلد الحالي، وهذا يطرح سؤالًا حول كيفية معرفة المجلد الحالي الذي نحن فيه، وهل نستطيع تغييره أم لا؟ ولا شك أننا نستطيع معرفة المجلد وتغييره باستخدام وحدة os: import os print( os.getcwd() ) #cwd=current working directory os.chdir("/usr/local") #chdir=change working directory print( os.getcwd() ) print( os.listdir('.') ) #عرض المجلدات الجديدة تعلمنا البحث عن ملف في المجلد الحالي، وكيف ننتقل من ذلك المجلد إلى أي مجلد نريد، لكن لا زال البحث عن ملف ما عمليةً متعبةً، ولتسهيلها سنستخدم الدالة os.walk()‎، فللعثور على ملف في مكان ما من نقطة بداية نستخدام os.walk، كما سننشئ دالة findfile التي نستطيع استخدامها في برامجنا، لكن سننشئ أولًا بيئة اختبار تتكون من هرمية مجلدات تحت مجلد الجذر Root، وسنضع بعض الملفات في كل مجلد، وسيكون الملف الذي نبحث عنه في أحدها، وقد سميناه traget.txt، ويمكن رؤية هذه الهرمية في لقطة الشاشة التالية: تأخذ دالة os.walk معاملاً هو نقطة البداية، وتعيد مولدًا generator هو أشبه بقائمة وهمية تبني نفسها عند الحاجة، ويتكون من صفوف tuples فيها ثلاثة عناصر، تسمى أحيانًا بالثلاثي triplet أو 3-tuple، وهذه العناصر هي: الجذر، قائمة المجلدات في الجذر الحالي، قائمة الملفات الحالية في مجلد الجذر. فإذا نظرنا إلى الهرمية التي أنشأناها، فسنتوقع أن يبدو صف tuple الأول كما يلي: ( 'Root', ['D1','D2','D3'], ['FA.txt','FB.txt'] ) نتحقق بسهولة من ذلك بكتابة حلقة for في المحث التفاعلي: >>> for t in os.walk('Root'): ... print( t ) ... ('Root', ['D1', 'D2', 'D3'], ['FA.txt', 'FB.txt']) ('Root/D1', ['D1-1'], ['FC.txt']) ('Root/D1/D1-1', [], ['FF.txt']) ('Root/D2', [], ['FD.txt']) ('Root/D3', ['D3-1'], ['FE.txt']) ('Root/D3/D3-1', [], ['target.txt']) >>> يوضح هذا المسارَ الذي أخذته os.walk، كما يوضح كيف يمكن العثور على ملف، وإنشاء مساره الكامل بالبحث في عنصر files من الصفوف التي تعيدها os.walk، ودمج الاسم بمجرد العثور عليه مع قيمة root للصف الذي يحويه. وإذا كتبنا دالتنا بحيث تستخدم التعابير النمطية وتعيد قائمةً، فنستطيع إنشاء دالة تكون أقوى من glob.glob البسيطة التي رأيناها من قبل، لكنها ستكون أبطأ أيضًا، لنجربها وننظر كيف تبدو: # على دالة واحدة findfile.py تحتوي وحدة # os.walk() المبنية على استخدام دالة ،find_file() هي دالة import os,re def find_file(filepattern, base = '.'): regex = re.compile(filepattern) matches = [] for root,dirs,files in os.walk(base): for f in files: if regex.match(f): matches.append(root + '/' + f) return matches احفظ ذلك في ملف اسمه findfile.py، ثم لنختبر المحث التفاعلي كما يلي: >>> import findfile >>> findfile.find_file('t.*','Root') ['Root/D3/D3-1/target.txt'] >>> findfile.find_file('F.*','Root') ['Root/FA.txt', 'Root/FB.txt', 'Root/D1/FC.txt', 'Root/D1/D1-1/FF.txt', 'Root/D2 /FD.txt', 'Root/D3/FE.txt'] >>> findfile.find_file('.*\.txt','Root') ['Root/FA.txt', 'Root/FB.txt', 'Root/D1/FC.txt', 'Root/D1/D1-1/FF.txt', 'Root/D2 /FD.txt', 'Root/D3/FE.txt', 'Root/D3/D3-1/target.txt'] >>> findfile.find_file('D.*','Root') [] لاحظ أن الوسيط الأول في find_file()‎ هو ‎'t.*'‎، وتذكر أنه تعبير نمطي وليس محرف بدل لاسم ملف؛ مثل الذي استخدمناه مع glob، لذا فإنه يشير إلى t متبوعةً بعدد من المحارف يساوي صفرًا أو أكثر، وليس ملفًا فقط مثل t.txt. يظهِر الخرج أن برنامجنا يعمل، ونلاحظ في المثال الأخير أنه يعمل فقط في حالة الملفات لأن أسماء المجلدات تكون في قوائم dirs التي لا نستطيع التحقق منها. جرب إضافة دالة جديدة إلى وحدة findfile سمِّها find_dir()‎، للبحث عن المجلدات التي تطابق تعبيرًا نمطيًا ما، ثم ادمجهما معًا لإنشاء دالة ثالثة هي find_all()‎ تبحث في كل من الملفات والمجلدات. نقل الملفات ونسخها وحذفها تحدثنا في مقال التعامل مع الملفات عن كيفية نسخ ملف من خلال قراءته ثم كتابته إلى موقع جديد، إلا أنه يمكن استخدام نظام التشغيل لينفذ هذا العمل بدلًا منا بتعليمة واحدة، ونستخدم في بايثون وحدة shutil لمثل هذه المهام، وهي تحتوي على عدة دوال مفيدة، سندرس منها ما يلي: الدالة copy(src, dst)‎ تنسخ هذه الدالة الملف المصدر src إلى الملف أو المجلد الوجهة dst، فإذا كانت الوجهة مجلدًا فسيُنشأ ملف له نفس اسم الملف المصدر، أو يكتب فوقه overwritten في المجلد المحدد، وتُنسخ بتات الصلاحية permission bits كذلك، وتعطى أسماء المصدر src والوجهة dst في صورة سلاسل نصية. الدالة move(src, dst)‎ تنقل هذه الدالة الملف أو المجلد تعاوديًا recursively إلى موقع جديد، فإذا كانت الوجهة على نظام الملفات الحالي فستعاد تسمية الملف المصدر src، وإلا فستنسخ الدالة الملف src إلى الوجهة dst، ثم تحذف المصدر src. كما سندرس أيضًا الدوال التالية من وحدة os: الدالة remove(path)‎ تحذف هذه الدالة مسار الملف، فإذا كان المسار path مجلدًا فيُرفع OSError، ولحذف المجلد انظر في rmdir()‎. rename(src, dst)‎ تعيد هذه الدالة تسمية الملف أو المجلد المصدر src ليكون اسم الملف الوجهة dst، فإذا كانت الوجهة مجلدًا dst فسيُرفع خطأ OSError. وأبسط طريقة لنرى بها هذه الدوال عمليًا هي تجربتها في المحث التفاعلي باستخدام بنية المجلد/الملف التي أنشأناها لمثال os.walk السابق: >>> import os >>> import shutil as sh >>> import glob as g >>> os.chdir('Root') >>> os.listdir('.') ['D1', 'D2', 'D3', 'FA.txt', 'FB.txt'] >>> sh.copy('FA.txt', 'CA.txt') >>> os.listdir('.') ['CA.txt', 'D1', 'D2', 'D3', 'FA.txt', 'FB.txt'] >>> sh.move('FB.txt','CB.txt') >>> os.listdir('.') ['CA.txt', 'CB.txt', 'D1', 'D2', 'D3', 'FA.txt'] >>> os.remove('FA.txt') >>> os.listdir('.') ['CA.txt', 'CB.txt', 'D1', 'D2', 'D3'] >>> for f in g.glob('*.txt'): ... newname = f.replace('C','F') ... os.rename(f,newname) ... >>> os.listdir('.') ['D1', 'D2', 'D3', 'FA.txt', 'FB.txt'] >>> >>> في الأمثلة السابقة نقلنا الملفات ونسخناها وحذفنا الملف الأصلي، ثم أعدنا التسمية لاستعادة المجلد إلى حالته الأولى، ويستطيع المستخدم تنفيذ كل تلك عمليات في سطر الأوامر أو في مدير الملفات، لكننا نفذناها هنا باستخدام بايثون. لاحظ استخدام حلقة for لتنفيذ التغييرات المتعددة، وقد كان باستطاعتنا إضافة جميع أشكال التحققات والقواعد داخل الحلقة، للسماح بإنشاء بعض الأدوات القوية للتعديل في الملفات، وبكتابة تلك الشيفرة في سكربت يمكننا تنفيذ تلك التغييرات بالقدر الذي نشاء بمجرد تشغيل السكربت. اختبار خصائص الملفات نحتاج عند التعامل مع الملفات إلى معرفة خصائصها، فمثلًا عندما نقرأ قائمة مجلد من glob، سنرغب في معرفة هل ما نريده ملف أم مجلد، وكذلك معرفة آخر مرة عدِّل عليه فيها، أو مراقبة ذلك لنرى إن كان يُعدَّل بانتظام، مما يدل على أن مستخدمًا غيرنا -أو حتى برنامجًا آخر- له وصول إلى الملف، أو ربما نريد مراقبة حجم الملف، لنرى إن كان يزيد مثلًا، ونستطيع فعل كل تلك الأمور من برامجنا باستغلال مزايا نظام التشغيل، ولكن يجب أن نرى أولًا كيف نتحقق من نوع الملف الذي نتعامل معه: import os.path as p import glob for item in glob.glob('*') if p.isfile(item): print( item, ' is a file' ) elif p.isdir(item): print( item, ' is a directory' ) else: print( item, ' is of unknown type' ) لاحظ أن دوال الاختبار توجد في وحدة os.path، وأن هناك عدة اختبارات أخرى متاحة، ويمكن الرجوع إليها والقراءة عنها في توثيق وحدة os.path. سننظر الآن في ميزة عمر الملف، إذ توجد عدة تواريخ مهمة في حياة كل الملف، أولها تاريخ إنشائه، ثم تاريخ آخر تعديل عليه، وأخيرًا تاريخ آخر وصول إليه، وقد لا توفر بعض أنظمة التشغيل جميع تلك التواريخ، لكن أغلبها توفر تواريخ الإنشاء والتعديل، ويمكن الوصول إليهما في بايثون من خلال وحدة os.path باستخدام الدالتين ctime()‎ وmtime()‎ على الترتيب، وسننظر في بعض الملفات الموجودة في بنية Root لدينا، وقد أنشئت جميعها بنفس الوقت تقريبًا، مع اختلاف طفيف لملفات المستوى الأعلى، لأننا أجرينا تعديلات عليها في مثالنا السابق باستخدام rename()‎. >>> import time as t >>> os.listdir('.') >>> for r,d,files in os.walk('.'): ... for f in files: ... print( f,' created: %s:%s:%s' % t.localtime(p.getctime(r+'/'+f))[3:6] ) ... print( f,' modified: %s:%s:%s' % t.localtime(p.getmtime(r+'/'+f))[3:6]) ... FA.txt created: 13:42:11 FA.txt modified: 13:36:27 FB.txt created: 13:42:11 FB.txt modified: 17:32:5 FC.txt created: 17:32:46 FC.txt modified: 17:32:5 FF.txt created: 17:34:3 FF.txt modified: 17:32:5 FD.txt created: 17:33:12 FD.txt modified: 17:32:5 FE.txt created: 17:33:53 FE.txt modified: 17:32:5 target.txt created: 17:34:28 target.txt modified: 17:32:5 >>> لاحظ النتيجة الغريبة لملف FA حيث يظهر أنه عُدّل قبل إنشائه! لأننا أنشأناه نسخةً من الملف الأصلي ثم حذفنا الأصل، وأعدنا تسمية النسخة بنفس اسم الملف الأصلي، فرأى نظام التشغيل أن إعادة التسمية لم تغير شيئًا من المحتوى فلم يغير تاريخ التعديل -وهو وقت عملية النسخ- لكنه رأى عملية إعادة التسمية على أنها توقيت إنشاء اسم الملف الحالي، فلابد أن هذا ملف FA.txt جديد بما أننا حذفنا الملف الأصلي! يختلف أمر الملف FB.txt قليلًا، إذ لم يتغير المحتوى لأننا نقلنا الملف بدلًا من نسخه، لذا تاريخ آخر تعديل هو نفسه تاريخ الإنشاء الأصلي -انظر الملفات الأخرى-، لكن مرةً أخرى يرى نظام التشغيل عملية إعادة التسمية على أنها إنتاج لملف FB.txt جديد، فتظهر هنا قيمة الوقت الأخرى. في نظام التشغيل دالة تستطيع إعادة أغلب المعلومات التي نحتاجها عن ملف في صف tuple واحد، وهي دالة stat()‎، ولها عدة صور، إلا أننا لن ندرس إلا النسخة الموجودة في وحدة os، حيث تعيد os.stat()‎ صف tuple يحتوي على ما يلي: st_mode: بتات الحماية. st_ino: رقم مؤشر الفهرسة inode. st_dev: جهاز. st_nlink: عدد الروابط الصلبة hard links. st_uid: معرِّف المستخدم المالك. st_gid: معرِّف المجموعة للمالك. st_size: حجم الملف بالبايت. st_atime: وقت آخر وصول للملف. st_mtime: وقت آخر تعديل للمحتوى. st_ctime: وقت الإنشاء، لكن وفقًا للمنصة. لاحظ أنه قد توجد بعض الحقول الإضافية أحيانًا وفقًا لما يدعمه نظام التشغيل نفسه، فتحقق من توثيق المنصة لديك. لننظر المثال التالي المطبق على ملف المستوى الأعلى FA.txt: >>> fmtString = "protection: %s\nsize: %s\naccessed: %s\ncreated: %s" >>> stats = os.stat('FA.txt') >>> print( fmtString % stats[0],stats[6],stats[7],stats[9] ) protection: 33279 size: 0 access: 1132407387 created: 1132407731 نحتاج لفك ترميز جميع القيم لنفهمها، باستثناء الحجم الذي ما هو إلا عدد البايتات في الملف، وسنرى كيفية العمل مع كل منها لاحقًا، أما العلامات الزمنية timestamps فهي سهلة لأن الأرقام فيها تمثل عدد الثواني لكل دورة، وقد شرحنا ذلك من قبل، ونستطيع استخدام دوال وحدة time، مثلما فعلنا في localtime()‎ أعلاه لتحويلها إلى بنية بيانات ذات فائدة لنا أو إلى سلسلة نصية. وتحتاج صيغة الحماية protection لفك ترميزها أولًا، باستخدام بعض القيم الخاصة الموجودة في وحدة stat، إلا أننا نحتاج إلى استخدام بعض العوامل operators الأخرى، والتي تعرف بالعوامل الثنائية bitwise operators. العوامل الثنائية والرايات تحتوي وحدة stat على مجموعة من الثوابت مسبقة التعريف، مثل المتغيرات ذات القيم التي لا تتغير، وتسمح تلك الثوابت بفك ترميز بيانات الصلاحيات باستخدام العوامل الثنائية، وهذه العوامل هي نفسها العوامل البوليانية المنطقية التي استخدمناها من قبل مثل and وor وnot، إضافةً إلى عامل جديد هو xor، لكن الفرق أن هذه تعمل على البتات الثنائية المنفردة من البيانات، بدلًا من القيمة الكلية. يمكن العثور على القيم الموجودة في stat بالنظر إلى المتغيرات المعرَّفة مثل قيم ثنائية، وتوفر بايثون خيار صيغة ثنائية مضمنة فيها هي bin، والتي تبدو كما يلي: >>> bin(22) '0b10110' يمثل الجزء 0b في بداية السلسلة النصية أسلوب بايثون في إخبارنا أن هذا عدد ثنائي، ونستطيع تحويل السلسلة النصية الثنائية إلى عدد عشري باستخدام دالة int، من خلال توفير وسيط ثانٍ قيمته 2، لأن قاعدة العدد الثنائي هي 2 في الاصطلاح الرياضي: >>> int('0b10110',2) 22 >>> int('10110',2) 22 لاحظ أن 0b في بداية السلسلة النصية اختيارية، لأن الوسيط الثاني 2 يخبر بايثون بوجوب معاملة السلسلة النصية على أنها ثنائية، وهذا مفيد إذا كنا نقرأ السلسلة من المستخدم مثلًا بدلًا من استخدام خرج bin. العوامل الثنائية Bitwise Operators سننظر الآن في كيفية عمل العوامل الثنائية باستخدام دالة bin لعرض قيم الدخل والخرج، ولننظر أولًا في تأثير and الثنائية التي رمزها &: >>> print( bin(5) ) '0b101' >>> print( bin(1) ) '0b001' >>> print( bin(2) ) '0b010' >>> print( bin(5 & 1) ) '0b001' >>> print( bin(5 & 2) ) '0b000' سنراجع تلك النتائج لنرى ما يحدث، تذكر أن and المنطقية تتحقق -أي تكون true- إذا وفقط إذا تحققت كلا القيمتين، أي كانتا true، وبالمثل فإن & الثنائية تكون true -قيمتها 1- إذا تحقق البتّان الموافقان -كان لهما القيمة 1-، وإذا نظرنا إلى ‎5 & 1 فسنجد أن البت الذي في أقصى اليمين يتحقق في كل من 5 و1، أي تكون قيمتها 1، وبناءً عليه فإن البت الذي في أقصى اليمين لـ ‎5 & 1 سيكون 1 أيضًا، أما في حالة ‎5 & 2 فلا توجد حالة تكون فيها لبتين اثنين القيمة 1 في كل من 5 و2، وعليه تكون النتيجة كلها أصفارًا بالنسبة لـ ‎5 & 2. يقود هذا السلوك إلى ميزة خاصة لعمليات & الثنائية، فمن خلال "جمع" قيمة ثنائية مع عدد يحتوي على رقم ثنائي وحيد مضبوط على القيمة 1، نستطيع معرفة إن كانت قيمة البت الموافقة في القيمة التي نختبرها هي 1 أيضًا أم لا، فإن كانت كذلك فسنحصل على نتيجة غير صفرية، وهي الموافقة للقيمة True في الاصطلاح البولياني، لنستعرض الآن مثالًا نفترض فيه أننا نريد التحقق من كون البت الثاني في عدد معيَّنًا أم لا، ونحن نعلم مما سبق أن القيمة التي فيها بت واحد في الموضع الثاني -إذا بدأنا العد من اليمين- هي 2: BIT2 = 2 for n in range(10): if n & BIT2: print( n,' = ',bin(n) ) ستكون النتيجة أن البت الثانية معينة -أي set- في كل من 2 و3 و6 و7. نستطيع تنفيذ أمور مشابهة لذلك باستخدام or الثنائية، والتي نستخدم لها الرمز |، وكذلك not الثنائية التي لها الرمز ~، رغم أن هذه الأخيرة قد يكون لها بعض النتائج الغريبة المتعلقة بكيفية تخزين الحواسيب للأعداد السالبة، جرب استخدام دالة bin()‎ مع هذه العوامل لعرض دخل وخرج البتّات لترى سلوكها، وتذكر أن توازن بين القيم بتًا بتًا. أما العامل الثنائي الأخير فهو or الحصرية أو xor، التي لها الرمز ^، وتتحقق -أي تكون true- إن تحققت قيمة واحدة فقط من قيمتي الاختبار، لكنها لا تتحقق عند تحقق كلا القيمتين، وسنحصل على نتائج مثيرة للاهتمام وفقًا لهذه القاعدة، فمثلًا إذا طبقنا هذا العامل على أي عدد مع نفسه فسنحصل على صفر، أما إذا طبقناه على أي عدد مع مفتاح فسنحصل على نتيجة، وإذا طبقنا هذا العامل مرةً ثانيةً على النتيجة والمفتاح فسنحصل على القيمة الأصلية، وهذا السلوك مفيد جدًا في علم التشفير. لننظر في بعض الأمثلة قبل أن نعود إلى وحدة stat ونبحث في قيم الصلاحيات. >>> print( bin(5 ^ 2) ) '0b111' >>> print( bin(5^5) ) '0b000' >>> print( bin((5^2)^2) ) '0b101' لاحظ أن النتيجة في الحالة الأخيرة هي سلسلة ثنائية للعدد 5، أي أننا إذا طبقنا العامل xor مرتين فسنحصل على القيمة الأصلية. الرايات Flags يسمى المتغير المستخدَم لتخزين قيمة بوليانية رايةً flag، لأن الراية يمكن رفعها أو خفضها، وعندما يكون لدينا قيم رايات كثيرة تتعلق بوحدة واحدة؛ فمن الشائع استخدام عدد واحد لتخزين الفئة المجمَّعة للرايات، باستخدام بتات بيانات منفردة لتمثيل كل راية منفردة، ويمكن جلب قيم الرايات فيما بعد باستخدام العوامل الثنائية التي شرحناها أعلاه، مدمجةً مع قيمة فك ترميز تعرف باسم القناع mask، مما يسمح لنا باستخراج البتات التي نريدها تحديدًا، فعلى سبيل المثال، كانت القيمة BIT2 أعلاه قناعًا لاستخراج البت الثاني، وتشكل وحدة stat مجموعةً من الأقنعة مسبقة التعريف لاختبار رايات الصلاحيات التي تعيدها الدالة os.stat()‎. استخدام ثوابت stat مع العوامل الثنائية سننظر الآن إلى بعض قيم stat مثل أعداد ثنائية، ونرى إن كنا نستطيع معرفة كيفية استخدامها: >>> import stat >>> dir(stat) ['ST_ATIME', 'ST_CTIME', 'ST_DEV', 'ST_GID', 'ST_INO', 'ST_MODE', 'ST_MTIME', 'ST_NLINK', 'ST_SIZE', 'ST_UID', 'S_ENFMT', 'S_IEXEC', 'S_IFBLK', 'S_IFCHR', 'S_IFDIR', 'S_IFIFO', 'S_IFLNK', 'S_IFMT', 'S_IFREG', 'S_IFSOCK', 'S_IMODE', 'S_IREAD', 'S_IRGRP', 'S_IROTH', 'S_IRUSR', 'S_IRWXG', 'S_IRWXO', 'S_IRWXU', 'S_ISBLK','S_ISCHR', 'S_ISDIR', 'S_ISFIFO', 'S_ISGID', 'S_ISLNK', 'S_ISREG', 'S_ISSOCK', 'S_ISUID', 'S_ISVTX', 'S_IWGRP', 'S_IWOTH', 'S_IWRITE', 'S_IWUSR', 'S_IXGRP', 'S_IXOTH', 'S_IXUSR', '__builtins__', '__doc__', '__file__', '__name__'] >>> print( bin(stat.S_IREAD) ) '0b100000000' >>> print( bin(stat.S_IWRITE) ) '0b010000000' >>> print( bin(stat.S_IEXEC) ) '0b001000000' الملاحظة الأولى هنا هي تعريفنا للكثير من الثوابت، والثانية أن القيم الثلاثة التي طبعناها هي القيم التي تحدد إمكانية قراءة الملف أو كتابته أو تنفيذه على الترتيب، ولاحظ أن لكل قيمة مجموعة بتات واحدة، كما في قيمة BIT2 في الأمثلة السابقة، لذا نستطيع استخدام عامل and الثنائي لإيجاد صلاحيات ملفنا، بعد استدعاء الدالة os.stat()‎، كما يلي: import os, stat permission = os.stat('FA.txt')[0] if permission & stat.S_IREAD: print( 'The file is readable' ) if permission & stat.S_IWRITE: print( 'The file is writeable' ) if permission & stat.S_IEXEC: print( 'The file is executable' ) هذه هي الصلاحيات التي نريدها غالبًا، ويمكنك الرجوع إلى توثيق وحدة stat للمزيد من الصلاحيات، والتحقق من فهمها بتجربتها في محث بايثون. كما توجد دالة access()‎ المساعِدة والموجودة في وحدة os، والتي تسمح لنا بالتحقق من أغلب صلاحيات الوصول الشائعة، غير أن منظور القناع البِتي bitmask الموصوف أعلاه يغطي خيارات أكثر، لذا يمكن استخدامه في المواضع التي لا يصلح استخدام access()‎ فيها. تغيير صلاحيات الملفات بعد أن عرفنا صلاحيات ملف ما، نستطيع استخدام وحدة os لتغييرها إلى ما يناسبنا، وتستخدم بايثون اصطلاحات يونكس لتغييرها، حيث يكون لكل ملف مجموعة من ثلاث رايات هي (قراءة read، كتابة write، تنفيذ execute)، لكل تصنيف من تصنيفات المستخدمين الثلاثة (المالك owner، المجموعة المالكة group، العالم world أي بقية المستخدمين)، لذا سيكون لدينا 9 رايات لكل ملف، وتمثَّل تلك الرايات بتسعة بتّات، تشكل البتات اليمنى في راية الصلاحيات التي تعيدها os.stat. تمثَّل مجموعات الصلاحيات تلك في التوثيق بسلسلة من تسعة محارف، تتكون من ثلاث مجموعات من المحارف rwx، مع شرطةٍ بدل المحرف إذا لم تكن الصلاحية مضبوطةً أو معيَّنةً set، وبناءً على ذلك ستعني السلسلة النصية "rwxr-xr--‎" أن للمستخدم صلاحية القراءة والكتابة والتنفيذ rwx، وللمجموعة صلاحية القراءة والتنفيذ r-x، وللنوع الثالث الذي هو العالم صلاحية القراءة فقط r--‎، وإذا أردنا تغيير الصلاحيات فسنعين البتات وفقًا لما نريد التغيير إليه، لذلك سنستخدم الدالة chmod()‎ في وحدة os، حيث تأخذ وسيطًا هو الرقم المكون من 9 بتات، فعلى سبيل المثال يمثل الرقم 0b111101100 الصلاحيات rwxr-xr--‎، ونستخدم ذلك لضبط الوصول لملف ما كما يلي: >>> os.chmod('FA.txt',0b111101100) وإذا كانت لديك خبرة سابقة بالأعداد الثُمانية octal فستعرف أن كل رقم ثُماني يمثل ثلاثة بتات ثنائية، وعلى ذلك نستطيع التعبير عن الصلاحيات بسهولة في ثلاثة أرقام ثُمانية، ويربط الجدول التالي القيم الثُمانية بنظائرها المكافئة لها من الأرقام الثنائية وصلاحيات rwx: table { width: 100%; } thead { vertical-align: middle; text-align: center; } td, th { border: 1px solid #dddddd; text-align: right; padding: 8px; text-align: inherit; } tr:nth-child(even) { background-color: #dddddd; } الثُماني الثنائي "rwx" 0 0b000 "---" 1 0b001 "‎--x" 2 0b010 "‎-w-" 3 0b011 "‎-wx" 4 0b100 "r--‎" 5 0b101 "r-x" 6 0b110 "rw-‎" 7 0b111 "rwx" لن يجد مستخدمو يونكس مشكلةً في التعبير عن الصلاحيات بهذه الطريقة، ويمكن استخدام ذلك في بايثون أيضًا لجعل استدعاء chmod يبدو كما يلي: >>> # يجب استخدام صفر في البداية ليُعامل على أنه ثُماني >>> os.chmod('FA.txt',0754) ينفذ المثالان أعلاه نفس الأمر، حيث يعيّنان صلاحيات المالكين لتكون قراءةً وكتابةً وتنفيذًا، ويعيّنان صلاحيات المجموعة لتكون قراءةً وتنفيذًا فقط، وصلاحيات العالم لتكون قراءةً فقط، وتجدر الإشارة إلى أن النسخة الثُمانية أسهل في الكتابة إذا أردت التعود على التحويلات بين الثُمانية والثنائية. المسارات والملفات والمجلدات من الشائع عند تطوير برنامج ما أن تكون ملفات البيانات في نفس المجلد الذي فيه ملفات البرنامج، ليسهل العثور على الملفات عند الحاجة، أما إذا كان استخدام البرنامج عامًا فلا يمكن افتراض أن الملفات ستكون في مواضع معروفة، لذا قد نحتاج إلى البحث عنها باستخدام glob أو os.walk اللتين شرحناهما أعلاه، فإذا وجدنا الملف الذي نريده وأردنا فتحه أو فحص خصائصه؛ فسنحتاج إلى تعيين المسار الكامل له، أما إذا كان لدينا اسم المسار الكامل فقد نفككه لاستخراج اسم الملف أو المجلد فقط، لوضعه في متغير مثلًا، وتوفر os.path إمكانية تنفيذ مثل تلك المهام. يُنظر إلى أسماء الملفات في بايثون على أنها تتكون من عدة أجزاء، فهناك حرف اختياري يمثل القرص الذي يوجد عليه الملف، رغم أن هذا قد لا يكون في جميع أنظمة التشغيل، إذ ليس لأنظمة التشغيل غير ويندوز هذا المفهوم الذي يضع اسم القرص الصلب جزءًا من اسم الملف، ثم يأتي تسلسل من أسماء المجلدات تفصل بينها بعض المحارف المحددة، ففي بايثون مثلًا نستخدم /، لكن قد يكون لبعض أنظمة التشغيل محارفها الخاصة، وأخيرًا لدينا اسم الملف أو الاسم القاعدي basename، والذي يحوي صورةً من صور امتدادات الملفات extension: F:/PROJECTS/PYTHON/Root/FA.txt يخبرنا المسار أعلاه أن الملف المسمى FA.txt موجود في مجلد الجذر Root، الذي يوجد بدوره في مجلد PYTHON تحت مجلد PROJECTS، في مجلد المستوى الأعلى للقرص F:‎، ويحمل الملف امتداد الملفات النصية ‎.txt. نستطيع الآن استخراج الاسم القاعدي base name، والامتداد extension، وتسلسل المجلدات من المسار الكامل، باستخدام الدوال الموجودة في وحدة os.path، كما يلي: >>> pth = F:/PROJECTS/PYTHON/Root/FA.txt >>> stem, aFile = os.path.split(pth) >>> print( 'stem : ',stem, '\nfile : ',aFile ) stem : F:/PROJECTS/PYTHON/Root file : FA.txt >>> # this only works on OS with drive concept, like Windows >>> print( os.path.splitdrive(pth) ) ('F:', '/PROJECTS/PYTHON/Root/FA.txt') >>> print( os.path.dirname(pth) ) F:/PROJECTS/PYTHON/Root >>> print( os.path.basename(pth) ) FA.txt >>> print( os.path.splitext(aFile) ) ('FA', '.txt') وندمجها معًا بالشكل: >>> print( os.path.join(stem,aFile) ) F:/PROJECTS/PYTHON/Root\\FA.txt يجب ملاحظة أن os.path.join تستخدم محرف الفصل الرسمي للنظام، فإذا أردنا بناء مسار يصلح للعمل على نظم تشغيل مختلفة فيجب استخدام os.path.join بدلًا من كتابة المسار في برنامجنا، كما يمكن تحديد أي عدد نرغب فيه من عناصر المسار في قائمة الوسطاء، فيمكن كتابة المثال أعلاه بالشكل: >>> print( os.path.join("F:\\", "PROJECTS", "PYTHON", "Root", "FA.txt")) F:\\PROJECTS\\PYTHON\\Root\\FA.txt واصفات الملفات وكائنات الملفات تستخدم بعض الوحدات من عائلة os آليةً مختلفةً قليلًا للوصول إلى الملفات، وهو ما يُعرف باسم واصف الملفات file descriptor، وهو مرتبط بشدة بمفهوم الملف في نظم التشغيل بدلًا من كائن الملف file object الذي استخدمناه حتى الآن، ومزيته أننا نستطيع الوصول إلى حزمة من عمليات الملفات منخفضة المستوى low-level operations، والتي تمكننا من الحصول على تحكم أكبر في الملفات وبياناتها، ويمكن إنشاء واصف ملف من كائن ملف والعكس، لكن من الأفضل ألا نخلط بين وضعي العمليات داخل دالة واحدة أو برنامج واحد، فإما أن نستخدم واصفات الملفات أو كائنات الملفات. تشمل دوال واصفات الملفات جميع عمليات الملفات المعتادة، مثل فتح open وقراءة read وكتابة write وإغلاق close، أما البرامج منخفضة المستوى فتكون صعبة الاستخدام، إضافةً إلى احتمال حدوث أخطاء عند استخدامها، لهذا يجب استخدام الوصول منخفض المستوى عند الضرورة فقط، أما في أغلب الحالات فيكفي استخدام كائنات الملف القياسية. لكن ما هي الحالات التي قد نحتاج فيها إلى وصول منخفض المستوى إلى الملفات؟ تستخدم العمليات القياسية مبدأً يعرف باسم التخزين المؤقت للدخل/الخرج أو buffered IO، حيث تُحفظ البيانات في مناطق تخزين تسمى بالمخازن المؤقتة buffers أثناء عمليات القراءة والكتابة، وقد تتسبب تلك المخازن في مشاكل عند الوصول إلى عتاد غريب أو إجراء عمليات ذات توقيت حرج time critical، ففي مثل تلك الحالات يكون الحل هو العمليات منخفضة المستوى، لكن إذا لم تكن متأكدًا من سبب استخدامها فلا تفعل، لكن مع هذا العيب الكبير في العمليات منخفضة المستوى، فإننا نقول إن استخدامها ليس بتلك الصعوبة التي تظهر من سياق الحديث، وإنما قصدنا أن هناك بعض المشاكل التي يجب تجنبها، لنبدأ بإجراء مهمة بسيطة، مثل فتح ملف نصي، وكتابة بعض البيانات فيه، ثم إغلاقه: fname = 'F:/PROJECTS/PYTHON/Root/FL.txt' mode = os.O_CREAT | os.O_WRONLY # create and write access = 0777 # read/write/execute for all data = 'Test text to check that it worked' fd = os.open(fname, mode, access) # NB. os version not the builtin! length = os.write(fd, data) if length != len(data): print( 'Amount of data written doesn't match the data!' ) os.close(fd) بالمثل نستطيع قراءة البيانات من الملف: mode = os.O_RDONLY # read only fd = os.open(fname,mode) # no access needed this time result = os.read(fd, length) print( result ) os.close(fd) نلاحظ عدة أمور هي: الطريقة التي نعين بها نوع وصول الملف أعقد هنا، ويجب أن نستخدم عامل or الثنائي لدمج جميع الرايات المطلوبة كما وفرتها وحدة os. نستطيع توفير مستوى وصول غير المستوى الافتراضي، وهذا أمر تمتاز به عن توابع كائن الملف القياسية. العدد الثُماني -لأنه يبدأ بصفر- هو نفسه العدد المذكور في قسم "تغيير صلاحيات الملفات" السابق. عند قراءة البيانات يجب أن نمرر طول البيانات المقروءة، باستخدام read القياسية، لكن هذا إجباري بالنسبة للعمليات منخفضة المستوى. أما البيانات المقروءة والمكتوبة فعلًا فهي من النوع سلسلة بايتات bytestring، وهذا لن يكون مشكلةً عند التعامل مع سلاسل المحارف، لأننا نستطيع استخدام تابع decode الخاص باليونيكود لتحويل البايتات إلى محارف، لكن تظهر المشكلة عند التعامل مع أنواع بيانات أخرى، إذ يجب استخدام وحدة struct كما شرحنا في مقال التعامل مع الملفات. معالجة العمليات يُعد تنفيذ البرامج أو تشغيلها من أكثر المهام التي ننفذها عن استخدام نظام التشغيل، ونفعل ذلك غالبًا من خلال واجهة رسومية أو صدفة سطر أوامر، كما يمكن أيضًا أن نبدأ البرامج من داخل برامج أخرى، فقد لا نحتاج أحيانًا إلى أكثر من بدء برنامج والسماح له بالعمل حتى نهايته، أما في أحيان أخرى فقد نحتاج إلى توفير بيانات الدخل أو قراءة الخرج إلى برنامجنا، ويُعرف هذا اصطلاحًا باسم التواصل البيني للعمليات أو التواصل بين العمليات inter-proces communication، أو IPC اختصارًا، وسنشرح هذا المفهوم بالتفصيل في المقال التالي. تعريف العملية العملية Process في الاصطلاح الحاسوبي هي ما يطلق عليه المستخدمون "تشغيل البرنامج"، فإذا كان لدينا ملف تنفيذي على الحاسوب ونريد تنفيذه؛ فسيبدأ التشغيل داخل مساحة الذاكرة الخاصة به، وقد يكون من الممكن بدء أكثر من نسخة من نفس الملف التنفيذي، ويشغل كل منها مساحةً خاصةً به من الذاكرة، ويدير بياناته الخاصة به، ويطلَق اسم العملية على كل واحد من تلك البرامج التنفيذية مع بيئة التشغيل الخاصة به. نستطيع أن نرى العمليات الحالية على الحاسوب باستخدام الأدوات التي يوفرها نظام التشغيل، فإذا كنت على ويندوز فاضغط على Ctrl+Alt+Del لتشغيل برنامج Task Manager، وانظر في التبويب المسمى Processes، وسترى قوائم طويلةً من العمليات الحالية التي قد تتعرف على بعضها من البرامج الخاصة بك، أما بقية العمليات فتكون خدمات بدأها نظام ويندوز نفسه، كما قد تلاحظ أن بعض التطبيقات تبدأ عدة عمليات، مثل قواعد البيانات العلائقية relational databases وخوادم الويب، وتوضح الصورة التالية مثالًا لبرنامج Task Manager: أما على لينكس أو نظام MacOS فيُستخدم الأمر ps لعرض العمليات أو المهام الحالية، أو top الذي يعطي عرضًا حيًا لتلك العمليات، وسيبدو أمر ps كما يلي: تشغيل برنامج خارجي: الدالة os.system()‎ نعلم الآن الفرق بين البرنامج والعملية، وسننظر في كيفية تنفيذ برنامج من بايثون، وتوجد الكثير من الطرق لذلك -لأسباب تاريخية-، لكننا سنكتفي باثنتين فقط، والأولى منهما بسيطة الاستخدام للغاية، لكنها محدودة الإمكانيات، أما الثانية فهي المنظور الذي يُنصح به هذه الأيام، وهي أكثر قوةً ومرونةً. الطريقة الأولى السهلة والقديمة هي استخدام دالة system()‎ من وحدة os، وهذا ينفذ سلسلة أمر command string، ويعيد شيفرة خطأ تعكس انتهاء الأمر على النحو الصحيح أو لا، ولا توجد طريقة للوصول إلى الخرج الفعلي للبرنامج المستدعى ولا لتزويد العملية الحالية بالدخل المناسب، لذا تناسب system()‎ تنفيذ البرامج التي لا تحتاج إلى متابعة، مثل إخلاء شاشة الطرفية، حيث لا نحتاج أن نعرف هل نُفّذ الأمر بنجاح أم لا، ولا أن نتفاعل مع الأمر بمجرد بدئه، ويمكن رؤية مثال على ذلك في يونكس: >>> import os >>> errorcode = os.system("clear") >>> print( errorcode ) 0 ويختلف الأمر قليلًا في أنظمة التشغيل المبنية على ويندوز: >>> errorcode = os.system("CLS") >>> print( errorcode ) 0 غير أن النتيجة في الحالتين يجب أن تكون إخلاء النافذة الطرفية، ويجب أن يكون رمز الخطأ errorcode هو الصفر إشارةً إلى نجاح التنفيذ، وقد لا يكون هذا مفيدًا؛ لكننا نستطيع استخدام system في سكربتاتنا حين نرغب في عرض الخرج الطبيعي للأمر، أو عندما لا يهمنا إلا نجاح الأمر أو فشله، فمثلًا نستطيع أن نطلب من المستخدم أن يعدل إعدادات ملف من خلال بدء جلسة محرر editor، ثم يغلق جلسة التحرير عند انتهائه، ويعود التحكم إلى برنامجنا الذي يستطيع عندئذ أن يقرأ الملف المعدَّل. >>> filename = 'xxyyzz.config' >>> errorcode = os.system('nano %s' % filename) >>> if not errorcode: ... with open(filename) as config: ... # للعملية config هنا ملف يُظهر المثال بعض التقنيات المفيدة، حيث يُظهر طريقةً لوصف استدعاءات النظام باستخدام تنسيق السلاسل النصية، كما يُظهر تفسير رمز الخطأ لتحديد نتيجة العملية. إذا نجحت عملية التعديل فسيكون رمز الخطأ صفرًا، حتى لو لم يحدث أي تعديل على الملف، لكن إذا فشلت -كما في حالة عدم العثور على المحرر مثلًا- فسنحصل على رمز خطأ قيمته غير الصفر. ومع أن system سهلة الاستخدام إلا أنها ليست مرنةً، ولا توجد طريقة مباشرة لتوصيل أي بيانات إلى برامجنا، ونستطيع محاكاة ذلك بالتقاط الخرج إلى ملف نصي مؤقت، ثم فتح ذلك الملف ومعالجته مثلما اعتدنا، لكن ثمة طريقة أفضل لتحقيق نفس النتيجة وهي استخدام وحدة subprocess. إدارة العمليات باستخدام الوحدة subprocess بعد العديد من المحاولات الفاشلة لتحسين التحكم في العمليات، حدث تطور كبير عند إدخال الوحدة subprocess إلى الإصدار 2.4 من بايثون، وقد جاءت تلك الوحدة خصيصًا لاستبدال جميع الآليات القديمة، ويمكن رؤية العديد من الأمثلة على كيفية استخدامها في توثيقها، أما هنا فسنغطي أغلب استخدامها العام، وتوجد دوال سهلة ومريحة إذا رغبت في محاكاة وظيفة os.system أو ما شابهها. بُنت الوحدة subprocess على صنف يسمى Popen، لاحظ الحرف الأول بالحرف الكبير، ويمكن استخدامه لإنشاء نسخة من أمر ما، لكن توثيق هذا الصنف قد يسبب الرهبة للبعض لأن باني Popen يحتوي على الكثير من المعامِلات الرائعة، لكن الجيد في الأمر أن لجميعها تقريبًا قيمًا افتراضية، ويمكن تجاهلها في الحالات بالغة البساطة، وبناءً على ذلك لتشغيل أمر من أوامر نظام التشغيل من داخل سكربت ما، لا نحتاج إلا إلى فعل ما يلي: import subprocess ps = subprocess.Popen(['ps', '-ef'], shell=False) الوسيط الأول قائمة من السلاسل النصية، التي تمثل الأمرَ وجميع وسطائه، ففي المثال أعلاه ننفذ أمر ps -ef. يمنع الوسيط الثاني shell=False تمرير الأمر من خلال برامج الصدفة الخاصة بالمستخدمين -مثل Bash-، مما قد ينتج عنه مشاكل أمنية، بسبب الأسماء البديلة aliases المخصصة للأوامر مثلًا، فيجب أن نستخدم shell=False كلما أمكن ذلك، لكن من الضروري أحيانًا أن نفسر الأمر بواسطة الصدفة، كما في حالة تمرير محارف بدل wild-cards مثل "*.jpg" إلى تطبيق معالجة للصور، فالصدفة هي التي توسع محرف البدل إلى قائمة من أسماء الملفات فعلًا. خزّنا نسخة Popen الناتجة في متغير سميناه باسم الأمر الذي ننفذه، وهذا ليس ضروريًا لكنه سلوك حسن إذا كنا نشغّل عدة عمليات مساعِدة في نفس الوقت. توجد دالة أخرى اسمها call يمكن استخدامها بدلًا من os.sytem في المثال أعلاه: subprocess.call(['ps', '-ef'], shell=False) تكاد دالة call أن تطابق استخدام صنف Popen الذي شرحناه من قبل، غير أنه ليس لها تلك الخيارات المتاحة في Popen، ولا تنشئ نسخًا، لذا فهي أوفر في استهلاك موارد النظام، لكن لها نفس عيوب os.system. لوحدة subprocess التي نستخدمها هنا مزية عن الدوال القديمة، وهي أنها ترفع استثناءً OSError إذا لم يوجد الأمر المطلوب، أما الدوال الأخرى فكانت ستتركنا دون أي إشارة على وجود أخطاء. التواصل مع العمليات باستخدام Popen من الممكن تنفيذ كل ما فعلناه بوحدة subprocess باستخدام os.system، لكن هذا على وشك التغير الآن حيث سنتعرف على كيفية تبادل البيانات مع عملية جارية بدأناها باستخدام subprocess.Popen، فإذا عدنا قليلًا إلى أمر ps الذي نفذناه من قبل فسنجد أننا شغلنا البرنامج، لكننا لم نستطع الوصول إلى خرجه، ونحتاج إلى إجراء تعديل بسيط لنتمكن من الوصول إلى ذلك الخرج: import subprocess as sub ps = sub.Popen(['ps', '-ef'], shell=False, stdout=sub.PIPE) print( ps.stdout.read().decode('utf8') ) لقد أضفنا وسيطًا هنا يخبر Popen أن يرسل خرجه القياسي stdout إلى أنبوب عملية فرعية subprocess Pipe وقد شرحنا مجرى الخرج والدخل القياسيين stdin وstdout في مقال قراءة البيانات من المستخدم، ونستطيع الآن أن نصل إلى بيانات الخرج باستخدام الخاصية stdout لنسخة Popen التي نقرؤها مثل أي ملف عادي، وتُحوَّل سلسلة البايتات bytestring الناتجة إلى محارف يونيكود باستخدام decode ثم تُطبع، لكن من الممكن أن نسندها إلى متغير ونعالجها بأي طريقة نشاء. انتبه، توجد بعض المشاكل في الوصول إلى مجرى الخرج القياسي بهذه الطريقة، تدور أغلبها حول إدارة عدة عمليات متزامنة معًا، لذا نشجع استخدام التابع Popen.communicating الذي يعيد قائمةً من مجاري البيانات data streams يكون مجرى الخرج القياسي stdout هو الأول فيها، ثم مجرى الدخل القياسي stdin، ثم مجرى الخطأ القياسي stderr. فإن مثّل ذلك مشكلةً فيمكن إعادة كتابة المثال السابق كما يلي: import subprocess as sub ps = sub.Popen(['ps', '-ef'], shell=False, stdout=sub.PIPE) print( ps.communicate()[0].decode('utf8') ) نستخدم Popen.communicate([0])‎ هنا للوصول إلى أنبوب الخرج القياسي بطريقة آمنة. ويمكن إرسال بيانات إلى عملية ما بطريقة مشابهة، إذ نخبر الصنف Popen أن يستخدم أنبوبًا لمجرى الدخل القياسي، ثم يكتب البيانات إلى مجرى البيانات ذاك مثل الملف العادي، رغم أن البيانات هنا يجب أن تكون سلسلة بايتات وليست سلسلة محارف. في المثال التالي، نفتح محرر أسطر يونكس ex، ونرسل إليه بعض البيانات لينشئ ملفًا نصيًا، ثم نغلق المحرر قبل التحقق من وجود ذلك الملف الجديد: import subprocess as sub import os ex = sub.Popen(['ex', '/tmp/testex.txt'],stdin=sub.PIPE) ex.stdin.write(b'i\nthis is some text\n.\n') ex.stdin.write(b'wq\n') ex.stdin.close() print( os.listdir('/tmp') ) لاحظ أن المدخلات كلها سلاسل بايتات، وأننا نحتاج إلى إدراج محارف الإرجاع carriage return على أنها محددات أسطر جديدة في السلاسل، كما أن النقطة الموجودة في أول سطر من ex.stdin.write هي التي تخبر ex بانتهاء تسلسل الدخل، ويؤكد استدعاء os.listdir أن الملف الجديد موجود في مجلد tmp، أو يمكن أن نتحقق من ذلك بواسطة مدير الملفات. وبهذا استطعنا الكتابة في عملية جارية، رغم أنها أقل شيوعًا من القراءة من العمليات. مسألة الأمان توفر نظم التشغيل هذه الأيام أغلب الأدوات التي تضمن أمان بيئة التشغيل التي يستخدمها المستخدم على الحاسوب، يمكن الوصول إليها -مثل باقي أدوات نظم التشغيل- من خلال واجهة برمجة التطبيقات API الخاصة بنظام التشغيل نفسه، لكن مع شرط تنظيم نظام التشغيل وصولنا إلى مزايا معينة؛ وفقًا للصلاحيات الممنوحة للمستخدم الذي يشغل البرنامج، فإذا أردنا الوصول إلى ملفات أحد المستخدمين فلا بد أن نملك صلاحية الوصول إلى ملفاته أولًا، وهذا لا يعني ترك مزايا الأمان المضمنة في نظام التشغيل. سندرس بعض الدوال المتعلقة بالأمان، مثل تحديد معرِّف المستخدم، وتغيير ملكية الملفات، واستخدام متغيرات البيئة للحصول على بيانات حول بيئة المستخدم الحالي. المستخدمون وملكية الملفات يمكن الحصول على معرِّفات المستخدمين باستخدام دالة os.getuid، والتي تعيد معرّف المستخدم في صورة رقم، ولا نحتاج إلى تحويله إلى اسم المستخدم نفسه إلا نادرًا،لأننا نستطيع الحصول على ذلك الاسم باستخدام دالة getpass.getuser()‎ التي تنظر في متغيرات البيئة التي قد تحمل تلك المعلومة. >>> import getpass >>> print( getpass.getuser() ) أما معرف المستخدم فيكون القيمة التي يحتاج البرنامج إليها لتغيير إعدادات الأمان، ونحصل عليه كما يلي: >>> import os >>> print( os.getuid() ) لعل أشهر استخدام لذلك هو تغيير ملكية ملف -أنشأناه سابقًا في جزء من برنامجنا- برمجيًا، فمثلًا سنستخدم أحد الملفات التي أنشأناها سابقًا في هذا المقال: import os os.chdir('src/Python/Root') os.system('ls -l *.txt') id = os.getuid() os.chown('FA.txt',id,-1) os.system('ls -l *.txt') نستخدم os.chdir لضبط مجلد العمل ليكون المكان الذي فيه الملفات، ثم نستخدم system()‎ لعرض قائمة المجلدات بما فيها صلاحيات الملفات قبل وبعد استدعاء chown()‎، لنستطيع أن نرى التغيرات إن وجدت. نستدعي chown()‎ مع معرف المستخدم الذي حصلنا عليه من getuid()‎، ونستخدم ‎-1 للمعامل الثالث الخاص بالدالة chown()‎، للإشارة إلى أننا لا نريد تغيير ملكية المجموعة، لكن إذا أردنا ذلك فسنستخدم الدالة os.getid()‎ التي تجلب معرف المجموعة. لاحظ أنه لن يكون للسكربت تأثير إلا إذا شغلناه من مستخدم مختلف عن الحالي، ويجب أن يكون للمستخدم صلاحيات تلك التغييرات، لذا ننصح أن تسجل الدخول بالمستخدم المدير administrator أو الجذر root. لا تخبرنا chown()‎ أي معلومات عن الخرج، لذا إذا أردنا التحقق من النتيجة فيجب أن نستخدم شيئًا مثل os.stat للتحقق من قيمة معرف المستخدم قبل استدعائها وبعده، وبهذا نتحقق من حدوث التغييرات التي نتوقعها. بيئة المستخدم يرث البرنامج عند بداية تشغيله سياق الذاكرة من البرنامج الذي شغّله، حيث يكون البرنامج المشغِّل غالبًا صدفة سطر الأوامر الخاصة بالمستخدم، CMD في ويندوز أو Bash أو غيرها في يونكس، وتشمل بيئة المستخدم تلك معلومات كثيرةً عن النظام، مثل اسم المستخدم، ومجلد home، والمجلد الحالي، والمجلد المؤقت، ومسارات البحث، وهذا يعني أن إعداد متغيرات البيئة المختلفة يمكّن كل مستخدم من تخصيص كيفية عمل نظام التشغيل وبرامجه إلى حد ما، فمثلًا تراقب بايثون متغير البيئة PYTHONPATH عند البحث عن الوحدات، لذلك قد يكون لكل مستخدم على نفس الحاسوب مسارات بحث مستقلة للوحدات، بما أن كل واحد منها يضبط قيمةً مختلفةً للمتغير PYTHONPATH، ويستفيد المبرمجون من ذلك بتعريف بعض متغيرات البيئة لبرنامج ما بحيث يستطيع المستخدم تغيير قيم البرنامج الافتراضية، ويجب أن نتمكن من قراءة البيئة الحالية للعثور على تلك القيم، بأن نقرأ متغيرًا واحدًا باستخدام دالة os.getenv()‎، أو نقرأ جميع المتغيرات المضبوطة حاليًا بالنظر في متغير os.environ الذي يحتوي قاموسًا بأزواج الاسم/القيمة. سنطبع قائمةً بجميع متغيرات البيئة، حيث تحتوي تلك القائمة على معلومات كثيرة: >>> import os >>> print( os.environ ) لا شك أننا نستطيع استخدام عمليات القاموس والسلاسل النصية المعتادة، لكن يُفضل في أغلب الحالات أن نحصل على قيم المتغيرات قيمةً قيمةً، كما يلي: >>> os.getenv('PYTHONPATH') أو: >>> os.environ['PYTHONPATH'] يبين لنا هذا هل ضبطنا المتغير PYTHONPATH أم لا؟ وعلى أي قيمة أيضًا. تتيح getenv()‎ إمكانية ضبط نتيجة افتراضية إذا لم يكن المتغير معرَّفًا، نظرًا لخطورة عدم تعريفه، ويمكن استخدام تابع القاموس القياسي get()‎ لتنفيذ نفس الشيء في قاموس environ، ويستخدَم هذا عادةً أثناء تهيئة البرامج، حين نضبط الإعدادات، مثل المجلد الذي ستوجد فيه ملفات البيانات، ففي المثال التالي سننظر أين يجب تخزين دليل جهات الاتصال الخاص بنا، باستخدام الإعداد الافتراضي للمجلد الحالي إن لم يكن ثمة متغير: # ... خطوات تهيئة هنا. folder = os.getenv('PY_ADDRESSES', os.getcwd()) # ... بقية البرنامج تعيد getenv()‎ وسيطها الثاني عند عدم وجود قيمة افتراضية للمتغير PY_ADDRESSES، وهو الموقع الافتراضي لنا. ينشئ المستخدم متغيرات البيئة تلك ويضبطها يدويًا باستخدام نظام التشغيل، ففي ويندوز مثلًا ينفّذ ذلك بتسلسل الإعدادات التالي: MyComputer->Properties->Advanced->Environment Variables أما في لينكس وماك فيُنفذ في سطر الأوامر باستخدام الأمرين export وsetenv وفقًا للصدفة المستخدمة. يمكن تغيير قيم متغير البيئة الحالي في بعض أنظمة التشغيل، لكن يجب استخدام ذلك بحذر، إذ قد يؤدي إلى الكتابة فوق قيم أخرى، كما قد تعكس بعض أنظمة التشغيل تلك التغييرات على بيئات المستخدمين، غير أن هذا لا ينطبق إلا في سياق عملية الكتابة غالبًا، فإذا كان نظام التشغيل يدعم تلك العملية فنستطيع كتابة قيمة المجلد الافتراضي الخاصة بنا إلى بيئة المستخدمين لضمان استخدام نسخ برنامجنا الأخرى لنفس الموقع، إلا أننا لا ننصح بذلك لهشاشة تلك الآلية، وإنما ننصح باستخدام ملف config لأنه أكثر موثوقيةً لمثل هذه الإعدادات. # شيفرة أخرى كما سبق putenv('PY_ADDRESSES', folder) # ... بقية البرنامج تُستخدم بعض متغيرات البيئة في يونكس من قبل برامج عديدة، منها على سبيل المثال: EDITOR: يحدد هذا المتغير برنامج التحرير الذي يفضله المستخدم، ويكون ed أو vi أو ViM أو Emacs، فتشغّل البرامج الأخرى هذا المحرر إذا احتاج المستخدم إلى تعديل ملف نصي في جزء من البرنامج، فمثلًا يمكننا استخدام getenv ('EDITOR')‎ لإطلاق المحرر الخاص بالمستخدم في مثال os.system أعلاه، بدلًا من ضبط المحرر nano ليكون هو الافتراضي. PRINTER: يحدد هذا المتغير إعدادات المستخدم المفضلة لطباعة الملفات. PAGER: يحدد هذا المتغير برنامج عرض الملفات الذي يفضله المستخدم، ويُضبط غالبًا على more أو less أو view. سنكتفي بهذا الشرح عن البيئات، وسنعود إليها في مقال لاحق، لكن نذكر أنه عند الحاجة إلى الحصول على بيانات تخص المستخدم فيجب التحقق من وجود متغير بيئة بالفعل أم لا، أو نتيح للمستخدم إمكانية ضبط ذلك من خلال متغير بيئة خاص ببرنامجنا. مزيد من المعلومات حول نظم التشغيل تحتوي وحدة os ومثيلاتها على إمكانيات أكثر مما يمكن أن نشرحه هنا، بل إن توثيق بايثون يحتاج إلى عدة صفحات HTML لشرح وحدة os وحدها، وصفحة لكل وحدة أخرى، ويمكن الرجوع إلى تلك التوثيقات لتصفح وظائف تلك الوحدات، وستجد فيها أسماءً غريبةً، تأتي أغلبها من يونكس وواجهة برمجة تطبيقاته. توفر os وظائف مكافئةً على أي نظام تشغيل، لكن إذا أردت معرفة المزيد عن وظائف تلك الدوال فيجب الرجوع إلى توثيق يونكس نفسه، فإن لم يكن لديك أحد أنظمة يونكس فيمكن الرجوع إلى كتاب Unix Systems Programming for SVR4، وإذا أعجبك ما شرحناه عن نظم التشغيل فربما تود قراءة كتاب Fundamentals of Operating Systems لصاحبه ليستر A. M. Lister، فهو كتاب قصير ويسهل فهم شرحه المدعوم بمخططات توضيحية، أما إذا رغبت في إلقاء نظرة فاحصة على نظم التشغيل فانظر كتاب أندرو تانينباوم Andrew Tanenbaum الشهير Operating Systems: Design and Implementation، الذي شجع لينوس تورفالدز Linus Torvalds على كتابة نواة لينكس. خاتمة نرجو في نهاية هذا المقال أن تتذكر ما يلي: يوفر نظام التشغيل بيئةً يمكن تشغيل العمليات فيها. كما يوفر وصولًا إلى عتاد الحاسوب. يمكن الوصول إلى نظام التشغيل من خلال واجهة برمجة التطبيقات، التي تكتَب عادةً بلغة C. توفر وحدة os الخاصة ببايثون مغلِّفًا لواجهة برمجة التطبيقات الخاصة بنظام التشغيل. تسهل الوحدتان os.path وglob الوصول إلى الملفات. توفر كل من os.system()‎ وsubprocess.Popen مستويات مختلفةً من التحكم في العمليات والتواصل بينها IPC. تسمح getuid()‎ وgetenv()‎ والمزايا الشبيهة بهما بالتعرف على المستخدم وإعداداته المفضلة. ترجمة -بتصرف- للفصل الخامس والعشرين: Working with the Operating System من كتاب Learning To Program لصاحبه Alan Gauld. اقرأ أيضًا المقال التالي: التواصل بين العمليات في البرمجة المقال السابق: التعامل مع قواعد البيانات أهم 20 أمرا في نظام التشغيل لينكس لجميع المستخدمين النسخة الكاملة لكتاب: البرمجة بلغة بايثون
  24. سنركز في هذا الجزء من السلسلة على بعض التطبيقات العملية التي يمكن استخدام لغة بايثون فيها، وكذلك وحدات المكتبات التي سنستخدمها في كتابة تلك التطبيقات، كما سنتعلم بعض التقنيات الجديدة أثناء كتابة تلك التطبيقات، مثل قواعد البيانات وشبكات الحواسيب والشبكة العالمية -الويب-، وكذلك بعض المزايا الأساسية لنظم تشغيل الحواسيب، لكننا لن نتعمق في هذه التقنيات كثيرًا لأننا نهتم بتعليم البرمجة فقط، ويمكنك الاستعانة بمواقع أخرى أو مصادر يمكن الاستزادة منها. وقد اخترنا موضوعات تعكس المجالات التي تتكرر في قائمة Python tutor البريدية (القائمة البريدية لمعلمي بايثون)، والتي يفترض أن تكون الأفضل في تلبية احتياجات المبرمجين الجدد، فإذا لم يكن المجال الذي تريده موجودًا فيها فقد تجد روابط إلى مصادر تتعلم فيها عن ذلك المجال. تعتمد جميع الفصول الباقية من السلسلة على بايثون وحدها، ولا شك أن الإمكانيات التي سنذكرها قد تكون موجودةً في جافاسكربت وVBScript، إلا أن الاختلافات في هذا المستوى من العمق والتفاصيل أكبر من أوجه التشابه بكثير، لأن هذه تطبيقات عملية وليست مفاهيم نظريةً.، فأسهل طريقة للوصول إلى ويندوز مثلًا من جافاسكربت أو VBScript ستكون من خلال مضيف سكربت ويندوز WSH الذي ذكرناه من قبل، لكن هذا يختلف كليًا عن وحدة نظام التشغيل في بايثون، فلا معنى للموازنة بينها. سننظر في هذا المقال من سلسلة تعلم البرمجة في كيفية تخزين البيانات ومعالجتها من خلال حزمة قاعدة البيانات، وقد رأينا سابقًا كيفية استخدام الملفات في تخزين كميات صغيرة من البيانات في برنامج دليل جهات الاتصال الذي مررنا عليه عدة مرات من قبل، غير أن استخدام الملفات يزداد تعقيدًا مع زيادة تعقيد البيانات نفسها، وزيادة حجمها، وتعقيد العمليات التي تُجرى عليها، مثل الفرز والبحث والترشيح filtering وغير ذلك، وتوجد عدة حزم لقواعد البيانات للعناية بإدارة الملفات، وكشف البيانات في شكل أكثر تجريدًا ويسهل التعديل عليه، بعضها عبارة عن مكتبات للشيفرات code libraries تبسط عمليات الملفات التي رأيناها من قبل مثل وحدتي pickle و shelve اللتين تأتيان مع بايثون، لكننا في هذا المقال سندرس حزمًا أكثر قوةً صممت للتعامل مع أحجام كبيرة من البيانات المعقدة، حيث سنشرح الحزمة SQLite، وهي حزمة مجانية مفتوحة المصدر وسهلة التثبيت والاستخدام، ومع هذا فهي قادرة على معالجة حاجات أغلب المبرمجين المبتدئين والمتوسطين أيضًا، ولا يحتاج المبرمج في الغالب إلى حزمة أقوى منها إلا إذا كان يتعامل مع مجموعات كبيرة للغاية من البيانات -ملايين السجلات مثلًا-، وحتى في تلك الحالة نستطيع نقل ما تعلمناه من SQLite إلى الحزمة الجديدة. يمكن تحميل حزمة SQLite من موقعها، فاختر حزمة سطر الأوامر -أي الأدوات- المناسبة لمنصتك، وبعد التحميل اتبع إرشادات التثبيت الموجودة في الموقع لتثبيت الحزمة. توجد عدة بيئات تطوير لـ SQLite، غير أننا لا نحتاجها في هذه السلسلة. سندرس في هذا المقال ما يلي: مفهوم قواعد البيانات وSQL. إنشاء الجداول وإدخال البيانات. استخراج البيانات والتعديل عليها. ربط مجموعات البيانات بعضها ببعض. الوصول إلى SQL من بايثون. مفاهيم قاعدة البيانات العلائقية يمكن وصف قواعد البيانات العلائقية relational databases بأنها مجموعة من الجداول، حيث يمكن لخلية في جدول فيها أن تشير إلى صف في جدول آخر، وتسمى الأعمدة في تلك الجداول بالحقول fields، كما تسمى الصفوف بالسجلات records. سيبدو جدول بيانات الموظفين في إحدى الشركات كما يلي: table { width: 100%; } thead { vertical-align: middle; text-align: center; } td, th { border: 1px solid #dddddd; text-align: right; padding: 8px; text-align: inherit; } tr:nth-child(even) { background-color: #dddddd; } EmpID Name HireDate Grade ManagerID 1020304 Hasan Saleh 20030623 Foreman 1020311 1020305 Amin Akbar 20040302 Labourer 1020304 1020307 Ayat Othman 19991125 Labourer 1020304 نلاحظ بعض المصطلحات هنا: لدينا حقل معرِّف ID فريد يعرف كل صف، ويُعرف باسم المفتاح الأساسي primary key، ويمكن أن يكون لدينا عدة مفاتيح أخرى، لكن سيكون لدينا حقل ID دومًا لتعريف سجل ما، وهذا مفيد إذا كان لموظفين اثنين نفس الاسم مثلًا. يمكن ربط صف بآخر بأن يحمل حقلٌ ما المفتاحَ الأساسي لصف آخر، فمثلًا يُحدَّد مدير الموظف بواسطة معرف المدير ManagerID الذي هو مرجع إلى حقل EmpID آخر، ويتضح بالنظر إلى البيانات التي لدينا أن لكل من Amin وAyat المدير نفسه وهو Hasan، و Hasan هذا له مدير آخر لكننا لا نرى بياناته في هذا الجزء من الجدول. ويمكن إنشاء جدول آخر للرواتب Salary مثلًا، فلسنا مقيدين بربط البيانات داخل جدول واحد، ويُربط هذا بالدرجة Grade الخاصة بكل موظف، فنحصل عندها على جدول شبيه بما يلي: SalaryID Grade Amount 000010 Foreman 60000 000011 Labourer 35000 نستطيع الآن أن نبحث عن درجة موظف ما مثل Hasan، وسنجد أن درجته هي كبير عمال Foreman، وإذا بحثنا في جدول Salary فسنجد أن راتب هذه الدرجة هو 60000$، وإمكانية ربط صفوف الجداول معًا في علاقات هي التي تعطي قواعد البيانات العلائقية اسمها. توجد قواعد بيانات أخرى مثل قواعد بيانات الشبكات network databases، وقواعد البيانات الهرمية hierarchical databases، وقواعد بيانات الملفات المسطحة flat-file databases، ولكن القواعد العلائقية هي أكثرها شهرةً، رغم أن الاتجاه السائد الآن في معالجة الأحجام الهائلة من البيانات هو NoSQL -أي ليست SQL فقط "Not only SQL"-، وهي قواعد بيانات تبنى في الغالب على هياكل شبكية أو هرمية. يمكن إجراء استعلامات أعقد من تلك التي أجريناها، وسنرى كيفية ذلك فيما يلي، لكن يجب أن ننشئ قاعدة بيانات أولًا ونضع فيها بعض البيانات. لغة الاستعلامات الهيكلية SQL لغة الاستعلامات الهيكلية أو Structured Query Language - SQL هي أداة قياسية تُستخدم لتعديل قواعد البيانات العلائقية، ويسمى التعبير فيها عادةً استعلامًا query حتى لو لم يجلب أي بيانات، وتتكون SQL من جزأين هما: لغة تعريف البيانات Data Definition Language واختصارًا DDL، وهي مجموعة من الأوامر التي تُستخدم لإنشاء وتعديل هيكل قاعدة البيانات نفسها، وتكون عادةً خاصةً لكل قاعدة بيانات، ويوفر كل مزود قواعد بيانات صيغةً مختلفةً قليلًا لمجموعة أوامر SQL الخاصة بتعريف البيانات، أما الجزء الآخر فهو لغة تعديل البيانات Data Manipulation Language، واختصارًا DML، وهي قياسية أكثر بين قواعد البيانات، وتُستخدم لتعديل محتويات البيانات، وهي التي سنستخدمها غالبًا في التعامل مع قواعد البيانات، لذا سنتعلم بعض أوامر DDL التي تكفينا لإنشاء قاعدة بياناتنا باستخدام التعليمة CREATE، وتدمير جداولها باستخدام التعليمة DROP، ثم ننتقل بعدها إلى ملء الجداول بالبيانات، ثم نجلب تلك البيانات بطرق مختلفة باستخدام أوامر DML مثل INSERT وSELECT وUPDATE وDELETE وغيرها. ربما تجدر الإشارة إلى مزية أخرى في SQL، وهي أنها ليست حساسةً لحالة الأحرف، على عكس بايثون وجافاسكربت، لذا يمكننا استخدام CREATE أو create أو Create أو حتى CrEaTe، فلن يهتم مفسر SQL بهذا، ومع هذا يتبع مبرمجو SQL نسقًا بحيث تكون كلمات SQL المفتاحية بأحرف كبيرة، بينما تكون المتغيرات وأسماء الجداول والحقول بأحرف صغيرة، وسنتبع هذا النسق في الشرح، لكننا ذكرنا الملاحظة أعلاه لننبه إلى أن SQL لا تهتم لحالة الأحرف. ومن الأمور التي تجعل SQL مختلفةً عن اللغات الأخرى أنها مصممة للتعبير عن الخرج المطلوب بدلًا من إخبار الحاسوب بكيفية تنفيذه، أي أننا نخبر المفسر بما نريده فقط، وليس بالكيفية التي نريد تنفيذه بها، ونترك آلية التنفيذ للمفسر، ويستطيع المبرمجون الخبراء في قواعد البيانات أو مدراء النظم adminstrators أن يغيروا سلوك المفسر في تنفيذ المهام من خلال تعريف خطة التنفيذ أو تعديلها، غير أن هذا مستوىً متقدم خارج نطاق شرحنا. إنشاء الجداول نستخدم الأمر CREATE لإنشاء جدول في SQL، وهو أمر سهل ويأخذ الصورة التالية: CREATE TABLE tablename (fieldName, fieldName,....); نلاحظ أن تعليمات SQL تنتهي بفاصلة منقوطة ;، وهي لا تهتم بمستويات الإزاحة أو المسافات البيضاء، لكننا سنرى اتباع اصطلاح بعينه -مع أنه ليس لازمًا، ولا تهتم SQL له إطلاقًا- ولا نستخدمه إلا لاتساق سير العمل. لنجرب الآن إنشاء جداول الموظفين والرواتب في SQLite، حيث سيكون أول ما علينا فعله هو بدء المفسر عن طريق استدعائه مع وسيط هو اسم الملف، فإذا كانت قاعدة البيانات موجودةً فسيفتح الملف، أما إذا لم تكن موجودةً فسينشئها، وعليه فمن أجل إنشاء قاعدة بيانات الموظفين نبدأ SQLite كما يلي: E:\PROJECTS\SQL> sqlite3 employee.db سينشئ هذا قاعدة بيانات فارغةً اسمها employee.db، ويتركنا عند محث sqlite>‎ لنكتب أوامر SQL، ثم ننشئ بعض الجداول كما يلي: sqlite> CREATE TABLE Employee ...> (EmpID,Name,HireDate,Grade,ManagerID); sqlite> CREATE TABLE Salary ...> (SalaryID, Grade,Amount); sqlite>.tables Employee Salary sqlite> لاحظ أننا نقلنا قائمة الحقول إلى سطر منفصل لتسهيل رؤيتها، وتُرتَّب الحقول هنا بالاسم، وليس لها أي معلومات تعرِّفها -مثل نوع البيانات- وهذا في SQLite وحدها، إذ تطلب أغلب قواعد البيانات الأخرى تحديد النوع مع الاسم، ويمكن تحديد النوع في SQLite، كما سنرى بعد قليل. ونلاحظ أيضًا أننا تحققنا من عمل تعليمات CREATE باستخدام الأمر ‎.tables لسرد جميع الجداول في قاعدة البيانات، وتحتوي SQLite على العديد من هذه الأوامر المنقوطة، والتي نستخدمها لجلب معلومات عن قاعدة البيانات، وللحصول على قائمة بتلك الأوامر يُستخدم الأمر ‎.help. يمكننا تحديد قيود على القيم، بالإضافة إلى التصريح عن أنواع البيانات في كل عمود، فمثلًا NOT NULL تعني أن القيمة إلزامية ويجب ملؤها، ونجعل عادةً حقل المفتاح الأساسي غير خالٍ NOT NULL وفريدًا UNIQUE، كما نستطيع تحديد الحقل الذي سيكون المفتاح الأساسي PRIMARY KEY. سنترك تعريف الجدول الأساسي كما هو، وننتقل إلى التعديل في البيانات نفسها. إدخال البيانات أول ما نفعله بعد إنشاء الجداول هو ملؤها بالبيانات، وذلك باستخدام تعليمة INSERT في SQL، والتي لها هيكل أساسي بسيط هو: INSERT INTO tablename ( column1, column2... ) VALUES ( value1, value2... ); كما توجد لها صيغة أخرى تستخدم استعلامًا لاختيار البيانات من مكان آخر في قاعدة البيانات، لكن هذا مستوىً متقدم ننصح بالقراءة عنه في دليل SQLite. يمكننا أن ندخِل بعض الصفوف في جدول موظفينا كما يلي: sqlite> INSERT INTO Employee (EmpID, Name, HireDate, Grade, ManagerID) ...> VALUES ('1020304','Hasan Saleh','20030623','Foreman','1020311'); sqlite> INSERT INTO Employee (EmpID, Name, HireDate, Grade, ManagerID) ...> VALUES ('1020305','Amin Akbar','20040302','Labourer','1020304'); sqlite> INSERT INTO Employee (EmpID, Name, HireDate, Grade, ManagerID) ...> VALUES ('1020307','Ayat Othman','19991125','Labourer','1020304'); وكذلك في جدول الرواتب: sqlite> INSERT INTO Salary (SalaryID, Grade,Amount) ...> VALUES('000010','Foreman','60000'); sqlite> INSERT INTO Salary (SalaryID, Grade,Amount) ...> VALUES('000011','Labourer','35000'); وبهذا نكون قد انتهينا من إنشاء جدولين وملئهما بالبيانات الموافقة للقيم الموصوفة في المقدمة أعلاه، وسننتقل الآن إلى إجراء بعض التجارب على البيانات. استخراج البيانات تُستخرج البيانات من قاعدة البيانات باستخدام الأمر SELECT في SQL، والذي هو لب SQLite، وهو أعقد الأوامر هيكلًا، لذا سنبدأ بأبسط صورة ثم نضيف مزايا جديدةً أثناء العمل. ستبدو أبسط صورة ممكنة لتعليمة SELECT كما يلي: SELECT column1, column2... FROM table1,table2...; فلاختيار أسماء جميع العاملين نستخدم: sqlite> SELECT Name FROM Employee; حيث سنحصل على قائمة بجميع الأسماء في جدول الموظفين، وهي ثلاثة أسماء في حالتنا، لكن إذا كان لدينا قاعدة بيانات كبيرة فسنحصل على معلومات أكثر مما نريد، وسنحتاج إلى تحسين بحثنا بطريقة ما للتحكم في الخرج، وتسمح لنا SQL بفعل ذلك بإضافة الشرط WHERE إلى تعليمة SELECT، كما يلي: SELECT col1,col2... FROM table1,table2... WHERE condition; حيث الشرط condition هو تعبير بولياني معقد وعشوائي، ويمكن أن يتضمن تعليمات SELECT متشعبةً داخله، لنستخدم الشرط WHERE لتحسين بحث الأسماء، حيث نريد البحث عن أسماء الموظفين العمال فقط، أي أصحاب الدرجة labourer. sqlite> SELECT Name ...> FROM Employee ...> WHERE Employee.Grade = 'Labourer'; سنحصل الآن على اسمين فقط، ونستطيع توسيع الشرط باستخدام معامِلات بوليانية مثل AND وOR وNOT وغيرها، لاحظ أن استخدام الشرط = في حالة السلسلة النصية مهم، فلم يكن البحث عن labourer لينجح لولاه، وسنرى كيفية حل هذه المشكلة لاحقًا. كما نلاحظ أننا استخدمنا الصيغة النقطية dot notation في شرط WHERE لإبراز حقل Grade، ولم يكن ذلك ضروريًا في هذه الحالة لأننا نعمل مع جدول واحد، لكن عند وجود عدة جداول محددة فسنحتاج إلى توضيح الجدول الذي ينتمي إليه الحقل، فمثلًا لنغير استعلامنا ليبحث عن أسماء جميع الموظفين الذين يحصلون على راتب أكثر من 50000$، حيث سنحتاج إلى النظر في بيانات كلا الجدولين: sqlite> SELECT Name, Amount FROM Employee, Salary ...> WHERE Employee.Grade = Salary.Grade ...> AND Salary.Amount > '50000'; نلاحظ استخدام المسافات البيضاء لترتيب شكل الاستعلام، وقد وضعنا شرط FROM هذه المرة في السطر الأول، وهذا أمر تنسيقي بحت يُستخدم لتحسين القراءة، فلغة SQLite لا تهتم بالفراغات. سنحصل هنا على اسم واحد كما توقعنا، وهو اسم كبير العمال foreman، لكن انتبه إلى أننا سنحصل على الراتب لأننا أضفنا Amount إلى قائمة الأعمدة المحددة، ولدينا شرط WHERE مكوَّن من جزأين مدمجين معًا باستخدام المعامِل البولياني AND، حيث يربط الجزء الأول الجدولين معًا عن طريق ضمان تساوي الحقول المشتركة، وهو ما يُعرف بالربط join في SQL، وقد يصبح أمر الربط معقدًا للغاية وفقًا لكل حالة، ولهذا يفضل القائمون على اعتماد المزايا الجديدة في SQL صورةً أكثر صراحةً من الربط، وهي مشروحة بالتفصيل في موقع guru99. علينا تحديد كلا الجدولين اللذين ستظهر النتيجة منهما، لأن الحقول التي نختارها تأتي من جدولين، ويكون ترتيب أسماء الحقول هو الترتيب الذي نحصل به على البيانات مرةً أخرى، لكن ترتيب الجداول نفسه لا يهم طالما أن الحقول تظهر في تلك الجداول. لقد حدَّدنا اثنين من أسماء الحقول الفريدة، فإذا أردنا عرض الدرجة الوظيفية Grade التي تظهر في كلا الجدولين، لكنا استخدمنا الصيغة النقطية لتحديد الجدول الذي نريده، كما يلي: sqlite> SELECT Employee.Grade, Name, Amount ...> FROM Employee, Salary etc/... آخر ما نريد الحديث عنه من مزايا SELECT هي القدرة على تصنيف الخرج، رغم وجود عدة مزايا أخرى يمكن الرجوع إليها في توثيق SQL، فقواعد البيانات تحتفظ بالبيانات بالترتيب الذي يسهل به إيجادها أو بالترتيب الذي أُدخلت به، وفي كلا الحالتين لا يكون هو الترتيب الذي نريد عرض البيانات به، لذا نستخدم الشرط ORDER BY الخاص بتعليمة SELECT لحل هذه المشكلة: SELECT columns FROM tables WHERE expression ORDER BY columns; نلاحظ أن شرط ORDER BY الأخير قد يأخذ عدة أعمدة، وهذا يمكننا من الحصول على طلبات الفرز والتصنيف الأولية والثانوية، لنستخدم ذلك الآن للحصول على قائمة بأسماء الموظفين مصنفة وفق تاريخ التوظيف HireDate: sqlite> SELECT Name FROM Employee ...> ORDER BY HireDate; لم يبقَ إلا ذكر أننا لم نستخدم شرط WHERE هنا، فإذا استخدمناه فسيأتي قبل شرط order by، لذا ورغم أن SQL لا تمانع إذا أهملنا الشرط إلا أنها تدقق كثيرًا في ترتيب الشروط داخل التعليمة. تعديل البيانات توجد طريقتان لتعديل البيانات في قواعد البيانات، إما بتغيير محتويات سجل واحد أو مجموعة سجلات، أو بحذف السجلات أو الجدول كاملًا، والحالة الأشهر هي تغيير محتويات سجل موجود بالفعل من خلال الأمر UPDATE في SQL، وأبسط صورة هي: UPDATE tablename SET column = value WHERE condition; نستطيع تجربة ذلك في قاعدة البيانات التي لدينا بتغيير راتب كبير العمال foreman إلى 70000$: sqlite> UPDATE Salary ...> SET Amount ='70000' ...> WHERE Grade = 'Foreman'; لاحظ أن جميع البيانات التي أدخلناها واخترناها كانت أنواعًا نصيةً string types، لأن SQLite تخزن بياناتها داخليًا في سلاسل نصية، لكنها تدعم عدة أنواع مختلفة من البيانات بما فيها الأعداد، لذا كان بالإمكان تحديد الراتب في صيغة رقمية لتسهيل العمليات الحسابية، وسنرى كيفية فعل ذلك فيما يلي. لكن المشكلة هنا أن SQL ستعدل كل الصفوف التي تطابق الشرط، فإذا كنا نريد تعديل صف واحد فقط فعلينا أن نتأكد أن الشرط WHERE يحدد حتمًا صفًا واحدًا فقط، إذ كثيرًا ما يغير المبرمجون المبتدئون دون قصد حقلًا في كل صف في الجدول أو فرع منه، لذا يجب الحذر عند استخدام أوامر التعديل لصعوبة إصلاح هذا الخطأ، ومن الأفضل التحقق من شرط WHERE بوضعه في تعليمة SELECT أولًا لمعرفة القيمة المعادة. أما الصورة الأخرى للتغيير الجذري الذي نستطيع تنفيذه على بياناتنا فهو حذف صف أو مجموعة صفوف، باستخدام الأمر DELETE FROM، كما يلي: DELETE FROM Tablename WHERE condition فإذا أردنا حذف Ayat Othman من جدول الموظفين فسنكتب ما يلي: sqlite> DELETE FROM Employee WHERE Name = 'Ayat Othman'; فإذا طابق شرطنا أكثر من صف فستُحذف تلك الصفوف جميعها، لأن SQL تنفَّذ على جميع الصفوف التي تطابق الاستعلام، فهي ليست مثل استخدام البحث المتتابع sequential search لملف ما أو سلسلة نصية باستخدام تعبير نمطي. أما لحذف الجدول كله بمحتوياته فنستخدم الأمر DROP، ويجب توخي الحذر الشديد عند استخدام مثل هذه الأوامر التدميرية مثل DELETE وDROP لما لها من آثار قد لا يمكن إصلاحها. ربط البيانات بين الجداول تحدثنا عن ربط البيانات بين الجداول من قبل في القسم الخاص بتعليمة SELECT، أما الآن فننتقل إلى جزء مهم في نظرية قواعد البيانات. قيود البيانات Data Constraints تمثل الروابط بين الجداول علاقات Relations بين وحدات البيانات التي تعطي قاعدة البيانات العلائقية -مثل SQLite- اسمها، وتحتفظ قاعدة البيانات بالبيانات الخام عن الكيانات، بل تحتفظ بمعلومات عن العلاقات بينها أيضًا. تُخزَّن المعلومات عن العلاقات في صيغة قيود لقاعدة البيانات، والتي تتصرف مثل قواعد تحدد نوع البيانات الذي يمكن تخزينها، بالإضافة إلى مجموعة قيمها الصالحة، وتطبَّق تلك القيود عندما نعرِّف هيكل قواعد البيانات باستخدام تعليمة CREATE، عادةً نعبر عن قيود كل حقل على حدة، لذا نستطيع توسيع التعريف الأساسي في تعليمة CREATE حيث نعرِّف أعمدتنا من: CREATE TABLE Tablename (Column, Column,...); إلى: CREATE TABLE Tablename ( ColumnName Type Constraint, ColumnName Type Constraint, ...); حيث أغلب القيود: NOT NULL PRIMARY KEY [AUTOINCREMENT] UNIQUE DEFAULT value يسهل فهم عمل القيد NOT NULL إذ يشير إلى أن القيمة يجب أن تكون موجودةً أي ليست NULL، حيث تشير القيمة NULL إلى قيمة غير محددة أو معرَّفة، وبالتالي فالعبارة NOT NULL تعني أنه يجب إعطاء قيمة لذلك الحقل، وإلا فسنحصل على خطأ ولن تُدخَل البيانات. أما المفتاح الرئيسي PRIMARY KEY فيخبر SQLite أن تستخدم هذا العمود مفتاحًا رئيسيًا لعمليات البحث، مما يُحسّن تنفيذ عمليات بحث أسرع. كما تعني AUTOINCREMENT أن قيمة النوع هي INTEGER ستُسنَد تلقائيًا عند كل عملية إدخال INSERT، وتتزايد القيمة بمقدار واحد، مما يوفر على المبرمج كثيرًا من حيث المحافطة على أعداد مستقلة، ولا تُستخدم الكلمة المفتاحية AUTOINCREMENT حقيقةً، وإنما تكون مضمنةً في تجميعة نوع/قيد بدمج INTEGER PRIMARY KEY، وهذه خاصية غير واضحة في توثيق SQLite إلى الحد الذي يجعلها من أبرز الأسئلة في الأسئلة الشائعة حول SQLite. وتدل UNIQUE على أن القيمة يجب أن تكون فريدةً في العمود، فإذا حاولنا إدخال قيمة موجودة مسبقًا في عمود له قيد UNIQUE فسنحصل على خطأ ولن يُدخَل الصف، ويُستخدم قيد UNIQUE عادةً لأعمدة المفاتيح الرئيسية غير العددية. يصاحب القيد DEFAULT قيمة دومًا، وهذه القيمة هي التي تخبرنا بما ستدخِله SQLite في ذلك الحقل إذا لم يقم المستخدم بذلك صراحةً، وهذا يفيد في أن الأعمدة التي لها القيد DEFAULT لا تكون NULL إلا نادرًا، لأن علينا ضبط القيمة NULL بصراحة إذا أردنا إنشاءها، ونستطيع رؤية مثال سريع على استخدام DEFAULT هنا: sqlite> CREATE TABLE test ...> (id Integer PRIMARY KEY, ...> Name NOT NULL, ...> Value Integer DEFAULT 42); sqlite> INSERT INTO test (Name, Value) VALUES ('Alan',24); sqlite> INSERT INTO test (Name) VALUES ('Heather'); sqlite> INSERT INTO test (Name,Value) VALUES ('Linda', NULL); sqlite> SELECT * FROM test; 1|Alan|24 2|Heather|42 3|Linda| sqlite> نلاحظ هنا كيف تعينت القيمة الافتراضية لحقل value الموافقة للاسم المدخَل Heather، وأن قيمة value للمدخل Linda غير موجودة أو NULL، وهذا اختلاف جوهري بين NOT NULL وDEFAULT، فالأول لن يسمح بقيم NULL افتراضيًا أو صراحةً، والقيد DEFAULT يمنع NULL غير المحددة، لكنه يسمح في نفس الوقت بالإنشاء المتعمد لها. لقد استخدمنا محرف النجمة * مكان قائمة الحقل في آخر تعليمة SELECT، وهذه طريقة بسيطة لجلب جميع الحقول في الجدول، وهي ممتازة لمثل هذه التجارب، لكن يجب ألا تُستخدم في البرامج العملية لأن أي تغيير في هيكل البيانات سيتسبب في تغيير النتائج أو تعطيل أي شيفرة تعتمد على عدد أو ترتيب الحقول التي طُلبت. توجد قيود يمكن تطبيقها على الجدول نفسه، لكننا لن نناقشها في هذه السلسلة. أما النوع الآخر من القيود الذي نستطيع تطبيقه كما ذكرنا من قبل فهو تحديد نوع العمود، وهو يشبه مفهوم الأنواع في لغة البرمجة، ومجموعة الأنواع الصالحة في SQLite هي ما يلي: TEXT. INTEGER. REAL. NUMERIC. BLOB. NULL. يجب أن تكون هذه الأنواع مفهومةً وواضحةً، باستثناء NUMERIC وBLOB، فالأول يسمح بتخزين أعداد الفاصلة العائمة floating-point numbers والأعداد الصحيحة، أما BLOB فيُستخدم لتخزين البيانات الثنائية، مثل الصور أو المستندات غير النصية، فهو أفضل في تخزين مثل تلك العناصر في ملفات منفصلة مع وجود مرجع reference فقط يشير إليها في قاعدة البيانات. أما NULL فهو ليس نوعًا حقيقيًا، وإنما يشير إلى أننا لا نحتاج إلى تحديد نوع مطلقًا، فأغلب قواعد البيانات تأتي بمجموعة واسعة من الأنواع بما فيها النوع DATE، لكن SQLite لديها أسلوب غير تقليدي في الأنواع التي تجعل مثل هذه التفاصيل غير مهمة. تطبق أغلب قواعد البيانات الأنواع المحددة بصرامة، لكن SQLite تتبع نهجًا أكثر ديناميكيةً ومرونةً، حيث يكون النوع المحدَّد أشبه بالتلميح أو الإرشاد hint، ويمكن تخزين أي نوع من البيانات في الجدول، وعند تحميل بيانات من نوع مختلف إلى الحقل فإن SQLite ستستخدم النوع المصرَّح عنه لتحاول تحويل البيانات إليه، فإن لم تستطع فستخزنها في صورتها الأصلية، فإذا صُرِّح عن حقل على أنه عددي INTEGER ثم مُررت القيمة النصية '123'، فستحول SQLite السلسلة النصية '123' إلى العدد 123، لكن إذا كانت القيمة النصية TEXT هي 'Amindy' فلن ينجح تحويلها إلى عدد، وستخزنها SQLite في صورتها كما هي في الحقل، وقد يسبب هذا سلوكًا غريبًا إذا لم يكن المبرمج على علم بهذا العيب، أما بقية قواعد البيانات فتعدّ التصريح عن الأنواع قيدًا صارمًا، وتفشل عند تمرير قيمة غير مسموح بها. نمذجة العلاقات مع القيود لنر الآن كيف تساعدنا هذه القيود في صنع نماذج للبيانات والعلاقات، من خلال العودة إلى قاعدة البيانات البسيطة ذات الجدولين التي بدأنا المقال بها: الجدول 1: EmpID Name HireDate Grade ManagerID 1020304 Hasan Saleh 20030623 Foreman 1020311 1020305 Amin Akbar 20040302 Labourer 1020304 1020307 Ayat Othman 19991125 Labourer 1020304 الجدول 2: SalaryID Grade Amount 000010 Foreman 60000 000011 Labourer 35000 ينبغي أن يكون نوع قيمة المعرِّف ID عددًا صحيحًا، أي INTEGER، ويحمل القيد PRIMARY KEY، أما العمود الآخر فيجب أن يكون NOT NULL، باستثناء ManagerID الذي يجب أن يكون عددًا صحيحًا. ونرى هنا في جدول الرواتب Salary أن معرِّف الراتب SalaryID يجب أن يكون عددًا صحيحًا INTEGER مع قيد PRIMARY KEY، كما يجب أن يكون عمود مقدار الراتب Amount عددًا صحيحًا، وسنطبق القيمة الافتراضية DEFAULT التي مقدارها 10000، وأخيرًا يجب أن يكون العمود Grade مقيدًا بقيد التفرد Unique بما أننا لا نريد أكثر من راتب واحد لكل درجة وظيفية، رغم أن هذه الفكرة غير عملية، لأن الراتب يتغير بعوامل عدة، مثل مدة العمل والدرجة، لكننا سنتجاهل هذا التفصيل الآن لتبسيط الشرح، فلو كان هذا الجدول في حالة حقيقية لسميناه جدول الدرجات وليس الرواتب. ستبدو SQL المعدلة كما يلي: sqlite> CREATE TABLE Employee ( ...> EmpID INTEGER pRIMARY kEY, ...> Name NOT NULL, ...> HireDate NOT NULL, ...> Grade NOT NULL, ...> ManagerID INTEGER ...> ); sqlite> CREATE TABLE Salary ( ...> SalaryID INTEGER PRIMARY KEY, ...> Grade UNIQUE, ...> Amount INTEGER DEFAULT 10000 ...> ); يمكنك تجربة هذه القيود بإدخال البيانات التي تتسبب في تعطيلها لترى ما يحدث، وينبغي أن ترى رسالة خطأ. الأمر الذي تجب الإشارة إليه هنا هو أن تعليمات INSERT التي استخدمناها من قبل لم تعد مناسبةً، فقد أدخلنا قيمنا الخاصة من قبل لحقول ID، أما الآن فهي تُملأ تلقائيًا، فينبغي أن نهملها من البيانات المدرجة، غير أن هذا يفتح الباب لصعوبة جديدة، فكيف نملأ حقل معرِّف المدير managerID إذا كنا لا نعرف المعرف التوظيفي EmpID له؟ والإجابة هي أننا نستخدم تعليمة SELECT متشعبة، وقد رأينا أن ننفذ هذا على مرحلتين باستخدام حقول NULL أولًا، ثم استخدام تعليمة update بعد إنشاء جميع الصفوف، ولتجنب تكرار الكتابة قد وضعنا جميع الأوامر في بضعة ملفات، سميناها employee.sql لأوامر إنشاء الجداول، وemployee.dat لتعليمات الإدراج، وهذا يشبه إنشاء ملف سكربت بايثون ذي الامتداد ‎.py لتوفير كتابة كل الأوامر في محث ‎>>>‎. سيكون ملف employee.sql كما يلي: DROP TABLE IF EXISTS Employee; CREATE TABLE Employee ( EmpID INTEGER PRIMARY KEY, Name NOT NULL, HireDate NOT NULL, Grade NOT NULL, ManagerID INTEGER ); DROP TABLE IF EXISTS Salary; CREATE TABLE Salary ( SalaryID INTEGER PRIMARY KEY, Grade UNIQUE, Amount INTEGER DEFAULT 10000 ); نلاحظ هنا أننا أسقطنا الجداول -أي حذفناها- قبل إنشائها، فأمر DROP TABLE الذي ذكرناه من قبل يحذف الجدول وأي بيانات موجودة فيه، وهذا يضمن أن قاعدة البيانات ستكون خاليةً نظيفةً قبل أن ننشئ جدولنا الجديد، كما أضفنا شرط IF EXISTS الذي يمنعنا من محاولة حذف جدول حذف سابقًا. أما ملف employee.dat فسيكون كما يلي: INSERT INTO Employee (Name, HireDate, Grade, ManagerID) VALUES ('Hasan Saleh','20030623','Foreman', NULL); INSERT INTO Employee (Name, HireDate, Grade, ManagerID) VALUES ('Amin Akbar','20040302','Labourer',NULL); INSERT INTO Employee (Name, HireDate, Grade, ManagerID) VALUES ('Ayat Othman','19991125','Labourer',NULL); UPDATE Employee SET ManagerID = (SELECT EmpID FROM Employee WHERE Name = 'Hasan Saleh') WHERE Name = 'Amin Akbar' OR Name = 'Ayat Othman'; INSERT INTO Salary (Grade, Amount) VALUES('Foreman','60000'); INSERT INTO Salary (Grade, Amount) VALUES('Labourer','35000'); نلاحظ هنا استخدام تعليمة SELECT المضمنة في أمر UPDATE، وكذلك استخدامنا لأمر UPDATE واحد لتعديل صفَّي الموظف باستخدام شرط OR البولياني، ويمكن إضافة موظفين أكثر مع نفس المدير بسهولة بتوسيع شرط OR، وهذا مثال للمشاكل التي قد نواجهها عند ملء قاعدة بيانات للمرة الأولى، إذ سنحتاج إلى تخطيط ترتيب التعليمات بعناية لضمان توفير البيانات لكل صف يجب أن يحتوي على قيمة مرجعية إلى جدول آخر، وذلك من أجل الإشارة إليها، وهذا أشبه بالبدء من أوراق شجرة ما إلى جذعها، إذ يجب إنشاء وإدراج البيانات التي لا تحوي مراجع في البداية، ثم البيانات التي تشير مرجعيًا إلى تلك البيانات الأولى، وهكذا. فإذا أضفنا البيانات بعد الإنشاء الأولي فسنحتاج إلى استخدام استعلامات للتحقق من وجود البيانات التي نحتاج إليها، وإضافتها إن لم تكن موجودةً، وهنا تبرز أهمية لغة مثل بايثون. ثم نشغل هذه الملفات من محث sqlite كما يلي: sqlite> .read employee.sql sqlite> .read employee.dat تأكد أولًا من حل أي مشاكل تتعلق بمسارات الملفات، إما بتشغيل Sqlite من نفس مجلد سكربتات SQL كما فعلنا هنا، أو بتوفير المسار الكامل إلى السكربت. والآن لنجرب استعلامًا للتحقق من عمل هذه الملفات كما يجب: sqlite> SELECT Name FROM Employee ...> WHERE Grade IN ...> (SELECT Grade FROM Salary WHERE amount >50000) ...> ; Hasan Saleh يبدو أننا نجحنا هنا، إذ أن Hasan Saleh هو الموظف الوحيد الذي يتقاضى أكثر من 50000$، ونلاحظ أننا استخدمنا الشرط IN مع تعليمة SELECT مضمنة أخرى، وهذه صورة مختلفة عن استعلام مشابه أجريناه سابقًا باستخدام وصلة بين الجداول cross-table join، ورغم أن كلا التقنيتين ستعملان إلا أن طريقة الوصلة أسرع. العلاقات التعددية بين الجداول أحد السيناريوهات التي لم نتحدث عنها هو ربط جدولين معًا بعلاقات تعددية، أي يُربط صف في أحد الجدولين بعدة صفوف في الجدول الآخر، في نفس الوقت الذي يمكن ربط صف من الجدول الآخر بعدة صفوف من الجدول الأول، فمثلًا لنفرض أننا نكتب قاعدة بيانات لدعم دار نشر للكتب، حيث سيكون لدينا قائمة من المؤلفين وقائمة من الكتب، وسيكتب كل مؤلف كتابًا أو أكثر، وفي نفس الوقت قد يكون للكتاب الواحد عدة مؤلفين، فكيف نعبر عن هذه العلاقات في قاعدة بيانات؟ الجواب هنا هو تمثيل العلاقة بين الكتب والمؤلفين في جدول مستقل بذاته، ويُدعى هذا الجدول بجدول التقاطع intersection table أو جدول الربط mapping table، وكل صف في ذلك الجدول يمثل علاقةً من النوع كتاب/مؤلف، فقد يكون لكل كتاب عدة علاقات كتاب/مؤلف، لكن لكل علاقة كتابًا واحدًا ومؤلفًا واحدًا، وبذلك نكون قد حولنا علاقة متعدد-متعدد إلى علاقتي واحد-متعدد، وبما أننا نعرف كيف نبني مثل هذه العلاقات باستخدام المعرِّفات، فلنر ذلك عمليًا: DROP TABLE IF EXISTS author; CREATE TABLE author ( ID INTEGER PRIMARY KEY, Name TEXT NOT NULL ); DROP TABLE IF EXISTS book; CREATE TABLE book ( ID INTEGER PRIMARY KEY, Title TEXT NOT NULL ); DROP TABLE IF EXISTS book_author; CREATE TABLE book_author ( bookID INTEGER NOT NULL, authorID INTEGER NOT NULL ); INSERT INTO author (Name) VALUES ('Jane Austin'); INSERT INTO author (Name) VALUES ('Grady Booch'); INSERT INTO author (Name) VALUES ('Ivar Jacobson'); INSERT INTO author (Name) VALUES ('James Rumbaugh'); INSERT INTO book (Title) VALUES('Pride & Prejudice'); INSERT INTO book (Title) VALUES('Emma'); INSERT INTO book (Title) VALUES('Sense & Sensibility'); INSERT INTO book (Title) VALUES ('Object Oriented Design with Applications'); INSERT INTO book (Title) VALUES ('The UML User Guide'); INSERT INTO book_author (BookID,AuthorID) values ( (SELECT ID FROM book WHERE title = 'Pride & Prejudice'), (SELECT ID FROM author WHERE Name = 'Jane Austin') ); INSERT INTO book_author (BookID,AuthorID) VALUES ( (SELECT ID FROM book WHERE title = 'Emma'), (SELECT ID FROM author WHERE Name = 'Jane Austin') ); INSERT INTO book_author (BookID,AuthorID) VALUES ( (SELECT ID FROM book WHERE title = 'Sense & Sensibility'), (SELECT ID FROM author WHERE Name = 'Jane Austin') ); INSERT INTO book_author (BookID,AuthorID) VALUES ( (SELECT ID FROM book WHERE title = 'Object Oriented Design with Applications'), (SELECT ID FROM author WHERE Name = 'Grady Booch') ); INSERT INTO book_author (BookID,AuthorID) VALUES ( (SELECT ID FROM book WHERE title = 'The UML User Guide'), (SELECT ID FROM author WHERE Name = 'Grady Booch') ); INSERT INTO book_author (BookID,AuthorID) VALUES ( (SELECT ID FROM book WHERE title = 'The UML User Guide'), (SELECT ID FROM author WHERE Name = 'Ivar Jacobson') ); INSERT INTO book_author (BookID,AuthorID) VALUES ( (SELECT ID FROM book WHERE title = 'The UML User Guide'), (SELECT ID FROM author WHERE Name = 'James Rumbaugh') ); يمكن أن نجرب الآن بعض الاستعلامات لنرى كيف ستعمل، فمثلًا لنبحث عما نشرته جين أوستن Jane Austin من كتب: sqlite> SELECT title FROM book, book_author ...> WHERE book_author.bookID = book.ID ...> AND book_author.authorID = (SELECT ID FROM author ...> WHERE name = "Jane Austin"); لعل الأمر صار معقدًا قليلًا، لكن الفكرة ستتضح مع التكرار والتدريب، ولاحظ كيف نحتاج إلى إدراج كل من الجدولين المشار إليهما book وbook_author في قائمة الجداول بعد SELECT، أما الجدول الثالث author فليس موجودًا هناك لأنه مدرج مقابل تعليمة SELECT الخاصة به. لنجرب الآن بالطريقة المعاكسة، أي لنر من ألف كتاب The UML User Guide: sqlite> SELECT name FROM author, book_author ...> WHERE book_author.authorID = author.ID ...> AND book_author.bookID = (SELECT ID FROM book ...> WHERE title = "The UML User Guide"); بالنظر إلى تلك الشيفرة سنجد تطابق هيكل الاستعلامين، فلم نغير إلا أسماء الحقل والجدول. سنعود الآن إلى مثال دليل جهات الاتصال الذي تركناه في مقال التعامل مع الملفات في البرمجة، ويُفضل الرجوع لهذا المقال قبل متابعة القراءة لنرى كيف سنحوله من تخزين مبني على الملفات إلى قاعدة بيانات كاملة. إعادة النظر في دليل جهات الاتصال في دليل جهات الاتصال الذي كتبناه من قبل وبنيناه على الملفات، استخدمنا قاموسًا فيه اسم الشخص هو المفتاح، وعنوانه عنصر بيانات وحيد، ولا بأس بهذا إذا كنا نعرف الاسم الذي نريده، أو إذا أردنا تفاصيل العنوان كلها، لكن ماذا لو أردنا جميع الأسماء الموجودة في مدينة بعينها؟ أو كل من اسمه Hasan؟ يمكننا كتابة شيفرة بايثون لكل استعلام، لكن مع زيادة عدد الاستعلامات الخاصة سيزيد الجهد المطلوب لكتابة تلك الشيفرات، وهنا يأتي دور قواعد البيانات حيث يمكننا فيها إنشاء استعلامات ديناميكيًا باستخدام SQL، وسيبدو دليل جهات الاتصال قاعدة بيانات من جدول واحد، ويمكن تقسيم البيانات إلى عنوان وشخص، ثم ربطهما معًا، فقد يكون لدينا عدة أصدقاء يعيشون في نفس المنزل، لكننا سنلتزم بالتصميم الأصلي ونستخدم جدولًا بسيطًا، إلا أننا سنقسم البيانات إلى عدة حقول، حيث سنقسم الاسم إلى الاسم الأول والاسم الأخير، والعنوان إلى أجزائه المكونة له، بدلًا من أن يكون لدينا هيكل لاسم واحد وعنوان واحد، وعلى الرغم من كثرة الدراسات التي أجريت حول أفضل الطرق لتقسيم هذه البيانات إلا أننا لم نصل إلى إجابة محددة، لكنها جميعًا تتفق في أن حقل العنوان الواحد فكرة سيئة لأنها تفتقر للمرونة، وستكون حقول جدول قواعد البيانات والقيود التي نريد تطبيقها كما يلي: Field Name Type Constraint First Name String Primary Key Last Name String Primary Key House Number String NOT NULL Street String NOT NULL District String Town String NOT NULL Post Code String NOT NULL Phone Number String NOT NULL نلاحظ عدة أمور هنا: لدينا مفتاحان رئيسيان primary keys وهذا غير مسموح به، وسنتعامل معه بعد قليل. جميع البيانات من نوع TEXT رغم أن House Number قد يكون عددًا صحيحًا INTEGER، إلا أن أرقام المنازل تتضمن أحرفًا، لذا يجب استخدام TEXT. الحقل الاختياري الوحيد هو الحقل district. الرمز البريدي محدد الصيغة للغاية، لكنه يختلف وفقًا لكل دولة، وهذا يعني أن علينا أن نجعله من النوع TEXT ليناسب جميع الاحتمالات. رغم أن رقم الهاتف Phone Number قد يبدو مناسبًا لوضع قيد UNIQUE إلا أن هذا لن يسمح بوجود شخصين يتشاركان نفس رقم الهاتف، وهي حالة محتملة. بالعودة إلى النقطة الأولى -وجود مفتاحين رئيسيين- وهذا غير مسموح في SQL، لكن نستطيع جمع عمودين معًا في ما يسمى بالمفتاح المركب composite key، والذي يسمح بمعاملتهما مثل قيمة واحدة فيما يخص تعريف الصف، وعلى ذلك يمكن إضافة سطر في نهاية تعليمة create table ليجمع الاسم الأول FirstName وLastName في مفتاح رئيسي واحد، وسيبدو ذلك كما يلي: CREATE TABLE address ( FirstName NOT NULL, LastName NOT NULL, ... PhoneNumber NOT NULL, PRIMARY KEY (FirstName,LastName) ); نلاحظ هنا السطر الأخير PRIMARY KEY (FirstName,LastName)‎ الذي يحوي الأعمدة التي نريد استخدامها لتكون مفتاحًا مركبًا، وهو مثال على قيد قائم على الجدول table-based constraint، غير أن هذه الفكرة غير سديدة، فإذا كنا نعرف شخصين بنفس الاسم فلن نستطيع تخزينهما معًا، ولن نخزن إلا واحدًا فقط منهما، وسنتعامل مع هذا بتعريف حقل integer primary key لتعريف جهات اتصالاتنا تعريفًا فريدًا رغم أننا لن نستخدم ذلك في الاستعلامات إلا نادرًا. نعرف كيفية التصريح عن قيد INTEGER PRIMARY KEY حيث فعلنا ذلك في مثال الموظف، ونستطيع تحويل ذلك مباشرةً إلى سكربت إنشاء بيانات SQLite كما يلي: -- احذف الجداول إذا كانت موجودة من قبل وأعد إنشاءها. -- استخدم القيود لتحسين كفاءة البيانات. DROP TABLE IF EXISTS address; CREATE TABLE address ( ContactID INTEGER PRIMARY KEY, First NOT NULL, Last NOT NULL, House NOT NULL, Street NOT NULL, District, Town NOT NULL, PostCode NOT NULL, Phone NOT NULL ); السطران الأولان في الشيفرة السابقة ما هما إلا تعليقات، فأي شيء متبوع بشرطتين -- هنا يُعد تعليقًا في SQL، كما في حالة رمز # في بايثون. نلاحظ أننا لم نعرّف النوع لأن TEXT هو النوع الافتراضي في SQLite، فإذا أردنا تحويل هذا المخطط أو تخطيط الجدول -أو نقله port بالاصطلاح الحاسوبي- إلى قاعدة بيانات أخرى فسيتوجب علينا إضافة بعض المعلومات. أما الخطوة التالية فهي تحميل بعض البيانات إلى الجدول لنبدأ تنفيذ الاستعلامات، وسنترك ذلك تدريبًا للقارئ -باستخدام رمز الإدراج أعلاه قالبًا-، لكن سنستخدم مجموعة البيانات التالية في الأمثلة أدناه: First Last House Street District Town PostCode Phone Mona Akbar 42 Any Street SomePlace MyTown ABC123 01234 567890 Jamil Masoud 17 Any Street SomePlace MyTown ABC234 01234 543129 Yousef Mohammad 9 Crypt Drive Hotspot Metropolis ABC345 01234 456459 Yasein Akbar 42 Any Street SomePlace MyTown ABC123 01234 567890 Yasein Akbar 12A Double Street AnyTown DEF174 01394 784310 Amal Akbar 12A Double Street AnyTown DEF174 01394 784310 لدينا الآن بعض البيانات ونريد إجراء التجارب عليها، لنرى كيفية استخدام الإمكانيات الموجودة في SQL لاستخراج البيانات بطرق لم نكن لنحلم بها في مثال القاموس المبني على الملفات في بايثون. من يعيش في هذا الشارع؟ هذا الاستعلام بسيط ومباشر نوعًا ما، لأننا قسمنا بيانات العنوان إلى حقول منفصلة، فلو لم نفعل ذلك لاحتجنا إلى كتابة شيفرة تحليل لاستخراج بيانات الشارع، وهذا أكثر تعقيدًا لا شك، وسيبدو استعلام SQL الذي نريده كما يلي: sqlite> SELECT First,Last FROM Address ...> WHERE Street = "Any Street"; من يحمل اسم Akbar؟ هذا أيضًا تعبير SELECT/WHERE بسيط في SQL: sqlite> SELECT First,Last FROM Address ...> WHERE Last = "Akbar"; ما هو رقم هاتف Yasein؟ وهذا أيضًا استعلام بسيط إلا أننا سنحصل على عدة نتائج: sqlite> SELECT First,Last, Phone FROM Address ...> WHERE First LIKE "Yas%"; نلاحظ أننا استخدمنا LIKE في شرط WHERE، وهذا يستخدم أسلوب الموازنة الخاص بمحرف البدل wild card، ويتجاهل حالة الأحرف، لاحظ أن رمز محرف البدل في SQL هو % بدلًا من محرف * الشائع، ونتيجةً لهذا نحصل على مطابقة أكثر مرونةً من التساوي الذي يتطلب تطابقًا تامًا، ونلاحظ أننا لو استخدمنا %Y فقط في محرف البدل لحصلنا على Yosef في النتائج أيضًا. ما هي الأسماء المتكررة؟ هذا استعلام أكثر تعقيدًا، وسنحتاج إلى اختيار مداخل الجدول التي تكررت أكثر من مرة، وهنا يبرز دور المفتاح ContactID: sqlite> SELECT DISTINCT A.First, A.Last ...> FROM Address AS A, Address AS B ...> WHERE A.First = B.First ...> AND A.Last = B.Last ...> AND NOT A.ContactID = B.ContactID; نستخدم هنا بعض المزايا الجديدة، حيث نضيف A وB -وهما اسمان بديلان aliases- إلى الجداول في شرط FROM، كما نضيف أسماءً بديلةً للقيم الناتجة أيضًا لتقليل الكتابة، ونستخدم هذه الأسماء عند الإشارة إلى الحقول الناتجة باستخدام الصيغة النقطية المعتادة، يمكن استخدام الاسم البديل في أي استعلام، لكننا مجبرون على استخدامه هنا لأننا نستخدم نفس الجدول Address في المرتين -ومن ثم نضمه إلى نفسه-، لذا نحتاج إلى اسمين بديلين للتمييز بين النسختين في شرط where، كما نضيف الكلمة المفتاحية DISTINCT التي تحذف أي نتائج مكررة. وخلاصة الفقرات السابقة أن الاستعلام يبحث عن الصفوف التي لها نفس الاسم الأول والأخير، لكن لها معرِّف جهة اتصال ContactID مختلف، ثم يحذف الصفوف المتشابهة قبل عرض النتائج. لمحث SQLite التفاعلي نفس قوة محث بايثون من حيث القدرة على تطوير استعلامات معقدة مثل هذا، فقد نبدأ باستعلام بسيط ثم نزيد التعقيد لاحقًا، فمثلًا آخر جزء أضفناه إلى الاستعلام الأخير كان كلمة DISTINCT، على الرغم من أنها الكلمة الثانية فيه. الوصول إلى SQL من بايثون توفر SQLite واجهة برمجة تطبيقات API تتكون من عدد من الدوال القياسية التي تسمح للمبرمجين بتنفيذ جميع العمليات الممكنة في محث SQL، وقد كُتبت API الخاصة بـ SQLite بلغة C، لكن توجد مغلِّفات لها للغات الأخرى، بما في ذلك بايثون. الاتصالات Connections أول ما نحتاج إليه للتعامل مع قواعد البيانات هو الاتصالات، ويأتي الاسم من حقيقة أن أغلب قواعد البيانات ما هي إلا برامج مخدمات server programs تعمل على حاسوب مركزي في مكان ما في الشبكة، ونريد أن نتصل بها، عادةً بواسطة التسجيل باسم مستخدم وكلمة مرور. ورغم أن SQLite ما هي إلا ملف موجود في نظام الملفات لدينا، إلا أن API تطلب الاتصال به -أي فتحه- للحفاظ على اتساق العمليات. المؤشرات Cursors من المهم عند استخدام قاعدة بيانات من داخل برنامج ما أن نعرف كيفية الوصول إلى الصفوف المتعددة التي يُحتمل أن تعيدها تعليمة SELECT، وذلك باستخدام ما يُعرف بمؤشرات SQL أي SQL cursors، والمؤشر هنا يشبه تسلسل بايثون في القدرة على الوصول فيه إلى صف واحد في كل مرة، وعليه فإن استخراج بياناتنا إلى مؤشر ثم استخدام حلقة تكرارية loop للوصول إليه يمكّننا من معالجة تجميعات كبيرة من البيانات. ولا يخزن المؤشر كل البيانات الناتجة، وإنما يخزن مرجعًا إليها يُحفظ في جدول مؤقت داخل قاعدة البيانات، وهذا أقل أهميةً بالنسبة لـ SQLite التي تكون في الغالب على نفس الحاسوب الذي عليه البرنامج، لكنه مهم عند التعامل مع قاعدة بيانات متصلة بشبكة العميل/الخادم. يسمح المؤشر بجلب البيانات بكميات صغيرة، وهذا أسرع وأوفر للذاكرة من نسخ جميع البيانات الناتجة إلى البرنامج مرةً واحدةً، وتبرز أهمية ذلك عند العمل على قواعد بيانات كبيرة جدًا أحجامها بالجيجابايت، لكن هذا يعني أننا عندما نعالج جزءًا من البيانات الناتجة في وقت ما، فيجب ألا ننفذ أي استعلامات أخرى باستخدام نفس المؤشر، وإلا فسنفقد الوصول إلى مجموعة النتائج الأصلية، لذا يجب إنشاء مؤشر جديد للاستعلام الجديد. أما في البرامج الصغيرة -مثل التي لدينا- فنستطيع نسخ جميع البيانات إلى هيكل بيانات بايثون لحل المشكلة، لكن يجب الانتباه إلى أننا قد نحتاج إلى عدة مؤشرات في البرامج الكبيرة. الواجهة البرمجية لقواعد البيانات DB API يمكن قراءة توثيق الإصدار الأخير من واجهة برمجة التطبيقات لقواعد البيانات DB API في بايثون على موقع بايثون في قسم Database Topic Guide، ويجب قراءته بعناية خاصةً عند برمجة قواعد بيانات ذات أهمية باستخدام بايثون. تثبيت تعريفات SQLite تأتي تعريفات SQLite في مكتبة بايثون القياسية افتراضيًا، فإذا أردنا استخدام قاعدة بيانات أخرى، مثل SQL Server الخاصة بمايكروسوفت أو MySQL أو Oracle، فسنحتاج إلى تنزيل الوحدات المناسبة لكل منها وتثبيتها، ويمكن الحصول على تعريفات أغلب قواعد البيانات المشهورة من pip أو في ملفات تنفيذية. سيكون أمر استيراد SQLite كما يلي: import sqlite3 استخدام DBI الأساسي لن نغطي جميع المزايا الموجودة في DBI، لكننا سنذكر ما يكفي ليمكننا من الاتصال بقاعدة بياناتنا، وتنفيذ بعض الاستعلامات، ومعالجة النتائج، وسنختم بإعادة كتابة برنامج دليل جهات الاتصال ليستخدم قاعدة بيانات جهات الاتصال بدلًا من ملف نصي. >>> db = sqlite3.connect('address.db') >>> cur = db.cursor() >>> cur.execute('SELECT * FROM address') >>> print( cur.fetchall() ) ستكون النتيجة ما يلي: [(1, 'Mona', 'Akbar', '42', 'Any Street', 'SomePlace', 'MyTown', 'ABC123', '01234 567890'), (2, 'Jamil', 'Masoud', '17', 'Any Street', 'SomePlace', 'MyTown', 'ABC234', '01234 543129'), (3, 'Yousef', 'Mohammad', '9', 'Crypt Drive', 'Hotspot', 'Metropolis', 'ABC345', '01234 456459'), (4, 'Yasein', 'Akbar', '42', 'Any Street', 'SomePlace', 'MyTown', 'ABC123', '01234 567890'), (5, 'Yasein', 'Akbar', '12A', 'Double Street', '', 'AnyTown', 'DEF174', '01394 784310')] تعيد cursor.fetchball()‎ قائمةً من الصفوف tuples، وهذا مشابه لما بدأنا به في مقال مدخل إلى البيانات وأنواعها: أنواع البيانات الأساسية، ونستطيع استخدام هذه القائمة في برنامجنا كما لو قرأناها من ملف مستخدمين قاعدة البيانات آليةً ثابتةً، غير أن قوة قواعد البيانات الحقيقية تكمن في قدرتها على تنفيذ استعلامات معقدة باستخدام SELECT. دليل جهات الاتصال لا زال برنامج دليل جهات الاتصال الخاص بنا يعتمد على سطر الأوامر وليست له واجهة رسومية، فإذا أردنا إضافة واجهة مستخدم فيجب أن نعيد هيكلة الشيفرة refactoring لفصل الوظائف عن العرض، على كل سنضيف واجهة ويب للبرنامج. لن نشرح كل تفصيل في الشيفرة هنا، فيجب أن يستطيع القارئ في هذا المستوى أن يفهمها بنفسه، لكننا سنركز على بعض النقاط ونناقشها. ############################### # Addressbook.py # # Author: A J Gauld # ''' Build a simple addressbook using the SQLite database and Python DB-API. ''' ############################### # set up the database and cursor import sqlite3 dbpath = "D:/DOC/Homepage/Tutor2/sql/" def initDB(path): try: db = sqlite3.connect(path) cursor = db.cursor() except sqlite3.OperationalError: print( "Failed to connect to database:", path ) db,cursor = None,None raise return db,cursor # Driver functions def addEntry(book): first = input('First name: ') last = input('Last name: ') house = input('House number: ') street = input('Street name: ') district = input('District name: ') town = input('City name: ') code = input('Postal Code: ') phone = input('Phone Number: ') query = '''INSERT INTO Address (First,Last,House,Street,District,Town,PostCode,Phone) VALUES (?,?,?,?,?,?,?,?)''' try: book.execute(query,(first, last, house, street, district, town, code, phone)) except sqlite3.OperationalError: print( "Insert failed" ) raise return None def removeEntry(book): name = input("Enter a name: ") names = name.split() first = names[0]; last = names[-1] try: book.execute('''DELETE FROM Address WHERE First LIKE ? AND Last LIKE ?''',(first,last)) except sqlite3.OperationalError: print( "Remove failed" ) raise return None def findEntry(book): validFields = ('first','last','house','street', 'district','town','postcode','phone') field = input("Enter a search field: ") value = input("Enter a search value: ") if field.lower() in validFields: query = '''SELECT first,last,house,street,district,town,postcode,phone FROM Address WHERE %s LIKE ?''' % field else: raise ValueError("invalid field name") try: book.execute(query, (value,) ) result = book.fetchall() except sqlite3.OperationalError: print( "Sorry search failed" ) raise else: if result: for line in result: print( line ) else: print("No matching data") return None def testDB(database): database.execute("SELECT * FROM Address") print( database.fetchall() ) return None def closeDB(database, cursor): try: cursor.close() database.commit() database.close() except sqlite3.OperationalError: print( "problem closing database..." ) raise # User Interface functions def getChoice(menu): print( menu ) choice = input("Select a choice(1-4): ") return choice def main(): theMenu = ''' 1) Add Entry 2) Remove Entry 3) Find Entry 4) Test database connection 9) Quit and save ''' try: theDB, theBook = initDB(dbpath + 'address.db') while True: choice = getChoice(theMenu) if choice == '9' or choice.upper() == 'Q': break if choice == '1' or choice.upper() == 'A': addEntry(theBook) elif choice == '2' or choice.upper() == 'R': removeEntry(theBook) elif choice == '3' or choice.upper() == 'F': try: findEntry(theBook) except: ValueError: print("No such field name")) elif choice == '4' or choice.upper() == 'T': testDB(theBook) else: print( "Invalid choice, try again" ) except sqlite3.OperationalError: print( "Database error, exiting program." ) # raise finally: closeDB(theDB,theBook) if __name__ == '__main__': main() نلاحظ عدة أمور هي: استخدمنا الشرط try/except لالتقاط أي أخطاء في قاعدة البيانات، وبما أن الخطأ هو نوع مخصص معرَّف داخل وحدة sqlite3، فسنحتاج إلى سبقه باسم الوحدة. استخدمنا الكلمة المفتاحية raise بعد طباعة رسالة الخطأ، فنتج عن ذلك رفع الاستثناء الأصلي إلى المستوى التالي، والذي هو main في حالتنا، حيث التقط وطُبعت رسالة أخرى. استخدمنا كذلك محرف البدل ? في سلاسل الاستعلامات لتحمل متغيرات البيانات، وهذا يشبه محدِّدات % المستخدمة في صياغة السلاسل النصية، لكن تُدخل القيم هنا جزءًا من تنفيذ الاستعلام بواسطة book.execute، حيث نمرر صف القيم المدرجة وسيطًا ثانيًا، وميزة هذا تكمن في التحقق الأمني من قيم الدخل مما يحسِّن من أمان الشيفرة، فإذا لم نتحقق من الدخل، أو استخدمنا الصياغة القياسية للسلاسل النصية؛ فقد يكتب أحد المستخدمين شيفرةً بدلًا من قيمة الدخل، لتدخل تلك الشيفرة إلى الاستعلام وتخرب قاعدة البيانات، وهذا يُعرف بهجمات الحقن injection attack في دوائر الأمن الرقمي، وهو أحد أكثر الاختراقات الأمنية شهرةً في الويب هذه الأيام. نستخدم كلًا من اسم الحقل وقيمة البحث حقول إدراج في الدالة findEntry، مما يجعل دالة البحث أكثر تنوعًا، ولولاه لاحتجنا إلى دالة بحث لكل معيار بحث criteria وهذا أمر مرهق جدًا. لكن توجد مشكلة هنا سببها أن آلية معامِلات SQLite تعمل للقيم فقط، وليس لعناصر SQL، مثل أسماء الحقول أو الجداول، ولحل هذا نحتاج إلى استخدام صياغة السلاسل النصية في بايثون لإدراج اسم الحقل، ونحتاج إلى التحقق من أن اسم الحقل هو أحد الأسماء المعرّفة قبل إدراجه في الاستعلام، لنضمن أن الاستعلام آمن، فإذا لم يكن الحقل صالحًا فسنرفع استثناء بايثون قياسي من النوع ValueError، ثم نحتاج إلى التقاط ذلك في دالة main()‎، ونلاحظ أن الاستعلام يستخدم تعبير البحث LIKE الذي يسمح لنا باستغلال خيار محرف البدل % في SQL في سلسلة البحث الخاصة بنا. تحتوي الدالة closeDB على استدعاء commit، وهذا يجبر قاعدة البيانات على كتابة جميع التغييرات في الجلسة الحالية إلى الملف، ويمكن النظر إليها على أنها تشبه التابع file.flush، فهي تنهي العملية transaction نوعًا ما. تغلف الدالة main كل شيء داخل بنية try/except/finally، ويلتقط الشرط except الاستثناءات التي رفعتها دوال المستوى الأدنى كما ذكرنا أعلاه، لكن نلاحظ أنه يحوي تعليمة raise التي أُخرجت من التنفيذ بوضع علامة تعليق قبلها، لأن التعقب الخلفي الكامل للخطأ مفيد جدًا في تنقيح الأخطاء رغم كونه غير مفضل للمستخدم من حيث قابلية القراءة، لذلك يمكن إلغاء التعليق من raise التي في المستوى الأعلى أثناء التطوير لنحصل على تعقب خلفي كامل على الشاشة، وبعد حلّ جميع الزلات البرمجية bugs نعيد التعليق إلى تعليمة raise مرةً أخرى لاستعادة العرض النهائي للبرنامج، وهذا الأسلوب ليس مقصورًا على قواعد البيانات وحدها، بل يمكن استخدامه في أي برنامج يحتمل رفع أخطاء كثيرة فيه ولا نريد إظهار ذلك للمستخدمين، لكننا نحن المكورون نريد أن نراها. يُستخدم الشرط finally في دالة main لضمان إغلاق قاعدة البيانات بأناقة بغض النظر قابلنا أخطاءً أم لا، وهذا يقلل خطر تخريب البيانات. ملاحظة عن الأمن الرقمي ذكرنا أعلاه أن استخدام DB API لمحددات ? بدلًا من استخدام % المعتادة كان بداعي الأمان، ويمكن استخدام صياغة السلاسل النصية المعتادة في الشيفرة، وسنجد أنها ستعمل، مما يغري باستخدامها، غير أنه يُفضل عدم فعل ذلك لما نعلم من كثرة الهجمات السيبرانية، فيجب هنا اتباع هذه الإرشادات لتصبح عادات للمبرمج للحفاظ على أمان الشيفرة. ورغم أنها حل غير كامل وقد نخسر معها رؤية استعلامات SQL الحقيقية المرسَلة إلى قاعدة البيانات، والذي كنا سنستفيد منه في تنقيح الأخطاء، لكن هذه أفضل طريقة للتغلب على احتمال أن يُدخل المستخدم بيانات شاذةً. كلمة أخيرة استخدمنا SQLite في أمثلتنا لأنها متاحة مجانًا، وسهلة التثبيت والاستخدام، ومرنة في مدى الأخطاء التي تسمح بها، غير أن هذه البساطة تعني أن المزايا الأكثر تقدمًا والموجودة في الحزم الأقوى غير موجودة فيها، فإمكانيات معالجة النصوص ومجال القيود المتاحة محدود للغاية، ويجب قضاء وقت كافٍ في قراءة الوثائق المرجعية عند التعامل مع قواعد بيانات مثل Oracle أو قاعدة بيانات DB2 من IBM، لأن استخدام المزايا التي توفرها قاعدة البيانات يقلل من كم الشيفرات المخصصة التي ستُكتب، ويحسن الأداء أيضًا. المزايا المتقدمة لقواعد البيانات المفاتيح الخارجية تحتوي أغلب قواعد البيانات -بما فيها SQLite- على مفاتيح خارجية foreign keys، تسمح لنا بتحديد الروابط أو العلاقات بين الجداول، بحيث تتكون هذه المفاتيح من مفاتيح رئيسية لجداول أخرى، وأحيانًا في قواعد بيانات أخرى. ورغم أننا لم نتحدث كثيرًا عن الروابط بين الجداول إلا أنها من أكثر المزايا شيوعًا في قواعد البيانات العلائقية خاصةً عند زيادة حجم البرامج. التكامل المرجعي التكامل المرجعي Referential integrity هو القدرة على عدم السماح بقيم بيانات في عمود إلا إذا كانت موجودةً في مكان آخر، ففي قاعدة بيانات الموظفين مثلًا، كان بإمكاننا تقييد القيمة في حقل Employee.Grade لتسمح بالقيم المعرَّفة في جدول Salary.Grade فقط، وهذه أداة بالغة القوة في الحفاظ على اتساق البيانات عبر قاعدة البيانات، خاصةً عندما تُستخدم القيم مفاتيح لربط جدولين، كما هو الحال في أعمدة grade. تدعم SQLite صورةً محدودةً من التكامل المرجعي في صورة قيد، لكنها تتطلب بعض المعالجة الخاصة، وهي أقل شموليةً من قواعد البيانات الأقوى. الإجراءات المخزنة الإجراءات المخزنة Stored Procedures هي دوال مكتوبة بلغة برمجة خاصة proprietary programming language يوفرها مزود قاعدة البيانات، وتُخزَّن في قاعدة البيانات، ومزيتها أنها إجراءات مصرَّفة compiled، وبالتالي أسرع كثيرًا من استخدام أوامر SQL المكافئة، كما أنها توفر من استهلاك الإنترنت وحجم البيانات المطلوب، من خلال طلب اسم الدالة والوسطاء فقط ليرسلها برنامج العميل، ولكونها مبنيةً داخل الخادم فهي تسمح لنا ببناء سلوكيات مشتركة -مثل قواعد العمل المعقدة- في قاعدة البيانات حيث يمكن تشاركها بواسطة جميع التطبيقات باستمرار، لكن عيبها أنها خاصة ومغلقة، فإذا أردنا تغيير مزود قاعدة البيانات لدينا فيجب إعادة كتابة جميع الإجراءات المخزنة، في حين أن SQL القياسية ستعمل دون تغيير على أي قاعدة بيانات، ولا تدعم SQLite أي إجراءات مخزنة. العروض العروض Views هي جداول افتراضية مكونة من جداول حقيقية أخرى، وقد تكون مجموعةً فرعيةً من البيانات في جدول آخر من أجل تبسيط التصفح، وفي الحالة الأشهر تكون بعض الأعمدة من جدول وبعضها من جدول آخر بحيث يكون الجدولان مرتبطين معًا بمفتاح ما. ويمكن النظر إليها على أنها استعلام SQL يُنفّذ باستمرار وتُخزن النتيجة في العرض، وسيتغير العرض مع تغير البيانات التي فيه، وقد تسمح بعض قواعد البيانات بقراءة البيانات في العرض، غير أنها جميعًا تسمح بالتحديثات. تُستخدم العروض في الغالب لتقسيم البيانات بحيث يستطيع المستخدم الواحد أن يرى مجموعة البيانات المتعلقة به فقط، وتدعم SQLite العروض، لكننا لم نشرحها هنا. عمليات الحذف المتتالية إذا أجرينا حذفًا متتاليًا cascaded delete بين عنصري بيانات فهذا يعني أنه عند حذف العنصر الرئيسي فستُحذف العناصر الثانوية أيضًا، وأحد أشهر الأمثلة على ذلك هو الطلبات orders، حيث يتكون الطلب عادةً من الطلب نفسه بالإضافة إلى العناصر المطلوبة، ويُخزن كل منها عادةً في جدول منفصل، فإذا حذفنا الطلب فإننا نرغب بالتأكيد في حذف عناصره، وتُهيأ عمليات الحذف المتتالية في تعليمات DDL لقواعد البيانات المستخدمة لإنشاء مخططات قواعد البيانات، وهي أحد أنواع القيود، ولا تدعم SQLite عمليات الحذف المتكررة. المحفزات تشبه المحفزات Triggers الأحداث إلى حد ما، فهي جزء من SQL يُنفَّذ عند وقوع حدث معين، كما في حالة إدراج صف جديد في جدول ما مثلًا، وهي مفيدة في التحقق من صلاحية البيانات تحققًا أعمق من مجرد النوع والقيم، كما تكون مفيدةً للغاية عند ربطها بالإجراءات المخزنة. أما عيبها فهو إمكانية إساءة استخدامها، وشرهها الزائد للموارد، مما يؤدي لإبطاء قاعدة البيانات كثيرًا، لذا يجب استخدامها بحذر، وتدعم SQLite محفزات SQL الأساسية والخالصة. أنواع البيانات المتقدمة تسمح بعض قواعد البيانات بتخزين مجموعات متنوعة من أنواع البيانات، فقد يكون لدينا عناوين شبكية network addresses وكائنات ثنائية binary كبيرة يشار إليها اختصارًا باسم BLOBS لملفات الصور وغيرها، إضافةً إلى البيانات العددية وبيانات المحارف والتاريخ والوقت المعتادة، ومن أنواع البيانات المشهورة أيضًا نوع يسمى بالنوع العشري ذي الدقة الثابتة fixed precision decimal type، وهو يُستخدم في البيانات المالية لتجنب أخطاء التقريب الموجودة في أعداد الفاصلة العائمة التقليدية، وتدعم SQLite بيانات BLOB لكنها لا تدعم بقية الأنواع المتقدمة، وللاطلاع على المزيد من الاستخدامات المعقدة لـ SQLite يمكن العودة إلى موقع sqlitetutorial الذي يحتوي على شرح ممتاز يسهل تعلم ما فيه بناءً على ما شرحنا هنا. خاتمة في نهاية هذا المقال نرجو أن تكون تعلمت ما يلي: قواعد البيانات تنظم البيانات في جداول. تتكون السجلات من حقول، وتشمل صفوف الجداول. SQL هي لغة تُستخدم في إدارة البيانات. الأوامر الأساسية في لغة SQL هي: CREATE وINSERT وSELECT وUPDATE. توفر لغات البرمجة مغلِّفات SQL للوصول إلى البيانات من البرامج. تخزن المؤشرات نتائج استعلامات SQL في صورة مؤقتة، لكن يمكن الوصول إليها. تُستخدم محدِّدات DB API لإدراج قيم في الاستعلامات، ولا تُستخدم صيغة السلاسل النصية القياسية. ترجمة -بتصرف- للفصل الرابع والعشرين: Working with Databases من كتاب Learn To Program لصاحبه Alan Gauld. اقرأ أيضًا المقال التالي: التواصل مع نظام التشغيل عبر بايثون المقال السابق: دراسة حالة برمجية التعامل مع البيانات (الإدخال، الحذف والتعديل) في SQL دوال التعامل مع البيانات في SQL مقارنة بين أنظمة إدارة قواعد البيانات العلاقية: SQLite مع MySQL مع PostgreSQL
  25. تعلمنا في الجزء الأول من هذه السلسلة كيفية بناء مدونة كتطبيق وحيد الصفحة باستخدام إطار العمل Angular للواجهة الأمامية، وقاعدة بيانات Firestore، وإضافة محرر للمدونة ثم إضافة تدوينات جديدة وعرضها على الصفحة الرئيسية، أما في هذا الجزء فسنتعلم كيفية التعديل على التدوينات وإضافة الترقيم في نهاية الصفحة الرئيسية لعرض عدد محدد من التدوينات فيها والتنقل بين صفحات التدوينات الأخرى. هذا المقال جزء من سلسلة عن بناء مدونة باستخدام إطار العمل Angular وقاعدة بيانات Firestore مقدمة في بناء تطبيقات الويب باستخدام إطار العمل Angular وقاعدة بيانات Firestore بناء مدونة باستخدام إطار العمل Angular وقاعدة بيانات Firestore - إضافة التدوينات وعرضها بناء مدونة باستخدام إطار العمل Angular وقاعدة بيانات Firestore - تعديل التدوينات بناء مدونة باستخدام إطار العمل Angular وقاعدة بيانات Firestore - إضافة الاستثيثاق نشر مدونة مبنية عبر Angular على Firebase حذف تدوينة سننشئ الآن خدمة Snackbar، وهي خدمة تُظهر شريطًا يعرض رسائل للمستخدم نعرض عبرها رسالة بعد حذف التدوينة، وننشئها بكتابة الأمر التالي: ng g s services/Snackbar افتح الملف snackbar.service.ts وضع الشيفرة التالية فيه: import { Injectable } from '@angular/core'; import { MatSnackBar } from '@angular/material/snack-bar'; @Injectable({ providedIn: 'root' }) export class SnackbarService { constructor(private snackBar: MatSnackBar) { } showSnackBar(message: string) { this.snackBar.open(message, 'Close', { duration: 2000, panelClass: 'snackbar-ribon', verticalPosition: 'top', horizontalPosition: 'center' }); } } لقد أنشأنا الآن التابع showSnackBar الذي يقبل معامِلًا يكون هو الرسالة التي نريد عرضها، والحد الأقصى لعرض هذه الرسالة هو 2000 مللي ثانية، وقد عرَّفنا موضع الشريط لينتصف أعلى الصفحة. أضف الآن التنسيق التالي لشريط Snackbar في الملف styles.scss: .snackbar-ribon { color: #FFFFFF; background: #17a2b8; } سنضيف الآن مزية حذف إحدى التدوينات الموجودة، وسنحذف التدوينة من تجميعة blogs وفقًا لمعرِّف التدوينة postID. أضف الشيفرة التالية في الملف blog.service.ts: deletePost(postId: string) { return this.db.doc('blogs/' + postId).delete(); } افتح الملف blog-card.comonent.ts واستورد SnackbarService كما يلي: deletePost(postId: string) { return this.db.doc('blogs/' + postId).delete();} ثم احقن خدمة SnackbarService في المنشئ كما يلي: constructor( // other service injection private snackBarService: SnackbarService ) { } كما سنحدّث تابع الحذف في الملف blog-card.comonent.ts، بحيث يكون تعريفه كما يلي: delete(postId: string) { if (confirm('Are you sure')) { this.blogService.deletePost(postId).then( () => { this.snackBarService.showSnackBar('Blog post deleted successfully'); } ); } } سيقبل تابع الحذف postID كمعامِل وسيعرض رسالة تحذير تطلب تأكيد الحذف، وعند ضغط المستخدم على OK، يُستدعَى تابع deletePost الخاص بالخدمة BlogService، ثم نعرض رسالة تظهر نجاح عملية الحذف باستخدام شريط snackbar. افتح المتصفح واضغط على زر Delete في بطاقة التدوينة، سيظهر صندوق جافاسكربت يطلب تأكيد عملية حذف التدوينة: إذا ضغط المستخدم على OK ستُحذف التدوينة ونحصل على رسالة توكيد في شريط Snackbar: التعديل على تدوينة موجودة سننفذ الآن خاصية التعديل على تدوينة قائمة وموجودة، من خلال إضافة التعريف التالي إلى الملف blog.service.ts: updatePost(postId: string, post: Post) { const putData = JSON.parse(JSON.stringify(post)); return this.db.doc('blogs/' + postId).update(putData); } سيقبل التابع updatePost كلا من postID وكائنًا من النوع Post كمعاملات، وسنحلل كائن Post إلى كائن JSON ثم نحدّث الكائن في تجميعة blogs. أضف توجيه وظيفة التعديل في الملف app.module.ts كما يلي: RouterModule.forRoot([ ... { path: 'editpost/:id', component: BlogEditorComponent }, ... ]) ثم أضف تعريف الاستيراد التالي في الملف blog-editor.component.ts: import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; صرِّح الآن عن متغير Subject جديد: private unsubscribe$ = new Subject<void>(); افتح الملف blog-editor.component.ts وأضف الشيفرة التالية في المنشئ: if (this.route.snapshot.params['id']) { this.postId = this.route.snapshot.paramMap.get('id'); } في الشيفرة أعلاه، نستخدم الصنف ActivatedRoute لجلب معرِّف التدوينة من الرابط. سنضيف الآن تابعًا لإعداد استمارة التعديل عند النقر على زر Edit في بطاقة التدوينة في الصفحة الرئيسية، ويكون تعريف التابع كما يلي: setPostFormData(postFormData) { this.postData.title = postFormData.title; this.postData.content = postFormData.content; } حدِّث الآن التابع ngOnInit داخل الصنف BlogEditorComponent كما يلي: ngOnInit() { this.setEditorConfig(); if (this.postId) { this.formTitle = 'Edit'; this.blogService.getPostbyId(this.postId) .pipe(takeUntil(this.unsubscribe$)) .subscribe( result => { this.setPostFormData(result); } ); } } إذا كان postID معيَّنًا set فهذا يعني أن هذا طلب تحرير Edit، وسنجعل عنوان الاستمارة Edit، ونستدعي التابع getPostbyID من BlogService لجلب تفاصيل التدوينة المتوافقة مع postID. عند النقر على Save، نحتاج إلى معالجة كلا من حالة إنشاء تدوينة جديدة وتحرير تدوينة موجودة من قبل، وعليه سنحدِّث saveBlogPost كما يلي: saveBlogPost() { if (this.postId) { this.blogService.updatePost(this.postId, this.postData).then( () => { this.router.navigate(['/']); } ); } else { this.postData.createdDate = this.datePipe.transform(Date.now(), 'MMdd-yyyy HH:mm'); this.blogService.createPost(this.postData).then( () => { this.router.navigate(['/']); } ); } } سننفذ الواجهة OnDestroy على الصنف BlogEditorComponent، وسنكمل اشتراك unsubscribe$‎ داخل التابع ngOnDestroy، انظر الشيفرة التالية: ngOnDestroy() { this.unsubscribe$.next(); this.unsubscribe$.complete(); } افتح المتصفح وانقر على زر Edit في بطاقة التدوينة في الصفحة الرئيسية، ستنتقل الصفحة إلى صفحة Edit Post. تستطيع الآن أن ترى محرر التدوينة وفيه محتوى التدوينة جاهزًا بداخله، وإذا نظرت إلى الرابط ستجد أنه يحتوي على postID الخاص بهذه التدوينة. انظر الصورة التالية: يمكن الآن تعديل محتوى التدوينة داخل المحرر، وبعد تمام التعديل ننقر على زر الحفظ لتحديث التدوينة بالمحتوى الجديد والعودة إلى الصفحة الرئيسية لنرى المحتوى الجديد في ملخص التدوينة: إضافة شريط تنقل بين صفحات التدوينات سنضيف خاصية الترقيم pagination في الصفحة الرئيسية وذلك للتنقل بين صفحات بطاقات التدوينات، مستخدمين ngx-pagination لهذا الغرض، وهو مكون مفتوح المصدر يوفر خاصية ترقيم بسيطة وسهلة الاستخدام لتطبيقات Angular. نفِّذ الأمر التالي لتثبيت المكون ngx-pagination: npm i ngx-pagination --save استورد NgxPaginationModule في الملف app.module.ts كما يلي: import { NgxPaginationModule } from 'ngx-pagination'; @NgModule( { imports: [ ... NgxPaginationModule, ], }) إنشاء مكون المرقم PaginatorComponent نفِّذ الأمر التالي في الطرفية الأصلية لتوليد مكون المرقِّم PaginatorComponent: ng g c components/paginator افتح الملف paginator.component.ts وأضف تعريفات الاستيراد التالية: import { Input } from '@angular/core'; import { Router } from '@angular/router'; سنضيف خاصيتي إدخال لهذا المكون، كما يلي: @Input() pageSizeOptions: []; @Input() config: any; احقن صنف الموجِّه router داخل المنشئ، كما يلي: constructor(private router: Router) { } سنضيف تابعًا يعالج حدث pageChange للمرقِّم الخاص بنا، وسيكون تعريف ذلك التابع كما يلي: pageChange(newPage: number) { this.router.navigate(['/page/', newPage]); } كذلك، نضيف التابع changePageItemCount في الصنف PaginatorComponent، ويُستخدم هذا التابع لإعداد ترقيم ديناميكي للمرقِّم، حيث يعين عدد العناصر التي يظهرها على كل صفحة وفقًا لاختيار من قائمة منسدلة: changePageItemCount(selectedItem) { localStorage.setItem('pageSize', selectedItem.value); this.config.itemsPerPage = selectedItem.value; } سنخزِّن القيمة التي يختارها المستخدم في الذاكرة المحلية، وذلك لضمان أن القيمة لا تُفقد عند تحديث الصفحة، وكذلك لضمان جودة تجربة المستخدم. افتح الملف paginator.component.html واستبدل الشيفرة التالية بالموجود فيه: <div class="paginator-controls"> <div> <pagination-controls (pageChange)="pageChange($event)" class="mypagination"></pagination-controls> </div> <div> <mat-form-field> <mat-label>Items per page: </mat-label> <mat-select [(ngModel)]="config.itemsPerPage" (selectionChange)="changePageItemCount($event)"> <mat-option *ngFor="let page of pageSizeOptions" [value]="page"> {{ page }} </mat-option> </mat-select> </mat-form-field> </div> </div> أخيرًا، سنضيف التنسيق الخاص بالمكون PaginatorComponent، فافتح الملف paginator.component.scss واستبدل الشيفرة أدناه بالموجود فيه: .my-pagination ::ng-deep .ngx-pagination { margin: 10px 0px 10px 0px; padding-inline-start: 0px; } .paginator-controls { display: flex; justify-content: space-between; padding-top: 10px; } @media screen and (min-width: 320px) and (max-width: 420px) { .paginator-controls { flex-direction: column-reverse; } } أما الآن، فسنضيف رابط موجِّهٍ في الملف app.module.ts لدعم الترقيم كما يلي: { path: 'page/:pagenum', component: HomeComponent }, إضافة المكون PaginatorComponent إلى قائمة التدوينات يجب أن نضيف المكون PaginatorComponent إلى مكون قائمة التدويناتBlogCardComponent من أجل تفعيل الترقيم فيها، لنصرح عن خاصيتين، كما يلي: config: any; pageSizeOptions = []; أضف الاستيراد للصنف ActivatedRoute في المكون، كما يلي: import { ActivatedRoute } from '@angular/router'; احقن الصنف ActivatedRoute في المنشئ، كما يلي: constructor( // other services private route: ActivatedRoute) { } أضف الشيفرة التالية داخل منشئ الصنف BlogCardComponent لبدء الخصائص المصرَّح عنها للتو: this.pageSizeOptions = [2, 4, 6]; const pageSize = localStorage.getItem('pageSize'); this.config = { currentPage: 1, itemsPerPage: pageSize ? +pageSize : this.pageSizeOptions[0] }; والآن، حدِّث التابع ngOnInit كما يلي: ngOnInit() { this.route.params.subscribe( params => { this.config.currentPage = +params['pagenum']; this.getBlogPosts(); } ); } تحديث قالب BlogCardComponent افتح الملف blog-card.component.html وأضف مكون المرقِّم كما يلي: <app-paginator [pageSizeOptions]="pageSizeOptions" [config]="config"></app-paginator> سنضيف أنبوب ترقيم أيضًا في التوجيه ngFor أثناء التكرار على قائمة التدوينات، كما يلي: <div *ngFor="let post of blogPost | paginate: config"> افتح المتصفح الآن، يجب أن ترى المرقِّم في الصفحة الرئيسية، كما تستطيع التنقل بين الصفحات كما تشاء، ويتغير الرابط برقم الصفحة التي انتقلت إليها، كما يمكن رؤية القائمة المنسدلة بجانب المرقِّم، والتي تسمح باختيار عدد العناصر التي ينبغي إظهارها في كل صفحة، انظر الصورة التالية: خاتمة تعلمنا في هذا الجزء من سلسلة بناء مدونة باستخدام إطار العمل Angular وقاعدة بيانات Firestore كيفية حذف التدوينات والتعديل عليها وإضافة الترقيم للصفحات، وسنتعلم في المقال التالي كيفية إضافة استيثاق جوجل للوصول إلى التطبيق وإضافة التدوينات والتعديل عليها. ترجمة -وبتصرف- لفصول من كتاب Build a full stack web application using angular and firebase لصاحبه Ankit Sharma. اقرأ أيضًا المقال السابق: بناء مدونة باستخدام إطار العمل Angular وقاعدة بيانات Firestore - إضافة التدوينات وعرضها بناء تطبيق ويب كامل باستخدام Angular ومنصة Firebase تهيئة بيئة تطبيقات Angular ونشرها على الويب
×
×
  • أضف...