لوحة المتصدرين
المحتوى الأكثر حصولًا على سمعة جيدة
عرض المحتوى الحاصل على سمعة أكبر منذ 10/20/24 in مقالات البرمجة
-
نحن نسمي أنفسنا "إنسان عاقل أو حكيم"، لأن ذكائنا أمر مهم جدًا بالنسبة لنا. لقد حاولنا منذ آلاف السنين أن نفهم كيف نفكر، أي كيف يمكن للعقل البشري أن يدرك ويُحلل ويفهم ويتنبأ ويتلاعب بعالم كبير ومعقد. يذهب الذكاء الصناعي إلى ماهو أبعد من ذلك؛ يحاول فهم الكيانات الذكية إلى جانب بناء كيانات ذكية أيضًا. الذكاء الاصطناعي هو أحد أحدث المجالات في العلوم والهندسة، وقد بدأ العمل به بجدية بعد الحرب العالمية الثانية بفترة وجيزة، لكنه لم يُبصر النور إلا مع بداية القرن الحادي والعشرين، حيث بدأ الإنترنت والبيانات بالانتشار إلى جانب تطور أجهزة الحواسيب. يتميز الذكاء الصناعي بأنه علم كبير وتعددي؛ يشارك فيه علماء الحاسوب والرياضيات والهندسة واللغة والفلسفة والمنطق. الذكاء الاصطناعي وثيق الصلة بأي مهمة فكرية؛ إنه مجال عالمي. ماهو الذكاء الاصطناعي لنتفق بدايةً أنّه لا فرق في قول "الذكاء الاصطناعي" أو "الذكاء الصناعي" بالعربية، فكلاهما يُشيران إلى شيء من صنع البشر وليس الطبيعة. مفهوم الذكاء الصناعي Artificial Intelligence -اختصارًا AI- هو مجال جديد ظهر تقريبًا عام 1950 على يد آلان تورينج (يُسميه البعض الأب الروحي للذكاء الصناعي) المقصود به باختصار هو جعل الآلة تفكر وتعمل مثل الإنسان. في البداية لاقى هذا المجال الكثير من الصعوبات لأن العلماء كانوا يحاولون محاكاة الذكاء والتفكير البشري، محاولين جعل الآلة تفكر وتعمل مثل الإنسان. بسبب هذا التفكير فشل العلماء في الوصول إلى تقدم حقيقي في هذا المجال، لأنه رغم كل التقدم الذي وصلت إليه العلوم لم يستطع العلماء تحديد الطريقة التي يفكر بها الإنسان. وصل العلماء لاحقًا إلى قناعة تفيد بأننا كبشر لا يهمنا كيف تعمل الآلة (أي لن نُقيد الآلة بطريقة التفكير البشري)؛ المهم أن نحصل على نفس النتيجة التي نحصل عليها من خلال الإنسان، فالإنسان يرى الصورة على أنها انعكاسات للضوء، والآلة ترى الصورة على أنها مصفوفة من البيكسلات والأصفار والواحدات. آنذاك بدأ الذكاء الصناعي بالتطور ودخل جميع مجالات حياتنا العملية سواءًا المجال العسكري والطبي والصناعي والتجاري وحتى التعليمي والترفيهي، فكانت دقة الأداء عالية جدًا، وفي بعض المجالات كانت نسبة الخطأ شبه معدومة، أي أن الآلة بدأت تحاكي التفكير البشري، حتى أنها أصبحت أفضل منه في كثير من المجالات، فالعلوم حاليًا هي علوم الذكاء الصناعي. إن كان الإنترنت هو ثورة السنوات الماضية، فالذكاء الصناعي هو ثورة الحاضر والمستقبل. تعريف الذكاء الاصطناعي الذكاء الصناعي هو مصطلح صاغه البروفيسور الفخري في جامعة ستانفورد جون مكارثي في عام 1955 لأول مرة ضمن ورشة عمل صيفية تسمى مشروع دارتموث الصيفي للبحوث حول الذكاء الاصطناعي على أنه: بالرغم من أن هناك اختلافات حول التعريف، إلا أن الجامعة الأشهر في الذكاء الصناعي "ستانفورد" تعتمده. من التعاريف الأخرى هو التعريف الذي صاغه أندرياس كابلان ومايكل هاينلين، وينص على أن الذكاء الصناعي هو: تُركز تعريفات الذكاء الاصطناعي الحديثة على أنّه مجال فرعي لعلوم الحاسب وكيف يمكن للآلات تقليد الذكاء البشري. يُقدم قاموس أكسفورد هذا التعريف: ما هو ذكاء الآلة ومتى نقول عن الآلة أنها ذكية؟ يُجيب عن هذا السؤال اختبار تورينج (نسبةً لآلان تورينج). إنها أشبه بلعبة بين ثلاث أطراف؛ اثنان من البشر (الأول لاعب والثاني حكم أو مراقب) والآلة المُراد اختبارها إن كانت ذكية (اللاعب الثاني). اللاعبين الثلاثة معزولين عن بعضهم البعض، ويكون التراسل بين الأطراف كتابيًا. يبدأ المراقب بطرح أسئلة على اللاعبين (الحاسب والشخص الآخر). ينجح الحاسوب في الاختبار (يكون ذكي) إذا لم يستطع المراقب التفريق بينه وبين الإنسان. عبقرية هذا المفهوم هي أنه ليست هناك حاجة لمعرفة ما إذا كانت الآلة تعرف شيئًا ما بالفعل أو أنها تُدرك ذاتها أو حتى إذا كانت إجاباتها صحيحة، وإنما يشير إلى قدرة تلك الآلة على معالجة كميات كبيرة من المعلومات وتفسير اللغة البشرية. الذكاء الاصطناعي وتعلم الآلة على الرغم من الخلط بين المصطلحين في بعض السياقات، إلا أن تعلم الآلة فرع من فروع الذكاء الصناعي العديدة. يشير الذكاء الصناعي إلى أي أسلوب يُعطي الآلة القدرة على محاكاة الذكاء البشري، بينما يشير التعلم الآلي إلى مجموعة التقنيات والخوارزميات التي تسمح للآلات بالتعلم من البيانات دون أن تُبرمج عليها صراحةً. ما أهمية الذكاء الاصطناعي؟ يُنظر إلى تقنيات الذكاء الصناعي على أنها أدوات وتقنيات تهدف لخدمة البشرية وتسهيل حياة الأفراد، فهي تهدف إلى جعل حياتنا أسهل، كما يمكن تطبيقه في جميع المجالات تقريبًا للحصول على كفاءة أعلى. فيُقدم الذكاء الصناعي العديد من الميزات والحلول التي تعود بالفائدة لأي مؤسسة حديثة تقريبًا، يتضمن ذلك: أتمتة العمليات: الذكاء الاصطناعي قادر على أتمتة المهام التي نُنجزها يدويًّا وبدقة وسرعة دون الشعور بأي إرهاق أو الاضطرار إلى أخذ فترات راحة مثلما يحتاج الموظف البشري (مثلًا مراقبة السيارات والإبلاغ عن المخالفات). تحليل البيانات الضخمة: كمية البيانات الموجودة حاليًّا على الإنترنت تفوق بكثير قدرة البشر على استيعابها وتفسيرها واتخاذ قرارات معقدة بناءً عليها. يمكن لخوارزميات الذكاء الصناعي معالجة تلك البيانات وتحليلها وفهمها، وبالتالي تمنح المؤسسات رؤى حول عملياتها ربما لم تكن على دراية بها من قبل. اتخاذ القرارات: يمكن لخوارزميات الذكاء الاصطناعي اتخاذ قرارات أكثر دقة من البشر في بعض الأحيان نظرًا لقدرتها على تحليل العلاقات المعقدة والمتعددة والاستفادة من البيانات الضخمة المنتشرة على الإنترنت. مجالات الذكاء الاصطناعي يعد الذكاء الاصطناعي مجالًا واسعًا للدراسة يتضمن العديد من النظريات والأساليب والتقنيات المختلفة، ومن أبرز مجالات الذكاء الاصطناعي مايلي: تعلم الآلة Machine learning: عرّف آرثر صموئيل تعلم الآلة بأنّه المجال الذي يعطي الحاسوب القدرة على التعلم من المشاكل التي يصادفها دون تعليمات واضحة تُعطى له، أي القدرة على معالجة مشاكل جديدة. الشبكات العصبية الاصطناعية Artificial Neural Networks: عبارة عن مجموعة من الخوارزميات المُصممة بطريقة مُستوحاة من الخلايا العصبية في الدماغ البشري، وهي مصممة للتعرف على الأنماط. التعلم العميق Deep Learning: يستخدم شبكات عصبية ضخمة مع العديد من طبقات وحدات المعالجة، حيث يستفيد من التطورات الحوسبية الكبيرة (المعالجات القوية مثلًا) وتقنيات التدريب المحسنة لتعلم الأنماط المعقدة بكميات كبيرة من البيانات. أتمتة العمليات الآلية Robotic Process Automation: يمكن أن يكون مصطلح أتمتة العمليات الآلية مربكًا بعض الشيء؛ لا تعني كلمة آلية أو روبوتية هنا الروبوتات المادية، وإنما الروبوتات التي تُمثل برامج (برامج آلية) تُنفِّذ بعض العمليات التقليدية المكررة، مثل وإدارة المعاملات وإرسال الفواتير وتقديم ردود نموذجية للعملاء (روبوتات الدردشة، لابد وأنك تعرفها). الروبوتات Robots: هو آلة يمكنها إنجاز المهام الموكلة إليها من خلال تنفيذ سلسلة معقدة من الإجراءات تلقائيًا. يمكن توجيه الروبوت بواسطة جهاز تحكم خارجي، أو قد يكون عنصر التحكم مضمنًا فيه. الأنظمة الخبيرة Expert systems: النظام الخبير هو محاولة جمع الخبرة البشرية المتعلقة بمجال محدد ضمن الحاسب لكي يحل محل الخبير، أو يمكننا القول أنّه برنامج مصمم لينفد مهاماً متعلقة بالخبرة البشرية، وهذا يتضمن التحليل والتشخيص واتخاذ القرارات والتنفيذ أيضًا. المنطق الترجيحي أو الضبابي Fuzzy Logic: المنطق الضبابي هو نهج للحوسبة يعتمد على "درجات الحقيقة degrees of truth" بدلاً من المنطق الثنائي "صح أو خطأ" المعتاد (1 أو 0) الذي يعتمد عليه الحاسب ويحاول حل المشكلات باستخدام طيف مفتوح وغير دقيق من البيانات والاستدلالات التي تجعل من الممكن الحصول على مجموعة من الاستنتاجات الدقيقة. لمزيد من التفاصيل المتعلقة بفروع أو مجالات الذكاء الصناعي، يمكنك قراءة مقالة مجالات الذكاء الاصطناعي. تعمل العديد من التقنيات على تمكين ودعم تطبيق الذكاء الاصطناعي منها: الرؤية الحاسوبية Computer vision تعتمد على خوارزميات التعلم العميق للتعرف على ما هو موجود في الصورة (أو الفيديو) وتحليلها وفهمها وتفسير مكوناتها. معالجة اللغة الطبيعية Natural language processing هي قدرة أجهزة الحاسب على تحليل وفهم وتوليد اللغة البشرية، بما في ذلك الكلام. تطور خوارزميات الذكاء الصناعي نقل هذا المجال من الظلام إلى النور. علم البيانات Data science: هو دراسة البيانات لاستخراج رؤى ذات مغزى تخدم الأعمال والمؤسسات. إنها مصطلح شامل للتقنيات الإحصائية وتقنيات التصميم وطرق التطوير. يُستخدم الذكاء الاصطناعي فيها بشكل متزايد للتعامل مع البيانات، وإزالة الإنسان من المهمة بأكملها للعمل بمفرده. إنترنت الأشياء Internet of things، هو ربط الأشياء (كرسي طاولة ثلاجة ..إلخ) مع بعضها البعض من خلال الإنترنت، وتمكينها من الاتصال مع بعضها البعض وتبادل المعلومات واتخاذ القرارات؛ أي باختصار "هو جعل الأشياء تتكلم وتتخذ القرارات من أجل خدمتنا". تعتبر وحدات المعالجة الرسومية Graphics processing unit مفتاحًا للذكاء الاصطناعي لأنها توفر القوة الحوسبية الكبيرة المطلوبة للمعالجة. يتطلب تدريب الشبكات العصبية بيانات كبيرة بالإضافة إلى قوة حوسبية. واجهات برمجة التطبيقات APIs عبارة عن حزم من التعليمات البرمجية التي تتيح إمكانية إضافة وظائف الذكاء الصناعي إلى المنتجات الحالية والبرامج. أنواع الذكاء الاصطناعي هناك عدة أنواع للذكاء الصناعي يمكن وضعها ضمن فئتين، الأولى تعتمد على القدرات والثانية تعتمد على الوظيفية. بالنسبة لفئة القدرات، تنقسم إلى: ذكاء اصطناعي ضعيف أو ذكاء اصطناعي ضيق: هو الذكاء الاصطناعي الذي يتخصص في مجال واحد (يستطيع تنفيذ مهمة واحدة فقط). ذكاء اصطناعي عام: حواسيب بمستوى ذكاء الإنسان في جميع المجالات. ذكاء اصطناعي خارق: هو ذكاء اصطناعي يفوق ذكاء وقدرة الإنسان. أما بالنسبة للفئة التي تعتمد على الوظيفة تنقسم إلى: الآلات التفاعلية Reactive machines: لا تتضمن أنظمة الذكاء الاصطناعي هذه ذاكرة، ويكون لها مهمة معينة. ذاكرة محدودة Limited memory: تتمتع أنظمة الذكاء الاصطناعي هذه بذاكرة، لذا يمكنها استخدام الخبرات السابقة في القرارات المستقبلية. نظرية العقل Theory of mind: يجب أن يفهم الذكاء الاصطناعي المشاعر البشرية والناس والمعتقدات وأن يكون قادرًا على التفاعل اجتماعيًا مثل البشر. الإدراك الذاتي Self-awareness: مستقبل الذكاء الاصطناعي. ستكون هذه الآلات فائقة الذكاء، وسيكون لها وعيها ومشاعرها وإدراكها الذاتي. تطبيقات الذكاء الاصطناعي تطبيقات الذكاء الاصطناعي لا حصر لها؛ يمكن تطبيق هذه التكنولوجيا على العديد من القطاعات والصناعات المختلفة. إليك أهم 10 تطبيقات للذكاء الاصطناعي: 1. الطب والرعاية الصحية أحدث الذكاء الصناعي تأثيرًا غير مسبوق في المجال الطبي، إذ أصبحت خوارزميات ونماذج التعلم الآلي قادرةً على تشخيص العديد من الأمراض والتنبؤ بها، مثل تحديد ما إذا كان مريض معين مصابًا بسرطان أو ورم خبيث أو حميد بناءً على الأعراض والسجلات الصحية والتاريخ أو التنبؤ بالإصابة بأمراض وأوبئة ..إلخ. 2. النقل أصبح إنتاج السيارات ذاتية القيادة التي تعتمد على الذكاء الصناعي -الشغل الشاغل للعديد من الشركات العالمية مثل شركة تسلا التي يرأسها إيلون ماسك. كما أنه يساعد في تقليل الازدحام والاختناقات المرورية. أما في النقل الجوي؛ فقد أصبحت الآلة تشارك في تخطيط المسارات جنبًا إلى جنب مع مخططات هبوط الطائرة والإقلاع. 3. التعليم يمكن للذكاء الاصطناعي أتمتة عملية تقييم الطلاب ووضع الدرجات، وبالتالي توفير الجهد والوقت على المدرسين. بالمناسبة، لقد كان مشروع التخرج الخاص بي هو نظام ذكي لمراقبة سلوك الطلاب خلال الدرس ورصد تعابير وجوههم لمعرفة الطالب الذي يشعر بالملل أو النائم والذي يُشارك باستمرار والذي يُثير الشغب ..إلخ، وتقديم تقرير عن كل طالب في نهاية الدرس. 4. الأعمال دُمجت خوارزميات التعلم الآلي مع أنظمة تحليل وإدارة علاقات العملاء CRM، لمعرفة كيفية خدمة العملاء بطريقة أفضل. كما دُمجت روبوتات الدردشة في مواقع الويب لتقديم خدمة فورية للعملاء. أصبحت أتمتة المناصب الوظيفية أيضًا نقطة نقاش بين الأكاديميين ومحللي تكنولوجيا المعلومات. 5. الأمن والحماية تستخدم المؤسسات التعلم الآلي في برامج إدارة المعلومات والأحداث SIEM والمجالات ذات الصلة لاكتشاف الحالات الشاذة وتحديد الأنشطة المشبوهة التي تشير إلى التهديدات. 6. المؤسسات المالية والمصرفية يلعب الذكاء الاصطناعي دورًا حيويًا في إدارة المعاملات المالية والتعامل مع العديد من الأنشطة البنكية الأخرى. من خلال نماذج التعلم الآلي يمكن التعامل مع العمليات اليومية للبنوك، مثل المعاملات والعمليات المالية وأموال سوق الأوراق المالية وإدارتها وما إلى ذلك بسهولة وكفاءة أكبر. كما تُستخدم في عمليات مكافحة غسيل الأموال وتحليل أنظمة الائتمان. 7. الألعاب والترفيه حقق الذكاء الصناعي تقدمًا كبيرًا في ألعاب الواقع الافتراضي والألعاب الحديثة، حيث يُستخدم لتوليد سلوكيات متجاوبة أو متكيفة أو ذكية لشخصيات اللاعبين تُحاكي الذكاء البشري. 8. الصناعة من خلال الذكاء الصناعي يمكننا توفير الوقت والمال عن طريق أتمتة العمليات والمهام الروتينية وتحسينها. زيادة الإنتاجية والكفاءات التشغيلية. اتخاذ قرارات أعمال أسرع بناءً على مخرجات التقنيات المعرفية. 9. الزراعة تساعد أنظمة الذكاء الاصطناعي في تحسين الجودة الشاملة للحصاد ودقته (تُعرق بالزراعة الدقيقة). يمكن للذكاء الصناعي أن يتنبأ بالوقت الذي يستغرقه محصول ما ليصبح ناضجًا وجاهزًا للقطف واكتشاف الأمراض في النباتات والآفات وسوء تغذية المزارع، وهذا ما يزيد من كفاءة الزراعة. 10. الفنون أصبح بإمكان الذكاء الاصطناعي إنتاج لوحات فائقة الجمال، كما أنّه دخل في مجال الموسيقى والغناء، حيث أصبح قادرًا على تأليف نوتات موسيقية وأغاني وإنتاج أنواع الأصوات المختلفة. الذكاء الاصطناعي والثورة الصناعية الرابعة 4IR لابد وأنك قد سمعت عن العصر الجديد من الصناعة والذي يُعرف بالثورة الصناعية الرابع "0.4 Industry". ترتكز الثورة الصناعية الرابعة على أتمتة العمليات إلى حد كبير جدًا واستخدام جداول زمنية أسرع للإنتاج ومستودعات ذكية (مخازن ذكية)، مما يسمح بإنتاج وتوزيع المنتجات بسرعة وفعالية أكبر، كما أنها ستتطلب قوة عاملة ذات مهارات عالية ومتعلمة وتتقن كيفية استخدام وتشغيل أحدث التقنيات. يأتي دور الذكاء الصناعي هنا في قدرته على إحداث هذه التغييرات بسرعة وسلاسة، ولاسيما من خلال الأنظمة الخبيرة والرؤية الحاسوبية والروبوتات وإنترنت الأشياء. ما هي مزايا وعيوب الذكاء الاصطناعي؟ تتطور تقنيات الذكاء الصناعي بسرعة كبيرة جدًا، ويرجع ذلك إلى أن الذكاء الاصطناعي يُمكنه معالجة كميات كبيرة من البيانات بسرعة، كما أنه يعطي تنبؤات أكثر دقة من الإنسان. إن الكميات الهائلة من البيانات يمكنها دفن قدرة العقل البشري على معالجتها وتحويلها إلى معلومات ذات معنى، إلا أن تقنيات الذكاء الاصطناعي يمكنها أخذ وتحويل تلك البيانات إلى معلومات مُفيدة وقابلة للتنفيذ بسرعة، لكن العيب الأساسي لاستخدام الذكاء الاصطناعي هو أنه من المكلف معالجة الكميات الكبيرة من البيانات التي تتطلبها برمجة الذكاء الاصطناعي. مزايا الذكاء الاصطناعي يجعل الآلات أكثر قوة وفائدة. يُقدم أساليب جديدة لحل المشاكل. أفضل من البشر في التعامل مع المعلومات. يُحسّن كفاءة العمل، إذ يقلل من المدة الزمنية لإنجاز مهمة مقارنة بالبشر. غالبًا ما يكون أكثر دقة من البشر. عيوب الذكاء الاصطناعي عدم القدرة على التعميم من مهمة إلى أخرى. أي يمكن للآلة أن تنفذ مهمة (أو عدة مهمات) محددة مُدربة عليها مسبقًا فقط، ولايمكنها أن تنفذ مهمة لم تُدرب عليها مُسبقًا. التكلفة (تكلفة تنفيذ تطبيقات الذكاء الاصطناعي مرتفعة للغاية). قلة الكفاءات (يتوفر عدد قليل من المبرمجين الأكفاء القادرين على تطوير برامج الذكاء الاصطناعي). يتطلب خبرة فنية عميقة. الروبوتات هي إحدى تطبيقات الذكاء الصناعي التي تحل محل الوظائف التي يشغلها البشر، وبالتالي قد تؤدي إلى تزايد البطالة. كيف يتم استخدام الذكاء الصناعي اليوم؟ يُستخدم الذكاء الاصطناعي بمستويات متفاوتة من التطور على نطاق واسع وعبر مجموعة من التطبيقات اليوم. لابد وأنك تستخدم اليوتيوب أو الفيسبوك، ولابد أنك لاحظت أنهم يقترحون لك مقاطع فيديو مُشابهة لما تُشاهده في العادة، هذه الاقتراحات هي من فعل "أنظمة التوصية" (أو أنظمة الاقتراح) التي تُراقب ما تبحث عنه في العادة لكي تقترح لك في المرات القادمة أشياء مُشابهة. من الأمثلة الأخرى برامج الدردشة التي تراها على مواقع الويب أو إن كنت من مستخدمي ويندوز فربما أنت تعرف المساعد الافتراضي الذكي آليكسا. يُستخدم الذكاء الاصطناعي أيضًا للتنبؤ بحالة الطقس والتنبؤات المالية (كأسعار الأسهم) ولتبسيط عمليات الإنتاج، كما يُستخدم في الألعاب والنقل والتسوق ومعالجة اللغة البشرية وغير ذلك الكثير. عمومًا، يمكن القول أن الذكاء الاصطناعي بدأ التشعب في جميع مفاصيل حياتنا اليومية وسيزداد استخدامه أكثر ويصبح البشر أكثر اعتمادًا عليه من قبل في السنوات القادمة. مستقبل الذكاء الاصطناعي في مؤتمر Web Summit في أواخر عام 2017، قدم الفيزيائي ستيفن هوكينغ رأيه حول مستقبل الذكاء الاصطناعي. كان يأمل في أن تتفوق التكنولوجيا على الذكاء البشري. قد يعني هذا على الأرجح أنه سيتم الشفاء من العديد من الأمراض الرهيبة وربما تكون هناك طرق للتعامل مع المشكلات البيئية، بما في ذلك تغير المناخ. لكن كان هناك جانب مظلم أيضًا. تحدث هوكينج عن إمكانية أن تكون التكنولوجيا "أسوأ حدث في تاريخ حضارتنا"، فربما تُحدث بعض المشاكل مثل البطالة الجماعية وحتى الروبوتات القاتلة! لهذا السبب، حث على طرق للتحكم في الذكاء الاصطناعي. أفكار هوكينغ ليست مجرد كلام على الهامش بالتأكيد، فقد أعرب رواد الأعمال البارزين في مجال التكنولوجيا مثل إيلون ماسك وبيل غيتس مرارًا وتكرارًا عن قلقهم العميق بشأن الذكاء الاصطناعي. على الجانب الآخر هنا الكثير من العلماء ورواد الأعمال المتفائلون. ماسايوشي سون، الرئيس التنفيذي لشركة SoftBank ومدير صندوق Vision هو واحد منهم. في مقابلة مع CNBC، أعلن أنه في غضون 30 عامًا، سيكون لدينا سيارات طائرة وسيعيش الناس لفترة أطول وسنكون قد عالجنا العديد من الأمراض. أشار أيضًا إلى أن التركيز الرئيسي لصندوقه ينصب على الذكاء الصناعي. بغض النظر عن كل ذلك، هناك شيء واحد مؤكد: سنرى في السنوات القادمة الكثير من الابتكارات والتطورات في الذكاء الصناعي، خصوصًا وأن هناك مبالغ ضخمة مستثمرة فيه. لنلقي الآن نظرةً على بعض المجالات التي من المحتمل أن يكون لها تأثير كبير على المجتمع: السيارات ذاتية القيادة: لقد كانت سمة مميزة للعديد من قصص الخيال العلمي لعقود عديدة! لكنها الآن أقرب إلى الواقع من الخيال -يمكننا ملاحظة مؤشرات ذلك من التطورات الأخيرة في سيارات تسلا من شركة تسلا موتورز التابعة لإيلون ماسك. السباق الاقتصادي بين الدول: توظيف الذكاء الاصطناعي في تسريع عجلة الاقتصاد والتصنيع بمختلف المجالات والتنافس على المرتبة الاقتصادية الأولى عالميًا. البطالة التكنولوجية: اكتسب هذا المفهوم شهرةً من الاقتصادي الشهير جون مينارد كينز خلال فترة "الكساد الكبير"، والذي يُشير إلى كيف يمكن أن تؤدي الابتكارات إلى فقدان الوظائف على المدى الطويل. عمومًا قد تكون هذه الرؤية غير دقيقة، فغالبًا ما تخلق الأشياء الجديدة أعمالًا جديدة للإنسان. تسليح الذكاء الاصطناعي: يُعد تسليح الذكاء الاصطناعي أو استخدام الذكاء الاصطناعي في مجال الصناعات الحربية والدفاعية أحد أكبر التهديدات التي تواجه المجتمع الدولي. اكتشاف الأدوية: تواجه شركات الأدوية العديد من المشاكل في التوصل إلى العلاجات لذا يجري الاعتماد على الذكاء الاصطناعي لتسريع العجلة وتخطي العقبات. إن تطوير الأدوية بالطريقة التقليدية غالبًا ما ينطوي على الكثير من التجربة والخطأ، مما قد يستغرق وقتًا طويلًا، إذن هل يمكن أن يكون هناك طريقة أفضل؟ يتطلع الباحثون إلى الذكاء الاصطناعي للحصول على المساعدة، وهناك العديد من الشركات الناشئة التي تحاول انتهاز هذه الفرصة للظهور. هناك العديد من المجالات الأخرى التي من المتوقع أن تتأثر مثل الأمور الحكومية والاجتماعية والتي لايسعنا ذكرها كلها الآن. اللغات والأدوات المستخدمة في الذكاء الصناعي هناك العديد من اللغات والأدوات المُساعدة في إنشاء نماذج الذكاء الاصطناعي، ومعظمها مفتوح المصدر. سنلقي الآن نظرةً على بعض اللغات والأدوات الأكثر شيوعًا للذكاء الاصطناعي: لغة بايثون Python هي لغة عالية المستوى مُفسَّرة ذات مجالٍ عام، وهي مرنةٌ وتحاول التعبير عن المفاهيم البرمجية بأقل قدر ممكن من الشيفرات. تدعم هذه اللغة البرمجة الكائنية والبرمجة الإجرائية، وفيها مكتبة قياسية كبيرة. تُعتبر لغة بايثون اللغة الأفضل للتعامل مع مهام الذكاء الصناعي، حيث تتميز بسهولة الاستخدام وسرعة التنفيذ، إضافةً إلى احتوائها على مكتبات هامة وأطر عمل لا غنى عنها، حيث أن أغلب أطر العمل تعمل عليها، وقد وفرت أكاديمية حسوب دورة متخصصة لتعلم الذكاء الاصطناعي وتعلم الآلة Machine Learning والتعلم العميق Deep Learning وغيرها من المفاهيم باستخدام لغة بايثون وباتباع بأسلوب عملي وشيق يركز على ممارسة ما تتعلمه من خلال مشاريع حقيقية تفيدك في سوق العمل. دورة الذكاء الاصطناعي احترف برمجة الذكاء الاصطناعي AI وتحليل البيانات وتعلم كافة المعلومات التي تحتاجها لبناء نماذج ذكاء اصطناعي متخصصة. اشترك الآن وتتضمن لغة بايثون العديد من المكتبات التي لا غنى عنها في مجال الذكاء الصناعي مثل: نمباي Numpy: تُعد مكتبة نمباي إحدى مكتبات لغة بايثون. تستخدم لتنفيذ عمليات الحوسبة العلمية والتعامل مع المصفوفات، وتهدف إلى توفير كائن مصفوفة سريع جدًا. باندا Panda: توفر هياكل بيانات وأدوات تحليل بيانات عالية الأداء وسريعة وسهلة الاستخدام لمعالجة البيانات الرقمية والسلاسل الزمنية. ماتبلوتليب Matplotlib: هي مكتبة شاملة لإنشاء رسوم بيانية ثابتة ومتحركة وتفاعلية في بايثون. سيبورن Seaborn: هي مكتبة رسوم بيانية مبنية على ماتبلوتليب. توفر واجهة عالية المستوى لرسم رسومات إحصائية جذابة وغنية بالمعلومات. أطر العمل Frameworks هناك عدد لا يحصى من أطر عمل الذكاء الاصطناعي، والتي توفر أنظمة شاملة لبناء النماذج وتدريبها ونشرها. إليك بعضًا من أهم هذه الأطر: تنسرفلو TensorFlow: هو إطار العمل الأكثر شعبية والمدعوم من شركة جوجل. بدأت الشركة في تطوير إطار العمل هذا في عام 2011، من خلال قسم دماغ جوجل Google Brain. كان الهدف هو إيجاد طريقة لإنشاء شبكات عصبية أسرع؛ لإتاحة إمكانية تضمين تكنولوجيا الذكاء الصناعي في التطبيقات. كيراس Keras: واحد من أطر العمل المهمة الأخرى، والذي ظهر لأول مرة في عام 2015 على يد الباحث فرانسوا كوليت (أحد باحثي جوجل). توفر كيراس واجهات برمجة تطبيقات متسقة وبسيطة، ويقلل من عدد إجراءات المستخدم المطلوبة لحالات الاستخدام الشائعة، ويوفر رسائل خطأ واضحة وقابلة للتنفيذ. كما أن لديها وثائق موسعة للمطورين. دُمجت كيراس مع تنسرفلو بدءًا من 2017. باي تورش PyTorch: في السنوات الأخيرة ظهر إطار عمل آخر يُدعى باي تورش مدعوم من قبل شركة ميتا Meta. إنها إطار عمل آخر مفتوح المصدر مستندة على تورش Torch. تتميز باي تورش عن أطر العمل الأخرى بكونها بايثونية أكثر (عندما تكتب النماذج باستخدامها تشعر وكأنك تكتب شيفرة بايثون عادية)، كما أن الباحثين يتجهون إلى استخدامها أكثر في الآونة الأخيرة. فرص العمل في تخصص الذكاء الاصطناعي مهندسو الذكاء الاصطناعي هم الأفراد الذين يقومون بتصميم وبناء واختبار وتحديث أنظمة وتقنيات الذكاء الاصطناعي التي يمكن أن تساعد المؤسسات على زيادة الكفاءة وخفض التكاليف وزيادة الأرباح واتخاذ قرارات أفضل. نظرًا للنمو الكبير والانتشار السريع للذكاء الاصطناعي، هناك حاجة إلى المهنيين المتخصصين في مجالاته المختلفة الآن أكثر من أي وقت مضى. الخبر السار هو أن هذا المجال مليء بالفرص الوظيفية المختلفة، مما يعني أنه يمكنك تولي أدوار ومسؤوليات مختلفة اعتمادًا على منصبك أو خبرتك أو اهتماماتك وبما أن الطلب مرتفع فالخبرة هي المقياس الوحيد ويمكن تخطي الشهادة الجامعية. تختلف رواتب مهندس الذكاء الاصطناعي بناءً على الخبرة والبلد، كما قد تختلف التعويضات من مؤسسة إلى أخرى. يمكنك البحث عن رواتب مهندس الذكاء الاصطناعي في موقع Glassdoor وملاحظة الفرق بسهولة. كما أن الراتب يختلف من تخصص لآخر، فراتب مهندس الذكاء الاصطناعي يختلف عن راتب المهندس الباحث في الذكاء الاصطناعي. وفقًا Glassdoor، فإن متوسط الراتب لمهندس الذكاء الاصطناعي في الولايات المتحدة هو 119297 دولارًا، ويمكن أن ينخفض الرقم إلى 78000 دولار أو يصل إلى 150 ألف دولار أو أكثر. أما في بلد عربي مثل الإمارات، فوفقًا للموقع المتخصص erieri، يبلغ متوسط الأجر لمهندس الذكاء الاصطناعي هو 337،135 درهمًا إماراتيًا في السنة، وهذه الأرقام إن دلت على شيء فإنها تدل على الأجر المرتفع للعامل في هذا المجال. كيفية تعلم الذكاء الاصطناعي ربما تطرح السؤال التالي كمبتدأ: كيف أتعلم الذكاء الصناعي؟ ومن أين أبدأ؟ يتطلب تعلم الذكاء الصناعي ما يلي: خلفية علمية بسيطة على الأقل (كلما زادت كان أفضل) في علم الجبر والجبر الخطي والإحصاء والاحتمالات والتحليل (لاسيما الاشتقاقات). خلفية برمجية جيدة، والقدرة على استخدام لغة بايثون (لا يجب أن تكون محترفًا لتبدأ، الاحتراف يأتي مع الممارسة والوقت). تعلم أُطر العمل الأساسية. هنا لن تحتاج إلى تعلم جميع أُطر ومكتبات الذكاء الصناعي؛ الأمر يعتمد على الفرع والمواضيع التي ترغب بالتخصص فيها. يمكنك أن تتعلم المجال إما بدخول أروقة الجامعة وهو الطريق الأطول الذي يأخذ عدة سنوات ولا توفر أغلب الجامعات تعلم مجال الذكاء الاصطناعي من البداية بل يكون ضمن برامج الماجستير والدراسات العليا، عدا عن التركيز على الجانب النظري والتقنيات القديمة، وقد فصلنا هذه النقطة في فقرة "طرق لتعلم البرمجة" من مقال كيف تتعلم البرمجة: نصائح وأدوات لرحلتك في عالم البرمجة. وفي أي حال يُنصح دومًا بالدورات البرمجية والمخيمات والكتب المتخصصة لتعلم المجال منها خصوصًا ما هو عملي ومطلوب في سوق العمل، وإحدى أفضل الدورات العربية التي تعلمك تخصص الذكاء الاصطناعي دورة تطوير التطبيقات باستخدام لغة Python الشاملة التي تبدأ من الصفر حيث تعلمك أساسيات البرمجة وحتى احترافها بلغة بايثون ثم تعلمك أساسيات الذكاء الاصطناعي وتعلم الآلة بإنشاء تطبيقات عملية تضيفها في معرض أعمالك، كما أن الدورة تضمن لك دخول سوق العمل بعد التخرج مباشرةً. إليك مصادر إضافية عربية لتعلم الذكاء الاصطناعي توفرها أكاديمية حسوب: تعلم الذكاء الاصطناعي: مقال شامل لتعلم الذكاء الصناعي موجه للمبتدئين. البرمجة بلغة بايثون: تعلم لغة بايثون تمهيدًا لكتابة تطبيقات ذكاء اصطناعي وتعلم آلة بها. مدخل إلى الذكاء الاصطناعي وتعلم الآلة: تعرف على أساسيات الذكاء الاصطناعي وتعلم الآلة. عشرة مشاريع عملية عن الذكاء الاصطناعي: طبق ما تعلمته على مشاريع ذكاء اصطناعي عملية بلغة بايثون. قسم الذكاء الاصطناعي: يحوي مقالات متنوعة عن كل ما يتعلق بمجال الذكاء الاصطناعي. أهم مصطلحات الذكاء الصناعي إليك قائمة مُختصرة بأهم المصطلحات والمفاهيم ذات الصلة بدراسة الذكاء الاصطناعي وتخصصاته: المصطلح الترجمة التعريف (Artificial intelligence (AI الذكاء الصناعي العلم الذي يحاول فهم الكيانات الذكية وبناء الآلات ذكية (Natural Language Processing (NLP معالجة اللغات الطبيعية العلم الذي يحاول فهم وتوليد ومعالجة اللغات البشرية (Computer vision (CV الرؤية الحاسوبية بناء تطبيقات ذكية قادرة على فهم محتوى الصور كما يفهمها الإنسان (Machine learning (ML تعلم الآلة قدرة الآلة على تقليد السلوك البشري الذكي من خلال بناء الخوارزميات التي "تتعلم" من البيانات (Reinforcement learning (RL التعليم المعزز أحد أنواع تعلم الآلة (Supervised learning (SL التعليم الخاضع للإشراف أحد أنواع تعلم الآلة (Semi-Supervised learning (SSL التعليم شبه الخاضع للإشراف أحد أنواع تعلم الآلة (UnSupervised learning (USL التعليم غير الخاضع للإشراف أحد أنواع تعلم الآلة (Deep Learning (DL التعلم العميق نوع من التعلم الآلي والذكاء الاصطناعي الذي يُقلد الطريقة التي يكتسب بها البشر أنواعًا معينة من المعرفة (Artificial neural networks (ANNs الشبكات العصبية الاصطناعية مجموعة مترابطة من عصبونات افتراضية تُنشئها برامج حاسوبية لتُشابه عمل العصبون البيولوجي (Robotic Process Automation (RPA أتمتة العمليات الآلية أحد أشكال تكنولوجيا أتمتة العمليات التجارية بناءً على روبوتات البرمجيات Expert systems الأنظمة الخبيرة برنامج مصمم لينفد مهاماً متعلقة بالخبرة البشرية Fuzzy Logic منطق ضبابي أو ترجيحي أو غيمي فرع من الذكاء الصناعي يُقدم حلولًا جديدًا ويرتكز على توسيع مفهوم المنطق الثنائي الكلاسيكي (Convolutional Neural Network (CNN شبكة عصبية التفافية نوع خاص من أنواع الشبكات العصبونية (Recurrent Neural Network (RNN شبكة عصبية تكرارية نوع خاص من أنواع الشبكات العصبونية (Long Short-Term Memory Network (LSTM الشبكات ذات الذّاكرة الطويلة قصيرة المدى نوع خاص من أنواع الشبكات العصبونية التكرارية RNNs Pre-trained Model نموذج مُدرّب مُسبقًا شبكة عصبية مُدربة مُسبقًا على مجموعة بيانات، ويمكن استخدامها وتكييفها على مهمة أخرى Model نموذج أداة أو خوارزمية تعتمد على مجموعة بيانات معينة يمكن من خلالها التوصل إلى قرار Transfer Learning نقل التعلم تخزين المعرفة المكتسبة أثناء حل مشكلة واحدة وتطبيقها على مشكلة مختلفة ذات صلة Optimization الاستمثال - التحسين اختيار العنصر أو القيمة الأمثل من بين مجموعة ممكنة من العناصر Structured Data البيانات المهيكلة البيانات المنظمة ضمن جداول Unstructured Data البيانات غير المهيكلة البيانات الغير منظمة، مثل الفيديو والصور والصوت Data augmentation تكثيف البيانات تقنية لتوليد بيانات جديدة من بيانات موجودة (مثل توليد صور جديدة من صورة معينة) Regression التوقع أحد تقنيات التعليم الخاضع للإشراف Clustering التجميع أحد تقنيات التعليم غير الخاضع للإشراف Classification التصنيف أحد تقنيات التعليم الخاضع للإشراف Logistic Regression الانحدار اللوجستي خوارزمية تعلم آلي للتصنيف Linear Regression الانحدار الخطي خوارزمية تعلم آلي للتنبؤ Neuron عصبون أحد عناصر الشبكات العصبونية Learning Rate مُعدّل التعلّم معلمة فائقة تُحدد مقدار التعلم في خوارزميات الذكاء الصناعي خاتمة كانت هذه المقالة بمثابة مدخل إلى الذكاء الاصطناعي؛ إنها تُجيبك عن العديد من الأسئلة المتعلقة بالذكاء الصناعي، مثل مفهومه وتعريفه وأهميته وتطبيقاته ومجالاته والتقنيات التي يدعمها وتخصصاته وأدواته والبدء في تعلمه …إلخ. وسنتحدث في المقالات القادمة عن العديد من الأمور الأخرى المتعلقة بالذكاء الصناعي ونتوسع بالنقاط التي ذكرناها في هذا المقال التي سيطول ذكرها والحديث عنها. يعدنا الذكاء الاصطناعي بأنه سيغير العالم، والخبر السار هو أن هناك العديد من الأشخاص الذين يركزون على جعل هذا حقيقةً واقعةً، ولا يتعلق الأمر بجني مبالغ طائلة أو الحصول على الشهرة؛ الهدف هو مساعدة البشرية وتغيير العالم إلى الأفضل. اقرأ أيضًا الذكاء الاصطناعي: أهم الإنجازات والاختراعات وكيف أثرت في حياتنا اليومية الذكاء البشري مقابل الذكاء الاصطناعي أهمية الذكاء الاصطناعي تعلم لغة بايثون فوائد الذكاء الاصطناعي لغات برمجة الذكاء الاصطناعي3 نقاط
-
سنبدأ في هذا المقال من سلسلة برمجة الذكاء الاصطناعي في تعلم أساسيات لغة بايثون، وهي من أهم لغات البرمجة على الإطلاق المستخدمة في مجال الذكاء الاصطناعي، ولكنها ليست لذلك فقط؛ إذ تُستعمَل لغة بايثون في كثير من المجالات الأخرى مثل برمجة المواقع وبرامج سطح المكتب وأنظمة التشغيل وغيرها. قبل البدء في أساسيات لغة بايثون: ما هي لغة البرمجة بايثون؟ تعني بايثون في اللغة الإنجليزية نوعًا من الثعابين الكبيرة، لكنها لم تُسمى لذلك بل سُمِّيَت بهذا الاسم تيمنًا ببرنامج ترفيهي قدَّمته قناة BBC يحمل اسم Monty Python’s Flying Circus، وذلك بعد ما شاهده مخترع اللغة. وتُعَدّ بايثون لغةً برمجيةً عامةً، أي تستطيع استخدامها في مجالات عدة على عكس بعض اللغات الأخرى التي تتخصص في مجال ما دونًا عن الآخر، كما تُعَدّ لغةً بسيطةً ومتطورةً للغاية، بالإضافة إلى أنها تدعم البرمجة كائنية التوجه Object Oriented Programming أو OOP اختصارًا. صُنِعت بايثون بواسطة الهولندي جايدو فان روسم Guido van Rossum، وأُصدِرت في شهر 11 من عام 1994م بعدما عُمِل عليها في معهد الأبحاث القومي للرياضيات وعلوم الحاسوب في هولندا، في حين نُشر الإصدار الثاني من بايثون في عام 2000م؛ أما الإصدار الثالث، فقد نُشِر في عام 2008م وهو الإصدار المستخدم حاليًا من بايثون لأن الإصدار الثاني السابق قد توقف دعمه وتطويره. خصائص لغة بايثون تُعَدّ لغة بايثون لغةً مفتوحة المصدر تجد شيفرتها المصدرية على موقع GitHub، وبالتالي يستطيع أيّ مبرمج المشاركة في تطوير اللغة. وبحسب موقع جيت هاب GitHub، فقد شارك أكثر من 1200 شخص حول العالم في تطويرها، كما تُعرَف بايثون بسهولة تراكيب الجمل فيها Syntax التي تشبه تركيب اللغة الإنجليزية بنسبة كبيرة، وهي لغة مهمة جدًا للطلبة والباحثين والمهنيين على حد سواء في الكثير من النطاقات العلمية والعملية. وتتميز بايثون بالميزات التالية: لغة برمجة مفسرة Interpreted تدعم البرمجة الكائنية مناسبة للمبتدئين مدعومة بالكثير من المكتبات لغة مجانية ومفتوحة المصدر تستخدم في العديد من التخصصات لغة برمجة مفسرة Interpreted أي أنها تُنفَّذ مباشرةً مثل لغة PHP ولغة Perl، ولا تحتاج إلى تصريف كامل الشيفرة أولًا ثم تنفيذها مثل لغة C، فلا يتطلب الأمر تحويل الشيفرة الخاصة بك إلى شيفرة ثنائية تفهمها الآلة أولًا لتبدأ عملية التنفيذ، وهذا قد يميز شيفرات بايثون في سرعة تنفيذها أثناء البرمجة. وفي تلك النقطة بالتحديد قد يختلف بعض المبرمجين، فالبرغم من تصنيف بايثون أنها لغة مفسَّرة، إلا أنّ الشيفرة تُصرَّف compiled أولًا ليستطيع المُفسِّر فهمها قبل تنفيذها، لذلك قد تجد بعض النقاشات المتباينة حول بايثون لمحاولة تصنيفها تصنيفًا دقيقًا. يذهب بعض المبرمجين إلى القول بأنّ لغة بايثون لها طريقتها الخاصة في تلك النقطة، فالأمر معقَّد ولا نريد الخوض فيه. تدعم البرمجة الكائنية تدعم بايثون نمطًا يُدعى الكائنية في البرمجة Object-oriented programming (أو تدعى الشيئية أحيانًا)، وهو نمط شهير ومهم، إذ تُكتَب الشيفرة ويُتعامَل مع أجزاء التطبيق على أساس الكائنات Objects، وهو نمط غير مدعوم في بعض اللغات القديمة مثل لغة C، كما أنها تدعم البرمجة الوظيفية Functional والهيكلية Structured وغيرها. أساسيات لغة بايثون مناسبة للمبتدئين تُعَد بايثون مناسبةً جدًا للمبتدئين، حيث أنَّ صياغة الجمل فيها بسيطة للغاية، ولا يتطلب الأمر الدخول في تفاصيل كثيرة عند كتابتها؛ لذلك فهي سهلة التعلم والقراءة. مدعومة بالكثير من المكتبات يمكنك في بايثون إيجاد مكتبات بسيطة الاستخدام تستطيع بها برمجة تطبيقات معقدة جدًا، فهي لغة لديها أرشيف واسع من المكتبات في كافة المجالات تقريبًا. لغة مجانية ومفتوحة المصدر توجد بعض لغات البرمجة غير المجانية، أي أنك مُطالَب بدفع الأموال لشركة ما، كي تستطيع استخدام تلك اللغة، كما أنَه لا يمكنك ولا يمكن لأيّ شخص آخر إصلاح مشكلة ما في اللغة أو أن يطوِّر ميزةً أو خاصيةً جديدةً في اللغة، فالشيفرة المصدرية في تلك الحالة تقع تحت أيدي الشركة المصنعة فقط، وهي الوحيدة التي يحق لها تطوير اللغة أو إصلاح مشاكلها أو إصدار نسخ جديدة منها. أما في بايثون والعديد من اللغات المجانية المفتوحة المصدر، فالأمر مختلف إذ عمِل على على لغة بايثون أكثر من 1200 شخص حول العالم، فالشيفرة المصدرية للغة موجودة ومتاحة على موقع GitHub، ويمكن لأيّ شخص له الخبرة والمعرفة الكافية أن يطوِّر أو يعدِّل ميزةً ما، كما يستطيع مجتمع مبرمِجي بايثون على الإنترنت من المشاركة بآرائهم في تطوير اللغة، فالأمر بالجميع وللجميع، وهي لغة مجانية بالكامل تستطيع استخدامها في أيّ مشروع خيري أو تجاري، بدون أية مشاكل قانونية على الإطلاق. تستخدم في العديد من التخصصات لا يقتصر الأمر أبدًا على برمجة الذكاء الاصطناعي وتعلّم الآلة، ولا يقتصر على برمجة مواقع الويب أيضًا، إذ تُعَدّ بايثون من أكثر لغات البرمجة انتشارًا وتوغلًا في العديد من المجالات في حياتنا اليومية، وفي التخصصات العلمية والأبحاث ومعامل ومختبرات الجامعات حول العالم، لذلك بتعلُُّمك للغة بايثون فإنّ الأمر لا يقتصر على فرصة عمل في مجال الذكاء الاصطناعي فحسب، وإنما تستطيع استخدام معرفتك وخبرتك في بايثون في مجالات أخرى تفتح عليك أبواب دخل إضافية. تُشتهر بايثون أيضًا في استخدامها في برمجة المواقع وتطبيقات سطح المكتب وبرمجة برامج تجارية عبر بايثون مثل أودوو Odoo الذي يُعَدّ أشهرها وله متخصصين وشركات تجارية تعتمد كليةً على استخدامه. كما أنَّ لغة بايثون كما أوردنا تدخل في الكثير من مجالات البحث العلمي، فهي من أكثر اللغات التي تحتوي على مكتبات تهدف إلى خدمة مجالات البحث العلمي والرياضيات من الذكاء الاصطناعي حتى التغير المناخي وتُعَد دراسة لغة بايثون أمرًا أساسيًا بالنسبة لمبرمجي الذكاء الاصطناعي، لذلك سنبدأ الآن في دراسة أساسيات اللغة حتى نكون على قدر من المعرفة المطلوبة لنبدأ في دراسة وتطبيق الخوارزميات الأساسية في تعلُّم الآلة. لذلك فإن السهل البدء بتعلم أساسيات بايثون والبدء في عالم البرمجة بسهولة. تثبيت لغة بايثون أول ما نبدأ به في تعلم أساسيات لغة Python ولكي تستطيع العمل بلغة بايثون، يجب عليك أولًا تثبيت البرنامج الذي يفهم اللغة ثم ينفذها، وذلك لكي يستطيع حاسوبك التعرف على الأوامر التي تكتبها لتعمل عليه بصورة صحيحة، لذلك من الضروري أن تكون أول خطوة نقوم بها هي تثبيت لغة بايثون على حاسوبك. يختلف أمر تثبيت اللغة باختلاف نظام التشغيل، فإذا كان حاسوبك مثلًا يعمل على نظام لينكس Linux، فعلى الأرجح أنّ حاسوبك مثبَّت عليه بالفعل لغة بايثون، وللتأكد من ذلك يمكنك فتح الطرفية Terminal ثم كتابة الأمر الآتي: >> python --version أول الأمر التالي بالنسبة للإصدار الثالث: >> python3 --version إذا كانت بايثون مثبتةً بالفعل على حاسوبك، فسيظهر لك رقم الإصدار المثبَّت، والجدير بالذكر أنه يجب أن يكون الإصدار المثبت لديك هو الإصدار الثالث، وبالتالي يجب بدء رقم الإصدار بالرقم 3؛ أما إذا لم تكن اللغة مثبتةً على حاسوبك، فيمكنك ذلك عبر تنفيذ الأمر الآتي في الطرفية Terminal على لينكس. >> sudo apt-get install python3.6 أما إذا كنت مستخدِمًا لنظام التشغيل ماك macOS بمختلف إصداراته، فعلى الأغلب أيضًا أنّ لغة بايثون مثبتة بالفعل على حاسوبك، وتستطيع اختبار ذلك عبر الأمر السابق ذكره بخصوص نظام لينكس، فإذا لم تكن اللغة مثبتةً، فيمكنك ببساطة تثبيتها مثل أيّ برنامج أخر عن طريق الموقع الرسمي للغة /Python. بعد تثبيت اللغة بالطرق الموضحة أعلاه في نظامي لينكس وماكينتوش، فمن المحتمل ألا يعمل أمر التحقق من الإصدار وألا يكون جاهزًا للعمل بعد، إذ أنه قد لا يُتعرَّف على برنامج بايثون عندما تُنفِّذ الأمر التالي: >> python --version ولحل ذلك يجب تنفيذ الأمر التالي في الطرفية Terminal: >> export PYTHONPATH=/usr/local/bin/python3.6 مع تغيير كلمة python3.6 لأنها قد تختلف حسب الإصدار الذي ثبَّته؛ لذلك يجب التحقق من ذلك المسار على حاسوبك أولًا لترى أيّ الإصدارات يجب استدعاؤها في الأمر السابق. أما في حالة مستخدمي نظام الويندوز، فالأمر بسيط للغاية، إذ تستطيع تنزيل برنامج اللغة من الموقع الرسمي السالف ذكره، ثم تثبيته مثل أيّ برنامج آخر على حاسوبك دون تعقيدات قد لا يعمل كذلك أمر التحقق من إصدار اللغة بصورة تلقائية بعد التثبيت، ولحل ذلك ببساطة يمكنك فتح موجِّه الأوامر Command Prompt في ويندوز ثم تنفيذ الأمر الآتي: >> %path%;C:\Python مع الأخذ في الحسبان إمكانية تغيير النص C:\Python إذا كنت قد تثبَّت اللغة في مسار آخر على حاسوبك أثناء عملية التثبيت. استعمال بايثون مع خدمة Google Colab ضمن أساسيات لغة بايثون وبالرغم من سهولة عملية تثبيت بايثون على حاسوبك، فإنه ليس من الضروري فعلًا فعل تلك الخطوات السالف ذكرها، فقد أصدرت شركة جوجل مؤخرًا ما يُدعى Google Colaboratory عبر موقع الأبحاث الخاص بها \colab.research، وبالتالي تستطيع ببساطة استخدام تلك الخاصية بإنشاء ذلك النوع من الملفات على خدمة Google Drive الموجودة مجانيًا لأي عنوان بريد إلكتروني مُسجَّل على Gmail، بعدها يمكنك البدء في كتابة وتنفيذ شيفرة البايثون الخاصة بك عبر الإنترنت دون الحاجة إلى الدخول في الكثير من التعقيدات والمشاكل التقنية أثناء تعلمك، أو حتى أثناء عملك في برمجة الذكاء الاصطناعي. كما تحتوى تلك الخدمة تلقائيًا على معظم وأهم مكتبات بايثون المستخدَمة في مجال الذكاء الاصطناعي عامةً ومجال تعلّم الآلة خاصةً، فنجد مثلًا تلقائيًا في تلك الخدمة أنّ مكتبات متخصصة في الرياضيات مثل Numpy، ومكتبات متخصصة في رسم البيانات مثل Matplotlib ومكتبات متخصصة في خوارزميات تعلّم الآلة مثل Keras، ومكتبات متخصصة في التعلّم العميق والشبكات العصبية مثل Tensorflow …إلخ مثبتة ومتاحة للاستخدام مباشرةً. أُصدِرت الخدمة أساسًا للتسهيل على العاملين في مجال برمجة الذكاء الاصطناعي، وبالأخص تعلُّم الآلة ليستطيع المبرمج مشاركة الشيفرة المصدرية الخاصة به مع نتائج هذه الشيفرة والملاحظات مع شركائه في العمل أو أي شخص آخر، وهي خدمة سحابية بالكامل، أي أنها تعمل عبر الإنترنت ولا تحتاج إلى أي متطلبات أو إمكانيات في حاسوبك، فكل ما تحتاجه لاستخدام الخدمة هي وصلة الإنترنت وعنوان بريد إلكتروني من Gmail. أفضِّل شخصيًا استخدام تلك الخدمة أثناء التعلم لأنها بسيطة وسهلة، وتحتوي تلقائيًا على الكثير من مكتبات بايثون الخاصة بالذكاء الاصطناعي التي قد يكون تثبيت بعضها عملًا شاقًا إذا حدث خطأ ما أثناء التثبيت والسبب الآخر الذي يدفعني إلى التوصية باستخدام تلك الخدمة بشدة، هو عدم امتلاك بعض أجهزة الحاسوب للإمكانيات اللازمة لتشغيل نماذج تعلّم الآلة، إذ تحتاج بعض الخوارزميات إلى ذاكرة عشوائية RAM كبيرة ليُدرَّب النموذج تدريبًا صحيحًا، وذلك اعتمادًا على حجم البيانات المتدفقة إلى النموذج. ولمزيد من التفاصيل، ارجع إلى مقال دليل استخدام Google Colab. برنامجك الأول في لغة بايثون من أساسيات لغة بايثون أنك تستطيع البدء في كتابة برنامجك الأول بعدة من الطرق، أولها عبر كتابة الشيفرة مباشرةً في الطرفية Terminal في لينكس وماك وموجِّه الأوامر Command Prompt في ويندوز؛ وثانيها، كتابة البرنامج في ملف أو عدة ملفات منفصلة، ثم تشغيلها عبر البرامج السابق ذكرها؛ أما ثالثها فتكون عن طريق خدمة Google Colab التي ذكرناها سابقًا. أما كتابة الشيفرة مباشرة في الطرفية وموجه الأوامر، فالخطوات لذلك بسيطة، وكل ما عليك فعله بعد فتح أحد تلك البرامج حسب نظام التشغيل الخاص بحاسوبك هو تنفيذ الأمر الآتي: >> python أو الأمر التالي بالنسبة للإصدار 3 من بايثون: >> python3 تستطيع بعد ذلك كتابة أوامر بايثون مباشرةً وتنفيذها، كما يمكنك الخروج من هذه الشاشة بعد ذلك عبر كتابة الأمر الآتي: >> quit() وأما كتابة الشيفرة في ملف منفصل، فتستطيع إنشاء ملف جديد في أيّ مكان في حاسوبك وتسميته بأيّ اسم تريده، كما يفضَّل أن يكون الاسم معبِّرًا، فالتسمية البسيطة والمعبِّرة من الأمور المهمة. احفظ بعد ذلك الملف بصيغة py -وهي صيغة اختصارية لكلمة Python-، فإذا كان مثلًا اسم الملف Program، فستكون التسمية الكاملة للملف Program.py، ثم اذهب إلى المكان المخزن فيه الملف غبر الطرفية أو موجِّه الأوامر، وبعدها نفِّذ الأمر التالي: >> python Program.py والطريقة الثالثة، تستطيع ببساطة استخدام Google Colab من خدمة Google Drive ومن ثم إنشاء ملف جديد من نوع Google Colaboratory، ثم البدء في إضافة الفقرات، فيمكنك إضافة شيفرات بايثون في ذلك الملف بجانب نصوص عادية وبذلك تستطيع كتابة ملاحظات وتعليقات بين أسطر الشيفرات ويمكنك في الوقت نفسه تنفيذ الشيفرات ككل أو أجزاء محددة. سنبدأ بأمر الطباعة لكتابة أول برنامج بايثون خاص بك، فوظيفة أمر الطباعة في بايثون وفي كثير من اللغات الأخرى، هي طباعة نص على شاشة المستخدِم عند تشغيل البرنامج، وقد ذكرنا ذلك الأمر سابقًا عند الحديث عن الخوارزميات في البرمجة، فعند كتابة الأمر print والذي يعني اطبع بالإنجليزية، فيجب إلحاقه بقوسين، ومن ثم فتح علامات تنصيص بداخل القوسين تحتوى على الجملة التي نريد طباعتها. print ("Hello World") قد يُستخدَم الأمر print لطباعة النصوص على الشاشة أو لطباعة الأرقام، فالأمر سيان في حالة الطباعة، ولكن لا يجب إضافة علامات تنصيص في حالة طباعة الأعداد. print (3) >> 3 كما أنه من الممكن طباعة نتيجة عملية رياضية بسيطة مثل عمليات الجمع والطرح كما في الأمثلة الآتية: print (3+3) >> 6 print (6-4) >> 2 يمكن أيضًا طباعة عمليات الضرب والقسمة وباقي القسمة، إذ يمكنك عبر كتابة الشيفرة التالية طباعة حاصل ضرب عددين مثلًا: print (6*6) >> 36 والأمر بسيط كذلك لطباعة حاصل قسمة عددين: print (49/7) >> 7.0 أما حالة طباعة باقي القسمة، فسنستخدِم رمز النسبة المئوية %: print (50%7) >> 1 كما يمكنك طباعة أيّ عدد من النصوص باستخدام علامة الزائد + كما في المثال الآتي: print ("Hello " + "World!") >> Hello World! إذا أردنا تضمين قيمة عددية داخل نص، فيجب فيجب تحويل العدد إلى نص لأنّ الأعداد في بايثون وفي عدد من اللغات الأخرى عمومًا هي نوع من أنواع البيانات، لذلك يجب استخدام دالة str في هذه الحالة لتحويل العدد إلى نص لتستطيع لغة بايثون التعامل معها على أساس نص. print ("Hello "+str(2)+"nd "+"World!") >> Hello 2nd World! نستطيع الاستغناء عن دالة str إذا أدرجنا الأعداد داخل علامات التنصيص، إذ ستَعُدّ بايثون الأعداد داخل علامات التنصيص نصًا عاديًا، كما سنتعرف على الدوال بصورة أكبر في الصفحات القادمة. print ("Hello " + "2nd " + "World!") >> Hello 2nd World! المعرفات في بايثون تعد المعرِّفات Identifiers من أساسيات البايثون وهي الكلمات التي تستطيع من خلالها تعريف اسم متغير Variable أو ثابت Constant أو دالة Function أو صنف Class أو وحدة Module، ونختصر ذلك كله الآن بكلمة المعرِّفات فقط للدلالة على أيّ منهم، فتلك المتغيرات والثوابت والدوال والأصناف والوحدات، كلها مواضيع وسنتعرف عليها بالتفصيل في هذا الكتاب. تخضع تسمية المعرفات إلى قواعد محدَّدة لا يُمكن الخروج عنها في بايثون؛ لأنه عند الخروج عن إحدى القواعد سيطبع مفسر بايثون رسالة خطأ عند محاولتك تشغيل البرنامج، وتلك القواعد كما يلي: يجب أن تبدأ بحرف إنجليزي أو شَرطة سفلية Underscore _ ولا يُمكنها البدء برقم أبدًا. لا يمكنها احتواء رموز مثل % أو $ أو & …إلخ، ولكن يمكنها احتواء الأرقام. ألا تكون مطابقةً لأيّ كلمة من الكلمات المفتاحية في بايثون. الكلمات المفتاحية في بايثون هي كلمات تُستخدَم في أصل اللغة، بمعنى أنّ تلك الكلمات يقرؤها مفسر لغة بايثون لإجراء مهمة ما، فكلمة مثل print كما علمنا من قبل تؤدي مهمة طباعة نص أو عدد على الشاشة، لذلك لا نستطيع تعريف متغير أو ثابت أو دالة بهذا الاسم، وتكون جميع الكلمات المفتاحية في لغة بايثون كما يلي: 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; } and exec not as finally or assert for Pass break from print class global raise continue if return def import try del in while elif is with else lambda yield except والجدير بالذكر أنّ جميع تلك الكلمات المفتاحية لا تحتوي على أي حرف كبير، وبما أنّ لغة بايثون لغة حساسة لحالة الأحرف، فمن تسمية أيّ معرِّف بتلك الكلمات في حالة تغيير حالة الأحرف، بمعنى أنه لا يُمكنك تسمية متغير باسم print، لكن يمكنك تسمية متغير باسم Print أو PRINT لأنه بالنسبة لبايثون، تكون الكلمات الثلاثة السابقة مختلفةً تمامًا عن بعضها، وبناءً على ذلك، فإذا أردت تسمية متغير أو دالة أو صنف في بايثون، فيجب عليك اتباع القواعد السابقة. كما أنّ هناك أيضًا في بايثون بعض التوصيات أثناء التسمية، وهي ليست قواعدًا يجب اتباعها بل هي أقرب إلى العُرف، ولكن من الأفضل اتباعها حتى تكون الشيفرة المصدرية في أفضل صورة ممكنة، وتلك التوصيات هي كما يلي: اسم الصنف من المفضل أن يبدأ بحرف كبير مثل Mouse وليس mouse. جميع المعرِّفات الأخرى مثل المتغيرات والدوال من الأفضل أن تبدأ بحرف صغير. إذا عرَّفت متغيرًا ما خاصًا، ولا تريد أن يُستخدَم في أيّ مكان آخر في البرنامج، فمن المفضل بدء اسم المتغير بشرطة سفلية واحدة أو شرطتين إذا كان المتغير خاصًا جدًا. السطور والمسافات لدى بايثون نوعًا فريدًا من القواعد عندما يتعلق الأمر بالأسطر والمسافات وتنظيم الشيفرة، إذ تستخدِم معظم لغات البرمجة الأخرى الأقواس المعقوصة { } لكتابة كتلة من الشيفرات، لكن الأمر في بايثون مختلف قليلًا، إذ تُنظَّم كتل الشيفرات باستخدام المسافات، وهي عادةً مسافة جدولة Tab، أو فراغين أو أربعة فراغات spaces، فنكتب كتلةً من الشيفرات لتُنفَّذ عند تحقق شرط معين بالشكل التالي: if something_happens: do_this() else: do_that() نقول للمفسر في المثال السابق الوهمي إذا حدث هذا الأمر، افعل هذا؛ وإذ لم يحدث، افعل ذاك، فالأمر بسيط للغاية، المهم دقق بالمسافات وكيف أن do_this تدخل ضمن الشرط if أما do_that فتدخل ضمن else. وبالمثل، عند كتابة كتلة من الشيفرة داخل أيّ قاعدة شرطية أو غيرها من القواعد، يجب عليك البدء في كتابة أسطر الشيفرة الخاصة بالكتلة بعد مسافة تفصل بينها وبين أول السطر، أو بمعنى أدق تفصل بينها وبين كتلة الشيفرة التي تسبقها، انظر مثلًا: count = 10 if count >= 10: if count <= 20: print ("Count is between 10 and 20") else: print ("Count is larger than 20") else: print ("Count is less than 10") وإليك المثال التالي لموازنة طريقة بايثون تلك مع اللغات الأخرى مثل لغة جافاسكربت: let count = 10; if (count <= 20) { if (count <= 20) { console.log("Count is between 10 and 20"); } else { console.log("Count is larger than 20"); } } else { console.log("Count is less than 10"); } تضمَّن كتل الشيفرة في هذا المثال بداخل القواعد الشرطية داخل أقواس معقوصة بغض النظر عن المسافة بين كل سطر وبدايته، المثال السابق يكافئ: let count = 10; if (count <= 20) { if (count <= 20) { console.log("Count is between 10 and 20"); } else { console.log("Count is larger than 20"); } } else { console.log("Count is less than 10"); } المثالان السابقان متطابقان تمامًا ويعملان بلا مشكلة؛ أما في بايثون، فتخضع الشيفرة إلى قاعدة مسافات الأسطر تلك، ولا يُمكن كسر تلك القاعدة، كما أنّ كافة مبرمجي بايثون يحبون قاعدة المسافات لأنها تُجبِر المبرمجين على كتابة شيفرة بسيطة ومنظمة وسهلة القراءة. ومن أساسيات البايثون وأهم القواعد الخاصة بالأسطر في بايثون، نجد قاعدة استكمال الأسطر، فإذا كنت تكتب سطرًا ما وكان هذا السطر طويلًا للغاية وتريد تقسيمه إلى سطرين، فستستطيع في بايثون تحقيق ذلك عبر استخدام الرمز \، فإذا كتبت سطرًا يجمع رقمَين مثلًا ثم يقسم أحدهما على الآخر، وكنت تريد تجزئة هذا السطر إلى سطرين مختلفين، فيمكنك فعل ذلك كما في المثال التالي: 30 + 6 / 6 >> 31.0 30 + 6 \ / 6 >> 31.0 كتبنا في السطر الأول عملية الجمع مع عملية القسمة في سطر واحد مباشرةً وأنتج ذلك العدد 31، أما في المثال الثاني كتبنا عملية الجمع في السطر الأول فقط، ثم ألحقنا عملية الجمع بالرمز \، واستكملنا السطر التالي العمليات بكتابة عملية القسمة مباشرةً، وأنتج ذلك في النهاية العدد نفسه، لكن توجد مع ذلك حالة خاصة لأيّ سطر في بايثون يحتوي على إحدى الأقواس بمختلف أنواعها، مثل [] أو {} أو ()، إذ يمكن كتابة تلك الأسطر على سطرين أو أكثر دون استخدام الرمز السابق ذكره، فالسطر التالي مثلًا يعمل بدون مشكلة حتى مع عدم استخدامنا للرمز. items = ['item_1', 'item_2', 'item_3', 'item_4', 'item_5', 'item_6'] علامات التنصيص توجد اختلافات بسيطة بين علامات التنصيص في لغة بايثون مثل أي لغة برمجة أخرى، إذ يمكنك في بايثون تضمين أيّ نص بين علامتَي تنصيص مُفرَدة ' أو علامتي تنصيص مزدوجة " أو علامتي تنصيص ثلاثية """ أو ''' لكن من أهم قواعد استخدام علامات التنصيص في بايثون هي إنهاء النص بعلامة التنصيص نفسها المُستخدَمة في البداية، فلا يُمكن استخدام علامة تنصيص مُفرَدة في بداية النص ثم استخدام علامة تنصيص مزدوجة في نهايته، وإنما يجب تطابق العلامة في البداية والنهاية للنص الواحد، وإليك أمثلةً على ذلك في أوامر الطباعة: print ("Hello World!") print ('Hello World!') print ("""Hello World!""") أما بالنسبة لعلامات التنصيص الثلاثية، فتُستخدَم في الغالب لامتلاكها ميزةً غير موجودة في العلامات المفرَدة والمزدوجة، إذ تُعَدّ قادرةً على معالجة النصوص التي تتكون من أكثر من سطر، في حين أنّ علامات التنصيص المُفردة والمزدوجة يجب احتوائها على نص مكوَّن من سطر واحد لا أكثر، فلا يمكنك مثلًا طباعة سطرين متتالين عبر علامات التنصيص المزدوجة، أي لا يمكنك تنفيذ المثال التالي في بايثون بصورة صحيحة: print ("Hello World!") لكن يمكنك تنفيذ ذلك الأمر عند استخدام علامات التنصيص الثلاثية كما يلي: print ("""Hello World!""") >> Hello World! التعليقات في أساسيات لغة بايثون ستحتاج في كثير من الأوقات أثناء كتابتك أو عملك على برنامج ما، إلى كتابة بعض الملاحظات على بعض الأسطر، فقد تكون تلك الملاحظات موجهةً لتذكيرك بكيفية عمل هذه الكتلة من الشيفرة، أو لتذكيرك بأمر ما تريد استكماله في هذه الأسطر في وقت لاحق، وتوفر بايثون مثلها مثل بقية لغات البرمجة إمكانية كتابة التعليقات عبر استعمال الرمز # والذي سيؤدي إلى تجاهل ما يليه حتى آخر السطر، انظر مثلًا الشيفرة التالية: # هذا تعليق print ("Hello, Python!") # تعليق آخر >> Hello, Python! كما ترى، فإنّ المثال السابق يعمل عملًا عاديًا وكأنه مكتوب بالشكل التالي دون تعليقات: print ("Hello, Python!") >> Hello, Python! فإذا كتبت أيّ سطر برمجي بعد رمز # فسيتجاهله مفسر بايثون تمامًا كما لو أنه غير موجود؛ وذلك لأن التعليقات هي في الأساس جمل من اللغة الطبيعية البشرية التي يستخدمها المبرمج للتعليق وكتابة الملاحظات بين تعليمات البرنامج. كما أنه في بايثون توجد طريقة أخرى لكتابة التعليقات في أسطر عدة، وذلك باستخدام علامات التنصيص الثلاثية، ومن مميزات هذه الطريقة أنها قد تُستخدم في توثيق الدوال وغير ذلك، كما أن هنالك أدوات تستخلص تلك التعليقات لتوليد توثيق لشيفرة البرنامج ووظائفه. """This is a multi line comment. It's wonderful how easy is Python language!""" print ("Hello World!") تُستخدَم التعليقات استخدامًا كبيرًا أثناء برمجة التطبيقات المعقَّدة، فغير أنها تُستخدَم للتعليق على الشيفرة، فإنها قد تكون مفيدةً بصورة كبيرة في تعطيل وتفعيل بعض الأسطر في الشيفرة أثناء عملك على حل مشكلة ما، مثل نسخ سطر ما ووضعه بداخل التعليق حتى يتجاهله البرنامج، ولكي أحتفظ بذلك السطر لاستخدامه لاحقًا. تعليمات متعددة في سطر واحد تنتهي التعليمة البرمجية في السطر في معظم لغات البرمجة مثل لغة PHP أو جافاسكربت JavaScript عن طريق كتابة رمز الفاصلة المنقوطة ; مما يسمح بكتابة أكثر من تعليمة برمجية في سطر واحد؛ أما في بايثون، فينتهي السطر عن طريق بداية سطر جديد، ولكن مع ذلك تدعم بايثون تلك الميزة أيضًا، إذ يمكنك إنهاء التعليمة البرمجية عبر الرمز ; وهو بالإنجليزية Semicolon، وهو أمر اختياري وليس إجباريًا كما في اللغات الأخرى، وبذلك تستطيع كتابة أكثر من تعليمة برمجية في سطر واحد مثل اللغات الأخرى. print ("Hello"); print("World") >> Hello >> World اقرأ أيضًا المقال السابق: البرمجة والخوارزميات والذكاء الاصطناعي المرجع الشامل إلى تعلم لغة بايثون النسخة العربية الكاملة من كتاب البرمجة بلغة بايثون3 نقاط
-
نعيش اليوم في عصر يتصف بتفجر غير مسبوق في كمية البيانات، فكل الأجهزة التي نتعامل معها في حياتنا اليومية سواء هواتفنا الجوالة أو مواقع التجارة الإلكترونية التي نتسوق منها أو شبكات التواصل الاجتماعي التي نتصفحها بشكل يومي وحتى أجهزة الاستشعار الموجودة في أجهزة إنترنت الأشياء التي باتت منتشرة في كل مكان حولنا…إلخ. كلها تتعقبنا وتسجل بياناتنا والإجراءات التي نقوم بها والخيارات التي نتخذها ولك أن تتخيل كمية البيانات المهولة التي تولد عن كل هذا طوال الوقت! هذه البيانات الضخمة في شكلها الأولي لا تعني أي شيء في الواقع لذا كان لا بد من تحليلها واستخراج المعلومات المفيدة منها وهنا يأتي دور علم البيانات الحديث الذي يعالج كل جزء من البيانات التي يتم إنشاؤها اليوم لتطوير وتيرة الأعمال واتخاذ القرارات الصائبة والموثوقة التي تعتمد على هذه المعلومات. سنركز في مقال اليوم على أحد التخصصات المهمة في هذا العلم وهو تحليل البيانات Data analysis وهو التخصص الذي يهتم باستخلاص معلومات ذات قيمة من هذه البيانات الخام ونوضح أهميته في عالم الأعمال اليوم ونكتشف أهم الأدوات والتقنيات والمهارات التي تحتاجها لتصبح محلل بيانات محترف، كما سنكتشف أهم الفروقات بين علم البيانات وتحليل البيانات وهندسة البيانات ونسرد بعض الأمثلة الواقعية على شركات تستخدم تحليل البيانات لتحسين أعمالها بأسلوب بسيط وسهل الفهم بعيدًا عن المصطلحات المعقدة. ما هو تحليل البيانات Data Analysis؟ علم تحليل البيانات Data analysis هو تنظيف وتحويل ونمذجة البيانات حتى تحويلها أخيرًا إلى معلومات مفيدة تساعد في اتخاذ قرارات أو توضيح رؤى، حيث يهدف إلى تحويل البيانات إلى معلومات والفرق بين البيانات والمعلومات هو أن الأولى عبارة أن أجزاء بيانات متناثرة تفتقد المعنى مثل عدد 25 أو اسم أحمد بينما الأخيرة هي بيانات لها معنى مثل أن العدد 25 هو عمر أحمد فأصبح له معنى، هذا على مستوى عدد فكيف لو كان لدينا آلاف أو ملايين البيانات والأعداد المماثلة، تخيل! يقوم محللو البيانات باستخراج البيانات الأولية وتنظيمها ثم تحليلها وتحويلها من أرقام غير مفهومة إلى معلومات مفسرة وواضحة وبعد الانتهاء من تفسير البيانات تصاغ النتائج التي تم التوصل إليها بشكل اقتراحات أو توصيات حول الخطوات التالية التي يجب اتخاذها في العمل وتتقاطع هذه المهام مع مهام مهندسي البيانات. يمكنك التفكير في مجال تحليل البيانات كشكل من أشكال ذكاء الأعمال أو ما يعرف استخبارات الأعمال Business intelligence واختصارًا BI، وهو علم يستخدم لحل مشاكل وتحديات معينة داخل المؤسسات والشركات، وتكمن أهميته وقوته في العثور على مجموعات وأنماط البيانات التي يمكنها أن تخبرنا بشيء مفيد وملائم حول مشكلة أو أمر معين من العمل يخص العملاء أو الموظفين أو المنتجات أو المخزون …إلخ. ولا يساعد هذا العلم على فهم السلوك الماضي فحسب بل يمكّننا من التنبؤ بالاتجاهات والسلوكيات المستقبلية وبهذا تكون أي قرارات تتخذ مدروسة بناءً على ما تخبرنا به البيانات وليست مجرد قرارات تعتمد على التخمين والحدس. الفرق بين علم البيانات Data Science وتحليل البيانات Data Analysis لا بد أن نعرف قبل الغوص في الفرق بين علم البيانات وتحليل البيانات أنّ كلا العلمين يتعامل مع البيانات الضخمة لكن لكل منهما نهجه الخاص. وعمومًا يشكل علم البيانات مظلة تضم تحتها علم تحليل البيانات وتستفيد من إمكاناته لكنه يغطي مجالًا أوسع في التعامل مع البيانات. يركز علم البيانات على إيجاد ترابط منطقي بين كم هائل من البيانات، بينما يركز تحليل البيانات على إيجاد ميزات الرؤى المستخلصة من تلك البيانات. بكلمات أخرى: علم البيانات هو فرع من علم البيانات يُعنى بالإجابة عن أسئلة محددة يطرحها علم البيانات وكيفية إنجاز أو تطبيق هذه الإجابات. يقتضي الفرق بين علم البيانات وتحليلها اختلافًا في الطرق المستخدمة في العمل، إذ يستخدم عالم البيانات الرياضيات والإحصاء وخوارزميات الذكاء الاصطناعي وتعلم الآلة لتصحيح وتنظيف ومعالجة وتفسير البيانات الخام لاستخلاص الرؤى منها وإنجاز نماذج أولية توضح الترابط بين البيانات المدروسة. أما محلل البيانات فهو من يتفحص مجموعات البيانات ليجد مدلولها ويخلص بنتائج ملموسة، إذ يجمع محلل البيانات كميات كبيرة من البيانات المهيكلة ثم ينظمها ويحللها ليتعرف على الأنماط التي يبحث عنها، ثم يحاول بعد ذلك تصوير هذه الأنماط بعرضها على شكل مخططات ورسومات وغير ذلك من الأشكال التي تسهل الفهم والتفاعل مع النتائج. باختصار ينقّب علم البيانات في البيانات الخام بحثًا عن رؤى وأفكار منها، بينما يُستخدم تحليل البيانات في نقل هذه الرؤى والأفكار التي قد تبدو معقدة إلى لغة أبسط يفهمها التقنيون وغير التقنيين في المؤسسة التي طلبت الدراسة ويطورون أنظمة لأتمتة وتحسين الأداء العام للعمل مع البيانات. وقد أفردنا لعلم البيانات مقالًا مفصلًا بعنوان علم البيانات Data science: الدليل الشامل يمكنك الرجوع إليه للاستزادة حول تخصص علم البيانات. أهمية تحليل البيانات في شركات الأعمال تبرز أهمية تحليل البيانات في المقام الأول بسبب الكمية الضخمة من البيانات التي تجمع في مختلف المنظمات ومؤسسات العمل فعلى سبيل المثال تقوم شركات البيع بالتجزئة اليوم بجمع وتخزين كميات هائلة من البيانات وتتعقب أي منتجات أو خدمات قمت بتصفحها وشرائها وتسجل كافة الصفحات التي قمت بزيارتها على مواقعها الإلكترونية وتتعقب القنوات التي اشتريت منها وتتعرف على عاداتك في الإنفاق وتجمع كل شاردة وواردة عنك! هذه البيانات التي تجمع بكميات مهولة هي واحدة من أهم أصول الشركات التجارية وأكثرها استراتيجية في عالم الأعمال لكن هل تساءلت لماذا تتنافس الشركات فيما بينها لجمع كل هذه المعلومات؟ لأن التنقيب في هذه البيانات وتحليلها وفهمها يساعدها على استخراج كنوز منها وهذه الكنوز هي معلومات قيمة تساعد أصحاب العمل على اتخاذ أفضل القرارات وتطوير الأداء بشكل مضمون. فالحصول على البيانات وجمعها لا يكفي وحده وهو ليس الغاية في الواقع فماذا يفعل صاحب العمل بكميات مهولة من البيانات المختلفة في بنيتها والتي قد تكون في كثير من الأحيان مكررة أو ربما ناقصة أو غير دقيقة، صاحب العمل يريد في النهاية الخلاصة أو بكلام آخر يريد القصة التي ترويها هذه البيانات والمستنتجة من كل هذا الزخم كي يبني عليها قرارًا صائبًا بشأن الميزانية أو الأسعار أو الموارد وفي نهاية المطاف يسعى في المقام الأول لزيادة أرباحه النهائية وهنا يبرز دور علم البيانات وتحليل البيانات. فشركات البيع على سبيل المثال قادرة الاستفادة من تحليل هذه البيانات في معرفة العادات الشرائية لعملائها وتوصيتهم بأنسب المشتريات وتحديد التحسينات الأنسب في أسعارها وتتبع مخزونها وكشف عمليات الاحتيال ومقارنة مستوى المبيعات وغير ذلك الكثير. وكي تتمكن الشركات من ذلك يجب أن تتمكن من صياغة البيانات وتمثيلها بشكل تقارير مناسبة توضح لصناع القرار في مجال الأعمال المغزى منها وتمكنهم على فهم دلالاتها واتخاذ إجراءات موثوقة وسريعة بالاعتماد عليها وإحداث تغيير إيجابي داخل الشركات لذا تلجأ إلى تحليل البيانات الذي يفسر لأصحاب العمل كل ما تحاول البيانات إخبارهم به. مهام محلل البيانات يلعب محلل البيانات دورًا حيويًا ومهمًا في الشركات والمنظمات ويساعدها على فهم البيانات الضخمة المتوفرة لديها ويتعاون مع باقي أعضاء فريق البيانات للمساعدة في استخراج عن أي معلومات مفيدة وقيمة. كما يقوم محلل البيانات بجمع وتحليل البيانات لحل مشكلة معينة ويكون مسؤولًا عن تحويل البيانات الأولية إلى رؤى ذات مغزى ويستخدم البيانات والأفكار التي توفرها عملية تحليل البيانات لحل مشاكل محددة أو الإجابة على أسئلة محددة. وإليك قائمة بأهم المهام التي يقوم بها محلل البيانات: جمع البيانات الأولية معالجة البيانات ضمان أمن وخصوصية البيانات نمذجة البيانات فهم وتفسير البيانات عرض البيانات نستعرض في الفقرات التالية المزيد من التفاصيل حول كل مهمة من هذه المهام. 1. جمع البيانات الأولية الخطوة الأولى هي جمع البيانات الخام ويمكن أن يقوم محلل البيانات بهذه المهمة ويجمع المعلومات المطلوبة فالبيانات التي سيحللها قد تكون موجودة في مصادر مختلفة، فهي إما أن تكون موجودة في قواعد بيانات الشركة مبعثرة هنا وقد يحتاج لجمعها من خلال إجراء استطلاعات الرأي أو من خلال تتبع بيانات زوار موقع الشركة على الويب، أو من خلال الاستعانة ببيانات الشركات المنافسة حيث يمكن للشركات تبادل البيانات فيما بينها لتحقيق مصالح مشتركة. 2. معالجة البيانات بعد جمع البيانات يجب على محلل البيانات البدء بتنظيف وإعداد هذه البيانات الأولية لأنها في الغالب تحتوي على نسخ مكررة أو قيم خاطئة أو غير دقيقة أو مفقودة للحصول على بيانات سليمة وموثوقة ومفهومة وذات جودة عالية وقد يحتاج إلى تحويل البيانات من هيكل إلى آخر أو من نوع إلى آخر حتى يصبح من الممكن التعامل معها بإحدى لغات البرمجة أو تخزينها في قواعد البيانات كي تكون تفسيرات هذه البيانات دقيقة فإذا لم تكن البيانات التي نبني نحللها نظيفة وصحيحة لن تكون التحليلات والنتائج التي تحصل عليها دقيقة. أحيانًا وفي الشركات أو المشاريع المتوسطة إلى الكبيرة يتولى هذه المهمة مهندس البيانات الذي يركز على هذه المهمة نظرًا لكبر المشروع أو ضخامة البيانات بينما يركز محلل البيانات على عملية التحليل بعيدًا عن عملية الجمع والمعالجة والتجهيز الذي يكون دوره تاليًا. 3. ضمان أمن وخصوصية البيانات قد يحتاج محلل البيانات لإخفاء هوية البيانات الحساسة والشخصية أو حذفها بالكامل لمنع الآخرين من الاطلاع عليها عندما لا تكون هناك حاجة لها للحصول على النتيجة التي يريدها، وأيضًا قد يتولى مهندس البيانات هذه المهمة وتأتي البيانات مشفرة ومحمية إلى محلل البيانات ليقوم بالخطوات التالية. 4. نمذجة البيانات الخطوة التالية هي تحليل وتحديد نقاط البيانات المختلفة التي تم جمعها وإنشاءها بواسطة محللي البيانات واختيار أنواع البيانات المراد تخزينها وجمعها وإنشاء علاقات بينها وتحديد كيفية ترابط مجموعات البيانات مع بعضها البعض وكيفية عرض هذه البيانات وتساعد النمذجة الصحيحة للبيانات على تسريع وتيرة فهمها وإعداد التقارير الخاصة بها. 5. فهم وتفسير البيانات بعد نمذجة البيانات تأتي الخطوة التالية وهي تفسير هذه البيانات من خلال تحديد الأنماط أو الاتجاهات في البيانات التي يمكنها أن توفر معلومات مفيدة تُستخلص منها إجابات على أسئلة توضح سلوكيات أو تفسر أسباب لمشكلات تخص العمل كما تُبنى عليها قرارات وغيرها. 6. عرض البيانات الخطوة الأخيرة والضرورية التي يتوجب على محلل البيانات القيام بها هي عرض وتقديم البيانات بشكل يضفي عليها الحيوية فالمعلومات التي حصلت عليها يجب أن تصاغ على هيئة مخططات ورسوم بيانية وتقارير مكتوبة بألوان متناسقة وخطوط مفهومة ثم تقدم لأصحاب العمل المهتمين لمساعدتهم على فهم ما تعنيه هذه البيانات وتمكينهم من اتخاذ قرارات دقيقة وحيوية بشأنها. هل تحتاج إلى تطوير أعمال شركتك وتحسين فرصها؟ وظّف محلل بيانات محترف من مستقل لتحليل بياناتك وتقديم رؤى استراتيجية تعزز أداء نشاطك التجاري أضف مشروعك الآن مجالات تحليل البيانات نظرًا للتطور التقني الحاصل في عصرنا الراهن فقد أصبح جمع البيانات وفرزها وتحليلها أمرًا ضروريًا لأي مجال من مجالات الحياة وبات من الضروري توظيف محللي البيانات في كافة قطاعات العمل، وفيما يلي نستعرض بعض المجالات والتخصصات التي يمكن لمحللي البيانات العمل فيها. محلل الأعمال محلل الأعمال هو المسؤول عن تحليل ومعالجة البيانات التي تساعد الشركات والمؤسسات على تفسير وتوثيق العمليات التجارية والمنتجات والخدمات والبرامج ويتمثل دوره الأساسي في زيادة كفاءة الأعمال. محلل تسويق محلل التسويق أو محلل أبحاث السوق هو الشخص المسؤول عن جمع وتحليل بيانات المنافسين والعملاء فهو يدرس المنافسين ويبحث عن تفضيلات العملاء وظروف العمل واتجاهات السوق وأي معلومات أخرى تساعد في جهود التسويق للشركة مثل تحديد المبيعات المحتملة لمنتج أو خدمة ما أو تحديد المنتجات التي يفضلها الناس وتقدير تكلفتها وتحديد الفئات التي ستشتريها ويسعى بشكل أساسي لزيادة الإيرادات وتحسين الحملات التسويقية. محلل العمليات محلل العمليات أو محلل أبحاث العمليات هو المسؤول عن تحليل وتقييم البيانات بهدف تحسين العمليات التجارية وحل المشكلات الداخلية وضمان سير عمليات الشركة بسهولة وسلاسة وإنشاء نماذج التسعير والتسويق، فهو من يحدد الحملات التسويقية التي ستجلب عملاء جدد ويجد الطرق الأنسب لخفض التكاليف دون المساس بجودة المنتج أو الخدمة التي تقدمها الشركة. محلل نظم تقنية المعلومات يعرف محلل نظم تقنية المعلومات أيضًا باسم محلل النظم وهو متخصص تقني لديه معرفة واسعة بأنظمة التشغيل والبرامج والأنظمة الأساسية ومهمته الأساسية تحليل وتصميم وتنفيذ نظم المعلومات والعمل على مشاكل العمل باستخدام التقنيات والأدوات التي يحترفها. المحلل المالي المحلل المالي Financial Analyst هو شخص مسؤول عن جمع البيانات وتنظيم المعلومات وتحليل البيانات المالية السابقة للعملاء والشركات بهدف تقديم المشورة الأفضل حول كيفية إنفاق الأموال لتعظيم الأرباح وتقييم نتائج السندات والأسهم والاستثمارات الأخرى. محلل كميات محلل الكميات أو المحلل الكمي quantitative analyst هو شخص متخصص في حل المشكلات المالية وإدارة المخاطر باستخدام الأساليب الرياضية والإحصائية فهو يطور وينفذ نماذج متقدمة تساعد المؤسسات والشركات التي تعمل في مجال الاستثمار وتداول الأوراق المالية مثل شركات التأمين وشركات المحاسبة وشركات البرمجيات المالية على اتخاذ القرارات المناسبة وتحديد فرص الاستثمار والتسعير المناسبة وإدارة المخاطر. محلل ذكاء الأعمال محلل ذكاء الأعمال business intelligence يحلل تقارير أبحاث السوق التي تسلط الضوء على أنماط السوق والاتجاهات التي قد يكون لها تأثير على عمليات الشركة وأهدافها المستقبلية ويعرض النتائج على الجمهور المناسب. محلل استراتيجي محلل استراتيجيات الشركة هو المختص في حل مشاكل العمل فهو يعتمد على تحليل البيانات التي تمكنه من توفير نتائج مفيدة تساعد الشركات على اتخاذ قرارات أفضل ومعالجة التحديات التي تواجهها وتحديد فرص النمو الجديدة للشركة وتطوير الخطط التي تحدد أفضل الطرق والاستراتيجيات لتحقيق الأهداف. محلل طبي يهتم المحلل الطبي أو محلل الرعاية الصحية بجمع وتنظيم وتحليل وتفسير البيانات الطبية مثل بيانات المرضى والعلاجات والمنتجات الطبية لتحسين العمليات التجارية للمستشفيات والمرافق الطبية وتطوير أدائها. محلل الأمني فحص المحلل الأمني البيانات لفحص أي تهديدات محتملة وتحديد ما إذا كان هناك هجوم قد وقع أو على وشك الوقوع. قد يستخدمون أيضًا معرفتهم الإحصائية والرياضية لتطوير طرق جديدة لجمع البيانات حول تهديدات محددة أو هجمات محتملة. مدير تحليل البيانات يوجه مدير تحليل البيانات فريق محللي البيانات في مقر العمل وينسق العمل بينهم ويشرف على عمليات تحويل البيانات الأولية إلى رؤى تجارية يمكن استخدامها لاتخاذ القرارات ويساعد في التوصية بحلول لإنجاز العمل والبحث عن طرق فعالة لجمع البيانات وإنشاء وتطوير النماذج الإحصائية المعقدة واستخدام الخوارزميات والاستراتيجيات الفعالة لتحليل البيانات. مسؤول قاعدة البيانات يراقب مسؤول قاعدة البيانات قاعدة البيانات ويهتم بسلامة بياناتها وسلامة الأجهزة التي توجد عليها وهو يشارك في معالجة البيانات وتحويلها والتحقق من صحتها وتنظيفها لتلبية احتياجات العمل والمتطلبات كما يهتم بأمن هذه البيانات ومنح الوصول لها واستخدامها وفق احتياجات ومتطلبات العمل فقط وتقييد وصول المستخدمين غير المصرح بهم إليها. ارتقِ بأعمالك وابدأ التحول الرقمي انقل نشاطك التجاري إلى الإنترنت وطور أنظمة رقمية شاملة لتنمية أعمالك مع خدمات الخبراء على خمسات ابدأ التحول الرقمي الآن أنواع تحليل البيانات يقسم تحليل البيانات إلى خمس مكونات أو أنواع وهي كالتالي: التحليل الوصفي Descriptive التحليل التشخيصي Diagnostic التحليل التنبؤي Predictive التحليل التقديري Prescriptive التحليل الإدراكي أو المعرفي Cognitive وكلما كان محلل البيانات أكثر خبرة كلما كان قادرًا على تحديد النوع الصحيح من التحليلات بما يتناسب واحتياجات العمل كي يضمن تحقيق أقصى استفادة من البيانات التي تمتلكها المؤسسة وبالتالي تحقيق أفضل النتائج من هذا التحليل. دعنا نتعرف بالتفصيل على طريقة إجراء كل نوع من هذه التحليلات وأهميتها في مكان العمل. 1. التحليل الوصفي Descriptive Analytic التحليل الوصفي هو نوع التحليل الأبسط والأكثر استخدامًا فهو يمكن محلل البيانات من تحليل البيانات المتوفرة باستخدام أدوات تحليل مثل Google Analytics التي تمكنه من فهم ما جرى في مؤسسته أو شركته، فالتحليل الوصفي يوفر لمحلل البيانات الإدراك المتأخر لما يجري في العمل. على سبيل المثال إذا كنت محلل بيانات وحصل انخفاض مفاجئ في مبيعات موقع التجارة الإلكترونية الخاص بشركتك في شهر ما لن تقف مكتوف الأيدي لتنتظر هل ستتحسن المبيعات في الشهر التالي بل عليك استخدام التحليلات الوصفية لتحليل بيانات كافة الأشخاص الذين زاروا الموقع في هذا الشهر لمعرفة سبب ما حدث وهل هو ناتج عن انخفاض في عدد زيارات الموقع أو خطأ في أحد الصفحات أو مرتبط بموسم محدد وتعثر على إجابة لكافة التساؤلات حياله ووصف النتائج التي حصلت عليها لأصحاب العمل. يمكن أن تستعين في إجراء هذه المهمة بأدوات التحليل مثل جوجل أناليتكس Google Analytics وتستسخدم مؤشرات قياس الأداء الرئيسية KPIs التي تمكنك من تتبع الأداء ومعرفة مدى نجاح وفشل الأهداف الرئيسية. فالتحليلات الوصفية باختصار تساعد في معرفة ما حدث في السابق مثل انخفاض المبيعات أو زيادة الإيرادات أو نقص الموارد وتلخص مجموعات البيانات الكبيرة وتصف النتائج التي تم التوصل لها لأصحاب العمل وتستفيد منها في معرفة أسباب النجاح أو الفشل السابق وإنشاء تقارير بها. هذا النوع من التحليل على أهميته يعطي المحلل نظرة ثاقبة فقط حول ما إذا كان كل شيء في العمل يسير على ما يرام أم لا، لكنه في الواقع لا يفسر السبب الجذري لوقوعها لذا تعمد الشركات عادة على الدمج بين هذا النوع من التحليل وأنواع التحليلات الأخرى للحصول على رؤية أفضل. 2. التحليل التشخيصي Predictive Analytic التحليلات التشخيصية هي الشكل الثاني لتحليل البيانات وهي تساعد أصحاب الأعمال في الإجابة عن السبب الأساسي في وقوع حدث ما أو العوامل التي تؤثر على سير العمل، فعندما يعرف محلل البيانات ما يحدث بالفعل في عمله باستخدام التحليلات الوصفية لكنه يريد أن يعرف الأسباب والعوامل التي تسببت بحدوثها بشكل جذري يأتي دور التحليل التشخيصي للإجابة عن أسئلة حول سبب وقوع الأحداث. على سبيل المثال كي يشخص محلل الأعمال إن كانت زيادة الأسعار الأخيرة على أسعار منتجات الشركة لها علاقة بانخفاض المبيعات يمكنه استخدام التحليل التشخيصي باستخدام برنامج إحصائي مثل Microsoft Excel أو يستخدم خوارزمية معينة تمكنه من تحليل بيانات المنتجات والعملاء وفحصها ومقارنتها للعثور على الإجابة الدقيقة. هناك العديد من المفاهيم الإحصائية التي يجب على محلل البيانات فهمها قبل أن يتمكن من إجراء التحليلات التشخيصية وأهمها اختبار الفرضيات والفرق بين الارتباط والسببية وتحليل الانحدار التشخيصي. تكمل تقنيات التحليلات التشخيصية التحليلات الوصفية الأساسية حيث يساعد دمج التحليلات التشخيصية والوصفية الشركات في العثور على العلاقات بين الأسباب والنتائج وفحص مؤشرات الأداء لاكتشاف سبب التحسن أو التراجع بدقة. بشكل عام تحدث هذه العملية في ثلاث خطوات: تحديد الشذوذ في البيانات فقد تكون هذه الحالات الشاذة تغييرات غير متوقعة فيمقياس أو سوق معين. جمع البيانات المتعلقة بهذه الحالات الشاذة. استخدم التقنيات الإحصائية لاكتشاف العلاقات والاتجاهات التي تشرح هذه الحالات الشاذة. 3. التحليل التنبؤي Predictive Analytic يساعد التنبؤ بالمستقبل أصحاب الأعمال على توقع اتجاهات السوق وسلوكيات العملاء وكشف حالات الاحتيال قبل وقوعها وتحليل المنافسين لتحسين وبناء استراتيجيات حديثة لتحسين نتائج الأعمال. يعتمد التحليل التنبؤي على النتائج التي تم الحصول عليها من التحليل الوصفي والتشخيصي ويستخدم للعثور على إجابات حول الأمور التي من المحتمل أن تحدث في المستقبل بناءً على النتائج والأنماط السابقة. على سبيل المثال يمكن استخدام التحليل التنبؤي في الشركات والبنوك لتحليل التركيبة السكانية للعملاء وسجلات الدفع السابقة والمنتجات التي اشتروها وأي سلوكيات سلبية حديثة وقعت من قبلهم لتوقع العملاء الذين سيتأخرون في دفع المستحقات والفواتير المترتبة عليهم ولن يسددوها في الوقت المحدد مما يمكنهم من إدارة التدفقات المالية بشكل أفضل واتخاذ خطوات للتخفيف من حدوث هذه المشكلة مثل تقديم خيارات دفع أخرى أو إرسال رسائل تذكير إلى العملاء الذين تم التنبؤ بأنهم سيتأخرون في تسديد المستحقات وتحديد أفضل تاريخ ووقت لإرسال هذه الرسائل وأفضل طريقة للاتصال بهم مثل البريد إلكتروني أو المكالمة الهاتفية أو الرسائل النصية …إلخ. كما تستخدم النماذج التنبؤية بشكل كبير في مجال الرعاية الصحية وتحلل مجموعة من البيانات المتغيرة حول المرضى مثل العمر أو العلاجات السابقة أو تاريخ المرض ومعدل الكوليسترول والوزن للتنبؤ بما إذا كان الشخص عرضة للإصابة بأمراض معينة كالسكري أو النوبات القلبية أم هشاشة العظام أم لا. يعتمد إجراء التحليل التنبؤي على الخوارزميات الإحصائية المتنوعة وعلى تقنيات التعلم الإحصائي وخوارزميات التعلم الآلي مثل الشبكات العصبية وأشجار القرار والانحدار …إلخ. التي تساعد محلل البيانات على تقديم توصيات وتوفير إجابات للأسئلة المتعلقة بما قد يحدث في المستقبل ولكونها تحليلات تعتمد على التخمينات والاحتمالات فهي تعطي نتائج تقديرية قد لا تكون صحيحة ودقيقة بنسبة مئة بالمئة. 4. التحليل التقديري Prescriptive Analytic التحليل التقديري هو الخطوة التالية التي تأتي بعد إجراء التحليل التنبؤي وهو يساعد الشركات على امتلاك رؤية ثاقبة عما يجب عليهم القيام به لحل مشاكل العمل بناءً على العوامل المشتقة من البيانات. فأثناء تحليل البيانات الضخمة لا تكون التنبؤات التي حصلنا عليها من المدخلات دقيقة كما ذكرنا وبالتالي لا يمكننا التيقن من السبب الحقيقي في حدوث مشكلات معينة وهنا يأتي دور التحليلات التقديرية. فعندما يحصل محلل البيانات على النتائج من التحليلات الوصفية والتشخيصية والتنبؤية ويعرف ما حدث ولماذا حدث ويتوقع ما قد يحدث في المستقبل يمكنه أن يستخدم التحليل التقديري لمساعدته في تحديد أفضل مسار للعمل وما الإجراءات التي يجب الإبقاء عليها وما الإجراءات التي يجب التخلي عنها لزيادة نتائج ومخرجات الأعمال. تعتمد تقنيات التحليلات التقديرية على تعلم الآلة لكونها قادرة على تحليل كميات كبيرة من البيانات بسرعة وكفاءة أكبر واختبار مجموعة كبيرة من الشروط والعثور على أنماط محددة في مجموعات البيانات الكبيرة وتقديم التوصيات بناء عليها. على سبيل المثال تستخدم خرائط جوجل التحليل التقديري لمساعدتك على اختيار وتقدير أفضل طريق عليك اتباعه للوصول لوجهتك من خلال الاعتماد على جميع البيانات ذات الصلة مثل المسافة والسرعة وحركة المرور إضافة للمعلومات السابقة المسجلة عن الأشخاص الذي سلكوا هذه الوجهة من قبل. ومن الأمثلة الأخرى على هذا النوع من التحليل توقع توصيات المحتوى المناسب لك على منصات التواصل الاجتماعي من خلال تحليل سجلات سلوكك والمحتوى الذي تشاهده وتتفاعل معه سواء على هذه المنصات نفسها أو على أنظمة أخرى وتمرير سلوكياتك السابقة لخوارزمية محددة تحلل هذه البيانات وتقدر بناء على ذلك نوع المحتوى الذي تهتم به وتقترحه لك. 5. التحليل المعرفي Cognitive Analytic هذا النوع من التحليل هو الأكثر تقدمًا ولا زال في بداياته وهو مستوحى من الطريقة التي يعالج فيها دماغنا البشري البيانات أي أنه يحلل البيانات بذكاء يشبه ذكاء الإنسان فهو يستخلص النتائج ويكتسب الخبرة من التعلم ويطور نفسه مع الزمن، ويساعدك على معرفة ما قد يحدث إذا تغيرت الظروف وتحديد أفضل الطرق للتعامل معها وهو أمر لا تستطيع التحليلات البسيطة القيام به. يعتمد هذا النوع من التحليل مجموعة من التقنيات الذكية مثل الذكاء الاصطناعي وخوارزميات التعلم الآلي ونماذج التعلم العميق والمزيد لمعالجة المعلومات واستخلاص النتائج من البيانات والأنماط الموجودة ويتوقع أن تصبح تطبيقاته واستخداماته أكثر فعالية بمرور الوقت من خلال تعلمه وتفاعلاته المستمرة مع البيانات ومع البشر. وباستخدام هذا النوع من التحليل ستتمكن من معالجة اللغة الطبيعية مباشرة مثل سجلات محادثة مركز الاتصال ومراجعات المنتجات فهو لا يفهم الكلمات في هذه النصوص فقط بل يفهم السياق الكامل لما يتم كتابته أو نطقه! على سبيل المثال تعد كل من Cortana من مايكروسوفت، و Siri من أبل، و Watson من IBM وآخرها ChatGPT من OpenAI روبوتات محادثة تستخدم التحليل المعرفي لتتفاعل معك بلغتك الطبيعية وتوفر لك المعلومات والرؤى التي تريدها. يمكن أن تستفيد الشركات من هذا التحليل للنظر في أنماط المشتريات من السنوات السابقة وتحديد المنتجات التي قد تكون شائعة العام المقبل وفهم سبب شعبية ورواج منتج معين وما إذا كانت شعبيته ستبقى في السنوات المقبلة مما يساعدها على تحديد فيما إذا كانت ستواصل تخزين كميات كبيرة من هذا المنتج الرائج أم لا كما يمكن للمؤسسات الطبية استخدام التحليل المعرفي لإعطاء أفضل العلاجات الممكنة للمرضى. هذه كانت نبذة عن أهم أنواع التحليلات التي يمكنك الاعتماد كمحلل بيانات عليها واختيار الأنسب من بينها لتعزيز مسار العمل والحصول على أي إجابات يحتاج صاحب العمل لمعرفتها لتعزيز تواجده في السوق أو زيادة أرباحه أو التخلص من مشاكل العمل الحالية أو المستقبلية …إلخ. دعنا نلخص هذه التحليلات كما يلي: إجراء التحليلات الوصفية لإدراك ما حدث بعد وقوعه. إجراء التحليلات التشخيصية إذا طلب منك معرفة لماذا حدث هذا الأمر. إجراء التحليلات التنبؤية إذا طلب منك أن تكون بعيد نظر وتعرف ماذا يمكن أن يحدث في المستقبل. إجراء التحليلات التقديرية لتكسب أصحاب العمل بصيرة ثاقبة يعرفون من خلالها ما الذي يجب عليهم فعله بعد ذلك؟ إجراء التحليلات المعرفية للحصول على رؤية صحيحة وصائبة لما يجب أن يتم. أهم أدوات وتقنيات تحليل البيانات في السابق كان تحليل البيانات أمرًا صعبًا ومرهقًا بسبب عدم توفر التقنيات المساعدة فكانت البيانات تجمع يدويًا بطريقة مرهقة، لكن يمكن اليوم لمحلل البيانات الاستعانة بالكثير من أدوات تحليل وتمثيل البيانات المتوفرة لمساعدته على أداء عمله بسرعة وسهولة وفيما يلي نذكر أهم 10 أدوات في تحليل البيانات: برنامج مايكروسوفت إكسل Microsoft Excel برنامج Microsoft Power BI برنامج التحليل الإحصائي SAS إطار عمل أباتشي سبارك Apache Spark لغة بايثون Python لغة البرمجة R لغة الاستعلام الهيكلية SQL تطبيق Jupyter Notebook منصة KNIME برنامج Tableau دعنا نشرح كل أداة من هذه الأدوات وكيف يمكن لمحلل البيانات الاستفادة منه في عمله. برنامج مايكروسوفت إكسل Microsoft Excel يمكننا برنامج جدولة البيانات مايكروسوفت إكسل من إجراء الحسابات على البيانات وفرزها وتجميعها ومعالجتها والبحث فيها وعرضها بشكل رسوم بيانية وإنشاء النماذج وإعداد التقارير، لكن المشكلة في برنامج إكسل أنه ضعيف في التعامل مع البيانات الضخمة. برنامج Microsoft Power BI مايكروسوفت باور بي آي Microsoft Power BI هو برنامج احترافي لتحليل بيانات الأعمال وهو برنامج تجاري مدفوع لكنه يوفر نسخة مجانية بمواصفات محدودة وقد بدأ كمكوِّن إضافي لبرنامج Excel ثم أعيد تطويره عام 2010 وصدر كبرنامج مستقل. يوفر هذا البرنامج مجموعة أدوات متكاملة لتحليل بيانات الأعمال وهو برنامج احترافي يسمح للمستخدمين بإنشاء تقارير مرئية تفاعلية ولوحات معلومات وهو يتكامل مع برنامج إكسل و SQL Server وخدمات جوجل السحابية ويوفر العديد من الميزات الأخرى المفيدة لمحللي البيانات. برنامج SAS برنامج SAS هو أداة تحليل إحصائي تستخدم لتحليل معلومات وبيانات المؤسسات التجارية الكبيرة تم تطويره لتحديد سمات العملاء وإعداد التقارير واستخراج البيانات وإجراء التحليلات التنبؤية ويملك وحدات برمجية لاستخدامات متقدمة مثل مكافحة غسيل الأموال وتحليل لإنترنت الأشياء لكنه منتج مدفوع وسعره مرتفع نوعًا ما. أباتشي سبارك Apache Spark أباتشي سبارك هو إطار عمل برمجي سريع وديناميكي وسهل الاستخدام لمعالجة البيانات وهو يحتوي مكتبة غنية لخوارزميات التعلم الآلي ويستخدم عادة من قبل محللي البيانات وعلماء البيانات لمعالجة البيانات الضخمة وغير المهيكلة وإجراء مهام التحليل الثقيلة حسابيًا من خلال توزيعها على عدة حواسيب. دورة تطوير التطبيقات باستخدام لغة Python احترف تطوير التطبيقات مع أكاديمية حسوب والتحق بسوق العمل فور انتهائك من الدورة اشترك الآن لغة البرمجة بايثون Python توفر لغة البرمجة بايثون لمحلل البيانات آلاف المكتبات المجانية التي تساعده على استخراج البيانات وتحليلها وإعداد التقارير عنها مثل مكتبات NumPy و pandas التي تبسط إجراء العمليات الحسابية ومكتبات Beautiful Soup و Scrapy لاستخراج البيانات من الويب ومكتبة Matplotlib لتمثيل البيانات رسوميًا وإعداد التقارير حولها. لغة البرمجة R لغة R هي لغة برمجة مفتوحة المصدر تستخدم في التحليل الإحصائي واستخراج البيانات وتوفر الكثير من الحزم المساعدة لمحللي البيانات بشكل مشابه لبايثون، ورغم أن كتابة التعليمات في لغة R أكثر تعقيدًا من لغة بايثون إلا أنها لغة مصممة خصيصًا للتعامل مع المهام الإحصائية وتمثيل البيانات المتقدم. لغة الاستعلام الهيكلية SQL تعد لغة SQL أحد التقنيات الأساسية لتحليل البيانات وإعداد التقارير وهي لغة شائعة وسهلة التعلم ومرنة بشكل كبير ما يجعلها اللغة المفضلة لمحللي البيانات لفلترة البيانات والاستعلام عنها وإعداد التقارير …إلخ. Jupyter Notebook تطبيق Jupyter Notebook هو تطبيق ويب مفتوح المصدر يسمح لمحللي البيانات بإنشاء مستندات تفاعلية تتضمن نصوص وأكواد ومعادلات رياضية ورسوم بيانية تشبه إلى حد ما مستندات وورد لكنها أكثر تفاعلية ومصممة خصيصًا لتحليل البيانات وهو متكامل مع أدوات تحليل البيانات الضخمة مثل Apache Spark. برنامج KNIME KNIME هي منصة مفتوحة المصدر وقائمة على السحابة تملك واجهة رسومية GUI سهلة الاستخدام تستخدم في مهام تحليل البيانات والتنقيب عن البيانات والتعلم الآلي تم تطويرها عام 2004 لصناعة المستحضرات الصيدلانية إلا أن قوتها في تجميع البيانات من العديد من المصادر في نظام واحد دفعت محللي البيانات إلى استخدامها في العديد من المجالات مثل تحليل العملاء وذكاء الأعمال والتعلم الآلي. وهي شائعة لدى الشركات الصغيرة ذات الميزانيات المحدودة. برنامج Tableau برنامج Tableau هو برنامج تجاري عملاق لتحليل البيانات وذكاء الأعمال يمكنه التعامل مع كميات كبيرة من البيانات ومعالجتها وإنشاء حسابات معقدة عليها، ويوفر استعلامات SQL لفلترة البيانات ويمكنك من كتابة استعلاماتك الخاصة وهو سهل الاستخدام ويملك واجهة رسومية GUI تعتمد تقنية السحب والإفلات. كانت هذه قائمة بأشهر أدوات والتقنيات المستخدمة. وتذكّر لا توجد أداة واحدة تفعل كل شيء! عليك كمحلل استخدام الأدوات التي تلبي حاجة عملك بأفضل صورة. مصادر تعلم تحليل البيانات ستجد في أكاديمية حسوب العديد من الدروس والمقالات التي تفيدك في تخصص تحليل البيانات ومن أبرز هذه المصادر دروس تعلم برنامج اكسل المشروحة بطريقة منظمة ومبسطة تساعدك على تعلمه بسرعة وسهولة. وإذا كنت مهتمًا بتعلم لغة بايثون التي تعد من أهم لغات البرمجة المستخدمة في تحليل البيانات فقد وفرت لك أكاديمية حسوب قسم دروس ومقالات متنوعة حول لغة بايثون وهي تُحدَّث باستمرار لذا كن على اطلاع دائم عليها لتتعلم كل جديد وإن كنت تفضل التعلم من الكتب المنهجية يمكنك تنزيل كتاب البرمجة بلغة باثيون من أكاديمية حسوب وللمزيد من المصادر أنصحك بزيارة موسوعة حسوب الشاملة التي تضم توثيقات الكثير من لغات البرمجة، بما في ذلك توثيق لغة بايثون. ومن المصادر المميزة التي تسهل عليك طريق الاحتراف دورة تطوير التطبيقات باستخدام لغة Python التي توفرها أكاديمية حسوب والتي تفرد فيهًا مسارًا كاملًا يشرح بشكل واضح ومبسط أساسيات تحليل البيانات ويعرفك على أهم أدوات ومكتبات بايثون وآليات تطبيقها لإجراء عمليات التحليل الإحصائي والوصفي والتصوير البياني وتنظيف وفهم البيانات وغيرها ذلك الكثير من المعلومات التي تؤهلك لبدء العمل كمحلل بيانات في أي شركة أو منظمة أيًا كان مجال عملها. كما توفر دورة الذكاء الاصطناعي التي تساعدك في احتراف برمجة الذكاء الاصطناعي AI وتحليل البيانات وتعلم كافة المعلومات التي تحتاجها لبناء نماذج ذكاء اصطناعي متخصصة وتطوير تطبيقات ذكية تقوم بتحليل البيانات Data Analysis وتمثيلها مرئيًا، وتطبيقات تعلم الآلة Machine Learning والتعلم العميق Deep Learning وغيرها من التطبيقات المنوعة التي تساعدك على احتراف هذا المجال. وأنصحك كذلك بتعلم البرمجة بلغة R التحليلية باللغة العربية وأسلوب منهجي ومنظم وبشرح مبسط من خلال الاطلاع على مجموعة المقالات والدروس حول لغة R التي توفرها أكاديمية حسوب. وتوفر لك أكاديمية حسوب سلسلة دروس ومقالات عن لغة SQL،كما توفر كتابًا تعليميًا متكاملاً بعنوان ملاحظات للعاملين بلغة SQL 1.0.0 يتضمن مجموعة من الملاحظات والأمثلة العملية عن مختلف مواضيع لغة SQL من الأساسيات حتى الاحتراف. الخلاصة تعرفنا في مقال اليوم على مفهوم تحليل البيانات واستكشفنا معًا المهام المختلفة لمحلل البيانات وكيف يتعامل مع جميع البيانات التي يتم إنشاؤها كل يوم والمتاحة في مكان عمله، من بيانات المعاملات في قاعدة بيانات تقليدية وبيانات القياس المختلفة والبيانات التي يتم جمعها من وسائل التواصل الاجتماعي وكيف يستخرج منها المعرفة التي تطور سير العمل وتحسنه للأفضل. هل لديك اهتمام بتحليل البيانات؟ إذا كانت الإجابة نعم فقد حان الوقت لتبدأ من الآن رحلتك في احتراف هذا التخصص الواعد الذي يزدهر الطلب عليه بشكل كبير في سوق العمل.2 نقاط
-
يمر أغلب مهندسي الذكاء الاصطناعي و تعلم الآلة أثناء تعلمهم للعديد من الخوارزميات الأساسية والتقليدية في تعلم الآلة بمكتبة ساي كيت ليرن Scikit Learn التي توفر هذه الخوارزميات وتوثيقًا جيدًا لها، في هذه المقالة سوف نستكشف هذه المكتبة القوية واستخداماتها ومميزاتها، وما الخوارزميات التي يوفرها، ونستعرض بعض الأمثلة العملية على حالات الاستخدام. ما هي مكتبة ساي كيت ليرن Scikit Learn تعد ساي كيت ليرن Scikit Learn أحد أشهر مكتبات أو أطر عمل لغة بايثون وأكثرها استعمالًا خاصة في مجالات علوم البيانات وتعلم الآلة، فهي توفر مجموعة من خوارزميات الذكاء الاصطناعي المبنية بكفاءة، وتتيح لنا استخدامها بسلاسة حيث تمتلك جميع خوارزميات التعلم المبنية بها طريقة شبه موحدة للتعامل معها، فاستخدام خوارزمية أخرى لنفس الغرض يتطلب ببساطة تغيير سطر واحد من الكود، وتوفر هذه المكتبة إمكانيات كبيرة عند بناء النماذج ومعالجة البيانات وتجهيزها، وحفظ النماذج في صيغة يمكن إعادة استخدامها لاحقًا. مميزات مكتبة ساي كيت ليرن Scikit Learn تسهل مكتبة ساي كيت ليرن Scikit Learn تطوير نماذج تعلم الآلة على المبتدئين والراغبين باختبار الأمور بسرعة، وتوفر لهم العديد من المميزات التي سنسردها ونتعرف عليها مثل: التوثيق الجيد: تتميز المكتبة بوجود توثيق مفصل وأمثلة استخدام كثيرة تساعدنا في البدء بتطوير واستخدام الخوارزميات المختلفة ومعرفة المعاملات التي يمكن ضبطها لتغير أداء النموذج وطريقة تدريبها القيم الافتراضية لمعاملات التحكم : لا داعي للقلق إن كنا نتعلم خوارزمية جديدة ونرغب في تجربتها دون الدخول في جميع التفاصيل وتأثيرات ضبط قيم معاملات التحكم أوالمعاملات الفائقة hyperparameters حيث تضبط المكتبة أغلب العوامل بقيم افتراضية مناسبة لأغلب الاستخدامات، لذا يمكننا التركيز على العوامل الأهم وفهمها بشكل أفضل أدوات للمفاضلة بين النماذج: مع تنوع الخوارزميات المبنية في المكتبة التي يمكنها القيام بنفس المهمة بطرق مختلفة يكون من الصعب على المبتدئ تقرير أي الخوارزميات هو الأفضل للمهمة التي يحاول إنجازها، لذلك توفر لنا المكتبة أدوات للمقارنة بين الخوارزميات المختلفة وعوامل التحكم المختلفة بسلاسة مكتبة غنية بالخوارزميات والأدوات: توفر المكتبة أغلب خوارزميات تعلم الآلة التقليدية، مما يغنينا عن عناء بناء هذه الخوارزميات من الصفر، إذ تتوفر عشرات الخوارزميات التي يمكن تطبيقها من خلال سطور معدودة من الكود، فيمكننا التركيز على تحسين معالجة البيانات وتحسين جودتها واختيار النموذج الأنسب للمشكلة التي لدينا التوافق مع المكتبات الأخرى: تعمل المكتبة بشكل سلس مع المكتبات الأخرى مثل باندا Pandas و نمباي NumPy التي توفر هياكل بيانات وعمليات تسهل اكتشاف أنماط البيانات وتحليلها ومعالجتها لتصبح جاهزة للنموذج الذي نحتاج لتدريبه معالجة البيانات باستخدام ساي كيت ليرن توفر ساي كيت ليرن Scikit Learn العديد من الأدوات الجيدة لمعالجة البيانات وتجهيزها لتدريب النماذج عليها، وكما نعرف تٌعد البيانات وجودتها العامل الأهم في تحسين دقة توقعات النماذج المستخدمة، لذلك هنالك بعض الخطوات التي نحتاج للقيام بها لمعالجة البيانات فمثلًا إذا كانت هناك قيم غير رقمية فنحن بحاجة لتحويلها إلى أرقام فنماذج تعلم الآلة هي نماذج رياضية ولن نستطيع القيام بعمليات حسابية على النصوص أو الصور بشكلها الأصلي. أمثلة على معالجة البيانات الترميز Encoding: هو عملية تبديل بعض البيانات بأرقام يسهل إجراء عمليات رياضية عليها، مع إمكانية إرجاعها لأصلها، يمكن ترميز البيانات في مكتبة Scikit Learn باستخدام الكود التالي: from sklearn.preprocessing import LabelEncoder # ترميز البيانات الوصفية city = ["القاهرة", "الرياض", "دمشق", "القاهرة"] # نعرف المٌرمز الذي يعوض عن اسمٍ برقم يعبر عنه encoder = LabelEncoder() # تقوم هذه الدالة بتجهيز المٌرمز # حيث سيمكننا أن نستخدمه أكثر من مرة بعد هذه الخطوة لترميز البيانات المدخلة له بناءً على أول بيانات أعطت له encoder.fit(city) # الآن يمكننا استخدامه على أي بيانات أخرى لترميزها city_encoded = encoder.transform(city) print(city_encoded) # Output: [1 0 2 1] print(encoder.transform(["الرياض"])) # Output: [0] # عكس الترميز print(encoder.inverse_transform(city_encoded)) # Output: ['القاهرة' 'الرياض' 'دمشق' 'القاهرة'] print(encoder.inverse_transform([2, 1, 0, 0, 1])) # Output: ['دمشق' 'القاهرة' 'الرياض' 'الرياض' 'القاهرة'](city_encoded) التعامل مع القيم المفقودة : قد تتضمن البيانات بعض القيم المفقودة ويمكن التعامل معها في مكتبة Scikit Learn بسهولة من خلال حذف الصفوف التي تحتوي قيمًا مفقودة إن كانت قليلة للغاية، أو التعويض عنها باستخدام المعلومات الإحصائية كالمتوسط الحسابي للقيم، أو بناء نموذج لتوقعها بحسب القيم الموجودة بالفعل. خوارزميات تعلم الآلة في مكتبة Scikit Learn تتضمن مكتبة Scikit Learn العديد من خوارزميات تعلم الآلة التي تساعدنا على تنفيذ مهام متنوعة، وفيما يلي نبذة عن أهم هذه الخوارزميات: أولًا: خوارزميات التعلم الخاضع للإشراف التعلم الخاضع للإشراف Supervised Learning هو نوع من التعلم الآلي يصف المهام التي تكون فيها البيانات المراد توقعها معلوم مخرجاتها الممكنة مسبقًا وتوجد بيانات تحتوي على ملاحظات سابقة تتضمن الوسوم Labels المراد تعليم النموذج توقعها، وسنوضح تاليًا أبرز الخوازرميات التي تندرج تحت هذه النوع. خوارزميات توقع الانحدار Regression توقع الانحدار هو نوع من المهام التي يمكننا القيام بها باستخدام خوارزميات مضمنة في ساي كيت ليرن Scikit Learn، يتوقع هذا النوع من الخوارزميات الحصول على أمثلة سابقة يتعلم منها العلاقة بين المدخلات المعطاة والوسم المراد توقعه، والذي يكون قيمة عددية مستمرة continuous مثل توقع درجة الحرارة أو توقع أسعار المنازل. أمثلة على خوارزميات توقع الانحدار: توقع الانحدار الخطي Linear Regression توقع الانحدار بالدوال متعددة الحدود Polynomial Regression خوزارزميات التصنيف Classification يصنف البشر كل شيء حولهم من الحيوانات والجمادات إلى أنواع الأفلام والروايات، وتتوفر خوارزميات تستطيع محاكاة البشر وتتعلم تصنيف الأشياء المختلفة بإعطاء نماذج وملاحظات سابقة لتصنيفات قام بها البشر من قبل حتي تستطيع الآلة تعلم التصنيف، يمكن الاستفادة من التصنيف في أتمتة العديد من المهام المرجو فيها تصنيف عدد ضخم من العناصر في وقت قليل بالتالي توفير الوقت وزيادة الكفاءة، عملية التصنيف تخرج لنا قيمًا منفصلة discrete. من الأمثلة على استخدام هذه الخوارزميات توقع حالة الطقس هل هو مشمس أم غائم أم ماطر أم حار ...إلخ. وتصنيف الصور، وتوقع تقييمات الأفلام. أمثلة على خوارزميات التصنيف الانحدار اللوجستي Logistic Regression مٌصنّف الجار الأقرب Nearest Neighbors Classification شجرة القرار Decision Tree خوارزميات تجميع النماذج Models Ensemble تتيح لنا ساي كيت ليرن Scikit Learn القدرة على دمج أكثر من نموذج تعلم آلة ليشكلوا نموذجًا أقوى، يمكن تشبيه الأمر بلجنة أو فريق من الأصدقاء كل منهم خبير في مجال معين وعند جمع خبرتهم معًا يغطون على نقاط الضعف الخاصة بهم. يمكن تجميع النماذج باستخدام التصويت Voting حيث نجري تدريب لعدد من النماذج ثم نأخذ بتوقع الأغلبية في حالة كون المشكلة تصنيفية، أما أن كانت المشكلة توقع انحدار يمكن أن تأخذ متوسط التوقعات، لنلاحظ الكود التالي: from sklearn.ensemble import VotingClassifier # التصنيف اللوجيستي model1 = LogisticRegression() # شجرة القرارات model2 = tree.DecisionTreeClassifier() # مٌصنف أقرب الجيران model3 = KNeighborsClassifier(n_neighbors=3) # تجميع لتوقعات النماذج باستخدام التصويت model = VotingClassifier(estimators=[('lr', model1), ('dt', model2), ('knn', model3)], voting='hard') # تدريب النموذج # لاحظ أن مدخلات هذه الدالة هي الخواص المطلوب من النموذج تعلم الأنماط بها # بالإضافة إلى الوسم المٌراد توقعه # تمثل هذه المدخلات التجارب المٌراد للنموذج التعلم منها # يمكنك أن تستخدم هذه الدالة في تدريب أي نموذج في ساي كيت ليرن model.fit(X_train, y_train) # استخدام النموذج في التوقع # البيانات المدخلة للنموذج لم يرها من قبل # ولكنها تحتوي نفس الخواص والأعمدة التي تم تدريب النموذج عليها # نرغب في تدريب النموذج على التعميم لبيانات لم يرها من قبل y_pred = model.predict(X_test) جمعنا في الكود أعلاه عدد من النماذج الضعيفة ومحدودة المعرفة حيث يتدرب كل نموذج على جزء من البيانات، وجمعنا معرفتهم معًا للخروج بتوقع واحد مثال على هذا النوع هو خوارزمية الغابة العشوائية Random Forest وهي تجميع لنماذج من شجرة القرارات Decision Tree البسيطة. تقلل هذه الطريقة من فرص حفظ النموذج للبيانات وتمنحه مرونة أكثر لتعلم الأنماط الحقيقية التي تمكنه من توقع الإجابات الصحيحة عند تعرضه لبيانات جديدة عند تشغيل النموذج. خوارزميات التعلم غير الخاضع للإشراف التعلم غير الخاضع للإشراف Unsupervised Learning هو نوع من تعلم الآلة تكون فيه البيانات غير موسومة، ومهمة النموذج تعلم الأنماط بين البيانات ليكتشف الفروقات بينها، مثلًا إن كانت المدخلات صور فتكون المهمة معرفة أي الصور يمكن اعتبارها تابعة لنفس الشيء دون إعطاء وسم للبيانات في عملية التدريب، ما يعرفه النموذج هو الخواص المُراد للنموذج التعلم منها فقط للتميز بين الصور بناء عليها، وسنوضح تاليًا أبرز الخوازرميات التي تندرج تحت هذه النوع. خوزارميات العنقدة أو التصنيف العنقودي Clustering لا نوفر للنموذج في هذه الحالة التصنيفات والوسوم المتوقع انتماء البيانات لها على غرار التصنيف العادي، ففي العنقدة Clustering على النموذج أن يكتشف هذا بنفسه من خلال تعلم الأنماط الموجودة بالبيانات للتمييز بينها. تستخدم خوزارميات العنقدة في أنظمة التوصية Recommendation systems لتقديم اقتراحات شخصية للمستخدمين تناسب اهتماماتهم، أو فصل عناصر الصورة Image segmentation من خلال تحديد البكسلات التي تنتمي لنفس العنصر Object في الصورة بالتالي تفريقها عن باقي العناصر. أمثلة على خوارزميات العنقدة: العنقدة حول عدد من نقاط التمركز k-means العنقدة الهرمية Hierarchical clustering خوارزميات اختزال البيانات نحتاج لاختزال البيانات Data Reduction في كثير من الحالات بسبب محدودية القدرة الحاسوبية وعدم تأثير كل هذه البيانات بشكل ملحوظ على أداء النموذج، ونجري اختزال البيانات عادة من خلال تقليل أبعادها بدمج بعض الأعمدة أو الخواص بدون خسارة المعلومات الهامة قدر الإمكان، فمثلًا يمكننا تقليل أبعاد الصورة مع الاحتفاظ بملامحها ودقتها قدر الإمكان، أو تقليل عدد الأعمدة من 100 إلى 10 مع احتفاظ الأعمدة العشرة بأغلبية المعلومات التي تؤثر على التوقعات. من أمثلة خوارزميات اختزال البيانات خوارزمية تحليل العنصر الأساسي Principal Component Analysis التي تمكننا من اختزال عدد الأعمدة أو الأبعاد بالبيانات مع الاحتفاظ بأكبر قدر ممكن من المعلومات. # تساعدنا هذه المكتبة على صنع هياكل بيانات مصفوفة # والقيام بالعديد من العمليات الحسابية import numpy as np # هذه الخوارزمية التي سنستخدمها لاختزال البيانات from sklearn.decomposition import PCA # في البداية لنصنع بيانات عشوائية لنقوم بالتجربة # يضمن لنا هذا السطر ثبات القيم العشوائية عند إعادة تشغيل هذا الكود np.random.seed(0) # نعرف مصفوفة عشوائية التوليد، تتكون من 10 صفوف و100 عمود X = np.random.rand(10, 100) # لنعرف الخوارزمية التي استوردناها pca = PCA(n_components=10) # نضع هنا عدد الأعمدة التي نرغب أن تصبح البيانات عليها # لنقم بتشغيل الخوارزمية على البيانات التي معنا x_pca = pca.fit_transform(X) # هذا السطر يقوم بتدريب الخوارزمية على اختزال البيانات وفي نفس الوقت يقوم باختزال البيانات المدخلة # لنرى النتائج print("حجم البيانات قبل الاختزال", X.shape) print("حجم البيانات بعد الاختزال", x_pca.shape) ''' المـــــــــخــرجـــــــــــــات ------------------------------------- حجم البيانات قبل الاختزال (10, 100) حجم البيانات بعد الاختزال (10, 10) ''' خوارزميات كشف الشذوذ كشف الشذوذ Anomaly Detection هو عملية ملاحظة الغير مألوف والخارج عن الأغلبية في البيانات. يستخدم في حالات عددية مثل اكتشاف المعاملات الاحتيالية في البنوك، واكتشاف الأنماط غير المعتادة في تدفق الشبكات مما قد يساعد على منع هجمات إغراق الشبكة بالطلبات، واكتشاف المنتجات المعيبة في خطوط الإنتاج واكتشاف الأنماط غير المعتادة للمؤشرات الحيوية لجسم الإنسان التي تستخدمها تطبيقات الساعات الذكية التي تجمع هذه المؤشرات. من الخوارزميات التي تطبق كشف الشذوذ خوارزمية غابة العزل Isolation Forest، وفيما يلي مثال على طريقة استخدامها: # استيراد نموذج كشف كشف الشذوذ from sklearn.ensemble import IsolationForest # سنستخدمها لتوليد بعض البيانات import numpy as np # نولد البيانات لتجربة النموذج X = np.array([[10, 10], [12, 12], [8, 8], [9, 9], [200, 200]]) # يمكنك ملاحظة أن النقطة الأخيرة شاذة عن باقي النقاط # لنقم بتعريف وتدريب النموذج clf = IsolationForest(contamination=0.2) # %يفترض هذا المعامل أن نسبة شذوذ 20 # لاحظ أن التدريب يتم بدون استخدام وسوم حيث أن هذا النموذج غير خاضع للإشراف clf.fit(X) # في حالة اكتشاف شذوذ سيتم وسمه بسالب واحد لتميزه predictions = clf.predict(X) print(predictions) # Output: [ 1 1 1 1 -1] خوارزميات التعلم الخاضع لإشراف جزئي يستخدم التعلم الخاضع لإشراف جزئي Semi-supervised Learning بيانات تتكون من خليط من البيانات الموسومة Labeled data والبيانات غير الموسومة Unlabeled data أثناء التدريب، يمكن أن يصبح هذا الأسلوب مفيدًا للغاية عندما يكون من الصعب الحصول على بيانات موسومة كافية أو يحتاج الحصول عليها إلى وقت ومجهود ضخم. يستخدم عادة في ترشيح المحتوى في أنظمة التوصية فبعض البيانات قد تكون متوفرة بشكل صريح مثل تقييمات المستخدم للمنتجات والتي يمكن الاستدلال بها لاقتراح المزيد من العناصر، ولكن يمكن أيضًا الاستفادة من المعلومات غير الموسومة والمعروفة ضمنية من خلال تفاعلات المستخدم. كما يستخدم في تدريب نماذج التعلم على الصور ومقاطع الفيديو حيث يمكن وسم بعض الصور أو العناصر فيها بشكل بشري لكن لا يمكن حصر جميع العناصر المختلفة التي قد تكون بداخل صورة ووسمها لذا سنستفيد من دمج الجزء الموسوم من البيانات مع الجزء غير الموسوم في توفير كمية أكبر من البيانات لتدريب نماذج أكثر دقة، وسنوضح تاليًا أبرز الخوازرميات التي تندرج تحت هذه النوع. خوراززميات التعلم الذاتي Self Training يمكننا استخدام التعلم الذاتي Self Training في ساي كيت ليرن Scikit Learn لتحويل أي نموذج تصنيف تقليدي إلى نموذج يمكنه التدريب على البيانات الموسومة وغير الموسومة معًا، شريطة أن يكون النموذج قادرًا على توقع التصنيفات كاحتمالات، ونحتاج لاستخدام نموذج يسمى SelfTrainingClassifier لتحويل النماذج العادية لنماذج خاضعة لإشراف جزئي، لاحظ الكود التالي: from sklearn.tree import DecisionTreeClassifier from sklearn.semi_supervised import SelfTrainingClassifier # نعرف أي مصنف ليكون نموذج الأساس base_classifier = DecisionTreeClassifier() # نقوم بإحاطة نموذج الأساس ليصبح قادرًا على التعلم الذاتي self_training_model = SelfTrainingClassifier(base_classifier) # نقوم بتدريب النموذج مثل أي نموذج تقليدي self_training_model.fit(X_train, y_train) ملاحظة: عند تجهيزنا لبيانات التدريب نحتاج لوسم البيانات غير الموسومة بقيمة 1- حيث أننا لا نستطيع أن نمرر البيانات خلال النموذج وهي غير موسومة. دورة الذكاء الاصطناعي احترف برمجة الذكاء الاصطناعي AI وتحليل البيانات وتعلم كافة المعلومات التي تحتاجها لبناء نماذج ذكاء اصطناعي متخصصة. اشترك الآن اختيار النموذج المناسب قد يبدو اختيار النموذج المناسب في مكتبة ساي كيت ليرن معقدًا، إذ يمكن استخدام أكثر من خوارزمية لحل نفس المشكلة. ولكل خوارزمية معاملات تحكم مختلفة، لذلك يجب علينا استخدام أدوات تساعدنا في مقارنة النماذج وقياس أدائها. فيما يلي بعض المعايير الرئيسية التي يمكن استخدامها: الدقة Accuracy: عدد التوقعات الصحيحة التي توقعها النموذج مقسومًا على إجمالي البيانات. كلما كانت النسبة أعلى، كان النموذج أفضل خطأ المتوسط التربيعي Mean Squared Error: الفرق بين القيمة الفعلية التي نريد التنبؤ بها والقيمة التي توقعها النموذج، ثم تربيع هذا الفرق. وهو يساعد في تحديد مدى دقة التوقعات بحث مصفوفة المعاملات GridSearch: يستخدم لاختبار عدد من المعاملات أو إعدادات النماذج المختلفة دفعة واحدة والعثور على أفضل مجموعة معاملات تحقق أفضل أداء. تستهلك هذه الطريقة وقتًا وموارد حاسوبية كبيرة خاصة إذا كانت المعاملات كثيرة جدًا مقارنة بين ساي كيت ليرن Scikit Learn و تنسورفلو TensorFlow يكمن الفرق الرئيسي بين تنسورفلو TensorFlow وبين ساي كيت ليرن Scikit Learn في تخصص الاستخدام، حيث أن ساي كيت ليرن مكتبة متخصصة بخوارزميات تعلم الآلة التقليدية Traditional Machine Learning بينما تنسورفلو TensorFlow إطار عمل شامل لتطوير وتشغيل نماذج التعلم العميق Deep Learning المبنية على الشبكات العصبية الاصطناعية. وعلى الرغم من إمكانية تدريب شبكات عصبية اصطناعية باستخدام ساي كيت ليرن فهي ليست محسنة لأجل هذا الغرض، إذ لا تستطيع المكتبة الاستفادة من وحدات المعالجة الرسومية GPUs التي تستطيع تسريع تدريب النماذج العميقة بشكل أفضل من وحدات المعالجة المركزية CPUs، بينما لا يقف دعم تنسورفلو TensorFlow عند استخدام GPU واحد، حيث يمكن توزيع التدريب على عدة أجهزة على التوازي وهو شيء صعب التحقيق باستخدام ساي كيت ليرن. الخلاصة تعرفنا في هذه المقالة على مكتبة الذكاء الاصطناعي الشهيرة ساي كيت ليرن Scikit Learn وأبرز مميزاتها ووضحنا بعض التطبيقات الواسعة لخوارزميات التعلم المبنية بها، وكذلك تعرفنا على الفرق بينها وبين إطار العمل تنسورفلو TensorFlow.ننصح بتعلم استخدام هذه المكتبة وتجربتها في بناء وتطبيق نماذج تعلم آلة مخصصة، فهي توفر أدوات قوية ومرنة تمكنكم من تنفيذ حلول مبتكرة في مختلف مجالات الذكاء الاصطناعي. اقرأ أيضًا الذكاء الاصطناعي: دليلك الشامل بناء مصنف بالاعتماد على طرق تعلم الآلة بلغة البايثون باستخدام مكتبة Scikit-Learn العمل مع ملفات CSV وبيانات JSON باستخدام لغة بايثون استخدام التدريب الموزع ومكتبة Accelerate لتسريع تدريب نماذج الذكاء الاصطناعي2 نقاط
-
نشرح في مقال اليوم الخطوات الأساسية لدمج نماذج الذكاء الاصطناعي التي توفرها شركة OpenAI في تطبيق جانغو Django، ففي الآونة الأخيرة ازادت شعبية نماذج OpenAI أو ما يعرف بنماذج GPT OpenAI بشكل كبير بفضل قدرتها على توليد محتوى نصي عالي الجودة في مختلف المجالات سواء كتابة رسائل البريد الإلكتروني والقصص، أو الإجابة على استفسارات العملاء، أو ترجمة المحتوى من لغة لأخرى. تُستخدم نماذج جي بي تي GPT models من قبل المستخدمين من خلال روبوت الدردشة تشات جي بي تي ChatGPT، وهو نظام محادثة ذكي أطلقته OpenAI، لكن يمكن للمطورين الاستفادة من هذه النماذج في تطوير تطبيقاتهم الخاصة باستعمال واجهة برمجة التطبيقات API التي وفرتها OpenAI لتوفير مرونة أكبر في التعامل مع هذه النماذج. وسنوضح في الفقرات التالية خطوات إنشاء تطبيق جانغو يستخدم هذه الواجهة البرمجية، وبالتحديد الواجهة البرمجية لنموذج إكمال المحادثة ChatCompletion API من أجل توليد قصة قصيرة ونتعرف على طريقة تخصص معاملات النموذج المختلفة، وتنسيق ردوده واستجاباته. متطلبات العمل كي نتمكن من إكمال هذه المقالة، سوف تحتاج الآتي: إطار جانغو Django مثبت على بيئة افتراضية env ضمن حاسوبنا إنشاء حساب على منصة OpenAI توليد مفتاح الواجهة البرمجية OpenAI API key من لوحة تحكم الحساب في منصة OpenAI تثبيت حزمة OpenAI Package الخاصة بلغة بايثون ضمن البيئة الافتراضية كما سنشرح في الخطوة التالية تثبيت مكتبة OpenAI في جانغو لنفترض أننا ثبَّتنا جانغو في البيئة افتراضية ضمن مجلد باسم django-apps. علينا التأكد من تفعيل البيئة الافتراضية وظهور اسمها داخل قوسين() في سطر الأوامر Terminal. إذا لم تكن البيئة الافتراضية مفعّلة فيمكننا تفعيلها يدويًا بالانتقال للمجلد django-apps في سطر الأوامر وكتابة الأمر التالي: hasoub-academy@ubuntu:$ .env/bin/activate بمجرد تفعيل البيئة الافتراضية، نشغل الأمر التالي لتنزيل حزمة OpenAI Package الخاصة بلغة بايثون: (env)hasoub-academy@ubuntu:$ pip install openai نحن الآن جاهزون للبدء بتطوير تطبيق جانغو الخاص بنا كما سنوضح في الخطوات التالية. إرسال الطلبات للواجهة البرمجية OpenAI API نحتاج بداية لإضافة مفتاح الواجهة البرمجية OpenAI API key لتطبيقنا كي نتمكن من إرسال الطلبات للواجهة البرمجية ChatCompletion API. واختبار الرد الذي نحصل عليه منها. لنكتب الأمر التالي لتشغيل بايثون داخل البيئة الافتراضية: (env)hasoub-academy@ubuntu:$ python نستورد بعدها المكتبة OpenAI ونعرًف العميل client المخصص للتفاعل مع الواجهة البرمجية كما يلي: import openai client = OpenAI(api_key="your-api-key") ملاحظة: نحتاج لاستبدالyour-api-key بمفتاح الواجهة البرمجية الخاص بنا وهو شبيه للتالي sk-abdfhghlisciodfop. بعدها نرسل طلب للواجهة البرمجية ChatCompletion API باستخدم الدالة chat.completions.create: response = client.chat.completions.create( model="gpt-3.5-turbo", messages=[ {"role": "user", "content": "عد من 1 إلى 10"} ] ) حددنا في الكود السابق النموذج الذي نحتاج لاستخدامه في تطبيقنا ليكون gpt-3.5-turbo، وأضفنا كائن رسالة واحد يحتوي على الدور مستخدم user، ومرّرنا مُوجّه prompt بسيط سنرسل لاختبار الواجهة البرمجية وهو في حالتنا طلب العد من واحد إلى عشرة. ملاحظة1: عند التفاعل مع نموذج GPT سنتعامل مع ثلاثة أدوار رئيسية وهي: دور المستخدم user الذي يطرح الأسئلة أو يطلب المساعدة من النموذج، ودور النظام system الذي يتضمن القواعد والتعليمات التي توجّه للنموذج، ودور المساعد assistance الذي يمثل نموذج الذكاء الاصطناعي نفسه والذي سنستخدمة للإجابة على أسئلة المستخدم أو تنفيذ الأوامر التي يطلبها منه. ملاحظة2: من المهم دائمًا الرجوع إلى التوثيق الرسمي لمنصة OpenAI للحصول على تعليمات دقيقة وشاملة حول كيفية استخدام نماذج GPT في تطبيقاتك، فهذه النماذج تتعدل وتتغير مع مرور الوقت. لنطبع الآن الرد المستلم من الواجهة البرمجية API والذي يتضمن عرض الأعداد من واحد إلى عشرة على شكل قائمة من خلال الأمر التالي: print(response.choices[0].message.content) سنحصل على النتيجة التالية: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 بهذا نكون قد نجحنا بإرسال طلب بسيط إلى الواجهة البرمجية، واستلمنا منها الرد، وتأكدنا أن كل شيء يسير على ما يرام. نحن جاهزون الآن لاستخدام الواجهة البرمجية لإرسال مُوجّه prompt أكثر صعوبة ونطلب من النموذج كتابة محتوى قصة قصيرة. ضبط معاملات النموذج Parameters بعد أن نجنا في إرسال طلب API بسيط إلى الواجهة البرمجية لإكمال المحادثة ChatCompletion API، لنتعرف على طريقة ضبط معاملات النموذج للتحكم بسلوك هذا النموذج. فهنالك العديد من المعاملات المتاحة للتحكم في النص المولد، سنوضح ثلاثة منها. 1. درجة الحرارة Temperature يتحكم هذا المعامل في مدى عشوائية الردود المولَّدة من قبل النموذج، ويأخذ قيمة بين الصفر والواحد، فكلما ارتفعت قيمته سنحصل على تنوع وإبداع في الردود والعكس صحيح. response = client.chat.completions.create( model="gpt-3.5-turbo", messages=[{"role": "user", "content": "اذكر خمس كلمات"}], temperature=0.1 ) print(response.choices[0].message.content) المخرجــــات 1. تفاح 2. سيارة 3. كتاب 4. شمس 5. شجرة لنجرب منحه قيمة قريبة من الصفر مثل 0.1 ونرى كيف ستولد الكلمات: response = client.chat.completions.create( model="gpt-3.5-turbo", messages=[{"role": "user", "content": "اذكر خمس كلمات"}], temperature=0.1 ) print(response.choices[0].message.content) المخرجــــات 1. تفاح 2. فيل 3. ضوء الشمس 4. مغامرة 5. سكون نلاحظ بالتجربة أننا عندما نطلب من النموذج أن يذكر خمس كلمات عدة مرات عند ضبط البرامتر بالقيمة 0.1 فسوف نحصل على نفس الكلمات في كل مرة، أما عندما نضبط قيمته إلى 0.8 ونجرب الطلب عدة مرات فسنلاحظ تغيّر النتائج التي نحصل عليها كل مرة: response = client.chat.completions.create( model="gpt-3.5-turbo", messages=[{"role": "user", "content": "اذكر خمس كلمات باللغة العربية"}], temperature=0.8 ) print(response.choices[0].message.content) المخرجــــات 1. تفاح 2. ضوء الشمس 3. سعادة 4. صداقة 5. تقنية 2. العدد الأقصى للوحدات النصية Max Token يسمح لنا هذا المعامل بتحديد طول النص المولد، فعند ضبطع بقيمة معينة سيضمن لنا أن الردود لن تتجاوز الرقم الذي حددناه في الوحدات النصية tokens، على سبيل المثال عندما نضبط قيمة max-token إلى 10: response = client.chat.completions.create( model="gpt-3.5-turbo", messages=[{"role": "user", "content": "اذكر خمس كلمات"}], max_tokens=10 ) print(response.choices[0].message.content) سنحصل على النتائج التالية: المخرجــــات 1. تفاحة 2. سيارة وعندما نضبط قيمة max-token إلى 20: response = client.chat.completions.create( model="gpt-3.5-turbo", messages=[{"role": "user", "content": "اذكر خمس كلمات"}], max_tokens=20 ) print(response.choices[0].message.content) سنحصل على النتائج التالية: المخرجــــات 1. تفاح 2. سيارة 3. موسيقى 4. محيط 5. صداقة 3. التدفق Stream يحدد هذا المعامل هل نريد أن تتدفق الردود على دفعات streams أو تعود لنا دفعة واحدة، فعند ضبطه بالقيمة True، سنستلم الرد بشكل متدفق، أي على دفعات خلال عملية توليدها. هذا يفيدنا في المحادثات الطويلة وفي تطبيقات الزمن الحقيقي التفاعلية. response = client.chat.completions.create( model="gpt-3.5-turbo", messages=[{"role": "user", "content": "اذكر خمس كلمات"}], stream=True ) collected_messages = [] for chunk in response: chunk_message = chunk.choices[0].delta.content if chunk_message is not None: collected_messages.append(chunk_message) print(collected_messages) المخرجــــات ['', 'قطة', '\n', 'كتاب', '\n', 'حاسوب', '\n', 'شمس', '\n', 'ماء'] سيحتفظ المتغير chunk_message بكل جزء من الرسالة المتدفقة بشكل مؤقت أثناء استلامها من الواجهة البرمجية، بعد ذلك، ستضاف هذه الأجزاء إلى القائمة collected_messages التي تُجمع فيها كل الرسائل. يجب علينا التأكد من أن الجزء المتدفق ليس None، لأن هذه القيمة تدل على انتهاء تدفق الردود وتستخدم كشرط للخروج من الحلقة التكرارية. صياغة مُوجِّه نظام System Prompt مخصص في هذه الخطوة، سنستخدم كل ما تعلمناه من مفاهيم أساسية لكتابة مُوجِّه نظام مخصص system prompt وتوفير السياق الذي يحتاجه نموذج GPT لفهم المطلوب منه ضمن تطبيق جانغو، وسنحدد القواعد التي يجب أن يتبعها النموذج لتوليد المحتوى. ننشئ بداية وحدة بايثون تحتوي على دالة تتولى المهمة المطلوبة. لذا ننشئ ملفًا جديدًا باسم story_generator.py داخل مجلد مشروع جانغو بكتابة الأمر التالي: (env)hasoub-academy@ubuntu:$ touch ~/my_blog_app/blog/blogsite/story_generator.py ثم نضيف مفتاح الواجهة البرمجية OpenAI API key إلى متغيرات البيئة environmental variables، فلا نضيفها في ملف بايثون مباشرة لحماية المفتاح: (env)hasoub-academy@ubuntu:$ export OPENAI_KEY="your-api-key" نفتح الآن الملف story_generator.py وننشئ بداخله عميل OpenAI client ونعرف دالة باسم generate_story وظيفتها توليد محتوى قصة بناءً على مجموعة من الكلمات التي يحددها المستخدم: import os from openai import OpenAI client = OpenAI(api_key=os.environ["OPENAI_KEY"]) def generate_story(words): # استدعاء واجهة برمجة التطبيقات من OpenAI لتوليد القصة response = get_short_story(words) # تنسيق الاستجابة وإرجاعها return format_response(response) لتنظيم الكود البرمجي، سنستدعي ضمن هذه الدالة البرمجية دالة منفصلة باسم get_short_story تطلب توليد القصة من الواجهة البرمجية OpenAI API، ودالة أخرى باسم format_response تنسِّق الرد المستلم من الواجهة البرمجية. لنركز الآن على دالة توليد القصة get_short_story حيث سنضيف الكود الخاص بها في نهاية الملف story_generator.py كما يلي: def get_short_story(words): # إنشاء موجه النظام system_prompt = f"""أنت مولد قصص قصيرة. اكتب قصة قصيرة باستخدام الكلمات التالية: {words}. لا تتجاوز فقرة واحدة.""" # الاتصال بواجهة برمجة التطبيقات response = client.chat.completions.create( model="gpt-3.5-turbo", messages=[{ "role": "user", "content": system_prompt }], temperature=0.8, max_tokens=1000 ) # إرجاع استجابة الواجهة البرمجية return response كما نلاحظ فقد ضبطنا هنا مُوجِّه النظام system prompt كي يخبر النموذج ما هو، وما هي المهمة التي عليه تأديتها، وحددنا في الموجّه حجم القصة المطلوبة، ثم مررنا هذا الموجّه للواجهة البرمجية ChatCompletion API. أخيرًا نكتب كود دالة التنسيق format_response في نهاية الملف story_generator.py: def format_response(response): # استخرج القصة المولدة من الاستجابة story = response.choices[0].message.content # إزالة أي نص أو تنسيقات غير مرغوبة story = story.strip() # إرجاع القصة المنسقة return story لاختبار هذه الدوال سنستدعي الدالة generate_story ونمرر لها مجموعة كلمات كمعاملات، ثم نطبع الرد الذي تعيده لنا من خلال إضافة سطر الكود التالي للملف: print(generate_story("قطة، كتاب، حاسوب شمس، ماء")) لنحفظ الملف ونغلقه، ونشغًله من داخل سطر الأوامر كما يلي: (env) sammy@ubuntu:$ python ~/my_blog_app/blog/blogsite/story_generator.py يجب أن نحصل على قصة تشابه القصة التالية: في زاوية مريحة من غرفة مشمسة، كانت هناك قطة ذات فرو ناعم تُدعى "مشمش"، تتمدد بكسل بجانب رف كتب شاهق. بين صفوف الكتب، كان حاسوب فضولي يهمس بهدوء. بينما كانت أشعة الشمس تتسلل عبر النافذة، مُلَقيةً ضوءًا دافئًا، لاحظت "مشمش" بقعة ماء صغيرة على الرف. مدفوعةً بالفضول، دفعت القطة الكتاب الأقرب إلى البقعة، ليُفتح الكتاب ويكشف عن مكان مخفي يحتوي على عقد ماسي متلألئ. مع اكتشاف السر، بدأت "مشمش" مغامرة غير متوقعة، حيث امتزجت أشعة الشمس، والماء، وقوة المعرفة لتنسج قصة مثيرة من الغموض والاكتشاف. بعد أن تأكدنا من عمل الدالة generate_story وتوليد القصة بشكل صحيح، لنغير طريقة تنفيذ الكود وبدلاً من طباعة القصة مباشرة في سطر الأوامر، سنستدعي الدالة من خلال عرض جانغو Django view لعرض القصة على واجهة المستخدم. print(generate_story("قطة، كتاب، حاسوب شمس، ماء")) يمكن تجربة تعديل مُوجّه النظام system prompt بما يناسبنا لتوليد محتوى أفضل. سنلاحظ بالتجربة أن بإمكاننا دائمًا تحسين النتائج بما يتناسب مع احتياجاتنا. لننتقل إلى الخطوة التالية، حيث سندمج الوحدة التي عرفناها في ملف story_generator.py مع مشروع جانغو الخاص بنا. دمج وحدة بايثون مع جانغو في الواجهة الخلفية لدمج وحدة story_generator مع مشروع جانغو في الواجهة الخلفية، علينا تنفيذ عدة خطوات بسيطة، سنبدأ أولاً بإنشاء عرض view جديد في جانغو لاستقبال الكلمات من المستخدم، ثم سنستخدم الدالة generate_story لتوليد القصة بناءً على تلك الكلمات، وفي النهاية سنعرض النتيجة للمستخدم عبر المتصفح. نفتح ملف views.py داخل مجلد مشروع جانغو، ونستورد الوحدات والحزم البرمجية اللازمة، ثم نضيف دالة عرض view باسم generate_story_from_words ونكتب ضمنها ما يلي: from django.http import JsonResponse from .story_generator import generate_story def generate_story_from_words(request): words = request.GET.get('words') # استخراج الكلمات المتوقعة من الطلب story = generate_story(words) # استدعاء دالة generate_story باستخدام الكلمات المستخرجة return JsonResponse({'story': story}) # إرجاع القصة في استجابة JSON بعدها نحتاج لربط الدالة بمسار URL في مشروع جانغو لتمكين المستخدمين من الوصول إليها عبر المتصفح. لنفتح الملف urls.py ونضيف نمط الرابط URL pattern للدالة generate_story_from_words كما يلي: urlpatterns = [ # أنماط URL الأخرى... path('generate-story/', views.generate_story_from_words, name='generate-story'), ] الآن يمكننا إرسال الطلبات من خلال نقطة الوصول التالية/generate-story/ باستخدام المتصفح، وإرسال طلب من النوع GET لها وتمرير الكلمات المتوقعة كمعاملات للطلب، نفتح سطر الأوامر ونكتب الأمر curl بالشكل التالي: (env)hasoub-academy@ubuntu:$ curl "http://your_domain/generate-story/?words=قطة,كتاب,حاسوب,شمس,ماء" علينا استبدال http://your_domain بالعنوان الفعلي الذي يستضيف مشروعنا. تمثّل الكلمات الممررة عبر هذا الرابط مثل كتاب، وماء، وحاسوب ما هي الكلمات التي نريد استخدامها لتوليد محتوى القصة. يمكن بالطبع تغيير هذه الكلمات واستخدام كلمات أخرى حسب الحاجة. بعد تشغيل أمر curl يجب أن نرى ردًا من الخادم يحتوي على القصة المولدة استنادًا إلى الكلمات التي قدمناها. (env)hasoub-academy@ubuntu:$ curl "http://your_domain/generate-story/?words="قطة,كتاب,حاسوب,شمس,ماء" وسنحصل على مخرجات قريبة للتالي: { "story": "كان يا مكان، في كوخ صغير مريح يقع وسط غابة كثيفة، قطة فضولية تُدعى 'مشمش' تجلس بجانب النافذة، تستمتع بأشعة الشمس الدافئة. بينما كانت 'مشمش' تحرك ذيلها بكسل، لفت نظرها كتاب مغبر ملقى على رف قريب. بدافع الفضول، قفزت بعناية إلى الرف، مما أدى إلى سقوط مجموعة من الكتب، فتح أحدها ليكشف عن مكان مخفي. داخل هذا المكان، اكتشفت 'مشمش' حاسوبًا قديمًا، بدأ شاشته يومض عندما لمست زر الطاقة. مفتونةً بالشاشة المتوهجة، انطلقت 'مشمش' في عالم من المناظر الافتراضية، حيث تجولت بحرية، تطارد الأسماك الرقمية وتوقف للإعجاب بشلالات رائعة. ضائعة في هذه المغامرة الجديدة، اكتشفت 'مشمش' عجائب العوالم الملموسة والافتراضية معًا، مدركةً أن الاستكشاف الحقيقي لا يعرف حدودًا." } الخلاصة إلى هنا نكون قد وصلنا لنهاية هذا المقال الذي وضحنا فيه الخطوات الأساسية التي نحتاجها لدمج OpenAI modes داخل تطبيق جانغو Django باستخدام الواجهة البرمجية OpenAI API، وتعلمنا طريقة إرسال الطلبات للواجهة البرمجية ChatCompletion API والتحكم بسلوك النموذج عن طريق ضبط معاملاته المختلفة. لتحسين هذا المشروع وزيادة ميزاته، يمكننا استكشاف المزيد من مميزات الواجهة البرمجية OpenAI API وتجريب مُوجِّهات نظام system prompt مختلفة، وقيم معاملات متنوعة حتى نحصل على قصة مميزة وإبداعية. ترجمة-وبتصرٌّف-للمقال How to Integrate OpenAI GPT Models in Your Django Project اقرأ أيضًا إنشاء تطبيق جانغو وتوصيله بقاعدة بيانات مدخل إلى إطار عمل الويب جانغو Django دليلك لربط واجهة OpenAI API مع Node.js استخدام وكلاء مكتبة المحولات Transformers Agents في الذكاء الاصطناعي التوليدي2 نقاط
-
"أريد تعلم البرمجة لكنني لا أعرف من أين أبدأ!" هذه هي أكثر عبارة تتردد على سمعي من حديثي العهد بالبرمجة، إذ يأتيني هذا السؤال مرارًا وتكرارًا؛ وفي كل مرة أحاول أن أجيب عنه في سياقه، أجد أنني أضيف معلومات جديدة على إجاباتي السابقة، لذا قررت كتابة هذا المقال بعنوان "تعلم البرمجة" لعله يفيد الراغبين في تعلم تطوير التطبيقات في بدء رحلتهم مع تعلم البرمجة من الصفر. جدول المحتويات حرصًا على تنظيم المقالة ولتسهيل الوصول إلى القسم الذي تريده بسهولة، سنذكر هنا جدول المحتويات باختصار: ما هي البرمجة؟ لماذا تتعلم البرمجة؟ ما عليك معرفته لتصبح مبرمجًا الأدوات اللازمة للبدء في تعلم البرمجة لماذا هناك العديد من لغات البرمجة؟ مفاهيم البرمجة مصادر تعلم البرمجة تطوير واجهات المستخدم تطوير الواجهات الخلفية تعلم تطوير تطبيقات الجوال تطوير الألعاب تطوير الأنظمة المدمجة تطوير تطبيقات سطح المكتب كيفية اختيار لغة البرمجة التي تناسبك نصائح لتعلم البرمجة ما هي البرمجة؟ البرمجة هي عملية تقسيم مهمة معينة يراد تنفيذها عبر الحاسوب إلى أجزاء صغيرة ومترابطة وقابلة للتنفيذ بأوامر بسيطة. بعد ذلك، تجري كتابة هذه الأوامر والتعليمات بإحدى لغات البرمجة، والتي هي وسيلة للتخاطب مع الحاسوب. إليك المثال العملي التالي الذي يشرح ماهية البرمجة: إن كنت تتوقع زيارة صديق لك اليوم، واتصل بك ليقول لك: "أنا واقف بجانب الحديقة ولا أعرف كيف أصل إلى منزلك". أنت عادةً تمر كل يوم من جانب الحديقة وتعرف الطريق بينها وبين منزلك شبرًا بشبر. برأيك هل ينفع إن قلت له: "منزلي معروف وقريب من الحديقة وأنا كل يوم أمر من جانبها"؟ لا، بالتأكيد. تحتاج إلى أن تقسِّم المشكلة إلى أجزاء تمثل خطوات بسيطة يستطيع صديقك فهمها وتنفيذها. مثلًا، أخبره أن ينفذ الأوامر التالية: "سر إلى الأمام عشرة أمتار" ثم "اتجه إلى اليمين" ثم "سر إلى نهاية الشارع" ثم "اتجه إلى اليسار". أخبره بعد ذلك: "عُدَّ الأبنية الموجودة على اليسار حتى تصل إلى البناء الرابع" ثم "اصعد إلى الطابق الثاني" ثم "اطرق على الباب الذي سيظهر أمامك". مبارك! بهذه الطريقة، تستطيع أن تدل صديقك على منزلك بدقة. البرمجة هي الشيء نفسه تمامًا. فهل ترى التعابير المكتوبة بين علامتي الاقتباس؟ إنها التعابير التي تكتب بإحدى لغات البرمجة والتي تخاطب الحاسوب بدلًا من صديقك السابق. لغات البرمجة هي مجموعة من المفردات والقواعد اللغوية التي تشكل لغةً وسيطةً للتخاطب مع الحاسوب وأمره بتنفيذ تعليمات وأشياء محدَّدة. فلا الحاسوب يفهم لغة البشر ولا البشر يفهمون لغة الحاسوب، لذا كان هنالك حاجة ملحة لوجود لغة وسيطة يفهمها كلاهما؛ نتيجةً لذلك، انبثق مفهوم لغة البرمجة. بعبارة أخرى، لو أردنا أن نقول للحاسوب "افعل كذا"، فسنحتاج إلى لغةٍ مشتركةٍ بيننا وبينه ليفهم ما نبتغيه، وهنا يأتي دور لغات البرمجة، إذ يمكنك أن تعدّ لغات البرمجة على أنها وسيط بين المبرمج والحاسوب. يهتم المبرمج بالتفكير في تسلسل الخطوات التي على الحاسوب القيام بها لإتمام العمل المطلوب منه (مثل حساب العمر اعتمادًا على تاريخ الولادة)، ثم كتابة هذه الخطوات بترتيب منطقي بإحدى لغات البرمجة. ربما لاحظتَ في الجملة السابقة أن جزءًا من مهمة المبرمج هو التفكير المنطقي، وهذا يجعلنا ننتقل إلى السؤال الشائع "هل أستطيع تعلم البرمجة وأصبح مبرمجًا؟" أو "هل أنا مؤهل لأصبح مبرمجًا؟". لماذا تتعلم البرمجة؟ يبدو أن تعلم البرمجة من الصفر ليس بالصعوبة التي توقعتها، لكنك تريد حافزًا يجعلك تتعلم البرمجة. تسمع كثيرًا أن البرمجة هي مجال المستقبل، وأن وظائف المبرمجين ستكتسح مجال التوظيف في السنوات القادمة؟ أستطيع أن أؤكد لك ذلك، كما أنَّ وظائف البرمجة هي من أعلى الوظائف دخلًا. فلو كنت تريد بدء مشوارك الاحترافي وتريد عملًا مستقرًا وذا دخلٍ ممتاز، فإن تعلم البرمجة والعمل بها هو أفضل خيارٍ أمامك. وظائف البرمجة مريحة عمومًا، فالعمل كله مكتبي أمام حاسوب في بيئة مريحة ومناسبة، وأغلبية الشركات تتبع نظام العمل 40 ساعة في الأسبوع (أي 5 أيام لمدة 8 ساعات يوميًا)، ولا تغفل عن قدرتك على العمل عن بعد من خلال الانترنت أو كمستقل في أوقات فراغك. تعلم البرمجة سيوسع أفق تفكيرك كثيرًا، خصوصًا أن تعاملك مع الحاسوب يتبع إلى التفكير المنطقي، وستجد أن البرمجة ستسهل لك القيام بأمور أخرى في الحاسوب. ما عليك معرفته لتصبح مبرمجًا يتردد الكثيرون في تعلم البرمجة متذرعين بأن مستواهم في الرياضيات ليس ممتازًا، وهذا ليس صحيحًا، فصحيحٌ أنَّ هنالك أمور تعترضك أثناء أداء عملك كمبرمج تتطلب خبرة في الرياضيات، إلا أنَّه قد تمر عليك فترات طويلة لا تحتاج فيها إلى مسائل رياضية. كل ما يلزمك للبدء في تعلم البرمجة هو الأساسيات التي يعرفها الجميع. إلى حين اعتراضك أية مسألة أو مشكلة تتطلب مهارة في الرياضيات، هنالك الكثير من المصادر والمراجع التي تستطيع الرجوع إليها آنذاك. بعبارة أخرى، أجِّل هذا الأمر قليلًا ولا تخف. الأهم من ذلك هو أن تكون قادرًا على التفكير بشكل منطقي. التفكير المنطقي التفكير المنطقي هو المهارة التي تجمع كافة المبرمجين تحت مظلة واحدة، وهي أساس كتابة الخوارزميات، إذ يجب أن تكون قادرًا على اكتساب هذه المهارة وتطويرها. الخوارزميات كلمة "الخوارزميات" هي الكلمة المرعبة التي ينفر منها البعض، فكل ما يتخيلونه عند ذكرها هو الرياضيات المعقدة والمعادلات الطويلة والرموز العجيبة، لكن الأمر بسيط جدًا؛ فالخوازرميات هي تطبيقٌ للتفكير المنطقي في خطوات متسلسلة واضحة تمامًا لحل مشكلة ما. لكي أوضِّح لك أن الخوارزميات ليست أمرًا معقدًا، سأخبرك بكيفية كتابة برنامج يسأل المستخدم عن سنة ميلاده، ثم يعيد عمره الحالي بالسنوات. الخطوة الأولى: إظهار رسالة نصية نطلب فيها من المستخدم إدخال تاريخ ميلاده. الخطوة الثانية: تخزين سنة الميلاد التي أدخلها المستخدم. الخطوة الثالثة: الحصول على السنة الحالية. الخطوة الرابعة: طرح مدخلات المستخدم من السنة الحالية. الخطوة الخامسة والأخيرة: إظهار الناتج. ما سبق هو خوارزمية بسيطة تتألف من خطوات متسلسلة، لكن إذا أمعنّا النظر فيها سنجد خللًا في حال أدخل المستخدم تاريخًا أكبر من التاريخ الحالي، أي لو أدخل 2050 مثلًا بدلًا من 1995. عندها سيصبح العمر المعاد من الخوارزمية سالبًا، ويمكننا أن نحل هذه الإشكالية منطقيًا بوضع شرط يمنع المستخدم من إدخال تاريخ أكبر من التاريخ الحالي. إطارات العمل كلمة أخرى شائعة جدًا في عالم البرمجة هي "إطارات العمل" frameworks، إطارات العمل هي مجموعة من الشيفرات البرمجية التي تسهل على المبرمج إنشاء التطبيقات، بتوفير وحدات جاهزة تقدم خدمات متنوعة مثل تسجيل المستخدمين، وإرسال البريد الإلكتروني، والتعامل مع قواعد البيانات. أي يمكنك أن تعدّها أدوات برمجية تساعدك في برمجة تطبيقك وتسهِّل لك فعل ذلك. الأدوات اللازمة للبدء في تعلم البرمجة تحتاج إلى حاسوبٍ بمواصفات جيدة (ليس من الضروري أن يكون من أفضل الحواسيب، وإنما أن يمتلك مقدارًا جيدًا من الذاكرة العشوائية). لا ننصح بمواصفات معينة أو نظام تشغيل معين، استعمل ما يحلو لك وما ترى نفسك معتادًا عليه (سواءً كان ويندوز أو لينكس أو ماك). ستحتاج أيضًا إلى اتصالٍ جيد بالإنترنت للوصول إلى المواد التعليمية، ولتنزيل البرمجيات والمكتبات اللازمة للتطوير. أما بخصوص أدوات التطوير، فستحتاج إلى برمجية لكتابة الشيفرات، وهنالك نوعان رئيسيان لها: المحررات النصية: مثل Visual Studio Code أو Atom أو Sublime Text أو Bracktes أو Notepad++. وهذه المحررات النصية تكون بسيطة في أغلبها، وتوفر ميزات أساسية مثل تلوين الشيفرات، وبعض ميزات الإكمال التلقائي، وتدعم أغلبيتها إضافات لزيادة وظائفها. وظيفة هذه المحررات النصية عمومًا هي تعديل الشيفرات بسهولة وسرعة. ننصحك بتجربة Visual Studio Code لشهرته حاليًا وكثرة إضافاته ودعمه الممتاز من شركة Microsoft. بيئات التطوير المدمجة: مثل Visual Studio و Eclipse و Android Studio و NetBeans و Apple Xcode وغيرها. وهذه البيئات توفر ميزات أكثر بكثير من المحررات النصية، مثل تشغيل الشيفرات وتنقيحها (debugging) وميزات التحكم بالإصدارات (version control) والاتصال بقواعد البيانات وخلاف ذلك. لماذا هناك العديد من لغات البرمجة؟ قد تتساءل، لماذا هناك العديد من لغات البرمجة؟ أليست هذه اللغات كلها تنفذ الهدف ذاته؟ لماذا لا يكون هنالك لغة موحدة بين المبرمجين والحاسوب؟ الحقيقة أنّه توجد لغة برمجة واحدة ولكن ليست إحدى اللغات التي تراها أمامك في الصورة. اللغة التي نشير إليها هي لغة الآلة التي يستطيع معالج الحاسوب قراءتها وفهمها. أتتساءل ما هي لغة الآلة وكيف تبدو؟ إليك مقطعًا منها: معلومٌ أنّ معالج الحاسوب لا يفهم شيئًا سوى الأصفار والواحدات، وهذه اللغة -أي لغة الآلة- هي تمثيل للأصفار والواحدات بطريقة تخبر الحاسوب بما يجب عليه فعله. الجدير بالذكر أن هذه اللغة عصية الفهم على البشر، وحتى إن استطعت كتابة شيفرة مثل الشيفرة الموضحة بالصورة (كما في السنوات الأولى من بداية اختراع الحاسوب)، لن يفهمها الآخرون ولن يستطيع أحد التعديل على الشيفرة وتطويرها لاحقًا باستثنائك. سعيًا لإيجاد لغة قريبة من لغة البشر، انقسمت لغات البرمجية إلى قسمين: لغات البرمجة منخفضة المستوى، ولغات البرمجة عالية المستوى وذلك تبعًا لمدى قربها من لغة الآلة أو لغة البشر على التوالي. أي أنّ لغات البرمجة منخفضة المستوى هي اللغات الأقرب للغة الآلة آنفة الذكر مثل لغة التجميع Assembly language، ولغات البرمجة عالية المستوى هي اللغات الأقرب للغة البشر مثل لغة بايثون وجافا. تنفيذ البرامج المكتوبة بلغات برمجة عالية المستوى يقودنا الحديث عن اللغات عالية المستوى واللغات منخفضة المستوى إلى الحديث عن كيفية تنفيذ المعالج للشيفرة المكتوبة بلغة عالية المستوى لا يفهمها المعالج (أليس هذا ما تفكر به الآن؟). عرفنا أن المعالج يفهم الأوامر والتعليمات المكتوبة بلغة منخفضة المستوى (لغة الآلة)، فمَثَلُ هذه العملية كمَثَلِ شخصٍ أجنبي تعلم اللغة العربية وبدأ التحدث مع ناطقٍ باللغة العربية، إذ يمكن لهما التواصل مباشرةً - ليخبر كل منها ما يريد من الآخر فعله - دون وسيط. أمَّا مَثَلُ كتابة برنامج بلغة عالية المستوى أقرب إلى لغة البشر والطلب من الحاسوب تنفيذه كمثل ناطق باللغة الهندية يريد التخاطب مع ناطق باللغة العربية دون أن يفقه أحدهما لغة الآخر. في هذه الحالة، لن يستطيع أحدهما فهم ما يتكلم به الآخر وستفشل عملية التواصل. قد تقول: لماذا لا يحضران مترجمًا يترجم ما يقوله كل منها للآخر؟ حسنًا، هذا ما يحصل تمامًا عندما يراد تنفيذ برنامج بلغة لا يفهمها معالج الحاسوب. في اللغات البشرية، هنالك نوع واحد من المترجمين يعرفه الجميع للترجمة من لغة إلى آخرى؛ أما في لغات البرمجة، هنالك نوعان من المترجمين بين اللغات هما: المفسر interpreter، والمترجم compiler. بناءً على ذلك، تنقسم لغات البرمجة إلى لغات مفسرة ولغات مترجمة. (من الآن وصاعدًا، كلما ذكرنا لغات البرمجة، فنحن نشير إلى لغات البرمجة عالية المستوى.) -المفسر (interpreter): وهو برنامج خاصٌ يفسِّر الشيفرة المصدرية لبرنامج مكتوب بلغة عالية المستوى سطرًا بسطر ويحولها إلى لغة منخفضة المستوى لينفذها الحاسوب مباشرةً. -المترجم (compiler): وهو برنامج خاصٌ يحوِّل الملفات المصدرية لبرنامج مكتوب بلغة عالية المستوى إلى ملف تنفيذي مكتوب بلغة الآلة دفعةً واحدةً، ثم يمكن تشغيل الملف التنفيذي على الحاسوب للقيام بالمهمة المطلوبة. لماذا يوجد الكثير من لغات البرمجة عالية المستوى؟ الآن وبعد أن عرفت الفرق بين لغة الآلة ولغة البشر، لربّما ما زلت تتساءل عن كثرة اللغات البرمجية عالية المستوى المتوافرة وعدم وجود لغة واحدة. نستطيع القول أنك خطوت خطوةً جيدةً للأمام إذ أصبحت الآن أكثر دقة. جواب سؤلك هو أنّ كل لغات البرمجة تُستخدم لتحويل فكرة منطقية إلى سلسلة أوامر يمكن للحاسوب أن ينفذها. فعلى سبيل المثال لا الحصر يمكنك استخدام أي من Ruby أو Java أو Python أو C# أو Go أو JavaScript لبناء موقع ويب. لكن يمكنك أن تعدّ لغات البرمجة على أنها أدوات، وكل أداة تسهّل مهمة دونًا عن أخرى. فعلى سبيل المثال، السيارة والحافلة والدراجة والمحراث الزراعي كلها وسائط نقل، لكنها مختلفة الاستخدام؛ فلا يمكنك أن تذهب وعائلتك لقضاء إجازة صيفية مستخدمين المحراث الزراعي، كما لا يمكنك استخدام سيارة سباق في مدينة مكتظة ذات شوارع ضيقة للذهاب بها إلى العمل. مع أن آلية عمل هذه المركبات متشابهة. والأمر سيانٌ بالنسبة إلى البرمجة. خلاصة القول أنّ هنالك لغات برمجة متخصصة بإنشاء تطبيقات سطح المكتب، وأخرى متخصصة بإنشاء تطبيقات الجوال، وأخرى تستعمل خصيصًا لمواقع الويب، وأخرى لبرمجة العتاد، وهذا ما يحيلنا إلى الحديث عن مجالات البرمجة واللغات الأنسب لكلٍ منها. مفاهيم البرمجة "حسنًا، اقتنعتُ أن البرمجة مناسبة لي وليست صعبة كما كنتُ أتخيل، من أين أبدأ طريقي في تعلم البرمجة إذًا؟" قبل الإجابة عن السؤال السابق، سآخذ وقتي لأشرح لك بعض المفاهيم الخاصة بالبرمجة، ثم سنتحدث عن مجالات العمل فيها وما المسار الأفضل لتعلمك كلًا منها. أنت تعلم أن البرنامج هو سلسلة أوامر ينفذها الحاسوب لحل مشكلة ما، والبرنامج نفسه مكتوب بلغة يفهمها الحاسوب تسمى لغة الآلة. من الأمور الملحوظة التركيز كثيرًا على لغة البرمجة ذاتها أثناء بداية تعلم البرمجة. سأخبرك حقيقةً صادمةً: "لغة البرمجة التي تستعملها ليست بتلك الأهمية التي تتوقعها"، أنا لا أقول لك أن جميع لغات البرمجة متماثلة أو تُستعمل لنفس الاستعمالات، لكن لا تركِّز كثيرًا على تعلم كيفية الكتابة في لغة برمجة ما وتهمل المفاهيم البرمجية التي تقف وراءها. المتغيرات والثوابت عليك أن تتعرف على مفهوم المتغيرات variables المستعمل في جميع لغات البرمجة، والذي يعني إسناد قيمة ما إلى رمز أو كلمة وتخزين هذه القيمة في الذاكرة. فلو أردنا أن نخزن العبارة "Hello World" في متغير ما فنكتب شيئًا شبيهًا بما يلي: var variable_name = "Hello World"; أي أننا نسند الجزء الموجود على يمين إشارة المساواة إلى المتغير المذكور على يسار إشارة المساواة. يمكننا أن نستنتج من اسم "المتغيرات" أن قيمتها قابلة للتغيير خلال تنفيذ البرنامج، فيمكننا في مكانٍ ما من الملف المصدري أن نعيد تعريف المتغير السابق بكتابة: var variable_name = "New value"; أما الثوابت فهي تتشابه مع المتغيرات في كثيرٍ من النواحي، إلا أنك لا تستطيع إعادة تعريف قيمتها بعد تعريفها أول مرة. قد تستفيد من الثوابت عندما تكون متأكدًا تمامًا من عدم تغيير القيمة خلال فترة تنفيذ البرنامج. فلو أردنا تعريف ثابت اسمه pi يحتوي على القيمة 3.14 (والتي سنعرف أنها لن تتغير مطلقًا)، فيمكننا أن نكتب: const pi = 3.14; وإذا حاولتَ تغيير قيمة الثابت بعد تعريفه فستحصل على رسالة خطأ. الشروط تدعم جميع لغات البرمجة تعريف شروط تُنفَّذ في حالات معينة. ففي الخوازرمية السابقة التي شرحنا فيها حساب العمر، يمكننا أن نكتب الشرط بالعربية كما يلي: إذا كان (تاريخ الميلاد أكبر من التاريخ الحالي): نقول للمستخدم أن هنالك خطأ وإلا: سنحسب العمر بطرح تاريخ الميلاد من التاريخ الحالي وإذا أردنا كتابتها بإحدى لغات البرمجة فستبدو شبيهةً بما يلي: if ( user_birth > current_year ) { // ERROR! } else { age = current_year - user_birth; } لا تلقِ للأقواس بالًا، فهي جزء من لغة البرمجة، وقد تختلف من لغة لأخرى، وليست موضع اهتمامنا حاليًا. حلقات التكرار ماذا لو كانت لدينا قاعدة بيانات فيها أكثر من مستخدم ولكل مستخدم تاريخ ميلاد. لا تقل لي سنأخذ التواريخ يدويًا وندخلها إلى البرنامج! هذا مضيعةٌ للوقت، والصواب هو إنشاء حلقة تكرار تأخذ قيمة تاريخ الميلاد الخاص بكل مستخدم ثم تحسب عمره كما أسلفنا في القسم السابق. دعنا نعدل الخوارزمية البسيطة لنضيف تكرارًا فيها: ما أجمل البرمجة! تخيل لو كان عندك ألف مستخدم، وكان عليك حساب أعمارهم، يمكنك بضغطة زر أن تحسبها كلها. الدوال الدالة function هي مجموعة من التعليمات البرمجية التي تقبل مدخلات وتعيد القيمة المطلوبة. تكون الدوال عادةً قصيرةً وتقوم بمهمة وحيدة فقط. فمثلًا لو أردنا تعريف دالة باسم divide تقبل عددين، وتعيد ناتج قسمة العدد الكبير على الصغير، فيمكننا أن نكتب الخورزمية الآتية: مصادر تعلم البرمجة للمبتدئين أول ما سيتبادر إلى ذهنك بعد قرارك تعلم البرمجة هو من أين سأتعلم؟ هنا يأتي دور القسم التعليمي المتكامل في حسوب ليقدم للمبتدئ (والمحترف على حدٍ سواء) محتوى علمي مميز ومبسط. تزخر أكاديمية حسوب بالمحتوى المفيد عن تعلم البرمجة للمبتدئين وحتى الخبراء أي على كافة المستويات، ستجد فيها أقسامًا تشرح لغات البرمجة وتقنياتها كلها. ولدينا قسم للأسئلة البرمجية التي يمكنك أن تطرح فيه سؤالك وسيجيب عليه أحد أفراد مجتمع أكاديمية حسوب. أضف إلى ذلك أن الأكاديمية توفر قسمًا للدورات المتخصصة التي تبدأ معك من الصفر وحتى احتراف لغة البرمجة التي تريد تعلمها مع كادر من المدربين المختصين الذي يقدمون لك المساعدة ويجيبون عن جميع استفساراتك. وهنالك قناة للأكاديمية على يوتيوب ننشر فيها دوريًا دروسًا قصيرةً عن تساؤلات محددة ومفاهيم البرمجة وخلافه. لا تنسَ الاشتراك في قناة الأكاديمية لتصلك الفيديوهات الجديدة. ماذا لو أردتَ التعمق أكثر في لغة معيّنة؟ تأتي هنا موسوعة حسوب التي توفِّر توثيقًا عربيًا كاملًا وعالي الجودة، مدعّمًا بالأمثلة لمختلف لغات البرمجة وتقنيات تطوير الويب والجوال. ستكون الموسوعة مرجعًا تعود إليه في مسيرتك البرمجية، وتستعين بها لمعرفة التفاصيل الدقيقة عن لغات البرمجة. فأنت لست مضطرًا لحفظ كل شيء في لغة البرمجة، إذ حتى المبرمجون المختصون ذوو الخبرة يعودون إلى التوثيقات بين الفينة والأخرى أثناء عملهم. لننطلق الآن للتحدث عن مجالات البرمجة الأساسية وما اللغات والتقنيات المستعملة فيها. تطوير واجهات المستخدم يبدأ أغلبية المطورين مشوارهم من خلال تعلم تطوير واجهات المستخدم عند اتخاذ قرارهم لدخول مجال تطوير وبرمجة مواقع الويب، وذلك لسهولة اللغات المستعملة في هذا المجال. هدف هذا المجال هو تطوير صفحات الويب التي تعرض محتوى مختلف مواقع الويب، وهي الصفحات التي تراها عند زيارتك لموقع أكاديمية حسوب أو موسوعة حسوب أو مستقل أو أي موقع آخر. تتألف صفحة الويب من مجموعة من المكونات، وتُكتَب هذه المكونات باستخدام لغة HTML، وبعد كتابة البنية الهيكلية للصفحة سنأتي على تنسيقها باستخدام لغة CSS، وهي اللغة المستعملة لإضفاء شكل وهيئة على عناصر HTML. أي أن عناصر HTML تصف محتوى الصفحة (مثل الترويسات والقوائم والمحتوى الرئيسي والفقرات والروابط والصور والفيدوهات)، وقواعد CSS تُعرِّف كيف يجب أن تبدو هذه العناصر (سواءً من ناحية الألوان أو المساحات أو الخلفيات أو الخطوط أو خلاف ذلك). تأتي لغة JavaScript مكملةً لهما وتستعمل لإعطاء بعض عناصر الصفحة صفاتٍ تفاعلية، مثل شريط متحرك من الصور أو قوائم تظهر عند وقوع حدث معيّن …إلخ. هنالك تقنيات كثيرة تستعمل في تسهيل إنشاء الواجهات الأمامية وسنذكر بعضها: إطار Bootstrap لتسهيل تنسيق عناصر الصفحة. مكتبة jQuery لتسهيل التعامل مع عناصر الصفحة باستخدام JavaScript. مكتبة React JS: لتسهيل تطوير واجهات المستخدم بالاعتماد على مكونات قابلة لإعادة الاستخدام. لغة Sass لإنشاء ملفات CSS بسرعة وسلاسة. أدوات بناء مثل Webpack الذي يسهِّل تحويل الملفات المصدرية للتطبيق إلى النسخة النهائية التي ستعرَض للمستخدم. لتعلم تطوير واجهات المستخدم، ننصحك بالتسجيل في دورة تطوير واجهات المستخدم المقدمة من أكاديمية حسوب، والتي تحتوي على أكثر من 72 ساعة فيديو تتوزع على ثمانية مسارات تعليمية تشرح أمثلة عملية تطبيقية شرحًا مفصلًا. أثناء مشاهدتك للدورة، يمكنك أن تعود إلى موسوعة حسوب لتتعرف على توثيق لغات البرمجة المذكورة، وذلك للاطلاع على تفاصيل وأمثلة أكثر عن كل جزئية من الجزئيات المشروحة في دورة تطوير واجهات المستخدم. اللغات والتقنيات المستخدمة في تطوير واجهات المستخدم: HTML و CSS و JavaScript و Bootstrap و Sass و jQuery و Webpack. تطوير الواجهات الخلفية قد تتساءل: ماذا يعني تطوير الواجهات الخلفية (backend)؟ وما الفرق بينه وبين تطوير واجهات المستخدم (frontend)؟ الفرق بينهما هو أن الواجهات الخلفية هي البرمجيات التي تُنفَّذ على الخوادم وتجري عمليات عليها مثل التعامل مع قواعد البيانات والملفات والخدمات الخارجية، أما واجهات المستخدم فهي الصفحات التي تظهر على شاشة الزائر في متصفحه. سأطرح عليك الخيارات المتاحة أمامك للبدء في مجال تطوير الواجهات الخلفية، وجميع اللغات المذكورة هنا هي لغات ناجحة وقوية ولا يهم أي لغة تختار منها، المهم أن تتطلع على شيفرات بسيطة من كل لغة وتتخذ قرار تعلمها، واحذر من تضييع وقتك في التنقل بين لغات البرمجة والبحث عن أفضلها، فكلُ لغةٍ ممتازةٌ في مجالها. تعلم البرمجة باستخدام لغة PHP بعد تبيان الفرق بين واجهات المستخدم والواجهات الخلفية، يمكن القول بأن أشهر لغة لتطوير الواجهات الخلفية هي لغة PHP، وتتفوق على اللغات المنافسة لها أضعافًا مضاعفة. تعلم البرمجة بلغة PHP أمر سلس، فهي لغة سهلة التعلم وبسيطة الشكل، والمجتمع حولها كبير وتطويرها مستمر. هذه اللغة هي خيار استراتيجي لمن يريد الدخول إلى مجال تطوير الواجهات الخلفية. هنالك عدد من البرمجيات المكتوبة بلغة PHP مثل ووردبريس WordPress ودروبال Drupal وميدياويكي MediaWiki (التي تشغِّل ويكيبيديا وموسوعة حسوب) وغيرها الكثير؛ إضافةً إلى عددٍ كبير من إطارات العمل مثل Laravel و CodeIgniter و Symfony و CakePHP و Yii وغيرها، وهذا ما يدل على إمكانيات اللغة الكبيرة والمجتمع الكبير الذي يحيط بها. لتعلم تطوير الواجهات الخلفية باستخدام PHP، ننصحك بالتسجيل في دورة تطوير تطبيقات الويب باستخدام PHP المقدمة من أكاديمية حسوب، والتي تحتوي على 75 ساعة فيديو تتوزع على اثني عشر مسارًا تعليميًا تبدأ بأساسيات لغة البرمجة PHP للمبتدئين، مرورًا بشرح أمثلة عملية تطبيقية بالتفصيل، ووصولًا لتطوير التطبيقات باستخدام إطار العمل Laravel، وشرح تطوير ووردبريس. أثناء مشاهدتك للدورة، يمكنك أن تعود إلى موسوعة حسوب للاطلاع على توثيق لغة PHP وإطار العمل Laravel. اللغات والتقنيات المستخدمة في تطوير تطبيقات الويب باستخدام PHP هي: PHP و Laravel وقواعد البيانات (مثل MySQL و PostgreSQL وغيرها). تعلم البرمجة باستخدام لغة روبي - Ruby إذا كنتَ تبحث عن لغةٍ أنيقة وسهلة الاستعمال فستجد ضالتك في لغة روبي Ruby فهي من أجمل اللغات وأسلسها كتابةً، وهي لغة برمجة عامة يمكن استخدامها لتطوير مختلف أنواع التطبيقات ومن ضمنها تطوير تطبيقات الويب. ذاع صيت روبي في تطوير الويب بعد نشر إطار العمل Ruby on Rails (يشار إليه اختصارًا "ريلز"). هنالك إطارات عمل أخرى مثل سيناترا Sinatra لكن يبقى ريلز أشهرها. لتعلم تطوير الواجهات الخلفية باستخدام روبي، ننصحك بالتسجيل في دورة تطوير تطبيقات الويب باستخدام روبي المقدمة من أكاديمية حسوب، والتي تحتوي على 20 ساعة فيديو تتوزع على أربعة مسارات تعليمية تشرح أمثلة عملية تطبيقية شرحًا مفصلًا، وتشرح تطوير التطبيقات باستخدام إطار العمل ريلز. أثناء مشاهدتك للدورة، يمكنك أن تعود إلى موسوعة حسوب للاطلاع على توثيق لغة روبي وإطار العمل ريلز. اللغات والتقنيات المستخدمة في تطوير تطبيقات الويب باستخدام روبي: روبي و ريلز وقواعد البيانات (مثل MySQL و PostgreSQL وغيرها). تعلم البرمجة باستخدام لغة جافا سكربت - JavaScript نعم! تستعمل JavaScript في تطوير الواجهات الخلفية أيضًا. الفضل يعود لبيئة Node.js التي تسمح للمطورين باستخدام JavaScript لكتابة برمجيات تعمل من جهة الخادم وذلك لتوليد صفحات ويب ديناميكية قبل إرسالها إلى المتصفح، وتستطيع Node.js التعامل مع الملفات وقواعد البيانات ومختلف أنظمة الشبكات وخدمات أنظمة التشغيل. هل يوجد أجمل من استخدام نفس اللغة لبرمجة الواجهات الأمامية لمواقع الويب والواجهات الخلفية؟ وكل ذلك باستخدام لغة سهلة التعلم والاستعمال ومدعومة دعمًا ممتازًا من المجتمع. تعلم لغة JavaScript لتطوير الواجهات الخلفية من خلال التسجيل في دورة تطوير التطبيقات باستخدام JavaScript المقدمة من أكاديمية حسوب، والتي تحتوي على 69ساعة فيديو تتوزع على أحد عشرمسارًا تعليميًّا تشرح أمثلة عملية تطبيقية شرحًا مفصلًا، وتشرح تطوير الواجهة الخلفية باستخدام Node.js. أثناء مشاهدتك للدورة، يمكنك أن تعود إلى موسوعة حسوب للاطلاع على توثيق لغة JavaScript وبيئة العمل Node.js. اللغات والتقنيات المستخدمة في تطوير تطبيقات الويب باستخدام JavaScript: لغة JavaScript وبيئة Node.js وإطار العمل Express.js وقواعد البيانات (مثل MongoDB و MySQL و PostgreSQL وGraphQL وغيرها). تعلم البرمجة باستخدام لغة بايثون - Python لغة بايثون متعددة الاستعمالات، ويمكن عدّها على أنها أسهل لغة برمجة على الإطلاق، إذ تبدو شيفرتها البرمجية كأنها مقالة مكتوبة باللغة الإنكليزية. إذا أردتَ لغةً سهلةً ومدعومةً دعمًا ممتازًا ولها أطر عمل كثيرة فأنت تبحث عن لغة بايثون. الخيارات المتاحة أمامك هي إطار العمل جانغو (Django) وفلاسك (Flask) وغيرها، يمكنك تعلم لغة البرمجة بايثون لتطوير الواجهات الخلفية من خلال قراءة سلاسل المقالات عن تعلم بايثون في قسم البرمجة في أكاديمية حسوب، ثم الانتقال إلى تعلم إطار العمل جانغو أو فلاسك. يمكنك أن تعود إلى موسوعة حسوب للاطلاع على توثيق لغة بايثون. تعلم لغة بايثون لتطوير الواجهات الخلفية من خلال التسجيل في دورة تطوير التطبيقات باستخدام Python المقدمة من أكاديمية حسوب، والتي تحتوي على 69 ساعة فيديو تتوزع على عشرةمسارات تعليمية تشرح أساسيات لغة بايثون للمبتدئين، ثم تطبق عمليًا بأمثلة واقعية، وتشرح إطار العمل جانغو Django وفلاسك Flask. اللغات والتقنيات المستخدمة في تطوير تطبيقات الويب باستخدام بايثون: لغة بايثون وإطارات العمل المبنية عليها (مثل جانغو وفلاسك) وقواعد البيانات (مثل MySQL و PostgreSQL وغيرها). تعلم تطوير تطبيقات الجوال ازداد عدد تطبيقات الجوال لأنظمة أندرويد و iOS ازديادًا كبيرًا في الفترة الماضية، وأصبح لكل شركة أو خدمة تطبيق خاص بها يسهِّل على مستخدميها الوصول إلى الخدمات التي توفرها. النظامان الرئيسيان المسيطران على سوق الجوال حاليًا هما أندرويد ثم iOS. يمكن برمجة تطبيقات أندرويد بلغة Java أو Kotlin (أو غيرهما) وبرمجة تطبيقات iOS باستخدام Swift (وغيرها). ستكتشف أنَّ عليك تطوير تطبيقين منفصلين تمامًا، واحد لهواتف أندرويد وآخر لهواتف iOS، وذلك يسبب زيادةً في حجم العمل المطلوب وصعوبةً في إدارة التغييرات. بسبب ذلك، ظهر مفهوم "التطبيقات متعددة المنصات"، وهي تطبيقات تعمل على نظام أندرويد و iOS دون أي تعديلات، وذلك باستخدام تقنيات مشتركة وهي في الغالب تقنيات الويب. أي أصبح بإمكان مطوري الويب الاستفادة من معلوماتهم في تطوير تطبيقات الجوال باستخدام منصات مثل آيونيك Ionic. تسمح آيونيك Ionic للمبرمجين بالتعامل مع مختلف وظائف الجهاز باستخدام لغة JavaScript، مثل الوصول إلى الموقع الجغرافي، والتقاط صور بالكاميرا، والتعامل مع الملفات وخلاف ذلك. طوِّرت في الفترة الماضية تقنيات أخرى مبنية على JavaScript مثل React Native المبنية على مكتبة React.js والتي تسمح للمطورين بكتابة تطبيقات أصيلة باستخدام تقنيات الويب. تستطيع تعلم تطوير تطبيقات الجوال عبر Ionic وعبر React Native من خلال التسجيل في دورة تطوير التطبيقات باستخدام لغة JavaScript المقدمة من أكاديمية حسوب، والتي تحتوي على 69 ساعة فيديو تشرح أمثلة عملية تطبيقية شرحًا مفصلًا. وكالعادة يمكنك أثناء مشاهدتك للدورة أن تعود إلى موسوعة حسوب للاطلاع على التوثيقات اللازمة. اللغات والتقنيات المستخدمة في تطوير تطبيقات الجوال: Java و Swift و Kotlin و Ionic و React Native وغيرها. تطوير الألعاب تطوير الألعاب هو المجال الذي يحلم جميع مستخدمي الحاسوب بالدخول إليه. فالأغلبية تعرفوا على الحاسوب من خلال ألعاب الفيديو ومن ثم بدؤوا برحلة الاستكشاف عن البرمجة والتطوير. أغلب من يجيب عن تطوير الألعاب يقول "عليك بتعلم لغة C++" لكن دعني أفصِّل لك الأمر قليلًا. برمجة الألعاب تتطلب عملًا كثيرًا من فريق عمل كبير، مدعوم من شركة تجارية. من الصعب على مطوِّر وحيد أن ينشئ لعبة كاملة من الصفر دون فريق. تُطور أغلبية الألعاب باستخدام محرِّك ألعاب Game Engine والذي يسهِّل الأمر على المطورين ويتيح بيئة تطوير مناسبة للألعاب، ويتيح الميزات الأساسية لجميع الألعاب مثل التحكم بالكاميرا ونمذجة الشخصيات ثلاثية الأبعاد وتحريكها والأمور الفيزيائية الأخرى. هنالك عدد كبير من محركات تطوير الألعاب، ومن المرجح أنك شاهدت شعارها في الألعاب التي لعبتها من قبل، ومن أشهرها: Unreal Engine و Unity و Godot. يمكن التعامل مع هذه المحركات باستخدام عدِّة لغات، مثل C++ (وهي أشهرها)، وجافا (خصوصًا للألعاب على هواتف أندرويد) وحتى يمكن استخدام JavaScript في التعامل مع بعضها. تذكر أنّ الألعاب غير محدودة بتطبيقات سطح المكتب أو الهواتف، فهنالك ألعاب كثيرة تعمل على المتصفحات باستخدام تقنيات HTML5 و JavaScript. اللغات والتقنيات المستخدمة في تطوير الألعاب: C++ و Java و JavaScript ومحركات Unity و Unreal Engine و Godot. برمجة الذكاء الاصطناعي يُعد الذكاء الاصطناعي (AI) من المجالات الرائدة والمطلوبة بكثرة في سوق العمل اليوم، لاسيما بعد أن أصبحت تطبيقاته في متناول الجميع وبات يستخدم في العديد من المجالات فتعلمك لهذا المجال الرائد يعزز قدراتك كمبرمج ويساعد على تعزيز تطبيقاتك بقدرات الذكاء الاصطناعي القوية. يتفرع الذكاء الاصطناعي لعدة مجالات من أبرزها تعلم الآلة والتعلم العميق التي تُمكّن الحواسيب من التعلم من البيانات وتحسين أدائها بمرور الوقت دون الحاجة لبرمجة تقليدية. كي تتعلم برمجة الذكاء الاصطناعي تحتاج لامتلاك فهم جيد للبرمجة وتحليل البيانات ويمكنك استخدام لغات برمجة متعددة في هذا المجال أشهرها لغة البرمجة بايثون التي توفر الكثير من المكتبات والأطر المساعدة مثل تنسرفلو TensorFlow وكيراس Keras وبايتورش PyTorch وباندا Pandas. إذا كنت مهتمًا بتعلم هذا الاختصاص القوي فستوفر لك دورة الذكاء الاصطناعي من أكاديمية حسوب التي تحتوي على 58 ساعدة تدريبية ممتدة على ثمانية مسارات تدريبية شاملة كل ما تحتاج إليه للبدء بتطوير تطبيقات ذكاء اصطناعي قوية واكتساب مهارة في تحليل البيانات من الصفر ودون الحاجة لامتلاك معرفة مسبقة. اللغات والتقنيات المستخدمة في برمجة الذكاء الاصطناعي هي Python و MongoDB وPymongo و TensorFlow و Keras و Pandas والنماذج اللغوية الكبيرة LLMs المختلفة. تطوير الأنظمة المدمجة الأنظمة المدمجة هي أنظمة حاسوبية شبيهة بالحاسوب ولكنها لا تملك كل ميزات الحاسوب الذي تراه أمامك الآن. بعبارة أخرى، النظام المدمج هو حاسوب صغير مبرمج لأداء مهام محددة فقط ومدمج ضمن الجهاز أو البيئة المراد استخدامه فيها. أنت الآن محاط بالكثير من الأنظمة المدمجة الآن مثل جهاز مقياس مستوى المياه وجهاز التحكم بالتلفاز وجهاز إنذار الحريق وأجهزة المراقبة …إلخ. حتى إشارات المرور وتنظيم السير وألعاب الأطفال الآلية تصنَّف على أنها أنظمة مدمجة. هل سمعت أيضًا بمصطلح "إنترنت الأشياء"؟ إنترنت الأشياء هو نظام مدمج متصل بالإنترنت. نعم، بهذه البساطة! لابد الآن أن يتبادر إلى ذهنك الساعات والثلاجات والغسالات الذكية وطائرات الدرون وأنظمة المراقبة عن بعد وأنظمة البيوت الذكية، إذ كلها أمثلة على إنترنت الأشياء. كيفية برمجة الأنظمة المدمجة أشهر وأكثر لغة برمجة تستعمَل في برمجة الأنظمة المدمجة وإنترنت الأشياء هي لغة C (أي لغة سي) وكل اللغات المشتقة منها (مثل لغة أردوينو C). تُستعمَل لغة C++ كثيرًا في هذا المجال، إذ تعدُّ لغة ذات مستوى أعلى من لغة C لدعمها للبرمجة كائنية التوجه. أضف إلى ذلك أنه بدأ حديثًا استعمال لغة بايثون في برمجة تطبيقات الأنظمة المدمجة مع أنها لم ترتبط تقليديًّا بهذا المجال سابقًا. صحيح أنَّ لغة بايثون ليست بقوة لغة C و C++ في هذا المجال إلا أنها تستمد ميزاتها وفعاليتها من المكتبات الهائلة المتوافرة فيها. بعيدًا عن C وبايثون، تستعمل في مجال الأنظمة المدمجة أيضًا لغات أخرى تنضوي ضمن "لغات توصيف العتاد" (Hardware Description Languages)؛ لغتي VHDL و Verilog هما من أشهر لغات توصيف العتاد المستعملة في هذا المجال. تُستعمَل مثل هذه اللغات في برمجة "مصفوفة البوابات المنطقية القابلة للبرمجة" (FPGA أي Field Programmable Gate Array). أخيرًا، قد تجد بعض المراجع تشرح برمجة الأنظمة المدمجة بلغة أخرى تدعى "لغة التجميع" (Assembly Language) التي تصنف من اللغات منخفضة المستوى. يتطلب تعلم البرمجة باستخدام هذه اللغة فهمًا واسعًا بمعمارية وحدة التحكم المركزية والمعالج بالمجمل لأنها أقرب لغة يفهمها الحاسوب. الانتقال إلى هذه اللغة قد يكون في مستويات متقدمة من تعلمك لبرمجة الأنظمة المدمجة وتطبيقات إنترنت الأشياء. من ميزات البرمجة بهذه اللغة هي التحكم الواسع بالعتاد والمعالج الذي لا توفره لغات أخرى. يقال أن هذه اللغة صعبة بعض الشيء ومعقدة، ولكن لا أرى ذلك! قد يكون سبب قول ذلك هو أن لغة التجميع هي لغة منخفضة المستوى وأقرب شيء إلى لغة الآلة ولا يستطيع من يلقي نظرة على شيفرة مكتوبة فيها فهمها مطلقًا إن لم يعرفها. تطوير تطبيقات سطح المكتب مجال تطوير تطبيقات سطح المكتب كالمحيط الواسع؛ إن لم تملك بوصلة وتعرف إلى أين تريد الاتجاه، ستضيع فيه حتمًا. هنالك الكثير من أنظمة التشغيل أشهرها - وأكثرها سيطرةً على السوق حاليًا - هي: نظام التشغيل ويندوز، ولينكس، وماك (macOS)، ويملك كل نظام تشغيل تطبيقات مكتبية خاصة به. لذلك، يجب عليك أولًا -قبل الدخول إلى سوق برمجة تطبيقات سطح المكتب- تحديد نظام التشغيل المستهدف. أي يجب الإجابة على السؤال التالي: هل يستهدف تطبيقك نظام تشغيل محدد، أم تريد لتطبيقك أن يعمل على عدة أنظمة تشغيل في آن واحد؟! بعد تحديد نظام التشغيل المستهدف، اطلع على اللغات المفضل استعمالها في ذلك النظام لبرمجة تطبيقاته؛ فعلى سبيل المثال، اللغات C و C++ و C# و VB.NET هي الأكثر استعمالًا في برمجة تطبيقات نظام التشغيل ويندوز، واللغات C و C++ و Bash هي الأكثر استعمالًا في برمجة تطبيقات توزيعات نظام التشغيل لينكس. أمَّا نظام الشغيل ماك، فينفرد باستعمال لغة Objective-C. حسنًا، دعني أخبرك الحقيقة، كل لغة برمجة عامية الغرض يمكن استعمالها في برمجة التطبيقات، إذ أشهر اللغات التي تُدرَّس أكاديميًّا في هذا المجال هي لغة جافا (Java). لا يخفى على القارئ دخول لغة بايثون بقوة على هذا المجال نظرًا لامتلاكها الكثير من المكتبات الرائعة وسهولة صياغتها. دخلت مؤخرًا لغة جافاسكريبت على سوق برمجة تطبيقات سطح المكتب عبر إطار العمل Electron (إلكترون)، إذ توظف في هذا المجال تقنيات تطوير الويب (HTML و CSS و JavaScript …إلخ.). بدأ هذا الإطار ينتشر كالنار في الهشيم مما دفع شركات كبيرة لتطوير تطبيقات سطح المكتب الخاصة بها باستعمال هذا الإطار ومنها شركة Slack التي استعملت هذا الإطار لتطوير تطبيقها المكتبي. أعلم أنك الآن تشعر بالضياع من كثرة لغات البرمجة والتقنيات المستعملة في هذا المجال؛ معك حق، فقد أخبرتك بذلك منذ قليل. دخول هذا السوق يحتاج منك تحديد هدفك منه بالضبط. هل لديك فكرة تطبيق وتريد إنشاءه والربح منه؟ هل تريد العمل لدى شركة محددة؟ ما هي مواصفات التطبيق الذي تريد إنشاءه أو تريد العمل على تطويره؟ كل ذلك يلعب دورًا في تحديد لغة البرمجة الأنسب لك لتعلمها. في النهاية، إن تعلمت أساسيات البرمجة وأتقنت العمل على لغة برمجية محددة، سيسهل عليك الانتقال إلى لغة برمجة أخرى، إذ أغلب لغات البرمجة تشبه بعضها بعضًا من ناحية المفهوم والمضمون وتختلف بعض الشيء من ناحية الصياغة والشكل. لذلك، اطمئن من هذه الناحية. كيفية اختيار لغة البرمجة التي تناسبك يمكنك اختيار لغة البرمجة اعتمادًا على المجال الذي تحب العمل فيه، سألخص لك مسار التعلم لمختلف مجالات العمل: العمل كمطور ويب full-stack: يعني ذلك تعلم تطوير واجهات المستخدم أو الواجهات الأمامية، وتطوير الواجهات الخلفية. يمكن التخصص بمجال واحد من هذين المجالين فقط، إذ يُطلَب كثيرًا في سوق العمل مبرمجين متخصصين في واجهات المستخدم أو الواجهات الخلفية. العمل كمطور تطبيقات للهواتف المحمولة: يمكنك تعلم برمجة تطبيقات أندرويد أو iOS كلًا على حدة، أو استعمال تقنيات مثل كوردوفا لتطوير لكلا النظامين معًا. العمل كمطور تطبيقات سطح المكتب: يمكنك البدء بالتخصص في تطوير تطبيقات مكتبية لنظام تشغيل محدَّد (مثل نظام التشغيل ويندوز أو لينكس) عبر تعلم لغة البرمجة المستعملة في ذاك المجال (كما أشرنا إلى ذلك في قسم تطوير تطبيقات سطح المكتب)؛ خيار آخر هو تعلم اللغات والتقنيات التي تمكنك من تطوير تطبيقات عابرة للمنصات (تعمل على عدة أنظمة تشغيل) مثل استعمال إطار العمل Electron. العمل كمطور للأنظمة المدمجة والأنظمة الذكية: لغة C هي أساس هذا المجال، سواءً كنتَ تتعامل مع المتحكمات مباشرةً، أو تتعامل مع شريحة مثل أردوينو (والتي تمتلك لغةً مشتقةً من C). يساعدك هذا الفيديو على معرفة المعايير التي من خلالها ستتمكن من اختيار لغة البرمجة التي تتناسب مع تطلعاتك وأهدافك المستقبلية. نصائح لتعلم البرمجة مشوار تعلم البرمجة من الصفر طويل وشائق، ولكنه جميل ومسلٍ بذات الوقت، قد تصاب بالإحباط في بداية طريقك لكثرة الأمور التي عليك الإلمام بها، لذا جهزت إليك النصائح الآتية من تجربتي في البرمجة: حدد هدفك من تعلم لغة البرمجة وسوق العمل الذي تريد دخوله واجعله واقعيًا. بدون هدف، أبشرك بأنك ستتخلى عن فكرة تعلم البرمجة بعد حين. انتبه إلى أن يكون هدفك واقعيًا وقابلًا للقياس والتجزيء على مراحل. بدون ذلك، ستفشل من أول عقبة وتترك تعلم البرمجة. أعرف نفسك جيدًا ونقاط قوتك وضعفك. كلنا لديه نقاط قوة وضعف، ولكن المفلح من عمل على ترميم وتحسين نقاط ضعفه في المجال الذي يرغب بتعلمه. رشح دورة واحدة وكتابًا واحدًا وابدأ بقراءة الكتاب ومتابعة الدورة تدريجيًّا ثم انتقل بعد الانتهاء إلى دورة أخرى وكتاب آخر، إذ سيجنبك ذلك التشتت بين الدورات الكثيرة والكتب العديدة. الشيء الذي أفعله قبل بداية تعلم شيء جديد هو ترشيح قائمة من عدة كتب ودورات ثم ترتيب هذه الكتب والدورات بحسب جودتها ومدى بساطتها وتعقيدها. أرقم الكتب والدورات وأبدأ بالخيار الأول منها. أحدد الوقت التقريبي الذي يأخذه كل خيار لدراسته وأجدول الخيارات البقية على رزنامتي الخاصة. لا تأخذ العلم إلا ممن تثق بعلمه، فالكثير من المبتدئين يحاولون مساعدة غيرهم وقد يضعون معلومات مغلوطة دون قصد. طبق ما تعلمته مباشرة، وأنشئ أي شيء من كل أمر جديد تتعلمه حتى لو كان رسمة بسيطة أو شيفرة من عدة أسطر فقط. فرحة إنجاز شيء مما تعلمته تدفعك لتعلم المزيد والاستمرار في طلب العلم. نظم وقتك بورقة وقلم، حدد بداية كل أسبوع خطةً لسائره والتزم بتنفيذها. أخبر أصدقائك أن لديك التزامات وأمور مهمة عليك إنجازها. خصص وقتًا للاستراحة بالطبع ولا تنسَ نصيبك منها. في نهاية كل أسبوع، وازن مدى الإنجاز الذي حققته ومدى تطبيق الخطة التي وضعها وحاول أن تصل النسبة إلى 100%. أنصحك بقراءة ومتابعة استراتيجيات تنظيم الوقت ورفع الإنتاجية. تمرس على حل المشكلات وتحدى نفسك باستمرار وتابع المسابقات البرمجية واشترك بها إن استطعت، أنصحك بقراءة مقالة حل المشكلات وأهميتها في احتراف البرمجة بعد هذه المقالة. لا تنسَ أن تكافئ نفسك في كل مرة تنهي فيها كتابًا أو تكمل العمل على مشروع. لا تنسَ حظك من الاستراحة، لأن طريق البرمجة قد يكون له بداية ولكن النهاية بعيدة ومتعبة -مثله مثل أي مجال آخر-. في النهاية أرجو لك كل التوفيق في مشوارك البرمجي. وأرجو منك أن تشاركنا تجربتك في تعلم البرمجة، لعل غيرك يستفيد منها. اقرأ أيضًا كيف تتعلم البرمجة المدخل الشامل إلى تعلم علوم الحاسوب المرجع الشامل إلى تعلم لغة بايثون تعرف على أعلى تخصصات البرمجة أجرا تعلم لغة HTML قواعد البرمجة ما هي فوائد تعلم البرمجة؟ أسهل لغات البرمجة أهمية البرمجة2 نقاط
-
هل أنت مهتم بتعلم البرمجة والتطوير لكنك تتساءل ما هي مدة تعلم البرمجة؟ وكم أحتاج من الوقت لتعلم لغة برمجة معينة، وهل سأستغرق وقتًا طويلًا لتعلمها والعمل بها؟ وفي مقال اليوم نحاول أن نجيبك على كل هذه الأسئلة ونقدم بعض النصائح المفيدة التي تساعدك على التقدم بشكل أسرع. في الواقع قد تختلف الإجابة على هذا السؤال اعتمادًا على عدة عوامل مثل الوقت الذي يمكنك توفيره لدراسة البرمجة يوميًا ومدى استيعابك، وهل تبدأ من الصفر أم لديك بعض المعلومات المسبقة عن البرمجة، وما هو المجال أو التخصص الذي ترغب بتعلمه كم يستغرق تعلم البرمجة دعنا نتفق أنه ليس من السهل تحديد جواب دقيق لهذا السؤال، جرب مثلًا أن تكتب في محرك البحث جوجل "كم يستغرق تعلم البرمجة" ستفاجئ بالحصول على إجابات متفاوتة بشكل كبير على هذا السؤال قد تتراوح من ثلاثة أشهر إلى خمس سنوات! يعزى هذا التفاوت الكبير في الإجابات إلى وجود عوامل عديدة تلعب دورًا في تحديد مدة تعلم البرمجة، بعض هذه العوامل فردية وتختلف من شخص لآخر فهناك أشخاص يتعلمون المفاهيم الجديدة أسرع من غيرهم، وبعضهم لديه متسع من الوقت يمكن تخصيصه يوميًا في دراسة البرمجة أكثر من غيره، وبعضها الآخر عوامل تتعلق بطبيعة لغة البرمجة التي تنوي تعلمها أو التخصص البرمجي التي تود تعلمه وهل ترغب بالتعلم لدخول سوق العمل أم لمجرد اكتساب مهارات شخصية فكل هذه العوامل تؤثر على وتيرة تعلمك وزمن تحقيق أهدافك. سنناقش في الفقرات التالية بعض العوامل المهمة التي تؤثر على مدة تعلم البرمجة ونوضح كم يستغرق تعلم البرمجة بناء على كل حالة من الحالات لنساعدك على تحديد الوقت المطلوب بشكل تقريبي بحسب حالتك. العوامل التي تؤثر على مدة تعلم البرمجة الخبرة المسبقة صعوبة لغة البرمجة المستوى الذي تطمح للوصول إليه التخصص أو المجال البرمجي أسلوب التعلم جودة مصادر التعلم الخبرة المسبقة فإذا كنت تنوي تعلم البرمجة من الصفر ولم يكن لديك أي خلفية تقنية وليس لديك أدنى فكرة عن مبادئ التعامل مع الحاسوب ومفهوم الخوارزميات وأسس التفكير المنطقي وحل المشكلات وعن أي لغة برمجة سابقة فسيستغرق تعلم البرمجة وقتًا طويلاً منك نظرًا لوجود مجموعة واسعة من المفاهيم التي عليك تعلمها وقد يستغرق الأمر عدة أشهر حتى تتمكن من كتابة استيعاب أساسيات البرمجة وفهم مفردات لغة البرمجة التي تستخدمها وكتابة برنامج الأول بها بنفسك وتنفيذه بشكل صحيح. من الضروري أن لا تشعر بالإحباط في بدايات تعلم البرمجة وتأسيس نفسك بها فالبدايات دومًا هي الأصعب فإذا تخطيت هذه المرحلة فستتمكن من التقدم بتعلم البرمجة بوتيرة أسرع وسيسهل عليك الانتقال لتعلم أي لغة برمجة أخرى. صعوبة لغة البرمجة أحد العوامل المهمة في زمن تعلم البرمجة هو اللغة التي تختارها فهناك العديد من لغات البرمجة المختلفة مثل لغة بايثون Python. وجافا Java و C++ و PHP وغيرها الكثير وبعض هذه اللغات سهل التعلم وبعضها الآخر أكثر صعوبة ويستغرق مدة تعلم أطول فتعلم لغة برمجة سهلة نسبيًا يستغرق حوالي أربعة إلى ستة أشهر وستحتاج لوقت أكبر إذا كنت تتعلم لغة برمجة صعبة. لذا عندما تقرر تعلم البرمجة فمن الأفضل أن تبحث عن لغة لها منحنى تعلم "Learning Curve" سهل وغير حاد أو معقد، ومنحنى التعلم هو طريقة بيانية للتعبير عن صعوبة تعلم الشخص لموضوع خلال فترة زمنية معينة ويعبر عن سرعة التقدم والخبرات المكتسبة في هذا الموضوع مع مرور الوقت. على سبيل المثال تملك لغة بايثون Python منحنى تعليمي أسهل من لغة جافا Java بسبب تعتبر لغة تركيبتها التي تشبه إلى حد كبير اللغة الإنجليزية وقواعدها السهلة، لهذا السبب فإن مدة تعلم لغة البايثون ستكون أقصر من مدة تعلم لغة جافا وتقدر المدة الوسطية لتعلم أساسيات بايثون بخمس إلى عشر أسابيع في حين تصل مدة تعلم جافا من ستة أشهر إلى 18 شهرًا، ويمكنك مطالعة المزيد من المعلومات حول لغات البرمجة التي يفضل أن تبدأ بها تعلم البرمجة من خلال مقال أسهل لغات البرمجة. المستوى الذي تطمح للوصول إليه إذا كنت تقصد عند سؤالك ما المدة التي أحتاجها لتعلم البرمجة أن تتعلم أساسيات البرمجة وتتعرف على طريقة أسلوب كتابة الشيفرات والتعليمات وتعريف المتغيرات وأنواع البيانات، والحلقات والشروط والدوال البرمجية …إلخ. لمجرد اكتساب مهارة تنمي تفكيرك المنطقي والتحليلي وتوسع مداركك وتمكنك من كتابة برامج حاسوبية لحل مشكلات بسيطة أو أتمتة مهامك اليومية المتكررة فهذا الأمر لن يتطلب منك سوى ثلاثة إلى ستة أشهر فقط لتعلم البرمجة بأي لغة كانت. لكن هذه المدة لن تكون كافية لك لاحتراف البرمجة ودخول سوق العمل فهذا الأمر قد يتطلب منك حوالي سنة أو أكثر للعمل على بناء برامج معقدة وتطبيقات احترافية متكاملة تتعامل مع مشكلات فعلية وتنبي من خلالها معرض أعمال جيد يعزز فرصتك في الحصول على عمل مناسب وإذا كنت تحتاج علم لغة برمجة سهلة نسبيًا يستغرق حوالي أربعة إلى ستة أشهر. التخصص أو المجال البرمجي إن مجالات البرمجة كثيرة ومتنوعة مثل تطوير الويب وبرمجة المواقع وبرمجة الألعاب والذكاء الاصطناعي وعلوم البيانات والأمن السيبراني وغيرها الكثير وبتطلب كل تخصص برمجي مجموعة مهارات مختلفة عن الآخر فكلما زادت المهارات المطلوبة وزاد تعقيدها، كلما زاد الوقت الذي تحتاجه لتعلمها. على سبيل المثال، تبلغ مدة تعلم برمجة المواقع حوالي ستة أشهر إلى عام واحد، في حين يحتاج تعلم أساسيات الذكاء الاصطناعي مدة أطول قد تصل لسنة أو أكثر لأنه مجال أكثر تعقيدًا ويتطلب وجود أساس جيد في الرياضيات والإحصاء ويحتج بعض الوقت للتآلف مع مصطلحاته والتعرف على تخصصاته المختلفة وتعلم خوارزميات التعلم الآلي ولغات برمجة الذكاء الاصطناعي كما يحتاج للكثير من الممارسة لإتقانه. أسلوب تعلم البرمجة تختلف مدة تعلم البرمجة أيضًا بحسب الطريقة التي تختارها للتعلم، فإذا اخترت دارسة البرمجة عن طريق التعليم الأكاديمي والتسجيل في إحدى الجامعات فستستغرق وقتًا طويلًا لا يقل عن أربع أو خمس سنوات لأنك ستضطر على الالتزام بمنهج محدد. أما إذا اخترت التعلم الذاتي فستتمكن من توفير الكثير من الوقت وتقتصر اعلى لغات البرمجة والتقنيات التي تحتاج لتعلمها وبقدر ما تثابر وتبذل من جهد وتلتزم بخطة تعلم منظمة وساعات تعلم محددة يوميًا فستختصر من زمن تعلم البرمجة وتتمكن من دخول سوق العمل بسرعة أكبر. جودة مصادر التعلم إذا قررت تعلم البرمجة فستجد الكثير من مصادر التعلم المتنوعة من دروس ومقالات وكتب ومقاطع فيديو ودورات تدريبية وغيرها من المصادر التي تساعدك لكن هذه المصادر ليست على نفس المستوى من الجودة وقد يصعب عليك كمبتدئ تمييز الغث من السمين وتحديد الترتيب الصحيح لمواضيع التعلم والتركيز على تعلم ما يهمك. كما أن تعلمك من مصادر مشتتة وبطريقة عبثية فتارة تشاهد مقطع فيديو عن موضوع ما وتارة تقرأ مقالة عن موضوع آخر وتارة تبدأ بقراءة كتاب ثم تمل منه سريعًا سيزيد بلا شك من مدة تعلم البرمجة وتحقيق هدفك وتذكر أن المشتت لا يصل. فإذا كنت تتعلم البرمجة دون خطة منهجية واضحة وتريد اختصار وقت تعلم البرمجة فمن الأفضل أن تستثمر وقتك وجهدك وتسجل في دورة تدريبية المنهجية التي تقدم لك المعرفة التي تحتاجها بالتسلسل الصحيح وتوضح لك الأدوات والتقنيات التي تحتاجها وتقيم مهاراتك بشكل معياري وتساعدك على تنفيذ تطبيقات عملية تعزز ما تعلمته وتزيد فرصتك في الحصول على وظائف برمجة مناسبة لمهاراتك. ستجد في أكاديمية حسوب الكثير من الدورات التعليمية عالية الجودة بمختلف التخصصات توفر لك إمكانية التعلم من الصفر دون الحاجة لأي معرفة مسبقة وتساعدك على التعلم بطريقة منظمة وتقرن التعليم النظري بالتطبيق العملي والأهم أنها توفر لك مدربين خبراء يرشدونك ويدعمونك طوال رحلتك التعليمية ويساعدونك في الإجابة على أي تساؤل وحل أي مشكلة تواجهك ويسعدون بتقديم المشورة التي تحتاجها حتى تحترف البرمجة وتجد فرصة العمل المناسبة. هل فات الوقت على تعلّم البرمجة كثيرًا ما نسمع أسئلة من قبيل أنا مهتم بالبرمجة والتقنية وأرغب في تعلمها لأعمل في وظيفة أفضل وذات مردود مادي أعلى أو أرغب بتعلم البرمجة لمواكبة التطور التقني وتعزيز مهارات حل المشكلات لدي ولكن عمري (كذا سنة) فهل فات الوقت على تعلم البرمجة؟ دعني أخبرك بأنه مهما كان عمرك فإن الأوان لم يفت على تعلم البرمجة فالعمر لا يشكل أي عائق في التعلم سواء في ظل وفرة الموارد المتاحة لمساعدتك. وقد يستغرق تعلم البرمجة مدة أطول مع التقدم في السن لكنك قادر على تقليل هذه المدة في حال خصصت وقتًا أطول وأسست نفسك بشكل جيد بالاعتماد على مصادر عالية الجودة وامتلكت الإرادة والرغبة الحقيقية للتعلم فهذا كفيل بجعلك تتغلب على أي صعوبات أو عوائق تواجهها. نصائح لتقليل مدة تعلم البرمجة حدد هدفك من تعلم البرمجة والتخصص البرمجي المناسب لك، وضع خطة لتعلم التقنيات واللغات التي تفيدك في هذا التخصص. عزز مهارة حل المشكلات والتفكير المنطقي قبل البدء بالبرمجة فهي مهارات أساسية تقلل مدة تعلم البرمجة. ركز على تعلم لغة برمجة سهلة وتناسب المبتدئين فهذا يسهل عليك استيعاب المفاهيم البرمجية بوقت أقل ويسهل عليك الانتقال لتعلم أي لغة برمجة أخرى. لا تستسلم بسرعة، فتعلم أي شيء جديد سيكون صعبًا في البداية ويستغرق بعض الوقت لفهم الأساسيات ومع الوقت والخبرة تصبح الأمور أسهل. اعتمد على مصدر جيد لتعلم البرمجة ولا تشتت نفسك بكثرة المصادر. احرص على التطبيق العملي لما تتعلمه من مفاهيم فهذا يعزز مهاراتك ويساعدك على بناء معرض أعمال يثبت خبرتك. تعلم مع أصدقاء لديهم نفس اهتمامك وضع معهم هدفًا مشترك وخطة للتعلم وتعاون معهم في حل المشكلات وتعلم المفاهيم الجديدة فهذا يجعل التعلم أكثر متعة ويحفزك على المواصلة. الخلاصة نأمل أن يكون هذا المقال قد ساعدك في تحديد كم يستغرق تعلم البرمجة ومعرفة أهم العوامل التي تلعب دورًا في الإجابة على هذا السؤال بشكل تقريبي، وكما وضحنا في المقال لا يوجد جواب واحد يناسب الجميع على هذا السؤال لكن بإمكانك اختصار مدة تعلم البرمجة ودخول سوق العمل بسرعة بالمثابرة والجهد. وتذكر في الختام أن البرمجة تحتاج منك إلى الاستمرار في التعلم وتطوير نفسك حتى بعد الاحتراف ودخول سوق العمل، فالتقنيات تتغير وتتطور باستمرار ومن الضروري مواكبة هذه التغييرات وتطبيقها في عملك للحفاظ على مكانتك التنافسية وتلبية متطلبات سوق العمل المتجددة. اقرأ أيضًا دليل شامل لتعلم البرمجة قواعد البرمجة ببساطة للمبتدئين اكتشف ما هي البرمجة وما أهمية تعلمها برمجة الحاسوب للمبتدئين لماذا يجب أن تعلم طفلك البرمجة؟2 نقاط
-
ربما تقرأ أو تشاهد يوميًا تقارير عن توقع في انخفاض أو ارتفاع مؤشرات أسواق المال أو تغيرات متوقعة في أسعار شراء بعض المنتجات على أساس شهري أو سنوي، أو حتى نجاح أو إخفاق لقاح لأحد الأمراض في مرحلة التجربة السريرية؛ فما مصدر هذه المعلومات؟ لا تُعد هذه الظواهر ظواهر علمية طبيعية أي لا تنتنج عن قوانين ثابتة يمكن تطبيقها في كل زمان ومكان، بل تأتي في معظم الأحيان نتيجة تطبيق طرق استدلالية أو تحليلية أو إحصائية على كم مترابط أو غير مترابط من البيانات المتوفرة عن هذه الظاهرة أو تلك، وتكون نتيجتها مجموعة محددة من المعلومات التي توصِّف هذه الظاهرة بلغة واضحة يمكن البناء عليها لاحقًا لاتخاذ قرار أو توثيق حادثة. يطلق على العلم القائم خلف هذه الطرق الاستدلالية والتحليلية والإحصائية اسم علم البيانات Data science أو العلم القائم على البيانات Data-driven science ويُعدّ حاليًا من أكثر العلوم التي تدفع عجلة التقدم التقني في مجالات تعلم الآلة والبحث عبر الإنترنت والتعرف الآلي على الصوت والصور والنقل والصحة واستكشاف المخاطر وغيرها الكثير. وأصبح هذا المجال أحد أهم المجالات في العالم الرقمي ولا عجب في ذلك فهو العلم الذي يهتم باستخراج القيمة الكامنة في البيانات التي تعد اليوم أهم أصول الشركات حتى أنها أصبحت تسمى النفط الجديد أو الذهب الجديد. وستكتشف في مقال اليوم كل خبايا هذا العلم وتتعرف على فوائده وأهم أدواته وتقنياته وحتى التعرف على سوق العمل فيه ومصادر تعلمه. ما هو علم البيانات Data Science؟ يُعد علم البيانات حقلًا لتطبيق المهارات التحليلية والوسائل العلمية لاستخلاص معلومات ذات قيمة وأهمية انطلاقًا من بيانات خام raw data أو بيانات مهيكلة أو غير مهيكلة وذلك لاتخاذ القرارات أو وضع خطط استراتيجية في مجال عمل معين أو تحليل الأنظمة أو بناء تصورات مسبقة عن سلوكها. تزداد أهمية علم البيانات يومًا بعد يوم، إذ تساعد الإضاءات التي يقدمها علم البيانات على زيادة كفاءة العمل وتحديد فرص عمل جديدة وزيادة فعالية النشاطات التجارية، وتضيف ميزات تنافسية قوية للأعمال التي تعتمد على علم البيانات موازنة بغيرها وفي مختلف المجالات والأصعدة. يتألف علم البيانات من ثلاث تخصصات أو مجالات متقاطعة مع بعضها البعض وهي كالتالي: علم البيانات هندسة البيانات تحليل البيانات قد تتداخل المهام في كل مجال من هذه المجالات، إلا أن المسؤوليات الأساسية لكل منها تختلف في مكان العمل وفيما يلي نوضح أهم الفروقات بين كل تخصص منها. علم البيانات علم البيانات هو المجال الذي يهتم بتطبيق تقنيات التحليلات المتقدمة والمبادئ العلمية لاستخراج معلومات قيمة من البيانات بهدف اتخاذ القرارات التجارية الأفضل والتخطيط الاستراتيجي . يعمل في مجال علم البيانات أشخاص ذوو كفاءة عالية يملكون معرفة أساسية في تخصص تحليل البيانات وهندسة البيانات فهم يتشابهون في عملهم مع مهندسي البيانات إلا أنهم أصحاب اليد العليا في جميع الأنشطة المتعلقة بالبيانات فعندما يتعلق الأمر باتخاذ القرارات المتعلقة بالأعمال يتمتع عالم البيانات بكفاءة أعلى وهو الذي يتخذ القرار النهائي بشأن العمل. يجب أن يمتلك المتخصص في هذا المجال مهارات تحليلية وبرمجية متقدمة تمكنه من حل مشكلات العمل بشكل كامل بالاعتماد على البيانات واستخراج المعلومات القيِّمة والمفيدة منها لتطوير الأعمال مستخدمًا برمجيات متقدمة من خلال الاعتماد على أفضل المنظومات والخوارزميات لحل المسائل المتعلقة بتنظيم البيانات واستخلاص المعلومات منها. يمكن أن نختصر ماهية علم البيانات بالنقاط التالية: طرح الأسئلة الصحيحة عن المسألة المدروسة وتحليل البيانات الخام. نمذجة البيانات باستخدام خوارزميات متنوعة ومتقدمة وعالية الكفاءة. تصوير البيانات لفهمها من منظور أوضح. فهم البيانات المتاحة لاتخاذ قرارات أفضل أو الوصول إلى نتيجة نهائية. باختصار علم البيانات هو العلم المسؤول عن استخراج معلومات مفيدة من بيانات مبعثرة ولا قيمة لها بشكلها الخام بعد تنظيفها وتصحيح أخطائها وإزالة القيم المكررة منها ومعالجة القيم المفقودة منها وهي تشبه عملية استخراج شيء مفيد من النفايات. علم هندسة البيانات Data Engineering هندسة البيانات هي العمود الفقري لعلم البيانات وتتضمن عملية تصميم وبناء أنظمة تسمح للأشخاص بالتنقيب عن البيانات الأولية وجمعها وتنظيفها من مصادر وتنسيقات متعددة وتخزينها واستعادتها ونقلها تمهيدًا لتحليلها واستخراج معلومات مفيدة منها. كما تهتم هندسة البيانات بالبيانات الوصفية التي تُعد بيانات تصف بيانات أخرى. وتأتي أهمية هندسة البيانات من ضرورة تهيئة البيانات التي جرى جمعها حتى تُخزن ويسهل استعادتها عند الطلب فلا معنى لأي تحليل أو تفسير للبيانات ما لم تجري أرشفة النتائج وتخزينها في منظومة معلوماتية يسهل التعامل معها لاتخاذ القرار. تتضمن هندسة البيانات المهام التالية: استخراج البيانات من مصادر مختلفة Data extraction معالجة البيانات Data processing وتحويل البيانات Data transformation والتي تتضمن تنظيف البيانات data cleaning ومعالجة القيم الفارغة وفصل القيم المجمَّعة وإزالة القيم الخطأ أو تحويلها إلى قيم صحيحة موحدة ومتناسقة. تحميل البيانات Data load وتخزين البيانات الناتجة في المصدر النهائي وعادة تكون قاعدة بيانات مخصصة للتحليل Database analysis تنفيذ العمليات الثلاث ETL التي تعني استخراج Extract وتحويل Transfer وتحميل Load والتي تعني مجتمعة عملية تنقل البيانات من قاعدة بيانات واحدة، أو قواعد بيانات متعددة، أو مصادر أخرى إلى مستودع موحد عادة ما يكون مستودع بيانات. فنظرًا لكون تحليل البيانات أمرًا صعبًا لأن البيانات تجمع بواسطة تقنيات مختلفة ويتم تخزينها بهياكل وتنسيقات مختلفة لكن الأدوات المستخدمة لتحليل البيانات تتطلب أن تكون كافة مجموعات البيانات مخزنة بنفس الهيكلية! وهنا يأتي دور هندسة البيانات في توحيد مجموعات البيانات وإنشاء البنية التحتية التي تزود أعضاء فريق البيانات ببيانات عالية الجودة ليعملوا عليها ويفهموها ويعثروا من خلالها على إجابات لأسئلتهم، وهم مسؤولون كذلك عن تصميم وصيانة هذه البنية التحتية. على سبيل المثال يمكن أن تجمع الشركات العديد من البيانات حول عملائها ومن مصادر متنوعة مثل معلومات حول الفواتير من برنامج مخصص لإدارة المبيعات ومعلومات عن الشحن من برنامج إدارة شركات الشحن والخدمات اللوجستية ومعلومات عن دعم العملاء من برنامج دعم العملاء ومراقبة مواقع التواصل الاجتماعي للحصول على المحتوى الذي يهتم به العملاء ويتفاعلون معه ومعلوماتهم الديموغرافية وأوقات نشاطهم …إلخ. توفر هذه البيانات الكثير من المعطيات للعميل لكن الحصول عليها من مصادر مختلفة وبتنسيقات متنوعة يجعل فهمها والحصول على الإجابات التي نريدها منها أمرًا صعبًا للغاية ويستهلك الكثير من الوقت والجهد لذا لا يمكننا أن نُعوِّل على إدراكنا البشري في هذا الأمر. لهذا السبب يقوم مهندسو البيانات بإعداد هذه البيانات وتنسيقها وتنظيمها وتخزينها في مستودعات بيانات مناسبة مصممة لمعالجة الاستعلامات بسرعة تضمن الأداء المناسب، وبعدها يقدمون هذه البيانات إلى مستهلكي البيانات النهائية مثل محللي البيانات الذين لن يتمكنوا من الوصول إلى البيانات وتحليلها واستخلاص النتائج والقرارات الصائبة منها بدون البنية التحتية التي ينشؤها لهم مهندسو البيانات. عمومًا، كان هذا تعريفًا مختصرًا بتخصص هندسة البيانات، وقد توسعنا بالحديث عنه في مقال منفصل بعنوان الدليل الشامل إلى هندسة البيانات Data Engineering فارجع إليه للاستزادة. علم تحليل البيانات Data analysis تحليل البيانات هو المجال المسؤول عن معالجة البيانات لاستخراج أو استخلاص معلومات مفيدة من شأنها أن تساعد الشركات والمنظمات في حل مشكلة ما أو الكشف عن فرصة ما لتطوير العمل وعرض هذه المعلومات والنتائج التي تم الحصول عليها بأفضل طريقة لصانعي القرار في العمل حتى يتمكنوا من اتخاذ قرارات من شأنها تطوير العمل نحو الأفضل. على سبيل المثال قد يطلب من محلل البيانات تقسيم العملاء بناءً على سلوك الشراء لديهم لتحديد العملاء الذين يجب أن يتم استهدافهم في الحملات التسويقية وإرسال العروض الأنسب المخصصة لكل منهم بناءً على سلوكه الشرائي أو يطلب منه تحديد التكلفة الأفضل للمنتجات للحفاظ على القوة الشرائية كي لا تنخفض عن مستويات السنوات السابقة. ومن أهم المهام التي يعنى بها تحليل البيانات ما يلي: جمع البيانات الخام من مصادر متعددة وتنظيمها. التأكد من جودة البيانات وتنظيفها وتحويلها عند الضرورة. نمذجة البيانات في تنسيقات محددة. التمثيل الرسومي للبيانات أو تصوير البيانات Data visualization ويقصد به عرض البيانات بطريقة مرئية كي يتمكن المتابع من فهم المحتوى الذي تقدمه ويستوعب الرؤى التي استخلصت من هذه البيانات. إيجاد إجابات وحلول لأي مشكلات أو استفسارات في مجال العمل من خلال تحليل البيانات ذات الصلة. الاستفادة من الإحصائيات الوصفية في تلخيص ووصف خصائص مجموعة البيانات. للقيام بهذه المهام يحتاج المختص في تحليل البيانات لامتلاك مجموعة من المهارات الفنية وأهمها الإلمام الجيد بلغة الاستعلام الهيكلية SQL لاستخراج البيانات التي يحتاجها من قواعد البيانات العلاقية المختلفة وإتقان البرامج المخصصة مثل MS Excel و MS Access و Microsoft Power BI التي تساعد في تحليل هذه البيانات وإنشاء نماذج منها وإجراء العمليات الحسابية والإحصائية المختلفة عليها. كما يحتاج بالطبع لامتلاك معرفة جيدة بالإحصاء والتحليل الرياضي لإضافة المهارات في التنظيم والتخطيط والاهتمام بأدق التفاصيل كي يتمكن من إدارة ومعالجة طلبات العمل بكفاءة، كما تعد مهارات التواصل مفيدة جدًا أيضًا لمحللي البيانات لأنهم بحاجة إلى التعبير عن نتائجهم وتفسيرها بوضوح لأرباب العمل. كان هذا تعريفًا مختصر بمجال تحليل البيانات، وقد توسعنا بالحديث عنه في مقال منفصل بعنوان الدليل الشامل لتحليل البيانات Data Analysis فارجع إليه للاستزادة. الفرق بين علم البيانات والذكاء الاصطناعي يُعرّف الذكاء الاصطناعي Artificial Intelligence واختصارًا AI بأنه وسيلة لتزويد الآلات بسلوك يحاكي السلوك البشري كي تقارب تفكيرهم وتتصرف مثلهم وبالتالي فإن الجانب الأساسي من تقنية الذكاء الاصطناعي مرتبط بتعلم الآلة وتعلم الآلة المعمّق. يلخص الجدول التالي الفرق بين علم البيانات والذكاء الاصطناعي من نواحي عدة كي نستطيع إدراك أوجه الشبه والاختلاف: وجه الموازنة علم البيانات الذكاء الاصطناعي الأساسيات علم البيانات هو دورة عمليات مفصلة تتضمن التحضير الأولي للبيانات وتحليلها ثم تصويرها واتخاذ القرار الذكاء الاصطناعي هو إنجاز نموذج قادر على التوقع بهدف التنبؤ بأحداث مستقبلية. الأهداف التعرف على الأنماط المطلوب إيجادها ضمن البيانات الخام للمشروع قيد الدراسة أتمتة العمليات ووضع بيانات التصرف الذاتي ضمن الوحدة البرمجية المدروسة. نوع البيانات التي يعمل عليها يعمل علم البيانات على أنواع مختلفة من البيانات مثل البيانات الخام والبيانات المهيكلة وغير المهيكلة. يستخدم الذكاء الاصطناعي أنواع معيارية من البيانات على شكل متجهات vectors وأنواع مدمجة أخرى من البيانات التقنيات المستخدمة يستخدم التقنيات الرياضية والإحصائية وخوارزميات تعلم الآلة وأدوات تحليل البيانات وتصويرها. يستخدم بشكل أساسي خوارزميات تعلم الآلة وتعلم الآلة المعمّق. المعرفة المكتسبة تُستخدم المعرفة التي يوفرها علم البيانات في إيجاد الأنماط والسلوكيات في البيانات. تصب المعرفة التي يوفرها الذكاء الاصطناعي في تزويد الوحدات البرمجية بشكل من أشكال التصرف الذاتي. أمثلة عن الأدوات المستخدمة ++R, Python, MATLAB,C Tensor flow, sci-kit-learn, Kaffee متى يُستخدم يُستخدم علم البيانات عندما تقتضي الضرورة استخدام حسابات رياضية سريعة أو تحليل بيانات استطلاعي أو تحليل توقعي predective analysis. لا بد في هذه الحالات من تحديد الأنماط والسلوكيات من خلال البيانات المتاحة ويتطلب ذلك معرفة بالإحصاء الرياضي. يُستخدم الذكاء الاصطناعي عندما تقتضي الضرورة التخلص من عمل ضروري متكرر. لا بد في هذه الحالات من تقييم مخاطر الانتقال إلى الذكاء الاصطناعي وسرعة اتخاذ القرار ودقة في التنفيذ بعيدًا عن المشاعر البشرية والانحياز. أمثلة عن الاستخدام تحسين العمليات واكتشاف سلوكيات العملاء والتحليل المالي وغيرها الكثير. الروبوتات وبرمجيات المحادثة الآلية والألعاب عبر الإنترنت وأنظمة المساعدة الصوتية. هنالك مسارات أخرى بدأت تتبلور تعكس التأثير الكبير لعلم البيانات على الذكاء الاصطناعي مع تزايد الاندفاع نحو ما يُعرف بالذكاء الاصطناعي القابل للتوضيح explainable AI والذي يقدم معلومات تساعد المستخدمين على فهم كيفية عمل نماذج تعلم الآلة ومقدار الثقة التي ينبغي أن يولوها لنتائج عمل هذه الوحدات عند اتخاذ القرارات. بالإضافة إلى دور علم البيانات في صياغة مبادئ تصميم الذكاء الاصطناعي المسؤول responsible AI principles للتأكد من عدالة جميع التقنيات المستخدمة وضمان عدم تحيزها وشفافيتها. مكونات علم البيانات ينبثق علم البيانات من مجموعة من المكوّنات أو العلوم ولا بد من استعراضها حتى تتوضح أبعاد هذا العلم: الإحصاء Statistics الرياضيات Mathematics البرمجة وعلوم الحاسوب Programming and Computer Science أساسيات الرياضيات لتتعلم علم البيانات لا بد من إتقان المفاهيم الأساسية في الرياضيات التي تعد الجزء الأكثر حيوية في مجال علوم البيانات، فهي الفضاء الذي تُدرس ضمنه الكميات والبنى والعلاقات ذات الصلة بالظاهرة المدروسة. إذ يُعد علم الرياضيات اللغة التي توصِّف الظواهر العلمية وتوفر الأدوات الضمنية التي يستخدمها علم البيانات مثل عمليات الاستقراء والتحليل والإحصاء والتفاضل والتكامل وغيرها. الإحصاء الرياضي يُعد الإحصاء الرياضي Statistics من أهم مكوّنات علم البيانات لأنه الوسيلة الأنسب لجمع وتحليل البيانات العددية مهما كانت كميتها كبيرة واستخلاص الأفكار منها. يتعامل هذا العلم مع مجموعات منفصلة من البيانات أو مجموعات مستمرة منها محاولًا تطبيق وسائل رياضية لدراسة ميل هذه البيانات للتقارب أو التباعد والمنحى الذي تأخذه في هذا السلوك ثم تضع أطرًا لتعريف وتصنيف هذه الوسائل. فمن منا لم يسمع في مرحلة ما من تحصيله الدراسي كلمة متوسط حسابي أو انحراف معياري أو منوال مثلًا، فهذه المصطلحات ما هي إلّا مقاييس لابتعاد قيم مجموعة من البيانات عن قيمها الوسطى. البرمجة وعلوم الحاسوب يأتي الحمل الأكبر في علم البيانات على البرمجة وتخصص علوم الحاسوب كي تتمكن من كتابة وتنقيح وتعديل الشيفرات التي تجمع وتحلل وتهيكل البيانات، حيث يجب على من يريد التخصص في علم البيانات تعلم إحدى لغات البرمجة والمكتبات البرمجية التي تدعم الوظائف الإحصائية والرياضية وبرمجيات التحليل وإيجاد علاقات الترابط وغيرها، إضافة لقواعد البيانات المسؤولة بشكل أساسي عن تخزين البيانات وتنظيمها واسترجاعها. كما يعد تعلم الآلة Machine learning أحد التقنيات المتقدمة التي تلعب في الآونة الأخيرة دورًا حيويًا في علم البيانات فمن خلاله يمكننا من الحصول على تنبؤات وقرارات أفضل دون الحاجة للتدخل البشري مما يساعد علماء البيانات في أداء مهامهم والحصول على حلول لمشكلات العمل بطريقة أسرع وأكثر ذكاء مقارنة بالاعتماد على التقنيات الإحصائية التقليدية. وإذا كنت مهتمًا بتعلم أسس علوم الحاسوب والتخصص في مجال علوم البيانات واكتساب خبرة عملية فيه بأسرع الطرق يمكنك مطالعة مقال أساسيات علوم الحاسوب فهو بمثابة دليل شامل يعرفك على اختصاص علوم الحاسب وأهم فوائده وتطبيقاته. دورة علوم الحاسوب دورة تدريبية متكاملة تضعك على بوابة الاحتراف في تعلم أساسيات البرمجة وعلوم الحاسوب اشترك الآن أهمية علم البيانات لم تكن البيانات المتوفرة حول مختلف المجالات خلال العقد الأول من هذه الألفية وما قبلها -وخاصة بشكلها الرقمي- ذات أحجام كبيرة جدًا، وكان من السهل تخزينها في هياكل مخصصة مثل الجداول الإلكترونية وقواعد البيانات العلاقيّة ومن ثم التعامل معها من خلال أدوات مختلفة بكل سهولة ويسر. فقد جمعت البيانات ما قبل الحقبة الرقمية بأساليب يدوية مرهقة بالاعتماد على الأشخاص والأوراق والجداول ولم تكن بيانات شاملة، بل كانت تقتصر على ما هو ضروري للجهة التي تحتاج هذه البيانات سواء أكانت حكومية أو سواها. مع التحول إلى الرقمنة، أصبحت عملية الحصول على البيانات وتصنيفها أسهل وأيسر وظهرت أنواع جديدة من قواعد البيانات التي تسهل التعامل مع هذه البيانات، لكن كما أشرنا بقيت ضمن حدود السيطرة. لكن الكم الهائل جدًا من البيانات التي تنتج يوميًا عن كل فرد قد وصلت وفق بعض الأبحاث إلى 1.7 ميغا بايت في الثانية عام 2020 وقد تصل إلى أضعاف هذا الرقم في لحظة كتابة هذه الأسطر. فانطلاقًا من البيانات البسيطة التي يسجلها الجوال عن مستخدميه، وبيانات التصفح واستخدام الحاسوب، وبيانات نشاطك على مختلف مواقع التواصل الاجتماعي وعمليات التسجيل والشراء أو أي نشاط على مختلف المواقع قد تُسجل وتؤرشف لغايات خاصة بمشغلي تلك المواقع فتأمل عندها الكميات الكبيرة من البيانات التي ستظهر حتى حركة مؤشر الفأرة على شاشة متصفح مسجلة وتستعملها المواقع عبر أدوات تعقب وتحليل مختلفة مثل تتبع الأقسام التي زرتها والروابط والمنتجات التي أبديت اهتمامُا بها وذلك لتحليل سلوكك وبالتالي تقديم تجربة أفضل لك. ولا ننسى تطور البرامج السحابية التي مكنت المؤسسات من تتبع أحجام ضخمة من بيانات الأعمال في الوقت الفعلي وتوفر مليارات من أجهزة إنترنت الأشياء IoT حول العالم التي تجمع كل لحظة كمًا ضخمًا من البيانات عن كل تحركاتنا، لذا يتوقع أن يكون هناك 175 زيتابايت من البيانات في عالم البيانات العالمي بحلول عام 2025 وللعلم فإن زيتابايت يساوي 1000 بايت للأس 7 وبعبارة أخرى فإن زيتابايت واحد يحتوي على 21 صفرًا ولهذا السبب نحن نعيش بالفعل حقبة انفجار البيانات الضخمة Big Data Explosion ونحتاج لطريقة تمكننا من معالجة هذا الكم الجنوني من البيانات! إن معالجة هذا الكم الهائل من البيانات هي مهمة صعبة جدًا على أي مؤسسة أو جهة، لهذا ظهرت الحاجة الماسة إلى أدوات وتقنيات فعالة لمعالجة وتحليل تلك البيانات وأشخاص مؤهلين قادرين على التعامل معها وبدأ علم البيانات بالتبلور ليكون مزيجًا من عدة علوم تتكامل لإنجاز ما يلي: تجميع البيانات الخام وإعدادها للمعالجة أو التحليل النوعي. تحويل هذه الكميات الكبيرة من البيانات الخام وغير المهيكلة إلى معلومات ذات قيمة. تقديم البيانات وعرضها بصريًا لتوضيح الاستراتيجيات أو القرارات المبنية على نتائج تحليل تلك البيانات. استخلاص الأفكار والرؤى من البيانات المحللة باستخدام تقنيات الذكاء الاصطناعي وخوارزميات تعلم الآلة. وضع استراتيجيات تطوير للأعمال انطلاقًا من نتائج التحليل والدراسة. وضع توقعات صحيحة أو قريبة من الصحة في مختلف المجالات مثل استطلاعات الرأي والانتخابات وحجوزات السفر واستكشاف حالات الغش والدراسات العلمية والاجتماعية وغيرها. لم يكن علم البيانات منذ عقد مضى ولا حتى العاملين في هذا المجال منتشرًا في سوق العمل، لكن الشعبية الكبيرة حاليًا لهذه الفئة من الخبراء تعكس طريقة تفكير الأعمال بالبيانات الضخمة. فلا يمكن بعد الآن تجاهل الكميات الهائلة من البيانات الخام التي أضحت بالنسبة للكثير من الشركات بمثابة منجم ذهب افتراضي طالما أن هناك خبراء متحمسين وطموحين ودقيقي الملاحظة قادرين على التنقيب فيها ورؤية ما لا يراه غيرهم. مجالات علم البيانات يلعب علم البيانات اليوم دورًا فعالًا في جميع جوانب الحياة التجارية والطبية والحكومية …إلخ، ويجد المختصون في المجالات المختلفة كل يوم تطبيقًا جديدًا لعلم البيانات بما يعزز العمل الذي يشرفون عليه ويحقق مكاسب على جميع الأصعدة، لكننا سنقف تاليًا على أبرز المجالات التي شاع استخدام علم البيانات فيها. التعرف على الصور وتمييز الكلام عندما تحمّل صورة على فيسبوك ثم ترى اقتراحات للإشارة إلى أصدقائك في الصورة، فإن ما يجري فعلًا أن موقع فيسبوك قد استخدم خوارزمية تمييز الصور تلقائيًا وقد تعرف على الأشخاص في هذه الصورة. إن هذه الخوارزمية هي جزء من علم البيانات. وكذلك الأمر عندما تقول "Ok Google" ليستجيب هاتفك الذكي ويستعد للأوامر الصوتية، فإن علم البيانات هو السبب في ظهور خوارزمية التعرف على الكلام التي استخدمها التطبيق توًا. محركات البحث عبر الإنترنت هل لاحظت كيف تقترح لك محركات البحث الشهيرة مثل جوجل وياهو وبينج ما هو قريب من نتيجة بحثك؟ هل لاحظت السرعة في عرض النتائج والتحسن المستمر في دقة نتيجة البحث؟ يعود الفضل في ذلك إلى علم البيانات وخوارزمياته التي تجعل تجربة البحث عبر الانترنت أكثر سرعة وفعالية ورضًى للمستخدم. العلوم الطبيعية تُستنبط معظم المعايير العلمية المتعلقة بالظواهر الطبيعية من كم البيانات الهائل الناتج عن مراقبة هذه الظواهر على مدى طويل من الزمن كالمناخ والبيئة والفضاء، إذ ترسل المسابر ملايين البايتات يوميًا إلى مراكز الأبحاث لتحليلها واستقراء النتائج وبالطبع لن يكون من السهل فهم هذه البيانات والربط بينها دون استخدام خوارزميات علم البيانات وطرائقه. عالم الألعاب سواء الألعاب الرياضية الحقيقية كدراسة وتحليل حركات لاعبي كرة القدم وحتى منصات الألعاب الرقمية في تعزيز تجربة اللاعبين. تعتمد الشركات التي ترعى هذه المواضيع على تحليل نتائج البيانات المأخوذة من كم هائل من المباريات ومن تجارب مئات الآلاف الذين يمارسون ألعاب الفيديو عبر الإنترنت. لقد حسَّن استخدام علم البيانات وتقنياته أداء الكثير من شركات الألعاب. النقل إن الهدف الرئيسي لاستخدام علم البيانات في عالم النقل هو الوصول إلى المركبات ذاتية القيادة التي يسعى مصمموها إلى تقليل الخطأ البشري إلى أدنى مستوى وتقليل عدد الحوادث المرورية وضبط معدلات التلوث بعوادم الوقود. إضافة إلى ذلك، يساعد علم البيانات في تحليل حركة المرور واكتشاف الازدحامات والاختناقات المرورية وإرسال إشعارات للسائقين لسلوك طريق آخر مثلًا لوجود ازدحام في الطريق الذي يسير عليه وتحليل الحوادث المرورية واتخاذ القرارات. الرعاية الصحية لعلم البيانات دور بارز في مجال الرعاية الصحية لما يؤمنه من مساهمة في تشخيص الحالات الطبية وتخطيط العلاج والبحث الطبي ويوفر نتائج حاسمة وتوقعات تقترب نسبة الخطأ فيها من الصفر وخاصة في مجالات الكشف عن الأورام وابتكار الأدوية وتحليل الصور الطبية. أنظمة التوصية بالمنتجات تعتمد معظم الشركات مثل غوغل وأمازون ونيتفليكس على علم البيانات الذي يقدم تكنولوجيا مفيدة جدًا في تحسين تجربة مستخدمي هذه الشركات من خلال التوصية بمنتجات هذه الشركات لمستخدميها من معرفة ميولهم وسلوكياتهم أو ما يعرف بالتزكية المخصصة. فعندما تبحث عن شيء ما ثم تجد اقتراحات لأشياء مشابهة لاحقًا فهي نتيجة تطبيق خوارزميات علم البيانات. اكتشاف المخاطر تواجه الشركات المالية مخاطر تتعلق بقضايا التزوير وخسارة رأس المال، لكن بوجود علم البيانات ستقل هذه الأخطار إلى مستويات منخفضة. إذ تستفيد شركات المال من علماء البيانات في دراسة البيانات المالية للاستثمارات المطروحة وإدارة المخاطر المالية واكتشاف المعاملات الاحتيالية وتقييم مخاطر الخسارة أو الإفلاس مما يرفع ثقة العملاء بأداء هذه الشركات، كما يساعد علم البيانات أنظمة تقنية المعلومات في منع الهجمات الإلكترونية ومنع التهديدات الأمنية المختلفة. ومن مجالات هذا العلم الأخرى مساعدة الشركات التجارية على إنشاء حملات تسويقية أقوى وإعلانات مستهدفة أكثر دقة لزيادة المبيعات والأرباح، ومنع حدوث أعطال المعدات في الأماكن الصناعية، ويبرز استخدام علم البيانات المجال الأكاديمية لمراقبة أداء الطلاب وتحسينه للأفضل وغير ذلك الكثير مما لا يتسع المقال لذكره. وقلما تجد اليوم مجالًا لا يساهم علم البيانات الحديث في تحسينه وتطويره نحو الأفضل. دورة حياة مشروع علم البيانات تمر دورة علم البيانات بالمراحل التالية: الاستكشاف إعداد البيانات تخطيط النماذج بناء النماذج التحضير للعمل إيصال النتائج الاستكشاف وهي أولى مراحل هذه الدورة وتبدأ بطرح الأسئلة الصحيحة عن الظاهرة المدروسة. فلا بد قبل أن تبدأ أي مشروع متعلق بعلم البيانات أن تحدد المتطلبات الاساسية لهذا المشروع وأولوياته وميزانيته. لا بد في هذه المرحلة من تحديد كل متطلبات المشروع كعدد العاملين فيه والتقنيات المستخدمة والزمن اللازم لإنجازه والبيانات التي سيجري العمل عليها والغاية منها، وبالتالي سنتمكن من وضع إطار أولي لحل المشكلة التي كانت سببًا في إطلاق المشروع. إعداد البيانات نحتاج في هذه المرحلة إلى إنجاز المهام التالية: تصحيح البيانات وتنظيفها Data cleaning اختزال البيانات وتقليل حجمها Data Reduction تكامل البيانات Data integration نقل البيانات Data transformation بعد إنجاز هذه المراحل الأربعة تصبح البيانات جاهزة لعمليات أخرى. التخطيط لبناء النماذج نحتاج في هذه المرحلة إلى تحديد النماذج المختلفة والتقنيات اللازمة لإيجاد العلاقات والروابط بين متغيرات الدخل. وتجري عادة عملية تحليل بيانات استطلاعي Exploratory data analytics -تختصر إلى EDA- باستخدام الدوال والصيغ الإحصائية ثم أدوات تصوير البيانات لفهم الروابط بين المتغيرات ومن ثم فهم ما ترشدنا إليه تلك البيانات. من أكثر الأدوات شيوعًا في إنجاز هذه المرحلة نجد: SQL Analysis Services R SAS Python بناء النماذج تبدأ في هذه المرحلة عملية بناء النماذج. إذ يجري خلال هذه المرحلة إنشاء مجموعات من البيانات لأغراض التمرين والاختبار لتساعد في تطبيق تقنيات مثل التجميع والتصنيف والربط على البيانات المتوفرة لوضع نماذج عن سلوكها. إليك بعض أدوات بناء النماذج الأكثر شيوعا: SAS Enterprise Miner: عبارة عن إضافة تتكامل مع قواعد بيانات أو جداول (مثل إكسيل) لبناء نماذج تحليلية تعطي توقعات عن البيانات الموجودة وفقًا لمسار التحليل الذي تتبعه. WEKA: وهي مجموعة من خوارزميات لغة الآلة كتبت بلغة جافا للتعامل مع مهام التنقيب عن البيانات. SPSS Modeler: برنامج من شركة IBM لتنفيذ مهام التنقيب عن البيانات وتمثيلها بيانيًا وفهمها واتخاذ القرارات بناء عليها. MATLAB: بيئة عمل رياضية وبرمجية متكاملة لمختلف الأغراض الحسابية والتحليلية وتصوير البيانات وبناء خوارزميات تعلم الآلة وتطبيقها. تحضير المشروع للعمل تُسلم في هذه المرحلة معظم التقارير النهائية عن المشروع إلى جانب الشيفرة والمستندات التقنية. تقدم هذه المرحلة نظرة شاملة عن أداء المشروع على صعيد محدود قبل أن يجري نشر نتائجه كاملةً. إيصال النتائج النهائية يتحقق فريق العمل في هذه المرحلة من أن الهدف الذي وضع للمشروع في مرحلة الاستكشاف قد أنجز أم لا، ثم تُسلم بعد ذلك المعلومات التي تمكن الفريق من حيازتها عن طريق النماذج التي بنيت ومن ثم إيصال النتائج النهائية إلى فريق الأعمال الذي طلب الشروع بالعمل. التخصص في مجال علم البيانات رأينا سابقًا كيف ظهرت الحاجة الملحة لعلم البيانات كتخصص قائم ومستقل بذاته للتنقيب عن المعرفة بين أكوام البيانات الخام ويُعتقد وفقًا لعدة استطلاعات رأي بأنّ هذا التخصص سيكون الأكثر طلبًا في السوق خلال هذا العقد. وبما أن الطلب شديد على هذا المجال فهناك نقص كبير في اليد العاملة فيه عربيًا وعالميًا، لذا أمامك فرصة سانحة لممارسته دون الحاجة لوجود شهادة أكاديمية متخصصة فيه إذ التركيز حاليًا على الخبرة نظرًا لنقص اليد العاملة فيه. أي كل ما تحتاجه هو الخبرة الأساسية في البرمجة والإحصاء الرياضي ورغبة في تعلم هذا المجال وتحصيل كل ما يكسبك الخبرة العملية فيه من دورات ومخيمات تدريبية تؤهلك لدخول سوق العمل والحصول على فرصة مميزة لدى الكثير من الشركات والمنظمات التي ستتهافت على تدريبك وتوظيفك لديها. لهذا السبب لا بد من الاطلاع على التخصصات التي يمكنك العمل بها في حال رغبت في التخصص في مجال علوم البيانات. الوظائف التي يتضمنها علم البيانات حتى تختار التخصص الذي تراه مناسبًا لخبراتك وميولك، سنفرد هذه الفقرة للتفصيل في مجموعة من أهم الوظائف والأدوار الوظيفية المرتبطة بالبيانات والمتطلبات الأساسية لكل وظيفة: عالم بيانات Data scientist محلل بيانات Data analyst مهندس بيانات Data engineer معماري بيانات Data architect مطوّر تصوير بيانات Data Visualization Developer خبير في تعلم الآلة Machine Learning expert لنكتشف المزيد حول كل دور من هذه الأدوار وأهم التقنيات والمهام المنوطة به. محلل البيانات هو شخص خبير ينقّب في أكوام البيانات الخام باحثًا عن نماذج وأنماط علاقات تربط بينها. يعمل بعد ذلك على عرض نتائج ما توصل له بما يساعد على اتخاذ قرار أو حل مشكلة. ما المهارات التي يجب أن يتقنها محلل البيانات؟ معرفة جيدة في الرياضيات. معرفة جيدة في التنقيب ضمن البيانات Data mining. معرفة أساسيات علم الإحصاء Statistic. أن يكون مطلعًا على بعض لغات البرمجة والأدوات البرمجية المستخدمة في علم البيانات مثل: Python MATLAB SQL Hive R JS SAS SPSS وغيرها مهندس بيانات وهو الشخص الذي يعمل مع كميات كبيرة من البيانات ويكون مسؤلًا عن بناء وصيانة بنى مناسبة لهذه البيانات وفقًا لمشروع علم البيانات الذي يعمل عليه. يعمل مهندس البيانات أيضًا على تصميم العمليات التي تتحكم بمجموعات البيانات وتُستخدم في نمذجة هذه المجموعات أو التنقيب فيها أو حيازة معلومات منها أو التحقق من سلامتها. ما المهارات التي يجب أن يتقنها مهندس البيانات؟ معرفة معمقة بتقنيات برمجية مثل: SQL MongoDB Cassandra HBase Apache Spark Hive MapReduce معرفة جيدة بلغات برمجة مثل Python, C/C++, Java, Perl. معماري بيانات وهو الشخص الذي يتصور ويصمم الأسلوب الذي تُنجز وفقه البنية التحتية المسؤولة عن تخزين وإدارة البيانات لأغراض التحليل سواء على صعيد العتاد الصلب أو الصعيد البرمجي. ما المهارات التي يجب أن يتقنها معماري البيانات؟ معرفة معمقة بقواعد تطوير البرمجيات والأنظمة. معرفة معمقة بالمعماريات المستخدمة في إنجاز قواعد البيانات. عالم بيانات عالم البيانات هو شخص خبير يعمل على تجميع وتحليل واستخلاص النتائج من كميات كبيرة من البيانات الخام أو المهيكلة أو غير المهيكلة. يجمع عمل عالم البيانات بين علوم الحواسب وخاصة برمجتها وعلم الإحصاء والرياضيات. يعمل عالم البيانات على تحليل ومعالجة ونمذجة البيانات ثم يفسر النتائج التي حصل عليها كي يُنشئ خطة عمل مناسبة للشركة أو المنظمة أو الجهة التي يعمل لديها. يُسخّر علماء البيانات قدراتهم ومهاراتهم في مختلف المجالات سواء التقنية منها أو الاجتماعية للبحث عن تفاصيل قد لا يراها ولا يفهمها سواهم في كم البيانات الهائل الذي يعملون عليه، إذ يتضمن عملهم عادة إيجاد ترابط منطقي بين بيانات غير مهيكلة أو خام تنتج عن مصادر مختلفة كالأجهزة الذكية وردود الأفعال على مواقع التواصل الاجتماعي ومحتوى رسائل البريد الإلكتروني وغيرها من المصادر التي يصعب ملاءمتها من قواعد البيانات المهيكلة. ما المهارات التي يجب أن يتقنها عالم البيانات؟ فهم معمق لعلم الإحصاء. معرفة جيدة في الرياضيات. مهارة في إحدى لغات البرمجة التالية أو أكثر Python R SAS SQL Hive Pig Apache spark MATLAB قدرة جيدة على تصوير البيانات Visualization. مهارات تواصل جيدة. دورة تطوير التطبيقات باستخدام لغة Python احترف تطوير التطبيقات مع أكاديمية حسوب والتحق بسوق العمل فور انتهائك من الدورة اشترك الآن مطور تصوير بيانات وهو شخص يعمل إلى جانب عالم البيانات لتمثيل البيانات بصريًا وتقديم عروض ومخططات تفصّل نتائج تحليل هذه البيانات بطريقة مرئية سهلة الفهم لإيصالها إلى من يستخدمها. ما المهارات التي يجب أن يتقنها مطور تصوير بيانات؟ مهارة في إحدى لغات البرمجة التالية أو أكثر: Python R SAS SQL Hive Pig Apache spark MATLAB قدرة تحليلية ممتازة. قدرة كبيرة على إيجاد الطرق الأمثل في تصوير البيانات. خبير في تعلم الآلة هو الشخص الذي يعمل مع مختلف خوارزميات تعلم الآلة التي تُستخدم في علم البيانات مثل خوارزميات الارتجاع أو الإنحدار Regression والتجميع clustering والتصنيف classification وشجرة القرار decision tree والغابة العشوائية random forest وغيرها. ما المهارات التي يجب أن يتقنها خبير تعلم الآلة؟ خبرة في أحد لغات البرمجة التالية أو أكثر: Python ++C R Java Hadoop فهم جيد للخوارزميات الكثيرة المستخدمة في علم البيانات وتعلم الآلة. مهارة تحليلية في حل المشاكل. معرفة جيدة في علمي الاحتمالات والإحصاء. مصادر تعلم علم البيانات هل أنت متحمس للتخصص في مجال علم البيانات وتعلمه بشكل ذاتي وبأقصر الطرق بعيدًا عن أروقة الجامعات ومناهجها المكثفة -بسنواتها الطويلة التي تمتد لأربع أو خمسة سنوات- لكنك لا تعرف من أين تبدأ؟ سنسلط في القسم الضوء على مصادر تعلم تخصص علم البيانات العربية لدخول سوق العمل، فكما أشرنا حاليًا السوق شره على المتخصصين ويركز على الخبرة والمشاريع العملية المنجزة ولا يتطلب شهادات جامعية حصرية. نفترض أنك أنهيت مراحل جيدة من التعليم الدراسي أو قد أنهيت المرحلة الثانوية أو تخصصت في أحد التخصصات الهندسية وبذلك تكون قد حصَّلت معرفة جيدة بأساسيات الرياضيات والإحصاء وحتى مواضيع متقدمة مثل التفاضل والتكامل (إن كنت قد اخترت التخصص العملي وليس الأدبي) وبذلك تكون قد قطعت شوطًا في تعلم هذا العمل، وعمومًا الأساسيات تكفي للبدء ويمكن لاحقًا التعمق في أي موضوع تحتاج إليه. بعدها يمكنك البدء بتعلم أساسيات علوم الحاسوب ولغات البرمجة المخصصة المستخدمة في علم البيانات وأهمها لغة بايثون و لغة R ولغة SQL فهي من أكثر اللغات المطلوبة والمخصصة للاستخدام مع البيانات. تؤمّن هذه اللغات قدرات وظيفية كبيرة في التواصل مع قواعد البيانات واستخلاص البيانات الخام وتحليلها وتنظيمها واستخلاص الرؤى وفقا للظاهرة المدروسة ومن ثم التقييم وإتخاذ القرار، وكل ذلك من خلال مجموعة واسعة من الخوارزميات التي توفرها هذه اللغات ضمنًا أو من خلال مكتبات متوافقة معها. من أهم المصادر العربية المتكاملة التي ننصحك بها كي تتعلم هذه التقنيات: كتاب ملاحظات للعاملين بلغة SQL 1.0.0 كتاب البرمجة بلغة بايثون الذي يشرح أساسيات لغة بايثون سلسلة تعلم لغة R التي تطلعك على كافة الأساسيات والمواضيع النظرية التي تحتاجها في هذه اللغات. سلسلة مقالات think stats التي توفر لك مجموعة مميزة من المقالات والدروس المتخصصة في تعليم الاحتمالات والإحصائيات لمبرمجي بايثون بأسلوب مبسط وسهل الفهم. وإذا كنت تفضل التعلم بإشراف مختصين يجيبونك على أي سؤال يخطر ببالك ويقرن التعليم النظري بالتطبيق العملي فأنصحك بالاطلاع على دورة أساسيات علوم الحاسب التي توفرها أكاديمية حسوب فهي كفيلة بأن تكسبك كافة الأسس التي تحتاجها لتعلم أسس البرمجة وقواعد البيانات، وكذلك دورة تطوير التطبيقات بلغة بايثون والتي تمكنك من تطوير طيف واسع من التطبيقات في مجالات منوعة من بينها تطبيقات عملية في تحليل البيانات تساعدك في التعرف على أبرز مكتبات بايثون المتخصصة في التعامل مع علم البيانات. إضافة إلى لغات البرمجة التي ذكرناها ستجد الكثير من المنصات والأدوات التي تدعم بشكل مباشر العمل مع البيانات الضخمة وتقدم مختلف الأدوات المساعدة في التحليل والتنظيم واتخاذ القرار والتي يمكنك تعلمها ومن أبرزها SAS و Spark و Hadoop و Azure و AWS. خاتمة ألقينا الضوء في هذا المقال على علم البيانات الذي يُتوقع أن يكون من أكثر الأعمال طلبًا خلال هذا العقد من الألفية نظرًا للحاجة الماسة للعمل ضمن كميات هائلة من البيانات الخام وضرورة الاستفادة منها في تطوير الأعمال على مختلف الأصعدة. كما تحدثنا عن المكونات والتخصصات التي يضمها ومجالات استخدامه وتطبيقه، كما تحدثنا عن دورة الحياة التي يمر بها أي مشروع يعتمد على علم البيانات. ومنعًا لتضارب الأفكار وضياع التسميات، فقد تحدثنا عن الفرق بين علم البيانات وتحليلها وكذلك الفرق بين علم البيانات والذكاء الاصطناعي. وهكذا نكون قد أحطنا بشكل مفصل أساسيات علم البيانات وتخصصاته ومجالاته المختلفة لمن يرغب فعليًا في امتهانه أو احتراف أحد اختصاصاته، ووضحنا المتطلبات الضرورية التي يحتاجها المتعلم حتى يبدأ رحلته في هذا المجال المهم والشيق والمجزي ماديًا والذي ينبئ بمستقبل واعد.2 نقاط
-
يُعتبر مبدأ المسؤوليّة الواحدة Single Responsibility Principle (أو اختصارًا SRP) المبدأ الأوّل من مبادئ التصميم SOLID، وهو مفيد بصورة خاصّة في التصميم كائنيّ التوجّه object-oriented design. يعتمد هذا المبدأ على تجزئة مكوّنات النظام البرمجي بحيث يكون لكلّ جزء منه مهمّة (مسؤوليّة) واحدة ووحيدة. ينص هذا المبدأ على ما يلي: لا يظهر من النص السابق أي إشارة مباشرة إلى المسؤوليّة الواحدة. لتوضيح الربط بين المسؤولية الواحدة وبين نص المبدأ السابق، لننظر إلى المثال التالي الذي يحوي صنفًا مكتوبًا بلغة ++C ويُستخدم للاتصال بخادوم قواعد بيانات MySQL. اسم هذا الصنف MySQL أيضًا، ويمتلك واجهة لتأسيس الاتصال مع خادوم MySQL وإغلاقه، وإرسال استعلامات SQL إلى الخادوم واستقبال ومعالجة النتائج: class MySQL { public: bool connect(); void disconnect(); bool executeQuery(std::string queryString); MySQLResult* getQueryResult(); }; من الواضح أنّ لهذا الصنف مهمّتان أساسيّتان، الأولى هي إدارة عملية الاتصال مع خادوم MySQL (فتح وإغلاق الاتصال) والثانية هي التواصل مع الخادوم في إجراء الاستعلامات واستقبال النتائج (تنفيذ استعلامات SQL). لو افترضنا الآن حدوث السيناريو التالي: أصبح خادوم MySQL يقبل الاتصالات المشفّرة فقط. حدثت بعض التغييرات ضمن الخادوم بحيث أنّه بدأ بالاستجابة بشكل مختلف لبعض الاستعلامات. سيؤدي ذلك بالطبع إلى حدوث تغييرين ضمن صنف MySQL السابق، أو بمعنى آخر، سيكون هناك سببان لتغيير الصنف MySQL. ويُعدّ هذا خرقًا لمبدأ المسؤولية الواحدة كما هو واضح. يُعتبر وضع أكثر من مهمّة قابلة للتغيير (من أجل سبب ما) لأحد الأصناف خطأً تصميميًّا. قد لا تبدو تلك مشكلةً في الوقت الحالي، ولكن أيّ نظام برمجي يتغيّر ويتطوّر. فما يبدو حلًّا مقبولًا في الوقت الحاضر، قد يُفضي إلى نتائج سيّئة في المستقبل. يمكن استخدام الحل التالي لمشكلتنا السابقة: class MySQLConnection { public: bool open(); /* former connect() */ void close(); /* former disconnect() */ }; class MySQLQuery { MySQLConnection* session; public: bool execute(std::string queryString); MySQLResult* getResult(); }; يبدو مبدأ المسؤوليّة الواحدة بسيطًا، ولكنّه في الحقيقة صعب التطبيق. والسبب في ذلك، هو أنّ وضع المسؤوليّات المتعدّدة لصنف ما معًا، هو أمر بديهي ومألوف بالنسبة إلينا، أمّا عملية الفصل والتجزئة إلى أصناف أصغر لكلٍّ منها مسؤوليّة واحدة، فقد لا تبدو جذّابةً أوّل الأمر. بالنسبة لي، عندما عدت وراجعت بعض تصميمات الأصناف القديمة لديّ، قلّما وجدت صنفًا من الممكن جعله يراعي هذا المبدأ. ولكن عندما أمعنت النظر والتفكير وجدت أنّ الفصل في المهام سيقلّل من تعقيد التصميم، وسيجعل الشيفرة أيسر للقراءة والفهم. بالمقابل، فإنّ تطبيق هذا المبدأ بشكل صارم، ليس فكرةً جيّدة. فعلى المرء أن يكون حكيمًا في تحديد متى يمكن تطبيق هذا المبدأ، وخصوصًا عندما يجد أنّ الملف الخاص بأحد أصنافه بات يحتوي على أكثر من 500 سطر من الشيفرة البرمجيّة! ترجمة -وبتصرّف- للمقال Single Responsibility Principle لصاحبه Radek Pazder.2 نقاط
-
يتضمن مجال تطوير الويب قسمين أساسين هما تطوير الواجهة الأمامية front-end (فرونت إند) وتطوير الواجهة الخلفية back-end (باك إند) وهما من المجالات الرائدة اليوم فجميع النشاطات التجارية والأشخاص يسعون للتواجد على شبكة الإنترنت ويحتاجون لمطوري ويب لإنشاء مدونات أو مواقع أو تطبيقات أو متاجر إلكترونية خاصة بهم. سنخصص مقال اليوم للحديث عن تطوير الواجهة الأمامية ونوضح كافة المفاهيم المرتبطة وكافة الخطوات والتقنيات التي تحتاجها لتتعلم كي تصبح مطور واجهات محترف فإذا كنت مهتمًا بهذا المجال لكنك لا تملك أدنى فكرة عن كتابة الشيفرات البرمجية أو إنشاء صفحات الويب ولا تعرف من أين تبدأ أنصحك بأن تقرأ المقال للنهاية. ما هو تطوير الواجهة الأمامية Front End Web Development؟ قبل أن نشرح تطوير الواجهة الأمامية front-end تحتاج لأن تعرف مراحل بناء أي موقع إلكتروني، فإنشاء أي موقع أو تطبيق يبدأ بتحديد فكرته وتوثيقها، بعدها ترسل هذه الفكرة إلى مصمم الواجهات الأمامية الذي يرسم واجهات الموقع وصفحاته كلها بمختلف تفاصيلها وحالتها، حيث تُراجع هذه الواجهات ثم ترسل إلى مطور الواجهات لتكويدها وبرمجتها وهنا تقسم العملية إلى برمجة واجهات أمامية وخلفية وتبرمج كل واجهة وتتفاعل الواجهتان مع بعضهما للحصول على المواقع المتكامل. فمطور الواجهة الأمامية front end web developer أو ما يعرف بمطور واجهات المستخدم user interface developer هو المبرمج المسؤول عن إنشاء كافة الأجزاء المرئية التي يراها المستخدم ويتفاعل معها عند زيارة مواقع وتطبيقات الويب وبرمجة كافة الواجهات ومكوناتها من أزرار وقوائم ونصوص ورسومات وصور ونماذج وغيرها وتحديد كيف سيبدو كل جزء من موقع الويب وكيف سيتفاعل المستخدم معه. الفرق بين تطوير الواجهة الأمامية front-end وتطوير الواجهة الخلفية back-end والتطوير الكامل Fullstack من الضروري أن تفهم أبرز الفروقات بين تطوير الواجهة الأمامية وتطوير الواجهة الخلفية والتطوير الكامل والتي تعكس في واقع الأمر تخصصات تطوير الويب أو بمعنى آخر الدور الذي يساهم به مطور الويب عند بناء المواقع والتطبيقات والتقنيات التي يستخدمها لأداء عمله، كما أنها تعبر عن مكان تشغيل الشيفرات البرمجية لهذه المواقع والتطبيقات. بدايةً يجب أن تعرف أن عرض موقع الويب على جهازك يتم دومًا في لغة HTML وهي لغة توصيفية يستخدمها مطورو الويب لإنشاء وعرض الصفحات، هناك عدة تقنيات يمكنك إنشاء المواقع من خلالها لكن مهما كانت التقنية المستخدمة فإن عرض الموقع لديك في نهاية المطاف سيكون بلغة HTML. الآن يمكن أن تحدث عملية عرض ملفات المواقع مباشرة على جهازك كما في حال المواقع البسيطة ذات المحتوى الثابت فهي تخزن على خادم الويب بالأساس بشكل ملفات HTML وترسل لك هذه الملفات مباشرة عند طلبها وتعرض لك كما هي على متصفحك. من ناحية أخرى قد تتطلب عملية عرض المواقع بعض المعالجة المسبقة التي تحدث على جانب خادم الويب أو يسمى الخادم البعيد مثل مواقع الويب الديناميكية التي لا تعرض نفس المحتوى لجميع المستخدمين وتتغير بناء على إدخالات المستخدم، فعندما ترسل طلبًا لعرض صفحة ما من موقع ديناميكي يقوم الخادم بمعالجة طلبك هذا وبعد الانتهاء ويجلب لك البيانات المطلوبة والعرض الأخير على جهازك يكون بشيفرة HTML. كل ما يتعلق بأمور عرض الموقع من جانب متصفح الويب أو يسمى طرف العميل client side يندرج تحت مجال تطوير الواجهة الأمامية للموقع، وكل ما يتعلق بأمور معالجة الموقع من طرف خادم الويب من معالجة البيانات وتخزينها وحفظها وإجراء عمليات عليها وغيرها يندرج تحت مجال تطوير الوجهة الخلفية للموقع ولكل منهما تقنياته وأدواته، على سبيل المثال عندما تسجل في موقع يطلب تاريخ ميلادك، تراه يعرضها لك أحيانًا بشكل عمر أي عدد وليس تاريخ، هذه المعالجة تُرسل عادة من طرف الخادم. ليس لزامًا عليك كمطور ويب تعلم تطوير الواجهة الأمامية أو الخلفية معًا بل يمكنك التخصص في إحداهما فقط، فإذا كنت تحب تنفيذ الجوانب المرئية لواجهات المستخدم وجعلها تعمل وفق التصميم المقترح سيناسبك تطوير الواجهة الأمامية أكثر، وإذا كنت تفضل حل المشاكل المنطقية والتعامل مع قواعد البيانات وواجهات برمجة التطبيقات والخوادم والخدمات السحابية فإن تطوير الواجهة الخلفية يناسبك. أما إذا كنت متحمسًا للقيام بكل ما سبق وكانت لديك القدرة لتعلم كافة التقنيات والمهارات اللازمة لتطوير الواجهة الأمامية وتطوير الواجهة الخلفية والقيام بالأمرين معًا عندها سيطلق عليك اسم المطور الكامل fullstack developer وستفتح أمامك الكثير من الفرص المجزية. وإذا كنت مهتمًا بمعرفة مزيد من التفاصيل حول مجالات تطوير الويب أنصح بمطالعة مقال المدخل الشامل لتعلم تطوير الويب وبرمجة المواقع ومقال دليلك الشامل إلى تطوير الواجهة الخلفية Backend. أهمية تطوير الواجهة الأمامية في سوق العمل إذا كنت مهتمًا بتطوير الويب فدعني أخبرك أن تبدأ به دون تردد فهو واحد من أكثر مجالات العمل نموًا مقارنة بباقي الوظائف فبحسب استبيان عام 2022 لموقع ستاك أوفر فلو الشهير الذي يضم آلاف خبراء البرمجة حول العالم فإن 25.96% من المشاركين في الاستبيان وعددهم 61,302 متخصصون في تطوير الواجهة الأمامية front-end، ويحتل هذا المجال المرتبة الثالثة بين أنواع المطورين بعد تطوير الواجهة الخلفية back-end والتطوير الكامل full-stack وهذا إن دلَّ على شيء فإنما يدل على مدى أهمية هذا المجال والطلب المرتفع عليه. أضف إلى ذلك فإن رواتب مطوري الواجهة الأمامية مرتفعة ومجزية ورغم كونها تتفاوت وتختلف حسب نوع الشركة ومقرها والمهارات المطلوبة للوظيفة ومستوى الخبرة إلا أن اكتسابك لمهارات عالية واحترافك لتطوير الواجهة الأمامية سيضمن لك الحصول على رواتب مرتفعة جدًا فمعظم جهات العمل تبحث عن مطور واجهة أمامية موهوب يمكنه إنشاء مواقع بتصاميم فريدة وبتجربة محسنة من شأنها زيادة رضا العملاء وجعل المواقع تتفوق على منافسيها. الجدير بالذكر أن أصعب جزء في مجال تطوير الواجهة الأمامية هو أنه متجدد باستمرار لذا يحتاج المطور للاطلاع بصورة دائمة على أحدث التقنيات في تطوير الويب ليتمكن من الاحتفاظ بالصدارة في سوق العمل لكنه مجال مجزٍ ويستحق الجهد. ما هي مهام مطور الواجهة الأمامية؟ مطور الواجهات الأمامية هو المسؤول بشكل عام عن إنشاء أجزاء المواقع والتطبيقات التي تعمل من جانب العميل (أو المتصفح)، وهذه المهمة تتضمن القيام بالعديد من المهام والتي تشمل: كتابة شيفرات HTML و CSS وجافا سكريبت لتنفيذ تصميم الموقع التي تكون عادة بشكل صور مصممة من قبل مصمم الواجهات الأمامية المسؤول عن تصميم واجهة المستخدم وتجربة المستخدم UI / UX بواسطة برامج متخصصة مثل فيجما Figma أو Sketch أو فوتوشوب. التواصل مع مطور الواجهة الخلفية المسؤول عن تحقيق وظائف الموقع والتأكد من توافق الواجهة الأمامية مع الواجهة الخلفية للموقع. تحسين أداء موقع الويب والتأكد من سرعة تحميله وتوفر تجربة مستخدم سهلة ومحسنة. التأكد من أن الموقع متوافق مع كافة متصفحات الويب ويعمل بالشكل الصحيح ومعالجة أي مشاكل توافق إن وجدت. التأكد من كون الموقع متجاوب ومتكيف مع كافة أحجام الشاشات بما في ذلك شاشات الهواتف الجوالة والأجهزة اللوحية وأجهزة الحاسوب. أهم أدوات تطوير الواجهة الأمامية إذا قررت التخصص في تطوير الواجهات الأمامية للويب ستجد الكثير من الخيارات المتاحة، فاللغات الثلاث الأساسية لأي مطور واجهة أمامية هي HTML و CSS وجافا سكريبت كما يمكنه إلى جانب ذلك استخدام العديد من اللغات وأطر العمل والمكتبات الأخرى الكثيرة التي تسهل عمله في تطوير الواجهات وفي الفقرات التالية سنسلط الضوء على أبرز هذه الأدوات. أهم لغات برمجة الواجهة الأمامية HTML CSS جافا سكريبت JavaScript تايب سكريبت TypeScript لنتناول بتفصيل أكثر كل لغة من هذه اللغات ودورها في تطوير الواجهات الأمامية للمواقع والتطبيقات. لغة HTML لغة HTML هي اختصار لعبارة HyperText Markup Language أي لغة ترميز النص التشعبي وهي اللغة الأساسية لتطوير الواجهة الأمامية للمواقع والتطبيقات وهي لغة وصفية أو لغة ترميز تصف البنية العامة لصفحات الويب ومحتوياتها من نصوص وأزرار وصور وقوائم باستخدام الوسوم وهي علامات موضوعة ضمن قوسي زاوية <> تحدد نوع المحتوى أو هيكليته على سبيل المثال لإنشاء صفحة ويب تتضمن عنوان وصورة ونص نكتب كود HTML التالي: <!DOCTYPE html> <html dir="rtl"> <head> <title>عنوان الصفحة</title> </head> <body> <h1>عنوان الصفحة</h1> <img id="myImage" src="html.png"> <p> HTML هي اختصار لـHyperText Markup Language أي لغة ترميز النص التشعبي وهي الأساسية لتطوير الواجهة الأمامية للمواقع والتطبيقات </p> </body> </html> احفظ الكود أعلاه في ملف نصي باسم index.html وقم بعرضه في متصفح الويب، عندها ستظهر الصفحة بالشكل التالي: للمزيد من المعلومات أنصح بمطالعة مقال تعلم لغة HTML الذي يشرح لك كافة الأساسيات التي تحتاجها للعمل مع هذه اللغة والاطلاع على توثيق HTML الشامل على موسوعة حسوب. لغة CSS لغة CSS هي اختصار لـ Cascading Style Sheets وهي لغة تصميم تستخدم لتحديد تنسيق صفحة الويب واختيار الألوان والخطوط والخلفيات وما إلى ذلك كما أنها تستخدم في جعل مواقع الويب متجاوبة مع مختلف الشاشات من خلال كتابة شيفرات تغير تنسيق وتخطيط العناصر بحسب أبعاد الشاشة. تستخدم لغة CSS قواعد تنسيق تستهدف عناصر HTML التي نريد تصميمها على سبيل المثال سنكتب التعليمات التالية لتنسيق صفحة الويب التي أنشأناها باستخدام HTML نكتب شيفرات CSS التالية ضمن الوسم <head>: <style> body { font-family: 'Cairo', sans-serif; background-color: #f2f2f2; margin: 0; padding: 0; } h1 { font-size: 36px; color: #333; text-align: center; margin: 50px 0; } img { display: block; margin: 0 auto; max-width: 100%; height: auto; } p { font-size: 18px; color: #666; text-align: center; margin: 50px; line-height: 1.5; } </style> تظهر الصفحة بعد إضافة التنسيقات كما يلي: وللمزيد من المعلومات يمكنك مطالعة سلسلة دروس CSS على أكاديمية حسوب إلى جانب توثيق CSS الشامل على موسوعة حسوب. لغة جافا سكريبت JavaScript بعد أن تقوم بتخطيط عناصر الواجهة الأمامية باستخدام HTML وتنسقها باستخدام CSS قد تحتاج إلى إضافة بعض التفاعلات إلى صفحاتك وهنا يأتي دور لغة جافا سكريبت JavaScript التي تعد واحدة من أشهر لغات البرمجة وأكثرها استخدامًا فهي تمكنك من تطوير كل من الواجهة الأمامية والخلفية. قد يكون تعلم جافا سكريبت هو الخطوة الأصعب لك كمطور واجهة أمامية لا سيما إن لم تكن تملك خبرة سابقة في البرمجة لكن بمجرد تعلمها ستتمكن من نقل الموقع إلى مستوى جديد وإضافة التأثيرات الديناميكية لصفحاته والاستجابة لتفاعل المستخدمين مع عناصره بدلًا من جعله يعرض معلومات ثابتة فقط. على سبيل المثال يمكنك كتابة شيفرات جافا سكريبت لعرض قائمة منسدلة أو إظهار رسالة منبثقة عند النقر فوق زر ما على الصفحة، أو إرسال طلب للتحقق من اسم المستخدم وكلمة المرور بعد النقر فوق زر تسجيل الدخول أو أي شكل من أشكال التفاعل مع الصفحة من طرف العميل. لنفرض أنك تحتاج لتكبير حجم صور الموقع قليلًا عند مرور مؤشر الفأرة فوقها، لن تتمكن من هذا إذا لم تكن تعرف جافا سكريبت وتدمجها مع HTML و CSS بدايةً عليك إضافة أكواد CSS التالية بعد الأكواد التي كتبتها في الخطوة السابقة: .zoom { transition: transform .2s; /* Add any other styles you want */ } .zoom:hover { transform: scale(1.5); /* Change the scale value to adjust the level of zoom */ } وبعدها عليك أن تضيف أكواد جافا سكريبت التالية قبل الوسم </body> ضمن كود HTML: const image = document.getElementById("myImage"); image.addEventListener("mouseover", function() { image.classList.add("zoom"); }); image.addEventListener("mouseout", function() { image.classList.remove("zoom"); }); تستمع شفرة جافا سكريبت هذه إلى حدث مرور مؤشر الفأرة فوق الصورة وتضيف تنسيق التكبير zoom إليه عند وقوع هذا الحدث. كما أنها تستمع إلى حدث خروج مؤشر الفأرة من عنصر الصورة وتزيل تنسيق التكبير منه عند وقوع هذا الحدث، وعند عرض الصفحة في المتصفح نحصل على التأثير التالي: للمزيد من التفاصيل أنصح بمطالعة مقال تعلم جافا سكريبت من الصفر حتى الاحتراف، كما توفر موسوعة حسوب توثيق لغة جافا سكريبت باللغة العربية يمكنك من خلالها تعلم كافة ما يتعلق بهذه اللغة. لغة TypeScript تعد لغة TypeScript لغة برمجة مفتوحة المصدر طورتها مايكروسوفت عام 2012 لتوفر ميزات إضافية تساعد على تطوير تطبيقات جافا سكريبت فهي تجعل تعليمات جافا سكريبت مفهومة بشكل أكبر وتوفر إمكانية تحديد أنواع المتغيرات كي تقلل من أخطاء الكود، وقد تزايدت شعبيتها بشكل كبير في الآونة الأخيرة لما توفره من ميزات لتحسين جودة التطبيقات وتسريع عملية التطوير . يمكنك مطالعة المزيد من المعلومات حول هذه اللغة وإمكانياتها من خلال مجموعة دروس TypeScript المتوفرة على أكاديمية حسوب أهم أطر عمل تطوير الواجهة الأمامية ظهرت أطر العمل frameworks والمكتبات البرمجية لتسهيل عمل المطور وتسريع عمله، لذا ستحتاج لاستخدامها في سوق العمل بدلًا من كتابة كل شيء بيدك من الصفر، وأطر عمل الواجهات الأمامية كثيرة ومن أبرزها: بوتستراب Bootstrap رياكت React أنغولار Angular فيو Vue جي كويري jQuery دعنا نلقي نظرة على كل تقنية منها ونشرح بمزيد من التفصيل دورها وأهميتها في تطوير الواجهة الأمامية. بوتستراب Bootstrap بوتستراب هو إطار ويب مجاني مفتوح المصدر مخصص للواجهة الأمامية فهو يستخدم لتصميم مواقع وتطبيقات ويب متجاوبة مع كافة أحجام الشاشات وذات مظهر احترافي بسرعة وسهولة فهو يحتوي على قوالب تصميم ومكونات جاهزة مكتوبة بلغة HTML ولغة CSS كما يوفر بالإضافة لذلك ملحقات تصميم مكتوبة بلغة جافا سكريبت. للاطلاع على المزيد من المعلومات يمكنك متابعة المقالات الدروس حول إطار عمل بوتستراب على أكاديمية حسوب إضافة لتوثيق بوتستراب الشامل على موسوعة حسوب. رياكت React رياكت React هي مكتبة جافا سكريبت مفتوحة المصدر طورتها شركة فيسبوك عام 2013 وهي تعد اليوم واحدة من أشهر مكتبات تطوير الواجهة الأمامية التي يمكنك من خلالها إنشاء مكونات قابلة لإعادة الاستخدام وتطوير واجهات مستخدم متجاوبة بسرعة وسهولة. يمكنك مطالعة المزيد حول هذه المكتبة وتعلم طريقة بناء واجهات المواقع والتطبيقات باستخدامها من خلال الدروس والمقالات الاحترافية حول React على أكاديمية حسوب وأيضًا توثيق React على موسوعة حسوب. أنغولار Angular أنغولار Angular هو إطار عمل مفتوح المصدر يعتمد على لغة TypeScript أطلقته شركة جوجل وهو يتميز بقدرته على تطوير تطبيقات ويب متطورة وضخمة وإدارتها بسهولة كبيرة فهو يوفر الكثير من الميزات التي تساعد مطوري الواجهة الأمامية مثل إدارة حالة التطبيق والتحقق من الصحة. كما يمكنك مطالعة المزيد من الدروس والمقالات الاحترافية حول Angular على أكاديمية حسوب لتتعرف على طريقة استخدامها في تطوير مواقع ويب احترافية. فيو Vue فيو Vue هو إطار عمل جافا سكريبت مفتوح المصدر طوره Evan You المبرمج في جوجل عام 2014 لتطوير واجهات المستخدم وتطبيقات الصفحة الواحدة وهو اليوم واحد من أكثر أطر عمل الواجهة الأمامية شيوعًا واستخدامًا. ما يميز إطار فيو Vue أنه مرن وخفيف الوزن وسهل الاستخدام فقد أزال كل المكونات الإضافية والمفاهيم غير الضرورية التي تأتي مع أطر عمل الواجهة الأمامية الأخرى مثل أنغولار Angular ورياكت React. وللمزيد من التفاصيل أنصح بمطالعة مقال مقارنة بين أطر الواجهات الأمامية: Angular و React و Vue لمعرفة الإطار الأنسب لمتطلباتك، كما أنصح بمتابعة الدروس والمقالات حول Vue التي توفرها أكاديمية حسوب بشكل دوري لتعلم المزيد حول استخدامات هذا الإطار. جي كويري jQuery جي كويري jQuery هي مكتبة مبنية بالاعتماد على لغة جافا سكريبت وهي توفر لمطوري الواجهة الأمامية الكثير من القوة والمرونة وتتضمن الكثير من الميزات التي تجعل كتابة شيفرات جافا سكريبت أبسط وأكثر اختصارًا. لمعرفة المزيد حول طريقة استخدام مكتبة jQuery عند تطوير مواقع الويب أنصح بمطالعات مجموعة المقالات والدروس حول jQuery المتوفرة على أكاديمية حسوب، كما أنصح بمطالعة توثيق jQuery على موسوعة حسوب. تقنيات وأدوات مهمة لتطوير الواجهة الأمامية إضافة لما سبق، يحتاج أي مطور واجهة أمامية لقائمة طويلة من المعارف والمهارات والأدوات الإضافية التي تعزز أداءه وتساعده في تطوير واجهات المستخدم وتكويدها بسرعة واحترافية، وإليك قائمة بأبرز هذه الأدوات نذكر: شجرة DOM والتعامل معها. معرفة أساسية بالشبكات وشبكة الإنترنت وأشهر برتوكولات التواصل مثل HTTP. لمحة عن قواعد التصميم وأساسيات تصميم واجهات المستخدم وتجربة المستخدم UX/UI. التصميم المتجاوب responsive design مع كافة أحجام الشاشات. التوافق مع المتصفحات Cross-browser. واجهة برمجة التطبيقات API. لمحة عن Node.js وأنظمة إدارة الحزم تحديدًا npm. نظام التحكم في الإصدارات git. شجرة DOM من الضروري أن يعرف أي مطور واجهة أمامية مهارات التعامل مع نموذج كائن المستند Document Object Model أو اختصارًا DOM أو شجرة DOM ومعالجته عبر لغة جافا سكريبت، و DOM هو مجموعة من المواصفات التي تمثل مستند الويب بشكل كائن وتعد أحد الطرق الأساسية في بناء مواقع تفاعلية حيث أنها تنشئ واجهة برمجة تطبيقات API تسمح للغات البرمجة مثل جافا سكريبت بالوصول لكافة عناصر صفحات الويب ومعالجتها والتحكم بها. ستساعدك معالجة DOM في تحديث بيانات الصفحة أو تغيير تخطيطها دون إعادة الحاجة لإعادة تحميلها على سبيل المثال يمكنك من خلال DOM إضافة عناصر HTML للصفحة أو إزالتها أو تعديل تنسيقات CSS لها عند وقوع حدث ما أو عند إعادة تحميل صفحة الويب. معرفة أساسية بالشبكات يحتاج مطور الواجهة الأمامية لامتلاك معلومات أساسية حول طريقة عمل الويب والشبكات الحاسوبية وشبكة الإنترنت ومفهوم العميل والخادم وكيفية التفاعل بينهما وبروتوكولات الاتصال عبر الويب مثل HTTP و HTTPS و SSL ومفهوم خدمة اسم المجال DNS فهذه المعرفة تمكنه من عرض واستدعاء المحتوى من الشبكة والاتصال مع الخادم بشكل آمن وتوفير تجربة مستخدم أفضل. للاطلاع على مزيد من المعلومات يمكنك مطالعة سلسلة المقالات والدروس حول الشبكات على أكاديمية حسوب. قواعد التصميم وأساسيات UX/UI ذكرنا سابقًا أن مطور الواجهة الأمامية قد يكون مسؤولًا عن تصميم موقع ويب من الصفر أو قد يكون مسؤولًا عن تحويل التصاميم الجاهزة إلى شيفرات برمجية، لكن في كلتا الحالتين أجد أنه من الضروري لأي مطور واجهة أمامية أن يعرف أفضل النصائح والقواعد لتصميم واجهة المستخدم والمبادئ والقواعد الأساسية في تصميم تجربة المستخدم UX وتصميم واجهة المستخدم UI فهذا من شأنه أن يساعده على فهم الواجهات وكيفية تفاعل المستخدمين معها بشكل أفضل وكيفية إنشاء واجهات أكثر جاذبية وسهولة في الاستخدام وبالتالي سيتمكن من كتابة شيفرات الواجهة الأمامية بشكل أفضل ويضمن أنها مطابق للقواعد التصميمة الصحيحة. التصميم المتجاوب مع كافة أحجام الشاشات التصميم المتجاوب Responsive Design هو تصميم يقوم بتغيير حجم عناصر صفحات الموقع أو إخفائها أو تصغيرها أو تكبيرها ليضمن ظهورها بطريقة واضحة وسهلة الاستخدام مهما كان نوع الجهاز المستخدم لعرضها. يحتاج مطور الواجهة الأمامية لمعرفة أساسيات تصميم الويب المتجاوب Responsive Web Design وطرق كتابة استعلامات الوسائط Media Queries في CSS بشكل صحيح كي يضمن ظهور المواقع بكفاءة على جميع أنواع وأحجام الأجهزة التي يستعملهما المستخدمون سواء الحواسيب ذات الشاشات الكبيرة أو الهواتف المحمولة ذات الشاشات الصغيرة. التوافق مع المتصفحات Cross-browser أحد المهارات الضرورية التي يجب على مطور الواجهة الأمامية تعلمها هو التأكد من أن الواجهات التي يبرمجها متوافقة مع مختلف المتصفحات وتظهر بشكل سليم ومتسق على المتصفحات الشهيرة مثل كروم وفايرفوكس وسفاري وEdge وOpera ويتعلم كيف يجري اختبارات التوافق مع المتصفحات cross-browser testing ويعالج أي مشكلات تواجهه في التوافق. يمكنك الاستعانة ببعض الأدوات والتقنيات المساعدة في اختبار توافق المتصفح Cross-browser مثل Markup Validation Service و CrossBrowserTesting و LambdaTest …إلخ. لكن تجدر الإشارة بأن أطر عمل الواجهات الأمامية مثل رياكت React وأنجولار Angular يمكنها أن تقوم بهذه المهمة عنك ولن تجعلك تكترث لها، يكفي أن تحدد لها أي نوع متصفح تريد أن نستهدف وهي تتولى الأمر لأنها تعالج دومًا الشيفرة التي تكتبها. استدعاء واجهة برمجة التطبيقات واجهات برمجة التطبيقات API هي صلة الوصل بين تطبيقات الواجهة الأمامية وبين النظم والوجهات الخلفية وبالرغم من أنك لا تحتاج كمطور واجهة أمامية لمعرفة كيفية كتابة واجهات برمجة التطبيقات لكونها مهمة مطور الواجهة الخلفية لكنك تحتاج لمعرفة طريقة الاتصال بهذه الواجهات وجلب البيانات منها وعرضها بشكل مناسب ومعرفة التقنيات المرتبطة بها مثل RESTful ومفهوم JSON. باختصار، يجري التواصل بين الواجهة الأمامية والواجهة الخلفية عبر واجهة برمجة التطبيقات وعادة ما ترسل البيانات من الواجهة الخلفية إلى الواجهة الأمامية بصيغة JSON لذا من الضروري معرفة هذه الصيغة، ويمكنك الرجوع إلى مقال تعلم JSON. تعلم Node.js وأنظمة إدارة الحزم يحتاج مطور الواجهة الأمامية إلى تعلم أحد أدوات إدارة الحزم Package Manager التي تجعل عملية تطوير الواجهة الأمامية أسرع وأسهل، فأدوات إدارة الحزم هي برمجيات تسمح لك بتثبيت الحزم المطلوبة للتطوير وإعدادها وتحديثها وإدارة تبعياتها وضمان عدم تعارضها بشكل تلقائي بدلًا من القيام بذلك بشكل يدوي ومن أشهرها npm و Yarn. وعادة يستعمل مطور الواجهات الأمامية مكتبة Node.js التي تأتي مع نظام إدارة الحزم الشهير npm والذي سيستعمله في تنزيل حزم المشروع وإدارتها ومكتبة Node.js هي أول أداة سيثبتها المطور على جهازه فبدونها لن يعمل مع لغة جافاسكريبت على الإطلاق، لذا يجب أن يتعرف عليها وعلى مدير الحزم npm. وقد شرحنا في مقال أساسيات إدارة الحزم في تطوير الويب من طرف العميل كل ما يتعلق باستخدام مدير الحزم وكيفية استخدامه في إدارة مشاريع الواجهة الأمامية. نظام التحكم في الإصدارات git يساعد نظام التحكم في الإصدار وأشهرها Git مطور الواجهة الأمامية على تتبع التغييرات التي يجريها على المواقع ويمكنه من العودة إلى إصدار كود سابق بكل سهولة إذا حدث خطأ ما في الكود كما يفيده في حال العمل على نفس المشروع مع فريق تطوير. تتوفر في أكاديمية حسوب مجموعة غنية ومنوعة من المقالات والدروس حول Git التي تساعدك في تعلم كافة المهارات اللازمة للتعامل مع نظام التحكم بالإصدارات Git. كانت هذه التقنيات جزءًا يسيرًا من التقنيات والأدوات التي على مطور الواجهة الأمامية معرفتها، وفي الفقرة التالية سنوضح المزيد من هذه التقنيات ونضع لك خارطة طريق منظمة تساعدك في تعلم تعلم تطوير الواجهة الأمامية. خارطة طريق تعلم تطوير الواجهة الأمامية إليك خارطة طريق لتعلم مجال تطوير الواجهات الأمامية والذي يعرض بوضوح طريق مطور الواجهات الأمامية بالكامل بدءًا من المرحلة المبتدئة وحتى المتقدمة وأغلب تلك المواضيع تجد عنها في أكاديمية حسوب وموسوعة حسوب: أهم مصادر تعلم تطوير الواجهة الأمامية إذا كنت مبتدئًا ولا تملك أي خبرة مسبقة وتبحث عن أقصر طريقة لتعلم تطوير الواجهة الأمامية أنصحك بالاطلاع على دروة تطوير واجهات المستخدم التي توفرها أكاديمية حسوب فهي دورة شاملة ومنظمة تزيد على 60 ساعة فيديو تدريبية ومن مسارات متعددة تبدأ معك من أساسيات تطوير واجهات المستخدم التي تشرح لك كل المفاهيم واللغات الأساسية وأطر ومكتبات العمل وتنتهي بك ببناء مشاريع عملية متقدمة ترسخ كل هذه الأساسيات وتساعدك في بناء معرض أعمالك. لن تكون وحدك خلال هذه الدورة بل سيكون معك فريق من المدربين لمساعدتك وإجابتك على أي تساؤل أو مشكلة تواجهك في رحلة التعلم، وفي نهاية الدورة ستحصل على شهادة معتمدة من أكاديمية حسوب تعزز سيرتك الذاتية. إضافة إلى ذلك توفر أكاديمية حسوب الكثير من مصادر التعلم المجانية باللغة العربية من دروس ومقالات وسلاسل تعلمية حول تطوير الويب تتعلم من خلالها كافة تقنيات ولغات برمجة الواجهات الأمامية وأطر العمل الشهيرة التي أوردناها في سياق المقال. وإن كنت تفضل الدراسة من الكتب بسبب شموليتها وتسلسلها في الشرح فإن الأكاديمية توفر لك مجموعة من الكتب القيمة التي تهم أي مطور واجهة أمامية من بينها: كتاب فهم أعمق لتقنيات HTML5 كتاب ملاحظات للعاملين في CSS كتاب البرمجة بلغة جافا سكريبت كتاب تصميم تجربة المستخدم سلسلة تطوير الويب وأخيرًا إذا كنت ترغب بمعرفة المزيد من المعلومات حول الواجهات الأمامية وأهم تقنيات برمجتها ومسار تعلمها أنصحك بمشاهدة هذا الفيديو. الخلاصة بهذا تكون وصلت إلى نهاية هذه المقالة الشاملة التي تناولنا فيها كل ما يتعلق بأساسيات تطوير الواجهة الأمامية front-end أو ما يعرف بتطوير واجهة المستخدم وتعرفنا على أهم اللغات وأطر العمل والأدوات التي تحتاجها كمطور واجهة أمامية لتنجز الجزء المرئي من الموقع الذي يتفاعل المستخدمون من خلاله مع التطبيقات والمواقع، كما شرحنا في ختامة أهم خطوات تعلم تطوير الواجهة الأمامية ومصادر تعلمها باللغة العربية. وفي حال كان لديك أي سؤال يتعلق بتطوير الويب وتحديدًا تطوير الواجهات الأمامية للويب فلا تتردد في كتابته في قسم التعليقات أسفل المقال، أو طرحه في قسم الأسئلة والأجوبة في أكاديمية حسوب ليجيبك عليه مبرمجون خبراء. اقرأ أيضًا المدخل الشامل لتعلم تطوير الويب وبرمجة المواقع برمجة مواقع الويب: دليلك المختصر ما الفرق بين تصميم المواقع الإلكترونية وتطوير المواقع الإلكترونية؟ عالم الويب ومعاييره ما هي صفحات الويب؟1 نقطة
-
يمكن أن تكون أدوات تطوير الويب من طرف العميل غير مفهومة بالنسبة لكثير من المطورين، لذلك سنوضّح من خلال سلسلة من المقالات الغرض من بعض أدوات تطوير الويب الأكثر شيوعًا من طرف العميل، وسنشرح أيضًا الأدوات التي يمكنك ربطها مع بعضها بعضًا، وكيفية تثبيتها باستخدام مدير الحزم، والتحكم فيها باستخدام سطر الأوامر، وسنقّدّم مثالًا كاملًا عن سلسلة أدوات يوضح كيفية زيادة الإنتاجية، ولكن في البداية وقبل محاولة استخدام هذه الأدوات يجب أن تتعلم أساسيات لغات HTML وCSS وجافاسكربت JavaScript. وفّرنا من خلال موسوعة حسوب مرجعًا لكل من لغات HTML وCSS وJavaScript يمكنك البدء منه. سنوضح في هذه السلسلة من المقالات المواضيع التالية لفهم أدوات تطوير الويب من طرف العميل: نظرة عامة على أدوات تطوير الويب من طرف العميل: نقدّم في هذا المقال نظرة عامة على أدوات الويب الحديثة، وأنواع الأدوات المتاحة وأين ستصادفها في دورة حياة تطوير تطبيقات الويب، وكيفية العثور على المساعدة باستخدام هذه الأدوات. دورة مكثفة لفهم سطر الأوامر: سيُطلب منك بلا شك تشغيل بعض الأوامر في الطرفية Terminal أو في سطر الأوامر خلال عملية التطوير، حيث يقدم هذا المقال مقدمة إلى الطرفية والأوامر الأساسية التي ستحتاج إلى إدخالها، وكيفية ربط الأوامر مع بعضها بعضًا، وكيفية إضافة أدوات واجهة سطر الأوامر Command Line Interface -أو CLI اختصارًا. أساسيات إدارة الحزم: سنلقي نظرة على مدراء الحزم بشيء من التفصيل لفهم كيفية استخدامها في مشاريعك لتثبيت اعتماديات Dependencies أدوات المشروع وتحديثها وغير ذلك. سلسلة أدوات كاملة: سنعمل في المقالين الأخيرين من السلسلة على ترسيخ معرفتك بالأدوات من خلال إرشادك خلال عملية بناء نموذج لسلسلة أدوات عن طريق إعداد بيئة تطوير ووضع أدوات التحويل في مكانها لنشر تطبيقك فعليًا على Netlify. كما سنقدم دراسة حالة مع إعداد بيئة التطوير الخاصة بنا وإعداد أدوات تحويل شيفرتنا. نشر التطبيق: سنأخذ في المقال الأخير من هذه السلسلة مثالًا عن سلسلة الأدوات التي أنشأناها في المقال السابق ونضيفها لنتمكن من نشر التطبيق، إذ سنرفع الشيفرة البرمجية للمشروع على موقع مشاركة الشيفرات جيت هب GitHub، وننشرها باستخدام نيتليفاي Netlify، وسنوضّح كيفية إضافة اختبار بسيط لهذه العملية. لنبدأ بمقالنا الأول من هذه السلسلة من خلال إلقاء نظرة سريعة على أدوات تطوير الويب من طرف العميل. المتطلبات الأساسية: الإلمام بمفاهيم لغات HTML و CSS وجافاسكربت الأساسية. الهدف: فهم أنواع الأدوات من طرف العميل وكيفية العثور عليها والحصول على المساعدة بشأنها. استخدام الأدوات الحديثة أصبحت كتابة برمجيات الويب أكثر تعقيدًا بمرور الوقت، وبالرغم من ذلك لا يزال كتابة برمجيات الويب يدويًا بلغة HTML و CSS وجافاسكربت أمرًا ممكنًا إلا أنه يوجد الآن مجموعة كبيرة من الأدوات التي يمكن للمطورين استخدامها لتسريع عملية إنشاء موقع ويب أو تطبيق. توجد بعض الأدوات المستقرة التي أصبحت أسماء مألوفة وشائعة في مجتمع تطوير الويب، بالإضافة إلى الأدوات الجديدة التي نراها تصدر كل يوم لحل مشكلات معينة، فيمكن أن تكتب برنامجًا للمساعدة في عملية التطوير الخاصة بك ولحل مشكلة معينة لا يمكن أن تحلها الأدوات الحالية. يمكنك استخدام عدد هائل من الأدوات وتضمينها في مشروع واحد، كما يمكنك استخدام أداة واحدة مثل Webpack وإعداد ملف تكوينها من مئات الأسطر، وغالبًا ما ينظر المبرمجين المبتدئين لهذه الشيفرة وكأنها تعويذات تؤدي المهمة بطريقة سحرية ولن يفهمها إلا المهندسون الخبراء. إلا أنه في الواقع غالبية الخبراء يواجهون مشاكلًا في استخدام الأدوات من وقت لآخر، إذ يمكن إضاعة ساعات في محاولة تشغيل مسار أدوات قبل لمس سطر واحد من شيفرة التطبيق. لذلك لا داعي للقلق، فأنت لست وحدك. سنزودك من خلال هذا المقال بنقطة بداية مفيدة لفهم أساسيات استخدام أدوات الويب، إذ يُفضَّل أن تبدأ على نطاق صغير، ثم تشق طريقك تدريجيًا إلى الاستخدامات أكثر تقدمًا. نظام أدوات المطورين الحديث يعدّ النظام البيئي Ecosystem الحديث لأدوات المطورين في يومنا الحالي ضخم نسبيًا، لذا يجب من الأفضل تكوين فكرة عامة عن المشاكل الرئيسية التي تحلها هذه الأدوات. إذا انتقلت إلى محرك البحث المفضل لديك وبحثت عن "أدوات مطور الواجهة الأمامية"، فستصل لمجموعة كبيرة من النتائج تتراوح من محرّرات النصوص والمتصفحات وحتى نوع الأقلام التي يمكنك استخدامها لتدوين الملاحظات. وبالرغم من أن اختيارك لمحرّر الشيفرة هو بالتأكيد جزء من خيارات الأدوات، ولكن في هذه السلسلة من المقالات سنتجاوز ذلك من خلال التركيز على أدوات المطور التي تساعدك على إنتاج شيفرة ويب ذات كفاءة عالية. يمكنك تصنيف الأدوات من طرف العميل ضمن الفئات الثلاث التالية: شبكة الأمان Safety Net: أدوات مفيدة أثناء تطوير شيفرتك. التحويل Transformation: الأدوات التي تحول الشيفرة بطريقة ما مثل تحويل لغة وسيطة إلى لغة جافاسكربت التي يمكن أن يفهمها المتصفح. أدوات ما بعد التطوير Post-development: الأدوات المفيدة بعد كتابة شيفرتك مثل أدوات الاختبار والنشر. لنلقِ نظرة على كل واحدة من هذه الفئات بمزيد من التفصيل. شبكة الأمان هي الأدوات التي تحسّن شيفرتك البرمجية التي تكتبها، ويجب أن تكون هذه الأدوات خاصةً ببيئة التطوير الخاصة بك، بالرغم من ذلك من غير المألوف أن يكون لدى الشركات سياسة أو إعدادات جاهزة للتثبيت لكي تضمن أن يستخدم جميع مطوري هذه الشركات العمليات نفسها. تتضمن هذه الأدوات أيّ شيء يسهّل عملية التطوير فيما يتعلق بإنشاء شيفرة مستقرة وموثوقة. كما يجب أن تساعدك أدوات شبكة الأمان في منع حدوث الأخطاء أو تصحيحها تلقائيًا دون الحاجة إلى إنشاء شيفرة من نقطة الصفر في كل مرة. سنوضّح فيما يلي بعض أنواع أدوات شبكة الأمان الشائعة التي يستخدمها المطورون. منقحات الصياغة Linters منقحات الصياغة هي أدوات تتحقق من شيفرتك وتخبرك بوجود أخطاء وبأنواعها وسطور الشيفرة التي توجد فيها. يمكن ضبط منقحات الصياغة للإبلاغ عن الأخطاء، وللإبلاغ عن أيّ انتهاكات لدليل النمط المحدَّد الذي يستخدمه فريقك مثل الشيفرة التي تستخدم عددًا خاطئًا من المسافات البادئة، أو استخدام صياغة قالب Template Literals بدلًا من صياغة سلسلة نصية عادية String Literals. يعدّ Eslint منقّح أخطاء معياري خاص بلغة جافاسكربت ويمكن ضبط هذه الأداة لاكتشاف أخطاء الصياغة المحتملة وتشجيعك لاستخدام أفضل الممارسات ضمن شيفرتك البرمجية. شاركت بعض الشركات والمشاريع إعدادات Eslint الخاصة بها، ويمكنك العثور على أدوات اكتشاف أخطاء للغات أخرى مثل Csslint. كما يمكنك استخدام Webhint وهو منقح أخطاء مفتوح المصدر يمكن ضبطه للويب، ويعرض أفضل الممارسات لاستخدامها بما في ذلك أساليب الوصول والأداء والتوافق مع المتصفحات باستخدام بيانات توافق متصفح MDN والأمان واختبار تطبيقات الويب ذات الصفحة الواحدة PWA وغير ذلك. كما يتوفر كأداة سطر أوامر Node.js وكامتداد VS Code. التحكم بالشيفرة البرمجية يُعرَف أيضًا باسم أنظمة التحكم بالإصدارات Version Control Systems أو VCS اختصارًا، ويُعَد التحكم بالشيفرة البرمجية ضروريًا لدعم العمل الفردي أو ضمن فريق. يتضمن نظام VCS إصدارًا محليًا من الشيفرة التي تجري تغييرات عليها، ثم ترفع التغييرات إلى إصدار رئيسي من الشيفرة داخل مستودع بعيد مُخزَّن على خادم في مكان ما. هناك عادةً طريقة للتحكم في التعديلات التي تُطبَّق على النسخة الرئيسية من الشيفرة وتنسيقها ومتى تطبَّق، وبالتالي لا يكتب فريق المطورين فوق عمل بعضهم بعضًا. يعد نظام جيت هاب Git من أشهر نظم التحكم بالشيفرة البرمجية الذي يستخدمه معظم المطورين حاليًا، إذ يمكن الوصول إليه عبر سطر الأوامر أو عبر واجهات سهلة الاستخدام. كما يمكنك رفع نسخة من المشروع إلى الخادم الخاص بك باستخدام شيفرتك في مستودع جيت، أو يمكنك استخدام موقع ويب مستضاف للتحكم بالشيفرة المصدرية مثل جيت هب GitHub أو جيت لاب GitLab أو بيت باكيت BitBucket، ولكن سنستخدم GitHub في مثالنا. مُنسِّقات الشيفرة Code Formatters ترتبط مُنسِّقات الشيفرة إلى حد ما بمنقّحات الصياغة، باستثناء أنه بدلًا من الإشارة إلى الأخطاء في شيفرتك، فإنها عادةً ما تميل إلى التأكد من تنسيق شيفرتك الصحيح وفقًا لقواعد النمط الخاصة بك، وتعمل تلقائيًا على إصلاح الأخطاء التي تعثر عليها. أحد الأمثلة الشائعة لمنسقات الشيفرة البرمجية هو Prettier، والذي سنستخدمه لاحقًا في مثالنا. الحزم Bundlers أو Packagers هي الأدوات التي تجعل شيفرتك جاهزةً لعملية الإنتاج عن طريق تقنية هز الشجرة Tree-Shaking مثلًا للتأكّد من إدراج أجزاء مكتبات الشيفرة التي تستخدمها فعليًا فقط في شيفرة الإنتاج النهائي، أو التصغير Minifying لإزالة كل مسافة فارغة في شيفرة الإنتاج، مما يصغّرها قدر الإمكان قبل رفعها إلى الخادم. تعد أداة Parcel من الأدوات الذكية التي يمكنها تطبيق المهام المذكورة السابقة، كما أنها تساعد أيضًا في حزم الملفات أو الملحقات assets مثل HTML وCSS وملفات الصور ضمن حزم ملائمة يمكنك نشرها لاحقًا، وتضيف اعتماديات تلقائيًا كلما حاولت استخدامها. كما يمكن لهذه الأداة التعامل مع بعض مهام تحويل الشيفرة نيابة عنك. يذكر أن أداة ويب باك Webpack هي أشهر أداة حزم تطبّق مهامًا مماثلة. التحويل Transformation تتيح هذه المرحلة من دورة حياة تطبيق الويب كتابة شيفرة برمجية إما في شيفرة مستقبلية مثل تحويل الشيفرة البرمجية لأحدث ميزات لغة CSS أو جافاسكربت التي يمكن ألّا تدعمها بعض المتصفحات حتى الآن، أو إنشاء شيفرة برمجية مكافئة لشيفرة برمجية مكتوبة بلغة معينة مثل لغة TypeScript، لتتوافق الشيفرة التي أنشأتها الأداة المطلوبة مع المتصفح لاستخدامها في عملية الإنتاج. يُنظَر إلى تطوير الويب على أنه مؤلَّف من ثلاث لغات هي HTML وCSS وجافاسكربت، وهناك أدوات تحويل لجميع هذه اللغات. يقدّم التحويل فائدتين رئيسيتين هما: القدرة على كتابة شيفرة برمجية باستخدام أحدث ميزات اللغة وتحويلها إلى شيفرة تعمل على جميع الأجهزة، فيمكن أن ترغب مثلًا في كتابة شيفرة بلغة جافاسكربت باستخدام ميزات لغة جديدة متطورة، ولكن لا يزال لديك شيفرة الإنتاج النهائي التي تعمل على المتصفحات القديمة التي لا تدعم هذه الميزات. تشمل الأمثلة التالية: Babel: مصرّف جافاسكربت JavaScript الذي يسمح للمطورين بكتابة شيفرة باستخدام أحدث إصدارات جافاسكربت، والتي يأخذها Babel ويحوّلها إلى إصدار جافاسكربت قديم يمكن لمزيد من المتصفحات فهمه. كما يمكن للمطورين كتابة ونشر إضافات Babel. PostCSS: تطبّق هذه الأداة الشيء نفسه الذي يطبّقه Babel، ولكن مع ميزات CSS المتطورة. إذا لم تكن هناك طريقة مكافئة لتطبيق شيء ما باستخدام ميزات CSS القديمة، فسيثبّت PostCSS تعويض نقص دعم المتصفحات Polyfill بلغة جافاسكربت لمحاكاة تأثير CSS الذي تريده. خيار كتابة الشيفرة بلغة مختلفة تمامًا وتحويلها إلى لغة متوافقة مع الويب مثل: Sass / SCSS: يتيح لك هذا الامتداد من لغة CSS استخدام المتغيرات والقواعد المتداخلة والمزج والدوال والعديد من الميزات الأخرى، إذ يُعَد بعضها متاحًا في لغة CSS الأصلية مثل المتغيرات، وبعضها ليس كذلك. TypeScript: هي مجموعة شاملة من لغة جافاسكربت التي تقدم مجموعة من الميزات الإضافية. يحوّل مصرّف TypeScript شيفرة TypeScript إلى جافاسكربت عند البناء بهدف الإنتاج. توفّر أطر العمل مثل React وEmber وVue الكثير من الوظائف مجانًا وتسمح لك باستخدامها عبر صيغة مخصَّصة مبنية على لغة جافاسكربت الصرفة Vanilla JavaScript. تعمل شيفرة جافاسكربت الخاصة بإطار العمل في الخلفية لتفسير هذه البنية المخصَّصة وتقديمها بوصفها تطبيق ويب نهائي. أدوات ما بعد التطوير Post Development تضمن أدوات ما بعد التطوير أن يصل برنامجك إلى الويب ويستمر في عمله، إذ تتضمن مرحلة ما بعد التطوير عمليات النشر وأطر عمل الاختبار وأدوات التدقيق وغير ذلك. تُعَد هذه المرحلة بأنها المرحلة التي تحتاج أقل قدر من التفاعل النشط بحيث تُشغَّل تلقائيًا بمجرد تهيئتها، وتخبرك بحدوث خطأ ما. أدوات الاختبار Testing Tools تأخذ هذه الأدوات شكل أداة تختبر تلقائيًا شيفرت البرمجية للتأكد من صحتها قبل المضي قدمًا مثل رفع تعديلات إلى مستودع جيب هب GitHub Repo. يمكن أن يشمل ذلك الكشف عن الأخطاء Linting، ويشمل إجراءات أكثر تعقيدًا مثل اختبارات الوحدة إذ تشغّل جزءًا من شيفرتك، مع التأكد من أنها تتصرف كما ينبغي. تشمل أطر عمل اختبارات الكتابة Jest وMocha وJasmine. تتضمن أنظمة التشغيل والاختبارات الآلية Travis CI وJenkins وCircle CI وغيرها. أدوات النشر Deployment Tools تسمح أنظمة النشر بنشر موقع الويب الخاص بك، وهي متاحة لكل من المواقع الثابتة والديناميكية، وتميل للعمل جنبًا إلى جنب مع أنظمة الاختبار، إذ ستنتظرك سلسلة الأدوات إلى أن ترفع التغييرات إلى المستودع البعيد، وتجري بعض الاختبارات لمعرفة ما إذا كانت التغييرات مناسبة، وإذا نجحت الاختبارات، فستنشر تطبيقك تلقائيًا على موقع إنتاج. تعد Netlify واحدة من أكثر أدوات النشر شيوعًا في الوقت الحالي، ولكن هناك أدوات أخرى مثل Vercel وGithub Pages. أدوات ما بعد التطوير الأخرى هناك عدد من أنواع الأدوات الأخرى المتاحة للاستخدام في مرحلة ما بعد التطوير، بما في ذلك Code Climate لجمع مقاييس جودة الشيفرة، وامتداد متصفح Webhint لإجراء تحليل وقت التشغيل للتوافق مع المتصفحات وعمليات التحقق الأخرى، وGithub bots لتوفير المزيد من ميزات GitHub القوية، وUpdown لتوفير مراقبة وقت تشغيل التطبيق وغير ذلك الكثير. أنواع الأدوات تُطبَّق أنواع الأدوات المختلفة في دورة حياة التطوير وفق ترتيب معين، ولكن كن مطمئنًا أنك لست مضطرًا إلى أن يكون لديك كل هذه الأدوات لإصدار موقع ويب، فلن لا تحتاج لأيٍّ منها. لكن سيؤدي تضمين بعض هذه الأدوات في عملياتك إلى تحسين تجربة التطوير، ويُحتمَل أن يؤدي إلى تحسين جودة شيفرتك الإجمالية. يستغرق استقرار أدوات المطور الجديدة بعض الوقت حسب تعقيدها. تشتهر إحدى أشهر الأدوات وهي Webpack بكونها معقدة للغاية للتعامل معها، ولكن كان هناك ضغط كبير لتبسيط الاستخدام في أحدث إصدار رئيسي، لذا قُلٍّل الإعداد المطلوب إلى الحد الأدنى. ليس هناك حل سحري يضمن النجاح باستخدام الأدوات، ولكن ستجد تدفقات عمل تناسبك أو تناسب فريقك ومشاريعك مع زيادة خبرتك، ويجب أن تكون سلسلة الأدوات شيئًا يمكنك نسيانه وأن تركّز على العمل فقط، بمجرد تسوية جميع مكامن الخلل في العملية. كيفية اختيار أداة معينة والحصول عليها تميل معظم الأدوات إلى كتابتها وإصدارها بصورة منفصلة، لذلك لا تتوفر أبدًا في المكان أو التنسيق نفسه، على الرغم من وجود مساعدة شبه مؤكدة، فيمكن أن يكون العثور على مساعدة في استخدام أداة أو حتى اختيار الأداة التي تريد استخدامها أمرًا صعبًا. المعرفة حول أفضل الأدوات لاستخدامها هي معرفة مجتمعية إلى حد ما، مما يعني أنه إن لم تكن بالفعل في مجتمع الويب، فستكون معرفة الأدوات التي تريدها بالضبط أمرًا صعبًا، وهذا هو أحد الأسباب التي دفعتنا إلى كتابة هذه السلسلة من المقالات، ونأمل أن نقدم تلك الخطوة الأولى التي يصعب إيجادها بطريقة أخرى. ستحتاج على الأرجح إلى مجموعة الأشياء التالية: نجح المدرسون أو الموجهون أو الزملاء الطلاب ذوو الخبرة أو الزملاء الذين لديهم بعض الخبرة في حل هذه المشكلات من قبل، ويمكنهم تقديم المشورة. مكان محدد مفيد للبحث، إذ تكون عمليات البحث العامة على الويب عن أدوات مطور الواجهة الأمامية عديمة الفائدة إلا إن عرفتَ اسم الأداة التي تبحث عنها. إذا استخدمتَ مدير الحزم NPM لإدارة اعتمادياتك على سبيل المثال، فيُفضَّل الانتقال إلى صفحة npm الرئيسية والبحث عن نوع الأداة التي تبحث عنها. حاول مثلًا البحث عن "التاريخ date" إن أردتَ أداة تنسيق التاريخ، أو "المُنسِّق formatter" إذا كنت تبحث عن مُنسق شيفرة عام. انتبه إلى درجات الشعبية والجودة والصيانة، وآخر تحديث للحزمة. انقر على صفحات الأداة لمعرفة عدد تنزيلات الحزمة الشهرية، واحتوائها على توثيق جيد يمكنك استخدامه للتأكد من أنها تطبّق ما تريده، وبالتالي تُعَد مكتبة date-fns أداة تنسيق تاريخ جيدة لاستخدامها. إذا أردت البحث عن إضافة Plugin لدمج وظائف الأدوات في محرّر الشيفرة، فألقِ نظرة على صفحة الإضافات / الامتدادات لمحرر الشيفرة، وراجع حزم Atom وامتدادات VSCode على سبيل المثال. ألقِ نظرة على الامتدادات المميزة في الصفحة الأولى، وحاول مرة أخرى البحث عن نوع الامتداد الذي تريده (أو اسم الأداة مثل البحث عن "eslint" في صفحة امتدادات VSCode). إذا حصلتَ على نتائج، فألقِ نظرة على معلومات عدد النجوم أو التنزيلات التي يحتويها الامتداد، إذ يُعَد ذلك مؤشرًا على جودته. المنتديات المتعلقة بالتنمية لطرح أسئلة حول الأدوات التي يجب استخدامها مثل قسم الأسئلة والأجوبة البرمجية في أكاديمية حسوب. إذا اخترت أداة لاستخدامها، فيجب أن يكون طريقة فهم الأداة هو الصفحة الرئيسية لمشروع الأداة والذي يكون غالبًا موقع ويب كامل أو يكون مستندًا تمهيديًا واحدًا في مستودع الشيفرة. يمكن أن ترغب في العثور على بعض البرامج التعليمية المخصصة لبدء استخدام أنواع معينة من الأدوات، لذا تعد المقالات البرمجية ومقالات DevOps في أكاديمية حسوب أماكن الانطلاق الرائعة للبحث. يُحتمَل أن تمر عبر العديد من الأدوات المختلفة أثناء البحث عن الأدوات المناسبة لك، وأن تجربها لمعرفة ما إذا كانت منطقية ومدعومة جيدًا وتطبّق ما تريده منها. يُعَد كل ذلك مناسبًا للتعلم، وسيصبح الطريق أسلس كلما اكتسبت مزيدًا من الخبرة. الخلاصة قدّمنا من خلال هذا المقال مقدمة بسيطة عن أدوات الويب من طرف العميل، وسنقدّم في المقال القادم دورة مكثفة عن سطر الأوامر، إذ تُستدعَى كثير من الأدوات منه، وسنلقي نظرة على ما يمكن أن يفعله سطر الأوامر ثم نحاول تثبيت الأداة الأولى ونستخدمها. هذا المقال جزء من سلسلة مقالات بعنوان تعلم تطوير الويب والتي تشرح كامل عملية تطوير الويب من واجهات أمامية وخلفية بالكامل. ترجمة -وبتصرُّف- للمقالين Understanding client-side web development tools وClient-side tooling overview. اقرأ أيضًا مدخل إلى أدوات التطوير في متصفح الويب DevTools كيف تستخدم أدوات المطوِّر في المتصفحات الحديثة الفرق بين مصمم الويب ومطور الويب وكيفية معرفة الأنسب بينهما الأدوات المستخدمة في بناء مواقع ويب1 نقطة
-
مقدمة من أهم أسباب انتشار ووردبريس وسيطرته على سوق أنظمة إدارة المحتوى هو الكم الهائل من إضافاته المجانية والمدفوعة والتي تقدم العديد من الخصائص والمميزات والتحسينات الإضافية التي لا تتوفر بصورة افتراضية في قلب ووردبريس WordPress Core. في هذا المقال سنتعرف سوّيًا على أساسيات إنشاء إضافة لووردبريس لكن قبل الدخول في لب الموضوع دعنا نجب على سؤال مُهمّ وكذلك تعريف إضافات ووردبريس. لماذا ننشئ إضافات ووردبريس هنالك قاعدة مهمة في تطوير ووردبريس، وهي: إياك أن تلمس الشيفرات Codes الأساسية لووردبريس أي لا تُعدّل على قلب ووردبريس WordPress Core وذلك لأنه عند التحديث سيتمّ استبدال بعض أو كل ملفات ووردبريس الأساسية، وبالتّالي ستفقد التعديلات التي قمت بها، ولهذا السبب نلجأ إلى تطوير إضافات عند الحاجة لإضافة التحسينات والخصائص الجديدة على النّظام. تعريف إضافات ووردبريس إضافة ووردبريس عبارة عن دالة أو مجموعة دوال (حزمة شيفرات code package) مكتوبة بلغة php تقوم بإضافة بعض الخصائص لنظام إدارة المُحتوى. وتندمج شيفرات الإضافة معه من خلال واجهة برمجية API يوفرها له. بالإضافة لملفات php يمكن أن تحتوي الإضافة على ملفات أخرى مثل ملفات JavaScript, CSS وبعض الصور. إنشاء إضافة ووردبريس هذه بعض الخطوات المهمة عند إنشاء أي إضافة ووردبريس وبعض الأمور التي يجب مراعاتها. اختيار اسم الإضافة في البدء عليك أن تقوم باختيار اسم فريد للإضافة التي تود إنشائها بحيث لا يكون الاسم مستخدما من قبل من إحدى إضافات ووردبريس حتى لا يحدث تعارض بين الإضافات مستقبلا. إنشاء مجلد الإضافة بعد اختيار اسم الإضافة تقوم بإنشاء مجلد لها بالاسم الذي اخترناه ويكون هذا المجلد داخل مجلد plugins الخاص بالإضافات والموجود داخل مجلد wp-content كما موضح بالصّورة. يمكنك إنشاء ملف php بنفس الاسم بدلًا عن إنشاء مُجلّد كامل لكن يُفضّل أن تنشئ مُجلّدًا خاصًّا حتى يستوعب بقية ملفات الإضافة، ما لم تكن الإضافة تحتوي على ملف php واحد فقط. إنشاء الملف الأساسي للإضافة بعد إنشائك للمُجلّد في الخطوة أعلاه عليك أن تقوم بإنشاء ملف php له نفس اسم المجلد السابق، وهذا الملف هو الملف الأساسي للإضافة والذي سيستخدمه ووردبريس للتّعرف على بعض الأمور المُتعلّقة بالإضافة مثل اسمها واسم المُبرمج ورخصة الإضافة وغيرها، وهذا يتم من خلال استخدام ترويسة للملف الأساسي للإضافة وهذه هي الصّيغة العامة لها: <?php /** * Plugin Name: هنا تكتب اسم الإضافة والذي يجب أن يكون فريدًا * Plugin URI: هنا تكتب رابط موقع الإضافة * Description: هنا نبذة مختصرة عن الإضافة * Version: رقم نسخة الإضافة، مثلا 1.0.0 * Author: اسم مطور الإضافة * Author URI: رابط موقع مطور الإضافة * License: اسم رخصة الإضافة */ السّطر الإجباري هو سطر اسم الإضافة فقط، ويتمّ استخدام بقية السطور (في حال ورودها) في إنشاء معلومات الإضافة التي تظهر في لوحة تحكم الإضافات عند استعراض الإضافة. برمجة الإضافة قبل أن تبدأ في برمجة الإضافة تحتاج لمعرفة بعض الأمور العامة في برمجة ووردبريس بالإضافة لبعض التسهيلات التي يقدمها ووردبريس للمبرمجين مثل الواجهات البرمجية الجاهزة WordPress API's. الخطافات في ووردبريس WordPress Hooks ( الدخول الى عمق ووردبريس) من أهم المفاهيم في ووردبريس مفهوم الخطافات hooks والتي تنقسم إلى قسمين: الأحداث actions والمُرشّحات filters. 1- الإجراءات في ووردبريس WordPress Actions فلنفترض أنه لدينا دالة معينة نريد أن يتم تنفيذها في لحظة معينة أثناء دورة حياة ووردبريس أو عند حدوث حدث معين، كيف يمكننا إنجاز هذا الأمر؟ أحد الخيارات أن نقوم بمناداة هذه الدالة بالطريقة العادية في المكان الذي نريدها أن تُنفّذ فيه، لكن هذا الأمر يتطلّب التّعديل على ملفات ووردبريس الأساسية. لك القاعدة التي ذكرناها مسبقا: إياك أن تلمس الشيفرات الأساسية لووردبريس تمنعنا من القيام بذلك. الحل الآخر هو أن نستخدم الإجراءات actions وهي عبارة عن آليّة رائعة يوفرها ووردبريس تمكّنك من إضافة الدّوال الخاصّة بك لتُنفّذ في وقت معين أثناء تنفيذ الشيفرات الخاصة بووردبريس إذًا، يمكننا أن نعرف الإجراءات بأنها طريقة تمكننا من إخبار ووردبريس بتنفيذ دالة معينة عند حصول حدث معين وبهذه الطريقة نستطيع الدخول إلى عمق ووردبريس من دون التعديل المباشر على ملفاته الأساسية Core files. يتم هذا كله من خلال ربط الدّوال التي تريدها مع الأحداث الجاهزة التي يوفرها ووردبريس والتي يقوم بتنفيذها أثناء دورة حياته وهذا ما يجعلك قادرا على تنفيذ الدّوال الخاصة بك في أي مكان تريده تقريبا. إذا كنّا نريد مثلا تنفيذ الدّالة my_function عندما ينفذ ووردبريس الحدث my_action علينا ببساطة أن نخبره بذلك من خلال إضافة هذه الدالة إلى هذا الحدث. ويتم ذلك من خلال الدالة add_actions بالطريقة التالية add_action('my_action', 'my_function'); 1-1مثال للإجراءات في ووردبريس فلنأخذ هذا المثال الذي يقوم بإرسال بريد إلى مدير الموقع (الدالة المراد تنفيذها) كلما نشر مقالًا جديدًا (الحدث الذي تنفذ عنده الدالة) add_action('publish_post', 'email_admin'); function email_admin(){ // هنا يتم إرسال البريد الإلكتروني إلى مدير الموقع } 2-المرشحات في ووردبريس WordPress Filters المُرشّحات هي النوع الثاني من الخطّافات التي يوفرها ووردبريس وهي مختصّة أكثر بالبيانات حيث أنها تتيح لنا إمكانية التعديل على قيم المتغيرات (اسم المقال مثلا) قبل حفظها في قاعدة البيانات أو قبل عرضها للمستخدم، وكما هو ظاهر من اسمها فهي تتيح لنا إمكانية ترشيح البيانات، بمعنى إدخالها إلى filter مُعيّن يُعدّل عليها قبل إخراجها من الجانب الآخر من هذا المُرشّح . بطبيعة الأمر وكما هو الحال بالنّسبة للأحداث فإن ووردبريس يُوفّر لك إمكانية إدخال أغلب مُتغيّراته في المُرشّحات التي تريدها من خلال اسم المتغير، ويمكنك الاطّلاع على المُتغيّرات التي يمكنك تمريرها عبر المُرشّحات بزيارة التوثيق الرسمي للمرشحات. يتم إضافة فلتر معين my_filter لبيانات معينة my_data من خلال الدّالة add_filter بالطريقة التالية add_filter( 'my_data', 'my_filter' ); حيث أن my_filter هي الدّالة التي ستقوم بالتعديل على البيانات ويتم تمرير البيانات لها من قبل ووردبريس أي أنها يجب أن تستقبل my_data كمعامل parameter. 2-1مثال للمرشحات في ووردبريس هذا المثال يقوم بتعديل محتوى المقال the_content حيث يقوم بإضافة التّوقيع لمُحتويات كل مقال في الموقع add_filter ( 'the_content', 'add_signiture' ); function add_signiture($the_content){ // هنا نقوم بإضافة الشيفرات التي تضيف التّوقيع لمحتويات المقال return $the_content; // بعد ذلك تقوم الدّالة بإرجاع القيم الجديدة لمحتويات المقال } هذه نظرة سريعة فقط على الخطافات في ووردبريس ولكن ما زال هنالك العديد من الأشياء المتعلقة بهذه الآلية الرّائعة التي يوفرها ووردبريس منها: إمكانية إضافة الـhooks الخاصة بك. تعديل أولوية تنفيذ الدّوال التابعة لنفس الـhook. ويمكنك التعرف على المزيد حول موضوع الخطافات في التّوثيق الرسمي لPlugin API وسوم القالب Template Tags قد تبدو الترجمة الحرفية مُضلّلة نوعًا ما خصوصا إذا علمت أن المقصود من وسوم القالب هو مجموعة من الدّوال الجاهزة التي يوفرها ووردبريس والتي تختصر لك الكثير من العمل، لذلك من الجيد أن تلقي نظرة عليها قبل البدء في برمجة الإضافة الخاصة بك. الجدير بالذّكر أن يتم استخدام كثير من هذه الدّوال داخل الحلقة الخاصّة بجلب المقالات في ووردبريس WordPress Loop والتي تستخدم بكثرة في القوالب، ولعل هذا هو سرّ تسميتها بوسوم القالب. حفظ بيانات/ الإضافة في قاعدة البيانات الكثير من إضافات ووردبريس إن لم يكن معظمها تحتاج لاستقبال بعض البيانات من مدير الموقع (خيارات الإضافة مثلا) وحفظها في قاعدة البيانات لاسترجاعها واستخدامها لاحقا، ولهذا السبب يتيح لنا ووردبريس عدّة طرق لحفظ البيانات في قاعدة بيانات الموقع واختيار الطريقة المناسبة يعتمد على نوع البيانات المراد حفظها. هذه الطرق هي: 1- استخدام آلية "الخيارات options" التي يوفرها ووردبريس وهذه الطريقة مناسبة في حالة كون البيانات المراد حفظها صغيرة نسبيا ولا تتغير كثيرا مثل البيانات التي تتوقع من مدير الموقع إدخالها بعد تنصيب الإضافة مباشرة (خيارات الإضافة) والتي نادرا ما تتغير. في هذه الطريقة يتم حفظ بيانات الإضافة في جدول wp_options والذي يستخدمه ووردبريس لحفظ خياراته الخاصة. 2-استخدام البيانات الوصفية الخاصة بالمقالات Post Meta وهذه الطريقة مناسبة في حالة البيانات المتعلقة بمقال أو صفحة مفردة (مثلا مزاج الكاتب عند كتابة المقال) 3-استخدام الفئات المخصّصة وهذه مناسبة لتصنيف البيانات مثل تصنيف المقالات أو المستخدمين أو التعليقات. 4- إنشاء جدول جديد في قاعدة البيانات هذه الطريقة مناسبة مع البيانات التي لا يصلح معها أي نوع من الأنواع الثلاثة السابقة والتي تتوقع أن تتزايد مع الزمن والتي لا يمكن حصرها في اسم محدد. الاستفادة من الواجهات البرمجية API's التي يوفرها ووردبريس يحتوي ووردبريس على مجموعة ضخمة من الدّوال والأصناف Classes المفيدة التي تمثل بوّابات تربطك بقلب ووردبريس WordPress Core بالإضافة إلى توفيرها لدوال مفيدة في كثيرا من الأمور البرمجية العامة في مجال الويب، وهذه أمثلة لبعض الواجهات البرمجية التي يوفرها ووربريس Plugin API: تتيح لك الدّوال المستخدمة في الاستفادة من ميكانيكية الخطافات وكذلك الدّوال المساعدة لإنشاء الخطافات الخاصة بك. Database API : واجهة برمجية تسهل التعامل مع قاعدة بيانات ووردبريس. Rewrite API: تتيح لك إمكانية تغير صيغة روابط المقالات والموقع عموما والتحكم فيها. Filesystem API: للتعامل مع نظام الملفات في نظام التشغيل. وغيرها الكثير من الواجهات البرمجية ويمكنك الإطلاع عليها من هنا أمور عامة عليك مراعاتها عند برمجة الإضافة 1- الاهتمام بأمن الشيفرة Code Security كما هو الحال عند برمجة أي سكربت من خلال لغة php عليك مراعاة أن يكون خاليا من الثغرات التي قد تعرض الموقع لخطر الاختراق، نفس الأمر ينطبق على إضافات ووردبريس فعليك الاهتمام بإغلاق الثّغرات المعروفة وحماية المدخلات وكذلك ملفات الإضافة بمنع الوصول المباشر لها عن طريق استخدام الشيفرة التالية مثلا defined( 'ABSPATH' ) or die( 'ممنوع الوصول المباشر' ); هنالك أشياء أخرى يجب مراعاتها خصوصا إذا أردت نشر إضافتك في مستودع إضافات ووردبريس، بعض هذه الأمور إجباري وتحتاج لعمله حتى يتم قبول إضافتك ونشرها في المستودع، من هذه الأمور: 2- ملف اقرأني Readme File هو ملف تقوم بتضمينه في مجلد الإضافة باسم readme.txt ويستخدمه مستودع الإضافات لأخذ بعض المعلومات بالإضافة للمعلومات التي تظهر في صفحة الإضافة في المستودع، يمكنك استخدام هذا المُوّلد لإنشائه 3- جعل الإضافة قابلة للترجمة من الأمور الأخرى التي عليك مراعاتها هو جعل الإضافة قابلة للترجمة لعدة لغات localized حيث يمكنك استخدام مكتبة gettext التي يوفرها ووردبريس والتي تجعل من عملية جعل الكلمات قابلة للترجمة أمر سهل، وبعد ذلك يتم إرفاق ملفات اللغة مع الإضافة، ويمكنك قراءة المزيد عن هذا الأمر من هنا 4- استخدام معايير تطوير وودبريس معايير التّطويرCoding Standard هي بعض القواعد العامة التي عليك مراعاتها عند كتابة الشيفرة لتجنب أخطاء التشفير Coding وتسهيل عملية كتابة الشيفرات ومراجعتها وقراءتها خصوصا في حالة تعاون أكثر من شخص في برمجة شيء ما. لووردبريس قواعده الخاصة أيضا والتي يحاول من خلالها المحافظة على قواعد ثابتة في شيفرات ووردبريس وكذلك شيفرات الإضافات والقوالب لذلك يفضل أن تلتزم بهذه القواعد عند كتابة شيفرات الإضافة الخاصة بك. يمكنك قراءة المزيد عن هذه القواعد من هنا. 5- تحديث الإضافة يستخدم مستودع إضافات ووردبريس نظام Subversion لتحديث ولمعرفة آلية القيام بذلك، زر هذه الصّفحة كانت هذه كانت مقدمة سريعة ونبذة مختصرة حاولنا أن نجعلها كمدخل لبرمجة إضافات ووردبريس وما زال هنالك المزيد لمعرفته عن برمجة إضافات ووردبريس في مقالات قادمة.1 نقطة
-
المصفوفة (array) هي بنية بيانات تخزّن عدة قيم في قيمة واحدة، وهي خريطة مرتبة تربط بين القيم والمفاتيح. تُنشَأ مصفوفة مباشرة عبر الأقواس المعقوفة [] أو عبر الدالة Array() التي تأخذ المعاملات التالية: المعامل التفاصيل key (المفتاح) المفتاح هو المعرّف الفريد وفهرس المصفوفة. من الممكن أن يكون سلسلة نصية أو عدد صحيح مثل 'foo'، '5'، 10، 'a2b' value (القيمة) يوجد لكل مفتاح قيمة مقابلة (وإلا تكون null ويمكن أن تكون القيمة من أي نوع، وستظهر رسالة خطأ إذا حاولت الوصول إليه) 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; } تهيئة مصفوفة يمكن أن نُهيأ مصفوفة فارغة عبر الدالة Array() أو الأقواس [] مباشرةً: // مصفوفة فارغة $foo = array(); // PHP 5.4 يمكن استخدام هذا التدوين المختزل بدءًا من الإصدار $foo = []; ويمكن أن نُهيأ مصفوفة ونعطيها قيم في نفس الوقت: // إنشاء مصفوفة بسيطة من 3 سلاسل نصية $fruit = array('apples', 'pears', 'oranges'); // PHP 5.4 يمكن استخدام هذا التدوين المختزل بدءًا من الإصدار $fruit = ['apples', 'pears', 'oranges']; ويمكن أيضًا أن نهيأ مصفوفة مع فهارس مخصصة (تسمى مصفوفة ترابطية associative array): // مصفوفة ترابطية بسيطة $fruit = array( 'first' => 'apples', 'second' => 'pears', 'third' => 'oranges' ); // يمكن أن نضبط القيمة والمفتاح كالتالي $fruit['first'] = 'apples'; // PHP 5.4 يمكن استخدام هذا التدوين المختزل بدءًا من الإصدار $fruit = [ 'first' => 'apples', 'second' => 'pears', 'third' => 'oranges' ]; ستنشئ PHP المتغير تلقائيًا إذا لم يكن قد اُستخدم سابقًا، وهذا يجعل الشيفرة ملائمة لكنها صعبة القراءة: $foo[] = 1; // Array( [0] => 1 ) $bar[][] = 2; // Array( [0] => Array( [0] => 2 ) ) تتابع PHP الفهرسة من حيث توقفت وتستخدم سلاسل نصية عددية كأعداد صحيحة للفهرسة: $foo = [2 => 'apple', 'melon']; // Array( [2] => apple, [3] => melon ) $foo = ['2' => 'apple', 'melon']; // نفس المصفوفة السابقة $foo = [2 => 'apple', 'this is index 3 temporarily', '3' => 'melon']; // نفس المصفوفة السابقة، سيقوم العنصر الأخير بالكتابة فوق العنصر الثاني يمكنك استخدام الصنف splfixedarray لتهيئة المصفوفة بحجم ثابت: $array = new SplFixedArray(3); $array[0] = 1; $array[1] = 2; $array[2] = 3; $array[3] = 4; // RuntimeException // زيادة حجم المصفوفة إلى 10 $array->setSize(10); ملاحظة: المصفوفة المنشأة باستخدام الصف SplFixedArray لها مساحة ذاكرة منخفضة لمجموعات كبيرة من البيانات، ولكن يجب أن تكون المفاتيح أعدادًا صحيحة. لتهيئة مصفوفة بحجم ديناميكي وبعدة عناصر غير فارغة يمكنك استخدام حلقة كالتالي: $myArray = array(); $sizeOfMyArray = 5; $fill = 'placeholder'; for ($i = 0; $i < $sizeOfMyArray; $i++) { $myArray[] = $fill; } print_r($myArray); // Array ( [0] => placeholder [1] => placeholder [2] => placeholder [3] => placeholder [4] => placeholder ) يمكنك استخدام الدالة array_fill() لإنشاء مصفوفة وإعطاء مفاتيحها نفس القيم. array array_fill ( int $start_index , int $num , mixed $value ) تنشأ التعليمة السابقة وتُرجع مصفوفة فيها العدد num من العناصر التي قيمتها value بدءًا من الفهرس start_index، وإذا كانت قيمة start_index سالبة فستبدأ المصفوفة بفهرس سالب ثم تبدأ قيم الفهارس التالية من الصفر. $a = array_fill(5, 6, 'banana'); // Array ( [5] => banana, [6] => banana, ..., [10] => banana) $b = array_fill(-2, 4, 'pear'); // Array ( [-2] => pear, [0] => pear, ..., [2] => pear) نتيجة: عندما تستخدم الدالة array_fill() تكون أكثر محدودية فيما تودّ فعله أما الحلقة فهي أكثر مرونة وتتيح لك الكثير من الخيارات. إذا أردت ملء المصفوفة بمجال أرقام (من 0 إلى 4 مثلًا) يمكنك إما إضافة كل عنصر بشكلٍ مفرد أو استخدام الدالة range(): array range ( mixed $start , mixed $end [, number $step = 1 ] ) تنشأ هذه الدالة مصفوفة تحوي مجال من العناصر، وفيها المعاملان الأول والثاني إلزاميان إذ يحددان بداية ونهاية المجال أما المعامل الثالث فهو خياري ويحدد مقدار زيادة العناصر في المجال. مثال: إنشاء مجال من 0 إلى 4 بمقدار زيادة 1 ستكون نتيجته مصفوفة عناصرها: 0، 1، 2، 3، 4 أما إذا كان مقدار الزيادة 2 فستكون عناصر المصفوفة 0، 2، 4. $array = []; $array_with_range = range(1, 4); for ($i = 1; $i <= 4; $i++) { $array[] = $i; } print_r($array); // Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 4 ) print_r($array_with_range); // Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 4 ) تعمل الدالة range بشكلٍ صحيح مع الأعداد الصحيحة والعشرية والمنطقية (التي حُوّلت إلى أعداد صحيحة) والسلاسل النصية، ولكن يجب أخذ الحذر عند استخدام الأعداد العشرية كوسيط بسبب مشكلة دقة الفاصلة العائمة. التحقق من وجود مفتاح يمكنك استخدام الدالة array_key_exists() أو isset() أو !empty() للتحقق من وجود مفتاح: $map = [ 'foo' => 1, 'bar' => null, 'foobar' => '', ]; array_key_exists('foo', $map); // true isset($map['foo']); // true !empty($map['foo']); // true array_key_exists('bar', $map); // true isset($map['bar']); // false !empty($map['bar']); // false لاحظ أن الدالة isset() تعامل العنصر الذي قيمته null على أنّه غير موجود، وتعامل !empty() بالمثل أي عنصر قيمته false (استخدام موازنة ضعيفة مثل null، السلسلة الفارغة ' '، 0 تعاملها كلها على أنها false)، أي أن نتيجة isset($map['foobar']) هي true أما نتيجة !empty($map['foobar']) هي false، يمكن أن يؤدي هذا إلى مشاكل (فمن الممكن أن تنسى مثلًا أنّ السلسلة النصية '0' تُعامَل على أنّها false) لذا فإنّ استخدام !empty() يمكن أن يكون غير مقبول. لاحظ أيضًا أنّ isset() و!empty() سيعملان ويعيدان false إذا كانت $map غير معرفة أبدًا وهذا يجعلهم عرضة للخطأ نوعًا ما عند الاستخدام: // "long"و "lang" الفرق بين اسمي المتحولين هو في الكلمتين $my_array_with_a_long_name = ['foo' => true]; array_key_exists('foo', $my_array_with_a_lang_name); // يظهر تحذير isset($my_array_with_a_lang_name['foo']); // false يمكنك أيضًا التحقق في المصفوفات العادية: $ord = ['a', 'b']; // [0 => 'a', 1 => 'b'] المصفوفة السابقة تكافئ array_key_exists(0, $ord); // true array_key_exists(2, $ord); // false لاحظ أنّ أداء isset() أفضل من array_key_exists() لأنّ الأخيرة هي دالة والأولى هي بنية لغوية، ويمكنك أيضًا استخدام الدالة key_exists() التي تعد كنية للدالة array_key_exists(). التحقق من نوع المصفوفة تُرجع الدالة is_array() القيمة true إذا كان المتغير مصفوفة. $integer = 1337; $array = [1337, 42]; is_array($integer); // false is_array($array); // true يمكنك كتابة تلميح في الدالة أنّ نوع المعامل المفروض هو مصفوفة أي أنّ تمرير أي نوع آخر سيسبب خطأً فادحًا. function foo (array $array) { /* هو مصفوفة $array نوع المتغير */ } يمكنك أيضًا استخدام الدالة gettype(). $integer = 1337; $array = [1337, 42]; gettype($integer) === 'array'; // false gettype($array) === 'array'; // true إنشاء مصفوفة من المتغيرات $username = 'Hadibut'; $email = 'hadibut@example.org'; $variables = compact('username', 'email'); // ['username' => 'Hadibut', 'email' => 'hadibut@example.org'] هي $variables قيمة يُستخدم هذا التابع غالبًا في إطارات العمل لتمرير مصفوفة متغيرات بين مكونين. التحقق من وجود قيمة في مصفوفة تُرجع الدالة in_array() القيمة true إذا كان العنصر موجودًا في المصفوفة. $fruits = ['banana', 'apple']; $foo = in_array('banana', $fruits); //true هي $foo قيمة $bar = in_array('orange', $fruits); //false هي $bar قيمة ويمكنك أن تستخدم الدالة array_search() لتحصل على مفتاح عنصر ما من المصفوفة. $userdb = ['Sandra Shush', 'Stefanie Mcmohn', 'Michael']; $pos = array_search('Stefanie Mcmohn', $userdb); if ($pos !== false) { echo "Stefanie Mcmohn found at $pos"; } الإصدار PHP 5.x من 5.5 وما فوق يمكنك بدءًا من الإصدار PHP 5.5 وما بعده استخدام array_column() بالتزامن مع array_search() ويعدّ هذا مفيدًا بشكلٍ خاص للتحقق من وجود قيمة في المصفوفة الترابطية: $userdb = [ [ "uid" => '100', "name" => 'Sandra Shush', "url" => 'urlof100', ], [ "uid" => '5465', "name" => 'Stefanie Mcmohn', "pic_square" => 'urlof100', ], [ "uid" => '40489', "name" => 'Michael', "pic_square" => 'urlof40489', ] ]; $key = array_search(40489, array_column($userdb, 'uid')); واجهات ArrayAccess وIterator الميزة المفيدة الأخرى هي الوصول إلى تجميعات الكائن المخصص كمصفوفات في PHP، يوجد واجهتين في PHP بدءًا من الإصدار PHP 5.0.0 لدعم ذلك وهما: ArrayAccess وIterator يتيحان لك الوصول إلى الكائنات المخصصة على أنّها مصفوفات. ArrayAccess بفرض لدينا الصنف user يعبر عن مستخدم وجدول في قاعدة البيانات يخزن كل المستخدمين ونريد إنشاء الصنف UserCollection ليقوم بما يلي: يسمح لنا بمخاطبة مستخدم عن طريق معرف الاسم الفريد. أداء العمليات الأساسية (ليس كل عمليات CRUD - الإنشاء والقراءة والتحديث والحذف - إنما على الأقل الإنشاء والاستعادة والحذف) على مجموعة المستخدمين لدينا. انتبه أننا نستخدم الصياغة القصيرة لإنشاء مصفوفة [] والمتاحة بدءًا من الإصدار 5.4: class UserCollection implements ArrayAccess { protected $_conn; protected $_requiredParams = ['username','password','email']; public function __construct() { $config = new Configuration(); $connectionParams = [ // معلومات الاتصال بقاعدة البيانات ]; $this->_conn = DriverManager::getConnection($connectionParams, $config); } protected function _getByUsername($username) { $ret = $this->_conn->executeQuery('SELECT * FROM `User` WHERE `username` IN (?)', [$username])->fetch(); return $ret; } // ArrayAccess بدء التوابع المطلوبة من public function offsetExists($offset) { return (bool) $this->_getByUsername($offset); } public function offsetGet($offset) { return $this->_getByUsername($offset); } public function offsetSet($offset, $value) { if (!is_array($value)) { throw new \Exception('value must be an Array'); } $passed = array_intersect(array_values($this->_requiredParams), array_keys($value)); if (count($passed) < count($this->_requiredParams)) { throw new \Exception('value must contain at least the following params: ' .implode(',', $this->_requiredParams)); } $this->_conn->insert('User', $value); } public function offsetUnset($offset) { if (!is_string($offset)) { throw new \Exception('value must be the username to delete'); } if (!$this->offsetGet($offset)) { throw new \Exception('user not found'); } $this->_conn->delete('User', ['username' => $offset]); } // ArrayAccess بدء التوابع المطلوبة من } بعد ذلك يمكننا كتابة: $users = new UserCollection(); var_dump(empty($users['testuser']),isset($users['testuser'])); $users['testuser'] = ['username' => 'testuser', 'password' => 'testpassword', 'email' => 'test@test.com']; var_dump(empty($users['testuser']), isset($users['testuser']), $users['testuser']); unset($users['testuser']); var_dump(empty($users['testuser']), isset($users['testuser'])); بفرض أنه لا يوجد لدينا المستخدم testuser قبل تنفيذ الشيفرة فسيكون لدينا الخرج التالي: bool(true) bool(false) bool(false) bool(true) array(17) { ["username"]=> string(8) "testuser" ["password"]=> string(12) "testpassword" ["email"]=> string(13) "test@test.com" } bool(true) bool(false) ملاحظة: لا تُستدعى الدالة offsetExists عندما تريد التحقق من وجود مفتاح مع دالة array_key_exists، لذا فإنّ الشيفرة التالية سيكون خرجها false مرتين: var_dump(array_key_exists('testuser', $users)); $users['testuser'] = ['username' => 'testuser', 'password' => 'testpassword', 'email' => 'test@test.com']; var_dump(array_key_exists('testuser', $users)); Iterator سنوسع الصنف في الأعلى بإضافة عدة دوال من الواجهة Iterator لنستطيع استخدام التكرار مع foreach وwhile. نحتاج أولًا إلى خاصيّة تحتوي الفهرس الحالي للمكرِّر، سنسميها $_position ونضيفها إلى خاصيّات الصنف: // Iterator موقع المكرِّر الحالي مطلوب من توابع الواجهة protected $_position = 1; ثم نضيف الواجهة Iterator إلى قائمة الواجهات التي سينفذها صنفنا: class UserCollection implements ArrayAccess, Iterator { ثم نضيف المطلوب من دوال الواجهة Iterator: // Iterator بدء التوابع المطلوبة من الواجهة public function current () { return $this->_getById($this->_position); } public function key () { return $this->_position; } public function next () { $this->_position++; } public function rewind () { $this->_position = 1; } public function valid () { return null !== $this->_getById($this->_position); } // Iterator نهاية التوابع المطلوبة من الواجهة أصبح لدينا مصدر كامل لتنفيذ الصنف لكِلا الواجهتين، لاحظ أنّ هذا المثال ليس مثاليًا لأنّ المعرفات في قاعدة البيانات قد لا تكون تسلسلية لكن كتبناه لإعطائك فكرةً أساسيةً وهي أنّه بإمكانك مخاطبة تجميعات الكائنات بأي طريقة ممكنة عن طريق تنفيذ الواجهتين ArrayAccess وIterator. class UserCollection implements ArrayAccess, Iterator { // Iterator موقع المكرِّر الحالي المطلوب من توابع الواجهة protected $_position = 1; // <إضافة التوابع القديمة من الشيفرة السابقة هنا> // Iterator بدء التوابع المطلوبة من الواجهة public function current () { return $this->_getById($this->_position); } public function key () { return $this->_position; } public function next () { $this->_position++; } public function rewind () { $this->_position = 1; } public function valid () { return null !== $this->_getById($this->_position); } // Iterator نهاية التوابع المطلوبة من الواجهة } ولكتابة حلقة تمر على كل الكائنات من نوع user باستخدام foreach: foreach ($users as $user) { var_dump($user['id']); } سينتج عن الشيفرة السابقة الخرج التالي: string(2) "1" string(2) "2" string(2) "3" string(2) "4" ... تكرار عدة مصفوفات معًا قد نحتاج أحيانًا إلى تكرار مصفوفتين لهما نفس الطول معًا مثال: $people = ['Tim', 'Tony', 'Turanga']; $foods = ['chicken', 'beef', 'slurm']; أبسط طريقة لتنفيذ ذلك هي استخدام الدالة array_map: array_map(function($person, $food) { return "$person likes $food\n"; }, $people, $foods); سينتج عن ذلك الخرج التالي: assert(count($people) === count($foods)); for ($i = 0; $i < count($people); $i++) { echo "$people[$i] likes $foods[$i]\n"; } إذا لم يكن للمصفوفتين مفاتيح تكرارية يمكننا استخدام array_values($array)[$i] بدلًا من $array[$i]، وإذا كان لهما نفس ترتيب المفاتيح يمكننا استخدام حلقة foreach مع مفتاح على إحداهما: foreach ($people as $index => $person) { $food = $foods[$index]; echo "$person likes $food\n"; } يمكن تكرار المصفوفات المستقلة فقط إذا كان لها نفس الطول ونفس اسم المفتاح، أي أنّه إذا لم يكن للمصفوفات مفاتيحًا فالمفاتيح مرقمة وهذا جيّد أو يمكنك تسمية المفاتيح ووضعهم في نفس الترتيب لكل مصفوفة، ويمكنك أيضًا استخدام الدالة array_combine. $combinedArray = array_combine($people, $foods); // $combinedArray = ['Tim' => 'chicken', 'Tony' => 'beef', 'Turanga' => 'slurm']; بعدها يمكنك كتابة حلقة تكرار كما في السابق: foreach ($combinedArray as $person => $meal) { echo "$person likes $meal\n"; } استخدام فهرس تزايدي تعمل هذه الطريقة على زيادة عدد صحيح من 0 وحتى أكبر فهرس في المصفوفة. $colors = ['red', 'yellow', 'blue', 'green']; for ($i = 0; $i < count($colors); $i++) { echo 'I am the color ' . $colors[$i] . '<br>'; } يمكنك أيضًا المرور على جميع عناصر المصفوفة بترتيب عكسي دون استخدام الدالة array_reverse التي قد تزيد الحِمل إذا كانت المصفوفة كبيرة. $colors = ['red', 'yellow', 'blue', 'green']; for ($i = count($colors) - 1; $i >= 0; $i--) { echo 'I am the color ' . $colors[$i] . '<br>'; } يمكنك تخطي أو إرجاع الفهرس بسهولة مستخدمًا هذه الطريقة. $array = ["alpha", "beta", "gamma", "delta", "epsilon"]; for ($i = 0; $i < count($array); $i++) { echo $array[$i], PHP_EOL; if ($array[$i] === "gamma") { $array[$i] = "zeta"; $i -= 2; } elseif ($array[$i] === "zeta") { $i++; } } الخرج: alpha beta gamma beta zeta epsilon لا يمكن أن نقوم بهذا بشكلٍ مباشر في المصفوفات التي لا تحوي فهارس تزايدية (بما في ذلك المصفوفات التي تكون فهارسها بترتيب عكسي مثل: [1 => "foo", 0 => "bar"], ["foo" => "f", "bar" => "b"])، لذا نستخدم الدوال array_values أو array_keys: $array = ["a" => "alpha", "b" => "beta", "c" => "gamma", "d" => "delta"]; $keys = array_keys($array); for ($i = 0; $i < count($array); $i++) { $key = $keys[$i]; $value = $array[$key]; echo "$value is $key\n"; } استخدام مؤشرات المصفوفة الداخلية تحوي كل نسخة مصفوفة مؤشرًا داخليًا، يمكن باستخدام هذا المؤشر استعادة عناصر مختلفة من المصفوفة عن طريق نفس الاستدعاء في مرات مختلفة. استخدام الدالة each يُرجع كل استدعاء للدالة مفتاح وقيمة عنصر المصفوفة الحالي ويزيد مؤشر المصفوفة الداخلي. $array = ["f" => "foo", "b" => "bar"]; while (list($key, $value) = each($array)) { echo "$value begins with $key"; } استخدام الدالة next $array = ["Alpha", "Beta", "Gamma", "Delta"]; while (($value = next($array)) !== false) { echo "$value\n"; } لاحظ أنّ هذا المثال يفترض أنّه لا يوجد عناصر في المصفوفة معرّفة بالقيمة المنطقية false، لمنع هذا الافتراض نستخدم الدالة key للتحقق من وصول المؤشر الداخلي إلى نهاية المصفوفة: $array = ["Alpha", "Beta", "Gamma", "Delta"]; while (key($array) !== null) { echo current($array) . PHP_EOL; next($array); } ويسهّل هذا أيضًا تكرار المصفوفة دون حلقة مباشرة: class ColorPicker { private $colors = ["#FF0064", "#0064FF", "#64FF00", "#FF6400", "#00FF64", "#6400FF"]; public function nextColor() : string { $result = next($colors); // إذا وصلت لنهاية المصفوفة if (key($colors) === null) { reset($colors); } return $result; } } استخدام foreach حلقة مباشرة foreach ($colors as $color) { echo "I am the color $color<br>"; } حلقة مع مفاتيح $foods = ['healthy' => 'Apples', 'bad' => 'Ice Cream']; foreach ($foods as $key => $food) { echo "Eating $food is $key"; } حلقة بالمرجعية إنّ تعديل قيمة ($color أو $food) في الأمثلة السابقة بشكلٍ مباشر لا يغيّر قيمتها في المصفوفة إنّما يجب استخدام العامل & لتصبح القيمة هي مؤشر مرجعي للعنصر في المصفوفة. $years = [2001, 2002, 3, 4]; foreach ($years as &$year) { if ($year < 2000) $year += 2000; } الشيفرة السابقة مماثلة للشيفرة التالية: $years = [2001, 2002, 3, 4]; for($i = 0; $i < count($years); $i++) { $year = &$years[$i]; if($year < 2000) $year += 2000; } التزامن يمكن تعديل مصفوفات PHP أثناء التكرار بدون مشاكل تزامن، إذا كانت المصفوفة تُكرَّر بالمرجع فإنّ التكرارات اللاحقة ستتأثر بتغييرات المصفوفة وإلا فإنّها لن تتأثر (كما لو أنّك تكرر نسخة من المصفوفة نفسها)، وازن التكرار بالقيمة: $array = [0 => 1, 2 => 3, 4 => 5, 6 => 7]; foreach ($array as $key => $value) { if ($key === 0) { $array[6] = 17; unset($array[4]); } echo "$key => $value\n"; } الخرج: 0 => 1 2 => 3 4 => 5 6 => 7 أما إذا كانت المصفوفة تُكرَّر بالمرجع: $array = [0 => 1, 2 => 3, 4 => 5, 6 => 7]; foreach ($array as $key => &$value) { if ($key === 0) { $array[6] = 17; unset($array[4]); } echo "$key => $value\n"; } الخرج: 0 => 1 2 => 3 6 => 17 لن تُكرَّر مجموعة القيمة-المفتاح 4 => 5 وستتغير 6 => 7 إلى 6 => 17. استخدام المكرِّر ArrayObject يسمح لك الصنف arrayiterator بتعديل وإلغاء ضبط القيم أثناء تكرار المصفوفات والكائنات. مثال: $array = ['1' => 'apple', '2' => 'banana', '3' => 'cherry']; $arrayObject = new ArrayObject($array); $iterator = $arrayObject->getIterator(); for($iterator; $iterator->valid(); $iterator->next()) { echo $iterator->key() . ' => ' . $iterator->current() . "</br>"; } الخرج: 1 => apple 2 => banana 3 => cherry ترجمة -وبتصرف- للفصول [Arrays - Array iteration] من كتاب PHP Notes for Professionals book اقرأ أيضًا المقال التالي: التنفيذ على المصفوفات والتعامل معها في PHP المقال السابق: المراجع (references) في PHP1 نقطة
-
تطبيق دالة على كل عنصر من عناصر المصفوفة نستخدم الدالة array_map() لتطبيق دالة على جميع عناصر مصفوفة ما، وتُرجع لنا مصفوفة جديدة: $array = array(1,2,3,4,5); // يتم المرور على كل عنصر من عناصر المصفوفة ويُخزَّن في معامل الدالة $newArray = array_map(function($item) { return $item + 1; }, $array); // array(2,3,4,5,6) الآن $newArray قيمة يمكنك استخدام دالة ذات اسم بدلًا من استخدام دالة مجهولة الاسم، فنكتب الشيفرة السابقة كالتالي: function addOne($item) { return $item + 1; } $array = array(1, 2, 3, 4, 5); $newArray = array_map('addOne', $array); إذا كانت الدالة المسمّاة هي تابع صنف فيجب تضمين مرجع إلى كائن الصنف الذي يعود التابع له عند استدعاء الدالة: class Example { public function addOne($item) { return $item + 1; } public function doCalculation() { $array = array(1, 2, 3, 4, 5); $newArray = array_map(array($this, 'addOne'), $array); } } الطريقة الثانية لتطبيق دالة على عناصر المصفوفة هي استخدام الدالة array_walk() والدالة array_walk_recursive()، يُمرَّر رد النداء (callback) إلى هاتين الدالتين ويأخذ مفتاح/فهرس وقيمة كل عنصر من عناصر المصفوفة، لا ترجع هذه الدوال دوالًا جديدة إنّما تُرجع قيمة منطقية تدل على نجاح تنفيذ الدالة، يمكننا مثلًا طباعة كل عنصر في المصفوفة بكتابة الشيفرة التالية: $array = array(1, 2, 3, 4, 5); array_walk($array, function($value, $key) { echo $value . ' '; }); // "1 2 3 4 5" يمكن تمرير قيمة معامل رد النداء بالمرجعية مما يسمح لك بتمرير القيمة مباشرةً في المصفوفة الأصلية: $array = array(1, 2, 3, 4, 5); array_walk($array, function(&$value, $key) { $value++; }); // array(2,3,4,5,6) الآن $array قيمة نستخدم الدالة array_walk_recursive() مع المصفوفات المتداخلة (nested) للتعامل مع كل مصفوفة فرعية: $array = array(1, array(2, 3, array(4, 5), 6); array_walk_recursive($array, function($value, $key) { echo $value . ' '; }); // "1 2 3 4 5 6" لاحظ أنّ الدالتين array_walk() وarray_walk_recursive() يسمحان لك بتغيير قيمة عناصر المصفوفة وليس المفاتيح، كما أنّه يمكنك تمرير المفاتيح بالمرجع في رد النداء لكن هذا ليس له تأثير. تقسيم المصفوفة إلى أجزاء (chunks) تقسّم الدالة array_chunk() المصفوفة إلى أجزاء صغيرة. بفرض لدينا الدالة أحادية البعد التالية: $input_array = array('a', 'b', 'c', 'd', 'e'); وطبّقنا الدالة array_chunk() عليها: $output_array = array_chunk($input_array, 2); تقسّم الشيفرة السابقة المصفوفة إلى مصفوفات أصغر تحتوي كلّ منها عنصرين وتنشئ مصفوفة جديدة متعددة الأبعاد: Array ( [0] => Array ( [0] => a [1] => b ) [1] => Array ( [0] => c [1] => d ) [2] => Array ( [0] => e ) ) إذا لم يكن من الممكن تقسيم عناصر المصفوفة بالتساوي وفقًا للحجم المحدد فإنّ المصفوفة الأخيرة ستحمل العناصر الباقية وتكون أصغر من باقي المصفوفات. إذا مررنا للوسيط الثاني عددًا أصغر من 1 سيُرمى E_WARNING وستكون مصفوفة الخرج NULL. المعامل تفاصيل $array (array) مصفوفة الدخل التي نريد العمل عليها $size (int) حجم المصفوفة الصغيرة (عدد صحيح) $preserve_keys (boolean) (اختياري) FALSE وإلا TRUE إذا أردت أن تحافظ المصفوفات الصغيرة على المفاتيح تكون قيمته 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; } تجميع عناصر مصفوفة لتشكيل سلسلة نصية تجمع الدالة implode() كل قيم المصفوفة لكنها تفقد معلومات المفاتيح: $arr = ['a' => "AA", 'b' => "BB", 'c' => "CC"]; echo implode(" ", $arr); // AA BB CC نستطيع تجميع المفاتيح باستدعاء الدالة array_keys(): $arr = ['a' => "AA", 'b' => "BB", 'c' => "CC"]; echo implode(" ", array_keys($arr)); // a b c يعدّ تجميع القيم مع المفاتيح أكثر تعقيدًا لكن يمكن القيام به بنمط الدالة: $arr = ['a' => "AA", 'b' => "BB", 'c' => "CC"]; echo implode(" ", array_map(function($key, $val) { // دالة تربط المفتاح بالقيمة return "$key:$val"; }, array_keys($arr), $arr)); // a:AA b:BB c:CC تفكيك مصفوفة باستخدام list() يمكن استخدام الدالة list() لإسناد قائمة من قيم المتغيرات إلى مصفوفة. كما يمكنك الاطلاع على الدالة compact(). // بمفاتيح مرقمة تبدأ من الصفر $array إلى عناصر المصفوفة $a,$b,$c إسناد قيم المتغيرات list($a, $b, $c) = $array; بدءًا من الإصدار 7.1 يمكنك استخدام الصيغة المختصرة: // بمفاتيح مرقمة تبدأ من الصفر $array إلى عناصر المصفوفة $a,$b,$c إسناد قيم المتغيرات [$a, $b, $c] = $array; //"a", "b", "c" والمفاتيح $array إلى عناصر المصفوفة $a,$b,$c إسناد قيم المتغيرات ["a" => $a, "b" => $b, "c" => $c] = $array; الدالة array_reduce تختزل الدالة array_reduce المصفوفة إلى قيمة واحدة. تمرّ الدالة على كل عنصر من عناصر المصفوفة بنتيجة مُعادة من التكرار السابق وتنتج قيمة جديدة تحتفظ بها للتكرار التالي. الاستخدام: array_reduce ($array, function($carry, $item){...}, $defaul_value_of_first_carry) $carry هي النتيجة المعادة من التكرار السابق و$item يحمل قيمة التكرار الحالي. مجموع مصفوفة $result = array_reduce([1, 2, 3, 4, 5], function($carry, $item){ return $carry + $item; }); // 15 أكبر عدد في المصفوفة $result = array_reduce([10, 23, 211, 34, 25], function($carry, $item){ return $item > $carry ? $item : $carry; }); // 211 هل كل العناصر أكبر من 100 $result = array_reduce([101, 230, 210, 341, 251], function($carry, $item){ return $carry && $item > 100; }, true); // true يجب أن تكون القيمة الافتراضية // true هل يوجد عنصر أصغر من 100 $result = array_reduce([101, 230, 21, 341, 251], function($carry, $item){ return $carry || $item < 100; }, false); // false يجب أن تكون القيمة الافتراضية // true تجميع مصفوفة $result = array_reduce(["hello", "world", "PHP", "language"], function($carry, $item){ return !$carry ? $item : $carry . "-" . $item ; }); // "hello-world-PHP-language" يمكنك أيضًا كتابة تابع للتجميع: function implode_method($array, $piece){ return array_reduce($array, function($carry, $item) use ($piece) { return !$carry ? $item : ($carry . $piece . $item); }); } $result = implode_method(["hello", "world", "PHP", "language"], "-"); // "hello-world-PHP-language" دفع عنصر إلى نهاية مصفوفة يوجد طريقتين لدفع عنصر إلى مصفوفة: الدالة array_push() و$array[] =. نستخدم الدالة array_push() كما يلي: $array = [1,2,3]; $newArraySize = array_push($array, 5, 6); // يُرجع التابع الحجم الجديد للمصفوفة print_r($array); // تُمرّر المصفوفة بالمرجع لذا تُعدّل المصفوفة الأساسية لتحتوي العناصر الجديدة ستطبع الشيفرة: Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 5 [4] => 6 ) نستخدم $array[] = كالتالي: $array = [1,2,3]; $array[] = 5; $array[] = 6; print_r($array); تطبع الشيفرة السابقة: Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 5 [4] => 6 ) ترشيح (Filtering) مصفوفة نستخدم الدالة array_filter لترشيح قيم من المصفوفة والحصول على مصفوفة جديدة تحقق كل شروط المُرشِّح. ترشيح القيم غير الفارغة أفضل حالة للترشيح هي إزالة جميع القيم الفارغة: $my_array = [1,0,2,null,3,'',4,[],5,6,7,8]; $non_empties = array_filter($my_array); // $non_empties will contain // [1,2,3,4,5,6,7,8] هو $non_empties يصبح محتوى المصفوفة الترشيح برد النداء بفرض أننا نريد الحصول على القيم الزوجية فقط: $my_array = [1,2,3,4,5,6,7,8]; $even_numbers = array_filter($my_array, function($number) { return $number % 2 === 0; }); تستقبل الدالة array_filter المصفوفة التي نريد ترشيحها في الوسيط الأول أما الوسيط الثاني فهو المُرشِّح الذي نريد تطبيقه. الإصدار PHP 5.6 وما بعده الترشيح تبعًا للفهرس يمكننا تمرير معامل ثالث للدالة array_filter يسمح بتعديل القيم الممررة إلى رد النداء، يمكن ضبط هذا المعامل على أنّه ARRAY_FILTER_USE_KEY أو ARRAY_FILTER_USE_BOTH، وهو يسمح أن يستقبل رد النداء المفاتيح بدلًا من القيم أو كلًا من المفاتيح والقيم كوسطاء. فإذا أردت التعامل مع الفهارس بدلًا من القيم مثلًا: $numbers = [16,3,5,8,1,4,6]; $even_indexed_numbers = array_filter($numbers, function($index) { return $index % 2 === 0; }, ARRAY_FILTER_USE_KEY); الفهارس في المصفوفة المرشَّحة لاحظ أنّ الدالة array_filter تحافظ على مفاتيح المصفوفة الأصلية، ومن الخطأ أن تقوم بتنفيذ حلقة for على المصفوفة المُرشَّحة: $my_array = [1,0,2,null,3,'',4,[],5,6,7,8]; $filtered = array_filter($my_array); // إظهار كل الأخطاء والملاحظات error_reporting(E_ALL); // for من الخطأ استخدام حلقة for ($i = 0; $i < count($filtered); $i++) { print $filtered[$i]; } /* :الخرج 1 Notice: Undefined offset: 1 2 Notice: Undefined offset: 3 3 Notice: Undefined offset: 5 4 Notice: Undefined offset: 7 */ حدث هذا لأن قيم الفهارس 1، 3، 5، 7 التي هي 0، null، سلسلة فارغة ''، مصفوفة فارغة [] على الترتيب قد حُذفت مع فهارسها. إذا كنت تحتاج تمرير حلقة على نتيجة مُرشِّح طُبِّق على مصفوفة مفهرسة، يجب أن تستدعي الدالة array_values لنتيجة الدالة array_filter لتُنشئ مصفوفة جديدة مع فهارس صحيحة: $my_array = [1,0,2,null,3,'',4,[],5,6,7,8]; $filtered = array_filter($my_array); $iterable = array_values($filtered); error_reporting(E_ALL); // إظهار كل الأخطاء والملاحظات for ($i = 0; $i < count($iterable); $i++) { print $iterable[$i]; } // لا يوجد تحذيرات إزالة عناصر من مصفوفة لإزالة عنصر من مصفوفة مثلًا العنصر الذي فهرسه 1: $fruit = array("bananas", "apples", "peaches"); unset($fruit[1]); ستزيل الشيفرة السابقة العنصر apples من المصفوفة لكن لاحظ أنّ الدالة unset لا تغيّر فهارس باقي العناصر لذا فإنّ المصفوفة $fruit تحتوي الآن الفهارس 0 و2. يمكنك الحذف في المصفوفات الترابطية كما يلي: $fruit = array('banana', 'one'=>'apple', 'peaches'); print_r($fruit); /* Array ( [0] => banana [one] => apple [1] => peaches ) */ unset($fruit['one']); تصبح الآن المصفوفة $fruit: print_r($fruit); /* Array ( [0] => banana [1] => peaches ) */ لاحظ أنّ الشيفرة التالية: unset($fruit); تزيل تعيين المتغير لذا تحذف كامل المصفوفة أي أنّه لم يعد بإمكاننا الوصول إلى أي عنصر من عناصرها. إزالة عناصر الأطراف تُزيل الدالة array_shift() عنصرًا من بداية المصفوفة. مثال: $fruit = array("bananas", "apples", "peaches"); array_shift($fruit); print_r($fruit); الخرج: Array ( [0] => apples [1] => peaches ) تُزيل الدالة array_pop() عنصرًا من نهاية المصفوفة. مثال: $fruit = array("bananas", "apples", "peaches"); array_pop($fruit); print_r($fruit); الخرج: Array ( [0] => bananas [1] => apples ) ترتيب مصفوفة يوجد عدة دوال لترتيب المصفوفات في PHP: الدالة sort() ترتّب هذه الدالة عناصر المصفوفة ترتيبًا تصاعديًّا وفقًا لقيمها. $fruits = ['Zitrone', 'Orange', 'Banane', 'Apfel']; sort($fruits); print_r($fruits); /* Array ( [0] => Apfel [1] => Banane [2] => Orange [3] => Zitrone ) */ الدالة rsort() ترتّب هذه الدالة عناصر المصفوفة ترتيبًا تنازليًّا وفقًا لقيمها. $fruits = ['Zitrone', 'Orange', 'Banane', 'Apfel']; rsort($fruits); print_r($fruits); /* Array ( [0] => Zitrone [1] => Orange [2] => Banane [3] => Apfel ) */ الدالة asort() تُرتِّب هذه الدالة عناصر المصفوفة ترتيبًا تصاعديًّا وتحافظ على اقتران الفهارس مع القيم المرتبطة بها. $fruits = [1 => 'lemon', 2 => 'orange', 3 => 'banana', 4 => 'apple']; asort($fruits); print_r($fruits); /* Array ( [4] => apple [3] => banana [1] => lemon [2] => orange ) */ الدالة arsort() تُرتِّب هذه الدالة عناصر المصفوفة ترتيبًا تنازليًّا وتحافظ على اقتران الفهارس مع القيم المرتبطة بها. $fruits = [1 => 'lemon', 2 => 'orange', 3 => 'banana', 4 => 'apple']; arsort($fruits); print_r($fruits); /* Array ( [2] => orange [1] => lemon [3] => banana [4] => apple ) */ الدالة ksort() تُرتّب هذه الدالة المصفوفة ترتيبًا تصاعديًّا حسب المفتاح. $fruits = ['d'=>'lemon', 'a'=>'orange', 'b'=>'banana', 'c'=>'apple']; ksort($fruits); print_r($fruits); /* Array ( [a] => orange [b] => banana [c] => apple [d] => lemon ) */ الدالة krsort() تُرتّب هذه الدالة المصفوفة ترتيبًا تنازليًّا حسب المفتاح. $fruits = ['d'=>'lemon', 'a'=>'orange', 'b'=>'banana', 'c'=>'apple']; krsort($fruits); print_r($fruits); /* Array ( [d] => lemon [c] => apple [b] => banana [a] => orange ) */ الدالة natsort() ترتّب هذه الدالة المصفوفة بنفس الطريقة التي يرتّب بها الإنسان (ترتيب طبيعي). $files = ['File8.stack', 'file77.stack', 'file7.stack', 'file13.stack', 'File2.stack']; natsort($files); print_r($files); /* Array ( [4] => File2.stack [0] => File8.stack [2] => file7.stack [3] => file13.stack [1] => file77.stack ) */ الدالة natcasesort() ترتّب هذه الدالة المصفوفة بنفس الطريقة التي يرتّب بها الإنسان (ترتيب طبيعي) لكن غير حساسة لحالة الأحرف. $files = ['File8.stack', 'file77.stack', 'file7.stack', 'file13.stack', 'File2.stack']; natcasesort($files); print_r($files); /* Array ( [4] => File2.stack [2] => file7.stack [0] => File8.stack [3] => file13.stack [1] => file77.stack ) */ الدالة shuffle() تخلط هذه الدالة عناصر المصفوفة (ترتيب عشوائي). $array = ['aa', 'bb', 'cc']; shuffle($array); print_r($array); بما أنّ الترتيب عشوائي فليس هناك نتيجة واحدة محددة للشيفرة السابقة، فقد تكون مثلًا: Array ( [0] => cc [1] => bb [2] => aa ) الدالة usort() ترتّب هذه الدالة المصفوفة باستخدام دالة موازنة معرّفة من قبل المستخدم. function compare($a, $b) { if ($a == $b) { return 0; } return ($a < $b) ? -1 : 1; } $array = [3, 2, 5, 6, 1]; usort($array, 'compare'); print_r($array); /* Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 5 [4] => 6 ) */ الدالة uasort() ترتّب هذه الدالة المصفوفة باستخدام دالة موازنة معرّفة من قبل المستخدم وتحافظ على ارتباط الفهارس بالقيم المقابلة. function compare($a, $b) { if ($a == $b) { return 0; } return ($a < $b) ? -1 : 1; } $array = ['a' => 1, 'b' => -3, 'c' => 5, 'd' => 3, 'e' => -5]; uasort($array, 'compare'); print_r($array); /* Array ( [e] => -5 [b] => -3 [a] => 1 [d] => 3 [c] => 5 ) */ الدالة uksort() ترتّب هذه الدالة المصفوفة حسب المفاتيح باستخدام دالة موازنة معرّفة من قبل المستخدم. function compare($a, $b) { if ($a == $b) { return 0; } return ($a < $b) ? -1 : 1; } $array = ['ee' => 1, 'g' => -3, '4' => 5, 'k' => 3, 'oo' => -5]; uksort($array, 'compare'); print_r($array); /* Array ( [ee] => 1 [g] => -3 [k] => 3 [oo] => -5 [4] => 5 ) */ إضافة بعض مفاتيح المصفوفة إلى اللائحة البيضاء يمكنك استخدام الدالتين array_intersect_key وarray_flip معًا عندما تريد السماح بوجود مفاتيح محددة فقط في المصفوفة خاصةً عندما تأتي المفاتيح من معاملات طلب ما. $parameters = ['foo' => 'bar', 'bar' => 'baz', 'boo' => 'bam']; $allowedKeys = ['foo', 'bar']; $filteredParameters = array_intersect_key($parameters, array_flip($allowedKeys)); // $filteredParameters = ['foo' => 'bar', 'bar' => 'baz] إذا لم يحتوي متغير المعاملات على أي مفتاح مسموح به فإنّ المتغير filteredParameters سيكون مصفوفة فارغة. ويمكنك أيضًا استخدام الدالة array_filter لنفس الوظيفة بدءًا من الإصدار PHP 5.6، ممررًا الراية ARRAY_FILTER_USE_KEY كمعامل ثالث. $parameters = ['foo' => 1, 'hello' => 'world']; $allowedKeys = ['foo', 'bar']; $filteredParameters = array_filter( $parameters, function ($key) use ($allowedKeys) { return in_array($key, $allowedKeys); }, ARRAY_FILTER_USE_KEY ); يوفر استخدام الدالة arrayfilter مرونةً إضافيةً لإجراء اختبار عشوائي على المفاتيح، فمثلًا يمكن أن تحتوي المصفوفة $allowedKeys أنماطًا تعبيرية بدلًا من السلاسل النصية العادية، كما أنّها تذكر الهدف من الشيفرة بشكلٍ أكثر صراحة من الدالتين array_intersect_key وarray_flip. إضافة عنصر إلى بداية المصفوفة يمكنك استخدام الدالة array_unshift() عند الحاجة إلى إضافة عنصر في بداية المصفوفة دون تغيير في ترتيب العناصر الحالية، إذ تضيف هذه الدالة العناصر الممررة بالكامل إلى بداية المصفوفة فتبقى العناصر الممررة بنفس الترتيب، وتعدَّل جميع المفاتيح العددية لتبدأ من الصفر بينما تبقى المفاتيح التي تكون بشكل سلسلة نصية كما هي. $myArray = array(1, 2, 3); array_unshift($myArray, 4); print_r($myArray); // Array ( [0] => 4 [1] => 1 [2] => 2 [3] => 3 ) بما أنّ الدالة array_unshift() تُجبر المصفوفة على إعادة تعيين أزواج مفتاح - قيمة والعنصر الجديد يجعل مفاتيح المداخل التالية تبدأ من n+1 فمن الأسهل إنشاء مصفوفة جديدة وإضافة المصفوفة الحالية إلى المصفوفة المُنشأة حديثًا. مثال: $myArray = array('apples', 'bananas', 'pears'); $myElement = array('oranges'); $joinedArray = $myElement; foreach ($myArray as $i) { $joinedArray[] = $i; } // Array ( [0] => oranges [1] => apples [2] => bananas [3] => pears ) يمكنك الاطلاع على المثال هنا تبادل القيم مع المفاتيح تستبدل الدالة array_flip() كل مفاتيح المصفوفة بالقيم المرتبطة معها. $colors = array( 'one' => 'red', 'two' => 'blue', 'three' => 'yellow', ); array_flip($colors); /* array( 'red' => 'one', 'blue' => 'two', 'yellow' => 'three' ) */ دمج مصفوفتين في مصفوفة واحدة تدمج الدالة array_merge() مصفوفتين أو أكثر. $a1 = array("red","green"); $a2 = array("blue","yellow"); print_r(array_merge($a1,$a2)); /* Array ( [0] => red [1] => green [2] => blue [3] => yellow ) */ المصفوفة الترابطية: $a1=array("a"=>"red","b"=>"green"); $a2=array("c"=>"blue","b"=>"yellow"); print_r(array_merge($a1,$a2)); /* Array ( [a] => red [b] => yellow [c] => blue ) */ تُدمج العناصر من مصفوفة أو واحدة أكثر فتُضاف قيم إحداها إلى نهاية المصفوفة الأخرى وتُرجع المصفوفة النهائية. إذا كان لمصفوفات الدخل نفس المفاتيح المكونة من سلاسل نصية فإنّ القيمة اللاحقة للمفتاح ستكتب فوق القيمة السابقة له أما إذا كانت المفاتيح عددية فإنّ القيمة اللاحقة ستُضاف ولن تكتب فوق القيمة السابقة للمفتاح. إذا كانت مفاتيح مصفوفة الدخل رقمية سيُعاد ترقيم القيم في مصفوفة النتيجة بمفاتيح تزايدية ابتداءً من الصفر. معالجة عدة مصفوفات معًا تقاطع (intersection) المصفوفات تُرجع الدالة array_intersect مصفوفة من القيم الموجودة في جميع المصفوفات الممررة إليها وتحافظ على المفاتيح المرتبطة مع القيم المعادة. $array_one = ['one', 'two', 'three']; $array_two = ['two', 'three', 'four']; $array_three = ['two', 'three']; $intersect = array_intersect($array_one, $array_two, $array_three); // $intersect = ['two', 'three'] تتحقق الدالة array_intersect من قيم المصفوفات فقط أما الدالة array_intersect_assoc تُرجع تقاطع القيم مع المفاتيح المرتبطة بها. $array_one = [1 => 'one',2 => 'two',3 => 'three']; $array_two = [1 => 'one', 2 => 'two', 3 => 'two', 4 => 'three']; $array_three = [1 => 'one', 2 => 'two']; $intersect = array_intersect_assoc($array_one, $array_two, $array_three); // $intersect = [1 =>'one',2 => 'two'] تتحقق الدالة array_intersect_key من التقاطع بتفحص المفاتيح فقط وتُرجع المفاتيح الموجودة في جميع المصفوفات الممررة. $array_one = [1 => 'one',2 => 'two',3 => 'three']; $array_two = [1 => 'one', 2 => 'two', 3 => 'four']; $array_three = [1 => 'one', 3 => 'five']; $intersect = array_intersect_key($array_one, $array_two, $array_three); // $intersect = [1 =>'one',3 => 'three'] دمج أو ضم مصفوفتين $fruit1 = ['apples', 'pears']; $fruit2 = ['bananas', 'oranges']; $all_of_fruits = array_merge($fruit1, $fruit2); //$all_of_fruits = [0 => 'apples', 1 => 'pears', 2 => 'bananas', 3 => 'oranges'] لاحظ أنّ الدالة array_merge() ستغيّر الفهارس الرقمية وتكتب فوق الفهارس النصية. $fruit1 = ['one' => 'apples', 'two' => 'pears']; $fruit2 = ['one' => 'bananas', 'two' => 'oranges']; $all_of_fruits = array_merge($fruit1, $fruit2); //$all_of_fruits = ['one' => 'bananas', 'two' => 'oranges'] تعيد الدالة array_merge() كتابة قيم المصفوفة الثانية فوق قيم المصفوفة الأولى إذا لم تستطع إعادة ترقيم فهارسها. يمكنك استخدام العامل + لدمج مصفوفتين بطريقة لا يمكن فيها للقيم أن يُكتب فوقها لكنها لا تُعيد ترقيم الفهارس العددية لذا تخسر قيم المصفوفات التي لها فهرس مُستخدم في المصفوفة الأولى. $fruit1 = ['one' => 'apples', 'two' => 'pears']; $fruit2 = ['one' => 'bananas', 'two' => 'oranges']; $all_of_fruits = $fruit1 + $fruit2; // $all_of_fruits = ['one' => 'apples', 'two' => 'pears'] $fruit1 = ['apples', 'pears']; $fruit2 = ['bananas', 'oranges']; $all_of_fruits = $fruit1 + $fruit2; // $all_of_fruits = [0 => 'apples', 1 => 'pears'] تغيير مصفوفة متعددة الأبعاد إلى مصفوفة ترابطية إذا كان لديك مصفوفة متعددة الأبعاد مثل: [ ['foo', 'bar'], ['fizz', 'buzz'], ] وتريد تغييرها إلى مصفوفة ترابطية مثل: [ 'foo' => 'bar', 'fizz' => 'buzz', ] فيمكنك استخدام الشيفرة التالية: $multidimensionalArray = [ ['foo', 'bar'], ['fizz', 'buzz'], ]; $associativeArrayKeys = array_column($multidimensionalArray, 0); $associativeArrayValues = array_column($multidimensionalArray, 1); $associativeArray = array_combine($associativeArrayKeys, $associativeArrayValues); أو يمكنك تخطي الإعداد $associativeArrayKeys و$associativeArrayValues واستخدام الشيفرة البسيطة التالية: $associativeArray = array_combine(array_column($multidimensionalArray, 0), array_column($multidimensionalArray, 1)); جمع مصفوفتين (المفاتيح من واحدة والقيم من الأخرى) تنشئ الدالة array_combine() مصفوفةً جديدةً عن طريق استخدام المفاتيح من أحد المصفوفات والقيم من مصفوفة أخرى. يبين المثال التالي كيفية دمج مصفوفتين في مصفوفة واحدة ترابطية فيها المفاتيح من المصفوفة الأولى والقيم من المصفوفة الثانية: $array_one = ['key1', 'key2', 'key3']; $array_two = ['value1', 'value2', 'value3']; $array_three = array_combine($array_one, $array_two); var_export($array_three); /* array ( 'key1' => 'value1', 'key2' => 'value2', 'key3' => 'value3', ) */ مكتبة PHP المعيارية لهياكل البيانات (SPL) SplFixedArray الاختلاف عن مصفوفة PHP يُنفَّذ نوع المصفوفة الافتراضي في PHP كخرائط hash مرتبة مما يسمح لنا بإنشاء مصفوفات تحتوي على الأزواج قيمة/مفتاح، يمكن أن تكون القيم من أي نوع والمفاتيح إما أرقام أو سلاسل نصية، ومع ذلك فإنّ هذه ليست الطريقة التقليدية لإنشاء المصفوفات. كما تلاحظ في الرسم التوضيحي فإنّه من الممكن أن تُعرض مصفوفة PHP مثل مجموعة مرتبة من الأزواج قيمة/مفتاح حيث يُربَط كل مفتاح إلى أي قيمة. لاحظ أنّه في هذه المصفوفة لدينا مفاتيح عددية ومفاتيح بشكل سلاسل نصية بالإضافة إلى قيم من أنواع مختلفة والمفتاح ليس له تأثير على ترتيب العناصر. $arr = [ 9 => "foo", 1 => 4.2, "bar" => null, ]; foreach($arr as $key => $value) { echo "$key => $value\n"; } تعطينا الشيفرة السابقة ما نتوقعه تمامًا: 9 => foo 1 => 4.2 bar => يُحدد حجم مصفوفات PHP العادية ديناميكيًا، ويزداد وينقص هذا الحجم بإضافة أو حذف عناصر إلى ومن المصفوفة بشكلٍ تلقائي، أما في المصفوفات التقليدية يكون الحجم ثابتًا وتتألف المصفوفة بالكامل من نفس نوع القيم ويمكننا الوصول إلى أي قيمة باستخدام الفهارس بدلًا من المفاتيح ويمكن استنتاج الفهرس من إزاحة القيمة في المصفوفة. وبما أننا سنعرف حجم نوع معين والحجم الثابت للمصفوفة فإنّ الإزاحة هي حجم النوع * n، إذ تمثّل n موضع القيمة في المصفوفة، يعطينا $arr[0] في المثال السابق القيمة 1 ويعطينا العنصر الأول في المصفوفة $arr[1] القيمة 2 وهكذا… ومع ذلك لا يقيّد الصنف SplFixedArray نوع القيم إنما يقيد نوع المفاتيح فقط والتي يجب أن تكون عددية، ?وأيضًا ذات حجم ثابت، وهذا يجعل المصفوفات من النوع SplFixedArray أكثر فعاليةٍ من المصفوفات العادية بطريقةٍ معينة فهي أصغر وتتطلب ذاكرة أقل. تهيئة المصفوفة تُنفَّذ المصفوفة من النوع SplFixedArray ككائن لكن يمكن الوصول إليها بنفس الصياغة التي نصل فيها إلى مصفوفة PHP العادية بما أنّها تنفّذ الواجهة ArrayAccess وتنفّذ أيضًا الواجهات Countable وIterator لذا لها نفس سلوك مصفوفات PHP العادية الذي اعتدت عليه (أي الأشياء مثل count($arr) وforeach($arr as $k => $v) تعمل بنفس الطريقة في المصفوفات من النوع SplFixedArray والمصفوفات العادية). يأخذ باني المصفوفة من النوع SplFixedArray وسيطًا واحدًا يعبّر عن حجم المصفوفة. $arr = new SplFixedArray(4); $arr[0] = "foo"; $arr[1] = "bar"; $arr[2] = "baz"; foreach($arr as $key => $value) { echo "$key => $value\n"; } تعطيك الشيفرة السابقة النتيجة: 0 => foo 1 => bar 2 => baz 3 => كما أنّ الشيفرة: var_dump(count($arr)); تعطينا ما نتوقع: int(4) لاحظ أنه في المصفوفات من النوع SplFixedArray يصف المفتاح ترتيب العنصر في المصفوفة لأنه فهرس حقيقي وليس مجرد خريطة كما في المصفوفات العادية.? تغيير حجم المصفوفة تذكر دائمًا بما أنّ المصفوفة ذات حجم ثابت فإنّ عدّها سيعيد دائمًا القيمة نفسها، لذا طالما أنّ نتيجة unset($arr[1]) هي $arr[1] === null تبقى نتيجة count($arr) هي 4، وتحتاج لتغيير حجم المصفوفة إلى استدعاء التابع setSize: $arr->setSize(3); var_dump(count($arr)); foreach($arr as $key => $value) { echo "$key => $value\n"; } الآن نحصل على النتيجة: int(3) 0 => foo 1 => 2 => baz الاستيراد من SplFixedArray والتصدير إلى SplFixedArray يمكنك استيراد/تصدير مصفوفة عادية إلى/من مصفوفة SplFixedArray باستخدام التوابع fromArray وtoArray. $array = [1,2,3,4,5]; $fixedArray = SplFixedArray::fromArray($array); foreach($fixedArray as $value) { echo $value, "\n"; } // 1 2 3 4 5 $fixedArray = new SplFixedArray(5); $fixedArray[0] = 1; $fixedArray[1] = 2; $fixedArray[2] = 3; $fixedArray[3] = 4; $fixedArray[4] = 5; $array = $fixedArray->toArray(); foreach($array as $value) { echo $value, "\n"; } // 1 2 3 4 5 ترجمة -وبتصرف- للفصول [Executing Upon an Array - Manipulating an Array - Processing Multiple Arrays Together - SPL data structures] من كتاب PHP Notes for Professionals book اقرأ أيضًا المقال التالي: التعامل مع الوقت والتاريخ في PHP المقال السابق: المصفوفات (Arrays) في PHP1 نقطة
-
الصنف Datetime إنشاء نسخة Datetime ثابتة من متغير يمكنك استخدام الشيفرة التالية لإنشاء \DateTimeImmutable في PHP الإصدار 5.6 وما بعده: \DateTimeImmutable::createFromMutable($concrete); أما في الإصدارات السابقة يمكنك استخدام: \DateTimeImmutable::createFromFormat(\DateTime::ISO8601, $mutable->format(\DateTime::ISO8601), $mutable->getTimezone()); إضافة أو طرح تاريخ نستخدم الصنف DateInterval لإضافة أو طرح فترة زمنية في كائن DateTime، إليك المثال التالي الذي نطرح فيه 7 أيام ونطبع رسالة على الشاشة: // التعليمة التالية بدون وسيط تُرجع التاريخ الحالي $now = new DateTime(); // الكائن التالي يمثل فترة زمنية مدتها 7 أيام $interval = new DateInterval('P7D'); // DateTime التعليمة التالية ستُرجع كائن $lastDay = $now->add($interval); // ويُرجع سلسلة نصية DateTime ينسّق هذا التابع كائن $formatedLastDay = $lastDay->format('Y-m-d'); echo "Samara says: Seven Days. You'll be happy on $formatedLastDay."; /* عند تنفيذ هذه الشيفرة في 1-8-2016 يكون الخرج Samara says: Seven Days. You'll be happy on 2016-08-08. */ نستطيع استخدام التابع الفرعي بطريقة مشابهة لطرح التواريخ: $now->sub($interval); echo "Samara says: Seven Days. You were happy last on $formatedLastDay."; /* عند تنفيذ هذه الشيفرة في 1-8-2016 يكون الخرج Samara says: Seven Days. You were happy last on 2016-07-25. */ getTimestamp getTimeStemp هو تمثيل unix لكائن من الصنف datetime. $date = new DateTime(); echo $date->getTimestamp(); سيؤدي ذلك إلى وضع مؤشر صحيح للثواني التي انقضت منذ 00:00:00 UTC، الخميس، 1 كانون الثاني 1970. setDate تضبط هذه الدالة التاريخ لكائن من الصنف datetime. $date = new DateTime(); $date->setDate(2016, 7, 25); تضبط هذه الشيفرة التاريخ ليصبح 25 تموز، 2015 وخرجها: 2016-07-25 17:52:15.819442 إنشاء DateTime من تنسيق معين إنّ PHP قادرة على تحليل عدة تنسيقات للتاريخ، يمكنك استخدام التابع الساكن DateTime::createFromFormat إذا أردت تحليل تنسيق غير معياري أو إذا أردت أن تحدد في شيفرتك تنسيق التاريخ المُستخدم بشكلٍ صريح: نمط كائني التوجه $format = "Y,m,d"; $time = "2009,2,26"; $date = DateTime::createFromFormat($format, $time); نمط إجرائي $format = "Y,m,d"; $time = "2009,2,26"; $date = date_create_from_format($format, $time); طباعة DateTime توفر PHP من الإصدار 4 وما بعده تابع تنسيق كائني التوجه يحول كائن DateTime إلى سلسلة نصية بالتنسيق الذي تريده: public string DateTime::format ( string $format ) تأخذ الدالة date() معاملًا واحدًا format بشكل سلسلة نصية ويستخدم محارف مفردة لتعريف التنسيق: Y: أربعة أرقام تمثل السنة (2016 مثلًا). y: رقمين يمثلان السنة (16 مثلًا). m: يمثّل الشهر بتنسيق رقم (من 01 إلى 12). M: يمثّل الشهر بثلاثة أحرف (مثل …Jan, Feb, Mar). j: يمثّل يوم في الشهر دون أصفار بادئة (من 1 إلى 31). D: يمثّل يوم في الأسبوع بثلاثة أحرف (مثل …Mon, Tue, Wed). h: يمثّل الساعة بتنسيق 12-ساعة (01 إلى 12). H: يمثّل الساعة بتنسيق 24-ساعة (00 إلى 23). A: إما AM أو PM. i: يمثّل الدقائق دون أصفار بادئة (من 00 إلى 59). s: يمثّل الثواني دون أصفار بادئة (من 00 إلى 59). يمكنك الاطلاع على اللائحة الكاملة هنا. الاستخدام يمكن استخدام هذه المحارف في تركيبات مختلفة لعرض الوقت بأي تنسيق تريده، إليك بعض الأمثلة: $date = new DateTime('2000-05-26T13:30:20'); /* Friday, May 26, 2000 at 1:30:20 PM */ $date->format("H:i"); /* 13:30 */ $date->format("H i s"); /* 13 30 20 */ $date->format("h:i:s A"); /* 01:30:20 PM */ $date->format("j/m/Y"); /* 26/05/2000 */ $date->format("D, M j 'y - h:i A"); /* Fri, May 26 '00 - 01:30 PM */ التنسيق الكائني التوجه: $date->format($format) التنسيق الإجرائي المشابه: date_format($date, $format) الحصول على الفرق بين تاريخين/وقتين يعدّ استخدام الصنف DateTime الطريقة الأكثر عمليّة لنحصل على الفرق بين تاريخين أو وقتين، مثال: <?php // DateTime إنشاء كائن من الصنف $twoYearsAgo = new DateTime("2014-01-18 20:05:56"); // DateTime إنشاء كائن ثاني من الصنف $now = new DateTime("2016-07-21 02:55:07"); // حساب الفرق $diff = $now->diff($twoYearsAgo); // فرق السنوات بين التاريخين $diff->y يحتوي $yearsDiff = $diff->y; // فرق الدقائق بين التاريخين $diff->m يحتوي $monthsDiff = $diff->m; // فرق الأيام بين التاريخين $diff->d يحتوي $daysDiff = $diff->d; // فرق الساعات بين التاريخين $diff->h يحتوي $hoursDiff = $diff->h; // فرق الدقائق بين التاريخين $diff->i يحتوي $minsDiff = $diff->i; // فرق الثواني بين التاريخين $diff->s يحتوي $secondsDiff = $diff->s; // فرق الأيام بين التاريخين $diff->days يحتوي $totalDaysDiff = $diff->days; // $diff استخلاص معلومات المتغير var_dump($diff); يمكننا أيضًا استخدام عوامل الموازنة للموازنة بين تاريخين بشكلٍ أسهل: <?php // DateTime إنشاء كائن من الصنف $twoYearsAgo = new DateTime("2014-01-18 20:05:56"); // DateTime إنشاء كائن ثاني من الصنف $now = new DateTime("2016-07-21 02:55:07"); var_dump($now > $twoYearsAgo); // bool(true) var_dump($twoYearsAgo > $now); // bool(false) var_dump($twoYearsAgo <= $twoYearsAgo); // bool(true) var_dump($now == $now); // bool(true) تغيير التاريخ إلى تنسيق آخر أسهل طريقة لتغيير تنسيق التاريخ إلى تنسيق آخر هي استخدام strtotime() مع date()، إذ أنّ strtotime() ستغير التاريخ إلى تنسيق الختم الزمني unix ثمّ يُمرَّر إلى date() لتغييره إلى تنسيق جديد. $timestamp = strtotime('2008-07-01T22:35:17.02'); $new_date_format = date('Y-m-d H:i:s', $timestamp); يمكن كتابة الشيفرة السابقة بسطرٍ واحد: $new_date_format = date('Y-m-d H:i:s', strtotime('2008-07-01T22:35:17.02')); تذكّر أنّ الدالة strtotime() تحتاج أن يكون التاريخ بتنسيقٍ صالح وإلا ستُرجع false وتصبح قيمة التاريخ 1969-12-31. استخدام DateTime() توفر PHP بدءًا من الإصدار 5.2 الصنف DateTime() الذي يمنح أدوات قوية للعمل مع التاريخ والوقت، يمكننا استخدامه لكتابة الشيفرة السابقة كالتالي: $date = new DateTime('2008-07-01T22:35:17.02'); $new_date_format = $date->format('Y-m-d H:i:s'); العمل مع الأختام الزمنية unix تأخذ الدالة date() معاملها الثاني بصيغة ختم زمني unix وتُرجع تاريخ منسّق: $new_date_format = date('Y-m-d H:i:s', '1234567890'); يعمل DateTime() مع الختم الزمني unix بإضافة @ قبل الختم الزمني: $date = new DateTime('@1234567890'); $new_date_format = $date->format('Y-m-d H:i:s'); إذا كان الختم الزمني لديك مقدّر بأجزاء الثانية (قد تكون نهايته 000 و/أو يتكون من 13 محرف) ستحتاج أن تحوّله إلى الثواني قبل أن تستطيع تغيير تنسيقه، يوجد طريقتين للقيام بذلك: حذف آخر 3 أرقام باستخدام substr(): يمكن حذف الأرقام الثلاثة الأخيرة بعدة طرق لكن أسهلها استخدام substr(): $timestamp = substr('1234567899000', -3); القسمة على 1000: يمكنك أيضًا تحويل الختم الزمني إلى الثواني عن طريق القسمة على 1000، يمكنك استخدام المكتبة BCMath للقيام بالعمليات الرياضية كسلاسل نصية لأنّ الختم الزمني كبير جدًا على أنظمة 32 بت: $timestamp = bcdiv('1234567899000', '1000'); يمكنك استخدام strtotime() للحصول على ختم زمني unix: $timestamp = strtotime('1973-04-18'); يمكنك استخدام DateTime::getTimestamp() مع DateTime(): $date = new DateTime('2008-07-01T22:35:17.02'); $timestamp = $date->getTimestamp(); يمكنك بدلًا من ذلك استخدام خيار التنسيق U إذا كنت تستخدم الإصدار PHP 5.2: $date = new DateTime('2008-07-01T22:35:17.02'); $timestamp = $date->format('U'); العمل مع تنسيق التاريخ الغامض وغير المعياري لسوء الحظ ليست كل التواريخ التي يحتاج المطور أن يتعامل معها تكون منسّقة بطريقة معيارية، لكن لحسن الحظ وفرت PHP 5.3 حلًّا لذلك، تسمح لنا DateTime::createFromFormat() بأن نخبر PHP عن تنسيق التاريخ لذا يمكن تحليلها بنجاح إلى كائن DateTime لمزيد من المعالجة. $date = DateTime::createFromFormat('F-d-Y h:i A', 'April-18-1973 9:48 AM'); $new_date_format = $date->format('Y-m-d H:i:s'); أعطتنا PHP 5.4 قابلة الوصول إلى عنصر في الصنف عند إنشاء نسخة مما يسمح لنا أن نكتب الشيفرة السابقة في سطر واحد: $new_date_format = (new DateTime('2008-07-01T22:35:17.02'))->format('Y-m-d H:i:s'); لكن هذا لا يعمل مع DateTime::createFromFormat() بعد. تحليل وصف التاريخ باللغة الانكليزية إلى تنسيق تاريخ يمكن تحليل نصوص مختلفة باللغة الانكليزية إلى تواريخ باستخدام الدالتين strtotime() وdate() معًا. // طباعة التاريخ الحالي echo date("m/d/Y", strtotime("now")), "\n"; // m/d/Y طباعة تاريخ 10 أيلول، 2000 بالتنسيق echo date("m/d/Y", strtotime("10 September 2000")), "\n"; // طباعة تاريخ الأمس echo date("m/d/Y", strtotime("-1 day")), "\n"; // طباعة نتيجة تاريخ اليوم + أسبوع echo date("m/d/Y", strtotime("+1 week")), "\n"; // طباعة نتيجة تاريخ اليوم + أسبوع ويومين و4 ساعات وثانيتين echo date("m/d/Y", strtotime("+1 week 2 days 4 hours 2 seconds")), "\n"; // طباعة تاريخ يوم الخميس القادم echo date("m/d/Y", strtotime("next Thursday")), "\n"; // طباعة تاريخ الاثنين الماضي echo date("m/d/Y", strtotime("last Monday")), "\n"; // طباعة تاريخ اليوم الأول من الشهر القادم echo date("m/d/Y", strtotime("First day of next month")), "\n"; // طباعة تاريخ اليوم الأخير من الشهر القادم echo date("m/d/Y", strtotime("Last day of next month")), "\n"; // طباعة تاريخ اليوم الأول من الشهر الماضي echo date("m/d/Y", strtotime("First day of last month")), "\n"; // طباعة تاريخ اليوم الأخير من الشهر الماضي echo date("m/d/Y", strtotime("Last day of last month")), "\n"; استخدام ثوابت معرّفة مسبقًا لتنسيق التاريخ بدءًا من الإصدار PHP 5.1.0 يمكننا استخدام ثوابت معرّفة مسبقًا لتنسيق التاريخ في الدالة date() بدلًا من السلاسل النصية. ثوابت تنسيق التاريخ المعرّفة مسبقًا المتاحة: DATE_ATOM // (2016-07-22T14:50:01+00:00) (ATOM) الذرة DATE_COOKIE // (Friday, 22-Jul-16 14:50:01 UTC) HTTP ملفات تعريف الارتباط DATE_RSS // (Fri, 22 Jul 2016 14:50:01 +0000) RSS DATE_W3C // (2016-07-22T14:50:01+00:00) اتحاد شبكة الويب العالمية DATE_ISO8601 // (2016-07-22T14:50:01+0000) ISO-8601 DATE_RFC822 // (Fri, 22 Jul 16 14:50:01 +0000) RFC 822 DATE_RFC850 // (Friday, 22-Jul-16 14:50:01 UTC) RFC 850 DATE_RFC1036 // (Fri, 22 Jul 16 14:50:01 +0000) RFC 1036 DATE_RFC1123 // (Fri, 22 Jul 2016 14:50:01 +0000) RFC 1123 DATE_RFC2822 // (Fri, 22 Jul 2016 14:50:01 +0000) RFC 2822 DATE_RFC3339 // (2016-07-22T14:50:01+00:00) DATE_ATOM نفس أمثلة: echo date(DATE_RFC822); // Fri, 22 Jul 16 14:50:01 +0000 echo date(DATE_ATOM,mktime(0,0,0,8,15,1947)); // 1947-08-15T00:00:00+05:30 ترجمة -وبتصرف- للفصول [Datetime Class - Working with Dates and Time] من كتاب PHP Notes for Professionals book اقرأ أيضًا المقال التالي: بنى التحكم والحلقات التكرارية في PHP المقال السابق: التنفيذ على المصفوفات والتعامل معها في PHP تعلم PHP1 نقطة
-
شاع استخدام مصطلح البيانات الضخمة Big Data في الآونة الأخيرة، فبعد أن صارت البيانات تُجمع بمعدل غير مسبوق من كل شيء حولنا، سواءً من أجهزة الاستشعار الخاصة بأجهزة إنترنت الأشياء IoT، أو إشارات نظام تحديد المواقع العالمي GPS من الهواتف المحمولة، أو منشورات وسائل التواصل الاجتماعي، أو المعاملات التجارية التي نجريها عبر الإنترنت، وغيرها من المصادر المتنوعة، مما زاد من حجم البيانات كثيرًا؛ دفع هذا الأمر الشركات للاستفادة من هذه البيانات وتحليلها واتخاذ القرارات بناءً عليها، وعليه صارت الكثير من القطاعات اليوم تسعى للاستفادة من هذا الكم الهائل من هذه البيانات لفهم توقعات عملائها وتعزيز عملياتها التجارية وزيادة قدرتها التنافسية في السوق. وفي ظل هذا التوجه والسعي الكبير لجمع البيانات وتحليلها، قد يخطر ببالنا سؤال مهم وهو هل البيانات الضخمة ضرورية بالفعل لعملنا؟ وهل تمتلك الشركات التي تستفيد من البيانات الضخمة قدرةً أكبر على تطوير الحلول المبتكرة مقارنةً بتلك التي نكتفي بالتعامل مع البيانات الصغيرة والمتوسطة الحجم أو التي تعرف باسم البيانات التقليدية؟ سنحاول في هذا المقال الإجابة على هذه التساؤلات، ونعقد مقارنةً بين البيانات الضخمة والبيانات التقليدية وحالات استخدام كل منهما. ما هي البيانات الضخمة Big Data البيانات الضخمة هي بيانات تستخدم لاستخراج وتحليل وإدارة معالجة أحجام هائلة ومعقدة من البيانات التي تنمو بتسارع. ووفقًا لمعدل أُسِّي، فهي تجمع باستمرار من مختلف المصادر وقد يصل حجمها إلى أرقام مهولة وضخمة جدًا. تتسم البيانات الضخمة بتنوع أشكالها، فهي لا تقتصر على البيانات المنظمة المخزنة في قواعد البيانات، بل تشمل أيضًا بيانات غير منظمة مثل النصوص والصور ومقاطع الفيديو. تتدفق هذه البيانات بسرعة كبيرة، لذا يصعب تسجيلها أو تخزينها أو تحليلها باستخدام أنظمة إدارة قواعد البيانات التقليدية، وهذا يستدعي منا استخدام تقنيات متقدمة للتعامل معها. تتميز البيانات الضخمة بخمس سمات رئيسية يشار لها اختصارًا بـ 5Vs، وهي: الحجم Volume: الذي يشير لكمية البيانات الإجمالية، والذي قد يصل إلى عشرات التيرابايت TeraByte السرعة Velocity: وتشير لسرعة توليد البيانات ومعالجتها وتحليلها التنوع Variety: ويشمل بيانات بأشكال مختلفة الدقة Veracity: وتحدد مدى موثوقية البيانات وصحتها وخلوها من الأخطاء القيمة Value: فتراكم البيانات وحده لا يخلق قيمة للبيانات بل يجب أن توفر هذه البيانات فائدة فعلية للعمل وإلا فلا داعي لتكديسها تُستخدم البيانات الضخمة في العديد من المجالات لتحسين العمليات واتخاذ القرارات الذكية؛ ففي الرعاية الصحية، تساعد في تقديم رعاية مخصصة واكتشاف الأمراض مبكرًا؛ أما في تجارة التجزئة، فتُستخدم لتحليل سلوك العملاء وتقديم توصيات مخصصة وتحسين إدارة المخزون؛ وفي القطاع المالي، تساهم في كشف الاحتيال وتقييم المخاطر الائتمانية؛ أما في قطاع الطاقة، فهي تُستخدم للتنبؤ بالطلب وتحسين كفاءة التوزيع والاستهلاك؛ وفي المدن الذكية، تعزز كفاءة الخدمات عبر تحليل البيانات المتعلقة بالمرور وإدارة الموارد وصيانة البنية التحتية. مصادر البيانات الضخمة قد تكون البيانات الضخمة بأشكال متنوعة ومن مصادر عديدة تشمل: البيانات المنظمة Structured Data على شكل جداول يسهل البحث فيها وتحليلها باستخدام استعلامات محددة تشبه جداول إكسل وقواعد البيانات العلاقية Relational Database، ومن الأمثلة عليها البيانات التي نجمعها من التطبيقات والمواقع الإلكترونية كسجلات المستخدمين أو سجلات المعاملات البنكية. البيانات غير المنظمة Unstructured Data من الصعب هيكلتها ضمن جداول، مثل مقاطع الفيديو والتغريدات ومنشورات وسائل التواصل الاجتماعي، أو بيانات أجهزة إنترنت الأشياء IoT، وهي تحتوي على قيمة تحليلية عالية، لكنها أصعب في التحليل وتحتاج لأساليب متقدمة لتخزين وتحليل البيانات. البيانات شبه المنظمة Semi-Structured Data وهي نوع هجين يحتوي على بعض التنظيم، ولكنه لا يتناسب تمامًا مع قواعد البيانات التقليدية كالبيانات التي تجمعها أجهزة الاستشعار ورسائل البريد الإلكتروني وملفات XML وJSON. أدوات التعامل مع البيانات الضخمة عند اعتماد البيانات الضخمة في بيئة العمل، سنحتاج لاستخدام العديد من الأدوات الاحترافية والمتخصصة للتعامل مع حجمها الهائل وتعقيدها. يمكن تقسيم هذه الأدوات إلى أربع أنواع رئيسية نوضحها فيما يلي: أدوات التخزين يجب أن تتمتع أنظمة تخزين البيانات الضخمة بالقدرة على استيعاب كميات ضخمة من البيانات مع إمكانية التوسع مع مرور الوقت وضمان سرعة نقل البيانات إلى أنظمة المعالجة والتحليل. ومن أبرز التقنيات المستخدمة في هذا المجال منصات تخزين البيانات الموزعة مثل Hadoop HDFS وAmazon S3. أدوات التنقيب في البيانات تهدف إلى استخراج أنماط ورؤى ذات قيمة من كم هائل من البيانات، مما يمكن المؤسسات من التنبؤ بالاتجاهات المستقبلية واتخاذ قرارات أدق. من بين الأدوات المستخدمة في التنقيب في البيانات Apache Spark MLlib وGoogle BigQuery، والتي تعتمد على تقنيات الذكاء الاصطناعي وتعلم الآلة. أدوات تنظيف البيانات قبل تحليل البيانات، يجب تنظيفها والتأكد من خلوها من الأخطاء وتوحيدها قبل معالجتها. تستخدم في هذه المرحلة أدوات مثل Trifacta و OpenRefine لضمان دقة البيانات وتحسين جودتها. أدوات تحليل البيانات بعد تنظيف البيانات، سنحتاج لمعالجتها وتحليلها لاستخلاص رؤى واضحة حول الأنماط والاتجاهات المستقبلية. سنحتاج لأدوات مختلفة لإجراء التحليل مثل Apache Kafka وTableau وPower BI لعرض البيانات بطريقة مرئية تدعم اتخاذ القرارات وتساعدنا على الإجابة على أسئلة معينة حول هذه البيانات وكما نلاحظ، فالعملية ليست بالسهولة التي قد تبدو عليها، إذ يتطلب التعامل مع البيانات الضخمة استخدام عدة أدوات وتقنيات، كما يحتاج لبنية تحتية قوية، ووجود خبرات بشرية متخصصة في هذا المجال، وسنواجه كذلك عدة تحديات أخرى سنناقشها في فقرة لاحقة يجب أخذها بالحسبان قبل أن نقرر جمعها والاعتماد عليها في أعمالنا. حالات استخدام البيانات الضخمة تتيح البيانات الضخمة للشركات والمؤسسات إمكانية جمع ومعالجة أحجام هائلة من البيانات في الوقت الفعلي، لكن البيانات الضخمة التي تجمعها الشركات بحد ذاتها ليس الهدف، فإن لم تكن لدى الشركة أهداف فعلية للاستفادة من هذه البيانات، فلا جدوى من جمعها وتكديسها لديها، وفيما يلي بعض حالات استخدام البيانات الضخمة المفيدة: كشف الاتجاهات والأنماط في سلوك العملاء من أجل توقع احتياجاتهم المستقبلية وتلبيتها تحليل تفضيلات العملاء وسلوكهم الشرائي لتخصيص المنتجات وفقًا لاحتياجاتهم مما يعزز رضاهم ويساهم في زيادة المبيعات المرونة والتكيف مع تغيرات السوق بسرعة والعمل على تحسين المنتجات الحالية أو تطوير منتجات جديدة اتخاذ قرارات استراتيجية في العمل وإيجاد فرص نمو جديدة تحديد نقاط الضعف في العمل واكتشاف الجوانب التي يمكن تحسينها، مثل تقليل التكاليف أو تحسين العمليات التشغيلية تقييم المخاطر والتعرف على التهديدات المحتملة في العمل بوقت مبكر وقبل أن تفع فعلًا، ووضع استراتيجيات فعالة لإدارتها والتخفيف من آثارها التنبؤ في الوقت الفعلي كأن نتوقع متى وأين سيزيد الطلب على منتج معين لتلبية احتياجات السوق وضمان وصوله للعملاء في الوقت المناسب فإذا لم تكن أولويات العمل تحتاج لتحليل سلوك العملاء، واتخاذ قرارات استراتيجية بناءً عليها، فلا داعي لتخزين البيانات بكميات ضخمة وتكبد وقت وجهد وتكلفة في تخزينها ومعالجتها. تحديات التعامل مع البيانات الضخمة ينشأ عن الاعتماد على البيانات الضخمة في العمل عدة تحديات وعوائق يجب الانتباه لها ومن أهمها: الخصوصية والأمان يمكن أن تصبح الكمية الضخمة من البيانات في المؤسسات هدفًا سهلًا للتهديدات الأمنية لاحتوائها على معلومات حساسة؛ فمع تزايد حجم البيانات، سيزداد خطر اختراقها وتسريبها، لذا يتوجب على الشركات الحفاظ على أمن بياناتها من خلال المصادقة المناسبة، والتشفير القوي والامتثال لمعايير صارمة لحمايتها. نمو البيانات بسرعة إن نمو البيانات بمعدل سريع يجعل من الصعب استخلاص الرؤى منها؛ فهناك المزيد والمزيد من البيانات التي يتم إنتاجها كل ثانية. ومن بين هذه البيانات، يجب انتقاء البيانات ذات الصلة والمفيدة فعليًا لتحليلها، كما يصعب على المؤسسات تخزين وإدارة كمية كبيرة من البيانات بدون الأدوات والتقنيات المناسبة. سرعة المعالجة بعض التطبيقات مثل أنظمة كشف الاحتيال تتطلب منا تحليل البيانات في الوقت الفعلي، وبالتالي سنحتاج لاستخدام تقنيات مخصصة، مثل Apache Flink و Spark Streaming لضمان الاستجابة الفورية بالوقت المناسب دون أي تأخير مشكلات جودة البيانات لا يمكن أن تكون البيانات الضخمة دقيقةً بنسبة 100٪، كما قد تحتوي على بيانات مكررة أو غير مكتملة؛ إضافةً إلى وجود ضوضاء وأخطاء عديدة فيها، لذا إن لم ننظف هذه البيانات ونجهز جيدًا فستؤدي إلى تحليلات غير دقيقة واستنتاجات خاطئة في العمل صعوبة دمج وتكامل البيانات تستورد فلبيانات من مصادر مختلفة وبصيغ متعددة، وقد لا تكون البيانات من مصدر معين محدثة مقارنةً مع البيانات من مصدر آخر. نقص الكفاءات المتخصصة يتطلب تحليل البيانات الضخمة مهارات تقنية متقدمة، مثل علم البيانات وتحليل البيانات، وعدد المتخصصين في هذا المجال لا يزال محدودًا لا سيما عربيًا. تحديات إدارية وتنظيمية قد تظهر بعض التحديات الإدارية والتنظيمية خلال التعامل مع الكم الهائل للبيانات الضخمة، مثل ضعف الحوكمة وعدم وجود سياسات وآليات واضحة لضبط جمع بيانات الأشخاص، وعدم وجود توضيحات كافية لطريقة استخدامها تضمن التعامل معها بأمان؛ لذا وقبل أن نقرر التعامل مع البيانات الضخمة، يجب أن تطرح على نفسنا السؤال التالي: هل نحن بحاجة فعلًا لكل هذا الكم الكبير من البيانات وكل هذه التحليلات المعقدة لنجاح عملنا، أم أن البيانات التقليدية ـأي البيانات الصغيرة والمتوسطة الحجم- وحدها تكفينا لتسيير أمور العمل بنجاح واستقرار. ما هي البيانات التقليدية؟ تشير البيانات التقليدية إلى البيانات المهيكلة التي يمكن تخزينها على هيئة جداول مكونة من أسطر وأعمدة بهيكلية واضحة ومنظمة، مثل معلومات العملاء وقوائم المخزون والسجلات المالية. وتعتمد معالجة البيانات في هذه الأنظمة على الأساليب الإحصائية التقليدية والأدوات، مثل لغة الاستعلامات الهيكلية SQL للبحث عن المعلومات واسترجاعها؛ فباستخدام هذه الأدوات، يمكن للشركات اتخاذ قرارات مفيدة وتحسين أدائها؛ وعلى الرغم من أن هذه البيانات المنظمة سهلة في التعامل، إلا أنها تكون قد محدودةً في حال احتجنا لتقديم رؤى متطورة ومعقدة تخص بعض الأعمال، مثل الحاجة لنظام مراقبة ذكي يراقب الأسواق المالية ويكشف الاحتيال في المعاملات البنكية فورًا. أدوات التعامل مع البيانات التقليدية البيانات التقليدية أسهل في التعامل من البيانات الضخمة لأنها غالبًا ما تكون صغيرة الحجم ومنظمةً جيدًا ومن أبرز أدوات البيانات التقليدية نذكر: قواعد البيانات العلائقية RDBM مثل MySQL و Oracle و SQL Server، والتي تستخدم لتخزين البيانات في جداول مترابطة، وهي مثالية للبيانات المنظمة والمهيكلة جداول البيانات Spreadsheets مثل إكسل Excel أو جداول جوجل Google Sheets لتحليل البيانات الصغيرة والمتوسطة خاصة عندما تكون البيانات محدودة ومنظمة برامج إدارة البيانات مثل SQLite التي تستخدم لتخزين وإدارة البيانات الصغيرة وتوفر لنا القدرة على إجراء بعض العمليات البسيطة على البيانات حالات استخدام البيانات التقليدية إذا كانت البيانات التي نجمعها في العمل هي بيانات منظمة مثل قواعد البيانات الجاهزة، فإن الحلول التقليدية مثل قواعد البيانات العلائقية غالبا ستكون كافيةً لإدارتها وتحليلها ولا داعي لأن نرهق أنفسنا بتعقيدات البيانات الضخمة. وفيما يلي بعض الحالات التي تعد فيها البيانات التقليدية هي الأنسب للاستخدام: إدارة السجلات المالية ضمن نظام يتعامل مع كمية محدودة من بيانات الفواتير والمدفوعات ويصدر تقارير مالية منظمة إدارة المخزون في متاجر صغيرة أو متوسطة تتضمن بيانات عن المنتجات والمبيعات ومستويات المخزون وتسعى لتحسين استراتيجيات المبيعات باستخدام قواعد بيانات تقليدية الرعاية الصحية ضمن مستشفيات تنظم وتدير معلومات المرضى، مع تتبع تاريخ المرضى ونتائج فحوصاتهم وتتابع خطط علاجهم وترقب التقدم في حالتهم الصحية إدارة الموظفين في الشركات الصغيرة والمتوسط باستخدام أنظمة تقليدية لتخزين المعلومات الشخصية للموظفين وجداول حضورهم وأدائهم إدارة المنصات التعليمية كالمدارس والمعاهد التعليمية التي تحتاج لإدارة بيانات الطلاب وتخزين درجاتهم وتتبع حضورهم ومستوياتهم الدراسية في كل هذه الحالات والحالات المشابهة، سيكون حجم البيانات محدودًا نسبيًا، أو ستكون البيانات منظمةً جيدًا، مما يسهّل معالجتها باستخدام الأنظمة التقليدية دون الحاجة إلى تقنيات معقدة كتلك التي تتطلبها البيانات الضخمة؛ أما في حال زاد تعقيد البيانات سواءً من حيث الحجم أو السرعة أو تنوع المصادر وكانت هناك حاجة لتحليلها بدقة واتخاذ قرارات بناءً عليها بسرعة، فعندها سيكون اللجوء إلى تقنيات البيانات الضخمة أمرًا ضروريًا. مميزات التعامل مع البيانات التقليدية يتسم التعامل مع البيانات التقليدية بما يلي: السهولة يمكن التعامل مع البيانات المعالجة باستخدام الأساليب التقليدية بسهولة باستخدام الأدوات القياسية، مما يجعلها أكثر سهولةً في التعامل ولا تتطلب معرفةً تقنيةً متقدمة. الوصول السريع للبيانات تقدم قواعد البيانات التقليدية وصولًا سريعًا وموثوقًا إلى البيانات من خلال العمل المستقل على خادم أو حاسوب محلي لا على بيئات سحابية أو خارجية، وتتجاوز مشكلات تأخير الشبكة أو انقطاع الخدمة أو اختراقات الأمان. سهولة حماية البيانات تُعَد البيانات الصغيرة والمتوسطة أسهل في تأمينها وحمايتها نظرًا لصغر حجمها وعدم اعتمادها على الهيكلية الموزعة، خاصةً وأنها لا تعتمد في أغلب الأحيان على التخزين الخارجي، مما يجعلها مناسبةً لإدارة المعلومات الحساسة أو السرية. سهولة إدارة البيانات تقدم قواعد البيانات التقليدية للمستخدمين تحكمًا كبيرًا في إدارة البيانات، حيث يمكن للمستخدمين تعريف أنواع البيانات، وتحديد القواعد بينها، وإنشاء العلاقات المخصصة وفقًا لاحتياجاتهم. تتطلب تكاليف وموارد أقل تتطلب الأساليب التقليدية تكاليف أقل وموارد أقل مقارنة بأنظمة معالجة البيانات الضخمة التي تتطلب تكاليف وموارد ضخمة. الخلاصة أصبحت البيانات الضخمة بلا شك جزءًا أساسيًا من العمليات التجارية والخدمات الحكومية، نظرًا للنمو السريع في حجم البيانات الرقمية. ومع تطور تقنيات الذكاء الاصطناعي، أتاح ذلك للمؤسسات القدرة على استخراج رؤى أكثر دقة واتخاذ قرارات أكثر ذكاءً وتحسينات كبيرة في مختلف القطاعات؛ لكن مع ذلك، ينبغي أن نتذكر أن البيانات الضخمة ليست مجرد جمع كميات هائلة من المعلومات، بل هي عملية تتطلب استراتيجيات مدروسة، وأدوات متخصصة، وتخطيطًا دقيقًا لتحقيق أقصى استفادة منها وتحويلها إلى قرارات تدعم النجاح والنمو. مع ذلك، وبالرغم من هذا التطور الكبير في مجال البيانات الضخمة، لازالت البيانات التقليدية الصغيرة والمتوسطة كافية للعديد من الحالات إن لم نقل أغلبها نظرًا لتوفير هذا النوع من البيانات حلولًا مناسبةً سهلة التعامل وبتكاليف أقل. لذا، متى لم يكن ما نعمل عليه يتطلب بيانات ضخمة للحصول على تحليلات وفهم كاف، فلا حاجة لأن نلجأ في أعمالنا لحلول البيانات الضخمة، لاسيما أنها تحتاج لخبرة وتكاليف أكبر وتعقيدات تقنية للتعامل مع البيانات وتحليلها وإدارتها، خاصةً وأننا إذا لم نحسن التعامل مع هذه البيانات ونستخدمها بطريقة صحيحة، فلن نتمكن من فهمها أو اتخاذ قرارات صائبة بناءً عليها. المصادر ?What is Big Data When to Use Big Data — and When Not To 7 Pros and Cons of Big Data Difference Between Traditional Data and Big Data Big Data Analytics Versus Traditional Data Analytics: A Comprehensive Overview اقرأ أيضًا مقدمة إلى مفهوم البيانات الضخمة Big Data المفاهيم الأساسية لتعلم الآلة أساسيات الذكاء الاصطناعي: دليل المبتدئين تعلم الذكاء الاصطناعي1 نقطة
-
سنشرح في هذا المقال طريقة بناء أداة ذكية للبحث داخل محادثات واتساب الخاصة بنا بعد تخزينها على هيئة ملفات PDF، تساعدنا هذه الأداة على البحث في محادثاتنا الشخصية و الوصول إلى معلومات محددة فيها بسرعة وكفاءة. سنوضح خطوة بخطوة طريقة استخراج النصوص من المحادثات وتحليلها، ثم تقسيمها إلى أجزاء صغيرة وتحويلها إلى تمثيلات رقمية Embeddings باستخدام نماذج ذكاء اصطناعي متقدمة مفتوحة المصدر لمعالجة اللغة الطبيعية يمكنها فهم السياق اللغوي حيث سنعتمد في أداتنا على نموذج BERT الذي يوفر إصدارات تدعم اللغة العربية لفهم وتحليل النصوص، وعلى نموذج Qwen لتوليد النصوص والردود التفاعلية، كما سنعتمد على قاعدة بيانات FAISS لنخزن التمثيلات الرقيمة لنصوص المحادثات وتمكين البحث السريع فيها، ونستخدم تقنية التوليد المعزز بالاسترجاع RAG للمساعدة في العثور على المعلومات المهمة في هذه المحادثات كالبحث عن مواعيد الاجتماعات والحجوزات، وتحديثات المشاريع بسرعة دون البحث المطول في سجل المحادثات. أخيرًا، سنوضح كيفية إنشاء واجهة تفاعلية سهلة الاستخدام تتيح لنا البحث في المحادثات والتفاعل معها بأمان، دون الحاجة إلى رفع بياناته إلى أي خوادم خارجية، مما يضمن الحفاظ على الخصوصية. متطلبات العمل أهم المتطلبات اللازمة لتنفيذ هذا المقال بنجاح: الحصول على مفتاح الوصول Token لاستخدام واجهة برمجة التطبيقات API الخاصة بمنصة Hugging Face معرفة أساسية بلغة البرمجة بايثون تثبيت Python على الجهاز مع محرر أكواد مناسب مثل Jupyter Notebook أو Visual Studio Code خطوات التطبيق العملي لنستعرض بالتفصيل خطوات التطبيق العملي لأداتنا الذكية للتفاعل مع رسائل واتساب. الخطوة 1: حفظ محادثات واتساب كملف PDF في البداية، نحتاج إلى تصدير محادثات واتساب الخاصة بنا وحفظها بصيغة PDF لتسهيل تحليلها لاحقًا. يتيح تطبيق WhatsApp ميزة تصدير الدردشة، والتي تمكننا من حفظ المحادثات كنصوص. بعد نجاح عملية التصدير، سنحويل المحادثات إلى تنسيق PDF لاستخدامها في التطبيق. لتصدير المحادثة، نفتح المحادثة المطلوبة، ثم ننقر على قائمة الخيارات أعلى يسار الدردشة ونختار المزيد، ثم نقل الدردشة من القائمة، ونحدد خيار -بدون وسائط- لحفظ النصوص فقط. بعد ذلك، يمكن فتح الملف الناتج بصيغة txt في أي تطبيق محرر نصوص مثل Microsoft Word أو Google Docs وتحويله إلى تنسيق pdf. الخطوة 2: استخراج النصوص من ملف PDF بعد حفظ محادثات واتساب بصيغة PDF، نحتاج إلى استخراج النصوص منها لمعالجتها وتحليلها. يمكننا تحقيق ذلك باستخدام مكتبة PyMuPDF مع LangChain، حيث تتيح لنا استخراج النصوص بسهولة من جميع صفحات ملف PDF على النحو التالي: # تثبيت المكتبات اللازمة !pip install langchain_community !pip install pymupdf # لتحميل الملف PyMuPDFLoader استيراد from langchain.document_loaders import PyMuPDFLoader # PDF تحميل ملف loader = PyMuPDFLoader("اسم الملف.pdf") # استخراج محتوى الملف pdf_text = loader.load() # دمج النصوص المستخرجة من جميع الصفحات في متغير واحد text = " ".join(page.page_content for page in pdf_text) يعمل الكود أعلاه على تثبيت المكتبات اللازمة وهي المكتبة langchain_community و pymupdf ثم يستخدم الصنف PyMuPDFLoader لتحميل ملف pdf واستخراج محتوياته، حيث يجمع النصوص من جميع صفحات الملف ويخزنها في المتغير text لاستخدامه لاحقًا في معالجة النصوص والبحث فيها. الخطوة 3: تقسيم النصوص إلى أجزاء صغيرة بعد استخراج النصوص من ملف pdf، سنحتاج إلى تقسيمها إلى أجزاء أصغر لتحسين كفاءة معالجتها وتحليلها. يساعد هذا التقسيم على تحسين أداء البحث والاسترجاع، كما يسهل على نماذج الذكاء الاصطناعي فهم البيانات بدقة أكبر. سنستخدم أداة CharacterTextSplitter من LangChain لتقسيم النص إلى مقاطع صغيرة بناءً على معايير مثل حجم الجزء، والفاصل بين الأجزاء، ومدى التداخل بينها. # استيراد أداة تقسيم النصوص from langchain.text_splitter import CharacterTextSplitter # إعداد معلمات تقسيم النصوص text_splitter = CharacterTextSplitter( separator="\n", chunk_size=500, chunk_overlap=100, length_function=len ) # تقسيم النص إلى أجزاء chunks = text_splitter.split_text(text) # طباعة عدد الأجزاء print(f"عدد الأجزاء: {len(chunks)}") يقسم الكود السابق النص text لأجزاء صغيرة باستخدام الصنف CharacterTextSplitter من LangChain، حيث حددنا هنا الفاصل separator الذي يحدد أماكن تقسيم النص ليكون فاصل الأسطر n\، مع ضبط الحد الأقصى لحجم كل جزء من النص أو عدد الأحرف في كل مقطع chunk_size ليكون 500 وحددنا عدد الأحرف المتداخلة بين الأجزاء chunk_overlap بقيمة 100 لضمان الاحتفاظ بالسياق، واستخدمنا الدالة length_function لحساب طول كل جزء، ثم طباعة عدد الأجزاء الناتجة. الخطوة 4: تحويل النصوص لتمثيلات رقمية Embeddings بعد تقسيم النصوص إلى أجزاء صغيرة، نحتاج إلى تحويلها إلى تضمينات أو تمثيلات رقمية Embeddings لنساعد النموذج على فهم السياق والعلاقات بين الكلمات والجمل. تلعب هذه التمثيلات الرقمية Embeddings دورًا أساسيًا في تحسين البحث داخل النصوص وتسمح لنا باسترجاع المعلومات الأكثر صلة بالاستفسارات. سنستخدم في هذه الخطوة مكتبة Sentence-Transformers لتحويل الأجزاء النصية إلى تمثيلات رقمية Embeddings. وسنختار نموذج AraBERT، لأنه مُدّرب خصيصًا على اللغة العربية ويوفّر تمثيلات دقيقة للنصوص العربية ويهدف إلى تحسين أداء المهام اللغوية المختلفة باللغة العربية مثل تصنيف النصوص، وتحليل المشاعر، والترجمة الآلية، والتعرف على الكيانات المُسماة NER. ولكونه مدُرّبًا باستخدام مجموعة ضخمة من النصوص العربية، فهو قادر على فهم التراكيب النحوية والدلالية الخاصة بالعربية بكفاءة. # SentenceTransformer استيراد from sentence_transformers import SentenceTransformer # تحميل نموذج يدعم العربية model = SentenceTransformer('aubmindlab/bert-base-arabertv02') # تحويل الأجزاء النصية إلى تمثيلات رقمية embeddings = model.encode(chunks, convert_to_tensor=True) يعمل الكود على تحميل نموذج BERT الداعم للغة العربية، ثم يحوّل قائمة chunks التي تحتوي على الأجزاء النصية إلى تمثيلات رقمية Embedding Vectors مع تمكين تحويل النتائج إلى موترات أو تنسورات Tensors لتحسين الأداء في العمليات الحسابية، فالتعلمية convert_to_tensor=True تجعل الخرج كائنًا من نوع Tensor بدلًا من مصفوفة NumPy، مما يسهل التعامل معه عند استخدام مكتبات مثل PyTorch. الخطوة 5: بناء قاعدة بيانات للبحث السريع باستخدام FAISS بعد تحويل النصوص إلى تمثيلات رقمية Embeddings، نحتاج إلى تخزينها بطريقة تتيح البحث السريع واسترجاع النصوص الأكثر تطابقًا مع استفسارات المستخدم. لتحقيق ذلك، سنستخدم مكتبة FAISS وهي اختصار لعبارة Facebook AI Similarity Search والتي تعد مكتبة قوية مفتوحة المصدر طورتها ميتا لتسهيل البحث السريع عن العناصر الأكثر تشابهًا داخل مجموعات بيانات ضخمة من المتجهات vectors. # FAISS تثبيت مكتبة pip install faiss-cpu # استيراد المكتبات اللازمة import faiss import numpy as np # تحديد أبعاد التمثيلات الرقمية embedding_dim = embeddings.shape[1] # إنشاء قاعدة البيانات index = faiss.IndexFlatL2(embedding_dim) # إضافة التمثيلات الرقمية إلى قاعدة البيانات index.add(np.array(embeddings.cpu())) في هذا الكود ننشئ قاعدة بيانات باستخدام مكتبة FAISS، بهدف تنفيذ عمليات بحث فعّالة عن التشابه بين التمثيلات الرقمية، فبعد تثبيت المكتبة نستوردها إلى جانب استيراد المكتبة numpy. بعد ذلك، نحدد عدد أبعاد التمثيلات الرقمية embedding_dim الناتجة من النموذج وننشئ من خلال التعليمة (faiss.IndexFlatL2(embedding_dimفهرسًا أو قاعدة بيانات تستخدم مربع المسافة الإقليدية Squared Euclidean Distance لمقارنة التمثيلات والعثور على النصوص الأكثر تشابهًا ثم نضيف التمثيلات embeddings إلى قاعدة البيانات مع تحويلها لصيغة مصفوفة NumPy لاستخدامها في البحث السريع عن النصوص. الخطوة 6: البحث عن المعلومات باستخدام RAG بعد إنشاء قاعدة البيانات باستخدام FAISS، يمكننا الآن البحث داخل محادثات WhatsApp بطريقة ذكية باستخدام التوليد المعزز بالاسترجاع RAG. تساعد هذه التقنية على استرجاع النصوص الأكثر صلة بالاستفسار، مما يؤدي إلى توليد إجابات دقيقة بناءً على البيانات المخزنة. # دالة البحث عن المعلومات داخل قاعدة البيانات def search_query(query, top_k=3): # تحويل الاستفسار إلى تمثيلات رقمية query_embedding = model.encode([query], convert_to_tensor=True).cpu().numpy() # البحث عن أقرب النصوص في قاعدة البيانات distances, indices = index.search(query_embedding, top_k) # استرجاع النصوص الأكثر صلة بالاستفسار results = [chunks[i] for i in indices[0]] return results # مثال على البحث داخل المحادثات query = "السؤال ؟" related_texts = search_query(query) # طباعة النتائج for text in related_texts: print(text) يبحث هذا الكود عن النصوص الأكثر صلة بالاستفسار داخل قاعدة البيانات حيث يحول في البداية الاستفسار query إلى تمثيل رقمي. بعد ذلك، يبحث عن أقرب النصوص المخزنة في قاعدة البيانات بناءً على هذا التمثيل الرقمي. وأخيرًا، يعرض لنا أفضل ثلاث نتائج تتطابق مع الاستفسار وبهذا يمكننا العثور على المعلومات المطلوبة بسرعة من مجموعة كبيرة من النصوص. الخطوة 7: توليد الإجابة باستخدام نموذج الذكاء الاصطناعي التوليدي بعد استرجاع النصوص ذات الصلة من قاعدة البيانات، يمكننا الآن استخدام نموذج ذكاء اصطناعي توليدي لإنشاء إجابة دقيقة بناءً على الاستفسار والمعلومات المسترجعة من قاعدة البيانات. سنعتمد في هذه الخطوة على نموذج Qwen مفتوح المصدر والذي طورته شركة Alibaba Cloud، وتحديدًا فريق Alibaba DAMO Academy والذي يوفر إصدارات متنوعة بعدة أحجام مختلفة لتناسب مختلف المتطلبات والاحتياجات، بدءًا من النماذج الصغيرة التي يمكن تشغيلها على الأجهزة الشخصية، وصولًا إلى النماذج الضخمة المناسبة للخوادم والسحابة. import requests # Hugging Face رابط واجهة النموذج على API_URL = "https://api-inference.huggingface.co/models/Qwen/Qwen2.5-Coder-32B-Instruct" # Hugging Face نستبدل المفتاح التالي بمفتاح من headers = {"Authorization": "Bearer hf_XXXXXXXXXXXXXXXXXXXX"} # إعداد الموجه prompt = f""" [SYSTEM]: أنت نموذج ذكاء اصطناعي متخصص في اللغة العربية. سيتم إعطاؤك أسئلة مع معلومات ذات صلة. مهمتك هي الإجابة عن الأسئلة بناءً على المعلومات المعطاة فقط. [USER]: السؤال: {query} المعلومات المعطاة: {related_texts} [ASSISTANT]: """ # دالة لإرسال الطلب إلى النموذج واستقبال الرد def query(payload): response = requests.post(API_URL, headers=headers, json=payload) return response.json() # استدعاء الدالة للحصول على الاستجابة من النموذج output = query({"inputs": prompt}) # استخراج النص الناتج من الرد generated_answer = output[0]['generated_text'].split("[ASSISTANT]:")[1] # طباعة النتائج print(generated_answer) يتواصل الكود أعلاه مع نموذج Qwen عبر الواجهة البرمجية Hugging Face API ويرسل موجه prompt للنموذج ليطلب منه الإجابة بناءً على المعلومات المعطاة فقط وكما نلاحظ يتضمن الموجه الأقسام [SYSTEM]و [USER] و [ASSISTANT] لتحديد أدوار المحادثة، بعد ذلك ينشئ دالةquery لإرسال الطلب إلى النموذج وإرجاع نص يتضمن الإجابة المستندة إلى المعلومات المتوفرة فقط، دون إضافة أي بيانات خارجية وطباعتها. ملاحظة: تقسم المحادثة مع نموذج الذكاء الاصطناعي إلى ثلاثة أقسام وهي: [SYSTEM] لتحديد التعليمات والنظام، و [USER]لعرض السؤال والمعلومات المقدمة للنموذج، و [ASSISTANT]لتحديد المكان الذي يبدأ فيه النموذج بتوليد إجابته. وهذا يساعد على تنظيم الحوار وتوجيه النموذج بحيث يفصل بين السؤال والمعلومات والإجابة، مما يضمن أن يقتصر الرد على الجزء المطلوب دون الخلط مع باقي النص. بناء أداة للتفاعل مع رسائل WhatsApp بعد أن تعرفنا على الخطوات الأساسية للتفاعل مع نماذج الذكاء الاصطناعي،سنعمل الآن على تطوير أداة تفاعلية تعتمد على هذه النماذج لتحليل محادثات WhatsApp المخزنة في ملفات PDF، مما يتيح لنا البحث داخل محادثاتنا والحصول على إجابات ذكية بناءً على استفساراتنا. نبدأ بتحميل ملف PDF الخاص بالمحادثات، ثم استخراج النصوص باستخدام PyMuPDF، وتقسيمها إلى مقاطع صغيرة بواسطة CharacterTextSplitter لضمان تحليل دقيق. بعد ذلك، تحول النصوص إلى تمثيلات رقمية Embeddings باستخدام نموذج AraBERT المخصص للغة العربية، ثم تخزنها في قاعدة بيانات FAISS للبحث السريع عن النصوص ذات الصلة. عند إدخال استفسار، تعمل الأداة على البحث عن المقاطع الأكثر صلة بالاستفسار، داخل قاعدة البيانات، ثم ترسلها إلى نموذج Qwen لإنشاء إجابة ذكية تعتمد على البيانات المخزنة، ثم تعرضها عبر واجهة مستخدم تفاعلية مبنية باستخدام مكتبة بايثون تسمى Gradio وهي مكتبة مفتوحة المصدر لإنشاء واجهات مستخدم تفاعلية لنماذج التعلم الآلي والذكاء الاصطناعي تتيح لنا تصميم واجهات سهلة الاستخدام عبر متصفح الويب وتسهل علينا استفساراتنا والحصول على نتائج النموذج بشكل مباشر، دون الحاجة لكتابة أكواد معقدة. فيما يلي الكود الكامل لبناء واجهة مستخدم تفاعلية مبنية باستخدام مكتبة Gradio تسمح لنا بتحميل ملف pdf المتضمن لمحادثاتنا على الوتساب ومعالجته بنماذج الذكاء الاصطناعي والتفاعل معه وعرض النتيجة. import requests import faiss import numpy as np import gradio as gr from sentence_transformers import SentenceTransformer from langchain.document_loaders import PyMuPDFLoader from langchain.text_splitter import CharacterTextSplitter # تحميل نموذج تحويل النصوص إلى تمثيلات رقمية model = SentenceTransformer('aubmindlab/bert-base-arabertv02') # نموذج الذكاء الاصطناعي التوليدي API_URL = "https://api-inference.huggingface.co/models/Qwen/Qwen2.5-Coder-32B-Instruct" # Hugging Face نستبدل المفتاح التالي بمفتاح من headers = {"Authorization": "Bearer hf_XXXXXXXXXXXXXXXXXXXX"} # دالة معالجة الملف وتحويله إلى تمثيلات رقمية def process_pdf(pdf_file): loader = PyMuPDFLoader(pdf_file.name) pages = loader.load() text = "\n".join([page.page_content for page in pages]) # تقسيم النص إلى أجزاء صغيرة text_splitter = CharacterTextSplitter(separator="\n", chunk_size=500, chunk_overlap=100, length_function=len) chunks = text_splitter.split_text(text) # تحويل الأجزاء إلى تمثيلات رقمية embeddings = model.encode(chunks, convert_to_tensor=True).cpu().numpy() # إنشاء قاعدة بيانات embedding_dim = embeddings.shape[1] index = faiss.IndexFlatL2(embedding_dim) index.add(embeddings) return index, chunks # دالة البحث داخل المحادثات def search_query(query, index, documents, top_k=3): query_embedding = model.encode([query], convert_to_tensor=True).cpu().numpy() distances, indices = index.search(query_embedding, top_k) results = [documents[i] for i in indices[0]] return results # دالة استدعاء النموذج التوليدي def generate_answer(pdf_file, query): index, documents = process_pdf(pdf_file) related_texts = search_query(query, index, documents) prompt = f""" [SYSTEM]: أنت نموذج ذكاء اصطناعي متخصص في اللغة العربية. سيتم إعطاؤك أسئلة مع معلومات ذات صلة. مهمتك هي الإجابة عن الأسئلة بناءً على المعلومات المعطاة فقط. [USER]: السؤال: {query} المعلومات المعطاة: {related_texts} [ASSISTANT]: """ response = requests.post(API_URL, headers=headers, json={"inputs": prompt}) output = response.json() return output[0]['generated_text'].split("[ASSISTANT]:")[1] # Gradio إنشاء واجهة تفاعلية باستخدام with gr.Blocks() as app: gr.Markdown("# 📂 WhatsApp أداة للتفاعل مع محادثات 🔍") pdf_input = gr.File(label="📄 PDF تحميل ملف المحادثة بصيغة ") user_input = gr.Textbox(label="📝 أدخل سؤالك هنا") search_button = gr.Button("🔎 بحث وتحليل") output_box = gr.Textbox(label="🤖 الإجابة:") search_button.click(generate_answer, inputs=[pdf_input, user_input], outputs=output_box) # تشغيل التطبيق app.launch() إذا شغلنا الكود أعلاه سنحصل على النتيجة التالية: تطبيقات عملية للأداة يمكننا الاستفادة من هذه الأداة الذكية في تطبيقات متعددة، لنستعرض بعضًا منها: استرجاع المواعيد والمهام المجدولة يمكن استخدام هذه الأداة لاسترجاع المواعيد والمهام المجدولة داخل محادثات واتساب بسهولة، حيث يمكن البحث عن التواريخ أو الأحداث المهمة داخل محادثاتنا باستخدام استعلامات بسيطة، مما يسهل تنظيم المهام اليومية والوصول إلى المعلومات بسرعة دون الحاجة إلى التمرير يدويًا عبر المحادثات الطويلة. في المثال التالي، لدينا مجموعة لطلاب جامعيين، ونريد أن نعرف موعد الاختبار. يمكن ببساطة إدخال استعلام مثل: البحث السريع عن المعلومات المهمة وتلخيص أهم المواضيع تتيح لنا الأداة للمستخدمين البحث بسرعة عن المعلومات المهمة داخل محادثات WhatsApp المخزنة، بالإضافة إلى تلخيص أهم المواضيع التي تمت مناقشتها. فعند إدخال استعلام مثل: البحث في المحادثات القانونية تساعد هذه الأداة في البحث داخل المحادثات القانونية لاستخراج المعلومات المهمة بسرعة، مما يسهل على المستخدمين العثور على النصوص المتعلقة بالاستشارات القانونية السابقة دون الحاجة إلى البحث اليدوي. على سبيل المثال، إذا كان هناك محادثة مع محامٍ، وأراد المستخدم معرفة معلومة معينة مثل: البحث في المحادثات الطبية يمكن استخدام هذه الأداة للبحث داخل المحادثات الطبية مع الأطباء أو الصيادلة لاستخراج المعلومات المهمة حول الأدوية والجرعات والإرشادات الطبية. على سبيل المثال، إذا أراد المستخدم معرفة: البحث في محادثات العمل تساعد هذه الأداة في البحث داخل محادثات العمل لاستخراج آخر التحديثات حول المشاريع والمهام الجارية. على سبيل المثال، إذا أراد المستخدم معرفة: نصائح لتحسين وتطوير الأداة دعونا نستعرض عدة أفكار لتحسين تطبيق التفاعل مع رسائل واتساب وتحسين نتائجه: استخدام طرق أخرى لقراءة ملفات PDF تواجه بعض المكتبات في لغة Python تحديات في التعامل مع النصوص باللغة العربية، حيث يمكن أن يحدث فقدان في الحروف أو التنسيق عند استخراج النصوص من ملفات PDF. لتحسين ذلك، يمكن تجربة مكتبات أخرى مثل pdfplumber أو PyPDF2 التي قد توفر دقة أكبر في استخراج النصوص العربية. بالإضافة إلى ذلك، يمكن دمج تقنيات التعرف على النصوص OCR في حالة الملفات التي تحتوي على صور نصية، مما يضمن استخراج النصوص بدقة أعلى. استخدام نماذج تضمين أفضل Embeddings لتحسين دقة تمثيلات النصوص، يمكن استخدام نماذج تضمين Embeddings مختلفة، أو تحسين النموذج الحالي عبر التدريب المستمر باستخدام بيانات محلية. هذا سيساعد في تخصيص النموذج بشكل أفضل للمجال المطلوب، مما يعزز التفاعل مع النصوص العربية ويزيد من دقة استرجاع المعلومات. تجربة نماذج توليدية مختلفة من أجل توليد إجابات دقيقة وواقعية، يمكن تجربة نماذج توليدية مختلفة مثل Llama أو GPT-3. كما يمكن النظر في استخدام نماذج متخصصة في مجالات معينة مثل الاستفسارات القانونية أو الاستشارات الطبية، لتحسين جودة الإجابات في تلك المجالات. تحسين إعدادات النماذج أو إعادة تدريبها باستخدام بيانات محلية سيسهم في تحسين الأداء العام. تحميل رسائل WhatsApp بطريقة تلقائية لتسريع عملية تحميل الرسائل، يمكن تطوير أداة تلقائية لتحميل المحادثات مباشرة من WhatsApp. يمكن أن توفر هذه الطريقة تحديثات مباشرة للمحادثات، مما يسهل الوصول إلى الملفات بسرعة ومرونة أكبر. كما يمكن أتمتة عملية التحميل بشكل دوري لضمان تحديث البيانات بشكل مستمر. ربط الأداة بأدوات أخرى لزيادة فعالية الأداة، يمكن دمجها مع أدوات أخرى مثل أداة التذكير بالمواعيد أو أداة متابعة المهام. على سبيل المثال، يمكن ربط الأداة بتقويم شخصي لتنبيه المستخدم بشأن المواعيد أو الاجتماعات المستخلصة من المحادثات. كما يمكن دمج الأداة مع أنظمة إدارة المشاريع مثل Trello للاستفادة من الذكاء الاصطناعي في تتبع المهام والتحديثات، مما يعزز إنتاجية المستخدم ويسهل إدارة العمل بشكل متكامل. الخاتمة في هذا المقال، استعرضنا كيفية بناء أداة ذكية تعتمد على الذكاء الاصطناعي لمعالجة وتحليل محادثات WhatsApp المخزنة في ملفات PDF، باستخدام تقنية التوليد المعزز بالاسترجاع RAG لاسترجاع المعلومات بدقة وتقديم إجابات فعالة. كما ناقشنا التطبيقات العملية للأداة في مجالات متنوعة، مثل الاستشارات القانونية وتحليل المحادثات الطبية، مما يبرز إمكانياتها في تحسين الوصول إلى المعلومات المهمة بسرعة وسهولة، كما استعرضنا طرقًا متعددة لتحسين الأداة، مثل تحسين استخراج النصوص من ملفات PDF باللغة العربية، وتجربة نماذج تضمين أكثر دقة، وتطوير حلول لتحميل المحادثات بشكل تلقائي. ندعوكم لتجربة تطوير أداة خاصة بكم تساعدكم على التفاعل مع بياناتكم الشخصية بأمان وفعالية، وتعزز إنتاجيتكم وتوفر وقتكم، ولو كان لديكم أية تساؤلات أو أفكار تطويرية على الأداة يمكنكم تركها في قسم التعليقات أسفل المقال. اقرأ أيضًا بناء تطبيق بايثون يجيب على أسئلة ملف PDF باستخدام الذكاء الاصطناعي بناء روبوت دردشة باستخدام بايثون و OpenAI API كتابة استعلامات SQL بسهولة باستخدام الذكاء الاصطناعي استخدام نموذج الذكاء الاصطناعي Code Llama لكتابة وتصحيح أكواد CSS1 نقطة
-
نحتاج كثيرًا إلى استعمال جداول البيانات لتخزين بيانات دورية خلال يومنا لتجنب نسيانها فقد لا نكون دومًا خلف طاولة العمل حيث الدفاتر والحاسوب بل قد نكون في الشارع أو الحافلة ولا نملك سوى الهاتف في يدنا ولا نريد استعمال تطبيق الملاحظات الممتلئ بملاحظات مبعثرة هنا وهناك. على سبيل المثال إذا احتجنا لاستخدام جداول بيانات جوجل Google Sheets لتسهيل تسجيل بعض البيانات ومتابعتها دوريًا من مكان واحد سنواجه صعوبة في التعامل مع Google Sheets على الجوال لأن الشاشة صغيرة وغير مريحة بالعمل، لذا قد نضطر إلى تدوين الملاحظات سريعًا لإدخالها في جداول البيانات وتنظيمها لاحقًا عند توفر الحاسوب. سنوضح في مقال اليوم طريقة سهلة وعملية لإدارة إدخال البيانات في جداول بيانات جوجل من خلال إنشاء بوت تلغرام Telegram وظيفته إدخال البيانات وتنظيمها مباشرةً في جداول البيانات، فلا يكاد يخلو أي هاتف جوال من تطبيق تلغرام الشهير وبهذا ندخل البيانات بسهولة من خلاله دون الحاجة لفتح تطبيق جداول البيانات، كل ما نحتاجه هو إرسال رسالة بصيغة معينة للبوت ليأخذها ويرسلها لجداول بيانات جوجل ويخزنها هناك.أي تتألف العملية من ثلاثة خطوات، ارسال الرسالة التي تحوي البيانات إلى البوت، ثم نقل البيانات، ثم أخيرًا تخزينها في وجهتها. متطلبات مسبقة للعمل نحتاج قبل إكمال هذا المقال إلى ما يلي: حساب على تطبيق تلغرام حساب جوجل مع إمكانية الوصول إلى تطبيق جداول بيانات جوجل Google Sheets معرفة مسبقة باستعمال Google Sheets، ويمكن الرجوع إلى مقال مقدمة إلى جداول بيانات جوجل Google Sheets معرفة أساسية بلغة جافاسكريبت، ويمكن الرجوع إلى مقال تعلم لغة جافا سكريبت JavaScript التطبيق النموذجي لربط بوت تلغرام مع جداول بيانات جوجل سنعتمد على نموذج بيانات بسيط بغرض التعلم حيث سنتعلم من خلاله آلية ربط بوت تلغرام مع جداول بيانات جوجل، والنموذج الذي سنستخدمه هنا هو بيانات الإيرادات والنفقات اليومية كما توضح الصورة التالية: ملاحظة: استخدمنا هذا النموذج بغرض التعلم ونترك لكم تطبيق ما ستتعلمونه على نموذج البيانات المناسب لاحتياجاتكم. الخطوة الأولى: إنشاء بوت تلغرام Telegram Bot سنستعمل تطبيق تلغرام على الويب للسهولة، لذا سنفتح تطبيق تلغرام ويب ونسجل الدخول، ثم نبحث في حقل البحث عن BotFather وهو كبيرُ البوتات الذي سيساعدنا على إنشاء بوتات تلغرام وإدراتها. لنتبه إلى أن مُعرِّف كبير البوتات الرسمي هو @botfather إذ ستظهر لنا عدة نتائج في حقل البحث: لنضغط بعدها على البدء Start وستظهر أمامنا رسالة فيها قائمة طويلة من الخيارات اللازمة لإنشاء بوتات تلغرام وإدارتها، بعدها سيسألنا كبيرُ البوتات عن اسم البوت الذي نريد إنشاءه فنجبه باسم البوت وسندخل هنا الاسم إيرادات ونفقات: سيطلب بعدها كبيرُ البوتات إدخال اسم مُعرِّف أو اسم المستخدم للبوت الجديد، وننتبه لأن هذا الاسم يجب أن ينتهي بالكلمة bot سواءً بالشكل usernameBot أو username_bot، وسنستخدم هنا الاسم MyIncomeAndExpensesBot: ملاحظة: قد لا يقبل البوت بعض اقتراحات اسم المستخدم مثلًا عندما جربنا إدخال اسم المستخدم IncomeExpensesBot وIncomeAndExpensesBot لم يقبلهما لكونهما محجوزان مسبقً، لذا قد نحتاج لتعديل الاسم حتى نجد اسمًا متاحًا. سينُشئ بعدها كبيرُ البوتات البوت الجديد ويرسل لنا رسالة يخبرنا فيها عن رابط الوصول للبوت ورمز الوصول إليه access token عبر طلبات HTTP: لنحفظ هذا الرمز لأننا سنستعمله لاحقًا في التواصل مع هذا البوت. تجربة التواصل مع بوت تلغرام الجديد سنلاحظ في آخر الرسالة الموضحة بالصورة السابقة أن كبير البوتات قد أشار إلى توثيق واجهة البوت البرمجية، سنحتاج دومًا لفتح هذا التوثيق ونرجع إليه دومًا في آلية ربط بوت تلغرام والتواصل معه، فقد تتغير الآلية وتتعدل الواجهة البرمجة مستقبلًا. لنتأكد أن البوت قد أُنشئ وأصبح جاهزًا للتواصل، وذلك بزيارة الرابط التالي في متصفح الويب بعد تبديل {access_token} برمز وصول البوت الذي حصلنا عليه مسبقًا: https://api.telegram.org/bot{access_token}/getMe إن سارت الأمور على ما يرام، فسنحصل على نتيجة مشابهة للنتيجة التالية تحوي تفاصيل البوت ورده علينا: { "ok": true, "result": { "id": 7666156735, "is_bot": true, "first_name": "إيرادات ونفقات", "username": "MyIncomeAndExpensesBot", "can_join_groups": true, "can_read_all_group_messages": false, "supports_inline_queries": false, "can_connect_to_business": false, "has_main_web_app": false } } نلاحظ أننا حصلنا من الرسالة السابقة على رقم البوت id، واسمه first_name، واسم المستخدم username، وبعض التفاصيل الأخرى التي لن تلزمنا في هذا المقال مثل إمكانية انضمام البوت للمجموعات وغيرها. ضبط بوت تلغرام قبل أن نكمل، نود أن نشير لإمكانية ضبط بوت تلغرام الجديد -وأي بوت آخر- عبر كبير البوتات BotFather مباشرةً، فمثلًا لنجرب كتابة / أو اضغط على زر قائمة Menu بجانب حقل الكتابة في المحادثة وستظهر لنا خيارات كثيرة كان كبير البوتات قد ذكر أهمها في أول رسالة أرسلها لنا بعد الضغط على زر البدء Start: سنذكر بعض هذه الأوامر: /mybots لعرض بوتات تلغرام الخاصة بنا /setname لتغيير اسم بوت تلغرام /setdescription لضبط أو تغيير وصف البوت /setuserpic لضبط أو تغيير صورة البوت يمكن تجربة هذه الأوامر مع بقية الأوامر لتتعلم أكثر عن ضبط وإدارة بوتات تلغرام. فهم آلية الربط والتواصل بين بوت تلغرام وجداول بيانات جوجل قبل أن ننتقل إلى الخطوة التالية من مقالنا، من الضروري فهم آلية ربط بوت تلغرام مع جداول بيانات جوجل -أو أي خدمة أخرى مثلًا- حتى نفهم كيف سنكمل عملية الضبط. لنتذكر أن هدف المقال إرسال رسالة بصيغة معينة إلى بوت تلغرام، ليقوم بدوره بتنفيذ أوامر محددة وظيفتها أخذ رسالتنا وإرسالها إلى جداول بيانات جوجل لتخزينها هناك، وبذلك يمكن تقسيم العملية إلى ثلاثة خطوات، الأولى إرسال الرسالة التي تحوي البيانات إلى البوت، و الثانية نقل البيانات، والثالثة تخزينها في وجهتها. يمكننا التواصل مع البوت عبر آليتين : الأولى هي التواصل عبر الواجهة البرمجية APIs مباشرةً وسؤاله عما نريد، مثلًا يمكن إرسال طلب للواجهة البرمجية /getMe لطلب معلومات عن البوت، أو الواجهة البرمجية /getUpdates لطلب كافة الرسائل المرسلة إلى البوت وغيرها، ويمكنك الرجوع إلى توثيق واجهات بوت تلغرام البرمجية للاطلاع على القائمة الكاملة. الآلية الثانية هي التواصل من خلال خطافات الويب Web Hooks أي أننا نطلب من البوت نفسه أن يتواصل معنا عند وقوع أحداث معينة، وسنجد في توثيق Update قائمة الأحداث المدعومة في بوت تلغرام، حيث نحدد ما هي الأحداث التي نحتاجها بالضبط. هذا يشبه آلية تواصلنا نحن البشر، تخيل لو كنا نريد -ونحن في العمل- معرفة إن وصلت طلبية طلبناها إلى منزلنا أم لا، عندها إما أن أتصل بالمنزل ونسأل الأهل إن وصلت الطلبية، أو أن نطلب من الأهل أن يتصلوا بنا متى ما وصلت الطلبية. سنعتمد في هذا المقال على آلية خطافات الويب web hooks وسنختار حدث استلام رسالة، فكلما استلم البوت رسالة سيقوم بأمر محدد وهو إرسالها إلى خادم جوجل ننشره على الإنترنت عبر عبر برمجة تطبيقات Google أو Apps Scripts والذي بدوره يستلم البيانات ويُخزِّنها في جدول بيانات جوجل وهذا ما سنعمل على ضبطه. ملاحظة: ذكرنا أننا سنعتمد على خادم ننشره عبر برمجة تطبيقات جوجل وبذلك لن نحتاج إلى إنشاء خادم خاص للتواصل، ولكن الأمر هنا يعود لما يناسب احتياجنا ومتطلباتنا، فيمكن إنشاء خادم خاص والتواصل مع البوت ومعالجة البيانات وتخزينها بأي لغة برمجة نريدها، وإظهارها بالشكل الذي نريد مما يفتح لنا أفاقًا واسعةً لبناء وتطوير بوتات تلغرام خدمية. الخطوة الثانية: إنشاء جدول بيانات جوجل والتحكم به برمجيًا لننشئ جدول بيانات جديد في درايف لتخزين البيانات الواردة من بوت التلغرام برمجيًا بشكل مؤتمت، وذلك عبر إضافة توفرها جوجل وهي لغة برمجة تطبيقات جوجل Apps Scripts . ما هي لغة Google Apps Scripts تعد Google Apps Scripts لغة برمجة هدفها إدارة جميع تطبيقات جوجل كبريد Gmail وتخزين Drive وجداول بيانات جوجل Sheets وغيرها، وهي مبنية على لغة جافاسكربت ولاحقتها ملفاتها البرمجية هي .gs وتوفر جوجل بيئة تطوير على السحابة Google Workspace تساعدنا على تنفيذ الأكواد التي نكتبها بهذه اللغة، أي لن نحتاج لبيئة تطوير لمعالجة وتنفيذ الملفات المكتوبة بهذه اللغة محليًا. التحكم بجدول البيانات برمجيًا بعد إنشاء جدول بيانات جديد وتسميته باسم الإيرادات والنفقات، يمكننا ربطه والتحكم به برمجيًا بسهولة عبر Apps Scripts من خيار الإضافات Extensions ثم برمجة تطبيقات Google كما في الصورة التالية: سيُنشَأ ملف بلغة برمجة تطبيقات جوجل Apps Scripts ويُربط بملف جداول البيانات: هنا يمكننا فعل أي شيء بملف جدول البيانات برمجيًا، وحتى الوصول إلى بقية خدمات جوجل وتطبيقاتها مثل البريد Gmail ومستندات جوجل، ويمكننا أيضًا التواصل مع خدمات خارجية وهو ما نريد فعله بربط جدول البيانات مع بوت التلغرام الذي أنشأناه. نلاحظ في الجزء الأيمن في قسم الملفات وجود ملف باسم الرمز.gs، نلاحظ أيضًا أن هذه البيئة تشبه بيئة التطوير إذ توفر لنا مكانًا لكتابة الكود وتنفيذه من الخيارات في الشريط العلوي. ملاحظة: يمكن تغيير اسم المشروع من الأعلى إلى اسم مناسب وهنا سنضعه بنفس اسم البوت. لنجرب بدايةً عرض ناتج تنفيذ الواجهة البرمجية getMe في هذه البيئة، لذا نغيّر اسم الدالة myFunction إلى getMe مثلًا ونكتب محتواها البرمجي التالي: function getMe() { const response = UrlFetchApp.fetch('https://api.telegram.org/bot7666156735:AAFlJYPgOzT5cTf8CfRx_5vf0GNuVmcvAuk/getMe'); Logger.log(response.getContentText()); } استعملنا الدالة UrlFetchApp.fetch لجلب محتوى رابط أو واجهة برمجية، ومررنا لها رابط الواجهة البرمجية /getMe كاملًا مع رمز الوصول access token، ثم استعملنا Logger.log لطباعة الناتج. نضغط على زر تنفيذ في الأعلى، وبما أننا ننفذ هذا السكربت لأول مرة فسيُطلَب منا إعطاءه صلاحيات محددة: نضغط على مراجعة الأذونات، ثم نحدد حسابنا ونضغط بعدها على السماح بعد مراجعة الأذونات المطلوبة، وسنجد بعدها ناتج تنفيذ الدالة getMe ضمن السكربت في قسم سجل التنفيذ في الأسفل: المعلومات هنا هي نفس المعلومات التي حصلنا عليها من فتح الرابط في المتصفح تمامًا، وبذلك نكون قد نجحنا في اختبار بيئة التطوير وجاهزيتها. ملاحظة: قد نضطر في كل تعديل إلى ضغط زر الحفظ وهو بجانب زر التنفيذ في الشريط العلوي أو ضغط الاختصار ctrl + s لحفظ المشروع. سنعيد تنظيم الشيفرة قليلًا ليسهل علينا استدعاء بقية الواجهات البرمجية بالشكل التالي: const token = '7666156735:AAFlJYPgOzT5cTf8CfRx_5vf0GNuVmcvAuk'; const url = 'https://api.telegram.org/bot' \+ token; function getMe() { const response = UrlFetchApp.fetch(url \+ '/getMe'); Logger.log(response.getContentText()); } يمكن الآن استدعاء /getUpdates بسهولة بكتابة دالة جديدة باسم getUpdates بالشكل التالي: const token = '7666156735:AAFlJYPgOzT5cTf8CfRx_5vf0GNuVmcvAuk'; const url = 'https://api.telegram.org/bot' \+ token; function getMe() {` const response = UrlFetchApp.fetch(url \+ '/getMe'); Logger.log(response.getContentText()); } function getUpdates() { const response = UrlFetchApp.fetch(url \+ '/getUpdates'); Logger.log(response.getContentText()); } لتنفيذ الدالة، نختار من القائمة الموجودة في الشريط العلوي اسم الدالة، ثم نضغط على تنفيذ ونشاهد الناتج في قسم سجل التنفيذ. ملاحظة: قد تظهر لنا رسالة تحذير بأن التطبيق غير آمن ولم يتحقق جوجل منه ولا بأس بالإكمال كما توضح الصورة التالية لأننا نحن من نطور السكربت ولكن يجب الحذر إن كان السكريبت من مصدر غير موثوق لأن قد يصل إلى معلومات حساسة. نشر تطبيق ويب يصل بين بوت تلغرام وجداول بيانات جوجل فهمنا سابقًا آلية التواصل التي سنطبقها والتي تتم بتواصل بوت التلغرام عبر خطاف ويب web hook مع خادم ويب كلما استلم البوت رسالة جديدة بعدها سيعمل خادم الويب على تخزين البيانات الواردة بعد معالجتها في جدول البيانات كما هو موضح بالصورة التالية: السؤال هو كيف سنحصل على خادم ويب؟ يمكننا بناء خادم ويب بأي لغة نريد سواءً بلغة بايثون أو لغة جافاسكربت، أو يمكننا الاستفادة من بيئة تطوير تطبيقات جوجل Apps Script فهي تمكننا من نشر المشروع على أنه تطبيق ويب على الإنترنت مباشرة واستضافته على خوادم جوجل السحابية. لنشر المشروع، نضغط على زر النشر في الأعلى ثم نختار تطبيق ويب: نختار من القائمة التي تظهر من حقل المستخدم الذي لديه الإذن بالوصول إلى عملية النشر الخيار أي شخص لكي يعمل التطبيق ثم نضغط على زر نشر: نحصل بعد تمام عملية النشر على رابط URL للتطبيق ويب جاهز ومنشور على الإنترنت، ويمكننا نسخ رابطه ولصقه في المتصفح للتأكد من عمل التطبيق، وإن جربنا في حالتنا فسنحصل على الخطأ التالي: Script function not found: doGet توضح هذه الرسالة أن السكربت لا يحوي دالة باسم doGet لتنفيذها وهو طلب HTTP من النوع get لذا نضيف الدالة doGet إلى السكربت: function doGet(e) { return HtmlService.createHtmlOutput("Hello " \+ JSON.stringify(e)); } تعمل الدالة السابقة على إعادة صفحة HTML فيها كلمة مرحبًا Hello وكائن بالمعلومات المرسلة بالطلبية، ولنعد إلى نافذة المتصفح حيث فتحنا رابط التطبيق وحدِّثنا الصفحة ولكن وجدنا أن الرسالة لم تتغير. يحصل ذلك لأننا لم ننشر نسخة جديدة من التطبيق بعد إضافة الدالة الجديدة إليه. لنشر نسخة جديدة من التطبيق، نضغط على زر نشر في الأعلى ثم نختار إدارة عمليات النشر ثم نضغط على زر التعديل في قسم الإعداد ثم نختار من قائمة الإصدار خيار الإصدار الجديد لنشر إصدار جديد من التطبيق: إن حدثنا الصفحة فسنرى ناتج تنفيذ الدالة doGet التالي: Hello {"queryString":"","contentLength":-1,"contextPath":"","parameters":{},"parameter":{}} ملاحظة: قد يحتاج تطبيق الويب لبعض الوقت بعد نشره أو نشر إصدار جديد منه للعمل. أصبحنا الآن جاهزين للانتقال إلى الخطوة التالية وهي ربط خطاف ويب web hook بوت التلغرام وبين تطبيق الويب المنشور الذي أنشأناه للتو. الخطوة الثالثة: ضبط خطاف الويب بين تطبيق الويب وبوت التلغرام يمكن لتطبيق الويب الذي أنشأناه عبر لغة برمجة تطبيقات جوجل أن يستقبل ويعالج طلبات HTTP، وقد رأينا كيف أنه استقبل طلب GET ويمكنه أيضًا أن يستلم طلب POST أيضًا، فعبر ربط خطاف الويب بين تطبيق الويب وبوت التلغرام، سيرسل البوت طلب POST كلما استلم رسالة جديدة. ولضبط خطاف الويب في بوت التلغرام، سنستعين بالواجهة البرمجية setWebhook التي تأخذ معاملًا باسم url وهو رابط تطبيق أو خادم الويب الذي ستُرسل إليه التحديثات الواردة من بوت التلغرام. نُعرِّف في السكربت دالة جديدةًبالاسم setWebhook والتي سترسل طلبية إلى الواجهة البرمجية تلك مع رابط تطبيق الويب، ويمكن أن نحصل على رابط تطبيق الويب بالضغط على زر نشر في الأعلى ثم الضغط على خيار إدارة عمليات النشر ثم ننسخ عنوان URL للتطبيق ونضغه في السكريبت بالشكل التالي: … const webAppUrl = "https://script.google.com/macros/s/AKfycbwkoaVQ6aIWp6R0Pz5Q1EkiIydaKMusCKI7hEUYtPWXau7SLiznaagiAHDqkfiLzhhyXw/exec"; function setWebhook() { const response = UrlFetchApp.fetch(url \+ '/setWebhook?url=' \+ webAppUrl); Logger.log(response.getContentText()); } نحصل بعد تنفيذ الدالة setWebhook وحفظ السكربت على الناتج التالي: {"ok":true,"result":true,"description":"Webhook was set"} تخبرنا الرسالة بأنه تم ضبط خطاف الويب بنجاح، لكن إن جربنا الآن أن نرسل رسالة إلى بوت التلغرام فلن يحصل أي شيء، لماذا؟ لأننا لم نضبط بعد عملية معالجة طلبات POST التي يرسلها البوت عبر خطاف الويب بعد، فعندما يتلقى الخادم طلبًا من البوت عبر POST مثلاً، عند وصول رسالة جديدة، يجب على الخادم أن يعالج هذا الطلب. وللقيام بالمعالجة المطلوبة سنعرِّف دالة باسم doPost التي تعالج طلبيات POST المستقبلة، وسنجرب حاليًا إرسال بريد إلكتروني إلى حسابنا كلما استلمنا رسالة جديدة بالشكل التالي: function doPost(e) { GmailApp.sendEmail(Session.getEffectiveUser().getEmail(), "رسالة جديدة من بوت التلغرام", JSON.stringify(e, null, 4)); } لنحفظ السكريبت ثم ننشر إصدارًا جديدًا من التطبيق والذي سيطلب مرة أخرى قبول أذونات جديدة لأننا أضفنا تطبيقًا جديدًا إلى السكريبت وهو تطبيق البريد GmailApp، لنقبلها بالضغط على رز تفويض الوصول ولنجرب مرة أخرى إرسال رسالة إلى البوت. إن أرسلنا رسالة إلى البوت، فستصل رسالة إلى البريد تحوي معلومات الطلب كالتالي: أصبحت الآن البيانات بحوزتنا وتصلنا إلى تطبيق الويب مباشرة من البوت عند استلامه أي رسالة جديدة، وخطوتنا التالية هي معالجة هذه البيانات وإدخالها ضمن جدول البيانات. الخطوة الرابعة: إرسال رد على كل رسالة يرسلها بوت التلغرام قبل أن نحفظ البيانات في جدول بيانات جوجل، سنعمل على كتابة دالة وظيفتها إرسال رد أو تأكيد على بوت التلغرام ونستفيد منها في التواصل مع البوت والرد عليه كما أرسل لنا تحديثًا. كانت خطوة إرسال البريد خطوة تجريبية فقط لعرض المعلومات التي وصلتنا من البوت لنحاول استخلاص بعض المعلومات المهمة منها وهي بالشكل التالي: { "contextPath": "", "queryString": "", "contentLength": 295, "parameters": {}, "parameter": {}, "postData": { "contents": "{\"update_id\":412227169,\n\" message\":{\"message_id\":39,\"from\":{\"id\":957260622,\"is_bot\":false,\"first_name\":\"Jamil\",\"username\":\"jBailony\",\"language_code\":\"en\"},\"chat\":{\"id\":957260622,\"first_name\":\"Jamil\",\"username\":\"jBailony\",\"type\":\"private\"},\"date\":1735667656,\"text\":\"Hi, this is my first message\"}}", "length": 295, "name": "postData", "type": "application/json" } } ما يهمنا هنا موجود ضمن postData في خاصية اسمها contents ولكنها بصيغة JSON لنفككها إلى كائن بالشكل التالية: const contents = JSON.parse(e.postData.contents); والناتج هو كالتالي: { "update_id": 412227169, "message": { "message_id": 39, "from": { "id": 957260622, "is_bot": false, "first_name": "Jamil", "username": "jBailony", "language_code": "en" }, "chat": { "id": 957260622, "first_name": "Jamil", "username": "jBailony", "type": "private" }, "date": 1735667656, "text": "Hi, this is my first message" } } يلزمنا مُعرِّف المحادثة id والرسالة نفسها التي وصلتنا: const contents = JSON.parse(e.postData.contents); const id = contents.message.from.id; const name = contents.message.from.first_name; نحتاج إلى المُعرِّفلأننا سنعتمد على الواجهة البرمجية /sendMessage التي تحتاج إلى المعامل chat_id الذي هو مُعرِّف المحادثة السابق id. لنكتب الدالة sendMessage التي تعتمد على تلك الواجهة البرمجية بالشكل التالي: function sendMessage(chatId, message) { const response = UrlFetchApp.fetch(${url}/sendMessage?chat_id=${chatId}\&text=${message}); Logger.log(response.getContentText()); } نلاحظ أن الواجهة البرمجية /sendMessage تحتاج أيضًا إلى المعامل text الذي يمثِّل نص الرسالة المراد إرسالها. لنستعملها الآن ضمن الدالة doPost بإرسال رد على الرسالة: function doPost(e) { GmailApp.sendEmail(Session.getEffectiveUser().getEmail(), "رسالة جديدة من بوت التلغرام", JSON.stringify(e, null, 4)); const contents = JSON.parse(e.postData.contents); const id = contents.message.from.id; const name = contents.message.from.first_name; const text = contents.message.text; sendMessage(id, `وصلتنا رسالتك، شكرًا لك يا ` + name); } نحفظ المشروع وننشر إصدارًا جديدًا منه ثم نرسل رسالة إلى البوت وسنجد أنه يرد علينا كما توضح الصورة التالية: ممتاز، كل شيء يعمل على ما يرام، وخطوتنا التالية هي إدخال المعلومات المستلمة ضمن جدول البيانات. الخطوة الخامسة: حفظ البيانات المستلمة من بوت التلغرام في جدول البيانات أصبح لدينا محتوى الرسالة المستلمة من البوت، ونحتاج الآن إلى إدخالها ضمن جدول البيانات ولكن قبل ذلك، لنتعلم استعمال بعض الدوال التي ستلزمنا في التعامل مع جداول بيانات جوجل Google Sheets. التعامل مع جداول بيانات جوجل عبر لغة Apps Script سنعتمد على الواجهة SpreadsheetApp في التعامل مع جداول بيانات جوجل، ولنكتب بداية الدالة التالية التي وظيفتها إضافة سطر في جدول البيانات المرتبط بالشكل التالي: function appendRow() {` SpreadsheetApp.getActiveSheet().appendRow([1, 2, 3, 4]); } إن حفظنا السكريبت ثم نفذنا الدالة appendRow فسنحصل على الناتج التالي: ملاحظة: سيُطلب منا مرة أخرى قبول أذونات جديدة لأننا استعملنا واجهة تطبيق جديد في السكريبت، وهذا سيحصل كلما أضفنا واجهة جديدة لأحد تطبيقات جوجل. عملت الطريقة السابقة بشكل صحيح، ولكنها ليست الطريقة الأفضل، فمن الأفضل استعمال رابط ملف جدول البيانات مباشرة في تحديد الملف بالشكل التالي: const fileURL = 'https://docs.google.com/spreadsheets/d/1LZlRezLubnD_4mGZulQ7RUZ9-itRefmJNSsSizRh8iY/edit'; function appendRow() { SpreadsheetApp.openByUrl(fileURL).appendRow([1, 2, 3, 4]); } أو يمكننا الاعتماد على مُعرِّف الملف الذي نستخلصه من رابط ملف جدول البيانات السابق بالشكل التالي فهذه الطريقة أفضل وأقصر: const fileId = '1LZlRezLubnD_4mGZulQ7RUZ9-itRefmJNSsSizRh8iY'; function appendRow() { SpreadsheetApp.openById(fileId).appendRow([1, 2, 3, 4]); } نلاحظ أن هذا الأمر سيضيف سطرًا في أول جدول بيانات أو ورقة sheet في الملف، ولكن ماذا لو أردنا إضافة بيانات في ورقة محددة؟ يمكننا استعمال الطريقة التالية: const fileId = '1LZlRezLubnD_4mGZulQ7RUZ9-itRefmJNSsSizRh8iY'; const sheetName = "Sheet1"; function appendRow() { SpreadsheetApp.openById(fileId).getSheetByName("Sheet1").appendRow([1, 2, 3, 4]); } استعملنا getSheetByName مع تمرير اسم الورقة إليها من أجل تعديلها. سنتعلم أخيرًا كيفية جلب قيمة محددة من السطر الأخير وإعادة إضافتها في السطر التالي مع زيادتها بقيمة 1 مثلًا وذلك بالشكل التالي: const fileId = '1LZlRezLubnD_4mGZulQ7RUZ9-itRefmJNSsSizRh8iY'; const sheetName = "Sheet1"; function appendRow() { const sheet = SpreadsheetApp.openById(fileId).getSheetByName("incomes"); sheet.appendRow([5]); const lastValue = Number(sheet.getRange(sheet.getLastRow(), 1).getValue()); sheet.appendRow([lastValue + 1]); } تعمل هذه الدالة على إضافة قيمة في آخر سطر ثم جلب هذه القيمة باستعمال الدالة getRange التي تأخذ رقم السطر والعمود إذ رقم السطر هو رقم آخر سطر حصلنا عليه من الدالة getLastRow والعمود مررناه يدويًا، وبعد تنفيذ الدالة حصلنا على الناتج المتوقع: هذا يكفي لمقالنا الحالي، وسمكن استكشاف بقية الدوال والواجهات من التوثيق الرسمي. إضافة البيانات المستلمة من بوت التلغرام إلى جدول البيانات سنختار صيغة البيانات المرسلة من البوت إلينا حتى نعالجها ولتكن بالشكل التالي: تمثِّل @ وما بعدها اسم الورقة ثم يليها رقم ثم يليها الوصف مباشرةً، ولنعتمد أنه إذا لم نحدد اسم الورقة فلتكن افتراضيًا ورقة المصاريف، ونأخذ هذه المعلومات ونضيفها في الورقة المحددة، لذا سنُعدِّل الدالة doPost والدالة appendRow بالشكل التالي: function doPost(e) { GmailApp.sendEmail(Session.getEffectiveUser().getEmail(), "رسالة جديدة من بوت التلغرام", JSON.stringify(e, null, 4)); const contents = JSON.parse(e.postData.contents); const id = contents.message.from.id; const name = contents.message.from.first_name; const text = contents.message.text; let sheetName = "مصاريف"; let itemValue, itemName; if (/^@/.test(text)) { const textArray = text.slice(1).split(" "); sheetName = textArray[0]; itemValue = textArray[1]; itemName = textArray.splice(2).join(" "); } else { const textArray = text.split(" "); itemValue = textArray[0]; itemName = textArray.shift().join(" "); } appendRow(sheetName, [new Date().toLocaleString(), itemValue, itemName]); sendMessage(id, `سجلت المبلغ والقيمة في جدول ${sheetName}، شكرًا لك!`); } function appendRow(sheetName, data) { const spreadSheet = SpreadsheetApp.openById(fileId); const sheet = spreadSheet.insertSheet(sheetName); sheet.appendRow(data); } السكربت المكتوب بسيط وهو يتحقق إن كانت اسم الورقة مضافة ضمن الرسالة فيأخذها ويحلل الرسالة وفقًا لذلك أو إن لم تكن مضافة يحلل الرسالة مباشرة ويستخلص منها البيانات، ثم يدخل البيانات مع التاريخ ولاحظ أننا استعملنا الدالة insertSheet في الدالة appendRow وذلك لإضافة الورقة ضمن الملف. نحفظ السكربت ونعيد نشره ثم نرسل للبوت الرسالة التالية @نفقات 10 شراء فواكه ونجد أنه قد رد علينا بالرسالة سجلت المبلغ والقيمة في جدول النفقات، شكرًا لك! وقد أضاف ورقة جديدة بالاسم نفقات وأضاف فيها البيانات: تعمل عملية الربط بصورة صحيحة إلى الآن ولكن ماذا لو جربنا أن نرسل الرسالة مرة أخرى نفسها؟ الخطوة السادسة: التقاط الأخطاء ومعرفتها وحلها إن جربنا إرسال نفس الرسالة للبوت @نفقات 10 شراء فواكه، لن يحصل أي شيء ولن يرد علينا البوت بأي رد، وهذا دليل بأنه حصل خطأ ولكن كيف سنعرفه ونحله؟ سنلتقط الخطأ أولًا عبر كتلة try/catch ونرسل داخل catch رسالة إلى البوت بالخطأ الحاصل بالشكل التالي: const chatId = 957260622; function doPost(e) { try { GmailApp.sendEmail(Session.getEffectiveUser().getEmail(), "رسالة جديدة من بوت التلغرام", JSON.stringify(e, null, 4)); const contents = JSON.parse(e.postData.contents); const id = contents.message.from.id; const name = contents.message.from.first_name; const text = contents.message.text; let sheetName = "مصاريف"; let itemValue, itemName; if (/^@/.test(text)) { const textArray = text.slice(1).split(" "); sheetName = textArray[0]; itemValue = textArray[1]; itemName = textArray.splice(2).join(" "); } else { const textArray = text.split(" "); itemValue = textArray[0]; itemName = textArray.shift().join(" "); } appendRow(sheetName, [String(new Date().toLocaleString()), itemValue, itemName]); sendMessage(id, `سجلت المبلغ والقيمة في جدول ${sheetName}، شكرًا لك!`); } catch (e) { sendMessage(chatId, `حصل خطأ`); sendMessage(chatId, JSON.stringify(e?.message ?? e, null, 4)); } } أخذنا رقم المحادثة وحفظناه في المتغير chatId الذي حصلنا عليه من المعلومات المرسلة إلينا في البريد والسبب أن الخطأ قد يحصل في أي مكان، فربما يحصل في البداية ويضيع رقم المحادثة وبالتالي لن يصلنا البريد. نلاحظ أيضًا أننا استعملنا التعبير e?.message ?? e وذلك لاستخراج نص الرسالة مباشرة وسبب الخطأ فلا نريد أن تصلنا الكثير من البيانات في الرسالة. إن جربنا حفظ السكريبت وإعادة نشر التطبيق ثم إرسال نفس الرسالة للبوت وهي @نفقات 10 شراء فواكه، فسنلاحظ أنه لم يتغير شيء ولم تصلنا رسالة بالخطأ الحاصل، وبعد التحقق من السكربت نجد أن الخطأ في الدالة sendMessage إذ يجب ترميز نص الرسالة عبر encodeURIComponent قبل إرسالها في حال إرسال كائن أو شيفرة برمجية وبعد التعديل على الدالة تصبح بالشكل التالي: function sendMessage(chatId, message) { const response = UrlFetchApp.fetch(`${url}/sendMessage?chat_id=${chatId}&text=${encodeURIComponent(message)}`); Logger.log(response.getContentText()); } نعيد نشر التطبيق ثم إرسال نفس الرسالة وحينها نحصل على الرد التالي من البوت: تقول رسالة الخطأ بأن هنالك ورقة بنفس الاسم نفقات موجودة سابقًا ولا يمكن إنشاء ورقة جديدة بالاسم نفسه. عرفنا الآن سبب الخطأ ويمكننا حله بتعديل الدالة appendRow بالشكل التالي: function appendRow(sheetName, data) { const spreadSheet = SpreadsheetApp.openById(fileId); const sheet = spreadSheet.getSheetByName(sheetName) ? spreadSheet.getSheetByName(sheetName) : spreadSheet.insertSheet(sheetName); sheet.appendRow(data); } تحققنا أن الورقة موجودة، فإن كانت موجودة نستعملها عبر getSheetByName ونضيف فيها أو ننشئها من جديد عبر insertSheet وبذلك تُحل المشكلة إن أعدنا إرسال الرسالة من جديدة وطبعًا بعد نشر إصدار جديد من تطبيق الويب.ن الشيفرة الكاملة للبوت فيما يلي الشيفرة الكاملة للبوت بعد الانتهاء منه وتنفيذ كافة الخطوات const token = '7666156735:AAFlJYPgOzT5cTf8CfRx_5vf0GNuVmcvAuk'; const url = 'https://api.telegram.org/bot' + token; const webAppUrl = "https://script.google.com/macros/s/AKfycbwkoaVQ6aIWp6R0Pz5Q1EkiIydaKMusCKI7hEUYtPWXau7SLiznaagiAHDqkfiLzhhyXw/exec"; const fileId = '1LZlRezLubnD_4mGZulQ7RUZ9-itRefmJNSsSizRh8iY'; const chatId = 957260622; function getMe() { const response = UrlFetchApp.fetch(url + '/getMe'); Logger.log(response.getContentText()); } function getUpdates() { const response = UrlFetchApp.fetch(url + '/getUpdates'); Logger.log(response.getContentText()); } function doGet(e) { return HtmlService.createHtmlOutput("Hello " + JSON.stringify(e)); } function setWebhook() { const response = UrlFetchApp.fetch(url + '/setWebhook?url=' + webAppUrl); Logger.log(response.getContentText()); } function appendRow(sheetName, data) { const spreadSheet = SpreadsheetApp.openById(fileId); const sheet = spreadSheet.getSheetByName(sheetName) ? spreadSheet.getSheetByName(sheetName) : spreadSheet.insertSheet(sheetName); sheet.appendRow(data); } function sendMessage(chatId, message) { const response = UrlFetchApp.fetch(`${url}/sendMessage?chat_id=${chatId}&text=${encodeURIComponent(message)}`); Logger.log(response.getContentText()); } function doPost(e) { try { GmailApp.sendEmail(Session.getEffectiveUser().getEmail(), "رسالة جديدة من بوت التلغرام", JSON.stringify(e, null, 4)); const contents = JSON.parse(e.postData.contents); const id = contents.message.from.id; const name = contents.message.from.first_name; const text = contents.message.text; let sheetName = "مصاريف"; let itemValue, itemName; if (/^@/.test(text)) { const textArray = text.slice(1).split(" "); sheetName = textArray[0]; itemValue = textArray[1]; itemName = textArray.splice(2).join(" "); } else { const textArray = text.split(" "); itemValue = textArray[0]; itemName = textArray.shift().join(" "); } appendRow(sheetName, [String(new Date().toLocaleString()), itemValue, itemName]); sendMessage(id, `سجلت المبلغ والقيمة في جدول ${sheetName}، شكرًا لك!`); } catch (e) { sendMessage(chatId, `حصل خطأ`); sendMessage(chatId, JSON.stringify(e?.message ?? e, null, 4)); } } أفكار لتطوير البوت انتهينا من تطوير تطبيقنا وربطنا بوت تلغرام مع جداول البيانات بطريقة صحيحة ولكن هنالك الكثير من الأفكار والتطويرات التي يمكن إجراؤها على التطبيق وفيما يلي أبرز الأفكار التحسينية. تحليل الرسالة المستقبلة من البوت لم نعمل على تحليل الرسالة التي يستقبلها البوت، لذا يُفضَّل إضافة خطوة تحقق validation منها، فإن كانت لا تُطابق شروطًا معينة مثلًا لا تحوي على قيمة عددية تمثل المصروف أو النفقات سنرفض الرسالة ونعيد إرسال رسالة للبوت توضح أن هنالك شيء ناقص في الرسالة مع توضيح كيفية استعمال البوت وصيغة التواصل معه. إضافة قائمة أوامر للبوت بعد فترة قد ننسى كيفية استعمال البوت ولا نريد أن تفتح الشيفرة البرمجية لذا يمكن أن نضيف قائمة أوامر commands للبوت عبر /setcommands فيها مثلًا كيفية الاستعمال ليرد علينا البوت بكيفية الاستعمال وغيرها من الأوامر السريعة التي توسِّع عمل البوت وتسهِّل استخدامه. تحسين تنسيق الرسالة المرسلة للبوت أرسلنا في تطبيقنا رسالة نصية عادية text ولكن يمكننا الاستفادة من المعامل parse_mode في الواجهة البرمجية /sendMessage لإرسال الرسالة بتنسيق مارك داون أو بتنسيق HTML، وللمزيد انظر التنسيقات المدعومة في التوثيق. تحسين تنسيق جدول البيانات وتطويره يمكنك إضافة جداول أو أوراق sheets مسبقة وتعديل تنسيقها بصيغة معينة، فنحن لم نركز في هذا المقال على تنسيق الجداول لأنه خارج نطاقنا- كما يمكنك أيضًا إضافة أعمدة أو صفوف جامعة sum أو متوسط حسابي average بحيث نربطها مع أمر في البوت يجلب لنا مجموع المصروف أو النفقات الكلية أو لشهر محدد مثلً،ا وهكذا نطور تطبيق المصاريف والنفقات أو نتوسع وتُطوِّر من التطبيق أكثر ليصبح تطبيق محاسبي يفيد المستخدم. كما يمكننا إضافة أوامر تجلب لنا صورة عن مخططات شهرية مثلًا ثم إرسال هذه الصورة إلى البوت عبر الواجهة البرمجية /sendPhoto وغيرها من الأفكار العديدة الأخرى. ربط البوت مع ChatGPT هذه فكرة مميزة جدًا إذ يمكننا تحليل البيانات ومعالجتها عبر ربط البوت مع أحد نماذج الذكاء الاصطناعي مثل التفاعل مع الواجهة البرمجية API لروبوت الدردشة الشهير ChatGPT ، وبهذا يمكن تمرير الرسائل التي يرسلها المستخدم للبوت، وتحويلها إلى ChatGPT للحصول على رد وإعادة الناتج إلى البوت من جديد وبذلك نطوِّر من قدرات البوت وإمكانياته. خاتمة تعلمنا في هذا المقال كيفية إنشاء تطبيق متكامل يربط بين بوت تلغرام وجداول بيانات جوجل، وبذلك أصبح لدينا بوت يحفظ البيانات المرسلة إليه ويرد علينا برسالة مخصصة تؤكد حفظ البيانات أو رسالة بملخص الخطأ إن حصل، ولا يكتفي بذلك بل أيضًا يرسل لنا رسالة إلى بريدنا كلما وصلته رسالة من المستخدم. وختمنا المقال بأفكار لتحسين التطبيق والبناء عليه لتطوير بوتات تلغرام أكثر احترافية، وإذا كانت لديكم أي أفكار أخرى تخص تطوير بوتات تلغرام نرحب بمشاركتها معنا في قسم التعليقات أسفل المقال. اقرأ أيضًا التعامل مع جداول البيانات والأوراق والنطاقات من خلال Apps Script أساسيات برمجة التطبيقات Apps Script باستخدام جداول بيانات جوجل بناء بوت Bot تلغرام باستخدام لارافيل وبوتمان BotMan برمجة الروبوت: الدليل الشامل1 نقطة
-
1 نقطة
-
تعلم الآلة machine learning هو أحد الدعائم الأساسية لتكنولوجيا المعلومات على مدار العقدين الماضيين، وبات اليوم جزءًا أساسيًا من حياتنا اليومية. فمع توفر كميات متزايدة من البيانات أصبح هناك سببٌ وجيهٌ للاعتقاد بأن التحليل الذكي للبيانات سيكون أكثر انتشارًا وأهميةً كمكون أساسي للتقدم التكنولوجي. في المقالة السابقة قدمنا دليلًا شاملًا لبدء تعلم الذكاء الاصطناعي وفي هذه المقالة والتي تعتبر جزءًا من سلسلة مقالات عن الذكاء الصناعي بدأناها مع مقال مقدمة شاملة عن الذكاء الاصطناعي نُضيء لك الطريق ونقدم لك دليلًا شاملًا للبدء بتعلم وفهم تعلم الآلة والتعرف على أهم المصطلحات المرتبطة بهذا التخصص. ملاحظة: إن لم يكن لديك معرفة مسبقة بمجال الذكاء الصناعي وفروعه وأساسياته، سيكون من الأفضل أن تقرأ مقال "مقدمة شاملة عن الذكاء" من هذه السلسلة على الأقل التي أشرت إليها للتو. ما المقصود بتعلم الآلة؟ تعلم الآلة Machine learning أو ما يعرف اختصارًا ML هو مصطلح تقني يعني استخدام مجموعة من التقنيات والأدوات التي تساعد أجهزة الحاسوب والآلات الذكية عمومًا على التعلم والتكيف من تلقاء نفسها. لقد نشأ علم التعلم الآلي عندما بدأ علماء الحاسوب بطرح الأسئلة التالية: نحن البشر نتعلم من التجارب السابقة أما الآلات فهي تفعل ما نمليه عليها فقط فهل يمكن أن نتمكن من تدريب هذه الآلات كي تتعلم من البيانات والخبرات السابقة وتحاكي طريقة تفكيرنا وتتمكن من التعلم والفهم والاستنتاج دون تدخلنا؟ هل يمكن للحواسيب أن تفعل ما نفعله وبالطريقة التي نريدها، وأن تتعلم من تلقاء نفسه كيفية أداء مهمة محددة؟ هل يمكن للحواسيب والآلات أن تفاجئنا وتتعلم من خلال البيانات من تلقاء نفسه بدلًا من قيام المبرمجين بصياغة قواعد معالجة البيانات لها بشكل يدوي؟ كل هذه التساؤلات فتحت الباب أمام نموذج برمجة بديل عن أسلوب البرمجة الكلاسيكية التي يُدخل فيها البشر القواعد ضمن برامج حاسوبية ويحددون بدقة البيانات التي يجب معالجتها وفقًا لهذه القواعد ويكون الخرج إجابات محددة ناتجة عن عمليات المعالجة. في نموذج البرمجة الجديد هذا الذي سمي تعلم الآلة أصبح بمقدور البشر إدخال البيانات للحاسوب بالإضافة إلى الإجابات المتوقعة وفقًا للبيانات، ويكون الخرج هو القواعد التي تم استنتاجها بشكل برنامج أو ما يُسمى بالنموذج model ثم يمكن بعد ذلك تطبيق هذه القواعد على البيانات الجديدة لإنتاج الإجابات. بمعنى آخر نظام التعلم الآلي يُدرّب بدلًا من برمجته صراحةً، حيث تقدّم له العديد من عينات البيانات المتعلقة بالمهمة المطلوبة، ليكتشف بنية إحصائية في هذه العينات تربط المدخلات بالمخرجات (البيانات بالإجابات) وتسمح في النهاية للنظام بالوصول إلى قواعد لأتمتة المهمة. على سبيل المثال إذا عرضنا على الحاسوب مجموعات ثنائية من الأرقام كالتالي (2 , 4) و (3 , 6) و (4 , 9) ثم طلبنا منه بناء على هذه المعطيات أن يتنبأ بالرقم الذي يجب أن يأتي مع الرقم 5 فسوف يحتاج في بداية الأمر إلى إيجاد المنطق بين مجموعات البيانات التي مررناها له وتطبيق نفس المنطق للتنبؤ بالرقم الجديد، عملية العثور على هذا المنطق يسمى تعلم الآلة وبعد إيجاد هذا المنطق سنتمكن من تطبيقه للتنبؤ بكل رقم جديد. و إذا كنت ترغب بأتمتة عملية تخمين أسعار المنازل -يمكنك إعطاء نظام التعلم الآلي مجموعة من العينات التي تمثّل مواصفات المنازل (بيانات) مع أسعارها (إجابات)، وسيتعلم النظام القواعد الإحصائية اللازمة لربط المواصفات بالأسعار. على الرغم من أن التعلم الآلي بدأ في الازدهار بدءًا من التسعينيات، إلا أنه سرعان ما أصبح المجال الفرعي الأكثر شعبية والأكثر نجاحًا في الذكاء الصناعي. هل ترغب في استخدام ذكاء الآلة في أعمالك؟ وظّف مهندس ذكاء اصطناعي خبير لتحقيق أهدافك عبر مستقل أضف مشروعك الآن تعريف تعلم الآلة؟ هناك العديد من التعاريف الخاصة بتعلم الآلة نذكر منها أهم تعريفين: تعريف آرثر صامويل 1959: "تعلم الآلة هو المجال الدراسي الذي يمنح أجهزة الحاسب القدرة على التعلم دون برمجتها صراحةً من قبل البشر" تعريف توم ميتشل: "تعلم الآلة هو دراسة خوارزميات الحاسوب التي تحسن أدائها تلقائيًا من خلال التجربة ويقال أَنَّ برنامجا حاسوبيًا يتعلَّم من الخبرة E التي تخص بمجموعة من المهام T بالنسبة إِلى مقياس الأداء P إذا تحسن أداءه على إنجاز المهام T بعد اكتساب الخبرة E بالمقدار P" على سبيل المثال في مجال لعب الشطرنج تكون الخبرة E هي عدد مرات اللعب ضد الحاسب و T هي مهمة لعب الشطرنج ضد الحاسب والمعيار P هو فوز/خسارة الحاسب. ويمكننا القول بتعريف بسيط أن تعلم الآلة مجال من مجالات الذكاء الصناعي يحاول بناء آلات قادرة على التعلّم من تلقاء نفسها. الفرق بين الذكاء الاصطناعي وتعلم الآلة يميل معظم الناس إلى استخدام مصطلحي الذكاء الاصطناعي وتعلم الآلة كمرادفين ولا يعرفون الفرق، إلا أن هذين المصطلحين هما في الواقع مفهومان مختلفان، فتعلم الآلة هو في الواقع جزء من الذكاء الاصطناعي أو أحد أنواع الذكاء الاصطناعي ويمكن القول أن الذكاء الاصطناعي هو مجال واسع من الموضوعات، ويشكل تعلم الآلة جزء صغير من هذه الموضوعات. يشير الذكاء الاصطناعي إلى القدرة العامة لأجهزة الحاسب على محاكاة الفكر البشري وأداء المهام في بيئات العالم الحقيقي، بينما يشير التعلم الآلي إلى التقنيات والخوارزميات التي تمكّن الأنظمة من تحديد طريقة لتعلّم الأنماط المخفيّة في البيانات واتخاذ القرارات وتحسين نفسها من خلال التجربة والبيانات. أهمية تعلم الآلة قد تتساءل عن أهمية مجال تعلم الآلة في عصرنا الحالي وللإجابة على هذا السؤال يمكننا تقسيم الإجابة إلى شقين الأول أهمية تعلم الآلة بالنسبة للمؤسسات وتطور الحياة عمومًا، والثاني أهميته بالنسبة لبقية فروع الذكاء الصناعي و الفروع ذات الصلة. بالنسبة للشق الأول، فالبيانات هي شريان الحياة لجميع قطاعات الأعمال وقد باتت القرارات التي تعتمد على البيانات تصنع الفارق وتشكل الفصل بين مواكبة المنافسة أو التخلف عن الركب. التعلم الآلي هو مفتاح إطلاق العنان لقيمة بيانات الشركات والعملاء واتخاذ القرارات التي تجعل الشركة في صدارة المنافسة. إذًا يعتبر التعلم الآلي مهمًا لأنه يمنح المؤسسات بمختلف أنواعها وجهة نظر حول اتجاهات وسلوك العملاء وأنماط تشغيل الأعمال فضلًا عن دعم عملية تطوير منتجات جديدة كما أنها تساعد في أمور أخرى مثل اكتشاف الأمراض وتوقعات الطقس …إلخ. وتستخدم العديد من الشركات الرائدة اليوم مثل فيسبوك Facebook وجوجل Google وأوبر Uber التعلم الآلي كجزء أساسي من عملياتها. بالنسبة للشق الثاني، ففروع الذكاء الصناعي الأخرى مثل معالجة اللغات الطبيعية أو الفروع ذات الصلة كالرؤية الحاسوبية لم تبصر النور إلا بعد التطورات الأخيرة التي شهدها تعلم الآلة الذي شكَّل ركيزة أساسية في تطور معظم فروع الذكاء الصناعي. على سبيل المثال تعد تطبيقات التعرف على الكائنات أو تتبعها أو تصنيف الأشياء قضايا شائعة في الرؤية الحاسوبية، وهي تعتمد بشكل شبه مطلق على خوارزميات التعلم العميق والأمر ذاته ينطبق على معالجة اللغات الطبيعية. البيانات وتعلم الآلة البيانات هي وقود التعلم الآلي، فبدون البيانات ستكون خوارزميات التعلم الآلي جائعة وضعيفة الأداء وستفشل في حل أي مشكلة بشكل صحيح. وبعض خوارزميات التعلم الآلي مثل خوارزميات التعلم العميق لا تشبع، وكلما زودتها بالبيانات ونوّعتها لها كلما ازدادت قوتها وقدراتها وتحسن أداؤها. وتجدر الإشارة هنا لأن الأمر لا يتعلق بزيادة حجم البيانات وكميتها فقط بل يتعلق كذلك بدقة البيانات وجودتها وتنوع حالات استخدامها للحصول على نتائج صحيحة ودقيقة. وفيما يلي نوضح أهم النقاط الأساسية المتعلقة بالبيانات والمرتبطة بالتعلم الآلي: هناك نوعان أساسيان للبيانات المستخدمة في التعلم الآلي: بيانات مُسماة labeled وغير مسماة unlabeled على سبيل المثال إذا كان المطلوب هو التنبؤ بعمر شخص ما فإن العمر هنا يعد من البيانات المسماة في حين أن البيانات غير المسماة لا تحتوي على أي سمة مميزة. تسمى خوارزميات تعلم الآلة التي تتعامل مع مجموعة بيانات مسماة خوارزميات التعلم الخاضع للإشراف في حين تسمى خوارزميات تعلم الآلة التي تستخدم مجموعة بيانات غير مسماة خوارزميات التعلم غير الخاضع للإشراف وسنشرح المزيد عن هذه الأنواع من التعلم الآلي في فقرة لاحقة. عادةً ما تكون البيانات المستخدمة في التعلم الآلي عددية Numerical أو فئوية Categorical. تتضمن البيانات العددية القيم التي يمكن ترتيبها وقياسها مثل العمر أو الدخل، وتتضمن البيانات الفئوية القيم التي تمثل الفئات، مثل الجنس أو نوع الفاكهة. يمكن تقسيم البيانات إلى مجموعات تدريب Training ومجموعات مراقبة أو تحقق Validation ومجموعات اختبار Testing حيث تُستخدم مجموعة بيانات التدريب لتدريب النموذج، وتُستخدم مجموعة المراقبة لمراقبة سير عملية التدريب وتعلّم النموذج وأخيرًا تُستخدم مجموعة الاختبار للتقييم النهائي لأداء النموذج. تعد المعالجة المسبقة للبيانات خطوة مهمة في تعلم الآلة حيث يتم من خلالها تنظيف البيانات ومعالجة القيم المفقودة والشاذة وهندسة الميزات. هناك فرق بين البيانات والمعلومات والمعرفة، فالبيانات يمكن أن تكون أي حقيقة أو قيمة أو نص أو صوت أو صورة غير معالجة لم تُفسّر أو تحلل أما المعلومات فهي البيانات بعد تفسيرها ومعالجتها. أي أنها شكل متطور للبيانات ذو فائدة ومعنى أكبر والمعرفة هي المرحلة الأكثر تطورًا والمتمثلة بالوعي والفهم والإدراك للمعلومات. تطبيقات تعلم الآلة للتعلم الآلي تطبيقات في جميع أنواع الصناعات وفي حياتنا اليومية عمومًا، يتضمن ذلك التصنيع والتجارة بالتجزئة والرعاية الصحية وعلوم الحياة والسفر والضيافة والخدمات المالية والطاقة والمواد الأولية والمرافق. بما أن تعلم الآلة يندرج تحت مظلة الذكاء الاصطناعي، فإن تطبيقات تعلم الآلة تدخل ضمن أي تطبيق ذكاء اصطناعي وقد تحدثنا عن تطبيقات الذكاء الاصطناعي في مقال تطبيقات الذكاء الاصطناعي لذا يمكنك الرجوع إليه. تشمل بعض حالات الاستخدام لمجال تعلم الآلة: التعرّف على الصور التعرف على الكلام التصنيف والتنبؤ الآلات والروبوتات الذكية -السيارات ذاتية القيادة التجارة الإلكترونية الأمان واكتشاف التزوير أو الاحتيال -الترجمة الآلية والخدمات المالية …إلخ. يُستخدم التعلم الآلي في العديد من المجالات الأخرى والتي قد لا يسعنا ذكر جميعها هنا. كما أن معظم تطبيقات الذكاء الصناعي اليوم تعتمد بشكل كامل على خوارزميات تعلم الآلة. طور أعمالك مع حلول الذكاء الاصطناعي المبتكرة اسبق منافسيك نحو المستقبل وحقق أهدافك بالاستعانة بقوة الذكاء الاصطناعي اطلب خدمات الذكاء الاصطناعي الآن في الفيديو التالي ستتعرف على المزيد من المعلومات حول معنى تعلم الآلة وأهدافها والمكونات الرئيسية لأي نظام معتمد على تعلم الآلة وأمثلة منوعة على التطبيقات المستخدمة في هذا المجال. أنواع تعلم الآلة ينقسم تعلم الآلة إلى أربعة أنواع أساسية أو مجالات أساسية بناءً على نوع البيانات المستخدمة وأسلوب التعلم المتبع وهذه الأنواع هي: التعلم الخاضع للإشراف Supervised learning التعلم غير الخاضع للإشراف UnSupervised learning التعلم شبه الخاضع للإشراف Semi-Supervised Learning التعلم المُعزز Reinforcement Learning يحاكي كل نوع من هذه الأنواع الطرق والأساليب المختلفة التي تتخذ بها نحن البشر قرارتنا وإليك شرحًا مفصلًا لكل نوع من بين هذه الأنواع. 1. التعلم الخاضع للإشراف Supervised learning هو أحد أكثر أنواع التعلم الآلي شيوعًا ونجاحًا. في هذا النوع تُعطى الخوارزمية مجموعةً من البيانات بالإضافة إلى الخرج الصحيح لها. أي أن الخوارزمية تُدرّب على مجموعةً بيانات مُسماة. مبدأ عمل الخوارزميات التي تنتهج هذا النهج هو: الحصول على مجموعة بيانات مُسماة، ثم تدريب النموذج على إيجاد علاقة أو دالة function تربط بين المدخلات والمخرجات. إذًا يمكننا القول أن هذا النهج يُستخدم عندما نريد بناء نموذج يتنبأ (كلمة يتنبأ هنا تشمل التصنيف أيضًا) بنتيجة معينة في ضوء مدخلات معينة ويتطلب تعلم الآلة الخاضع للإشراف جهدًا بشريًا لبناء مجموعة التدريب المناسبة. هناك نوعان رئيسيان من مشكلات التعلم الآلي الخاضعة للإشراف هما التصنيف Classification والتوقع Regression. يكون الهدف في حالة التصنيف هو التنبؤ بتسمية فئة من قائمة محددة مسبقًا من الفئات. المثال الذي ورد في الفقرة السابقة هو خير مثال على ذلك، حيث نُدرّب الخوارزمية على التمييز بين فئتين أو نوعين من الفاكهة هما البرتقال والتفاح. التصنيف بدوره يُقسم إلى نوعين أساسيين هما: التصنيف الثنائي Binary Classification والتصنيف المتعدد Multiclass-Classification. يحدث التصنيف الثنائي عندما يكون لدينا فئتين من البيانات كما في مثال البرتقال والتفاح، مثال آخر هو تصنيف رسائل البريد الإلكتروني على أنها بريد عشوائي أو بريد حقيقي أما التصنيف المتعدد فهو يحدث عندما يكون لدينا أكثر من فئتين (مثلًا لو كان المطلوب جعل النموذج سالف الذكر يميز بين 3 أنواع من الفاكهة هي البرتقال والتفاح والموز. بالنسبة لمهام التوقع، فإن الهدف يكون توقع قيمة من مجال غير محدد وخير مثال على ذلك هو توقع أسعار المنازل أو توقع الدخل السنوي للفرد بناءًا على مستواه التعليمي وعمره ومكان إقامته فسعر المنازل أو الدخل السنوي يمكن أن تكون أي قيمة ضمن مجال ما. 2. التعلم غير الخاضع للإشراف UnSupervised learning في هذا النوع من أنواع تعلم الآلة تُعطى الخوارزمية مجموعةً من البيانات بدون الخرج الصحيح لها، أي أن الخوارزمية تُدرّب على مجموعةً بيانات غير مُسماة. مبدأ عمل الخوارزميات التي تنتهج هذا النهج هو: الحصول على مجموعة بيانات غير مُسماة، ثم تدريب النموذج على إيجاد علاقات مخفيّة بين هذه المُدخلات. هناك نوعان أساسيين من الخوارزميات التي تنتهج هذا النهج هما خوارزميات التحويل Transformation وخوارزميات العنقدة أو التجميع Clustering. تُنشئ خوارزميات التحويل تمثيلًا جديدًا للبيانات قد يكون من الأسهل على البشر أو خوارزميات التعلم الآلي الأخرى فهمه مقارنةً بالتمثيل الأصلي للبيانات. بالنسبة للنوع الآخر المتمثل بخوارزميات العنقدة، فهي تعتمد على تقسيم البيانات إلى مجموعات مميزة من العناصر المتشابهة. خذ مثلًا عملية تحميل الصور على أحد مواقع التواصل الاجتماعي كمثال، هنا قد يرغب الموقع في تجميع الصور التي تُظهر الشخص نفسه مع بعضها بغية تنظيم صورك إلا أن الموقع لا يعرف من يظهر في الصور ولا يعرف عدد الأشخاص المختلفين الذين يظهرون في مجموعة الصور خاصتك. تتمثل الطريقة المنطقية لحل المشكلة في استخراج كل الوجوه وتقسيمها إلى مجموعات من الوجوه المتشابهة، وبعدها يتم وضع كل صورة جديدة تحملها في المجموعة الأكثر شبهًا لها ومن أشهر خوارزميات العنقدة نذكر خوارزمية K-means. التعلم شبه الخاضع للإشراف Semi-Supervised Learning تحدثنا سابقًا عن أهمية البيانات، وأنّه كلما زاد حجم البيانات التي نُدرّب النموذج عليها تزداد قوته، ولاسيما بالنسبة خوارزميات التعلم العميق التي تنتهج النهج الخاضع للإشراف والتي تعتمد على البيانات المُسماة. نشأ التعلم شبه الخاضع للإشراف من السؤال التالي: ماذا لو لم يكن لدينا ما يكفي من البيانات المُسماة لخوارزميتنا التي تنتهج المنهج الخاضع للإشراف؟ قد يخطر ببالك في هذه الحالة محاولة تسمية البيانات يدويًا لكن هذا ليس مضيعة للوقت فقط لكنه أيضًا عرضة للعديد من أنواع الأخطاء البشرية الحل البديل الجديد هو استخدام التعلّم شبه الخاضع للإشراف وهو مزيج من التعلم الخاضع للإشراف والتعلم غير الخاضع للإشراف فهو يستخدم البيانات غير المسماة (والتي تكون كثيرة) والبيانات المسماة (والتي تكون قليلة) معًا، لإنشاء تقنيات تعلم أفضل من تلك التي تُنشأ باستخدام البيانات غير المسماة فقط أو المسماة فقط. التعلم المعزز Reinforcement Learning في هذا النوع من تعلم الآلة ابتكر المطورون طريقة لمكافأة السلوكيات المرغوبة ومعاقبة السلوكيات السلبية للآلة حيث يعتمد التعلم المُعزز على التعلم من خلال التفاعل مع البيئة أي أن الخوارزمية أو الروبوت أو البرنامج والذي يسمى في هذه الحالة الوكيل "agent" يتعلم من من عواقب أفعاله بدلًا من تعليمه صراحةً. فالوكيل يختار أفعاله وقرارته المستقبلية على أساس تجاربه السابقة (الاستغلال) وأيضًا من خلال الخيارات الجديدة (الاستكشاف) أي أن التعلم يرتكز على مبدأ التجربة والخطأ ويتعلق الأمر باتخاذ الإجراءات المناسبة لزيادة المكافأة إلى أقصى حد في موقف معين. يتطلب التعلم المعزز عددًا كبيرًا من التفاعلات بين الوكيل والبيئة لجمع البيانات للتدريب ويستخدم في مجال الألعاب حيث تعد الألعاب من أبرز مجالات استخدام التعلم المعزز فهو قادر على تحقيق أداء خارق في العديد من الألعاب مثل لعبة Pac-Man. ومن الأمثلة على استخدامه هو تدريب السيارات على التوقف باستخدام نظام القيادة الآلي حيث يتم تعليم حاسوب السيارة أو الوكيل على الوقوف في المكان الصحيح من خلال قراءة بيانات أجهزة استشعار مثل الكاميرات ونظام تحديد المواقع GPS واتخاذ الإجراءات المناسبة مثل الضغط على الفرامل وتغيير الاتجاه ويحتاج الوكيل بالطبع إلى إيقاف السيارة مرارًا وتكرارًا باستخدام التجربة والخطأ ويتم تقديم إشارة مكافأة لتقييم جودة التجربة وتعزيز عملية التعلم. نماذج تعلم الآلة لقد وصل التعلم العميق وهو نوع متقدم من أنواع تعلم الآلة إلى مستوى من الاهتمام العام والاستثمار الصناعي لم يسبق له مثيل في تاريخ مجال علوم الحاسوب ولكنه ليس أول شكل أو نموذج ناجح للتعلم الآلي ويمكننا القول إن معظم خوارزميات التعلم الآلي المستخدمة في الصناعة هذه الأيام -ليست خوارزميات التعلم العميق. يوفر مجال تعلم الآلة العديد من النماذج machine learning models أشهرها التعلم العميق لكن في الواقع لا يعد التعلم العميق دائمًا الأداة المناسبة، ففي بعض الأحيان لا توجد بيانات كافية ليكون التعلم العميق قابلاً للتطبيق، ويفضل أن تُحلّ المشكلة بطريقة أفضل من خلال خوارزمية مختلفة وفيما يلي نوضح أهم أنواع طرق تعلم الآلة: النمذجة الاحتمالية Probabilistic modeling أساليب النواة Kernel Methods أشجار القرار Decision Trees والغابات العشوائية Random Forests الشبكات العصبية Neural Networks التعلم العميق Deep Learning لنتعرف على قرب على كل نموذج من هذه النماذج وأشهر استخداماته وخوارزمياته. النمذجة الاحتمالية Probabilistic modeling تعتمد النمذجة الاحتمالية على تطبيق مبادئ الإحصاء في تحليل البيانات. لقد كانت أحد أقدم أشكال التعلم الآلي، والتي لا تزال مستخدمة حتى يومنا هذا واحدة من أشهر الخوارزميات في هذه الفئة هي خوارزمية بايز الساذج Naive Bayes. أساليب النواة Kernel Methods عندما بدأت الشبكات العصبية تكتسب شهرة بين الباحثين في التسعينيات ظهر نهج جديد للتعلم الآلي سمي أساليب النواة وسرعان ما أدى لتراجع شعبية الشبكات العصبية، وأساليب النواة هي مجموعة من خوارزميات التصنيف، وأشهرها خوارزمية الآلة متجه الدعم (SVM). أشجار القرار Decision Trees والغابات العشوائية Random Forests هي إحدى طرق النمذجة التنبؤية التي تُستخدم في الإحصاء واستخراج البيانات وتعلم الآلة وهي عبارة عن هياكل شبيهة بالمخططات التدفقية تتيح لك تصنيف نقاط البيانات المُدخلة أو التنبؤ بقيم المخرجات بناءًا على البيانات المُدخلة مثلًا تعطيها مواصفات المنزل، فتتوقع السعر وقد تم تفضيلها على أساليب النواة. الشبكات العصبية Neural Networks حتى عام 2010 تقريبًا، كانت الشبكات العصبية مُهمّشة إلى أن بدأ عدد من الباحثين الذين كانوا ما يزالون يؤمنون بالشبكات العصبية في تحقيق نتائج مهمة باستخدامها، وبذلك بدأت التطورات على الشبكات العصبية تتسارع وتفرض هيمنتها في معظم مهام تعلم الآلة. التعلم العميق Deep Learning السبب الرئيسي وراء انتشار التعلم العميق وتطوره بسرعه هو أنه قدّم أداءً أفضل في العديد من المشكلات واختصر العديد من الخطوات المعقدة التي كانت موجودة في الأساليب السابقة، والتعلم العميق اليوم هو الأسلوب الأنجح في جميع المهام الحسية أو الإدراكية مثل مهام الرؤية الحاسوبية ومعالجة اللغات الطبيعية NLP. وللتعرف على المزيد من الأساليب المتطورة لخوارزميات وأدوات التعلم الآلي يمكنك إلقاء نظرة على مسابقات التعلم الآلي على موقع Kaggle نظرًا لبيئتها شديدة التنافس (بعض المسابقات لديها آلاف المشاركين وجوائز بملايين الدولارات) وللتنوع الكبير في مشكلات التعلم الآلي التي تغطيها. لغة بايثون وتعلم الآلة تعد لغة البرمجة بايثون اللغة الأكثر شهرة في مجال تعلم الآلة لعدد كبير من الأسباب فهي لغة سهلة التعلم والفهم و ولها شعبية كبيرة وتستخدم من قبل عدد كبير من الأشخاص والمؤسسات وتملك العديد من المكتبات وأطر العمل التي تختص في مجال الذكاء الصنعي وتعلم الآلة فيما يلي سنكتب كود تعلم آلة في بايثون، حيث سنستخدم خوارزمية أشجار القرار لتوقع نوع الفاكهة (برتقال أو تفاح) بناءًا على وزنها ونسيجها. from sklearn import tree # الخطوة 1 # الخطوة 2 X = [[140, 1], [130, 1], [150, 0], [170, 0]] y = [0, 0, 1, 1] # 0: apple, 1: orange # الخطوة 3 clf = tree.DecisionTreeClassifier() clf = clf.fit(X, y) # الخطوة 4 prediction = clf.predict([[160, 0]]) print(prediction) # النتيجة: 1 شرح تنفيذ الشيفرة: الخطوة الأولى: هي استيراد المكتبة ساي كيت ليرن sklearn التي تحتوي العديد من خوارزميات تعلم الآلة الجاهزة. الخطوة الثانية: هي تحديد بيانات التدريب. هنا سيكون لدينا 4 عينات، كل عينة تُمثّل نقطة بيانات الخطوة الثالثة: هي تدريب خوارزمية أشجار القرار على البيانات السابقة الهدف هنا هو جعل الخوارزمية قادرة على التنبؤ بنوع الفاكهة بعد أن ندربها على البيانات السابقة. الخطوة الرابعة: بعد الخطوة 3 نكون انتهينا من تدريب النموذج، أي أنه أصبح جاهزًا للاستخدام الفعلي. لذا نعطيه عينة بيانات، ونطلب منه توقع نوع الفاكهة. إذا كنت مهتمًا بإتقان تعلم الآلة باستخدام لغة البرمجة بايثون يمكنك البدء مع دورة الذكاء الاصطناعي AI التي توفرها أكاديمية حسوب والتي تبدأ معك من الصفر ولا تتطلب منك أي خبرة مسبقة فهي تبدأ معك بتعلم كل ما تحتاجه بلغة بايثون وتطوير تطبيقات تستفيد من دمج مختلف نماذج LLMs الحديثة مثل GPT من OpenAI و LLaMA 2 من Meta لتطوير تطبيقات ذكية بسهولة وكفاءة كما تشرح لك تحليل البيانات Data Analysis وتمثيلها مرئيًا، ومفاهيم تعلم الآلة Machine Learning والتعلم العميق Deep Learning وغيرها من خلال التركيز على الشرح العملي المعد من قبل مجموعة من المطورين المُختصين، الذين يُرافقونك طيلة الدورة وحتى بعد الدورة للإجابة على أي سؤال أو مشكلة تواجهك كما تضمن لك الدورة دخول السوق والحصول على فرصة عمل بعد تخرجك من الدورة خلال ستة أشهر. دورة الذكاء الاصطناعي احترف برمجة الذكاء الاصطناعي AI وتحليل البيانات وتعلم كافة المعلومات التي تحتاجها لبناء نماذج ذكاء اصطناعي متخصصة. اشترك الآن مصادر تعليمية لتعلم الآلة بالإضافة إلى دورة بايثون الشاملة التي ذكرناها للتو والتي تعد من أفضل الدورات العربية لتعلم بايثون وتعلم الآلة، توفر توفر لك أكاديمية حسوب أيضًا مجموعة من المقالات والدروس التعليمية ومنشورات الكتب العربية التي تعد من أفضل مصادر تعلم الآلة وتعلم البرمجة وعلوم الحاسوب نذكر لك منها: كتاب البرمجة بلغة بايثون كتاب مدخل إلى الذكاء الاصطناعي وتعلم الآلة كتاب عشرة مشاريع عملية عن الذكاء الاصطناعي سلسلة برمجة الذكاء الاصطناعي المفاهيم الأساسية لتعلم الآلة نظرة سريعة على مجال تعلم الآلة أدوات برمجة نماذج تعلم الآلة وننصحك بتفصّح ومتابعة قسم مقالات الذكاء الاصطناعي في أكاديمية لقراءة المقالات الجديدة المنشورة حول الذكاء الاصطناعي وتعلم الآلة وما يتعلق بهما. أفضل مكتبات تعلم الآلة في بايثون إليك قائمة بأهم المكتبات التي قد تحتاجها في تعلّم الآلة (جميعها تعمل في لغة بايثون): نمباي Numpy: من أفضل مكتبات بايثون في مجال تعلم الآلة والذكاء الصناعي فهي مكتبة قوية وشائعة الاستخدام تسهل معالجة المصفوفات والتعامل معها وتسهل عمليات معالجة البيانات والعمليات الإحصائية عليها. سي باي Scipy: توفر هذه المكتبة مجموعة من الحزم المخصصة للاستخدام في مجال للحوسبة العلمية والهندسة والتقنية وتحتوي على وحدات مختلفة للجبر الخطي والتكامل والإحصاءات. ساي كيت ليرن Scikit-learn: اختصارًا Sklearn وهي مكتبة فعالة توفر العديد من أدوات وخوارزميات تعلم الآلة. باندا Pandas: هي مكتبة تستخدم لمعالجة البيانات وتحليلها وتسهل عمليات تنظيم البيانات وفهرستها ووضعها ضمن جداول وإجراء العمليات عليها. ماتبلوتليب Matplotlib: هي مكتبة بايثون خاصة بتصميم الرسوميات والمخططات البيانية وإنشاء رسومات تفاعلية وتصديرها إلى تنسيقات مختلفة. إضافة للعديد من أطر العمل القوية مثل ثيانو Theano وتنسرفلو TensorFlow وكيراس Keras وباي تورش PyTorch التي تسهل بناء نماذج الشبكات العصبية وتطبيق خوارزميات التعلم العميق. مستقبل تعلم الآلة بالرغم من أن خوارزميات تعلم الآلة كانت موجودة منذ عقود إلا أنها اكتسبت شعبية أكبر مع تنامي الذكاء الاصطناعي فمعظم تطبيقات الذكاء الصناعي المتقدمة التي نراها اليوم هي تطبيقات تعمل باستخدام خوارزميات تعلم الآلة (لاسيما التعلم العميق) بدءًا من خوارزميات التوصية التي نراها في موجز أخبار فيسبوك وغيرها من شبكات التواصل الاجتماعي والتي تعتمد على اهتماماتنا وعاداتنا في القراءة وصولًا السيارات ذاتية القيادة مثل سيارات تسلا Tsla ومعالجة اللغات الطبيعية مثل تطبيق الدردشة ChatGPT. كما تندمج الحلول التي يقدمها تعلم الآلة يومًا بعد يوم في العمليات الأساسية للشركات واستخدامات حياتنا اليومية مثل الترجمة الآلية للغات والتشخيص الطبي البحث الصوتي والبحث عن أقصر الطرق للوصول إلى وجهة ما وغيرها الكثير من التطبيقات ومن المتوقع أن ينمو السوق العالمي للتعلم الآلي من 8.43 مليار دولار أمريكي في عام 2019 إلى 117.19 مليار دولار أمريكي بحلول عام 2027 وفقًا لتوقع Fortune Business Insights. وقد بدأت العديد من الشركات بالفعل في استخدام خوارزميات التعلم الآلي نظرًا لقدرتها على إجراء تنبؤات وقرارات تجارية أكثر دقة ففي عام 2020 تم رصد 3.1 مليار دولار لتمويل شركات تعلم الآلة، وذلك لقدرة تعلم الآلة على إحداث تغييرات كبيرة في الصناعات. فيما يلي بعض التوقعات لمستقبل التعلم الآلي: يمكن للحوسبة الكمية أن تحدد مستقبل تعلم الآلة: والحوسبة الكمومية هي أحد المجالات التي لديها القدرة على تعزيز قدرات التعلم الآلي وهي تسمح بأداء عمليات متعددة الحالات في وقت واحد، مما يتيح معالجة أسرع للبيانات ففي عام 2019 أجرى معالج كمي خاص بشركة جوجل Google مهمة في 200 ثانية من شأنها أن تستغرق 10000 عام لإكمالها على أفضل حاسب عملاق في العالم! قد يتمكن برنامج AutoML من تسهيل عملية تطوير نماذج تعلم الآلة من البداية إلى النهاية: يعمل AutoML الذي طورته جوجل على أتمتة عملية بناء وتطبيق خوارزميات التعلم الآلي وهو يسمح لأي شخص أو شركة تجارية بتطبيق نماذج وتقنيات التعلم الآلي المعقدة وتخصيصها وفق احتياجات أعمالهم خلال دقائق دون أن يكون خبيرًا في التعلم الآلي. دخول تعلم الآلة بقوة في عملية التصنيع: لا زالت الشركات المصنعة ما زالت في المراحل الأولى فقط من تبني التعلم الآلي. ففي عام 2020 استفادت 9٪ فقط من الشركات المشاركة في استطلاع رأي حول استخدام الذكاء الاصطناعي في عملياتهم التجارية، لكن مع التطورات المستمرة التي نشهدها في مجال تعلم الآلة يتوقع أن تزداد هذه النسبة بشكل كبير ويصبح الاعتماد على استخدام تقنيات تعلم الآلة والروبوتات في أماكن التصنيع أكثر بكثير في المستقبل القريب. السيارات والمركبات ذاتية القيادة: تعمل شركات مثل تسلا وهوندا باستمرار على إنتاج هذا النوع من السيارات مستفيدة من تقنيات التعلم الآلي، وقد قدمت هذه الشركات بالفعل سيارات مؤتمتة جزئيًّا لكن لا تزال السيارات ذاتية القيادة قيد التطوير ولم تصل إلى الشكل النهائي. الخلاصة قدمنا من خلال هذه المقالة دليلًا شاملًا عن تعلم الآلة وبدأنا بتوضيح المفهوم نفسه وأنواع التعلم الآلي وتطبيقاته والفروقات بينها والفرق بين التعلم الآلي والذكاء الاصطناعي، كما تعرفنا على أهمية لغة البرمجة بايثون في مجال التعلم الآلي وسردنا أهم المكتبات وأطر العمل التي توفرها في مجال التعلم الآلي وقدّمنا مثلًا برمجيًا لتطبيق خوارزمية الانحدار اللوجستي كما سردنا أهم المصادر والمراجع لتعلم مجال الذكاء الاصطناعي عمومًا وتعلم الآلة خصوصًا ثم ألقينا نظرة أخيرًا على مستقل مجال تعلم الآلة. نرجو أن تكون هذه المقالة قد قدمت لك فهمًا جيّدًا لمجال تعلم الآلة ووضحت لك المفاهيم الأساسية لتنطلق في رحلة تعلم الآلة والانتقال إلى مواضيع وتطبيقات عملية حتى دخول سوق العمل.1 نقطة
-
كانت لحظة مرعبة حينما جلست على حاسوبي بعد أن «عضّ القرش» كبل الإنترنت وانقطع، وأدركت حينها كم أقضي وقتًا على الإنترنت حينما أستعمل حاسوبي؛ فلدي عادة أن أتحقق من بريدي يدويًا (مع أن التنبيهات تصلني أولًا بأول!) وأفتح تويتر (إكس، سمهِّ ما شئت) وأنظر ما آخر المستجدات. كثيرٌ من عملنا على الحاسوب يتطلب وصولًا إلى الانترنت، ومصطلح «استخراج البيانات من الويب» Web scraping يستعمل مع البرامج التي تنزل المحتوى من الإنترنت وتعالجه. فمثلًا لدى غوغل عدد من البوتات لتنزيل محتوى صفحات الويب وفهرستها وأرشفتها لتستعملها في محرك البحث. سنتعلم في هذا المقال عن عددٍ من الوحدات في بايثون التي تسهل علينا استخراج البيانات من الويب: webbrowser: حزمة تأتي مع بايثون وتفتح متصفحًا على صفحة ويب معينة. requests: تنزل الملفات وصفحات الويب من الإنترنت. bs4: تفسّر شيفرات HTML التي تكتب فيها صفحات الويب. selenium: تشغل وتتحمل في متصفح ويب، والوحدة selenium قادرة على ملء الاستمارات ومحاكاة ضغطات الفأرة في المتصفح. مشروع: برنامج mapIt.py مع وحدة webbrowser الدالة open() في الوحدة webbrowser تفتح صفحة ويب معينة في نافذة متصفح جديدة. جرب ما يلي في الصدفة التفاعلية: >>> import webbrowser >>> webbrowser.open('https://academy.hsoub.com/') ستجد أكاديمية حسوب مفتوحةً في لسانٍ جديد في المتصفح. هذا كل ما تستطيع الوحدة webbrowser فعله، لكن مع ذلك يمكننا أن نجري بعض الأمور اللطيفة مع الدالة open()، فمثلًا قد تكون مهمة فتح خرائط جوجل والبحث عن عنوان معين أمرًا مملًا، ونستطيع التخلص من بضع خطوات لو كتبنا سكربتًا يفتح خرائط جوجل ويوجهها إلى عنوان الشارع المنسوخ في الحافظة لديك، وبالتالي سيكون عليك أن تنسخ العنوان إلى الحافظة وتشغل السكربت، وستفتح الخريطة لديك. هذا ما يفعله البرنامج: يحصل على عنوان الشارع من وسائط سطر الأوامر أو من الحافظة يفتح نافذة متصفح ويوجهها إلى صفحة خرائط جوجل المرتبطة بعنوان الشارع. هذا يعني أن على الشيفرة البرمجية أن تفعل ما يلي: تقرأ وسائط سطر الأوامر تقرأ محتويات الحافظة تستدعي الدالة webbrowser.open() لتفتح صفحة الويب. احفظ ملفًا جديدًا باسم mapIt.py، ولنبدأ برمجته. الخطوة 1: معرفة الرابط الصحيح اعتمادًا على التعليمات الموجودة في الملحق ب، اضبط برنامج mapIt.py ليعمل من سطر الأوامر كما في المثال الآتي: C:\> mapit 870 Valencia St, San Francisco, CA 94110 سيستخدم البرنامج وسائط سطر الأوامر بدلًا من الحافظة، وإذا لم نمرر إليه أيّة وسائط فحينها سيقرأ محتويات الحافظة. علينا بدايةً أن نحصِّل ما هو عنوان URL الذي يجب فتحه للعثور على شارع معين. إذا فتحت خرائط جوجل في المتصفح وبحثت عن عنوان فسيكون الرابط في الشريط العلوي يشبه: https://www.google.com/maps/place/870+Valencia+St/@37.7590311,-122.4215096,17z/data=!3m1!4b1!4m2!3m1!1s0x808f7e3dadc07a37:0xc86b0b2bb93b73d8 نعم العنوان في الرابط، لكن هنالك نص كثير إضافي غيره. تضيف المواقع عادةً بيانات إضافية لتتبع الزوار أو تخصيص المواقع. لكن إن حاولت الذهاب إلى الرابط التالي: https://www.google.com/maps/place/870+Valencia+St+San+Francisco+CA/ فسترى العنوان مفتوحًا أمامك. وبهذا كل ما نحتاج إليه هو فتح صفحة ويب ذات العنوان التالي: https://www.google.com/maps/place/your_address_string حيث your_address_string هو العنوان الذي تريد عرضه في الخريطة. الخطوة 2: التعامل مع وسائط سطر الأوامر يجب أن تبدو الشيفرة لديك كما يلي: #! python3 # mapIt.py - تشغيل خريطة في المتصفح باستخدام عنوان # من سطر الأوامر أو الحافظة. import webbrowser, sys if len(sys.argv) > 1: # Get address from command line. address = ' '.join(sys.argv[1:]) # TODO: الحصول على العنوان من الحافظة. بعد سطر !# سنستورد الوحدة webbrowser لتشغيل المتصفح والوحدة sys لمحاولة قراءة وسائط سطر الأوامر. يخزن المتغير sys.argv اسم الملف ووسائط سطر الأوامر، وإذا احتوت هذه القائمة على أكثر من عنصر واحد (الذي هو اسم الملف) فيجب أن تكون قيمة استدعاء len(sys.argv) أكبر من 1، وهذا يعني أن هنالك وسائط في سطر الأوامر. عادةً ما يُفصَل بين وسائط سطر الأوامر بفراغات، لكن في هذه الحالة نريد أن نفسر جميع الوسائط على أنها سلسلة نصية واحدة، ولما كانت قيمة sys.argv هي قائمة تحتوي على سلاسل نصية، فيمكننا استخدام التابع join() معها، مما يعيد سلسلة نصية واحدة؛ لكن انتبه أننا لا نريد اسم الملف ضمن تلك السلسلة النصية، فعلينا استخدام sys.arv[1:] لإزالة أول عنصر في القائمة، ثم سنتخزن تلك القيمة في المتغير address. يمكنك تشغيل البرنامج بكتابة ما يلي في سطر الأوامر: mapit 870 Valencia St, San Francisco, CA 94110 وستكون قيمة المتغير sys.argv هي القائمة: ['mapIt.py', '870', 'Valencia', 'St, ', 'San', 'Francisco, ', 'CA', '94110'] وبالتالي تكون قيمة المتغير address هي السلسلة النصية '870 Valencia St, San Francisco, CA 94110'. الخطوة 3: التعامل مع محتويات الحافظة وتشغيل المتصفح تأكد أن الشيفرة الخاصة بك تشبه الشيفرة الآتية: #! python3 # mapIt.py - تشغيل خريطة في المتصفح باستخدام عنوان # من سطر الأوامر أو الحافظة. import webbrowser, sys, pyperclip if len(sys.argv) > 1: # Get address from command line. address = ' '.join(sys.argv[1:]) else: # الحصول على العنوان من الحافظة. address = pyperclip.paste() webbrowser.open('https://www.google.com/maps/place/' + address) إذا لم تكن هنالك وسائط ممررة عبر سطر الأوامر، فسيفترض البرنامج أن العنوان منسوخ إلى الحافظة، ويمكننا الحصول على محتوى الحافظة باستخدام pyperclip.paste() وتخزينها في المتغير address. آخر خطوة هي تشغيل المتصفح مع توفير رابط URL صحيح لخرائط غوغل عبر webbrowser.open(). ستوفر عليك بعض البرامج التي ستطورها ساعات من العمل، لكن بعض قد يكون بسيطًا ويوفر عليك بضع ثوانٍ في كل مرة تجري فيها مهمة تكرارية مثل فتح عنوان ما على الخريطة، الجدول التالي يقارن بين الخطوات اللازمة لعرض الخريطة: فتح الخريطة يدويًا استخدام سكربت mapIt.py تحديد العنوان نسخ العنوان فتح متصفح الويب الذهاب إلى خرائط غوغل الضغط على حقل الإدخال لصق العنوان الضغط على enter تحديد العنوان نسخ العنوان تشغيل mapIt.py مقارنة الخطوات اللازمة لعرض الخريطة أفكار لبرامج مشابهة تساعدك الوحدة webbrowser إذا كان لديك عنوان URL لصفحة معينة تريد اختصار عملية فتح المتصفح والتوجه إليها، يمكنك أن تستفيد منها لإنشاء: برنامج يفتح جميع الروابط المذكورة في مستند نصي في ألسنة جديدة. برنامج يفتح المتصفح على صفحة الطقس لمدينتك. برنامج يفتح مواقع التواصل الاجتماعي التي تزورها عادة. تنزيل الملفات من الويب باستخدام الوحدة requests تسمح لك الوحدة requests بتنزيل الملفات من الويب دون أن تفكر في مشاكل الشبكة أو الاتصال أو ضغط البيانات. لا تأتي الوحدة requests مضمنةً في بايثون، وإنما عليك تثبيتها أولًا من سطر الأوامر بتشغيل الأمر pip install --user requests. أتت الوحدة requests لتقدم حلًا بديلًا لوحدة urllib2 في بايثون لأنها معقدة زيادة عن اللزوم، وأنصحك أن تزيل الوحدة urllib2 من ذهنك تمامًا، لأنها وحدة صعبة دون داعٍ، وعليك استخدام الوحدة requests دومًا. لنجرب الآن أن الحزمة requests مثبتة صحيحًا بإدخال ما يلي في الصدفة التفاعلية: import requests>>> import requests إذا لم تظهر أي رسالة خطأ فهذا يعني أن الحزمة requests مثبتة عندك. تنزيل صفحة ويب باستخدام الدالة requests.get() الدالة requests.get() تقبل سلسلةً نصيةً فيها رابط URL لتنزيلها. إذا استعملت الدالة type() على القيمة المعادة من الدالة requests.get() فسترى أن الناتج هو كائن Response، الذي يحتوي على الرد الذي تلقاه برنامجك بعد إتمام الطلبية إلى خادم الويب. سنستكشف سويةً الكائن Response بالتفصيل لاحقًا، لكن لنكتب الآن الأسطر الآتية في الطرفية التفاعلية على حاسوب متصل بالإنترنت: >>> import requests ➊ >>> res = requests.get('https://automatetheboringstuff.com/files/rj.txt') >>> type(res) <class 'requests.models.Response'> ➋ >>> res.status_code == requests.codes.ok True >>> len(res.text) 178981 >>> print(res.text[:250]) The Project Gutenberg EBook of Romeo and Juliet, by William Shakespeare This eBook is for the use of anyone anywhere at no cost and with almost no restrictions whatsoever. You may copy it, give it away or re-use it under the terms of the Proje الرابط الذي طلبناه هو مستند نصي لمسرحية روميو وجولييت على موقع الكتاب الأصلي ➊، يمكنك أن ترى نجاح الطلبية إلى صفحة الويب بالنظر إلى السمة status_code من الكائن Response، إذا كانت القيمة الخاصة بها تساوي requests.codes.ok فهذا يعني أن كل شيء على ما يرام ➋. بالمناسبة، رمز الاستجابة الذي يدل على أن الأمور على ما يرام OK في HTTP هو 200، ومن المرجح أنك تعرف الحالة 404 التي تشير إلى رابط غير موجود. يمكنك العثور على قائمة برموز الاستجابة في HTTP ومعانيها في الصفحة قائمة رموز الاستجابة في HTTP من ويكيبيديا. إذا نجحت الطلبية، فستخزن صفحة الويب التي نزلناها كسلسلة نصية في المتغير text في كائن Response. يحتوي هذا المتغير على سلسلة نصية طويلة فيها المسرحية كاملةً. وإذا استدعيت len(res.text) فسترى أنها أطول من 178,000 محرف. استدعينا في النهاية print(res.text[:250]) لعرض أول 250 محرف. إذا فشل الطلب وظهرت رسالة خطأ مثل "Failed to establish a new connection" أو "Max retries exceeded" فتأكد من اتصالك بالإنترنت. لا نستطيع نقاش جميع أسباب عدم القدرة على الاتصال بالخوادم لتعقيد الموضوع، لكن أنصحك بالبحث في الويب عن المشكلة التي تواجهك لترى حلها. التأكد من عدم وجود مشاكل كما رأينا سويةً، يملك الكائن Response السمة status_code التي تأكدنا أنها تساوي requests.codes.ok (وهو متغير فيه القيمة الرقمية 200) للتحقق من نجاح عملية التنزيل. هنالك طريقة أخرى سهلة للتحقق من نجاح التنفيذ هو استدعاء التابع raise_for_status() على الكائن Response، التي ستؤدي إلى إطلاق استثناء إذا حدث خطأ حين تنزيل الملف، ولن تفعل شيئًا إن سارت الأمور على ما يرام. جرب ما يلي في الصدفة التفاعلية: >>> res = requests.get('https://inventwithpython.com/page_that_does_not_exist') >>> res.raise_for_status() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "C:\Users\Al\AppData\Local\Programs\Python\Python37\lib\site-packages\requests\models .py", line 940, in raise_for_status raise HTTPError(http_error_msg, response=self) requests.exceptions.HTTPError: 404 Client Error: Not Found for url: https://inventwithpython .com/page_that_does_not_exist.html يضمن لنا التابع ()raise_for_status أن البرنامج سيتوقف إذا حدثت مشكلة في التنزيل، وهذا مناسب جدًا إذا أردنا إيقاف البرنامج حين حصول مشكلة في التنزيل. أما لو كنا نريد استمرار البرنامج حتى لو فشل تنزيل الملف فيمكننا حينئذٍ أن نحيط التابع raise_for_status() بالتعبيرات try و except لمعالجة هذا الاستثناء: import requests res = requests.get('https://inventwithpython.com/page_that_does_not_exist') try: res.raise_for_status() except Exception as exc: print('There was a problem: %s' % (exc)) التابع raise_for_status() في الشيفرة السابقة سيؤدي إلى طباعة ما يلي: There was a problem: 404 Client Error: Not Found for url: https:// inventwithpython.com/page_that_does_not_exist.html احرص دومًا على استدعاء التابع raise_for_status() بعد استدعاء requests.get() لتضمن أن برنامجك قد نزَّل الملف دون مشاكل قبل إكمال التنفيذ. حفظ الملفات المنزلة إلى نظام الملفات يمكنك الآن حفظ صفحة الويب إلى نظام الملفات لديك باستخدام الدالة open() والتابع write()، هنالك بعض الاختلافات البسيطة عمّا فعلناه سابقًا: علينا أن نفتح الملف في وضع الكتابة بالنظام الثنائي write binary بتمرير السلسلة النصية 'wb' كوسيط ثانٍ إلى الدالة open() حتى لو كان الملف المنزل نصيًا (مثل مسرحية روميو وجولييت في المثال أعلاه)، لأننا نريد كتابة البيانات الثنائية بدلًا من البيانات النصية للحفاظ على ترميز النص encoding. لنستعمل حلقة for مع التابع iter_content() للكائن Response لكتابة صفحة الويب إلى ملف: >>> import requests >>> res = requests.get('https://automatetheboringstuff.com/files/rj.txt') >>> res.raise_for_status() >>> playFile = open('RomeoAndJuliet.txt', 'wb') >>> for chunk in res.iter_content(100000): playFile.write(chunk) 100000 78981 >>> playFile.close() يعيد التابع iter_content() قطعًا من النص في كل تكرار لحلقة التكرار، وكل قطعة يكون لها نوع البيانات bytes وتحدد لها كم بايتًا يجب أن يكون طول كل قطعة، وأرى أن مئة ألف بايت هو حجم مناسب، لذا لنمرر 100000 إلى التابع iter_content(). أنشأنا الآن الملف RomeoAndJuliet.txt في مجلد العمل الحالي، لاحظ أن اسم الملف في موقع الويب هو rj.txt بينما اسم الملف المحفوظ لدينا مختلف. تذكر أن الوحدة requests تنزل محتويات صفحات الويب لديك، وبعد تنزيلها يكون على عاتقك التعامل معها وحفظها إن شئت أينما تشاء. للمراجعة، هذه هي الخطوات الكاملة لتنزيل وحفظ ملف: استدعاء التابع requests.get() لتنزيل ملف. استدعاء open() مع الخيار 'wb' لإنشاء ملف جديد وفتحه للكتابة في الوضع الثنائي. المرور على التابع iter_content() للكائن Response. استدعاء التابع write() في كل تكرار لكتابة المحتوى إلى الملف. إغلاق الملف close(). هذا كل ما يتعلق بالوحدة requests! قد تبدو لك حلقة for مع iter_content() معقدةً مقارنةً باستخدام open() و write() و close() التي استخدمناها لكتابة الملفات النصية؛ لكننا فعلنا ذلك لنضمن أن برنامجنا لن يستهلك ذاكرة كثيرة إذا نزلنا ملفات ضخمة. يمكنك قراءة المزيد حول ميزات الوحدة requests الأخرى من requests.readthedocs.org. لغة HTML قبل أن نستخلص المعلومات من صفحات الويب، لنتعلم بعض أساسيات HTML أولًا، ولنرى كيف نصل إلى أدوات المطور في متصفح الويب، التي ستجعل عملية استخراج البيانات من الويب أمرًا سهلًا جدًا. مصادر لتعلم HTML لغة HTML هي الصيغة التي تكتب فيها صفحات الويب، ويفترض هذا المقال أن لديك بعض الأساسيات حول HTML، لكن إن كنت تريد البدء من الصفر فأنصحك أن تراجع: توثيق HTML في موسوعة حسوب. قسم HTML في أكاديمية حسوب. تذكرة سريعة في حال لم تلمس HTML من مدة، سأخبرك بملخص بسيط عنها. ملفات HTML هي ملفات نصية لها اللاحقة html، وتكون النصوص فيها محادثة بالوسوم tags، وكل وسم يكون ضمن قوسي زاوية <>، وتخبر هذه الوسوم المتصفحات كيف يجب أن تعرض الصفحة. يمكن أن يكون هنالك نص بين وسم البداية ووسم النهاية، وهذا ما يؤلف عنصرًا element. فمثلًا، الشيفرة الآتية تعرض لك Hello, world! في المتصفح، وتكون كلمة Hello بخط عريض: <strong>Hello</strong>, world! وستبدو في المتصفح كما في الشكل الآتي: مثال Hello, world! معروضة في متصفح وسم البداية <strong> يخبر المتصفح أن النص سيكون بخط عريض، ووسم النهاية </strong> يخبر المتصفح أين هي نهاية النص العريض. هنالك وسوم متنوعة في HTML، ولبعض تلك الوسوم خاصيات تُذكَر ضمن قوسَي الزاوية <>، مثلًا الوسم <a> يعني أن النص هو رابط، وتكون قيمة هذا الرابط محددة بالخاصية href. مثال: Al's free <a href="https://inventwithpython.com">Python books</a>. ستبدو صفحة الويب كما في الشكل الآتي: رابط معروض في متصفح. تمتلك بعض العناصر الخاصية id التي تستخدم لتعريف عناصر الصفحة بشكل فريد، ويمكنك أن تطلب من برامجك البحث عن عنصر ما باستخدام معرفه id، لهذا تكون معرفة قيمة id لأحد العناصر من أهم الأمور التي سنستعمل فيها أدوات المطور أثناء كتابة برامج استخلاص البيانات من صفحات الويب. عرض مصدر صفحة HTML إذا أردت إلقاء نظرة على مصدر صفحة HTML لإحدى الصفحات التي تزورها، اضغط على الزر الأيمن للفأرة واختر View page source كما في الشكل التالي. هذا النص هو ما يحصل عليه متصفحك وهو يعرف كيف يعرض الصفحة اعتمادًا على ذاك النص. عرض مصدر صفحة ويب أنصح -وبشدة- أن تجرب عرض مصدر صفحات HTML لبعض مواقعك المفضلة، حتى لو لم تفهم تمامًا كل ما تراها أمامك، فلست بحاجة إلى احتراف HTML لتعرف كيف تكتب برامج لاستخراج البيانات؛ فليس المطلوب منك برمجة موقعك الشخصي وإنما أن يكون لديك ما يكفي لتحصل البيانات المطلوبة. فتح أدوات المطور إضافةً إلى عرض المصدر، يمكنك أن تلقي نظرة على صفحات HTML باستخدام أدوات المطور في متصفحك. يمكنك أن تضغط الزر F12 في كروم لإظهارها، أو الضغط على F12 مرة أخرى لإخفائها. يمكنك أيضًا فتحها من القائمة الجانبية ثم Developer Tools، أو الضغط على ⌘-⌥-I في ماك. أدوات المطور في متصفح كروم أما في فايرفكس، فيمكنك فتح أدوات المطور بالضغط على Ctrl+Shift+C في ويندوز ولينكس، أو ⌘-⌥-C في ماك، وأدوات المطور هنا تشبه كروم كثيرًا. بعد تفعيل أدوات المطور في متصفحك، يمكنك الضغط بالزر الأيمن للفأرة على أي عنصر واختيار Inspect Element في القائمة المنبثقة لترى شيفرة HTML المسؤولة عن ذاك الجزء من الصفحة. ستستفيد من ذلك كثيرًا عندما تبدأ تفسير صفحات HTML لاستخراج البيانات منها. استخدام أدوات المطور للعثور على عناصر HTML بعد أن نزل برنامج صفحة الويب باستخدام الوحدة requests فسيكون لدينا صفحة الويب كاملةً كسلسلة نصية واحدة، وعلينا أن نجد طريقة لمعرفة ما هي عناصر HTML التي تحتوي على المعلومات التي نريد استخراجها من الصفحة. ستساعدنا هنا أدوات المطور في ذلك. لنقل مثلًا أننا نريد كتابة برنامج لجلب بيانات الطقس من موقع weather.gov. لكن قبل أن نبدأ بكتابة الشيفرات فعلينا القيام ببعض التحريات أولًا. إذا زرنا الموقع وبحثنا عن الرمز البريدي 94105 فستحصل على صفحة تظهر لك الطقس في تلك المنطقة. ماذا إن كانت مهتمًا باستخراج بيانات الطقس لهذا العنوان البريدي؟ اضغط بالزر الأيمن على مكان معلومات الطقس في تلك الصفحة واختر Inspect Element من القائمة، وستظهر لك نافذة أدوات المطور، التي تريك شيفرات HTML المسؤولة عن ذاك الجزء من الصفحة كما يظهر في الشكل التالي. انتبه إلى أن الموقع قد يتغير دوريًا وقد تظهر لك عناصر مختلفة وعليك اتباع نفس الخطوات لتفحص العناصر الجديدة. تفحص عناصر صفحة الطقس باستخدام أدوات المطور يمكننا أن نرى ما هي شيفرة HTML المسؤولة عن عرض الطقس في الصفحة السابقة، وهي: <div class="col-sm-10 forecast-text">Sunny, with a high near 64. West wind 11 to 16 mph, with gusts as high as 21 mph.</div> هذا ما نبحث عنه تمامًا، يبدو أن معلومات الطقس موجودة داخل عنصر <div> له صنف CSS باسم forecast-text. اضغط بالزر الأيمن على العنصر في أدوات المطور واختر من القائمة Copy ▸ CSS Selector، وستُنسَخ لك سلسلة نصية مثل الآتية إلى الحافظة: 'div.row-odd:nth-child(1) > div:nth-child(2)' ويمكنك أن تستخدم تلك السلسلة النصية مع التابع ذ في BS4 أو find_element_by_css_selector() في Selenium كما هو مشروح في هذا المقال. الآن وبعد أن عرفت ما الذي تبحث عنه تحديدًا، يمكن لوحدة Beautiful Soup أن تساعدك في العثور عليه. تفسير HTML مع وحدة BS4 تستخدم الوحدة Beautiful Soup في استخراج المعلومات من صفحة HTML، واسم الوحدة في بايثون هو bs4 للإشارة إلى الإصدار الرابع منها، ويمكننا تثبيتها عبر الأمر pip install --user beautifulsoup4 (راجع الملحق أ لتعليمات حول تثبيت الوحدات). صحيح أننا استخدمنا beautifulsoup4 لتثبيت الوحدة، لكن حين استيرادها في بايثون سنستعمل import bs4. ستكون أمثلتنا عن BS4 عن تفسير ملف HTML (أي تحليلها والتعرف على أجزائها) مخزن محليًا على حاسوبنا. افتح لسانًا جديدًا في محرر Mu وأدخل ما يلي فيه واحفظه باسم example.html: <!-- This is the example.html example file. --> <html><head><title>The Website Title</title></head> <body> <p>Download my <strong>Python</strong> book from <a href="https:// inventwithpython.com">my website</a>.</p> <p class="slogan">Learn Python the easy way!</p> <p>By <span id="author">Al Sweigart</span></p> </body></html> نعم، حتى ملفات HTML البسيطة فيها مختلف العناصر والخاصيات، وستكون الأمور أعقد بكثير في المواقع الكبيرة، لكن مكتبة BS4 هنا لمساعدتنا وتسهيل الأمر علينا. إنشاء كائن BeautifulSoup من سلسلة HTML نصية يمكننا استدعاء الدالة bs4.BeautifulSoup() مع تمرير سلسلة نصية تحتوي على شيفرة HTML التي ستفسر. تعيد الدالة bs4.BeautifulSoup() كائن BeautifulSoup. جرب ما يلي في الصدفة التفاعلية على حاسوبك مع وجود إنترنت: >>> import requests, bs4 >>> res = requests.get('https://academy.hsoub.com') >>> res.raise_for_status() >>> academySoup = bs4.BeautifulSoup(res.text, 'html.parser') >>> type(academySoup) <class 'bs4.BeautifulSoup'> هذه الشيفرة تستعمل requests.get() لتنزيل صفحة الويب من موقع أكاديمية حسوب ثم تمرر قيمة السمة text للرد إلى الدالة bs4.BeautifulSoup() التي تعيد كائن BeautifulSoup نخزنه في المتغير academySoup. يمكننا أيضًا تحميل ملف HTML من القرص لدينا بتمرير كائن File إلى الدالة bs4.BeautifulSoup() مع وسيط ثانٍ يخبر وحدة BS4 ما المفسر الذي عليها استعماله لتفسير الملف. أدخل ما يلي في الصدفة التفاعلية مع التأكد أنك في نفس المجلد الذي يحتوي على ملف example.html: >>> exampleFile = open('example.html') >>> exampleSoup = bs4.BeautifulSoup(exampleFile, 'html.parser') >>> type(exampleSoup) <class 'bs4.BeautifulSoup'> المفسر 'html.parser' المستخدم هنا يأتي مع بايثون، لكن يمكنك استخدام المفسر 'lxml' الأسرع إذا ثبتت الوحدة الخارجية lxml. اتبع التعليمات الموجودة في الملحق أ لتثبيت الوحدة باستخدام الأمر pip install --user lxml. إذا لم نضمِّن الوسيط الثاني الذي يحدد المفسر فسيظهر التحذير: UserWarning: No parser was explicitly specified. بعد أن يكون لدينا كائن BeautifulSoup سنتمكن من استخدام توابعه لتحديد أجزاء معينة من مستند HTML. العثور على عنصر باستخدام التابع select() يمكنك الحصول على عنصر من عناصر صفحة الويب في الكائن BeatuifulSoup باستدعاء التابع select() وتمرير محدد CSS (أي CSS Selector) للعنصر الذي تبحث عنه. المحددات تشبه التعابير النمطية في وظيفتها: تحدد نمطًا يمكن البحث عنه في صفحات الويب. نقاش محددات CSS خارج سياق هذه السلسلة، لكن هذه مقدمة مختصرة عنها في الجدول التالي، وأنصحك بالاطلاع على توثيق المحددات في موسوعة حسوب. المحدد الذي يمرر إلى التابع ()select سيطابق soup.select('div') جميع عناصر <div> soup.select('#author') جميع العناصر التي لها الخاصية id وقيمتها author soup.select('.notice') جميع العناصر التي لها خاصية class ولها صنف CSS باسم notice soup.select('div span') جميع عناصر <span> الموجود داخل عناصر <div> soup.select('div > span') جميع العناصر <span> الموجودة مباشرةً داخل عناصر <div> بدون وجود أي عنصر بينهما soup.select('input[name]') جميع عناصر <input> التي لها الخاصية name بغض النظر عن قيمتها soup.select('input[type="button"]') جميع عناصر <input> التي لها الخاصية type وتكون مساوية إلى button أمثلة عن محددات CSS يمكن دمج مختلف أنماط المحددات مع بعضها لمطابقة أنماط أكثر تعقيدًا، فمثلًا soup.select('p #author') ستطابق أي عنصر له خاصية id قيمتها author لكن يجب أن يكون هذا العنصر موجودًا داخل عنصر <p>. بدلًا من محاولة كتابة المحددات بنفسك، يمكنك الضغط بالزر الأيمن على أي عنصر في صفحة الويب واختيار Inspect Element، وحينما تفتح أدوات المطور اضغط بالزر الأيمن على عنصر HTML واختر Copy ▸ CSS Selector لنسخ محدد CSS إلى الحافظة لتستطيع لصقه في الشيفرة لديك. التابع select() سيعيد قائمةً بعناصر Tag، وهذا ما تفعله وحدة BS4 لتمثيل عنصر HTML. هذه القائمة ستحتوي على كائن Tag لكل مطابقة للمحدد في كائن BeautifulSoup. يمكن تمرير كائن Tag إلى الدالة str() لعرض وسوم HTML التي تمثلها. تمتلك قيم Tag أيضًا السمة attrs التي تظهر جميع خاصيات HTML للعنصر ممثلةً كقاموس. لنجرب على ملف example.html بإدخال ما يلي في الصدفة التفاعلية: >>> import bs4 >>> exampleFile = open('example.html') >>> exampleSoup = bs4.BeautifulSoup(exampleFile.read(), 'html.parser') >>> elems = exampleSoup.select('#author') >>> type(elems) # elems هي قائمة من كائنات Tag <class 'list'> >>> len(elems) 1 >>> type(elems[0]) <class 'bs4.element.Tag'> >>> str(elems[0]) # تحويل الكائن إلى سلسلة نصية. '<span id="author">Al Sweigart</span>' >>> elems[0].getText() 'Al Sweigart' >>> elems[0].attrs {'id': 'author'} ستستخرج الشيفرة السابقة العنصر الذي له id="author" في مستند HTML. سنستخدم select('#author') للحصول على قائمة بجميع العناصر التي لها id="author"، وسنخزن قائمة كائنات Tag في المتغير elems، وسيخبرنا التعبير len(elems) أن لدينا كائن Tag وحيد في القائمة، أي جرت عملية المطابقة لعنصر HTML وحيد. استدعاء التابع getText() على العناصر سيعيد النص الموجود في العنصر، أي السلسلة النصية الموجودة بين وسم البدء والإغلاق. أما تمرير الكائن إلى الدالة str() سيعيد سلسلة نصيةً فيها وسمَي البداية والنهاية مع نص العنصر؛ أما السمة attrs فستعطينا قاموسًا فيه خاصيات العنصر كاملةً. يمكنك أيضًا استخراج جميع عناصر <p> من كائن BeautifulSoup كما في المثال الآتي: >>> pElems = exampleSoup.select('p') >>> str(pElems[0]) '<p>Download my <strong>Python</strong> book from <a href="https:// inventwithpython.com">my website</a>.</p>' >>> pElems[0].getText() 'Download my Python book from my website.' >>> str(pElems[1]) '<p class="slogan">Learn Python the easy way!</p>' >>> pElems[1].getText() 'Learn Python the easy way!' >>> str(pElems[2]) '<p>By <span id="author">Al Sweigart</span></p>' >>> pElems[2].getText() 'By Al Sweigart' ستعطينا select() ثلاث مطابقات، والتي ستخزن في المتغير pElems. سنجرب استخدام str() على الكائنات pElems[0] و pElems[1] و pElems[2] لعرض العناصر كسلاسل نصية، وسنجرب أيضًا التابع getText() لإظهار نص تلك العناصر فقط. الحصول على معلومات من خاصيات العنصر يسهل علينا التابع get() الخاص بكائنات Tag الوصول إلى خاصيات العناصر، ونمرر لهذا التابع سلسلةً نصيةً باسم الخاصية attribute وسيعيد لنا قيمتها. لنجرب المثال الآتي على الملف example.html: >>> import bs4 >>> soup = bs4.BeautifulSoup(open('example.html'), 'html.parser') >>> spanElem = soup.select('span')[0] >>> str(spanElem) '<span id="author">Al Sweigart</span>' >>> spanElem.get('id') 'author' >>> spanElem.get('some_nonexistent_addr') == None True >>> spanElem.attrs {'id': 'author'} يمكننا استخدام select() للعثور على أي عناصر <span> ثم تخزين أول عنصر مطابق في المتغير spanElem، الذي سنمرر للتابع get() القيمة 'id' للحصول على قيمة المعرف الخاصة به، وهي 'author' في مثالنا. مشروع: فتح جميع نتائج البحث في كل مرة أبحث فيها في جوجل، لا أريد أن أرى نتيجة بحث واحدة فقط ثم أنتقل إلى النتيجة التي بعدها، بل أضغط بسرعة على الزر الأوسط للفأرة على كل الروابط (أو الضغط عليها مع زر Ctrl) لفتحها في لسان جديد وأقرؤها معًا لاحقًا. فعلت هذا الأمر كثيرًا في جوجل لدرجة أنني مللت من البحث ثم الضغط على كل الروابط واحدًا واحدًا. ماذا لو كتبت برنامجًا أستطيع عبره كتابة عبارة البحث وسيفتح لي متصفحًا فيه كل نتائج البحث الأولى مفتوحةً كل واحد منها في لسان في المتصفح؟ لنكتب سكربتًا يفعل ذلك مع صفحة نتائج بحث فهرس حزم بايثون. يمكن تعديل هذا البرنامج ليعمل على الكثير من المواقع الأخرى، لكن انتبه إلى أن محركات البحث غوغل و DockDockGo عادةً ما تصعب عملية استخراج نتائج البحث من مواقعها. هذا ما يفعله البرنامج: الحصول على عبارة البحث من سطر الأوامر الحصول على صفحة نتائج البحث فتح لسان متصفح جديد لكل نتيجة هذا يعني أن على برنامجك أن يفعل ما يلي: قراءة وسائط سطر الأوامر من sys.argv. الحصول على صفحة نتائج البحث عبر الوحدة requests. العثور على جميع روابط نتائج البحث. استدعاء الدالة webbrowser.open() لفتحها في المتصفح. لنبدأ البرمجة بفتح ملف جديد باسم searchpypi.py في محررنا. الخطوة 1: الحصول على وسائط سطر الأوامر وطلب صفحة نتائج البحث قبل أن نبدأ بالبرمجة، علينا أن نعرف ما هو رابط URL لصفحة نتائج البحث. انظر إلى شريط العنوان في المتصفح بعد إتمامك لعملية البحث، وسترى أن الرابط يشبه https://pypi.org/search/?q=SEARCH_TERM_HERE. يمكننا استخدام الوحدة requests لتنزيل هذه الصفحة، ثم استخدام BS4 للبحث عن الروابط في مستند HTML. يمكننا في النهاية أن نستعمل وحدة webbrowser لفتح تلك الروابط في ألسنة جديدة. يحب أن تكون الشيفرة كما يلي: #! python3 # searchpypi.py - فتح عدة نتائج بحث. import requests, sys, webbrowser, bs4 print('Searching...') # عرض النص ريثما تحمل الصفحة res = requests.get('https://pypi.org/search/?q=' + ' '.join(sys.argv[1:])) res.raise_for_status() # TODO: Retrieve top search result links. # TODO: فتح لسان لكل نتيجة. سيحدد المستخدم كلمات البحث عبر تمريرها إلى سطر الأوامر أثناء تشغيل البرنامج، وستخزن في sys.argv كما رأينا في المقالات السابقة لهذه السلسلة. الخطوة 2: العثور على كل النتائج ستحتاج الآن إلى وحدة BS4 لاستخراج نتائج البحث من مستند HTML المنزل. لكن كيف يمكننا معرفة المحدد المناسب لحالتنا؟ ليس من المنطقي مثلًا البحث عن جميع عناصر <a> لوجود روابط كثيرة لا تهمنا؛ والحل هنا أن نفتح أدوات المطور في المتصفح وننظر إلى المحدد المناسب الذي سينتقي لنا الروابط التي نريدها فقط. بعد أن نبحث فسنجد بعض العناصر التي تشبه التالي: <a class="package-snippet" href="/project/pyautogui/"> ولا يهمنا إن كانت تلك العناصر معقدة، وإنما نحتاج إلى النمط الذي علينا استخدامه للبحث عن الروابط. لنعدل شيفرتنا إلى: #! python3 # searchpypi.py - Opens several google results. import requests, sys, webbrowser, bs4 --snip-- # Retrieve top search result links. soup = bs4.BeautifulSoup(res.text, 'html.parser') # فتح لسان لكل نتيجة. linkElems = soup.select('.package-snippet') إذا ألقيت نظرةً إلى عناصر <a> فستجد أن جميع نتائج البحث لها الخاصية class="package-snippet" وإذا بحثنا في كامل مصدر الصفحة فسنتأكد أن الصنف package-snippet ليس مستخدمًا إلا لروابط نتائج البحث. لا يهمنا ما هو الصنف package-snippet ولا ما يفعل، وإنما يهمنا كيف سنستفيد منه لتحديد عناصر <a> التي نبحث عنها. لننشِئ كائن BeautifulSoup من صفحة HTML التي نزلناها ونستخدم المحدد '.package-snippet' لتحديد جميع عناصر <a> التي لها صنف CSS المحدد؛ ضع في ذهنك أن موقع PyPI قد يحدث واجهته الرسومية وقد تحتاج إلى استخدام محدد CSS مختلف مستقبلًا، إن حدث ذلك فمرر المحدد الجديد إلى التابع soup.select() وسيعمل البرنامج على ما يرام. الخطوة 3: فتح نتائج البحث في المتصفح لنخبر برنامجنا الآن أن يفتح لنا النتائج الأولى في متصفح الويب. أضف ما يلي إلى برنامجك: #! python3 # searchpypi.py - فتح عدة نتائج بحث. import requests, sys, webbrowser, bs4 --snip-- # فتح لسان لكل نتيجة. linkElems = soup.select('.package-snippet') numOpen = min(5, len(linkElems)) for i in range(numOpen): urlToOpen = 'https://pypi.org' + linkElems[i].get('href') print('Opening', urlToOpen) webbrowser.open(urlToOpen) سيفتح البرنامج افتراضيًا أول خمسة روابط في المتصفح باستخدام الوحدة webbrowser، لكن قد يكون ناتج بحث المستخدم أقل من خمس نتائج، فحينها ننظر أيهما أقل، 5 أم عدد عناصر القائمة المعادة من استدعاء التابع soup.select(). الدالة المضمنة في بايثون min() تعيد العدد الأصغر من الوسائط الممررة إليها (والدالة max() تفعل العكس). يمكنك أن تستخدم الدالة min() لمعرفة إذا كان عدد الروابط أقل من 5 وتخزين الناتج في المتغير numOpen، والذي ستستفيد منه في حلقة for عبر range(numOpen). سنستخدم الدالة webbrowser.open() في كل تكرار لحلقة for لفتح الرابط في المتصفح. لاحظ أن قيمة الخاصية href في عناصر <a> لا تحتوي على https://pypi.org لذا علينا إضافتها بأنفسنا إلى قيمة الخاصية href قبل فتح الرابط. يمكنك الآن فتح أول 5 نتائج بحث عن «boring stuff» في محرك بحث PyPI بكتابة الأمر searchpypi boring stuff في سطر الأوامر. أفكار لبرامج مشابهة من الجميل أن يكون لدينا برنامج يفتح لنا عدة ألسنة في المتصفح لأي عملية روتينية مكررة، مثل: فتح جميع صفحات المنتجات في متجر أمازون بعد البحث عن منتج معين. فتح كل روابط المراجعات لمنتج ما. فتح الصور الناتجة بعد إجراء عملية بحث سريعة على أحد مواقع الصور مثل Flickr. مشروع: تنزيل كل رسمات XKCD عادةً ما تحدث المواقع والمدونات الصفحة الرئيسية لها بعرض آخر منشور فيها، مع وجود زر «السابق» الذي يأخذك إلى المنشور السابق، ثم تجد في المنشور السابق زرًا يأخذك للمنشور الذي قبله، وهلم جرًا، مما ينشِئ سلسلةً من الصفحات التي تأخذك من الصفحة الرئيسية إلى صفحة أول منشور في الموقع. إذا أردت نسخةً من محتوى موقعٍ ما لتقرأها وأنت غير متصل بالإنترنت، فيمكنك أن تفتح بنفسك كل صفحة وتحفظها، لكن هذا الأمر ممل جدًا ومن المناسب كتابة برنامج لأتمتة هذه المهمة. موقع XKCD هو موقع كوميكس له نفس البنية المذكورة. وصفحته الرئيسية فيها زر Prev للعودة إلى الكوكميس السابقة، لكن عملية تنزيل كل الكوميكس واحدةً واحدةً تأخذ وقتًا كثيرًا، لكننا نستطيع كتابة سكربت لأتمتة ذلك في ثوانٍ معدودة. هذا ما سيفعله برنامجنا: فتح صفحة XKCD الرئيسية حفظ صورة الكوميكس في تلك الصفحة الانتقال إلى صفحة الكوميكس السابق تكرار العملية حتى الوصول إلى أول صورة كوميكس. هذا يعني أن الشيفرة البرمجية ستفعل ما يلي: تنزيل الصفحات باستخدام الوحدة requests. العثور على رابط URL لصورة الكوميكس باستخدام وحدة BS4. تنزيل وحفظ صورة الكوميكس إلى نظام الملفات باستخدام iter_content(). العثور على رابط صورة الكوميكس السابقة، وتكرار العملية كلها. افتح ملفًا جديدًا في محررك وسمِّه باسم downloadXkcd.py. الخطوة 1: تصميم البرنامج إذا فتحت أدوات المطور في المتصفح ونظرت إلى عناصر الصفحة، فسترى ما يلي: رابط URL لملف صورة الكوميكس في الخاصية href في العنصر <img>. العنصر <img> موجود داخل العنصر <div id="comic">. الزر Perv له الخاصية rel وقيمتها prev. صفحة أول صورة كوميكس يشير فيها الزر Prev إلى الرابط https://xkcd.com/# مما يشير إلى عدم وجود صفحات سابقة. عدّل الشيفرة لتبدو كما يلي: #! python3 # downloadXkcd.py - تنزيل كل صورة كوميكس في XKCD. import requests, os, bs4 url = 'https://xkcd.com' # starting url os.makedirs('xkcd', exist_ok=True) # store comics in ./xkcd while not url.endswith('#'): # TODO: Download the page. # TODO: Find the URL of the comic image. # TODO: Download the image. # TODO: حفظ الصورة إلى ./xkcd. # TODO: الحصول على رابط الصفحة السابقة. print('Done.') سيكون لدينا متغير اسمه url يبدأ بالقيمة 'https://xkcd.com' وتحدث قيمته دوريًا ضمن حلقة for لتصبح الرابط الموجود في الزر Prev للصفحة الحالية. وسننزل صورة الكوميكس في كل تكرار من تكرارات حلقة for الموجودة في الرابط url، وسننتهي من حلقة التكرار حينما تنتهي قيمة url بالعلامة '#'. سننزل ملفات الصور إلى مجلد موجود في مجلد العمل الحالي باسم xkcd، وسنتأكد من أن المجلد موجود باستدعاء os.makedirs() مع تمرير وسيط الكلمات المفتاحية exist_ok=True الذي يمنع الدالة من رمي استثناء إن كان المجلد موجودًا مسبقًا. بقية الشيفرة هو تعليقات سنملؤها في الأقسام القادمة. الخطوة 2: تنزيل صفحة الويب لنكتب الشيفرة الآتية التي ستنزل الصفحة: #! python3 # downloadXkcd.py - تنزيل كل صورة كوميكس في XKCD. import requests, os, bs4 url = 'https://xkcd.com' # starting url os.makedirs('xkcd', exist_ok=True) # store comics in ./xkcd while not url.endswith('#'): # Download the page. print('Downloading page %s...' % url) res = requests.get(url) res.raise_for_status() soup = bs4.BeautifulSoup(res.text, 'html.parser') # TODO: Find the URL of the comic image. # TODO: Download the image. # TODO: حفظ الصورة إلى ./xkcd. # TODO: الحصول على رابط الصفحة السابقة. print('Done.') لنطبع بدايةً قيمة url ليعرف المستخدم ما هو رابط URL الذي يحاول البرنامج تنزيله، ثم سنستخدم الدالة requests.get() في الوحدة requests لتنزيل الصفحة. ثم سنستدعي التابع raise_for_status() كالعادة لرمي استثناء إن حدثت مشكلة ما في التنزيل؛ ثم إن سارت الأمور على ما يرام فسننشِئ كائن BeautifulSoup من نص الصفحة المنزلة. الخطوة 3: البحث عن صورة الكوميكس وتنزيلها لنعدل شيفرة برنامجنا: #! python3 # downloadXkcd.py - تنزيل كل صورة كوميكس في XKCD. import requests, os, bs4 --snip-- # Find the URL of the comic image. comicElem = soup.select('#comic img') if comicElem == []: print('Could not find comic image.') else: comicUrl = 'https:' + comicElem[0].get('src') # Download the image. print('Downloading image %s...' % (comicUrl)) res = requests.get(comicUrl) res.raise_for_status() # TODO: حفظ الصورة إلى ./xkcd. # TODO: الحصول على رابط الصفحة السابقة. print('Done.') بعد تفحص صفحة XKCD عبر أدوات المطور، سنعرف أن عنصر <img> لصورة الكوميكس موجود داخل عنصر <div> له الخاصية id التي قيمتها هي comic، وبالتالي سيكون المحدد '#comic img' صحيحًا لتحديد العنصر <img> عبر كائن BeautifulSoup. تمتلك بعض صفحات موقع XKCD على محتوى خاص لا يمثل صورة بسيطة، لكن لا بأس فيمكننا تخطي تلك الصفحات، فإن لم يطابِق المحدد الخاص بنا أي عنصر فسيعيد استدعاء soup.select('#comic img') قائمة فارغة، وحينها سيظهر برنامجنا رسالة خطأ ويتجاوز الصفحة دون تنزيل الصورة. عدا ذلك، فسيعيد المحدد السابق قائمةً فيها عنصر <img> وحيد، ويمكننا الحصول على قيمة الخاصية src لعنصر <img>ونمررها إلى requests.get() لتنزيل صورة الكوميكس. الخطوة 4: حفظ الصورة والعثور على الصفحة السابقة لنعدل الشيفرة لتصبح كما يلي: #! python3 # downloadXkcd.py - تنزيل كل صورة كوميكس في XKCD. import requests, os, bs4 --snip-- # حفظ الصورة إلى ./xkcd. imageFile = open(os.path.join('xkcd', os.path.basename(comicUrl)), 'wb') for chunk in res.iter_content(100000): imageFile.write(chunk) imageFile.close() # الحصول على رابط الصفحة السابقة. prevLink = soup.select('a[rel="prev"]')[0] url = 'https://xkcd.com' + prevLink.get('href') print('Done.') أصبح لدينا ملف صورة الكوميكس مخزنًا في المتغير res، وعلينا كتابة بيانات هذه الصورة إلى ملف في نظام الملفات المحلي لدينا. سنحدد اسم الملف المحلي للصورة ونمرره إلى الدالة open()، لاحظ أن المتغير comicUrl يحتوي على قيمة تشبه القيمة الآتية: 'https://imgs.xkcd.com/comics/heartbleed_explanation.png' ويبدو أنك لاحظت وجود مسار الملف فيها. يمكنك استخدام الدالة os.path.basename() مع comicUrl لإعادة آخر جزء من رابط URL السابق، أي 'heartbleed_explanation.png'، ويمكنك حينها استخدام هذا الاسم حين حفظ الصورة إلى نظام الملفات المحلي. يمكنك أن تضيف هذا الاسم إلى اسم مجلد xkcd باستخدام الدالة os.path.join() كما تعلمنا سابقًا لكي يستخدم برنامجك الفاصل الصحيح (الخط المائل الخلفي \ في ويندوز، والخط المائل / في لينكس وماك). أصبح لدينا الآن اسم ملف صحيح، ويمكننا استدعاء الدالة open() لفتح ملف جديد بوضع الكتابة الثنائية 'wb'. إذا كنت تذكر حينما حفظنا الملفات التي نزلناها عبر الوحدة requests في بداية المقال كنا نمر بحلقة تكرار على القيمة المعادة من التابع iter_content()، وستكتب الشيفرة الموجودة في حلقة for قطعًا من بيانات الصورة (كحد أقصى 100,000 بايت كل مرة) إلى الملف، ثم تغلق الملف. أصبحت الصورة محفوظة لديك محليًا الآن! علينا بعدئذٍ استخدام المحدد 'a[rel="prev"]' لتحديد العنصر <a> الذي له العلاقة rel مضبوطةً إلى prev. يمكنك استخدام قيمة الخاصية href لعنصر <a> المحدد للحصول على رابط صورة الكوميكس السابقة، والتي ستخزن في المتغير url، ثم ستدور حلقة while مرة أخرى وتعيد تنفيذ عملية التنزيل من جديد على الصفحة الجديدة. سيبدو ناتج تنفيذ البرنامج كما يلي: Downloading page https://xkcd.com... Downloading image https://imgs.xkcd.com/comics/phone_alarm.png... Downloading page https://xkcd.com/1358/... Downloading image https://imgs.xkcd.com/comics/nro.png... Downloading page https://xkcd.com/1357/... Downloading image https://imgs.xkcd.com/comics/free_speech.png... Downloading page https://xkcd.com/1356/... Downloading image https://imgs.xkcd.com/comics/orbital_mechanics.png... Downloading page https://xkcd.com/1355/... Downloading image https://imgs.xkcd.com/comics/airplane_message.png... Downloading page https://xkcd.com/1354/... Downloading image https://imgs.xkcd.com/comics/heartbleed_explanation.png... --snip– هذا المشروع هو مثال ممتاز لبرامج تتبع الروابط تلقائًا لاستخراج كمية معلومات كبيرة من الويب. يمكنك تعلم المزيد من المعلومات حول ميزات Beautiful Soup الأخرى من توثيقها الرسمي. أفكار لبرامج مشابهة تنزيل صفحات الويب وتتبع الروابط فيها هو أساس أي برنامج زحف crawler. يمكنك أن تبرمج برامج تفعل ما يلي: تنسخ موقعًا كاملًا احتياطيًا. تنسخ جميع التعليقات من أحد المنتديات. تعرض قائمة بجميع المنتجات التي عليها تخفيضات في أحد المتاجر. الوحدتان requests و bs4 رائعتين جدًا، لكن عليك أن تعرف ما هو رابط URL المناسب لتمريره إلى requests.get()، لكن في بعض الأحيان قد لا يكون ذلك سهلًا؛ أو ربما عليك تسجيل الدخول إلى أحد المواقع قبل بدء عملية الاستخراج، لهذا السبب سنستكشف سويةً الوحدة selenium لأداء مهام معقدة. التحكم في المتصفح عبر الوحدة selenium تسمح الوحدة selenium لبايثون بالتحكم برمجيًا بالمتصفح بضغط الروابط وتعبئة الاستمارات، مثلها كمثل أي تفاعل من مستخدم بشري. يمكننا أن نتفاعل مع صفحات الويب بطرائق أكثر تقدمًا في الوحدة selenium مقارنة مع requests و bs4، لكنها قد تكون أبطأ وأصعب بالتشغيل في الخلفية لأننا نفتح متصفح ويب كامل مقارنة بتنزيل بعض الصفحات من الويب. لكن إن كان علينا التعامل مع صفحات الويب بطريقة تعتمد على شيفرات JavaScript التي تحدث الصفحة، فعلينا استخدام selenium بدلًا من requests. أضف إلى ذلك أن المواقع الشهيرة مثل أمازون تستخدم برمجيات للتعرف على الزيارات الآتية من سكربتات التي تحاول استخراج البيانات من صفحاتها أو إنشاء عدّة حسابات مجانية، ومن المرجح أن تحجب هذه المواقع برامجك بعد فترة؛ وهنا تأتي الوحدة selenium التي تعمل مثل متصفحات الويب العادية. أحد أشهر العلامات التي تتعرف فيها المواقع أن الزيارات آتية من برنامج (أو سكربت script) هي عبارة user-agent، التي تُعرِّف متصفح الويب المستخدم وتضمَّن في كل طلبيات HTTP. فمثلًا تكون عبارة user-agent للوحدة requests شيء يشبه 'python-requests/2.21.0'. يمكنك زيارة موقع مثل whatsmyua.info لتعرف ما هي user-agent الخاصة بك. أما الوحدة selenium فمن المرجح أن تظن المواقع أنها مستخدم بشري، لأنها تستخدم user-agent شبيه بالمتصفحات العادية مثل: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:124.0) Gecko/20100101 Firefox/124.0 ولأن نمط التصفح فيها يشبه المتصفحات الأخرى، فستُنزَّل الصور والإعلانات وملفات تعريف الارتباط والمتتبعات كما في المتصفحات العادية. لكن يمكن للمواقع كشف selenium وتحاول شركات شراء بطاقات الدخول والمتاجر الإلكترونية حجب أي سكربتات تستعمل متصفح selenium. تشغيل متصفح تتحكم فيه selenium سنرى في الأمثلة القادمة كيفية التحكم في متصفح فيرفكس من selenium، إذا لم يكن مثبتًا لديك فيمكنك تنزيله من getfirefox.com، ويمكنك تثبيت selenium،من سطر الأوامر بتشغيل pip install --user selenium، وأذكرك بالذهاب إلى الملحق أ لمزيد من المعلومات. قد يكون استيراد مكونات selenium مختلفًا عليك، فبدلًا من import selenium سنستعمل from selenium import webdriver (سبب فعل selenium لذلك خارج نطاق هذه السلسلة لا تقلق حوله). يمكنك بعد ذلك تشغيل فايرفوكس مع selenium بكتابة ما يلي في الصدفة التفاعلية: >>> from selenium import webdriver >>> browser = webdriver.Firefox() >>> type(browser) <class 'selenium.webdriver.firefox.webdriver.WebDriver'> >>> browser.get('https://inventwithpython.com') ستلاحظ أن متصفح فايرفوكس قد بدأ بالعمل حين استدعاء webdriver.Firefox(). استدعاء type() على webdriver.Firefox() سيظهر أنها من نوع البيانات WebDrive، واستدعاء التالي: browser.get('https://inventwithpython.com') سيوجه المتصفح إلى https://inventwithpython.com/. بعد استدعاء webdriver.Firefox() و get() ستفتح الصفحة في متصفح فايرفوكس إذا واجهت مشكلة من قبيل 'geckodriver' executable needs to be in PATH فهذا يعني أن عليك تنزيل محرك فايرفوكس يدويًا قبل استخدام selenium للتحكم به. يمكنك التحكم بمتصفحات أخرى غير فيرفكس إذا ثبتت محرك الويب لهم webdriver. لمتصفح فايرفوكس، اذهب إلى github.com وثبت محرك geckodriver لنظام تشغيلك. (كلمة «Gecko» هي اسم محرك المتصفح engine في فيرفكس). سيحتوي الملف المضغوط المنزل على geckodriver.exe في ويندوز أو geckodriver في ماك ولينكس، وعليك وضعه في مسار PATH الخاص في نظامك، راجع الإجابة الآتية stackoverflow.com. أما لمتصفح كروم فاذهب إلى chromium.org ونزل الملف المضغوط المناسب لنظامك، وضع الملف chromedriver.exe أو chromedriver في مسار PATH كما ذكرنا أعلاه. يمكن فعل نفس الأمر لبقية المتصفحات الرئيسية، ابحث سريعًا في الويب عن اسم المتصفح متبوعًا بالكلمة webdriver وستجدها. قد تواجه مشاكل في تشغيل المتصفحات الجديدة في selenium، بسبب عدم التوافقية بينهما، لكن يمكنك إجراء حل التفافي بتثبيت نسخة قديمة من المتصفح أو من وحدة selenium. يمكنك معرفة تاريخ الإصدارات من pypi.org. للأسف قد تحدث مشاكل توافقية بين selenium وبعض إصدارات المتصفحات، وأنصحك حينها بالبحث في الويب عن الحلول المقترحة، وراجع الملحق أ لمعلومات حول تثبيت إصدار محدد من selenium (مثل تثبيت pip install --user -U selenium==3.14.1). العثور على عناصر في الصفحة توفر كائنات WebDriver عددًا من التوابع للعثور على عناصر صفحة، ويمكن تقسيمها إلى قسمين من التوابع find_element_ و find_elements_*. توابع find_element_* تعيد كائن WebElement وحيد يمثل أول عنصر في الصفحة يطابق الطلبية التي حددتها، بينما تعيد توابع _find_elements قائمة من كائنات WebElement_* لكل عنصر مطابق في الصفحة. يظهر الجدول الموالي أمثلة على التوابع find_element_ و find_elements_ المستدعاة على كائن WebDriver مخزن في المتغير browser. اسم التابع كائن/قائمة كائنات WebElement browser.find_element_by_class_name(name) browser.find_elements_by_class_name(name) العناصر التي تستخدم صنف CSS باسم name browser.find_element_by_css_selector(selector) browser.find_elements_by_css_selector(selector) العناصر التي تطابق محدد CSS معين browser.find_element_by_id(id) browser.find_elements_by_id(id) العناصر التي تطابق id معين browser.find_element_by_link_text(text) browser.find_elements_by_link_text(text) عناصر <a> التي يطابق محتواها القيمة text كاملةً browser.find_element_by_partial_link_text(text) browser.find_elements_by_partial_link_text(text) عناصر <a> التي يطابق محتواها القيمة text جزئيًا browser.find_element_by_name(name) browser.find_elements_by_name(name) العناصر التي لها الخاصية name وتطابق قيمة معينة browser.find_element_by_tag_name(name) browser.find_elements_by_tag_name(name) العناصر التي تطابق وسمًا معينًا، وهي غير حساسة لحالة الأحرف (أي <a> يمكن أن يطابق عبر 'a' أو 'A') توابع WebDriver للعثور على العناصر في selenium باستثناء التوابع *_by_tag_name() تكون جميع الوسائط الممررة إلى الدوال حساسةً لحالة الأحرف، وإذا لم تكن العناصر موجودة في الصفحة فستطلق selenium الاستثناء NoSuchElement، وعليك استخدام عبارات try و except إذا لم ترغب بتوقف برنامج عن العمل عند ذلك. بعد أن تحصل على كائن WebElement فيمكنك أن تتعرف على المزيد حوله بقراءة سماته أو استدعاء توابع المذكورة في الجدول التالي: السمة أو التابع الوصف tag_name اسم الوسم، مثل 'a' لعنصر <a> get_attribute(name) قيمة خاصية name للعنصر text النص الموجود داخل العنصر، مثل 'hello' في <span>hello</span> clear() مسح النص المكتوب في الحقول النصية is_displayed() إعادة True إذا كان العنصر ظاهرًا، وإلا فيعيد False is_enabled() إعادة True إذا كان حقل الإدخال مفعلًا، وإلا فيعيد False is_selected() لأزرار الانتقاء radio ومربعات التأشير checkbox ستعيد True إذا كان العنصر مختار، وإلا فتعيد False location قاموس فيه المفاتيح 'x' و 'y' لمكان العنصر في الصفحة سمات وتوابع الكائن WebElement مثلًا، افتح ملفًا جديدًا واكتب البرنامج الآتي: from selenium import webdriver browser = webdriver.Firefox() browser.get('https://inventwithpython.com') try: elem = browser.find_element_by_class_name(' cover-thumb') print('Found <%s> element with that class name!' % (elem.tag_name)) except: print('Was not able to find an element with that name.') فتحنا هنا متصفح فيرفكس ووجهناه إلى رابط URL معين، وحاولنا العثور على العناصر التي لها الصنف bookcover، وإذا عثرنا على أحد العناصر فسنطبع اسم الوسم عبر السمة tag_name؛ أما لو لم يعثر على أي عنصر فسنطبع رسالة مختلفة. سيعيد البرنامج الناتج الآتي: Found <img> element with that class name! أي عثرنا على عنصر <img> له اسم الصنف 'bookcover'. الضغط على عناصر الصفحة تمتلك كائنات WebElement المعادة من التوابع find_element_* و find_elements_* التابع click() الذي يحاكي ضغطات الفأرة على العنصر، ويمكن استخدام هذا التابع للضغط على رابط أو تحديد زر انتقاء أو الضغط على زر الإرسال أو أي حدث آخر يُطلَق عند الضغط على أحد العناصر. جرب المثال الآتي في الطرفية التفاعلية: >>> from selenium import webdriver >>> browser = webdriver.Firefox() >>> browser.get('https://inventwithpython.com') >>> linkElem = browser.find_element_by_link_text('Read Online for Free') >>> type(linkElem) <class 'selenium.webdriver.remote.webelement.FirefoxWebElement'> >>> linkElem.click() # follows the "Read Online for Free" link سيفتح متصفح فيرفكس الصفحة ويحصل على العنصر <a> الذي يحتوي على النص Read it Online ويحاكي الضغط على الرابط كما لو ضغطته بنفسك. تعبئة وإرسال الاستمارات يمكن تعبئة الحقول النصية مثل <input> أو <textarea> بالبحث عنها ثم استدعاء التابع send_keys(). جرب ما يلي في الطرفية التفاعلية: >>> from selenium import webdriver >>> browser = webdriver.Firefox() >>> browser.get('https://login.metafilter.com') >>> userElem = browser.find_element_by_id('user_name) >>> userElem.send_keys('your_real_username_here') >>> passwordElem = browser.find_element_by_id('user_pass') >>> passwordElem.send_keys('your_real_password_here') >>> passwordElem.submit() لطالما لم تغيّر صفحة MetaFilter المعرف id لحقول اسم المستخدم وكلمة المرور بعد نشر هذا الكتاب، فيمكنك استخدام الشيفرة السابقة لملء تلك الحقول النصية (تذكر أنك تستطيع استخدام أدوات المطور للتأكد من المعرف id للحقول في أي وقت). استدعاء التابع submit() على أي عنصر في الاستمارة له نفس تأثير الضغط على زر الإرسال. تحذير: ابتعد عن تخزين كلمات المرور الخاصة بك في الشيفرة المصدرية لبرامجك قدر الإمكان، فمن السهل تسريب كلمات المرور إذا تركناها دون تشفير. يمكن لبرنامجك أن يطلب كلمة المرور من المستخدم أثناء التشغيل كما ناقشنا في مقال سابق. إرسال المفاتيح الخاصة تمتلك selenuim وحدةً للمفاتيح الخاصة التي لا يمكن كتابتها كسلسلة نصية، مثل زر Tab أو الأسهم. تلك القيم مخزنة كسمات في الوحدة selenium.webdriver.common.keys، ولأن اسم الوحدة طويل جدًا فمن الأسهل كتابة from selenium.webdriver.common.keys import Keys في بداية البرنامج، وحينها تستطيع استخدام Keys في أي مكان تريد أن تكتب فيه selenium.webdriver.common.keys. يعرض الجدول 12-5 أشهر القيم المستخدمة. الجدول 12-5: أشهر القيم المستخدمة في الوحدة selenium.webdriver.common.keys. السمة الشرح Keys.DOWN و Keys.UP و Keys.LEFT و Keys.RIGHT الأسهم في لوحة المفاتيح Keys.ENTER و Keys.RETURN زر Enter Keys.HOME و Keys.END و Keys.PAGE_DOWN و Keys.PAGE_UP أزرار Home و End و PageDown و PageUp على التوالي Keys.ESCAPE و Keys.BACK_SPACE و Keys.DELETE أزرار Escape و Backspace و Delete على التوالي Keys.F1 و Keys.F2 و . . . و Keys.F12 الأزرار F1 حتى F12 في الصف العلوي من لوحة المفاتيح Keys.TAB زر Tab فمثلًا لو لم يكن المؤشر موجودًا داخل حقل نصي، فالضغط على زر Home و End سيؤدي إلى التمرير إلى بداية ونهاية الصفحة على التوالي. جرب ما يلي على الصدفة التفاعلية ولاحظ كيف يؤدي استدعاء send_keys() إلى تمرير الصفحة: >>> from selenium import webdriver >>> from selenium.webdriver.common.keys import Keys >>> browser = webdriver.Firefox() >>> browser.get('https://nostarch.com') >>> htmlElem = browser.find_element_by_tag_name('html') >>> htmlElem.send_keys(Keys.END) # scrolls to bottom >>> htmlElem.send_keys(Keys.HOME) # scrolls to top العنصر <html> موجود في كل ملفات HTML، ويكون كامل محتوى مستند HTML داخله؛ وتحديد هذا العنصر مفيد لو أردنا إرسال المفاتيح إلى صفحة الويب عمومًا، وهذا بدوره مفيد إذا كانت الصفحة تحمِّل محتوى جديد عند التمرير إلى أسفل الصفحة. الضغط على أزرار المتصفح يمكن أن تحاكي الوحدة selenium الضغط على أزرار المتصفح المختلفة: التابع browser.back() يضغط على زر الرجوع التابع browser.forward() يضغط على زر إلى الأمام التابع browser.refresh() يضغط على زر التحديث التابع browser.quit() يضغط على زر إغلاق النافذة المزيد من المعلومات حول Selenium يمكن للوحدة selenium فعل الكثير مما لم نذكره هنا، فيمكنك أن تعدل محتوى ملفات تعريف الارتباط، وتأخذ لقطة شاشة، وتشغل سكربت JavaScript مخصص …إلخ. لمزيد من المعلومات حول تلك الخصائص فأنصحك أن تزور التوثيق الرسمي. الخلاصة المهام المملة ليست متعلقة بالملفات المحلية على حاسوبك. إذا كنت قادرًا على تنزيل صفحات الويب برمجيًا فستستطيع أتمتة أي مهمة تردك! تسهل الوحدة requests تنزيل صفحات الويب، وبعد تعلم أساسيات HTML فيمكنك أن تستخدم الوحدة BeautifulSoup لتفسير الصفحات التي تنزلها. لكن إن كانت تريد أتمتة أي مهمة متعلقة بالويب أيًا كانت، فيمكنك التحكم برمجيًا مباشرةً بمتصفح الويب عبر الوحدة selenium، التي تسمح لك بفتح المواقع وملء الاستمارات كما لو كان برنامجك كائنًا بشريًا يتصفح المواقع. مشاريع تدريبية لكي تتدرب، اكتب برامج لتنفيذ المهام الآتية. إرسال البريد الإلكتروني من سطر الأوامر اكتب برنامج يقبل عنوان بريد إلكتروني وسلسلة نصية في سطر الأوامر، ثم يستخدم selenium للدخول إلى حسابك البريدي وإرسال بريد إلكتروني إلى العنوان المحدد (أنصحك بإنشاء حساب تجريبي مختلف عن حسابك الأساسي). اكتب برامج أخرى لإضافة منشورات إلى فيسبوك أو تويتر (إكس، سمه ما شئت!). منزِّل الصور اكتب برنامج يفتح أحد مواقع مشاركة الصور مثل Flickr ويبحث عن تصنيف معين من الصور وينزل جميع نتائج البحث في الصفحة الأولى. يمكنك أن تكتب برنامج يعمل على أي موقع مشاركة صور ولديه خاصية البحث. لعبة 2048 لعبة 2048 هي لعبة بسيطة تسمح لك بجمع مربعات بجعلها تنزلق إلى أحد الاتجاهات باستخدام أزرار الأسهم. يمكنك أن تحصل على نتيجة عالية إذا جعلت الانزلاق بهذا الترتيب مرارًا وتكرارًا: الأعلى ثم اليمين ثم الأسفل ثم اليسار. اكتب برنامج بسيط يفتح اللعبة gabrielecirulli.github.io وينفذ النمط السابق للعب اللعبة تلقائيًا. التحقق من الروابط اكتب برنامج يأخذ رابط URL من صفحة ويب، ويحاول أن ينزل كل صفحة مرتبطة فيها، ويُعلِّم كل الصفحات التي تعيد 404 وتؤشر عليها أنها روابط مكسورة. ترجمة -بتصرف- للمقال Web Scraping من كتاب Automate the Boring Stuff with Python. اقرأ أيضًا المقال السابق: تنقيح أخطاء Debugging شيفرتك البرمجية باستخدام لغة بايثون برمجة عملاء ويب باستخدام بايثون أهم 10 مكتبات بايثون تستخدم في المشاريع الصغيرة مشاريع بايثون عملية تناسب المبتدئين النسخة العربية الكاملة لكتاب البرمجة بلغة بايثون1 نقطة
-
قبل شرح كيفية تهيئة بايثون، نود إعلامك أن هذا سيكون أول مقال من سلسلة مقالات أتمتة المهام عبر بايثون. ستشرح هذه السلسلة أساسيات البرمجة بلغة بايثون، والمهام المختلفة التي يمكن لحاسوبك أتمتتها، كما سنشاركك مشاريع عملية مع نهاية كل جزئية منه، والتي تستطيع استعمالها ودراستها ومشاركتنا تطبيقاتك لها في التعليقات. ما هي بايثون؟ بايثون هي لغة برمجة، ولغة البرمجة هي مجموعة قواعد لكتابة الشيفرة يجب الالتزام بها ليفهمها مترجم اللغة، ومترجم بايثون Python interpreter هو برمجية تقرأ الشيفرات المصدرية بلغة بايثون وتطبق التعليمات البرمجية فيها. يمكنك أن تنزل مفسر لغة بايثون مجانًا من موقع اللغة الرسمي، الذي فيه إصدارات لأنظمة تشغيل ويندوز وماك ولينكس. إذا كنتَ تتساءل من أين أتى اسم بايثون، فهو من مجموعة كوميدية بريطانية اسمها Monty Python، ولا علاقة للثعابين والأفاعي باسمها. تنزيل وتثبيت بايثون يمكنك تنزيل بايثون لنظام تشغيل ويندوز أو ماك أو لينكس مجانًا من رابط موقع اللغة، وستعمل معك جميع التطبيقات المشروحة في هذه السلسلة معك. ستجد في موقع بايثون نسختين إحداهما 64-بت والأخرى 32-بت لكل نظام تشغيل، لذا عليك اختيار الملف الصحيح لتنزله وتثبته. إذا اشتريت حاسوبك بعد عام 2007 فمن المرجح أنك تستعمل نظام 64-بت، وإلا فعليك استخدام نسخة 32-بت. إذا كنت تستعمل نظام ويندوز فنزِّل مثبت بايثون (الذي ينتهي باللاحقة .exe) وشغِّله، ثم اتبع ما يرشدك إليه المثبِّت على الشاشة. أما على نظام macOS فنزِّل ملف .pkg ثم شغله واتبع الإرشادات الموجودة على الشاشة. أما إذا كنت تستعمل توزيعة أوبنتو (أو ما يشبهها من التوزيعات المبنية على دبيان) فيمكنك تثبيت بايثون من سطر الأوامر بتنفيذ الأمر الآتي: sudo apt install python3 python3-pip idle3 تنزيل وتثبيت محرر Mu صحيحٌ أن مفسِّر بايثون هو البرنامج الذي يشغل شيفرات بايثون التي تكتبها، لكن برمجية Mu editor هي مكان إدخالك للشيفرات، بنفس الطريقة التي تكتب فيها بمعالج النصوص المفضل لديك. يمكنك تنزيل محرر Mu من موقعه. نزِّل المثبِّت الخاص بنظامك إن كنت تستعمل ويندوز أو ماك، ثم ابدأ عملية التثبيت بفتح المثبت، أما على لينكس فستحتاج إلى تثبيت محرر Mu كحزمة بايثون، وفي تلك الحالة اتبع الإرشادات الموجودة في الموقع. تشغيل محرر Mu بعد انتهاء تثبيت Mu، يمكنك تشغيله: في نظام ويندوز بالضغط على قائمة ابدأ ثم البحث عن Mu. في نظام MacOS بفتح Finder ثم Applications ثم الضغط على أيقونة mu-editor. في لينكس عليك تشغيل الطرفية Terminal ثم كتابة mu-editor. وحين تشغيلك لمحرر Mu لأول مرة فستظهر لك نافذة تخيّرك بين عدة خيارات وعليك اختيار Python 3، يمكنك في أي وقت تغيير النمط بالضغط على زر Mode في أعلى نافذة المحرر. تشغيل IDLE نستعمل في هذه السلسلة Mu كمحرر وصدفة تفاعلية interactive shell، لكنك تستطيع استخدام أي محرر تشاء لكتابة شيفرات بايثون، وتثبت بيئة التطوير والتعليم المدمجة Integrated Development and Learning Environment (اختصارًا IDLE) مع بايثون تلقائيًا، ويمكنها أن تعمل كمحرر ثانوي لك إن لم يعمل يثبت عندك محرر Mu. لنشغل IDLE: في نظام ويندوز بالضغط على قائمة ابدأ ثم البحث عن IDLE. في نظام macOS بفتح Finder ثم Applications ثم الضغط على أيقونة Python. في لينكس عليك تشغيل الطرفية Terminal ثم كتابة idle3. الصَدَفة التفاعلية Interactive Shell عندما تشغل Mu فستظهر أمامك نافذة تحرير الملف، ويمكنك فتح الصَدَفة التفاعلية بالضغط على زر REPL. الصَدَفة Shell هي برنامج يسمح لك بإعطاء تعليمات للحاسوب، كما تفعل حينما تفتح الطرفية Terminal في لينكس أو ماك، أو موجه الأوامر في ويندوز. تسمح لك الصدفة التفاعلية في بايثون بإدخال التعليمات لينفذها مفسِّر بايثون مباشرةً. تجد الصدفة التفاعلية في محرر Mu في إطار في الجزء السفلي من النافذة فيها النص الآتي: Jupyter QtConsole 4.7.7 Python 3.6.9 (default, Mar 15 2022, 13:55:28) Type 'copyright', 'credits' or 'license' for more information IPython 7.16.3 -- An enhanced Interactive Python. Type '?' for help. In [1]: إذا كنت تستعمل IDLE، فالصدفة التفاعلية هي أول ما ستراه أمامك، ويفترض أن تكون فارغة باستثناء نص يبدو كما يلي: Python 3.6.9 (default, Mar 15 2022, 13:55:28) [GCC 8.4.0] on linux Type "help", "copyright", "credits" or "license()" for more information. >>> الأسطر التي تبدأ بالعبارة In [1]: أو <<< تسمى محثًا prompt (أي أنها عبارة «تحثّ» المستخدم على كتابة أمر وراءها). أمثلة هذه السلسلة ستستخدم <<< للإشارة إلى محث الصدفة التفاعلية لأنه أكثر شيوعًا. إذا شغلت مفسر بايثون من سطر الأوامر فستجد أمامك المحث <<< أيضًا. يستخدم محرر Jupyter Notebook الشهير المحث In [1]: وشاع بسببه. لنجرب مثالًا بسيطًا، أدخل السطر الآتي في الصدفة التفاعلية بعد المحث: >>> print('Hello, world!') بعد كتابة السطر السابق فاضغط على زر Enter، ويجب أن يظهر ما يلي في الصدفة: >>> print('Hello, world!') Hello, world! لقد أعطيت الحاسوب أمرًا ونفذه لك. مبارك! تثبيت الوحدات الخارجية في بايثون كتب العديد من المطورين وحداتهم الخاصة، مما أدى إلى توسيع قدرات لغة بايثون Python إلى ما هو أبعد مما توفره المكتبة المعيارية للوحدات المُدمَجة مع بايثون، والطريقة الأساسية لتثبيت هذه الوحدات الخارجية هي استخدام الأداة Pip في بايثون، حيث تنزِّل هذه الأداة وحدات بايثون وتثبّتها بطريقة آمنة على حاسوبك من موقع الويب الخاص بمؤسسة برمجيات بايثون، ويُعَد PyPI أو Python Package Index متجر التطبيقات المجاني لوحدات بايثون. ملاحظة: يمكنك تثبيت جميع الوحدات المطلوبة مع الإصدارات المستخدمة في هذه السلسلة من المقالات من خلال تثبيت الوحدة automateboringstuff باستخدام الأداة Pip، لذا شغّل الأمر الآتي من موجّه الأوامر أو نافذة الطرفية Terminal. pip install --user automateboringstuff الأداة Pip تُثبَّت الأداة Pip تلقائيًا مع الإصدار 3.4 من بايثون والإصدارات الأحدث على نظامي تشغيل ويندوز Windows وماك macOS، ولكن يجب أن تثبّتها تثبيتًا منفصلًا على نظام لينكس Linux. يمكنك معرفة ما إذا كانت الأداة Pip مُثبَّتة مسبقًا على نظام لينكس من خلال تشغيل الأمر which pip3 في نافذة الطرفية Terminal، حيث إذا كانت مثبَّتة، فسترى موقع الأداة pip3 معروضًا، وإلّا فلن يُعرض أيّ شيء. يمكنك تثبيت الأداة pip3 على نظام أوبنتو Ubuntu أو نظام دبيان Debian Linux من خلال فتح نافذة طرفية جديدة وإدخال الأمر sudo apt install python3-pip، ويمكنك تثبيت الأداة pip3 على نظام فيدورا لينكس Fedora Linux من خلال إدخال الأمر sudo dnf install python3-pip في نافذة الطرفية، ويجب أن تدخِل كلمة مرور المدير الخاصة بحاسوبك. تُشغَّل الأداة pip من نافذة الطرفية (وتُسمَّى أيضًا سطر الأوامر)، وليس من صدفة بايثون التفاعلية Interactive Shell. شغّل برنامج "موجّه الأوامر Command Prompt" من قائمة "ابدأ Start" في نظام تشغيل ويندوز، وشغّل الطرفية من أيقونة سبوت لايت Spotlight على نظام ماك macOS، وشغّل الطرفية من أيقونة Ubuntu Dash أو اضغط على الاختصار Ctrl-Alt-T في نظام أوبنتو لينكس Ubuntu Linux. إن لم يكن مجلد pip موجودًا في متغير البيئة PATH، فيجب تغيير المجلد في نافذة الطرفية باستخدام الأمر cd قبل تشغيل الأداة pip. إذا أردتَ معرفة اسم المستخدم الخاص بك، فشغّل الأمر echo %USERNAME% على نظام ويندوز أو الأمر whoami على نظامي ماك macOS ولينكس، ثم شغّل الأمر cd pip folder، حيث يكون مجلد pip على نظام ويندوز في الآتي: C:\Users\<USERNAME>\AppData\Local\Programs\Python\Python39\Scripts ويوجد هذا المجلد في نظام ماك macOS على: /Library/Frameworks/Python.framework/Versions/3.9/bin/ كما يوجد هذا المجلد في نظام لينكس على: /home/<USERNAME>/.local/bin/ ، وبذلك ستكون في المجلد الصحيح لتشغيل الأداة pip. تثبيت الوحدات الخارجية يُسمَّى الملف القابل للتنفيذ للأداة pip بالاسم pip على نظام ويندوز ويسمّى pip3 على نظامي ماك macOS ولينكس. مرّر الأمر install متبوعًا باسم الوحدة التي تريد تثبيتها من سطر الأوامر، فمثلًا يمكنك إدخال الأمر pip install --user MODULE في نظام ويندوز، حيث MODULE هو اسم الوحدة. قد تكون التغييرات المستقبلية على هذه الوحدات الخارجية غير متوافقة مع الإصدارات السابقة، لذا نوصي بتثبيت الإصدارات المحدَّدة المستخدمة في هذه السلسلة من المقالات كما سنوضّح لاحقًا، حيث يمكنك إضافة الخيار -U MODULE==VERSION إلى نهاية اسم الوحدة لتثبيت إصدار محدّد، ولاحظ وجود إشارتي مساواة في خيار سطر الأوامر، فمثلًا يثبّت الأمر الآتي الإصدار 1.5.0 من الوحدة send2trash: pip install --user -U send2trash==1.5.0 يمكنك تثبيت جميع الوحدات التي تغطيها هذه السلسلة من المقالات من خلال تنزيل ملفات المتطلبات "requirements" لنظام تشغيلك من موقع nostarch وتشغيل أحد الأوامر التالية: على نظام ويندوز: pip install --user –r automate-win-requirements.txt ––user على نظام ماك macOS: pip3 install --user –r automate-mac-requirements.txt --user على نظام لينكس: pip3 install --user –r automate-linux-requirements.txt --user تحتوي القائمة التالية على الوحدات الخارجية المستخدمة في هذه السلسلة من المقالات مع إصداراتها المختلفة، حيث يمكنك إدخال هذه الأوامر إدخالًا منفصلًا إذا أردتَ تثبيت عددٍ محدّد من هذه الوحدات على حاسوبك: pip install --user send2trash==1.5.0 pip install --user requests==2.21.0 pip install --user beautifulsoup4==4.7.1 pip install --user selenium==3.141.0 pip install --user openpyxl==2.6.1 pip install --user PyPDF2==1.26.0 pip install --user python-docx==0.8.10 (تثبيت python-docx وليس docx) pip install --user imapclient==2.1.0 pip install --user pyzmail36==1.0.4 pip install --user twilio pip install --user ezgmail pip install --user ezsheets pip install --user pillow==9.2.0 pip install --user pyobjc-framework-Quartz==5.2 (على نظام ماك فقط) pip install --user pyobjc-core==5.2 (على نظام ماك فقط) pip install --user pyobjc==5.2 (على نظام ماك فقط) pip install --user python3-xlib==0.15 (على نظام لينكس فقط) pip install --user pyautogui ملاحظة: يمكن أن يستغرق تثبيت الوحدة pyobjc في نظام ماك 20 دقيقة أو أكثر، لذا لا تنزعج إذا استغرق الأمر بعض الوقت، ويجب عليك أيضًا تثبيت الوحدة pyobjc-core أولًا، مما سيؤدي إلى تقليل وقت التثبيت الإجمالي. يمكنك اختبار نجاح تثبيت الوحدة بعد تثبيتها من خلال تشغيل الأمر import ModuleName في الصدفة التفاعلية، وإذا لم تُعرَض أيّ رسائل خطأ، فسنفترض نجاح تثبيت هذه الوحدة. إذا كانت الوحدة مثبتة مسبقًا، ولكنك ترغب في ترقيتها إلى أحدث إصدار متاح على موقع PyPI، فشغّل الأمر الآتي على نظامي ماك macOS ولينكس: pip install --user -U MODULE أو pip3 install --user -U MODULE حيث يثبَت الخيار --user الوحدة في مجلد المستخدم الخاص بك، مما يؤدي إلى تجنب أخطاء الأذونات المحتملة التي قد تواجهها عند محاولة التثبيت لجميع المستخدمين. تُجرِي الإصدارات الأحدث من وحدات Selenium و OpenPyXL تغييرات غير متوافقة مع الإصدارات السابقة المُستخدَمة في هذه السلسلة من المقالات، بينما تتفاعل وحدات Twilio و EZGmail و EZSheets مع الخدمات عبر الإنترنت، ولكن قد يُطلَب منك تثبيت أحدث إصدار من هذه الوحدات باستخدام الأمر: pip install --user -U ملاحظة: اقترحنا سابقًا استخدام الأمر sudo إذا واجهتَ أخطاء في الأذونات أثناء تشغيل أمر pip كما يلي: sudo pip install module، ولكنها تُعَد ممارسة سيئة، لأنها تثبّت وحدات مع تثبيت بايثون الذي يستخدمه نظام تشغيلك، إذ قد يشغّل نظام تشغيلك سكربتات بايثون لتنفيذ المهام المتعلقة بالنظام، وإذا ثبّتَ وحدات مع تثبيت بايثون بحيث تتعارض هذه الوحدات مع وحداته الحالية، فقد يؤدي ذلك إلى إنتاج أخطاء يصعب إصلاحها، لذا لا تستخدم الأمر sudo أبدًا عند تثبيت وحدات بايثون. تثبيت وحدات للمحرّر Mu يمتلك محرّر Mu بيئة بايثون الخاصة به، وهي منفصلة عن البيئة التي تمتلكها عمليات تثبيت بايثون النموذجية، إذ يمكنك تثبيت الوحدات بحيث تستخدمها في السكربتات التي يشغّلها المحرّر Mu من خلال إظهار لوحة المدير Admin Panel عند النقر على رمز الترس في الزاوية اليمنى السفلية للمحرّر Mu، ثم انقر على تبويب الحزم الخارجية Third Party Packages في النافذة التي ستظهر واتبع الإرشادات الخاصة بتثبيت الوحدات في هذا التبويب. لا تزال القدرة على تثبيت الوحدات في المحرّر Mu ميزة حديثة وقيد التطوير، لذا قد تتغير هذه التعليمات. إن لم تتمكّن من تثبيت الوحدات باستخدام لوحة المدير، فيمكنك أيضًا فتح نافذة الطرفية وتشغيل الأداة pip الخاصة بالمحرّر Mu. يجب أن تستخدم خيار سطر الأوامر --target الخاص بالأداة pip لتحديد مجلد الوحدة الخاص بالمحرّر Mu، وهذا المجلد على نظام ويندوز هو: C:\Users\<USERNAME>\AppData\Local\Mu\pkgs وعلى نظام ماك macOS: /Applications/mu-editor.app/Contents/Resources/app_packages ولكنك لا تحتاج في نظام لينكس إلى إدخال الوسيط --target ، لذا شغّل الأمر pip3 فقط. شغّل الأوامر التالية مثلًا بعد تنزيل ملف المتطلبات لنظام تشغيلك من موقع nostarch: على نظام ويندوز: pip install –r automate-win-requirements.txt --target "C:\Users\USERNAME\AppData\Local\Mu\pkgs" على نظام ماك macOS: pip3 install –r automate-mac-requirements.txt --target /Applications/mu-editor.app/Contents/Resources/app_packages على نظام لينكس: pip3 install --user –r automate-linux-requirements.txt إذا أردتَ تثبيت بعض الوحدات فقط، فيمكنك تشغيل الأمر pip (أو pip3) العادي وإضافة الوسيط --target. تشغيل البرامج في بايثون إذا كان برنامجك مفتوحًا في المحرّر Mu، فيُعَد تشغيله أمرًا بسيطًا من خلال الضغط على مفتاح F5 أو النقر على زر التشغيل Run الموجود أعلى النافذة، وهي طريقة سهلة لتشغيل البرامج أثناء كتابتها، ولكن يمكن أن يكون فتح المحرّر Mu لتشغيل برامجك النهائية عبئًا عليك، لذا توجد طرق أكثر ملاءمة سنوضّحها في هذا المقال لتنفيذ سكربتات بايثون اعتمادًا على نظام التشغيل الذي تستخدمه. تشغيل البرامج من نافذة الطرفية Terminal إذا فتحتَ نافذة طرفية مثل موجّه الأوامر على نظام ويندوز Windows أو الطرفية Terminal على نظامي ماك macOS ولينكس Linux، فسترى نافذةً فارغة لإدخال أوامر نصية فيها. يمكنك تشغيل برامجك من الطرفية، ولكن إن لم تكن معتادًا على ذلك، فسيكون استخدام حاسوبك عبر هذه الطرفية (التي تُسمَّى سطر الأوامر أيضًا) أمرًا صعبًا، إذ لن تقدّم الطرفية أيّ تلميحات حول ما يُفترض أن تفعله على عكس واجهة المستخدم الرسومية. يمكنك فتح نافذة طرفية على نظام ويندوز من خلال النقر على زر "ابدأ أو Start"، ثم أدخل إلى موجّه الأوامر، واضغط على مفتاح ENTER. انقر على أيقونة Spotlight في الجزء العلوي الأيمن في نظام ماك macOS، واكتب Terminal، ثم اضغط على مفتاح ENTER. يمكنك في نظام أوبنتو لينكس Ubuntu Linux الضغط على مفتاح WIN لإظهار أيقونة Dash، ثم اكتب Terminal، واضغط على مفتاح ENTER، وسيفتح اختصار لوحة المفاتيح Ctrl-Alt-T أيضًا نافذة الطرفية على نظام أوبنتو. تحتوي الصدفة التفاعلية على سطر الأوامر <<<، وتعرض الطرفية أيضًا هذا السطر لإدخال الأوامر. سيكون المسار التالي هو المسار الكامل للمجلد الذي تتواجد فيه حاليًا على نظام ويندوز: C:\Users\Al>your commands go here يعرض سطر الأوامر على نظام ماك macOS اسم حاسوبك ونقطتين ومجلد العمل الحالي (مع تمثيل مجلد المنزل home directory بالرمز ~ اختصارًا) واسم المستخدم الخاص بك متبوعًا بإشارة الدولار الأمريكي ($) كما يلي: Als-MacBook-Pro:~ al$ your commands go here يشبه سطر الأوامر في نظام أوبنتو لينكس سطرَ الأوامر في نظام ماك macOS باستثناء أنه يبدأ باسم المستخدم والإشارة @ كما يلي: al@al-VirtualBox:~$ your commands go here ملاحظة: يمكن تخصيص سطور الأوامر، ولكن لن نوضّح ذلك في هذا المقال. إذا أدخلتَ أمرًا مثل الأمر python على نظام ويندوز أو الأمر python3 على نظامي ماك macOS ولينكس، فستتحقق الطرفية من وجود برنامج يحمل هذا الاسم في المجلد الذي تتواجد فيه حاليًا، وإذا لم تجده هناك، فستتحقق من المجلدات المُدرَجة في متغير البيئة PATH، حيث يمكن عَدّ متغيرات البيئة بأنها متغيرات على مستوى نظام التشغيل بأكمله، إذ تحتوي على عددٍ من إعدادات النظام. يمكنك رؤية القيمة المُخزَّنة في متغير البيئة PATH من خلال تشغيل الأمر echo %PATH% على نظام ويندوز والأمر echo $PATH على نظامي ماك macOS ولينكس. إليك مثال على نظام ماك macOS: Als-MacBook-Pro:~ al$ echo $PATH /Library/Frameworks/Python.framework/Versions/3.9/bin:/usr/local/bin:/usr/ bin:/bin:/usr/sbin:/sbin يوجد ملف البرنامج python3 على نظام ماك macOS في المجلدك /Library/Frameworks/Python.framework/Versions/3.9/bin لذلك لا حاجة لإدخال المسار الآتي: /Library/Frameworks/Python.framework/Versions/3.9/bin/python3 أو يمكنك التبديل إلى هذا المجلد أولًا لتشغيل البرنامج، حيث يمكنك إدخال الأمر python3 من أيّ مجلد، وستجده الطرفية في أحد مجلدات متغير البيئة PATH، إذ تُعَد إضافة مجلد البرنامج إلى متغير البيئة PATH اختصارًا مناسبًا. إذا أردتَ تشغيل برنامج .py، فيجب أن تدخِل الأمر python (أو python3) متبوعًا باسم ملف .py، مما يؤدي إلى تشغيل بايثون التي تشغّل بدورها الشيفرة البرمجية التي تجدها في ملف .py، وستعود إلى موجّه الطرفية بعد انتهاء برنامج بايثون. سيبدو برنامج بسيط يظهِر الرسالة "Hello, world!" مثلًا في نظام ويندوز كما يلي: Microsoft Windows [Version 10.0.17134.648] (c) 2018 Microsoft Corporation. All rights reserved. C:\Users\Al>python hello.py Hello, world! C:\Users\Al> يؤدي تشغيل الأمر python (أو python3) بدون أيّ اسم ملف إلى أن تشغّل بايثون الصدفة التفاعلية. تشغيل برامج بايثون على نظام ويندوز توجد عدة طرق أخرى يمكنك من خلالها تشغيل برامج بايثون على نظام ويندوز بدلًا من فتح نافذة الطرفية لتشغيل سكربتات بايثون، حيث يمكنك الضغط على الاختصار WIN-R لفتح مربع حوار التشغيل Run وإدخال الأمر الآتي: py C:\path\to\your\pythonScript.py وكما هو موضح في الشكل التالي، يكون البرنامج py.exe مثبَّتًا على المسار C:\Windows\py.exe الموجود في متغير البيئة PATH، وتُعَد كتابة امتداد الملف .exe أمرًا اختياريًا عند تشغيل البرامج. مربع حوار التشغيل Run في نظام ويندوز الجانب السلبي لهذه الطريقة هو أنه يجب أن تدخِل المسار الكامل للسكربت الخاص بك، وإذا شغّلنا سكربت بايثون من مربع الحوار، فستُفتح نافذة طرفية جديدة لعرض خرج هذا السكربت، وستُغلق هذه النافذة تلقائيًا عند انتهاء البرنامج، وبالتالي قد تفوِّت بعض الخرج. يمكنك حل هذه المشاكل من خلال إنشاء سكربت دفعي Batch Script، والذي هو ملف نصي صغير له امتداد الملف .bat ويمكنه تشغيل أوامر طرفية متعددة، وهو يشبه إلى حد كبير سكربت الصدفة Shell Script في نظامي ماك macOS ولينكس. يمكنك استخدام محرّر نصوص مثل المفكرة Notepad لإنشاء هذه الملفات. ننشئ ملف دفعي من خلال إنشاء ملف نصي جديد يحتوي على سطر واحد كما يلي: @py.exe C:\path\to\your\pythonScript.py %* @pause ضع مسار برنامجك المطلق مكان المسار السابق، واحفظ هذا الملف مع امتداد الملف .bat مثل الملف pythonScript.bat. تمنع الإشارة @ الموجودة في بداية كل أمر عرضَه في نافذة الطرفية، ويوجّه الرمز *% أيّ وسطاء مُدخَلة في سطر الأوامر بعد اسم الملف الدفعي إلى سكربت بايثون، ويقرأ برنامج بايثون بدوره وسطاء سطر الأوامر من قائمة sys.argv. سيمنعك هذا الملف الدفعي من الاضطرار إلى كتابة المسار المطلق الكامل لبرنامج بايثون في كل مرة تريد تشغيله فيها، وسيضيف @pause عبارة الضغط على أيّ مفتاح للمتابعة "Press any key to continue..." بعد نهاية سكربت بايثون لمنع اختفاء نافذة البرنامج بسرعة كبيرة. ننصحك بوضع جميع الملفات الدفعية وملفات .py في مجلد واحد موجود فعليًا في متغير البيئة PATH مثل المجلد C:\Users\<USERNAME>. لن تحتاج من خلال إعداد ملف دفعي لتشغيل سكربت بايثون إلى فتح نافذة طرفية وكتابة مسار الملف الكامل واسم سكربت بايثون الخاص بك، إذ يمكنك فقط الضغط على الاختصار WIN-R وإدخال pythonScript (اسم الملف pythonScript.bat الكامل ليس ضروريًا)، ثم اضغط على مفتاح ENTER لتشغيل السكربت الخاص بك. تشغيل برامج بايثون على نظام ماك macOS يمكنك إنشاء سكربت صدفة لتشغيل سكربتات بايثون الخاصة بك في نظام ماك macOS من خلال إنشاء ملف نصي له امتداد الملف .command. أنشئ ملفًا جديدًا في محرّر النصوص مثل المحرّر TextEdit وأضِف المحتوى التالي: #!/usr/bin/env bash python3 /path/to/your/pythonScript.py احفظ هذا الملف مع امتداد الملف .command في مجلدك الرئيسي (مثل المجلد /Users/al)، واجعل سكربت الصدفة قابلًا للتنفيذ من خلال تشغيل الأمر chmod u+x yourScript.command في نافذة الطرفية. ستتمكّن الآن من النقر على أيقونة Spotlight (أو الضغط على الاختصار -SPACE) وإدخال yourScript.command لتشغيل سكربت الصدفة، والذي بدوره سيشغّل سكربت بايثون الخاص بك. تشغيل برامج بايثون على نظام أوبنتو لينكس يتطلب تشغيل سكربتات بايثون في أوبنتو لينكس من قائمة Dash إعدادًا إضافيًا. لنفترض أن لدينا السكربت /home/al/example.py، إذ قد يكون سكربت بايثون الخاص بك موجودًا في مجلد مختلف وباسم ملف مختلف، ونريد تشغيله من قائمة Dash. استخدم أولًا محرر نصوص مثل المحرّر gedit لإنشاء ملف جديد مع المحتوى التالي: [Desktop Entry] Name=example.py Exec=gnome-terminal -- /home/al/example.sh Type=Application Categories=GTK;GNOME;Utility; احفظ هذا الملف في المجلد الآتي: /home/<al>/.local/share/applications (مع وضع اسم مستخدمك مكان al) بالاسم example.desktop. إن لم يُظهِر محرّر النصوص مجلد .local لأن المجلدات التي تبدأ بنقطة تُعَد مجلدات مخفية، فيجب أن تحفظه في مجلدك الرئيسي (مثل /home/al) وتفتح نافذة طرفية لنقل الملف باستخدام الأمرك mv /home/al/example.desktop /home/al/.local/share/applications. إذا كان الملف example.desktop موجودًا في المجلد الآتي: /home/al/.local/share/applications فستتمكن من الضغط على مفتاح Windows في لوحة المفاتيح لإظهار قائمة Dash وكتابة example.py (أو أي شيء تضعه في الحقل Name)، مما يؤدي إلى فتح نافذة طرفية جديدة أو برنامج gnome-terminal على وجه التحديد الذي يشغّل سكربت الصدفة /home/al/example.sh الذي سننشئه لاحقًا. أنشئ ملفًا جديدًا مع المحتوى التالي في محرّر النصوص: #!/usr/bin/env bash python3 /home/al/example.py bash احفظ هذا الملف في الملف /home/al/example.sh الذي هو سكربت صدفة، والذي هو سكربت يشغّل سلسلةً من أوامر الطرفية، حيث يشغّل سكربت الصدفة سكربت بايثون /home/al/example.py ثم يشغّل برنامج صدفة باش Bash Shell. إن لم نضع أمر باش الموجود في السطر الأخير، فستُغلَق نافذة الطرفية بعد انتهاء سكربت بايثون وستفقد أيّ نصٍ يعرضه استدعاء الدالة print() على الشاشة. يجب أن تضيف أذونات التنفيذ إلى سكربت الصدفة، لذا شغّل الأمر التالي من نافذة الطرفية: al@ubuntu:~$ chmod u+x /home/al/example.sh أعددنا الملفين example.desktop و example.sh، وستتمكّن الآن من تشغيل السكربت example.py من خلال الضغط على مفتاح Windows وإدخال example.py أو أي اسم تضعه في الحقل Name الخاص بالملف example.desktop. تشغيل برامج بايثون مع تعطيل التأكيدات Assertions يمكنك تعطيل تعليمات assert في برامج بايثون الخاصة بك للحصول على تحسين بسيط في الأداء، لذا ضمّن مفتاح -O بعد الأمر python أو python3 وقبل اسم ملف .py عند تشغيل بايثون من الطرفية، مما يؤدي إلى تشغيل نسخة مُحسَّنة من برنامجك تتخطى عمليات التحقق من التأكيد. أين تجد المساعدة يميل المطورون إلى التعلم بالبحث في الإنترنت عن إجابات عن أسئلتهم، وهذه الطريقة مختلفة كثيرًا عمّا اعتاد كثيرون على فعله من حضور دروس لمدرس يلقي محاضرةً ويجيب عن أسئلة الطلاب. ما يميز استخدام الإنترنت للتعلم أنك ستجد مجتمعات كاملة فيها أشخاص يستطيعون الإجابة عن أسئلتك، بل ومن المرجح أن تكون أسئلتك مجاب عنها مسبقًا وتنتظرك الإجابات عنها لتقرأها. إذا واجهت رسالة خطأ أو حدث خطبٌ ما أثناء محاولتك تشغيل شيفرتك، فلن تكون أول شخص يواجه هذه المشكلة، وأؤكد لك أن العثور على حلها أسهل مما تظن بكثير. لنسبب خطأً عمدًا في برنامجنا للتجربة: أدخل '42' + 3 في الصدفة التفاعلية، لا حاجة إلى شرح ما الذي تفعله هذه الشيفرة الآن لأننا سنتعلمها لاحقًا، لكن سيظهر لك الخطأ الآتي: >>> '42' + 3 ➊ Traceback (most recent call last): File "<pyshell#0>", line 1, in <module> '42' + 3 ➋ TypeError: Can't convert 'int' object to str implicitly >>> رسالة الخطأ ➋ تظهر لأن بايثون لا تستطيع فهم التعليمة التي أعطيتها إياها، والجزء الأول ➊ من رسالة الخطأ يبين لنا التعليمة الخطأ ورقم سطرها وما المشكلة التي واجهتها بايثون معها. إذا لم تكن متأكدًا من معنى رسالة الخطأ فابحث عنها في الويب. أدخل "TypeError: Can’t convert ‘int’ object to str implicitly" (بما فيها علامات الاقتباس) في محرك البحث المفضل لديك وستجد عشرات الصفحات التي توضح لك ما هذا الخطأ وما مسبباته كما في الصورة الآتية: الشكل 2: نتائج بحث جوجل حول رسالة خطأ برمجي ستجد أن أحدهم كان له نفس سؤالك وأتى مطور من أولي الخبرة وأجابه. اعلم أنه لا يمكن لشخص واحد أن يعرف كل شيء عن البرمجة، لذا يكون البحث عن إجابات الأسئلة التقنية جزءًا من يومك كمطور برمجيات. طرح أسئلة برمجية ذكية إذا لم تجد إجابةً عن سؤالك في الإنترنت، فيمكنك أن تجرب سؤال الخبراء في أحد المنتديات أو المواقع المخصصة مثل Stack Overflow أو مجتمع Learn Programming في Reddit. لكن أبقِ في ذهنك أن هنالك طرائق ذكية لطرح الأسئلة البرمجة لتساعد الآخرين على مساعدتك. فبدايةً احرص على قراءة قسم الأسئلة الشائعة FAQ في تلك المواقع لتعرف الطريقة الصحيحة لطرح السؤال. حين طرحك لسؤال برمجي فتذكر ما يلي: اشرح ما تحاول فعله، وليس ما فعلته. هذا يسمح لمن يريد مساعدته أن يخبرك إن كنت على الطريق الصحيح لحل المشكلة. حدد النقطة التي يحدث الخطأ عندها، هل تحدث مثلًا حين بدء تشغيل البرنامج كل مرة أم حين وقوع حدث معين؟ وما هو هذا الحدث الذي يحدث ويسبب ظهور الخطأ. انسخ والصق رسالة الخطأ كاملة على مواقع تسمح لك بمشاركة الشيفرات مع الآخرين بسرعة مثل pastebin أو gits.github أو قسم الأسئلة والأجوبة في أكاديمية حسوب، فعبرها تستطيع مشاركة نصوص طويلة دون أن تفقد تنسيق النص، وبعد ذلك ضع رابط URL التابع للشيفرة التي شاركتها في مشاركتك أو سؤالك. اشرح ما حاولت فعله لحل المشكلة، وبهذا تخبر الآخرين أنك بذلت جهدًا لمحاولة حل المشكلة بنفسك. ضع إصدار بايثون الذي تستخدمه (إذ هنالك اختلافات جوهرية بين الإصدار الثاني من مفسر بايثون والإصدار الثالث). اذكر أيضًا نوع نظام تشغيلك وإصداره. إذا حدث الخطأ بعد إجراء تعديل على شيفرتك فاذكر ما هو التعديل الذي أجريته. أرجو منك أيضًا أن تتبع آداب طرح النقاشات في الإنترنت، فاحرص على سلامة السؤال من الأخطاء الإملائية أو اللغوية، وأن تكون لغته واضحة للجميع، وإذا طرحت سؤالك بالإنكليزية فلا تضعه بأحرف كبيرة، ولا تقدم مطالب غير معقولة وغير منطقية ممن يمد إليك يد المساعدة. الخلاصة يرى أغلبية مستخدم الحاسوب أن حاسوبهم هو صندوق سحري بدل رؤيته كأداة يمكنهم استخدامها كيفما يشاؤون؛ وبتعلمك البرمجة ستصل إلى أقوى أدوات المتاحة في عالمنا الحالي وهي القدرة الحاسوبية الهائلة المتوافرة أمامك! وتذكر أن تستمتع بوقتك أثناء البرمجة وتعلمها، فالبرمجة ليست كالجراحة العصبية فلا بأس أن تخطئ وتجرب كما تشاء. نفترض في هذه السلسلة أنك لا تعرف شيئًا عن البرمجة وستتعلم فيه الكثير، لكن إن كانت لديك أسئلة خارج سياقه فتذكر أن تبحث عنها أو أن تطرحها على الخبراء بأسلوب واضح فالبحث عن الإجابات من أهم الأدوات التي عليك احترافها لتعلم البرمجة. ترجمة -وبتصرف- لمقدمة كتاب Automate the boring stuff with Python لصاحبه Al Sweigart. اقرأ أيضًا تعلم لغة بايثون تعرف على أبرز مميزات لغة بايثون تطبيقات لغة بايثون النسخة العربية الكاملة لكتاب البرمجة بلغة بايثون1 نقطة
-
لغات البرمجة هو مفهوم واسع كبير يحتوي على أسماء عدة شتى قد يحتار فيها الداخل الجديد إلى مجال علوم الحاسوب لتعلم البرمجة، فقد يتساءل أي لغة برمجة يجب أن أتعلم أولًا، وما هي أشهر لغة برمجة تُستعمل على نطاق واسع استفيد منها، وما هي أسهل لغة برمجة ابدأ بها وغيرها من الأسئلة المحيرة، فإن فتحت مثلًا قائمة لغات البرمجة على ويكيبيديا فستجد عشرات لغات البرمجة المذكورة وهو ما يزيد المشكلة وهنا لابد من الاستعانة بدليل. يقودك هذا المقال تدريجيًا في جولة سريعة في عالم لغات البرمجة كي تتكون لديك صورة عامة موسّعة عن لغات البرمجة لتكون عونًا لك إن كنت ستتعلم إحداها، وسينتقل بك المقال من شروحات مبسطة لمفهوم لغات البرمجة ومستويات لغة البرمجة وأقسامها إلى أنواعها واستخداماتها سواء لبرمجة الحواسيب أو الأجهزة الذكية أو الأجهزة الإلكترونية وحتى الروبوتات، ثم سنجاوب على بعض الأسئلة الشائعة المتعلقة بلغات البرمجة مثل التي أشرنا إليها قبل قليل في نهاية المقال. ينبغي أن تكوّن في نهاية المقال فكرة واضحة عن ما يُدعى لغة برمجة ولغات البرمجة عمومًا تكون ركيزة صلبة تعتمد عليها في اختيار لغة البرمجة التي تناسب المجال الذي تخطط الدخول له إن أردت تطوير مسارك المهني ودخول عالم البرمجة. إليك فهرس المقال لكي يسهل عليك التنقل بين أقسامه: تعريف البرمجة ما هي لغات البرمجة لغة البرمجة واللغات البشرية أنواع لغات البرمجة لغات برمجة السكربت Scripting Languages اللغات التوصيفية Markup Languages أسئلة شائعة عن لغات البرمجة تعريف البرمجة البرمجة هي العملية التي تستطيع بواسطتها إنجاز فكرة معينة أو حل مشكلة ما عن طريق تقسيم الفكرة أو المشكلة إلى خطوات متتالية قابلة لإعادة التكرار وصولًا إلى النتيجة المطلوبة. فلو سألت أحدهم ما هو ناتج العملية الرياضية التالية 5*(2-3) فقد يعطيك مباشرة الجواب 5 لكن ما فعله الدماغ هو عملية تحليل للمسألة ووضع طريقة لحلها وهذا ما يُدعى بوضع خوارزمية Algorithm. فخوارزمية حل المسألة البسيطة السابقة هي: اطرح 2 من 3 وسجل الجواب: 1 =2-3. احسب جداء الناتج مع العدد 5: 5x1. قل الجواب: 5. وخلاصة القول أن البرمجة هي طريقة لترتيب وتنظيم مسألة ما للحصول على النتيجة بالمعنى العام، أما في عالم الحواسيب فهي وسيلة للتخاطب مع هذه الأجهزة. أما الأسلوب المقترح لتنفيذ هذه الخطوات فهي الخوارزمية، وستكون عندها لغة البرمجة هي الوسيلة التي نخبر فيها الحاسوب أو التجهيزة كيفية تنفيذ الخوارزمية لحل المشكلة المعروضة. ما هي لغات البرمجة؟ لغات البرمجة تشير ببساطة على أنها وسيلة للتواصل بين البشر والحواسب أو بعض التجهيزات أو الآلات المهيأة لتنفيذ برامج متغيرة والتي تُدعى تجهيزات قابلة للبرمجة. ونظرًا للتقدم التكنولوجي الهائل ودخول تقنيات المعلومات إلى مختلف نواحي الحياة، ازداد توجه الصانعين إلى إنتاج تجهيزات قادرة على التخاطب والتفاعل مع المستخدم لتنفيذ وظائف متعددة كالصرافات الآلية ونقاط الخدمة الذاتية والهواتف الذكية وحتى التجهيزات المنزلية والسيارات، وكلما زاد تعقيد هذه التجهيزات وتعددت مهامها احتاجت إلى طريقة فعّالة لتخبرها بما هو مطلوب منها. وهنا تأتي أهمية لغات البرمجة وضرورة وجود أنواع مختلفة من لغات البرمجة وفق سويات مختلفة لتأمين إدارة تلك التجهيزات والتواصل الأمثل معها. إذًا فلغة البرمجة هي مجموعة من التعليمات والتوجيهات التي تكتب أو تُجمّع أو تُركّب ضمن سياق معين كي تنقل بعد معالجتها إلى الجهاز الهدف بغية تنفيذها. ويُقصد بمعالجة لغات البرمجة هو تحويلها من تعليمات مقروءة -في لغات البرمجة المكتوبة Written Programming Languages- أو مرئية بالنسبة للبشر -في لغات البرمجة المرئية Visual programing languages- إلى توجيهات تفهمها الآلة المستهدفة سواء حاسوب أو أية أنظمة إلكترونية أخرى. فما يفهمه الحاسوب هو برنامج مكوّن من الواحدات 1 والأصفار 0 التي تخبره وفقًا لتسلسلها بطريقة محددة سلفًا ما عليه فعله، وتعرف لغة البرمجة التي تُكتب برنامجًا بهذه الطريقة "لغة الآلة" machine language. ونظرًا لصعوبة فهمها للبشر، ظهرت الحاجة إلى لغات برمجة أكثر قربًا من البشر وهنا بدأت الحكاية. تتكون لغة البرمجة -مثلها مثل أي لغة- عمومًا من الأقسام التالية: صياغة لغة البرمجة Syntax هي الطريقة التي نصيغ فيها تعليمات لغة البرمجة ونربطها مع بعضها لإنتاج عبارات صحيحة الصياغة يمكن استخدامها في تنفيذ البرنامج وقد تكون الصياغة: نصية: وتمثل تعليمات اللغة وكلماتها المفتاحية keywords وعباراتها ومتنها. رسومية أو كتلية: تُنظَّم فيها التعليمات التي تؤدي عملًا محددًا ضمن كتلة واحدة، ثم تُمثَّل هذه الكتلة بطريقة مرئية كمربع أو دائرة تُعطى لونا واسمًا يدل على طبيعة العمل الذي تنفذه. ويبنى البرنامج عندها بضم هذه الكتل إلى بعضها لإنجاز الوظيفة المنوطة بالبرنامج. تعطي الصياغة إذًا الشكل العام الصحيح لطريقة كتابة التعليمات بناء على معايير خاصة خارج نطاق مقالنا، وإن أردنا تقريب الأمر فهي بمثابة القواعد النحوية للغات البشر أو اللغات الطبيعية. إذ تُعد مثلًا الجملة "إن المبرمجون مبدعون." في اللغة العربية خاطئة الصياغة لمخالفتها قواعد اللغة ومن المفترض أن نقول" إن المبرمجين مبدعون.". دلالة لغة البرمجة Semantic هي مجموعة قواعد تحدد ما إن كانت طريقة صياغة التعليمات ستعطي النتيجة المرجوة أم لا، وتضع بعض القيود على الصياغة الصحيحة التي قد لا تؤدي إلى نتيجة. لن نخوض كثيرًا في هذه الفكرة لكن سنسهل الأمر عليك عزيزي القارئ: لن تمنعنا أية قاعدة نحوية في اللغة العربية من القول بأنني "أتناول برتقالًا حامضًا لا طعم له" لكن كيف يكون حامضًا ولا طعم له في نفس الوقت! صياغة صحيحة ومدلول لا معنى له. تحديد الأنواع في لغة البرمجة Types وهي الطريقة التي تصنّف فيها لغة البرمجة القيم والتعابير ضمن أنواع مختلفة وكيفية التعامل مع هذه الأنواع والتحويل فيما بينها. فهنالك مثلًا قيم نصية كأن استخدم القيمة "انقر هنا" وقيم عددية كأن استخدم الرقم 5 وقيم منطقية كأن استخدم القيمة "صحيح" true. وقد تكون نتيجة تنفيذ العملية نوعًا محددًا من البيانات كأن تُنتج العملية الحسابية عددًا أو تنتج نصًا. لهذا تحاول معظم اللغات وضع أنواع للقيم التي تتعامل معها. لكن في المقابل ستجد عدة لغات لا تعتمد على الأنواع مثل جافاسكربت JavaScript وماتلاب MatLab. إن وجدت هذا الفكرة غامضة قليلًا لا تكترث وتابع القراءة فستبدو هذه الفكرة غاية الوضوح ما أن تكتب برنامجك الأول في لغة تختارها. المكتبات المعيارية Standard Libraries وهي مجموعة من التعليمات أو العمليات الجاهزة التي توفرها لغة البرمجة لعمل مختلف أجزائها مع بعضها ولتنفيذ المهام الأساسية المنوطة بلغة البرمجة تلك مثل التعامل مع النصوص والأعداد والتواصل مع نظام التشغيل ونظام الملفات وغيرها، وتوضع عادة في ملفات منفصلة وتضاف إلى البرنامج الذي تُنفّذه. إذ تساعدك بعض المكتبات مثلًا على إضافة نصٍ إلى نص آخر مباشرة باستخدام إشارة الجمع + على الرغم من كونها عملية حسابية تجري على الأعداد. إذ تضم تلك المكتبات القدرة على فهم أن هذه العملية هنا ليست لجمع عددين بل لضم نصين. تصنّف لغات البرمجة في فئات ومجموعات وفقًا لصياغتها وطريقة معالجتها للمعلومات وطريقة تنفيذ تعليمات لغة البرمجة وهذا ما سنتوسع فيه بعد قليل. لغة البرمجة واللغات البشرية إنّ اللغات البشرية هي الطريقة الطبيعية للتواصل بين البشر وتتكون من حروف تكوّن كلمات ومن ثم تشكل جملًا وفق مجموعة من القواعد التي ندعوها في العربية "نحوًا" ومن ثم نستخدم هذه الجمل بعناية لإيصال المعنى المطلوب. ويُفترض بالإنسان أن يُلم بأساسيات لغة الشخص الذي يحاوره كي لا تقع مشاكل في التواصل. الأمر مشابه في لغات البرمجة كونها لغة للتخاطب بين البشر والحواسيب أو الآلات التي تقبل البرمجة عمومًا. إضافة إلى ذلك، للغات الطبيعية ولغات البرمجة نوع من الهيكلية أو البنية التي تنتظم وفقها تلك اللغات، فالكلمات في اللغات الطبيعية قد تشابه التعليمات في لغة البرمجة والجمل sentences قد تشابه التعابير البرمجية Expressions، وتستخدم لغات البرمجة ما تستخدمه اللغات الطبيعية من علامات للترقيم لكن لأغراض خاصة بوظيفتها، وتستخدم عوامل تشابه حروف العطف والاختيار والموازنة في اللغات الطبيعية للربط بين التعابير البرمجية واستخلاص المعنى، فلهذه اللغات جميعها أساليب في الصياغة والمدلول. ومن أوجه الشبه أيضًا ما يُدعى بالعائلات، فاللغات الطبيعية تنحدر من عائلات تتشابه اللغات فيها كاللغات السامية أو اللغات الجرمانية أو السلافية. كذلك الأمر في لغات البرمجة التي تنحدر جميعها من لغات ظهرت في البداية مثل Fortran التي انحدرت منها Algol ثم C و ++C إذ تتشابه هاتين الأخيرتين كثيرًا. أما الاختلافات فتأتي من كون التعليمات في لغات البرمجة معدة سلفًا وقابلة للحصر حتى إن تطورت سيكون التطور بإلغاء تعليمة ووضع أخرى بينما تتطور اللغات الطبيعية وفقًا للحاجة ويظهر ذلك تلقائيًا. كذلك يظهر الاختلاف في عدم قدرة لغات البرمجة على التعبير بطرح أسئلة أو استخدام الإيحاءات بل تعتمد على مجموعة قواعد صارمة فيما يخص الصياغة وطريقة استخدام اللغة. تأتي أهمية هذا النقاش من ضرورة الفهم الأصيل للغات البشرية ولغات البرمجة لما سيقود ذلك من تطور في مجال البرمجيات التي تتعرف على الكلام أو المترجمات الآلية أو الذكاء الاصطناعي وغيرها الكثير. دورة الذكاء الاصطناعي احترف برمجة الذكاء الاصطناعي AI وتحليل البيانات وتعلم كافة المعلومات التي تحتاجها لبناء نماذج ذكاء اصطناعي متخصصة. اشترك الآن أنواع لغات البرمجة هنالك المئات من لغات البرمجة وجدت لتحقيق أهداف مختلفة وحتى هذه اللحظة تظهر لغات برمجة جديدة باستمرار، لذا تصنف هذه اللغات إلى أنواع عدة بالاعتماد على وظائف كل لغة وتطبيقاتها وطريقة معالجتها وغيرها من المقاييس ونوضح في الصورة التالية بعض الأنواع أو الفئات التي تنضوي تحتها لغات البرمجة. أنواع لغات البرمجة الشائعة هي تنقسم إلى الأنواع التالية: أنواع لغات البرمجة وفق مستوى الترميز لغات البرمجة منخفضة المستوى Low level Programming Languages لغة الآلة Machine language لغات التجميع Assembly languages لغات البرمجة عالية المستوى High level languages أنواع لغات البرمجة وفق طريقة معالجة التعليمات اللغات المُصرَّفة Compiled Languages اللغات المُفسَّرة Interpreted languages اللغات الهجينة المصرّفة المفسّرة أنواع لغات البرمجة وفق أسلوب تنظيم الشيفرة لغات البرمجة الوظيفية Functional Programming لغات البرمجة الإجرائية Procedural Programming لغات البرمجة الكائنية Object-oriented Programming أنواع لغات البرمجة وفق مجالات الاستخدام لغات البرمجة عامة الغرض General Purpose programming Languages لغات البرمجة خاصة الغرض Special Programming Languages شرح كل الأنواع السابقة سيطيل المقال وهو خارج موضوع التعريف بلغات البرمجة ويكفي أن تأخذ فكرة على أنواع لغات البرمجة وتتعرف على أشهر أصنافها لأنك عادة عندما تتعلم لغة برمجة يفترض أن تعرف نوعها والصنف الذي تتبع له لأن الأنواع الواحدة تشترك بمفاهيم واحدة تقريبًا يمكن تعلمها بشكل منفصل. ويمكنك الرجوع إلى مقال أنواع لغات البرمجة لتكتشف المزيد من التفاصيل حول معايير وطرق تصنيف وتنظيم لغات البرمجة وشرح مفصل لكل الأنواع التي ذكرناها بالأعلى. لغات برمجة السكربت تُعد لغة برمجة ما أنها لغة سكربت إن كانت: تستخدم مجموعة من التعليمات النصية المكتوبة لتنفيذ أي نوع من العمليات. تعتمد على مضيف: إذ لا يمكن أن تُنتج برامجًا تنفيذية قائمة بحد ذاتها بل ترتبط بنظام تشغيل مثل (سكربتات الطرفيات) أو بيئة عمل (سكربت ويب على الخادم) أو برنامج ( سكربت كتابة ماكرو أو موسّع) أو لغة برمجة أخرى لتنفيذ مجموعة من العمليات التي تهدف إلى تعديل أو تطوير أو زيادة القدرة الوظيفية للمضيف أو تتوسط بينها وبين منظومات أخرى ليشار إليها عندها إلى أنها لغات صمغية glue code. أن تكون لغة مفسّرة وليست مُصرَّفة. تتميز لغات السكربت بكونها، مفتوحة المصدر غالبًا، وسهلة التعليم نسبيًا ولا ضرورة لوجودها ضمن ملف خاص كي تُفسّر، ولا يمكن كتابة تطبيقات أو برامج باستخدامها مباشرة بل تحتاج إلى مضيف لذلك يُقال أنها محمولة. أضف إلى ذلك أنها سريعة التنفيذ كونها تستطيع تنفيذ الطلبات مباشرة (تنفيذ أمر مباشرة) دون الحاجة إلى تعليمات أخرى لتفعيل الطلب كما يزيد سرعتها كونها لغة برمجة مفسّرة. يمكنك مثلًا أن تُنفّذ الأمر ('مرحبًا')window.alert مباشرة في جافاسكربت وهي لغة سكربت مشهورة جدًا، لكنك لن تستطيع فعل ذلك باستخدام لغة ++C. لاحظ ماذا سيتطلب الأمر: // لنقول مرحبًا C++ برنامج بلغة #include <iostream> using namespace std; int main(){ cout<<"مرحبًا"; return 0; } تُصنف لغات برمجة السكربت إلى: سكربتات تطوير الويب: وتستخدم لكتابة صفحات ويب ديناميكية وتطوير مواقع وتطبيقات الويب، ويمكن أن نميز بين نوعين من السكربتات في هذه الصدد سكربتات تعمل من جانب العميل (أي تُستخدم في بناء الواجهة الأمامية للتطبيق أو الموقع) نجد: JavaScript React Next.js سكربتات تعمل من جانب الخادم (أي تستخدم لبناء الواجهة الخلفية للتطبيق، وهي ما يستعرضه المتصفح) نجد منها: JavaScript PHP Node.js ASP.net Ruby Perl Python سكربتات تعمل مع طرفيات أنظمة التشغيل: وتستخدم لتنفيذ الأوامر ضمن واجهات سطر الأوامر في أنظمة التشغيل المختلفة مثل ويندوز ولينكس. من الأمثلة عليها: BASH: في طرفيات لينكس، وتنفذ طيفًا واسعًا من التعليمات مثل الكتابة والقراءة من وإلى الملفات وتنزيل البرمجيات من الإنترنت وتثبيتها وتشغيل البرمجيات وغيرها الكثير. Windows powerShell: في ويندوز، وتنفذ مهامًا مشابهة لما تنفذه طرفية لينكس. سكربتات للأغراض العامة: يمكن أن تُنفذ تقريبًا أي شيء نذكر منها: Ruby Python يمكن استخدام السكربتات في كل المجالات تقريبًا مثل تطبيقات الويب وتطبيقات الهواتف المحمولة وسطح المكتب والتعامل مع الأنظمة وأتمتة المهام على المنظومات السحابية والتنقيب عن البيانات وبرمجة الموّسعات والإضافات إلى البرامج وغيرها الكثير. نفذ مشاريعك البرمجية باللغة التي تحتاجها استعن بأفضل المبرمجين في كتابة وتصحيح الأكواد البرمجية على خمسات اطلب خدمتك الآن اللغات التوصيفية Markup Languages يشير مصطلح اللغات التوصيفية markup languages إلى آلية لترميز النصوص عن طريق إضافة مجموعة من الرموز إلى النص تتحكم بتنسيقه أو بإيجاد علاقات بين أقسامه وتسهل عملية أتمتته. إذ تضم اللغات التوصيفية مجموعة من الوسوم أو القواعد التي يشير كل منها إلى دلالة معينة وتستخدم لتنظيم البيانات النصية وعرضها بطريقة يسهل تمييزها بالنسبة للإنسان أو الحاسوب كأن تشير إلى عبارة على أنها عنوان وتبرز عبارة أخرى بكتابتها بخط ثخين وهكذا. لا تُعرض تلك القواعد أو الوسوم ولا تُضاف إلى المحتوى الفعلي بل وظيفتها وصف البيانات فقط وترتيبها. تتطلب هذه اللغات فقط برنامجًا ليحلل الوسوم ويعرض المحتوى وفقًا لمدلول كل وسم وغالبًا ما تحلل المتصفحات أكواد HTML وأكواد XML ثم تعرض النتائج بينما تحلل برمجيات أخرى مخصصة لغات توصيفية أخرى مثل Markdown و DocBook اللتان تستخدمان في المحررات النصية ولاتخ LaTex لكتابة الأوراق البحثية الأكاديمية وغيرها الكثير. لا تحتاج اللغات التوصيفية كلغات البرمجة إلى تصريف Compilation أو تفسير Interpretation كي تحول الشيفرة المكتوبة إلى مجموعة أخرى من التعليمات التي يفهمها الحاسوب، فهي لا تنفذ أية عمليات أو إجرائيات لذلك لا تُعد اللغات التوصيفية لغات برمجة. فكل ما تفعله محللات اللغات التوصيفية هو قراءة الوسوم ومعرفة بدايتها ونهايتها ثم عرض هذه الوسوم بالطريقة الصحيحة تبعًا لدلالة تلك الوسوم. يمكن استخدام هذه اللغات لتصميم صفحات ويب مثل HTML أو لتنسيق صفحات الويب مثل CSS أو لتخزين البيانات مثل XML أو لتنسيق النصوص مثل Markdown وغيرها الكثير. تشرح دورة تطوير واجهات المستخدم من أكاديمية حسوب كل من لغات تطوير واجهات المستخدم الأمامية وهي HTML و CSS وجافاسكربت شرحًا شاملًا بعدد ساعات يزيد عن 50 ساعة فيديو بتطبيقات عملية تطبيقية تناسب سوق العمل. يمكنك الرجوع في هذا الصدد إلى مقال تعلم لغة HTML الذي يتحدث عن اللغات التوصيفية عمومًا ولغة HTML خصوصًا. أسئلة شائعة عن لغات البرمجة إليك بعض الإجابات عن أكثر الأسئلة شيوعًا حول لغات البرمجة. كم عدد لغات البرمجة الموجودة حاليًا؟ عدد لغات البرمجة وفقًا لموقع ويكيبيديا يقارب 700 لغة برمجة مستخدمة أو توقف استخدامها باستثناء اللغات التوصيفية. لكن يرى البعض أنها قد تصل بجميع تصنيفاتها إلى 8000-9000 وهذا رقم مبالغ فيه قليلًا. ما السبب في وجود عدد كبير من لغات البرمجة؟ التنوع نابع عن الحاجة، فلن تتمتع لغة برمجة واحدة بجميع المزايا التي تسهّل العمل في جميع المجالات بفعالية ودقة. قد يكون الأمر مشابهًا لوجود أنواع عدة من المركبات منها السيارة والطائرة والدراجة الهوائية والنارية فلكل استخدامه، إذ يولّد التطور التقني المتسارع الحاجة إلى وجود لغات أكثر مرونة وفعالية في مجالات مختلفة مما يدفع إلى تطوير لغات جديدة تلبي هذه الحاجة. ما هي أحدث لغات البرمجة؟ إذا استثنينا الإصدارات الجديدة من اللغات القديمة مثل الإصدار 3 من لغة Python يمكن أن نجد: لغات البرمجة بالدوال: ELIXIR ELM PURESCRIPT SWIFT لغات البرمجة الإجرائية: Go لغات البرمجة بالكائنات: DART PONY CARBON لغات أغراض عامة: HACK Kotlin NIM RUST ما هي لغات البرمجة السائدة (أشهر لغات البرمجة)؟ إليك أكثر لغات البرمجة استخدامًا وأشهر لغات البرمجة لكن دون نسب مئوية للاستخدام ودون أفضلية لعدم وجود إحصائيات دقيقة وموثوقة. Python JavaScript JAVA C++/C GO Ruby #C PHP أشهر لغة من بينها تُستعمل في بناء تطبيقات سطح مكتب تعمل على مختلف أنظمة التشغيل الحاسوبية هي لغة جافا Java وبايثون Python والأخيرة تستعمل في مجال الذكاء الاصطناعي وتعلم الآلة والتعامل مع البيانات وغيرها، أما في مجال الويب، فأشهر لغة فيه حاليًا هي لغة جافاسكربت JavaScript فيمكنك باستعمالها تطوير الواجهات الأمامية Frontend وأصبح بإمكانك أيضًا تطوير الواجهات الخلفية Backend عبر بيئة Node.js وكما يمكنك باستعمال تقنيات الويب تطوير تطبيقات لسطح المكتب تعمل على كل أنظمة التشغيل باستعمال إطار العمل Electron.js، وتعد دورة تطوير التطبيقات باستخدام لغة JavaScript أفضل مرجع عربي يشرح لغة جافاسكربت وكافة تطبيقاتها لبناء تطبيقات الويب وتطبيقات سطح المكتب شرحًا عمليًا. ما هي أسهل لغات البرمجة من حيث التعلم والاستخدام؟ لا يمكن أن نجد إجابة محددة عن سؤال أسهل لغات البرمجة فالغرض من استخدامك للغة البرمجة وتآلفك معها مسألة حاجة ورغبة: PHP Python JavaScript Ruby C/C++/JAVA Kotlin Swift عمومًا، يقال عن لغة بايثون أنها أسهل لغة برمجة يمكن البدء بتعلمها والسبب أنها صياغة اللغة قريبة جدًا من صياغة اللغة الإنجليزية فعندما تكتب شيفرة برمجية كأنك تصيغ فقرة من لغة إنجليزية وهذا ما يميزها عن بقية اللغات التي تكثر فيها الأحرف والكلمات الغامضة وعلامات الترقيم والأقواس المتناثرة هنا وهناك، ولهذا السبب تبدأ أغلب الجامعات بشرح هذه اللغة كأول لغة برمجة لطلاب علوم الحاسوب وتبدأ أغلب الدورات والكورسات البرمجة بشرحها لمن يريد تعلم البرمجة بمفرده، وأفضل مرجع عربي شامل متكامل من تلك الدورات هي دورة تطوير التطبيقات باستخدام لغة Python من أكاديمية حسوب. هل عليَّ تعلم لغة برمجة؟ إن كنت تنوي تطوير مهنتك الهندسية أو العلمية أو التسويقية أو الاقتصادية أو التحليلية فالجواب نعم بكل تأكيد. ما الفائدة من تعلم لغة برمجة؟ تطوير مسيرتك المهنية، فكل الدلائل تشير إلى أننا مقبلون وبشدة على عصر الآلات الذكية. الاطلاع على الطريقة التي تعمل بها الآلات المبرمجة مما قد يساعدك على استخدامها بالشكل الصحيح. تحسين قدراتك العقلية على التحليل وترتيب الأفكار. إضافة إلى تلك الأسباب العامة، ستجد من مهنة المبرمج أو مطور ويب مهنة ممتعة ومجزية ماديًا فالطلب يزداد بشكل كبير على المنتجات الرقمية وتتنوع مجالات استخداماتها لما تقدمه من فوائد على جميع الأصعدة مثل أتمتة المهام المختلفة وتحليل البيانات والحسابات الرياضية والتقنية المتقدمة وإدارة المتاجر الإلكترونية والأعمال وغير ذلك الكثير. فالبرمجة هي مهنة المستقبل بامتياز، وأيًا كانت مهنتك الأصلية ستجد البرمجة سبيلًا إليها، وهكذا ستجني فائدة مضاعفة بتعلمك إحدى لغات البرمجة. هل من الصعب تعلم لغة برمجة؟ الجواب لا إن كنت تمتلك الإرادة والمثابرة. تعلم البرمجة شبيه بركوب الدراجة ما أن تُصِرَّ على تعلمها ثم تتعلم كيف تستخدمها لن تنسى أبدًا كيف ستقودها وكذلك لن تنسى كيف تفكر برمجيًا. لكن إن أردت أن تصبح محترفًا، فهذا طريق طويل تعترضك فيه بعض الصعوبات. ما هي مجالات استخدام لغات البرمجة؟ من كتابة كلمة "مرحبًا" على شاشة حاسوبك إلى التحكم بمسبار فضائي يحط على كوكب آخر. فكل ما تعرضه لك الأجهزة الإلكترونية من بسيطها إلى أعقدها هي نتاج عملية برمجة لهذه الأجهزة. ويمكن تلخيص استخدامات لغات البرمجة وفق الخطوط العريضة التالية: تطوير تطبيقات للحواسب تطوير تطبيقات للويب تطوير تطبيقات للهواتف الذكية برمجة الآلات والتجهيزات القابلة للبرمجة تطوير وإدارة الخدمات السحابية تطوير أنظمة تشغيل تطوير أنظمة وآلات ذاتية التعلم مجالات الذكاء الاصطناعي والروبوتات أنشئ موقع إلكتروني لأعمالك بدون خبرة برمجية صمم موقع احترافي لأعمالك بالسحب والإفلات مع أكثر من 70 قالب جاهز وقابل للتخصيص ليناسب هويتك التجارية جرب سنديان الآن خاتمة تعرفنا في هذه المقال على لغات البرمجة التي نستخدمها في برمجة الحواسب والأجهزة الإلكترونية الذكية أو القابلة للبرمجة واستعرضنا الخطوط العامة لمكوّنات أي لغة برمجة ثم فصلنا في أنواعها وقلنا أنها قد تكون عامة الغرض أو مخصصة من ناحية الاستخدام أو لغات مكتوبة أو مرئية من ناحية إظهار الشيفرة وأنها مفسّرة أو مصرّفة من ناحية معالجة المعلومات. كما ذكرنا أن لغات البرمجة التي تقترب تعليماتها وظيفيًا من التعليمات التي يفهمها الحاسوب هي لغات منخفضة المستوى ويزداد مستواها باستخدامها تعليمات تنفذ وظائف أكبر من تعليمات الحاسوب الأساسية. ومررنا أخيرًا على مفهوم لغات السكربت واستخداماتها بشيء من التفصيل، وعلى مفهوم اللغات التوصيفية واختلافها عن لغات البرمجة. وبهذا الشكل نكون قد أحطنا ولو بالشيء اليسير بمفاهيم هذا العالم الواسع لتكون خطوتك الأولى في الإنطلاق إلى عالم البرمجة. اقرأ أيضًا المدخل الشامل لتعلم علوم الحاسوب كيف تتعلم البرمجة فوائد تعلم البرمجة دليلك إلى: لغات برمجة الألعاب المدخل الشامل لتعلم تطوير الويب وبرمجة المواقع المرجع الشامل إلى تعلم لغة بايثون البرمجة بلغة جافاسكربت مقارنة بين JavaScript و TypeScript مقارنة بين PHP و NodeJS1 نقطة
-
لقد أحدثت النماذج اللغوية الكبيرة LLMs وأشهرها روبوت المحادثة ChatGPT الذي طورته شركة OpenAI ثورة في الكثير من المجالات وأثبتت قدرتها على توليد نصوص تشبه النصوص البشرية، كما سهلت أداء العديد من المهام في مختلف المجالات ومن أبرزها مجال تطوير البرمجيات، فقد وفرت للمطورين والمبرمجين واجهات برمجية APIs تساعدهم في إنشاء تطبيقات ذكاء اصطناعي بسهولة كبيرة. سنتعلم في مقال اليوم كيفية تطوير تطبيق بايثون قادر على فهم نصوص ملف PDF والإجابة على أي أسئلة نطرحها حول محتوى هذا الملف بالاستفادة من ميزات نماذج الذكاء الاصطناعي التي توفرها واجهة برمجة تطبيقات OpenAI API وإطار عمل LangChain، وهو إطار عمل للغة البرمجة بايثون يمكن دمجه في تطبيقاتك لتعزز إمكانيات النماذج اللغوية الكبيرة. نظرة عامة على التطبيق المطلوب ومتطلباته نريد تطوير تطبيق بايثون باسم "اسأل PDF" يتيح هذا التطبيق للمستخدم تحميل ملف PDF من جهاز الحاسوب الخاص به، ويسمح له بطرح أي سؤال، ويستخدم تقنيات معالجة اللغة الطبيعية NLP للبحث عن إجابة مناسبة على هذا السؤال بناءً على محتوى الملف ويعرض له الإجابة. يحتاج تنفيذ التطبيق إلى المتطلبات التالية: معرفة بأساسيات لغة بايثون وتثبيت بيئة بايثون على الحاسوب المحلي. تثبيت أداة pip لتثبيت وإدارة حزم البرمجيات المساندة لبايثون. إنشاء حساب على على منصة OpenAI والحصول على مفتاح الواجهة البرمجية OpenAI API key خاص بك. معرفة بأساسيات نماذج وأطر عمل الذكاء الاصطناعي واختيار النماذج المناسبة لعمل التطبيق. معرفة بطريقة معالجة النصوص باستخدام التضمينات الرقمية ومخازن المتجهات. ما أهمية التضمينات الرقمية في تطبيقات البحث كي نتمكن من إنجاز عملية البحث في ملف pdf نحتاج لإنشاء تضمينات رقمية "Embedding" لكل جزء من أجزاء الملف، فبما أننا سنبحث في ملفات تتضمن الكثير من النصوص، فسنحتاج للاعتماد على تقنية التضمين وهي تقنية تستخدم في معالجة اللغة الطبيعية NLP وتقوم بتمثيل النصوص بشكل أعداد عشرية لتساعدنا على اكتشاف المعنى الدلالي للكلمات والعبارات والجمل بسرعة وفعالية، وتحولها لتنسيق يسهل الوصول إليه والبحث فيه عن المعلومات بدقة وكفاءة، بعدها سنقسم الملف إلى أجزاء صغيرة chunks حجم كل منها مثلًا 1000 حرف، ونفهرس هذه الأجزاء في قاعدة بيانات أو مخزن متجهات vectors حتى نتمكن من استرجاعها بسهولة عندما نريد الإجابة على الأسئلة الموجودة فيه. بهذه الطريقة ستملك النصوص ذات المحتوى المتشابه لغويًا متجهات متشابهة وبهذا يمكن مقارنة المتجهات والعثور على النصوص المتشابهة بسهولة وسرعة، وعندما نريد الحصول على إجابة لسؤال معين فسوف ننشئ كذلك تضمين رقمي لنص السؤال، ثم نقارن تضمين السؤال مع جميع المتجهات التي خزناها في مخزن المتجهات، ونختار الأكثر تشابهًا بناءً على حسابات رياضية على المتجهات، ثم نمرر تضمين السؤال مع التضمينات الأكثر تشابهًا معه إلى روبوت المحادثة ليولّد لنا الإجابة المناسبة بناءً على هذه المعطيات. خطوات التطبيق العملي لننشئ تطبيق واجهة رسومية GUI بلغة بايثون باستخدام المكتبة المدمجة Tkinter يمكننا من خلالها تحميل ملف PDF الذي نريده ثم نبدأ بمعالجة محتواه واستخراج كافة النصوص منه، فبعد تحميل الملف المطلوب سنحول نصوصه إلى تضمينات كما شرحنا سابقًا، ثم سنبدأ بعملية طرح سؤال متعلق بمحتوى الملف. سنحول السؤال كذلك لتضمين أو تمثيل رقمي ونبحث عن كافة المحتوى المشابه له وسنرسل بعد ذلك للواجهة البرمجية ChatGPT API سلسلة تتضمن السؤال وكل المحتوى المرتبط به الذي وجدناه ضمن الملف كمدخلات، ثم سنولّد بناءً على ذلك الإجابة المناسبة بالاستفادة من إمكانيات النماذج اللغوية الكبيرة LLMs. وإليك خطوات القيام بذلك بالتفصيل: خطوة 1: الحصول على مفتاح API الخاص بك من OpenAI للحصول على مفتاح API الخاص بك من OpenAI عليك اتباع الخطوات التالية: انتقل إلى الصفحة الرسمية لمنصة openai وأنشئ حسابًا جديدًا إذا لم تكن قد أنشأته من قبل ثم سجل الدخول لحسابك. انقر على القسم اAP للدخول لحسابك في صفحة مطوري OpenAI. انقر على أيقونة ChatGPT أعلى يمين الصفحة واختر البند API Keys. انقر على Create new secret key لإنشاء مفتاح API الخاص بك. أدخل اسمًا اختياريًا لمفتاح API للرجوع إليه لاحقًا. هذا كل ما يلزم لإنشاء مفتاح API الخاص بك من OpenAI. سيبدأ المفتاح بـ sk- انسخه واحفظه في مكان آمن واحرص على عدم مشاركته مع أحد أو كتابته في كود عام، فقد يقوم الآخرون باستخدام مفتاح API الخاص بك ويستهلكون رصيدك المتاح. ملاحظة: عليك الاشتراك بخطة مدفوعة للاستفادة من واجهة برمجة التطبيقات OpenAI API في تطبيقاتك، وسيكون المبلغ المقتطع بحسب الاستهلاك والنموذج المستخدم، فلكل نموذج تكلفة مختلفة وكلما زادت طلباتك أو عدد الرموز tokens المرسلة والمستقبلة من النموذج كلما زادت فاتورتك، لكن يمكنك في البداية الحصول على رصيد مجاني بقيمة 5 دولار عند الاشتراك حديثًا في المنصة للتجربة. خطوة 2: إنشاء ملفات تطبيق بايثون اسأل PDF للقيام بهذه الخطوة يجب أن تكون بيئة بايثون مثبتة على جهازك، ولإنشاء مشروع بايثون جديد، افتح سطر الأوامر (أو الطرفية) في نظام التشغيل وانتقل للمسار المطلوب، وأنشئ مجلدًا جديدًا للمشروع وليكن باسم askpdf، ثم أنشئ ضمنه ملفين الأول ask_pdf.py لإضافة كود الواجهة الرسومية للتطبيق، والثاني ملف .env لإضافة مفتاح الواجهة الرسومية OpenAI API Key اللازمة لعمل التطبيق من خلال كتابة التعليمات التالية تباعًا في سطر الأوامر: C:\Users\PC>d: D:\>md askpdf D:\>cd askpdf D:\askpdf>touch ask_pdf.py Touching ask_pdf.py D:\askpdf>touch .env Touching .env D:\askpdf> تثبيت المكتبات اللازمة لعمل التطبيق يحتاج التطبيق إلى تثبيت العديد من مكتبات ووحدات بايثون الخارجية باستخدام مدير الحزم pip وهي كالتالي: pip install python-dotenv PyPDF2 langchain langchain-openai langchain-community faiss-cpu إليك وصفًا موجزًا لكل مكتبة ولماذا استخدمناها في التطبيق: المكتبة python-dotenv لقراءة قيمة المفتاح الذي سأخزنه في الملف env. المكتبة PyPDF2 ضرورية للتعامل مع ملف PDF وقراءته محتوياته. إطار عمل LangChain ليسهل التعامل مع نموذج text-embedding-ada-002 لتقسيم النصوص، وإنشاء تضمينات وفهارس لها، كما أنه يدعم نموذج GPT-3.5 Turbo Instruct لتوليد إجابات على الأسئلة المطروحة. سنستدعي مكتبات langchain و langchain-openai و langchain-community من هذا الإطار وهي مكتبات مفيدة تتكامل مع نماذج OpenAI وتوسع إمكانياتها. وأخيرًا سنستخدم مكتبة Faiss وهي مكتبة بايثون يوفرها إطار LangChain تسرع عملية البحث عن التشابه في البيانات النصية دون الحاجة لاستهلاك الكثير من الموارد. كتابة الكود البرمجي للتطبيق الخطوة التالية هي إضافة الكود الخاص بالتطبيق، سأفتح الآن مجلد المشروع بمحرر الأكواد VSCode وأكتب بدايةً في ملف إعدادات التطبيق .env قيمة مفتاح الواجهة البرمجية على النحو الآتي: OPENAI_API_KEY= Your_KEY وعليك بالطبع استبدال Your_KEY في الكود السابق بالقيمة الفعلية لمفتاحك ليعمل التطبيق بشكل صحيح. الآن سننتقل للملف الأساسي للتطبيق ask_pdf.py ونستورد بدايةً كافة المكتبات والوظائف اللازمة لعمل التطبيق. ويوضح التعليق ضمن الكود دور كل منها على النحو الآتي: import os from dotenv import load_dotenv # مكتبات إنشاء الواجهة الرسومية import tkinter as tk from tkinter import filedialog, scrolledtext, ttk from tkinter import font from PIL import Image, ImageTk # قراءة ومعالجة ملفات PDF from PyPDF2 import PdfReader # الواجهة البرمجية OpenAI from langchain_openai import OpenAI from langchain_community.vectorstores import FAISS from langchain_community.callbacks import get_openai_callback from langchain.text_splitter import CharacterTextSplitter from langchain.chains.question_answering import load_qa_chain from langchain_openai import OpenAIEmbeddings بعدها سننشئ الصنف الأساسي للتطبيق باسم askpdfgui ونعرّف بداخله التابع __init__ لإضافة وتهيئة عناصر الواجهة الرسومية Widgets للتطبيق، ستتضمن الواجهة عناصر متعددة مثل حاويات العناوين Labels وشريط تقدم Progressbar وزِرَّين Buttons الأول لتحميل ملف PDF من الجهاز لذاكرة التطبيق ومعالجته، والثاني للبحث عن إجابة السؤال الذي يكتبه المستخدم ولا يكون هذا الزر مُفعّلًًا إلا بعد اكتمال تحميل ومعالجة الملف. class askpdfgui: def __init__(self, root): self.root = root self.root.title("اسأل PDF") self.root.geometry("800x700") custom_font = font.Font(family="Verdana", size=24, weight="bold") self.label = tk.Label(root, text="? PDF اسأل", font=custom_font) self.label.pack(pady=10) # عرض تقدم حالة تحميل الملف self.progress_label = ttk.Label(root, text="", foreground="green") self.progress_label.pack(pady=5) self.progress_bar = ttk.Progressbar(root, orient="horizontal") self.progress_bar.pack(pady=5) script_dir = os.path.dirname(os.path.abspath(__file__)) image_path = os.path.join(script_dir, "robopdf.png") image = Image.open(image_path) tk_image = ImageTk.PhotoImage(image) self.image_label = tk.Label(root, image=tk_image) self.image_label.image = tk_image self.image_label.pack(pady=10) # إضافة زر تحميل الملف self.upload_button = tk.Button( root, text="حمل ملفك هنا", command=self.upload_pdf ) self.upload_button.pack(pady=10) # حقل نصي لكتابة السؤال self.question_entry = tk.Entry(root, width=60, justify="center") self.question_entry.pack(pady=10) # زر طرح السؤال وإلغاء تفعيله لحين اكتمال معالجة الملف self.ask_button = tk.Button( root, text="اطرح السؤال", command=self.ask_question, state=tk.DISABLED ) self.ask_button.pack(pady=10) # عرض نتيجة السؤال self.result_text = tk.Text(root, wrap=tk.WORD, width=60, height=10) self.result_text.configure(font=("TkDefaultFont", 12)) self.result_text.pack(pady=10, anchor=tk.CENTER) سيكون شكل التطبيق على النحو التالي: الآن وبعد أن انتيهنا من تصميم واجهة التطبيق وتهيئة خصائص عناصر واجهة المستخدم سنبرمج وظائفه، بداية نحقق كود الدالة upload_pdf التي ستمكن المستخدم من فتح نافذة لتحميل ملف PDF الخاص به لداخل التطبيق كما يلي: def upload_pdf(self): file_path = filedialog.askopenfilename(filetypes=[("PDF Files", "*.pdf")]) if file_path: self.process_pdf(file_path) بعد أن يختار المستخدم ملف PDF يستدعى التابع process_pdf الذي يأخذ كوسيط مسار هذا الملف لبدء عملية المعالجة ويستخرج النصوص منه باستخدام الدالة extract_text، ويقسمه إلى أجزاء أو مقاطع أو نصوص بطول 1000 حرف مع تداخل بقيمة 200 حرف بين الأجزاء كي لا يفقد السياق، بمعنى سيكون الجزء الأول من البداية إلى الحرف 1000 أما الجزء الثاني فسيبدأ من الحرف 801 لضمان استمرارية المعنى وعدم فقدان معلومات مهمة بين النصوص المتجاورة. هناك عدة تقنيات مختلفة متاحة لتنفيذ مهمة التضمين والفهرسة في تطبيقنا، وقد اعتمدنا في هذا هذا التطبيق على الصنف OpenAIEmbeddings من مكتبة langchain_openai ومررنا قيمة مفتاح الواجهة البرمجية openai_api_key لباني الصنف لأنه سيستخدم هنا النموذج Embading الذي توفره هذه الواجهة لتكوين التضمينات الرقمية وإنشاء المتجهات الخاصة بها بالاستعانة بمكتبة FAISS على النحو التالي: def process_pdf(self, file_path): self.progress_label.config(text="انتظر اكتمال تحميل ملف PDF...") self.progress_bar.start() self.root.update_idletasks() pdf_reader = PdfReader(file_path) text = "" for page in pdf_reader.pages: text += page.extract_text() # تقسيم نص الملف إلى أجزاء text_splitter = CharacterTextSplitter( separator="\n", chunk_size=1000, chunk_overlap=200, length_function=len ) chunks = text_splitter.split_text(text) # إنشاء تضمينات النصوص embeddings = OpenAIEmbeddings(api_key=openai_api_key) knowledge_base = FAISS.from_texts(chunks, embeddings) self.docs = knowledge_base.similarity_search("") بالنسبة للسطر الأخير في الكود: self.docs = knowledge_base.similarity_search("") سينفذ هذا السطر عملية بحث عن التشابه ويجد أقرب الجمل لسؤالك الذي ستطرحه باستخدام قاعدة بيانات المتجهات knowledge_base ويخزن النتيجة في متغير docs فهذا المتغير يخزن معلومات حول النصوص المتشابهة ودرجة التشابه بين النص أو السؤال الذي تبحث عنه والنص المخزن في قاعدة البيانات، لكن هنا لم نكتب السؤال بعد لذا نخزن نتائج البحث باعتبار السؤال فارغ، لاحقًا عندما ستتم عملية البحث الفعلية سيحدد النصوص المشابهة بشكل أفضل ويحسن عملية البحث. إليك مثالًا بسيطًا لبنية هذا المتغير، إذا كان السؤال الذي كتبه المستخدم هو "ما فائدة تعلم الذكاء الاصطناعي في تحسين مهارات التطوير" فسوف يحتوي المتغير عندها على قائمة من النصوص التي حصل عليها من الملف مع درجة التشابه مع السؤال المطروح على نحو مشابه للبنية التالية: self.docs = [ {"text": "تعلم لغات البرمجة يساعد في تطوير مهارات البرمجة", "similarity_score": 0.85}, {"text": "تعلم الذكاء الاصطناعي يحسن من تجربة المستخدم", "similarity_score": 0.92}, # ... وهكذا تأخذ هذه العملية بعض الوقت لقراءة الملف بالكامل ومعالجته بالاعتماد على حجم الملف وبعد اكتمال تحميل الملف وتحويله لتضمينات وفهرسته بالشكل المطلوب، سيُفعّل زر طرح السؤال إذ يمكن للمستخدم الآن كتابة أي سؤال في الحقل النصي question_entry للإجابة عليه بناءً على المحتوى الذي أنشأه البرنامج. self.progress_label.config(text="اكتملت عملية التحميل يمكنك طرح السؤال الآن") self.progress_bar.stop() self.progress_bar["value"] = 100 # تمكين زر طرح السؤال self.ask_button["state"] = tk.NORMAL الخطوة التالية والأخيرة هي تعريف التابع ask_question وهو أهم تابع في تطبيقنا وسنستدعيه بعد كتابة السؤال والنقر على زر طرح السؤال، ليبدأ بالبحث عن إجابة مناسبة على السؤال من محتوى المتغير doc ويرسل الطلب لواجهة OpenAI لتقديم إجابة مناسبة. def ask_question(self): user_question = self.question_entry.get() if user_question: llm = OpenAI(model="gpt-3.5-turbo-instruct", api_key=openai_api_key, temperature=0.0) chain = load_qa_chain(llm, chain_type="stuff") with get_openai_callback(): response = chain.run(input_documents=self.docs, question=user_question) print(response) # عرض الإجابة على السؤال self.result_text.tag_configure("center", justify="center") # مسح أي نص قديم إن وجد self.result_text.delete("1.0", tk.END) self.result_text.insert(tk.END, response, "center") كما هو موضح في الكود أعلاه سيحصل التابع على نص السؤال الذي أدخله المستخدم في الحقل النصي question_entry ثم يخزنه في المتغير user_question ويمرر مدخلات المستخدم إلى النموذج gpt-3.5-turbo-instruct لتوليد الإجابة، وهنا نحتاج كذلك لإدخال قيمة المفتاح openai_api_key لإنشاء اتصال مع واجهة برمجة تطبيقات OpenAI ولتخصيص أي وسطاء نحتاجها لتخصيص إجابة النموذج وأهم هذه الوسطاء temperature الذي يحدد درجة دقة السؤال. ويفضل في حالة تطبيقنا أن تبقى قيمته صفر للحصول على إجابات منطقية وحتمية تلتزم بمحتوى الملف، وعدم ترك النموذج يبدع ويؤلف إجابات لا صلة لها بالسياق وسنوضح المزيد عنه لاحقًا عن تجربة تنفيذ التطبيق. بعدها نستدعي الدالة load_qa_chain التي تنشئ سلسلةً نصيةً من نوع stuff لترسلها كمطالبة إلى الواجهة البرمجية OpenAI التي تفهم بدورها الطلب الذي أرسلناه وتعيد لنا الإجابة المناسبة response. ملاحظة: يحدد نوع السلسلة chain_type طريقة تمرير المستندات إلى النموذج اللغوي الكبير LLM وهنا مررنا القيمة ليكون stuff التي ترسل جميع المستندات في طلب واحد للواجهة البرمجية وهي تناسب حالة التعامل مع مستند واحد أو عدة مستندات صغيرة الحجم وتتضمن نفس طبيعة المحتوى، وهناك طرق أخرى هي Map-reduce تفيد في حال التعامل مع مستندات كبيرة هي تلخص كل مستند على حدا ثم تجمع التلخيصات في ملخص نهائي. أخيرًا نكتب كود تشغيل التطبيق كبرنامج رئيسي من خلال تحميل بيانات مفتاح OpenAI API من ملف .env وفحص فيما إذا كان المفتاح قد تم تعيينه أم لا، والبدء بإنشاء واجهة المستخدم الرسومية وتشغيل التطبيق حتى يتم إغلاق النافذة. if __name__ == "__main__": load_dotenv() openai_api_key = os.getenv("OPENAI_API_KEY") if openai_api_key is None: print( "OpenAI API تأكد من تعيين قيمة مفتاح" ) else: root = tk.Tk() app = askpdfgui(root) root.mainloop() تجربة عمل التطبيق لننفذ الآن كود التطبيق ونختبر آلية عمله: انتقل لمسار وجود التطبيق واكتب الأمر python ask_pdf.py في سطر الأوامر أو الطرفية لتشغيله، ستظهر لك الواجهة الأولية ولتجربة التطبيق سأنقر على زر "حمل ملفك هنا" يمكن تحميل أي ملف pdf خاص بك في التطبيق، وفي حالتي سأختار ملف يتحدث عن لغات برمجة الذكاء الاصطناعي كما يلي: بعد اكتمال عملية التحميل سأطرح السؤال التالي: "ما هي لغات برمجة الذكاء الاصطناعي؟" وسأحصل على الإجابة كما هو موضح في الصورة التالية: كما يمكن طرح أي أسئلة أخرى حول الملف مثل اسم الكاتب أو تاريخ نشره وسيتمكن من الإجابة كما توضح الصورة أدناه: الآن لو طرحت سؤالًا لا علاقة له بمحتوى هذا الملف مثل "من اخترع المصباح الكهربائي" ستكون النتيجة كما يلي: تأثير الوسيط Temperature على دقة نتائج التطبيق يستخدم المعامل أو الوسيط temperature كما وضحت سابقًا للتحكم في دقة أو عشوائية النتائج التي تعيدها نماذج واجهة برمجة تطبيقات OpenAI وتتراوح قيمة هذا الوسيط بين 0 و 2، فعند ضبط درجة الدقة على قيم قريبة من الصفر ستحصل على نتائج واقعية وذات صلة بالطلب وحين تضبطه على قيم قريبة من 2 ستحصل على نتائج أكثر إبداعًا لكنها قد تكون غير دقيقة ولا صلة لها بالسؤال. لذا عليك تعديل قيمة هذا المعامل بما يتناسب مع طبيعة تطبيقك، وهل يحتاج للدقة كما في حال تطبيقنا الذي يبحث عن النتائج الموافقة للسؤال، أم يسمح فيه الإبداع والابتكار كتطبيقات تأليف القصص والروايات. سأجرب على سبيل المثال تغير درجة الحرارة في الكود السابق وجعلها مثلًا 1.5 وأحمّل الملف نفسه واطرح سؤال "من هو أديسون؟" مثلًا ستكون النتيجة غير منطقية كما يلي! أما عند إعادة ضبطه بالقيمة 0 فسيجيب التطبيق بأنه لا يملك معلومات عن أديسون وفق الملف الذي وفرته له. قيود على عدد الرموز Tokens في التطبيق يمكنك تجربة التطبيق على أي ملف pdf خاص بك، لكن تملك نماذج من OpenAI API حدًا أقصى لعدد الرموز Token Limits التي تمثل إجمالي طول المدخلات التي تستقبلها والنتائج التي تولدها وفي حالة النموذج gpt-3.5-turbo-instruct المستخدم في الكود فالعدد الأقصى هو 4096 رمزًا، وبالتالي قد تحصل على الخطأ التالي عند تحميل ملفات كبيرة وتجاوز إجمالي الرموز في دخل وخرج النموذج هذا العدد، ومن الإجراءات الممكنة لتجاوز هذه القيود، تحديد قيمة المعامل max_tokens للنموذج كي تحدد له طول الرد الذي سينتج وتمنعه من إنشاء محتوى طويل جدًا أو تقصير نص الطلب أو السؤال قدر المستطاع. كما تحدد بعض النماذج سرعة معالجة الرموز في الدقيقة الواحدة، فالحد الأقصى المسموح به للتضمينات في نموذج text-embedding-ada-002 هو 15000 رمز في الدقيقة، وبالتالي إذا استخدمت ملفات pdf كبيرة تتجاوز هذه الحدود فسوف تحصل على كذلك أخطاء في التنفيذ بسبب القيود التي تفرضها الواجهة البرمجية ولحلها عليك رفع خطة الاشتراك في الواجهة البرمجية. الخلاصة بهذا نكون قد وصلنا لنهاية مقالنا، الذي شرحنا فيه خطوات إنشاء تطبيق بايثون يستفيد من واجهة برمجة تطبيقات OpenAI لتحميل ملف PDF وطرح أسئلة حوله وتوليد إجابات عليها من محتوى الملف، وهناك بالطبع الكثير من الأفكار الأخرى التي يمكنك الاستفادة منها من النماذج اللغوية الكبيرة LLMs في تطوير تطبيقات متقدمة في مجال الذكاء الاصطناعي، أطلق العنان لإبداعك واستفد من قوة هذه النماذج وإمكانياتها الهائلة. اقرأ أيضًا تطوير تطبيق "وصفة" لاقتراح الوجبات باستخدام ChatGPT و DALL-E في PHP تطوير تطبيق "اختبرني" باستخدام ChatGPT ولغة جافاسكربت مع Node.js إعداد بيئة العمل للمشاريع مع بايثون اكتشاف دلالات الأخطاء في شيفرات لغة بايثون كود التطبيق ask_pdf.zip1 نقطة
-
إذا كنت من محبي لغة البرمجة بايثون وترغب في تعلمها واحترافها وتبحث عن اكواد مشاريع بايثون فهذا المقال سيوفر لك مجموعة متنوعة من مشاريع بايثون للمبتدئين الذين أنهوا تعلم أساسيات لغة بايثون ويرغبون في تعزيز معرفتهم بالتطبيق العملي والتدرب على طريقة التفكير في حل مشكلات برمجية مختلفة والاستفادة من الوحدات والمكتبات العديدة التي توفرها لغة بايثون المناسبة التي تساعد على حلها بسلاسة وسرعة. سنوفر لك الأكواد البرمجية لهذه المشاريع، لكن الأفضل قبل أن تطلع على أكواد المشاريع أن تفكر في طريقة حل كل مشروع منها وتبحث عن المكتبات المساعدة لحله وطريقة استخدامها، كما يفضل أن تقوم بكتابة كافة الأكواد بنفسك وتعمل على تحسينها وإضافة أفكار جديدة لها والتدرب على تصحيح أي أخطاء تظهر لك خلال التنفيذ، فهذا يساعدك على تحقيق الهدف من المقال بشكل أفضل. أهمية تنفيذ مشاريع بايثون للمبتدئين لاشك أن تطبيق مشاريع عملية خطوة ضرورية لأي مبرمج أنهى تعلم أساسيات لغة البرمجة وفهم أهم مبادئ البرمجة بشكل نظري، فبعد أن تنهي تعلم أساسيات لغة بايثون يمكنك البدء بتنفيذ أفكار مشاريع بسيطة تطبق من خلالها ما تعلمته من مفاهيم نظرية وتصقل مهاراتك البرمجية من خلال التعلم من الأخطاء التي تواجهها وتعمل على تصحيحها، فمهما قرأت من دروس وكتب وشاهدت من مقاطع فيديو فلن تتقن ما تتعلمه إذا لم تطبق ما تتعلمه على مشاريع فعلية. ستجد في الفقرات التالية عدة أفكار لمشاريع بايثون مختلفة بعضها غاية في البساطة وبعدها أصعب قليلًا كي تتعلم من خلالها تنفيذ بعض العمليات الرياضية ومعالجة النصوص والتعامل مع عناصر الواجهة الرسومية واستخراج بيانات الويب، وهذه المشاريع هي: مشروع آلة حاسبة بلغة بايثون. مشروع بايثون لطباعة سلسلة أعداد فيبوناتشي. مشروع التحقق من قوة كلمة المرور. مشروع حساب عدد الأحرف الصوتية والفراغات والكلمات في نص. مشروع حاسبة الزكاة. مشروع حل معادلة درجة ثانية ورسم خطها البياني. مشروع ساعة رقمية. مشروع استخراج بيانات من موقع ويب. سنتناول في فقراتنا التالية كل مشروع من مشاريع بايثون المذكورة في هذه القائمة ونشرح الهدف منه ونوضح ما هي مدخلاته ومخرجاته وأهم خطوات تنفيذه برمجيًا. مشروع آلة حاسبة بلغة بايثون يعد مشروع تنفيذ الآلة الحاسبة من خلال واجهة سطر الأوامر أحد مشاريع بايثون البسيطة التي يمكنك من خلالها تطبيق العديد من المفاهيم مثل تعريف المتغيرات وتخزين القيم فيها، والتعامل مع أنواع البيانات المختلفة في بايثون مثل الأرقام الصحيحة والأرقام العشرية، وكيفية طلب البيانات من المستخدم وقراءتها وتحويلها لقيم عددية، وتعريف دوال لتنفيذ العمليات الحسابية واستخدام العبارات الشرطية لاستدعاء وتنفيذ الدالة الحسابية الصحيحة بناءً على شروط معينة وهذه المفاهيم على بساطتها تمكنك من كتابة مشاريع بايثون أكثر تعقيدًا فيما بعد. الدخل: رمز العملية الحسابية المطلوب إجراؤها والعددان المطلوب تنفيذ العملية عليهما (يجب أن يدخل المستخدم رمز صحيح وإلا يمكن أن تعرض له رسالة تطلب منه إدخال رمز صحيح أو تنهي البرنامج) الخرج: هو طباعة نتيجة العملية الحسابية. كود مشروع آلة حاسبة باستخدام بايثون: # calculator1.py # دالة جمع عددين def add(num1, num2): return num1 + num2 # دالة طرح عددين def subtract(num1, num2): return num1 - num2 # دالة جداء عددين def multiplnum2(num1, num2): return num1 * num2 # دالة قسمة عددين def divide(num1, num2): if num2 == 0: return "لا يمكنك القسمة على صفر" return num1 / num2 # استدعاء الدالة المناسبة print("اختر العملية الحسابيةالمطلوبة ") print("للجمع اختر 1 ") print("للطرح اختر 2 ") print("للجداء اختر 3 ") print("للقسمة اختر 4 ") print("اختر أي مفتاح آخر لأنهاء التنفيذ") while True: # إدخال قيمة العددين choice = input("حدد العملية المطلوبة (1/2/3/4): ") if choice in ("1", "2", "3", "4"): num1 = float(input("Enter first number: ")) num2 = float(input("Enter second number: ")) if choice == "1": print(num1, "+", num2, "=", add(num1, num2)) elif choice == "2": print(num1, "-", num2, "=", subtract(num1, num2)) elif choice == "3": print(num1, "*", num2, "=", multiplnum2(num1, num2)) elif choice == "4": print(num1, "/", num2, "=", divide(num1, num2)) else: print("إنهاء التنفيذ ") break عند تنفيذ المشروع سنحصل على خرج مشابه لما هو مبين في الصورة التالية: يمكنك إجراء بعض التحسينات على الكود السابق كأن تنشئ مكتبة أو وحدة خاصة بك لتعريف الدوال الحسابية وليكن اسمها math_operations.py ثم تستوردها في ملف البرنامج الرئيسي لتفهم الغرض من مكتبات باثيون فعندما تستورد مكتبة بايثون ستتمكن من الوصول لكافة وظائفها العامة وهذا ينظم كود مشروعك ويسهل فهمه وصيانته. لاحظ الكود التالي عرفنا في البداية ملف باسم math_operations.py يمثل المكتبة ويتضمن تعريف كافة العمليات الحسابية. # math_operations.py # استيراد المكتبة import math_op # استدعاء الدالة المناسبة print("اختر العملية الحسابيةالمطلوبة ") print("للجمع اختر 1 ") print("للطرح اختر 2 ") print("للجداء اختر 3 ") print("للقسمة اختر 4 ") print("اختر أي مفتاح آخر لأنهاء التنفيذ") while True: # إدخال قيمة العددين choice = input("حدد العملية المطلوبة (1/2/3/4): ") if choice in ("1", "2", "3", "4"): num1 = float(input("أدخل العدد الأول ")) num2 = float(input("أدخل العدد الثاني ")) if choice == "1": print(num1, "+", num2, "=", math_op.add(num1, num2)) elif choice == "2": print(num1, "-", num2, "=", math_op.subtract(num1, num2)) elif choice == "3": print(num1, "*", num2, "=", math_op.multiplnum2(num1, num2)) elif choice == "4": print(num1, "/", num2, "=", math_op.divide(num1, num2)) else: print("إنهاء التنفيذ ") break ثم عرفنا ملف المشروع الأساسي calculator2.py الذي يستورد المكتبة ويستخدم وظائفها كما يلي: # calculator2.py # استيراد المكتبة import math_op # استدعاء الدالة المناسبة print("اختر العملية الحسابيةالمطلوبة ") print("للجمع اختر 1 ") print("للطرح اختر 2 ") print("للجداء اختر 3 ") print("للقسمة اختر 4 ") print("اختر أي مفتاح آخر لأنهاء التنفيذ") while True: # إدخال قيمة العددين choice = input("حدد العملية المطلوبة (1/2/3/4): ") if choice in ("1", "2", "3", "4"): num1 = float(input("أدخل العدد الأول ")) num2 = float(input("أدخل العدد الثاني ")) if choice == "1": print(num1, "+", num2, "=", math_op.add(num1, num2)) elif choice == "2": print(num1, "-", num2, "=", math_op.subtract(num1, num2)) elif choice == "3": print(num1, "*", num2, "=", math_op.multiplnum2(num1, num2)) elif choice == "4": print(num1, "/", num2, "=", math_op.divide(num1, num2)) else: print("إنهاء التنفيذ ") break لتنفيذ هذا المشروع بشكل صحيح يجب أن تحفظ كل من ملف المشروع الرئيسي calculator2.py وملف المكتبة التي عرفتها math_op.py في نفس المجلد. توصيات حول المشروع: جرب أن تضيف المزيد من التحسينات على هذا المشروع بأن تعرف دوال رياضية مثل دالة حساب رفع عدد لأس، أو حساب الجذر التربيعي لعدد ما، وجرب كذلك أن تحوله إلى مشروع واجهة رسومية بالاعتماد على مكتبات بايثون المناسبة. دورة تطوير التطبيقات باستخدام لغة Python احترف تطوير التطبيقات مع أكاديمية حسوب والتحق بسوق العمل فور انتهائك من الدورة اشترك الآن مشروع بايثون لطباعة سلسلة أعداد فيبوناتشي يعد مشروع طباعة سلسلة أعداد فيبوناتشي Fibonacci series على بساطته من مشاريع بايثون الكلاسيكية للمبتدئين فهي تعلمه كيف يفكر منطقيًا في الخطوات اللازمة لحساب وطباعة سلسلة أعداد فيبوناتشي وكتابة دالة برمجية مناسبة تحقق له المطلوب. سلسلة فيبوناتشي هي عبارة عن سلسلة من الأعداد تبدأ بالعددين 0 و 1 والأعداد التالية ناتجة عن مجموع العددين السابقين، أي تكون أرقام السلسلة على النحو التالي: F(0) = 0 F(1) = 1 F(2) = 0+1=1 F(3) = 1+1=2 F(3) = 2+1=3 F(n) = F(n-1) + F(n-2) (n > 1) وهذه السلسلة لها تطبيقات واسعة في الرياضيات وعلوم الحاسوب والهندسة وغيرها من المجالات. الدخل: عدد عناصر السلسلة المطلوب حسابها وليكن num. الخرج: طباعة عناصر السلسلة. هناك طريقتان يمكنك من خلالهما تنفيذ هذا البرنامج، الأولى باستخدام حلقات التكرار (Loops) في بايثون والثانية باستخدام مفهوم التعاود (Recursion)، سنكتب الكود البرمجي لمشروع بايثون يعرض سلسلة أعداد فيبوناتشي بطريقة التعاود كما يلي: #fibonacci-series.py # سلسلة أعداد فيبوناتشي def fibonacci(n): if n == 1 or n == 0: return n; else: return fibonacci(n-2) + fibonacci(n - 1) num = int(input("أدخل عددًا صحيحًا موجبًا ")) if num < 0: print("العدد الذي أدخلته سالب") i = 0 print("سلسلة أعداد فيبوناتشي \n: ") for i in range(0, num+1): print("F(", i, "):", fibonacci(i)) عند تنفيذ المشروع نحصل على الخرج التالي: جرب تنفيذ المشروع باستخدام إحدى الحلقات التكرارية في بايثون ونفذه على قيم دخل كبيرة وقارن سرعة الحل بين طريقة حلقات التكرار وطريقة التعاود واستنتج أيهما أسرع وأكثر كفاءة. مشروع التحقق من قوة كلمة المرور ستحتاج في الكثير من مشاريع بايثون لا سيما في مواقع وتطبيقات الويب التي تحتاج لتسجيل دخول المستخدمين إلى التحقق من قوة كلمة المرور التي يدخلها المستخدم لضمان أمانه وحماية حسابه من الاختراق، وفي هذا المشروع سنكتب الكود البرمجي اللازم لفحص كلمة مرور المستخدم وتحديد فيما إذا كانت كلمة المرور قوية أم ضعيفة بناءً على مجموعة من الشروط وهي كالتالي: يجب أن تحتوي كلمة المرور على حروف صغيرة (a-z). يجب أن تحتوي كلمة المرور على حروف كبيرة (A-Z). يجب أن تحتوي كلمة المرور على محارف خاصة (!@#$^%). يجب أن تحتوي كلمة المرور على أرقام (0-9). يجب أن لا يقل طول الكلمة عن 8 محارف ولا يزيد على 20 محرف إذا توفرت جميع هذه الشروط في كلمة المرور التي أدخلها المستخدم سنعتبرها كلمة مرور قوية وإذا لم تتوفر جميع الشروط سنعتبرها كلمة ضعيفة ونطلب منه إدخال كلمة أخرى. أسهل طريقة لتحقيق هذا المشروع هي باستخدام مفهوم التعابير النمطية في البرمجة regular expression والمعروفة اختصارًا باسم Regex، فمن خلالها يمكن تعريف نمط بحث للتحقق من قوة كلمة المرور بالشكل التالي: ^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*``#?&])[A-Za-z\d@$!#%*?&]{6,20}$ يفحص هذا التعبير النمطي قوة كلمة المرور حيث يبدأ بالرمز ^ الذي يعني أن الاختبار يجب أن يبدأ من بداية كلمة المرور وبعدها يليه (?=.*[a-z]) الذي يتحقق من وجود حرف صغير على الأقل في كلمة المرور ثم القسم (?=.*[A-Z]) الذي يتحقق من وجود حرف كبير على الأقل في كلمة المرور ثم (?=.*\d) الذي يتأكد من وجود رقم واحد على الأقل فيها والقسم (?=.*[@$!%*#?&]) للتأكد من وجود محرف خاص على الأقل في كلمة المرور والقسم [A-Za-z\d@$!#%*?&]{6,20} للتحقق من أن طول كلمة المرور بين 8 إلى 20 محرف وأنهينا التعبير النمطي بكتابة الرمز $ الذي يعني أن الاختبار يستمر حتى نهاية كلمة المرور. وللتحقق من مطابقة كلمة المرور لهذا النمط في مشروعنا سنعتمد على مكتبة بايثون المسماة re وهي مكتبة قياسية في بايثون تساعدك على تعريف التعابير النمطية والتحقق من مطابقة سلسلة ما لنمط معين. الدخل: كلمة المرور المطلوب فحصها. الخرج: طباعة رسالة تظهر فيما إذا كانت كلمة المرور قوية أم ضعيفة. مشروع بايثون للتحقق من قوة كلمة المرور: import re def is_strong_password(pwd): pattern = '^[a-z]+[A-Z]+[!@#$^%]+[0-9]+$' return bool(re.search(pattern, pwd)) while True: password = input("أدخل كلمة المرور: ") if is_strong_password(password): print("كلمة المرور قوية") break else: print("\nكلمة المرور ضعيفة، أدخل واحدة أخرى") عند تنفيذ الكود أعلاه سنحصل على خرج مشابه للصورة التالية: توصيات حول المشروع: قد تبدو كتابة التعابير النمطية صعبة قليلًا لكنها الطريقة المثلى لتنفيذ التحقق، فهي تختصر عليك الكثير من الوقت، جرب على سبيل المثال التحقق من قوة كلمة المرور وفق الشروط التي ذكرناها دون الاعتماد على التعابير النمطية ولاحظ كمية التعليمات الشرطية التي ستحتاجها لتنفيذ المشروع. وحاول فكرة تعديل المشروع لجعله يولد لك كلمة مرور قوية بشكل تلقائي بدل إنشائها يدويًا. مشروع حساب عدد الأحرف الصوتية والفراغات والكلمات في نص يحتاج أي مبتدئ إلى تنفيذ عدة مشاريع بايثون تعالج السلاسل النصية وتستخدم دوال النصوص المناسبة للحصول على النتائج المطلوبة، في هذا المشروع سنكتب كود بايثون يطلب من المستخدم إدخال نص معين باللغة الإنجليزية ونحسب عدد الأحرف الصوتية الواردة فيه وعدد فراغاته وعدد كلماته. بالنسبة للأحرف الصوتية فهي كما خمسة حروف a وe i و o و u ويجب أن تراعي وجود الأحرف الصغيرة والكبيرة أو يمكنك بشكل بديل تحويل النص المدخل من قبل المستخدم بالكامل إلى حروف صغيرة أو كبيرة لتسهيل عملية البحث. أما بالنسبة للفراغات فيمكن أن تتحقق من وجود فراغ في نص ما بسهولة باستخدام الدالة الجاهزة isspaceو ويمكن كذلك حساب عدد الكلمات بعدة طرق ومن أسهل هذه الطرق الاستعانة بالدالة split التي تقسم الجملة إلى كلمات باستخدام الفراغ كفاصل وتعيد قائمة List بكافة هذه الكلمات وبعدها نستخدم الدالة len التي تعيد لنا عدد عناصر هذه القائمة. الدخل: هو النص المطلوب البحث فيه الخرج: عدد الأحرف الصوتية والفراغات والكلمات في هذا النص. إليك كود بايثون لحساب الأحرف الصوتية والفراغات وعدد الكلمات في سلسلة نصية ويمكنك بالطبع تجربة طرق أخرى للحصول على النتائج المطلوبة. # حساب عدد الفراغات والكلمات والأحرف الصوتية في سلسلة نصية countv=0 countw=0 counts=0 input_sentence=input("أدخل النص هنا: ") # عدد الأحرف الصوتية والفراغات sentence=input_sentence.lower() vowles=["a","e","i","o","u"] for char in sentence: if char in vowles: countv=countv+1 if(char.isspace()): counts=counts+1 # عدد الكلمات countw = len(input_sentence.split()) # طباعة النتائج print(" عدد الأحرف الصوتية :", countv) print(" عدد الكلمات :", countw) print(" عدد الفراغات :", counts) عند تنفيذ البرنامج على السلسلة النصية "Learn PYTHON with Welcome to Hsoub Academy" نحصل على الخرج التالي: توصيات حول المشروع: فكر في طرق أخرى لاستخراج النتائج المطلوبة من سلسلة نصية، وحاول تحويل المشروع من مشروع سطر الأوامر إلى مشروع واجهة رسومية لسهولة الاستخدام. مشروع حاسبة الزكاة يعرض هذا المشروع واجهة رسومية لحساب زكاة المال حيث يطلب من المستخدم إدخال قيمة أمواله كي يحسب الزكاة المستحقة بناءً على القيمة المدخلة فإذا كانت قيمة المال الذي حال عليه الحول تفوق النصاب أي الحد الأدنى للثروة التي يجب عليها الزكاة وجل دفع زكاة مال تبلغ 2.5% من قيمة المال وإلا فلا يتوجب دفع الزكاة أي أن قيمة الزكاة تكون صفر، وقد افترضنا هنا أن قيمة النصاب هي 442 دولار بحسب هيئة الإغاثة الإسلامية العالمية. بالطبع قيمة النصاب المستخدمة هنا ليست ثابتة وهي تتغير بحسب سعر الذهب أو الفضة وحساب المبلغ الدقيق للزكاة يعتمد على العديد من العوامل التي يجب أخذها بالحسبان، لكن الهدف من مشروعنا البسيط هذا هي تعلم إنشاء مشاريع بايثون من خلال واجهة رسومية، وأسهل طريقة لبناء واجهة المستخدم الرسومية هو تعلم طريقة بناء واجهات مستخدم رسومية في بايثون باستخدام المكتبة Tkinter فهي مكتبة قياسية وسهلة الاستخدام وتتيح لك إنشاء نوافذ وأزرار وحقول إدخال وغيرها من عناصر واجهة المستخدم بسرعة ومرونة كبيرة. الدخل: قيمة المال المطلوب حساب زكاته، وفي حال أدخل المستخدم قيمة أموال غير صحيحة كأن يدخل نصًا بدلاً من رقم يجب أن تظهر له رسالة خطأ تطالبه بإدخال قيمة صحيحة. الخرج: عرض قيمة الزكاة المستحقة للمال إذا تجاوز النصاب. إليك مشروع بايثون لحساب مقدار زكاة المال: # مشروع بايثون لحساب زكاة المال from tkinter import * from tkinter import messagebox # إنشاء واجهة المستخدم window = Tk() window.geometry("600x350") window.resizable(0, 0) window.config(bg="lightblue") window.title("حاسبة زكاة المال") # نصاب الزكاة بالدولار nisab = 442 # إنشاء متغير لتخزين قيمة أموالك money = DoubleVar() # دالة حساب الزكاة def calculate_zakat(): try: money = float(money_entry.get()) zakat_amount = money * 0.025 if money > nisab else 0 result_label.config( text=f"قيمة الزكاة الواجبة عليك هي: {zakat_amount:.2f} دولار" ) except ValueError: messagebox.showerror("خطأ", "الرجاء إدخال قيمة صالحة.") Label( window, text="أدخل قيمة أموالك بالدولار", font="Tahoma 14", fg="gray", justify="right", ).place(x=200, y=20) money_entry = Entry(window, textvariable=money, font="tahomab 12") money_entry.place(x=200, y=70) # إنشاء زر الحساب calculate_button = Button( window, text="حساب الزكاة", font="tahoma 14 bold", bg="lightgreen", padx=2, command=calculate_zakat, justify="right", ) calculate_button.place(x=220, y=120) # إنشاء تسمية لعرض النتيجة result_label = Label( window, text="", font="tahoma 14 bold", bg="lightblue", justify="right" ) result_label.place(x=100, y=180) window.mainloop() عند تنفيذ الكود السابق سيظهر الخرج كما في الصورة التالية: توصيات حول المشروع: جرب أن تحسن مظهر الواجهة الرسومية للمشروع من خلال استخدام مكتبة أخرى غير tkinter لتصميم الواجهة الرسومية للمشروع فهناك مكتبات أكثر احترافية مثل مكتبة PyQt5 أو Kivy. دورة الذكاء الاصطناعي احترف برمجة الذكاء الاصطناعي AI وتحليل البيانات وتعلم كافة المعلومات التي تحتاجها لبناء نماذج ذكاء اصطناعي متخصصة. اشترك الآن مشروع ساعة رقمية يهدف هذا المشروع من مشاريع باثيون Python للمبتدئين إلى تعليم المبرمج المبتدئ لكيفية إنشاء تطبيق جهة رسومية يعرض لك التوقيت المحلي والتوقيت العالمي GMT بالاستفادة من مكتبات بايثون المساعدة كما وكيفية تحديث الواجهة الرسومية كل ثانية لتحديث الساعة وجعلها تظهر لنا الوقت الحالي بدقة. يمكن تحقيق المشروع المطلوب من خلال إنشاء واجهة رسومية بسيطو باستخدام المكتبة القياسية tkinter والمكتبة القياسية time للوصول إلى معلومات الوقت وتنسيقه بالشكل المناسب. الدخل: لا يحتاج المشروع للحصول على أي مدخلات من المستخدم الخرج: عرض الساعة بالتوقيت المحلي والعالمي وتنسيقها بالشكل المطلوب # مشروع بايثون لعرض التوقيت المحلي والعالمي # digital-clock.py # استيراد الوحدات المطلوبة from tkinter import * from time import strftime, gmtime,localtime # إنشاء نافذة رئيسية window = Tk() window.title("مشروع بايثون لعرض التوقيت المحلي والعالمي") window.configure(background="lavender") #إنشاء نافذة بأبعاد ثابتة window.geometry("510x250") window.resizable(False, False) # تعريف دالة تعيد لناالتوقيت المحلي والعالمي def get_time(): # توقيت GMT # %I نظام 12 ساعة # %M الدقائق # %S الثواني # %p تعرض AM / PM timeFormat1 = strftime("%I:%M:%S %p", gmtime()) clock_g.config(text="GMT: " + timeFormat1) # توقيت محلي بتنسيق 12 ساعة timeFormat2 = strftime("%I:%M:%S %p",localtime()) clock_l.config(text="LOC: " + timeFormat2) # جدولة تكرار استدعاء الدالة كل 1000 ميلي ثانية window.after(1000, get_time) clock_l = Label(window, font="Verdana 37 bold", pady=30, bg="lavender") clock_l.pack(side=TOP) clock_g = Label(window, font="Verdana 37 bold", pady=30, bg="pink") clock_g.pack(side=BOTTOM) # استدعاء دالة عرض الوقت get_time() # تشغيل النافذة الرئيسية mainloop() عند تنفيذ المشروع ستظهر لك الواجهة التالية التي تعرض الساعة بالتوقيت المحلي وبتوقيت غرينتش توصيات حول المشروع: جرب تطوير مشروع بايثون الحالي واعرض الوقت وكذلك التاريخ بتنسيقات مختلفة وجرب استخدام مكتبات بايثون أخرى للتعامل مع الوقت مثل الوحدة datetime وتعرف على الفرق بينها وبين الوحدة time. مشروع حل معادلة درجة ثانية ورسم خطها البياني في مشروع بايثون التالي سنقوم بإنشاء تطبيق واجهة مستخدم رسومية لحل معادلة رياضية من الدرجة الثانية أو ما يعرف بالمعادلة التربيعية بطريقة المميز delta ونرسم خطها البياني الذي يكون عادة على شكل قطع مكافئ، وسنستخدم كل من المكتبة Tkinter لبناء واجهة المستخدم الرسومية والمكتبة matplotlib لرسم الخط البياني. الدخل: معاملات المعادلة a و b و c الخرج: عرض حلول المعادلة x1 و x2 بحسب قيمة المميز ورسم خطها البياني. # quadratic-equation.py import tkinter as tk from tkinter import messagebox from matplotlib.figure import Figure from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg # تعريف دالة لحساب جذور المعادلة def solve_quadratic(a, b, c): try: a, b, c = float(a), float(b), float(c) delta = b**2 - 4 * a * c if delta > 0: x1 = (-b + delta**0.5) / (2 * a) x2 = (-b - delta**0.5) / (2 * a) x1_rounded = round(x1, 2) x2_rounded = round(x2, 2) return f"x1= {x1_rounded}, x2={x2_rounded}" elif delta == 0: x = -b / (2 * a) x_rounded = round(x, 2) return f"x= {x_rounded}" else: return "لا يوجد حلول حقيقة للمعادلة" except ValueError: return "أدخل قيم صحيحة للمعاملات" # تعريف دالة لرسم المعادلة def plot_quadratic(a, b, c): try: a, b, c = float(a), float(b), float(c) x = range(-10, 11) y = [a * x_val**2 + b * x_val + c for x_val in x] fig = Figure(figsize=(6, 4), dpi=100) ax = fig.add_subplot(111) ax.plot(x, y) canvas = FigureCanvasTkAgg(fig, master=window) canvas_widget = canvas.get_tk_widget() canvas_widget.grid(row=4, column=0, columnspan=3) except ValueError: messagebox.showerror("خطأ", "قيم خاطئة للمعاملات") def calculate(): a_val = a_entry.get() b_val = b_entry.get() c_val = c_entry.get() result = solve_quadratic(a_val, b_val, c_val) result_label.config(text=result) plot_quadratic(a_val, b_val, c_val) # إنشاء الواجهة الرسومية window = tk.Tk() window.title("حل معادلة درجة ثانية") window.geometry("800x600+100+50") a_label = tk.Label(window, text="a:", font=("tahoma", 12)) a_label.grid(row=0, column=0, padx=10, pady=10) a_entry = tk.Entry(window, font=("tahoma", 12)) a_entry.grid(row=0, column=1, padx=10, pady=10) b_label = tk.Label(window, text="b:", font=("tahoma", 12)) b_label.grid(row=1, column=0, padx=10, pady=10) b_entry = tk.Entry(window, font=("tahoma", 12)) b_entry.grid(row=1, column=1, padx=10, pady=10) c_label = tk.Label(window, text="c:", font=("tahoma", 12)) c_label.grid(row=2, column=0, padx=10, pady=10) c_entry = tk.Entry(window, font=("tahoma", 12)) c_entry.grid(row=2, column=1, padx=10, pady=10) calculate_button = tk.Button( window, text="Calculate", command=calculate, font=("tahoma", 12) ) calculate_button.grid(row=3, column=0, columnspan=2, padx=10, pady=10) result_label = tk.Label(window, text="", font=("tahoma", 14)) result_label.grid(row=3, column=2, padx=10, pady=10) plot_label = tk.Label(window, text="الرسم البياني", font=("tahoma", 14)) plot_label.grid(row=4, column=0, columnspan=3, padx=10, pady=10) window.mainloop() توضح الصورة التالية نتيجة تنفيذ المشروع لحل معادلة درجة ثانية ورسم خطها البياني توصيات حول المشروع: تأكد من تثبيت المكتبة matplotlib على نظامك قبل تنفيذ المشروع باستخدام التعليمة pip install matplotlib وجرب تطوير واجهة المشروع وتخصيص شكل الرسم البياني ليظهر أكثر احترافية ويظهر حلول المعادلة بيانيًا. مشروع استخراج بيانات من موقع ويب تعد مشاريع بايثون التي تقوم باستخراج البيانات من الويب Web Scraping من تطبيقات بايثون المفيدة والمطلوبة في سوق العمل فمن خلالها يمكنك جمع المعلومات المختلفة مثل أحدث الأخبار والمقالات، أو عناوين الكتب، أو المنشورات والتعليقات من مواقع التواصل، أو أسعار المنتجات من مواقع ويب بشكل تلقائي لسهولة تصفحها أو تنظيمها وتخزينها في ملفات قواعد بيانات ثم تحليلها ومقارنتها بدلاً من جلب هذه البيانات يدويًا من عدة أماكن. يمكنك بناء مشاريع بايثون Python لاستخراج بيانات الويب بسهولة بفضل ما توفره لغة بايثون من مكتبات مساعدة في هذا المجال مثل Beautiful Soup و Scrapy و Selenium لكن انتبه فبعض المواقع قد لا تسمح لك باستخراج البيانات منها وقد تحظر أي طلبات تقوم بها. لاستخراج البيانات من موقع ما عليك بداية تحديد البيانات التي تريد استخراجها كالنصوص أو الصور أو الروابط وفحص بنية HTML الخاصة بالموقع باستخدام أدوات مطور المتصفح لتحديد العناصر التي تحتاج إلى استهدافها بدقة بعدها سيكون عليك كتابة التعليمات البرمجية اللازمة لإجراء طلبات استرداد صفحات الويب المطلوبة من الموقع وتحليل محتوى HTML واستخراج البيانات التي تحتاجها والتعامل مع الحالات الخاصة التي قد لا تتمكن فيها من الحصول على البيانات المطلوبة، قد تحتاج بعد ذلك إلى تنسيق البيانات أو تخزينها أو تحليلها حسب الطلب. سنقوم بإنشاء مشروع بلغة بايثون يستخرج أحدث المقالات المنشورة في موقع ووردبريس بالعربية باستخدام المكتبة tkinter و BeautifulSoup وهي مكتبة بايثون مشهورة تستخدم لتحليل مستندات HTML وXML واستخراج بياناتها والمكتبة requests لتقديم طلب HTTP GET إلى عنوان URL لصفحة الويب التي تريد استخراج بياناتها. كود بايثون لاستخراج بيانات من موقع ويب: # مشروع استخلاص البيانات من موقع ووردبريس بالعربية import tkinter as tk from tkinter import ttk from tkinter import scrolledtext # لإضافة scrollbar للنتائج import requests from bs4 import BeautifulSoup # استخلاص عناوين المقالات المنشورة حديثًا def fetch_and_extract_labels(): url = url_entry.get() result_text.config(state=tk.NORMAL) result_text.delete(1.0, tk.END) result_text.config(state=tk.DISABLED) try: response = requests.get(url) response.raise_for_status() soup = BeautifulSoup(response.text, 'html.parser') labels = [link.get('aria-label') for link in soup.find_all('a', class_='p-flink')] result_text.config(state=tk.NORMAL) result_text.delete(1.0, tk.END) result_text.tag_configure("rtl", justify="right") for label in labels: result_text.insert(tk.END, f"{label}\n", "rtl") except requests.exceptions.RequestException as e: result_text.config(state=tk.NORMAL) result_text.delete(1.0, tk.END) result_text.insert(tk.END, "خطأ قي جلب البيانات-تحقق من العنوان") except Exception as e: result_text.config(state=tk.NORMAL) result_text.delete(1.0, tk.END) result_text.insert(tk.END, f"خطأ: {str(e)}") finally: result_text.config(state=tk.DISABLED) app = tk.Tk() app.title("استخلاص البيانات") button_style = ttk.Style() button_style.configure("TButton", font="tahoma", padding=5, background="#3498db") url_label = ttk.Label(app, text="عنوان الموقع", font="tahoma") url_label.pack(pady=5) default_url = "https://www.wpar.net/" url_entry = ttk.Entry(app, width=50 , font="tahoma") url_entry.insert(0, default_url) url_entry.pack(pady=5) scrape_button = ttk.Button(app, text="استخراج", style="TButton", command=fetch_and_extract_labels) scrape_button.pack(pady=10) result_text = scrolledtext.ScrolledText(app, wrap=tk.WORD, height=15, width=50,font="tahoma") result_text.pack(pady=5) result_text.config(state=tk.DISABLED) app.mainloop() عند تنفيذ المشروع والنقر على زر استخراج ستحصل على البيانات المطلوبة بالشكل التالي: توصيات حول المشروع: عليك تثبيت المكتبات المطلوبة من خلال التعليمة pip install module_name لتنفيذ الكود بشكل صحيح، كما يتوجب عليك التحقق باستمرار من الكود البرمجي الذي يستخلص البيانات من موقع معين لأن بعض المواقع قد تغير تصميمها، وبالتالي يتوجب عليك التأكد من أن الكود البرمجي الذي كتبته يجلب لك البيانات الصحيحة، وبعد تنفيذ هذا المشروع جرب جلب بيانات أخرى مثل صور المقالات أو روابطها أو اسم الكاتب واعرضها بالشكل المناسب. أفكار مشاريع بايثون أخرى للتدريب استعرضنا لك في الفقرات السابقة عدة مشاريع بايثون جاهزة للمبتدئين والتي يمكنك تجربتها كمبتدئ وهناك بالطبع الكثير من أفكار شاريع بايثون للتدريب يمكنك تطبيقها فمجالات وتطبيقات لغة بايثون كثيرة ومتنوعة وإذا كنت مهتمًا بأحد هذه المجالات فمن الأفضل أن تركز على تطوير مشاريع فيه. إليك قائمة ببعض الأفكار الأخرى لمشاريع عملية متنوعة تناسب المبتدئين يمكنك تنفيذها لغة البرمجة بايثون. مشروع يطلب من المستخدم إدخال تاريخ ميلاده ويحسب عمره بالأيام أو الأشهر أو السنوات. مشروع التحويل بين العملات. مشروع لعبة بسيطة مثل لعبة Tic-Tac-Toe أو لعبة مسابقات تطرح الأسئلة وتتحقق من الإجابات. مشروع توليد رمز QR للروابط. مشروع لتلخيص النصوص. مشروع فهرس أو قاموس بلغة بايثون. استخراج النص من مقطع فيديو. مشروع أتمتة مهام مثل مهمة التقاط الشاشة أو إرسال بريد إلكتروني. مشروع قواعد بيانات لحفظ أسماء جهات اتصالك وأرقامهم وعناوينهم. مشروع قائمة المهام. مشروع التحقق من صحة البريد الإلكتروني. مشروع استخراج أسماء وأسعار المنتجات من مواقع للتجارة الإلكترونية. مشاريع ذكاء اصطناعي بلغة البايثون مثل مشروع تصنيف الصور أو مشروع تصنيف رسائل البريد الإلكتروني. مشاريع بايثون للويب مثل تطبيق إدارة المهام To-do List أو صفحة ويب بسيطة تعرض أعمالك. قبل تنفيذ أي مشروع بايثون من هذه المشاريع حاول فهم المشكلة المطلوبة بشكل صحيح وتحديد المدخلات والمخرجات المطلوبة، وفكر في خوارزمية الحل الصحيحة التي تمكنك من معالجة المدخلات للحصول على النتائج الصحيحة، ثم ابحث عن وجود مكتبات مساعدة لتنفيذ المطلوب فلغة بايثون غنية بالمكتبات الجاهزة التي توفر عليك الوقت وتختصر كتابة الكثير من الأكواد. وفي حال رغبت بتنفيذ مشاريع بلغة بايثون أكثر تقدمًا واحترافية تساعدك على فهم لغة باثيون Python بعمق والتعرف على متطلبات سوق العمل أنصحك بمطالعة دورة تطوير التطبيقات باستخدام لغة Python التي توفرها أكاديمية حسوب فهي دورة متكاملة تمنحك الفرصة لبدء تعلم بايثون من الصفر وتطبيق العديد من مشاريع بايثون العملية المتكاملة التي تعزز معرض أعمالك وتساعدك في العثور على فرصة عمل مناسبة، كما توفر لك متابعة دورية مع مدربين أكفاء يجيبونك في حال وجود أي تساؤل أو استفسار بخصوص ما تطبقه وتتعلمه. الخلاصة اقترحنا في هذه المقالة لك العديد من الأفكار المتنوعة حول مشاريع بايثون يمكنك تنفيذها وتطويرها، ستساعدك هذه المشاريع على التمكن من أساسيات لغة بايثون وفهمها بشكل أفضل، وممارسة كتابة الأكواد وتصحيح الأخطاء. وتذكر دومًا أن الممارسة والتطبيق العملي هي المفتاح لتحسن مستواك في البرمجة وبمجرد الانتهاء من هذه المشاريع البسيطة يمكنك تجربة أفكار مشاريع أكثر تقدمًا. هل لديك أفكار مشاريع بايثون أخرى تود أن تقترحها أو تناقشها معنا وتجد أنها تناسب المبرمجين المبتدئين، نرحب بأي فكرة مشروع بايثون تكتبها في قسم التعليقات أسفل المقال. اقرأ أيضًا تعلم كتابة أكواد بايثون من خلال الأمثلة العملية مقدمة إلى دوال التعامل مع السلاسل النصية في بايثون 3 المرجع الشامل إلى تعلم لغة بايثون كتابة دوال فعالة في بايثون بناء لعبة نرد بسيطة بلغة بايثون1 نقطة
-
بدأنا في مقال الجزء الأول ببناء مشروع عملي بلغة رست وهو عبارة عن خادم ويب متعدد مهام المعالجة، إذ بنينا الخادم الأساسي وكان أحادي خيط المعالجة، وعملنا في مقال الجزء الثاني على تحويله إلى خادم متعدد خيوط المعالجة، وسننهي في هذا المقال بناء الخادم ليصبح جاهزًا، فإذا لم تكن قرأت المقالات السابقة، فارجع لها قبل قراءة هذا المقال. الإغلاق الرشيق وتحرير الذاكرة تستجيب الشيفرة 20 للطلبات بصورةٍ غير متزامنة عبر استخدام مجمع خيط كما نريد، إذ نحصل على بعض التحذيرات من حقول workers و id و thread التي لن نستخدمها مباشرةً وتذكرنا أننا لم نحرر أي شيء من الذاكرة. عندما نستخدم الحل البدائي الذي هو استخدام مفتاحي "ctrl-c" لإيقاف الخيط الرئيسي، تتوقف الخيوط مباشرةً حتى لو كانوا يخدّمون طلبًا. سننفّذ سمة Drop لاستدعاء join على كل خيط في المجمع لكي ننهي الطلبات التي تعمل قبل الإغلاق، ثم سننفّذ طريقةً لإخبار الخيوط ألا تقبل طلبات جديدة قبل الإغلاق. لرؤية عمل هذا الكود سنعدّل الخادم ليقبل طلبين فقط قبل أن يغلق مجمع الخيط thread pool. تنفيذ سمة Drop على مجمع خيط لنبدأ بتنفيذ Drop على مجمع الخيط الخاص بنا. عندما يُسقط المجمع يجب أن تجتمع كل الخيوط للتأكد من أن عملهم قد انتهى. تظهر الشيفرة 22 المحاولة الأولى لتطبيق Drop، إذ لن تعمل الشيفرة حاليًا. اسم الملف: src/lib.rs impl Drop for ThreadPool { fn drop(&mut self) { for worker in &mut self.workers { println!("Shutting down worker {}", worker.id); worker.thread.join().unwrap(); } } } [الشيفرة 22: ضم كل خيط عندما يخرج المجمع خارج النطاق] أولًا، نمرّ على كل workers في مجمع الخيط، واستُخدمت &mut هنا لأن self هو مرجع متغيّر، ونريد أيضًا تغيير worker. نطبع لكل عامل رسالةً تقول أن هذا العامل سيُغلق، ثم نستدعي join على خيط العمال. إذا فشل استدعاء join نستخدم unwrap لجعل رست تهلع وتذهب إلى إغلاق غير رشيق. سنحصل على هذا الخطأ عند تصريف هذه الشيفرة: $ cargo check Checking hello v0.1.0 (file:///projects/hello) error[E0507]: cannot move out of `worker.thread` which is behind a mutable reference --> src/lib.rs:52:13 | 52 | worker.thread.join().unwrap(); | ^^^^^^^^^^^^^ ------ `worker.thread` moved due to this method call | | | move occurs because `worker.thread` has type `JoinHandle<()>`, which does not implement the `Copy` trait | note: this function takes ownership of the receiver `self`, which moves `worker.thread` --> /rustc/d5a82bbd26e1ad8b7401f6a718a9c57c96905483/library/std/src/thread/mod.rs:1581:17 For more information about this error, try `rustc --explain E0507`. error: could not compile `hello` due to previous error يوضّح الخطأ أننا لا يمكن أن نستدعي join لأنه لدينا استعارة متغيرة على كل worker وتأخذ join ملكية وسطائها، ولمعالجة هذه المشكلة نحن بحاجة لنقل الخيط خارج نسخة Worker التي تملك thread حتى تستطيع join استهلاك الخيط، وقد فعلنا ذلك في الشيفرة 15 من المقال تنفيذ نمط تصميمي Design Pattern كائني التوجه Object-Oriented في لغة رست. إذا احتفظ Worker بـ Option<thread::JoinHandle<()>>، يمكننا استدعاء تابع take على Option لنقل القيمة خارج المتغاير Some وإبقاء المتغاير None في مكانه، بمعنى آخر سيحتوي Worker عامل على متغاير Some في Thread الخاص به وعندما نريد تحرير ذاكرة Worker نستبدل Some بالقيمة None حتى لا يوجد لدى Worker أي خيط لينفذه. لذا نحن نعرف أننا نريد تحديث تعريف Worker على النحو التالي. اسم الملف: src/lib.rs struct Worker { id: usize, thread: Option<thread::JoinHandle<()>>, } الآن لنتابع المصرّف لنجد أية أماكن أُخرى تحتاج تغيير، وبالتحقق من الشيفرة نجد خطأين: $ cargo check Checking hello v0.1.0 (file:///projects/hello) error[E0599]: no method named `join` found for enum `Option` in the current scope --> src/lib.rs:52:27 | 52 | worker.thread.join().unwrap(); | ^^^^ method not found in `Option<JoinHandle<()>>` | note: the method `join` exists on the type `JoinHandle<()>` --> /rustc/d5a82bbd26e1ad8b7401f6a718a9c57c96905483/library/std/src/thread/mod.rs:1581:5 help: consider using `Option::expect` to unwrap the `JoinHandle<()>` value, panicking if the value is an `Option::None` | 52 | worker.thread.expect("REASON").join().unwrap(); | +++++++++++++++++ error[E0308]: mismatched types --> src/lib.rs:72:22 | 72 | Worker { id, thread } | ^^^^^^ expected enum `Option`, found struct `JoinHandle` | = note: expected enum `Option<JoinHandle<()>>` found struct `JoinHandle<_>` help: try wrapping the expression in `Some` | 72 | Worker { id, thread: Some(thread) } | +++++++++++++ + Some errors have detailed explanations: E0308, E0599. For more information about an error, try `rustc --explain E0308`. error: could not compile `hello` due to 2 previous errors لنعالج الخطأ الثاني الذي يشير إلى الشيفرة في نهاية Worker::new، إذ نريد تغليف قيمة thread في Some عندما ننشئ Worker جديد. أجرِ الخطوات التالية لتصحيح هذا الخطأ: اسم الملف: src/lib.rs impl Worker { fn new(id: usize, receiver: Arc<Mutex<mpsc::Receiver<Job>>>) -> Worker { // --snip-- Worker { id, thread: Some(thread), } } } الخطأ الأول هو في تنفيذ Drop، وذكرنا سابقًا أننا أردنا استدعاء take على قيمة Option لنقل thread خارج worker. أجرِ التغييرات التالية لتصحيح هذا الخطأ: اسم الملف: src/lib.rs impl Drop for ThreadPool { fn drop(&mut self) { for worker in &mut self.workers { println!("Shutting down worker {}", worker.id); if let Some(thread) = worker.thread.take() { thread.join().unwrap(); } } } } كما تحدثنا سابقًا في المقال البرمجة كائنية التوجه OOP في لغة رست، يأخذ التابع take على Option المتغاير Some خارجًا ويبقي None بدلًا عنه. استخدمنا if let لتفكيك Some والحصول على الخيط، ثم استدعينا join على الخيط. إذا كان خيط العامل هو أساسًا None نعرف أن العامل قد حرًر ذاكرته ولا يحصل شيء في هذه الحالة. الإشارة للخيط ليتوقف عن الاستماع إلى الوظائف تُصرّف الشيفرة بدون تحذيرات بعد كل التغييرات التي أجريناها، ولكن الخبر السيء أنها لا تعمل كما أردنا. النقطة المهمة هي في منطق المغلفات المنفذة بواسطة خيوط نسخ Worker، إذ نستدعي حتى اللحظة join لكن لا تُغلق الخيوط لأننها تعمل في loop للأبد بحثًا عن وظائف. إذا أسقطنا Threadpool بتنفيذنا الحالي للسمة drop، سيُمنع الخيط الأساسي للأبد بانتظار الخيط الأول حتى ينتهي، ولحل هذه المشكلة نحتاج لتغيير تنفيذ drop في ThreadPool، ثم إجراء تغيير في حلقة Worker. أولًا، سنغير تنفيذ drop في ThreadPool ليسقِط صراحةً sender قبل انتظار الخيوط لتنتهي. تظهر الشيفرة 23 التغييرات في ThreadPool لتسقط صراحةً sender. استخدمنا نفس تقنياتOption و take كما فعلنا مع الخيط لكي يستطيع نقل sender خارج ThreadPool. اسم الملف: src/lib.rs: pub struct ThreadPool { workers: Vec<Worker>, sender: Option<mpsc::Sender<Job>>, } // --snip-- impl ThreadPool { pub fn new(size: usize) -> ThreadPool { // --snip-- ThreadPool { workers, sender: Some(sender), } } pub fn execute<F>(&self, f: F) where F: FnOnce() + Send + 'static, { let job = Box::new(f); self.sender.as_ref().unwrap().send(job).unwrap(); } } impl Drop for ThreadPool { fn drop(&mut self) { drop(self.sender.take()); for worker in &mut self.workers { println!("Shutting down worker {}", worker.id); if let Some(thread) = worker.thread.take() { thread.join().unwrap(); } } } } [الشيفرة 23: إسقاط sender صراحةً قبل جمع الخيوط الفعالة] يغلق إسقاط sender القناة، وهذا يشير بدوره إلى عدم إرسال أي رسائل إضافية، وعندما نفعل ذلك تعيد كل الاستدعاءات إلى recv التي تجريها الخيوط الفعالة في الحلقة اللانهائية خطأً. نغير حلقة Worker في الشيفرة 24 لتخرج من الحلقة برشاقة في تلك الحالة، يعني أن الخيوط ستنتهي عندما يستدعي join عليهم في تنفيذ drop في ThreadPool. اسم الملف: src/lib.rs impl Worker { fn new(id: usize, receiver: Arc<Mutex<mpsc::Receiver<Job>>>) -> Worker { let thread = thread::spawn(move || loop { let message = receiver.lock().unwrap().recv(); match message { Ok(job) => { println!("Worker {id} got a job; executing."); job(); } Err(_) => { println!("Worker {id} disconnected; shutting down."); break; } } }); Worker { id, thread: Some(thread), } } } [الشيفرة 24: الخروج صراحةً من الحلقة عندما تعيد recv خطأ] لرؤية عمل هذه الشيفرة: سنعدل main لتقبل فقط طلبين قبل أن تُغلق الخادم برشاقة كما تظهر الشيفرة 25. اسم الملف: src/main.rs fn main() { let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); let pool = ThreadPool::new(4); for stream in listener.incoming().take(2) { let stream = stream.unwrap(); pool.execute(|| { handle_connection(stream); }); } println!("Shutting down."); } [الشيفرة 25: إغلاق الخادم بعد خدمة طلبين عن طريق الخروج من الحلقة] لا نريد أن يتوقف خادم حقيقي بعد خدمة طلبين فقط، وتبين هذه الشيفرة أن الإغلاق الرشيق وتحرير الذاكرة يعملان بصورةٍ نظامية. تُعرّف دالة take في سمة Iterator وتحدد التكرار إلى أول عنصرين بالحد الأقصى. سيخرج ThreadPool خارج النطاق في نهاية main وستُطبَّق سمة drop. شغّل الخادم باستخدام cargo run وأرسل ثلاثة طلبات. سيعطي الطلب الثالث خطأ وسترى الخرج في الطرفية على النحو التالي: $ cargo run Compiling hello v0.1.0 (file:///projects/hello) Finished dev [unoptimized + debuginfo] target(s) in 1.0s Running `target/debug/hello` Worker 0 got a job; executing. Shutting down. Shutting down worker 0 Worker 3 got a job; executing. Worker 1 disconnected; shutting down. Worker 2 disconnected; shutting down. Worker 3 disconnected; shutting down. Worker 0 disconnected; shutting down. Shutting down worker 1 Shutting down worker 2 Shutting down worker 3 يمكن أن ترى ترتيبًا مختلفًا للخيوط الفعالة والرسائل المطبوعة. تعمل الشيفرة وفقًا لهذه الرسائل كما يلي: أخذ العاملان 0 و 3 الطلبين الأولين وتوقف الخادم عن قبول الاتصالات بعد ثاني اتصال، وبدأ تنفيذ Drop في العمل على ThreadPool قبل أخذ العامل 3 وظيفته. يفصل إسقاط sender كل العمال ويخبرهم أن يُغلقوا، ويطبع كل عامل رسالةً عندما يُغلقوا ويستدعي مجمع الخيط join لانتظار كل خيط عامل لينتهي. لاحظ ميّزة مهمة في هذا التنفيذ، إذ قام ThreadPool بإسقاط sender وجرّبنا ضم العامل 0 قبل أن يستقبل أي عامل خطأ. لم يتلق العامل 0 أي خطأ من recv بعد، لذا تنتظر كتلة الخيط الأساسية أن ينتهي العامل 0. في تلك الأثناء استقبل العامل 3 وظيفة ثم استقبلت كل الخيوط خطأ. ينتظر الخيط الأساسي باقي العمال لينتهوا عندما ينتهي العامل 0. وبحلول هذه النقطة يخرج كل عامل من حلقته ويتوقف. تهانينا، فقد أنهينا المشروع ولدينا الآن خادم ويب بسيط يستخدم مجمع خيط للاستجابة بصورةٍ غير متزامنة، ونستطيع إجراء إغلاق رشيق للخادم الذي يحرر من الذاكرة كل الخيوط في المجمع. هذه هي الشيفرة الكاملة بمثابة مرجع. اسم الملف: src/main.rs use hello::ThreadPool; use std::fs; use std::io::prelude::*; use std::net::TcpListener; use std::net::TcpStream; use std::thread; use std::time::Duration; fn main() { let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); let pool = ThreadPool::new(4); for stream in listener.incoming().take(2) { let stream = stream.unwrap(); pool.execute(|| { handle_connection(stream); }); } println!("Shutting down."); } fn handle_connection(mut stream: TcpStream) { let mut buffer = [0; 1024]; stream.read(&mut buffer).unwrap(); let get = b"GET / HTTP/1.1\r\n"; let sleep = b"GET /sleep HTTP/1.1\r\n"; let (status_line, filename) = if buffer.starts_with(get) { ("HTTP/1.1 200 OK", "hello.html") } else if buffer.starts_with(sleep) { thread::sleep(Duration::from_secs(5)); ("HTTP/1.1 200 OK", "hello.html") } else { ("HTTP/1.1 404 NOT FOUND", "404.html") }; let contents = fs::read_to_string(filename).unwrap(); let response = format!( "{}\r\nContent-Length: {}\r\n\r\n{}", status_line, contents.len(), contents ); stream.write_all(response.as_bytes()).unwrap(); stream.flush().unwrap(); } اسم الملف: src/lib.rs use std::{ sync::{mpsc, Arc, Mutex}, thread, }; pub struct ThreadPool { workers: Vec<Worker>, sender: Option<mpsc::Sender<Job>>, } type Job = Box<dyn FnOnce() + Send + 'static>; impl ThreadPool { /// Create a new ThreadPool. /// /// The size is the number of threads in the pool. /// /// # Panics /// /// The `new` function will panic if the size is zero. pub fn new(size: usize) -> ThreadPool { assert!(size > 0); let (sender, receiver) = mpsc::channel(); let receiver = Arc::new(Mutex::new(receiver)); let mut workers = Vec::with_capacity(size); for id in 0..size { workers.push(Worker::new(id, Arc::clone(&receiver))); } ThreadPool { workers, sender: Some(sender), } } pub fn execute<F>(&self, f: F) where F: FnOnce() + Send + 'static, { let job = Box::new(f); self.sender.as_ref().unwrap().send(job).unwrap(); } } impl Drop for ThreadPool { fn drop(&mut self) { drop(self.sender.take()); for worker in &mut self.workers { println!("Shutting down worker {}", worker.id); if let Some(thread) = worker.thread.take() { thread.join().unwrap(); } } } } struct Worker { id: usize, thread: Option<thread::JoinHandle<()>>, } impl Worker { fn new(id: usize, receiver: Arc<Mutex<mpsc::Receiver<Job>>>) -> Worker { let thread = thread::spawn(move || loop { let message = receiver.lock().unwrap().recv(); match message { Ok(job) => { println!("Worker {id} got a job; executing."); job(); } Err(_) => { println!("Worker {id} disconnected; shutting down."); break; } } }); Worker { id, thread: Some(thread), } } } يمكننا إجراء المزيد إذا أردنا تحسين المشروع، وإليك بعض الأفكار: أضِف المزيد من التوثيق إلى ThreadPool وتوابعه العامة. أضِف بعض الاختبارات لوظيفة المكتبة. غيّر الاستدعاءات من unwrap إلى معالجة خطأ أكثر متانة. استخدم ThreadPool لتنفيذ أعمال غير خدمة طلبات الويب. ابحث عن وحدة مجمع خيط مصرفة على creats.io ونفذ خادم ويب باستخدام الوحدة المصرفة، ثم قارن واجهة برمجة التطبيقات API والمتانة بينها وبين مجمع الخيط الذي نفذناه. خاتمة عظيم جدًا! فقد وصلنا إلى نهاية سلسلة البرمجة بلغة رست . نريد أن نشكرك لانضمامك إلينا في هذه الجولة في رست. أنت الآن جاهز لتنفيذ مشاريع رست ومساعدة الآخرين في مشاريعهم. تذكر أنه هناك مجتمع مرحب من مستخدمي رست الذين يحبون المساعدة في أي صعوبة يمكن أن تواجهها في استعمالك رست. ترجمة -وبتصرف- لقسم من الفصل Final Project: Building a Multithreaded Web Server من كتاب The Rust Programming Language. اقرأ أيضًا المقال السابق: بناء خادم ويب متعدد مهام المعالجة بلغة رست - الجزء الثاني تزامن الحالة المشتركة Shared-State Concurrency في لغة رست وتوسيع التزامن مع Send و Sync مقدمة إلى الخيوط Threads في جافا1 نقطة
-
نسلط الضوء في مقال اليوم على مستقبل البرمجة أحد أكثر المجالات تغيرًا وتجددًا، فالتقنيات والتخصصات البرمجية المختلفة تتطور بوتيرة هائلة وسريعة جدًا ما يحتم على أي مبرمج أو مطور أن يواكب هذه التغييرات ويكون على دراية بأهم الاتجاهات التي يتوقع أن تشهدها البرمجة في السنوات القادمة وتأثيرها على سوق العمل والوظائف المستقبلية. الذكاء الاصطناعي ومستقبل البرمجة لعل أول تساؤل يخطر ببال أي مبرمج بشأن مستقبل البرمجة هل ستحل الروبوتات والذكاء الاصطناعي محل المبرمجين في المستقبل، والجواب هو أن الذكاء الاصطناعي سوف يساعد المبرمجين بدلًا من استبدالهم كما أن تقنيات الذكاء الاصطناعي ستتطور بشكل أكبر ويساعد البشر على القيام بمهامهم المختلفة والحصول على النتائج التي يريدونها حول أي موضوع بشكل أفضل وأسرع. وكما تعرف فقد بدأ الذكاء الصناعي بالفعل في الآونة الأخيرة يؤثر بشكل مباشر على مختلف جوانب حياتنا، ويتوقع أن يزداد تأثيره في المستقبل أكثر وأكثر نتيجة لتطوير البنية التحتية التي يعتمد عليها وتطوير معيار اتصال الواي فاي wifi7 فائقة السرعة والتي تصل لغاية 36 جيجا بت في الثانية بعرض نطاق ترددي يصل إلى 320 ميجاهرتز وانتشار شبكات اتصالات الجوال من الجيل الخامس 5G والبدء بشبكات الجيل السادس 6g التي ستكون أسرع 1000 مرة من شبكة 5G. سيحسن هذا التطور في البنية التحتية من سرعة نقل البيانات ويقلل زمن وصولها ويعطي المبرمجين المتخصصين في الذكاء الاصطناعي وتعلم الآلة القدرة على تحليل ومعالجة هذه البيانات بكفاءة عالية، كما سيزيد من قدرتهم على تطوير حلول إنترنت الأشياء IoT عالية الكفاءة وتطوير تطبيقات متقدمة لم تكن متاحة مع الشبكات السابقة، وسيزيد الطلب أيضًا على برمجة أجهزة ذكية قادرة على اتخاذ القرارات مثل السيارات ذاتية القيادة وروبوتات المحادثة والمساعدين الافتراضيين والروبوتات الصناعية التي ستعمل جنبًا إلى جنب معنا نحن البشر أو ربما تؤدي مهامنا وتستغني عن وجودنا بالكامل لكن في مهن وتخصصات محدودة. كما سيلعب الذكاء الصناعي وتعلم الآلة دورًا أساسيًا في مستقبل البرمجة وكتابة الكود وسيزداد التوجه إلى الإصدار الثاني من البرمجيات Software 2.0 وهي البرمجيات التي تستخدم خوارزميات تعلم الآلة ML والشبكات العصبية لتؤدي عملها دون تدخل بشري ولا بد أنك سمعت أو استخدمت بوت المحادثة الذكي ChatGPT من Open AI وأداة OpenAI Codex الأكثر تخصصًا والتي تساعدك على إنتاج الأكواد البرمجية وتدعم العديد من لغات البرمجة فهما مثالان على برمجيات تعتمد على الذكاء الاصطناعي والتي من شأنها مساعدة المطورين والمبرمجين في تحسين عملهم وزيادة إنتاجيتهم ليركزوا على الأمور الأكثر أهمية في عملية التطوير. فإذا كنت مهتمًا بهذا المجال من الضروري أن تحرص على تعلم لغات البرمجة الخاصة بالذكاء الاصطناعي وتعلم الآلة ولعل أهمها لغة البرمجة بايثون Python التي توفر الكثير من أطر العمل والمكتبات القوية في مجال الذكاء الاصطناعي مثل مكتبة SciKit-Learn و TensorFlow و PyTorch و Keras. ولمطالعة المزيد من المعلومات حول خارطة طريق تعلم الذكاء الاصطناعي ومعرفة أدواته وتقنياته المختلفة أنصح بقراءة مقال تعلم الذكاء الاصطناعي ومقال تعلم الآلة Machine Learning. دورة الذكاء الاصطناعي احترف برمجة الذكاء الاصطناعي AI وتحليل البيانات وتعلم كافة المعلومات التي تحتاجها لبناء نماذج ذكاء اصطناعي متخصصة. اشترك الآن مستقبل إنترنت الأشياء إنترنت الأشياء IoT هو التقنية التي تجعل الأجهزة من حولنا ذكية وتتفاعل مع بعضها البعض وترسل البيانات عبر شبكة الإنترنت وتحللها وهو بلا شك أحد الجوانب التي ستؤثر على مستقبل البرمجة بشكل كبير، ومن المتوقع أن يزداد تأثيره في السنوات القادمة ليطبق بشكل أكبر في أتمتة منازلنا والتحكم بمختلف الأجهزة التي نستخدمها في حياتنا اليومية كأجهزة الإنذار وأنظمة التدفئة وأنظمة الإضاءة الذكية وأنظمة التحكم بالأبواب والستائر ويمكننا من التحكم بها من خلال التطبيقات المثبتة على هواتفنا الذكية، ولن يقتصر تطبيق إنترنت الأشياء على منازلنا فحسب بل سيستخدم بصورة أكبر في مختلف المجالات الصناعية كصناعة السيارات ومجال الرعاية الصحية وغيرها. ربما ستزيد هذه التقنيات من اعتمادية الناس العادية على الأجهزة لكنها ستفرض على معشر المبرمجين بذل جهد أكبر في تعلم تقنيات تطوير تطبيقات الأجهزة المضمنة وتطبيقات الأجهزة قابلة للارتداء والاطلاع على أحدث التغييرات التي ستطرأ على تطوير تطبيقات الجوال وتطبيقات الويب، إلى جانب اكتساب مهارات كافية في علوم البيانات لجعل هذه التطبيقات قادرة على التعامل مع كمية ضخمة من البيانات Big data فأجهزة إنترنت الأشياء ستولد لنا كميات هائلة من البيانات وهذه البيانات الضخمة تحتاج إلى تحليلها ومعالجتها واتخاذ قرارات صائبة منها. كما يحتاج المبرمجون المهتمون بهذا المجال إلى التركيز بشكل أكبر على أمان التطبيقات والمواقع التي يطورونها، ويتعلموا بشكل جيد طريقة التعامل مع بروتوكولات الاتصال وأجهزة الاستشعار والمنصات السحابية المناسبة حسب نوع التطبيق المطلوب، ويتقنوا اللغات والبروتوكولات الخاصة بإنترنت الأشياء مثل MQTT و CoAP و Zigbee. مستقبل البرمجة وعلم البيانات علم البيانات Data Science هو مجال حديث يجمع بين الإحصاء والرياضيات وعلوم الحاسوب ويهتم بدراسة البيانات ويعتمد عليها في اتخاذ القرارات من خلال الاستعانة بخوارزميات الذكاء الاصطناعي وتعلم الآلة، ويتوقع أن يزداد الطلب عليه بشكل أكبر في المستقبل نتيجة التضخم الهائل في حجم البيانات الذي نشهده، كما يتوقع أن يكون علم البيانات أحد أكثر المجالات المطلوبة في المستقبل لأن كافة المؤسسات والمنظمات وقطاعات العمل بدأت في الاعتماد عليه لاتخاذ قراراتها المختلفة مثل كشف عمليات الاحتيال والتوصية بالمنتجات المناسبة للعملاء وستحتاج للاعتماد عليه بشكل أكبر مستقبلًا. فإذا كنت مهتمًا بمجال علم البيانات أنصحك بأن تبدأ من الآن بتعلم التقنيات ولغات البرمجة الشهيرة في هذا المجال مثل لغة بايثون python ولغة R ونظم إدارة قواعد البيانات وبرامج التحليلات الإحصائية والتمثيل الرسومي للبيانات مثل Tableau و Power BI ومنصات البيانات الضخمة وتفهم أطر البيانات الضخمة مثل Spark و Hadoop لضمان مهنة لها دور واعد في مستقبل البرمجة. لمطالعة مزيد من المعلومات حول علم البيانات وتخصصاته وكيفية تعلمه أنصح بمطالعة مقال علم البيانات Data science: الدليل الشامل ومقال الدليل الشامل إلى تحليل البيانات Data Analysis. مستقبل تقنية البلوكتشين Blockchain أحدثت تقنية البلوكتشين Blockchain ثورة في طريقة التعامل الرقمي مع البيانات وهي تقنية تعتمد على تخزين المعاملات في قاعدة بيانات عملاقة مشفرة وآمنة لا مركزية وغير قابلة للتعديل تسمى دفتر الأستاذ الموزع distributed ledger وقد اكتسبت هذه التقنية شهرتها من العملات المشفرة المبنية عليها. ففي هذه التقنية تتم المعاملات على قاعدة البيانات بترتيب تسلسلي وتكون المعاملات لامركزية أي أنها تعمل على حواسيب موزعة في جميع أنحاء العالم وتتم مباشرة بين المستخدمين دون تدخل طرف ثالث وتكون مؤمنة بشكل كبير، على سبيل المثال عندما يبيع شخصان السلع لبعضهما البعض باستخدام عملة بيتكوين Bitcoin فلن يحتاجوا إلى المرور عبر وسيط مثل بيبال لإتمام هذه المعاملة. تتطور تقنية بلوكتشين بشكل متسارع ويتوقع أن تشهد المزيد من الاستخدامات في المستقبل في عدة مجالات فإلى جانب تحويل العملات المشفرة عبر الأجهزة سيعتمد عليها في إنشاء عقود ذكية مخصصة قادرة على التعامل مع المعاملات المعقدة والتحقق من المعاملات متعددة الخطوات وتسريع معالجة البيانات ونقلها بأمان، وبدأت تعتمد في العديد من القطاعات والمجالات مثل عمليات التصويت للانتخابات وحفظ المعاملات المالية وسندات الملكية. يتوقع أن تؤثر هذه التقنية على مستقبل البرمجة وتزيد الطلب على مطوري البلوكتشين بمختلف تخصصاتهم سواء المطورين الأساسيين blockchain core أو مطوري تطبيقات blockchain أو مطوري التطبيقات اللامركزية DApps ومطوري العقود الذكية باستخدام لغات مخصصة مثل solidity، فإذا كنت ترغب في تعلم مجال رائد في مستقبل البرمجة يمكنك البدء بتعلم تقنيات تطوير البلوكتشين والتعرف على منصاتها وبروتوكولاتها المختلفة. الحوسبة الكمومية Quantum Computing ستحل الحوسبة الكمومية التي تستخدم البتات الكمومية quantum bits أو ما يعرف بالكيوبتات qubits محل بالحوسبة الكلاسيكية التي تستخدم البتات bits أو نظام الأرقام الثنائية binary digits لتمثيل البيانات وتنفيذ العمليات، وستلعب دورًا فعالًا في مستقبل البرمجة من خلال زيادة سرعة معالجة كميات هائلة من البيانات وتسهيل حل المشكلات المعقدة التي استعصى على البشرية حلها. لا تزال الحوسبة الكمومية في بدايتها ويقتصر استخدام الحواسيب الكمومية اليوم على المجالات البحثية ولازالت تواجه حتى اليوم بعض التحديات التقنية والعملية التي يعمل الخبراء على حلها، وحين تستقر سيبدأ استخدامها في تطبيقات فعلية مختلفة ويتوقع أن تطور العديد من تخصصات البرمجة وأبرزها الأمن السيبراني وتحليل البيانات وتطور مجال الرعاية الطبية وتساعد في اكتشاف الأدوية وتحسن من الاقتصاد. تستخدم الحوسبة الكمومية أسلوبًا مختلفًا في البرمجة وتحتاج لتطوير خوارزميات جديدة لذا يحتاج المبرمجون المهتمون بهذا المجال إلى تعلم لغات برمجة وأطر عمل جديدة مصممة للعمل على الحواسيب الكمومية مثل Q# و Cirq و Qiskit، كما يمكنهم استخدام لغات برمجة تقليدية مثل بايثون لكن مع الاستعانة بمكتبات خاصة مصممة للعمل مع الأنظمة الكمومية مثل QuTip وسيحتاجون كذلك لفهم أساسيات الجبر الخطي وميكانيك الكم للتعامل مع هذه التقنية الرائدة. مستقبل البرمجة دون كود No-Code ستبقى البرمجة التقليدية التي تعتمد على كتابة الشيفرات البرمجية أو ما يعرف بالتطوير عالي الكود High-code development موجودة في مستقبل البرمجة بالتأكيد، لكن يتوقع أن يزداد الاعتماد كذلك على منصات التطوير بدون كود No-code development أو التطوير منخفض الكود Low-code development الذي يسمح لأي شخص غير مختص بالتقنية بتطوير البرامج والتطبيقات والمنتجات الخاصة به وأتمتة أعماله بنفسها. تتميز البرمجة منخفضة الكود بشكل أساسي بتوفير واجهات رسومية سهلة الاستخدام تعتمد السحب والإفلات ولا تحتاج لكتابة الشيفرات والتعليمات باستخدام إحدى لغات البرمجة المعقدة، ويمكن أن تعتمد أيضًا على أنظمة تصميم ومكونات مسبقة الصنع يمكن لأي شخص استخدامها مباشرة وإنشاء تطبيقاته بسرعة وسهولة. قد تتساءل هل هذا يعني أن الاعتماد على المبرمجين والمطورين المتخصصين سوف ينخفض في المستقبل؟ والجواب هو بالنفي فالحلول بدون كود مهما كانت مرنة وسهلة الاستخدام فلن تتمكن من الاستغناء عن دور المبرمجين بالكامل وستصلح للأنظمة البرمجية البسيطة نسبيًا وستبقى كتابة الأكواد مطلوبة لتطوير الأنظمة البرمجية الاحترافية والتحكم بهذه المنصات نفسها فهذه المنصات تعمل وراء الكواليس بواسطة الشيفرات البرمجية وستظل بحاجة لمبرمجين يطورونها ويقومون بصيانتها، كما يمكن أن تكون هذه المنصات بذات الوقت أداة مساعدة يمكن للمبرمجين دمجها مع أساليب البرمجة التقليدية لتحسن إنتاجيتهم وتسريع وتيرة عملهم. مستقبل تطبيقات الويب التقدمية PWA يتوقع أن تسيطر تطبيقات الويب التقدمية PWAs وهي اختصار لعبارة Progressive Web Applications على مستقبل برمجة تطبيقات الويب ويزداد الاعتماد عليها من قبل الشركات والمؤسسات المختلفة، فهذه التطبيقات وفرت أسلوبًا جديدًا لتطوير تطبيقات الأجهزة المحمولة ومكنت المبرمجين من تطوير تطبيقات ويب تتصرف مثل التطبيقات الأصيلة native applications وتعمل بكفاءة على كافة أنواع أنظمة التشغيل وتتوافق مع كافة الأجهزة وأحجام الشاشات سواء الحواسب المكتبية أو الأجهزة المحمولة ويتم الوصول لها من خلال مستعرض الويب وهي لا تتطلب من المستخدم تثبيت أي شيء لاستخدامها كما يمكنها العمل دون الحاجة للاتصال بالإنترنت. تستخدم تطبيقات الويب التقدمية تقنيات تطوير الويب الأساسية HTML و CSS وجافاسكريبت إلى جانب أدوات وأطر العمل المخصصة مثل Angular و React و Vue.js، فإذا مهتمًا بمجال برمجة وتطوير التطبيقات أنصحك بالبدء بتعلم تطوير PWAs واكتساب المهارات اللازمة في هذا المجال لضمان مهنة مطلوبة في سوق العمل في السنوات القادمة. لمطالعة مزيد من التفاصيل حول تطبيقات الويب التقدمية والتعرف على أهم مميزاتها يمكنك مطالعة مقال مدخل إلى تطبيقات الويب التقدمية PWA أهمية البرمجة في المستقبل لاشك أن مستقبل البرمجة واعد ومشرق في عصرنا الرقمي متسارع الخطى فالطلب على المطورين والمبرمجين يزداد بشكل كبير في الشركات التقنية المتخصصة، كما أن البرمجة قد تصبح مطلبًا أساسيًا للتوظيف في العديد من مجالات العمل الأخرى مثل الاقتصاد والصناعة ومؤسسات الرعاية الصحية إلى جانب زيادة الاعتماد عليها في مجالات الحياة اليومية. فالبرمجة لغة المستقبل وعلى الجميع تعلمها ولكن لنتذكر دومًا أن عالم البرمجة في تغير مستمر ومن الضروري لأي مهتم بالبرمجة أن يواكب التطورات الحاصلة فيها ويركز على تعلم الاتجاهات الحديثة التي يتوقع أن يزداد الطلب عليها إذا أراد أن يضمن البقاء في الصدارة في سوق العمل المستقبلي. إذا كنت مهتمًا بتعلم البرمجة واحترافها يمكنك البدء بأحد التخصصات البرمجية التي شرحناها سابقًا والتي يتوقع أن تشهد ازدهارًا وطلبًا مرتقعًا في مستقبل البرمجة، وتذكر أن مهنة البرمجة بلا شك بجميع مجالاتها وتخصصاتها الأخرى ستبقى واحدة من أكثر المهن التي تنبئ بمستقبل واعد، فإذا كنت مهتمًا بتعلم البرمجة وتقنياتها لا تتردد وابدأ من اليوم بتحديد المجال الذي يوافق ميولك وضع خطة لتعلمه مع الاهتمام إلى جانب ذلك بتنمية مهاراتك الناعمة مثل مهارات التواصل الفعال وحل المشكلات والقدرة على التعلم وتطوير الذات لأن هذه المهارات ستصبح أكثر أهمية في المستقبل وستمكنك من إثبات وجودك والتميز في سوق العمل. وإذا كنت مهتمًا بمعرفة مزيد من التفاصيل حول مستقبل البرمجة أنصحك بمشاهدة هذا الفيديو: الخلاصة حاولنا في مقال اليوم أن نستشرف مستقبل البرمجة ونعرفك على أهم التخصصات البرمجية التي يتوقع أن تشهد وجودًا قويًا في السنوات القليلة القادمة ومن أبرزها الذكاء الاصطناعي، والتعلم الآلي، والتعلم العميق، وإنترنت الأشياء، وعلم البيانات، وتقنيات البلوكتشين، والبرمجة بدون كود أو منخفضة الكود، وناقشنا أهمية تخصص البرمجة والمستقبل الواعد لدراسة هندسة البرمجيات وزيادة الطلب على المبرمجين والمطورين في سوق العمل المستقبلي. اقرأ أيضًا تعرف على أعلى تخصصات البرمجة أجرًا البرمجة والخوارزميات والذكاء الاصطناعي تطوير تطبيق وصفة لاقتراح الوجبات باستخدام ChatGPT و DALL-E في PHP برمجة الذكاء الاصطناعي1 نقطة
-
مصطلح إطار العمل أو الفريم وورك Framework يعد أحد المصطلحات الفنية والبرمجية التي تربك المبتدئين على وجه الخصوص في بداية مشوار تعلم البرمجة والتي لا يستطيع فهم دلالتها ولا إدراك مدى أهميتها بشكل جيد. وكثيرًا ما يتساءل المبرمج المبتدئ عن معنى إطار العمل Framework وعن مزايا ومحدويات استخدام أطر العمل Frameworks في عمله البرمجي وعملية البرمجة عمومًا، وهل يتوجب عليه تعلم إطار عمل للغة برمجة محددة، أم أن تعلمه للغة البرمجة نفسها يكفيه في سوق العمل، وهل تعلم إطار العمل صعب ويستغرق وقتًا، ومالفرق بين إطار العمل والمكتبة، وغيرها من الأسئلة من هذا القبيل. فإذا كنت مهتمًا بعرفة الإجابة على كل هذه التساؤلات فتابع قراءة هذا المقال للنهاية. ما هو إطار العمل Framework؟ إطار العمل Framework في البرمجة هو ببساطة آلية يتم من خلالها إعداد وتجهيز كافة الوظائف الضرورية والشائعة التي تستخدم بكثرة عند تطوير التطبيقات والأنظمة وإتاحتها للمبرمج ليستخدمها ويستفيد منها في عمله دون أن يحتاج لإعادة كتابة هذه الوظائف بنفسه من الصفر وبهذا نستنتج أن استخدام إطار العمل يختصر الكثير من الوقت ويجعل العمل البرمجي أكثر كفاءة. لتفهم الأمر بصورة أفضل تخيل أنك تحتاج لكتابة سيرتك الذاتية، سيكون أمامك خياران إما أن تفتح مستندًا فارغًا وتبدأ بكتابة كل شيء وتنسيقه بنفسك من الصفر، أو تعتمد على قالب جاهز للسيرة الذاتية يكون مقسمًا ومنسقًا وكل ما عليك هو ملء البيانات الضرورية الخاصة بك فقط دون أن تشغل بالك بالكثير من التفاصيل الأخرى سيكون الخيار الثاني أفضل وأسرع بالتأكيد. يساعدك إطار العمل في مشروعك البرمجي بطريقة مشابهة فهو يعمل كقالب أو هيكل أساسي عليك الالتزام به لإنشاء التطبيقات الخاصة بك، ويوفر لك مجموعة من الأدوات أو المكونات أو الحلول البرمجية الجاهزة لبناء تطبيقات مخصصة بطريقة آمنة وسريعة ومنظمة. ستجد الكثير من أطر عمل لكل لغات البرمجة الشائعة مثل جافاسكريبت وبايثون و PHP وجافا، ومن أجل استخدام أي إطار منها عليك بداية تعلم كيفية تطوير المشاريع في كل إطار منها والاستفادة من التسهيلات الكثيرة التي توفرها لك هذه الأطر. أنشئ موقع إلكتروني لأعمالك بدون خبرة برمجية صمم موقع احترافي لأعمالك بالسحب والإفلات مع أكثر من 70 قالب جاهز وقابل للتخصيص ليناسب هويتك التجارية جرب سنديان الآن ما الفرق بين إطار العمل والمكتبة؟ كثيرًا ما يتم الخلط بين مفهوم إطار العمل Framework ومفهوم مشابه له في البرمجة وهو المكتبة Library ورغم التشابه بينهما في طريقة العمل واستخدامهما بالتبادل في بعض الأحيان، إلا أن مفهوم المكتبة أبسط وأكثر محدودية فالمكتبة تركز على توفير وظيفة محددة في حين يوفر إطار العمل مجموعة متكاملة من الميزات التي تمكنك من برمجة تطبيقات في مجال محدد. تُعرَّف المكتبة بأنها عبارة عن مجموعة من التعليمات البرمجية المختبرة القابلة لإعادة الاستخدام والتي تنفذ وظيفة معينة وتحل مشكلة محددة، في حين ينفذ إطار العمل حزمة وظائف متكاملة أو يوفر مخططًا عامًا لبناء التطبيقات في حين لا توفر المكتبات هذه الميزة كما تحدد أطر العمل قواعد وإرشادات كتابة التعليمات البرمجية الخاصة بك وتنظم الملفات والمجلدات الخاصة بمشاريعك، ويمكن أن تتضمن مجموعة من المكتبات وتستخدمها لتنفذ مهام معينة. على سبيل المثال من بين المكتبات الشائعة نذكر مكتبة ريآكت React وهي مكتبة برمجية مبنية بلغة جافاسكربت ومتخصصة في بناء واجهات المستخدم ومكتبة jQuery التي تختصر العديد من الأكواد والتعليمات البرمجية المكررة في جافا سكريبت لتسهيل عملية البرمجة، ومن بين أطر العمل الشائعة نذكر أنجولار Angular وفيو Vue.js وهما إطارا عمل بلغة جافا سكريبت مختصان في تصميم واجهات مواقع الويب. ما الفرق بين إطار العمل ولغة البرمجة؟ يمكن للمطور أن يستخدم لغة البرمجة ويكتب كافة التعليمات البرمجية اللازمة لبناء التطبيقات من الصفر كما يمكنه إن شاء الاستعانة بإطار عمل Framework مخصص لتطوير برامجه وتطبيقاته. ورغم أن استخدام إطار العمل يفيد المطورين ويسرع وتيرة عملهم، إلا أنه يحد من حريتهم في كتابة التعليمات البرمجية ويقيد إمكانيات التطوير ويمكنهم من بناء تطبيقات لأغراض محددة فقط، في حين أن استخدام لغة برمجة يمكنهم من تطوير ما يشاؤون من تطبيقات متنوعة، حتى إطار العمل نفسه تم بناؤه في النهاية بإحدى لغات البرمجة. باختصار لغة البرمجة هي الأساس ومن خلال تعلمها يمكنك بناء ما تشاء من تطبيقات، أما إطار العمل فهو مصمم لنوع محدد من التطبيقات مثل تطبيقات الويب أو تطبيقات الجوال أو تطبيقات علم البيانات أو الذكاء الاصطناعي وإنترنت الأشياء …إلخ ويفضل أن تتعلم استخدامه بعد أن تتعلم البرمجة وتتمكن من أساسياتها. أهمية إطار العمل في البرمجة تبرز أهمية إطار العمل framework بشكل أساسي في كونه يتيح لك إعادة استخدام التعليمات البرمجية بدلًا من إعادة كتابتها من جديد، وفيما يلي جملة من الفوائد التي يمكن أن يوفرها استخدام إطار العمل: يساعد على توفير كود أكثر أمانًا لكونه يتضمن شيفرات تتحقق من المصادقات والصلاحيات وتحمي تطبيقك من الاختراق وتعالج الكثير من الثغرات الأمنية الشائعة مثل CSRF و XSS و SQL Injection. تركيز الجهود على كتابة التعليمات البرمجية الخاصة بالمشروع فقط بدلًا من برمجة وظائف متكررة وشائعة الاستخدام. توحد أنماط وقواعد كتابة التعليمات البرمجية وتوفر مخططًا عامًّا يمكن لكافة الفرق البرمجية فهمه بسهولة. يساعد في تطوير مشروعك وإضافة ميزات جديدة له بسهولة دون الحاجة للتعديل على الكود الأساسي لإطار العمل. يغني عن إعادة اختراع العجلة ويوفر لك الوقت والتكلفة اللازمين لتطوير المشاريع والتطبيقات. يساعد في كتابة كود نظيف وغير مكرر. يسهل عملية اختبار الكود وتصحيح الأخطاء البرمجية. يقلل بالعموم من كمية الأخطاء البرمجية لأنك ستكتب كود أقل وبالتالي ستنتج لديك أخطاء برمجية أقل. محدوديات إطار العمل لا شكَّ أن استخدام إطار العمل يفيدك كمطور ويساعدك على تسريع وتحسين العمل البرمجي، إلا أن الاعتماد على أطر العمل وحدها يفرض عليك بعض القيود وإليك أبرزها: يوفر وظائف محددة ويختص في بناء تطبيقات في مجالات معينة فقط. الاعتماد عليها قد يعيق المبرمج من فهم لغات البرمجة بشكل متعمق وواضح. بعض أطر العمل معقدة ويستغرق تعلمها وفهمها بشكل جيد وتطوير التطبيقات باستخدامها الكثير من الوقت. نحتاج إلى اختيار إطار العمل المناسب للتطبيق فاختيار الإطار غير الملائم قد يؤثر سلبًا على أداء تطبيقاتك وتجربة المستخدمين. تصدر لها تحديثات جديدة بشكل دوري، لذا سيتوجب عليك البقاء على اطلاع دائم على كل جديد ومعرفة كل الميزات الجديدة المضافة للإطار والمميزات التي تم الاستغناء عنها في كل إصدار. توقف تحديث إطار العمل أو تغيره ينعكس على سير عملية تطوير التطبيق المبرمج فيه وأمانه مثلما حصل مع إطار العمل AngularJS عندما قررت غوغل التوقف عن تطويره وإطلاق نسخة عنه مختلفة تمامًا. صفات إطار العمل الجيد تتوافر عشرات أطر العمل في المجالات البرمجية المختلفة الأمر الذي يشعرك بالحيرة في تحديد الإطار الأفضل لمشروعك ويجعلك تتساءل كيف أختار إطار العمل المناسب؟ بالعموم يتصف إطار العمل الجيد بثلاث صفات أساسية وهي: التوثيق الجيد توفير الوظائف المطلوبة لعملك الشهرة والدعم المجتمعي لنوضح بمزيد من التفصيل كل صفة من هذه الصفات وأهميتها في اختيار إطار العمل الأفضل. التوثيق الجيد اختر إطار عمل موثقًا بشكل جيدًا كي تتمكن من العودة إليه عندما تحتاج لمعرفة المزيد من المعلومات حول استخدام ميزة معينة أو حل مشكلة تواجهك في استخدامه، فالتوثيق الجيد يوفر عليك الكثير من الوقت والجهد. توفير الوظائف المطلوبة لعملك ضع في اعتبارك أن لكل إطار عمل حدود معينة لذا من الضروري أن تبحث بشكل جيد في ميزات الإطار الذي تريد اعتماده وتتأكد من أنه يلبي متطلبات مشروعك ويحقق لك كافة الوظائف والميزات التي تحتاج لتحقيقها بالشكل الأنسب، وبنفس الوقت لا تختر إطار عمل شديد التعقيد أو مكتظًا بالميزات التي قد لا تحتاجها على الإطلاق! الشهرة والدعم المجتمعي لاشك أن شهرة إطار العمل ووجود مجتمع داعم له يدل على قوته والطلب الكبير عليه في سوق العمل، لذا احرص على استخدام إطار عمل معروف وله قاعدة مستخدمين نشطة ويفضل بعض المبرمجين الاعتماد على أطر عمل حرة ومفتوحة المصدر وغير مقيدة أو مدعومة من شركات معينة لتخوفهم من انعكاس أي طارئ يحصل لها أو تغير في سياستها على إطار العمل. ولذلك السبب ترى البعض يميل إلى استخدام إطار العمل Vue.js الذي انبثق من أروقة المجتمع الحر بدلًا من إطار العمل Angular الذي ولد بين أروقة شركة غوغل مثلًا، ولكن هنالك طرف مقابل يشير إلى تنظيم وقوة وسرعة تطوير أطر العمل التي تقف خلفهم الشركات نظرًا لدعمهم السخي طويل الآجل عادةً خصوصًا إن وقفت شركات تقنية كبيرة خلفهم والحديث يطول في هذه النقطة وهي خارج موضوع المقال فقط أحببت الإشارة إليها نظرًا لأهميتها في أي نقاش يدور حول المفاضلة بينها. أنواع أطر العمل frameworks في البرمجة هناك عدة أنواع من أطر العمل حيث يختص كل إطار بمجال استخدام معين، وفيما بعض أهم أنواع أطر العمل حسب التطبيقات أو الوظائف التي يؤديها: 1. أطر عمل تطوير الويب Web development frameworks تستخدم هذه الأطر في تطوير تطبيقات الويب ومن أشهرها إطار عمل أنجولار Angular وفيو جي إس Vue.js وهي أطر عمل جافا سكريبت شائعة تستخدم لتطوير الواجهات الأمامية للويب، وإطاري عمل إكسبرس Express و NestJS وهي أطر عمل Node.js لتطوير الواجهات الخلفية للويب، وإطاري عمل جانغو Django وفلاسك Flask وهي أطر عمل مفتوحة المصدر مكتوب بلغة بايثون مخصصة لتطوير الواجهات الخلفية للويب، وإطار عمل Ruby on Rails الذي يوفر لك كل ما تحتاجه لإنشاء تطبيق ويب بسهولة وسرعة وأمان وإطار عمل لارافيل Laravel المبني بالاعتماد على لغة PHP. 2. أطر عمل تطوير الجوال Mobile development frameworks من أشهرها في تطوير تطبيقات الجوال نذكر إطار عمل React Native مفتوح المصدر مكتوب بلغة جافا سكريبت طورته فيسبوك لتطوير تطبيقات جوال متوافقة مع كافة الأنظمة الأساسية، وإطار أيونيك Ionic الذي يستخدم تقنيات الويب HTML و CSS وجافا سكريبت من أجل تطوير تطبيقات الجوال وهو يتكامل مع أطر تطوير الواجهات الأمامية مثل Angular و Vue، وإطار عمل فلاتر Flutter وهو إطار عمل مفتوح المصدر للغة دارت Dart من جوجل لتطوير تطبيقات الجوال وهو يدعم أنظمة iOS و Android ويحتوي على عناصر واجهة مستخدم قابلة للتخصيص بالكامل، وإطار عمل أباتشي كوردوفا Apache Cordova الذي يمكنك من تطوير تطبيقات هجينة للهاتف الجوال. 3. أطر عمل علم البيانات Data science frameworks تعرف هذه الأطر كذلك بأطر التعلم الآلي Machine Learning Frameworks وهي تساعد علماء البيانات على إنشاء نماذج تعلم آلي وتصميمها بشكل أسرع وأسهل واستخراج المعلومات المفيدة من مجموعات البيانات بالاستفادة من تقنيات البرمجة والذكاء الاصطناعي والتعلم الآلي. وهناك العديد من أطر عمل علم البيانات ومن ضمنها scikit-Learn و XGBoost و TensorFlow و PyTorch. 4. أطر إدارة المحتوى Content management frameworks تعرف أيضًا باسم نظم إدارة المحتوى Content Management Systems أو اختصارًا CMS هي برمجيات توفر مكونات قابلة لإعادة الاستخدام لإنشاء وإدارة محتوى الويب وعرضه ضمن مدونات أو مواقع إلكترونية أو تطبيقات جوال وهي توفر ميزات أخرى مثل سهولة الاستخدام وتحسين محركات البحث والأمان. ومن أشهر هذه النظم نذكر نظام ووردبريس WordPress الشهير المستخدم في إنشاء ما يقارب من نصف المواقع الإلكتروني ودروبال Drupal الذي يعد نظام مثالي لتطوير المواقع التي تحتوي على الكثير من المحتوى وهو يتطلب معرفة تقنية أكثر من بقية نظم إدارة المحتوى. 5. أطر عمل أتمتة الاختبار Test Automation frameworks يستخدم مطورو البرمجيات أطر عمل الأتمتة من أجل إنشاء حالات اختبار التطبيقات والتأكد من سير عملها بكفاءة وتوفر لهم أدوات وتوصيات للتحقق من جودة البرمجيات واتباع معايير الترميز المناسبة. من أشهر أطر الاختبار نذكر سيلينيوم Selenium وهو إطار مفتوح المصدر لأتمتة اختبار تطبيقات الويب، وCypress المبني بجافا سكريبت والمخصص لاختبار الواجهة الأمامية لتطبيقات الويب، و Playwright للاختبار الشامل لتطبيقات الويب. هل يمكن البدء باستخدام إطار العمل دون تعلم لغة البرمجة؟ لاشك أن إطار العمل يوفر لك كمطور أداة قيمة لتطوير البرامج التطبيقات المختلفة، لكن السؤال الذي يطرح نفسه هل يغني تعلم أطر العمل واستخدامها في بناء التطبيقات العملية عن تعلم لغات البرمجة وفهمها بشكل متعمق؟ في الواقع حتى لو لم تكن ترغب في تطوير التطبيقات بإحدى لغات البرمجة وتميل للاستفادة من ميزات أحد أطر العمل فلا غنى لك عن تعلم لغة البرمجة وفهم أساسياتها إلى جانب إطار العمل فكلما فهمت لغة البرمجة بشكل أفضل سيسهل عليك فهم أطر العمل. كما أن تعلّم البرمجة يوسع أفق عملك ويمكنك من بناء العديد من التطبيقات في مختلف المجالات، أما إطار العمل فهو مصمم كما ذكرنا سابقًا لغرض واحد فقط وبالتالي سيقيدك بنوع محدد من التطبيقات. ويمكن باختصار أن نلخص الإجابة على هذا السؤال بجملة واحدة: يمكنك استخدام أطر العمل، لكن قبل ذلك تعلم أساسيات لغة البرمجة واتقنها ثم استفد من ميزات إطار العمل الخاص بتلك اللغة كما يحلو لك. الخلاصة تعرفنا اليوم على مفهوم إطار العمل Framework ودوره المهم في توفير الوظائف القياسية وتحديد الخطوط العريضة التي تنظم المشاريع البرمجية وتوفر وقت وجهد المطورين والمبرمجين، واكشتفنا أهم الفروقات بين أطر العمل وبين أدوات تطوير البرامج الأخرى مثل المكتبات ولغات البرمجة، وتعلمنا طريقة اختيار أفضل إطار عمل يناسب متطلباتنا وعددنا أهم صفات إطار العمل الجيد، وأخيرًا استعرضنا قائمة بأهم أطر العمل المستخدمة في مجالات مختلفة كتطبيقات الويب وتطبيقات الجوال وغيرها من المجالات. هل تستخدم في عملك أحد أطر العمل التي وردت في سياق المقال أو أطر عمل أخرى؟ ما هو هذا الإطار وفي أي مجال تستخدمه؟ هل هناك أي مشاكل تواجهها في التعامل مع هذا الإطار أم أنك راضٍ عن أدائه. شاركنا تجربتك في التعليقات أسفل المقال. اقرأ أيضًا تعلم أساسيات البرمجة قواعد البرمجة ببساطة للمبتدئين أسهل لغات البرمجة مهندس البرمجيات من هو وما هي مهامه تعرف على تخصص هندسة البرمجيات1 نقطة
-
بدأنا هذه السلسلة بمقال عن كيفية التعامل مع رسائل الأخطاء في بايثون وسنتابع الحديث في هذا المقال عن كيفية التعامل مع الملفات والمسارات في بايثون. وبايثون هي لغة برمجة عالية المستوى، وتفاعلية وكائنية. وتتمتع بمقروئية عالية، إذ تستخدم كلمات إنجليزية بسيطة، على خلاف اللغات الأخرى التي تستخدم الرموز، كما أنّ قواعدها الإملائية والصياغية بسيطة، ما يجعل تعلمها سهلًا موازنةً بلغات برمجة أخرى. ولعلّ الخطوة الأولى قبل الإبحار في تعلّم بايثون هي إعداد البيئة، والتي تعرّف بأنها عملية تنظيم الحاسوب اللازمة لاستخدامه في كتابة الشيفرات البرمجية، الأمر الذي يتضمن تثبيت أي أدوات ضرورية وإعدادها، والتعامل مع أي مشاكل قد تواجهك أثناء عملية الإعداد، ولإنجاز هذه الخطوة لابد من فهمك الجيد لنظام الملفات وكيفية التعامل مع المسارات في بايثون. سنحاول في هذا المقال توصيف بعض المبادئ الأساسية لمساعدتك في إدارة حاسوبك باستخدام نظام الملفات. قد يبدو فهم هذه المبادئ دون جدوى، فنحن في نهاية الأمر نسعى لكتابة الشيفرات لا، إلا أن اكتساب هذه المهارات الأساسية سيوفر عليك الوقت على المدى الطويل. نظام الملفات إن نظام الملفات هو الوسيلة التي يعتمدها نظام التشغيل لتنظيم البيانات وتخزينها واستعادتها، إذ يضم الملف خاصيتين رئيسيتين: اسم الملف (وهو عبارة عن كلمة واحدة عادةً) ومساره. لنفرض مثلًا وجود ملف على حاسوب محمول ذو نظام التشغيل ويندوز 10 يدعى project.docx ضمن المسار C:\Users\Al\Documents، يحدد المسار موقع الملف في الحاسوب، أما الجزء الذي يلي اسم الملف بعد النقطة فهو لاحقة الملف التي تبين نوعه. فيشير مثلًا اسم الملف project.docx إلى أن هذا الملف مستند لبرنامج معالج النصوص Word أما Users و Al و Documents فهي اسماء مجلدات، والتي يمكن أن تحتوي على ملفات ومجلدات أخرى. في مثالنا السابق يوجد الملف project.docx ضمن مجلد المستندات Documents الذي يوجد في المجلد Al الموجود بدوره ضمن مجلد المستخدمين Users، ويبين الشكل التالي ترتيب هذه المجلدات. ملف ضمن تسلسل هرمي للمجلدات إذ يمثل الجزء \:C من مسار الملف المجلد الأساسي الذي يحتوي على جميع المجلدات الأخرى. يعطى المجلد الأساسي في نظام التشغيل ويندوز Windows الاسم \:C، ويسمى أيضًا القرص :C، بينما في أنظمة التشغيل ماك أو إس Mac os ولينكس Linux فيشار إليه بالشكل /. سنعبّر عن المجلد الأساسي بطريقة نظام التشغيل ويندوز، أي بالشكل التالي \:C، أما إن كنت ستكتب أوامر أمثلة الصَدفة التفاعلية في نظام التشغيل ماك أو إس أو لينكس فأدخل / بدلاً عنها. هناك نماذج أخرى مثل محركات الأقراص DVD ومحركات الأقراص القابلة للإزالة USB flash drive والتي ستظهر بشكل مختلف في أنظمة التشغيل المختلفة، ففي نظام التشغيل ويندوز تظهر كمجلد أساسي جديد يحمل رمز حرف معين مثلاً \:D أو \:E، بينما في نظام ماك أو إس فتظهر كمجلد جديد ضمن المجلد Volumes/، وفي نظام التشغيل لينكس تظهر كمجلد جديد ضمن المجلد /mnt ("mount") ومن الجدير بالملاحظة أن أسماء المجلدات والملفات ليست حساسة لحالة الأحرف في نظامي ويندوز أو ماك أو إس، إلا أنها كذلك في نظام تشغيل لينكس. المسارات في بايثون يُستخدم الخط المائل العكسي \ للفصل بين أسماء المجلدات والملفات في نظام التشغيل ويندوز، لكن في نظامي ماك أو إس ولينكس فيتولى الخط المائل الأمامي / تلك المهمة، لذا وبدلًا عن كتابة كل شيفرة بالطريقتين لجعل النص البرمجي المكتوب بلغة بايثون قابلاً للتطبيق على مختلف أنظمة التشغيل، يمكننا استخدام الوحدة pathlib والمعامل / بدلًا من ذلك. من الممكن استيراد مكتبة pathlib من خلال تنفيذ الأمر from pathlib import Path، ولأن صنف المسار Path هو أكثر الأصناف استخدامًا في وحدة pathlib، فمن المسموح كتابة Path وحدها بدلًا من كتابة pathlib.Path. وبإمكاننا أن نمرر إلى الدالة ()Path سلسة نصية هي عبارة عن اسم المجلد أو اسم الملف، وذلك بغية إنشاء كائن مسار Path لاسم هذا المجلد أو الملف. وبما أن أن الكائن في أقصى يسار السطر البرمجي ما هو إلا كائن مسار Path، فيمكننا الآن استخدام المعامل / لدمج كائنات أو سلاسل هذا المسار مع بعضها. والآن لنكتب الشيفرة التالية في الصدفة التفاعلية: >>> from pathlib import Path >>> Path('spam') / 'bacon' / 'eggs' WindowsPath('spam/bacon/eggs') >>> Path('spam') / Path('bacon/eggs') WindowsPath('spam/bacon/eggs') >>> Path('spam') / Path('bacon', 'eggs') WindowsPath('spam/bacon/eggs') ونلاحظ بأنه كوننا ننفذ الشيفرة السابقة على حاسوب يعمل بنظام تشغيل ويندوز، فإن الدالة ()Path تعيد كائن مسار ويندوز windowspath، في حين ستتم إعادة الكائن PosixPath في حال استخدام أحد نظامي التشغيل ماك أو إس أو لينكس. (تعد POSIX مجموعة معايير لأنظمة التشغيل الشبيهة بنظام يونيكس ولن نتطرق لها في دراستنا). ومن الممكن تمرير كائن المسار إلى أي دالة تتطلب اسم ملف في المكتبة المعيارية لبايثون. فعلى سبيل المثال يعد استدعاء الدالة التالية: open(Path('C:\\') / 'Users' / 'Al' / 'Desktop' / 'spam.py') مكافئًا لاستدعاء الدالة التالية: open(r'C:\Users\Al\Desktop\spam.py') المجلد الرئيسي ما من مستخدم إلا ولديه مجلد رئيسي يخزن فيه ملفاته على الحاسوب، ومن الممكن الحصول على كائن مسار لهذا المجلد الرئيسي باستدعاء التابع ()path.home بالشكل: >>> Path.home() WindowsPath('C:/Users/Al') وتوجد المجلدات الرئيسية في مكان محدد بناءً على نوع نظام التشغيل: توجد المجلدات الرئيسية في نظام التشغيل ويندوز ضمن C:\Users. توجد المجلدات الرئيسية في نظام التشغيل ماك أو إس ضمن Users/. توجد المجلدات الرئيسية في نظام التشغيل لينكس ضمن home/. تمتلك النصوص البرمجية غالبًا أذونات القراءة والكتابة على الملفات في المجلد الرئيسي وبالتالي تعد هذه المجلدات مكانًا مثاليًا لتخزين الملفات التي ستتعامل معها برامج بايثون. مجلد العمل الحالي لكل برنامج يعمل على الحاسوب مجلد عمل حالي (cwd) توجد فيه جميع أسماء الملفات والمسارات التي لا تبدأ بالمجلد الأساسي. وعلى الرغم من أن كلمة "مجلد folder" هي الاسم الحديث للدليل Directory، يعد cwd (أو ما يعرف بدليل العمل الحالي) هو المصطلح المعياري وليس "مجلد العمل الحالي". يمكننا الحصول على دليل العمل في هيئة كائن مسار باستخدام الدالة ()Path.cwd وتغييره باستخدام الدالة ()os.chdir، ولإنجاز ذلك سنكتب الشيفرة التالية في الصدفة التفاعلية: >>> from pathlib import Path >>> import os 1 >>> Path.cwd() WindowsPath('C:/Users/Al/AppData/Local/Programs/Python/Python38') 2 >>> os.chdir('C:\\Windows\\System32') >>> Path.cwd() WindowsPath('C:/Windows/System32') اعتبرنا في الشيفرة السابقة أن مسار دليل العمل هو: C:\Users\Al\AppData\Local\Programs\Python\Python381 وبالتالي سيكون مسار الملف project.docx كالآتي: C:\Users\Al\AppData\Local\Programs\Python\Python381\project.docx وعندما نغير دليل العمل ليصبح C:\Windows\System32 سيصبح مسار الملف project.docx بالشكل C:\Windows\System32\project.docx، وسيظهر بايثون رسالة خطأ إن غيرنا المجلد إلى مجلد غير موجود: >>> os.chdir('C:/ThisFolderDoesNotExist') Traceback (most recent call last): File "<stdin>", line 1, in <module> FileNotFoundError: [WinError 2] The system cannot find the file specified: 'C:/ThisFolderDoesNotExist' ويعد استخدام الدالة ()os.getcwd من الوحدة os هو الطريقة الأقدم للحصول على مسار دليل العمل في هيئة سلسلة نصية. المسارات المطلقة والنسبية يوجد طريقتان لتحديد مسار ملف: المسار المطلق وهو الذي يبدأ دائمًا بالمجلد الأساسي. المسار النسبي والذي يشير عادةً إلى دليل العمل الخاص بالبرنامج. وهناك أيضًا المجلدات ذات النقطة (.) أو النقطتين (..). وهي ليست مجلدات حقيقية لكنها أسماء خاصة يمكن استخدامها في المسار. فالنقطة الوحيدة (.) تعد اختصارًا للدلالة على المجلد الحالي أو "هذا المجلد"، أما وجود نقطتين (..) فيشير إلى "المجلد الأب". ويبين الشكل التالي مثالًا لبعض المجلدات والملفات، فعندما يكون دليل العمل بالشكل C:\bacon تكون المسارات النسبية للمجلدات والملفات الأخرى كما هو مبين في الشكل أدناه. أما وجود الرمز في بداية المسار النسبي فهو أمر اختياري، فعلى سبيل المثال يشير كل من spam.txt. و spam.txt إلى الملف ذاته. المسارات النسبية للملفات والمجلدات في دليل العمل C:\bacon البرامج والعمليات يعرف البرنامج بأنه أي تطبيق برمجي يمكن تشغيله، كمتصفح الويب وتطبيق جدول البيانات ومعالج النصوص، في حين أن العملية عبارة عن نسخة قيد التشغيل running instance من البرنامج، فعلى سبيل المثال يبين الشكل أدناه خمس عمليات قيد التشغيل لنفس برنامج الآلة الحاسبة. تشغيل برنامج الآلة حاسبة عدة مرات على شكل عدة عمليات منفصلة إذ تبقى العمليات منفصلة عن بعضها حتى التابعة منها لنفس البرنامج، فمثلًا إن شغلنا عدة نسخ من برنامج بايثون في نفس الوقت ضمن عمليات مستقلة، فيمكن أن يكون لكل منها قيم متغيرات خاصة بها ومختلفة، فلكل عملية دليل العمل ومتغيرات البيئة الخاصة بها وذلك حتى بالنسبة للعمليات التابعة لنفس البرنامج، وعمومًا تُشغّل نوافذ سطر الأوامر عملية واحدة في كل مرة (ومن الممكن أيضًا فتح عدة نوافذ أوامر في نفس الوقت). ولكل نظام تشغيل طريقته لعرض قائمة العمليات قيد التنفيذ، ففي نظام ويندوز من الممكن تشغيل تطبيق مدير المهام عبر الضغط على مفاتيح CTRL+SHIFT+ESC، أما في نظام ماك أو إس فيمكن الوصول إليها من قائمة التطبيقات Application ومنها نختار الخدمات Utilities ومن ثم مراقب الأداء Activity Monitor، أما في نظام أبونتو لينكس يمكننا الضغط على مفاتيح CTRL+ALT+DEL معًا لتشغيل تطبيق يدعى أيضًا بمدير المهام، ويمكن لمدير المهام أيضًا إنهاء عملية ما قيد التشغيل إن لم تكن تستجيب. الخلاصة يتضمن ضبط البيئة كافة الخطوات الضرورية لجعل الحاسوب قادرًا على تشغيل برامجنا بسهولة، وتتطلب هذه العملية منا معرفة بعض مفاهيم الأولية حول كيفية عمل الحاسوب، كفهم نظام الملفات والمسارات والعمليات. إن نظام الملفات هو الآلية التي ينظم بها الحاسوب الملفات، فلكل ملف مسار مطلق كامل أو مسار نسبي بالنسبة لدليل العمل الحالي، ويمكنك التنقل في نظام الملفات من خلال سطر الأوامر. قد يستغرق الأمر وقتًا لتعتاد التعامل مع نظام الملفات باستخدام موجه الأوامر، لذا لا تتردد في البحث مطولًا على الإنترنت عن المساعدة، فهو الأمر الطبيعي الذي يقوم به مطورو البرامج يوميًا. ترجمة -وبتصرف- للفصل الثاني "إعداد البيئة وواجهة سطر الأوامر" من كتاب Beyond the Basic Stuff with Python لصاحبه Al Sweigart. اقرأ أيضًا المقال السابق: أصول طلب المساعدات البرمجية في بايثون عبر الإنترنت التعامل مع الملفات النصية في بايثون كيفية التعامل مع الملفات النصية في بايثون 3 التعامل مع الصفوف، المجموعات والقواميس في بايثون1 نقطة
-
لكل مهنة قواعد تنظمها وتضمن إنجاز الأعمال فيها بأفضل صورة ممكنة، ومهنة البرمجة ليست استثناء! حيث تعد قواعد البرمجة من الأمور التي ينبغي على أي مبرمج تعلمها، والحرص على اتباعها عند تطوير البرامج والتطبيقات المختلفة. نضعك في مقال اليوم على بداية الطريق، ونعرفك على أهم قواعد البرمجة، ونوضح لك أهمية استخدامها وكيف يمكنك تحقيقها، وبالتدريب والممارسة ستتمكن من اتباعها عندما تطور برامجك وتطبيقاتك. ما هي قواعد البرمجة؟ قواعد البرمجة هي مجموعة من التوصيات والإرشادات التي ينبغي للمبرمجين اتباعها والالتزام بها عند استخدام أي لغة من لغات البرمجة للحصول على كود برمجي عالي الجودة وسهل الصيانة. يضمن لك تطبيق قواعد البرمجة إنتاج برامج مفهومة وواضحة وسهلة القراءة والتعديل، وهو أمر مهم لأي مبرمج لاسيما عندما يعمل ضمن فريق عمل ويتشارك مع عدة مبرمجين أو مطورين على تطوير نفس المشروع. لاشك أن تطبيق قواعد البرمجة ليس بالأمر السهل ولن يتحقق بسرعة، فتطبيق القواعد يأتي في مرحلة لاحقة، فبعد أن تتمكن من أساسيات البرمجة، وتتدرب على طريقة التفكير البرمجي، وحل المشكلات، عليك أن تتقدم خطوة للأمام وتتعلم كيف تحسن من برامجك من خلال تطبيق القواعد البرمجية عليها. سنعرض الآن عددًا من أهم قواعد البرمجة فكن جاهزًا! أهم قواعد البرمجة إليك أهم ثمان قواعد أساسية ينبغي عليك اتباعها لتبرمج كالمحترفين: اتبع القواعد العرفية للغة التي تبرمج بها وثق الكود الذي تكتبه حافظ على البساطة KISS لا تكرر نفسك DRY ادمج الأجزاء الصغيرة لإنجاز الأعمال الكبيرة لا تبرمج ما لا تحتاجه افصل الأكواد في أجزاء مستقلة اكتب أكوادًا نظيفة نشرح في الفقرات التالية كل قاعدة من قواعد البرمجة هذه بمزيد من التفصيل ونوضح أهميتها وكيفية تطبيقها عند تطوير البرامج والتطبيقات. اتبع القواعد العرفية للغة التي تبرمج بها لكل لغة من لغات البرمجة قواعد كتابة خاصة بها تعرف باسم صياغة، واتباع هذه القواعد عند كتابة الكود البرمجي ليس خيارًا للمبرمج، لأن الكود البرمجي لن يعمل بشكل صحيح إذا لم يكن مكتوبًا وفق هذه القواعد. فليس المقصود هنا صياغة اللغة وقواعدها، ولكن ما أقصده هو مراعاة اصطلاحات اللغة المتعارف عليها أو ما يسمى في أوساط المبرمجين باسم "العرف" Conventions، فلكل لغة قواعد اصطلاحية متعارف عليها بين مبرمجي تلك اللغة، مثل ضرورة كتابة كل تعليمة على سطر جديد، ومراعاة قواعد التباعد، وأماكن وضع الأقواس مثل () و {} ضمن البرنامج، ووضع المسافات البادئة في كل سطر، وقواعد تسمية المتغيرات والدوال والأصناف …إلخ. هذه الأمور تتغير من لغة إلى لغة وليس لها معيار موحد، لذا عليك التعرف على اصطلاحات اللغة التي تبرمج بها وتحرص على اتباعها، فإن انتقلنا مثلًا إلى لغة جافاسكربت، فيعرض مقال نمط كتابة شيفرة جافاسكربت هذا الموضوع بالتفصيل ويتحدث عن العرف المتبع بين مبرمجي لغة جافاسكربت كما يشير أخيرًا في فقرة "شروحات لأنماط كتابة الشيفرة" أشهر المعايير والأعراف العالمية للغة جافاسكربت منها أسلوب Google وأسلوب Airbnb والأسلوب المعياري الرسمي وغيرها، فلا حاجة لكل فريق أي يخترع عرفًا ومعيارًا يسير عليه بل يقتدي بعرف شهير شائع منظم موجود مسبقًا. أضرب مثلًا عن أسلوب Airbnb في تعريف المتغيرات في لغة جافاسكربت بالشكل التالي: // سيء const items = getItems(), goSportsTeam = true; // جيد const items = getItems(); const goSportsTeam = true; لاحظ أن تعريف متغير واحد في كل سطر هو الأسلوب المتبع ويجب تجنب تعريف عدة متغيرات في سطر واحد رغم أنه لا فرق في التنفيذ بينهما. أتريد مثلًا آخر؟ خذ هذا المثال أيضًا من أسلوب PEP8 في لغة بايثون: # Line Break with Binary Operator # سيء income = (gross_wages + taxable_interest - student_loan_interest) # جيد income = (gross_wages + taxable_interest - student_loan_interest) # Imports # سيء import sys, os # جيد import os import sys قد تجد أن الاختلاف بسيط أحيانًا بين العُرف الجيد المتبع وبين الأسلوب السيء في كتابة الشيفرة وهذا صحيح، ولكن تذكر أن الشيفرة لا تُكتب مرة واحدة فقط ولن يعمل عليها شخص واحد فقط، بل ستُعدل مرارًا وتكرارًا ويمر عليها عشرات المبرمجين فإن اتبع كل مبرمج أسلوبه الخاص فُقد التنظيم وسادت العشوائية وأصبحت الشيفرة عرضة للخطأ عند تعديلها. وتذكر دومًا أن العُرف هذا يضعه مبرمجون أصحاب خبرة بعشرات السنوات يحاولون به نقل خبرتهم أفضل طريقة لكتابة شيفرة متسقة سهلة القراءة والتعديل وأقل عرضة للأخطاء. دورة علوم الحاسوب دورة تدريبية متكاملة تضعك على بوابة الاحتراف في تعلم أساسيات البرمجة وعلوم الحاسوب اشترك الآن وثق الكود الذي تكتبه هذه القاعدة على بساطتها مفيدة للغاية، فمن الضروري أن تعتاد على كتابة تعليقات توضيحية في الأكواد التي تكتبها لتوثيق عملك، وتشرح ما الذي تقوم به، وتوضح وظائف الدوال والأصناف والمكتبات المختلفة. التعليقات أمر مهم لكل مبرمج، فهي من جهة تساعده على فهم ما كتبه عند العودة له لاحقًا لأن المبرمج سينسى الكثير مما كتبته ولماذا كتبته بعد مرور فترة من الزمن، كما أن التعليقات تفيد أي مبرمج آخر يقرأ الكود في فهمه بسرعة في حال احتاج إلى تطويره أو التعديل عليه. ومن الضروري أن تتعلم أفضل ممارسات كتابة التعليقات على الكود الخاص بك، وتعرف متى وأين يتوجب عليك كتابة التعليقات ومتى لا يلزمك ذلك. اكتب التعليقات عندما تحتاج لوصف أي ميزة غير واضحة في التعليمات البرمجية، وفي أي موضع ترى أنه يتطلب المزيد من الشرح والتوضيح للآخرين، أما عندما يكون الهدف من الكود واضحًا ومفهومًا فيمكنك الاستغناء عن كتابتها. باختصار التعليقات تساعد المبرمجين على فهم المشكلات التي كنت تحاول حلها في تعليماتك البرمجية دون الحاجة لبذل كثير من الجهد لفهم واستنباط ما كتبته ولكن الأفضل من كتابة التعليقات أن تكتب شيفرة مفهومة بدون تعليقات وهذه هي القاعدة دومًا. حافظ على البساطة KISS قاعدة KISS هي اختصار لعبارة "Keep It Simple, Sweetie" التي تعني أبقها بسيطة يا عزيزي! أو أبقِ أكوادك بسيطة ومباشرة، وهذه القاعدة تطبق عند تصميم كافة الأنظمة البرمجية فقد تبين أن هذه الأنظمة تعمل بشكل أفضل إذا كانت بسيطة وخالية من التعقيد. فإذا كنت تستطيع أن تحل مشكلة ما بعشرة أسطر من الكود البرمجي لا داعي لأن تكتب خمسين سطرًا لحلها، وإذا كنت تحتاج لبرمجة نموذج ما يحتوي 10 حقول، فلا تضع فيه 20 حقلًا من البيانات التي لن تقدم أي فائدة في سير عمل برنامجك. الخلاصة، إذا كنت تطور أحد البرامج وكنت تستطيع تجنب التعقيد في كتابة الكود، فتجنبه قدر الإمكان، واحرص على إبقاء الأكواد البرمجية التي تكتبها فيه بسيطة، وتلبي المتطلبات قدر المستطاع. لا تكرر نفسك DRY من قواعد البرمجة الهامة قاعدة DRY وهي اختصار للعبارة "Don't Repeat Yourself" التي تعني لا تكرر نفسك، والتي تؤكد على المبرمج أن لا يكرر كتابة نفس الكود البرمجي مرارًا وتكرارًا، وينبغي عليه عند وجود هذه الحالة أن يتخلص من هذا التكرار بطريقة ما. لا مشكلة من تكرار نفس الكود مرة واحدة، ولكن عندما تستخدم نفس الكود عدة مرات في مواضع مختلفة من برنامجك فعليك أن تفكر في تعديله، وتجد طريقة ذكية لكتابة الكود مرة واحدة وإعادة استخدامه كلما احتجت له لتكون مطبقًا لهذه القاعدة. من المنهجيات البرمجية التي تساعدك على تقليل الكود البرمجي المكرر وجعل برامجك سهلة القراءة والصيانة هي استخدام الحلقات التكرارية التي تجنبك تكرار نفس التعليمات البرمجية وتجعل الكود البرمجي أقصر، وأيضًا استخدام الدوال والإجراءات البرمجية، وتعريف المكتبات والوحدات البرمجية التي تغلف شيفراتك البرمجية وتمكنك من إعادة استعمالها كلما أردت. ستدرك أهمية هذه القاعدة البرمجية إذا احتجت لإجراء تعديل ما في هذا الكود البرمجي المكرر، أو اكتشفت فيه خطأً ما وأردت تصحيحه، عندها سيتوجب عليك إجراء التعديلات في جميع الأماكن التي قمت فيها بإدراج هذا الكود وسيكون الأمر مرهقًا وغالبًا ستنسى ما قد كتبته حقًا، و قد لا تعدله أنت بل يعدله مبرمج آخر قد لا يفطن للتكرار مما يولد أخطاء مستقبلية. وبالتالي عندما تطور برنامجًا لحل مشكلة ما، وتجد أنك تقوم بالكثير من عمليات النسخ واللصق لنفس الكود لاستخدامه في أكثر من موضع، فابحث عن طريقة أخرى لكتابة هذا الكود، وفكر كيف يمكن أن تتجنب تكرار نفسك. ادمج الأجزاء الصغيرة لإنجاز أعمال أكبر يعتبر الدمج Composition من قواعد البرمجة المهمة، وهو يعني تجزئة المسائل البرمجية إلى مجموعة عناصر أصغر، كل جزء يقوم بمهمة محددة وواضحة، بعدها يتم دمج هذه الأجزاء لتشكيل جزء أكبر وأكثر تعقيدًا ينجز العمل بأكمله. يمكنك على سبيل المثال تطبيق هذه القاعدة إذا كنت مطور واجهة أمامية وتريد تطوير واجهة تطبيق ما وكتابة الكود البرمجي اللازم لتحقيق تصميم معين، حيث يمكنك تحويل كل عنصر من عناصر التصميم إلى مكون مستقل له الكود الخاص به، ثم تجمع هذه المكونات مع بعضها في النهاية لتحصل على التصميم الكامل. كما يتم تطبيق هذا المبدأ بشكل واضح في البرمجة كائنية التوجه OOP، من خلال تعريف صنف Class مستقل لكل جزء أو سلوك محدد من نظامك البرمجي، وجعل هذه الأصناف تتعاون مع بعضها لتنجز العمل المطلوب. باتباع هذه القاعدة ستوفر على نفسك كتابة أكواد ضخمة ومعقدة وصعبة الفهم. وتركز على برمجة كل مكون ليقوم بشيء واحد فقط، وإذا احتجت لتعديل جزء ما في برامجك فستعدل فقط الأجزاء التي طرأ عليها التعديل بكل سلاسة. فإذا كانت لديك شيفرة برمجية ضخمة لمكون ما في أحد برامجك تنجز عدة أمور مختلفة في نفس الوقت، فكر إن كان بالإمكان تقسيمها لأجزاء منفصلة أكثر تحديدًا. لا تبرمج ما لا تحتاجه من أهم قواعد البرمجة التي عليك اتباعها قاعدة YAGNI وهي اختصار للعبارة "You Aren't Gonna Need It" التي تعني أنت لن تحتاجها! لذا لا تقم ببرمجتها. فلا ينبغي عليك أن تكتب في برامجك أي أكواد لإنجاز مهام أو وظائف معينة تحل من خلالها مشكلة غير موجودة بالأساس، أو تضيف ميزة لا تحتاجها الآن لكنك تتوقع أنك ستحتاجها في مرحلة لاحقة. فإذا طلب منك على سبيل المثال كتابة كود برمجي يتحقق من صحة البريد الإلكتروني وكلمة المرور عند تسجيل دخول المستخدمين، فلا داعي لأن تتحقق أيضًا من صحة اسم المستخدم ورقم هاتفه لأنك قد لا تحتاج لهذا أبدًا. باختصار، كي تطبق هذه القاعدة ركز فقط على كتابة القدر المطلوب من الكود البرمجي الذي يحقق متطلباتك الحالية بالضبط بلا زيادة ولا نقصان، ولا داعي لأن تستشرف المستقبل. افصل الأكواد في أجزاء مستقلة يطلق على هذه القاعدة اسم فصل الاهتمامات "Separation of Interests" وهي من قواعد البرمجة الضرورية، وتؤكد على أهمية تصميم البرنامج ضمن وحدات أو أجزاء فريدة معزولة عن بعضها البعض. يعتبر أسلوب نموذج وعرض ومتحكم MVC من أوضح الأمثلة على تطبيق هذه القاعدة، ففي هذا النموذج يتم تنظيم كود البرامج ضمن ثلاثة أجزاء هي: النموذج Model الذي يتفاعل مع البيانات ويجلبها من قاعدة البيانات، والعرض View الذي يمثل الواجهة المرئية التي يتفاعل معها المستخدم بشكل مباشر، والمتحكم Controller الذي يمثل الوسيط بين العرض والنموذج ويربط بينهما. فالمتحكم يتلقى طلبات المستخدم من العرض أو واجهة المستخدم، ويعالجها، ثم يتصل بالنموذج ويطلب منه جلب ما يريده المستخدم من قاعدة البيانات، ثم يعيد النتيجة مرة أخرى إلى العرض ويظهرها على واجهة المستخدم. عند كتابة برامجك بهذا الأسلوب لن يحتاج الكود البرمجي الذي يتعامل مع قاعدة البيانات إلى معرفة تفاصبل عمل كود عرض البيانات، فكود العرض يحصل على المدخلات من المستخدم، وكود المتحكم يعالج هذه البيانات، وبهذا يكون كل جزء من الكود مستقلًا تمامًا. إن اتباع هذه القاعدة في البرمجة يمكنك من الحصول على كود برمجي سهل التطوير والصيانة، فإذا احتجت على سبيل المثال إلى إعادة كتابة كود العرض، فيمكنك القيام بذلك أن يتأثر أي شيء في كود حفظ ومعالجة البيانات. هذا الأسلوب يستخدم في العديد لغات البرمجة وأطر العمل، فمن لغات البرمجة التي تستخدم نموذج MVC لغة C++ وC# و Java و Ruby …إلخ. ومن أطر العمل التي تستخدم نموذج MVC إطار العمل أنجولر Angular وجانغو Django وفلاسك Flask ولارافيل Laravel …إلخ. اكتب أكوادًا نظيفة تعد قاعدة كتابة الأكواد البرمجية النظيفة والمفهومة وسهلة الصيانة مهارة ضرورية على كل مبرمج إتقانها، ويشير مصطلح الكود النظيف Clean Code ببساطة إلى الكود سهل القراءة والفهم من قبل المبرمجين الآخرين، وعادةً عندما تتبع كافة قواعد البرمجة التي وردت أعلاه ستحصل بالنتيجة على كود نظيف بصورة تلقائية. احرص كذلك على تنظيف أكوادك من كافة التعليمات لن تستخدم عند تنفيذ البرنامج، واحذف المتغيرات التي صرحت عنها لكنك لم تستخدمها، والدوال البرمجية التي عرفتها لكنها لم تنادها على الإطلاق، والأصناف التي لم تشتق منها أي كائنات برمجية، وكذلك الأكواد التي كتبتها ثم حولتها إلى تعليقات ضمن الكود لإبطال عملها …إلخ. فهذه كلها أكواد ميّتة وأنت لا تريد أن تجعل برنامجك مقبرة! وكي تعرف بسهولة إن كان الكود الذي تكتبه نظيفًا، اعرضه على مبرمج آخر لم يسبق له أن اطلع عليه واطلب منه تعديل أمر ما فيه، فإذا تمكن المبرمج من فهم الغرض من التعليمات البرمجية الخاصة بك، وعدلها وأضاف أكواده الخاصة عليها بسهولة ومرونة، فهذا يعني أن كتبت بالفعل كودًا نظيفًا. وتذكر أن كتابة الكود النظيف ليس مهارة يمكن اكتسابها بين عشيّة وضحاها بل هو ميزة يتم تطويرها بالممارسة والتدرب على تطبيق كافة هذه القواعد كلما قمت بكتابة كود برمجي ما حتى تكتسب الخبرة المطلوبة. ملخص لأهم قواعد البرمجة التي ينبغي للمبرمج اتباعها نعرض ما يلي ملخص قواعد البرمجة التي ذكرناها ليسهل عليك تذكرها وحفظها: احرص على كتابة كود سهل القراءة والفهم مع إضافة التعليقات التوضيحية إن لزم فهي ضرورية لتوثيق وتسهيل فهم الكود وصيانته عند العودة له لاحقًا. اكتب أكوادًا بسيطة ومباشرة والمقصود هنا أن تصمم برامجك ببساطة، وتحذف أي ميزة لا تحتاجها، فالأنظمة البرمجية تعمل بشكل أفضل وتكون أسهل في الصيانة كلما كانت أبسط. افصل الأكواد في أجزاء معزولة بحيث يكون كل جزء مسؤولًا على إنجاز مهمة محددة. لا تكرر نفسك ولا تنسخ وتلصق نفس الكود في أكثر من موضع، بل اكتبه مرة وأعد استخدامه كلما دعت الحاجة. لا تضف ما لن تحتاجه كي لا تهدر وقتك ومالك على أشياء لمجرد أنك تتوقع أنك ستحتاجها لاحقًا، فقد لا تحتاجها أبدًا. اكتب كودًا نظيفًا غير مكرر أو معقد، وهو ما ستحصل عليه إذا اتبعت كل القواعد السابقة. ماذا سيحصل لو لم أتبع قواعد البرمجة؟ عندما تبدأ تعلم البرمجة ستكون سعيدًا عندما يعمل أي برنامج بالشكل الصحيح، وقد لا تعير اهتمامًا لمدى أهمية اتباع قواعد البرمجة، لكن يجب أن تضع في الحسبان أنك إذا لم تعتد على اتباع القواعد الصحيحة في كتابة أكوادك البرمجية، فإن هذا سينعكس سلبًا على أداء برامجك على المدى البعيد. في تلك الحالة قد تحصل على كود سيء وفوضوي وغير مفهوم، وصحيح أن برنامجك يعمل، لكنه سيكون مكتظَا بالأكواد البرمجية المكررة، أو الوظائف غير المستخدمة، أو المتغيرات التي لا فائدة من وجودها، وبرنامج كهذا قد يتعطل أو يفشل بعد أول تعديل أو تطوير مطلوب. فتعلم هذه القواعد وتطبيقها من شأنه أن يحسِّن من خبرتك ويطور أسلوب كتابة شيفراتك البرمجية، وأغلب أصحاب الأعمال سيطلعون على عينة من كود كتبته سابقًا وسيفضلون مبرمجًا محترفًا يتبع هذه القواعد عمن لا يتبعها. وتذكر أن البرمجة لا تقتصر على كتابة تعليمات برمجية تعمل فحسب، بل هي كتابة تعليمات برمجية فعالة ذات جودة عالية ويمكن صيانتها وتعديلها بكل مرونة سواء من قبلك أو من قبل أي مبرمج آخر، لذا احرص على اتباع هذه القواعد البرمجية والتدرب على تطبيقها قدر المستطاع لأنها سبيلك لتكون مبرمجًا ناجحًا ومتميزًا. ماذا بعد تعلم قواعد البرمجة؟ بعد أن تتقن أساسيات البرمجة وتتعلم تطبيق قواعد البرمجة قد تتساءل: كيف يمكنني المضي قدمًا وتطوير مهاراتي البرمجية بصورة أكبر؟ سؤال جيد، سأجيبك! من الأمور التي ينبغي عليك تعلمها في رحلتك لاحتراف البرمجة مهارات إعادة التصميم لمشاريعك الحالية، والتعرف على مفهوم أنماط التصميم وتطبيقها لحل المشكلات التقنية التي تواجهك مستقبلًا. يشير مفهوم إعادة التصميم "Refactoring" إلى الخطوات التي ينبغي للمبرمج اتباعها لتعديل الشيفرات البرمجية وإعادة هيكلتها وتحسينها والعثور على أي أخطاء أو ثغرات كامنة فيها، مع المحافظة على وظائفها الأساسية. أما أنماط التصميم "Design Patterns"، فهي عبارة عن نماذج يضعها المطورون لحل المشكلات المتكررة والمتشابهة، وستكتسب من خلال تعلمها القدرة على إعادة استخدام نفس الأنماط في كل مرة تظهر فيها نفس المشكلة، ويمكنك اعتبارها بمثابة فكرة مجردة توضح طريقة حل المشكلة وتسهل عليك تحقيقها برمجيًا. الخلاصة تعرفنا في مقال اليوم على أهم قواعد البرمجة التي على المبرمج اتباعها، فلا ينبغي أن تتعلم أساسيات البرمجة فقط، بل عليك أن تتقدم خطوة للأمام وتحرص على اتباع أفضل الممارسات البرمجية عند كتابة الكود كي يكون المنتج الرقمي الذي تنشؤه أكثر كفاءة وموثوقية واحترافية. وتذكر أنه يمكن للجميع كتابة كود برمجي يفهمه الحاسوب لكن القليلين فقط يمكنهم كتابة كود جيد يفهمه الإنسان أيضًا، ومن خلال حرصك على اتباع قواعد البرمجة التي شرحناها تضمن أن تكون من هذه الفئة القليلة من المبرمجين المحترفين، كل ما تحتاجه هو التدريب الجيد على كتابة الأكواد والبرامج بصورة محسنة تراعي هذه القواعد بأفضل طريقة. اقرأ أيضًا تعلم تطوير الويب دليلك الشامل إلى لغات البرمجة أسهل لغات البرمجة ما هي فوائد تعلم البرمجة؟1 نقطة
-
تعرفنا في المقال السابق على كيفية التعامل مع رسائل الأخطاء في بايثون وعلى الطرق المساعدة في فهم فحواها وإيجاد مسببات ظهورها، وذلك من خلال الاستعانة بمتتبع الأخطاء لتحديد مصدر الخطأ أو باستخدام منقح صياغة لتلافي وقوع أخطاء ما أمكن، أو اللجوء إلى الإنترنت بحثًا عن تفسير لمضمون رسالة الخطأ. ولكن ماذا لو فشلت هذه المحاولات، أو إن لم تجد في بحر الإنترنت سؤالًا مشابهًا لسؤالك، في هذه الحالة لابد من طرح سؤالك في أحد المنتديات أو ربما عبر إحدى المجموعات البريدية. في حال اضطررت لطرح سؤال جديد، فيجب عليك الالتزام بالعديد من القواعد والأصول لزيادة احتمالية الرد على سؤالك. سيرشدك هذا المقال نحو كيفية طلب المساعدة البرمجية باحترافية. كيفية طلب المساعدة البرمجية عند فشل كل من عمليات البحث على الإنترنت ومنقحات الصياغة في تحديد مشكلة برنامجك وحلها، ما من سبيل أمامك سوى طلب المساعدة البرمجية عبر الإنترنت، إلا أن لطلب النصيحة آداب وأصول ليكون أكثر فعالية، فعليك الاستفادة بكفاءة من وقت مطوري البرمجيات المحترفين كونهم مستعدون للإجابة عن تساؤلاتك بالمجان. ويجب أن يكون هذا الحل هو الأخير دائمًا بالنسبة لك، فقد تمر ساعات أو أيام قبل أن يرد أحد الأشخاص على سؤالك المنشور هذا إن رد أحدهم عليه أصلًا، لذا يبقى البحث في الإنترنت هو الأسرع عبر البحث عن آخرين قد طرحوا نفس سؤالك وقراءة الإجابات التي تلقوها، ومن هنا جاءت فكرة بناء التوثيقات ومحركات البحث، بغية أتمتة عمليات الإجابة عن الأسئلة التي كان يتعين على البشر الإجابة عنها. وفي حال سدت كل السبل في طريقك واستنفذتَ خياراتك بحيث لم يتبقَ أمامك سوى خيار طرح السؤال على جمهور المبرمجين، فتجنب الأخطاء الشائعة التالية: إضاعة الوقت بالسؤال عما إذا كان من المقبول طرح سؤالك بدلًا من طرحه مباشرةً. أن يكون سؤالك ضمنيًا وغير مباشر. طرح السؤال في الموقع الإلكتروني أو المنتدى غير المناسب. أن يكون عنوان السؤال غير محدد من قبيل "لدي مشكلة" أو "أرجو المساعدة". أن تذكر كون برنامجك لا يعمل دون توضيح الطريقة التي تريدها أن يعمل بها. عدم تضمين رسالة الخطأ كاملةً. عدم مشاركة الشيفرة. مشاركة شيفرة رديئة التنسيق. عدم ذكر الخطوات التي قد جربتَها أصلًا. عدم ذكر معلومات نوع نظام التشغيل وإصداره. طلب كتابة برنامج كامل. إن قائمة "أشياء لا يجب فعلها" السابقة ليست بهدف اللباقة فحسب، وإنما لأن فعلها لن يمكّن من يرغب بمساعدتك من تحقيق ذلك، فالخطوة الأولى لأي شخص قد يساعدك تتمثّل في تنفيذ الشيفرة محاولًا إعادة إظهار المشكلة بنفس الطريقة التي واجهتك، ولإتمام ذلك لا بد من توفر الكثير من المعلومات حول شيفرتك وحاسوبك وتطلعاتك حول نتائج البرنامج. فمن الشائع جدًا تقديم معلومات قليلة جدًا حول السؤال المطروح بدلًا من تقديم الكثير منها، وسنستعرض في الأقسام التالية الممارسات الواجب اتباعها لتجنب هذه الأخطاء الشائعة وفيها سنفترض بأنك تنشر أسئلتك في أحد المنتديات البرمجية، إلا أن القواعد نفسها تنطبق في حال طرحها عبر البريد الإلكتروني لشخص واحد أو لقائمة بريدية. قلل من النقاشات غير المجدية بتقديم كافة المعلومات اللازمة مقدما لو افترضنا أنك تطرح على أحدهم سؤالك وجهًا لوجه، فسيكون من المناسب والمريح سؤاله حول إمكانية طرح سؤالك لمعرفة ما إذا كان متوفرًا، ولكن في المنتديات الأمر مختلف، فمن سيساعدك قد يؤجل رده عليك إلى حين توفر الوقت المناسب له، ونظرًا لاحتمالية وجود ساعات ما بين طرح السؤال والحصول على الردود، فمن الأفضل طرح السؤال مباشرة وتوفير كافة المعلومات التي قد يحتاجها من سيساعدك بدلًا من إضاعة الوقت في السؤال عن إمكانية طرح السؤال، وبذلك وفي حال عدم تلقيك لأي ردود، يمكنك ببساطة نسخ معلومات سؤالك كاملًا لطرحها في منتدى أخر. اطرح سؤالك على هيئة سؤال فعلي قد تفترض مجازًا أن مُساعديك على اطلاع حول ما تتحدث عنه لدى شرح مشكلتك، إلا أن البرمجة مجال واسع جدًا وقد لا يكون لديهم الخبرة في الجزئية التي تواجه مشكلة فيها، لذا من المهم طرح سؤالك على هيئة سؤال فعلي، فعلى الرغم من كون الجمل التي تبدأ بعبارات من قبيل "أريد …. " أو "الشيفرة لا تعمل" قد توضح ماهية سؤالك، إلا أنه من الضروري تضمين أسئلة صريحة ومباشرة، أي جمل تنتهي بإشارات استفهام، وإلا وفي حال عدم استخدامها قد لا يتضح تمامًا ما تطلبه. اطرح سؤالك في المكان المناسب غالبًا سيكون من غير المجدي طرح سؤال حول بايثون في منتدى مخصص لجافاسكربت، أو سؤال حول الخوارزميات في قائمة بريدية مخصصة لأمن الشبكات، فغالبًا ما تتضمن المنتديات والقوائم البريدية على مستندات تتضمن الأسئلة الشائعة FAQ أو صفحات وصف لطبيعتها والتي تبين المواضيع المناسبة للنقاش فيها. فعلى سبيل المثال تتمحور القائمة البريدية python-dev حول الميزات التصميمية للغة بايثون ولا تمثل قائمة بريدية عامة للمساعدة حول بايثون بصورة عامة. وستوجهك صفحة المساعدة إلى المكان المناسب وفق طبيعة سؤالك حول بايثون. لخص سؤالك في العنوان لعل من أحد فوائد نشر سؤالك في منتدى على الإنترنت أن المبرمجين المستقبليين ممن سيواجهون نفس المشكلة سيجدون سؤالك وإجابته لدى البحث على الإنترنت، لذا تأكد من اختيارك لعنوان يلخص سؤالك بالفعل الأمر الذي يساعد على تنظيمه في محركات البحث، فالعناوين العامة من قبيل "أرجو المساعدة" أو "لماذا لا يعمل هذا الأمر؟" مبهمة، وكذلك الأمر في حال إرسال بريد إلكتروني، ففي حال اختيارك لعنوان ذو معنى، فهذا سيساعد المتلقي على معرفة فكرة سؤالك بمجرد تصفحه لصندوقه الوارد. وضح الهدف المرجو من شيفرتك سؤال من قبيل "لماذا لا يعمل برنامجي؟" يتجاهل تفاصيل دقيقة حول ما المتوقع من هذا البرنامج فعله أصلًا، فلن يكون هذا بالأمر الجلي دائمًا لمن سيساعدك كونه لا يعرف على وجه التحديد غايتك المرجوة من البرنامج، وحتى إن كان سؤالك من نوع "لماذا يظهر هذا الخطأ لي؟" فمن المفيد أيضًا تحديد الهدف النهائي للبرنامج، ففي بعض الأحيان قد يرشدك المساعد إلى منهجية مختلفة تمامًا في تحقيق غايتك ما يجعلك تتخطى المشكلة تمامًا بدلًا من إضاعة الوقت في محاولة حلها. ضمّن رسالة الخطأ كاملة تأكد دائمًا من نسخ رسالة الخطأ بأكملها مع ملخص متتبّع الأخطاء، فإن وصف الخطأ وحده كقولك "أتلقى خطأ من نوع Out of range" لا يوفر لمن يساعدك تفاصيلًا كافية لاكتشاف ماهية الخطأ، كما يجب عليك تحديد ما إذا كان خطأً عابرًا أم دائمًا، وفي حال كنت قد اكتشفت الظروف التي يحدث عندها الخطأ، فضمّنها أيضًا في سؤالك. شارك شيفرتك كاملة إلى جانب رسالة الخطأ الكاملة وملخص متتبّع الأخطاء، شارك الشيفرة المصدرية لبرنامجك كاملةً، بحيث يتمكن من سيساعدك من تشغيلها على حاسوبه مستخدمًا منقّح أخطاء لاكتشاف ما يحدث، فيجب عليك توفير نسخة من شيفرتك فيها ما يهم من سيساعدك بالكامل بأقل تعقيد وبحيث تكون قابلة للتعديل وإعادة التنفيذ، وهذا ما أطلق عليه موقع Stack Overflow اختصارًا MCR. إذ يرمز الحرف M إلى Minimal بمعنى أن تكون الشيفرة أقصر ما يمكن مع بقائها تسبب المشكلة التي تواجهك، أما الحرف C فيرمز إلى Complete بمعنى أن تكون الشيفرة كاملة ومتضمنة كل ما يلزم لظهور المشكلة، والحرف R فيرمز إلى Reproducible بمعنى أن الشيفرة ستسبب نفس المشكلة التي تصفها عند كل تنفيذ، أما إن كان برنامجك مضمنًا في ملف واحد، فسيكون من السهل إرفاقه بسؤالك بعد التأكد من تنسيقه بطريقة صحيحة. اجعل شيفرتك مقروءة ومفهومة باستخدام التنسيق الملائم إن الهدف الرئيسي من إرفاق الشيفرة الخاصة ببرنامجك مع سؤالك هو السماح لمن سيساعدك بتشغيل هذه الشيفرة للحصول على نفس الخطأ الظاهر لديك، فلا يحتاج هذا الشخص مجرد الشيفرة فحسب، بل يحتاجها منسقة بالشكل الصحيح، فيجب عليك التأكد من كونه قادرًا على نسخها لتكون جاهزة لتشغيلها مباشرةً، فمن الجدير بالملاحظة مثلًا أن العديد من مضيفي البريد الإلكتروني يزيلون المسافات البادئة تلقائيًا، ما يجعل الشيفرة تبدو بالشكل: def knuts(self, value): if not isinstance(value, int) or value < 0: raise WizCoinException('knuts attr must be a positive int') self._knuts = value فالأمر ليس بمجرد الوقت الذي سيستغرقه من سيساعدك في إعادة إدخال المسافات البادئة لكل سطر في شيفرتك، بل وحيرته بشأن مقدارها لكل سطر. وللتأكد من الحفاظ على صحة تنسيق الشيفرة الخاصة ببرنامجك، انسخها إلى أحد مواقع مشاركة الشيفرات مثل https://pastebin.com/ أو https://gist.github.com/ والتي تخزن شيفرتك على هيئة رابط مختصَر وعام، فمثلًا إن أرفقت الشيفرة مع سؤالك على هيئة رابط مثل https://pastebin.com/XeU3yusC سيكون أيسر وأسهل من إرفاقها كملف مرفق. وإذا كنت في صدد نشر شيفرة برنامجك في أحد المواقع الإلكترونية مثل stackoverflow أو قسم الأسئلة في أكاديمية حسوب أو reddit، فتأكد من استخدامك لأدوات التنسيق التي توفرها الصناديق النصية فيها، فمثلًا باستخدامك لمسافة بادئة مكونة من أربعة مسافات سيضمن بالنتيجة استخدام نمط خط ذو تباعد مفرد للشيفرة بالغالب وهو الأسهل للقراءة، كما يمكنك تضمين الشيفرة ما بين علامات اقتباس مائلة (`) لتنسيقها بنمط خط ذو تباعد مفرد. وعادةً ما تتضمن هذه المواقع رابطًا لشرح قواعد التنسيق، والتي بعدم اتباعها ستظهر شيفرتك بشكل غير واضح، كأن تظهر مكتوبة في سطر واحد بالكامل، كما يلي: def knuts(self, value):if not isinstance(value, int) or value < 0:raise WizCoinException('knuts attr must be a positive int') self._knuts = value ومن المهم أيضًا عدم مشاركتك للشيفرة على هيئة صورة أو لقطة شاشة، الأمر الذي يجعل من المستحيل نسخها، ناهيك عن كونه في هذه الحالة -على الغالب- غير مقروء. اذكر في سؤالك جميع المحاولات التي أجريتها عند نشرك لسؤال ما، لا تنسَ إخبار من سيساعدك بما قد حاولت تجريبه كحلول وما كانت نتائج كل محاولة، لما لهذه المعلومات من دور في توفير الوقت والجهد على من سيساعدك في تجربة حلول غير ناجحة، ناهيك عن الانطباع الذي تعطيه حيال بذلك لجهد في سبيل حل مشكلتك. كما أن تقديمك لهذه المعلومات يوضح أنك تطلب المساعدة فقط، ولست اتكاليًا تنتظر من يكتب لك شيفرة لبرنامجك عوضًا عنك. فالخبر السيئ أن الكثير من طلاب علوم الحاسوب اعتادوا أن يطلبوا من الأشخاص على الإنترنت حل واجباتهم، أو من المستقلين أن يعدّو لهم تطبيقات سريعة مجانًا، متناسين أن منتديات المساعدة البرمجية لم تعد أصلًا لهذا الغرض. وصف الإعدادات التي تستخدمها إن لإعدادات حاسوبك الأثر البالغ في كيفية تنفيذ شيفرة برنامجك وعلى نوعية الأخطاء التي قد تنتج، ولضمان تمكن من سيساعدك من الحصول على نفس المشكلة التي تواجهك على حاسوبه، يجب عليك تقديم المعلومات التالية حول حاسوبك: نوع نظام التشغيل وإصداره، كأن تذكر أنه الإصدار الاحترافي من ويندوز 10 أو إصدار كاتالينا (الخامس عشر) من ماك أو إس. إصدار بايثون المستخدم في تنفيذ برنامجك، كأن تذكر بأن الإصدار 3.7 من بايثون أو الإصدار 3.6.6 منها. أي وحدات خارجية تستخدمها في برنامجك مع ذكر إصدار كل منها، كأن تذكر أنك تستخدم الإصدار 2.1.1 من وحدة جانغو. ولمعرفة إصدارات الوحدات الخارجية المستوردة في برنامجك، يمكنك تشغيل الأمر pip list، كما يمكنك التأكد من رقم إصدار كل منها باستخدام سمة الإصدار __version__، كما في المثال التالي المكتوب ضمن صَدفة بايثون التفاعلية: >>> import django >>> django.__version__ '2.1.1' ورغم كون هذه المعلومات ليست بذلك القدر من الأهمية، إلا أن ذكرها سيقلل من الوقت الضائع في النقاشات (الصد والرد)، لذا من المحبذ عرضها من البداية. أمثلة على أسئلة متكاملة نبين فيما يلي مثالًا على سؤال مطروح بطريقة صحيحة وفقًا للإرشادات والنصائح الواردة في هذا المقال: محرك الويب سيلينيوم: كيف أجد كافّة سمات العنصر؟ لدى استخدامي لوحدة سيلينيوم في بايثون، فبإمكاني الحصول على قيمة أي سمة من سمات كائن عنصر الويب باستخدام التابع ()get_attribute بالشكل: get_attribute(): foo = elem.get_attribute('href') وفي حال عدم وجود اسم السمة href، ستكون القيمة المعادة لا شيء None. سؤالي هو: كيف أحصل على قائمة بكافة سمات كل عنصر؟ فيبدو أنه لا يوجد توابع لجلب السمات من قبيل get_attributes() أو ()get_attribute_names. علمًا أني أستخدم الإصدار 2.44.0 من وحدة سيلينيوم في بايثون. لقد ورد هذا السؤال في قسم الأسئلة في أكاديمية حسوب، وفيه نلاحظ بأن العنوان قد لخص مضمون السؤال كاملًا في جملة واحدة، إذ ذُكرت المشكلة وهي التي تتحدث عن صيغة الخطأ الذي يظهر أثناء التنفيذ، وبذلك إذا قرأ شخص ما هذا العنوان مستقبلًا في نتائج البحث، فسيتضح له مباشرةً فيما إذا كان ذو صلة بسؤاله أم لا. كما أن الشيفرة ضمن السؤال منسقة بطريقة جيدة، وأجزاء النص مفصولة على هيئة فقرات، كما أن وجه السؤال واضح تمامًا، وقد تمت الإشارة له بعبارة "كيف أحل المشكلة؟"، كما يتحدث عن حدوث المشكلة أحيانًا وليس دائمًا، وهذا يدل على أن السائل قد حاول بالفعل إيجاد جواب وجرب حل الموضوع وتجريبه عدة مرات قبل أن يتجه لطرح السؤال. الخلاصة لعل وصولك إلى إجابات عن أسئلتك الخاصة بنفسك هي واحدة من أهم المهارات التي عليك اكتسابها كمبرمج، وهنا يمثّل الإنترنت ثروة من المصادر المتضمنة الإجابات التي تحتاج. إلا أن الإجراء الأول الذي يجب اتخاذه هو محاولة تحليل رسالة الخطأ المبهمة المعروضة من قبل بايثون، وفي حال عدم تمكنك من إيجاد حل لمشكلتك عبر البحث في الإنترنت، فحاول عندها نشر سؤالك في أحد المنتديات البرمجية أو إرسال بريد إلكتروني لأحد المختصين، إذ قدمنا في هذا المقال نصائح وإرشادات من شأنها ضمان كون هذه العملية فعالة ومثمرة من خلال طرح سؤال جيد. وتتمثل مواصفات السؤال الجيد في كونه محددًا ومفصلًا، يوفر الشيفرة المصدرية المسببة للخطأ كاملةً بالإضافة إلى رسالة الخطأ نفسها، شارحًا الإجراءات المجربة أصلًا مع تحديد نوع نظام التشغيل وإصدار بايثون المستخدم. وبحصولك على إجابة لسؤالك، لن تقتصر الفائدة عليك، بل على أي مبرمج مستقبلي قد يواجه نفس مشكلتك. وتذكر أن البرمجة مجال واسع جدًا، ولا يمكن لأحد أن يحيط بجميع تفاصيله، لذا لا تشعر بالإحباط إن اضطررت للبحث باستمرار عن إجابات لأسئلتك، فحتى مطورو البرمجيات المتمرسون يبحثون في الإنترنت عن التوثيقات والحلول يوميًا، وبدلًا من تضييع وقتك بالإحساس بالإحباط ركز على اكتساب مهارة إيجاد الحلول، وهي خطوة مهمة في طريقك لتصبح خبير بايثون. ترجمة -وبتصرف- للفصل الأول "التعامل مع الأخطاء وطلب المساعدة" من كتاب Beyond the Basic Stuff with Python لصاحبه Al Sweigart. اقرأ أيضًا المقال السابق: التعامل مع رسائل الأخطاء في بايثون كيفية استخدام سطر أوامر بايثون التفاعلي كيفية التعامل مع الأخطاء البرمجية1 نقطة
-
تعد بايثون Python إحدى أشهر لغات البرمجة وأكثرها استخدامًا، وهي خيار ممتاز ليبدأ به المبرمجون المبتدئون، إذ يمكن استخدامها في معظم المجالات، بدءًا من ألعاب الفيديو، وحتى تحليل البيانات والتعلم الآلي. بايثون هي لغة برمجة عالية المستوى، وتفاعلية وكائنية. وتتمتع بمقروئية عالية، إذ تستخدم كلمات إنجليزية بسيطة، على خلاف اللغات الأخرى التي تستخدم الرموز، كما أنّ قواعدها الإملائية والصياغية بسيطة، ما يجعل تعلمها سهلًا موازنةً بلغات برمجة أخرى. وفي بدايات تعلّمك لغة بايثون ، وكما هو الحال في رحلة تعلّم أي لغة برمجة، قد تواجهك بعض العقبات ورسائل الأخطاء غير المفهومة، وفي هذه المرحلة من الشائع الشعور بالفشل لدى اضطرارك لاستشارة مواقع الإنترنت عدة مرات في اليوم. لكن حتى أمهر مطوري البرمجيات يبحثون في الإنترنت ويراجعون التوثيقات لإيجاد إجابات حول أسئلتهم البرمجية. كن على يقين بأنه طالما أنك لا تمتلك الموارد الاجتماعية أو المادية اللازمة للحصول على مدرس خصوصي للإجابة على أسئلتك البرمجية، فما من سبل أمامك سوى حاسوبك والإبحار في محركات البحث وصبرك، والخبر الجيد أنه من شبه المؤكد كون جميع تساؤلاتك قد طُرحت من قبل. فحتى تكون مبرمجًا لا بد من امتلاكك مهارة إيجاد إجابات على أسئلتك بنفسك، الأمر الذي يفوق بأهميته معرفتك لأي خوارزمية برمجية أو بنية معطيات ما. سيعمل هذا المقال على إرشادك نحو تطوير هذه المهارة البالغة الأهمية. كيفية فهم رسائل الأخطاء في بايثون عندما يواجه العديد من المبرمجين رسائل الأخطاء المليئة بالثرثرة التقنية، فإن أول ما يفكرون بفعله هو تجاهلها تمامًا، إلا أن رسالة الخطأ هذه تتضمن الإجابة حول الخطأ الحاصل في البرنامج، فإيجاد هذه الإجابة عبارة عن عملية ذات خطوتين: الأولى هي فحص متتبع الأخطاء، والثانية هي البحث في الإنترنت حول رسالة الخطأ هذه. فحص متتبع الأخطاء تتوقف برامج بايثون عن العمل لدى مصادفتها استثناءً دون وجود عبارة استثناء except للتعامل معه، وفي حال حدوث ذلك، تُعرض رسالة بهذا الاستثناء مع تتبّع له وهو ما يدعى أيضًا مكدّس الاقتفاء Stack trace، والذي يُظهر مكان حدوث الاستثناء في برنامجك ومسارات استدعاءات الدوال المسببة له. وبغية التدرب على كيفية قراءة تتبعات الأخطاء، سنكتب البرنامج البسيط التالي ونحفظه باسم abcTraceback.py، إذ تلعب أرقام الأسطر دور المرجع والدليل للسطر وليست جزءًا من الشيفرة. 1. def a(): 2. print('Start of a()') 1 3. b() # Call b(). 4. 5. def b(): 6. print('Start of b()') 2 7. c() # Call c(). 8. 9. def c(): 10. print('Start of c()') 3 11. 42 / 0 # This will cause a zero divide error. 12. 13. a() # Call a(). في البرنامج السابق، تستدعي الدالة ()a الدالة ()b، التي تستدعي بدورها الدالة ()c المتضمنة للتعبير الرياضي 42/0 المسبب لخطأ القسمة على صفر، فعند تشغيل هذا البرنامج، سيبدو الخرج بالشكل: Start of a() Start of b() Start of c() Traceback (most recent call last): File "abcTraceback.py", line 13, in <module> a() # Call a(). File "abcTraceback.py", line 3, in a b() # Call b(). File "abcTraceback.py", line 7, in b c() # Call c(). File "abcTraceback.py", line 11, in c 42 / 0 # This will cause a zero divide error. ZeroDivisionError: division by zero لنتفحص الآن تقرير متتبع الأخطاء سطرًا بسطر، والذي يبدأ من السطر: Traceback (most recent call last): وتهدف هذه الرسالة إلى إبلاغك بأن ما يتلوها هو تقرير متتبّع الأخطاء، وتشير العبارة most recent call last والتي تعني أن الاستدعاء الأخير سيظهر في نهاية التقرير إلى كون استدعاءات التوابع ستظهر في التقرير بنفس ترتيب ورودها في الشيفرة، بدءًا من استدعاء أول دالة وانتهاءً بآخرها. أما السطر التالي فيظهر تقرير تتبّع استدعاء أول دالة: File "abcTraceback.py", line 13, in <module> a() # Call a(). وندعو هذين السطرين بملخص كائن الإطار، كما أنهما يُظهران معلوماتهما ضمن كائن إطار. فعند استدعاء دالة ما فإن كل من بيانات المتغير المحلي والمكان المخصص في الشيفرة لإسناد القيمة المعادة من الدالة بعد استدعائها يُخزنان ضمن كائن إطار، إذ تتضمن كائنات الأطر كل من المتغيرات المحلية وغيرها من البيانات المتعلقة باستدعاء الدوال، إذ يتم إنشاء هذه الكائنات لحظة استدعاء الدوال وينتهي بإعادة الدالة لقيمتها. ويُظهر متتبّع الأخطاء ملخصًا على هيئة إطار لكل إطار قد انتهى دوره بإعادة قيمة دالته، ونلاحظ من التقرير أعلاه أن استدعاء هذه الدالة قد تم في السطر ذو الرقم 13 من الملف abcTraceback.py، ويشير الوسم <module> إلى كون هذا السطر مصرح عنه ضمن المجال العام، ليظهر بعدها السطر 13 نفسه مسبوقًا بمسافتين بادئتين. وتظهر الأسطر الأربعة التالية ملخصات الأطر التالية: File "abcTraceback.py", line 3, in a b() # Call b(). File "abcTraceback.py", line 7, in b c() # Call c(). ومنه نستنج أنه قد تم استدعاء الدالة ()b في السطر الثالث ضمن الدالة ()a، ما أدى بدوره إلى استدعاء الدالة ()c في السطر 7 ضمن الدالة ()b. ومن الجدير بالملاحظة أن تقرير التتبع لا يُظهر استدعاء الدالة ()print الذي تم في كل من الأسطر 2 و 6 و 10 من الشيفرة رغم تشغيلها حتى قبل استدعاء الدوال آنفة الذكر، والسبب في ذلك هو أن التقرير يشمل فقط الأسطر الحاوية على استدعاءات التوابع المسببة للاستثناء. وآخر إطار من ملخص تقرير تتبع الأخطاء يظهر رقم السطر المتضمن للاستثناء الذي لم يتم التعامل معه متبوعًا باسمه ورسالة الخطأ الخاصة به: File "abcTraceback.py", line 11, in c 42 / 0 # This will cause a zero divide error. ZeroDivisionError: division by zero ومن الجدير بالملاحظة أن رقم السطر المعطى في متتبع الأخطاء هو مكان عثور بايثون على آخر خطأ، وبالتالي من الممكن كون مصدر الخطأ الرئيسي في سطر ما قبله. وتُعرف رسائل الخطأ بكونها مختصرة ومبهمة، فالكلمات الثلاث "قسمة على صفر" لن تعني شيئًا ما لم تكن تعلم أنه من المستحيل قسمة أي عدد على الصفر رياضيًا وبأنه يمثل خطأً برمجيًا شائعًا، وفي برنامجنا السابق ليس من الصعب تحديد موطن الخطأ، فبمجرد النظر إلى رقم سطر الشيفرة في إطار ملخص تقرير متتبع الأخطاء يتضح أن خطأ القسمة على صفر يحدث عند التعبير 42/0 من الشيفرة. والآن دعونا ننتقل إلى حالة أصعب قليلًا. لذا، اكتب الشيفرة التالية ضمن محرر النصوص واحفظ الملف باسم zeroDivideTraceback.py: def spam(number1, number2): return number1 / (number2 - 42) spam(101, 42) ولدى تشغيل هذا البرنامج، سيبدو الخرج كالتالي: Traceback (most recent call last): File "zeroDivideTraceback.py", line 4, in <module> spam(101, 42) File "zeroDivideTraceback.py", line 2, in spam return number1 / (number2 - 42) ZeroDivisionError: division by zero إن رسالة الخطأ هي نفسها كما في المثال السابق، إلا أن خطأ القسمة على صفر في السطر البرمجي return number1 / (number2 - 42) غير واضح تمامًا، ولكن من الممكن استنتاج وجود عملية قسمة من وجود المعامل /، وبأن التعبير (number2-42) يساوي الصفر، وهذا ما يمكننا من استنتاج أن الدالة spam() ستعطي خطأ في حال كان الوسيط الثاني number2 المُمرر لها مساويًا للعدد 42. وقد يشير متتبّع الأخطاء أحيانًا إلى كون الخطأ في السطر التالي لمسبب الخطأ الحقيقي. فعلى سبيل المثال، في البرنامج التالي ينقص السطر الأول منه قوس إغلاق دالة الطباعة: print('Hello.' print('How are you?') إلا أن رسالة الخطأ لهذا البرنامج تشير لكون المشكلة في السطر الثاني منه: File "example.py", line 2 print('How are you?') ^ SyntaxError: invalid syntax والسبب في ذلك هو أن مفسر بايثون لن يلاحظ هذا الخطأ إلا عند قراءته للسطر الثاني، فقد يشير متتبّع الأخطاء إلى مكان حدوث الخطأ والذي لن يكون بالضرورة هو نفس موضع مسبب حصول الخطأ الفعلي. وفي حال فشل إطار الملخص في تقديم ما يكفي من معلومات لاكتشاف الخطأ، أو في حال كون المسبب الحقيقي للخطأ في سطرٍ سابق غير موضح في متتبّع الأخطاء، عندها عليك المرور على برنامجك مستخدمًا منقّح الأخطاء، كما يمكنك التحقق من رسائل السجل بحثًا عن السبب. الأمر الذي قد يستغرق وقتًا ليس بالقليل، لذا فإن البحث في الإنترنت حول المشكلة قد يعطيك دلائل مهمة حول كيفية حلها بسرعة أكبر. البحث حول رسائل الخطأ تكون رسائل الأخطاء في الغالب قصيرة جدًا ولا تمثل جملًا كاملة، والسبب في ذلك هو كونها رسائل تذكيرية وليست تفسيرية، إذ يصادفها المبرمجون بانتظام. وإذا كنت تواجه رسالة خطأ للمرة الأولى، فإن نسخها ولصقها في أحد محركات البحث على الإنترنت سيوصلك في الغالب إلى شرح تفصيلي حول الخطأ وأسباب حدوثه المحتملة. ويبين الشكل التالي نتائج البحث عن الجملة python "ZeroDivisionError: division by zero" أي "خطأ القسمة الصفرية: قسمة على صفر" بايثون، إذ من المفيد تضمين رسالة الخطأ ما بين إشارتي تنصيص في إيجاد عبارة موافقة بدقة، كما أن إضافة كلمة Python يؤدي إلى تضييق نطاق البحث أكثر. نسخ رسالة خطأ ولصقها في إحدى أدوات البحث على الإنترنت يمكن أن يؤمن تفسيراتٍ وحلولًا سريعة. ولا يمكن عد البحث حول رسائل الخطأ شكلًا من أشكال الغش أو الاتكالية، فمن شبه المستحيل أن يحفظ الشخص كافة رسائل الخطأ المحتملة لأي لغة برمجة، إذ يبحث مطورو البرمجيات المحترفون عن إجابات لأسئلتهم البرمجية في الإنترنت يوميًا. وفي حال كون أحد أجزاء رسالة الخطأ التي تواجهك هو خاص بشيفرتك أنت، فمن الأفضل استبعاده أثناء البحث، ولتوضيح هذه النقطة لنأخذ رسائل الخطأ التالية: >>> print(employeRecord) Traceback (most recent call last): File "<stdin>", line 1, in <module> 1 NameError: name 'employeRecord' is not defined >>> 42 - 'hello' Traceback (most recent call last): File "<stdin>", line 1, in <module> 2 TypeError: unsupported operand type(s) for -: 'int' and 'str' يوجد في هذا المثال خطأ كتابي في اسم المتغير employeRecord ما سبب حدوث الخطأ 1، وبما أن المعرف employeRecord خاص بشيفرتك، وذلك في رسالة الخطأ NameError: name 'employeRecord' is not defined والتي تعني حدوث خطأ في الاسم بسبب كون اسم المتغير employeRecord غير معرف. أما في السطر الأخير فمن الواضح أن الأجزاء int و str من رسالة الخطأ 2 تعود للقيم 42 و hello على التوالي، ففي هذه الحالة من الأفضل اقتصار البحث على العبارة python "TypeError: unsupported operand type(s)" for والتي تعني خطأ في نمط البيانات ناتج عن كون أحد المعاملات ذو نمط غير مدعوم، وذلك بدلًا من تضمين البحث بأجزاء من الرسالة تخص شيفرتك على وجه التحديد، وإذا فشل هذا البحث المختصر في الوصول إلى نتائج مفيدة، فجرب كتابة رسالة الخطأ كاملةً. تجنب حدوث الأخطاء باستخدام منقحات الصياغة لعل الطريقة الأفضل في إصلاح الأخطاء هي عدم الوقوع بها من الأصل، وهنا يأتي دور منقّحات الأخطاء Linters، وهي عبارة عن تطبيقات تعمل على تحليل الشيفرة المصدرية لتنبهك حول أي خطأ محتمل فيها، أما اسمها "Linters" فقد أتى تيمنًا بأداة جمع الألياف الصغيرة والأوبار في مجفف الملابس. ورغم كون منقّح الأخطاء لن يكتشف أخطاء الشيفرة بالكامل، إلا أن التحليل الساكن الذي يجريه (أي فحص الشيفرة المصدرية دون تشغيلها) قادر على تحديد العديد من الأخطاء الشائعة الناتجة عن الأخطاء الإملائية وسنستعرض في مقالات لاحقة كيفية استخدام تلميحات الكتابة التي يقدمها التحليل الساكن. وتتضمن العديد من محررات النصوص وبيئات التطوير البرمجية المتكاملة IDEs على منقّحات صياغة تعمل في الخلفية، والقادرة على التنبيه إلى الأخطاء المكتشفة بالزمن الحقيقي كما هو موضح في الشكل التالي. منقّح صياغة يشير إلى متغير غير مصرح عنه وذلك في محرر النصوص MU (الشكل الأعلى) وفي المحرر PyCharm (الشكل الأوسط) وفي المحرر Sublime (الشكل الأسفل). وبذلك تعمل إشعارات الأخطاء شبه الفورية التي يوفرها منقّح الأخطاء على تحسين إنتاجية العمل البرمجي بشكل ملموس، فبدون وجوده ستضطر إلى تشغيل برنامجك لتكتشف وجود خطأ، منتقلًا إلى ملخص متتبّع الأخطاء بحثًا عن السطر في الشيفرة المصدرية المتسبب في الخطأ لإصلاح الخطأ الإملائي المسبب له، ولكن ماذا لو ارتكبت عدة أخطاء إملائية؟ عندها لن تجدها إلا بإعادة تنفيذ البرنامج عدة مرات فكل دورة تشغيل ستجد خطأ واحد تتوقف عنده، في حين أن منقّحات الصياغة قادرة على الإشارة لوجود عدة أخطاء معًا ويتم ذلك مباشرةً في محرر النصوص أثناء كتابة الشيفرة، ما يمكنك من تحديد السطر الذي حدثت فيه المشكلة مباشرةً. وقد لا يأتي محرر النصوص أو البيئة البرمجية المتكاملة التي تستخدمها مع منقّح صياغة أصلًا، ولكن إن كانت تدعم الإضافات، فمن شبه المؤكد وجود منقّح صياغة كإضافة، وغالبًا ما تستخدم هذه الإضافات وحدة تنقيح صياغة تدعى Pyflakes أو وحدات أخرى تؤدي هذا الغرض. وبإمكانك تثبيت الوحدة Pyflakes من الرابط https://pypi.org/project/pyflakes/ أو باستخدام أمر تثبيت الحزم pip بكتابة الأمر pip install --user pyflakes، الأمر الذي يستحق العناء لإنجازه. ملاحظة: يمكنك في نظام ويندوز تشغيل كل من الأمرين pip و python، ولكن في حال استخدامك لأنظمة ماك أو إس أو لينكس فتكون أسماء هذين الأمرين بهذا الشكل فقط من أجل الإصدار الثاني من بايثون، أما للإصدار الثالث فيصبحان بالشكل pip3 و python3، انتبه لهذا الموضوع كلما صادفت أحد الأمرين pip أو python في سياق المقال. تأتي بيئة التطوير المتكاملة الخاصة ببايثون IDLE بدون منقّح صياغة وبدون القابلية لتثبيته فيها. الخلاصة لعل وصولك إلى إجابات عن أسئلتك الخاصة بنفسك هي واحدة من أهم المهارات التي عليك اكتسابها كمبرمج، وهنا يمثل الإنترنت ثروة من المصادر المتضمنة الإجابات التي تحتاج. إلا أن الإجراء الأول الذي يجب اتخاذه هو محاولة تحليل رسالة الخطأ المبهمة المعروضة من قبل بايثون، ولا تقلق إن لم تفهم محتواها، فبإمكانك نسخ نص الرسالة إلى أحد محركات البحث وصولًا إلى تفسير حولها باللغة الإنجليزية العادية مع بيان سببها المحتمل، كما أن متتبع الأخطاء سيشير إلى مكان وقوع الخطأ في شيفرة برنامجك. وهنا يلعب منقح الصياغة دورًا مهمًا في الإشارة إلى وقوع الأخطاء المطبعية والمشاكل المحتملة لحظة وقوعها، فهذه المنقحات مفيدة جدًا ولا غنى عنها في التطوير الفعال للبرمجيات، وفي حال كون محرر النصوص أو بيئة التطوير التي تستخدمها لا تملك منقحًا وغير قابلة لإضافته، فمن المفضل أن تنتقل إلى أحد المحررات التي تدعم وجود منقحات الصياغة. وتذكر أن البرمجة مجال واسع جدًا، ولا يمكن لأحد أن يحيط بجميع تفاصيله، لذا لا تشعر بالإحباط إن اضطررت للبحث باستمرار عن إجابات لأسئلتك، فحتى مطورو البرمجيات المتمرسون يبحثون في الإنترنت عن التوثيقات والحلول يوميًا، وبدلًا من تضييع وقتك بالإحساس بالإحباط ركز على اكتساب مهارة إيجاد الحلول، وهي خطوة مهمة في طريقك لتصبح خبير بايثون. ترجمة -وبتصرف- للفصل الأول "التعامل مع الأخطاء وطلب المساعدة" من كتاب Beyond the Basic Stuff with Python لصاحبه Al Sweigart. اقرأ أيضًا كيفية التعامل مع الأخطاء البرمجية أساسيات البرمجة بلغة بايثون إعداد بيئة العمل للمشاريع مع بايثون النسخة العربية الكاملة لكتاب البرمجة بلغة بايثون1 نقطة
-
تُعد مكتبة NumPy إحدى مكتبات لغة بايثون Python وتُستخدم للتعامل مع المصفوفات، وتهدف إلى توفير كائن مصفوفة أسرع بما يصل إلى 50 مرة من قوائم بايثون التقليدية. يطلق على كائن المصفوفة في مكتبة NumPy اسم ndarray، ويوفر العديد من الوظائف الداعمة التي تجعل التعامل مع المصفوفات أمرًا سهلًا جدًا. تعتمد مكتبة NumPy على العمليات على المتجهات vectorization، فإذا كنت معتادًا على التعامل مع لغة بايثون، فهذه هي الصعوبة الرئيسية التي ستواجهها لأنك ستحتاج إلى تغيير طريقة تفكيرك، كما ستتغير نوع العناصر التي ستستخدمها. أكثر العناصر شيوعًا في مكتبة NumPy هي المتجهات vectors والمصفوفات arrays والعروض views والدوال العمومية ufuns. هذا المقال جزء من سلسلة متقدمة حول NumPy وإليك كامل روابط السلسلة: مفاهيم متقدمة حول مكتبة NumPy في بايثون استخدام المتجهات vectorization في لغة بايثون مع مكتبة NumPy الاعتماد على المتجهات في حل المشاكل باستعمال مكتبة NumPy في بايثون تخصيص أسلوب المتجهات Custom vectorization عبر استعمال مكتبة NumPy ما بعد مكتبة NumPy في بايثون مثال بسيط سنأخذ مثالًا بسيطًا وهو المشي العشوائي random walk، إذ يتوجب علينا في الطريقة التقليدية المعتمدة على البرمجة كائنية التوجه OOP تعريف صنف class يأخذ الاسم RandomWalker، ثم إنشاء التابع walk لإرجاع الموقع الحالي بعد كل خطوة عشوائية. يمكن تنفيذ هذا المثال باستخدام التعليمات البرمجية التالية: class RandomWalker: def __init__(self): self.position = 0 def walk(self, n): self.position = 0 for i in range(n): yield self.position self.position += 2*random.randint(0, 1) - 1 walker = RandomWalker() walk = [position for position in walker.walk(1000)] وتعطي تجربة قياس السرعة النتيجة التالية: >>> from tools import timeit >>> walker = RandomWalker() >>> timeit("[position for position in walker.walk(n=10000)]", globals()) 10 loops, best of 3: 15.7 msec per loop النهج الإجرائي Procedural approach يمكننا لحل مثل هذه المشكلة البسيطة حفظ تعريف الصنف والتركيز على دالة المشي walk التي تحسب المواقع المتتالية بعد كل خطوة عشوائية. def random_walk(n): position = 0 walk = [position] for i in range(n): position += 2*random.randint(0, 1)-1 walk.append(position) return walk walk = random_walk(1000) توفر هذه الطريقة من استهلاك وحدة المعالجة المركزية CPU ولكن ليس لحدٍ كبير لأنها تشبه الطريقة السابقة المعتمدة على البرمجة كائنية التوجه. >>> from tools import timeit >>> timeit("random_walk(n=10000)", globals()) 10 loops, best of 3: 15.6 msec per loop النهج المعتمد على المتجهات Vectorized approach يمكننا باستخدام وحدة itertools تحسين الأداء بطريقة أفضل، إذ تقدم هذه الوحدة مجموعةً من الدوال لإنشاء تكرارات لحلقات فعالة. نلاحظ أن مثال المشي العشوائي ما هو إلا تراكم خطوات، لذلك سنعيد كتابة الدالة بإنشاء جميع الخطوات أولًا، ثم تجميعها بدون استخدام أي حلقة، كما توضح التعليمات التالية: def random_walk_faster(n=1000): from itertools import accumulate # Only available from Python 3.6 steps = random.choices([-1,+1], k=n) return [0]+list(accumulate(steps)) walk = random_walk_faster(1000) اعتمدنا في هذا المثال على المتجهات في الدالة، فبدلًا من استخدام التكرار لاختيار الخطوات وإضافتها إلى الموضع الحالي، أنشأنا أولًا جميع الخطوات دفعةً واحدةً، ثم استخدمنا دالة التجميع accumulate لحساب جميع المواضع. تخلصنا من الحلقة وبالتالي أصبح تنفيذ التعليمات أسرع: >>> from tools import timeit >>> timeit("random_walk_faster(n=10000)", globals()) 10 loops, best of 3: 2.21 msec per loop لاحظ أننا وفرنا 85% من وقت الحساب مقارنةً بالإصدار السابق، لكن الإيجابية التي تميز الإصدار الجديد هي تبسيط العمليات المعقدة على المتجهات. سنحتاج إلى استبدال أدوات itertools بأدوات numpy: def random_walk_fastest(n=1000): # No 's' in numpy choice (Python offers choice & choices) steps = np.random.choice([-1,+1], n) return np.cumsum(steps) walk = random_walk_fastest(1000) هذه الطريقة سهلة وتوفر الكثير من الوقت كما توضح النتائج التالية: >>> from tools import timeit >>> timeit("random_walk_fastest(n=10000)", globals()) 1000 loops, best of 3: 14 usec per loop يركز هذا الدليل يركز على الاعتماد على المتجهات سواءٌ كان ذلك على مستوى المشكلة أو الشيفرات البرمجية، وسنوضح أهمية هذا الاختلاف قبل الانتقال إلى دراسة المتجهات المخصصة. سهولة القراءة مقابل السرعة قبل الانتقال إلى القسم التالي، سنلقي نظرةً على مشكلة محتملة قد تواجهها بعد أن تصبح على دراية بمكتبة NumPy؛ فمكتبة NumPy مكتبة قوية جدًا ويمكنك أن تصنع العجائب بها، ولكن هذا على حساب سهولة القراءة، لذلك إذا أهملت إضافة التعليقات أثناء كتابة التعليمات البرمجية، فلن تتمكن من معرفة وظيفة بعض التعليمات بعد بضع أسابيع أو ربما أيام. على سبيل المثال هل يمكنك معرفة ما هي نتيجة تنفيذ الدالتين التاليتين؟ ربما ستتمكن من فهم الدالة الأولى ولكن من غير المرجح أن تفهم الثانية: def function_1(seq, sub): return [i for i in range(len(seq) - len(sub)) if seq[i:i+len(sub)] == sub] def function_2(seq, sub): target = np.dot(sub, sub) candidates = np.where(np.correlate(seq, sub, mode='valid') == target)[0] check = candidates[:, np.newaxis] + np.arange(len(sub)) mask = np.all((np.take(seq, check) == sub), axis=-1) return candidates[mask] استخدمت الدالة الثانية مكتبة NumPy وهي أسرع بعشر مرات، ولكن المشكلة هي بصعوبة قراءة وفهم التعليمات البرمجية التي تستخدمها. تشريح المصفوفة كما أوضحنا سابقًا ينبغي أن تكون لديك خبرةً أساسيةً في التعامل مع مكتبة NumPy قبل المتابعة في هذا الدليل، وإذا لم يكن لديك هذه الخبرة فمن الأفضل أن تتعلم عنها قبل العودة إلى هنا، وبناءً على ذلك سنبدأ هذا الدليل بتذكير سريع على الهيكلية الأساسية للمصفوفات المعقدة، خاصةً بما يتعلق بتخطيط الذاكرة وعرضها ونسخ البيانات وتحديد نوعها، وهذه مفاهيم أساسية يجب أن تفهمها إذا كنت تريد أن تستفيد من فلسفة مكتبة numpy. لنفكر في مثال بسيط نريد من خلاله مسح جميع القيم في مصفوفة من النوع np.float32. كيف يمكن كتابة تعليمات تنفذ المثال السابق بسرعة؟ الصيغة أدناه واضحة إلى حد ما (على الأقل لأولئك الذين هم على دراية بمكتبة NumPy) ولكن السؤال أعلاه يطلب العثور على أسرع عملية. >>> Z = np.ones(4*1000000, np.float32) >>> Z[...] = 0 إذا دققت بنوع عناصر المصفوفة dtype وحجمها، يمكنك ملاحظة أنه يمكن تحويل هذه المصفوفة إلى العديد من أنواع البيانات "المتوافقة" الأخرى. نقصد هنا أنه يمكن تقسيم Z.size * Z.itemsize إلى أنواع عناصر dtype جديدة. >>> timeit("Z.view(np.float16)[...] = 0", globals()) 100 loops, best of 3: 2.72 msec per loop >>> timeit("Z.view(np.int16)[...] = 0", globals()) 100 loops, best of 3: 2.77 msec per loop >>> timeit("Z.view(np.int32)[...] = 0", globals()) 100 loops, best of 3: 1.29 msec per loop >>> timeit("Z.view(np.float32)[...] = 0", globals()) 100 loops, best of 3: 1.33 msec per loop >>> timeit("Z.view(np.int64)[...] = 0", globals()) 100 loops, best of 3: 874 usec per loop >>> timeit("Z.view(np.float64)[...] = 0", globals()) 100 loops, best of 3: 865 usec per loop >>> timeit("Z.view(np.complex128)[...] = 0", globals()) 100 loops, best of 3: 841 usec per loop >>> timeit("Z.view(np.int8)[...] = 0", globals()) 100 loops, best of 3: 630 usec per loop ولكن في الواقع فإن طريقة تصفية جميع القيم ليست هي الأسرع، فقد زاد معدل السرعة بنسبة 25% من خلال تحويل بعض عناصر المصفوفة إلى نوع البيانات np.float64، بينما زاد معدل السرعة بنسبة 50% من خلال عرض المصفوفة واستخدام نوع البيانات np.int8. تتعلق أسباب التسريع بهيكلية عمل مكتبة numpy. تخطيط الذاكرة Memory layout يُعرّف الصنف ndarray وفقًا لتوثيق Numpy كما يلي: المصفوفة هي كتلة مجاورة من الذاكرة يمكن الوصول إلى عناصرها باستخدام مخطط الفهرسة indexing scheme، الذي يحدد شكل ونوع البيانات، وهذا هو المطلوب لتعريف مصفوفة جديدة. Z = np.arange(9).reshape(3,3).astype(np.int16) حجم عناصر المصفوفة Z في التعليمة السابقة هو 2 بايت (int16)، وعدد أبعاد (len(Z.shape هو 2. >>> print(Z.itemsize) 2 >>> print(Z.shape) (3, 3) >>> print(Z.ndim) 2 نظرًا لأن Z ليست طريقة عرض، يمكننا استنتاج خطوات المصفوفة التي تحدد عدد البايتات التي يجب أن تخطوها لاجتياز كل بعد من أبعاد المصفوفة. >>> strides = Z.shape[1]*Z.itemsize, Z.itemsize >>> print(strides) (6, 2) >>> print(Z.strides) (6, 2) لنتمكن من الوصول إلى عنصر معين (مصمم بواسطة فهرس index tuple)، أي كيفية حساب إزاحة البداية والنهاية: offset_start = 0 for i in range(ndim): offset_start += strides[i]*index[i] offset_end = offset_start + Z.itemsize سنستخدم الآن طريقة التحويل tobytes للتأكد من المعلومة السابقة: >>> Z = np.arange(9).reshape(3,3).astype(np.int16) >>> index = 1,1 >>> print(Z[index].tobytes()) b'\x04\x00' >>> offset = 0 >>> for i in range(Z.ndim): ... offset + = Z.strides[i]*index[i] >>> print(Z.tobytes()[offset_start:offset_end] b'\x04\x00' يمكن تمثيل هذه المصفوفة بطرق (تخطيطات) مختلفة: تخطيط العنصر item layout تخطيط العنصر المسطّح Flattened item layout تخطيط الذاكرة Memory layout (C order, big endian) إذا أخذنا الآن شريحة من Z، فإن النتيجة هي عرض المصفوفة الأساسية Z: V = Z[::2,::2] يُحدّد هذا العرض باستخدام نوع dtype وشكل وخطوات، إذ أصبح من غير الممكن استنتاج الخطوات strides من النوع والشكل فقط: تخطيط العنصر item layout تخطيط العنصر المسطّح Flattened item layout تخطيط الذاكرة Memory layout (C order, big endian) العروض والنسخ تُعد العروض Views والنسخ copies مفاهيمًا مهمة لتحسين حساباتك الرقمية. بالرغم من تعاملنا مع هذه المفاهيم في الفقرات السابقة إلا أن الموضوع أكثر تعقيدًا. الوصول المباشر وغير المباشر أولًا علينا التمييز بين نوعي الفهرسة indexing و fancy indexing؛ إذ يعيد النوع الأول عرضًا view دائمًا، بينما يعيد النوع الثاني نسخةً copy. يؤدي تعديل العرض في الحالة الأولى إلى تعديل المصفوفة الأساسية، بينما لن يحدث ذلك في الحالة الثانية: >>> Z = np.zeros(9) >>> Z_view = Z[:3] >>> Z_view[...] = 1 >>> print(Z) [ 1. 1. 1. 0. 0. 0. 0. 0. 0.] >>> Z = np.zeros(9) >>> Z_copy = Z[[0,1,2]] >>> Z_copy[...] = 1 >>> print(Z) [ 0. 0. 0. 0. 0. 0. 0. 0. 0.] إذا كنت تريد استخدام نوع الفهرسة fancy indexing فمن الأفضل الاحتفاظ بنسخة الفهرس fancy index ثم التعامل معه: >>> Z = np.zeros(9) >>> index = [0,1,2] >>> Z[index] = 1 >>> print(Z) [ 1. 1. 1. 0. 0. 0. 0. 0. 0.] إذا لم تكن متأكدًا مما إذا كانت نتيجة الفهرسة هي عرض أو نسخة، فيمكنك التحقق باستخدام الأداة base؛ فإذا كانت النتيجة "None"، فسيكون النوع هو نسخة: >>> Z = np.random.uniform(0,1,(5,5)) >>> Z1 = Z[:3,:] >>> Z2 = Z[[0,1,2], :] >>> print(np.allclose(Z1,Z2)) True >>> print(Z1.base is Z) True >>> print(Z2.base is Z) False >>> print(Z2.base is None) True لاحظ أن بعض وظائف numpy تُعيد عرضًا view، مثل ravel عندما يكون ذلك ممكنًا، بينما يعيد البعض الآخر نسخةً copy، مثل flatten: >>> Z = np.zeros((5,5)) >>> Z.ravel().base is Z True >>> Z[::2,::2].ravel().base is Z False >>> Z.flatten().base is Z False نسخة مؤقتة Temporary copy يمكن إنشاء النسخ بطريقة صريحة كما في الأمثلة السابقة، ولكن الطريقة الأكثر استخدمًا هي الإنشاء الضمني للنسخ الوسيطة. يوضح المثال التالي إجراء العمليات الحسابية باستخدام المصفوفات: >>> X = np.ones(10, dtype=np.int) >>> Y = np.ones(10, dtype=np.int) >>> A = 2*X + 2*Y أنشأنا في هذا المثال ثلاث مصفوفات وسيطة: مصفوفة للاحتفاظ بنتيجة X*2 والثانية للاحتفاظ بنتيجة Y*2، والأخيرة لإيجاد نتيجة Y*2 + X*2، وتكون المصفوفات في هذه الحالة صغيرة الحجم ولا تحدث هذه الطريقة أي فرق واضح؛ ولكن في حال كانت المصفوفات كبيرة الحجم فعليك أن تكون حذرًا مع هذه التعبيرات وتفكر بطريقة مختلفة لإيجاد الحل، فعلى سبيل المثال إذا كانت النتيجة النهائية هي فقط المهمة ولم تكن بحاجة إلى X أو Y، فسيكون الحل البديل: >>> X = np.ones(10, dtype=np.int) >>> Y = np.ones(10, dtype=np.int) >>> np.multiply(X, 2, out=X) >>> np.multiply(Y, 2, out=Y) >>> np.add(X, Y, out=X) استغنينا باستخدام هذا الحل البديل عن فكرة إنشاء مصفوفات مؤقتة، لكن المشكلة أن هناك بعض الحالات التي تتطلب إنشاء هذه النسخ المؤقتة وهذا يؤثر على الأداء كما هو موضح في المثال التالي: >>> X = np.ones(1000000000, dtype=np.int) >>> Y = np.ones(1000000000, dtype=np.int) >>> timeit("X = X + 2.0*Y", globals()) 100 loops, best of 3: 3.61 ms per loop >>> timeit("X = X + 2*Y", globals()) 100 loops, best of 3: 3.47 ms per loop >>> timeit("X += 2*Y", globals()) 100 loops, best of 3: 2.79 ms per loop >>> timeit("np.add(X, Y, out=X); np.add(X, Y, out=X)", globals()) 1000 loops, best of 3: 1.57 ms per loop الخلاصة في الختام سندرس المثال التالي: لنفرض لدينا متجهين Z1 و Z2، ونرغب في معرفة ما إذا كان Z2 هو عرض view للمتجه Z1، وإذا كانت الإجابة نعم فما هو هذا العرض view؟ >>> Z1 = np.arange(10) >>> Z2 = Z1[1:-1:2] أولاً سنحدد نوع الفهرسة وهل Z1 هي أساس Z2: >>> print(Z2.base is Z1) True حتى الآن تأكدنا أن Z2 هي عرض view للمتغير Z1، مما يعني أنه يمكن التعبير عن Z2على النحو التالي: [Z1[start:stop:step. وتكمن الصعوبة في التعرف على البداية والتوقف والخطوة؛ إذ يمكننا بالنسبة للخطوة استخدام خاصية strides لأي مصفوفة تعطي عدد البايتات للانتقال من عنصر إلى آخر في كل بُعد. في حالتنا ولأن كلا المصفوفتين أحادي البعد، يمكننا مقارنة الخطوة الأولى فقط. >>> step = Z2.strides[0] // Z1.strides[0] >>> print(step) 2 الصعوبة التالية هي العثور على مؤشرات البداية والتوقف، إذ يمكننا فعل ذلك بالاستفادة من طريقة byte_bounds التي تُرجع مؤشرًا إلى نقاط نهاية المصفوفة. >>> offset_start = np.byte_bounds(Z2)[0] - np.byte_bounds(Z1)[0] >>> print(offset_start) # bytes 8 >>> offset_stop = np.byte_bounds(Z2)[-1] - np.byte_bounds(Z1)[-1] >>> print(offset_stop) # bytes -16 يعد تحويل هذه الإزاحات offset إلى مؤشرات أمرًا سهلاً باستخدام حجم العناصر مع الأخذ بالحسبان أن offset_stop سلبي (حد نهاية Z2 أصغر منطقيًا من حد النهاية لمصفوفة Z1)، لذلك نحتاج إلى إضافة حجم عناصر Z1 للحصول على فهرس النهاية الصحيحة: >>> start = offset_start // Z1.itemsize >>> stop = Z1.size + offset_stop // Z1.itemsize >>> print(start, stop, step) 1, 8, 2 وعند اختبار النتائج نحصل على ما يلي: >>> print(np.allclose(Z1[start:stop:step], Z2)) True يمكنك التمرين من خلال تحسين هذا التنفيذ الأول والبسيط جدًا من خلال مراعاة: خطوات سلبية. مصفوفة متعددة الأبعاد. ترجمة -وبتصرف- للفصلين Introduction و Anatomy of an array من كتاب From Python to Numpy لصاحبه Nicolas P. Rougier. اقرأ أيضًا المرجع الشامل إلى تعلم لغة بايثون أهم 8 مكتبات بلغة البايثون تستخدم في المشاريع الصغيرة1 نقطة
-
يتناول هذا المقال، الأول من سلسلة دروس عن لغة الاستعلام البنائية Structured Query language التي تعرف بالاختصار المشهور SQL، مفهوم قواعد البيانات، وماذا نقصد بأنظمة إدارة قواعد البيانات، وما هو الجدول، وما هي خصائص قواعد البيانات العلاقية. ما هي قاعدة البيانات؟ بطريقة بسيطة مجرّدة من مفاهيم التقنية، قاعدة البيانات هي مكان لحفظ بيانات معينة على نحو مستمر بهدف الرجوع إليها وقت الحاجة، فدفتر أرقام الهواتف الذي كنا نستعمله في الماضي يُعدّ قاعدة بيانات؛ والكم الهائل من الفواتير المحاسبية الورقية المحفوظة في خزانات الأقسام المالية في الشركات قديماً، أيضاً هو قاعدة بيانات. وقِس على ذلك العديد من الأمثلة الواقعية والملموسة. نستنبطُ من هذا التعريف البسيط وجود خاصية هامة لقاعدة البيانات، ألا وهي “الاستمرارية” أو “الدوام” في حفظ البيانات. في الجانب التقني والبرمجي، فإن قاعدة البيانات Database هي عبارة عن مستودع تُحفظ البيانات فيه داخل جهاز الحاسوب أو الخادوم، ويتمتع هذا المستودع بخاصية الاستمرارية في حفظ البيانات. ونعني بخاصية الاستمرارية هنا أنه في حال إطفاء جهاز الحاسوب أو إعادة تشغيله أو انقطاع التواصل معه، فإن قاعدة البيانات وما تحتويه من بيانات تبقى موجودة ومحفوظة دون أي خلل. أنظمة إدارة قواعد البيانات العلاقية تُسمى البرمجيات التي تنشئ وتدير قواعد البيانات بأنظمة إدارة قواعد البيانات (Databases Management Systems) وتكتب بالاختصار DBMS. ما هي أنواع أنظمة إدارة قواعد البيانات؟ تختلف وتتعدد تسميات أنواع أنظمة إدارة البيانات، وهذا الاختلاف نابع بالدرجة الأولى من تقدم الزمن وما صاحبه من تقدم في العلوم والتقنيات، ومن ثم بالدرجة الثانية، ينبع الاختلاف من التقنيات والخصائص المتعددة لهذه الأنظمة وما تقدمه من خدمات. تنقسم أنواع أنظمة قواعد البيانات إلى ثلاثة أنواع رئيسية. نظام قاعدة البيانات الملف والواحد Flat File Database: يعدّ هذا النوع من الأنظمة قديما ومن النادر أن تجد أحدا يعمل عليه إلى الآن، وهو ببساطة قاعدة بيانات من ملف واحد كبير يحتوي على كل البيانات، وهو يشبه جدول واحد به كل البيانات. نظام إدارة قاعدة البيانات غير العلاقية Non-Relational DBMS :ظهر هذا النوع من أنظمة قواعد البيانات في ظل عصر تضخم البيانات وزيادة حجمها، وخاصة مع انتشار ما يسمى بالمواقع الاجتماعية وتطبيقات الجوال وصفحات الوب الحديثة، فهذا النوع من الأنظمة يسمح بحفظ بيانات غير مرتبة وفق بنية معينة Unstructured Data، وليس من الشرط أن تترابط هذه البيانات Not relational، كما يطلق عليها No-SQL Databases. نظام إدارة قاعدة البيانات العلاقية Relational DBMS: وهو النوع الأشهر والأكثر استخداما منذ بداية ظهوره والذي سنعتمده في هذه السلسلة لشرح SQL، حيث تُجمَّع في هذا النوع من الأنظمة البيانات التي لها علاقة ببعضها البعض في مكان واحد يسمى الجدول، مع وجود الإمكانية لربط الجداول مع بعضها البعض بعلاقات ترابط. دورة علوم الحاسوب دورة تدريبية متكاملة تضعك على بوابة الاحتراف في تعلم أساسيات البرمجة وعلوم الحاسوب اشترك الآن ما هو الجدول؟ يُعدّ الجدول العنصر الأساسي في قواعد البيانات العلاقية، وعليه تعتمد أغلب مكونات قاعدة البيانات من مشاهد Views ودوال Functions وحِزم Packages وغيرها من العناصر الأخرى. يتكون الجدول من أعمدة Columns وصفوف Rows، حيث تمثل الأعمدة ما يسمى بالخصائص Features، والصفوف عبارة عن القيم التي تأخذها الأعمدة وتسمى بالسجلات Records. يوضح الشكل التالي مثالا لجدول يحتوي على بيانات تواريخ ميلاد وأسماء طلاب في مدرسة، وفي المثال نوضح مكونات الجدول في قاعدة البيانات. خصائص قواعد البيانات العلاقية ومميزاتها ظلت قواعد البيانات العلاقية مسيطرة منذ بدايات ظهور النموذج الأساسي لها عام 1970 على يد عالم الحاسوب Frank Codd أثناء عمله لصالح شركة IBM، ولم تكن هذه الأفضلية التي يتمتع بها نظام قواعد البيانات العلاقية تأتي من فراغ، بل من الخصائص التي تتمتع بها. البساطة تُرتَّب البيانات في أنظمة قواعد البيانات العلاقية وتُحفَظ بطريقة بعيدة عن التعقيد، حيث يعدّ الجدول الذي تُحفظ فيه البيانات مفهوما لأغلب المستخدمين وخاصة الذين مارسوا أعمالا في مجال البيانات المجدولة أو مراجعة السجلات. سهولة الاستعلام عن البيانات بعد عمليات الإضافة على قاعدة البيانات، وعند الحاجة للرجوع لها، فإن نظام قواعد البيانات العلائقية يوفر آلية سهلة للاستعلام عن هذه البيانات واستردادها، وذلك عن طريق لغة SQL، بالإضافة إلى وجود الإمكانية للمستخدم أن يستعلم عن البيانات من أكثر من جدول في نفس الوقت باستخدام جمل الربط Joins. كما أن خاصية ترشيح Filtering البيانات وتحديد شروط خاصة لظهور سجلات معينة هو أمر متاح بكل سهولة. سلامة البيانات تعدّ هذه الخاصية أساسية في أي نظام قواعد بيانات بغض النظر عن نوعه. ونعني بهذه الخاصية أن تتوفر جميع القدرات والإمكانات في نظام قواعد البيانات لضمان دقة وصحة المعلومات الموجودة فيه. ويندرج تحت هذه الخاصية ما يسمى بقيود التكامل Integrity constraints والتي هي عبارة عن مجموعة من القيود التي يجب الالتزام بها عند التعامل مع البيانات في الجدول، وسنتكلم عنها في مقال متقدم. المرونة تتمتع قواعد البيانات العلاقية بطبيعتها بالمرونة والقابلية للتطوير، مما يجعلها قابلة للتكيف مع طلبات التغيير والزيادة في كم البيانات. وهذا يعني مثلا أنك تستطيع التغيير على هيكلية جدول معين دون التأثير على البيانات الموجودة فيه أو على قاعدة البيانات ككل، كما أنك – مثلا - لن تحتاج إلى وقف قاعدة البيانات وإعادة تشغيلها مرة أخرى لتنفيذ بعض لتغييرات عليها. ما هي البرمجيات التي تقدم قواعد البيانات العلاقية؟ تَتَعدد الشركات والبرمجيات التي تُقدم أنظمة إدارة قواعد البيانات، وكل منها له سوقه ومجاله الذي يشتهر به. نُقدم لكم في الفقرات القادمة بعضًا من أشهر أنظمة إدارة قواعد البيانات العلاقية. قواعد بيانات MySQL أحد أشهر أنظمة قواعد البيانات العلاقية مفتوحة المصدر. تستطيع إنشاء العديد من قواعد البيانات بداخلها، وتستطيع الوصول لها عبر الوِب. تَعمل MySQL على هيئة خِدمة Service تُتيح لأكثر من مستخدم الوصول إلى أكثر من قاعدة بيانات، وتشتهر بين معشر مبرمجي تطبيقات الوِب لارتباطها الشائع مع لغة البرمجة PHP، ويمكن تنصيبها على أكثر من نظام تشغيل مثل وندوز أو لينكس أو ماك. تعدّ MySQL الخيار المفضل للشركات الناشئة أو المتوسطة وذلك لسهولة التعامل معها وانخفاض تكاليف تشغيلها مقارنة بخيارات أخرى. قواعد بيانات أوراكل Oracle تعدّ شركة أوراكل عملاق الشركات البرمجية التي تقدم أنظمة إدارة قواعد البيانات العلاقية، وتأتي قاعدة البيانات أوراكل بأكثر من إصدار (حسب البيئة والغرض) تبدأ من الإصدار الشخصي والخفيف، وتنتهي بالإصدار المتقدم Enterprise. تتميز قواعد بيانات أوراكل بكم كبير من الإمكانات التي تسهل عليك حل العديد من المشاكل والعقبات في التطبيقات التي تديرها وتنشئها، مع وجود دعم فني قوي عبر مجتمع أوراكل، لذلك فهي تعتبر الخيار الإستراتيجي (البعيد المدى) للعديد من الشركات الكبيرة والجامعات والحكومات. قواعد بيانات مايكروسوفت Microsoft SQL Server من قواعد البيانات الشهيرة، والذي تأتي أيضا بأكثر من إصدار، لتلبي احتياجات المستخدمين المختلفة وبيئات عملهم، ولكي تتعامل مع البيانات في هذا النوع تحتاج لاستخدام النسخة الخاصة من SQL والمسماة T-SQL اختصارا ل Transact SQL والتي هي عبارة عن نسخة SQL مضاف عليه ادوال خاصة وتعديلات على طريقة حذف وتعديل السجلات. قواعد بيانات PostgreSQL قواعد بينات PostgreSQL من قواعد البيانات العلاقية المفضلة لدى بعض مطوري تطبيقات الوِب وتطبيقات سطح المكتب، وهو نظام إدارة قواعد بيانات مفتوح المصدر. توجد الكثير من الشركات الكبيرة والعاملة في مجال نطاقات إنترنت تعتمد على هذا النوع من قواعد البيانات.1 نقطة
-
لغة بايثون هي لغة برمجة سهلة التعلم موازنةً باللغات الأخرى مثل لغة جافا ولغة C ولغة ++C، بالإضافة لكونها متعددة الأغراض فهي تستخدم في بناء تطبيقات سطح المكتب وألعاب الفيديو والرسومات ثلاثية الأبعاد والمواقع الإلكترونية وغيرها، زد على أنها لغة قوية برمجيًا وممتازة للتطبيقات المتقدمة، هذا كله جعلها خيارًا مثاليًا للجميع بصرف النظر عن عملهم وعمرهم وعدد سنوات خبرتهم، بالأخص للراغبين بتعلم البرمجة. هذا المقال جزءًا من سلسلة مقالات حول تصميم لعبة بلغة بايثون ومكتبة Pygame وإليك كامل مقالات السلسلة: بناء لعبة نرد بسيطة بلغة بايثون. بناء لعبة رسومية باستخدام بايثون ووحدة الألعاب PyGame. إضافة لاعب إلى اللعبة المطورة باستخدام بايثون و Pygame. تحريك شخصية اللعبة باستخدام PyGame. إضافة شخصية العدو للعبة. إضافة المنصات إلى لعبة بايثون باستخدام الوحدة Pygame. محاكاة أثر الجاذبية في لعبة بايثون. إضافة خاصية القفز والركض إلى لعبة بايثون. إضافة الجوائز إلى اللعبة المطورة بلغة بايثون. تسجيل نتائج اللعبة المطورة بلغة بايثون وعرضها على الشاشة. إضافة آليات القذف إلى اللعبة المطورة بلغة بايثون. تثبيت بايثون ستحتاج إلى تثبيت بايثون الإصدار 3 لتتابع معنا خطوات العمل، لذا اتبع الخطوات المناسبة لنظام تشغيلك. إن كنت تستخدم نظام تشغيل لينكس، فستجد بايثون متوفرًا ضمنه على الأغلب، استعلم عن إصداره بالأمر التالي: python --version وانظر إلى الخرج فلو تبين لك أن الإصدار الموجود هو 2، أو أن بايثون غير مثبت على الإطلاق، حاول كتابة الأمر بالشكل التالي: python3 --version وإن حصلت على رسالة مفادها عدم التعرف على الأمر، فثبت بايثون 3 باستخدام مركز التطبيقات أو مدير الحزم الخاص بتوزيعة لينكس التي تعتمدها مثل apt في أوبونتو أو dnf في فيدورا. إن كانت توزيعتك هي فيدورا، ثبت بايثون 3 بالأمر التالي: sudo dnf install python3 اتبع الخطوات نفسها في نظام تشغيل macOS لتتأكد من وجود بايثون 3 في النظام، وإن لم يكن مثبتًا، حمله من موقع بايثون الرسمي ثم ثبته، وهنا لديك هذه الطريقة فقط إذ إن macOS لا يملك مدير حزم. أما لو كنت تستخدم نظام تشغيل ويندوز فحمل بايثون 3 من الموقع الرسمي في البداية، ويمكنك الاستعانة بالمقال كيفية تثبيت بايثون 3 وإعداد بيئته البرمجية على ويندوز 10 لهذا الغرض. عمومًا أيًا كان نظام التشغيل الذي تعتمده يمكنك الاستعانة بقسم تثبيت بايثون 3 وإعداد بيئتها البرمجية من المرجع الشامل لتعلم بايثون المتوفر باللغة العربية على أكاديمية حسوب. دورة تطوير التطبيقات باستخدام لغة Python احترف تطوير التطبيقات مع أكاديمية حسوب والتحق بسوق العمل فور انتهائك من الدورة اشترك الآن تشغيل بيئة التطوير المتكاملة IDE فعليًا كل ما تحتاج إليه لكتابة البرامج بلغة بايثون هو محرر شيفرات، ولكن استخدامك بيئة تطوير متكاملة IDE سيسهل عليك كتابة الشيفرة كثيرًا، فهذه البيئات تتضمن وظيفة محرر الشيفرات البسيط مع بعض الأدوات الإضافية الملائمة لكتابة شيفرة بايثون، ويتوفر العديد من الخيارات مفتوحة المصدر لبيئات التطوير المتكاملة، سنعرض منها IDLE 3 و PyCharm. بيئة التطوير IDLE 3 الأساسية هي بيئة التطوير الأساسية المضمنة مع بايثون، وتتميز هذه البيئة بتلوين أجزاء الشيفرة ما يسهل قراءتها واكتشاف الأخطاء على المبرمج، وأيضًا بإعطاء تلميحات لإكمال التعليمات البرمجية، بالإضافة إلى وجود زر تشغيل لتسهيل تشغيلها واختبارها. لبدء استخدام هذه البيئة في لينكس ونظام macOS يكفيك كتابة الأمر idle3 في نافذة الطرفية، أما لاستخدامها في ويندوز فابحث عن بايثون 3 في قائمة ابدأ وستجد هذه البيئة بين خياراتها، وفي حال لم تجد بايثون في قائمة ابدأ، افتح سطر الأوامر بكتابة cmd في خانة البحث، ومن ثم اكتب ضمنه السطر التالي: C:\Windows\py.exe وإن لم ينفع، أعد تثبيت بايثون وتأكد من تفعيل خيار إضافة بايثون إلى متغير البيئة PATH في أثناء عملية التثبيت. وإن لم ينفع ذلك أيضًا، استخدم لينكس ضمن ويندوز نفسه أو بتثبيت لينكس مع ويندوز، فهو في النهاية مجاني، وهذا الانتقال في البيئة لن يكلفك أكثر من حفظ ملفات بايثون خاصتك على قرص USB محمول ونقلها. بيئة التطوير Pycharm النسخة المجتمعية تعدّ Pycharm من أفضل بيئات التطوير مفتوحة المصدر المتوافقة مع بايثون، تتميز بتلوين الشيفرات لتسهيل قراءتها ولاكتشاف أخطاء الكتابة، وإكمال الأقواس وعلامات الاقتباس لضمان صيغ قواعدية سليمة، بالإضافة إلى ميزة ترقيم الأسطر المفيدة في أثناء تنقيح الأخطاء، وعلامات المسافة البادئة، وزر التشغيل لتسهيل اختبار الكود. لتستخدم هذه البيئة ثبّت النسخة المجتمعية من Pycharm، إن كان نظام تشغيلك هو لينكس فيمكنك تثبيتها باستخدام flatpak من منصة FlatHub أو تحميلها من الموقع الرسمي وتثبيتها يدويًا، أما لو كنت تعتمد ويندوز أو macOS فحمل نسخة البرنامج المناسبة لك من موقعه الرسمي، ومن ثم ثبتها. افتح البرنامج بعد التثبيت وأنشئ مشروعًا جديدًا. أخبر بايثون بما تريد تنفيذه الكلمات المفتاحية هي كلمات أساسية تُعرّف الدوال والأصناف وغيرها فهي إذًا الوسيلة التي تخبر بايثون بكل ما تريد تنفيذه. لتجرب إحداها، اكتب السطر التالي ضمن مشروعك الجديد الذي أنشأته على بيئة التطوير: print("Hello world.") والآن شغله بإحدى الطريقتين: إن كنت تستخدم IDLE استعرض قائمة التشغيل وحدد الخيار "تشغيل الوحدة Run Module". أما في PyCharm انقر فوق الزر "تشغيل ملف Run file" ضمن أزرار شريط الأدوات. تطبع print -الكلمة المفتاحية التي جربناها- النص المكتوب بين علامتي اقتباس الموجود ضمن القوسين كما هو أيًا كان. وننوه لك أن بايثون افتراضيًا لا تستخدم إلّا الكلمات المفتاحية الأساسية مثل print و help وتلك الخاصة بالعمليات الحسابية الأساسية وما شابه، ولكن التعليمة import تتيح للمبرمج استيراد المزيد من الوظائف واستخدامها. استخدام وحدة الرسم turtle في بايثون اكتب الأسطر التالية في ملفك (بعد حذف الموجود فيه)، ومن ثم شغله: import turtle turtle.begin_fill() turtle.forward(100) turtle.left(90) turtle.forward(100) turtle.left(90) turtle.forward(100) turtle.left(90) turtle.forward(100) turtle.end_fill() لاحظ الأشكال التي يمكنك رسمها باستخدام مكتبة الرسم turtle والتي تدعى سلحفاة. لتمسح كل الموجود في مساحة الرسم، استخدم: turtle.clear() حاول تخمين معنى الدالة من اسمها الأجنبي: turtle.color("blue") لابد أنك أصبت، سيصبح لون الخط أزرق بدل الأسود، فسهولة فهم التعليمات وتفسيرها هي إحدى ميزات بايثون. سنحاول الحصول على النتيجة نفسها بكتابة كود مختلف أكثر تعقيدًا، وذلك باستخدام الحلقة while التي ستوجه بايثون ليكرر عملية رسم الخط والانعطاف أربع مرات متتالية عوضًا عن إعادة كتابة السطر نفسه أربع مرات كما فعلنا في الفقرة السابقة، أما المتغير الذي سيحدد عدد مرات التكرار فيسمى العداد counter، ستتعلم المزيد عن المتغيرات لاحقًا، ولكن الآن اكتب الأسطر التالية ونفذها لترى كيفية تفاعل المتغير مع الحلقة: import turtle as t import time t.color("blue") t.begin_fill() counter=0 while counter < 4: t.forward(100) t.left(90) counter = counter+1 t.end_fill() time.sleep(2) تعلم بايثون عبر بناء لعبة بسيطة هدفنا أساسًا تعلم البرمجة عبر لغة بايثون، وتمهيدًا لاستخدامها في برمجة متقدمة تعتمد على الرسوميات، سنبدأ في هذا المقال بتعلم منطق اللعبة وكيفية تنظيم البيئة لبناء لعبة نرد بسيطة، يلعب فيها المستخدم مقابل الحاسوب ويلقي كل منهما النرد الافتراضي ليفوز صاحب القيمة الأعلى. التخطيط للعبة يبدأ تطوير البرمجيات عادةً بكتابة توثيق -ولو كان بسيطًا- للمتطلبات والأهداف يبين ما يفترض أن يكون عليه البرنامج، وفي لعبة النرد التي نعمل عليها سيتضمن التوثيق آلية العمل التالية. ابدأ اللعبة واضغط على زر Return أو Enter في لوحة المفاتيح لتبدأ دورة النرد. ستظهر النتيجة على الشاشة. ستُطالب بعدها بإعادة اللعب أو بالخروج. اللعبة بسيطة هذا صحيح، لكن توثيقها سيبين لك كمًّا لا بأس به من التفاصيل لتعمل عليها، مثل حاجتك لهذه المكونات. اللاعب: وهو العنصر البشري الذي سيستخدم اللعبة. AI: وترمز للذكاء الصنعي أي جهاز الحاسوب الذي يحاكي دور اللاعب الخصم، حتى يكون لديك فائز وخاسر. رقم عشوائي: الشائع في لعبة النرد استخدام نرد سداسي الأضلاع وبالتالي الرقم سيكون بين 1 و 6. عامل إجرائي: عملية رياضية بسيطة لموازنة رقمي اللاعبين ومعرفة الأكبر بينهما. رسالة فوز أو خسارة. مطالبة باتخاذ إجراء: إما اللعب مجددًا أو الخروج. بناء الإصدار الأول من لعبة النرد يتضمن الإصدار الأول من البرنامج الميزات الأساسية فقط، قلة هم من يبدأون تطوير برامجهم بميزات كاملة من أول إصدار. سنعرض مفهومين أساسيين قبل البدء. أولًا المتغير variable هو قيمة قابلة للتغيير، يستخدم لتخزين بعض المعلومات التي يحتاجها البرنامج وهو شائع الاستخدام في بايثون، فمثلًا المحرف x هو متغير في المعادلة التالية لأنه يشير إلى قيمةٍ ما أو ينوب عنها: x + 5 = 20 وثانيًا العدد الصحيح integer فيشمل الأعداد الصحيحة الموجبة والسالبة، مثلًا: 1، -1 ،14 ،10947. يتضمن إصدارنا الأول من اللعبة -والمسمى ألفا dice-alpha- متغيرين هما player و ai. لتبدأ بإنشائه، افتح مشروعًا جديدًا، وسمّه dice-alpha ثم اكتب ضمنه الكود التالي: import random player = random.randint(1,6) ai = random.randint(1,6) if player > ai : print("You win") # لاحظ المسافة البادئة else: print("You lose") شغل اللعبة، ولاحظ أن وظيفتها الأساسية تعمل جيدًا، لكنها لا تبدو لعبةً متكاملة حتى الآن، فاللاعب لا يعرف نتيجة رميته ولا رمية الخصم، بالإضافة إلى أنها تنتهي مباشرةً حتى لو رغب اللاعب بالاستمرار، في الواقع يعدّ هذا شائعًا في الإصدارات الأولى من البرامج التي تسمى الإصدارات ألفا، لكنك في نهاية المطاف حللت الإجراء المهم في اللعبة وهو رمي النرد وأصبحت متيقنًا من عمله، فيمكنك استكمال بقية الميزات فيما بعد. تحسين اللعبة سنبني الآن الإصدار الثاني وهو الإصدار بيتا، بإضافة بعض الميزات ليصبح برنامجنا أقرب للعبة فعلًا. 1. إظهار تفاصيل النتيجة في إصدارنا الأول أظهرنا للاعب عبارةً واحدة ليعرف إن فاز أو خسر، والآن سنطوّر الآلية ليعرف اللاعب مقدار العدد العشوائي الذي حصل عليه أي مقدار رميته للنرد وكذلك رمية الخصم. جرب إجراء التعديل التالي في برنامجك، ومن ثم شغله: player = random.randint(1,6) print("You rolled " + player) ai = random.randint(1,6) print("The computer rolled " + ai) بمجرد تشغيله ستحصل على خطأ، والسبب أن بايثون قد فهم برنامجك على أنه عملية حسابية تجمع حروف وأعداد، الحروف هي حروف العبارة التي ستُظهر النتيجة على الشاشة والعدد هو قيمة المتغير player أو المتغير ai، وهذا بالطبع غير منطقي وغير قابل للتطبيق. لتصحيح الخطأ سنجعل بايثون يتعامل مع قيمة المتغير بصفتها نصًا أو بالأحرى سلسلة نصية string بدلًا من معاملتها على أساس أنها عدد صحيح integer. نفذ إذًا التعديل التالي وأعد تشغيل اللعبة ولاحظ النتائج: player = random.randint(1,6) print("You rolled " + str(player) ) ai = random.randint(1,6) print("The computer rolled " + str(ai) ) 2. إضافة عامل التشويق أضفنا بعض التسلية للعبة بإظهار النتائج، والآن سنضيف بعض الإثارة بإبطاء اللعبة في الأجزاء المشوقة، أما وسيلتنا لذلك فهي الدالة time إحدى دوال بايثون. نفذ التالي وتفقد النتائج: import random import time player = random.randint(1,6) print("You rolled " + str(player) ) ai = random.randint(1,6) print("The computer rolls...." ) time.sleep(2) print("The computer has rolled a " + str(player) ) if player > ai : print("You win") # لاحظ المسافة البادئة else: print("You lose") 3. اكتشاف ثغرة التعادل لو ثابرت على اللعب لفترةٍ جيدة، ستكتشف أن لعبتك لا تمتلك التعليمات اللازمة للتعامل مع حالة التعادل أي الحالة التي يحصل فيها اللاعب والحاسوب على القيمة نفسها، وهذه تعدّ ثغرة أو خطأ منطقي في الكود المكتوب، وحتى نعالجها سنجعل بايثون يتحقق من كون القيمتين متساويتين ويعرض عندها نتيجة التعادل. سنستخدم إشارة يساوي مزدوجة == للتحقق من تساوي القيمتين، إذ إن إشارة يساوي مفردة تعني في بايثون إسناد قيمة ما لأحد المتغيرات، أما بخصوص إدراج خيار ثالث للنتيجة، فسنعتمد على الكلمة المفتاحية elif (اختصار لـ else if) وهي مفيدة في الحالات التي تحتاج فيها للمطابقة مع ثلاثة احتمالات أو أكثر ضمن التعليمات الشرطية، بدلاً من مجرد احتمالين أحدهما صحيح والآخر خاطئ. الآن عدّل برنامجك ليغدو كما يلي: if player > ai : print("You win") # لاحظ المسافة البادئة elif player == ai: print("Tie game.") else: print("You lose") وبعدها جرب اللعبة عدة مرات لتصادف حالة التعادل وتتأكد من عملها. يمكنك تعلم المزيد عن الدوال الشرطية في بايثون بالاطلاع على المقال كيفية كتابة التعليمات الشرطية في بايثون 3 ضمن دليل تعلم بايثون على أكاديمية حسوب. بناء الإصدار النهائي للعبة تفوق الإصدار بيتا وظيفيًا على الإصدار ألفا، وكان أكثر قربًا منه للألعاب الحقيقية، والآن سنبني إصدارنا النهائي الأكثر تكاملًا وستتعلم خلاله بناء دالتك الأولى في بايثون. الدالة function هي مجموعة من التعليمات البرمجية التي يتم استدعائها ضمن البرنامج بصورة كتلة واحدة متميزة، تفيد الدوال في تنظيم التطبيقات بالأخص تلك التي تتضمن عددًا كبيرًا من التعليمات البرمجية التي لا يُفترض أن تعمل في وقتٍ واحد وشروطٍ واحدة، والدوال هنا هي من تحدد ما الذي سيحدث وفي أي وقت وشرط سيحدث. عدّل الآن برنامجك ليصبح: import random import time def dice(): player = random.randint(1,6) print("You rolled " + str(player) ) ai = random.randint(1,6) print("The computer rolls...." ) time.sleep(2) print("The computer has rolled a " + str(ai) ) if player > ai : print("You win") elif player == ai: print("Tie game.") else: print("You lose") print("Quit? Y/N") cont = input() if cont == "Y" or cont == "y": exit() elif cont == "N" or cont == "n": pass else: print("I did not understand that. Playing again.") في هذا الإصدار سيُسأل اللاعب إن كان يريد الخروج من اللعبة، وفي حال أجاب بنعم عبر كتابة Y أو y، فإن بايثون سينهي استدعاء الدالة وتتم مغادرة اللعبة. إذًا فقد بنيت دالتك الأولى المسماة نرد dice لكنها لن تعمل ما لم تستدعيها ضمن البرنامج، وهذا ما ستفعله الحلقة While True. أضف التعليمات التالية في نهاية برنامجك، وانتبه للمسافات البادئة فقد أعدنا كتابة آخر سطرين في الكود السابق عن قصد ليكون السياق واضحًا أمامك: … # الحلقة الأساسية while True: print("Press return to roll your die.") roll = input() dice() هذه الحلقة هي أول ما سيعمل في برنامجك، وتتكرر دومًا ما لم يكسرها أمرٌ من بايثون، إذ إن شرط عملها محقق دائمًا وتلقائيًا فهو True، لاحظ تسلسل عملها فهي تطالب المستخدم أولًا باتخاذ إجراء حتى يبدأ اللعب، ومن ثم تستدعي الدالة dice، ومن بعدها بناءً على إجابة المستخدم ستستمر الحلقة بالعمل أو تتوقف. ومن الجدير بالذكر أن الحلقات هي واحدة من أشيع الطرق المستخدمة لبدء التطبيقات فهي تضمن بقاء التطبيق متاحًا أمام المستخدم لفترة كافية تمكنه من استخدام وظائفه المختلفة. يمكنك تعلم المزيد عن الحلقات التكرارية بالاطلاع على المقال كيفية إنشاء حلقات تكرار while في بايثون 3، والمقال كيفية استخدام تعابير break و continue و pass عند التعامل مع حلقات التكرار في بايثون 3 ضمن دليل تعلم بايثون على أكاديمية حسوب. ختامًا تعرفنا في هذا المقال على أساسيات البرمجة بلغة بايثون، وسنتعلم في مقالنا التالي كيفية بناء لعبة فيديو باستخدام الوحدة PyGame المتخصصة في هذا المجال. ترجمة -وبتصرف- للمقال Learn how to program in Python by building a simple dice game لصاحبه Seth Kenlon. اقرأ أيضًا المقال التالي: بناء لعبة رسومية باستخدام بايثون ووحدة الألعاب Pygame تعرف على أشهر لغات برمجة الألعاب برمجة لعبة حجرة ورقة مقص باستخدام لغة بايثون النسخة العربية الكاملة من كتاب البرمجة بلغة بايثون1 نقطة
-
إحدى أولى المفاهيم التي يتعلمها مبرمج أنظمة يونكس هي أنّ عمل كل برنامج يبدأ بثلاث ملفات تكون مفتوحةً مسبقًا: 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; } الاسم الوصفي الاسم المختصر رقم الملف الشرح مجرى الدخل القياسي stdin 0 الدخل من لوحة المفاتيح مجرى الخرج القياسي stdout 1 الخرج الظاهر على الطرفية مجرى الخطأ القياسي stderr 2 خرج رسائل الخطأ على الطرفية (ملفات يونيكس الافتراضية) يستحضر هذا إلى أذهاننا السؤال عمّا يمثله الملف المفتوح وكيفية فتحه، إذ تسمى القيمة التي يعيدها استدعاء open لفتح الملف اصطلاحًا بواصف الملف file descriptor، وهي أساسًا فهرس لمصفوفة من الملفات المفتوحة المخزَّنة في النواة. (فائدة واصفات الملفات في عملية التجريد) تُعَدّ واصفات الملفات فهرسًا لجدول واصفات الملفات تخزنه النواة، بحيث تنشئ النواة واصف ملف استجابةً لاستدعاء open وتربطه ببعض التجريد لكائن يشبه الملف سواءً كان جهازًا فعليًا أو نظام ملفات أو شيء بعيد عن هذا كل البعد، وبالتالي توجه النواة استدعاءات عمليات القراءة read والكتابة write التي تشير إلى واصف الملف ذاك إلى الموضع الصحيح لتنفذ مهمة مفيدة في النهاية. تعرض الصورة نظرةً عامةً على تجريد العتاد، وباختصار يُعَدّ واصف الملف البوابة إلى تجريدات النواة للعتاد والأجهزة الأساسية. لنبدأ من المستوى الأدنى، إذ يتطلب نظام التشغيل وجود مبرمج ينشئ تعريفًا للجهاز device driver أو برنامج تعريف حتى يتمكن من التواصل مع أحد أجهزة العتاد، ويُكتَب تعريف الجهاز هذا إلى واجهة API التي توفرها النواة بالطريقة نفسها والتي وردت في مثال المقال السابق، إذ سيوفر تعريف الجهاز مجموعة دوال تستدعيها النواة استجابةً للمتطلبات المختلفة، ويمكننا في المثال المبسَّط في الصورة السابقة رؤية أن تعريف الجهاز يوفِّر دالة القراءة read والكتابة write اللتين ستُستدعيان استجابةً للعمليات المماثلة التي تنفذ على واصف الملف، كما يعلم تعريف الجهاز كيف يحوِّل هذه الطلبات العامة إلى طلبات أو أوامر محددة لجهاز محدد. تقدم النواة واجهة-ملف file-interface لتوفير التجريد لمساحة المستخدِم عبر ما يسمى بطبقة الجهاز device layer عمومًا، إذ تمثَّل الأجهزة المادية على المضيف بملف له نظام ملفات خاص مثل dev/، ففي أنظمة يونكس وما يشابهها تحتوي عقد الجهاز device-nodes على ما اصطلح تسميته بالعدد الرئيسي major number والعدد الثانوي minor number، مما يتيح للنواة ربط عقد محددة بما يقابلها ببرنامج التعريف الموفر، كما يمكنك الاطلاع عليها من خلال الأمر ls كما هو موضح في المثال التالي: $ ls -l /dev/null /dev/zero /dev/tty crw-rw-rw- 1 root root 1, 3 Aug 26 13:12 /dev/null crw-rw-rw- 1 root root 5, 0 Sep 2 15:06 /dev/tty crw-rw-rw- 1 root root 1, 5 Aug 26 13:12 /dev/zero ينقلنا هذا إلى واصف الملف، وهو الأداة التي تستخدِمها مساحة المستخدِم للتواصل مع الجهاز الأساسي، وبصورة عامة ما يحدث عند فتح الملف هو أنّ النواة تستخدِم معلومات المسار لربط map واصف الملف بشيء يوفِّر واجهتّي API قراءة وكتابة وغيرهما مناسبة، فعندما تكون عملية فتح الملف open للجهاز مثل /dev/sr0 في مثالنا السابق، فسيوفر العدد الرئيسي والثانوي لعقدة الجهاز المفتوح المعلومات التي تحتاجها النواة للعثور على تعريف الجهاز الصحيح وإتمام عملية الربط mapping، كما ستعلم النواة بعد ذلك كيف توجه الاستدعاءات اللاحقة مثل القراءة read إلى الدوال الأساسية التي يوفرها تعريف الجهاز. يعمل الملف غير المرتبط بجهاز non-device file بآلية مشابهة، على الرغم من وجود طبقات أكثر خلال العملية، فالتجريد هنا هو نقطة الوصل أو الربط mount point، وكما تملك عملية توصيل نظام الملفات file system mounting غايةً مزدوجةً تتمثل في إعداد عملية الربط mapping، بحيث يتعرف نظام الملفات على الجهاز الأساسي الذي يوفِّر التخزين وتعلم النواة أنّ الملفات المفتوحة في نقطة التوصيل تلك يجب أن توجَّه إلى تعريف نظام الملفات، كما تُكتَب أنظمة الملفات على واجهة API محددة لنظام الملفات العام التي توفرها النواة على غرار تعريفات الأجهزة. بالطبع الصورة الكاملة معقدة أكثر في الواقع، إذ تضم عدة طبقات أخرى، فتبذل النواة على سبيل المثال جهدًا كبيرًا لتخزين cache أكبر قدر ممكن من البيانات الواردة من الأقراص في الذاكرة الخالية، ويقدِّم هذا العديد من الميزات التي تحسِّن السرعة، كما تحاول النواة تنظيم الوصول إلى الجهاز بأكثر طريقة فعالة وممكنة مثل محاولة طلب الوصول إلى القرص للتأكد من أن البيانات المخزَّنة فيزيائيًا بالقرب من بعضها ستستعاد معًا حتى لو لم ترد الطلبات بترتيب تسلسلي، بالإضافة إلى انتماء العديد من الأجهزة إلى فئة أعم مثل أجهزة USB أو SCSI التي توفِّر طبقات التجريد الخاصة بها للكتابة عليها، وبالتالي ستمر أنظمة الملفات في هذه الطبقات المتعددة بدلًا من الكتابة مباشرةً على الأجهزة، أي يكون فهم النواة هو فهم كيفية ترابط واجهات API المتعددة تلك وتواجدها مع بعضها. الصدفة Shell تُعَدّ الصدفة بوابة التفاعل مع نظام التشغيل سواءً كانت باش bash أو zsh أو csh أو أيّ نوع من أنواع الأصداف الأخرى العديدة، إذ تشترك جميعها أساسًا في مهمة رئيسية واحدة فقط، وهي أنها تتيح لك تنفيذ البرامج، كما ستبدأ بفهم آلية تنفيذ الصدفة لهذه المهمة فعليًا عندما سنتحدث لاحقًا عن بعض العناصر الداخلية لنظام التشغيل. لكن الأصداف قادرة على تنفيذ مهام أكبر بكثير من مجرد إتاحة تنفيذ برنامج، إذ تتميز بقدرات قوية لإعادة توجيه الملفات، وتتيح لك تنفيذ عدة برامج في الوقت نفسه وكتابة نصوص برمجية تبني برامج متكاملة، وهذا كله يعيدنا إلى مقولة كل شيء هو عبارة عن ملف. إعادة التوجيه Redirection لا نريد في معظم الأحيان أن تشير واصفات الملفات القياسية التي تحدثنا عنها في بداية المقال إلى مواضع محددة افتراضيًا، فقد ترغب مثلًا في تسجيل كامل خرج البرنامج على ملف تحدده على القرص أو في جعله يتلقى أوامره من ملف أعددته مسبقًا، وقد ترغب في تمرير خرج برنامج ليكون دخل برنامج آخر، إذ تيسّر الصدفة ذلك وأكثر بالعمل مع نظام التشغيل. الاسم الأمر الوصف مثال إعادة التوجيه إلى ملف filename < أخذ كامل الخرج الناتج عن Standard Out وتسجيله في الملف filename (استبدل filename باسم الملف). ملاحظة: استخدم << لتُلحق الخرج بنهاية محتوى الملف بدلًا من استبدال محتواه ls > filename القراءة من ملف filename > نسخ كافة البيانات من الملف إلى دخل البرنامج القياسي standard input echo < filename التمرير Pipe program1 | program2 أخذ كامل خرج standard out البرنامج الأول program1 وتمريره إلى دخل standard input البرنامج الثاني program2 ls | more تنفيذ عملية التمرير pipe يُعَدّ تنفيذ الأمر ls | more مثالًا آخرَ على قدرة التجريد، فما يحدث هنا بصورة أساسية هو أنه بدلًا من ربط واصف الملف لمجرى الخرج القياسي بإحدى الأجهزة الأساسية مثل الطرفية لعرض الخرج عليها، يوجَّه الواصف إلى مخزن مؤقت buffer في الذاكرة توفِّره النواة ويطلق عليه عادةً الأنبوب pipe، والمميز هنا هو إمكانية عملية أخرى أن تربط دخلها القياسي standard input بالجانب الآخر من المخزن المؤقت ذاته buffer وتستحوذ على خرج العملية الأخرى بفعالية كما هو موضَّح في الصورة التالية: (الأنبوب) الأنبوب هو مخزن مؤقت في الذاكرة يربط عمليتين معًا، وتشير واصفات الملف إلى كائن الأنبوب الذي يخزن البيانات المرسلة إليه من خلال عملية الكتابة ليصرِّفها من خلال عملية القراءة. تخزِّن النواة عمليات الكتابة في الأنبوب حتى تصرّف عملية قراءة مقابلة من الجانب الآخر للمخزن المؤقت، وهذا مفهوم قوي جدًا وهو أحد الأشكال الأساسية للتواصل بين العمليات inter-process communication -أو IPC اختصارًا- في أنظمة يونكس وما يشابهها، كما لا تقتصر عملية التمرير على نقل البيانات، إذ يمكن أن تؤدي دور قناة إشارات signaling channel، فإذا قرأت إحدى العمليات أنبوبًا فارغًا، فستعطله أو تجمده block افتراضيًا أو تضعه في حالة سبات hibernation إلى حين توفر بعض البيانات، وسنتعمق في هذا أكثر في مقال لاحق من هذه السلسلة، وبالتالي قد تستخدِم عمليتان أنبوبًا للإبلاغ عن اتخاذ إجراء ما عن طريق كتابة بايت واحد من البيانات، فبدلًا من أن تكون البيانات الفعلية مهمةً، فإن مجرد وجود أية بيانات في الأنبوب يمكن أن تشير إلى رسالة، فلنفترض مثلًا أنّ إحدى العمليات تطلب طباعة عملية أخرى لملف وهو أمر سيستغرق بعض الوقت، لذا قد تُعِدّ العمليتان أنبوبًا بينهما بحيث تقرأ العملية التي أرسلت الطلب الأنبوب الفارغ، وبما أنه فارغ، فسيعطّل هذا الاستدعاء وتبطِل العملية، لكن بمجرد الانتهاء من الطباعة، ستكتب العملية الأخرى رسالةً في الأنبوب ويؤدي ذلك إلى إيقاظ العملية التي أرسلت الطلب بصورة فعالة وإرسال إشارة تدل على انتهاء العمل. ينبثق عن السماح للعمليات بتمرير البيانات بين بعضها بهذه الطريقة مصطلح شائع آخر في يونكس للأدوات الصغيرة التي تنفذ أمرًا معينًا، ويضفي تسلسل هذه الأدوات الصغيرة مرونةً لا تستطيع أداة موحَّدة إضفاءها في معظم الأحيان. ترجمة -وبتصرُّف- لقسم من الفصل Chapter 1. General Unix and Advanced C من كتاب Computer Science from the Bottom Up. اقرأ أيضًا المقال التالي: تعرف على نظام العد الثنائي Binary أساس الحوسبة المقال السابق: مفهوم التجريد abstraction في أنظمة التشغيل وأهميته للمبرمجين التجريد (Abstraction) والواجهات (Interfaces) والسمات (Traits) في PHP النسخة العربية الكاملة لكتاب: أنظمة التشغيل للمبرمجين1 نقطة
-
أضاف الإصدار ES6 من معايير ECMAScript الصادر عام 2015 ميزة قالب النص Template Literals إلى لغة جافاسكربت والتي تعد شكلًا جديدًا لصياغة السلاسل النصية Strings في جافاسكربت مُضيفًا العديد من الإمكانيات الجديدة الفعّالة، كإمكانية إنشاء سلاسل نصية متعدّدة السطور بطريقة سهلة، وإمكانية استخدام المواضع المؤقتة placeholder لتضمين قيم التعابير البرمجية Expressions في السلاسل النصية. إضافة لوجود ميزة متقدمة تدعى قوالب النصوص الموسومة Tagged Template Literals والتي تسمح لك بإجراء العمليات على التعابير في السلاسل النصية. تزيد كل هذه الإمكانات من خياراتك كمطور لكتابة السلاسل النصية ببراعة واحترافية، جاعلة إياك قادرًا على إنشاء سلاسل نصية ديناميكية يمكن توظيفها في عناوين الويب URLs أو في الإجراءات التي تعدّل عناصر صفحات HTML. ستتعرف في هذا المقال على الاختلافات ما بين السلاسل النصية المحصورة بين علامتي اقتباس مفردة أو مزدوجة وقوالب النصوص، كما ستتعرف على الطرق المتعدّدة للتصريح عن سلاسل نصية من أشكال مختلفة بما يتضمن السلاسل الممتدّة على أكثر من سطر والديناميكية منها التي تتغير تبعًا لقيمة متحول أو تعبير ما. ومن ثمّ ستتعلم عن قوالب النصوص الموسومة وسترى بعض الأمثلة الواقعية لمشاريع باستخدام هذه القوالب. التصريح عن السلاسل النصية سنستعرض في هذا القسم كيفية التصريح عن السلاسل النصية باستخدام علامات الاقتباس المفردة والمزدوجة، ومن ثم سننتقل لاستعراض كيفية إجراء ذلك في حالة استخدام قوالب النصوص. يمكنك كتابة سلسلة المحارف في جافاسكربت باستخدام علامات اقتباس مفردة ' ': const single = 'Every day is a good day when you paint.' كما يمكن كتابة سلسلة المحارف باستخدام علامات اقتباس مزدوجة " ": const double = "Be so very light. Be a gentle whisper." وإجمالًا لا يوجد اختلافات جوهرية ما بين استخدام علامات الاقتباس المفردة أو المزدوجة في جافاسكربت، وذلك على خلاف بعض لغات البرمجة والتي تتيح إمكانية التضمين Interpolation باستخدام إحدى الطريقتين حصرًا، والمقصود بالتضمين التعامل مع المواضع المؤقتة كجزء ديناميكي من سلسلة المحارف. ويعد استخدام علامات الاقتباس المفردة والمزدوجة خيارًا شخصيًا، كما يمكن استخدامهما معًا بشرط إغلاق أيًا منها بنفس نوع البدء: // الإغلاق هنا باستخدام علامة اقتباس مفردة لأننا بدأنا بمثلها const single = '"We don\'t make mistakes. We just have happy accidents." - Bob Ross' // الإغلاق هنا باستخدام علامة اقتباس مزدوجة لأننا بدأنا بمثلها const double = "\"We don't make mistakes. We just have happy accidents.\" - Bob Ross" console.log(single); console.log(double); وسيقوم الإجراء log( ) بالنتيجة بطباعة نفس سلسلة المحارف على الخرج: "We don't make mistakes. We just have happy accidents." - Bob Ross "We don't make mistakes. We just have happy accidents." - Bob Ross في حين أنّه تكتب قوالب النصوص عبر حصر السلسة النصية بين علامتي اقتباس مائلتين (`) : const template = `Find freedom on this canvas.` وهي لا تحتاج للإغلاق بعلامة اقتباس مفردة أو مزدوجة: const template = `"We don't make mistakes. We just have happy accidents." - Bob Ross` ولكن لا بدّ من إغلاقها بعلامة اقتباس مائلة كما بدأت: const template = `Template literals use the \` character.` وتؤدّي قوالب النصوص كافّة الوظائف التي تؤديها السلاسل النصية العادية، وبالتالي يمكنك استبدال كافّة السلاسل النصية في مشروعك بقوالب نصوص، إلّا أنّ القواعد الأساسية الشائعة في كتابة الشيفرات البرمجية تنص على استخدام قوالب النصوص فقط عند الحاجة الفعلية لها لما تقدمه من إمكانات إضافية عن السلاسل النصية العادية، وبالتالي يفضّل استخدام علامات التنصيص المفردة أو المزدوجة فقط لحصر السلاسل النصية البسيطة، وهذا ما سيجعل قراءة واختبار شيفرتك البرمجية أسهل لأي مطوّر آخر. الآن وبعد معرفتك لكيفية التصريح عن السلاسل النصية باستخدام علامات الاقتباس المفردة والمزدوجة وعلامات الاقتباس المائلة، سننتقل للتعرّف على أول فوائد قوالب النصوص وهي الكتابة على عدّة أسطر. كتابة السلاسل النصية على عدّة أسطر سنرى بدايةً كيفية التصريح عن السلاسل النصية متعددة الأسطر ما قبل ES6، ثمّ سننتقل لنلاحظ كيف سهّل استخدام قوالب النصوص من هذا الأمر. فسابقًا، وفي حال رغبت بكتابة سلسلة نصية على عدة أسطر في محرر النصوص، كان لا بدّ من استخدام عملية ربط سلاسل (+) والتي لا تمثّل دائمًا الطريقة الأفضل. فمثلًا وعلى خلاف الواقع، يبدو أنّ السلسلة النصية التالية ستظهر عند التنفيذ على عدّة أسطر: const address = 'Homer J. Simpson' + '742 Evergreen Terrace' + 'Springfield' ولكن في الواقع الإجراء السابق سيسمح لك بتقسيم السلسلة النصية إلى أجزاء أصغر وكتابتها على عدّة أسطر في محرر النصوص فقط، دون حدوث أي أثر على نتيجة الخرج، بمعنى أن السلسلة ستظهر على الخرج في سطر واحد وبدون مسافة فاصلة (رغم استخدام مسافات بادئة في بداية كل جزء من السلسلة في محرّر النصوص) بين جزء وآخر منها، ويكون ناتج تنفيذ الإجراء الإجراء log( ) عند تمرير المتغير address بالشّكل: Homer J. Simpson742 Evergreen TerraceSpringfield كما يمكنك استخدام الخط المائل العكسي \ لكتابة السلسلة النصية على عدّة أسطر في محرر النصوص كالتالي: const address = 'Homer J. Simpson\ 742 Evergreen Terrace\ Springfield' والميزة هنا أنّ المسافات البادئة ستظهر فعلًا كمسافات فارغة في السلسة النصية الناتجة، إلّا أنّها ستظهر أيضًا على سطر واحد بالشّكل : Homer J. Simpson 742 Evergreen Terrace Springfield والحل الوحيد لإنشاء سلاسل نصية على عدّة أسطر عند التنفيذ هو استخدام محرف الانتقال لسطر جديد \n أثناء كتابة الرمز، مثلًا: const address = 'Homer J. Simpson\n' + '742 Evergreen Terrace\n' + 'Springfield' وسيظهر الخرج عند التنفيذ بالشّكل: Homer J. Simpson\n 742 Evergreen Terrace\n Springfield إلّا أنّ استخدام محرف الانتقال لسطر جديد (\n) يمكن ألا يكون أمرًا بديهيًا، فيمكن أن يظن المبرمج أنّ الانتقال لسطر جديد أثناء كتابة الرمز في محرّر النصوص كافيًا لتظهر النتيجة المطلوبة في الخرج، وهذا ما توفره قوالب النصوص؛ فمع استخدامها لن تحتاج لإضافة علامة ربط السلاسل النصية أو محرف انتقال لسطر جديد ولا حتّى خط مائل عكسي، كل ما تحتاجه هو مجرّد الضغط على زر Enter وستظهر السلسلة النصية على عدّة أسطر افتراضيًا، مثلًا: const address = `Homer J. Simpson 742 Evergreen Terrace Springfield` وبذلك سيكون خرج السلسة النصية تمامًا كما كُتبت، أي في مثالنا بالشّكل: Homer J. Simpson 742 Evergreen Terrace Springfield كما أنّ استخدام قوالب النصوص سيحتفظ أثناء التنفيذ بأي مسافات بادئة وضعتها، لذا تجنّب استخدام أي مسافات إلّا في موضعها المطلوب، فمثلًا لدى كتابة الترميز التالي: const address = `Homer J. Simpson 742 Evergreen Terrace Springfield` فبالرغم من كون طريقة الكتابة السابقة أسهل وأنسب للقراءة، إلّا أنّ الخرج لن يكون كذلك، بل سيكون بالشّكل: Homer J. Simpson 742 Evergreen Terrace Springfield بعد التعرّف على السلاسل متعدّدة الأسطر، فيما يلي سنستعرض كيفية تضمين قيم التعابير البرمجية لحالات التصريح عن السلاسل النصية المختلفة. تضمين قيم التعابير البرمجية في السابق وقبل إصدار ES6 كان يستخدم علامة ربط السلاسل النصية لإنشاء سلاسل نصية ديناميكية باستخدام المتحولات أو التعابير البرمجية (سلاسل نصية ذات قيم متغيرة تبعًا لقيم هذه المتحولات أو التعابير البرمجية)، مثلًا: const method = 'concatenation' const dynamicString = 'This string is using ' + method + '.' فعند تمرير dynamicString إلى الإجراء log( )، نحصل في الخرج عند التنفيذ على النتيجة: This string is using concatenation. يمكنك تضمين التعابير البرمجية في المواضع المؤقتة مع استخدام قوالب النصوص، ويعبّر عن المواضع المؤقتة برمجيّا باستخدام الرمز ${}، فيصبح التعامل مع مضمون الأقواس على أنّه جافاسكربت وكل ما هو خارج الأقواس على أنّه سلسلة نصية، كما في المثال: const method = 'interpolation' const dynamicString = `This string is using ${method}.` وعند تمرير dynamicString إلى التابع log( )، نحصل في الخرج عند التنفيذ على النتيجة: This string is using interpolation. ويعدّ تضمين القيم في السلاسل النصية لإنشاء عناوين ويب ديناميكية Dynamic URLs من أكثر الأمثلة شيوعًا، لأنّ تنفيذ ذلك باستخدام علامات ربط السلاسل النصية لن يكون بالأمر السهل، فمثلًا الإجراء التالي يعرّف تابعًا لإنشاء السلسلة اللازمة لمنح الوصول لبروتوكول التوثيق OAuth: function createOAuthString(host, clientId, scope) { return host + '/login/oauth/authorize?client_id=' + clientId + '&scope=' + scope } createOAuthString('https://github.com', 'abc123', 'repo,user') وبتمرير هذا التابع إلى تابع log( ) نحصل في الخرج على عنوان الويب التالي: https://github.com/login/oauth/authorize?client_id=abc123&scope=repo,user ولكن ومع استخدام ميزة التضمين في السلاسل النصية التي تقدمها قوالب النصوص، لن تكون مضطرًا لاستخدام علامات الربط أو تتّبع أماكن بدء وانتهاء السلاسل، وفيما يلي نستعرض نفس المثال السابق ولكن عند بناءه باستخدام قوالب النصوص: function createOAuthString(host, clientId, scope) { return `${host}/login/oauth/authorize?client_id=${clientId}&scope=${scope}` } createOAuthString('https://github.com', 'abc123', 'repo,user') وهذا ما سيعطي نفس الخرج كما في حالة استخدام علامات ربط السلاسل النصية: https://github.com/login/oauth/authorize?client_id=abc123&scope=repo,user كما يمكنك تطبيق الإجراء trim() على أي قالب محرفي للتخلص من الفراغات في طرفي السلسلة النصية، في المثال التالي استخدامنا البناء المختصر لتابع يُنشئ عنصر قوائم في HTML برابط مخصّص: const menuItem = (url, link) => ` <li> <a href="${url}">${link}</a> </li> `.trim() menuItem('https://google.com', 'Google') ومع استخدام الإجراء trim() ستُقتص الفراغات من على جانبي القالب المحرفي مما يضمن عرض العنصر بطريقة صحيحة، كالتالي: <li> <a href="https://google.com">Google</a> </li> ولا يقتصر التضمين على المتحولات فقط، بل من الممكن تضمين أي تعبير برمجي، كما في مثال إيجاد ناتج جمع عددين التالي: const sum = (x, y) => x + y const x = 5 const y = 100 const string = `The sum of ${x} and ${y} is ${sum(x, y)}.` console.log(string) يعرّف هذا الترميز البرمجي التابع sum، والمتحولين x وy، ومن ثمّ يستخدم كلًا من التابع والمتحولين في سلسلة نصية، وتكون نتيجة التنفيذ على الخرج بالشّكل: The sum of 5 and 100 is 105. ولهذا فائدة كبيرة خاصّة عند استخدام عمليات اتخاذ قرار Ternary Operators، إذ تسمح بتضمين الشروط في السلاسل النصية، مثلًا: const age = 19 const message = `You can ${age < 21 ? 'not' : ''} view this page` console.log(message) وفي هذه الحالة ستتغير الرسالة في الخرج تبعًا لقيم المتحول age هل هو أعلى أم أقل من 21، وبما أنّ قيمة هذا المتحول في مثالنا هي 19، نحصل على الخرج التالي: You can not view this page وبذلك تكون كوّنت فكرة حول فوائد قوالب النصوص في تضمين التعابير البرمجية. وفيما يلي سنتفحّص قدرة قوالب النصوص الموسومة على التعامل مع التعابير البرمجية الممررّة إلى المواضع المؤقتة. قوالب النصوص الموسومة يعد استخدام قوالب النصوص الموسومة ميزة جيدة متطورّة لقوالب النصوص، والتي تسمّى أيضًا بالقوالب الموسومة. ويبدأ القالب الموسوم بتابع وسم يضيف الوسم للقالب المحرفي، مقدمّاً لك المزيد من التحكّم في عمليات التضمين للحصول على سلاسل نصية ديناميكية. في المثال التالي، ستُنشئ تابع وسم يعمل باستخدام القوالب الموسومة، يتضمّن هذا التابع عاملين، سميّ الأوّل string ويتضمّن السلسلة النصية المجردّة، والثاني هو عامل يستخدم مفهوم Rest Parameters والذي يمكن أن يتضمّن عددًا غير محدّدًا من الوسطاء تمثّل التعابير البرمجية المراد تضمينها في السلسلة النصية. يمكنك التحكّم بهذين العاملين والتنفيذ لرؤية ما سينتج عن تعديل كل منهما، بالشّكل: function tag(strings, ...expressions) { console.log(strings) console.log(expressions) } استخدم التابع tag كتابع القالب الموسوم ونفذ عملية التحويل على السلسلة النصية كالتالي: const string = tag`This is a string with ${true} and ${false} and ${100} interpolated inside.` وبما أنّ الترميز يتضمن إخراج كل من العاملين strings وexpressions، يكون الخرج بالشّكل: (4) ["This is a string with ", " and ", " and ", " interpolated inside." (3) [true, false, 100] العامل الأوّل strings عبارة عن شعاع يتضمّن كافّة قوالب النصوص التالية: * "This is a string with " * " and " * " and " * " interpolated inside." كما أنّ الخاصيّة raw متوفرة لهذا الوسيط من خلال استخدام strings.raw، والتي تتعامل مع السلسلة دون أخذ أي سلسلة هروب بالحسبان، فمثلًا يكون التعامل مع /n على أنّه محرف عادي ولن يفسر على أنه انتقال لسطر جديد. العامل الثاني …expressions وهو شعاع rest، ويحوي كافّة التعابير وهي: * true * false * 100 وتمرر السلاسل النصية المجرّدة والتعابير كعوامل لتابع القالب الموسوم tag، ومن الجدير بالملاحظة أنّه ليس من الضروري أن يعيد القالب الموسوم قيم من النوع سلاسل نصية حصرًا، فهو قادر على التعامل معها إلّا أنّه يعيد أي نوع من أنواع المعطيات، فعلى سبيل المثال يمكننا جعل التابع يتجاهل كل شيء ويعيد قيمة خالية null كما في التابع returnsNull التالي: function returnsNull(strings, ...expressions) { return null } const string = returnsNull`Does this work?` console.log(string) وبتمرير المتحول strings إلى الإجراء log( ) تكون القيمة المعادة في الخرج: null ويعد تغيير جانبي كل تعبير مضمّن مثالًا على الإجراءات الممكن تنفيذها في القوالب الموسومة، كما في حال رغبتك بإحاطة كل التعابير بأحد وسوم HTML. مثلًا من الممكن بناء التابع bold الذي يقوم بإضافة <strong> و</strong`> إلى جانبي كل تعبير: function bold(strings, ...expressions) { let finalString = '' //التكرار على كافّة التعابير المضمّنة في السلسة expressions.forEach((value, i) => { finalString += `${strings[i]}<strong>${value}</strong>` }) // إضافة السلسلة المجرّدة النهائية finalString += strings[strings.length - 1] return finalString } const string = bold`This is a string with ${true} and ${false} and ${100} interpolated inside.` console.log(string) يستخدم هذا الترميز الحلقة forEach للمرور على كافّة عناصر الشعاع expressions مضيفًا لكل منها عناصر جعل الخط غامقًا، ويكون الخرج الناتج بالشكل: This is a string with <strong>true</strong> and <strong>false</strong> and <strong>100</strong> interpolated inside. ولا يوجد سوى عدد قليل من الأمثلة على قوالب النصوص الموسومة في المكتبات الشائعة من جافاسكربت، فمثلَا تستخدم المكتبة graphq1-tag القالب الموسوم gq1 لتحويل السلاسل النصية من نتائج الاستعلام GraphQL إلى نمط شجرة البنية المجرّدة the abstract syntax tree (AST) وهو النمط الذي يفهمه GraphQL: import gql from 'graphql-tag' // سجل يقوم بالحصول على اسم وكنية المستخدم ذو الترتيب 5 const query = gql` { user(id: 5) { firstName lastName } } ومن المكتبات التي تستخدم توابع القوالب الموسومة أيضًا هي styled-components، والتي تمكنّك من إنشاء عناصر تفاعلية جديدة من عناصر DOM العادية عبر تطبيق تنسيقات CSS عليها: import styled from 'styled-components' const Button = styled.button` color: magenta; ` ومن الآن وصاعدًا يمكن استخدام الثابت Button كمكوّن مخصّص custom component// ولضمان عدم التعامل مع سلسلة نصية على أنّها سلسلة هروب، يمكنك استخدام الإجراء string.raw في قوالب النصوص الموسومة بالشّكل: const rawString = String.raw`I want to write /n without it being escaped.` console.log(rawString) وهذا ما سيعطي الخرج التالي: I want to write /n without it being escaped. الخلاصة راجعت في هذا المقال طريقة استخدام كل من علامات الاقتباس المفردة والمزدوجة في السلاسل النصية، كما تعلمّت عن قوالب النصوص العادية منها والموسومة، إذ تؤدي قوالب النصوص الكثير من المهام الشائعة المتعلقة بالسلاسل النصية بسهولة كبيرة عبر إمكانية تضمين التعابير البرمجية أو الكتابة على عدّة أسطر دون استخدام أي علامة ربط للسلاسل النصية أو استخدام سلاسل الهروب. كما أنّ القوالب المحرفية الموسومة تمثّل ميزة جديدة متطورة والتي قامت العديد من المكتبات الشائعة باستخدامها، مثل GraphQL و styled-components. ترجمة -وبتصرف- للمقال Understanding Template Literals in JavaScript لصاحبه Tania Rascia. اقرأ أيضًا السلاسل النصية (strings) في جافاسكربت كيفية التعامل مع النصوص في البرمجة ترميز النصوص والتعامل مع كائنات الملفات في جافاسكربت1 نقطة
-
مقدمة تُعتبر المصفوفة في الجافا سكريبت كائن عمومي (global) الغرض منه هو تخزين البيانات، وتحتوي المصفوفة إما على مجموعة من العناصر بنوع بيانات واحد أو أكثر، وقد تكون فارغة. نستخدم الفهارس العددية التي تبدأ من القيمة 0 للوصول إلى عناصر المصفوفة. المصفوفات مفيدة جدًا بما أنها تُخزن عدة قيم في متغير واحد، وهذا الأمر يقلل وينظم الشيفرة البرمجية التي نكتبها ويجعلها أكثر ملائمة للقراءة والصيانة. تستطيع المصفوفة أن تحتوي على أي نوع بيانات، ابتداءً من الأرقام ومرورا بالنصوص والكائنات وغيرها من أنواع البيانات. لتوضيح كيف من الممكن أن تكون المصفوفات مهمة، لنفترض أننا نريد أن نحفظ أسماء المحيطات في متغيرات عدة، بحيث يكون لكل محيط المتغير الخاص به: oceans.js // Assign the five oceans to five variables const ocean1 = "Pacific"; const ocean2 = "Atlantic"; const ocean3 = "Indian"; const ocean4 = "Arctic"; const ocean5 = "Antarctic"; هذه الطريقة مُضجرة جدا، وتُصبح أكثر صعوبة بشكل متسارع في المتابعة والصيانة. باستخدام المصفوفات، نستطيع تبسيط الأمر. oceans.js // Assign the five oceans let oceans = [ "Pacific", "Atlantic", "Indian", "Arctic", "Antarctic", ]; بدلًا من استخدام خمسة متغيرات منفصلة، نستطيع الان أن يكون لدينا متغير واحد يحتوي على جميع العناصر الخمسة. لإنشاء المصفوفة، نستخدم الأقواس المربعة [ ] كما هو واضح في الشيفرة البرمجية السابقة، وللوصول إلى عنصر معين في المصفوفة، نستخدم الفهرس مع المصفوفة بالطريقة التالية: // Print out the first item of the oceans array oceans[0]; Output Pacific في هذا الدرس سنتعلم كيفية بناء المصفوفة، وكيفية الوصول إلى عناصرها، والاضافة إليها وتعديلها والحذف منها، كما سنتعلم كيفية المرور خلال عناصرها باستخدام حلقة التكرار. إنشاء مصفوفة يوجد طريقتان لإنشاء المصفوفة في جافا سكريبت: التعريف اللفظي باستخدام الأقواس المعكوفة. التعريف بواسطة الباني (constructor) باستخدام كلمة new. لنوضح كيفية إنشاء مصفوفة تحتوي على أنواع سمك القرش، وذلك باستخدام التعريف اللفظي بواسطة الأقواس المربعة: sharks.js // Initialize array of shark species with array literal let sharks = [ "Hammerhead", "Great White", "Tiger", ]; الان نُعرف نفس المصفوفة باستخدام الباني وذلك بواسطة الجملة new Array() : sharks.js // Initialize array of shark species with array constructor let sharks = new Array( "Hammerhead", "Great White", "Tiger", ); كلا الطريقتين سوف يُنشئ لنا المصفوفة، ولكن طريقة التعريف اللفظي هي المشهورة والأكثر تفضيلا بما أن التعريف باستخدام الباني قد يؤدي إلى نتائج غير مستقرة وغير متوقعة وعليك الانتباه في حال صادفتك تلك الطريقة في التعريف أو في حال استخدامك لها. نستطيع طباعة محتويات المصفوفة بكتابة المتغير الخاص بها مباشرة: // Print out the entire sharks array sharks; Output [ 'Hammerhead', 'Great White', 'Tiger' ] تُستخدم المصفوفات عادة في تجميع العناصر أو القوائم من نفس نوع البيانات، ولكن من الناحية التقنية، فإن المصفوفات تستطيع أن تحتوي على عناصر من أنواع مختلفة بالإضافة إلى إمكانية أن تحتوي على مصفوفات أخرى: // Initialize array of mixed datatypes let mixedData = [ "String", null, 7, [ "another", "array", ], ]; بعد أن تعلمنا كيفية إنشاء المصفوفة، نستطيع الان التعامل معا بأكثر من طريقة، ولكننا في البداية نحتاج الى فهم كيفية فهرسة المصفوفات (Arrays Indexing). ملاحظة: قد تجد اخر عنصر في المصفوفة ينتهي بفاصلة وأحيانا قد لا تجد هذه الفاصلة. تُعرف هذه الفاصلة بالفاصلة التابعة (Trailing comma)، ومن الشائع ان تكون غير موجودة، ولكن بشكل عام أصبح من الأفضل أن يتم استخدامها في الشيفرة البرمجية بسبب أنها تجعل الاختلافات بين الإصدارات (في عملية إدارة الإصدارات Versions Control) أكثر وضوحا وتسهل من إضافة وإزالة عناصر المصفوفة دون أخطاء. لاحظ أن الفاصلة التابعة غير مسموح بها في ملفات JSON. فهرسة المصفوفات إذا تعاملت مسبقاً مع النصوص والفهرسة في الجافا سكريبت، ستكون مُلمًا بمفهوم فهرسة المصفوفات، حيث أن النص يُعتبر شبيهًا بالمصفوفة. لا تحتوي المصفوفات على عناصر مزدوجة على شكل اسم/قيمة، وبدلا من ذلك، فإن المصفوفات تُفهرس بقيم عددية تبدأ من القيمة 0. المثال التالي ينشئ مصفوفة باسم seaCreatures: seacreatures.js let seaCreatures = [ "octopus", "squid", "shark", "seahorse", "starfish", ]; الجدول التالي يُفصل كيف يتم فهرسة كل عنصر في المصفوفة بقيمة عددية ابتداءً من 0: octopus squid shark seahorse starfish 0 1 2 3 4 العنصر الأول في المصفوفة هو octopus ومُفهرس في الموقع 0 من المصفوفة، والعنصر الأخير هو starfish ومُفهرس في الموقع 4. تبدأ الفهرسة من 0، وهذا يتضارب مع طبيعتنا الفطرية ببدء العد من القيمة 1، لذلك نحتاج لأخذ الاحتياط وأن نتذكر هذه النقطة دائما حتى تصبح طبيعية. نستطيع أن نحصل على عدد العناصر في المصفوفة باستخدام الخاصية length: seaCreatures.length; Output 5 على الرغم من أن الفهارس الخاصة بالمصفوفة seaCreatuers تبدأ من 0 إلى 4، فإن الخاصية length سوف تُرجع العدد الفعلي للعناصر الموجودة في المصفوفة. إذا أردنا معرفة رقم الفهرس لعنصر معين في المصفوفة، وليكن مثلا seahorse، نستطيع أن نستخدم لذلك الوظيفة indexOf() : seaCreatures.indexOf("seahorse"); Output 3 إذا لم تحتوي المصفوفة على العنصر الذي نريده، فلن نحصل على رقم فهرس لعنصر غير موجود، وفي هذه الحالة، فإن الوظيفة سترجع لنا القيمة -1 كما في المثال التالي: seaCreatures.indexOf("cuttlefish"); Output -1 بواسطة أرقام الفهارس المرتبطة بعناصر المصفوفة، فإنه لدينا القدرة على الوصول لكل عنصر بشكل منفرد بهدف العمل على هذا العنصر والتعامل معه. الوصول لعناصر المصفوفة يتم الوصول لعنصر في مصفوفة جافا سكريبت بواسطة الإشارة لرقم الفهرس للعنصر بين قوسين معكوفين: seaCreatures[1]; Output squid نعلم أن الرقم 0 سيعيد لنا دائما العنصر الأول في المصفوفة. كذلك نستطيع إيجاد العنصر الأخير في المصفوفة بواسطة إجراء عملية طرح قيمة 1 من قيمة الخاصية length للمصفوفة، والإشارة لناتج هذه العملية كرقم فهرس للعنصر الأخير كما هو موضح في المثال التالي: const lastIndex = seaCreatures.length - 1; seaCreatures[lastIndex]; Output starfish محاولة الوصول لعنصر غير موجود سيعيد لنا undefined: seaCreatures[10]; Output undefined للوصول لعنصر مصفوفة متداخلة (مصفوفة داخل مصفوفة)، فعلينا إضافة فهرس اخر يعود للمصفوفة الداخلية: let nestedArray = [ [ "salmon", "halibut", ], [ "coral", "reef", ] ]; nestedArray[1][0]; Output coral في المثال السابق، قمنا بالوصول للعنصر coral بالإشارة لرقم الفهرس الذي يحتوي المصفوفة الداخلية وهو 1، ثم أشرنا للفهرس الذي يحتوي على العنصر في المصفوفة الداخلية وهو 0. إضافة عنصر لمصفوفة في المتغير seaCreatuers يوجد لدينا 5 عناصر بأرقام فهراس تبدأ من 0 الى 4. إذا أردنا أن نُضيف عنصر جديد لهذه المصفوفة، فيمكننا أن نقوم بذلك بإعطاء قيمة للفهرس التالي الذي يلي اخر فهرس: seaCreatures[5] = "whale"; seaCreatures; Output [ 'octopus', 'squid', 'shark', 'seahorse', 'starfish', 'whale' ] إذا قمنا بإضافة عنصر وتجاهلنا قيمة الفهرس التالي ووضعنا بدلا منه فهرس بقيمة 7 مثلا، فإن ذلك يؤدي لإضافة عنصر غير مُعرف (undefined) للمصفوفة كما في المثال التالي: seaCreatures[7] = "pufferfish"; seaCreatures; Output [ 'octopus', 'squid', 'shark', 'seahorse', 'starfish', 'whale', , 'pufferfish' ] هذه المشكلة نستطيع تجنبها باستخدام الوظيفة push() والتي تقوم بإضافة العنصر الجديد في نهاية المصفوفة: // Append lobster to the end of the seaCreatures array seaCreatures.push("lobster"); seaCreatures; Output [ 'octopus', 'squid', 'shark', 'seahorse', 'starfish', , 'whale', 'pufferfish', 'lobster' ] على العكس تماما من الوظيفة push()، فإن الوظيفة unshift() تقوم بإضافة العنصر في بداية المصفوفة: // Append dragonfish to the beginning of the seaCreatures array seaCreatures.unshift("dragonfish"); seaCreatures; Output [ 'dragonfish', 'octopus', 'squid', 'shark', 'seahorse', 'starfish', 'whale', , 'pufferfish', 'lobster' ] باستخدام الوظيفتين السابقتين، ستكون لديك المقدرة على إضافة عناصر جديدة للمصفوفة إما في بدايتها، أو نهايتها. إزالة عنصر من مصفوفة لإزالة عنصر معين من مصفوفة، نستخدم الوظيفة splice(). في المصفوفة seaCreatuers قمنا بإضافة عنصر غير مُعرف وليس له قيمة، ولإزالته نقوم بالتالي: seaCreatures.splice(7, 1); seaCreatures; Output [ 'dragonfish', 'octopus', 'squid', 'shark', 'seahorse', 'starfish', 'whale', 'pufferfish', 'lobster' ] في الوظيفة splice()، المُعامل الأول يشير لرقم الفهرس الذي سنبدأ بالإزالة من عنده (في هذه الحالة 7)، والمُعامل الثاني يشير لعدد العناصر التي نرغب بإزالتها (في حالتنا سيكون 1 حيث أننا نرغب بإزالة عنصر واحد). الوظيفة splice() ستؤثر على المتغير الأصلي. لذلك، إذا أردنا أن نحافظ على المصفوفة الأصلية دون تغيير، نستخدم الوظيفة slice() ونعطي القيمة الناتجة عنها لمتغير جديد. let newArray = slice(7, 1); الوظيفة pop() ستزيل العنصر الأخير من المصفوفة: // Remove the last item from the seaCreatures array seaCreatures.pop(); seaCreatures; Output [ 'dragonfish', 'octopus', 'squid', 'shark', 'seahorse', 'starfish', 'whale', 'pufferfish' ] العنصر lobster أُزيل من المصفوفة لأنه العنصر الأخير، ولإزالة العنصر الأول في المصفوفة، نستخدم الوظيفة shift(): // Remove the first item from the seaCreatures array seaCreatures.shift(); seaCreatures; Output [ 'octopus', 'squid', 'shark', 'seahorse', 'starfish', 'whale', 'pufferfish' ] باستخدام الوظيفتين pop() و shift() نستطيع إزالة العناصر من بداية المصفوفة أو نهايتها. يُفضل استخدام الوظيفة pop() قدر الإمكان، حيث أن باقي العناصر في المصفوفة تبقى في مواقعها دون تغيير. تعديل العناصر في المصفوفة نستطيع تغيير أي قيمة عنصر في المصفوفة وذلك بإعطاء القيمة الجديدة للعنصر باستخدام عملية المساواة، كما نفعل تماما عند التعامل مع المتغيرات العادية: // Assign manatee to the first item in the seaCreatures array seaCreatures[0] = "manatee"; seaCreatures; Output [ 'manatee', 'squid', 'shark', 'seahorse', 'starfish', 'whale', 'pufferfish' ] طريقة أخرى لتغيير قيمة العنصر باستخدام الوظيفة splice() وذلك بإضافة مُعامل جديد. فمثلا، إذا أردنا تغيير قيمة العنصر seahorse والذي يقع في الفهرس 3، نستطيع إزالته وإضافة قيمة جديدة بدلا منه: // Replace seahorse with sea lion using splice method seaCreatures.splice(3, 1, "sea lion"); seaCreatures(); Output [ 'manatee', 'squid', 'shark', 'sea lion', 'starfish', 'whale', 'pufferfish' ] في المثال السابق، قمنا بإزالة العنصر seahorse من المصفوفة، ووضعنا بدلا منه القيمة sea lion في نفس الفهرس 3. حلقة التكرار خلال المصفوفة نستطيع المرور على عناصر المصفوفة من خلال حلقة تكرار for وذلك بالاستفادة من خاصية length. في المثال التالي، نُنشئ مصفوفة باسم shellfish ونطبع رقم كل فهرس فيها بالإضافة إلى قيمة العنصر المرتبط بالفهرس: // Create an array of shellfish species let shellfish = [ "oyster", "shrimp", "clam", "mussel", ]; // Loop through the length of the array for (let i = 0; i < shellfish.length; i++) { console.log(i, shellfish[i]); } Output 0 'oyster' 1 'shrimp' 2 'clam' 3 'mussel' نستطيع أيضا استخدام حلقة التكرار for…of وهي خاصية جديدة في الجافا سكريبت: // Create an array of aquatic mammals let mammals = [ "dolphin", "whale", "manatee", ]; // Loop through each mammal for (let mammal of mammals) { console.log(mammal); } Output dolphin whale manatee حلقة التكرار for…of لا تقوم باستخدام رقم الفهرس للعناصر في المصفوفة، ولكنها بشكل عام طريقة أبسط وأكثر اختصارا للمرور على المصفوفة من خلال حلقة التكرار. استخدام حلقات التكرار مفيد بشكل كبير في طباعة قيم عناصر المصفوفة وهو يشبه عرض العناصر من قاعدة بيانات خلال موقع الكتروني. خاتمة تُعتبر المصفوفات جزء أساسي ومهم في برمجة الجافا سكريبت. في هذا الدرس تعلمنا كيفية إنشاء المصفوفة، وكيفية فهرستها، وتعلمنا إجراء بعض العمليات المهمة على المصفوفات مثل إزالة العناصر والتعديل عليها. وكذلك تعلمنا طريقتين للمرور على عناصر المصفوفة من خلال حلقات التكرار والتي تهدف لإجراء عمليات على عناصر المصفوفة مثل طباعة محتوياتها وطباعة أرقام الفهارس. ترجمة -وبتصرّف- للمقال Understanding Arrays in JavaScript لصاحبه Tania Rascia حقوق الصورة البارزة محفوظة لـ Freepik1 نقطة
-
حققت برامج التعلم العميق والذكاء الاصطناعي نموًا متزايدًا في الآونة الأخيرة، إذ تشير الإحصاءات إلى أن القيمة السوقية لهذه التقنيات الحديثة قد تصل إلى 930 مليون دولار بحلول العام 2025م، كما ارتفع عدد الأعمال والوظائف التي تتطلب فهم مهارات الذكاء الاصطناعي بنسبة 450 % منذ تسع سنوات مضت. فما هو التعلم العميق Deep Leaning؟ وما هي تطبيقاته الأكثر استخدامًا في العالم؟ إليك قائمة محتويات المقال: مفهوم التعلم العميق كيف يعمل التعلم العميق؟ الفرق بين تعلم الآلة والتعلم العميق تطبيقات التعلم العميق الرعاية الصحية التعلم العميق في التسويق الإلكتروني البحث الصوتي والمرئي والدردشة الآلية التعلم العميق في التعليم عالم الترفيه تقصى الحقائق وكشف الأخبار المزيفة السيارات ذاتية القيادة الأرصاد والمناخ تحديات التعلم العميق الجودة الضعيفة للبيانات خداع التعلم العميق عدم فهم السياق جيدًا ضغوط على المؤسسات قرصنة التعلم العميق مفهوم التعلم العميق التعلم العميق Deep Learning هو فئة فرعية من تعلم الآلة Machine Learning الذي يعتمد على الشبكات العصبية الاصطناعية إلى جانب التعلم التمثيلي. لذلك، فإنه عبارة عن تقنية حاسوبية تحاكي العقل البشري من خلال تصميم خوارزميات مستوحاة من بنية القشرة الدماغية ووظيفتها حتى يمكنها تقليد جميع قدرات الدماغ مثل فهم اللغة الطبيعية والأصوات ومحتوى الصور والقدرة على تنفيذ العديد من الأوامر والتعليمات كما يفعل الإنسان. ويعد التعلم العميق من العلامات الفارقة المميزة في العصر الحديث، فقد نجح العلماء في إنشاء شبكات البرسبترون العصبونية Perceptron القائمة على فكرة وظائف الشبكات العصبية Neural network، فهو يتضمن بناء شبكات عصبية قادرة على معالجة البيانات المعقدة بدرجة أكثر شمولًا وتركيزًا من تقنيات الذكاء الاصطناعي الأخرى. كيف يعمل التعلم العميق؟ استطاع العلماء دراسة العقل البشري وكيفية عمل الأدمغة التي تحتوي على مليارات الخلايا العصبية المتشابكة معًا، وذلك بهدف إنشاء نموذج محاكاة من هذه الخلايا العصبية القادرة على تصفية المعلومات وتصنيفها ومعالجتها كما يحدث في دماغ الإنسان، ومن هنا جاءت فكرة إنشاء خوارزميات التعلم العميق. ويطلق عليه التعلم العميق لأنه يستخدم الشبكة العصبية الاصطناعية العميقة. وهذه الشبكة الاصطناعية تحتوي على خلايا عصبية تضم مجموعة من الطبقات المتصلة والمتراكمة فوق بعضها بعضًا، التي تبدأ بطبقة الإدخال المستوحاة من حواس الإنسان وتستقبل إشارات البيانات والمعلومات وتنتهي بطبقة الإخراج التي تظهر النتيجة النهائية للمعلومات، وبين هاتين الطبقتين توجد طبقات مخفية تكون مسؤولة عن تحليل البيانات للوصول إلى الاستنتاجات قبل استخراجها على هيئة معلومات مفيدة. وكل طبقة في الشبكات العصبية العميقة Deep Neural Networks تكون مسؤولة عن التقاط أنماط معينة من البيانات أو معلومات محددة ومعالجتها باستخدام خوارزميات التعلم العميق. ويطلق على الخلية العصبية في هذه الشبكة اسم (عصبون) وكل خلية لها وزن يحدد أهمية كل عنصر على حدة، إضافة إلى إمكانية تعديل الأوزان أكثر من مرة لضمان الحصول على نتائج دقيقة في نهاية المطاف. وبذلك يمكن لخاصية التعلم العميق معالجة كمية هائلة من البيانات. وتعد الشبكات العصبية التلافيفية Convolutional Neural Network التي تعرف اختصارًا CNN، من أبرز الشبكات العصبية العميقة المستخدمة في التعلم العميق، فإنها تشتمل على طبقات متعددة ذات بنية استثنائية بهدف معالجة بيانات غير منظمة غالبًا مثل الصور للتنبؤ بما فيها وقراءتها ومعرفة الميزات الفريدة بها. ما الفرق بين تعلم الآلة والتعلم العميق؟ يظن الكثيرون من غير المتخصصين أن التعلم العميق وتعلم الآلة والذكاء الاصطناعي مفاهيم مترادفة وتُستخدم لتنفيذ الوظائف التقنية ذاتها، لكن الحقيقة عكس ذلك، لأن تعلم الآلة Machine Learning أحد فروع الذكاء الاصطناعي Artificial Intelligence، وأعم وأشمل من التعلم العميق Deep learning. ببساطة، يركز تعلم الآلة عمومًا على جعل الأجهزة الحاسوبية لديها القدرة على أداء المهام دون الحاجة إلى برمجة واضحة استنادًا إلى خوارزميات أكثر بساطة كتلك التي تعتمد على التوقع الخطي أو شجرة القرارات، أما التعلم العميق يستوجب إنشاء خوارزميات أكثر تعقيدًا وذات مستويات مختلفة مثل الشبكات العصبية الاصطناعية ANNs والشبكات العصبية التلافيفية CNN. كما أن خوارزميات التعلم الآلي يمكن تغذيتها ببيانات منظمة من أجل تحليلها والوصول إلى استنتاجات مفهومة، أما التعلم العميق يحتاج إلى بيانات غير منظمة وأنماط معقدة مثل النصوص المكتوبة والصور ومقاطع الفيديو والأصوات واللغات. كذلك، يتطلب التعلم العميق تدخلًا بشريًا أقل من تعلم الآلة، لكنه يحتاج إلى قوة حاسوبية وطاقة كبير للغاية من أجل المشكلات الأكثر تعقيدًا ومعالجة البيانات الضخمة باستخدام أجهزة وتقنيات معينة، على عكس تعلم الآلة الذي يتطلب كمية أقل من البيانات وقوة حاسوبية أقل أيضًا. تطبيقات التعلم العميق لا يقتصر استخدام تقنيات التعلم العميق على فهم الصور ومقاطع الفيديو فحسب، إنما يُستخدم على نطاق واسع في مجالات وقطاعات مختلفة، ونرى العديد من التطبيقات في حياتنا الراهنة خاصة مع تزايد حجم البيانات وبعدما أصبحت التكنولوجيا ميسورة التكلفة، فنلاحظ مثلًا أن النظام الأساسي في شبكة التواصل الاجتماعي "فيسبوك" لديه القدرة على معرفة أصدقائك وقراءة صورهم وتمييزها، وفيما يلي أهم تطبيقات التعلم العميق: الرعاية الصحية مع تطور الذكاء الاصطناعي، دخلت خوارزميات التعلم العميق في مجالات الطب والرعاية الصحية، ومكنت هذا القطاع من توفير القدرة على تحليل البيانات وفحصها بسرعة استثنائية، إضافة إلى دعم رعاية المرضى مع تقليل التكاليف وتحسين الكفاءات وتشخيص الأمراض. على سبيل المثال، تُستخدم أداة Aidoc في دعم الأطباء خاصة أنها تعتمد على خوارزميات تسرع تشخيص المريض وعلاجه مثل اكتشاف أماكن النزيف داخل الجمجمة والانسداد الرئوي، وغير ذلك. وبفضل خوارزميات التعلم العميق، نجح فريق بجامعة كاليفورنيا في عام 2016م، بتطوير تقنية تصور الخلايا في عينات الدم بسرعة كبيرة دون أن تؤثر سلبًا على هذه الخلايا والاستفادة منها في التحليلات المستقبلية الأخرى. كما تُستخدم الشبكات العصبية التلافيفية CNN في معرفة نتائج التصوير بالرنين المغناطيسي والأشعة السينية. وتوصلت دراسة -نُشرت نتائجها في المجلة العلمية Annals of Oncology- إلى أن خوارزميات الشبكات CNN قادرة على تحليل صور الأمراض الجلدية التي تحدد الإصابة بسرطان الجلد بدقة أكبر من الأطباء البشريين بنسبة 10%. لذلك أكد الفريق البحثي أن هذه الشبكات الاصطناعية تُعد أداة مناسبة للكشف عن سرطان الجلد. لا تقتصر تطبيقات التعلم العميق في القطاع الطبي على ذلك، بل شملت الدخول في عالم الطب الدقيق واكتشاف وتصنيع الأدوية والتنبؤ بالوفيات في المستشفيات. على سبيل المثال، طور فريق من جوجل بالتعاون مع جامعات أمريكية تقنية تعتمد على خوارزمية التعلم العميق ومعالجة اللغة الطبيعية التي حللت ما يزيد عن 46 مليار نقطة بيانات في 216 ألف سجل صحي إلكتروني عبر مستشفيين. وساعدت هذه التقنية في التنبؤ بطول فترة إقامة المرضى واحتمالات الوفاة بينهم. التعلم العميق في التسويق الإلكتروني أصبح التعلم العميق جزءًا لا يتجزأ من التسويق الإلكتروني، إذ سخرت قنوات التسويق الرقمي مثل فيسبوك قدرات التعلم العميق لتقديم أفضل تجربة للمتسوقين والمعلنين، وذلك من خلال استخدام تحليلات النص العميق Deep Text الذي يعالج اللغة بالذكاء الاصطناعي ويفهمها مثل البشر، إضافة إلى تصفية "موجز الأخبار" الخاص بالمستخدمين واكتشاف المحتوى الجديد وفهم النصوص المرغوب فيها وتجنب غيرها. وتشير الإحصائيات إلى أن أكثر من 51% من المسوقين يستثمرون تقنيات الذكاء الاصطناعي والتعلم العميق في حملات التسويق الإلكتروني للحصول على رؤى مستنيرة حول جمهورهم المستهدف في العام 2019، وفقا لما نقلته شبكة "businessinsider". بينما يرى 52% من جهات التسويق أن الذكاء الاصطناعي مهم لنجاح حملاتهم التسويقية ويؤكد 41% منهم أن تسريع نمو الإيرادات كان نتاجًا عن استخدام هذه الخوارزميات ويتوقع 80% منهم أتمتة أكثر من ربع مهامهم التسويقية خلال السنوات الخمسة المقبلة. يوجد العديد من المسوقين الذين يستخدمون تقنيات تعلم الآلة والتعلم العميق في تقديم محتوى مخصص وتحليل الفيديو والوصول إلى جمهور أكثر استهدافًا وفقًا لتفضيلاتهم أو سلوكياتهم والتفاعل معهم بفاعلية والتنبؤ برغبات العملاء والاستفادة من البيانات لأداء عروض أسعار في الوقت الفعلي. على سبيل المثال وليس الحصر، تهتم منصة "Google Cloud Video Intelligence" بإنشاء تحليلات لمقاطع الفيديو وتتيح إعداد ملخصات آلية لمستخدميها. البحث الصوتي والمرئي والدردشة الآلية هناك العديد من الشركات التي تستخدم خاصية التعلم العميق في منتجاتها الرقمية، فنجد تطبيق المساعد الصوتي Apple Siri الذي ترجم الصوت البشري إلى أوامر حاسوبية تسمح لمالكي أجهزة آيفون الحصول على المعلومات بناءً على أسئلتهم، كما أن أداة البحث الصوتي التي تستخدم خوارزميات جوجل Google Voice Search تتيح البحث بالصوت بدلًا من النصوص المكتوبة. فهي أدوات قائمة على فهم الأوامر الصوتية التي يطلبها المستخدمين. وهناك برامج سخرت التعلم العميق في البحث المرئي للجوال، مثل تطبيق "CamFind" الذي يتيح لمستخدميه التقاط صورة ما واستخدامها في إجراء عمليات البحث بدلًا من كتابة النصوص. إضافة إلى روبوتات الدردشة الآلية المستخدمة في حل مشكلات العملاء والتواصل معهم دون تدخل بشري، وهذه الروبوتات فعالة في التسويق عبر مواقع التواصل الاجتماعي والتفاعل مع العملاء وتقديم استجابات فورية لهم. التعلم العميق في التعليم يُستخدم تعلم الآلة والتعلم العميق في التعليم لمنح الطلاب تجربة تعليمية فردية وتحليل أدائهم وتعديل طرق التدريس والمناهج الدراسية استنادًا إلى البيانات التي يتم معالجتها في أثناء تجارب الطلاب، ويساعد على زيادة كفاءة المعلمين من خلال فهم إمكانات الطلاب وتقديم محتوى تعليمي ممتع يشجع المتعلمين على التعلم والمشاركة. كما يسهم في إجراء التحليلات المتقدمة والتنبؤية المتعلقة بالعملية التعليمية. ومِنْ ثَمَّ، اتخاذ القرارات والإجراءات الصحيحة الأكثر عقلانية. توجد أمثلة عديدة لاستخدام التعلم العميق والتعلم الآلي في التعليم، مثل أداة "Quizlet" التي تتيح للمتعلمين تصميم الاختبارات والبطاقات التعليمية والرسوم البيانات وتضم ما يزيد عن 50 مليون مستخدم نشط. أما منصة "SchooLinks" فإنها تمكّن الطلاب من تصميم السير الذاتية ومعرفة الدورات التدريبية التي ينبغي الحصول عليها، وغيرها من الخدمات التي تتطلب استخدام خوارزميات التعلم الآلي. وغيرها من التطبيقات والأدوات التي تستعين بخوارزميات التعلم العميق والهادفة إلى جذب الطلاب وزيادة مشاركتهم وتنوع طرق التدريس. عالم الترفيه تُستخدم تطبيقات التعلم العميق والذكاء الاصطناعي في عالم الترفيه من أجل تقديم تجربة ممتعة للعملاء، فهناك شركات عالمية عديدة مثل يوتيوب وأمازون ونتفلكس تستغل خوارزميات الذكاء الاصطناعي في عرض الأفلام والأغاني ومقاطع الفيديو المختلفة بناءً على رغبات وسلوكيات وخيارات العميل التي نفذها سابقًا. كما يمكن الاستعانة بتقنيات التعلم العميق في تحويل أصوات الممثلين إلى ترجمات نصية تلقائية أو إدراج الأصوات في الأفلام السينمائية الصامتة. وقد استخدمت بعض شركات الترفيه هذه الخوارزميات لإنشاء نمذجة التنبؤ في الوقت الفعلي اعتمادًا على الاتجاهات الحالية للعملاء التي تُجمع من مصادر البيانات، وذلك يساعد الشركات على التفاعل مع عملائهم بشكل فوري، وتوقع سلوكياتهم المستقبلية والتعرف على الأفلام ومقاطع الفيديو التي تستهلكها شرائح صغيرة من الجمهور في الوقت الحالي ومن المتوقع شهرتها مستقبلًا، فضلًا عن إمكانية إنتاج الموسيقى باستخدام نماذج قائمة على خوارزميات التعلم العميق. تقصي الحقائق وكشف الأخبار المزيفة لجأت غرف الأخبار وصالات التحرير إلى تقنيات الذكاء الاصطناعي والتعلم العميق للتحقق من المعلومات المضللة وتقصي الحقائق، فقد طور باحثون من جامعة Waterloo الكندية نظام يستخدم خوارزميات الذكاء الاصطناعي للتعلم العميق لتقييم المقالات الإخبارية تلقائيًا بهدف تحديد المعلومات المضللة. وهناك منصات عديدة لتقصي الحقائق مثل Snopes و FactCheck.org، و PolitiFact تسخر الذكاء الاصطناعي في هذه المهمة. وتعد تقنية التحليل الرقمي "InVID" من أبرز الأدوات التي تستخدم خوارزميات التعلم العميق والذكاء الاصطناعي في الكشف عن الأخبار المزيفة والمعلومات المضللة، فهي تتضمن أكثر من 15 أداة لتقصي الحقائق، فمثلًا تسمح بتجزئة الفيديو إلى صور ثابتة لإجراء بحث عكسي عليها عبر محركات البحث العملاقة مثل Google و Yandex و Baidu، إضافة إلى استخراج البيانات الوصفية للفيديوهات وتحليلها والتعرف على ما إذا كانت الصور معدلة أم أصلية، وما إلى ذلك. السيارات ذاتية القيادة واحدة من تطبيقات التعلم العميق التي أدهشت العالم، هي السيارات ذاتية القيادة التي تعتمد على الشبكات العصبية الاصطناعية في القيادة وتحديد إشارات المرور واكتشاف الأشياء التي ينبغي تجنبها في أثناء القيادة دون أي تدخل بشري، إضافة إلى التعرف على وقت ضبط السرعة وتوجيهها بطريقة آمنة في الطرقات. ففي عام 1989م، استخدمت أول سيارة ذاتية القيادة التي عرفت باسم ALVINN الشبكات العصبية لاكتشاف خطوط الممرات وتقسيم البيئة وإمكانية القيادة، وكانت النتيجة جيدة إلا أنها محدودة لعدم توافر البيانات وضعف المعالجة. والآن، أضحت هذه التجربة أفضل مما كانت عليه في الماضي، فقد استحوذت خوارزميات التعلم العميق على النواحي الفرعية للقيادة الذاتية، لا سيما في ظل توفر البيانات الضخمة والمعالجات القوية. وتعتمد القيادة الذاتية على أجهزة الاستشعار المختلفة مثل الكاميرات أو GPS لجلب البيانات من البيئة المحيطة بالسيارة ومعالجتها باستخدام خوارزميات التعلم العميق من أجل اتخاذ القرارات المناسبة والجيدة وذات الصلة بالبيئة، وهذا يتطلب توافر فحص وفهم أربعة مكونات أساسية في هذه السيارات تتمثل في التصور والإدراك perception ومعرفة الخريطة والموقع المبدئي Localization والتنبؤ بالأشياء المحيطة Prediction وصناعة القرار Decision Making. الأرصاد والمناخ ساعدت تقنيات التعلم العميق على تحليل بيانات الأرصاد الجوية والأبحاث البيولوجية والتنبؤات المناخية ومعرفة أحوال الطقس مثل احتمالات سقوط الأمطار أو وقوع الزلازل واندلاع البراكين، مما يسهم في اتخاذ الاحتياطات والإجراءات اللازمة التي تحمي الناس من مخاطر هذه الكوارث الطبيعية. على سبيل المثال، ابتكر فريق بحثي في جامعة واترلو الكندية تقنية تعتمد على خوارزميات التعلم العميق للكشف عن نقاط التحول في التغير المناخي والعمل كنظام إنذار مبكر. وإذا كنت ترغب في تطبيق هذه الخوارزميات في مشروعك أو خدماتك التقنية وتحتاج إلى بعض المساعدة، فإنه يمكنك الاستعانة بخدمات التعلم العميق التي توفرها منصة خمسات -أكبر سوق عربي لبيع وشراء الخدمات المصغرة- وتضم لفيف من الخبراء العرب والمحترفين في مجال الذكاء الاصطناعي والتعلم العميق ولديهم القدرة على تقديم الدعم لك على أكمل وجه. تحديات التعلم العميق على الرغم من الطفرة الهائلة التي أحدثتها خوارزميات التعلم العميق في مختلف القطاعات، فهو ليس حلًا سحريًا لمعالجة جميع المشكلات، لأن هناك تحديات صعبة تواجه هذه التقنيات الحديثة وتمنعها من منافسة العقل البشري. فعلى سبيل المثال، تستلزم عملية التعرف على صورة ما معالجة ملايين البيانات لتحديدها. الجودة الضعيفة للبيانات تتطلب تقنيات التعلم العميق استخدام بيانات عالية الجودة لاستخراج نتائج جيدة ودقيقة، أما البيانات الرديئة التي تحتوي على أخطاء كثيرة وقيم متطرفة وبيانات فوضوية، فلن تعمل خوارزميات التعلم العميق بصورة صحيحة. لذلك، يعكف الكثير من علماء البيانات على تنظيف البيانات وتنقيتها في أغلب أوقاتهم من خلال تجاهل القيم المتطرفة أو إصلاحها وملء البيانات المفقودة يدويًا. خداع التعلم العميق يظن البعض أن خوارزميات التعلم العميق لا يمكن خداعها، وهذا اعتقاد خاطئ تمامًا، لأنه من السهل نسبيًا استخدام الاحتيال مع هذه التقنيات. فقد أجرى باحثون في معهد ماساتشوستس للتكنولوجيا MIT في عام 2017م، دراسة حول إمكانية خداع مصنف الصور InceptionV3 التابع لجوجل، وبعد التلاعب المتعمد في صورة سلحفاة ثلاثية الأبعاد، صنفتها الشبكة العصبية الاصطناعية على أنها بندقية وليست سلحفاة، وفي تجربة أخرى حدث خلط بين طائرة الهليكوبتر والبندقية. عدم فهم السياق جيدا تحتاج خوارزميات التعلم العميق إلى بيانات كافية لتعمل بطريقة صحيحة، فهي جيدة في ربط المدخلات مع المخرجات، لكنها لا تفهم سياق البيانات التي تتعامل معها بدقة في كثير من الأحيان. فكلمة "عميق" في مصطلح التعلم العميق تركز على بنية الخوارزميات وعدد الطبقات المخفية أكثر من مستوى فهمها لما تعالجه من بيانات. وتتطلب الشبكة العصبية الاصطناعية التدريب والتأقلم حتى تفهم السياق إذا حدثت أي تغيرات في البيانات. ضغوط على المؤسسات توصلت دراسة استقصائية أجريت في عام 2017 إلى أن 80% من المؤسسات تستثمر في الذكاء الاصطناعي رغم توقعها بوجود عوائق صعبة أمامها. وهذه النتيجة تشير إلى احتمالية وجود ضغط متزايد على الشركات ومطوريها للتركيز على تقنيات التعلم العميق وحلول الذكاء الاصطناعي لزيادة الإنتاجية والوصول إلى استنتاجات مستنيرة واتخاذ قرارات صائبة تدفع هذه الشركات للأمام. قرصنة التعلم العميق هناك تخوفات من أن تصبح الشبكات العصبية عرضة للقرصنة والهجمات الإلكترونية، على سبيل المثال، من المحتمل استغلال خوارزميات التعلم العميق في السيارات ذاتية القيادة لتغيير سلوكها بطريقة مؤذية، وهذا ما فعله باحثون في تجربة نُشرت نتائجها في دورية Nature، فقد تعمدوا تضليل الشبكات العصبونية بالسيارة ذاتية القيادة من خلال وضع ملصقات معينة على كلمة "توقف" إلا أن النظام أخطأ في قراءتها واعتبرها "الحد الأقصى للسرعة 45". أخيرًا، هل يمكن القول بأن تجارب التعلم العميق محكوم عليها بالفشل؟ بالتأكيد لا، لأن تقنيات التعلم العميق تعمل بكفاءة عالية إذا ما توفرت البيانات الكافية وعالية الجودة، كما يكرس علماء البيانات والمطورون جهودهم من أجل التغلب على هذه التحديات وتحسين نماذج التعلم العميق وتطويرها وسط تخوفات من تهديد التعلم العميق النسيج الاجتماعي والاقتصادي من خلال دفع البشر إلى البطالة أو غير ذلك. المراجع والمصادر What is Deep Learning and How Does It Works [Explained] The Best Introduction to Deep Learning - A Step by Step Guide Top 10 Deep Learning Applications Used Across Industries Deep Learning Tutorial for Beginners: Neural Network Basics Difference Between Deep Learning and Machine Learning Vs AI Are There Really as Many Neurons in the Human Brain as Stars in the Milky Way? How Many Neurons Are in the Brain? ما هو التعلم العميق؟ Deep Learning vs. Machine Learning — What’s the Difference? Difference Between Machine Learning and Deep Learning Deep learning vs. machine learning – What’s the difference? The Amazing Ways Google Uses Deep Learning AI How is Machine Learning enhancing the Future of Education? Artificial intelligence may be set to reveal climate-change tipping points AI in Marketing: How brands can improve personalization, enhance ad targeting, and make their marketing teams more agile The 2021 State of Marketing AI Report MACHINE LEARNING IN EDUCATION: EXPLANATION, BENEFITS, CASE What Is Deep Learning and How Will It Change Healthcare? DEEP LEARNING IN HEALTHCARE – HOW IT’S CHANGING THE GAME Top Use Cases for AI in Media and Entertainment Deep learning won’t detect fake news, but it will give fact-checkers a boost Taking a Stance on Fake News: Towards Automatic Disinformation Assessment via Deep Bidirectional Transformer Language Models for Stance Detection Deep Learning in Self-Driving Cars Self-Driving Cars With Convolutional Neural Networks (CNN) 5 Challenges of Machine Learning! 5 Key Deep Learning/AI Challenges in 2018 The limits and challenges of deep learning Turtle or rifle? Google AI tricked by MIT students مشكلةٌ عويصة تواجه تقنيات التعلم العميق The Complete Beginner’s Guide to Deep Learning: Artificial Neural Networks كيف يمكن للذكاء الاصطناعي أن يشكل مستقبل تسويق المحتوى اقرأ أيضًا الذكاء الاصطناعي: مراحل البدء والتطور والأسس التي نشأ عليها تعلم الآلة: التحديات الرئيسية وكيفية التوسع في المجال تعلم الذكاء الاصطناعي1 نقطة
-
يمكن لرسوم JavaScript التعامل مع حالات لا يمكن أن تتعامل معها CSS، مثل التحرك على مسار معقد مختلف عن منحنيات بيزيه Bezier curves باستخدام دالة توقيت، أو رسوميات متحركة على لوحة رسم. استخدام الدالة setInterval يمكن إنجاز الرسوم المتحركة في صورة سلسلة من الإطارات، والتي تكون عادةً تغيرات صغيرةً في خصائص HTML/CSS، فعلى سبيل المثال: يؤدي تغيير قيمة الخاصية style.left من 0px إلى 100px إلى تحريك العنصر، وإذا زدنا هذه القيمة ضمن الدالة setInterval، فسيؤدي تغير مقداره 2px مع تأخير ضئيل، لتكرار العملية بمقدار 50 مرةً في الثانية، مما يجعل الحركة سلسةً وناعمةً، ويُتَّبع هذا الأسلوب في السينما، فعرض 24 إطارًا في الثانية يجعل الصورة سلسةً. إليك الشيفرة المجردة pseudo-code للفكرة: let timer = setInterval(function() { if (animation complete) clearInterval(timer); else increase style.left by 2px }, 20); // تغير بمقدار 2 بكسل بتأخير 20 ميلي ثانية يعطي 50 إطار في الثانية وهذا مثال أكثر تعقيدًا: let start = Date.now(); // تذكر وقت البدء let timer = setInterval(function() { // كم مضى من الوقت منذ البداية let timePassed = Date.now() - start; if (timePassed >= 2000) { clearInterval(timer); // أنهي الحركة بعد ثانيتين return; } // ارسم إطار الحركة في اللحظة الحالية draw(timePassed); }, 20); // عندما يتغير الوقت بين 0 و2000 ميلي ثانية // تتغير قيمة الخاصية من 0 بكسل إلى 400 بكسل function draw(timePassed) { train.style.left = timePassed / 5 + 'px'; } إليك المثال النموذجي التالي: شيفرة الملف index.html: <!DOCTYPE HTML> <html> <head> <style> #train { position: relative; cursor: pointer; } </style> </head> <body> <img id="train" src="https://js.cx/clipart/train.gif"> <script> train.onclick = function() { let start = Date.now(); let timer = setInterval(function() { let timePassed = Date.now() - start; train.style.left = timePassed / 5 + 'px'; if (timePassed > 2000) clearInterval(timer); }, 20); } </script> </body> </html> وستكون النتيجة: See the Pen JS-p3-05-JavaScript-animations -ex1 by Hsoub (@Hsoub) on CodePen. استخدام الدالة requestAnimationFrame لنفترض تنفيذ عدة حركات انتقالية معًا. إذا شغّلنا هذه الرسوم منفصلةً فسيعيد المتصفح -وعلى الرغم من أنّ لكل حركة دالة (setInterval(..., 20 خاصةً- رسم الصور بمعدل أكبر بكثير من 20 ميلي ثانية، ويحدث هذا لوجود أوقات بداية مختلفة لكل حركة، وبالتالي سيختلف تكرار التغيّر الذي ضبطناه عند 20 ميلي ثانية بالنسبة لكل حركة، وهكذا سنكوِّن حالات تشغيل مستقلةً لكل حركة انتقالية تتكرر كل 20 ميلي ثانية، وبكلمات أخرى انظر الشيفرة التالية: setInterval(function() { animate1(); animate2(); animate3(); }, 20) والتي ستكون أخفّ من ناحية التنفيذ على المتصفح من الشيفرة: setInterval(animate1, 20); // حركة انتقالية مستقلة setInterval(animate2, 20); // في أماكن مختلفة من السكربت setInterval(animate3, 20); ينبغي تجميع عمليات الرسم المستقلة لتسهيل الأمر على المتصفح، ولتخفيف الحِمل على وحدة المعالجة إلى جانب إظهار حركة أكثر نعومةً. تذكر دائمًا أنه يجب ألا نشغل عملية الرسم كل 20 ميلي ثانية، لأنها قد تزيد حمولة وحدة المعالجة، أو لوجود أسباب لتقليل عملية إعادة الرسم، مثل الحالة التي تكون ضمن نافذة مخفية للمتصفح. ولتمييز ذلك في JavaScript سنستخدم ميزةً تُدعى توقيت الحركة Animation timing، والتي تزوّدنا بالدالة requestAnimationFrame التي تتعامل مع هذه الأمور وأكثر، وإليك صيغة استخدامها: let requestId = requestAnimationFrame(callback) تجدول الدالة requestAnimationFrame دالة الاستدعاء callback للعمل في أقرب وقت يريد فيه المتصفح تنفيذ الحركة، فإذا نفَّذنا أي تغييرات على العناصر ضمن الدالة callback، فستُجمّع مع غيرها من دوال الاستدعاء التي تجدولها الدالة requestAnimationFrame ومع رسوميات CSS، وهكذا سيعيد المتصفح الحسابات الهندسية، ثم يعيد الرسم مرةً واحدةً بدلًا من مرات متعددة. يمكن استخدام القيمة requestId التي تعيدها الدالة requestAnimationFrame في إلغاء الاستدعاء: // ألغ تنفيذ الاستدعاءات المجدولة cancelAnimationFrame(requestId); لدالة الاستدعاء callback وسيط واحد، وهو الوقت الذي انقضى منذ بداية تحميل الصفحة مقدرًا بالميكروثانية، والذي يمكن الحصول عليه باستدعاء التابع performance.now. يُنفَّذ الاستدعاء callback مبكرًا إلا في حالة التحميل الزائد للمعالج، أو عندما تقارب بطارية الحاسوب المحمول على النفاد أو لأسباب مشابهة، وتظهر الشيفرة التالية الوقت المستغرق خلال مرات التنفيذ العشرة الأولى للدالة requestAnimationFrame، وهو عادةً بين 10-20 ميلي ثانية: <script> let prev = performance.now(); let times = 0; requestAnimationFrame(function measure(time) { document.body.insertAdjacentHTML("beforeEnd", Math.floor(time - prev) + " "); prev = time; if (times++ < 10) requestAnimationFrame(measure); }) </script> See the Pen JS-p3-05-JavaScript-animations -ex2 by Hsoub (@Hsoub) on CodePen. الرسومات المتحركة المهيكلة Structured animation سننشئ الآن دالةً أكثر عموميةً مبنيةً على الدالة requestAnimationFrame: function animate({timing, draw, duration}) { let start = performance.now(); requestAnimationFrame(function animate(time) { // يتحرك الزمنين 0 و1 let timeFraction = (time - start) / duration; if (timeFraction > 1) timeFraction = 1; // حساب الحالة الراهنة للرسوم المتحركة let progress = timing(timeFraction) draw(progress); // تنفيذ الرسم if (timeFraction < 1) { requestAnimationFrame(animate); } }); } تقبل الدالة animate ثلاثة معاملات تصف الحركة، وهي: duration: الزمن الكلي لتنفيذ الحركة مقدرًا بالميلي ثانية. (timing(timeFraction: دالة توقيت تشابه الخاصية transition-timing-function في CSS، وتعطي نسبة الوقت الذي انقضى (0 عند البداية و1 عند النهاية)، وتعيد ما يدل على اكتمال الحركة، مثل الإحداثي y عند رسم منحني بيزيه، ولنتذكر أن الدالة الخطية تعني أن الحركة ستتقدم بانتظام وبالسرعة ذاتها: function linear(timeFraction) { return timeFraction; } وسيبدو الرسم البياني للدالة الخطية كالتالي: وهي مشابهة تمامًا للخاصية transition-timing-function، وسنرى لاحقًا بعض أشكال الاستخدام الأخرى. (draw(progress: وهي الدالة التي تأخذ معاملًا هو مقدار اكتمال الحركة وترسمه، وتشير القيمة progress=0 إلى حالة بداية الحركة، بينما تشير القيمة progress=1 إلى حالة النهاية، فهي الدالة التي ترسم الحركة فعليًا، إذا يمكنها نقل عنصر مثلًا: function draw(progress) { train.style.left = progress + 'px'; } أو تنفيذ أي شيء آخر، وبالتالي يمكننا تحريك أي شيء بالطريقة التي نريد، لنحرّك العنصر width من 0 حتى 100% باستخدام هذه الدالة: شيفرة الملف animate.js: unction animate({duration, draw, timing}) { let start = performance.now(); requestAnimationFrame(function animate(time) { let timeFraction = (time - start) / duration; if (timeFraction > 1) timeFraction = 1; let progress = timing(timeFraction) draw(progress); if (timeFraction < 1) { requestAnimationFrame(animate); } }); } شيفرة الملف index.html: <!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <style> progress { width: 5%; } </style> <script src="animate.js"></script> </head> <body> <progress id="elem"></progress> <script> elem.onclick = function() { animate({ duration: 1000, timing: function(timeFraction) { return timeFraction; }, draw: function(progress) { elem.style.width = progress * 100 + '%'; } }); }; </script> </body> </html> ستكون النتيجة كالتالي: وإليك الشيفرة المستخدمة: animate({ duration: 1000, timing(timeFraction) { return timeFraction; }, draw(progress) { elem.style.width = progress * 100 + '%'; } }); يمكننا بهذا الأسلوب تنفيذ أي دوال توقيت ورسم على خلاف CSS، ولا ترتبط دوال التوقيت بمنحني بيزيه فقط، كما يمكن للدالة draw أن تتخطى الخصائص إلى إنشاء عناصر جديدة لرسوميات نحتاجها، مثل الألعاب النارية. دوال التوقيت اطلعنا في الفقرات السابقة على أبسط الدوال وهي الدالة الخطية، لنرى الآن بعض الدوال الأخرى، حيث سنجرب بعض الحركات الانتقالية باستخدام دوال توقيت مختلفة. دالة القوة من الدرجة n يمكن استعمال progress بدلالة القوة من الدرجة n لتسريع الحركة، مثل الدالة التربيعية (أي من الدرجة 2): function quad(timeFraction) { return Math.pow(timeFraction, 2) } إليك الرسم البياني: لترى النتيجة انقر على الشكل التالي: كما يمكنك استعمال الدالة التكعيبية (من الدرجة 3)، وسترى أن سرعة الحركة ستزداد بزيادة درجة القوة، إليك نموذجًا تكون فيه progress من الدرجة 5: الدالة المثلثية القطعية arc صيغة الدالة: function circ(timeFraction) { return 1 - Math.sin(Math.acos(timeFraction)); } الرسم البياني: المثال النموذج: دالة إطلاق السهم back عند اطلاق السهم bow shooting فسنسحب وتر القوس ثم نحرره، وخلافًا للدالتين السابقتين، ستعتمد الدالة على معامل إضافي x هو ثابت المرونة elasticity coefficient، والذي يُعرِّف المسافة التي نسحب بها وتر القوس: function back(x, timeFraction) { return Math.pow(timeFraction, 2) * ((x + 1) * timeFraction - x) } الخط البياني للدالة عندما x = 1.5: المثال النموذجي عند نفس القيمة للمعامل x: دالة الارتداد bounce عندما نرمي كرةً فستسقط للأسفل وترتد عدة مرات ثم تتوقف. تسلك الدالة bounce هذا السلوك تمامًا لكن بترتيب معكوس، حيث يبدأ الارتداد مباشرةً، وتستخدم هذه الدالة بعض الثوابت الخاصة: function bounce(timeFraction) { for (let a = 0, b = 1, result; 1; a += b, b /= 2) { if (timeFraction >= (7 - 4 * a) / 11) { return -Math.pow((11 - 6 * a - 11 * timeFraction) / 4, 2) + Math.pow(b, 2) } } } إليك نموذجًا يستخدم دالة الإرتداد: دالة الحركة المرنة elastic إليك دالةً أخرى "مرنةً" تقبل معاملًا إضافيًا x يضبط المجال الابتدائي للحركة: function elastic(x, timeFraction) { return Math.pow(2, 10 * (timeFraction - 1)) * Math.cos(20 * Math.PI * x / 3 * timeFraction) } الخط البياني للدالة عندما x=1.5: إليك نموذجًا عن استخدام الدالة: الدوال بترتيب معكوس تعرفنا حتى اللحظة على دوال التوقيت التي تُعرف بتحويلات الدخول السهل easeIn، لكننا قد نحتاج أحيانًا إلى عرض الحركة بترتيب معكوس. تُنفَّذ هذه الحركات بالتحويل الذي يُعرف باسم الخروج السهل easeOut. التحويل easeOut تُوضع الدالة timing في هذا التحويل ضمن المُغلِّف timingEaseOut: timingEaseOut(timeFraction) = 1 - timing(1 - timeFraction) بعبارة أخرى لدينا دالة التحويل makeEaseOut التي تقبل دالة توقيت نظاميةً وتعيد المُغلّف الذي يحيط بها: // accepts a timing function, returns the transformed variant function makeEaseOut(timing) { return function(timeFraction) { return 1 - timing(1 - timeFraction); } } يمكن على سبيل المثال اختيار الدالة bounce التي شرحناها سابقًا وتطبيقها: let bounceEaseOut = makeEaseOut(bounce); وهكذا لن تكون الحركة الارتدادية في بداية الحركة بل في نهايتها، وستبدو الحركة أفضل: شيفرة الملف style.css: #brick { width: 40px; height: 20px; background: #EE6B47; position: relative; cursor: pointer; } #path { outline: 1px solid #E8C48E; width: 540px; height: 20px; } شيفرة الملف index.html: <!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <link rel="stylesheet" href="style.css"> <script src="https://js.cx/libs/animate.js"></script> </head> <body> <div id="path"> <div id="brick"></div> </div> <script> function makeEaseOut(timing) { return function(timeFraction) { return 1 - timing(1 - timeFraction); } } function bounce(timeFraction) { for (let a = 0, b = 1, result; 1; a += b, b /= 2) { if (timeFraction >= (7 - 4 * a) / 11) { return -Math.pow((11 - 6 * a - 11 * timeFraction) / 4, 2) + Math.pow(b, 2) } } } let bounceEaseOut = makeEaseOut(bounce); brick.onclick = function() { animate({ duration: 3000, timing: bounceEaseOut, draw: function(progress) { brick.style.left = progress * 500 + 'px'; } }); }; </script> </body> </html> وستكون النتيجة: سنرى هنا كيف سيغيّر التحويل سلوك الدالة، إذ ستعرَض التأثيرات الموجودة في بداية الحركة -مثل الارتداد- في النهاية، ففي الشكل التالي ستجد الارتداد الاعتيادي باللون الأحمر، والارتداد وفق تحويل الخروج السهل باللون الأزرق. الارتداد الاعتيادي: يرتد الكائن عند القاع، ثم يقفز بحدّة إلى القمة في النهاية. باستخدام easeOut الخروج السهل: يقفز أولًا إلى القمة ثم يرتد هناك. التحويل easeInOut يمكن أن نُظهر التأثير المطلوب في بداية ونهاية الحركة معًا، ويُدعى هذا التحويل بالدخول والخروج السهل easeInOut. سنحسب حالة الحركة باعتماد تابع توقيت ما كالتالي: if (timeFraction <= 0.5) { // نصف الحركة الأول return timing(2 * timeFraction) / 2; } else { // النصف الثاني للحركة return (2 - timing(2 * (1 - timeFraction))) / 2; } شيفرة المُغلِّف: function makeEaseInOut(timing) { return function(timeFraction) { if (timeFraction < .5) return timing(2 * timeFraction) / 2; else return (2 - timing(2 * (1 - timeFraction))) / 2; } } bounceEaseInOut = makeEaseInOut(bounce); إليك مثالًا نموذجيًا: شيفرة الملف style.css: #brick { width: 40px; height: 20px; background: #EE6B47; position: relative; cursor: pointer; } #path { outline: 1px solid #E8C48E; width: 540px; height: 20px; } شيفرة الملف index.html: <!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <link rel="stylesheet" href="style.css"> <script src="https://js.cx/libs/animate.js"></script> </head> <body> <div id="path"> <div id="brick"></div> </div> <script> function makeEaseInOut(timing) { return function(timeFraction) { if (timeFraction < .5) return timing(2 * timeFraction) / 2; else return (2 - timing(2 * (1 - timeFraction))) / 2; } } function bounce(timeFraction) { for (let a = 0, b = 1, result; 1; a += b, b /= 2) { if (timeFraction >= (7 - 4 * a) / 11) { return -Math.pow((11 - 6 * a - 11 * timeFraction) / 4, 2) + Math.pow(b, 2) } } } let bounceEaseInOut = makeEaseInOut(bounce); brick.onclick = function() { animate({ duration: 3000, timing: bounceEaseInOut, draw: function(progress) { brick.style.left = progress * 500 + 'px'; } }); }; </script> </body> </html> وستكون النتيجة: يدمج التحويل كائنين رسوميين معًا، وهما التحويل easeIn (الاعتيادي) في النصف الأول للحركة، والتحويل easeOut (المعكوس) للنصف الثاني. سنرى التأثير بوضوح عند الموازنة بين التحويلات الثلاث easeIn وeaseOut وeaseInOut عند تطبيقها على دالة التوقيت circ: easeIn: باللون الأحمر. easeOut: باللون الأخضر. easeInOut: باللون الأزرق. كما نرى طبقنا على النصف الأول من الحركة easeIn، وعلى النصف الآخر easeOut، لذا ستبدأ الحركة وتنتهي بنفس التأثير. دالة draw أكثر تميزًا يمكننا القيام بأكثر من مجرد تحريك العنصر، وكل ما علينا فعله هو كتابة شيفرة مناسبة للدالة draw، إليك طريقةً لإظهار ارتداد أثناء كتابة نص مثلًا: شيفرة الملف style.css: textarea { display: block; border: 1px solid #BBB; color: #444; font-size: 110%; } button { margin-top: 10px; } شيفرة الملف index.html: <!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <link rel="stylesheet" href="style.css"> <script src="https://js.cx/libs/animate.js"></script> </head> <body> <textarea id="textExample" rows="5" cols="60">He took his vorpal sword in hand: Long time the manxome foe he sought— So rested he by the Tumtum tree, And stood awhile in thought. </textarea> <button onclick="animateText(textExample)">Run the animated typing!</button> <script> function animateText(textArea) { let text = textArea.value; let to = text.length, from = 0; animate({ duration: 5000, timing: bounce, draw: function(progress) { let result = (to - from) * progress + from; textArea.value = text.substr(0, Math.ceil(result)) } }); } function bounce(timeFraction) { for (let a = 0, b = 1, result; 1; a += b, b /= 2) { if (timeFraction >= (7 - 4 * a) / 11) { return -Math.pow((11 - 6 * a - 11 * timeFraction) / 4, 2) + Math.pow(b, 2) } } } </script> </body> </html> وستكون النتيجة كالتالي: خلاصة يمكن أن تساعدك JavaScript في تنفيذ الرسوميات التي لا تستطيع CSS التعامل معها، أو تلك التي تتطلب تحكمًا دقيقًا. تّنفّذ حركات JavaScript باستخدام التابع المدمج requestAnimationFrame الذي يسمح بإعداد دالة استدعاء تُشغَّل عندما يحضّر المتصفح نفسه لعملية إعادة الرسم Repaint. لن تُنفَّذ عملية إعادة الرسم إطلاقًا عندما تكون الصفحة في الخلفية، وبالتالي لن تعمل دالة الاستدعاء وسيُعلّق تنفيذ الحركة، ولن يكون هناك استهلاك للموارد. إليك الدالة المساعدة animate التي تحضّر معظم الرسوميات المتحركة التي تحتاجها: function animate({timing, draw, duration}) { let start = performance.now(); requestAnimationFrame(function animate(time) { // timeFraction goes from 0 to 1 let timeFraction = (time - start) / duration; if (timeFraction > 1) timeFraction = 1; // calculate the current animation state let progress = timing(timeFraction); draw(progress); // draw it if (timeFraction < 1) { requestAnimationFrame(animate); } }); } الخيارات هي: duration: الزمن الكلي للحركة مقدرًا بالميلي ثانية. timing: الدالة التي تحسب مقدار تقدم الحركة، حيث تقبل الدالة قيمًا زمنيةً هي نسبة بين 0 و1، وتعيد مقدار تقدم العملية. draw: الدالة التي ترسم الحركة. وبالطبع يمكن تحسين هذه الدوال وإضافة العديد من الأمور الأخرى، لكن لا يتكرر استخدام رسوميات JavaScript كثيرًا، فهي تستخدَم لإظهار شيء مهم لا لأمور تقليدية، لذا يمكنك إضافة الميزة التي تريدها عند الحاجة. يمكن أن تستخدم JavaScript أي دوال توقيت، وقد غطينا الكثير منها في هذا الفصل وطبقنا عليها تحويلات عدةً، إذًا لسنا مقيدين بمنحنيات بيزيه كما هي الحال في CSS. يمكننا استخدام draw لتحريك أي شيء وليس خصائص CSS فقط. مهام لإنجازها 1. تحريك كرة مرتدة أنشئ كرةً ترتد كما في المثال التالي: افتح المثال في بيئة تجريبية. الحل لجعل الكرة ترتد، سنسنتعمل الخاصية top والخاصية position:absolute مع الكرة والخاصية position:relative مع الملعب، ويكن إحداثيات أرضية الملعب هي field.clientHeight. تشير الخاصية top إلى بداية أعلى الملعب لذا يجب أن تتغير من 0 إلى field.clientHeight - ball.clientHeight وهو أدنى موضع يمكن أن تنخفض إليه حافة الكرة العلوية. يمكن تطبيق تأثير الارتداد باستعمال دالة التوقيت bounce في الوضع easeOut. إليك الشيفرة النهاية الناتجة: let to = field.clientHeight - ball.clientHeight; animate({ duration: 2000, timing: makeEaseOut(bounce), draw(progress) { ball.style.top = to * progress + 'px' } }); افتح الحل في بيئة تجريبية. 2. حرك الكرة المرتدة إلى اليمين اجعل الكرة ترتد إلى اليمين كالتالي: اكتب الشيفرة بحيث تكون مسافة الانتقال إلى اليمين هي 100px. الحل احتجنا في التمرين السابق إلى تحريك خاصية واحدة فقط، بينما سنحتاج في هذا التمرين إلى تحريك خاصية إضافية هي elem.style.left. نريد تغيير الاحداثيات الأفقية للكرة بزيادتها تدريجيًا نحو اليمين أثناء السقوط، لذا سنضيف حركة إضافة anumate يمكن أن نستعمل معها دالة التوقيت linear ولكن تبدو makeEaseOut(quad) أفضل بكثير. إليك الشيفرة النهاية الناتجة: let height = field.clientHeight - ball.clientHeight; let width = 100; // animate top (bouncing) animate({ duration: 2000, timing: makeEaseOut(bounce), draw: function(progress) { ball.style.top = height * progress + 'px' } }); // animate left (moving to the right) animate({ duration: 2000, timing: makeEaseOut(quad), draw: function(progress) { ball.style.left = width * progress + "px" } }); افتح الحل في بيئة تجريبية. ترجمة -وبتصرف- للفصل JavaScript Animation من سلسلة The Modern JavaScript Tutorial اقرأ أيضًا المقال السابق: إنشاء رسوم متحركة باستخدام CSS النسخة العربية الكاملة لكتاب: التحريك عبر CSS iframe { border: 1px solid #e7e5e3 !important; width: 100%; } iframe div#path { margin: auto; }1 نقطة
-
هذا المقال جزء من سلسلة «مدخل إلى الذكاء الاصطناعي»: الذكاء الاصطناعي: أهم الإنجازات والاختراعات وكيف أثرت في حياتنا اليومية الذكاء الاصطناعي: مراحل البدء والتطور والأسس التي نشأ عليها المفاهيم الأساسية لتعلم الآلة تعلم الآلة: التحديات الرئيسية وكيفية التوسع في المجال يمكنك قراءة السلسلة على شكل كتاب إلكتروني بالانتقال إلى صفحة الكتاب، مدخل إلى الذكاء الاصطناعي وتعلم الآلة. إن سبق وحاولت قراءة أي مقالٍ على الإنترنت يتحدث عن تعلّم الآلة، فلا بدّ من أنك عثرت على نوعين من المقالات؛ فإما أن تكون سميكة وأكاديمية ومليئة بالنظريات (عن نفسي لم أستطع حتى تجاوز نصف مقال)، أو عن القصص الخيالية المريبة حول سيطرة الذكاء الصنعي على البشر، أو منهم من يتحدث عن البيانات وتأثيرها الساحر على مجالات العلوم الأخرى أو البعض الآخر من المقالات يتحدث عن كيفية تغيّر وظائف المستقبل. لم يكن هنالك أي كتاب يضعني على بداية الطريق لكي أتعلم أبسط الأساسيات لأنتقل بعدها إلى المفاهيم المعقدة واثق الخطى. لذا كان لا بدّ لي من كتابة مقالٍ بسيط ومفهوم وواقعي لطالما تمنيت وجوده. سيكون هذا المقال مقدمة بسيطة لأولئك الّذين أرادوا دومًا فهم طريقة عمل مجال تعلّم الآلة. بتطبيق أفكاره على أمثلة من مشاكل العالم الحقيقي، والحلول العملية المطبقة، بلغة بسيطة ومفهومة، وتجنب النظريات الصعبة قدر الإمكان. ليستطيع الجميع فهم ماهيّة هذا العِلم سواءً أكانوا مبرمجين أو مدراء بل وحتى لأي شخص كان. فهرس المحتويات لماذا نريد من الآلات أن تتعلم؟ المكونات الرئيسية لتعلم الآلة 1. البيانات (Data) 2. الميّزات (Features) 3. الخوارزميات (Algorithms) الفرق بين التعلم (Learning) والذكاء (Intelligence) تعلم الآلة التقليدي التعلم الموجه (Supervised Learning) التصنيف (Classification) أشجار القرار (Decision Trees) الانحدار (Regression) التعلم غير الموجه (Unsupervised learning) التجميع (Clustering) خوارزمية K-mean خوارزمية DBSCAN تقليل الأبعاد (Dimensionality Reduction) تعلم قواعد الربط (Association Rule Learning) التعلم المعزز (Reinforcement Learning) طريقة المجموعات 1. طريقة التكديس (Stacking) 2. طريقة التعبئة (Bagging) 3. طريقة التعزيز (Boosting) الشبكات العصبية (Neural Networks) والتعلم العميق (Deep Leaning) الشبكات العصبية (Neural Networks) الشبكات العصبية التلافيفية (Convolutional Neural Networks) الشبكات العصبية المتكررة (Recurrent Neural Networks) التعلم العميق (Deep Learning) الفرق بين الشبكات العصبية والتعلم العميق الخلاصة المراجع وإليك المخطط الرئيسي للمواضيع التي سنتناولها في هذه المقالة ملخصة بالصورة التالية: لماذا نريد من الآلات أن تتعلم؟ هذا صديقنا أحمد يريد شراء سيارة ويحاول حساب مقدار مبلغ المال الّذي سيحتاجُ لتوفيره شهريًا. واستعرض عشرات الإعلانات على الإنترنت وعلم بأن السيارات الجديدة يبلغ سعرها حوالي 20000 دولار، والسيارات المستعملة لعام واحد يبلغ سعرها 19000 دولار، والمستعملة لعامين يبلغ سعرها 18000 دولار وهكذا دواليك. يبدأ أحمد -محللنا الرائع- بملاحظة نمط معين لسعر السيارات؛ إذ يعتمد سعر السيارة على مدة استخدامها، وينخفض سعرها بمقدار 1000 دولار مقابل كلّ عام من عمرها، لكن سعرها لن ينخفض أقل من 10000 دولار. في هذه الحالة وطبقًا لمصطلحات تعلّم الآلة يكون أحمد قد ابتكر ما يُعرفُ بالانحدار (Regression): وهي طريقة لتوقع قيمة (أو سعر) معيّن على أساس بيانات قديمة معروفة. أغلب الناس تؤدي هذا الأمر طوال الوقت دون أن تشعر به، فمثلًا عند محاولتنا لتقدير السعر المعقول لجهاز أيفون مستعمل على موقع eBay، أو أثناء محاولتنا معرفة وزن اللحوم المناسب والكافي لبلوغ حدّ الشبع لكلّ شخص من المدعوين على عزومة الغداء. فعندها سنبدأ بتقدير الأمر ونسأل أنفسنا، هل 200 غرام كافي للشخص؟ أم 500 غرام أفضل؟ سواءً اعترفنا بذلك أم لا، أغلبنا يؤدي هذه المهمة لا شعوريًا. دورة الذكاء الاصطناعي احترف برمجة الذكاء الاصطناعي AI وتحليل البيانات وتعلم كافة المعلومات التي تحتاجها لبناء نماذج ذكاء اصطناعي متخصصة. اشترك الآن سيكون من الجميل أن يكون لدينا صيغة بسيطة مثل هذه لحلّ كلّ مشكلة في العالم. وخاصة بالنسبة لعزومة الغداء. ولكن لسوء الحظ هذا مستحيل. لنعود إلى مثال السيارات. المشكلة الحقيقية في هذا المثال هو وجود تواريخ تصنيع مختلفة، وعشرات الأنواع من السيارات، والحالة الفنية للسيارة، بالإضافة لارتفاع الطلب الموسمي على سيارة معينة، والكثير من العوامل المخفية الأخرى الّتي تؤثر بسعر السيارة. وبالتأكيد لن يستطيع صديقنا أحمد الاحتفاظ بكلّ هذه البيانات في رأسه أثناء حسابه للسعر. معظم الناس كسالى بطبعهم ولذلك سنحتاج حتمًا لآلات لتأدية العمليات الرياضية. لذا لنجاري الوضع الحاصل ولِنتجه باتجاه توفير آلة تؤدي هذه المهمة الحسابية الّتي واجهناها. ولنُوفر لها بعض البيانات اللازمة وسنطلبُ منها العثور على جميع الأنماط المخفية المتعلقة بالسعر. الجميل في الأمر أن هذه الآلة ستُؤدي هذه المهمة بطريقة أفضل بكثير مما سيُؤديه بعض الناس عند تحليلهم بعناية لجميع التبعيات المتعلقة بالسعر في أذهانهم. في الحقيقة كان هذا النوع من المشاكل المحفز الأساسي لولادة تعلّم الآلة. المكونات الرئيسية لتعلم الآلة لو أردنا اختصار جميع الأهداف الكامنة وراء مجال تعلّم الآلة فسيكون الهدف الوحيد هو توقع النتائج معينة بناءً على البيانات المدخلة (أي التعلّم من البيانات المدخلة). وهذا خلاصة الأمر. إذ يمكن تمثيل جميع مهام تعلّم الآلة بهذه الطريقة. كلّما زاد تنوع البيانات (تسمى في بعض الأحيان بالعينات) المجمعة لديك، كلّما كان مهمة العثور على الأنماط ذات الصلة والتنبؤ بالنتيجة أسهل نسبيًا. لذلك، فإن أي نظام يستخدم تعلّم الآلة سيحتاجُ لثلاثة مكونات رئيسية وهي: 1. البيانات (Data) هل تريد الكشف عن رسائل البريد الإلكتروني المزعجة؟ احصل على عينات من الرسائل هذه الرسائل المزعجة. هل تريد التنبؤ بالتغيرات الّتي تطرأ على أسعار الأسهم؟ ابحث عن سجلات أسعار الأسهم. هل تريد معرفة ما هي تفضيلات المستخدم؟ حللّ أنشطته على الفيسبوك، واعتقد بأن مارك زوكربيرج ماهرٌ جدًا في ذلك. كلما كانت البيانات أكثر تنوعًا، كانت النتيجة أفضل. في بعض الأحيان تكون عشرات الآلاف من سجلات البيانات هي الحد الأدنى لاستنتاج معلومة معينة. وفي البعض الآخر نحتاج إلى ملايين العينات. هناك طريقتين رئيسيتين للحصول على البيانات: الطريقة اليدوية. الطريقة الآلية. تتميز البيانات المجمّعة يدويًا باحتوائها على أخطاء أقل بكثير بالموازنة مع نظيرتها الآلية، ولكنها بالمقابل تستغرق وقتًا أطول في التجميع مما يجعلها أكثر تكلفة عمومًا. أما الطريقة الآلية فتكون أرخص إذ كلّ ما سنفعله هو جمع كلّ ما يمكننا العثور عليه على أمل أن تكون جودة هذه البيانات مقبولة. تستخدم بعض الشركات مثل غوغل عملائها لتصنيف البيانات لهم مجانًا. هل تعلم لماذا طريقة التحقق البشري ReCaptcha (المستخدمة في أغلب المواقع) تجبرك على "تحديد جميع لافتات الشوارع الموجودة في صورة معينة"؟ في الحقيقة إن هذه الطريقة ما هي إلا وسيلة لتصنيف البيانات وتعظيم الاستفاد منها. إذ يستغلون حاجتك للتسجيل في الموقع معين ويسخّرونك مجبرًا للعمل لديهم وبالمجان. مدعين بأنهم بهذه الطريقة يختبرونك بأنك بشري! نعم هذا بالضبط ما يفعلونه! تبًا لهم الأشرار! أراهن لو أنك بمكانهم فستُظهر رمز التحقق البشري أكثر منهم بكثير. أليس كذلك؟ بيد أن من الصعوبة بمكان الحصول على مجموعة جيدة من البيانات -والتي تسمى عادةً مجموعة بيانات (Dataset). وهذه المجموعات مُهمّة للغاية بل إن مجموعة البيانات ذات الجودة العالية هي في الواقع كنز حقيقي لصاحبها لدرجة أن الشركات يمكن أن تكشف أحيانًا عن خوارزمياتها، إلا أنها نادرًا ما تكشف مجموعات البيانات الخاصة بها. 2. الميزات (Features) تُعرف أيضًا باسم المعاملات (Parameters) أو المتغيّرات (Variables). والتي يمكن أن تعبر عن المسافة المقطوعة بالسيارات، أو جنس المستخدم، أو سعر السهم، أو تكرار كلمة معينة في النص. بعبارة أخرى، هذه هي الميزات الّتي يجب أن تنظرَ لها الآلة. عندما تكون البيانات مخزنة في الجداول، يكون الأمر بسيطًا - فالميّزات هي أسماء الأعمدة. ولكن ماذا لو كان لديك 100 غيفابايت من صور القطط؟ بكلّ تأكيد لا يمكننا اعتبار كلّ بكسل ميزّة. هذا هو السبب بكون اختيار الميّزات الصحيحة يستغرق عادة وقتًا أطول من أي خطوة أخرى في بناء نظام يعتمد على تعلّم الآلة. وهذا أيضًا هو المصدر الرئيسي للأخطاء. ولذلك دائمًا ما تكون الاختيارات البشرية غير موضوعية. إذ يختارون فقط الميّزات الّتي يحبونها أو تلك الّتي يجدونها "أكثر أهمية". ولذا من فضلك تجنب أن تكون بشريًا! 3. الخوارزميات (Algorithms) وهو الجزء الأسهل والأكثر وضوحًا. إذ يمكن حلّ أي مشكلة بطرق مختلفة. بيد أن الطريقة الّتي تختارها ستُؤثر على دقة النموذج النهائي وأدائه وحجمه. هناك فارق بسيط واحد مهم: إذا كانت البيانات سيئة فلن تساعدك حتى أفضل خوارزمية موجودة. في بعض الأحيان يشار إليها بمصطلح "الدخل السيئ سيؤدي إلى نتائج سيئة". لذلك لا تهتم كثيرًا لنسبة الدقة، وحاول الحصول على المزيد من البيانات كبداية. من الجدير بالذكر أن مصطلح نموذج (Model) يشير إلى ما خلاصة ما تعلمته من البيانات، ويكمننا في بعض الأحيان استخدام نموذج جاهز وتمرير البيانات له أو تحسين نموذج حالي. الفرق بين التعلم (Learning) والذكاء (Intelligence) إن سبق ورأيت مقالًا بعنوان "هل ستحلّ الشبكات العصبية محل تعلم الآلة؟" أو على شاكلته من العناوين الّتي تنشرها بعض المواقع التابعة لوسائل إعلامية على الإنترنت. دائمًا ما يسمي رجال الإعلام هؤلاء أي انحدار خطي (Linear Regression) على أنه ذكاء اصطناعي، بل إن بعض وسائل الإعلام تضخم الأمور لدرجة يصعب تصديقها حتى أصبحنا نخاف من الذكاء الصنعي كما خاف أبطال فيلم Terminator من الروبوت SkyNet. وإليك صورة توضح المفاهيم وتفض الالتباس الموجود: علوم الحاسب (Computer Science): عمومًا هو دراسة أجهزة الحاسب بما فيها من أسس نظرية و حسابية، كما تشتمل على دراسة الخوارزميات، وبُنى المعطيات وأساسيات تصميم الشبكات ونمذجة البيانات ..وغيرها. الذكاء الصناعي (Artificial Intelligence): وهو فرع من فروع علوم الحاسب يهدف إلى تعزيز قدرة الآلات والحواسيب على أداء مهام مُعينة تُحاكي وتُشابه تلك الّتي تقوم بها الكائنات الذكيّة؛ كالقدرة على التفكير، أو التعلُم من التجارب السابقة، أو غيرها من العمليات الأُخرى الّتي تتطلب عمليات ذهنية. تعلم الآلة (Machine Learning): وهو جزء مهم من الذكاء الاصطناعي، وهو أحد فروع الذكاء الاصطناعي الّذي يُعنى بجعل الحاسوب قادرًا على التعلُم من تلقاء نفسه من أيّ خبرات أو تجارب سابقة، مما يجعله قادرًا على التنبؤ واتخاذ القرار المُناسب بصورة أسرع، ولكن تعلم الآلة ليس الفرع الوحيد الّذي يؤدي هذه المهمة. الشبكات العصبية الاصطناعية (Artificial Neural Networks): وهي من أحد أشهر الطرق الشعبية في مجال تعلّم الآلة، ولكن هناك طرق أخرى جيدة أيضًا. التعلم العميق (Deep Learning): هو طريقة حديثة لبناء وتدريب واستخدام الشبكات العصبية. وهي بالأساس هيكلية جديدة للشبكات العصبية. وحاليًا لا أحد يفصل التعلم العميق عن "الشبكات العصبية العادية". حتى أننا نستخدم نفس المكتبات لهم. من الأفضل دومًا تسمية نوع الشبكة وتجنب استخدام الكلمات الرنانة. من المهم دائمًا تذكر بأنه لا توجد طريقة واحدة أبدًا لحل مشكلة معينة في مجال تعلّم الآلة. بل هناك دائمًا العديد من الخوارزميات الّتي يمكنها حل نفس المشكلة، وتبقى مهمة اختيار الطريقة أو الخوارزمية الأنسب عائدة إليك. إذ يمكنك حلّ أيّ شيء باستخدام شبكة عصبية اصطناعية، ولكن من الّذي سيدفع لك ثمن استئجار (أو حتى شراء) بطاقة معالجة الرسوميات (GPU) من نوع GeForces؟ لنبدأ بنظرة عامة أساسية على الاتجاهات الأربعة السائدة حاليًا في مجال تعلّم الآلة. تعلم الآلة التقليدي جاءت الطرق الأولى لتعلّم الآلة من مجال الإحصاء البحت في خمسينات القرن الماضي. إذ اعتمد العلماء على حلّ معظم المهام الرياضية الرسمية من خلال البحث عن الأنماط في الأرقام، وتقييم قرب نقاط البيانات، وحساب اتجاه المتجهات. يعمل حاليًا نصف الإنترنت على هذه الخوارزميات. فعندما ترى قائمة بالمقالات المرشحة لك قراءتها في أحد المواقع، أو عندما يحظر البنك الّذي تتعامل معه بطاقتك عند تمريرك إياها على الآلة في محطة وقود عشوائية في مكان مجهول بعيدة عن سكنك، فعلى الأرجح هذه الأفعال ناتجة عن خوارزميات تعلّم الآلة. تعد الشركات التكنولوجيا الكبرى من أكبر المعجبين بالشبكات العصبية، إذ أنها تستطيع الاستفادة منها بقدر أكبر من الشركات الناشئة. فمثلًا يمكن لدقة صغيرة ولتكن 2٪ لإحدى خوارزمياتها الحساسة أن تعود بالنفع على إيرادات الشركة بمبلغ مالي ضخم يبلغ 2 مليار دولار. ولكن عندما تكون شركتك صغيرة وناشئة، فهذه النسبة ليست ذات فائدة كبيرة. فإذا أمضى المهندسين في فريقك البرمجي سنة كاملة يعملون على تطوير خوارزمية توصية جديدة لموقع التجارة الإلكترونية الخاص بك، مع معرفتهم بأن 99٪ من الزيارات تأتي من محركات البحث. عندها ستكون فائدة الخوارزمية قليل جدًا إذ لم عديمة الفائدة تمامًا وخصيصًا أن معظم المستخدمين لم يفتحوا الصفحة الرئيسية. فهذا سيكون أكبر هدر لطاقة فريقك البرمجي وبذلك سيكون أسوء استثمار لهذه العقول خلال هذه السنة. بصرف النظر عن ما يقال عن هذه الطرق إلا أنها سهلة سهولة كبيرة. بل إنها مثل أساسيات الرياضيات وأغلبنا يستخدمها يوميًا بدون أن يفكر بها. ينقسم تعلّم الآلة الكلاسيكي إلى فئتين وهما التعلّم الموجّه (ويسمى أيضًا التعلّم الخاضع للإشراف) و التعلّم غير الموجّه (ويسمى أيضًا التعلّم غير الخاضع للإشراف). التعلم الموجه (Supervised Learning) تحتوي الآلة على "مشرف" أو "مُعلّم" يزود الآلة بجميع الإجابات الصحيحة والدقيقة، مثل تحديد فيما إذا كان الشكل في الصورة لقطة أو كلب. قسّم (أو صنّف) المعلم بهذا الطريقة فعليًا البيانات إلى قطط وكلاب، ويستخدم الجهاز هذه الأمثلة الصحيحة للتعلم منها. واحدًا تلو الآخر. أما التعلم غير الموجّه فأن سيترك الآلة بمفردها مع كومة كبيرة من صور الحيوانات ومهمتها ستكون تصنيف هذه الصور. وذلك لأن البيانات غير مصنفة، ولا يوجد معلّم يحدد لنا ما الشكل الموجود في هذه الصور، ولذلك ستحاول الآلة بمفردها العثور على أي أنماط في الصور لتحديد الفوارق ومعرفة ما الموجود في الصور. سنتحدث عن هذه الطرق في التعرف على الأنماط لاحقًا. من الواضح أن الآلة ستتعلم أسرع بكثير مع معلّم، لذلك فالتعلّم الموجّه مستخدمٌ بكثرة في المهام الواقعية. هناك نوعين رئيسيين لطريقة التعلم الموجّه وهما: التصنيف (Classification): التنبؤ بصنف كائن معين. الانحدار (Regression): التنبؤ بنقطة معينة على محور رقمي. التصنيف (Classification) تقسيم الكائنات أو العناصر بناءً على إحدى السمات المعروفة مسبقًا. افصل الجوارب بحسب اللون، والمستندات بحسب اللغة، والموسيقى بحسب الأسلوب. وعمومًا يستخدم التصنيف من أجل: تصفية البريد الإلكتروني من الرسائل المزعجة. كشف عن اللغة المستخدمة. البحث عن وثائق مماثلة. تحليل المشاعر. التعرف على الحروف والأرقام المكتوبة بخط اليد. الكشف عن الغش. ومن بعض الخوارزميات الشائعة المستخدمة للتصنيف: خوارزمية بايز أو المصنّف المعتمد على قانون بايز في الاحتمالات Naive Bayes. خوارزمية شجرة القرار Decision Tree. خوارزمية الانحدار اللوجستي Logistic Regression. خوارزمية الجار الأقرب K-Nearest Neighbours. خوارزمية الدعم الآلي للمتجه Support Vector Machine. ويوجد أيضًا العديد من الخوارزميات الأخرى. غالبًا ما يعتمد مجال تعلّم الآلة على تصنيف الأشياء. إذ تكون الآلة في هذه الحالة مثل طفل يتعلم كيفية فرز الألعاب: فها هي الدمية، وهذه هي السيارة، وهذه هي الشاحنة …إلخ ولكن مهلًا. هل هذا الأمر صحيح؟ هل سيعرف الطفل المعنى الحقيقي للدمية أو للسيارة؟ ليستطيع بعدها تمييز أي دمية مهما اختلف شكلها ولونها وطريقة صنعها؟ أي بعبارة أخرى، هل سيستطيع أن يعمم ما تعلمه؟ في التصنيف سنحتاج دائمًا لمعلّم. ويجب تصنيف البيانات بميّزات (Features) حتى تتمكن الآلة من تعيين الأصناف المناسبة بناءً على هذه الميّزات. في الحقيقة يمكننا تصنيف كلّ شيئ تقريبًا ابتداءً من تصنيف المستخدمين بناءً على اهتماماتهم (كما تفعل خوارزمية فيسبوك)، والمقالات المستندة إلى اللغة أو الموضوع (وهذا أمر مهم لمحركات البحث)، والموسيقى المبنية على الأسلوب سواءً أكانت موسيقى جاز أو هيب هوب …إلخ (هذا الأمر نشاهده في قوائم تشغيل الخاصة بتطبيق Spotify)، وحتى تصنيف رسائل البريد الإلكتروني الخاصة بك. في تصفية الرسائل المزعجة وغير المرغوب بها، تستخدم خوارزمية بايز Naive Bayes على نطاق واسع. إذ تحسبُ الآلة عدد الكلمات الجيدة في الرسالة وعدد الكلمات الاحتيالية أيضًا بناءً على تصنيف سابق للكلمات موجود في قاعدة بيانات أو مجموعة بيانات (Dataset)، ومن ثمّ تضرب الاحتمالات باستخدام معادلة بايز، وتجمعُ النتائج النهائية وبهذه البساطة أصبح لدينا جهاز يستفيد من طرق تعلّم الآلة من أجل أن يزيد ذكائه ومعرفته. بعدها بفترة وجيزة تعلم مرسلو البريد العشوائي كيفية التعامل مع هذه المرشحات -إن صح التعبير- والّتي تعتمد على خوارزمية بايز فعكفوا على إضافة الكثير من الكلمات المصنّفة على أنها "جيدة" في نهاية البريد الإلكتروني لتُتضاف هذه الكلمات إلى العملية الحسابية الخاصة بحساب احتمالات كون الرسالة مزعجة أم لا. ومن المفارقة أن هذه الثغرة سمّيت لاحقًا بتسمم بايز. دخلت خوارزمية بايز التاريخ باعتبارها من أوائل الخوارزميات الأنيقة والمفيدة عمليًا في ترشيح رسائل البريد الإلكتروني، ولكن في وقتنا الحالي لا تستخدم هذه الخوارزمية وإنما تستخدم خوارزميات أكثر قوة وذكاءً معتمدًا على الشبكات العصبية الاصطناعية لتصفية رسائل البريد العشوائي المزعج. إليك مثال عملي آخر على تطبيقات خوارزميات التصنيف. لنفترض أنك بحاجة لاقتراض بعض المال عن طريق بطاقتك الائتمانية. كيف سيعرف البنك إذا كنت تريد فعلًا أن تسدد هذا القرض أم لا؟ وبالتأكيد لا توجد طريقة مباشرة لمعرفة ذلك، مثل أن يسألك مثلًا. ولكن لدى البنك الكثير من الملفات الشخصية لأشخاص اقترضوا مالًا في الماضي. في الواقع لدى البنك جميع البيانات المهمة حول أعمار الأشخاص المقترضين ومستوى تعليمهم ومهنهم ورواتبهم -والأهم من ذلك- حقيقة أن هل هؤلاء المقترضين سددوا القرض أم لا. وهذه البيانات مهمة جدًا إذ يمكننا تمريرها للنظام الداخلي للبنك الّذي يعتمد على تعلّم الآلة للعثور على الأنماط المحددة الموجودة في الأشخاص الّذين يسددون القروض، وبذلك يمكننا الحصول على الإجابة المبنية على هذه البيانات السابقة. في الواقع لا توجد مشكلة حقيقية في الحصول على إجابة من هذه البيانات. وإنما تكمن المشكلة في أنه لا يستطيع البنك أن يثق في إجابة الآلة ثقةً عمياء. فماذا لو حدث فشل في النظام أو في جزء منه مثل تعطل أحد الاقراص الصلبة المخزن عليها قواعد البيانات المطلوبة، أو أن أحد قراصنة الإنترنت هجم على الخادم وتلاعب بالخوارزميات أو البيانات. فما الّذي سيحدث في هذه الحالة؟ للتعامل مع هذه الحالة لدينا خوارزمية شجرة القرار. والتي ستقسّم جميع البيانات تلقائيًا إلى أسئلة أجوبتها نعم أو لا. قد يبدو الأمر غريبًا بعض الشيئ من منظور بشري، فمثلًا ما المشكلة إذا كان الدائن يكسب أكثر من 128.12 دولارًا أمريكيًا؟ بالرغم من ذلك تضع الآلة مثل هذه الأسئلة لتقسيم البيانات بشكل أفضل في كلّ خطوة. وهكذا تُصنعُ شجرة القرار. كلما كان الفرع أعلى كلما كان السؤال أعم. يمكن لأي محلل أن يأخذ ناتج الخوارزمية ويعلّم تمامًا ما هو القرار المناسب. يمكن ألا يشعر بأن كلّ تفاصيلها منطقية إلا أنه يستطيع أن يبني عليها قراره. أشجار القرار (Decision Trees) تستخدم خوارزمية شجرة القرار على نطاق واسع في المجالات ذات المسؤولية العالية مثل: التشخيص والطب وفي الأمور المالية. من أكثر الخوارزمات شيوعًا لتشكيل الأشجار هما خوارزمية CART وخوارزمية C4.5. ونادرًا ما تستخدم طريقة بناء أشجار القرار الأساسية الصرفة في وقتنا الحالي. إلا أنها غالبًا ما تضع حجر الأساس للأنظمة الكبيرة، بل إن المُجمّعات (Ensembles) المعتمدة على أشجار القرار تعمل بطريقة أفضل من المجمعات المعتمدة على الشبكات العصبية الاصطناعية (سنتحدث لاحقًا في هذا المقال عن كلّ جزء منهم بالتفصيل). عندما تبحث عن شيء ما في غوغل، فما يحدث بالضبط هو أن مجموعة من الأشجار ستبحث عن إجابة أو مجموعة من الإجابات المناسبة لك. وهذه الأشجار سريعة جدًا، ولذلك تحبها محركات البحث. تعدّ خوارزمية الدعم الآلي للمتجه (Support Vector Machines) والتي يشار إليها اختصارًا (SVM) هي الطريقة الأكثر شيوعًا للتصنيف الكلاسيكي. والمستخدمة لتصنيف كلّ شيئ موجود تقربيًا مثل: النباتات حسب مظهرها في الصور، والوثائق بحسب الفئات …إلخ. الفكرة وراء خوارزمية الدعم الآلي للمتجه بسيطة جدًا إذ تحاول رسم خطين بين نقاط البيانات الخاصة بك مع أكبر هامش بينهما. هناك جانب مفيد جدًا من خوارزميات التصنيف وهو الكشف عن البيانات الشاذة. فعندما لا تتناسب الميزة مع أيّ من الفئات، فإننا نبرزها. وتستخدم هذه الطريقة حاليًا في الطب وتحديدًا في أجهزة التصوير بالرنين المغناطيسي، تبرز الحواسيب جميع المناطق المشبوهة أو انحرافات الاختبار. كما تستخدم أيضًا في أسواق الأسهم للكشف عن السلوك غير الطبيعي للتجار لمعرفة ما يحدث وراء الكواليس. الجميل في الأمر أنه عندما نعلّم الحاسب الأشياء الصحيحة فنكون علمناه تلقائيًا ما هي الأشياء الخاطئة. القاعدة الأساسية هي كلّما زاد تعقيد البيانات، زاد تعقيد الخوارزمية. بالنسبة للنصوص والأرقام والجداول سنختار النهج الكلاسيكي. إذ النماذج الناتجة ستكون أصغر، وتتعلم أسرع وتعمل بوضوح أكبر. أما بالنسبة للصور ومقاطع الفيديو وجميع أنواع البيانات المعقدة الأخرى، سنتجه بالتأكيد نحو الشبكات العصبية. منذ خمس سنوات فقط كان بإمكانك العثور على مصنف للوجه مبني على خوارزمية الدعم الآلي للمتجه (SVM). حاليًا أصبح من السهل الاختيار من بين مئات الخوارزميات المعتمدة على الشبكات العصبية المدربة مسبقًا. أما بالنسبة لمرشحات البريد العشوائي فلم يتغير شيئ. فلا تزال بعض الأنظمة مكتوبة بخوارزمية الدعم الآلي للمتجه (SVM). الانحدار (Regression) وهو طريقة لرسم خط بين مجموعة نقاط. نعم، هذا هو التعلّم الآلة! يستخدم الانحدار حاليًا في تطبيقات متعددة، مثل: توقعات أسعار الأسهم. تحليل حجم الطلب والمبيعات. التشخيص الطبي. أي ارتباطات عددية. ومن الخوارزميات الشائعة نذكر: خوارزمية الانحدار الخطي Linear. خوارزمية االانحدار متعدد الحواف Polynomial. الانحدار هو في الأساس آلية للتصنيف ولكن هنا نتوقع رقمًا بدلًا من فئة. ومن الأمثلة على ذلك توقع سعر السيارة من خلال المسافة المقطوعة، وتوقع حركة المرور بحسب وقت محدد من اليوم، وتوقع حجم الطلب من خلال نمو الشركة، وما إلى ذلك. ويكون من الواجب استخدام الانحدار عندما تعتمد مشكلة معينة على الوقت. كلّ من يعمل في مجالات التمويل والتحليل المالي يحب خوارزميات الانحدار. حتى أن معظمها مدمج في برنامج مايكروسوفت إكسل (Excel). وطريقة استخدامها سلسة جدًا من الداخل إذ تحاول الآلة ببساطة رسم خط يشير إلى متوسط الارتباط (Average Correlation). على عكس الشخص الّذي يحاول رسم شكل الانحدار يدويًا على السبورة، فإن الآلة ترسم الشكل بدقة رياضية عالية جدًا، بحساب متوسط الفاصل الزمني لكل نقطة. عندما يكون خط الانحدار مستقيمًا فيكون هذا الانحدار خطيًا، أما عندما يكون خط الانحدار منحنيًا فيكون الانحدار متعدد الحواف (Polynomial). وهذه الأنواع الرئيسية من الانحدار. والبعض الآخر أكثر غرابة مثل الانحدار اللوجستي (Logistic Regression) وسيكون شكله مميز كتميز الخروف الأسود في قطيع غنم. ولكن لا تدعه يخدعك، لأنه مجرد طريقة تصنيف وليس انحدارًا. لا بأس في الخلط بين الانحدار والتصنيف. إذ يتحول العديد من المصنّفات لتنفيذ عملية انحدار بقليل من الضبط والإعداد. وعمومًا تستخدم طرق الانحدار عندما لا يمكننا تحديد فئة الكائن، وإنما يمكننا تحديد ومعرفة مدى قربه من هذه الفئة، وهنا بالضبط تأتي مهمته. في حال أردت التعمق أكثر في التعلم الموجّه، فراجع هذه السلسلة: Machine Learning for Humans. التعلم غير الموجه (Unsupervised learning) ظهر التعلّم غير الموجّه بعد ظهور التعلّم الموجّه بقليل، وتحديدًا في التسعينيات. ويستخدم أقل من التعلّم الموجّه، ولكن في بعض الأحيان لن يكون لدينا خيار آخر سوى استخدامه. تعدّ البيانات المصنّفة نوع فاخر من البيانات. ولكن ماذا لو كنت رغبت في إنشاء تصنيف مخصص للحافلات (الباصات)؟ هل يجب عليك التقاط صور يدويًا لمليون حافلة في الشوارع وتصنيف كلّ واحدةٍ منها؟ مستحيل، سيستغرق هذا الأمر عمرًا بأكمله. في هذا النوع من التعلم من منظورنا نحن نعطيها أومر معينة للتجميع أو تقليل الأبعاد وهي تؤدي هذه المهمة من خلال تحليلها لقيم الميّزات (Features) ومحاولة الربط بينها ومعرفة العلاقات أو الارتباط بين هذه البيانات. كما يمكن أن تكون البيانات معقدة للغاية، ولذلك لا يمكن لهذه الخوارزميات التكهن بالنتيجة المطلوبة بصورة صحيحة. في تلك الحالات نحاول تنظيم بياناتنا أو إعادة هيكلتها في صيغة منطقية أكثر من السابق من أجل معرفة فيّما إذا استطاعت هذه الخوارزميات استنتاج شيئ ما، وبذلك الأمر له عدة جوانب للحلّ ومتعلّق بنوعية البيانات وطريقة تنظيمها وجودتها. ولكن هناك بعض الأمل إذ لدينا الملايين من المنصات الّتي توفر خدمات رخيصة نسبيًا تبدأ من 5 دولار أمريكي، وغالبًا نعتمد عليها لمساعدتنا في تصنيف البيانات وهذه الطريقة المعتمدة الّتي تجري وفقها أمور تطوير البيانات في هذا المجال. بعض الأنواع للتعلّم غير الموجّه: التجميع (Clustering). تقليل الأبعاد أو التعميم (Dimensionality Reduction). تعلم قواعد الربط (Association rule learning). التجميع (Clustering) تُقسّم عملية التجميع الكائنات على أساس ميّزات غير معروفة. إذ تختار الآلة أفضل طريقة لفرز الميّزات الّتي تراها مناسبة. هذه بعض التطبيقات لعملية التجميع في وقتنا الحالي: تقسيم السوق (أو تقسيم أنواع العملاء، أو طريقة ولائهم للعلامة التجارية). دمج نقاط قريبة على الخريطة. ضغط الصورة. تحليل وتسمية البيانات الجديدة. الكشف عن السلوك غير الطبيعي. ومن بعض خوارزميات الشائعة للتجميع: خوارزمية K-mean_clustering. خوارزمية Mean-Shift. خوارزمية DBSCAN. تعدّ عملية التجميع فعليًا عملية تصنيف ولكن المفارقة هنا أنها لا تحتوي على فئات محددة مسبقًا. مشابهة جدًا لعملية تقسيم الجوارب في الدرج بحسب ألوانهم، وذلك عندما لا تتذكر كلّ الألوان الّتي لديك فعندها ستجلب الجورب الأول ذو اللون الأسود وتضعه جانبًا وتأخذ الجورب الثاني ..وهكذا. تحاول خوارزميات التجميع العثور على كائنات متشابهة (بحسب بعض الميزات) ودمجها في مجموعة. تُجمّع الكائنات الّتي لديها الكثير من الميزات المماثلة في فئة واحدة. وتسمح لنا بعض الخوارزميات حتى تحديد العدد الدقيق للمجموعات الّتي نريدها. من أحد أشهر الأمثلة على التجميع هي تجميع العلامات (أو المؤشرات) على خرائط الوِب. فمثلًا عندما تبحث عن جميع المطاعم النباتية المحيطة بك، سيجمّعُ محرك البحث الخاص بالخريطة جميع المطاعم على شكل أرقام. ولو أنه لم يجمّعها لك فحتمًا سيتجمد متصفحك بعد عملية البحث لأنه سيحاول رسم جميع المطاعم النباتية الموجودة على سطح الكرة الأرضية وعددهم سيكون كبير بكلّ تأكيد. ومن بعض الاستخدامات الأخرى لخوارزميات التجميع تطبيقات الهواتف المحمولة مثل: Apple Photos وGoogle Photos إذ كِلاهما يستخدمان خوارزميات تجميع معقدة أكثر من المثال السابق، وذلك لإنهم يبحثان عن الوجوه المميزة في الصور بهدف إنشاء ألبومات خاصة لأصدقائك. لا يعرف التطبيق عدد أصدقاؤك ولا حتى كيف تبدوا أشكالهم، ولكنه مع ذلك يحاول العثور على ميزات صريحة في وجوههم، والموازنة بينها لمعرفة عددهم، وعرض الألبومات وفقًا لذلك. ومن بعض الاستخدامات الأخرى هي ضغط الصورة فعند حفظ الصورة بلاحقة PNG، يمكنك ضبط مجموعة الألوان وليكن عددها 32 لونًا. هذا يعني أن آلية التجميع ستأخذ جميع البكسلات "المحمرة" وتحسب قيمة "المتوسط الأحمر" وتضبطه على جميع البكسلات الحمراء. وبذلك يكون لدينا ألوان أقل، مما يؤدي في نهاية المطاف إلى حجم ملف أقل، وبذلك تنخفضُ مصاريف التخزين المحلي أو السحابي. ومع ذلك يمكن أن نواجه بعض مشاكل في الألوان مثل الألوان القريبة من لونين بنفس الوقت مثل لون الأزرق السمائي (Cyan). إذ لا يمكننا تصنيفه فيما إذا كان أخضرًا أم أزرق؟ هنا يأتي دور خوارزمية K-Means. خوارزمية K-mean إذ تعيّن خوارزمية K-Means مجموعة من النقاط اللونية والبالغ عددها 32 نقطة لونية بطريقة عشوائية في مجموعة الألوان. وتسمى هذه النقاط (أو الألوان) بالنقاط المركزية (Centroids). وتُحدد النقاط المتبقية على أنها مخصصة لأقرب نقطة (لون) مركزي. وبعدها سنُلاحظ أننا حصلنا نوعًا ما على ما يشبه المجرات حول هذه الألوان 32. ثم ننقل النقطة المركزية إلى وسط مجرتنا، ونكرر ذلك حتى تتوقف النقطة المركزية عن التحرك. نفذنا جميع المهام بنجاح. ولدينا 32 مجموعة محددة ومستقرة. وإليك شرحًا كرتونيًا وتفصيليًا لما جرى: البحث عن الألوان المركزية مريح. إلا أن التجميعات في الحياة الواقعية ليست دائمًا على شكل دوائر. لنفترض أنك عالم جيولوجيا. وتحتاج للعثور على بعض المعادن المتماثلة على الخريطة. في هذه الحالة، يمكن تشكيل تجميعات بطريقة غريبة وحتى متشعبة. ولا يمكنك أيضًا أن تعرف عددهم فهل هم 10؟ أم 100؟ بكل تأكيد أن خوارزمية K-means لن تتناسب مع هذه الحالة، وإنما ستكون خوارزمية DBSCAN مفيدةً أكثر. خوارزمية DBSCAN لنفترض أن النقاط لدينا هم أناس في ساحة البلدة. اَبحث عن أي ثلاثة أشخاص يقفون بالقرب من بعضهم البعض واطلب منهم أن يمسكوا أيديهم. ثم اطلب منهم البدء في الإمساك بأولئك الجيران الّذين يمكنهم الوصول إليهم. وهكذا دواليك. إلى أن نصل لشخص لا يستطيع الامساك بأي شخص آخر. هذه هي مجموعتنا الأولى. كرر هذه العملية ليُجمعُ كلّ الناس بمجموعات. ملاحظة: الشخص الّذي ليس لديه من يمسك يده - هو فعليًا مجرد بيانات شاذة. إليك رسم توضيحي يبين لك كيف سيبدو الحل: وإن كنت مهتم بخوارزميات التجميع؟ يمكنك الاطلاع على هذه المقالة The 5 Clustering Algorithms Data Scientists Need to Know. نلاحظ أن التجميع مشابه تمامًا للتصنيف، إذ يمكن استخدام المجموعات للكشف عن الحالات الشاذة. هل لاحظت بأن المستخدم يتصرف بطريقة غير طبيعية بعد اشتراكه بموقعكK أو بخدمتك؟ دع الآلة تحجبه مؤقتًا، وتنشئ تذكرة للدعم الفني لفحص هذا النشاط المريب لاتخاذ القرار المناسب. فربما يكون روبوت آلي يحاول إشغال الخادم الّذي تحجزه لموقعك. في الحقيقة لن نحتاج حتى لمعرفة ماهيّة "السلوك الطبيعي" للمُستخدم وإنما سنأخذ جميع أفعال ونشاطات المستخدم ونحملها إلى نموذجنا ونترك الآلة تقرر ما إذا كان هذا المستخدم "نموذجيًا" أم لا. يمكن أن لا يعمل هذا النهج بطريقة جيد بالموازنة مع التصنيف، ولكن القرار النهائي سيُبنى على المحاولة والتجربة. تقليل الأبعاد (Dimensionality Reduction) وتعرف أيضًا بالتعميم (Generalization) وهي عملية تجميع ميّزات محددة بداخل ميّزات ذات مستوى أعم وأعلى. ومن بعض التطبيقات العملية لهذه الطريقة نجد: أنظمة التوصية. التصورات (المحاكاة) الجميلة. نمذجة الموضوعات والبحث عن وثائق مماثلة. تحليل الصور المزيفة. إدارة المخاطر. ومن بعض الخوارزميات الشائعة لتطبيقها: خوارزمية تحليل المكونات الرئيسية Principal Component Analysis ويشار لها اختصارًا (PCA). خوارزمية تحليل القيمة المفردة Singular Value Decomposition ويشار لها اختصارًا (SVD). خوارزمية Latent Dirichlet allocation. خوارزمية التحليل الدلالي الكامن Latent Semantic Analysis ويشار إليها اختصارًا (LSA أو pLSA أو GLSA). خوارزمية t-SNE (التي تستخدم في مجال الرؤية الحاسوبية). استخدم علماء البيانات المتعصبون سابقًا هذه الأساليب، وكان عليهم العثور على "شيئ مثير للاهتمام" في أكوام ضخمة من الأرقام. وعندما لم تساعدهم مخططات إكسل بهذه المهمة أجبروا الآلات على العثور على الأنماط. حتى حصلوا على طريقة تقليل الأبعاد أو ميّزة تعلّم كيفية تقليل البعد. من الأفضل دائمًا استخدام التلخيص أو التجريد (Abstractions)، عوضًا عن مجموعة من الميزات المجزأة. فمثلًا، يمكننا دمج كلّ الكلاب ذات الآذان مثلثية الشكل والأنوف الطويلة والذيل الكبير ليصبح لدينا تلخيص لشكل كلب لطيف وهو كلب "شبيرد". نعم فقدنا بعض المعلومات حول الصفات المميزة الخاصة بالكلب شبيرد، إلا أن التلخيص الجديد يعدّ أكثر فائدة لتسمية الأغراض وتوضيحها. بالإضافة إلى ذلك، إن النماذج المُلخAصة تتعلّم بطريقة أسرع، ولا تظهر لديها مشكلة "فرض التخصيص" (Overfitting) -الّتي سنتحدث عنها بالتفصيل لاحقًا- بكثرة وهي تستخدم عددًا أقل من الميّزات. أصبحت هذه الخوارزميات أداة مذهلة "لنمذجة المواضيع". إذ يمكننا تلخيص مواضيع من كلمات محددة لمعانيها. هذا ما تفعله خوارزمية التحليل الدلالي الكامن. تعتمد على عدد مرات تكرار كلمة معينة في موضوع محدد. مثل: استخدام كلمة "تقنية" بكثرة في المقالات التقنية، وبالتأكيد سنعثر على أسماء الأشخاص السياسيين بكثرة في الأخبار السياسية وهكذا. كما يمكننا بكل تأكيد إنشاء مجموعات من جميع الكلمات في المقالات، ولكننا سنفقد جميع الروابط المهمة بين معاني الكلمات خصيصًا العلاقة بين الكلمات ذات المعنى نفسه مثل البطارية (Battery) والبطارية المقصود بها المدخرات الكهربائية - (Accumulator) الموجودة في مستندات مختلفة. إلا أن خوارزمية التحليل الدلالي الكامن ستتعامل معها بالطريقة الصحيحة، ولهذا السبب تحديدًا سمّيت "بخوارزمية التحليل الدلالي الكامن". لذلك نحن بحاجة إلى ربط الكلمات والمستندات في ميزة واحدة للحفاظ على هذه الاتصالات الكامنة واتضح لنا بأن خوارزمية التفكيك المفرد (Singular decomposition) تؤدي هذه المهمة بقوة، مما يشفُ عن فائدة المجموعات المجمعة بحسب الموضوع الّتي تحدثنا عنها سابقًا. من الاستخدامات الشائعة الأخرى هي أنظمة التوصية (Recommender Systems) والتصفية التعاونية (Collaborative Filtering) من أجل تقليل الأبعاد. مما يبدو أنه إذا كنت تستخدمه في تلخيص تقييمات المستخدمين، فستحصل على نظام رائع للتوصية بالأفلام والموسيقى والألعاب بل وحتى أي شيئ تريده. للمزيد من المعلومات حول هذا الموضوع نوصيك بالكتاب الرائع "برمجة الذكاء الجمعي" Programming Collective Intelligence. بالكاد سنتمكن من فهم فهمًا كاملًا لفكرة التلخيص (أو التجريد) الآلي، ولكن من الممكن رؤية بعض الارتباطات عن قرب. إذ يرتبط بعضها بعمر المستخدم فمثلًا يلعب الأطفال لعبة ماين كرافت (Minecraft) ويشاهدون معها الرسوم المتحركة بكثرة، ويرتبط بعض المستخدمين الآخرين بنوعية فيلم معينة أو بهوايات مخصصة وهكذا. تستطيع الآلات الحصول على هذه المفاهيم التجريدية عالية المستوى من دون حتى فهم ماهيتها، بناءً فقط على معرفة تقييمات المستخدم. تعلم قواعد الربط (Association Rule Learning) وهي طريقة للبحث عن الأنماط في تدفق الطلبات. حاليا تستخدم في عدد من المجالات مثل: التنبؤ بالمبيعات والخصومات. تحليل البضائع المشتراة معًا. معرفة كيفية وضع المنتجات على الرفوف. تحليل أنماط تصفح الإنترنت. الخوارزميات الشائعة لها هي: خوارزمية Apriori. خوارزمية Eclat. خوارزمية FP-growth. وتستخدم هذه الطريقة لتحليل عربات (سلّات) التسوق الإلكترونية أو الواقعية، كما تستخدم أيضًا لأتمتة استراتيجية التسويق، والمهام الأخرى المتعلقة بمثل هذه الأحداث. وتحديدًا عندما يكون لديك تسلسل لشيئ معين وترغب في إيجاد أنماط فيه - جرب هذه الأشياء. لنفترض أن العميل سيأخذ ستة عبوات من العصائر ويذهب إلى طاولة المحاسبة ثم إلى باب الخروج. هل يجب أن نضع الفول السوداني بجانب الطريق المؤدي إلى طاولة المحاسبة؟ وفي حال وضعناها، كم مرة سيشتريها الناس بالمجمل؟ لربما تتماشى العصائر مع الفول السوداني، ولكن ما هي التسلسلات الأخرى الّتي يمكننا التنبؤ بها اعتمادًا على البيانات؟ هل يمكن لتغييرات بسيطة في ترتيب البضائع أن تؤدي إلى زيادة كبيرة في الأرباح؟ وينطبق نفس الشيء على التجارة الإلكترونية. إذ المهمة هنا أكثر حماسية وإثارة للاهتمام، فما الّذي سيشتريه العميل في المرة القادمة؟ هل سيشتري المنتجات النباتية؟ أم الحيوانية؟ تعتمد الأساليب الكلاسيكية لتعلم الآلة على نظرة مباشرة على جميع السلع المشتراة باستخدام الأشجار أو المجموعات. يمكن للخوارزميات البحث عن الأنماط فقط، ولكن لا يمكنها تعميمها أو إعادة إنتاجها بما يتوافق مع الأمثلة الجديدة. أما في العالم الحقيقي فإن كلّ متجر تجزئة كبير يبني حلًا خاصًا ومناسبًا له، لذلك لا نرى تطورات كبيرة في هذا المجال. وعلى المستوى التقني فإن أعلى مستوى من التقنيات المستخدمة هي أنظمة التوصية (أو تسمى أحيانًا الأنظمة الناصحة). التعلم المعزز (Reinforcement Learning) وهو عملية رمي روبوت في متاهة وتركه بمفرده ليجد طريق الخروج بنفسه. من بعض التطبيقات العملية المستخدمة حاليًا: السيارات ذاتية القيادة. روبوت تنظيف الأرضية. الألعاب. أتمتة التداول. إدارة موارد المؤسسة. من أبرز الخوارزميات الشائعة لها: خوارزمية التعلم المعزز وفق النموذج الحر Q-Learning. خوارزمية خطة ماركوف للتعلّم المعزز لاتخاذ القرار SARSA. خوارزمية التعلم المعزز العميق وفق النموذج الحر DQN. خوارزمية الناقد المميز غير المتزامن A3C. الخوارزمية الجينية Genetic algorithm. أخيرًا وليس آخرًا، نصل إلى شيئ يشبه الذكاء الحقيقي. في كثير من المقالات نرى خطأ شائعًا بأن يصنف التعلّم المعزز تحت قسم التعلّم الموجّه أو أحيانًا في قسم التعلّم غير الموجّه. لذا وجب التنويه إلى كونه طريقة تعلّم منفصلة. يستخدم التعلّم المعزز في الحالات الّتي لا تتعلق فيها مشكلتك بالبيانات على الإطلاق، وإنما لديك بيئة افتراضية تتعامل معها. مثل عالم ألعاب الفيديو أو مدينة افتراضية للسيارات ذاتية القيادة. إن معرفة جميع قواعد الطرقات الجوية في العالم لن تعلّم الطيار الآلي كيفية القيادة على بأحد الطرق الجوية. بغض النظر عن مقدار البيانات الّتي نجمعها، لا يزال يتعذر علينا توقع جميع المواقف المحتملة. وهذا هو السبب الأساسي لهدف التعلم المعزز وهو ** تقليل الخطأ، وليس التنبؤ بجميع التحركات المحتملة**. إن البقاء على قيد الحياة في البيئة الافتراضية هي الفكرة الأساسية للتعلم المعزز. إذ سنعتمد على ترك الروبوت الصغير الفقير يتجول في الحياة الافتراضية ونُعاقبه على الأخطاء ونُكافؤه على الأفعال الصحيحة. بنفس الطريقة الّتي نعلم بها أطفالنا، أليس كذلك؟ الطريقة أكثر فعالية لتدريب الروبوت هي بناء مدينة افتراضية والسماح للسيارة ذاتية القيادة بتعلم كلّ طرق القيادة وحيلها فيها أولًا. في الحقيقة هذه هي الطريقة المعتمدة في تدريب الروبوت الموجودة في السيارات ذاتية القيادة. إذ ننشئ في البداية مدينة افتراضية استنادًا لخريطة المدينة الحقيقية، ونضيف إليها أناس افتراضيين يمشون في الشوارع (لمحاكاة الواقع) ونترك السيارة تتعلم بمفردها وذلك بوضع هدف نصب أعيننا وهو "تقليل العدد الّذي تقتله من الناس بأقل ما يمكن" وهكذا يستمر الروبوت في التدرب إلى أن يصل لمرحلة لا يقتل بها أحد. عندما يؤدي الروبوت أداءً جيدًا في لعبة GTA عندها سنُحرره ونختبره في الشوارع الحقيقية. قد يكون هناك نهجان مختلفان للتعلم المعزز وهما: نهج قائم على نموذج (Model-Based). نهج غير قائم على نموذج أو النهج الحر (Model-Free). إن النهج القائم على نموذج يعني أن السيارة بحاجة لحفظ كامل الخريطة أو أجزائها. هذا نهج قديم جدًا لأنه من المستحيل بالنسبة للسيارة الفقيرة ذاتية القيادة أن تحفظ الكوكب بأكمله. أما في النهج غير القائم على نموذج فلا تحفظ السيارة كلّ حركة ولكنها تحاول تعميم المواقف، ومحاولة التصرف بعقلانية إلى جانب محاولتها الحصول على أقصى مكافأة. هل تذكر الأخبار المتداولة حول خسار بطل العالم بلعبة Go أمام الذكاء الصنعي؟ هل تعلم بأن عدد التركيبات القانونية المحتملة للعبِ بهذه اللعبة أكبر من عدد الذرات الموجودة في الكون كلّه؟ حتى أن العلماء أثبتوا ذلك لاحقًا. ولكن هل سنطلب من هذا الروبوت المسكين حفظ كلّ ذلك؟ في الواقع أن الآلة لم تتذكر جميع التركيبات المحتملة للعب ومع ذلك فازت بلعبة Go، إذ حاولت تطبيق أفضل حركة في كلّ دور على حدة (تمامًا كما فعلت في لعبة الشطرنج عندما هزمت غاري كاسباروف في المباراة الشهيرة سنة 1997 والّتي سميت بمباراة القرن). هي فعليًا اختارت ببساطة أفضل حركة (من ناحية المكسب) لكلّ حالة، وقد فعلت ما يكفي للتغلب على البشر. يعد هذا النهج مفهومًا أساسيًا أدى لظهور التعلّم المعزز وفق النموذج الحرّ (Q-learning) وهو فرع من فروع التعلّم المعزز بل وظهور الخوارزميات مثل خوارزمية خطة ماركوف للتعلّم المعزز لاتخاذ القرار (SARSA) وخوارزمية التعلّم المعزز العميق وفق النموذج الحرّ (DQN). ومن الجدير بالذكر أن حرف "Q" يشير إلى "الجودة" (Quality) إذ يتعلم الروبوت أداء الفعل الأكثر "نوعية" في كلّ حالة ويحفظ جميع المواقف على أنها سلسلة ماركوفية بسيطة. يمكن للآلة اختبار مليارات المواقف والحالات في البيئة افتراضية، ويمكنها تذكر جميع الحلول الّتي أدت لمكافأة أكبر. ولكن كيف يمكنها أن تميز المواقف الّتي رأتها مسبقًا عن المواقف الجديدة كليًا؟ فمثلًا إذا كانت السيارة ذاتية القيادة في إحدى التقاطعات بين الشوارع وكانت إشارة المرور حمراء وتحولت فجأة الإشارة الخضراء فهل هذا يعني أنها يمكن أن تسير مباشرة؟ ماذا لو كانت هناك سيارة إسعاف تسير في شارع قريب وتطلب من السيارات الأخرى إفساح الطريق لها؟ الإجابة الحالية على هذا السؤال وفق المعطيات المتاحة إلى يومنا هذا هو "لا أحد يعرف ما الّذي ستفعله هذه السيارة ذاتية القيادة". فعليًا لا توجد إجابة سهلة. لطالما استمر الباحثون في المحاولة للعثور على إجابة، ولكن في الوقت نفسه لا يجدون سوى الحلول المؤقتة لبعض الحالات. إذ يعتمد البعض على محاكاة جميع المواقف يدويًا الّتي تنتج حلًا للحالات الاستثنائية، مثل: مشكلة العربة. والبعض الآخر يتعمق أكثر من ذلك ويترك للشبكات العصبية مهمة اكتشافها. وهذا قادنا لتطور التعلم المعزز وفق النموذج الحر (Q-learning) إلى شبكات التعلم المعزز العميق (Deep Q-Network). لكنها ليست بالحل المثالي أيضًا. طريقة المجموعات وهو مجموعة أشجار غبية تتعلّم تصحيح أخطاء بعضها البعض. من بعض تطبيقاتها العملية في وقتنا الحالي: جميع التطبيقات الّتي تعمل على الخوارزميات الكلاسيكية (الفارق هنا أنها تقدم أداء أفضل). أنظمة البحث. الرؤية الحاسوبية. الكشف عن الأغراض. من أبرز الخوارزميات الشائعة لها: خوارزمية الغابات العشوائية (Random Forest). خوارزمية التدرج المعزز (Gradient Boosting). حان الوقت للأساليب الحديثة والكبيرة. تعدّ المجمعات والشبكات العصبية مقاتلان رئيسيان يمهدان طريقنا نحو التفرد في عملية التعلّم. واليوم ينتجون أكثر النتائج دقة ويستخدمون على نطاق واسع في جميع الأحداث. على الرغم من فعاليتها العالية إلا أن الفكرة الكامنة وراءها بسيطة للغاية. إذ تعتمد على أخذ مجموعة من الخوارزميات ذات الفعالية العادية، وتجبرها على تصحيح أخطاء بعضها بعضًا، فستكون الجودة الإجمالية للنظام أفضل من أفضل خوارزميات تعمل بطريقة منفردة. ستحصل على نتائج أفضل إذا أخذت أكثر الخوارزميات تقلبًا في النتائج، والّتي تتوقع نتائج مختلفة تمامًا في حالة حدوث ضوضاء صغيرة على بيانات الدخل. مثل خوارزميات أشجار القرار وأشجار الانحدار. هذه الخوارزميات حساسة للغاية، حتى أنه يمكن لقيمة شاذة واحدة خارجية مطبقة على بيانات الدخل أن تجعل النماذج يجن جنونها. في الحقيقة هذا بالضبط ما نحتاجه. هنالك ثلاث طرق لبناء المجمعات: طريقة التكديس (Stacking). طريقة التعبئة (Bagging). طريقة التعزيز (Boosting). سنشرح كلّ واحدٍ منهم على حدة: 1. طريقة التكديس (Stacking) تُمرر مجموعة من النماذج المتوازية كمدخلات للنموذج الأخير والّذي سيتخذ القرار النهائي. تَنتجُ هذه النماذج من تطبيق خوارزميات مختلفة وكلمة "مختلفة" تعني أي أن خلط تكديس نفس الخوارزميات على نفس البيانات لن يكون له أي معنى أو أهمية. وإن عملية اختيار الخوارزميات أمر متروك لك مطلق الحرية في اختباره. إلا أنه بالنسبة للنموذج المعني باتخاذ القرار النهائي، عادة ما يكون الانحدار خيارًا جيدًا لخوارزميته. 2. طريقة التعبئة (Bagging) وهي معروفة أيضًا باسم Bootstrap Aggregating. في هذه الطريقة نستخدم نفس الخوارزمية، ولكن ندربها على مجموعات فرعية مختلفة من البيانات الأصلية. في النهاية نحسب متوسط الإجابات فقط. يمكن أن تتكرر البيانات في مجموعات فرعية عشوائية. فمثلًا، يمكننا الحصول على مجموعات فرعية من المجموعة "1-2-3" مثل: "2-2-3" و"1-2-2" و"3-1-2" وما إلى ذلك. نستخدم مجموعات البيانات الجديدة هذه لتعليم الخوارزمية نفسها عدة مرات، ثمّ نتوقع الإجابة النهائية عن طريق خوارزمية البسيطة التصويت بالأغلبية. أشهر مثال على استخدام طريقة التعبئة هي خوارزمية الغابات العشوائية (Random Forest) والتي ببساطة تعبأ باستخدام أشجار القرار (الّتي سبق وأن وتحدثنا عنها في الفقرات السابقة). فمثلًا عند فتحك لتطبيق الكاميرا الخاص بهاتفك ورؤيتك لمربعات مرسومة حول وجوه الأشخاص فيجب أن تسأل نفسك، كيف حدث ذلك؟ في الحقيقة من المحتمل أن تكون هذه النتيجة بفضل خوارزمية الغابات العشوائية. وذلك لأن الشبكات العصبية بطيئة جدًا عند تشغيلها في الزمن الحقيقي (Real-time)، وبالمقابل تكون طريقة التعبئة مثالية بهذه الحالات لأنه يمكنها أن تبني أشجار القرار على جميع البطاقات الرسومية الضعيفة والقوية بل وحتى على المعالجات الجديدة الفاخرة الخاصة بتعلّم الآلة! في بعض المهام، تكون الاستراتيجية المتبعة هي التركيز على قدرة الغابة العشوائية على العمل بالتوازي مثلما يحدث عند استخدام الشبكات العصبية الاصطناعية أما طريقة التجميع لا تستطيع العمل بالتوازي، والبعض الآخر من التطبيقات تتطلب السرعة الّتي تستطيع تحققها طرق المجموعات بغض النظر عن أسلوب تطبيقها وتحديدًا في المهام الّتي تتطلب معالجة بالزمن الحقيقي. ولكنها في النهاية مسألة مفاضلة بين خياري الدقة أو السرعة وذلك بحسب كلّ مهمة. 3. طريقة التعزيز (Boosting) وهي الطريقة الّتي تعتمد على تدريب الخوارزميات واحدةً تلو الآخرى. وكلّ خوارزمية لاحقة تولي معظم اهتمامها لنقاط البيانات الّتي أخطأت الخوارزمية السابقة في تفسيرها. وتكرر هذه العملية إلى أن تصبح النتيجة مرضية. كما هو الحال في طريقة التعبئة، تستخدم الخوارزمية مجموعات فرعية متنوعة من بياناتنا ولكن هذه المرة لن نُنشئها بطريقة عشوائية. وإنما في كلّ عينة فرعية، نأخذ جزءًا من البيانات الّتي فشلت الخوارزمية السابقة في معالجتها. وبذلك نُنشئ خوارزمية جديدة لتتعلم كيفية إصلاح الأخطاء الموجودة في الخوارزمية السابقة. الميزة الرئيسية في طرق التجميع هي الدقة الممتازة بالموازنة مع الوقت المأخوذ، وتعد أسرع بكثير من الشبكات العصبية. تقريبًا الأمر أشبه ما يمكن بسباق بين سيارة وشاحنة على المضمار. يمكن للشاحنة أن تؤدي المزيد من الأفعال، ولكن في حال أردت أن تسير بسرعة فحتمًا ستأخذ السيارة. لالقاء نظرة على مثال حقيقي لاستخدام طرق التجميع (وتحديدًا طريقة التعزيز) افتح موقع فيسبوك أو موقع غوغل واكتب أي استعلام في مربع البحث. هل يمكنك سماع جيوش من الأشجار تزأر وتتحطم معًا لفرز النتائج حسب الصلة؟ ذلك بسبب أن هذه الشركات يستخدمون طريقة التجميع باستخدام التعزيز. حاليًا هناك ثلاث أدوات شائعة لتطبيق طريقة التعزيز، يمكنك قراءة هذا التقرير المفصل الّذي يوازن بينها CatBoost مقابل LightGBM مقابل XGBoost. الشبكات العصبية (Neural Networks) والتعلم العميق (Deep Leaning) الشبكات العصبية (Neural Networks) الشبكات العصبية: وهي عبارة عن مجموعة من الخلايا العصبية الاصطناعية الموجودة في طبقاتٍ متوضعةٍ فوق بعضها بعضًا، ولها طبقة أولية، وطبقة النهائية، تتلقى الطبقة الأولية المعلومات الخام، وتعالجها لتُمررها لاحقًا للطبقة الّتي تليها وهكذا إلى أن نحصل على الخرج من الطبقة النهائية. بعض أشهر تطبيقاتها العملية المستخدمة في وقتنا الحالي: تحديد الكائن في الصور ومقاطع الفيديو. التعرف على الكلام والتراكيب اللغوية. معالجة الصور وتحويل التنسيق. الترجمة الآلية. بالإضافة إلى أنه يمكنها أن تعمل عوضًا عن جميع تطبيقات طرق تعلّم الآلة السابقة. من بعض الهيكليات الشائعة للشبكات العصبية: الشبكات العصبية بيرسيبترون (Perceptron). الشبكات العصبية التلافيفية (CNN). الشبكات العصبية المتكررة (RNN). الشبكات العصبية ذات الترميز التلقائي (Autoencoders). إن أي شبكة عصبية اصطناعية هي في الأساس مجموعة من الخلايا العصبية الاصطناعية (Neurons) و الاتصالات (Connections) الّتي بينهم. وإن الخلية العصبية الاصطناعية: هي مجرد تابع لديه مجموعة من المدخلات وخرج وحيد. وتتمثل مهمة الخلية العصبية الاصطناعية في أخذ جميع الأرقام من مدخلاتها، وأداء الوظيفة المنوطة إليها وإرسال النتيجة للخرج. الاتصالات تشبه إلى حدٍ ما القنوات بين الخلايا العصبية الحقيقية. إذ تربط مخرجات خلية عصبية معينة لمدخل خلية عصبية أخرى حتى يتمكنوا من إرسال الأرقام والنتائج لبعضهم بعضًا. وكلّ اتصال له وسيط واحد فقط وهو الوزن (Weight). وهو مشابه لقوة الاتصال للإشارة. فعندما يمر الرقم 10 من خلال اتصال بوزن 0.5 يتحول إلى 5. هذه الأوزان تطلب من الخلية العصبية الاصطناعية أن تستجيب أكثر للدخل ذو الوزن الأكبر، وأقل للدخل ذو الوزن الأقل. تُعدل هذه الأوزان عند التدريب وهكذا تتعلّم الشبكة العصبية الاصطناعية. فيما يلي مثال لخلايا عصبية اصطناعية بسيطة ولكنها مفيدة في الحياة الواقعية: ستجمع جميع الأرقام من مدخلاتها وإذا كان هذا العدد أكبر من N فستُعطي النتيجة 1 وإلا ستعطي النتيجة 0. لمنع حدوث فوضى في الشبكة، ترتبط الخلايا العصبية بطبقات، وليس بطريقة عشوائية. لا ترتبط الخلايا العصبية داخل الطبقة الواحدة، وإنما تتصل بالخلايا العصبية للطبقات التالية والسابقة (الأعلى والأسفل). تتحرك البيانات في الشبكة العصبية الاصطناعية تحركًا صارمًا باتجاه واحد من مدخلات الطبقة الأولى إلى مخرجات الطبقة الأخيرة. إذا وضعت عددًا كافيًا من الطبقات ووضعت الأوزان بطريقة صحيحة، فستحصل على النتيجة المرجوة وإليك مثلًا يوضح الأمر، تريد أن تكتشف ما هو الرقم المكتوب بخط اليد في الصورة الممررة، ستمرر الصورة إلى الشبكة عن طريق مدخلات الطبقة الأولى، وبعدها فإن البكسلات السوداء ستُنشّط الخلايا العصبية المرتبطة بها، وهي بدورها ستُنشّط الطبقات التالية المرتبطة بها، وهكذا حتى يضيء أخيرًا المخرج المسؤول عن الرقم أربعة. إذا هكذا وصلنا للنتيجة المرجوة (سنأخذ هذا المثال بوضوح أكبر وبكلّ تفاصيله الدقيقة في الجزء الثاني من هذه السلسلة). في الواقع عند برمجة الخلايا العصبية على الحاسب لا نكتب عمليًا الخلايا العصبية والوصلات المرتبطة بها. وإنما يمثل كلّ شيء كمصفوفات وتحسب النتيجة بناءً على ضرب المصفوفات ببعضها بعضًا للحصول على أداء أفضل. يبسط هذا الفيديو كيف تحدث عملية التعلّم في الخلايا العصبية الاصطناعية، وكيف تحدد عملية الضرب دقة الشبكة العصبية الّتي لدي (لا تنس أن تغعّل خيار التعليقات التوضيحية لأن الفيديو مترجم إلى اللغة العربية). تحتوي الشبكة على طبقات متعددة لها روابط بين كلّ خلية عصبية تسمى الشبكات العصبية بيرسيبترون المتعددة (Multilayer Perceptron) وتسمى اختصارًا (MLP) وتعد أبسط بنية مناسبة للمبتدئين. بعد إنشاء الشبكة، ستكون مهمتنا هي تعيين الطرق المناسبة لتتفاعل الخلايا العصبية مع الإشارات الواردة بطريقة صحيحة. وسنُعطي الشبكة بيانات الدخل أو "مدخلات الشبكة العصبية" صورة الرقم المكتوب بخط اليد وبيانات الخرج أو "مخرجات الشبكة العصبية" ستكون الرقم الموافق للصورة المُمررة عبر مدخلات الشبكة. أي سنقول للشبكة "عدلي أوزانك بالطريقة الصحيحة حتى تستطيعين معرفة الصورة الممررة لك على أنها صورة للرقم 4". في البداية تُسند جميع الأوزان بطريقة عشوائية. بعد أن نعرض لها رقمًا معينًا، إذ تنبعث منها إجابة عشوائية لأن الأوزان ليست صحيحة حتى الآن، ونوازن مدى اختلاف هذه النتيجة عن النتيجة الصحيحة. ثم نبدأ في بالرجوع للخلف عبر الشبكة من المخرجات إلى المدخلات ونخبر كلّ خلية عصبية، لقد تنشطت هنا وأديت عملًا رهيبًا وهكذا. بعد مئات الآلاف من هذه الدورات "الاستدلال ثمّ التحقق ثمّ التغيير" المتتالية هناك أمل في أن تُصحح الشبكة العصبية أوزانها وتجعلها تعمل على النحو المنشود. الاسم العلمي لهذه المنهجية هي "منهجية الانتشار العكسي" (Backpropagation). يبسط هذا الفيديو كيف تَحدثُ عملية التعلّم بالتفاصيل الدقيقة في الطبقات المخفية وكيف تتعلم من أخطائها (مرة أخرى لا تنسَ أن تغعّل خيار التعليقات التوضيحية لأن الفيديو مترجم إلى اللغة العربية). يمكن للشبكة العصبية المدربة تدريبًا جيدًا أن تنوب عن عمل أي من الخوارزميات الموضحة في هذا الفصل (بل وغالبًا ما يمكنها أن تعمل بدقة أكثر منهم). وهذا ما جعلها شائعة الاستخدام على نطاق واسع. اتضح لاحقًا أن الشبكات الّتي تحتوي على عدد كبير من الطبقات تتطلب قوة حسابية لا يمكن تصورها آنذاك (عند بداية ظهور الشبكات العصبية). أما حاليًا فأي حاسوب مُخصص للألعاب يتفوق بالأداء على أداء مراكز البيانات الضخمة آنذاك. لذلك لم يكُ لدى الناس أي أمل في أن تصبح هذه القدرة الحسابية متوفرة ذلك الحين، وكانت فكرة الشبكات العصبية مزعجة بضخامتها. سنتاول في شرحنا أهم الهياكل المشهورة للشبكات العصبية في الوقت الحاضر. الشبكات العصبية التلافيفية (Convolutional Neural Networks) أحدثت بنية الشبكات العصبية التلافيفية والتي تدعى اختصارًا (CNN) ثورة في عالم الشبكات العصبية حاليًا. إذ تستخدم للبحث عن الكائنات في الصور وفي مقاطع الفيديو، كما تستخدم أيضًا للتعرف على الوجوه، وتحويل التنسيق، وتوليد وتحسين الصور، وإنشاء تأثيرات مثل التصوير البطيء وتحسين جودة الصورة. باختصار تستخدم بنية الشبكات العصبية التلافيفية في جميع الحالات الّتي تتضمن صورًا ومقاطع فيديو. يمكنك ملاحظة كيف استطاعت تقنيات تعلم الآلة الّتي طورتها شركة فيسبوك من تحديد الكائنات الموجودة في الصورة بدقة ممتازة. من أبرز المشاكل الرئيسية الّتي تواجهنا عند التعامل مع الصور هي صعوبة استخراج الميزات منها. على عكس سهولة الّتي نجدها عند التعامل مع النصوص، إذ في النصوص يمكنك ببساطة تقسيم النص بحسب الجمل، والبحث عن الكلمات ذات سمات معينة، وما إلى ذلك. ولكن في الصور الأمر أعقد من ذلك بكثير إذ يجب تصنيف الصور تصنيفًا يدويًا لكي تتمكن برامج تعلّم الآلة من معرفة مكان آذان القطط أو ذيولها في هذه الصورة المحددة والمنصفة. سميت هذه المنهجية لاحقًا باسم "صناعة الميزات يدويًا" وكان يستخدمها الجميع تقريبًا. ولكن الأمر لم يتوقف إلى هذا الحد فحسب وإنما ظهرت العديد من المشاكل مع منهجية صناعة الميزات يدويًا.فمثلًا في البداية إذا كانت تعرفت الشبكة العصبية على أذني القطة وأبعدت هذه القطة عن الكاميرا فنحن في مشكلة لأن الشبكة لن ترى شيئًا (بسبب تغيّر حجم أذن القطة). ثانيًا لنحاول تسمية 10 ميزات مختلفة تميّز القطط عن بقية الحيوانات الأخرى (في الحقيقة أنا أول من فشل في هذه المهمة)، ولكن مع ذلك عندما أرى نقطة سوداء تُسرعُ من جانبي أثناء تجولي في الشارع عند منتصف الليل - حتى لو لمحتها فقط في زاوية عيني - سأستطيع أن أحدد بأنها قطة وليست فأر. والسبب بسيط جدًا إذ لا شعوريًا يصنف دماغنا العديد من الميزات الخاصة بالقطط ولا ينظر إلى شكل الأذن أو عدد الأرجل فقط وذلك بدون أي جهد مني ولا حتى تفكير. وبناءً على ذلك سيصعب الأمر جدًا عند محاولتي لنقل هذه المعرفة إلى الآلة. لذا فهذا يعني أن الآلة ستحتاج إلى تعلّم هذه الميزات بمفردها، وإنشاء هذه الميزات اعتمادًا على الخطوط الأساسية للصورة. سننفذ ما يلي: سنقسم الصورة بأكملها إلى كتل ذات حجم 8×8 بكسل. سنخصص لكل نوع من أنواع الخطوط على الصورة رمزًا معينًا - سواء أكان الخط أفقيًا سيكون الرمز [-] أو رأسيًا سيكون الرمز [|] أو قطريًا سيكون الرمز [/]. يمكن أيضًا أن يكون العديد منها مرئيًا للغاية - وهذا يحدث ولذلك لسنا دائمًا على ثقة تامة. سيكون الناتج عدة جداول من الخطوط الّتي هي في الواقع أبسط الميزات الّتي تمثل حواف الكائنات على الصورة. إنها صور بمفردها ولكنها مبنية من الخطوط. وهكذا نستمر في أخذ كتلة ذات حجم 8×8 ونرى كيف تتطابق معًا. ونعيدها مرارًا وتكرارًا. تسمى هذه العملية بعملية الإلتفاف أو الطيّ (Convolution)، مستمدة هذا الاسم من تابع الطيّ المطبق فيها. يمكن تمثيل عملية الطيّ كطبقة من الشبكة العصبية، لأنه في نهاية الأمر يمكن لكلّ خلية عصبية أن تكون بمثابة تابع يؤدي أي وظيفة أريدها. عندما نغذي ونزود شبكتنا العصبية بالكثير من صور القطط، فإنها ستعيّن تلقائيًا أوزانًا أكبر لمجموعات الخطوط الّتي تتكرر كثيرًا في هذه النوع من الصور. لا تهتم الآلة ما إذا كان ظهر القطة خطًا مستقيمًا أو جسمًا هندسيًا معقدًا مثل وجه القطة، وبالمجمل ستكون بعض مجموعات الخطوط ستكون نشطة دائمًا. كمخرجات ستنظر هذه الشبكة العصبية الاصطناعية ذات البنية التلافيفية لأكثر المجموعات نشاطًا في هذه الصور وستبني عليها قرارها فيما إذا كانت الصور لقطة أو لكلب. يكمن جمال هذه الفكرة في أن الشبكة العصبية ستبحث عن الميزات الأكثر تميزًا للكائنات بمفردها. لسنا بحاجة لاختيارها يدويًا. يمكننا تزويد الشبكة بكمية كبيرة من الصور لأي كائن فقط من خلال البحث في غوغل عن مليارات من الصور المشابهة وهكذا سوف تنشئ شبكتنا خرائط مميزة من الخطوط وتتعلم كيفية تمييز أي كائن بمفردها. الشبكات العصبية المتكررة (Recurrent Neural Networks) تعدّ الشبكات العصبية المتكررة والتي يشار لها اختصارًا (RNN) من أكثر البُنى الهيكلية للشبكات العصبية الاصطناعية شيوعًا في وقتنا الحاضر. وذلك لفوائدها الجمّة إذ أعطتنا الكثير من الأشياء المفيدة مثل: الترجمة الآلية، والتعرف على الكلام، وتركيب صوت مميز للمساعد الشخصي مثل المساعد سيري (Siri). وعمومًا تعدّ هذه البنية من أفضل الخيارات الموجودة للبيانات التسلسلية مثل: الصوت أو النص أو الموسيقى. هل تذكر القارئ الصوتي الخاص الموجود في نظام التشغيل ويندوز إكس بي (Windows XP)؟ هذا الرجل المضحك يبني الكلمات حرفًا بحرف، محاولًا لصقها معًا. الآن وازن بين صوته وصوت المساعد الشخصي أليكسا الخاص بشركة أمازون، أو المساعد الشخصي الخاص بغوغل، فرق كبير بينهم، أليس كذلك؟ إنهم لا ينطقون الكلمات بوضوح فقط وإنما يضيفون لكنة خاصة مناسبة لهم! إليك هذا الفيديو اللطيف لشبكة عصبية تحاول أن تتحدث. كلّ ذلك لأن المساعدين الصوتيين الحديثين مدربون على التحدث على عبارات كاملة دفعة واحدة وليس حرفًا بحرف، يمكننا أخذ مجموعة من النصوص الصوتية وتدريب شبكة عصبية لإنشاء تسلسل صوتي أقرب إلى الكلام الأصلي. بمعنى آخر، سنستخدم النص كمدخل للشبكة العصبية الاصطناعية وصوت الشخص المجرّد كخرج لهذه الشبكة. نطلب من الشبكة العصبية إنشاء بعض الأصوات لنص محدد، ثم موازنته بالصوت الأصلي ومحاولة تصحيح الأخطاء للاقتراب قدر الإمكان من الصوت الأصلي المثالي. تبدو عملية التعلم بسيطة وكلاسيكية أليس كذلك؟ حتى الشبكات العصبية ذات التغذية المُسبقة تستطيع فعل ذلك. ولكن كيف يجب تعريف مخرجات هذه الشبكة؟ هل سيكون بلفظ كلّ عبارة ممكنة موجودة في اللغة الإنكليزية؟ بالتأكيد هذا ليس خيارًا جيدًا. هنا ستساعدنا حقيقة أن النص أو الكلام أو حتى الموسيقى؛ ما هي إلا تسلسلات من المعلومات. تتكون من وحدات متتالية (مثل المقاطع اللفظية للكلمات الإنكليزية). تبدو جميعها فريدة من نوعها ولكنها تعتمد على مقاطع سابقة. ألغِ هذا الاتصال بين هذه المقاطع وستحصل على مقطع موسيقي من نوع دبستيب (Dubstep). يمكننا تدريب الشبكة العصبية بيرسيبترون لتوليد هذه الأصوات الفريدة، ولكن كيف ستتذكر الإجابات السابقة؟ لذا تكمن الفكرة في إضافة ذاكرة خاصة لكلّ خلية عصبية اصطناعية، واستخدامها كمدخل إضافي عند تشغيل المقطع التالي. يمكن للخلايا العصبية أن تدون ملاحظات لنفسها مثل اكتشافها لحرفٍ متحرك، ولذلك يتوجب عليها أن تُظهر المقطع الصوتي التالي بنبرة أعلى (في الحقيقة إنها مجرد مقاربة بسطية للغاية). بهذه الطريقة ظهرت الشبكات المتكررة. كان لهذا النهج مشكلة كبيرة وهي عندما تتذكر جميع الخلايا العصبية نتائجها السابقة، يصبح عدد الاتصالات في الشبكة ضخمًا جدًا لدرجة أنه من المستحيل -من الناحية الفنية- ضبط جميع الأوزان. لذلك عندما لا تستطع الشبكة العصبية نسيان بعض الأشياء غير الهامّة فلن تتمكن من تعلّم الأشياء الجديدة (حتى نحن البشر لدينا نفس المشكلة نسيان بعض المعلومات غير الهامة، أو لعلّها ميزة؟ وخصيصًا إذا كانت هذه الأشياء هي ذكريات مؤلمة!). كان التحسين الأول بسيطًا جدًا وذلك بتحديد حجم معين لذاكرة الخلية العصبية الاصطناعية. لنقل بأن الشبكة ستحفظ آخر 5 نتائج فقط. ولكن أليست هذه الفكرة مناقضة للفكرة الأساسية الّتي انطلقنا منها (وهي تذكر ما تعلمته الشبكة بالكامل)؟ بعد تحديثاتٍ وتطويرات كثيرة جاء لاحقًا نهج أفضل بكثير، والّذي سيستخدم خلايا خاصة، تشبه إلى حدٍ ما ذاكرة الحاسوب. يمكن لكلّ خلية إمكانية تسجيل رقم معين أو قراءته أو إعادة تعيينه. وسميت هذه الخلايا بخلايا الذاكرة طويلة وقصيرة الأجل (LSTM). والآن عندما تحتاج الخلية العصبية إلى تعيين منبه لتذكر هذا المقطع، فإنها ستضع راية (Flag) في تلك الخلية. مثل "كان الحرف ساكنًا في الكلمة، استخدم المرة التالية قواعد نطق مختلفة". عندما لا تستدعي الحاجة لاستخدام الرايات، سيُعاد ضبط الخلية تاركة فقط الاتصالات "طويلة الأجل" للشبكة العصبية. وبعبارة أخرى، ستُتدربُ الشبكة العصبية ليس فقط لكي تتعلّم كيفية ضبط الأوزان وإنما لتتعلّم أيضًا كيفية ضبط الرايات (وهي أشبه ما يمكن بالمنبهات) في الخلايا العصبية. قد يبدو الحل بسيط جدًا ومع ذلك يعمل بكفاءة عالية. لكن ماذا لو دمجنا إمكانية تعديل مقاطع الفيديو باستخدام الشبكات العصبية التلافيفية (CNN) مع إمكانية تعديل الصوت باستخدام الشبكات العصبية المتكررة (RNN) على ماذا سنحصل؟ هل حقًا سنحصل على الرئيس السابق للولايات المتحدة الأمريكية؟ إليك هذا الفيديو لتكتشف الأمر. التعلم العميق (Deep Learning) إذا أردنا أن نختصر التعلم العميق بجملة واحدة وواحدة فقط ستكون حتمًا: "التعلّم العميق هو شبكة عصبية اصطناعية كبيرة". من بعض التطبيقات العملية للتعلم العميق: التعرف على الصور والأصوات. تحليل بيانات الأرصاد الجوية. تحليل بيانات الأبحاث البيولوجية. مجال التسويق واختيار الجمهور المستهدف من الإعلانات. من بعض الهيكليات الشبكة العصبية الاصطناعية المستخدمة بكثرة في التعلّم العميق نجد: شبكات بيرسيبترون متعددة الطبقات (Multilayer Perceptron Networks). الشبكات العصبية التلافيفية (Convolutional Neural Networks). الشبكات العصبية المتكررة ذات الذاكرة قصيرة وطويلة الأمد (Long Short-Term Memory Recurrent Neural Networks). والعديد من البنى الأخرى للشبكة. بعد بناء العلماء والباحثين للعديد من البُنى (المعماريات) الخاصة بالشبكات العصبية في محاولة منهم للعثور على البنية الأنسب لاكتشاف الأنماط في البيانات، ومن بين أبرز هذه البُنى (المعماريات) كانت البنية الخاصة بالشبكة التعلم العميق، ويذكر أن أول مرة ظهر فيها مفهوم التعلم العميق كان في عام 2006، وعرفت في ذلك الوقت على أنها مجال فرعي من مجالات تعلّم الآلة (مع أنها تندرج تحت نفس فئة الشبكات العصبية)، إلا أنها لاقت الاهتمام الواسع عندما طبق جيفري هينتون وزملائه بنية الشبكة الخاصة بالتعلّم العميق في مسابقة ImgNet وحققوا آنذاك نتائج مبهرة، إذ استطاعوا تحقيق دقة أفضل بـ10% من البُنى القديمة في التعرف على الصور. بعد هذا النجاح المدوّي استطاعت بجدارة لفت الأنظار حولها وبدأت بالظهور العديد من التطبيقات والأبحاث الجديدة الخاصة بالتعلم العميق، مما أدى إلى تطورها تطورًا كبيرًا، كما أنها أثببت جودتها بتحقيقها نتائج مذهلة في العديد من التطبيقات، وبذلك أوجدت لنفسها مكانة لا يستهان بها في مجال الذكاء الصنعي عمومًا ومجال تعلم الآلة خصوصًا. يعتمدُ مفهوم التعلم العميق في أساسه على طريقة تعلّم مؤلفة من عدّة طبقات من التمثيلات المقابلة لبنيةٍ هرمية من السمات، ويتم تعريفُ السِّمات والمفاهيم عالية المستوى نزولًا إلى المفاهيم ذات المستوى الأدنى، وهي تعمل أيضًا نمط التعلم الموجه وغير الموجه إلا أنها تعمل عملًا ممتازً مع البيانات المصنفة (أي مع التعلّم الموجّه). إن للتعلم العميق علاقة وطيدة مع البيانات إذ لا بدّ من الحصول على كميات كبيرة من البيانات إذا أردنا استخدام هذا النوع من التعلّم. ومع ازدياد البيانات سوف تتحسن الدقة تحسنًا كبيرًا مما سيؤدي لنتائج أفضل في نهاية المطاف. الفرق بين الشبكات العصبية والتعلم العميق في الحقيقة إن التعلم العميق ما هو إلا بنية مخصصة من الشبكات العصبية، ولكنها سميت بالتعلم العميق نسبة إلى عدد الطبقات الّتي تحتويها هذه البنية الشبكية، وبما أنها أكبر من عدد الطبقات الخاصة بالشبكات العادية آنذاك فلذلك سُميت بهذا الإسم. تكمن قوة التعلم العميق في إمكانيته في تعلّم الميزات (Features) بطريقة هرمية، أي تتعلّم التسلسل الهرمي للميزات انطلاقًا من ميزات من مستوى عالٍ مرورًا بميزات بمستوى أخفض وهكذا إلى أن نصل لآخر الميزات ذات المستوى الأدنى، مما يعطي لأسلوب التعلم هذا مستوًى جديدًا من التجريد للنظام وخصوصًا مع الوظائف والمفاهيم المعقدة من خلال بنائها من المفاهيم الأبسط فالأبسط. من الشكل السابق نلاحظ كيف أن التعلم العميق يستطيع تعلم التمثيلات الهرمية للبيانات. الّتي تربط المدخلات مع المخرجات مباشرة من البيانات دون الاعتماد على الميزات الّتي حددها الإنسان. أي تستطيع استنتاج كميات كبيرة من الميزات ومحاولة تحليلها وبطها بالصورة الكاملة للمشكلة. يطلق على هذا النوع من طريقة تعلّم الميزات الخاصة بالبيانات بتعلم الميزات (Feature learning). ومن بين أبرز الطفرات العلمية الّتي شهدها التعلم العميق كان على يد شركة ديب مايند (والتي استحوذت عليها شركة ألفابت)، إذ استطاعت شركة ديب مايند أن تدمج بين التعلم العميق مع التعلم المعزز من أجل حلّ المشاكل المعقدة مثل لعب الألعاب. أطلقوا لاحقًا على طريقتهم هذه اسم شبكات التعلم المعزز العميق (Deep Q-Network)، بعدها اصبح التعلّم العميق في أغلب البنى الخاصة بالشبكات العصبية. ومن الملاحظ مما سبق أن طريقة التعلم العميق تتطلب أجهزة حاسب قوية جدًا، وذلك لأنها تتعامل مع كميات كبيرة من البيانات. هنالك العديد من البنى الخاصة بالشبكات العصبية لدرجة أننا نحتاج لكتاب كامل لتغطية كافة أنواعها ومميزاتها وسلبياتها وطرق عملها ..إلخ، إلا أنه وبما أنك استطعت تعلم الأساسيات فحتمًا ستستطيع تعلم أصعب البنى الشبكية، ولإعطاء نظرة دقيقة للأمر إليك الصورة التالية: كما يمكنك ايضًا الرجوع إلى هذا المقال لمزيد من المعلومات. دورة تطوير التطبيقات باستخدام لغة Python احترف تطوير التطبيقات مع أكاديمية حسوب والتحق بسوق العمل فور انتهائك من الدورة اشترك الآن الخلاصة بعد تعرفنا على أهم الأساسيات الخاصة بتعلّم الآلة، وكيف تختلف عن بعضها بعضًا، وما هي النقاط الّتي يجب علينا التركيز عليها عند اختيارنا لطريقة ما على حساب الأخرى، وتعرفنا أخيرًا على الشبكات العصبية والتعلم العميق، لا بدّ لنا من أن نسأل أنفسنا، ما هي المشاكل الّتي يُواجهنا هذا المجال؟ ما نوع هذه المشاكل؟ وكيف نستطيع تجاوزها؟ في مقالنا القادم سنحاول الإجابة على هذه الأسئلة ونتعلم أيضًا بعض الأمور المهمة والّتي ستساعدنا في المضي قدمًا في هذا المجال. المراجع مقال Machine Learning for Everyone. كتاب Hands on Machine Learning with Scikit Learn Keras and TensorFlow الطبعة الثانية. مقال What is Deep Learning?. اقرأ أيضًا المقال التالي: تعلم الآلة: التحديات الرئيسية وكيفية التوسع في المجال المقال السابق: الذكاء الاصطناعي: مراحل البدء والتطور والأسس التي نشأ عليها النسخة الكاملة من كتاب مدخل إلى الذكاء الاصطناعي وتعلم الآلة1 نقطة
-
قواعد صنف الاختبار بفرض لدينا الصنف LoginForm مع التابع rules()، والذي يستخدم في صفحة تسجيل الدخول مثل قالب لإطار العمل: class LoginForm { public $email; public $rememberMe; public $password; // (1) public function rules() { return [ // البريد الإلكتروني وكلمة السر مطلوبان [['email', 'password'], 'required'], // يجب أن يكون البريد الإلكتروني بصياغة بريد إلكتروني ['email', 'email'], // يجب أن يكون الحقل rememberMe قيمة منطقية ['rememberMe', 'boolean'], // يجب أن تطابق كلمة السر هذا النمط (أي تحوي أحرف وأرقام فقط) ['password', 'match', 'pattern' => '/^[a-z0-9]+$/i'], ]; } // تتحقق هذه الدالة من صحة القواعد الممررة public function validate($rule) { $success = true; list($var, $type) = $rule; foreach ((array) $var as $var) { switch ($type) { case "required": $success = $success && $this->$var != ""; break; case "email": $success = $success && filter_var($this->$var, FILTER_VALIDATE_EMAIL); break; case "boolean": $success = $success && filter_var($this->$var, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) !== null; break; case "match": $success = $success && preg_match($rule["pattern"], $this->$var); break; default: throw new \InvalidArgumentException("Invalid filter type passed") } } return $success; } } في الموضع (1) يعيد التابع rules() مصفوفة بمتطلبات كل حقل، يستخدم نموذج تسجيل الدخول البريد الإلكتروني وكلمة المرور لاستيثاق المستخدم. نستخدم اختبار الوحدات لإجراء الاختبارات على هذا الصنف، أي للتحقق من الشيفرة المصدرية لمعرفة إذا كانت تناسب توقعاتنا: class LoginFormTest extends TestCase { protected $loginForm; // تنفيذ الشيفرة في بداية الاختبار public function setUp() { $this->loginForm = new LoginForm; } // (1) public function testRuleValidation() { $rules = $this->loginForm->rules(); // التهيئة للتحقق من صحة واختبار البيانات التالية $this->loginForm->email = "valid@email.com"; $this->loginForm->password = "password"; $this->loginForm->rememberMe = true; $this->assertTrue($this->loginForm->validate($rules), "Should be valid as nothing is invalid"); // اختبار صحة البريد الإلكتروني // بما أننا حددنا أن يكون البريد الإلكتروني بصياغة بريد إلكتروني فلا يمكن أن يكون فارغًا $this->loginForm->email = ''; $this->assertFalse($this->loginForm->validate($rules), "Email should not be valid (empty)"); // لا يحتوي البريد الإلكتروني على العلامة "@" لذا فهو غير صحيح $this->loginForm->email = 'invalid.email.com'; $this->assertFalse($this->loginForm->validate($rules), "Email should not be valid (invalid format)"); // قيمة صحيحة للبريد الإلكتروني من أجل الاختبار التالي $this->loginForm->email = 'valid@email.com'; // اختبار صحة كلمة المرور والتي يجب ألا تكون فارغة (بما أنها مطلوبة) $this->loginForm->password = ''; $this->assertFalse($this->loginForm->validate($rules), "Password should not be valid (empty)"); // قيمة صحيحة لكلمة المرور من أجل الاختبار التالي $this->loginForm->password = 'ThisIsMyPassword'; // اختبار صحة الحقل rememberMe $this->loginForm->rememberMe = 999; $this->assertFalse($this->loginForm->validate($rules), "RememberMe should not be valid (integer type)"); // قيمة صحيحة للحقل rememberMe من أجل الاختبار التالي $this->loginForm->rememberMe = true; } } في الموضع (1) يجب أن نستخدم التابع validate() للتحقق من صحة قواعدنا، يعود التابع testRuleValidation() إلى اختبار الوحدة الخاص بالصنف LoginFormTest ويختبر القواعد المذكورة سابقًا. كيف يمكن أن يساعد اختبار الوحدات هنا (باستثناء الأمثلة العامة)؟ يناسبنا عند الحصول على نتائج غير متوقعة مثلًا، بفرض لدينا هذه القاعدة: ['password', 'match', 'pattern' => '/^[a-z0-9]+$/i'], إذا نسينا شيئًا واحدًا مهمًا وكتبنا: ['password', 'match', 'pattern' => '/^[a-z0-9]$/i'], من الصعب اكتشاف الأخطاء مع وجود عشرات القواعد المختلفة، وبفرض أننا لا نستخدم البريد الإلكتروني وكلمة المرور فقط، إليك اختبار الوحدة هذا: // التهيئة للتحقق من صحة واختبار البيانات التالية $this->loginForm->email = "valid@email.com"; $this->loginForm->password = "password"; $this->loginForm->rememberMe = true; $this->assertTrue($this->loginForm->validate($rules), "Should be valid as nothing is invalid"); سيمرر هذا الاختبار مثالنا الأول وليس الثاني لأنه لدينا خطأ مطبعي في المثال الثاني (لم نكتب علامة +)، مما يعني أنه سيقبل حرف/رقم واحد فقط. يمكن تنفيذ اختبار الوحدات في الطرفية باستخدام الأمر phpunit [path_to_file]، إذا كان كل شيء صحيحًا، يجب أن نكون قادرين على رؤية الحالة OK لكل الاختبارات وإلا سنرى إما Error لخطأ في الصيغة، أو Fail على الأقل لسطر واحد لم يُمرَّر في ذلك التابع. يمكننا أيضًا باستخدام معاملات إضافية مثل --coverage أن نحصل على عدد الأسطر المُختبرة من الشيفرة في الواجهة الخلفية backend وأيها نجحَ/فشلَ، يُطبَّق هذا على أي إطار عمل ثبّتَ PHPUnit. إليك مثال عن طريقة ظهور اختبار PHPUnit في الطرفية، وهو مثال عام وليس له صلة بمثالنا: مقدمو بيانات PHPUnit تحتاج توابع الاختبار عادةً إلى بيانات لتُختَبر بها، ولاختبار بعض التوابع كاملةً تحتاج لتوفير مجموعات بيانات مختلفة لكل حالة اختبار ممكنة، يمكنك القيام بذلك يدويًا باستخدام الحلقات، مثال: ... public function testSomething() { $data = [...]; foreach($data as $dataSet) { $this->assertSomething($dataSet); } } ... يمكن أن تجد هذه الطريقة مريحة ولكن لها بعض العيوب، أولًا عليك أن تؤدي إجراءات إضافية لاستخراج البيانات إذا كانت دالة الاختبار تقبل عدة معاملات، ثانيًا سيكون من الصعب في حالة الفشل تمييز مجموعة البيانات الخاطئة بدون تنقيح أخطاء ورسائل إضافية، ثالثًا يوفر PHPUnit طريقة تلقائية للتعامل مع مجموعات بيانات الاختبار باستخدام مقدمي البيانات. مقدم البيانات دالة يجب أن ترجع بيانات حالة الاختبار الخاصة بك، ويجب أن تكون هذه الدالة عامة وترجع إما مصفوفة من المصفوفات أو كائن ينفّذ الواجهة Iterator ويُرجع مصفوفة لكل خطوة تكرارية. كل مصفوفة جزء من المجموعة collection التي سيستدعيها تابع الاختبار مع محتويات المصفوفة كوسائط لها. لاستخدام مقدم البيانات مع الاختبار نستخدم التوصيف @dataProvider مع اسم دالة مقدم البيانات المحددة: /** * @dataProvider dataProviderForTest */ public function testEquals($a, $b) { $this->assertEquals($a, $b); } public function dataProviderForTest() { return [ [1,1], [2,2], [3,2] //this will fail ]; } مصفوفة مصفوفات لاحظ أنّ الدالة dataProviderForTest() ترجع مصفوفة من مصفوفات، كل مصفوفة متداخلة تحتوي عنصرين سيملآن المعاملات الضرورية للدالة testEquals()، إذا لم يكن هناك عناصر كافية سيُرمى خطأ مشابه للخطأ التالي: Missing argument 2 for Test::testEquals() حيث سيمر PHPUnit تلقائيًا على كل البيانات وينفذ الاختبارات، كما هو ظاهر فيما يأتي: public function dataProviderForTest() { return [ [1,1], // [0] testEquals($a = 1, $b = 1) [2,2], // [1] testEquals($a = 2, $b = 2) [3,2] // [2] There was 1 failure: 1) Test::testEquals with data set #2 (3, 4) ]; } يمكن أن تُسمَّى كل مجموعة بيانات ليكون من الأسهل اكتشاف بيانات الفشل: public function dataProviderForTest() { return [ 'Test 1' => [1,1], // [0] testEquals($a = 1, $b = 1) 'Test 2' => [2,2], // [1] testEquals($a = 2, $b = 2) 'Test 3' => [3,2] // [2] There was 1 failure: // 1) Test::testEquals with data set "Test 3" (3, 4) ]; } المكررات class MyIterator implements Iterator { protected $array = []; public function __construct($array) { $this->array = $array; } function rewind() { return reset($this->array); } function current() { return current($this->array); } function key() { return key($this->array); } function next() { return next($this->array); } function valid() { return key($this->array) !== null; } } ... class Test extends TestCase { /** * @dataProvider dataProviderForTest */ public function testEquals($a) { $toCompare = 0; $this->assertEquals($a, $toCompare); } public function dataProviderForTest() { return new MyIterator([ 'Test 1' => [0], 'Test 2' => [false], 'Test 3' => [null] ]); } } كما تلاحظ، فإنَّ المكرِّر البسيط يعمل أيضًا، وأنّ مقدم البيانات يجب أن يرجع مصفوفة $parameter حتى من أجل معامل واحد. إذا غيّرنا التابع current() الذي يعيد البيانات في كل تكرار، بالشكل التالي: function current() { return current($this->array)[0]; } أو غيّرنا البيانات الفعلية: return new MyIterator([ 'Test 1' => 0, 'Test 2' => false, 'Test 3' => null ]); سنحصل على خطأ: There was 1 warning: 1) Warning The data provider specified for Test::testEquals is invalid. من غير المفيد طبعًا استخدام الكائن Iterator لتكرار محتويات مصفوفة بسيطة، يجب أن ينفّذ بعض المنطق المحدد لحالتك. المولدات generators لم يُشار إليها بشكلٍ صريح في التوثيق الرسمي لكن يمكنك استخدامها كمقدم بيانات أيضًا، لاحظ أنّ الصنف Generator ينفّذ الواجهة Iterator فعليًا، إليك مثال عن استخدام DirectoryIterator مع مولِّد: /** * @param string $file * * @dataProvider fileDataProvider */ public function testSomethingWithFiles($fileName) { // $fileName متاح هنا // اختبر هنا } public function fileDataProvider() { $directory = new DirectoryIterator('path-to-the-directory'); foreach ($directory as $file) { if ($file->isFile() && $file->isReadable()) { // تنفيذ المولِّد هنا yield [$file->getPathname()]; } } } لاحظ أنّ مقدم البيانات يُرجع مصفوفة، وستحصل على تحذير أنّ مقدم البيانات غير صحيح. استثناءات الاختبار لنفرض أنك تريد اختبار تابع يرمي استثناءً. class Car { /** * @throws \Exception */ public function drive() { throw new \Exception('Useful message', 1); } } يمكنك القيام بذلك عن طريق تضمين استدعاء التابع في كتلة try/catch وإجراء توكيدات على خاصيات كائن الاستثناء، أو يمكنك استخدام توابع توكيد الاستثناء للمزيد من الملاءمة، يمكنك بدءًا من الإصدار PHPUnit 5.2 استخدام توابع expectX() المتاحة لتأكيد نوع ورسالة وشيفرة الاستثناء. class DriveTest extends PHPUnit_Framework_TestCase { public function testDrive() { // التحضير $car = new \Car(); $expectedClass = \Exception::class; $expectedMessage = 'Useful message'; $expectedCode = 1; // الاختبار $this->expectException($expectedClass); $this->expectMessage($expectedMessage); $this->expectCode($expectedCode); // التنفيذ $car->drive(); } } يمكنك أن تستخدم التابع setExpectedException بدلًا من expectX() إذا كنت تستخدم إصدارًا قديمًا من PHPUnit لكن تذكر أنه تابع مُهمل وسيُحذف في الإصدار 6. class DriveTest extends PHPUnit_Framework_TestCase { public function testDrive() { // التحضير $car = new \Car(); $expectedClass = \Exception::class; $expectedMessage = 'Useful message'; $expectedCode = 1; // الاختبار $this->setExpectedException($expectedClass, $expectedMessage, $expectedCode); // التنفيذ $car->drive(); } } الأداء التحليل مع Xdebug تُعَدّ إضافة Xdebug متاحةً للمساعدة في تحليل تطبيقات PHP، بالإضافة إلى تنقيح الأخطاء وقت التنفيذ، عند تنفيذ المحلل يُكتب الخرج في ملف بصياغة ثنائية تدعى cachegrind. توجد تطبيقات متوفرة على كل منصة لتحليل هذه الملفات. لتمكين التحليل نثبّت الإضافة ونعدّل إعدادات ملف php.ini. سننفذ في مثالنا المحلل اختياريًا بالاعتماد على معامل الطلب، يسمح لنا هذا بالحفاظ على الإعدادات ثابتة وتشغيل المحلل عندما نحتاج فقط. // اضبطه إلى 1 لتشغيله عند كل طلب xdebug.profiler_enable = 0 // لنستخدم معامل GET/POST لتشغيل المحلِّل xdebug.profiler_enable_trigger = 1 // قيمة GET/POST التي سنمررها، فارغة من أجل أي قيمة xdebug.profiler_enable_trigger_value = "" // عرض ملفات الذاكرة cachegrind في المسار /tmp حتى ينظفها النظام لاحقًا xdebug.profiler_output_dir = "/tmp" xdebug.profiler_output_name = "cachegrind.out.%p" ثم استخدم عميل ويب يرسل طلبًا إلى رابط التطبيق الذي ترغب بتحليله، مثل: http://example.com/article/1?XDEBUG_PROFILE=1 أثناء معالجة الصفحة للطلب سيكتب في ملف له اسم مشابه للتالي: /tmp/cachegrind.out.12345 لاحظ أنّه سيكتب ملف واحد لكل عملية/طلب PHP يُنفَّذ، لذا إذا أردت تحليل نموذج مُرسل بالطريقة POST سيُكتب تحليل واحد من أجل الطريقة GET لعرض نموذج HTML وستحتاج إلى تمرير المعامل XDEBUG_PROFILE ، من أجل الإقدام على طلب POST اللاحق لتحليل الطلب الثاني الذي يعالج النموذج، لذا فقد يكون من الأسهل تنفيذ مكتبة curl لإرسال نموذج بالطريقة POST مباشرةً عند التحليل. بمجرد أن يُكتب التحليل، فيمكنك قراءة الذاكرة المخبئية cache بتطبيق مثل KCachegrind: سيعرض التطبيق معلومات التحليل متضمنةً: الدوال المنفَّذة وقت استدعاء الدالة بمفردها واستدعاءات الدالة اللاحقة. عدد مرات استدعاء كل دالة. رسوم بيانية للاستدعاء روابط للشيفرة المصدرية من الواضح أنّ ضبط الأداء خاص جدًا بحالات استخدام كل تطبيق، بشكل عام من الأفضل التركيز على النقاط التالية: يجب ألا ترى استدعاءات متكررة لنفس الدالة، بالنسبة للدوال التي تعالج البيانات وتستعلم عنها قد يكون هناك فرص للتخزين المؤقت. وجود دوال بطيئة التنفيذ، أين يستهلك التطبيق معظم وقته؟ أفضل عائد لضبط الأداء هو التركيز على أجزاء التطبيق التي تستهلك معظم وقته. ملاحظة: إنّ إضافة Xdebug وخاصةً ميزاتها التحليلية مكثّفة للموارد وتبطئ تنفيذ PHP، لذا يُنصح بعدم تنفيذها في بيئة خادم الإنتاج. استخدام الذاكرة يُضبط حد ذاكرة زمن تنفيذ PHP باستخدام موجّه INI الـ memory_limit، حيث يمنع هذا الضبط أي تنفيذ PHP مفرد من استخدام الكثير من الذاكرة مما يؤدي إلى استنزافها من أجل السكربتات الأخرى وبرنامج النظام. حد الذاكرة الافتراضي هو 128MB ويمكن أن يتغير في ملف php.ini أو في وقت التنفيذ. يمكن أن يُضبط ليكون غير محدود لكن يعدّ هذا عمومًا ممارسةً سيئة. يمكن أن يُحدَّد الاستخدام الدقيق للذاكرة أثناء وقت التنفيذ عن طريق استدعاء الدالة memory_get_usage() التي تعيد عدد بايتات الذاكرة المحجوزة للسكربت الحالي المُنفَّذ. بدءًا من الإصدار PHP 5.2 يوجد لهذه الدالة معامل منطقي اختياري للحصول على ذاكرة النظام المحجوزة الكلية على عكس الذاكرة الفعالة التي تستخدمها PHP. <?php echo memory_get_usage() . "\n"; // الخرج 350688 (أو شيء ما مشابه وهذا يعتمد على النظام وإصدار PHP) // لنستهلك جزءًا من الذاكرة RAM $array = array_fill(0, 1000, 'abc'); echo memory_get_usage() . "\n"; // 387704 // حذف المصفوفة من الذاكرة unset($array); echo memory_get_usage() . "\n"; // 350784 تعطيك الآن الدالة memory_get_usage استخدام الذاكرة في الوقت الذي نُفِّذت فيه، قد تخصص وتلغي تخصيص الكثير من الذاكرة بين استدعاءات الدالة المتلاحقة، يمكنك استخدام الدالة memory_get_peak_usage() للحصول على الحجم الأعظمي من الذاكرة المستخدمة حتى نقطة معينة. <?php echo memory_get_peak_usage() . "\n"; // 385688 $array = array_fill(0, 1000, 'abc'); echo memory_get_peak_usage() . "\n"; // 422736 unset($array); echo memory_get_peak_usage() . "\n"; // 422776 لاحظ أنّ القيمة إما سترتفع أو تبقى ثابتة. التحليل باستخدام XHProf XHProf محلل PHP مكتوب من قِبل شركة فيسبوك لتوفير بديل أخف للإضافة XDebug، يمكن تمكين/تعطيل التحليل بعد تثبيت الوحدة xhprof من شيفرة PHP: xhprof_enable(); doSlowOperation(); $profile_data = xhprof_disable(); ستحتوي المصفوفة المُرجعة على بيانات حول عدد الاستدعاءات ووقت المعالج واستخدام الذاكرة لكل دالة تم الوصول إليها من داخل doSlowOperation(). يمكن استخدام الدالة الموالية على أساس خيار أخف لتسجيل معلومات التحليل لجزء من الطلبات فقط (وبصياغة مختلفة). xhprof_sample_enable()/xhprof_sample_disable() ولهذا يستخدم المحلل بعض الدوال المساعدة (معظمها غير موثَّق) لعرض البيانات (اطلع على هذا المثال)، أو يمكنك أاستعمال أدوات أخرى لتصورها (يمكنك الاطلاع على هذا المثال من مدونة platform.sh). ترجمة -وبتصرف- للفصول Unit Testing - Performance من كتاب PHP Notes for Professionals book1 نقطة
-
التشفير وفك التشفير المتناظر لملفات كبيرة باستخدام OpenSSL لا توفر PHP دالة مضمنة لتشفير وفك تشفير الملفات الكبيرة، يمكن استخدام الدالة openssl_encrypt لتشفير السلاسل النصية لكن يعد تحميل ملف كبير جدًا في الذاكرة فكرةً سيئةً، لذا يجب كتابة دالة تقوم بهذا العمل، يستخدم هذا المثال خوارزمية AES-128-CBC المتناظرة لتشفير أجزاء صغيرة من ملف كبير وكتابتها في ملف آخر. تشفير الملفات // (1) define('FILE_ENCRYPTION_BLOCKS', 10000); /** * تشفير الملف الممرر وحفظ النتيجة في ملف جديد باللاحقة ".enc" * * @param string $source مسار الملف الذي نريد تشفيره * @param string $key المفتاح المستخدم للتشفير * @param string $dest اسم الملف الذي نريد أن نكتب فيه الملف المشفَّر * @return string|false * تعيد هذه الدالة اسم الملف المنشأ أو FALSE إذا حدث خطأ */ function encryptFile($source, $key, $dest) { $key = substr(sha1($key, true), 0, 16); $iv = openssl_random_pseudo_bytes(16); $error = false; if ($fpOut = fopen($dest, 'w')) { // ضع شعاع التهيئة في بداية الملف fwrite($fpOut, $iv); if ($fpIn = fopen($source, 'rb')) { while (!feof($fpIn)) { $plaintext = fread($fpIn, 16 * FILE_ENCRYPTION_BLOCKS); $ciphertext = openssl_encrypt($plaintext, 'AES-128-CBC', $key, OPENSSL_RAW_DATA,$iv); // استخدم أول 16 بايت من النص المشفر كشعاع التهيئة التالي $iv = substr($ciphertext, 0, 16); fwrite($fpOut, $ciphertext); } fclose($fpIn); } else { $error = true; } fclose($fpOut); } else { $error = true; } return $error ? false : $dest; } نحدد في الموضع (1) عدد الكتل التي يجب قراءتها من الملف المصدري من أجل كل جزء، بحيث تتألف كل كتلة من 16 بايت من أجل الخوارزمية الآتية: 'AES-128-CBC' لهذا، فإذا قرأنا 10000 كتلة نحمّل 160 كيلوبايت في الذاكرة، يمكنك تعديل هذه القيمة لقراءة/كتابة أجزاء أصغر/أكبر. فك تشفير الملفات يمكنك استخدام هذه الدالة لفك تشفير الملفات المشفرة بالدالة السابقة. /** * فك تشفير الملف الممرر وحفظ النتيجة في ملف جديد مع حذف آخر 4 محارف من اسم الملف * @param string $source مسار الملف الذي نريد فك تشفيره * @param string $key المفتاح المستخدم لفك التشفير (ويجب أن يكون نفس المفتاح المستخدم للتشفير) * @param string $dest اسم الملف حيث يجب أن نكتب الملف الجديد بعد فك التشفير * @return string|false * تعيد هذه الدالة اسم الملف المنشأ أو FALSE إذا حدث خطأ */ function decryptFile($source, $key, $dest) { $key = substr(sha1($key, true), 0, 16); $error = false; if ($fpOut = fopen($dest, 'w')) { if ($fpIn = fopen($source, 'rb')) { // الحصول على شعاع التهيئة من بداية الملف $iv = fread($fpIn, 16); while (!feof($fpIn)) { $ciphertext = fread($fpIn, 16 * (FILE_ENCRYPTION_BLOCKS + 1)); // يجب أن نقرأ كتلة واحدة زيادة عن التشفير لفك التشفير $plaintext = openssl_decrypt($ciphertext, 'AES-128-CBC', $key, OPENSSL_RAW_DATA,$iv); // استخدم أول 16 بايت من النص المشفر كشعاع التهيئة التالي $iv = substr($ciphertext, 0, 16); fwrite($fpOut, $plaintext); } fclose($fpIn); } else { $error = true; } fclose($fpOut); } else { $error = true; } return $error ? false : $dest; } طريقة الاستخدام إليك الشيفرة التالية لتعرف كيفية استخدام الدوال السابقة. $fileName = __DIR__.'/testfile.txt'; $key = 'my secret key'; file_put_contents($fileName, 'Hello World, here I am.'); encryptFile($fileName, $key, $fileName . '.enc'); decryptFile($fileName . '.enc', $key, $fileName . '.dec'); ستنشئ هذه الشيفرة ثلاثة ملفات: testfile.txt وفيه النص الأصلي. testfile.txt.enc فيه الملف المشفر. testfile.txt.dec فيه الملف بعد فك تشفيره ويجب أن يكون نفس محتويات الملف testfile.txt. التشفير المتناظر يوضح هذا المثال التشفير المتناظر باستخدام خوارزمية AES 256 بالنمط CBC وهو اختصار لـ Cipher Block Chaining، نحتاج شعاع تهيئة لذا نولّد واحدًا باستخدام دالة openssl، ويستخدم المتغير $strong لتحديد فيما إذا كان شعاع التهيئة المولَّد قويًا من ناحية التشفير. التشفير // طريقة التشفير $method = "aes-256-cbc"; // الحصول على طول شعاع التهيئة المطلوب $iv_length = openssl_cipher_iv_length($method); // ضبط للقيمة false من أجل السطر التالي $strong = false; // توليد شعاع التهيئة $iv = openssl_random_pseudo_bytes($iv_length, $strong); /* يحتاج شعاع التهيئة للاسترجاع لاحقًا لذا خزنه في قاعدة البيانات لكن لا تعيد استخدام نفس شعاع التهيئة لتشفير بيانات مرةً أخرى */ if(!$strong) { // رمي استثناء إذا لم يكن شعاع التهيئة قويًا من ناحية التشفير throw new Exception("IV not cryptographically strong!"); } // الرسالة السرية $data = "This is a message to be secured."; // كلمة المرور $pass = "Stack0verfl0w"; /* يجب أن تُرسل كلمة المرور بالطريقة POST عبر جلسة HTTPS، قمنا بتخزينها في متغير هنا لأغراض توضيحية * */ // التشفير $enc_data = openssl_encrypt($data, $method, $password, true, $iv); فك التشفير // استعادة شعاع التهيئة من قاعدة البيانات وكلمة المرور من الطلب POST // فك التشفير $dec_data = openssl_decrypt($enc_data, $method, $pass, true, $iv); التشفير وفك التشفير بالأساس 64 إذا كانت البيانات المشفرة تحتاج للإرسال أو التخزين في نص قابل للطباعة عندها يمكن استخدام الدالتين ()base64_encode، و ()base64_decode على الترتيب. // تشفير الترميز بالأساس 64 $enc_data = base64_encode(openssl_encrypt($data, $method, $password, true, $iv)); // فك الترميز وفك التشفير $dec_data = openssl_decrypt(base64_decode($enc_data), $method, $password, true, $iv); دوال تعمية كلمة المرور بما أنّ خدمات الويب الأكثر أمنًا تتجنب تخزين كلمات المرور بصياغة نص واضح فإنّ بعض اللغات مثل PHP توفر دوال تعميةصعبة الاستخراج hashing، ومتنوعة لدعم معيار الصناعة الأكثر أمنًا. يوفر هذا المثال توثيقًا لعمليات التعمية المناسب باستخدام PHP. إنشاء كلمة مرور معماة ننشئ نسخة معماة لكلمة المرور باستخدام الدالة password_hash() لاستخدام تعمية معيارية بأفضل ممارسة للصناعة الحالية أو لاشتقاق المفتاح، في وقت كتابة هذا النص المعيار هو bcrypt مما يعني أنّ PASSWORD_DEFAULT له نفس قيمة PASSWORD_BCRYPT. $options = [ 'cost' => 12, ]; $hashedPassword = password_hash($plaintextPassword, PASSWORD_DEFAULT, $options); المعامل الثالث ليس إجباريًا. يجب أن نختار القيمة 'cost' بالاعتماد على تجهيزات خادم الإنتاج، ستجعل زيادتها كلمة المرور أكثر تكلفةً عند توليدها، كلما زادت تكلفة استخراج وفك الكلمة المعماة، استغرق الأمر وقتًا أطول عند محاولة شخص ما استخراجها؛ ومثاليًا يجب أن تكون التكلفة أعلى ما يمكن لكن من الناحية العملية يجب ضبطها بحيث لا تؤدي إلى بطء شديد في كل شيء، من المناسب أن تكون بين 0.1 و0.4 ثانية، إذا كنت محتارًا استخدم القيمة الافتراضية. في الإصدارات السابقة للإصدار 5.5، الدوال password_* غير متوفرة، يجب أن تستخدم حزمة التوافق للحصول على بديل لهذه الدوال، لاحظ أنّ حزمة التوافق تتطلب الإصدار PHP 5.3.7 أو أعلى أو إصدار يحتوي على التصحيح $2y (مثل ريدهات). إذا لم تكن قادرًا على استخدامها فيمكنك تنفيذ عملية تعمية على كلمة المرور باستخدام الدالة crypt()، وبما أنّ password_hash() تُنفَّذ كغلاف حول الدالة crypt() فلن تحتاج لفقدان أي وظيفة. المثال التالي هو تنفيذ بسيط للتعمية بالمعيار bcrypt والتوافق مع password_hash() ومن غير المضمون أن يحافظ على نفس قوة تشفير التنفيذ الكامل للدالة password_hash(). إضافة غُفْل في عملية تعمية كلمة المرور على الرغم من موثوقية خوارزمية التشفير إلا أنّه ما يزال يوجد ثغرة تستهدف جداول قوس قزح ولذا ينصح باستخدام غُفْل salt، والغفل بالعربية هو شيء ما يُضاف لكلمة المرور قبل تعميتها لجعل السلسلة النصية المصدر فريدة (انظر كتاب «علم التعمية واستخراج المعمى عند العرب»)، بالنظر إلى كلمتي مرور متطابقتين فإنّ نتيجة التعمية لهما ستكون فريدة أيضًا لأن الأغْفَال المضافة إليها فريدة. يعد إضافة الأغفال العشوائية أحد أهم أجزاء أمان كلمة المرور الخاصة بك، وهذا يعني أنّه حتى مع جدول البحث lookup table لكلمات المرورة المعماة المعروفة فإنّ المهاجم لن يتمكن من مطابقة كلمة المرور المعماة الخاصة بالمستخدم مع كلمة المرور المعماة في قاعدة البيانات بسبب استخدام أغفال مختلفة، يجب أن تستخدم دائمًا أغفال عشوائية وقوية من ناحية التشفير اقرأ المزيد. باستخدام خوارزمية bcrypt ودالة password_hash() تُخزَّن أغفال النص الأصلي وأغفال النص المعمى الناتج مما يعني أنّه يمكن نقل النص المعمى عبر أنظمة ومنصات مختلفة وستبقى متطابقة مع كلمة المرور الأصلية. في الإصدارات السابقة للإصدار 7.0 يمكنك استخدام الخيار salt لتعريف الأغفال العشوائية الخاصة بك على الرغم من عدم التشجيع على هذا الإجراء. $options = [ 'salt' => $salt, ]; ملاحظة: إذا أهملت هذا الخيار ستولّد الدالة password_hash() غُفْلًا عشوائيًا لكل كلمة مرور مقطعة. بدءًا من الإصدار PHP 7.0.0 أُهمل خيار إضافة الغُفْل ومن المفضل الآن استخدام الغُفْل المولّد افتراضيًا. ترقية كلمة مرور معماة موجودة إلى خوارزمية أقوى إذا كنت تستخدم طريقة PASSWORD_DEFAULT لتجعل النظام يختار الخوارزمية الأفضل لتعمية كلمات المرور بها، مع زيادة قوة الخوارزمية الافتراضية قد ترغب في إعادة تعمية كلمات المرور القديمة عندما يسجل المستخدمون الدخول. <?php // حدد أولًا إذا كانت كلمة المرور الموفرة صحيحة if (password_verify($plaintextPassword, $hashedPassword)) { // حدد الآن إذا كانت النسخة المعماة الموجود قد أُنشئت بخوارزمية لم تعد افتراضية بعد الآن if (password_needs_rehash($hashedPassword, PASSWORD_DEFAULT)) { // أنشئ كلمة معماة جديدة مع الخوارزمية الافتراضية الجديدة $newHashedPassword = password_hash($plaintextPassword, PASSWORD_DEFAULT); // ثم احفظه في مخزن بياناتك // $db->update(...); } } ?> إذا لم تكن الدوال password_* متوفرةً في نظامك ولا تستطيع استخدام حزمة التوافق، فعندها يمكنك تحديد الخوارزمية واستخدامها لإنشاء التعمية الأصلية بطريقة مشابهة للتالي: <?php if (substr($hashedPassword, 0, 4) == '$2y$' && strlen($hashedPassword) == 60) { echo 'Algorithm is Bcrypt'; // يحدد "cost" مدى قوة إصدار Bcrypt preg_match('/\$2y\$(\d+)\$/', $hashedPassword, $matches); $cost = $matches[1]; echo 'Bcrypt cost is '.$cost; } ?> التحقق من كلمة المرور مقابل كلمة معماة توفر الدالة password_verify() المدمجة بدءًا من الإصدار PHP 5.5، إمكانية التحقق من صحة كلمة مرور مقابل كلمة معماة مقابلة لها، أو غير مقابلة. <?php if (password_verify($plaintextPassword, $hashedPassword)) { echo 'Valid Password'; } else { echo 'Invalid Password.'; } ?> تخزن كل خوارزميات عملية التعمية المدعومة معلومات تحدد آلية التعمية المستخدمة، لذا لا حاجة للإشارة إلى الخوارزمية المستخدمة لتعمية كلمة المرور الأصلية. إذا لم تكن الدوال password_* متوفرةً في نظامك ولا تستطيع استخدام حزمة التوافق، فيمكنك التحقق من كلمة المرور باستخدام الدالة crypt()، لاحظ أنه يجب اتخاذ احتياطات محددة لتجنب هجمات التوقيت. <?php // غير مضمون أن يحافظ على نفس قوة تشفير تنفيذ password_hash() الكامل if (CRYPT_BLOWFISH == 1) { // تتجاهل crypt() كل المحارف التي تتجاوز طول الغفل، لذا يمكننا تمرير ?كامل كلمة المرور المعماة $hashedCheck = crypt($plaintextPassword, $hashedPassword); // هذه موازنة وقت ثابت أساسية تعتمد على التنفيذ الكامل المستخدم في `password_hash()` $status = 0; for ($i=0; $i<strlen($hashedCheck); $i++) { $status |= (ord($hashedCheck[$i]) ^ ord($hashedPassword[$i])); } if ($status === 0) { echo 'Valid Password'; } else { echo 'Invalid Password'; } } ?> ترجمة -وبتصرف- للفصول Cryptography - Password Hashing Functions من كتاب PHP Notes for Professionals book1 نقطة
-
يُعَدّ Docker حاويةً شائعة جدًا تُستخدم على نطاقٍ واسع كحلّ لنشر الشيفرة في بيئات الإنتاج، كما أنها تسهّل إدارة وتوسيع تطبيقات الويب والخدمات الصغيرة. الحصول على صورة دوكر من أجل php لنشر التطبيق على دوكر نحتاج أولًا للحصول على الصورة من السجل registry. docker pull php سيوفر لك هذا أحدث إصدار للصورة من مستودع php الرسمي، تُستخدم php بشكلٍ عام لنشر تطبيقات الويب لذا نحتاج إلى خادم http ليتوافق مع الصورة. تأتي الصورة في الإصدار php:7.0 (أو إصدار أحدث) مُثبّتة مسبقًا مع apache لتنشر تطبيقك بدون مشاكل. كتابة dockerfile يُستخدم Dockerfile لضبط الصورة المخصصة التي سننشئها مع شيفرات تطبيق الويب، ننشئ ملف جديد Dockerfile في المجلد الجذر للمشروع ونضع فيه المحتويات التالية: FROM php:7.0-apache COPY /etc/php/php.ini /usr/local/etc/php/ COPY . /var/www/html/ EXPOSE 80 يستخدم السطر الأول لوصف الصورة التي يجب استخدامها لإنشاء صورة جديدة، يمكن تغيير هذا إلى أي إصدار PHP آخر محدد من السجل، والسطر الثاني لتحميل ملف php.ini إلى الصورة ويمكنك تغيير هذا الملف إلى موقع ملف مخصص آخر، وينسخ السطر الثالث الشيفرات في المجلد الحالي إلى /var/www/html والذي هو webroot بالنسبة لنا، تذكر أن /var/www/html داخل الصورة، أما السطر الأخير فسيفتح المنفذ 80 داخل حاوية دوكر. قد يكون لديك في بعض الحالات بعض الملفات التي لا تريدها على الخادم مثل ملف إعدادات البيئة، بفرض أنّ إعدادات البيئة موجودة لدينا في ملف .env ونريد تجاهله عندها نضيفه إلى .dockerignore في المجلد الجذر لشيفرتنا. بناء الصورة إنّ بناء الصورة شيء غير محدد في php، لكن لبناء الصورة التي تحدثنا عنها في الأعلى نستخدم مايلي: docker build -t <Image name> . يمكننا التحقق من بناء الصورة باستخدام: docker images سيعطيك هذا الأمر كل الصور المثبتة في نظامك. بدء حاوية التطبيق يمكننا البدء بتقديم الخدمة بمجرد أن تصبح الصورة جاهزة، نستخدم ما يلي لإنشاء حاوية من الصورة: docker run -p 80:80 -d <Image name> ستوجّه -p 80:80 في الأمر السابق المنفذ 80 الخاص بخادمك إلى المنفذ 80 الخاص بالحاوية، وستخبر الراية -d أنّه يجب تنفيذ الحاوية في الخلفية وتصف <Image name> الصورة التي يجب استخدامها لبناء الحاوية. التحقق من الحاوية نستخدم ما يلي للتحقق من الحاويات قيد التنفيذ: docker ps سيعطينا هذا الأمر قائمة بكل الحاويات التي تُنفَّذ. سجلات التطبيق تعدّ السجلات مهمة جدًا لتنقيح أخطاء التطبيق، وللتحقق منها نستخدم الأمر: docker logs <Container id> مخزن APCu APCu هو مخزن قيمة-مفتاح للذاكرة المشتركة في PHP، تُشارك الذاكرة بين عملياتPHP-FPM (أي Fast Process Manager) في نفس المجمع pool وتستمر البيانات المخزنة بين العمليات. تكرار محتويات المداخل يسمح الصنف APCUIterator بتكرار محتويات المداخل في المخزن المؤقت cache: foreach (new APCUIterator() as $entry) { print_r($entry); } يمكن تهيئة المكرِّر بتعبير نمطي اختياري لاختيار المداخل المتطابقة مع المفاتيح فقط: foreach (new APCUIterator($regex) as $entry) { print_r($entry); } يمكن الحصول على معلومات مدخل ذاكرة مؤقتة واحدة بالشكل التالي: $key = '…'; $regex = '(^' . preg_quote($key) . '$)'; print_r((new APCUIterator($regex))->current()); تخزين واسترجاع بسهولة يمكن استخدام apcu_store لتخزين قيم وapcu_fetch لاستعادتها: $key = 'Hello'; $value = 'World'; apcu_store($key, $value); print(apcu_fetch('Hello')); // 'World' تخزين معلومات توفر apcu_cache_info معلومات حول المخزن ومداخله: print_r(apcu_cache_info()); لاحظ أنّ استدعاء apcu_cache_info() بدون حد سيعيد كل البيانات المخزنة حاليًا، ولهذا نستخدم apcu_cache_info(true)، للحصول على البيانات الوصفية فقط، كما أنه من الأفضل استخدام الصنف APCUIterator للحصول على معلومات عن مداخل ذاكرة تخزين مؤقتة محددة. ترجمة -وبتصرف- للفصل Docker deployment - APCu من كتاب PHP Notes for Professionals book1 نقطة
-
خرج الصورة يمكن إنشاء صورة باستخدام دوال image* حيث * هي صيغة الملف، وهذه الدوال لها الصيغة المشتركة التالية: bool image___(resource $im [, mixed $to [ other parameters]] ) الحفظ إلى ملف يمكنك تمرير اسم الملف أو مجرى ملف مفتوح للمتغير $to إذا كنت تريد حفظ الصورة إلى ملف، إذا مررت مجرى فلا تحتاج لإغلاقه لأنّ مكتبة GD تغلقه تلقائيًا، مثلًا لحفظ ملف PNG: imagepng($image, "/path/to/target/file.png"); $stream = fopen("phar://path/to/target.phar/file.png", "wb"); imagepng($image2, $stream); // لا حاجة لإغلاق المجرى تأكد عند استخدام fopen من أنك تستخدم الراية b وليس الراية t لأن الملف هو خرج ثنائي، ولا تحاول أن تمرر fopen("php://temp", $f) أو fopen("php://memory", $f) لأنّ الدالة تُغلق المجرى بعد الاستدعاء ولن تبقى قادرًا على استدعائه أو استخدامه لاسترداد محتوياته مثلًا. الخرج كرد HTTP لا تحتاج إلى تمرير شيء (أو مرر null) كوسيط ثانٍ إذا كنت تريد أن ترجع هذه الصورة مباشرةً كرد للصورة (لإنشاء بطاقات ديناميكية مثلًا)، لكنك تحتاج إلى تحديد نوع المحتوى في رد HTTP: header("Content-Type: $mimeType"); $mimeType هو نوع الصياغة المُرجعة في الترويسة MIME مثل image/png وimage/gif وimage/jpeg. الكتابة إلى متغير يوجد طريقتين للكتابة إلى متغير: استخدام المخزن المؤقت للخرج (OB): ob_start(); // تمرير null للكتابة افتراضيًا في مجرى الخرج القياسي imagepng($image, null, $quality); $binary = ob_get_clean(); استخدام مغلِّف المجرى: قد يكون لديك سبب ما لعدم استخدام المخزن المؤقت للخرج كأن يكون لديك بالفعل مخزن مؤقت قيد التشغيل لذا تحتاج إلى بديل، يمكنك تسجيل مغلَّف مجرى جديد باستخدام الدالة stream_wrapper_register لذا يمكنك تمرير مجرى إلى دالة إظهار الصورة واستعادته لاحقًا. <?php class GlobalStream{ private $var; public function stream_open(string $path){ this->var =& $GLOBALS[parse_url($path)["host"]]; return true; } public function stream_write(string $data){ $this->var .= $data; return strlen($data); } } stream_wrapper_register("global", GlobalStream::class); $image = imagecreatetruecolor(100, 100); imagefill($image, 0, 0, imagecolorallocate($image, 0, 0, 0)); $stream = fopen("global://myImage", ""); imagepng($image, $stream); echo base64_encode($myImage); في هذا المثال يكتب الصنف GlobalStream أي دخل إلى المتغير المرجعي (أي الكتابة بشكل غير مباشر إلى المتغير العام للاسم المعطى)، يمكن استرجاع المتغير العام لاحقًا بشكلٍ مباشر. يجب الانتباه إلى عدة أمور: صنف مغلِّف المجرى المنفَّذ بشكلٍ كامل يجب أن يشبه هذا الصنف لكن وفقًا للاختبارات باستخدام تابع __call السحري فإنّه من الممكن استدعاء stream_open وstream_write وstream_close فقط من الدوال الداخلية. لا توجد رايات مطلوبة في استدعاء fopen لكن يجب أن تمرر سلسلة فارغة على الأقل، لأنّ الدالة fopen تتوقع مثل هذا المعامل، حتى لو لم تستخدمها في تنفيذ stream_open يبقى هذا المعامل مطلوبًا. تستدعى الدالة stream_write عدة مرات وفقًا للاختبارات، تذكر أن تستخدم إسناد الدمج .= وليس إسناد المتغير المباشر =. مثال: في وسم <img> في HTML، يمكن توفير صورة بشكلٍ مباشر بدلًا من استخدام رابط خارجي: echo '<img src="data:image/png;base64,' . base64_encode($binary) . '">'; إنشاء صورة نستخدم الدالة imagecreatetruecolor لإنشاء صورة فارغة: $img = imagecreatetruecolor($width, $height); المتغير $img هو متغير مورد الآن بعرض $width وطول $height بكسل، لاحظ أنّ العرض يُحسب من اليسار إلى اليمين والطول من الأعلى إلى الأسفل. يمكن أن يُنشأ أيضًا مورد الصورة من دوال إنشاء الصورة مثل imagecreatefrompng وimagecreatefromjpeg ودوال imagecreatefrom* أخرى. قد تُحرَّر موارد الصورة لاحقًا عندما لا توجد مراجع إليها، لكن لتحرير الذاكرة بشكلٍ مباشر (قد يكون هذا مهمًا عند معالجة عدة صور كبيرة) يمكننا استخدام imagedestroy() على الصورة عندما لا تبقى حاجة لاستخدامها وتكون هذه ممارسة جيدة. imagedestroy($image); تحويل صورة إنّ الصور التي تُنشأ من تحويل الصور لا تعدّل الصورة حتى تُخرجها، لذا يمكن أن يكون محوِّل الصورة ببساطة عبارة عن ثلاثة أسطر من الشيفرة: function convertJpegToPng(string $filename, string $outputFile) { $im = imagecreatefromjpeg($filename); imagepng($im, $outputFile); imagedestroy($im); } اقتصاص الصورة وتغيير حجمها يمكنك استخدام الدالة imagecopyresampled إذا كان لديك صورة وتريد إنشاء صورة جديدة بأبعاد جديدة، أنشئ أولًا صورة جديدة بالأبعاد المرغوبة: // صورة جديدة $dst_img = imagecreatetruecolor($width, $height); خزّن الصورة الأصلية في متغير، يمكنك القيام بذلك باستخدام إحدى دوال createimagefrom* حيث يمكن أن تكون * هي jpeg أو gif أوpng أوstring، مثال: // الصورة الأصلية $src_img=imagecreatefromstring(file_get_contents($original_image_path)); ثم استخدم الدالة imagecopyresampled لنسخ كل الصورة الأصلية (أو جزء منها) (src_img) إلى الصورة الجديدة (dst_img): imagecopyresampled($dst_img, $src_img, $dst_x ,$dst_y, $src_x, $src_y, $dst_width, $dst_height, $src_width, $src_height); لضبط أبعاد src_* وdst_*، استخدم الصورة التالية: إذا كنت تريد الآن نسخ كامل الصورة المصدر (الأصلية) إلى كامل منطقة الهدف (بدون اقتصاص): $src_x = $src_y = $dst_x = $dst_y = 0; // عرض الصورة الجديدة $dst_width = $width; // طول الصورة الجديدة $dst_height = $height; // عرض الصورة الأصلية $src_width = imagesx($src_img); // طول الصورة الأصلية $src_height = imagesy($src_img); مكتبة Imagick التثبيت باستخدام apt في الأنظمة المعتمدة على Debian: sudo apt-get install php5-imagick باستخدام Homebrew في أنظمة OSX/macOs: brew install imagemagick باستخدام الإصدارات الثنائية: التعليمات في موقع imagemagick. الاستخدام <?php $imagen = new Imagick('imagen.jpg'); // إذا وضعت قيمة المعامل 0 ستتم المحافظة على نسبة العرض $imagen->thumbnailImage(100, 0); echo $imagen; ?> تحويل صورة إلى سلسلة نصية بالأساس 64 يُظهر هذا المثال كيفية تحويل صورة إلى سلسلة نصية بالأساس 64 (أي سلسلة نصية يمكنك استخدامها مباشرةً في السمة src لوسم img)، يستخدم هذا المثال مكتبة Imagick لكن يمكن استخدام مكتبات أخرى مثل GD. <?php // (1) $img = new Imagick('image.jpg'); // (2) $img->resizeImage(320, 240); // (3) $imgBuff = $img->getimageblob(); // (4) $img->clear(); // (5) $img = base64_encode($imgBuff); echo "<img alt='Embedded Image' src='data:image/jpeg;base64,$img' />"; في الموضع (1) يُحمَّل الملف image.jpg للمعالجة، مسار الملف نسبي إلى ملف .php المتضمن هذه الشيفرة لذا في هذا المثال يجب أن يكون ملف image.jpg في نفس مجلد السكربت. في الموضع (2) يتغير حجم الصورة للحجم المُعطى كطول وعرض وإذا أردت تغيير دقة الصورة أيضًا مع تغيير الحجم يمكنك استخدام الدالة $img->resampleimage(320, 240)، لاحظ أنّه يمكنك ضبط المعامل الثاني إلى 0 للمحافظة على نسبة عرض الصورة. في الموضع (3) تُرجع الدالة تمثيل الصورة على شكل سلسلة نصية غير مشفرة. في الموضع (4) يُزال المورد image.jpg من الكائن $img ويُدمَّر الكائن مما يحرر موارد النظام المحجوزة لمعالجة الصورة. في الموضع (5) تُنشأ نسخة بتشفير الأساس 64 من السلسلة النصية السابقة غير المشفرة ثم تُعرَض كصورة في الصفحة، لاحظ أنّه قد يتغير الجزء image/jpeg في السمة src وذلك بالاعتماد على نوع الصورة التي تستخدمها (png أوjpeg مثلًا). ترجمة -وبتصرف- للفصول [Image Processing with GD - Imagick] من كتاب PHP Notes for Professionals book اقرأ أيضًا المقال التالي: مدخل إلى تعلم الآلة (Machine learning) في PHP المقال السابق: اصطلاحات ومواضيع متفرقة مهمة لكل مبرمج PHP1 نقطة
-
يسألني الناس أينما ذهبت - في المؤتمرات، المحاضرات، لدى وكالات تطوير المواقع وغيرها - عن ملف composer.lock. يبدو وكأن الأمر يتعلّق بلغز يزرع الشكوك حول المعمورة! أقدّم لك هذا المقال لتوضيح ماهية هذا الملف وفكّ اللغز الذي يمثّله. يعدّ Composer أداة تدير الإصدارات الخاصة بمكتبات PHP التي يستخدمها المطوّرون في مشاريعهم البرمجية. سأفترض - لأغراض هذا المقال - أنه سبق لك استخدام Composer في مشاريع سابقة. فلنفترض أن لدينا مشروع PHP جديدا ندير اعتماديّاته Dependencies عن طريق Composer. نبدأ بملف composer.json الذي يُستخدَم لإعداد لائحة بالاعتماديّات التي نريد تثبيتها. يبدو الملف على النحو التالي: { "require": { "assassins/ezio": "1.1.0", "assassins/edward": "1.1.2", "templars/shay": "1.1.*", } } عرّفنا بوضوح الإصدارات التي نحتاجها بالنسبة للحزمتين الأولى والثانية؛ إلا أن الأمر مختلف قليلا يالنسبة للحزمة الثالثة templars/shay التي حدّدنا لها بطريقة أكثر مرونة فلم نعرّف إصدار الترقيع Patch version؛ وبالتالي سيكون أي ترقيع للإصدار 1.1 مناسبا للمشروع. تنبغي ملاحظة أن هذه الأسماء المذكورة في الشفرة أعلاه هي أسماء مفترضة لحزم وليست حزما حقيقية يمكن تثبيتها. يمكن القول إن ملف composer.json هو دليل “تقريبي” للإصدارات التي نريد تثبيتها؛ فاستخدام ماسك المكان * يجعل إصدارات عدّة متوافرة لاستخدامها. بمعنى آخر، يحدّد الملف هامشا مقبولا لهرميّة الاعتماديّات في التطبيق. لا يوجد لدينا لحدّ الساعة، أي في بداية المشروع، ملفّ composer.lock؛ إلا أنه سيظهر بعد تنفيذنا للأمر composer install. نجد مباشرة بعد تنفيذ الأمر composer install ملفّا غريبا باسم composer.lock في المجلّد الجذر للمشروع. إن ألقيت نظرة على ما بداخله فستجد أنه كبير نوعا ما. حان الوقت الآن لكشف اللّغز. في الواقع؛ الملف composer.json هو دليل تقريبي - كما قلنا - لإصدارات الاعتماديّات التي يتوجّب على Composer تثبيتها، بينما الملف composer.lock هو تسجيل دقيق بالإصدارات التي ثُبِّتت عند تنفيذ الأمر composer install. أي أنه يسجّل ما ثبّته Composer من مكتبات لمشروعك. في ما يلي مثال بسيط: "source": { "type": "git", "url": "https://github.com/templars/shay.git", "reference": "98c313c831e5d99bb393ba1844df91bab2bb5b8b" }, هل ترى سلسلة المحارف الطويلةَ تلك؟ هذا هو المعرّف الدقيق لإيداع Commit الإصدار المثبّت عندما اتّبع Composer تعليمات composer.json. يحتفظ الملف composer.lock كذلك بجميع إصدارات الاعتماديّات التي تتطلّبها اعتماديّات المشروع؛ والمكتبات التي تقوم عليها اعتماديّات اعتمديّات المشروع.. وهكذا دواليك. يعني هذا أن الملف composer.lock يحوي التسلسل الهرمي الكامل لاعتماديّات التطبيق. في ماذا يفيد وجود التسلسل الهرمي لاعتماديّات المشروع في الملف composer.lock؟ حسنا؛ يمكن أن تجرّب حذف المجلّد الذي توجد به اعتماديّات المشروع، مثلا vendor في Laravel؛ ثم تنفيذ الأمر composer install من جديد. سيجد Composer هذه المرة أن لديك ملفّ composer.lock وبدلا من البحث عن إصدارات متوافقة مع تعليمات الملف composer.jsonفسيلجأ إلى الإصدارات الدقيقة المذكورة في الملف composer.lock ويثبّتها. يعني هذا أننا سنحصُل على نفس المكتبات التي حذفناها بحذف مجلّد الاعتماديّات. سؤال آخر.. هل يجب تضمين الملف composer.lock في مستودع Git؟ يجب أن تكون الإجابة الآن واضحة. إن أردت تسجيل الإصدارات الدقيقة للاعتماديّات التي استخدمتها في المشروع فالإجابة هي نعم؛ وهذا هو الواقع في أغلب المشاريع. إن كنت تعمل ضمن فريق مطوّرين فإن جعل الملف composer.lock في المستودع يضمن أن الجميع يستخدم نفس الإصدارات؛ الأمر الذي يمكن أن يكون مفيدا في تنقيح Debugging الأخطاء التي تظهر لدى مطوّر واحد فقط من الفريق. إن كنت توزّع تطبيقك عبر Git فإن تضمين الملف composer.lock في المستودع سيضمن أن إصدارات الاعتماديّات التي استخدمتها في التطوير وأجريت عليها الاختبارات هي نفسها المستخدمة في بيئة الإنتاج. لماذا من المهم استخدام نفس إصدارات الاعتماديّات؟ فلنفترض أن Git يتجاهل وجود الملف composer.lock. تنفّذ الأمر composer install، يبحث Composer عن آخر ترقيع للإصدار 1.1 من الحزمة templars/shay فيجد الإصدار 1.1.4 ويثبّته. تعمل على المشروع باستخدام الإصدار 1.1.4، وفي هذه الأثناء يقدّم فريق الحزمة templars/shay الإصدار 1.1.5 الذي - لسوء الحظ - يتضمّن علة برمجيّة Bug حرجة. عندما تنشُر مشروعك على بيئة الإنتاج يثبّت Composer - بالاعتماد على تعليمات الملف composer.json - الإصدار 1.1.5 من الحزمة الذي يحوي علّة تمنع تطبيقك من العمل على النحو الذي تريده. يمكنك استنتاج أنه لو كان الملف composer.json في المستودع لأدّى تنفيذ الأمر composer install في بيئة الإنتاج إلى تثبيت الإصدار 1.1.4 من الحزمة templars/shay الذي سبق لك اختبار التطبيق معه. باختصار: في الأخير.. متى يتغيّر الملف composer.lock ولأي سبب؟ أرى طوال الوقت مطورين ينفّذون الأمر composer update كلّما حدّثوا الملف composer.json، للحصول على الحزم الجديدة التي أضافوها إلى الملف. في الواقع هذا الأمر خاطئ! يجب أن تستخدم الأمر composer install بدلا من ذلك، إذ أنه يثبّت الحزم الجديدة دون تحديث إصدارات الحزم الأخرى؛ هذه الطريقة آمن كثيرا. في ما يلي لائحة بإجراءات تتسبّب في تحديث الملف composer.lock: تنفيذ الأمر composer install للمرة الأولى. يُنشَأ الملف composer.lock لتسجيل الإصدارات الدقيقة للاعتماديّات المثبّتة. تنفيذ الأمر composer install بعد إضافة حزم جديدة. يُضاف الإصدار الدقيق للحزمة إلى الملف composer.lock. تنفيذ الأمر composer update. تُحدَّث إصدارات جميع الحزم إلى الترقيع الأخير بما يتوافق مع تعليمات الملف composer.json، وهو ما ينتُج عنه تحديث الإصدارات الدقيقة في الملف composer.lock. تنفيذ الأمر composer update package/name لتحديث الحزمة المذكورة إلى آخر ترقيع، بما يتوافق مع تعليمات الملف composer.json، وبالتالي يُحدَّث الملف composer.lock ليعكس التغيير الحاصل في إصدار الحزمة. يعني ما سبق أن composer install أمر “آمن”، ولن ينتُج عنه سوى إضافة حزم جديدة إلى الملف composer.lock (وليس تحديث حزم موجودة مسبقا). في حين أن الأمر composer update أمر “خطِر”، إذ أنه يتسبّب في تغيير مباشر على الإصدارات الدقيقة الموجودة في الملف composer.lock . أرجو أن يكون الملف اللغز composer.lock قد اتّضح لك بعد قراءة هذا المقال. إن كنت تعلّمت شيئا أو اثنين من هذا المقال فأرجو أن تشاركه مع أصدقائك حتى يعرفوا هم أيضا سر الملف العظيم. ترجمة - بتصرّف - للمقال PHP: The Composer Lock File لصاحبه Dayle Rees. حقوق خلفية الصورة البارزة محفوظة لـ Freepik1 نقطة
-
شهد مجال تطوير الوِب في السنوات الأخيرة تطورات هائلة على جميع المستويات والذي أدى إلى تحسنيات كبيرة على مستوى السرعة والجودة وقابلية الصيانة. ليس ذلك فحسب بل تعدى الأمر إلى إمكانية أتمتة بعض المهام الروتينية والتركيز على جودة العمل المُسلم ورفع الإنتاجية وذلك باستخدام أدوات مساعدة مثل Webpack، والتي تعدّ من أشهر الأدوات المساعدة بل إنها أصبحت عنصرًا أساسيًا في أي مشروع يُبنى بلغة جافاسكربت. حدثت بعض هذه التطورات على صعيد تطوير الواجهات الخلفية (Back-end) مثل ظهور Node.js والّتي تستخدم استخدامًا كبيرًا في هذه الأيام، وبعضها الآخر كان في تطوير الواجهات الأمامية (front-end)، ومن أبرز هذه التطورات هي النقلة النوعية للغة جافاسكربت ودعمها للعديد من المميزات والخصائص، والتي أدت في نهاية المطاف لجعلها واحدةً من أبرز الخيارات القوية في برمجة الوِب. بل وحتى إنها احتلت المرتبة الأولى في ترتيب أشهر لغات البرمجة شعبية لعام 2019 وذلك بحسب إحصائية موقع Stackoverflow. وكما أعلنت شركة Web3Techs أن لغة جافاسكربت مُستخدمة من قِبل حوالي 95% من مواقع العالم قاطبةً، وهي أيضًا على رأس قائمة "أكثر لغة مشهورة في برمجة الواجهات الأمامية" بحسب نفس الشركة. ولكن كيف جرت هذه التحولات السريعة والقوية بنفس الوقت لهذه اللغة؟ وما هي المراحل الأساسية الّتي مرت بها؟ وما هي الأدوات المختلفة الّتي ظهرت بالتزامن مع تطور هذه اللغة؟ وما هي أدوات البناء (مثل Gulp)؟ وما هو مجمع الوحدات (مثل Webpack)؟ ولماذا ظهر؟ وما هي مميزاته؟ سنحاول في هذا الدليل مرافقتكم في رحلة استكشافية للإجابة على هذه الأسئلة، ولنستعرض فيها أيضًا التاريخ العريق لهذه اللغة، ومعرفة الاسباب الرئيسية لتطورها وكيف احتلت بهذه السرعة المكانة العالية الّتي هي عليها اليوم. فهل أنت مستعد لمشاركتنا في هذه الرحلة؟ لمحة تاريخية بالعودة إلى زمن ما قبل الأدوات الحديثة كيف كان الحال آنذاك؟ في الحقيقة كانت الأمور بسيطة وسهلةً جدًا. سنبدأ رحلتنا بالتعرف على طرق استخدام لغة جافاسكربت في ملفات HTML. طرق استخدام لغة جافاسكربت يوجد طرقٌ عديدة يمكننا لتضمين الشيفرات البرمجية للغة جافاسكربت في ملفات HTML، يعتمد اختيارنا للطريقة بحسب حجم المشروع الّذي سنعمل عليه وسنذكر أهم الطرق المستخدمة من البداية وحتى يومنا الحالي. الشيفرة السطرية بدأت لغة جافاسكربت في كتابة شيفرتها البرمجية بهذه الطريقة البسيطة إذ أن الشيفرة البرمجية مكتوبة مباشرة في ملف HTML داخل وسم <script>. لا بدّ بأن معظمنا كتبَ شيفرة برمجية بهذه الطريقة في بداية تعلمه لهذه اللغة وذلك من كونها أسهل الطرق لتطبيق شيفرة برمجية معينة. في المثال التالي يحتوي الملف index.html على شيفرة جافاسكربت سطرية: <html> <head> <meta charset="UTF-8"> <title>Inline Example</title> </head> <body> <h1> The Answer is <span id="answer"></span> </h1> <script type="text/javascript"> function add(a, b) { return a + b; } function reduce(arr, iteratee) { var index = 0, length = arr.length, memo = arr[index]; for(index += 1; index < length; index += 1){ memo = iteratee(memo, arr[index]) } return memo; } function sum(arr){ return reduce(arr, add); } /* Main Function */ var values = [ 1, 2, 4, 5, 6, 7, 8, 9 ]; var answer = sum(values) document.getElementById("answer").innerHTML = answer; </script> </body> </html> هذه الطريقة جيدة جدًا للبدء إذ لا يوجد أي ملفات خارجية أو تبعية ناشئة بين الملفات، ولكن هذه هي الطريقة المثالية لبناء شيفرة برمجية غير قابلة للصيانة وذلك بسبب المشاكل التالية: عدم إمكانية إعادة استخدام الشيفرة البرمجية: فإذا احتجنا إلى إضافة صفحة أخرى وهذه الصفحة تحتاج إلى بعض الوظائف المحققة في الشيفرة البرمجية الّتي كتبناها سابقًا في الملف السابق فيجب علينا حينها نسخ الشيفرة البرمجية المطلوبة ولصقها في الصفحة المراد تحقيق الوظائف فيها. عدم وجود ثبات في التبعية بين الشيفرة البرمجية: أنت مسؤول عن تنسيق التبعية بين الدوال المستخدمة على سبيل المثال إن كان هنالك دالة معينة تعتمد في وظيفتها على نتيجة دالة أخرى محققة قبلها فيجب علينا حينها الانتباه لهذا الأمر وعدم تغيير ترتيب تواجد الدوال في الشيفرة البرمجية. التضارب في المتغيرات العامة (Global Variables): جميع الدوال والمتغيرات ستكون موجودة على نطاق عام (Global Scope) وهذا بدوره سيؤدي إلى تضارب في المتحولات، ويحدث هذا عند ازدياد ضخامة المشروع وكتابة شيفرة برمجية كبيرة مما يجعل إمكانية إعادة استخدام نفس أسماء المتحولات أمر وارد الحدوث بقوة، وخصيصًا إن كان هنالك أكثر من مبرمج يعمل على نفس المشروع. استخدام الملفات الخارجية الطريقة الأخرى المستخدمة في كتابة الشيفرة البرمجية للغة جافاسكربت هي استخدام ملفات منفصلة إذ سنجزّء الشيفرة البرمجية إلى أجزاء صغيرة ونحملها تباعًا في ملف index.html. وبهذه الطريقة يمكننا استدعاء مكتبات منفصلة والّتي تقدم لنا وظائف إضافية مثل مكتبة moment (والتي تتيح لنا التلاعب بالتواريخ وإمكانية إجراء تحويلات معينة من نمط تاريخٍ معين إلى نمطٍ آخر). وبالإضافة إلى ذلك أدى استخدام الملفات المنفصلة في الشيفرة البرمجية إلى إتاحة الفرصة لنا بإعادة استخدام الشيفرة البرمجية أكثر من مرة ومن أي مكان نريد، وبذلك نكون تخلصنا من فكرة نسخ الشيفرة البرمجية من مكان ما ولصقها في مكان آخر متى ما أردنا استخدام هذه الشيفرة. الملف index.html هو الملف الّذي سيستدعي جميع التبعيات (ملفات جافاسكربت) الّتي سيحتاجها ويكون محتواه على الشكل التالي: <html> <head> <meta charset="UTF-8"> <title>External File Example</title> <!-- الملف الرئيسي الّذي سيستدعي ملفات جافاسكربت --> </head> <body> <h1> The Answer is <span id="answer"></span> </h1> <script type="text/javascript" src="./add.js"></script> <script type="text/javascript" src="./reduce.js"></script> <script type="text/javascript" src="./sum.js"></script> <script type="text/javascript" src="./main.js"></script> </body> </html> إن هذا المثال يجمع عناصر المصفوفة الموجودة في الملف main.js ويظهرها في صفحة index.html ويكون محتوى الملفات على الشكل التالي: الملف add.js: function add(a, b) { return a + b; } الملف reduce.js function reduce(arr, iteratee) { var index = 0, length = arr.length, memo = arr[index]; index += 1; for(; index < length; index += 1){ memo = iteratee(memo, arr[index]) } return memo; } الملف sum.js function sum(arr){ return reduce(arr, add); } الملف main.js var values = [ 1, 2, 4, 5, 6, 7, 8, 9 ]; var answer = sum(values) document.getElementById("answer").innerHTML = answer; ولكن هذا الحل لم يكُ مثاليًا بل واجه المشاكل التالية: عدم وجود ثبات في التبعية بين الشيفرة البرمجية. التضارب في المتغيرات العامة مازالت موجودة. تحديث المكتبات أو الملفات المستدعاة سيكون يدويًا في حال ظهور نسخة جديدة للمكتبة (أو الملف). زيادة عدد طلبات HTTP بين المخدم والعميل: يؤدي زيادة الملفات المتضمنة في إلى زيادة الحمل على المخدم. فعلى سبيل المثال في الشيفرة السابقة سيحتاج كلّ ملف من الملفات الأربع طلب HTTP منفصل (أي أربع رحلات ذهاب وعودة من المخدم وإلى جهاز العميل) وبناءً عليه سيكون من الأفضل لو استخدمنا ملفًا واحدًا بدلًا من أربع ملفات منفصلة. كما في المثال التالي: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>External File Example</title> <!-- الملف الرئيسي الّذي سيستدعي ملفات جافاسكربت --> </head> <body> <h1> The Answer is <span id="answer"></span> </h1> <script src="/dist/bundle.js"></script> </body> </html> استخدام كائن الوحدات (Module Object) ونمط الوحدات (Module Pattern) باستخدام نمط الوحدات (والذي تحدثنا عنه في مقال مفصّل) يمكننا أن نقلل التضارب في المتغيّرات العامة. إذ إننا سنكشف عن كائن واحد للمجال العام (Global Scope) وهذا الكائن سيحتوي على كافة الدوال والقيم الّتي سنحتاج إليها في تطبيق الوِب خاصتنا. في المثال التالي سنكشف عن كائن واحد وهو myApp للمجال العام (Global Scope)، وكلّ الدوال ستكون متاحة عن طريق هذا الكائن. والمثال التالي سيُوضح الفكرة: الملف my-app.js: var myApp = {}; الملف add.js: (function(){ myApp.add = function(a, b) { return a + b; } })(); الملف reduce.js: (function () { myApp.reduce = function (arr, iteratee) { var index = 0, length = arr.length, memo = arr[index]; index += 1; for (; index < length; index += 1) { memo = iteratee(memo, arr[index]) } return memo; } })(); الملف sum.js: (function () { myApp.sum = function (arr) { return myApp.reduce(arr, myUtil.add); } })(); الملف main.js: (function (app) { var values = [1, 2, 4, 5, 6, 7, 8, 9]; var answer = app.sum(values) document.getElementById("answer").innerHTML = answer; })(myApp); الملف index.html: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>JS Modules</title> </head> <body> <h1> The Answer is <span id="answer"></span> </h1> <script type="text/javascript" src="./my-app.js"></script> <script type="text/javascript" src="./add.js"></script> <script type="text/javascript" src="./reduce.js"></script> <script type="text/javascript" src="./sum.js"></script> <script type="text/javascript" src="./main.js"></script> </body> </html> لاحظ أن كلّ ملف من الملفات غُلّف بطريقة نمط الوحدات ما عدا my-app.js إذ أن طريقة التغليف العامة المتبعة في نمط الوحدات هي على الشكل التالي: (function(){ /*... your code goes here ...*/ })(); بهذه الطريقة نجد أن كلّ المتحولات المحلية ستبقى ضمن مجال الدالة المستخدمة فيه. وبذلك لن يكون هنالك أي احتمالية لحدوث تضارب في المتغيرات العامة. وهكذا نكون حللنا مشكلة التضارب في المتغيرات العامة. سيكون الوصول إلى الدوال المعرفة في الملفات مثل (add و reduce ..إلخ) عن طريق ربط اسم الدالة مع الكائن myApp كما في المثال التالي: myApp.add(1,2); myApp.sum([1,2,3,4]); myApp.reduce(add, value); كما يمكننا أيضًا تمرير الكائن myApp كوسيط مثل ما فعلنا في ملف main.js وذلك من أجل تصغير أسم الكائن وجعل الشيفرة البرمجية أصغر حجمًا. تعدّ هذه الطريقة تحسنًا ممتازًا بالموازنة مع المثال السابق وفي الحقيقة إن أشهر مكتبات جافاسكربت مثل jQuery تستخدم هذه الطريقة؛ إذ أنها فقط تكشف عن متغير عام وهو $ وكل التوابع تُستدعى عن طريق هذا الكائن. في الحقيقة إننا إلى هذه اللحظة لم نصل إلى الحل النهائي إذ أن الحل السابق لا يزال يعاني من بعض المشاكل مثل: عدم وجود ثبات في التبعية بين الشيفرة البرمجية: نلاحظ في ملف index.html الملفات لا تزال بحاجة إلى وضعها وفق ترتيب معين يحافظ على التبعية بين الملفات إذ أن الملف myApp.js يجب أن يأتي قبل أي ملف وملف main.js يجب أن يأتي بعد كلّ الملفات. التضارب في المتغيّرات العامة: صحيح أننا قللنا عدد المتغيّرات العامة إلى الواحد ولكنها لا تزال موجودة. تحديث المكتبات: إن تحديث المكتبات (أو التبعيات أو أي ملف عمومًا) المستدعاة سيكون يدويًا في حال ظهور نسخة جديدة للمكتبة أو للتبعية. زيادة عدد طلبات HTTP بين الخادم والعميل: وذلك بعد زيادة عدد الملفات المستدعاة في ملف index.html. ظهور CommonJS جرت نقاشات عديدة في عام 2009 حول إمكانية جلب لغة جافاسكربت إلى الواجهات الخلفية (استخدامها من جانب الخادم) وفعلًا كان ذلك على يد مهندسٍ شاب يعمل لدى شركة موزيلا ويُدعى كيفن دانجور (Kevin Dangoor). قدمت CommonJS طريقة لتعريف الوحدات لحل مشكلة المجال في جافاسكربت من خلال التأكد من تنفيذ كلّ وحدة في فضاء الأسماء (namespace) الخاص بها وذلك بإجبار الوحدات على تصدير تلك المتغيّرات صراحةً (الذين نريد عرضهم واستخدامهم في المجال العام) وأيضًا تعريف تلك الوحدات المطلوبة للعمل بالشكل الصحيح مع بعضها بعضًا. بالإضافة إلى ذلك قدمت CommonJS واجهة برمجية مخصصة للجافاسكربت هذه المميزات فتحت أبصار العالم لإمكانيات هذه اللغة العظيمة، وجذبت اهتمام كبير من المطورين والذي انعكس في سرعة تطورها وتأقلمها مع جميع التغيّرات والمشاكل الّتي واجهتها. إن CommonJS ليست مكتبة جافاسكربت وإنما هي معايير تنظيمية لكتابة الشيفرة البرمجية (على سبيل المثال الطريقة الّتي خصصتها لاستيراد الوحدات استيرادً منظمًا) وهذه المعايير شبيه بالّتي تطرحها منظمة ECMA (European Computer Manufacturers Association). ولتحقيق التنظيم في طريقة استدعاء الوحدات تقدم لنا CommonJS الدوال والأغراض المساعدة لذلك وهي: دالة require(): والّتي تسمح لنا باستيراد وحدات معينة في المجال المحلي الّذي نكون فيه. كائن الوحدة module.exports: والذي يسمح لنا بتصدير دالة ما من المجال الحالي إلى الوحدة. ولنأخذ مثلًا بسيطًا عن كيفية استخدام CommonJS: الملف moduleA.js: module.exports = function( value ){ return value*2; } الملف moduleB.js: var multiplyBy2 = require('./moduleA'); var result = multiplyBy2( 4 ); لاحظ أننا لم نستخدم الاسم الكامل للملف moduleA.js وإنما حذفنا اللاحقة، كما أن /. تشير إلى أن الوحدة moduleA موجودة في نفس المجلد الموجود فيه moduleB. وبفضل مشروع CommonJS ظهر أكبر مشروع معتمدًا عليه وهو Node.js وهي بيئة تشغيل لغة جافاسكربت مفتوحة المصدر وتعمل على جميع أنظمة التشغيل، والّتي تستطيع تشغيل شيفرة جافاسكربت خارج المتصفحات. بالإضافة إلى ذلك تسمح Node.js للمطوري الواجهات الخلفية باستخدام جافاسكربت لكتابة برمجيات تعمل من جهة الخادم وذلك لتوليد صفحات الوِب توليدًا ديناميكيًا قبل إرسالها إلى المتصفح، وكما تستطيع أيضًا التعامل مع الملفات وقواعد البيانات، ومختلف أنظمة الشبكات وخدمات أنظمة التشغيل. الوحدة غير المتزامنة AMD علِمنا إن الهدف الرئيسي الّذي بنيت عليه CommonJS هو استخدامها في الواجهات الخلفية (من طرف المخدم) ولذلك مشكلة استدعاء الوحدات استدعاءً متزامنًا لم تكُ مشكلة في ذلك الحين، بل ولم تكُ لتظهر لولا إصرار مجتمع المطورين على جلب CommonJS إلى الواجهات الأمامية ولنُلخص مشكلة CommonJS هي عندما نستدعي الوحدة معينة في ملف ما ولتكن مثلًا add كما في السطر التالي: var add=require('add'); سيتوقف النظام حتى تصبح الوحدة add جاهزة؛ أي أن هذا السطر البرمجي سيجمد المتصفح أثناء تحميل هذا الملف. ماذا لو كان هنالك أكثر من وحدة مطلوبة كيف ستكون الأمور عندها؟ لذلك إنها ليست أفضل طريقة لتعريف الوحدات من جانب المتصفح. من أجل نقلِ صياغة تعريف وحدة ما من صياغة يفهمها الخادم إلى صياغة يفهمها المتصفح قدمت لنا CommonJS العديد من التنسيقات لتعريف الوحدات وكانت واحدة من أشهرها هي تعريف الوحدات بالطريقة غير المتزامنة (Asynchronous Module Definition) والّتي تُعرف إختصارًا AMD وتكون طريقة تعريفها كما في المثال التالي: define([‘add’, ‘reduce’], function(add, reduce){ return function(){...}; }); إن الدالة define تأخذ قائمة بالتبعيّات الموجودة والتي مرّرناها لها كقائمة وستُعيد النتيجة إلى الدالة المجهولة (Anonymous function) كوسطاء (الدالة المجهولة هي الدالة الّتي ليس لديها اسم ولقد فصلنا في مقالٍ سابق كيفية استخدمها وذلك في سلسلة تعلم جافاسكربت). وسيكون ترتيب التبعيات بنفس الترتيب الموجود في القائمة ومن ثم ستُعيد الدالة المجهولة النتيجة والتي سنُصدرها ونستخدمها في نهاية المطاف. هذه الطريقة تُكافئ الطريقة السابقة لاستدعاء الوحدات (التبعيات) لأنها تعطي نفس النتائج الوظيفية، إلا أن هذه الطريقة تستخدم التحميل غير المتزامن للوحدات. إن CommonJS و AMD حلّت آخر مشكلتين متبقيتين مع نمط الوحدات وهما على الشكل التالي: عدم وجود ثبات في التبعية بين الشيفرة البرمجية. التضارب في المتغيرات العامة. نحن فقط سنهتم بالتبعيات الموجودة من أجل كلّ وحدة (أو ملف) وبالتأكيد في هذه الحالة لا يوجد هناك أي تضارب في المتغيرات العامة. مُحمل الوحدات RequireJS في الحقيقة إن طريقة استخدام AMD مع CommonJS كانت مفيدة جدًا، ولكن كيف يمكننا استخدامها في المتصفح وهنا جاء محمل الوحدات RequireJS إلى الساحة والّذي سيساعدنا لتحميل الوحدات تحميلًا غير متزامن AMD. والذي يعتبر من أوائل التطبيقات الفعلية لمكتبة CommonJS مع AMD. على الرغم من إسمها، إلا أن هدفها ليس دعم بناء جملة 'require' في CommonJS. إن RequireJS تُتيح لنا كتابة وحدات من نمط AMD. ملاحظة: قبل أن تطبق المثال التالي، يجب عليك تنزيل ملف require.js من موقعه الرسمي. لاحظ أن الاستدعاء الوحيد الموجود في ملف index.html هو: <script data-main=”main” src=”require.js”> </script> هذا الوسم سيُحمِّلُ محليًا مكتبة require.js إلى الصفحة، ومن بعدها السمة data-main في الوسم <script> ستخبر المكتبة من أي ملف ستبدأ. بعد أن تستدعي require.js ملف main.js سيقودنا هذا الملف إلى التبعيات المتعلقة به، وهكذا إلى أن نحمل جميع التبعيات (الملفات) المطلوبة. ملاحظة: استخدمنا main فقط بدون الإشارة إلى اللاحقة والتي هي js وذلك لأن هذه المكتبة تفترض بأن كلّ القيم الّتي سنُسندها لهذه الخاصية ستكون ملفات جافاسكربت. وسيكون تحميل التبعيات للمثال السابق كما في الصورة التالية: نلاحظ أن المتصفح يحمّل الملف index.html والملف بدوره يحمّل المكتبة require.js والّذي سيتكفل ببقية الملفات الأخرى. وبهذا نكون حللنا جميع المشاكل الّتي واجهتنا حتى هذه اللحظة، ولكن وكما هي العادة في عالم البرمجة في كلّ محاولة لإصلاح مشكلةٍ ما تظهر مشكلةٌ أخرى، ولكن عادة ما تكون أخف من سابقتها في التأثير. ومن المشاكل الّتي ظهرت مع هذا الحل هي: صياغة AMD طويلة ومضجرة: إذ أن كلّ شيء يجب تغليفة بالدالة define ولذا يوجد مسافة بادئة (يُقصد تعريف الدالة define) للشيفرة البرمجية وهذه المشكلة يمكن ألا تظهر مع الملفات الصغيرة ولكن ما إن يكبر حجم الملف وتزداد تفاصيله ستصبح مشكلة كبيرة. قوائم الاعتماديات الموجودة في المصفوفة: إن قائمة الاعتماديات الموجودة في المصفوفة يجب أن تتشابه تمامًا مع القائمة المررة كوسيط للدالة وإذا كان لدينا العديد من التبعيات ستزداد الأمور تعقيدًا. في النسخة الحالية من HTTP للمتصفحات تحميل العديد من الملفات الصغيرة سيخفف من الأداء (وخصيصًا بدون استخدام أي تقنيات مساعدة مثل: ذاكرة التخزين المؤقت Cache). مجمع الوحدات أو مجمع الحزم (Module Bundler) انطلاقًا من الأسباب السابقة أراد بعض الأشخاص بناء التعليمات من خلال CommonJS لكن هذه الأخيرة مخصصة للعمل على الخوادم وليس المتصفح وهي تدعم التحميل المتزامن أيضًا. بقيت هذه الإشكالية عصية على الحل حتى جاء مجمع الوحدات Browserify لينقذ الموقف ويقدم لنا حلولً مناسبة. وهو يعدّ أول مجمع وحدات وجد آنذاك، وكان باستطاعته تحويل الوحدات المكتوبة بصياغة CommonJS والتي لا يستطيع المتصفح أن يفهمها بطبيعة الحال (وذلك لأنها بُنيت بالأساس للتعامل مع الخادم) إلى صياغة يفهمها المتصفح. يمكننا التعامل مع مجمع الحزم Browserify من خلال سطر الأوامر إذ يمكنك إعطاؤه أمرًا ما وتمرير بعض الخيارات الإضافية المتاحة لكل أمر من الأوامر الموجودة. وهو يعتمد في بنيته على مدير الحزم npm وبيئة Node.js. يمكن لمُجمع الوحدات Browserify تجميع شجرة التبعيات للشيفرة البرمجية الخاصة بك وتحزيمها في ملف واحد. وأيضًا يحل مشكلة عدم إمكانية الوصول إلى الملفات من قبل المتصفح إذ إنه يبحث عن جميع تعليمات require (والتي لا يمكن للمتصفح أن يستدعي الملف المطلوب لأنه لا يملك الصلاحيات المناسبة لذلك) فيستبدلها بمحتوى الملف المراد تضمينه (وذلك انطلاقًا من اعتماده على Node.js والتي تستطيع الوصول إلى الملفات) وهكذا يصبح الملف جاهزًا للتنفيذ في المتصفح ولا يواجه أي مشكلة. حلول كثيرة فأي منها سنستخدم؟ إذا لدينا الكثير من الخيارات المتاحة فأي واحدة منهم سنستخدم في مشروعنا القادم؟ إذ إننا حتى هذه اللحظة ناقشنا العديد من الخيارات المتاحة لكتابة الوحدات مثل: نمط الوحدات (Module Pattern) وطريقة CommonJS مع AMD وطريقة RequireJS فأي منهم سنعتمده لمشروعنا القادم؟ الجواب: ولا واحدة منها. كما نعلم بأن لغة جافاسكربت لم تكُ تدعم نظام الوحدات في أصل اللغة، ولهذا نلاحظ وجود العديد من الخيارات المتاحة لتعويض هذا النقص. ولكن هذا الأمر لم يستمر طويلًا إذ بعد تحديث المواصفات القياسية للغة جافاسكربت ES6 أصبح وأخيرًا نظام الوحدات جزءًا أساسيًا منها وهذا يكون جواب سؤالنا الرئيسي أي الخيارات سنستخدم؟ إنها طريقة ES6 (تحدثنا في سلسلة مقالاتٍ سابقة عن المميزات الجديدة لهذا الإصدار من لغة جافاسكربت ES6). تُستخدم التعليمة import و export لاستيراد وتصدير الوحدات في التحديث الجديد ES6. وإليك مثالًا عمليًا يوضح لك كيفية استخدامها: الملف main.js: import sum from "./sum"; var values = [ 1, 2, 4, 5, 6, 7, 8, 9 ]; var answer = sum(values); document.getElementById("answer").innerHTML = answer; الملف sum.js: import add from './add'; import reduce from './reduce'; export default function sum(arr){ return reduce(arr, add); } الملف add.js: export default function add(a,b){ return a + b; } الملف reduce.js: export default function reduce(arr, iteratee) { let index = 0, length = arr.length, memo = arr[index]; index += 1; for(; index < length; index += 1){ memo = iteratee(memo, arr[index]); } return memo; } في الحقيقة دعم جافاسكربت لنظام الوحدات بهذا الشكل المختصر قلبَ مجريات الُلعبة، بل إن نظام الوحدات هذا سيحكم عالم جافاسكربت في نهاية المطاف. إنها باختصار مستقبل لغة جافاسكربت. ولكن! (أعلم بأنك سئمت من هذه الكلمة ولكن يجب علينا إكمال بقية جوانب هذه الطريقة لتوضيح جميع تفاصيل المشهد لديك) هذا التحديث من اللغة لم تدعمه جميع المتصفحات المستخدمة في هذا اليوم، أو لنكن أكثر دقة ما تزال بعض المتصفحات لا تدعم هذه التحديث وخصوصًا المتصفحات القديمة وفي الحقيقة نسبة المستخدمين لهذه المتصفحات كبيرة وتؤخذ بعين الإعتبار. إذا ما الّذي يجب علينا فعله الآن؟ وكيف سنحوّل الشيفرة البرمجية من الإصدار ES6 إلى الإصدار ES5؟ هنا يأتي دور أهم أداة سنتعرف عليها اليوم ألا وهي مجمع الوحدات Webpack. ما هي Webpack؟ هي عبارة عن مجمع واحدات (Module Bundler) أو أداة بناء (Build Tool) مثل أداة Browserify وهي تحول شجرة تبعية الملفات وتُجمعها في ملف واحد. ليس ذلك فحسب وإنما تحوي على الكثير من المميزات الأخرى نذكر منها: تقسيم الشيفرة البرمجية: عندما يكون لدينا تطبيقات متعددة تتشارك نفس الوحدات يمكننا من خلال هذه الأداة تجميع الشيفرة البرمجية في ملفين أو أكثر. فمثلًا إذا كان لدينا التطبيقين التاليين app1 و app2 ويشترك كلاهما في العديد من الوحدات إذا استخدمنا Browserify سيكون لدينا app1.js و app2.js وكل ملف منهم مجمع فيه الشيفرات البرمجية الخاصة بكل تطبيق، بينما مع أداة Webpack يمكننا إنشاء ملف app1.js وملف app2.js وبالإضافة إلى الملف المشترك shared-lib.js. نعم ستضطر إلى تحميل ملفين في صفحة Html ولكن مع إمكانية استخدام تقنيات مساعدة مثل: التخزين في الذاكرة المؤقتة للمتصفح (Cache) واستخدام شبكة توصيل المحتوى الموزعة CDN (Content Delivery Network) كلّ هذه التقنيات ستقلل من وقت التحميل الإبتدائي للصفحات. المُحملات (Loaders): مع استخدام المُحمل المخصص يمكنك تحميل أي ملف إلى التطبيق إذ يمكنك استخدام الدالة reuiqre ليس فقط لتحميل ملفات جافاسكربت فقط (مثلما كانت أداة Browserify) وإنما ملفات التنسيقات وملفات SaSS وملفات Less بالإضافة إلى إمكانية تحميل الصور والخطوط والملفات والكثير غيرها. الملحقات (Plugins): تقدم Webpack ميزة الملحقات مجموعة واسعة من المهام مثل تحسين الحزمة وإدارة الملحقات (مثل الصور) بالإضافة إلى ذلك يمكننا حتى التلاعب بالملفات قبل تحميلها وتحزيمها في الملف الهدف (على سبيل المثال إمكانية ضغط الصور قبل رفعها على المخدم سنتطرق لهذه الميزّة لاحقًا في هذا الدليل). نظام الأوضاع (Mode): توفر لك هذه الأداة ثلاث أنواع من الأوضاع وضع التطوير ووضع الإنتاج أو بدون وضع. باختصار يستخدم كلّ وضع من الأوضاع من أجل سيناريو معين: وضع التطوير: يستخدم عند العمل في مرحلة التطوير لمشروع الوِب وتكون الشيفرة البرمجية مقروءة ومفهومة. وضع الإنتاج: يستخدم عند العمل في مرحلة عرض مشروع الوِب على الإنترنت وتكون الشيفرة البرمجية مختصرة وغير مقروءة. بدون وضع: يكون الشيفرة الّتي استخدمت في مرحلة التطوير هي ذاتها الّتي ستعرض على الإنترنت بدون أي تعديل. تسهل عملية تحويل الشيفرات البرمجية إلى إصدار أقدم (Transpiling): إمكانية تحويل شيفرات جافاسكربت البرمجية الحديثة مثل ES6 والّتي لا تدعمها بعض المتصفحات إلى شيفرات جافاسكربت البرمجية القديمة مثل ES5 من خلال Babel على سبيل المثال، وبذلك نكون ضربنا عصفورين بحجر واحد أولهما أننا كتبنا التطبيق بالإصدار الحديث من اللغة، وثانيهما أننا استطعنا تشغيل التطبيق على كافة المتصفحات. أليس هذا رائعًا؟ لابد بأنك متحمسٌ جدًا للتعرف على هذه الأداة والبدء في استخدامها على الفور في مشاريعك القادمة إذًا هيا بنا نبدأ لنتعرف عليها أكثر ونتعلم كيفية استخدامها. مفاهيم أساسية قبل الشروع في العمل مع هذه الأداة لا بدّ لنا من التعرف على بعض المفاهيم الرئيسية والتي سنستخدمها بكثرة في الأمثلة ملف الإعداد webpack.config.js :هو عبارة عن ملف يحدد كيفية تعامل الأداة Webpack مع بعض الخصائص للمحملات أو الملحقات وبعض خصائص الأداة نفسها. وعند إنشائنا لمشروع جديد لن نجده في مجلد المشروع وذلك بسبب ميزة التعديلات الصفرية (zero configuration) الجديدة الّتي جاءت مع الإصدار الرابع أو الأحدث من هذه الأداة والتي تمكننا من استخدام الأداة بدون الحاجة لأي تعديل في ملف الإعداد. بل يمكننا عدم إنشاؤه من الأساس. يمكن تخصيص هذا الملف تخصيصًا بسيطًا أو متقدمًا وذلك بحسب المشروع الّذي تعكفُ على تطويره، وهنالك بعض الخصائص الأساسية المشتركة في كلّ المشاريع، والّتي يجب التنويه إليها: الخاصية Entry: تحدد هذه الخاصية ملف الأولي من الشروع الّذي سنبنيه (نجمعه) في أول التنفيذ. الخاصية Output: تحدد مجلد المشروع الّذي سنستخدمه في مرحلة الإنتاج (أو النشر) يكون فيه الشيفرة البرمجية الّتي نريد استخدامها لنشر المشروع على الإنترنت. تحتوي هذه الخاصية على بعض الخيارات نذكر منها: filename: نحدد فيها أسم الملف الّذي نريد تجميع الحزم فيه. path: نحدد فيها مسار الملف الّذي نريد تجميع الحزم فيه. الخاصية Loaders: تحدد المحملات الّتي نريد أن نستخدمها مع Webpack. كلّ مُحمل يحتوي على بعض الخيارات نذكر منها: test: تحدد نوع الملفات الّتي سيُحملها هذا المُحمل (يمكننا استخدام التعابير النمطية في تحديد الملفات). exclude: الملفات الّتي نريد استبعادها (والتي من الممكن أن تحقق الخاصية الأولى). use: ما هو المُحمل الّذي سنستخدمه لإجراء التغييرات على الملفات المقبولة في test ولم تُستبعد في الخاصية exclude. الخاصية Plugins: تحدد هذه الخاصية الملحقات الّتي نريد استخدامها وكما تحدد بعض الخيارات لهذه الملحقات. الخاصية Mode: تحدد هذه الخاصية الوضع الّذي نريد العمل عليه أي طريقة نشر المشروع إلى مجلد الخرج (output). كانت هذه أبرز المفاهيم الأساسية الّتي سنتعامل معها في الأمثلة القادمة. إعداد بيئة التطوير بما أن مجمعات الحزم (الوحدات) تعتمد على Node.js اعتمادً أساسيًا للوصول إلى نظام الملفات من أجل تجميع الاعتماديات بشكلها النهائي لذا لابد لنا من تثبيت Node.js في البداية وإليك الخطوات الكاملة لتثبيته على نظام التشغيل ويندوز (يمكنك الاطلاع على مقال سابق تحدثنا فيه عن كيفية تثبيت Node.js على نظام لينكس): ندخل إلى الموقع الرسمي الخاص ببيئة Node.js ونحمل النسخة الموافقة لنظام التشغيل الخاص بك (يفضل تحميل الإصدارات ذات الدعم الطويل والتي تُدعى LTS). بمجرد إنتهاء التنزيل نفتح الملف المُنزّل. سيسألك معالج التثبيت عن موقع التثبيت والمكونات الّتي تريد تضمينها في عملية التثبيت يمكنك ترك تلك الخيارات بوضعها الافتراضي. انقر فوق تثبيت وانتظر حتى ينتهي معالج التثبيت. تهانينا أصبحت بيئة Node.js جاهزة للعمل. ملاحظة: يمكنك التأكد من تثبيت البيئة تثبيتًا صحيحًا من خلال تنفيذ الأمر التالي على سطر الأوامر (Command line) node –v يجب أن يظهر لك نسخة Node.js المثبتة وفي حالتنا ستظهر 12.16.1. كما يمكنك التأكد من تثبيت مدير الحزم Node Package Manager والّذي يُعرف اختصارًا npm من خلال الأمر npm –v يجب أن تظهر لك نسخة npm المثبتة وفي حالتنا ستظهر 6.13.4. نحن جاهزون الآن لإنشاء مشروع جديد وتثبيت Webpack! إنشاء مشروع جديد وتثبيت Webpack في البداية ننشئ مجلدًا جديدًا للمشروع وندخل إليه عبر التعليمات التالية: $ mkdir project; cd project ثم ننشئ مشروعًا جديدًا عبر التعليمة التالية: $ npm init -y ثم نثبت أداة Webpack عبر التعليمة التالية: $ npm install -D webpack webpack-dev-server يجب أن يظهر لك نتيجة مماثلة للصورة التالية: الآن لننشئ بنية الملفات الهرمية التالية: webpack-demo |- package.json + |- index.html + |- /src + |- index.js ملاحظة: جرى عرض الملفات في هذه المقالة بأسلوب عرض التغييرات في git فالأسطر الّتي بجانبها إشارة موجبة + يجب عليك إضافتها والّتي بجانبها إشارة سالبة - يجب عليك حذفها. الآن نفتح ملف index.js الموجود في مجلد src ونجري عليه التعديلات التالية: unction component() { const element = document.createElement('div'); // Lodash, currently included via a script, is required for this line to work element.innerHTML = _.join(['Hello', 'webpack'], ' '); return element; } document.body.appendChild(component()); ونعدل الملف index.html الموجود في مجلد webpack-demo ونجري عليه التعديلات التالية: <!doctype html> <html> <head> <title>Getting Started</title> <script src="https://unpkg.com/lodash@4.16.6"></script> </head> <body> <script src="./src/index.js"></script> </body> </html> كما يجب علينا أن نعدل ملف package.json لتفعيل الوضع الخاص كي نمنع النشر العرضي للشيفرة البرمجية الخاصة بنا ليصبح على الشكل التالي: { "name": "webpack-demo", "version": "1.0.0", "description": "", + "private": true, - "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "webpack": "^4.20.2", "webpack-cli": "^3.1.2" }, "dependencies": {} } لمزيد من المعلومات حول التفاصيل الداخلية لملف package.json ننصحك بأخذ جولة في التوثيق الرسمي الخاص به. في المثال السابق هنالك تبعيات ضمنية إذ أن الملف index.js يعتمد على loadash (وهي مكتبة تساعد المبرمجين على كتابة شيفرة برمجية أكثر إيجازًا وتزيد من قابلية الصيانة) في عمله وبناءً عليه يجب أن يكون loadash مُضمن قبل أن تعمل الشيفرة البرمجية للملف index.js. ولكن إن الملف index.js لم يُصرح بوضوح عن حاجته لهذه المكتبة وإنما افترض أنها موجودة ضمن المتحولات العامة. في الحقيقة إن إدارة المشروع بهذه الطريقة تعدّ مشكلة وذلك للأسباب التالية: ليس من الواضح أن الشيفرة البرمجية للملف index.js تعتمد على مكتبة خارجية. إذا كانت التبعية مفقودة، أو ضُمنت في الترتيب الخطأ، فلن يعمل التطبيق بالطريقة الصحيحة. إذا ضُمنت تبعيةً ما ولكن لم تُستخدم، سيضطر المتصفح إلى تنزيلها مع أنها غير ضرورية. لنستخدم Webpack لإدارة هذه المشروع بدلًا من الطريقة الحالية. إنشاء حزمة باستخدام Webpack سنعدل بنية المشروع قليلًا لفصل الشيفرة البرمجية الّتي سنعمل عليها عن الشيفرة البرمجية الّتي سننشرها. وتجدر الإشارة إلى أن الشيفرة البرمجية الّتي سننشرها هي الناتج المصغّر والمحسّن لعملية البناء الناتجة عن الشيفرة الّتي كتبناها والتي ستُحمّل في نهاية المطاف في المتصفح. إذًا سنضع الشيفرة البرمجية الّتي سنعمل عليها في المجلد src أما الّتي سننشرها ستكون في مجلد dist أي ستكون بهذا الشكل: webpack-demo |- package.json + |- /dist + |- index.html - |- index.html |- /src |- index.js لتحزيم مكتبة loadash (والّتي هي تبعية في ملف index.html) باستخدام الملف index.js سنحتاج أولًا إلى تثبيت هذه المكتبة محليًا باستخدام الأمر التالي: npm install --save lodash عند تثبيت حزمة (مكتبة) معينة والّتي سنحتاجها في عملية التحزيم النهائية قبل النشر النهائي يجب علينا إضافة install --save أما إذا أردت تثبيت حزمة (مكتبة) معينة لمرحلة التطوير فقط يجب عليك إضافة install --save-dev. لمزيد من المعلومات ننصحك بالإطلاع على التوثيق الرسمي لمدير الحزم NPM. الآن لنضيف تعليمة استيراد الحزمة في الشيفرة البرمجية للملف index.js الموجود في المجلد src كما في الشكل التالي: + import _ from 'lodash'; + function component() { const element = document.createElement('div'); - // Lodash, currently included via a script, is required for this line to work element.innerHTML = _.join(['Hello', 'webpack'], ' '); return element; } document.body.appendChild(component()); بما أننا قمنا باستيراد مكتبة loadash في الملف السابق لنعدل الملف index.html بما يتوافق مع ذلك ليكون كما في الشكل التالي: <!doctype html> <html> <head> <title>Getting Started</title> - <script src="https://unpkg.com/lodash@4.16.6"></script> </head> <body> - <script src="./src/index.js"></script> + <script src="main.js"></script> </body> </html> ملاحظة: يتطلب ملف index.js صراحة وجود المكتبة (أو أي تبعية إذا أردنا تعميم الفكرة) loadash ويربطه كمتحول _ (أي لا يوجد تضارب في المجال). من خلال تحديد التبعيات الّتي تحتاجها الوحدة، يمكن لمُجمع الوحدات (المقصود Webpack) استخدام هذه المعلومات لإنشاء مخطط بياني للاعتماديات (dependency graph). ثم يستخدم الرسم البياني لإنشاء حزمة محسنة والّتي ستُنفذ الاستدعاءات بالترتيب الصحيح. لننفذ التعليمة التالية npx webpack والتي ستأخذ الشيفرة البرمجية في الملف index.js وهو القيمة المسندة للخاصية entry وتنشر الخرج في ملف main.js والذي سيكون القيمة في المسندة للخاصية output. إن تعليمة npx والتي تأتي مع نسخة 8.2 من Node.js أو أحدث، و 5.2.0 من مدير الحزم NPM أو أحدث. إذ تعمل على أداة Webpack الثنائية الموجودة في (./node_modules/.bin/webpack) الّتي ثبتناها في البداية. ويكون ناتج التنفيذ كما يلي: npx webpack ... Built at: 13/06/2018 11:52:07 Asset Size Chunks Chunk Names main.js 70.4 KiB 0 [emitted] main ... WARNING in configuration The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment. You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/configuration/mode/ ملاحظة: من الممكن أن يختلف الناتج الّذي سيظهر لك بعض الشيء ولكن إذا نجحت عملية البناء فلا تقلق من رسالة التحذير فإن الأمور على ما يرام. افتح الملف index.html يجب أن يظهر لك Hello webpack فإذا ظهرت لديك تهانينا هذا يدلّ على أنك أنجزت جميع الخطوات بنجاح. إذا ظهرت لديك رسالة خطأ في صياغة ملف جافاسكربت المصغّرة (minified) وذلك عند فتحك لملف index.html فعيّن وضع التطوير ومن ثم شغل الأمر npx webpack من جديد. هذا الخطأ يتعلق بتشغيل حزمة الوٍب npx على أحدث نسخة من Node.js (الإصدار 12.5 أو الأحدث) بدلًا من الإصدار ذو الدعم الطويل LTS. الوحدات في المواصفات القياسية لنسخة جافاسكربت ES6 دُعمت تعليمتي import وexport إذ أن معظم المتصفحات تدعمها في الوقت الحالي (ولكن يوجد بعض المتصفحات لا تدعمها) وWebpack ليست استثناءً بل إنها تدعمها دعمًا متميزًا. تدعم Webpack هذه الخاصية من خلال تحويل (transpiles) الشيفرة البرمجية المقابلة للتعليمتين import وexport إلى نسخة أقدم من ES6 مثل ES5 وبذلك تؤمن فهم المتصفح ما تعنيه هذه التعليمتين باللغة الّتي يفهمها. إضافةً إلى ذلك يدعم Webpack العديد من صيغ الوحدات الأخرى لمزيد من المعلومات يمكنك زيارة التوثيق الرسمي. ملاحظة: إن Webpack لن يحوّل أي تعليمة برمجية عدا تعليمتي import وexport ولذلك في حال كنت تستخدم مميزات أخرى من المواصفات القياسية ES6 فعندها يجب عليك استخدام محولات المخصصة لذلك مثل Babel أو Bublé. استخدام ملف الإعداد إن جميع الإصدارات الّتي جاءت بعد الإصدار الرابع من Webpack تدعم ميزة التعديلات الصفرية الّتي تحدثنا عنها سابقًا في هذا الدليل، ولذا إذا أردنا أن نخصص بعض الإعدادات في المشروع لا بد لنا من إنشاء ملف الإعداد إنشاءً يدويًا. إذًا سنضيف ملف الإعداد على بنية الملفات وستصبح البنية الهرمية للمشروع على الشكل التالي: webpack-demo |- package.json + |- webpack.config.js |- /dist |- index.html |- /src |- index.js وسنُضيف إليه بعض التعليمات المهمة والتي سنستخدمها كثير في المشروع وبذلك ستتحسن إنتاجيتنا أكثر من ذي قبل. وتكون الإضافة كما يلي: const path = require('path'); module.exports = { entry: './src/index.js', output: { filename: 'main.js', path: path.resolve(__dirname, 'dist'), }, }; أما الآن لنجرب تنفيذ التعليمة التالية: npx webpack --config webpack.config.js ... Asset Size Chunks Chunk Names main.js 70.4 KiB 0 [emitted] main ... WARNING in configuration The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment. You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/configuration/mode/ ملاحظة: في حالة وجود أكثر من ملف للإعداد تلتقط التعليمة Webpack ذلك إلتقاطًا إفتراضيًا. ونستخدم خيار --config وبعده اسم الملف لتوضيح فكرة أنه بإمكانك تمرير أسم أي ملف تريده تمريرًا يدويًا، وهذا سيكون مفيدًا جدًا لملفات الإعداد الأكثر تعقيدًا والتي سنحتاج لتقسيمها إلى ملفات متعددة. يتيح ملف التكوين مرونة أكبر بكثير من استخدام سطر الأوامر CLI (Command Line Interface) البسيط. إذ يمكننا تحديد وتثبيت قواعد معينة للمُحمل (Loader) والملحقات (Plugin) وتخصيص الخيارات بالإضافة للعديد من التحسينات الأخرى. لمزيد من المعلومات يمكنك الإطلاع على التوثيق الرسمي لملف الإعداد. إنشاء إختصار لتعليمة البناء يمكننا استخدام مميزات Webpack لجعل الأمور أسهل من خلال وضع بعض اللمسات الجمالية مثل اختصار بعض الخطوات، وذلك من خلال كتابة الأوامر في ملف package.json وتحديدًا في scripts. وبذلك نختصر على أنفسنا عناء كتابة بعض التعليمات الطويلة والمُملة. إذًا لنعدل ملف package.json ليصبح على الشكل التالي: { "name": "webpack-demo", "version": "1.0.0", "description": "", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "echo \"Error: no test specified\" && exit 1", + "build": "webpack" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "webpack": "^4.20.2", "webpack-cli": "^3.1.2" }, "dependencies": { "lodash": "^4.17.5" } } يمكننا الآن استخدام الأمر npm run build بدلًا من الأمر npx الّذي استخدمنا سابقًا. لاحظ بأنه يمكننا دائمًا الإشارة إلى الحزم المثبتة محليًا في مدير الحزم npm في السمة scripts في الملف package.json بنفس الطريقة الّتي استخدمناها مع التعليمة npx. هذا الطريقة هي متعارف عليها في معظم المشاريع القائمة على مدير الحزم npm لأنه يسمح لجميع المساهمين لاستخدام نفس التعليمات المشتركة (وحتى مع بعض الخيارات مثل --config). ملاحظة: يمكنك تمرير الخيارات الخاصة لتعليمة ما من خلال إضافة شرطتين -- بين الأمر npm run build والخيارات الّتي نريد تخصيصها مثل npm run build -- --colors. npm run build ... Asset Size Chunks Chunk Names main.js 70.4 KiB 0 [emitted] main ... WARNING in configuration The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment. You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/configuration/mode/. أما الآن وبعد أن تعلمنا الأساسيات عن كيفية استخدام Webpack لننتقل إلى الاستخدامات الأهم لهذه الأداة مثل إدارة الصور والخطوط ..إلخ. إذا نفذت جميع التعليمات السابقة تنفيذًا صحيحًا يجب أن يكون البنية الهرمية للمشروع على الشكل التالي: webpack-demo |- package.json |- webpack.config.js |- /dist |- main.js |- index.html |- /src |- index.js |- /node_modules ملاحظة: إذا كنت تستخدم الإصدار الخامس من مدير الحزم npm من الممكن أن ترى ملفًا إضافيًا اسمه package-lock.json. استخدام Webpack لإدارة الملحقات بعد أن تعلمنا أساسيات Webpack وإنشأنا مشروعًا صغيرًا يعرض "Hello Webpack"، سنحاول الآن أن نركز أكثر على الأمور المهمة والتي تخدمنا بها هذه الأداة مثل إدارة ملفات التنسيق والصور وسنرى بالضبط كيف تتعامل هذه الأداة مع كلٍّ منهم. يستخدم مطورو الواجهات الأمامية أدوات بناء مثل: Grunt و Glup لمعالجة هذه الملحقات ونقلها من مجلد src إلى مجلد dist أو حتى لإنشاء مجلد جديد لهذه الملحقات، تستخدم Webpack نفس الفكرة للتعامل مع الوحدات، بالإضافة إلى أن Webpack تجمع كلّ التبعيات ديناميكيًا وتنشئ ما يعرف بمخطط التبعيات وهذا أمر رائع لأن كلّ وحدة (Module) توضح صراحة ما هي تبعياتها وبذلك نتجنب تجميع الوحدات غير المستخدمة في المشروع. واحدة من أروع مميزات Webpack هي إعطاؤك إمكانية تضمين أي نوع آخر من الملفات، إلى جانب جافاسكربت، ولهذه الفكرة تحديدًا أنشئ المحمل (Loader). أي يمكن تطبيق نفس المزايا المذكورة أعلاه (التبعيات المستخدمة من قبل الوحدات) على كلّ شيء مستخدم في إنشاء المواقع أو تطبيقات الوِب أيضًا. إدارة ملفات التنسيق CSS في البداية سنعدل قليلًا في بنية الملفات وبعض الملفات قبل أن ندير ملفات التنسيق. سنعدل الملف dist/index.html ليصبح كما يلي: <!doctype html> <html> <head> - <title>Getting Started</title> + <title>Asset Management</title> </head> <body> - <script src="main.js"></script> + <script src="bundle.js"></script> </body> </html> وكما سنعدل أيضًا ملف الإعداد webpack.config.js ليصبح: const path = require('path'); module.exports = { entry: './src/index.js', output: { - filename: 'main.js', + filename: 'bundle.js', path: path.resolve(__dirname, 'dist'), }, }; وبذلك يُصبح كلّ شيء جاهز لنبدأ. أولًا لنثبت محمل ملفات التنسيق css-loader الّذي سيساعدنا في معالجة تعليمة الاستيراد import الّتي سنستخدمها أيضًا من أجل استيراد ملفات التنسيق ومحمل التنسيق style-loader الّذي سيساعدنا في أخذ ملف التنسيق ووضعه في ملف (أو ملفات) تنسيق منفصلة. إذًا لنُنفذ الأمر التالي: npm install --save-dev style-loader css-loader ولنُعدل ملف الإعداد webpack.config.js ليحوي المعلومات اللازمة لحزم المُحمل (Loader) الّتي ثبتناها للتو وسيصبح الملف على الشكل التالي: const path = require('path'); module.exports = { entry: './src/index.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist'), }, + module: { + rules: [ + { + test: /\.css$/, + use: [ + 'style-loader', + 'css-loader', + ], + }, + ], + }, }; ملاحظة: تستخدم Webpack التعابير النمطية (Regular Expression) لتحديد الملفات الّتي يجب البحث عنها وتقديمها إلى مُحمل (Loader) محدد. في الحالة السابقة نلاحظ أنه ستُقدم جميع ملفات التنسيق (ذات اللاحقة css) إلى المُحمل style-loader والمُحمل css-loader. وهذا بدوره سيمكنك من استيراد ملف التنسيق الّذي سيكون مثل هذا import './style.css' إلى الملف الّذي يعتمد على ملف التنسيق هذا. عند تشغيل مجمع الحزم Webpack سيُضاف ملف تنسيق مخصص في وسم <style> وذلك في داخل الوسم <head>. لنجرب ذلك من خلال إضافة ملف تنسيق جديد style.css إلى مشروعنا واستيراده في الملف index.js: لننشئ أولًا ملف التنسيق style.css في مشروعنا لتصبح البنية الهرمية للمشروع على الشكل التالي: webpack-demo |- package.json |- webpack.config.js |- /dist |- bundle.js |- index.html |- /src + |- style.css |- index.js |- /node_modules ومن ثم لنُضف بعض الخصائص إلى ملف style.css ليصبح على الشكل التالي: .hello { color: red; } ولنستدعي ملف التنسيق style.css في ملف index.js ليصبح على الشكل التالي: import _ from 'lodash'; + import './style.css'; function component() { const element = document.createElement('div'); // Lodash, now imported by this script element.innerHTML = _.join(['Hello', 'webpack'], ' '); + element.classList.add('hello'); return element; } document.body.appendChild(component()); ومن ثم نُنفذ أمر البناء التالي: npm run build ... Asset Size Chunks Chunk Names bundle.js 76.4 KiB 0 [emitted] main Entrypoint main = bundle.js لنفتح الآن ملف index.html ولنرى ما هي التغييرات الّتي جرت عليه. لاحظ أن كلمة "Hello Webpack" أصبحت الآن باللون الأحمر. لمعرفة ما الّذي فعلته Webpack افحص الصفحة من خلال أدوات المطوّر (المُقدمة من متصفح جوجل كروم على سبيل المثال)، ولكن لا تعرض مصدر الصفحة لأنها لن تقدم لك النتيجة الّتي نود الإشارة إليها. إذ أن الوسم <style> سيُنشئ ديناميكيًا من قِبل جافاسكربت. لذلك افحصها حصرًا من خلال أدوات المطوّر وافحص تحديدًا الوسم <head> يجب أن يحتوي على الوسم <style> والذي استوردناه في ملف index.js. ملاحظة: سابقًا كان علينا تصغير (Minimize) ملفات التنسيق تصغيرًا يدويًا قدر الإمكان وذلك بحذف المساحات الفارغة بين الخصائص الموجودة في الملف من أجل زيادة سرعة تحميل الصفحة، ولكن مع الإصدار الرابع من مجمع الحزم 4 Webpack أو الأحدث منه أصبح تصغير ملفات التنسيق خطوة افتراضية في الأداة، وبذلك أضافت لنا هذه الأداة بُعدًا آخر لتحسين الشيفرة البرمجية وسبب وجيّه لزيادة محبتنا لها. إدارة ملفات SASS تتيح لنا Webpack إمكانية التعامل مع ملفات SASS وتحويلها إلى ملفات تنسيق عادية. ولنأخذ مثالًا عمليًا نطبق فيه كيفية تحويل ملفات SASS إلى ملفات تنسيق عادية. سنركز في هذا المثال على دعم الملفات SCSS مثل: (your-styles.scss) و الملفات SCSS modules مثل: (your-component.module.scss). تجنبًا لتعقيد الأمور أكثر من اللازم سنبدأ بمشروع جديد ننفذ فيه هذه الفكرة. سنفترض أنك أنشأت مشروعًا جديدًا وثبتّ أداة Webpack، لننتقل الآن لتثبيت الإضافات والمُحملات اللازمة لهذا المشروع. سنبدأ أولًا بتثبيت الحزم التالية: npm install --save-dev node-sass sass-loader style-loader css-loader mini-css-extract-plugin ستكون مهمة كلّ حزمة من الحزم على الشكل التالي: node-sass: ستوفر هذه الحزمة ربط Node.js مع LibSass وهذا الأخير هو مترجم SASS. sass-loader: هو مُحمّل ملفات SASS إلى مشروعنا. css-loader: تستخدم هذه الحزمة لتفسير التعليمة @import و @url() بما تشير إليه في ملفات التنسيق. style-loader: تستخدم هذه الحزمة لإسناد الخصائص الموجودة في ملفات التنسيق إلى الوسوم الفعلية في شجرة DOM الافتراضية. mini-css-extract-plugin: هذه الحزمة تستخرج الخصائص الموجودة في ملفات التنسيق إلى ملفات منفصلة. إذ أنها تنشئ لكل ملف جافاسكربت ملف تنسيق الخاص به وهو لدعم ميّزة التحميل عند الطلب (On-Demand-Loading) لملفات التنسيق و خرائط الشيفرة البرمجية المحوّلة Source Maps (لمزيد من المعلومات عنها يمكنك الإطلاع على المقال التالي). سنحتاج إلى إضافة مُحملين، أحدهما للتنسيقات العامة والأخرى للتنسيقات المركبة. واللّذان يشار إليهما بملفات (SCSS modules). إذ أن هذه الأخيرة تعمل جيدًا مع المكتبات أو أطر العمل المُعتمدة على المكونات (component-based) مثل: React. سنضيف هذه الحزمة الملحقة إلى ملف الإعداد webpack.config.js على الشكل التالي: + const MiniCssExtractPlugin = require('mini-css-extract-plugin') module.exports = { plugins: [ + new MiniCssExtractPlugin({ + filename: isDevelopment ? '[name].css' : '[name].[hash].css', + chunkFilename: isDevelopment ? '[id].css' : '[id].[hash].css' + }) ] } نلاحظ أننا أضفنا خاصية أسماء الملفات المجزأة من أجل زيادة فعالية وسهولة خرق ذاكرة التخزين المؤقّت (Cache Bustring وهي تحِلُّ مشكلة التخزين المؤقت في المتصفح باستخدام إصدار معرف فريد للملف يميزه وذلك من أجل أخباره في حال وجود نسخة جديدة من الملف الذي حفظه فعلًا في هذه الذاكرة، وذلك من أجل أن يحملها تلقائيًا إلى ذاكرة التخزين المؤقت بدلًا من نسخة الملف القديمة الموجودة فيه)، والآن سنضيف الخواص المناسبة لملف الإعداد webpack.config.js من أجل عملية التحويل المناسبة للملفات: module.exports = { module: { rules: [ + { + test: /\.module\.s(a|c)ss$/, + loader: [ + isDevelopment ? 'style-loader' : MiniCssExtractPlugin.loader, + { + loader: 'css-loader', + options: { + modules: true, + sourceMap: isDevelopment + } + }, + { + loader: 'sass-loader', + options: { + sourceMap: isDevelopment + } + } + ] + }, + { + test: /\.s(a|c)ss$/, + exclude: /\.module.(s(a|c)ss)$/, + loader: [ + isDevelopment ? 'style-loader' : MiniCssExtractPlugin.loader, + 'css-loader', + { + loader: 'sass-loader', + options: { + sourceMap: isDevelopment + } + } + ] + } ] }, resolve: { - extensions: ['.js', '.jsx'] + extensions: ['.js', '.jsx', '.scss'] } } نلاحظ أن القاعدة الأولى المطبقة في الشيفرة السابقة ستُطبق على الملفات ذات الامتدادات .module.scss أو .module.sass إذ في البداية ستُحوّلُ ملفات SASS إلى CSS من خلال sass-loader ومن ثم ستُمرّر إلى الحزمة css-loader لمعالجة التعليمات @import() و url() ..إلخ. ومن ثمّ ستُسندُ الحزمة style-loader الخصائص المناسبة في DOM أو ستسند من خلال الحزمة Mini CSS Extract Plugin وذلك لإخراج ملفات التنسيق أثناء وضع النشر. القاعدة الثانية مشابهة جدًا للقاعدة الأولى باستثناء أننا لا نحوّل أسماء الأصناف. الآن أصبح ملف الإعداد جاهز نحتاج الآن لإنشاء ملف تنسيقات SASS للتأكد من أن كل شيء يعمل مثلما خطط له. أنشئ مجلد src ثم أنشئ بداخله ملفًا جديدًا باسم app.module.scss وأضف الشيفرة البرمجية التالية: .red { color: red; } أي عنصر سيأخذ الصنف red سيكون لونه أحمر. افتح الملف app.js واستدعي الملف السابق على الشكل التالي: import styles from './app.module' نلاحظ أن اسم الملف لا يحتوي على اللاحقة .scss وذلك لأننا سبق وأخبرنا Webpack بأن يأخذ بعين الاعتبار هذه اللاحقة وذلك في ملف الإعداد. ثم لنُضيف الآن الدالة التالية في نفس الملف app.js ليصبح على الشكل التالي: function App() { return <h2 className={styles.red}>This is our React application!</h2> } أليست سهلة جدًا؟ بغض النظر عن كيفية تحويل الحزمة css-loader اسم الصنف الّذي بنيناه (red) والّذي سيصبح مثل: _1S0lDPmyPNEJpMz0dtrm3F أو شيء من هذا القبيل، ولكنها ساعدتنا في مهمتنا مساعدةً كبيرة. لنُضيف الآن بعض التنسيقات العمومية. لننشئ ملف جديد وليكن global.scss في المجلد src ولِنفتحه ونُضيف بداخله الشيفرة البرمجية التالية: body { background-color: yellow; } هذا الملف سيجعل لون خلفية الصفحة الرئيسية لتطبيق الوِب خاصتنا أصفر. ولكن يجب أن نفتح الملف index.js ونستدعي ملف التنسيق السابق في بداية الملف. مثلما هو موضح في الشيفرة التالية: import './global' واخيرًا سنحصل على الخرج التالي: نلاحظ أن استخدام وحدات SCSS يتطلب منا جهدًا لا بأس به، ولكن بالموازنة مع كمية الفائدة الّتي تقدمها وحدات SCSS من سهولة في الصيانة لتطبيق الوِب في المستقبل فأعتقد أن الأمر يستحق هذا الجهد. بالإضافة إلى ذلك توفر أداة Webpack حزم أُخرى مخصصة لأي نكهة من نكهات ملفات التنسيق مثل الحزمة: postcss لتوفير دعم Postcss أو الحزمة Less لدعم ملفات التنسيق من نوع Less أيضًا. إدارة الصور تتيح Webpack لنا إمكانية إدارة الصور مثل: الخلفيات والأيقونات وذلك من خلال مُحمل الملفات. في البداية لنثبت أولًا مُحمل الملفات من خلال الأمر التالي: npm install --save-dev file-loader ومن ثم سنضيف إلى ملف الإعداد webpack.config.js المعلومات اللازمة لعمل هذا المُحمل كما في الشكل التالي: const path = require('path'); module.exports = { entry: './src/index.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist'), }, module: { rules: [ { test: /\.css$/, use: [ 'style-loader', 'css-loader' ], }, + { + test: /\.(png|svg|jpg|gif)$/, + use: [ + 'file-loader', + ], + }, ], }, }; عند استيراد لصورة معينة ولتكن import MyImage from './my-image.png' ستضاف هذه الصورة إلى مجلد الخرج (output) الّذي حددناه في ملف الإعداد وسيحمل المتغير MyImage عنوان الرابط التشعبي الخاص بالصورة (URL) بعد معالجتها. عندما استخدمنا محمل ملفات التنسيق css-loader جرى نفس السيناريو السابق. أي أنه سيكون الخاصية التالية في ملفات التنسيق url('./my-image.png') والمُحمل سيلاحظ أن الملف هذا موجود محليًا وبذلك سيُحول './my-image.png' إلى المسار النهائي المُسند للخاصية (output) في ملف الإعداد webpack.config.js ومُحمل ملفات html (html-loader) سيتعامل مع <img src="./my-image.png" /> بنفس الطريقة. لنُضف الآن الصور اللازمة في مشروعنا. وهنا يمكنك استخدام أي صورة تريدها. لننسخ الصورة الّتي سنعمل عليها ولتكن icon.png إلى مشروعنا. لتصبح البنية الهرمية للمشروع على الشكل التالي: webpack-demo |- package.json |- webpack.config.js |- /dist |- bundle.js |- index.html |- /src + |- icon.png |- style.css |- index.js |- /node_modules ومن ثم لنستورد هذه الصورة في ملف src/index.js، ولنُضيفها إلى وسم <div> المتواجدة فيه، ولتصبح الشيفرة البرمجية للملف src/index.js على الشكل التالي: import _ from 'lodash'; import './style.css'; + import Icon from './icon.png'; function component() { const element = document.createElement('div'); // Lodash, now imported by this script element.innerHTML = _.join(['Hello', 'webpack'], ' '); element.classList.add('hello'); + // Add the image to our existing div. + const myIcon = new Image(); + myIcon.src = Icon; + + element.appendChild(myIcon); return element; } document.body.appendChild(component()); ومن ثم سنعدل ملف التنسيق من أجل تضمين الصور الّتي نعمل عليها ليصبح بذلك ملف التنسيق src/style.css على الشكل التالي: .hello { color: red; + background: url('./icon.png'); } ولننفذ الآن أمر البناء التالي: npm run build ... Asset Size Chunks Chunk Names da4574bb234ddc4bb47cbe1ca4b20303.png 3.01 MiB [emitted] [big] bundle.js 76.7 KiB 0 [emitted] main Entrypoint main = bundle.js ... إذا نفذت جميع الخطوات السابقة تنفيذًا صحيحًا يجب أن ترى الأيقونة (الصورة) مكررة في الخلفية، بالإضافة إلى وسم <img> بجوار النص "Hello webpack". وإذا فحصت الصورة ستجد أن اسمها الفعلي تغيّر إلى شيء شبيه بهذا الاسم 5c999da72346a995e7e2718865d019c8.png هذا يعني أن Webpack عثرت على الملف في مجلد src وعالجته. الخطوة المنطقية التالية الّتي سننفذها هي تصغير حجم الصور الّتي سنستخدمها في المشروع وتحسينها وذلك من خلال الحزم المساعدة المتوفرة مع الأداة Webpack مثل الحزمة Imagemin. ضغط الصور باستخدام Imagemin إن طريقة ضغط الصور الّتي سنستخدمها في المشروع هي باستخدام حزمة Imagemin إذ تعدّ هذه الحزمة خيارًا ممتازًا وذلك لأنها تدعم مجموعة متنوعة من أنواع الصور وسهلة التكامل مع الشيفرة البرمجية لأدوات البناء أو مجمع الحزم (الوحدات). سنعمل على مشروع جديد تجنبًا للمشاكل التي من الممكن أن تظهر لنا في حال أكملنا العمل على المشروع السابق. سنفرض أنك أنشأت مشروعًا جديدًا وثبّت الأداة Webpack تثبيتًا صحيحًا. في البداية لنثبت هذه الحزم عبر التعليمة التالية: npm install imagemin-webpack-plugin copy-webpack-plugin --save-dev ملاحظة: أن الحزمة copy-webpack-plugin ستساعدنا على نسخ الصور من مجلد images/ إلى مجلد dist/ وهو مجلد النشر وهو اختصار لكلمة distribution. لننشئ ملف الإعداد webpack.config.js ولنعدله ليتناسب مع الحزم الجديدة ليصبح على الشكل التالي: const ImageminPlugin = require('imagemin-webpack-plugin').default; const CopyWebpackPlugin = require('copy-webpack-plugin'); const path = require('path'); module.exports = { entry: './index.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist') }, plugins: [ new CopyWebpackPlugin([{ from: 'img/**/**', to: path.resolve(__dirname, 'dist') }]), new ImageminPlugin() ] } تعدّ هذه الطريقة من أسهل الطرق لإعداد لهذه الحزمة. ولنضغط الصور الّتي في المجلد images/ وننسخها إلى المجلد dist/ من خلال تنفيذ الأمر التالي: webpack --config webpack.config.js --mode development نلاحظ من التعليمة السابقة أن وضع التنفيذ الحالي هو وضع التطوير، ولكن ما الّذي سيحدث إذا نفذنا التعليمة في وضع النشر؟ لنرى ما الّذي سيحدث. webpack --config webpack.config.js --mode production ستُظهر لنا في هذه المرة أداة Webpack تحذيرًا يخبرك بأن الصور ذات النوعية PNG الخاصة بك لا تزال تتجاوز الحد الأقصى للحجم الموصى به، على الرغم من بعض الضغط. ولذلك سنحتاج إلى ضبط اليدوي لعملية الضغط لهذا النوع من الصور لتصبح أفضل مما قبل. لنعدل قيمة الضغط للصور ذات النوعية PNG لتصبح 50% وسيكون ملف الإعداد على الشكل التالي: const ImageminPlugin = require('imagemin-webpack-plugin').default; const CopyWebpackPlugin = require('copy-webpack-plugin'); const path = require('path'); module.exports = { entry: './index.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist') }, plugins: [ new CopyWebpackPlugin([{ from: 'img/**/**', to: path.resolve(__dirname, 'dist') }]), new ImageminPlugin({ pngquant: ({quality: [0.5, 0.5]}), }) ] } نلاحظ أننا مررنا للغرض Pngquant مجالًا لقيمة جودة الصور من 0.5 إلى 0.5 أي من الحدّ الأدنى إلى الحدّ الأعلى لجودة الصورة. إذ أن الحدّ الأعلى الأفتراضي 1 والحدّ الأدنى الافتراضي 0. ولكن ماذا لو أردنا أن نضبط الجودة (نسبة الضغط) المستخدمة لبقية الأنواع من الصور بنفس الطريقة السابقة؟ في الحقيقة يوجد بعض الملحقات الإضافية المساعدة لهذا الغرض تحديدًا والّتي سنستعرضها في هذا الجدول: نوع الصور ضغط مع خسارة بعض معلومات الصورة ضغط بدون خسارة بعض معلومات الصورة JPEG imagemin-mozjpeg imagemin-jpegtran PNG imagemin-pngquant imagemin-optipng GIF imagemin-giflossy imagemin-gifsicle SVG Imagemin-svgo WebP imagemin-webp 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; } نلاحظ أن لدينا نوعين من طرق ضغط الصور وهما كالتالي: ضغط مع خسارة بعض معلومات الصورة (Lossy): يؤدي استخدام هذا النوع إلى تصغير حجم الصورة تصغيرًا ملحوظًا، ولكن مع فقدان بعض معلومات الصورة. ضغط بدون خسارة بعض معلومات الصورة (Lossless): يؤدي استخدام هذا النوع إلى تصغير حجم الصورة تصغيرًا أقل من الطريقة السابقة، ولكن بدون فقدان بعض معلومات الصورة. إن طريقة الضغط الإفتراضية للحزمة imagemin للصور ذات النوعية JPEG هي الطريقة imagemin-jpegtran، سنستعرض كيفية ضغط الصور باستخدام الحزمة الأخرى وهي imagemin-mozjpeg. في البداية يجب علينا تثبيت هذه الحزمة من خلال الأمر التالي: npm install imagemin-mozjpeg ولنُعدل ملف الإعداد webpack.config.js لضبط طريقة ضغط الصور وفق ما نريده. ليصبح الملف على الشكل التالي: const imageminMozjpeg = require('imagemin-mozjpeg'); const ImageminPlugin = require('imagemin-webpack-plugin').default; const CopyWebpackPlugin = require('copy-webpack-plugin'); const path = require('path'); module.exports = { entry: './index.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist') }, plugins: [ new CopyWebpackPlugin([{ from: 'img/**/**', to: path.resolve(__dirname, 'dist') }]), new ImageminPlugin({ pngquant: ({quality: [0.5, 0.5]}), plugins: [imageminMozjpeg({quality: 50})] }) ] } نلاحظ أن نسبة الضغط في هذه الحزمة من 100 إذ مررنا القيمة 50 وبذلك نخبره بأننا نريد ضغط الصور من النوع JPEG بنسبة 50%. ولنُنفذ الآن التعليمة التالية لنرى النتيجة: webpack --config webpack.config.js --mode production تهانينا في حال نفذّت جميع الخطوات تنفيذًا صحيحًا يجب أن تكون الصور مضغوطة وفقَ المطلوب. إن الأداة Webpack تحذرنا من الصور ذات الحجم الكبير، ولكنها لا تستطيع إخبارنا إن كانت الصور مضغوطة أم لا، ولهذا السبب سنستخدم الأداة Lighthouse للتحقق من التغييرات المُنفّذة. تسمح لنا الأداة Lighthouse من التحقق من ترميز الصور بكفاءة وإن كانت الصور الموجودة في صفحتك مضغوطة على نحوٍ أمثلي أم لا (لمزيد من المعلومات حول هذه الأدة ننصحك بالاطلاع على هذا المقال المفصّل). وستكون النتيجة مشابهة للصورة التالية: بنفس الطريقة يمكنك استخدام بقية الحزم لتخصيص قيمة الضغط المطلوب للأنواع الأخرى من الصور المستخدمة في مشروعك. إدارة الخطوط يمكننا إدارة الخطوط أيضًا مع Webpack من خلال مُحمل الملفات الّذي ثبتناه في إدارة الصور (سنعمل على نفس المشروع الّذي بنيناه في فقرة إدارة الصور)، والذي سيأخذ أي ملف تضعه له في ملف الإعداد ويضعه في المسار النهائي المُسند للخاصية (output) في ملف الإعداد webpack.config.js. أي أن مُحمل الملفات قادر على التعامل الخطوط أيضًا. لنعدل الآن ملف الإعداد webpack.config.js ليصبح على الشكل التالي: const path = require('path'); module.exports = { entry: './src/index.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist'), }, module: { rules: [ { test: /\.css$/, use: [ 'style-loader', 'css-loader' ], }, { test: /\.(png|svg|jpg|gif)$/, use: [ 'file-loader', ], }, + { + test: /\.(woff|woff2|eot|ttf|otf)$/, + use: [ + 'file-loader', + ], + }, ], }, }; أضف خطًا معينًا إلى مجلد المشروع لتصبح البنية الهرمية للمشروع على الشكل التالي: webpack-demo |- package.json |- webpack.config.js |- /dist |- bundle.js |- index.html |- /src + |- my-font.woff + |- my-font.woff2 |- icon.png |- style.css |- index.js |- /node_modules من خلال التعديلات الّتي أجريناها على ملف الإعداد لمُحمل الملفات يمكننا الآن جعل التعليمة الّتي تصرح بها عن المسارات للخطوط @font-face إلى الشكل التالي url(...). سيعاد توجيه هذه المسارات إلى المسار النهائي المُسند للخاصية (output) في ملف الإعداد webpack.config.js تمامًا كما تعامل مع الصور. إذا سيصبح ملف التنسيق src/style.css على الشكل التالي: + @font-face { + font-family: 'MyFont'; + src: url('./my-font.woff2') format('woff2'), + url('./my-font.woff') format('woff'); + font-weight: 600; + font-style: normal; + } .hello { color: red; + font-family: 'MyFont'; background: url('./icon.png'); } لنرى كيف سيتعامل Webpack مع الخطوط ولننفذ أمر البناء على الشكل التالي: npm run build ... Asset Size Chunks Chunk Names 5439466351d432b73fdb518c6ae9654a.woff2 19.5 KiB [emitted] 387c65cc923ad19790469cfb5b7cb583.woff 23.4 KiB [emitted] da4574bb234ddc4bb47cbe1ca4b20303.png 3.01 MiB [emitted] [big] bundle.js 77 KiB 0 [emitted] main Entrypoint main = bundle.js ... افتح ملف index.html وانظر إلى النص "Hello webpack" كيف تغير شكل الخط ليصبح مطابق لشكل الخط الجديد. أما الآن لننتقل إلى واحدٍ من أبرز استخدامات مجمع الحزم Webpack وهو تحويل الشيفرات البرمجية الخاصة بالإصدارات الحديثة من المواصفات القياسية للغة جافاسكربت مثل ES6 إلى ES5. تحويل الشيفرة البرمجية باستخدام Babel بعد أن تعرفنا كيف ندير جميع التبعيات الموجودة في شيفرات جافاسكربت البرمجية من خلال Webpack. لا بُدّ لنا من جعل هذه الشيفرة البرمجية تعمل على جميع المتصفحات وذلك لكي نضمن أنه مهما يكن المتصفح الّذي سيستخدمه العميل (أو المستخدم) ستظهر النتيجة المطلوبة تمامًا مثل ما نريده. عملية التحويل (Transpiling): هي عملية تغيير الشيفرة البرمجية من إصدار معين إلى إصدار أقدم وذلك لضمان عمل هذه الشيفرة البرمجية على المتصفحات كلها. مقتطف من المخطط التفصيلي لدعم المتصفحات للمميزات الإصدار ES5 والإصدار ES6 من لغة جافاسكربت. سننشئ مشروعًا بسيطًا لشرح طريقة استخدام هذا المُحول: mkdir webpack-demo2 cd webpack-demo2 npm init -y npm install webpack webpack-cli --save-dev ملاحظة: لن نتطرق للتفاصيل نظرًا لأنها شُرحت في بداية هذا الدليل. ستكون البنية الهرمية للمشروع على الشكل التالي: webpack-demo2 |- package.json + |- index.html + |- /src + |- index.js في البداية سنحتاج لتثبيت ثلاث حزم للتعامل مع المحول Babel وستكون على الشكل التالي: npm install babel-core babel-loader babel-preset-env --save-dev الحزمة babel-core: تحتوي على الشيفرة البرمجية للنواة الأساسية للمُحول Babel. الحزمة babel-preset-env: تحتوي على الشيفرة البرمجية الّتي ستمكن النواة الأساسية للمحول Babel من تحويل الشيفرة البرمجية للجافاسكربت ذات الإصدار 6ES إلى الإصدار ES5. الحزمة babel-loader: أو (مُحمل المحول) وهي الّتي ستستخدمها Webpack في تحميل المحول والتعامل معه في عملية التحزيم (Bundling). أما الآن سننشئ ملف babelrc. والذي سيطلب من المحول Babel أن يستخدم الحزمة babel-preset-env أثناء عملية التحويل وسيكون الملف babelrc. على الشكل التالي: +{ "presets": ["env"] } ومن ثم سننشئ ملف الإعداد webpack.config.js ونطلب من Webpack الإستعانة بالمحمل Babel أثناء تحزيمه. وسيكون ملف الإعداد webpack.config.js على الشكل التالي: + const path = require('path'); + module.exports = { + entry: { main: './src/index.js' }, + output: { + path: path.resolve(__dirname, 'dist'), + filename: 'main.js' + }, + module: { + rules: [ + { + test: /\.js$/, + exclude: /node_modules/, + use: { + loader: 'babel-loader' + } + } + ] + } + }; سنضع الآن في ملف src/index.js شيفرة برمجية من الإصدار ES6، وليصبح على الشكل التالي: + const fn = () => "Arrow functions're Working!"; + alert(fn()); ومن ثم ننفذ الأمر التالي: npm run dev ومن ثم لنفتح ملف dist/main.js نلاحظ أن الدالة السهمية (Arrow function) تُحوّلُ إلى دالة عادية وذلك وفق الطريقة المتبعة في الإصدار ES5 من لغة جافاسكربت. وسيكون محتوى الملف dist/main.js على الشكل التالي: 'use strict'; var fn = function fn() { return "Arrow functions're Working!"; }; alert(fn()); وبذلك استطعنا استخدام مميزات الإصدار الحديث من لغة جافاسكربت ES6 وتحويله إلى إصدار أقدم ES5 لتفهمه المتصفحات القديمة. هل من المخاطرة تعلم Webpack؟ بعد أن تعرفنا سريعًا على Webpack يمكن لسائل أن يسأل ماذا لو أنني تعلمت العمل على Webpack وبعدها ظهرت أداة جديدة أفضل منها أو تغطي مجال أوسع في العمل؟ أليس ذلك هدرًا لوقتي ولجهدي؟ صراحة، الشيء الوحيد الّذي استطيع تأكيده لك هو أن عجلة التحديث في مجال الواجهات الأمامية سريع الدوران، وما إن تظهر مشكلة ما حتى يتسارع المطورون لحلها فمن الممكن أن تظهر أداة أقوى منها (وهذا لا اتوقعه أن يحدث قريبًا وخصيصًا مع الدعم الكبير الّتي تشهده هذه الأداة من الشركات العملاقة مثل فيسبوك) هذا وارد الحدوث، ولكن هذا الأمر لا يُلغي فكرة أهمية تعلمك العمل مع هذه الأداة إذ أن معظم الأدوات الّتي تظهر لحل مشكلة معينة تكون متشابهة في البنية وطريقة العمل مع بعض الإختلافات. أي إن تعلمك العمل مع هذه الأداة سيجهزك للعمل مع الأدوات الأخرى المستقبلية. ومن يعلم ربما تكون أنت صاحب فكرة الأداة الجديدة الّتي ستتفوق على Webpack! والسؤال الأخر الّذي من الممكن يخطر في أذهاننا أيضًا هل تستحق هذه الأداة الوقت المبذول لتعلمها؟ أو بتعبير أخر هل النتائج الّتي سأجنيها من استخدام هذه الأداة ستغطي على الوقت المبذول لتعلمها؟ في الحقيقة لا أبالغ أن قُلت أنه من الواجب عليك تعلمها فورًا وبدون تردد وخصيصًا إن كُنت تتخذُ من مهنة تطوير الواجهات الأمامية (أو مطور برمجيات عمومًا) مصدرًا أساسيًا للدخل في حياتك! لأنها ستعزز كثيرًا من إنتاجيتك وسرعتك وجودة العمل المُسلّم وهذا ما ستشعر به من أول شهر من استخدامك لها. في الحقيقة إن مجيئ Webpack بكل هذه المميزات وقابلية التخصيص والإمكانيات أطاح بجميع المنافسين لديها مثل Browserify، ليس ذلك فحسب بل تخطّت إمكانياتها حدود الفكرة التي أُنشأت من أجلها لتهدد أدواتٍ مساعدةٍ أخرى كأدوات البناء مثل Gulp (والتي تحدثنا عنها في مقالٍ سابق) إذ أنه يمكننا من خلال NPM Script أن نعوّض عمل Gulp ولكن هذا سيكون على حساب الصعوبة إذ أن العمل مع Webpack ليس بسهولة العمل مع Gulp. ننصحك بالانتقال بعد الانتهاء من هذا المقال إلى مقال، أيهما أفضل كأداة مساعدة Webpack أم Browserify مع Gulp؟ الذي يشرح الفروقات بين كل هذه الأدوات وحالات استخدامها وغيرها من التفاصيل المفيدة. بالإضافة إلى ذلك وفرت لنا Webpack إمكانية التكامل مع أدوات مساعدة أُخرى مثل أداة السقالة Yeoman (والتي تحدثنا عنها في مقالٍ سابق) وبذلك نحصل على فوائد كِلتا الأداتين ونختصر وقتنا اختصارًا ملحوظًا. وبذلك يمكننا القول بأن المرونة الموجودة لدى Webpack وملحقاتها الرائعة والدعم المتميز من مجتمعها ومستخدميها جعلها من أقوى الخيارات الموجودة في الساحة حاليًا. الخاتمة بدأنا هذا الدليل ونحن لا نعرف شيئًا عن Webpack، ثم حفرنا عميقًا في تاريخها لنفهم تمامًا ما هي الأسباب الّتي أدت لظهور أداةٍ قوية كهذه الأداة، ثم بدأنا بتجهز المتطلبات اللازمة لتشغيلها، وفصلّنا في جميع المفاهيم الأساسية لها، وتعلمنا كيفية استخدامها في إدارة ملفات التنسيق والصور والخطوط ، وكيفية استخدامها لضغط الصور قبل رفعها وتعلمنا طريقة استخدامها لتحويل الشيفرة البرمجية من إصدار حديث إلى إصدار أقدم منه. وأخيرًا ناقشنا أهمية تعلمها وفوائده. وختامًا إن هذا الدليل لم يغطي كافة المميزات والجوانب الموجودة في أداة Webpack وإنما فقط أردنا من هذا الدليل أن يلفت نظرك لأهمية هذه الأداة وقدراتها المتميزة في مساعدتك في العمل على المشاريع وخصوصًا الكبيرة منها. بل وجعلها يدك اليمنى في أي مشروع جديد وبالتأكيد إن كلّ هذه المعلومات لن تُشبع فضول المطوّر المحترف ولذلك يمكنك دومًا الاطلاع على التوثيق الرسمي للأداة لمزيد من المعلومات. المصادر التوثيق الرسمي لأداة Webpack. التوثيق الرسمي لمدير الحزم npm. المقال Using Imagemin with webpack لصاحبته Katie Hempenius. المقال How to configure SCSS modules for Webpack لصاحبه Jon Preece. المقال Brief history of JavaScript Modules لصاحبه SungTheCoder.1 نقطة
-
في هذا الجزء من المقالات التعليمية، نتطرَّق إلى لغة JavaScript كما هي بدون تعديلات خاصة بالبيئة. لكن ما زلنا نستخدم المتصفح كبيئة تجريبية، لذلك يجب أن تتعرف على عددٍ قليلٍ من دوال واجهة المستخدم الخاصة به. ستتعرف في هذا الفصل على هذه الدوال التفاعلية الخاصة بالمتصفح. الدالة alert الصياغة: alert(message); تعرض هذه الدالة رسالة نصية وتوقف تنفيذ السكربت مؤقتًا حتى يضغط المستخدم على «موافق» (OK). إليك الشيفرة البسيطة التالية مثلًا: alert("مرحبًا"); تسمى الرسالة النصية التي تظهر على شكل نافذة صغيرة تدعى «النافذة المنبثقة الشرطية» (modal window، وهي عنصر تحكم رسومي)؛ تعني كلمة «شرطية» أنه لا يمكن للزائر التفاعل مع بقية الصفحة، أو الضغط على أزرار أخرى وما إلى ذلك، إذ تشترط عليه التفاعل معها فقط، أي حتى يضغط على «موافق» (Ok) في هذه الحالة. الدالة prompt تقبل الدالة prompt وسيطين (arguments) لتكون صياغتها بالشكل التالي: result = prompt(title, [default]); تعرض هذه الدالة نافذة منبثقة شرطية مع رسالة نصية مخصصة، وحقل إدخال للمستخدم، وزرَّين (موافق [OK] وإلغاء [CANCEL]). الوسيط title: هو عبارة عن النص الذي سيعرض للمستخدم. الوسيط default: هو وسيط اختياري يمثِّل القيمة الأولية لحقل الإدخال الخاص بالمستخدم. قد يكتب المستخدم شيئًا ما في حقل الإدخال، ثمَّ يضغط على موافق (Ok). أو يمكنه إلغاء الإدخال عند الضغط على إلغاء (CANCEL) أو الضغط على مفتاح الهروب (Esc). استدعاء الدالة prompt يرجع سلسلة نصية تمثِّل القيمة التي أدخلها المستخدم في حقل الإدخال أو يرجع القيمة null إذا تم الخروج من النافذة وإلغائها. جرب نفِّذ المثال التالي في الطرفية وعدل عليه: let age = prompt('كم عمرك؟', 100); alert(`عمرك ${age} سنة!`); في IE (أي المتصفح Internet Explorer)، دائمُا ما يتم إضافة الوسيط default. أي هذا الوسيط اختياري في جميع المتصفحات باستثناء المتصفح IE الذي يعدُّه اجباريًّا، وإذا لم نحدِّد قيمته، يفترض المتصفح Internet Explorer أنَّ قيمته "undefined". نفِّذ هذه الشيفرة في متصفح Internet Explorer لرؤية الناتج: let test = prompt("Test"); لجعل الدالة prompt تعمل جيدًا في المتصفح IE، نوصي دائمًا بتمرير قيمة الوسيط الثاني default: let test = prompt("Test", ''); // <-- IE للمتصفح الدالة confirm الصياغة: result = confirm(question); تُظهر الدالة confirm نافذة منبثقة شرطية تحتوي على سؤال question، وزريّن (موافق [OK] وإلغاء [CANCEL]). تكون النتيجة true إذا ضغط المستخدم على الزر "Ok" وتكون false عدا ذلك. جرِّب المثال التالي في طرفيتك: let isBoss = confirm("Are you the boss?"); alert( isBoss ); الخلاصة ذكرنا في هذا المقال ثلاثة دوال للتفاعل مع مستخدمي الموقع وهي: الدالة alert: تعرض رسالة لإعلام المستخدم بشئ ما، وُتعطل كافة عمليات الصفحة حتى يتفاعل مع هذه الرسالة. الدالة prompt: تعرض رسالة تطلب من المستخدم إدخال شيء ما في حقل إدخال خاص لتعيد القيمة المدخلة في سلسلة نصية، أو ترجع القيمة null إذا تم العملية. الدالة confirm: تعرض رسالة (بمثابة سؤال) وتنتظر من المستخدم الرد عليها بالقبول أو الرفض، أي تكون النتيجة true إذا تم الضغط على زر "Ok" أو تكون false عدا ذلك. كل هذه الدوال مشروطة: فهي تتوقف عن تنفيذ السكربت ولا تسمح للمستخدم بالتفاعل مع بقية الصفحة حتى يتم التفاعل مع النافذة التي تعرضها. هناك اثنين من القيود التي تشترك بها جميع الدوال المذكورة أعلاه: يحدد المتصفح الموقع الذي ستظهر فيه النافذة، وعادة ما يكون في الوسط أو الأعلى. يعتمد شكل النافذة أيضًا على المتصفح، ولا يمكننا تعديله. هذا هو ثمن البساطة. هناك طرق أخرى لإظهار نوافذ أكثر جمالًا وفاعلية، ولكن إذا كانت التنسيقات الجمالية غير مهمة، فهذه الدوال تفي بالغرض. .task__importance { color: #999; margin-left: 30px; } .task__answer { border: 3px solid #f7f6ea; margin: 20px 0 14px; position: relative; display: block; padding: 25px 30px; } code { background-color: rgb(250, 250, 250); border-radius: 3px; } تمارين صفحة بسيطة الأهمية: 4 قم بإنشاء صفحة ويب تطلب اسمًا ما ثم تعرضه. الحل شيفرة JavaScript: let name = prompt("ما اسمك؟", ""); alert(name); الشيفرة كاملة: <!DOCTYPE html> <html> <body> <script> 'use strict'; let name = prompt("ما اسمك؟", ""); alert(name); </script> </body> </html> ترجمة -وبتصرف- للفصل Interaction: alert, prompt, confirm من كتاب The JavaScript Language اقرأ أيضًا المقال التالي: المعاملات الشرطية المقال السابق: معاملات الموازنة كامل مقالات دليل تعلم جافاسكربت1 نقطة
-
فلنقل إنك تسير في شارع مكتظ وسط المدينة، تتأهب للمرور في مفترق طرق وفي هذه الأثناء انتقلت الإشارة الضوئية الخاصّة بالراجلين إلى اللون الأحمر. مالذي ستفعله؟ تتوقف… أليس كذلك؟ ماذا لو تبدّل اللون إلى الأخضر بعد ذلك؟ تعود إلى المشي. يمكننا اعتماد نفس المبدأ في الشفرات البرمجية. يبدو الأمر كما لو أنك تقول “إن أصبح لون الإشارة أحمر فيجب عليك التوقف وإلا استمرّ في المشي”. هذا بالضبط هو عمل الجملة if/else (إنْ… وإلا) في جافاسكريبت. الجملة if/else تساعد الجملة if/else بالتحكّم في ما يفعله برنامجك في حالات محدّدة. تأخذ الصيغة التالية: if (condition) { // افعل شيئا هنا } else { // افعل شيئا مغايرا هنا } يخبر الشرط Condition الجملة if/else مالذي يجب عليها التحقّق منه قبل الاستمرار. إذا كانت قيمة الشرط صحيحة (تساوي true) فإن جافاسكريبت سينفّذ الشفرة الموجودة داخل كتلة if. أما إذا كانت قيمة الشرط غير صحيحة (أي false) فإن الشفرة الموجودة في الكتلة else هي ما سيُنفّذ. بالعودة إلى مثال الإشارة الضوئية أعلاه فإن الأمر سيأخذ الصيغة التالية: if (الإشارة حمراء) { // توقّف عن المشي } else { // استمرّ في المشي } إن احتجت للتحقّق من شروط عدّة فيمكنك إضافة else if بين كتلتيْ if وelse. متى ستحتاج لشرط ثان؟ فلنقل إنك تمرّ عبر طريق صغيرة. إن لم تكن هناك سيارات فهل ستستمر في الانتظار إلى أن يتغيّر لون الإشارة الضوئية؟ على الأرجح ستواصل طريقك. بترجمة الحالة أعلاه إلى شفرة برمجية نجد التالي: if (الإشارة حمراء) { // توقّف عن المشي } else if (توجد سيارات) { // توقّف عن المشي } else if (شرط آخر) { // افعل أمرا آخر } else { // أمر أخير } إذا كان الشرط الأول في الشفرة أعلاه متحقّقا فإن مفسّر جافاسكريبت ينفّذ الشفرة الموجودة ضمن كتلة if، أما إذا كان هذا الشرط غير متحقّق فإن المفسّر ينظُر في الشرط الموجود في جملة else if الموالية لمعرفة ما إذا كان متحقّقا… وهكذا إلى إن يمرّ عبر جميع جمل else if. يعتمد مفسّر جافاسكريبت على أساسيْن لمعرفة تحقّق الشرط من عدمه: عوامل المقارنة Comparison operators. القيم الصحيحة و القيم الخاطئة. عوامل المقارنة توجد أربعة عوامل أساسية للمقارنة: “أكبر من” < أو “أكبر من أو يساوي”=< “أصغر من” > أو “أصغر من أو يساوي”=> “يساوي تماما” === أو “يساوي” == “يختلف تماما” ==! أو “يختلف” =! النوعان الأولان من عوامل المقارنة واضحان ويستخدمان لمقارنة الأعداد: 24 > 23 // صحيح 24 > 24 // خاطئ 24 >= 24 // صحيح 24 < 25 // صحيح 24 < 24 // خاطئ 24 <= 24 // صحيح النوعان التاليّان يُستخدمان لمقارنة تساوي شيئين: 24 === 24 // صحيح 24 !== 24 // خاطئ إلا أنه يوجد فرق بين “يساوي تماما” === و “يساوي” ==، وبين “يختلف تماما” == ! و “يختلف” =! '24' === 24 // خاطئ '24' == 24 // صحيح '24' !== 24 // صحيح '24' != 24 // خاطئ يتّضح من المثال أعلاه أن مقارنة العدد 24 بسلسلة المحارف 24 تعطي نتيجة خاطئة عند استخدام العامل “يساوي تماما” (===) بينما تعطي نتيجة صحيحة عند استخدام العامل “يساوي” (==). لماذا هذا الاختلاف؟ فلنر الفرق بين “يساوي تماما” و “يساوي”. الفرق بين === و == (و بين ==! و =!) أنواع البيانات Data types في جافاسكريبت ليست صرامة بل متساهلة، عكس لغات أخرى. يعني هذا أننا لا نهتم عندما نعرّف متغيّرا بنوع البيانات الذي ستأخذه قيمة هذا المتغيّر. يمكنك تعريف أي متغيّر وسيتكفّل مفسّر جافاسكريبت بالتعامل مع نوع البيانات الخاصّ بقيمة المتغيّر: const aString = 'Some string' const aNumber = 123 const aBoolean = true عند استخدام العامل “يساوي تماما” (===) أو “يختلف تماما” (==!) فإن مفسّر جافاسكريبت يأخذ أنواع بيانات قيم المتغيّرات بالحسبان؛ لهذا السبب فإن سلسلة المحارف 24 تختلف عن العدد 24. '24' === 24 // خطأ '24' !== 24 // صحيح أما عند استخدام العامل “يساوي” (==) أو “يختلف” (=!) فإن مفسّر جافاسكريبت يحوّل نوع البيانات بحيث يتساوى نوع طرفيْ المقارنة قبل أن ينظُر في القيمة. عمومًا، يحاول مفسّر جافاسكريبت تحويل جميع أنواع البيانات إلى أعداد عند استخدام عوامل المقارنة (ما عدا ===و==!). تُحوَّل سلسلة المحارف 24 في المثال أدناه إلى العدد 24 قبل المقارنة. هذا هو السبب الذي يجعل سلسلة المحارف 24 تساوي العدد 24 عند استخدام العامل ==: '24' == 24 // صحيح '24' != 24 // خاطئ يمكن كذلك تحويل القيم المنطقية (true وfalse) إلى أعداد، وعندها تصبح قيمة true تساوي 1 وfalse تساوي 0: 0 == false // صحيح 1 == true // صحيح 2 == true // خاطئ يعدّ التحويل التلقائي الذي يقوم به مفسّر جافاسكريبت أثناء استخدام عوامل المقارنة أحد أكثر الأسباب شيوعا لصعوبة التعرف على العلل Bugs أثناء تطوير البرامج؛ لذا استخدم دوما عوال المقارنة التامّة (=== أو==!). دورة تطوير التطبيقات باستخدام لغة Python احترف تطوير التطبيقات مع أكاديمية حسوب والتحق بسوق العمل فور انتهائك من الدورة اشترك الآن مقارنة الكائنات والمصفوفات حاول أن تقارن بين الكائنات أو بين المصفوفات بالعامل === أو == وستجد نتيجة مفاجئة: const a = { isHavingFun: true } const b = { isHavingFun: true } console.log(a === b) // خطأ: الكائن a مختلف تماما عن الكائن b console.log(a == b) // خطأ: الكائن a مختلف عن الكائن b الكائنان a وb في المثال أعلاه يبدوان متشابهين تماما: كلاهما كائن ويحويان نفس القيم. الأمر الغريب هو أن المقارنة a === b ترجع دائما قيمة خاطئة false؛ لماذا؟ فلنفترض أنكَ وأخاك (أو أنكِ وأختك) توأم. تبدو مشابهًا تمامًا لأخيك: نفس لون الشعر، نفس شكل الوجه، نفس الثياب؛ كيف يمكن التفريق بينك وأخيك؟ سيكون الأمر صعبًا. لدى كل كائن في جافاسكريبت بطاقة تعريف (هوية) تُسمّى مرجع الكائن Object’s reference. عند استخدام عوامل المقارنة للتحقّق من تساوي كائنين في جافاسكريبت فإنك تطلُب من المفسر التحقّق ممّا إذا كان للكائنيْن نفسُ المرجع (بطاقة التعريف). ليس غريبًا الآن أن تكون قيمة الشرط a === b في المثال أعلاه مساوية لـfalse. فلنعدّل قليلاً على المثال ونسند a إلى b: const a = { isHavingFun: true } const b = a تصبح نتيجة المقارنة a === b الآن مساوية لـ true (أي أن الكائنين متساويان). السبب في ذلك هو أن الكائنين a وb لديهما الآن نفس المرجع. console.log(a === b) // true القيم الصحيحة و القيم الخاطئة إن وضعت اسم متغيّر (hasApples - بمعنى لديه تفاح - في المثال أدناه) مكان الشرط في جملة if/else فإن مفسّر جافاسكريبت سيبحث عن قيمة صحيحة أو قيمة خاطئة. const hasApples = 'true' if (hasApples) { // تناول تفاحة } else { // اشتر تفاحا } القيم الخاطئة هي قيم تأخذ القيمة false عند تحويلها إلى نوع البيانات المنطقية Boolean. توجد ست قيم خاطئة في جافاسكريبت: false undefined null 0 (العدد صفر) "" (سلسلة محارف فارغة) NaN على الجانب الآخر، القيم الصحيحة هي تلك التي تأخذ القيمة true بعد تحويلها إلى بيانات منطقية. في حالة الأعداد فإن أية قيمة مغايرة للصفر تُحوَّل إلى قيمة صحيحة. تُشجّع جافاسكريبت على استخدام التحويل التلقائي إلى قيم صحيحة وقيم خاطئة لكونها تجعل من الشفرة البرمجية أقصر وأسهل فهما. إن أردت على سبيل المثال التحقّق من أن سلسلة محارف فارغة فيمكنك استخدام هذه السلسلة مباشرة في شرط الجملة if/else: const str = '' if (str) { // سلسلة المحارف غير فارغة } else { // سلسلة المحارف فارغة } خاتمة تُستخدم الجمل الشرطية if/else للتحكّم في عمل البرامج في حالات محدّدة؛ فتسمح لك بتحديد ما إذا كان يتوجب عليك الاستمرار في المشي أو الانتظار لتجاوز مفترق طرق. توجد طريقتان للتحقّق من الشروط في جافاسكريبت: عوامل المقارنة القيم الصحيحة والقيم الخاطئة ترجمة - تصرّف - للمقال Understanding if/else statements لصاحبه Zell Liew.1 نقطة
-
Django هو إطار عمل مجّاني ومفتوح المصدر، مكتوب بلغة Python، وتتبع المشاريع فيه بنية Model-View-Template (عادة ما تختصر إلى MVT). يؤكّد Django على قابلية إعادة الاستخدام Reusability للمكونات وكذلك على التطوير السريع، بالإضافة إلى مبدأ عدم التكرار. تستخدم لغة Python في جميع مفاصل إطار العمل هذا، كالإعدادات ونماذج قواعد البيانات وغيرها. ومن أشهر المواقع التي تستخدم Django هي: Pinterest ،Instagram ،Mozilla ،The Washington Times ،Disqus ،National Geographic وغيرها الكثير. طوّر Django سنة 2003 على يدي المبرمجين Adrian Holovaty و Simon Willson اللذين يعملان في صحيفة Lawrence Journal World، وذلك عندما انتقلا إلى لغة Python لبناء التطبيقات. ثم أطلق Django سنة 2005 تحت رخصة BSD، وقد سمّي بهذا الاسم تيمنًا بعازف الغيتار Django Reinhardt. بنية MVT تنقسم بنية المشاريع في Django إلى ثلاثة أقسام مرتبطة ببعضها البعض، ولكنّها مختلفة عن أطر العمل الأخرى التي تتبع بنية (MVC - Model, View, Controller) مثل Laravel في PHP وغيرها، حيث تتكون المشاريع في Django من النموذج Model والعرض View والقالب Template. يتولى قسم النموذج معالجة البيانات والتعامل معها واسترجاعها، ويدعم Django العديد من قواعد البيانات، مثل: SQlite ،MySQL، و PostgreSQL. أما العرض فعبارة عن مجموعة من دوال Python التي تستجيب لعنوان URL معين، ووظيفة العرض هي تحديد البيانات والمعلومات التي يجب عرضها. أما القالب فهو عبارة عن ملف بصيغة HTML يتم من خلاله تحديد الطريقة التي ستظهر بها المعلومات التي يعرضها قسم العرض. أين المتحكم Controller إذًا؟ المتحكم هنا هو إطار العمل نفسه، أي الآلية التي يتم من خلالها إرسال الطلب إلى العرض المناسب بالاعتماد على عنوان URL محدّد. تثبيت Django إطار العمل Django هو إحدى الحزم الخاصة بلغة البرمجة بايثون، وتوفّر هذه اللغة مدير حزم خاصّ يدعى pip يتم من خلاله تثبيت وتحديث وإزالة الحزم بسهولة ويسر؛ لذا ستكون الخطوة الأولى في تثبيت Django هي التأكد من وجود مدير الحزم pip وتثبيته إن لم يكن متوفّرًا. تنصيب pip لتنصيب إطار العمل Django ستحتاج إلى مدير الحزم الخاصّ بـ Python وهو pip، ولحسن الحظّ فإن pip متوفّر في نسخة Python 2.7.9 وما بعدها، وفي نسخة Python 3.4 وما بعدها. في حال عدم توفّر pip في نسخة Python المنصّبة لديك يمكنك تنصيبه باتباع الخطوات التالية: حمّل الملفّ get-pip.py. توجه في سطر الأوامر إلى المكان الذي حملت فيه الملف السابق، ثم اكتب التعليمة التالية: python get-pip.py استخدام سطر الأوامر لنجرب الآن استخدام مدير الحزم في بايثون لتنصيب Django، توجّه الآن إلى سطر الأوامر ثم اكتب الأمر: pip install django==1.9 هل ظهرت لك رسالة خطأ؟ ما المشكلة، ألم نقم بتنصيب pip قبل قليل؟ هذا صحيح، ولكننا لم نخبر سطر الأوامر بأن يوجّه أي تعليمة تبدأ بكلمة pip إلى مدير حزم بايثون، وللقيام بذلك اتبع الخطوات التالية: في أوبنتو: يجب تنصيب حزمة python3-pip إن كنت تستخدم الإصدار الثالث من بايثون أو python-pip للإصدار الثاني من بايثون، لتتمكن من استخدام pip في سطر الأوامر في أبونتو، وللقيام بذلك اكتب الأمر التالي في سطر الأوامر: sudo apt-get install python3-pip أدخل كلمة المرور الخاصة بك، وستبدأ عملية التثبيت، وبعد الانتهاء يمكنك تنصيب أي حزمة خاصة بلغة بايثون عن طريق سطر الأوامر مباشرة. في نظام Windows: أما في نظام Windows فيجب إضافة السطر التالي: C:\Python34\scripts; إلى مسار النظام System path، وللقيام بذلك اتبع الخطوات التالية: انقر بزر الفأرة الأيمن على أيقونة Computer واختر Properties من القائمة المنسدلة: انقر على أيقونة Advance system settings، وفي مربع الحوار المنبثق اضغط على أيقونة Environment Variables. انقر نقراً مزدوجًا على متغير النظام Path في الجزء السفلي من مربع الحوار المنبثق. أضف السطر السابق إلى نهاية السلسلة النصّية، بعد الفاصلة المنقوطة (;) (إن لم تكن هناك فاصلة منقوطة في نهاية السطر فقم بإضافتها). اضغط Ok ثم أغلق بقية النوافذ بالضغط على Ok. يمكنك الآن استخدام pip من سطر الأوامر مباشرة. البيئة الافتراضية Virtual Environment قبل البدء بتنصيب Django سنعمل على تنصيب أداة مفيدة جدًّا من شأنها المساعدة على ترتيب البيئة البرمجية على حاسوبك. يمكن تجاوز هذه الخطوة، ولكن ينصح بها بشدّة. تعمل البيئة الافتراضية على عزل مشاريع Python أو Django الخاصّة بك عن بعضها البعض، وهذا يعني أن إجراء التعديلات على موقع إلكتروني معيّن لن تؤثّر على المشاريع الأخرى التي تعمل عليها. ستحتوي البيئة الافتراضية على الملفات التنفيذية الخاصة بـ Python بالإضافة إلى نسخة من مكتبة pip يمكنك استخدامها في تنصيب حزم Python المختلفة. سننشئ مجلدًا سيحتوي على البيئة الافتراضية التي سوف ننشئها بعد قليل. mkdir mysite cd mysite يتطلب إنشاء البيئة الافتراضية تنصيب حزمة virtualenv وسنستعين بـ pip للقيام بذلك: pip install virtualenv لاستخدام virtualenv من سطر الأوامر مباشرة في أوبنتو يجب تنصيب الحزمة virtualenv، وللقيام بذلك اكتب الأمر التالي في سطر الأوامر: sudo apt-get install virtualenv بعد اكتمال عملية التنصيب يمكنك إنشاء البيئة الافتراضية بالشكل التالي: virtualenv myvenv ستنشئ هذه الشيفرة بيئة افتراضية وهي عبارة عن مجموعة من المجلدات. لتفعيل البيئة الافتراضية الجديدة في نظام Windows استخدم الشيفرة التالية: myvenv\Scripts\activate أما في نظامي Linux و OS X فاستخدم: source myvenv/bin/activate ملاحظة: قد لا تحصل على النتيجة المرجوّة من الشيفرة السابقة، لذا يمكنك استخدام هذه الشيفرة: . myvenv/bin/activate سيتغيّر سطر الأوامر وذلك بإضافة كلمة (myvenv) إلى بداية السطر، وهذا يعني أن الأمور تسير على ما يرام. ولإغلاق البيئة الافتراضية يمكنك استخدام التعليمة التالية: deactivate تنصيب Django بعد اكتمال الخطوتين السابقتين يمكننا الآن تنصيب Django وذلك بتنفيذ الأمر التالي (انتبه إلى وجود علامتي مساواة لا علامة واحدة): pip install django==1.9 بعد اكتمال عملية التنصيب، وللتأكد من أن الأمور تجري على ما يرام، اكتب الأمر التالي في سطر الأوامر: python3 -c "import django; print(django.get_version())" إن حصلت على رقم النسخة (1.9 في حالتنا هذه) التي قمت بتنصيبها، فقد أصبحت جاهزًا لإنشاء مشروعك الأول على Django. إنشاء المشروع الأول مشروعنا الأول سيكون عبارة عن تطبيق استطلاع بسيط، يتألف من جزئين: موقع عام يتيح مشاهدة الاستطلاعات والتصويت عليها. لوحة تحكم تتيح لنا إضافة وحذف وتعديل الاستطلاعات. هذا المشروع سيكون مبنيًا على الإصدار 1.9 من Django والإصدار 3.4 من Python. في حال كنت تستخدم الإصدار 2.7 من Python فيتوجب عليك حينها إضافة بعض التعديلات على الشيفرة التي تكتبها، وسنشير إلى ذلك في محلّه. انتقل إلى سطر الأوامر وتوجه من خلاله إلى المجلد الذي ترغب استخدامه لإنشاء المشروع، وبإمكانك استخدام أي مجلد تحت أي تسمية وفي أي موقع في القرص الصلب، فلا مشكلة لدى Django في ذلك. لإنشاء المشروع نفّذ الأمر التّالي في سطر الأوامر (انتبه إلى النقطة في نهاية السطر): django-admin startproject mysite . سيعمل هذا الأمر على إنشاء مجلد باسم mysite داخل مجلد المشروع. انتبه كذلك إلى كتابة النقطة في نهاية السطر، فهي توجّه الشيفرة إلى تنصيب Django في المجلد الحالي. البنية الأولية للمشروع يحتوي مجلد mysite الذي أنشأته التعليمة السابقة، على مجموعة الملفات التالية: manage.py /mysite __init__.py settings.py urls.py wsgi.py manage.py، يُوصف هذا الملف بالسكين السويسري، وهو الأداة التي سنستعين بها للقيام بالكثير من الأشياء في إدارة الموقع، وفي تهجير قواعد البيانات وتشغيل الخادوم الخاص بـ Django، وغير ذلك الكثير. المجلد mysite هو حزمة بايثون الخاصة بمشروعنا، وسنستخدم هذا الاسم عندما نرغب في استيراد أي شيء داخله. (مثال mysite.urls). mysite/__init__.py ملف فارغ، ووجوده يعني أن هذا المجلّد هو حزمة من حزم بايثون. mysite/settings.py ملف الإعدادات الخاصة بمشروعنا. mysite/urls.py يحتوي على عناوين URL الخاصة بموقعنا، وهو أشبه ما يكون بجدول المحتويات الخاص بالموقع. mysite/wsgi.py نقطة الولوج إلى الخواديم المتوافقة مع WSGI. تشغيل الخادوم توجه في سطر الأوامر إلى المجلد الذي يحوي الملف manage.py ثم اكتب الأمر التالي: python manage.py runserver وستظهر العبارات التالية في سطر الأوامر: Performing system checks... System check identified no issues (0 silenced). You have unapplied migrations; your app may not work properly until they are applied. Run 'python manage.py migrate' to apply them. February 01, 2016 - 15:50:53 Django version 1.9, using settings 'mysite.settings' Starting development server at http://127.0.0.1:8000/ Quit the server with CONTROL-C. ملاحظة: لا تستخدم هذا الخادوم في المشاريع الإنتاجية على الإطلاق، فالهدف من هذا الخادوم هو استخدامه لأغراض التطوير فقط. أدخل العنوان التالي في متصفح الإنترنت: http://127.0.0.1:8000 ستظهر الصفحة التالية لتشير إلى نجاحنا في إنشاء أول مشروع في Django.1 نقطة