لوحة المتصدرين
المحتوى الأكثر حصولًا على سمعة جيدة
المحتوى الأعلى تقييمًا في 10/21/21 في كل الموقع
-
3 نقاط
-
الطريقة التي تقوم بها خاطئة , سوف نقوم بفعل ذلك من خلال 3 خطوات وهي كالتالي: ادخال القيمة على أنها سلسلة نصية. تقسيم القيمة وتخزين القيمة في list, يمكن فعل ذلك من خلال حلقة تكرار طباعة عناصر القائمة من الخلف, يمكن فعل ذلك من خلال استخدام slice فيكون شكل الكود كالتالي n=input('enter a three digit integer ') //ادخال الرقم كأنه سلسلة نصية l= [x for x in n] // المرور على كل عنصر في السلسلة النصية وتخزينه في list num=''.join(l[::-1]) // باستخدام join وأيضا باستخدام slice قمنا بطباعة عناصر السلسلة من الخلف وصولا الى أول عنصر print('The revers number is :',num) // طباعة النص الناتج من عملية الطباعة العكسية2 نقاط
-
"الحاجة أم الإختراع"، تنبع أغلب أفكار التطبيقات من مشاكل كانت تواجهة صانيعيها أو مشاكل تواجهة فئة معينة من المستخدمين، لذلك يمكنك أن تبحث عن المشاكل التي تواجهة فئة من المستخدمين في الوقت الحالي، ويكون ذلك عبر سؤالهم بشكل مباشر أو البحث بشكل يدوي عن هذه المشاكل من خلال تجربة التطبيقات والبرامج أو المواقع بنفسك ومحاولة إعادة إنشائها مرة اخرى مع حل المشكلات الموجودة بها بالفعل. حتى أن المشكلة التي تواجهك الآن (صعوبة الحصول على أفكار لمشاريع وتطبيقات) قد تُعد فكرة لمشروع جديد في حد ذاتها، وبذلك يمكنك عمل تطبيق يحتوي على أفكار لمشاريع بسيطة ويمكن للمستخدمين إضافة أفكار جديدة ليقوم أحد المبرمجين بمحاولة إنشاء هذه الفكرة، وإنتاج مشروع جديد يُفيد المستخدمين.. أيضًا يمكنك أن تقوم بتصفح مواقع العمل الحر للحصول على أفكار لمساعدة العملاء، فعلى سبيل المثال قد تجد أن كثير من العملاء يطلبون إنشاء متجر إلكتروني متعدد الأصناف وبمميزات معينة، ويمكنك حينها إنشاء مشروع يسهل على العملاء هذه العملية، وبعد الإنتهاء من المشروع يمكنك بيعه في شكل خدمة SAAS أو منتج بإشتراك شهري على سبيل المثال. في كثير من الأحيان ستجد أن الفكرة التي لديك قام أحد ما بتنفيذها بالفعل، لكن هذه ليست مشكلة، فبإمكانك تحليل المنافسين ومعرفة المميزات التي يقدمونها والعيوب التي لديهم، مثل سعر عالي مقارنة بالخدمة أو بطء في الدعم الفني أو حنى مشاكل تقنية مختلفة، وبذلك تستطيع تحسين المنتج الخاص بك أيضًا. لا يمكن الجزن بشكل حاسم عن الوقت المستغرق في إنشاء أي تطبيق حتى وإن كانت مواصفات التطبيق معروفة ومحددة بالفعل، لأن هذا الأمر يختلف من مطور لآخر، فيمكن لمطور ما أن يقوم بإنشاء مدونة من الصفر في يومين فقط، بينما يمكن لمطور آخر أن يقوم بإنشاء نفس المدونة في أسبوع مثلًا، والفرق هنا يكمن في الكثير من الأشياء مثل الخبرة وطريقة التنظيم والتقنيات المستخدمة لإنشاء المشروع .. إلخ. ولن يستطيع أحد أن يخبرك عن الوقت الذي سوف تستغرقه أنت في إنشاء أي مشروع، فأنت الوحيد من يمكنه تحديد هذا الأمر، وذلك بناء على تجربتك في إنشاء المشاريع سابقًا.2 نقاط
-
لدي جدول لسجل مشاهدة الأفلام لكل مستخدم، وأريد عرض الأفلام التي لم يشاهدها للآن بناءاً على الربط عن طريق رقم المستخدم2 نقاط
-
1 نقطة
-
1 نقطة
-
يُقدر أنّ عدد لغات البرمجة الإجمالي يتجاوز 9000 لغة برمجة، منها حوالي 50 لغة تُستخدم على نطاق واسع من قبل المبرمجين [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; } إنّ أسئلة من قبيل: أيّ لغة برمجة ينبغي أن أتعلم؟ أو ما هي أفضل لغة برمجة؟ أو هل اللغة الفلانية خير من اللغة الفلانية؟ هي من الأسئلة الجدلية. يكفي أن تبحث على جوجل على مثل هذه الأسئلة وستجد ما يشبه حربا ضروسا على شبكة الإنترنت. فهذا يقول إنّ لغة البرمجة الفلانية هي أفضل اللغات، والآخر يقول بل اللغة الفلانية الأخرى خير. هناك سبب وجيه لهذا الاختلاف، ذلك أنّه لا توجد لغة برمجة تناسب الجميع، أو تتفوق على غيرها في كل المجالات. لكل لغة برمجة نقاط قوة ونقاط ضعف. سنحاول في هذه المقالة أن نساعد المبتدئ، وحتى من له خبرة سابقة في البرمجة ويريد تعلم لغات برمجة إضافية، على اختيار لغة البرمجة المناسبة ليتعلمها ويبدأ بها. سنركز في هذه المقالة على ثلاث من أشهر لغات البرمجة وأكثرها شعبية، وهي بايثون وروبي و PHP. سنوازن بين هذه اللغات ونستعرض أهم مميزات كل منها من الجوانب التالية: استخدامات اللغة وتطبيقاتها سهولة التعلم الشعبية الدعم والاستقرَار الأمان المكتبة وإطارات العمل الطلب في سوق العمل محاسن ومساوئ كل لغة باختصار سنختم هذه المقالة بخلاصة لنجيب فيها عن سؤال أيّ هذه لغات البرمجة أنسب لكي تتعلمها وتبدأ بها. استخدامات اللغة وتطبيقاتها بايثون بايثون هي لغة برمجة متعددة الأغراض، أي أنّه يمكن استخدامها لتطوير كافة أنواع التطبيقات، من تطبيقات الويب، وحتى الألعاب وتطبيقات سطح المكتب. تطوير الويب: يمكن استخدام بايثون لتطوير المواقع وتطبيقات الويب، إذ توفّر عددا من إطارات العمل المتقدمة، مثل Django و Flask. لكن شعبيتها لدى مطوري الويب أقل عموما من روبي و PHP. تطوير تطبيقات سطح المكتب: بايثون مثالية لتطبيقات سطح المكتب، إذ أنّها لغة مستقلة عن المنصات وأنظمة التشغيل، فبرامج بايثون يمكن أن تعمل دون جهد إضافي على ويندوز وأنظمة يونيكس. الذكاء الاصطناعي: نحن نعيش ثورة جديدة ستغير كل شيء من حولنا، وهي ثورة الذكاء الاصطناعي وتعلم الآلة التي أصبحت تطبيقاتها في كل مكان، في السيارات ذاتية السياقة وأجهزة التلفاز الذكية وروبوتات الدردشة والتعرف على الوجوه وغيرها من التطبيقات. تُعد بايثون أنسب لغات البرمجة للذكاء الاصطناعي كما يراها 57% من المطورين [2]. إذ توفر للباحثين في هذا المجال مكتبات متقدمة في مختلف مجالات البحث العلمي، مثل Pybrain لتعلم الآلة، وكذلك TensorFlow، وهي مكتبة يمكن استخدامها في الشبكات العصبونية والتعرف على الصور ومعالجة اللغات الطبيعية وغيرها . البحث العلمي: توفر بايثون للباحثين مكتبات عملية متقدمة تساعدهم على أبحاثهم، مثل مكتبة Numpy الخاصة بالحوسبة العلمية، و Scipy الخاصة بالتحليل العددي. بايثون تُستخدم بكثافة في القطاعات الأكاديمية والتجارية، هذه بعض المشاريع والشركات التي طُوِّرت باستخدامها: جوجل: لدى جوجل قاعدة عامة تقول: "استخدم بايثون ما أمكن، واستخدم C++ عند الضرورة". انستغرام: إحدى أكبر الشبكات الاجتماعية Netflix: أكبر منصة لبث الأفلام والمسلسلات على الشبكة Uber: أكبر تطبيق للتوصيل روبي تشبه روبي بايثون في العديد من الجوانب، من ذلك أنّها لغة برمجة متعددة الأغراض، إذ يمكن استخدامها في كافة أنواع التطبيقات. روبي هي لغة كائنية خالصة، أي أنّ كل شيء في روبي هو كائن له توابعه وخاصياته. يجعلها هذا مثالية للبرامج التي تعتمد بكثافة على نمط البرمجة الكائنية. تطبيقات الويب: روبي مثالية لتطوير تطبيقات الويب، إذ توفر إحدى أشهر وأفضل منصات تطوير الويب، وهي Ruby on Rails. والدليل على ذلك أنّ بعض أكبر المنصات والمواقع تستخدم Ruby on Rails، مثل منصة التجارة الإلكترونية Shopify. المشاريع الكبيرة: تُستخدم روبي في المشاريع الكبيرة والمعقدة والتي تستغرق مدة طويلة، وتتطلب تغييرات مستمرة. لغة نمذجة: تُستخدم روبي في تطوير نماذج أولية للبرامج ( prototypes) قبل البدء بتطويرها الفعلي. لغة سكريبتات: تُستخدم روبي (وبايثون كذلك) لبرمجة السكربتات، وهي ملفات تحتوي مجموعة من الأوامر التي يمكن تنفيذها دون الحاجة إلى تصريفها. من أكبر المشاريع والمواقع التي طُوِّرت باستخدام روبي نذكر على سبيل المثال لا الحصر: Sass: أحد أفضل امتدادات لغة CSS. Hulu: منصة لبث الأفلام والمسلسلات والوثائقيات Github : أكبر منصة لاستضافة المشاريع البرمجية PHP على خلاف روبي وبايثون، PHP ليست متعددة الأغراض، وإنما هي لغة متخصصة في برمجة الخوادم. الاستخدام الأساسي للغة PHP هو تطوير الواجهات الخلفية للمواقع وتطبيقات الويب، سواء الساكنة أو الديناميكية. تطبيقات سطح المكتب: صحيح أنّ PHP لغة متخصصة في برمجة الخوادم، إلا أنّه يمكن استخدامها لتطوير تطبيقات سطح المكتب باستخدام مكتبة PHP-GTK. لغة PHP لغة قوية، وقد طُوِّرت بها بعض أكبر المواقع على شبكة الإنترنت، مثل: فيسبوك: أكبر شبكة اجتماعية ياهو: محرك بحث ويكيبيديا: تستخدم هذه الموسوعة الضخمة PHP ضمن مجموعة من اللغات الأخرى ووردبريس: أكبر منصة لإدَارة المحتوى سهولة التعلم إحدى أهم عوامل المفاضلة بين لغات البرمجة هي سهولة تعلمها، خصوصا لدى المبتدئين. تعد بايثون على العموم أبسط وأسهل للتعلم موازنة بلغة روبي أو PHP. بايثون لغة مختصرة وبعيدة عن الإسهاب، في الحقيقة يُقدّر أنّ بايثون تختصر في المتوسط حوالي 80% من الشفرات المكتوبة موازنة بلغات البرمجة الكائنية الأخرى [3]. أضف إلى ذلك أن كتابة شيفرة برمجية بلغة بايثون أشبه بكتابة قصيدة أو قصة باللغة الإنجليزية الأمر الذي لا يجعل كتابة شيفرات بايثون عملية سهلة وممتعة، بل حتى قراءتها أيضًا. تعلم PHP أصعب عمومًا من تعلم بايثون، ذلك أنّ بايثون لغة متعددة الأغراض، أما PHP فهي لغة متخصصة تتطلب معرفة أولية بلغات أخرى، مثل HTML و CSS و Javascript. لكن إن كنت تريد تعلم PHP، فأتوقع أنك تريد أن تتعلم تطوير المواقع، ما يعني أنّك غالبا تعرف أساسيات هذه اللغات. فيما يخص روبي، فهي أصعب قليلا، وقد تحتاج إلى معرفة أولية بأساسيات البرمجة قبل تعلمها. الشعبية تحل بايثون في المرتبة الرابعة كأكثر لغات البرمجة شعبية أثناء تحديث هذا المقال، كما تتربع على عرش لغات البرمجة متعددة الأغراض، إذ يستخدمها حوالي 44% من المبرمجين. ثمّ تأتي لغة PHP في المرتبة الثامنة في قائمة أكثر لغات البرمجة شعبية، إذ يستخدمها حوالي 26% من المطورين، أما روبي فتأتي في المرتبة الرابع عشرة بنسبة استخدام تقارب 7%. لا تتمتع بايثون بالشعبية وحسب، ولكنها محبوبة أيضا لدى مجتمع المبرمجين، ففي الاستطلاع نفسه لعام 2020، جاءت بايثون في المرتبة الثالثة كأحب لغات البرمجة إلى المبرمجين، إذ أنّ أكثر من ثلثي المبرمجين المُستطلَعين قالوا أنّهم يحبونها. بالمقابل أتت كل من روبي و PHP في المرتبتين 19 و 20 على التوالي في هذه القائمة، حيث أنّ 43% من المبرمجين قالوا أنّهم يحبون روبي، و37% منهم قالوا أنهم يحبون PHP. هناك فرق واضح بين بايثون وبين PHP وروبي من حيث الشعبية وحب المبرمجين. بايثون بلا شك تتفوق في هذا الجانب تفوقا واضحا. لكن تجدر الإشارة إلى أنّ لغة PHP متخصصة، فهي تكاد تُستخدم حصرا في برمجة الخوادم، على خلاف بايثون وروبي متعدّدتي الأغراض، واللتان تُستخدمان في كل المجالات تقريبا. لذا رغم أنّ شعبية PHP أقل من بايثون، إلا أنّ هذا لا يقلل من قيمتها، ولا يعني أنّها غير مفيدة أو أنّه ليس لها مستقبل. بل على العكس، فهذا دليل على قوتها، لتتأكد من هذا حاول مقارنة شعبية PHP بلغة البرمجة ASP المتخصصة في المجال نفسه (برمجة الخوادم). لغة ASP ليست موجودة حتى في قائمة أكثر 25 لغة البرمجة استخدامًا. وهذا يعطيك فكرة عن قوة PHP وشعبيتها رغم أنّها لغة متخصصة في مجال واحد فقط. من جهة أخرى، لغتا PHP وروبي ليست محبوبتين للمبرمجين، إذ احتلّتا مرتبتين متأخرتين في قائمة أكثر اللغات المحبوبة. الدعم والاستقرار لغات بايثون وروبي PHP لغات مفتوحة المصدر، وتتمتع بمجتمع كبير من المبرمجين، وتُستخدم على نطاق واسع في المشاريع البحثية والتجارية. ظهرت هذه اللغات الثلاث في أوقات متقاربة: PHP: ظهرت سنة 1995، وهي في الإصدار 7.3 حاليا. بايثون: ظهرت سنة 1991، وهي في الإصدار 3.8 حاليا روبي: ظهرت سنة 1995، وهي في الإصدار 2.7 حاليا ما فتئت هذه اللغات تتطور منذ تأسيسها، خصوصا بايثون و PHP اللتان تُحدَّثان بوتيرة سريعة. كما تتمتع هذه اللغات بمجتمعات كبيرة وحيوية تدعمها، سواء عبر المكتبات أو المقالات أو الدروس والشروح. هناك مسألة يجدر الانتباه لها، وهي أّنه يوجد من بايثون إصداران: الإصدار 2.x والإصدار 3.x. وهما إصداران غير متوافقين، فالبرامج المكتوبة ببايثون 2.x، لن تعمل على بايثون 3.x، والعكس صحيح. هذا الأمر يمكن أن يكون مزعجا، خصوصا للمبتدئين. ولكن لا ينبغي أن تقلق من هذا، إذ أنّ دعم بايثون 2.x توقف سنة 2020، وسيبقى الإصدار بايثون 3.x وحسب. هناك ملاحظة أخرى مهمة، وهي أنّ لغة PHP انتقلت من الإصدار 5 إلى الإصدار 7 مباشرة، إذ أنّه ليس هناك إصدار سادس من هذه اللغة. السبب في ذلك هو أنّه كانت هناك خلافات كثيرة عليها، لذلك انتقل المطورون إلى الإصدار السابع مباشرة، والذي جاء بتعديلات كثيرة وجذرية على اللغة. يُفضل على العموم العمل بهذا الإصدار، لأنه الأحدث، كما أنّ بعض أنظمة إدارة المحتوى، مثل ووردبريس، تتطلب استخدام الإصدار السابع. هذه اللغات الثلاث على العموم مستقرة وتتمتع بدعم كبير وتُحدَّث باستمرار. وستبقى كذلك على الأرجح لمدة طويلة. الأمن لقد أصبح موضوع الأمن الرقمي والخصوصية من المواضيع المهمّة في الوقت الحالي. فكل يوم نسمع عن حالات اختراق وسرقة للبيانات الحساسة، حتى لدى الشركات الكبيرة مثل فيسبوك وجوجل. لهذا السبب ينبغي أن يحرص المبرمج على تأمين تطبيقاته وبرامجه وحماية خصوصيات المستخدمين وبياناتهم الحساسة. لا توجد عمومًا لغة برمجة آمنة تماما، فالأمر لا يعود إلى اللغة أو المنصة المُستخدمة، ولكن يعود إلى مدى احترام المبرمج لمعايير الأمن وكتابة شيفرات نظيفة وخالية من الثغرات الأمنية. قد تجد البعض يقول أنّ PHP أقل أمانا من بايثون وروبي، أو أنها لغة غير آمنة، وهذا أمر مردود. فلو كانت PHP غير آمنة، أنظنّ أنّ أكبر شبكة اجتماعية في العالم، وهي فيسبوك التي تخزن أكبر قاعدة بيانات للبيانات الشخصية للمستخدمين ستستخدم PHP؟ هذا غير ممكن. PHP مثلها مثل بايثون أو روبي، هي لغة مستقرة ويسهر عليها آلاف المطورين الذين يحدثونها باستمرار ويحرصون على سد أيّ ثغرة تظهر فيها. ربما كان السبب الذي يجعل البعض يقول هذا هو أنّ صياغة بايثون البسيطة تقلل من احتمال وجود ثغرات في الشفرة، وذلك على خلاف PHP التي تُعد أعقد من بايثون. قد يكون هذا الأمر صحيحا نسبيا، لكنّ الأمر يعود في النهاية إلى المبرمج، إن كان المبرمج يرتكب أخطاء ولا يحترم معايير الأمن، فلن تكون برامجه آمنة مهما كانت اللغة التي يكتب بها. الأداء والسرعة سرعة التنفيذ هي إحدى العوامل الأساسية لاختيار لغات البرمجة، خصوصا في المجالات التي تحتاج إلى إجراء حسابات مكثّفة، مثل الرسوميات وتطوير الألعاب. هناك نوعان من لغات البرمجة: لغات البرمجة المُفسّرة (interpreted): هي لغات برمجة يتم تنفيذ الشفرات المكتوبة بها مباشرة. لغات البرمجة الُمصرّفة (compiled): هي لغات برمجة تُصرّف (تُترجم) شفراتها إلى لغة المُجمّع أو أيّ لغة وسيطة قبل تنفيذها. على العموم، لغات البرمجة المصرّفة أسرع من لغات البرمجة المفسّرة. تُعد كل من بايثون وروبي لغتين مفسرتين، أما PHP فرغم أنّها مفسرة على العموم، إلا أنّ أنّ البرنامج الذي يسمح لك بتفسير تعليمات PHP مُصرَّف إلى رُقامة (bytecode) وسيطة. لهذا السبب فإنّ PHP عموما أسرع من بايثون، كما أنّ بايثون عموما أسرع من روبي. المكتبات وإطارات العمل تُقاس قوة كل لغة برمجة بالمكتبات التي توفرها. المكتبات هي حُزم من الشفرات الجاهزة والمنظمة التي تقدم دوالا وأصنافًا جاهزة لحل مشاكل معينة، أو إنشاء تطبيقات في مجال معين. أما إطارات العمل فهي منصات للبرمجة والتطوير، وعادة ما توفر أدوات تساعد على إنشاء المشاريع وإدارتها، وتنفيذ الشفرات وتنقيح الأخطاء وغيرها من المهام اليومية التي تسهل عمل المبرمجين. سوف نستعرض في هذه الفقرة بعض المكتبات وإطارات العمل الشهيرة للغات بايثون وروبي و PHP. بايثون Django: هو إطار عمل مجاني ومفتوح المصدر لتطوير المواقع. يوفر Django العديد من المزايا، مثل إدارة قواعد البيانات والمصادقة (authentication) وإدارة المستخدمين وغيرها. pycharm: هو إطار عمل لكتابة البرامج بلغة بايثون، يتولى pycharm التفاصيل الروتينية، ويتيح لك أن تركز على المهام الكبيرة والمعقدة. pycharm هو بيئة تطوير متكاملة، ويوفر العديد من المزايا، مثل الإكمال التلقائي للشفرات وفحص الأخطاء وإدارة المشاريع وغيرها. TensorFlow: هي مكتبة مجانية ومفتوحة المصدر للذكاء الاصطناعي من تطوير شركة جوجل. تُستخدم TensorFlow لكتابة وتقديم خوارزميات الذكاء الاصطناعي والتعلم الآلي والعصبونات. تُستخدم TensorFlow في العديد من مشاريع الذكاء الاصطناعي، مثل البحث الصوتي في جوجل. PyGame: مكتبة لتطوير ألعاب الفيديو، وتوفر العديد من المكتبات لمعالجة الصوت والصورة وكل الجوانب الضرورية لتطوير الألعاب. روبي Ruby on Rails: هو إطار عمل لتطوير تطبيقات الويب، ويوفر كل المزايا والوظائف التي تحتاجها لتطوير تطبيقات ومواقع ويب متقدمة. هذا الإطار مفتوح المصدر ومجاني. Bundler: هي بيئة متكاملة لإدارة مشاريع روبي تمكن من تثبيت المكتبات ومعالجة الإصدارات بسهولة. Better_errors: مكتبة لاختبار الشفرات المكتوبة بلغة روبي وتنقيح الأخطاء. PHP Laravel: أحد أشهر إطارات العمل الخاصة بلغة PHP. يُسرّع Laravel وتيرة العمل على المشاريع الكبيرة، إذ يوفر الكثير من المزايا الجاهزة، مثل المصادقة على المستخدمين وإدارة الجلسات والتخزين المؤقت وغيرها من المهام الأساسية لتطوير تطبيقات الويب. ووردبريس: ووردبريس هو أشهر نظام لإدارة المحتوى، ويُشغِّل ملايين المواقع على الشبكة. هذه المنصة مبنية على PHP. Ratchet: تمكّن هذه المكتبة من إنشاء تطبيقات ثنائية الاتجاه بين الخادم والعميل. تتوفر بايثون وروبي و PHP على المئات إن لم أقل الآلاف من المكتبات وإطارات العمل، وكل سنة تظهر مكتبات وإطارات عمل جديدة تستبدل القديمة أو تنافسها. مهما كانت اللغة التي اخترتها، ومهما كان المجال الذي تعمل فيه، فستجد حتمًا مكتبات جاهزة لمساعدتك على كتابة برامجك. الطلب في سوق العمل الطلب في سوق العمل هو أحد المؤشرات الأساسية للموازنة بين لغات البرمجة، خصوصا لمن كان يبحث عن وظيفة. بحسب استطلاع stackoverflow، فإنّ مطوري روبي يحصلون على أعلى أجر موازنة بمطوري بايثون و PHP. إذ يحصل مطور روبي في المتوسط على 71 ألف دولار سنويا، أما مطور بايثون فيحصل على 59 ألف دولار سنويا، بالمقابل لا يحصل مطور PHP إلا على 39 ألف دولار سنويا. من الواضح أنّ روبي هي الأفضل من حيث الأجور وفرص العمل، وقد يعود ذلك إلى قلة من يتقنون روبي، فقد رأينا من قبل أنّ شعبيتها بين المبرمجين قليلة موازنة ببايثون أو حتى PHP. هذه الأرقام تُحسب على صعيد عالمي، لكن قد يختلف الواقع من دولة إلى أخرى، مثلا في السعودية يحصل مطور PHP سنويا على حوالي 16 ألف دولار [4]، فيما يحص مطور بايثون على حوالي 18 ألف دولار سنويا [5]. أجور مطوّري PHP على العموم أقل من أجور مطوري بايثون وروبي، لكنّ الرواتب لا تُحدد بلغة البرمجة وحسب، إذ يمكن أن يحصل مطوّر PHP محترف وذو خبرة على أكثر مما يحصل عليه مطورو بايثون أو روبي، فالعبرة هنا بالاحترافِية وإتقان العمل. محاسن ومساوئ كل لغة بايثون محاسن مساوئ سهلة التعلم ومناسبة للمبتدئين هناك إصداران غير متوافقان منها صياغة بايثون بسيطة وقريبة من اللغة الطبيعية التعامل مع الأخطاء ليس مثاليا مختصرة وموجزة غير مناسبة لتطبيقات الجوال تتمتع بشعبية كبيرة لدى المبرمجين ليست مثالية للبرامج التي تعتمد على الاستخدام المكثف للذاكرة مكتبة ضخمة تساعد على تطوير كافة أنواع التطبيقات ليست مناسبة للبرامج المتوازية التي تعمل على المعالجات المتعددة روبي محاسن مساوئ مناسبة للبرامج الكبيرة صعبة على المبتدئين تمكن من تطوير التطبيقات بسرعة مصادر تعلم روبي على العموم أقل من بايثون و PHP مجتمع نشيط وحيوي ومكتبة كبيرة بطيئة موازنة باللغات الأخرى تتوفر على إحدى أفضل منصات تطوير تطبيقات الويب: ruby on rails التطوير والتحديث بطيئ PHP محاسن مساوئ سهلة التعلم صياغتها ليست ببساطة بايثون تدعم جميع خوادم الويب الرئيسية مثل: أباتشي ومايكروسوفت و Netscape أسماء الدوال مربكة وغير متناسقة لها شعبية كبيرة جدا لدى مطوري الويب بطيئة موازنة باللغات الأخرى مدعومة من أكبر نظام لإدارة المحتوى، وهو ووردبريس لا تدعم التطبيقات المتوازية خلاصة القول لقد استعرضنا مميزات لغات بايثون وروبي و PHP، ووازنّا بينها من عدة جوانب، وذكرنا بعض مساوئ ومحاسن كل منها. خلاصة القول أنّه لا توجد لغة مثالية تصلح للجميع. لكن إن كنت مبتدئا ولم تكن لك خبرة سابقة بالبرمجة، فإني أنصحك بأن تبدأ بلغة بايثون، فبساطتها وسهولتها ستساعدك على هضم المفاهيم البرمجية بسرعة وبعدها يمكنك أن تنتقل إلى تعلم اللغة التي تريدها بخطى ثابتة وأنت متمكن من المفاهيم البرمجية الأساسية التي تشترك بها كل لغات البرمجة. أما إن كانت لك خبرة سابقة في البرمجة وأردت أن تطور مستواك وتعمل على مشاريع كبيرة، فيمكن أن تتعلم روبي. وإن كنت تريد أن تتخصص في تطوير تطبيقات الويب أو تريد العمل بووردبريس، فالأولَى أن تتعلم PHP. اقرأ أيضًا تعرف على أبرز مميزات لغة بايثون علم البيانات Data science: الدليل الشامل1 نقطة
-
يحتاج كلّ رائد أعمال منذ انطلاقته، إلى خطّة عمل. وخاصّةً في المراحل المبكّرة من شركته، حين يكون من السّهل فقدان التّركيز. ذلك أنّ خطّة العمل المكتوبة تساعد على إعادته إلى فكرته الأصليّة. ويمكن تقسيم خطط العمل إلى أربعة أنواع مختلفة: الخطّة التّشغيليّة. الخطّة الإستراتيجيّة. الخطّة التّكتيكيّة. الخطّة الاحتياطيّة. سنركّز في هذا المقال على الخطّة التّشغيليّة، وهي مجموع النّشاطات الّتي لا يتحتّم على رائد الأعمال أو مالكها تنفيذها، ذلك أنّ هذه النّشاطات وكيفيّة تقديمها إلى العملاء هي بمثابة مفتاح رئيسيّ في نجاح الشّركة طويل الأمد. الخطة التشغيلية للأعمال في بدايات القرن العشرين، أدخل المهندس الميكانيكي ومستشار الإدارة فريدريك تايلور تقنيات الإدارة العلميّة على مجال التّصنيع، وتطوّر بعدها التّخطيط التّشغيليّ ليصبح واحدًا من أهمّ مكوّنات إدارة الأعمال، إذ تُفصّل الخطّة التّشغيليّة إجابات الأسئلة التّالية المتعلّقة بنشاطات الشّركة: ما هي أنشطة العمل؟ ومتى تحدث؟ ومن المسؤول عنها عند حدوثها؟ وكم يستغرق كلّ نشاط؟ وما هي الأدوات أو المعدّات الضرورية لتلك الأنشطة؟ وما هو مقدار الوقت والتمويل الضّرورين لتنفيذها؟ يجب أن تكون خطط الأعمال التشغيلية مرنةً بما يكفي للتكيُّف مع التحدّيات الّتي ستواجهها، إذ ينبغي إجراء بعض التغييرات الصّغيرة يوميًّا أو حتى كلّ ساعة، فيما تحصل التّغييرات الضّروريّة المعتبرة مرّةً أو اثنتين على مدار العام، لكنّ الغاية الأساسيّة من وراء الخطّة التّشغيليّة هي توفير الإرشاد والتّوجيه، إذ يعرف من خلالها كلّ فرد في الشّركة وظائفه المحدّدة، ومن المسؤول عن المهام الفرديّة، ومتى تقع الأحداث الكبرى. أنشئ جدولًا أو مخططًا على برنامج إكسل Excel أو جووجل شيتس Google Sheets أو أيّ برنامج مخطّطات آخر ليساعدك على التّخطيط والجدوَلة. يوضّح الشّكل 8.12 كيفيّة جدولة المهام في متجر بقالة على برنامج ميكروسوفت إكسل، حيث تُعَنوَن الأعمدة بالأنشطة الوظيفيّة، ومهام العمل المحددة، ونوبات العمل، أو محطّات العمل؛ أمّا ساعات العمليّات فمسجّلة على الأسطر، ثمّ تُدخل أسماء الموظّفين في الخانات المناسبة لتوضيح المسؤول عن كلّ مهمّة أو محطّة عمل. ولا يظهر الجدول كلّ منصب، ولكنّه يحمل ما يكفي ليعطيك فكرةً عن كيفيّة استخدام التّنسيق ذاته في نشاطك التّجاريّ. الشكل 8.12: يُظهر هذا الجدول جدول مواعيد محّطات العمل بالسّاعة. حفظ الحقوق: تصميم مسجّل باسم جامعة رايس، OpenStax، تحت ترخيص CC BY 4.0 يعرض هذا النوع من الجدول الزمني كلّ منصب وظيفيّ، والسّاعات، والساعات التي يجب تغطية كلّ منصب فيها، وكذا الموظف الذي عُيّن لهذه الوظيفة في أيّ وقت. حيث يمكن للمدير إلقاء نظرة على هذا الجدول ومعرفة أنّه قد عُيِّن موظف كلّ وظيفة خلال فترة زمنية محددة، وإذا لم يُنهى العمل، فهذا النوع من الجدول الزمني قد يساعد المدير في اتخاذ قرار بشأن تعيين المزيد من الموظفين أو تغيير بعضهم، كما يسمح للمدير في حالة حدوث مشكلة ما بمعرفة من الموظّف الّذي كان يعمل وقتها، مما يسهّل حلّها؛ كما يمكّن الجدول المدير من تغيير أوقات العمل إذا لم يكن أحد الموظّفين قادرًا على أداء ورديّته، وهذا يضمن إتمام كلّ مهمّة في وقتها، وشغل كلّ منصب طول وقت العمل. يمكن أيضًا عرض الجداول الفردية، ومحطّات العمل المخصصة في ورقة عمل (الشّكل 9.12)، وهذا يسمح للمدير بجدوَلة الموظف لعدد الساعات المناسب في الأسبوع، ويساعد في حساب المرتبات، كما يعرف الموظفون بفضل هذا الجدول أماكن عملهم، ومتى من المقرر أخذهم لاستراحات الغداء أو العشاء. الشكل 8.12: يظهر هذا الجدول جدول معمل الموظّفين بالسّاعة. حفظ الحقوق: تصميم مسجّل باسم جامعة رايس، OpenStax، تحت ترخيص CC BY 4.0 يجلب استخدام أدوات مثل جداول البيانات لجدولة العمليات اليومية وإدارتها، التنظيم والاستقرار، حيث يعرف المديرون أنّ لكلّ مهمّة شخصًا معيّنًا، كما يعرف الموظفون المكان الذي يجب أن يكونوا فيه أو ما يجب عليهم فعله على مدار اليوم. تحتاج الأعمال المعقدة مع العديد من الموظفين والعديد من الوظائف، إلى مزيد من التخطيط والهيكل، وقد تكون الشركات التي لديها عدد قليل جدًا من الموظفين أقلّ تنظيماً، ومع ذلك يجب أن تسرد الخطة المكتوبة معظم المهام والأنشطة التي يجب إنجازها، ومن سينجزها بها، ومتى. .addtional__paragraph { border: 3px solid #f5f5f5; margin: 20px 0 14px; position: relative; display: block; padding: 25px 30px; } رائد أعمال في الميدان تبدو الجدولة أمرا يسيرا قد يكون من الصّعب جدولة أدوات وأجزاء عمليّة ثابتة، لكنّ الأصعب والأكثر تحدّيًا هو تنظيم جدول مواعيدك الشّخصيّ مع احتياجات "رعاية الأطفال حسب الطّلب" قرب مكان عملك. أخذت آفني باتل تومسون هذا التّحدي على عاتقها حين أطلقت بوبي Poppy سنة 2015، وهي شركة رعاية أطفال حسب الطّلب. من الصّعب تعيين الموظّفين وجلب العملاء إلى أيّ عمل، فكيف إذا كان نموذج عمل شركتك متمركزًا حول عملاء ذوي طلبات غير محدّدة الوقت، وموظّفين يريدون دخلًا ثابتًا. عندها ستحتاج إلى حلّ عالي التّقنية، ولهذا كانت بابي تطبيقًا هاتفيًّا يطلب من خلاله الأولياء المشغولون رعايةً لأطفالهم، فيفحص التّطبيق كلّ الموظّفين المتاحين في المدة الّتي اختارها الوليّ، والمقيمين قريبًا منه. وبعد إنهاء التّطبيق لعمله، يتّخذ موظّف القرار النّهائيّ ويؤكِّد راعي الأطفال للعائلة. فشلت الشّركة للأسف بسبب الظّروف الاقتصاديّة المحيطة بمجال رعاية الأطفال، واضطرّت إلى الإقفال في ديسمبر 2018، لكنّ نموذج عملها مثال جيّد عن إحدى طرائق حلّ مشاكل الجدولة المستعصية. لماذا التّطبيق أفضل في متطلّبات الجدولة هذه من موظّفين بدوام كامل؟ ما هي المتطلّبات الواجبة على العميل؟ والموظّف؟ والشّركة؟ هل يمكن لتطبيق جديد اجتياز عوامل التّسويق والاقتصاد؟ ما مدى نجاعة هذه التقنية؟ وما هي التّهديدات المحتملة لطريقة الجدولة التّقليديّة عندما تتطوّر التّقنية؟ بالنسبة للمهام التي تتطلّب الانتباه على أساس شهري أو ربع سنوي أو سنوي، فقد يكون المنظّم أو التقويم البسيط أداةً ممتازةً للمساعدة في التنظيم، وتذكيرك بما يجب القيام به، ومتى يجب ذلك. تشمل المهام التي يجب عليك إكمالها في الوقت المحدد طوال العام ودائع وتقارير ضرائب الرواتب، وطلبات تجديد التأمين، والتصاريح وتجديد التراخيص، ومتطلّبات تدريب الموظفين وإعادة التأهيل، وفواتير الحساب لعملاء معيَّنين. قد يساعدك التقويم أيضًا في جدولة الأنشطة الإعلانية والتسويقيّة، إذ تحدث بعض الأحداث بانتظام كلّ عام في نفس الوقت أو ضمن إطار زمني معروف، وذلك قد يساعد على تذكيرك بوقت بدء حملاتك الإعلانية والتسويقية. يمكنك التخطيط لعمليات الصيانة والإصلاح الرئيسية مسبقًا أو تتّبع الزيادات المجدوَلة في الأسعار، وزيادات الأجور، وإضافة عناصر القائمة أو إزالتها، وإعادة ترتيب الرفوف للمنتجات الموسمية، وأنشطة التنظيف أو الصيانة الرئيسية. عندما تبدأ عملك، قد تحتاج إلى إجراء بعض التعديلات على خطتك التشغيلية، وقد يتغاضى رائد الأعمال عن العوامل التي تحدث بانتظام، أو يرى أنّ تأثير بعض العوامل ضئيل، والواقع عكس ذلك، فبمجرد فتح العمل قد يتصرّف العملاء والمنافسون عكس المتوقَّع، كما قد يكون لدى الموظّفين مجموعات مهارات حُذِفت من الخطّة المكتوبة، أو قد يفتقرون إلى مجموعات المهارات المطلوبة. لذا فحتى الخطة التشغيلية المكتوبة جيدًا ستحتاج على الأرجح إلى التعديل بعد وقت قصير من بدء العمليات، ولكن إذا صِغتَ خطّتك بطريقة صحيحة في البداية، فنادرًا ما ستحتاج خطّتك التشغيلية الوظيفية إلى إصلاح شامل. المراقبة العنصر الّذي يجب تضمينه في كلّ خطة تشغيلية هو التحكم، سواءً في الخطة التشغيلية، أو خطة التسويق، أو خطة تطوير الموظف، أو أيّ نوع آخر من الخطط المستخدمة في الأعمال. ونعني بالمراقبة، قياس النتائج وتقييم الأنشطة التي أدّت إليها. يُجيب عنصر التحكّم في خطط العمل على الأسئلة، "هل أنجزنا ما أردنا تحقيقه؟" و "هل حقّقنا أهدافنا في الإطار الزمني الذي أردناه؟" وبدون قياس نتائج الأداء، لا يعرف رائد الأعمال ما إذا كانت الشركة تعمل كما هو متوقَّع، أو أسوأ من المتوقَّع، أو أفضل مما كان متوقَّعًا. إذا كان أداء العمل التجاري أفضل من المتوقَّع، فيجب على صاحب المشروع التفكير فيما إذا كانت التوقّعات الأصلية منخفضةً جدًا أو إذا كان هناك عامل آخر ساهم في الأداء الأفضل من المتوقَّع. من ناحية أخرى، إذا كان أداء العمل أسوأ من المتوقَّع، فيجب إجراء مراجعتين. أولها، لماذا النتائج أقلّ من المتوقَّع؟ وما الذي يمكن تغييره لتحسين الأداء؟ ثانيًا، كيف تؤثّر النتائج المنخفضة على جدوى العمل؟ تُعَدّ موازنة النتائج الفعلية بالنتائج المتوقَّعة نوعًا من الموازنة الداخلية، ويسمى "تحديد المرجع" "baselining"، وهو مهمٌّ للغايّة لأنّ على صاحب المشروع إجراء تقييمٍ ذاتيّ لما أنجزته الشركة مقابل ما يمكنها فعله أو ما ينبغي لها فعله. يمكن لرائد الأعمال أن يقرِّر تعديل قدرة العمل بعد إجراء دراسة مرجعيّة، ومع ذلك يجب أن تقترن الموازنات الداخلية بتحليل خارجي يسمّى قياس الأداء ("المعيار": benchmarking)، من خلال موازنة نشاطك التجاري بمنافس قريب أو بمتوسط الصناعة، ويمكنك الحصول على فكرة أفضل عن كيفية تناسُب نشاطك التجاري مع السوق الأكبر. معايير الصناعة إذا سجَّل فريق كرة السلة 68 نقطة، فهل يفوز؟ إذا قطع سبّاح مسافة 100 متر خلال 20 ثانية، هل يحتل المركز الأول؟ وإذا سجل فريق كرة قدم هدفين، فهل يخسر؟ الإجابة على الأسئلة الثلاثة بسيطة: نحتاج إلى مزيد من المعلومات، فبدون معرفة نتيجة الفريق الآخر، لا نعرف ما إذا كان الفريق قد فاز أو خسر، أي يجب أن تكون هناك بعض النقاط الأخرى للموازنة، وإلا فمعرفة النّقاط المسجّلة لا معنى له. وبالمثل، تحتاج الشركات إلى موازنة أدائها الفردي ببعض مقاييس الأداء الخارجية، تسمى الموازنة مع متوسط الصناعة، أو الرائد داخل الصناعة، أو شريحة السوق، بالموازنة المعيارية benchmarking . وهي تسمح بإجراء موازنة مباشرة لشركتك مع طرف آخر، إمّا رائد الصّناعة، أو متوسّط السّوق، أو معطيات الصّناعة كلّها. وذلك من خلال النظر في العديد من مقاييس الأداء. حيث يمكنك معرفة ما إذا كان أداء شركتك بمستوى يحافظ على نفسها على المدى الطويل، أو ما إذا كان السوق المحلي لشركتك غير عادي قياسًا مع سوق شركة أخرى. فإذا كان مستوى أداء شركة ناشئة لا يتطابق مع متوسّط الصناعة أو قائد الصناعة، فهذا لا يعني أنّ الشركة تُدار بطريقة سيّئة، ولا أنّها لن تكون مربحة. وفي كثير من الأحيان، تكون الموازنة مع منطقة السوق المحلية أفضل من الموازنة مع الرّائدين الوطنيين أو الصناعة ككلّ. الاحتياجات التشغيلية السؤال الأول الذي يجب عليك طرحه عند بدء عملك، هو ما إذا كان أيّ شخص يريد شراء منتجك أو خدمتك، فمن السهل إنشاء منتج أو خدمة جديدة، ففي الواقع من 70 إلى ما يفوق 95% من المنتجات الجديدة سنويًا تُعَدّ فاشلة. ومع هذا المعدَّل المنخفض للنجاح، ستحتاج إلى إجراء بحث دقيق وتشغيل تجريبيّ صغير لتحديد جدوى منتجاتك الجديدة.، إذ لا تحتاج فقط إلى معرفة ما إذا كان أيّ شخص سيشتري منتجاتك، ولكن ما إذا كان العملاء سيدفعون السعر الّذي حدّدته، لكي تحقّق الشّركة ربحًا، أو على الأقّل نقطة التعادل. أنت بحاجة لطرح هذين السؤالين المهمين جدًا مقدّمًا، لأنه إذا كانت الإجابة على أيّ منهما "لا"، فلا داعي لفعل أيّ شيء آخر. تُركِّز السلسلة الثانية من الأسئلة التي تحتاج إلى معالجتها على موقع عمليات الشركة. أين سوف تفتتح عملك؟ هل ستستأجر أو تشتري مبنى أو منشأة؟ هل تحتاج منشأتك إلى سهولة الوصول إليها في منطقة ذات كثافة مرورية عالية؟ أو قد تكون في منطقة أكثر هدوءًا، حيث تكون التكاليف أقلّ؟ بالإضافة إلى الوصول والتكاليف، هل سيكون عملك ضمن مجال تأثير المنافس الجغرافي؟ إذ سيكون من المؤسف تجاهلك لجميع العوامل الإيجابية لمنتجك الرائع وخطة عملك القابلة للتطبيق عن طريق اختيار الموقع الخطأ. إلى جانب تحديد الموقع المناسب، ستحتاج أيضًا إلى مراعاة حجم منشأتك، فقد يؤدّي اختيار هيكل صغير جدًا من البداية إلى إعاقة أيّ نمو في المراحل الأولى من عملك، كما قد يكون الاضطرار إلى الانتقال إلى منشأة أكبر بعد وقت قصير من بدء العمليات ضارًا بعملياتك. من ناحية أخرى، فاختيار منشأة كبيرة جدًا، سيضغط على التدفق النقدي، حيث ستدفع إيجارًا أو رهنًا مقابل مساحة بناء غير منتجة. لذا فإيجاد التوازن بين "كبير بما يكفي للنمو" و "صغير بما يكفي لتحمل انخفاض المبيعات" هو مأزق يواجهه العديد من أصحاب الأعمال، سواءً كانوا رواد أعمال جدد أو قدامى محنّكين. ستحتاج إلى اتخاذ قرارات مماثلة بشأن الأثاث، والمعدّات، والمفروشات. أي هل هذه العناصر متاحة للشراء أو الإيجار؟ في بعض الأحيان يكون عقد الإيجار أفضل، حيث تكون المدفوعات الأولية أقلّ، ولكن بمرور الوقت قد يساعد شراء المعدّات والأثاث في تحسين التدفق النقدي بمجرّد دفع ثمنها. ومع ذلك فمن الصّعب تحديد مقدار الكمّ، والجودة، والحجم. وقد يساعد مندوبو مبيعات المعدّات الجيدون في اتخاذ قرارات المعدّات. للبدء، سوف تحتاج إلى تحديد مستويات المخزون المناسبة. ما هي مدة صلاحية مخزونك؟ إذ تتمتع بعض المنتجات بعمر افتراضي طويل، بينما قد يهلك البعض الآخر بسرعة، لذا اسأل نفسك "كم أحتاج؟"، و"متى سأحتاجه؟" وستحتاج قبل بدء عمل تجاري إلى تراخيص وتصاريح، إذ يجب فحص المباني والموافقة عليها قبل دخولها لبدء العمل، وقد تتطلب تصاريح البناء عمليات التفتيش الكهربائية، والسباكة، والتكييف، والتفتيش الهيكلي، لهذا يجب اتّخاذ إجراءات لجلب المياه، والغاز، وجمع القمامة قبل شغل المنشأة. يلخِّص الجدول 3.12 الاحتياجات التشغيلية التي يجب مراعاتها عند بدء مشروع. قائمة الاحتياجات التشغيلية 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; } البند الأوّل تحديد التّنظيم القانوني لشركتك (الملكية الفردية أو المشتركة أو المنظّمة)، واختيار الهيكل القانوني للعمليات والإدارة في شركتك (شركة محدودة المسؤولية، شراكة عامة، أو شراكة محدودة، شركة سي، أو منظّمة آس). البند الثاني قرّر اسمًا لشركتك، فهذا الاسم سيصبح الاسم القانوني في التعاملات الحكومية، ويمكن اختيار أيّ اسم لا تستخدمه شركة أخرى.، كما يمكن أن يختلف الاسم التجاري عن الاسم الرّسمي، على أن يعكس الاسم التّجاري طبيعة المنتج أو الصّناعة. البند الثالث تحرّر أنت وأيّ مسؤولين آخرين في نشاطك، ووافِقوا على كلّ بنود التّأسيس، أو اللوائح، أو اتفاقيات الإدارة. البند الرابع تقديم الوثائق التّنظيمية إلى الجهة الحكومية المسؤولة حيثما أسّست الشّركة. البند الخامس تقدّم أنت وأيّ مسؤولين آخرين في شركتك مدفوعات مالية إلى الشّركة لبدء حساب بنكي. البند السادس احصل على رقم تعريفي للشّركة من وزارة التجارة أو أيّ جهة تمثّلها في بلدك، وسيكون هذا هو الرقم الجبائي الّذي تستخدمه في الفواتير والوثائق. البند السابع تأكد من إدراج شهادة الاسم التجاري والموافقة عليها في الملفّ التسجيلي، إذا كان يختلف عن اسم الشركة الرسمي. البند الثامن دشِّن رقم هاتف الشركة، وموقعها وبريدها الإلكترونيّين، ونطاقها على الإنترنت، واطبع بطاقات العمل الجديدة. البند التاسع افتح حسابًا جاريًا باسم الشركة واسمها التجاري، وسجّل فيه الموقّعين المصرّح لهم، وقدّم كلّ الوثائق الّتي يطلبها البنك لفتح حساب تجاريّ. أودع تمويلك الابتدائيّ، وثبّت ثمّ جرّب عمليات الإيداع. البند العاشر احرص على توقيعك أنت وشركائك على العقود المتعلّقة بالنشاط التجاري. البند الحادي عشر إشترٍ أو استأجِر مساحةً مكتبيةً. واسعَ إلى الحصول على شهادة حكومية لشغل المبنى، فربّما تحتاج تفتيشًا إضافيًا للمبنى، والسباكة، واحتياطات الحرائق والصحّة، قبل الحصول على التّرخيص. البند الثاني عشر افتتح حسابات المرافق، والماء، والغاز، والكهرباء، والنفايات، والهاتف. البند الثالث عشر انشر الملاحظات المطلوبة في الأماكن المنصوص عليها حسب القواعد المعمول بها في منطقتك. البند الرابع عشر تقدَّم بطلب ترخيص تجاري وتصاريح الموظّفين، وانشرها حيثما تطلبه قواعد منطقتك. البند الخامس عشر اُحصُل على تأمين للمبنى، والمسؤولية التجارية، وتأمينات العمال. البند السادس عشر اِشترِ ورتّب الأثاث، ومرافق المكتب، وما إلى ذلك. البند السابع عشر اِشترِ مخزونك، وسطِّر قائمة منتجاتك مع أسعارها. البند الثامن عشر عيِّن ووظِّف عمّالك. ربّما تحتاج إلى تدريبهم وترخيصهم قبل بدئهم العمل، وتأكد من إنهائهم للتّدريب قبل تدشين عملك،عادةً ما يكون اليوم الأول من العمل حدثًا بسيطًا للتأكُّد من أنّ كلّ شيء يجري كما ينبغي، وأنّ فريقك يعرف مهامه ومسؤولياته. وهذا يعطيك الوقت لتصحيح أيّ أخطاء أو تجاوزات قبل عِلم الرّأي العام ببدء نشاطك. حدِّد افتتاحك الرّسمي الكبير بعد أيام أو حتّى أسابيع من افتتاحك الفعليّ، ويمكنك دعوة المستثمرين، ومسؤولي المنطقة، وأفراد العائلة، والعملاء المميَّزين، ورؤساء العمل السّابقين، وأصحاب الشّركات أو الأنشطة المجاورة، والمنافسين. بهذا تكون قد تعرّفت على كيفية وضع الخطة التشغيلية للأعمال وتسطير قائمة الاحتياجات التّشغيليّة، وسنتابع في المقال الموالي في ذكر تتمة كيفية وضع الخطة التشغيلية من ناحية مجال إدارة العمليات. ترجمة وبتصرف للفصل Building Networks and Foundations من كتاب Entrepreneurship. اقرأ أيضًا المقال التالي: إدارة العمليات في الخطة التشغيلية للأعمال المقال السابق: تشكيل فريق الأحلام الريادي أفضل الوسائل لحل معضلة الدجاجة والبيضة للشركات الناشئة أفضل الطرق للبدء بكسب العملاء لشركة ناشئة أفضل برامج لإنشاء قاعدة المعرفة للشركات الناشئة والمشاريع الصغيرة1 نقطة
-
المحتوى هو أحد أهم العناصر في موقع الويب أيًا كان نوعه ووظيفته، إذ بنيت المواقع والتطبيقات للمستخدمين حتى يستفيدوا من محتواها سواء لقراءة أو تعلم أو تسوق وما إلى ذلك. فثبت عبر تجارب سلوكيات المستخدمين أن نصفهم يجرون عمليات البحث ضمن المواقع التي يتصفحونها، ومن هنا نشأت الحاجة إلى استخدام المطورين لأساليب بحث داخلية في مواقعهم، والأفضل من ذلك استخدام محركات بحث داخلية، حيث يوفر محرك البحث الداخلي تجربة أفضل للمستخدم تجعل الوصول إلى ما يريده من الموقع عملية سريعة وبسيطة، خاصة إذا كان الموقع يعرض منتجات تجارية مثلًا ويريد المستخدم أن يبحث عما يريد، أو إذا كان موقع محتوى متخصصًا وأراد المستخدم أن يبحث عن موضوع معين فيه. كم وافر من المحتوى الموجود على الإنترنت موجود باللغة الإنكليزية، وهنالك وسائل ومحركات بحث وفيرة تتيح إمكانية البحث باللغة الإنكليزية، ولكن عندما يأتي الأمر إلى المستخدم العربي والمحتوى العربي، نجد قصورًا في جودة البحث إلى الدرجة التي تجعل البحث الداخلي في المواقع عملية دون فائدة، فأتى محرك البحث العربي لبلب ليحل هذه المشكلة بالاعتماد على أفضل الأساليب والتقنيات، وبمجهود موجه للجمهور المتحدث بالعربية. سنبني في هذا المقال موقع ويب يعرض مقالات، بشكل مبسط، باستخدام Node.js وقاعدة بيانات MySQL (أو MariaDB) وسنرى معًا الفارق بين وظيفة البحث التي سننشئها يدويًا، وبين نتائج البحث التي يعطينا إياها لبلب عند استخدامه في الموقع، فهيا بنا. جدول المحتويات التهيئة الأولية للمشروع تصميم الصفحات تهيئة إدارة قواعد البيانات وإنشاء الموجهات Routes إضافة المقالات بناء عملية البحث اعتمادًا على قاعدة البيانات مفاهيم متعلقة بمحرك البحث الداخلي تهيئة حزمة لبلب بناء عملية الفهرسة Indexing تعديل عملية البحث وتجارب البحث تجارب البحث باستخدام لبلب الخلاصة التهيئة الأولية للمشروع سننشئ مجلدًا جديدًا باسم my-blog للمشروع ونفتحه باستخدام محرر Visual Studio Code وبعدها نفتح نافذة سطر الأوامر، وننفذ الأمر التالي فيها لإنشاء مشروع Node.js جديد: npm init اختر ملف الانطلاق app.js عند السؤال عن ذلك ثم أنشئه بعدها في جذر المجلد بإنشاء ملف جديد ضمن محرر الأكواد vscode. يجب أن ننتبه إلى أهمية تنظيم ملفات عمل المشروع، فمن المهم جدًا أن تكون أسماء المجلدات دالةً على وظيفتها، وأن تكون الملفات مقسمةً تقسيمًا صحيحًا. علينا أن ننشِئ مجلدًا للضبط باسم config ونضع بداخله ملفًا لإنشاء قاعدة البيانات والجدول articles إن لم تكن موجودةً، لكن قبل ذلك، علينا أن نثبت بعض الحزم من مدير الحزم npm لتضمين الوحدات modules التي تلزمنا في عملنا. اكتب ما يلي في سطر الأوامر: npm install express express-session body-parser sequelize uuid ejs mysql سنشرح سريعًا وظيفة كل حزمة من الحزم السابقة: express: هي إطار العمل المساعد في تطبيقات node.js، وحزمة express-session هي حزمة تعريف الجلسة لكل مستخدم حيث ستفيدنا في عملية البحث. body-parser: هي الأداة التي ستساعدنا في قراءة الطلبات requests. sequelize: هي عبارة عن orm (وسيلة تواصل بين الخادم وقاعدة البيانات تتولى جميع الاستفسارات بين التطبيق والخادم وقاعدة البيانات) سيساعدنا في إدارة عمليات قاعدة البيانات. uuid: هي أداة تولد معرفات فريدة عالميًا. ejs: هي محرك العرض الذي سنستخدمه لعرض صفحاتنا. mysql: هي حزمة للتواصل مع قواعد البيانات. يمكنك الرجوع دائمًا إلى موقع npm لمعرفة المزيد عن هذه الحزم. سننشِئ قاعدة بيانات باسم myBlog، سنبدأ بكتابة الملف dbCreation.js ضمن مجلد config كما يلي، لا تنسَ تغيير معلومات الاتصال من المستخدم الجذر root أو أي مستخدم آخر وتغيير كلمة المرور password إلى كلمة المرور الخاصة بك: //تنفذ الأوامر الموجودة فى هذا الملف فى بداية إنشاء المشروع فقط let mysql = require('mysql'); //معلومات الاتصال بالخادم المحلى let con = mysql.createConnection({ host: "localhost", user: "root", password: "password", multipleStatements: true }); //تعريف أمر إنشاء قاعدة البيانات وإنشاء الجدول المستخدم فى التطبيق let sqlCommand = ` CREATE DATABASE IF NOT EXISTS myBlog CHARACTER SET utf8 COLLATE utf8_general_ci; use myBlog; CREATE TABLE IF NOT EXISTS articles ( id int AUTO_INCREMENT, title varchar(200), author varchar(100), content text, tags varchar(500), createdAt datetime, updatedAt datetime, PRIMARY KEY (id) ); ` con.connect(function(err) { //تنفيذ إنشاء قاعدة البيانات con.query(sqlCommand, function (err, result) { if (err) throw err; }); }); تخزن قاعدة البيانات معلومات كل مقال كما يوضح الكود إذ تحتوي على جدول فيه الحقول الآتية: حقل id رقمي من النوع int والذي يمثل معرِّف المقال وهو المفتاح الرئيسي primary key للجدول، ويزداد تلقائيًا. الحقول title و author و tags لتخزين عنوان المقال واسم كتابها والوسوم المستعملة فيها وذلك على التتالي وبالترتيب، وهي من النوع varchar. الحقل content من النوع text الذي يمثل محتوى المقال. الحقلان createdAt و updatedAt لتخزين متى أُنشِئت المقالة ومتى حدثت، وهما من النوع datetime. بعد إنشاء قاعدة البيانات وضبطها، لنشغل الخادم عبر كتابة الكود التالي في ملف app.js: const express = require("express"); const bodyParser = require("body-parser"); const session = require("express-session"); const uuid = require("uuid"); const errorHandler = require("./middleware/errorHandler"); const db = require("./config/dbCreation"); // لإنشاء التطبيق باستخدام express const app = express(); //تحديد محرك العرض app.set("views", `${__dirname}/views`); app.set("view engine", "ejs"); // خيارات حزمة body-parser app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json({ extended: true })); // تعيين المجلد الحاوي للملفات القابلة للإرسال app.use('/public', express.static('public')); // تحديد المنفذ const port = process.env.PORT || 5000; // تحديد session secret const sessionSecret = "keyboard cat"; // استخدام حزمة الجلسة لتمييز كل مستخدم app.use( session({ genid: (req) => { return uuid.v4(); }, secret: sessionSecret, resave: true, saveUninitialized: true }) ); // استدعاء المستقبل article routes require("./routes/article.routes")(app); // معالجة الأخطاء app.use(errorHandler); app.listen(port, () => { console.log(`server is up, listening on port ${port}`); }); بناء على ما كتبناه هنا، علينا إنشاء مجلد views على جذر المشروع وهو ما سيحوي صفحات العرض والتي سيكون امتدادها ejs حيث خصصنا ejs كمحرك للعرض، كما سننشئ مجلدًا اسمه public يحوي ملفًا اسمه style.css حيث عيننا هذا المجلد على أن محتوياته قابلة للإرسال إلى حاسوب العميل. تصميم الصفحات سنحتاج في مشروعنا هذا إلى الصفحات التالية: الصفحة الرئيسية (فيها عرض للمقالات أو لنتائج البحث). صفحة عرض المقالة. صفحة إنشاء المقالة. إن أمعنا النظر فسنجد أن الترويسة والتذييل لهذه الصفحات نفسها، فلا حاجة لتكرار الشيفرات نفسها في أكثر من ملف، لذا سنقسم الملفات إلى الملفات التي سيلي ذكرها في هذا القسم. سننشئ ضمن المجلد views ملفًا نسميه header.ejs يحوي الشيفرة التالية: <!DOCTYPE html> <html lang="ar"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>مدونتي</title> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css"> <link rel="stylesheet" href="../public/style.css"> </head> <body> <nav class="navbar fixed-top navbar-expand-md "> <div class="container"> <a class="navbar-brand mr-0 ml-4 " href="/">مدونتي</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation"> <i class="fas fa-bars"></i> </button> <div class="collapse navbar-collapse" id="navbarNav"> <ul class="navbar-nav mr-md-1"> <li class="nav-item ml-md-2 active"> <a class="nav-link" href="/article/create"> <i class="fas fa-plus ml-1"></i> إنشاء مقال <span class="sr-only">(current)</span> </a> </li> </ul> <form class="form-inline mt-2 mt-md-0" action="/search" method="GET" > <input name="q" id="q" class="form-control ml-sm-2" type="text" placeholder="عن ماذا تريد أن تبحث ؟" aria-label="Search" required> <button class="btn btn-primary my-2 my-sm-0" type="submit">ابحث</button> </form> </div> </div> </nav> وهذه هي ترويسة الصفحة، استدعينا فيها مكتبة Bootstrap من نظام توصيل المحتوى CDN، واستدعينا فيها مكتبة fontawesome من نظام توصيل المحتوى CDN، واستدعينا ملف style.css الذي أنشأناه، كما بنينا شريط التنقل للموقع. سننشئ ضمن المجلد views ملفًا آخر اسمه footer.ejs وهو تذييل الصفحة، ونكتب فيه التالي: </div> <script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script> <script src="../public/script.js"></script> </body> </html> وهنا أيضًا استدعينا مكتبة jQuery وملف JavaScript الخاص بمكتبة Bootstrap، وملف script.js الذى يحتوى على السكربت الخاص بالتطبيق، وأغلقنا الأوسمة المفتوحة الموجودة في ملف header.ejs. سنهيئ الآن الصفحة الرئيسية في الموقع والتي ستمكننا من عرض المقالات. لننشئ الآن ملف index.ejs أيضًا في مجلد views ولنكتب فيه: <%- include('_header') %> <main role="main" class="container-fluid"> <div class="jumbotron"> <div class="container"> <h1 class="text-center">أحدث المقالات</h1> </div> </div> <div class="container pt-4 pb-4"> <div class="row"> <% if(!articles || articles.length == 0) { %> <h5 class="col mt-5 pt-5 text-center">لا توجد مقالات لعرضها</h5> <% }else { %> <% articles.forEach(article => { %> <div class="mb-4 col-md-6 col-sm-12"> <div class="card shadow-sm p-3 bg-white rounded"> <div class="card-body"> <h2 class="card-title mb-3"> <a class="text-primary text-decoration-none" href="/article/<%= article.id %>"><%= article.title %></a> </h2> <p class="card-text mb-4"><i class="fas fa-user-circle"></i> <%= article.author %></p> <button class="delete-btn btn btn-danger btn-sm" data-id="<%= article.id %>">حذف المقال</button> </div> </div> </div> <% }) %> <% } %> </div> </div> </main> <%- include('_footer') %> الشيفرات المحاطة بالإشارتين <% و %> هي شيفرات JavaScript يقرؤها ejs لتنفيذ ما ضمنها، وفي حالتنا هنا نستورد الترويسة والتذييل للصفحات، ونضع ما يعبر عن المقالات في الكائن الذي سنوفره عند تنفيذ الصفحة حتى نعرض بياناته. لنضع تنسيقًا لتحسين شكل الصفحة، إذ سنكتب شيفرة التنسيق التالية في الملف style.css الذي أنشأناه في المجلد public: /*-الخط المستخدم بالموقع-*/ @import url('https://fonts.googleapis.com/css2?family=Almarai&display=swap'); @import url('https://fonts.googleapis.com/css2?family=Almarai:wght@700&display=swap'); /*-الإعدادات العامة للموقع-*/ body { direction: rtl; text-align: right; font-family: 'Almarai', sans-serif; font-size: 16px; } .bg-light{ background-color: #e9ecef !important; } textarea{ resize: none; } .container--error{ margin-top: 70px; } .container--error p{ font-weight: 700; } .container-fluid{ padding: 0 !important; margin-top: 56px; } .navbar{ background-color: #e9ecef; padding: 15px; } .navbar-toggler{ border: 1px solid #212529; } .navbar-toggler:focus{ border:1px solid #212529 !important; } .navbar-brand{ color: #212529 !important; font-weight: 700; } .navbar .navbar-collapse form{ margin-right: auto; } .navbar .navbar-nav{ padding-right: 0; } .navbar .navbar-nav .nav-link{ color: #212529; } .navbar .navbar-nav .nav-link i{ font-size: 13px; } .jumbotron{ border-radius: 0; padding: 6rem 2rem; } .card{ border: none; height: 100%; } .card-title a{ transition: all 0.3s ease; } .form-control{ border: none; height: auto; } .article-head{ display: inline-flex; align-items: flex-start; justify-content: center; flex-direction: column; } .article-head h5{ color: #868686; } /*-responsive-*/ @media (min-width: 1100px){ .container--article-create{ max-width: 900px; } .container--article-view{ max-width: 900px; } } @media (max-width: 768px){ .navbar-nav > li:first-child{ margin-top: 20px; } .navbar > .container{ padding-right: 15px; padding-left: 15px; } } @media (max-width: 576px){ .navbar-collapse form button[type=submit]{ width: 100%; } .navbar > .container{ padding-right: 0; padding-left: 0; } } أنشأنا حتى الآن الصفحة الرئيسية التي ستعرض كل المقالات أو نتائج البحث، ولننشئ الآن الصفحة التي ستمكننا من إضافة مقالات جديدة؛ سننشئ في مجلد views ملفًا اسمه create_article.ejs ونكتب فيه: <%- include('_header'); %> <main role="main" class="container-fluid"> <div class="jumbotron"> <div class="container"> <h1 class="text-center">أنشئ مقالًا</h1> </div> </div> <div class="container container--article-create pt4 pb-4"> <form action="/article" class="pt-5 pb-5" method="POST" id="create-article-form"> <div class="form-group"> <label for="title">عنوان المقال</label> <input type="text" class="form-control pt-2 pb-2 mt-1 bg-light" id="title" name="title" placeholder="أدخل عنوانًا مناسبًا لمقالك" required> </div> <div class="form-group"> <label for="author ">الكاتب</label> <input type="text" class="form-control pt-2 pb-2 mt-1 bg-light" id="author" name="author" placeholder="ما اسم كاتب المقال؟" required> </div> <div class="form-group"> <label for="content">نص المقال</label> <textarea class="form-control pt-2 pb-2 mt-1 bg-light" id="content" name="content" placeholder="نص المقال هنا" rows="7" required></textarea> </div> <div class="form-group"> <label for="tags">الوسوم</label> <input type="text" class="form-control pt-2 pb-2 mt-1 bg-light" id="tags" name="tags" placeholder="مثال على الوسوم: الكتابة,العمل" required> </div> <div class="form-group text-center"> <input type="submit" class="btn btn-lg btn-block mt-3 btn-primary" value="أنشئ المقال"> </div> </form> </div> </main> <%- include('_footer'); %> والآن لننشئ الصفحة التي ستعرض مقالًا عند النقر على عنوانه في الصفحة الرئيسية؛ سننشئ ضمن المجلد views ملفًا اسمه article.ejs ونكتب فيه: <%- include('_header'); %> <article class="container-fluid"> <div class="jumbotron"> <div class="container text-center"> <% if(!article) { %> <h1 class="text-center">لا يوجد مقالات!</h1> <% } else { %> <div class="article-head text-right"> <h1 class="text-right mb-3"><%= article.title %></h1> <h5 class="text-right mt-1">الكاتب: <%= article.author %></h5> </div> <% } %> </div> </div> <div class="container container--article-view"> <% if(!article) { %> <h1>المقال الذي طلبته غير موجود!</h1> <a href="/" class="btn btn-secondary btn-sm">عد إلى الصفحة الرئيسية</a> <% } else { %> <div> <%-article.content%> </div> <% } %> </div> </article> <%- include('_footer'); %> والآن لننشئ الصفحة التي ستعرض الخطأ للمستخدم في حالة قام بكتابة رابط غير موجود، سننشئ ضمن المجلد views ملفًا اسمه error.ejs ونكتب فيه: <%- include("_header"); %> <div class="container-fluid"> <div class="jumbotron"> <div class="container"> <h1 class="text-center">حدث خطأ ما!</h1> </div> </div> <div class="container container--error text-center"> <h2 class="text-center">أعد المحاولة لاحقًا </h2> <a href="/" class="btn btn-lg mt-3 btn-primary">عد إلى الصفحة الرئيسية</a> </div> </div> <%- include("_footer"); %> تهيئة إدارة قواعد البيانات وإنشاء الموجهات Routes بعد أن انتهينا من تصميم الصفحات، حان الوقت الآن لإنشاء طريقة التعامل مع قواعد البيانات، وكما تحدثنا سابقًا، سنستخدم Sequelize التي هي ORM شهيرة في Node.js. سننشِئ ملفًا جديدًا باسم sequelize.js، وسنضع فيه الشيفرة الآتية لتهيئة عملية الاتصال بقاعدة البيانات، وأذكِّرك بتغيير اسم المستخدم وكلمة المرور وفقًا لبيئة العمل الخاصة بك: const { Sequelize } = require("sequelize"); const DATABASE_NAME = "myBlog"; const USER_NAME = "root"; const PASSWORD = "password"; const DIALECT = "mariadb"; const sequelize = new Sequelize(DATABASE_NAME, USER_NAME, PASSWORD, { dialect: DIALECT, dialectOptions: { connectTimeout: 1000 }, logging: false, }); module.exports = sequelize; لتستطيع حزمة sequelize التعرف على قاعدة البيانات من نوع MariaDB (أو MySQL)، علينا تثبيت الحزمة المُخصَّصة لها بتنفيذ الأمر التالي: npm install mariadb وبهذا أصبح المشروع جاهزًا لكتابة الموجهات routes؛ لننشئ مجلدًا باسم routes بداخله ملف article.routes.js يحوي الشيفرة الآتية: const controller = require("../controllers/article.controller"); module.exports = (app) => { app.get("/", controller.viewIndex); }; ولكن يجب أن ننشئ مجلدًا باسم controllers وننشئ ملف باسم article.controller.js ونكتب فيه ما يلي: const Article = require("../models/article"); exports.viewIndex = (req, res, next) => { Article.findAll() .then((articles) => { res.render("index", { articles: articles }); }) .catch((error) => { next(error); }); }; هيأنا هنا الموجه الرئيسي، وعند طلب العنوان localhost:5000 في المتصفح فسيجلب الخادم كل المقالات من قاعدة البيانات، ويفسر الصفحة index.ejs ويعطيها الكائن articles حتى يعرض معلومات المقالات. نشغل المشروع عن طريق كتابة الأمر التالي في ملف المشروع في سطر الأوامر: npm start يجدر بالذكر أننا عدلنا القسم scripts في ملف package.json ووضعنا سكربت start لبدء تشغيل التطبيق عبر node للملف app.js. [...] "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "node app.js" }, [...] في الخطوة التالية لنهيئ المستقبل الذي يوجهنا إلى نموذج أو استمارة إنشاء مقال؛ سنضيف داخل ملف article.routes.js بعد الشيفرة السابقة: app.post("/article", controller.create); app.get("/article/create", controller.viewCreate); بعد ذلك نضيف الشيفرة الآتية داخل ملف article.controller.js: exports.viewCreate = (req, res) => { res.render("create_article"); }; exports.create = (req, res, next) => { Article.create(req.body) .then((article) => { article.save(); res.redirect("/"); }) .catch((error) => { next(error); }); }; وبهذا نستطيع الآن إنشاء مقالات جديدة، واستعراضها من الصفحة الرئيسية، وحتى نرى المقال بعد الضغط على بطاقته في الصفحة الرئيسية، سنضيف ما يلي داخل ملف article.routes.js بعد الشيفرة السابقة: app.get("/article/:id", controller.viewArticle); بعد ذلك نضيف الشيفرة الآتية داخل ملف article.controller.js: exports.viewArticle = (req, res, next) => { Article.findOne({ where: { id: req.params.id, }, }) .then((article) => { res.render("article", { article: article }); }) .catch((error) => { next(error); }); }; وبهذا أصبح المشروع جاهزًا لإضافة وعرض المقالات من قاعدة البيانات. لا تنسَ حفظ كل شيء ثم تشغيل المشروع، أو استخدم حزمة nodemon لتعيد تشغيل المشروع تلقائيًا عند كل تعديل تجريه على شيفراتك. إضافة المقالات سننشئ بداية مقالًا للتحقق من صحة الإدخال إلى قاعدة البيانات، وليكن بالمعلومات التالية: وبعد أن تحققت من صحة العمليات التي بنيتها، سأنشئ مجموعة من المقالات ذات المواضيع المتقاربة من أكاديمية حسوب، ولا بد أن نتحدث عن كل المقالات التي أدخلناها حتى نفهم نتائج البحث. سأدخل المقال الأول بعنوان «كيف تقدّر أجر مساعدك عن بعد» وسأدخل اسم الكاتب عدنان، وفي نص المقال سأنسخ فقط المقدمة، وفي صندوق الوسوم سأدخل كلمة أجر مساعدك. المقال الثاني بعنوان «أسس القيادة التقنية» والكاتب ابراهيم سليمان، وسأنسخ فقط المقدمة، وفي صندوق الوسوم سأدخل أسس القيادة. والمقال الثالث بعنوان «معضلة الإنتاجية والكاتب هو عمر، وسأنسخ فقط المقدمة، وفي صندوق الوسوم سأدخل الإنتاجية. إذًا حصلنا الآن على ثلاثة مقالات، مواضيعها مختلفة، بالإضافة إلى المقال الأول التجريبي، وأصبح لدينا ثلاث كُتَّاب لكل منهم مقال، ولنبن الآن مستَقبِل البحث. بناء عملية البحث اعتمادًا على قاعدة البيانات يعتمد معظم المطورين على المعامل like في عبارات SQL لبحثهم، العملية كافية بالنسبة للبحث في شيء محدد يدركه المستخدم مسبقًا ولا مجال فيه للاختلاف الكبير بين آراء مختلف المستخدمين وصياغتها لعبارة البحث، وكل مافي الأمر هنا أن تبحث باستخدام هذا المعامل عن ما يشبه عبارة البحث في حقل العنوان أو حقل الوسوم tags للمقال، وتوفير مربع بحث آخر للبحث حسب الكاتب. وتُنفّذ العملية ببساطة بمقارنة السلاسل النصية المطلوبة مع عبارة البحث التي أدخلها المستخدم، دون أدنى شكل من أشكال تحليل محتوى المقال أو تعرف أداة البحث على موضوعه ومدى فائدته للمستخدم بناء على عبارة البحث. حتى أنشئ وظيفة البحث التقليدية، سأذهب إلى قسم الموجهات routes في ملف article.routes.js وأضيف الموجه التالي: app.get("/search", controller.search); بعد ذلك نضيف الشيفرة الآتية داخل ملف article.controller.js: exports.search = (req, res, next) => { Article.findAll({ where: { [Op.or]: { title: { [Op.like]: `%${req.query.q}%` }, tags: { [Op.like]: `%${req.query.q}%` }, content: { [Op.like]: `%${req.query.q}%` }, }, }, }) .then((articles) => { res.render("index", { articles: articles }); }) .catch((err) => { next(err); }); }; سيبحث هذا التابع في حقول العنوان والمحتوى والوسوم عن ما يتضمن حرفيًا ما أدخلناه في عبارة البحث، فإذا بحثنا باستخدام إحدى العبارات: أسس القيادة التقنية، معضلة الإنتاجية، مقال تجريبي؛ فإنه سيعيد لنا نتيجة واحدة كانت قيمة وسومها تحتوي العبارة. لكن ماذا إذا بحثنا مثلًا عن "أشياء إنتاجيّة"؟ نذكر أن أحد مقالاتنا كان يتحدث عن الإنتاج وفيه فقرة عن أشياء إنتاجيّة حقيقيّة، وتعلم أن تحصيلك لنتيجة بحث دقيقة تعطي المستخدم ما هو مفيد له فقط بناء على الدالة like شيء مستحيل، جرب مثلًا البحث عن "اشياء إنتاجيّة" دون همزة ستجد أنه لا يعيد لك أي نتائج. ولربما تبحث عن أمر آخر، كلمة أسس مكتوبة مع همزة في المقال الذي عنوانه أسس القيادة التقنية، ابحث عن "اسس" دون همزة، وستجد أنه لا يعيد لك أي نتائج! مفاهيم متعلقة بمحرك البحث الداخلي يأتي هنا دور محرك البحث لبلب والذي له القدرة على تحليل النص ومعرفة موضوعه ومضمونه، وجدولة نتائج البحث على أساس هذا التحليل، لنجرب الآن بناء البحث باستخدام لبلب لنرى إن كان سينجح في إعادة نتائج لنا بناء على العبارات التي لم تعد نتائج في البحث السابق، ولكن قبل أن نبدأ ببناء الوظائف، لنفهم بعض المفاهيم الأساسية. محرك البحث لبلب هو محرك بحث سحابي، يعمل على جدولة أو فهرسة indexing المحتوى الذي يصله من الموقع، ومن ثم التفاعل مع عبارة البحث التي تصله وتوفير النتائج التي يجدها مناسبة. من هنا نعرف أنه لدينا عمليتين حتى نصل إلى المطلوب: الأولى جدولة المحتوى، والثانية هي عملية البحث. يوفِّر محرك البحث لبلب واجهة برمجية Web API للتعامل معها بشكل مباشر، كما يوفر حزمة برمجية SDK لكل من المنصات: Node.js و PHP Laravel و WordPress، حتى تسهل التعامل مع الواجهة البرمجية API الخاصة به. يمكنك الرجوع إلى التوثيق الرسمي للواجهة البرمجية وللحزم البرمجية لأي تفاصيل ومعلومات إضافية. يتطلب التعامل مع واجهة لبلب البرمجية حسابًا على موقع لبلب، ويتم الحفاظ على وثوقية وأمان المعلومات عند التعامل مع لبلب من خلال استخدام مفاتيح خاصة بمشروعك API Key تستطيع توليد مفاتيح جديدة من خلال لوحة التحكم الخاصة بمشروعك (من خلال الدخول الى لوحة التحكم -> ثم الضغط على اسم المشروع الخاص بك -> ثم الدخول الى قسم API Keys) ونلاحظ وجود مفتاحين: الأول للقيام بعملية الفهرسة عند لبلب والثاني لإجراء عمليات البحث من بإستخدام لبلب. تهيئة حزمة لبلب لدي مشروع اسمه academyhsoub في حسابي على لبلب، ولهذا المشروع جدول collection اسمه posts وله البنية التالية: أستطيع من هنا التحكم في حقول هذا الجدول بإضافة حقول جديدة ومنحها أسماء أو حذف حقول موجودة، وجعلها إلزامية بتفعيل الخاصية required لها. سنثبت حزمة لبلب بالأمر الآتي: npm install @lableb/javascript-sdk وبعدها ننشئ ملفًا باسم lableb.js داخل المجلد config ونضع به الشيفرة الآتية: const { LablebClient } = require("@lableb/javascript-sdk"); const PROJECT_NAME = "academyhsoub"; const INDEXING_TOKEN = "محتوى هذا الحقل من حسابك على لبلب"; const SEARCH_TOKEN = "محتوى هذا الحقل من حسابك على لبلب "; let lableb; LablebClient({ platformName: PROJECT_NAME, APIKey: SEARCH_TOKEN, indexingAPIKey: INDEXING_TOKEN }) .then(lablebClient => { lableb = lablebClient; }) .catch(error => { console.error(error); }) module.exports = lableb; وهكذا سنستطيع استخدام المتغير lableb لمختلف العمليات. هيأنا هذا الثابت بإعطائه اسم المشروع ومفاتيح الواجهة API KEYs الخاصة بالجدولة والبحث، حيث أن الحزمة ستوجه الطلبات إلى رابط واجهة لبلب البرمجية بالشكل التالي في حال عملية الجدولة: https://api.lableb.com/api/v2/${PROJECT_NAME}/indices/${COLLECTION_NAME}/documents?apikey=${INDEXING_TOKEN} وبالشكل التالي في عملية البحث: https://api.lableb.com/api/v2/${PROJECT_NAME}/indices/${COLLECTION_NAME}/search/default?q=${SEARCH_QUERY}&cat=Lifestyle&limit=1&apikey=${SEARCH_TOKEN} وبذلك تختصر علينا الحزمة كتابة هذه العناوين وتشكيلها يدويًا. بناء عملية الفهرسة Indexing سأضيف الآن عمليات الفهرسة بتوسيع extend صنف قاعدة البيانات حتى نعمل ببنية صحيحة. سنبني عملية فهرسة Indexing مرتبطة بالصنف Article وظيفتها جدولة كل المقالات السابقة في قاعدة البيانات، وستفيدنا هذه العملية في التأكد من فهرسة المقالات التي أضيفت إلى قاعدة البيانات قبل استخدام محرك البحث، أو عندما يكون قد جرى تعديل على المقالات ولم تتم فهرسته. وعملية الفهرسة مرتبطة بالكائن article عند إنشاء كل كائن جديد حتى تتم فهرسته بعد الإنشاء مباشرة. ولبناء العمليتان، ننشئ مجلدًا جديدًا باسم models وبداخله ننشئ ملف باسم article.js ونكتب بداخله الشيفرة التالية: const { Sequelize, Model } = require("sequelize"); const sequelize = require("../config/sequelize"); const lableb = require("../config/lableb"); class Article extends Model { //إنشاء مستند قابل للفهرسة خارج الكائن _document() { return { id: this.id, title: this.title, content: this.content, url: `/article/${this.id}`, tags: this.tags, authors: this.author, }; } // إنشاء مستندات قابلة للفهرسة لجميع المقالات static async _findAllDocuments() { return Article.findAll().map((a) => a._document()); } // فهرسة مستند واحد _index() { return lableb.index({ documents: [this._document()] }); } // حذف مستند واحد من الفهرسة async _deleteIndex() { return lableb.delete({ documentId: this.id }); } // فهرسة جميع المقالات static async indexAll() { const documents = await Article._findAllDocuments(); return lableb.index({ documents: documents }); } // تحويل نتائج البحث القادمة من لبلب إلى مقالات قابلة للعرض static async search(query, limit) { const lablebResult = await lableb.search({ query: encodeURIComponent(query), limit: limit }); const searchResults = lablebResult.response.results; return searchResults.map((searchResult) => ({ id: searchResult.id, title: searchResult.title, content: searchResult.content, author: searchResult.authors[0], tags: searchResult.tags[0], })); } } Article.init( { title: Sequelize.STRING, author: Sequelize.STRING, content: Sequelize.STRING, tags: Sequelize.STRING, }, { hooks: { afterSave: function (article) { article._index(); }, beforeDestroy: function(article) { article._deleteIndex(); } }, sequelize, modelName: "article", } ); module.exports = Article; سنشرح الشيفرة السابقة؛ أنشأنا في البداية صنفًا يحتوي على الدالة document_ ليكون وسيطًا معبرًا عن المقال الواجب جدولته. بعد ذلك أنشأنا التابع findAllDocuments_ لإنشاء مستندات قابلة للفهرسة لجميع المقالات وأنشأنا بعد ذلك التابع index_ لفهرسة مستند واحد والتابع indexAll لفهرسة جميع المقالات، ولا بد أن نذكر هنا أن خدمة لبلب تتعامل مع المعلومات المفهرسة فيها عبر حقل id، فإذا تم إرسال المقالات إلى لبلب وكانت مُعرِّفاتُها موجودة مسبقًا، فسيتم تحديثها لا تكرارها. ونلاحظ أثناء بناء المصفوفة documents_ أننا خزننا حتى روابط هذه المقالات. ونُذكِّر أننا أضفنا هذا الجزء من قبل وهو مسؤول عن عرض وجدولة كل المقالات: exports.viewIndex = (req, res, next) => { Article.findAll() .then((articles) => { res.render("index", { articles: articles }); }) .catch((error) => { next(error); }); }; تعديل عملية البحث وتجارب البحث رأينا في السابق نتائج البحث التي لم تكن ذات جدوى عالية، والآن لنعلق دالة البحث القديمة بحيث تصبح بدون تأثير على التطبيق ونضع الدالة الآتية بدلًا منها فى الملف article.controller.js وجعلها كالآتي: exports.search = (req, res, next) => { Article.search(req.query.q, 10) .then((articles) => { res.render("index", { articles: articles }); }) .catch((error) => { next(error); }); }; exports.indexAll = (req, res, next) => { Article.indexAll(); }; ونحصل من دالة بحث لبلب على نتائج البحث لنتصرف فيها. إذا علقنا كل محتوى القديم وكتبنا الأسطر التي تنفذ عملية البحث باستخدام لبلب، وتعتمد على نتائج بحث لبلب في عرض المقالات، عوضًا عن قاعدة بياناتنا وهكذا بنينا كامل عملية البحث. تجارب البحث باستخدام لبلب لدينا ثلاثة مقالات تتحدث عن مواضيع مختلفة، وموضوع واحد بعنوان مقال تجريبي، لنجرب البحث عن كلمة "اشياء إنتاجيّة": ونلاحظ أنه أعاد لنا المقالة التى تتحدث عن أشياء إنتاجية وهى "معضلة الإنتاجية "على الرغم أنها لا تبدأ بهمزة، وأعاد أيضًا مقال أسس القيادة التقنية بعدها لأنها تحتوى على كلمة الأشياء. جرب الآن البحث عن كلمة "اسس" دون همزة. و"أسس" مع همزة. ونلاحظ هنا أنه جلب لنا مقال أسس القيادة التقنية فى كلتا الحالتين، هل كنا سنستطيع برمجة دالة بحث تعطينا نفس الدقة في النتائج؟ حسنٌ، لنبحث عن عبارة مخصصة جدًا في مقال كيف تقدّر أجر مساعدك عن بعد، لنبحث عن عبارة "ميزانية مشروعك" ونلاحظ أننا حصلنا فقط على نتيجة واحدة وهي مقالة كيف تقدّر أجر مساعدك عن بعد، ويجب أن تتذكر أننا وضعنا المقدمة فقط فى المحتوى الخاص بالمقالة، لذلك اخترت عبارة من المقدمة وبحثت عنها، وسنفعل المثل فى عمليات البحث القادمة. لنبحث عن كلمة "نيويوركر" ونلاحظ مجددًا أنه أعاد مقالة "معضلة الإنتاجية" فقط إذ أنَّها المقالة الوحيدة لدينا التى تحتوى على هذه الكلمة. لنبحث الآن باستخدام عبارة أقرب لما يكتبه البشر عادة، لنبحث عن "ما هى المعضلة الانتاجية؟" وسنرى أنه أعاد لنا مقالة معضلة الإنتاجية فقط، واستثنى المقالات الأخرى: نستنتج أن محرك البحث استطاع عرض نتيجة بناء على عبارة سؤال طبيعي. لنجرب البحث عن عبارة "مقال تجريبي" وسنجد أنه أعاد المقالات التى تحتوى على كلمة مقال أو تجريبى ولكن "مقال تجريبى" فى بداية الترتيب. لنبحث عن اسم الكاتب "عدنان": ونرى أن النتيجة عادت فقط بالمقالات التي كتبها عدنان، دون أي مجهود منا لجعل عملية البحث تستهدف حقل الكاتب من كائن المقال. الخلاصة رأينا الفائدة من استخدام محرك بحث تجريبي، تخيل أن لديك موقع تجارة إلكترونية يعرض منتجاته باللغة العربية، أليس جميلًا أن تحصل على دقة كهذه في إرجاع النتائج، فضلًا عن ترتيبها حسب الأقرب للبحث؟ وهل تستطيع بناء دالة بحث بنفس القدرات باستخدام الأدوات التقليدية مثل تعليمات SQL أو مقارنة السلاسل النصية باستخدام لغة البرمجة التي بنيت موقعك بها؟ أجرينا في هذا المقال مقارنة بين البحث باستخدام دالة بدائية يدوية، والبحث باستخدام محرك بحث عربي، واخترنا لبلب لهذه المهمة، واستنتجنا أن محرك البحث يتجه أكثر نحو فهم الموضوع واستيعاب مختلف صيغ عبارات البحث التي يدخلها المستخدم بلغة طبيعية غير مصطنعة كما هو الحال في البحث باستخدام الوسوم، ونرجو أن يكون المقال مفيدًا ونرحب بأية تعليقات أو استفسارات لديكم. اقرأ أيضًا إنشاء صفحة البحث في الووردبريس نمذجة البيانات وأنواعها في عملية تصميم قواعد البيانات1 نقطة
-
الي الان تواجهني هذه المشكلة ولم استطع حلها نهائيًا حتيّ الآن، ولا احد يريد مُساعدتي فهل من مُتَطوع يرشدني ارجوكم؟ ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════ The following _CastError was thrown building SettingPage(dirty, dependencies: [_InheritedProviderScope<UserBloc>, _InheritedProviderScope<NotificationBloc>, _LocalizationsScope-[GlobalKey#6f6f3], _InheritedTheme], state: _SettingPageState#444e0): Null check operator used on a null value The relevant error-causing widget was: SettingPage SettingPage:file:///C:/Users/mrlor/Downloads/wadahly-app21/lib/pages/home.dart:120:191 نقطة
-
كيف يمكنني رسم الوقت (HH:MM:SS.mm) على المحور x والأرقام على المحور y باستخدام Matplotlib؟1 نقطة
-
كيف يمكنني إنشاء صورة RGB جديدة . لا أريد تحميل الصورة من ملف ، أريد إنشاء صورة فارغة جاهزة لإجراء العمليات عليها.1 نقطة
-
حاولي الخطوات التالية: الذهاب لمجلد xampp، والدخول لمجلد mysql C:\xampp\mysql يوجد مجلد اسمه data أعيدي تسميته إلى data_old إنشاء مجلد جديد باسم data نسخ محتويات مجلدbackup (إن وجد) إلى المجلد data (المنشئ في الخطوة السابقة) نسخ واستبدال كل محتويات المجلد data_old إلى المجلد data ما عدا التالي: mysql performance_schema phpmyadmin تشغيل خدمة MySQL من XAMPP مجددًا1 نقطة
-
الخطأ لديك في جلب الرقم الأوسط حيث أنك تقوم بحساب باقي قسمة 324 على 100 و الباقي سيكون 24 بالتالي يجب عليك أخذ حاصل قسمة الناتج على 10 للحصول على 2 بهذا الشكل: num = 324 d1 = (int) (num / 100) d2 = int((num % 100) / 10) d3 = num % 10 print(f"The reverse number of: {num} is: {d3}{d2}{d1}") # The reverse number of: 324 is: 423 لكن الطريقة ليست الأفضل و ليست عامة لكل الحالات، لذلك قدم المدربين في التعليقات أعلاه حلول أفضل.1 نقطة
-
يمكنك أيضًا أن تقوم بعكس ترتيب الأرقام من خلال الكود التالي: num = input("Enter:") print("The reverse number is :", num[::-1]) أو يمكنك أن تقوم بإختصار الكود ليكون في سطر واحد: print("The reverse number is :", input("Enter:")[::-1]) كما يمكنك التأكد من إدخال المستخدم لرقم صحيح من خلال إستخدام التابع isdigit، على النحو التالي: num = input("Enter:") if not num.isdigit(): # عرض رسالة خطأ في حالة قيام المستخدم بإدخال نص غير وليس رقم صحيح raise Exception("Error: Please enter an integer") print("The reverse number is :", num[::-1]) يمكنك أيضًا أن تقوم بعمل حلقة تكرار لعكس ترتيب الرقم: number = int(input("Enter Number: ")) reverse = 0 while number > 0: reminder = number % 10 reverse = (reverse * 10) + reminder number = number // 10 print("The reverse number is : %d" %reverse)1 نقطة
-
جربت طريقتك ونجحت مشكور لكن فش طريقة حل قريبة من الي انا عاملها لانه هذا اخر ما تعلمناه ولو نسخت الي انت عامله راح يكون عبارة عن نسخ ولصق فقط1 نقطة
-
أعتقد أكبر مشاكل المواجهة للمبرمج أو مطور تطبيقات هي إيجاد الأفكار للتطبيقات ؟ صحيح ؟ اذا كان المبرمج جيد في البرمجة ، أين يجد أفكار للتطبيقات ؟ وكم تستغرق عمل تطبيق واحد ؟ يوم أو يومين ؟ تطبيق مبسط يعني مش معقد كثير أقصد ؟1 نقطة
-
حاول تشغيل XAMP كمسؤول ربما تكون المشكلة في صلاحيات التنفيذ، عبر الضغط بالزر الأيمن واختيار Run as Administrator1 نقطة
-
1 نقطة
-
قم بفتح مدير المهام عبر الضغط على Ctrl + Shift + Esc الذهاب الى تبويب Performance ثم فتح مراقب الموارد Resource Monitor (على Windows 10 الضغط على Open Resource Monitor) الذهاب الى التبويب Network فتح القائمة Listening Ports في الأسفل، وفيها كل الاجرائيات التي تستمع الى منافذ معينة قم بالبحث عن الاجرائية التي تعمل على المنفذ 3066 (منفذ قاعدة البيانات التي تحاول تشغيلها) حاول تعطيلها واغلاق البرنامج الخاص بها1 نقطة
-
واجهتني مشكله و لي اكثر من 10 ايام اريد حلها , و م لقيت لها حل .. وهي المشكله بمكتبه kivy تظهر لي هذه مشكله / [CRITICAL] [App ] Unable to get a Window, abort اتمنى ان تحلوها لي .. وشكرا لكم . للمعلوميه : عدت اكثر من 5 مرات في التثبيت لكن ايضا لن تزبط . و شكرااا.1 نقطة
-
لدي حاويتين من Docker ولكل منهما ملف إعداد/تكوين خاص بها، كيف أستطيع الربط بينهما. أي جعل إمكانية للتواصل بين الحاويتين؟ مثلاً الأولى لقاعدة البيانات و الثانية للوحة التحكم. قاعدة البيانات mydb.yml: version: '3' networks: default: external: name: my_backend volumes: mongo_data: services: mongodb: image: mongodb container_name: mongodb restart: always ports: - 27017:27017 networks: - backend volumes: - mongo_data:/data/db لوحة التحكم my_admin.yml: version: '3' networks: default: external: name: my_backend volumes: mongo_data: services: mongoclient: image: mongoclient/mongoclient restart: always ports: - 3000:3000 networks: - backend depends_on: - mongodb links: - mongodb1 نقطة
-
1 نقطة
-
يوجد خيارات كميزات إضافية لمخدم nginx: تحديد وزن المخدم (ثقله - قوة المعالجة له) مما يزيد عدد الطلبيات الموجهة له weight: http { upstream backend { server 192.0.0.1 weight=5; ^^^^^^^^^ } } يمكن وضع عنوان دومين domain عادي بدل وضع ip مثل: http { upstream backend { server backend5.example.com; ^^^^^^^^^^^^^^^^^^^^ } } يمكن تحديد مخدم إحتياطي backup، يعمل في حال فشل المخدمات البقية، أي لا يرسل له أي طلبية حتى توقفهم: http { upstream backend { server 192.0.0.1 backup; } } في حال تعطل أحد المخدمات ورغبتنا بعودته للعمل يمكننا اختباره بعد مرور مدة زمنية باستخدام الخاصية slow start: upstream backend { server backend1.example.com slow_start=30s; ^^^^^^^^^^^^^^ } في حال تعطل أحد المخدمات يمكننا تحديده ك down upstream backend { server backend6.example.com down; ^^^^^ } تحديد العدد الأعظمي من قنوات الاتصال، upstream backend { server backend1.example.com max_conns=3; ^^^^^^^^^^^ } وعمل رتل queue لعدد الاتصالات مع تحديد وقت انتهاء timeout upstream backend { server backend2.example.com; queue 100 timeout=70; ^^^^^^^^^^^^^^^^^^^^^ } يمكن الاطلاع علي كيفية ضبط الخادم وأساسياته من خلال:1 نقطة
-
بالإضافة إلى إجابة أستاذ أحمد, يوجد مواقف تحتاج أن تستخدم فيها الأسماء المستعارة (aliases) حتى تتمكن من تنفيذ الجملة الإستعﻻمية المُراد تنفيذها, مثلاً إن كان لدينا الجدول employee وأردنا أن نجلب جميع الموظفين الذين لديهم نفس المدينة, وقتها نحتاج أن نقوم بما يُدعى بالself join حيث أنك تقوم بكتابة جملة join ولكن بدلاً من أن تكون بين جدولين تكون بين الجدول ونفسه, مثال: SELECT a.name AS name1, n.name AS name2, a.City FROM Customers a, Customers n WHERE a.id <>n.id AND a.City = n.City بدون إعطاء أسماء مستعارة لن نتمكن من تفنيذ جملة مثل السابقة1 نقطة
-
نستخدم الاسماء المستعارة في sql وذلك لجعل الاستعلام أسهل وأوضح، فهي كانها متغير في لغة البرمجة، فنقوم باسناد أمر معين لهذا المتغير، الأمر الذي يجعل أستخددامه أسهل وأوضح من إعادة كتابته من البداية وهكذا. وسبب أخر مهم و هو أكثر موضوعية. إذا ظهر الجدول أكثر من مرة في جملة From فأنت بحاجة إلى أسماء مستعاره للجدول من أجل الاحتفاظ بما قمت باستخراجة مميزا. تنضم إلى الاحتياج ذاته الحالات التي يحتوي فيها الجدول على مفتاح أجنبي foreign key يشير إلى المفتاح الأساسي primary key لنفس الجدول أما عن طريقة استخدامها فهي كالتالي: SELECT inv_no AS invoice_no, amount, due_date AS 'Due date', cust_no 'Customer No' FROM invoices; مثال أخر: SELECT emp.deptno as "DeptID", SUM(emp.sal) as "DeptSal" FROM employees emp GROUP BY emp.deptno HAVING emp.deptno = 20;1 نقطة
-
مفهوم Redis: Redis هو عبارة عن مخزن مفتوح المصدر يُستعمل لتخزين البيانات على شكل أزواج من مفتاح-قيمة Key-Value في الذاكرة الرئيسية In-Memory، حيث Key-Value storage عبارة عن نظام تخزين يتم فيه تخزين البيانات على شكل أزواج من المفاتيح والقيم ، تخزّن هذه الأزواج في الذاكرة الرئيسية RAM وهذا ما نقصده بـ In-Memory وبهذا يمكننا القول أن تقنية Redis تخزن البيانات في الذاكرة الرئيسية على شكل أزواج من المفاتيح والقيم. يكون المفتاح في هذه التقنية عبارة عن سلسلة نصية String، أما القيمة فيمكن أن تكون سلسلة محارف String أو قائمة List أو مزيج منهما. يُمكن استخدام Redis إمّا كخادوم قاعدة بيانات لوحده أو مرتبطًا مع قاعدة بيانات أخرى مثل MySQL. خطوات تثبيت Redis على أوبنتو: إعداد بيئة ومتطلبات Redis نقوم في البداية بتحديث جميع حزم apt-get: sudo apt-get update بعد ذلك نقوم بتحميل مُترجم (compiler) باستخدام الحزمة build-essential، والّتي من شأنها المساعدة في تنصيب Redis من المصدر: sudo apt-get install build-essential سنقوم بعدها بتحميل الأداة tcl الّتي يَعتمد عليها Redis: sudo apt-get install tcl8.5 تنصيب Redis: بعد أنّ تمّ تنصيب المُتطلّبات الأساسيّة، فمن المُمكن الآن الشروع وتنصيب redis، ويُمكن تحديد الإصدار المطلوب أو تحميل الإصدار الأخير والذي سيحمل دائمًا الاسم redis-stable: wget http://download.redis.io/redis-stable.tar.gz يجب بعد ذلك فك ضغط الملفّ والانتقال إليه: tar xvzf redis-stable.tar.gz cd redis-stable ثم المتابعة بتنفيذ الامر: make make ولتنصيب Redis على كامل النّظام، فيُمكن إما نسخ ملفاته من المصدر: sudo cp src/redis-server /usr/local/bin/ sudo cp src/redis-cli /usr/local/bin/ أو تنفيذ الأمر التّالي: sudo make install بعد انتهاء عمليّة التنصيب، من المُستحسن تشغيل Redis كحارس (daemon) في خلفيّة النّظام، ولعمل ذلك يأتي Redis بملفّ برمجي (سكريبت) لهذه المُهمّة. يجب الانتقال إلى المسار utils للوصول إلى هذا الملفّ: cd utils ومن ثم تشغيل الملفّ الخاص بتوزيعات Ubuntu/Debian: sudo ./install_server.sh سيَعرض السكريبت بعض الأسئلة لإتمام عمليّة التهيئة، ولكن يُمكن الاعتماد على الإعداد الافتراضي والاكتفاء بالضغط على Enter، وبعد انتهاء عملية التهيئة سيكون خادم Redis يعمل في الخلفيّة (background). يُمكن تنفيذ الأمر التّالي للوصول إلى قاعدة البيانات Redis: redis-cli يُمكن اختبار Redis كالتّالي: λ redis-cli 127.0.0.1:6379> ping PONG 127.0.0.1:6379> set name hsoub OK 127.0.0.1:6379> get name "hsoub" 127.0.0.1:6379> بإمكانك المتابعة مع المقال التالي: الذي يشرح كيفية التثبيت بشكل مفصل و الإطلاع على بقية أوامر Redis.1 نقطة
-
Git هي أنسب أداة لإدارة النسخ وخصوصا في المشاريع البرمجية، ما هو Git وكيف يعمل بتبسيط لمفهوم عملها هي أداة تقوم بحفظ نسخة عن كامل ملفات المشروع في كل مرة تأمرها بذلك، وتقوم بحفظ كل نسخة باسم تلقائي، وتربط هذه النسخ ببعضها حسب من اي نسخة تم اشتقاق النسخة الجديدة عمليًا Git لا يقوم بحفظ نسخة جديدة كاملة عن ملفات المشروع انما يقوم بالمقارنة مع النسخة السابقة ويخزن فقط الملفات التي حدث فيها تغيير لتوفير مساحة التخزين مزايا Git ادارة نسخ العديدة للمشروع والحصول عليها عند الحاجة إمكانية إحداث تغييرات على المشروع دون الخوف من تعقيد الرجوع عنها امكانية دمج عدة نسخ للحصول على نسخة جديدة تتضمن كل محتويات النسخ امكانية تعاون عدة مطورين معا على نفس نظام النسخ واضافة ودمج أجزاء عملهم لاحداث نسخ جديدة أهم المصطلحات كما تسمى في Git commit: النسخة عن الملفات merge: دمج نسختين branch: سلسلة من النسخ المشتقة من بعضها مقالات توضيحية يمكن الاطلاع على المقالات التالية1 نقطة
-
يمكن استخدام LIKE في أي مكان يمكن استخدام الشروط فيه مثل = , != , IN , وغيرهم بعض قواعد البيانات لاتدعم معامل دمج النصوص + مثلا في SQL SERVER نحتاج لاستخدام دالة CONCATE SELECT * FROM A INNER JOIN B ON B.MYCOL LIKE CONCAT('%', A.KEY, '%'); ^^^^^^^ == ^^^^^^^^^^^^^^^^^^^^^^^^ كما يمكن استخدام كامل ميزات LIKE فيها1 نقطة
-
الحالة المعروضة لن تفرق في الأداء كثيرا مهما كبر حجم البيانات وذلك لأن الأمر نفسه صغير. وبشكل عام فأن الأداء يعتمد على عدد الصفوف التي يتم العمل عليها وعدد الأعمدة التي تقوم بأرجاعها وهنا لا فرق بين الأثنين لذا لن تجد فرقا في الأداء. وهذا لان خطط الإستعلام لكلاهما واحدة، لذا فإن عدد الصفوف المتأثرة وعدد الأعمدة التي ترجع واحدة، وبشكل عام فأن الخادم sql server سيقوم بتحويلهم لنفس الصورة في النهاية فلا فرق. اما اذا كان الإستعلام يحتوى على بعض الحسابات أو التجميعات ( calculations, aggregations) فإن الطريقة الثانية أفضل بالتاكيد، اما هذة الحالة فلا لانه لا توجد حسابات أو تجميعات.1 نقطة
-
نعم يمكنك استخدامها, لنفترض لدينا جدولين , الجدول الأول اسمه a والجدول الثاني اسمه b, يمكنك استخدام LIKE مع JOIN كالتالي SELECT * FROM TABLE a JOIN TABLE b ON b.column LIKE '%'+ a.column +'%'1 نقطة
-
يُمكنك تنفيذ ذلك عبر إستخدام الإتحاد(union) حيث وظيفة خاصية الإتحاد أن تقوم بدمج عناصر مجموعتين ليصبحو ع هيئة مجموعة واحدة فمثلاً {1, 3, 7, 5} union {2, 4, 6, 8} = {1, 2, 3, 4, 5, 6, 7, 8} ويتم تنفيذه في لغة sql بالشكل التالي (SELECT * FROM a) UNION (SELECT * FROM b) وتقوم بتبديل a و b بإسم الجداول المُراد دمجها1 نقطة
-
يمكنك إضافة بيانات الجدول الآخر من خلال الاستعلام التالي: INSERT INTO [table2] SELECT * FROM [table1] WHERE [condition]; بحيث يشير table2 الجدول الحالي الذي ترغب بإضافة البيانات إليه، أما الجدول table1 فهو يحوي البيانات التي ترغب بالحصول عليها وإضافتها هنا. كما يمكنك وضع شرط محدد في حال أردت إضافة بيانات محددة من ذلك الجدول أو الاستغناء عن الشرط وبالتالي يتم جلب كافة البيانات التي يحويها. مثال: INSERT INTO Customers SELECT * FROM Customers_bk;1 نقطة
-
عند ضم جدولين أو أكثر تكون القيم التي تقوم بضمها في بعض الأحيان غير متتطابقة تمامًا بين الجداول. وهناك العديد من الطرق لحل هذا الأمر، ومن ضمن هذه الطرق يمكن إستخدام جملة CASE عند ربط الجداول معًا، وذلك عند تحديد قيمة الحقل مكان ON. بفرض أن لدينا جدول orders يحتوي على معلومات عن طلبات العملاء وهو على الشكل التالي: لاحظي كيف أن لنفس العميل أكثر من قيمة cust_num متشابهة. وأيضًا لدينا الجدول cust_table والذي يحتوي على معلومات حول العملاء أنفسهم: الآن عندما نقوم بعمل ربط بين الجدولين عن طريقة cust_num نجد أن النتيجة كالتالي: لاحظي وجود قيم NULL في حقل residence وذلك لعدم تشابهة قيمة الحقل cust_num بين الجدولين. لحل هذه المشكلة، يمكن الإستعانة بجملة CASE عند الربط بين الجدولين كالتالي: SELECT a.*, b.residence FROM orders AS a LEFT JOIN cust_table AS b ON CASE -- إزالة الرمز -EC من نهاية رقم العميل cust_num إن وجد WHEN a.cust_num LIKE '%-EC' THEN SUBSTRING(a.cust_num, 1, LEN(a.cust_num) - 3) -- في حالة لم يتم العثور على الرمز -EC في رقم العميل فلا حاجة لإستخدام الدالة SUBSTRING ELSE a.cust_num END = b.cust_num ORDER BY order_year عند تنفيذ الإستعلام السابق سوف تكون النتيجة كالتالي: بهذا الشكل لن يحتوي الجدول على قيم NULL وسيتم تعويضها بالبيانات بشكل سليم. لمعرفة المزيد حول CASE في SQL يمكن الإطلاع على هذه المقالة: أو من خلال موسوعة حسوب حول لغة SQL من هنا1 نقطة
-
أداة Docker عبارة عن أداة تستخدم المحاكاة الافتراضية virtualization على مستوى نظام التشغيل لتقديم البرامج في حزم تسمى الحاويات. أي أنه يقدم كل حاوية وكأنها نظام تشغيل منفصل عن غيره من الحاويات. يتم عزل الحاويات عن بعضها البعض وتقوم بتجميع البرامج والمكتبات وملفات التكوين configuration files الخاصة بها؛ يمكن للحاويات التواصل مع بعضهم البعض من خلال قنوات محددة جيدًا. والسبب في إستخدام هذه التقنية بدلًا من الأنظمة الإفتراضية Virtual Systems هو أن جميع الحاويات تشترك في خدمات services نواة نظام تشغيل واحدة، وبالتالي يتم إستخدام موارد أقل بكثير من الأنظمة الإفتراضية Virtual Systems. لاحظ كيف أن الحاويات تتشارك نفس النواة الخاصة بنظام التشغيل، مما يسمح بتشغيل عدد أكبر من التطبيقات المعزولة عن بعضها البعض، بينما في الأنظمة الإفتراضية تكون معزولة عن بعضها البعض، ولكنها تستهلك الموارد أكثر. كما أن Docker توفر مجموعة مختلفة من الأدوات مثل Docker Hub والتي يمكن رفع الحاويات عليها لتشاركها مع أشخاص محددين او بشكل مفتوح المصدر و Docker Compose التي تسمح بتعريف وتشغيل تطبيقات دوكر متعددة الحاويات. وتستخدم ملفات خاصة مكتوبة بصيغة YAML (مشابهة إلى حدٍ ما من JSON ولكن بدون أقواس). تستعمل أداة Docker في الوقت الحالي لنشر تطبيقات الويب، حيث يتم إستخدام نفس الحاوية المستخدمه في عملية التطوير على الخادم Server وبالتالي تقليل المشاكل والإختلافات بين بيئة التطوير على الجهاز المحلي وبيئة الإنتاج Production على الخادم Server.1 نقطة
-
كل الدورات الموجوة في الأكاديمية تعلمك البرمجة، ولكن قبل تعلم البرمجة يجب تحديد هدف من تعلم البرمجة أولًا، هل تريد عمل تطبيقات للهواتف الذكية، أم تريد إنشاء مواقع ويب تفاعلية وكبيرة، ربما تريد عمل ألعاب ثلاثية الأبعاد، أو قد تريد إنشاء برامج سطح المكتب، لذلك يجب تحديد ما تريد فعله أولًا عند تعلم البرمجة، لكي لا تصاب بالتشتيت والضياع بين العشرات من لغات البرمجة والتقنيات المختلفة، بعد أن تحدد ما تريد فعله يمكنك أن تبحث عن دورة شاملة تقوم بتعليم ما تريده، وعلى العموم ستجد أن أغلب المجالات والتقنيات تحتاج إلى حد أدنى من المعرفة البرمجية، مثلًا كيف يعمل الحاسوب أو ما هي المتغيرات والدوال والكائنات .. إلخ. وقد قامت أكاديمية حسوب بشرح كل الأساسيات في دورة علوم الحاسوب والتي تقوم بشرح أساسيات الحاسوب وعلومه والتفكير المنطقي وما هي الخوارزميات، ثم ستقوم بتطبيق هذه الأساسيات من خلال عمل برامج وألعاب بسيطة باستخدام بيئة سكراتش Scratch التفاعلية. بعد ذلك سوف تنطلق في تعلم أول لغة برمجة لك وهي JavaScript والتي سيتم من خلالها تعلم المزيد من الأمور البرمجة وكيفية إنشاء برامج واقعية وعملية، كذلك سوف تتعلم أساسيات أنظمة التشغيل المختلفة (مثل ويندوز و Linux) وكيفية التعامل معها، بعد ذلك ستنتقل لتعلم قواعد البيانات وأنواعها، و كيفية عمل صفحات ويب بسيطة وكيف تعمل الشبكات والخوادم من الأساس. وبعد كل هذه الأمور ستتعلم لغة برمجة أخرى وهي بايثون وستعرف لماذا يوجد أكثر من لغة برمجة وستتعلم أمور برمجية متقدمة أكثر مثل الخوارزميات المتقدمة وهياكل البيانات. ملاحظة: عند الإشتراك في أحد الدورات يتم فتح المسار الأول من كل دورة وبالتالي يمكنك أن تتعرف أكثر عن كل دورة ومعرفة محتواياتها وما ستتعمله في النهاية أيضًا. بعد تعلم الأساسيات ستحتاج إلى تحديد ما تريد التخصص به كما ذكرت سابقًا وأنصح بهذه المقالة التي تعطي نبذة عن كل مجال وما هي متطلباته وما ستحتاج إليه لكي تبدأ في العمل في هذا المجال: لمعرفة المزيد عن دورات حسوب الأخرى يمكنك أن تنظر هذه الإجابة: أو يمكنك أن تزور صفحة الدورات من هنا.1 نقطة
-
UI هي واجهة المستخدم (User Interface)، بينما UX هي تجربة الإستخدام (User Experience)، ولكل منهما العديد من التفاصيل والشروحات والأداوات التي يمكنك إستخدامها، ومصمم واجهة الاستخدام UI/UX Designer لا يقوم بكتابة الأكواد ولكن كتابة الأكواد هي عمل UI/UX Developer، فالمصمم هو من يقوم بعمل مخطط للتصميم ثم يقوم المختص بتحويلها الى كود فعلي. في الوقت الحالي لن تجد الكثير من المحتوى العربي الذي يتخصص في تصميم واجهة الاستخدام UI/UX Design (على الأقل مقارنة بالمحتوى الأجنبي)، يمكنك أن تحصل على دورة مقدمة من Google بخصوص تجربة الإستخدام User Experience وهي دورة مجانية لفترة تجريبية (للحصول على الشهادة يجب أن تقوم بدفع مبلغ مالي) تقوم بدراستها من خلال موقع Coursera، تقدم الدورة شرح للأساسيات مثل wireframing و prototyping مع أسخدام أدوات مثل Adobe X.D و Figma. كما أن أكاديمية حسوب تحتوي على العشرات من المقالات في التصميم بشكل عام وفي تصميم واجهة الاستخدام UI/UX Design بشكل خاص، وأنصحك بأن تبدأ بسلسلة مقدمة إلى UI لتعلم كل ما يخص واجهة المستخدم User Interface، بالإضافة إلى سلسلة مدخل إلى تجربة المستخدم لتعلم تجربة الإستخدام User Experience، وكلٌ من السلسلتين يُعد مدخل ممتاز يحتوي على شرح لكل ما ستحتاج تعلمه للبدأ في العمل في هذا المجال. ستتعلم من خلال دورة جوجل ومن خلال السلستين السابقتين العديد من المصطلحات مثل: User Interviewing - مقابلة المستخدمين Usability Testing - اختبار قابلية الاستخدام Human Computer Interaction - تفاعل الإنسان والحاسوب Strategy Design - تصميم الإستراتيجية وغيرها الكثير. أيضًا سوف تحتاج إلى التدرب على أشهر أدوات التصميم مثل Adobe X.D و Figma فالطبع لن تستطيع عمل تصميم ممتاز حتى وإن كانت لديك معرفة كبيرة بالمجال ما لم يكن لديك معرفة بالأدوات التي سوف تستعملها. عند إنتهائك من تعلم الدروس والأدوات السابقة أنصحك بالإطلاع على المقالات العامة في قسم التصميم لأنك سوف تحصل على معرفة ممتازة بأدوات وأشياء وقواعد لم تكن تعلمها من قبل مما سيؤدي بالنهاية إلى جعل تصاميمك أكثر إحترافية. بعد تعلم ما سبق سوف تجد أن الأمور أصبحت أكثر وضوحًا وستعرف تلقائيًا الخطوة التالية.1 نقطة
-
تُعَد البيانات وجافاسكربت للواجهة الأمامية من الناحية العملية أحداثًا متنافية، إذ يرى سوق العمل أن وظيفة الواجهة الخلفية معالجة البيانات وتجميعها، أما وظيفة جافاسكربت فهي عرض البيانات المُجمّعة مسبقًا، كما يُنظر إلى عرض النطاق الترددي وزمن المعالجة على أنهما عقبتان رئيسيتان لدى التعامل مع البيانات في الواجهة الأمامية وهذا صحيح إلى حدٍ كبيرٍ، ولكن توجد حالاتٌ من المجدي فيها معالجة البيانات ضمن المتصفح. إذًا فكيف يمكن النجاح بمعالجة البيانات في هذه الحالات؟ التفكير في البيانات يتطلب العمل على البيانات باستخدام جافاسكربت امتلاكًا كاملًا للبيانات وفهمًا للأدوات المتوفرة دون اتصالٍ غير ضروريٍ بالخادم، حيث من المفيد التمييز بين البيانات التابعة لثلاثة أطرافٍ والبيانات المُلّخصة. تتألف البيانات ثلاثية الأطراف من بيانات معاملاتٍ أولية، وهي بيانات منخفضة المستوى يصعب تحليلها لوحدها؛ وتوجد من ناحيةٍ أخرى البيانات المُلخصة وهي البيانات الممكن عرضها بطريقةٍ مفيدةٍ ومنطقية، وتُدعى أيضًا بالبيانات المكوّنة. يهتم المطورون بهيكلية البيانات الكامنة بين تفاصيل المعاملات والبيانات المكوّنة، وهذه هي النقطة التي سنُركز عليها، فهذه البيانات مُجمّعة ولكنها تتضمن أكثر مما نحتاج للعرض النهائي، كما تمتلك بُعدين أو أكثر (متعددة الأبعاد)، وهذا يوفّر مرونةً في طريقة عرضها، فهي تسمح للمستخدمين النهائيين بتشكيل البيانات واستخراج المعلومات لمزيدٍ من التحليل، وبالرغم من أنها صغيرة وذات أداء جيدٍ، إلا أنها توفّر تفاصيلًا تسمح لنا وللمؤلف بالاطلاع على معلوماتٍ لم نكن نتوقعها. يجب أن لا يكون الهدف هو الوصول بالبيانات إلى هيئةٍ مثالية، وذلك لتجنب أي تلاعبٍ بها في الواجهة الأمامية، بل يجب تقليص البيانات إلى مجموعة بياناتٍ متعددة الأبعاد، كما يجب استخدام أبعادٍ متعددة يهتم بها العميل المُستهدف مثل الأشخاص والمنتجات والأماكن والوقت، وقياساتٍ متعددة مثل المجموع والتعداد والمتوسط وأصغر قيمة وأعظم قيمة، وبالتالي فعلينا في النهاية عرض هذه البيانات على صفحةٍ مع عناصر نموذج تسمح بتقسيم البيانات لتحليلها بصورةٍ أعمق. يُعَد إنشاء مجموعات البيانات عمليةً دقيقة جدًا، حيث لا بد من امتلاك بياناتٍ كافية ليكون تحليلنا ذو قيمة وبدون إجهاد جهاز العميل سواءً كان حاسوبًا أو هاتفًا ذكيًا أو غير ذلك، وهذا يعني الوصول لمتطلباتٍ واضحة وموجزة، وسوف نحتاج لاستخدام أبعاد متنوعة وقياسات مختلفة، وهذا يعتمد على مدى اتساع مجموعة البيانات التي نتعامل معها. سنذكر فيما يلي بعض الأمور الواجب أخذها بالحسبان: هل غالبية المحتوى هو محتوى مميز أو سوف يُستخدم مرارًا؟ حيث نعتمد على قاعدة 80/20 التي تنص على أن 80% من المستخدمين عامةً يحتاجون إلى 20% مما هو متوفرٌ. هل كل الأبعاد منتهية؟ حيث يجب أن تمتلك الأبعاد مجموعةً من القيم المُحددة مسبقًا، فمثلًا مخزون منتج ما يزداد باستمرار سوف يتضخم بسرعة، لذلك فإن العمل على تصنيفات المنتج ربما سيكون أفضل. العمل على تجميع البيانات ما أمكن وبالأخص التواريخ، وإن كنت تستطيع الاكتفاء بعملية التجميع باستخدام الأعوام فافعل ذلك، وإن كنت بحاجة للتجميع بالاعتماد على الشهر فلا بأس بذلك، ولكن تجنب المجالات الأصغر من ذلك. اعتماد مبدأ "القلة أفضل"، فكلما كان عدد القيم ضمن البعد أقل، كان هذا أفضل من ناحية الأداء. لنأخذ مجموعة بيانات مؤلفةً من 200 صفٍ على سبيل المثال، فإذا أضفنا بعدًا آخر بأربع قيمٍ ممكنة، فسوف تتضخم مجموعة البيانات هذه إلى 200x4 = 800 صفٍ كحدٍ أعظمي؛ أما إذا أضفت بعدًا بخمسين قيمة، فعندها سوف تتضخم مجموعة البيانات إلى 200x50 = 10000 صفًا، وهذا سوف يتضاعف مع كل بعد نُضيفه. تجنُب القياسات المُلخصة في مجموعات البيانات متعددة الأبعاد لأنها تحتاج إعادة الحساب في كل مرةٍ تتغير فيها مجموعة البيانات، إذ يجب عليك مثلًا تضمين المجموع الكلي والعدد الكلي وحساب المتوسطات ديناميكيًا إذا كنت تخطط لعرض المتوسط، ونتمكن بهذه الطريقة من إعادة حساب المتوسطات باستخدام القيم المُلخصة عند تلخيص البيانات. تأكد من فهمك الجيد للبيانات التي تعمل عليها قبل البدء بتنفيذ أيٍ من المذكور سابقًا، فمن المحتمل أن تفترض افتراضاتٍ خاطئةٍ تقود إلى قراراتٍ مبنيةٍ على معلوماتٍ خاطئة، لذلك فإن جودة البيانات هي أولويةٌ هامة وهذا ينطبق على البيانات التي تطلبها أو تُنشئها. لا تأخذ أي مجموعة بيانات وتبني افتراضاتٍ عن بعد أو قياسٍ فيها، ولا تتردد بالسؤال دائمًا عن فهرس البيانات أو أي توثيقٍ خاصٍ بها يُمكن أن يساعد على فهم ما تتعامل معه، حيث لا يعتمد تحليل البيانات على الحدس أو التنبؤ، فربما طُبقت قواعد خاصة بعملٍ تجاريٍ أو حُذفت بيانات في خطوةٍ سابقة، وبالتالي فإن كنت لا تملك هذه المعلومات فسينتهي بك الأمر بإنتاج مجموعات بياناتٍ وتصوراتٍ لا معنى لها أو مضللة بأسوء الأحوال. سوف يساعد المثال التالي على فهم ما سبق. حالة الاستخدام المدروسة سوف نستخدم مجموعة بيانات BuzzFeed المختصة بتحليل البيانات المتعلقة بالأماكن التي يأتي منها اللاجئون إلى الولايات المتحدة والأماكن التي يذهبون إليها، حيث سنبني تطبيقًا صغيرًا يعرض لنا عدد اللاجئين الواصلين لولايةٍ محددة في عامٍ محدد، وسنعرض على وجه الخصوص واحدةً مما يلي بناءً على طلب المستخدم: العدد الكلي للواصلين إلى ولايةٍ معينة في عامٍ معينٍ. العدد الكلي للواصلين خلال كل الأعوام لولايةٍ معينة. العدد الكلي للواصلين لكل الولايات في عام معيّن. سوف تكون واجهة المستخدم عبارة عن نموذجٍ بسيطٍ لاختيار الولاية والعام، وسوف تعمل الشيفرة على: إرسال طلبٍ بالبيانات. تحويل النتيجة إلى JSON. معالجة البيانات. تسجيل أي خطأ في الطرفية. عرض النتائج للمستخدم. لن نمرّر مجموعات بياناتٍ ضخمة الحجم للمتصفح لسببين هما عرض الحزمة، وقدرات وحدة المعالجة المركزية CPU، لذلك ستُجمع البيانات في الخادم باستخدام Node.js. بيانات المصدر [{"year":2005,"origin":"Afghanistan","dest_state":"Alabama","dest_city":"Mobile","arrivals":0}, {"year":2006,"origin":"Afghanistan","dest_state":"Alabama","dest_city":"Mobile","arrivals":0}, ... ] البيانات متعددة الأبعاد: [{"year": 2005, "state": "Alabama","total": 1386}, {"year": 2005, "state": "Alaska", "total": 989}, ... ] كيفية ضبط هيكلية البيانات في المكان الصحيح واجهة AJAX وFetch API توجد عدة طرق في جافاسكربت من أجل جلب البيانات من مصدرٍ خارجيٍ، وكان علينا قديمًا استخدام طلب XHR لذلك، لأنه مدعوم على نطاقٍ واسعٍ ولكنه معقد ويتطلب استخدام عدة طرقٍ مختلفة، كما توجد مكتبات تُساعد على تخفيض التعقيد، مثل Axios أو jQuery's Ajax API، كما أنها توفّر دعمًا عبر المتصفحات، ولهذا فهي خيارٌ متاحٌ إن كنت تستخدم أحدها، لكن لا بد من اختيار الحلول الأصيلة ما أمكن. توجد أيضًا طريقة Fetch API وهي الأحدث، ولذلك فهي مدعومةٌ على نطاقٍ أضيق من سابقاتها، ولكنها أسهل وقابلة للتسلسل، وستُحوّل الشيفرة البرمجية إلى مكافئٍ مدعومٍ على نطاقٍ أوسع إن كنت تستخدم ناقلًا مثل Babel. ستُستخدم واجهة Fetch API في الحالة المدروسة لجلب البيانات للتطبيق. window.fetchData = window.fetchData || {}; fetch('./data/aggregate.json') .then(response => { // when the fetch executes we will convert the response // to json format and pass it to .then() return response.json(); }).then(jsonData => { // take the resulting dataset and assign to a global object window.fetchData.jsonData = jsonData; }).catch(err => { console.log("Fetch process failed", err); }); الشيفرة البرمجية السابقة هي جزءٌ من ملف main.js الموجود في مستودع GitHub، حيث ترسل الطريقة fetch() طلبًا بالبيانات ثم نحوّل النتائج إلى JSON، وستُستخدم الطريقة then() من أجل ضمان عدم تنفيذ التعليمة التالية إلا بعد جلب كامل مجموعة البيانات، وستُنفذُ جميع عمليات معالجة البيانات ضمن هذه الكتلة، كما ستُسجل الأخطاء باستخدام console.log(). الهدف هنا هو تحديد الأبعاد الأساسية المطلوبة لعمل تقريرٍ بالعام والولاية قبل تجميع عدد الواصلين المرتبطين بهذه الأبعاد، وإزالة الدولة الأم والمدينة المتوجهين لها، ويمكنك الاطلاع على النص البرمجي Node.js في الملف preprocess/index.js/ في مستودع GitHub لفهم كيفية إنجاز العمليات السابقة بصورةٍ أكبر، حيث يُنشئ هذا النص البرمجي ملف aggregate.json الذي يجلبه التابع fetch(). البيانات متعددة الأبعاد الهدف من الصيغة متعددة الأبعاد هو تحقيق المرونة بحيث تكون البيانات مُفصلةً جيدًا، حتى لا يُضطر المستخدم لطلب استعلام للخادم في كل مرةٍ يحتاج فيها إجابةً عن سؤالٍ مختلف، وتكون مُلخصةً بنفس الوقت بحيث لا يُضطر التطبيق للبحث في كامل مجموعة البيانات مع كل جزءٍ جديدٍ من البيانات. يجب علينا توقع الأسئلة وتقديم بيانات تُجيب عن هذه الأسئلة لأن المستخدم يحتاج إلى أن يكون قادرًا على إجراء بعض التحليلات دون أن يشعر بأنه مُقيدٌ أو مغمورٌ بكمٍ هائلٍ من المعلومات. ستُستخدم بيانات JSON كما هو الحال مع معظم واجهات برمجة التطبيقات APIs، فهي معيارٌ مُستخدمٌ لإرسال البيانات للتطبيقات على أنها كائناتٌ تتألف من أزواج (اسم وقيمة). ألقِ نظرةً على العينة التالية من مجموعة بياناتٍ متعددة الأبعاد قبل العودة إلى الحالة المدروسة: const ds = [{ "year": 2005, "state": "Alabama", "total": 1386, "priorYear": 1201 }, { "year": 2005, "state": "Alaska", "total": 811, "priorYear": 1541 }, { "year": 2006, "state": "Alabama", "total": 989, "priorYear": 1386 }]; تستطيع استخدام جافاسكربت على نحوٍ أكبر لتحليل مجموعة البيانات عندما تكون مُجمّعةً بطريقة صحيحة. لنُلقِ نظرةً على بعض من توابع مصفوفات جافاسكربت المُستخدمة لتكوين البيانات. كيفية العمل بفعالية مع البيانات من خلال جافاسكربت ترشيح المصفوفة تأخذ طريقة filter() الخاصة بالنموذج الأولي للمصفوفة Array.prototype.filter()، وظيفة اختبار كل عنصرٍ ضمن المصفوفة، وتُعيد مصفوفةً أخرى تحتوي على القيم التي تجاوزت الاختبار، وهذا يسمح بإنشاء مجموعة بياناتٍ فرعيةٍ ذات معنى عند استخدام القائمة المنسدلة أو مرشحات النص، كما سيتمكن المستخدم من الاطلاع على المعلومات من خلال عرض أقسامٍ من البيانات، وهذا صحيحٌ أيضُا عند استخدام أبعادٍ ذات معنى ومنفصلة لمجموعة البيانات متعددة الأبعاد. ds.filter(d => d.state === "Alabama"); // Result [{ state: "Alabama", total: 1386, year: 2005, priorYear: 1201 },{ state: "Alabama", total: 989, year: 2006, priorYear: 1386 }] ربط بيانات المصفوفة تأخذ طريقة map() الخاصة بالنموذج الأولي للمصفوفة Array.prototype.map() وظيفة تمرير كل عنصرٍ في المصفوفة وإعادة مصفوفةً جديدةً بنفس عدد العناصر القديم، حيث يسمح ربط البيانات بإنشاء مجموعات بياناتٍ مرتبطة، وأحد استخدامات هذه الطريقة هو ربط بياناتٍ غامضةٍ مع بياناتٍ ذات معنى وموصوفة، أو استخدامها لأخذ قياسات وإجراء حسابات على عناصر المصفوفة لتحقيق تحليلٍ أكثر عمقًا. 1. ربط البيانات ببيانات ذات معنى ds.map(d => (d.state.indexOf("Alaska")) ? "Contiguous US" : "Continental US"); // Result [ "Contiguous US", "Continental US", "Contiguous US" ] 2. ربط البيانات مع النتائج المحسوبة ds.map(d => Math.round(((d.priorYear - d.total) / d.total) * 100)); // Result [-13, 56, 40] تلخيص بيانات المصفوفة تأخذ طريقة reduce()الخاصة بالنموذج الأولي للمصفوفة Array.prototype.reduce() وظيفة معالجة كل عنصرٍ ضمن المصفوفة وإعادة بياناتٍ مُجمعةٍ، وتُستخدم لإنجاز حساباتٍ رياضيةٍ مثل إضافة أو ضرب كل رقمٍ ضمن المصفوفة، ويُمكن استخدامها أيضًا لضم المحارف والعديد من الأمور الأخرى، ولا بد من تعلُّم هذه الدالة من خلال مثالٍ نظرًا لصعوبتها. عليك التأكد من تلخيص البيانات عند عرضها، بحيث تُقدم فكرةً مُلخصةً للمستخدمين، ولذلك يُمكن تجميع البيانات اعتمادًا على ما يحتاجه المُستخدم حتى عند تطبيق عمليات تلخيصٍ عامة على البيانات من جهة الخادم، وبالنسبة للتطبيق الذي ننشئه، فعليّنا إضافة المجموع الكلي لكل مُدخلٍ وعرض النتيجة المُجمّعة باستخدام طريقة reduce() للمرور على كل سجلٍ وإضافة القيمة الحالية إلى المجمّع، وبهذا تكون النتيجة النهائية هي المجموع الكلي لقيم كل مصفوفة. ds.reduce((accumulator, currentValue) => accumulator + currentValue.total, 0); // Result 3364 تطبيق هذه الدوال على الحالة المدروسة حالما نحصل على البيانات سنعيّن حدثّا للزر "Get the Data" من أجل عرض المجموعة الفرعية من البيانات المناسبة، حيث توجد عدة مئاتٍ من العناصر ضمن بيانات JSON الخاصة بالتطبيق، وتتواجد الشيفرة المسؤولة عن دمج البيانات مع الزر في الملف main.js الخاص بنا: document.getElementById("submitBtn").onclick = function(e){ e.preventDefault(); let state = document.getElementById("stateInput").value || "All" let year = document.getElementById("yearInput").value || "All" let subset = window.fetchData.filterData(year, state); if (subset.length == 0 ) subset.push({'state': 'N/A', 'year': 'N/A', 'total': 'N/A'}) document.getElementById("output").innerHTML = `<table class="table"> <thead> <tr> <th scope="col">State</th> <th scope="col">Year</th> <th scope="col">Arrivals</th> </tr> </thead> <tbody> <tr> <td>${subset[0].state}</td> <td>${subset[0].year}</td> <td>${subset[0].total}</td> </tr> </tbody> </table>` } سوف يأخذ حقل الولاية أو العام القيمة الافتراضية "All" عندما يكون فارغًا. ويمكن الاطلاع على الشيفرة البرمجية التالية المُتاحة في الملف js/main.js/ وإلقاءِ نظرةٍ على الدالّة ()filterData التي نسجّل ضمنها حصة الأسد من عمليتي الترشيح والتجميع. // with our data returned from our fetch call, we are going to // filter the data on the values entered in the text boxes fetchData.filterData = function(yr, state) { // if "All" is entered for the year, we will filter on state // and reduce the years to get a total of all years if (yr === "All") { let total = this.jsonData.filter( // return all the data where state // is equal to the input box dState => (dState.state === state) .reduce((accumulator, currentValue) => { // aggregate the totals for every row that has // the matched value return accumulator + currentValue.total; }, 0); return [{'year': 'All', 'state': state, 'total': total}]; } ... // if a specific year and state are supplied, simply // return the filtered subset for year and state based // on the supplied values by chaining the two function // calls together let subset = this.jsonData.filter(dYr => dYr.year === yr) .filter(dSt => dSt.state === state); return subset; }; // code that displays the data in the HTML table follows this. See main.js. كما ذُكر سابقًا فإن القيمة الافتراضية لحقل الولاية أو العام هي "All" في حال بقي فارغًا، حيث تُرشح مجموعة البيانات وتُلخص قياسات جميع الأسطر حسب هذا البعد، كما ستُرشح قيمة كلٍ من العام والولاية عند إدخالهما. لدينا الآن مثال مجرب، حيث: بدأنا بمجموعة بياناتٍ أوليةٍ ذات معاملات. ثم أنشأنا مجموعة بياناتٍ متعددة الأبعاد وشبه مُجمعة. وبنينا نتيجةً كاملةً التكوين ديناميكيًا. يُمكن التلاعب بالبيانات حالما تصل للمستخدم بعدة طرقٍ دون الحاجة للاتصال المتكرر بالخادم، وهذا مفيد جدًا في حال فقد المستخدم الاتصال، لأنه بذلك لن يفقد القدرة على التفاعل مع البيانات، وهذه ميزةٌ رائعةٌ خصوصًا عند بناء تطبيق ويب تقدُّمي Progressive Web App أو اختصارًا PWA، يحتاج أن يعمل دون اتصالٍ بالانترنت. يمكن إنشاء أي تحليلٍ لأي مجموعة بيانات حالما تُحكم قبضتك على هذه الطرق الثلاث، لذلك اربط أحد الأبعاد ضمن مجموعة البيانات مع تصنيفٍ أكثر شمولية، ولخّص البيانات باستخدام reduce. تستطيع أيضًا استخدام مكتبة D3 من أجل ربط البيانات مع جداول ورسوم بيانية تسمح بتصوُّر مرئي مخصص بالكامل لهذه البيانات. الخلاصة يُطلعنا هذا المقال على الإمكانيات الكامنة في جافاسكربت عند التعامل مع البيانات، وكما ذُكر سابقًا فإن جافاسكربت للواجهة الأمامية ليست بديلًا لتفسير وتحويل البيانات على الخادم حيث تُنجز المهمات الصعبة، كما يجب بنفس الوقت عدم استبعادها عند معالجة مجموعات البيانات بالطريقة الصحيحة. ترجمة -وبتصرّف- للمقال Taming Data with JavaScript لصاحبه Brian Greig. اقرأ أيضًا هياكل البيانات: الكائنات والمصفوفات في جافاسكريبت ماهي جافاسكريبت؟ أمثلة على الاستخدامات برمجة الكائنات Objects في جافاسكريبت1 نقطة
-
يرغب الجميع بأن يصبح خبيرًا، إذ يوجد على مر السنين نوعان من البشر يُدعون "الخبراء"؛ حيث خبراء النوع الأول هم ممن يعرفون جميع الأدوات المتوفرة في لغة البرمجة ويحرصون على استخدام كل جزئيةٍ منها سواءً كانت تُفيدهم أم لا؛ والنوع الثاني هم ممن يعرفون كل جزئيةٍ من لغة البرمجة ولكنهم انتقائيون بما يجب استخدامه لحل المشاكل البرمجية، حيث يأخذون بالحسبان مجموعةً من العوامل المرتبطة بالشيفرة البرمجية وأمورًا أخرى غير برمجية. يمكننا تخمين أي نوعٍ من هؤلاء الخبراء يرغب مدير الفريق العمل معهم، إذ يقع الاختيار غالبًا على النوع الثاني من الخبراء، فهم مطورون يركزون على تسليم سطورٍ برمجيةٍ مقروءة من جافاسكربت ومفهومةٍ أيضًا، كما يعملون على صيانتها، إضافةً إلى قدرتهم على جعل المعقد يبدو بسيطًا. هناك عدة عواملٍ يجب النظر إليها من قِبل الخبراء عند كتابة شيفرةٍ مقروءة، وتحديد الخيارات الواضحة الصحيحة منها والخاطئة. الخيار الواضح لقد أضاف TC39 الكثير من الميزات الجديدة إلى ECMAScript خلال السنوات الماضية بهدف تحسين تجربة المطوّر، حيث تتضمن هذه الميزات أنماطًا مُحسنةً ومستوحاةً من لغاتٍ أخرى، وأحد هذه الإضافات في ES2019 هي Array.prototype.flat()، حيث يُطلب مُدخلٌ واحدٌ وهو العمق أو Infinity لنشر مصفوفة، ويكون العمق الافتراضي عند عدم استخدام أي مدخلٍ هو 1، وبدون هذه الإضافة كان علينا استخدام الصيغة التالية لنشر المصفوفة في مستوٍ واحدٍ. let arr = [1, 2, [3, 4]]; [].concat.apply([], arr); // [1, 2, 3, 4] أما عند إضافة flat() أصبح من المُمكن التعبير عن نفس الوظيفة باستخدام تعليمةٍ واحدةٍ وهي الدالّة التالية. arr.flat(); // [1, 2, 3, 4] يُعَد السطر الثاني من الشيفرة أكثر قابليةً للقراءة، وسوف يتفق على هذه النقطة كِلا النوعين من الخبراء. لا يعلم جميع المطورين بوجود الدالّة flat() وهم ليسوا بحاجةٍ لذلك، وعند ورودها فإن flat سيكون فعلًا يصف نفسه ويتضمن محتوى ما يفعله وهي أسهل للفهم من concat.apply(). من النادر وجود جوابٍ واضحٍ وصريح بأفضلية الصيغ الجديدة عن القديمة، وسوف يختار الخبير -لأي مجموعةٍ كان ينتمي- الخيار الثاني إن كان على علمٍ بكلا الخيارين لكتابة التعليمات، لأن الخبير يميل لاختيار الشيفرة الأقصر والأوضح والتي تسهل صيانتها وتتبع الخطأ فيها. الفحص الداخلي تتميز لغة جافاسكربت بأنها متعددة الاستخدام وواسعة الانتشار، فهي مُستخدمة في جميع أجزاء شبكة الويب، ويمكن كتابة الشيفرة نفسها بعدة طرقٍ ولكن لن تتمكن من تحديد الخيار الصحيح ما لم تفهم جيدًا الخيارات المتوفرة والقيود التي تُرافق كل منها. ستُستخدم البرمجة الوظيفية مع map() مثالًا لذلك وستُشرح جميع التكرارات التي تعطي نفس النتيجة، ويُعَد المثال التالي النسخة الأقصر من الأمثلة التي تستخدم map() حيث يتسع في سطرٍ واحدٍ. const arr = [1, 2, 3]; let multipliedByTwo = arr.map(el => el * 2); // multipliedByTwo is [2, 4, 6] سيُضاف مِحرفان فقط إلى المثال التالي وهما قوسان "()"، حيث توجد دائمًا خسارةٌ وكسب بعد أي تغيير، كما يوجد اختلافُ عند استخدام دالةٍ متعددة المتغيرات الأقواس دائمًا، ولا يوجد ضررٌ في إضافة هذين القوسين هنا فهما يحسّنان التناسق عند كتابة دالةٍ متعددة المتغيرات، وحقيقةً يجبرنا Prettier على استخدام الأقواس، فهو لا يسمح بإنشاء دالةٍ سهميّةٍ دون استخدام الأقواس. let multipliedByTwo = arr.map((el) => el * 2); ستُرفع سوية المثال وتُضاف أقواس مجموعة وتعليمة return لتبدو هذه الدالّة أشبه بالدوال التقليدية. هذه الإضافات مطلوبة عندما تكون الدالّة أكثر من سطرٍ واحد، وبالتأكيد ستُكتب العديد من الدوال المتضمنة أكثر من سطر واحد ضمن الشيفرة البرمجية. let multipliedByTwo = arr.map((el) => { return el * 2; }); ستُزال الآن الدالّة السهمية وتُستخدم نفس صيغة المثال السابق لكن مع استخدام الكلمة المفتاحية function، وهذا مثير لأن هذه الصيغة سوف تعمل في جميع الحالات، ولن ينتج أي خطأ مهما كان عدد المتغيرات أو السطور، وذلك نظرًا لكونها مقروءةً ومألوفة أكثر من الصيغة المستخدمة في المثال الأول، ولكن هل هذا التغيير سيء؟ وكيف سيكون وقعه على مُبرمجٍ جديد أو شخصٍ خبير جدًا بلغةٍ مختلفةٍ عن جافاسكريبت؟ هل سوف تُشكل هذه الصيغة عبئًا على شخص يعرف جافاسكربت جيدًا بالموازنة مع المثال الأول؟ let multipliedByTwo = arr.map(function(el) { return el * 2; }); وصلنا الآن إلى الخيار الأخير وهو تمرير الدالّة فقط، حيث يمكن كتابة timesTwo بأي طريقةٍ تريدها ولا توجد مشكلة يُسببها تمرير اسم الدالّة في أية حالة، لكن لنتوقف للحظة ونفكر فيما إذا كانت هذه الصيغة تُسبب الحيرة أم لا، فإذا كنت جديدًا على طريقة كتابة هذه الشيفرة، فلن يكون واضحًا لك أن timesTwo هي دالّة وليست كائنًا، ولكن map() موجودة لتُعطيك تلميحًا، لذلك هناك العديد من الأمور الهامة الواجب الانتباه إليها وهي امكانية إغفال هذه الدالة، وسهولة العثور عليها، وتأثيرها على النتيجة. const timesTwo = (el) => el * 2; let multipliedByTwo = arr.map(timesTwo); لا توجد إجابةٌ واضحةٌ هنا، حيث أن اتخاذ الخيار الصحيح لطريقة كتابة الشيفرة يعني فهم جميع الخيارات المتوفرة ومحدوديتها، كما يجب إدراك أن التناسق يتطلب استخدام أقواس المجموعة والأقواس العادية والكلمة المفتاحية return. يجب أن تسأل نفسك مجموعةً من الأسئلة عند كتابة شيفرة برمجية، والأسئلة المرتبطة بالأداء هي الأكثر رواجًا، ولكن عندما تنظر إلى شيفرة برمجية متطابقة من الناحية الوظيفية، فيجب أن يكون اختيارك مبنيًا على الإنسان وكيفية فهم غيرك لهذه الشيفرة. ليس بالضرورة أن يكون الأحدث هو الأفضل طُرح حتى الآن مثالٌ يوّضح أي صيغةٍ برمجيةٍ جديدةٍ، بحيث يستخدم كل نوعٍ من الخبراء حتى وإن كانت غير معروفةٍ عالميًا، كما طُرح مثالٌ يدعو للكثير من التساؤلات دون إجاباتٍ كافية، وأصبح الوقت الآن مُناسبًا للتعمق أكثر في الشيفرة البرمجية التي كُتبت سابقًا ثم أُزيلت، وهي الشيفرة البرمجية التي استخدمت صيغًا غير معروفة على نطاقٍ واسع لحل مشكلة، إضافةً إلى قابلية صيانتها بالاعتماد على القواعد المعروفة لكتابة الشيفرة. يسمح لك التعيين بالتفكيك Destructing assignment؛ إمكانية تفريغ القيم من الكائنات (أو المصفوفات) وهو مماثل للشكل الآتي. const {node} = exampleObject; وهو يُهيئ متغيرًا ويُسند له قيمةً في سطرٍ واحد ولكن هذا غير ضروري. let node ;({node} = exampleObject) يُسنِد السطر الأخير من الشيفرة البرمجية قيمةً للمتغير باستخدام التفكيك، لكن التصريح عن المتغير يشغل سطرًا قبله، وهذا أمرٌ يرغب الكثير باستخدامه، إلا أن الغالبية لا تُدرك إمكانية ذلك. نلاحظ عند النظر إلى الشيفرة بتمعُّن؛ وجود الفاصلة المنقوطة غير المُستخدمة لإنهاء السطر كما جرت العادة، إضافةً إلى استخدام الأقواس للإحاطة بالتعليمة واستخدام أقواس مجموعة داخلها أيضًا، وبالتأكيد فإن وظيفة هذه التعليمة غير واضحة، فمن الصعب قراءتها، و يجب ألا تكون موجودة في أي شيفرةٍ مكتوبة من قِبل خبير. let node node = exampleObject.node تحل هذه الشيفرة المشكلة فهي تعمل ووظيفتها واضحة، كما يسهل فهمها دون الحاجة للبحث عنها، وبالتالي فلا يجب استخدام الصيغة التفكيكية فقط لأننا نستطيع ذلك. الشيفرة ليست كل شيء كما هو ملاحظ فقد كان حل خبراء النوع الثاني واضحًا بالاعتماد على الشيفرة فقط، ومع ذلك لا يزال هناك فرقٌ واضحٌ بالنسبة للشيفرة التي يكتبها كل خبير، وذلك لأن الشيفرة موجهةٌ للآلة كي تقرأها وللإنسان كي يُفسرها، وبالتالي لا توجد عوامل مرتبطة بالشيفرة هنا لأخذها بالحسبان. تختلف صيغة لغة البرمجة التي تستخدمها من أجل فريقٍ من مطوّري جافاسكربت عن تلك التي تستخدمها من أجل فريقٍ متعدد اللغات لم يتعمق أفراده في تفاصيل اللغة، ونذكر على سبيل المثال الصيغة spread مقابل concat()، حيث أُضيفت spread إلى ECMAScript منذ عدة سنوات واعتُمدت على نحوٍ واسعٍ، فهي تُعَد ميزةً للصيغة تسمح لك بإنجاز العديد من الأمور وأحدها هو تعاقب تسلسل مجموعةٍ من المصفوفات. const arr1 = [1, 2, 3]; const arr2 = [9, 11, 13]; const nums = [...arr1, ...arr2]; بالرغم من فعالية وقوة spread إلا أنها ليست رمزًا بديهيًا تستطيع التنبؤ بعمله، وبالتالي إن كنت لا تعلم وظيفته فلن يكون مفيدًا. بينما يعتقد العديد من الخبراء أن هذه الصيغة مألوفةً بالنسبة لفريقٍ من مُختصي جافاسكربت، يتساءل خبراء النوع الثاني عما إذا كان هذا الكلام صحيحًا بالنسبة لفريقٍ من المبرمجين متعددي اللغات، لذلك فمن المُحتمل أن يختار هؤلاء الخبراء استخدام concat() بدلًا من spread لأن اسمها يُعبّر عن عملها. ينتج عن الشيفرة البرمجية التالية نفس النتيجة التي تُقدمها spread في المثال السابق. const arr1 = [1, 2, 3]; const arr2 = [9, 11, 13]; const nums = arr1.concat(arr2); كان هذا أحد الأمثلة لتأثير العامل البشري على خيارات الشيفرة البرمجية، لذلك عند التعامل مع شيفرةٍ برمجيةٍ تعمل عليها فرقٌ مختلفة، فلا بد من الالتزام بمعاييرٍ صارمةٍ لا تراعي بالضرورة الصيغة الأحدث للغة البرمجة، وتنتقل بعد ذلك لعواملٍ أخرى مرتبطة بالأدوات المُستخدمة والتي تجعل العمل أكثر سلاسةً أو صعوبةً لأفراد الفريق. توجد شيفرات برمجية من الصعب اختبارها، وشيفرات من الصعب استخدامها على مجالٍ أوسع في المستقبل نظرًا لصعوبة إضافة وظائف إضافية لها، وشيفرات ذات أداءٍ ضعيف، وشيفرات لا تستطيع التعامل مع متصفحاتٍ مختلفة، وهذه جميعها عواملٌ يُفكر بها خبراء النوع الثاني، إضافةً إلى تأثير الأسماء المستخدمة. ولكن حتى هم لا يستطيعون اعتماد صيغةٍ صحيحةٍ معظم الوقت لهذا الأمر. الخلاصة لا يُثبت الخبير نفسه من خلال قدرته على استخدام كل جزئية من خواص لغة البرمجة، بل من خلال معرفة ما يكفي من هذه الخواص لاستخدامٍ حكيمٍ لصيغةٍ برمجية واتخاذ القرارات المناسبة، فهكذا يكون الخبراء، وبهذه الطريقة يساهمون في تخريج خبراء جُدد، وهذا يعني الكثير لمن يجد نفسه خبيرًا أو يطمح إلى أن يصبح خبيرًا، إذ عليه أن يسأل نفسه العديد من الأسئلة عند كتابة شيفرة برمجية والتفكير بمن يُتابعه من المطوّرين، حيث أن أفضل شيفرةٍ برمجية هي تلك التي تُنفِذ شيئًا معقدًا، ولكنها بنفس الوقت مفهومةٌ عند مراجعتها من قِبل فريق العمل، وهذا بالطبع ليس أمرًا سهل المنال ولا توجد طريقةٌ واضحةٌ للوصول له لكن لا بد من أخذه بالحسبان عند كتابة أي دالّة. ترجمة -وبتصرّف- للمقال Human-Readable JavaScript: A Tale of Two Experts لصاحبه Laurie Barth. اقرأ أيضًا تطويع البيانات في جافاسكربت التخاطب بين نوافذ المتصفح عبر جافاسكريبت مشروع تطبيقي لبناء رجل آلي (روبوت) عبر جافاسكريبت1 نقطة
-
نشرح في هذا الفيديو عن نظام إدارة الحزم وفوائد استخدامه. ولماذا نحن بحاجة إلى مثل هذه الأنظمة. نشرح في هذا الدرس كيفية استخدام سطر الأوامر لتنزيل حزم باستخدام مدير الحزم npm. ستتعرف أيضًا على الملف package.json وما هي الفائدة منه. وكذلك الأمر بالنسبة لمجلد node_modules وكيف يمكنك تضمين مكتبة من داخل هذا المجلد في مشروعك.1 نقطة
-
يشير مصطلح مفتوح المصدر (open source) لأي شيء يمكن لأي شخص تعديله ومشاركته لأن تصميمه متاح للجميع. نشأ هذا المصطلح في سياق تطوير البرمجيات للدلالة على نهج خاص لإنشاء برامج للحاسوب. أما اليوم، فإن مصطلح "مفتوح المصدر" يشير لمجموعة أوسع من القيم - والّتي نسميها "الثقافة مفتوحة المصدر. تتبنى المشاريع، أو المنتجات، أو المبادرات مفتوحة المصدر مبادئ التبادل المفتوح والمشاركة التعاونية والنماذج الأولية السريعة والشفافية العالية والجدارة والتنمية الموجهة للمجتمع. ما هي البرمجية مفتوحة المصدر؟ البرمجيات مفتوحة المصدر: هي برمجيات يمكننا رؤية شيفرتها البرمجية وفحصها وتعديلها وتحسينها. "الشيفرة البرمجية" هي جزء من برمجية لا يراه معظم مستخدمي الحاسوب على الإطلاق، ويتلاعب مبرمجو الحاسوب بالشيفرة لتغيير طريقة عمل البرمجية - سواءً أكانت "برنامج" أو "تطبيق". يمكن للمبرمجين الّذين يستطيعون الوصول للشيفرة البرمجية لبرنامج الحاسوب تحسين هذا البرنامج من خلال إضافة ميزات إليه أو إصلاح الأجزاء الّتي لا تعمل دائمًا عملًا صحيحًا. ما الفرق بين البرمجيات مفتوحة المصدر والأنواع أخرى؟ هناك بعض البرمجيات الّتي لا تُملكُ شيفرتها أو يمكن التعديل عليها سوى الجهة الّتي أنشأتها سواءً أكانت ممثلة بشخص أو فريق أو مؤسسة وتحتفظ هذه الجهة بالسيطرة الحصرية عليها. ويطلق الناس على هذا النوع من البرمجيات "بالبرمجيات المحتكرة" (proprietary) أو "مغلقة المصدر" (closed source). يمكن لأصحاب البرمجيات المحتكرة وحدهم نسخ هذه البرمجيات، وفحصها وتغييرها بطريقة قانونية. ولاستخدام البرمجيات المحتكرة لابد أن يوافق مستخدمي الحاسوب (للتوقيع على الترخيص المعروض والّذي يعرض عادةً عند التشغيل للمرة الأولى للبرمجيات) والّتي تنص على أنهم لن يفعلوا أي شيء للبرمجية مخالف صراحةً لما يسمح به منشئي هذه البرمجية. ومن هذه البرمجيات نذكر Microsoft Office وAdobe Photoshop. تختلف البرمجيات مفتوحة المصدر عن نظيرتها المحتكرة. إذ يتيح منشئي البرمجيات المفتوحة المصدر عرض الشيفرة البرمجية، ونسخها، والتعلم منها، وتغييرها، ومشاركتها أيضًا. ومن هذه البرمجيات نذكر محرر النصوص ليبر أوفيس LibreOffice وبرنامج التلاعب بالصور Gimp. وكما هو الحال مع البرمجيات المحتكرة يجب على المستخدمين عند استخدامهم البرمجيات مفتوحة المصدر الموافقة على شروط الترخيص بيدَ أن هذه الشروط تختلف اختلافًا كبيرًا عن شروط البرمجيات المحتكرة. تحدّد تراخيص البرمجيات مفتوحة المصدر طريقة استخدام البرمجيات، وتعديلها، وتوزيعها. وعمومًا تَمنحُ هذه التراخيص إذنًا باستخدام البرمجيات لأي غرض يرغب به المستخدم. إلا أن البعض الأخر من التراخيص والّتي يسميها البعض "الحقوق المتروكة" تنص على وجوب عرض الشيفرة البرمجية الخاصة لكلّ نُسخة مُعدلة من هذه البرمجية علنيًا. علاوة على ذلك بعض التراخيص تُوجبُ على أي شخص يعدلّ البرمجية ويشاركها مع الآخرين أن يشارك أيضًا المصدر الأصلي للشيفرة بدون فرض رسوم الترخيص عليها. تعمدُ تراخيص البرمجيات مفتوحة المصدر على تعزيز روح التعاون والمشاركة لأنها تسمح للجميع بإجراء تعديلات على الشيفرات البرمجية، ودمج هذه التغييرات في مشاريعهم الخاصة. وهم بذلك يشجعون مبرمجي الحاسوب بالوصول إلى البرمجيات مفتوحة المصدر وعرضها وتعديلها بأي وقت يحلو لهم، طالما أنهم سمحوا للآخرين بفعل نفس الشيئ عندما يشاركون برمجياتهم. هل البرمجيات مفتوحة المصدر مهمة لمبرمجي الحاسوب فقط؟ بالتأكيد لا. بل إن التكنولوجيا مفتوحة المصدر والعقلية المنفتحة للمصادر المفتوحة عمومًا تفيد كلًا من المبرمجين وغير المبرمجين. لأن المخترعين الأوائل للإنترنت شيدوا جزءًا كبيرًا منه على تقنياتٍ مفتوحة المصدر - مثل: نظام التشغيل Linux وتطبيق خادم الوِب المحلي Apache - وبذلك أي شخص يستخدم الانترنت فهو في الحقيقة يستفيد من البرمجيات مفتوحة المصدر. عند كلّ عملية استعراض لصفحة وِب أو التحقق من البريد الإلكتروني، أو الدردشة مع الأصدقاء، أو استخدام منصات البث الموسيقي عبر الإنترنت، أو اللعب بألعاب فيديو متعددة اللاعبين فإن حاسوب المستخدم، أو هاتفه المحمول، أو طرفيات الألعاب ستتصل بشبكة عالمية من الحواسيب من خلال برمجيات مفتوحة المصدر من أجل توجيه ونقل البيانات إلى أجهزتهم "المحلية" الموجودة أمام أعينهم. عادةً ما تتواجد هذه الحواسيب الّتي تؤدي كلّ هذا العمل الهام في أماكن بعيدة عن أنظار المستخدمين أو لا يستطيعون الوصول إليها فعليًا - وهذا هو السبب في أن بعض الأشخاص يطلقون على هذه الحواسيب "بالحواسيب البعيدة". يعتمد الناس أكثر فأكثر على الحواسيب البعيدة عند أداء مهامهم بدلًا من أجهزتهم المحلية. فمثلًا، قد يستخدمون برمجيات معالجة الكلمات وإدارة البريد الإلكتروني وتحرير الصور وهي غير مثبتة على حواسيبهم الشخصية. وإنما، ببساطة يصلون لها عبر الحواسيب البعيدة من خلال متصفح الوِب أو تطبيق على الهاتف محمول. وعندما يفعلون ذلك، فهم ينخرطون في "الحوسبة عن بُعد". يطلق بعض الأشخاص على الحوسبة عن بُعد "بالحوسبة السحابية" وذلك لأنها تتضمن أنشطة (مثل: تخزين الملفات أو مشاركة الصور أو مشاهدة مقاطع الفيديو) والّتي لا تتضمن حواسيب محلية فقط وإنما شبكة عالمية من الحواسيب البعيدة أيضًا الّتي تشكل سحابة. تتوالى أهمية الحوسبة السحابية يومًا بعد يوم وخصيصًا في الحياة اليومية للأجهزة المتصلة بالإنترنت. ومن بعض تطبيقات الحوسبة السحابية المحتكرة Google Apps. أما بعض التطبيقات الأخرى مفتوحة المصدر نذكر: ownCloud وNextcloud. تعمل تطبيقات الحوسبة السحابية "على قمة" من البرمجيات الإضافية المساعدة لها لتعمل بسلاسة وكفاءة، لذلك غالبًا ما سيقول الناس أن البرمجيات الّتي تعمل "تحت" تطبيقات الحوسبة السحابية تعمل بمثابة "منصة" لتطبيقات الحوسبة السحابية، وتكون هذه المنصات إما مفتوحة المصدر أو مغلقة المصدر. فمثلًا المنصة OpenStack هي منصة مفتوحة المصدر. لماذا يفضل الناس استخدام برمجيات مفتوحة المصدر؟ يفضل الناس البرمجيات مفتوحة المصدر على حساب البرمجيات المحتكرة لعدد من الأسباب: زيادة السيطرة على البرمجية يفضل كثير من الناس البرمجيات مفتوحة المصدر لأنها تعطيهم مزيدًا من السيطرة والتحكم. إذ يمكنهم فحص الشيفرة البرمجية للتأكد من أنها ستؤدي نفس المهمة الّتي يريدونها، بل ويمكنهم حتى تغيير أي جزء منها لا يحبونه. كما يستفيد غير المبرمجين من هذه البرمجيات أيضًا، لأنهم يمكنهم استخدام هذه البرمجية لأي غرض يرغبون فيه - وبذلك لا تُفرض عليهم الطريقة الّتي يعتقد شخص ما -صاحب البرمجية مثلًا- بأنه يجب عليهم استخدام البرمجية وفقًا لها (كما يحدث في البرمجيات المحتكرة). التعلم والتدرب من هذه البرمجيات يحبُ البعض الآخر من الناس هذه البرمجيات لأنها تساعدهم ليصبحوا مبرمجين أفضل. نظرًا لأن الشيفرة البرمجية متاحة للجميع، وبذلك يمكن للطلاب دراستها بسهولة أثناء تعلمهم لإنشاء برمجية أفضل. يمكن للطلاب مشاركة عملهم مع الآخرين أيضًا، ودعوتهم للتعليق والنقد البناء، وبذلك يصقل الطلاب مهاراتهم. عندما يكتشف الأشخاص أخطاءً في الشيفرات البرمجية لبرامجهم، يمكنهم مشاركة هذه الأخطاء مع الآخرين لمساعدتهم على تجنب ارتكاب نفس هذه الأخطاء. الحماية والأمان يُفضل بعض الأشخاص هذه البرمجيات لأنهم يرونها أكثر أمانًا واستقرارًا من البرمجيات المحتكرة. نظرًا من كون الجميع يستطيع عرض وتعديل البرمجيات مفتوحة المصدر، فيمكن لأي شخص أن يكتشف خطأ غفِلَ عنه أصحاب البرمجية أنفسهم بل ويمكن أن يصحح أو يحذف هذا الخطأ. ولأن العديد من المبرمجين يمكنهم العمل على جزء معين من البرمجية بدون طلب إذن من أصحابها، فسيُسرّع ذلك من وتيرة إصلاح البرمجية وتحديثها وترقيتها أكثر من البرمجيات المحتكرة. الاستقرار والثبات يفضل العديد من المستخدمين البرمجيات مفتوحة المصدر على نظيرتها المحتكرة للمشاريع المهمة وطويلة الأمد. نظرًا لتوزيع المبرمجين الشيفرة البرمجية علنًا للبرمجيات مفتوحة المصدر، فيمكن للمستخدمين الّذين يعتمدون على هذه البرمجيات في المهام الحرجة التأكد من أن أدواتهم لن تختفي أو تتعطل إذا توقف أصحابها عن تطويرها -وذلك لأن لديها عدة مبرمجين آخرين مهتمين بها- علاوة عن ذلك، تميل البرمجيات مفتوحة المصدر للاندماج والعمل وفقًا للمعايير المفتوحة. المجتمع الداعم للبرمجية غالبًا ما تستقطب البرمجيات مفتوحة المصدر جمهورًا من المستخدمين والمطورين المحبين لها. وهذا ليس حكرًا على هذه البرمجيات بل العديد من التطبيقات الشعبية لها مجتمعات كبيرة ومواضيع يناقشونها في لقاءاتهم واجتماعاتهم. غير أن في البرمجيات مفتوحة المصدر يكون المجتمع ليس مجرد قاعدة جماهيرية تشتري (سواء عاطفيًا بالدعم أو ماليًا بسعر البرمجية) وتكوّن بذلك مجموعة مميزة من المستخدمين وحسب، وإنما مجموعة من الأشخاص الّذين ينتجون ويختبرون ويستخدمون ويروجون بل ويؤثرون تأثيرًا جوهريًا على البرمجية الّتي يحبونها. هل يعني مصطلح "مفتوح المصدر" بأنه مجاني؟ لا. هذا مفهوم خاطئ ومنتشر حول ما يعنيه مصطلح "مفتوح المصدر"، وممكن ألا يتعلق هذا المصطلح بالمال. يمكن لمبرمجي هذه البرمجيات أن يتقاضوا المال مقابل البرمجيات مفتوحة المصدر الّتي يصنعونها أو يساهمون فيها. ولكن في بعض الحالات، نظرًا لأن ترخيص المصدر المفتوح يتطلب منهم إصدار الشيفرة البرمجية علنًا عندما يبيعون هذه البرمجيات للآخرين، ولذلك يجدُ بعض المبرمجين أن فرض رسوم على المستخدمين مقابل الخدمات والدعم الفني للبرمجية (بدلًا من البرمجية بحد ذاتها) أكثر ربحًا. وبهذا تظل برمجياتهم مجانية، ويكسبون المال من مساعدة الآخرين في تثبيتها واستخدامها واستكشاف أخطائها وإصلاحها. على الرغم من كون بعض البرمجيات مفتوحة المصدر مجانية، إلا أن مهارة البرمجة واستكشاف الأخطاء وإصلاحها في البرمجيات مفتوحة المصدر يمكن أن تكون ذات قيمة كبيرة. يسعى الكثير من أرباب العمل لتوظيف مبرمجين لديهم خبرة سابقة بالعمل على برمجيات مفتوحة المصدر تحديدًا. ما هي الثقافة مفتوحة المصدر "أي أبعد من الشيفرة البرمجية"؟ إن التعامل مع جميع جوانب الحياة بثقافة مفتوحة المصدر يعني التعبير عن الرغبة في المشاركة والتعاون مع الآخرين بشفافية (ليتمكن الآخرين من المشاهدة أو حتى الانضمام أيضًا)، واحتضان الفشل كوسيلة للتطوّر، وتوقع -أو حتى تشجيع- الجميع ليشاركوا وينضموا إلى هذه الثقافة. ويعني الالتزام أيضًا بدور فعّال في تحسين العالم، وهو أمر ممكن في حال تمكن الجميع من الوصول للطريقة الّتي صُمّم بها هذا العالم. إن العالم مليء "بالشيفرات البرمجية" - المخططات والوصفات والقواعد - الّتي توجه طريقة تفكيرنا وتشكلها من أجل أن نتصرف على أساسها. نؤمن تمامًا بأن هذه الشيفرة الضمنية (مهما كان شكلها) يجب أن تكون مفتوحةً وقابلة للوصول والمشاركة من قِبل الجميع — ليتمكنوا من تغييرها للأفضل. ترجمة -وبتصرف- للمقال What is open source software?1 نقطة
-
أداة البناء Grunt أو Gulp، مكتبة require.js، browserify، الإصدار السادس من ES، المفسرات، أطر عمل React و Angular و Amber، التعابير المغلقة (closures)، سلسلة prototype. ارتفاع في ضغط الدم يؤدي إلى سكتة دماغية. حسنًا، تطوير الويب أمرٌ ممتع جدًا، لكن JavaScript مروعة! تجد نفسك منسجمًا تمامًا مع جميع جوانب تطوير الويب، لكن عندما يأتي الأمر إلى JavaScript فستشعر أنَّ جزءًا كبيرًا من المعلومات الأساسية ينقصك بينما يعرفه الآخرون، والذي سيؤدي إلى جعلهم يفهمون سكربتات JavaScript. نعم، الحقيقة هي أنَّك تفتقد بالفعل إلى بعض القطع؛ لكن هذا لا يعني أنَّ التوجه الحالي لتطوير الواجهات الأمامية ليس مجنونًا! اطمئن، فأنت لستَ بمفردك، لذا اسحب كرسيًا واجلس، وجهِّز نفسك لكتابة تطبيق JavaScript. أوّل خطوة هي ضبط بيئة التطوير المحلية، لذا اتخذ قرارك: هل ستستخدم Gulp، أم Grunt، لا! سأستعمل سكربتات NPM. هل أستعمل Webpack أم Browserify أم Require.js؟ هل أتخذ قرارًا مصيريًا بالانتقال إلى الإصدار السادس من ES؟ أليس ضروريًا أن أضع مرجعًا عن أمراض القلب بجواري؟ كيف سأنظِّم اختبار الشيفرات؟ هل من إطارِ عملٍ تنصحني به؟ أليس من الأفضل تشغيل الاختبارات من سطر الأوامر، لنستعمل إذًا PhantomJS؟ مع أي إطارٍ أذهب: Angular أم React؟ ربما Ember؟ ماذا عن Backbone؟ ربما قرأتَ بعض صفحات توثيق React ووجدتَ فيها أنَّ «Redux هو حاويةٌ ذاتُ حالةٍ قابلةٍ للتوقع لتطبيقات JavaScript» وبدت على وجهك أمارات الرضى، فمن المؤكد أنَّك ستحتاج إلى هذه الميزة العظيمة، بغض النظر عن أنَّك لم تفهم حرفًا من شرحها. السؤال الآن هو: لماذا أصبح تطوير تطبيقات JavaScript أمرًا يدفع إلى الجنون؟! دعني أساعدك لفهم سبب ذلك. لنبدأ بمثالٍ بسيطٍ ثم سنستعرض صورًا جميلةً توضِّح وجهة نظري. هذا تطبيق «Hello, World!» مكتوبٌ باستخدام React: // main.js var React = require('react'); var ReactDOM = require('react-dom'); ReactDOM.render( <h1>Hello, world!</h1>, document.getElementById('example') ); لم ننتهِ منه بعد: $ npm install --save react react-dom babelify babel-preset-react $ browserify -t [ babelify --presets [ react ] ] main.js -o bundle.js هنالك عدِّة خطوات ناقصة هنا، مثل تثبيت مكتبة browserify أو ما الذي عليك فعله لتشغيل الصفحة في المتصفح، إذ لا يبدو أنَّ ما سبق سيُنشِئ صفحة ويب قادرة على فعل أيّ شيء! بعد أن تنتهي من إنجاز ما سبق، فستجد ملفًا يدعى bundle.js يحتوي على تطبيق «Hello, World!» السابق المكتوب بمكتبة React والذي يضم حوالي 19374 سطرًا برمجيًا، وكل ما فعلتَه هو تثبيت browserify و babelify و react-dom، التي «تزن» آلاف الأسطر البرمجية. هذه صورة تعبيرية عن برنامج «Hello, World!» في React: حسنًا، هذا تطبيق «Hello, World!» باستخدام JavaScript دون مكتبات: <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width" /> <title>Hello World</title> </head> <body> <div id="container"></div> <script> document.body.onload = function(){ var container = document.getElementById("container"); container.innerHTML = '<h1>"Hello, world!"</h1>'; } </script> </body> </html> هذا كل ما في الأمر! 18 سطر برمجي (يمكن اختصارها إلى أقل من ذلك)، التي تستطيع نسخها ولصقها في ملفٍ باسم index.html وتنقر نقرتين عليه مما يفتحه في متصفحك. يا للبساطة! إذا كنتَ تفكِّر في هذه اللحظة «أليس إطار React يفعل أكثر من ذاك المثال البسيط الذي كتبته، والذي لا يرقى أن يكون تطبيق JavaScript» فأنت مصيبٌ (تقريبًا)، وعلى بعد خطوة واحدة من فهمك لماذا كل هذا التعقيد. انظر إلى هذه الصورة: أغلبية تطبيقات JavaScript التي ستعمل عليها ستقع في مكانٍ ما في منتصف المنحني الجرسي (bell curve) السابق. وإذا كنتَ في منتصف المنحني السابق وبدأت تطبيقًا بالاعتماد على React فسوف ينتهي بك المطاف بهندسة تطبيقك زيادةً عن اللزوم من بدايته. وهذا هو سبب تعقيد تطوير تطبيقات JavaScript، لأنَّ غرض أغلبية الأدوات التي تظن أنَّك بحاجةٍ إليها هو حلّ المشاكل التي لن تتعرض إليها بتاتًا. أصبحت حالة تطوير تطبيقات JavaScript في الآونة الأخيرة معقدةً ومربكةً لأنَّ الجميع يبالغون في هندسة تطبيقاتهم دون أن يدركوا ذلك. إذًا، كيف يجب أن نبدأ بتطوير تطبيق JavaScript؟ هل علينا استخدام مكتبة شبيهة بمكتبة React أو Angular؟ هل يجب أن نستخدم مدير للحزم؟ ماذا يفترض علينا أن نفعل إذا لم نستخدمهما؟ هل كتابة الاختبارات ضرورية؟ هل علينا أصلًا توليد شيفرات HTML عبر JavaScript؟ هذه هي الأسئلة التي يجب أن تسألها لنفسك قبل أن تبدأ بمجموعة ضخمة من أدوات التطوير. عندما تبدأ بتطوير تطبيق JavaScript فمن المهم أن تختار نقطةً في المنحني الجرسي في المكان الذي تظن أنَّ من المرجح أن يصله تطبيقك في المستقبل من ناحية التعقيد. لن أكذب عليك، فعل ذلك ليس سهلًا ويحتاج خبرةً، لكن هنالك منطقةٌ كبيرة يمكنك أن تبدأ منها أغلبية تطبيقات JavaScript: استعمل مكتبة jQuery مع قوالب لصفحات الواجهة الأمامية مع أداة بناء بسيطة لجمع الملفات وتصغيرها (بفرض أنَّ إطار العمل الذي تستعمله لتطوير السند الخلفي [backend] لا يفعل ذلك تلقائيًا). إذا أردتَ أن تتعلم كيفية هيكلة تطبيق JavaScript بطريقةٍ صحيحة، فعليك أن تبدأ بفهم كيف ومتى ولماذا تستخدم إطار عمل أو حزمة npm أو إصدار ES6 أو متى تكتب اختبارات أو هل عليك جعل الاختبارات تعمل محليًا أو في متصفح، ثم سيأتي دور بقية الأسئلة وحلّ بقية المشاكل. إن أردتَ أن تملأ الفجوات الموجودة في معلوماتك حول تطوير JavaScript وأن تتجنّب الشعور بأنّك تبالغ في تصميم تطبيق JavaScript فحاول أن تتابع ما نطرحه هنا في قسم البرمجة في أكاديمية حسوب. ترجمة -وبتصرّف- للمقال Why JavaScript Development is Crazy لصاحبه Sean Fioritto1 نقطة
-
وضع Netscape’s Brendan Eich أسس جافا سكريبت سنة 1995. وكان الغرض منها أن تكون لغة ترميز سهلة خاصة بالمواقع ومكملة للجافا في تطبيقات الويب المعقدة، ولكن سهولة دمج جافا سكريبت والدعم الذاتي لها مع المتصفحات جعلها أكثر شيوعًا من لغة الجافا الأصلية في واجهات الويب. لا يقتصر استخدام جافا سكريبت مقتصرة على المتصفحات، ف Node.js مشروع قائم بذاته ويقدم إمكانية بناء تطبيقات إنترنت قائمة بذاتها. صيغة الشفرة البرمجية الخاصة بجافا سكريبت شبيهة بطريقة كتابة لغة C، فإذا كنت قد تعاملت مع لغة البرمجة C قبل ذلك أو جافا، ستكون الكثير من الأساسيات مألوفة لك. على الرغم من ذلك، وعلى الرغم من سهولة الاسم، إلا أن النموذج الكائني في جافا سكريبت مختلف تماماً عن الموجود في الجافا. سنتناول في هذا المقال المواضيع التالية: التعليقات. الأرقام، النصوص والعمليات. المتغيرات، المصفوفات والكائنات. جمل التحكم والمنطق. الدوال، نطاق الوصول و Closures. المشيّدات Constructors والنماذج الأولية Prototypes التعليقات لكتابة تعليق من سطر واحد نبدأ السطر بعلامتي / كما في السطر التالي: // Single-line comments start with two slashes. لكتابة تعليق من أكثر من سطر، نستخدم /* و */ في إحاطة الأسطر التي نريدها كما في الأسطر التالية: /* Multiline comments start with slash-star، and end with star-slash */ تنتهي الجمل في جافا سكريبت بفاصلة منقوطة، ولكن هذا الأمر غير ضروري، حيث يتم إضافة الفاصلة المنقوطة تلقائيا عند وجود سطر جديد وعدم وجود الفاصلة، وهذا الأمر مستثنى في بعض الحالات: doStuff(); بدون فاصلة: doStuff() سنعتمد في هذا الدرس استخدام الفاصلة المنقوطة. دورة تطوير التطبيقات باستخدام لغة JavaScript تعلم البرمجة بلغة جافا سكريبت انطلاقًا من أبسط المفاهيم وحتى بناء تطبيقات حقيقية. اشترك الآن الأرقام، النصوص والعمليات تحتوي جافا سكريبت على نوع رقمي واحد (64-bit IEEE 754 double). الأرقام من نوع Double (الأعداد الحقيقة) تحتوي على 52 بت من الأساس العشري، بما يكفي لتخزين الأعداد الصحيحة Integers حتى 9✕10¹⁵ بدقة. 3; // = 3 1.5; // = 1.5 بعض العمليات الحسابية الأساسية: 1 + 1; // = 2 0.1 + 0.2; // = 0.30000000000000004 8 - 1; // = 7 10 * 2; // = 20 35 / 5; // = 7 5 / 2; // = 2.5 10 % 2; // = 0 30 % 4; // = 2 18.5 % 7; // = 4.5 العمليات الثنائية متاحة أيضا، فعند إجراءك لعملية ثنائية، فإن الأعداد العشرية Float يتم تحويله إلى أعداد طبيعية Int حتى 32 بت: 1 << 2; // = 4 ترتيب العمليات يتم بواسطة استخدام الأقواس: (1 + 3) * 2; // = 8 توجد ثلاثة قيم أرقام غير حقيقية كالتالي: Infinity; // ناتجة عن قسمة رقم موجب على صفر -Infinity; // ناتجة عن قسمة رقم سالب على صفر NaN; //تشير إلى قيمة "غير رقم" القيم المنطقية: true; false; يتم استخدام علامة التنصيص المنفردة أو المزدوجة لبناء النصوص: 'abc'; "Hello، world"; لعكس القيمة نستخدم علامة التعجب: !true; // = false !false; // = true لفحص المساواة: 1 === 1; // = true 2 === 1; // = false لفحص عدم المساواة: 1 !== 1; // = false 2 !== 1; // = true عمليات المقارنة: 1 < 10; // = true 1 > 10; // = false 2 <= 2; // = true 2 >= 2; // = true دمج النصوص يتم بواسطة عملية + : "Hello " + "world!"; // = "Hello world!" وعملية الدمج + لا تعمل فقط مع النصوص، بل مع الأرقام أيضا والتراكيب مثل المصفوفات: "1، 2، " + 3; // = "1، 2، 3" "Hello " + ["world"، "!"] // = "Hello world،!" من الممكن مقارنة النصوص: "a" < "b"; // = true لإجراء عملية فحص المساواة باعتبار تحويل أنواع البيانات (في حالة اختلافها) نستخدم عملية = مرتين: "5" == 5; // = true null == undefined; // = true في حالة استخدام = ثلاثة مرات، لا تتم عملية التحويل: "5" === 5; // = false null === undefined; // = false لابد من الانتباه من التحويل التلقائي للنوع تجنبا لبعض الحالات غير المرغوبة: 13 + !0; // 14 "13" + !0; // '13true' نستخدم charAt للوصول لمحرف Character معين في النصوص بتعيين مكانها في سلسلة المحارف: "This is a string".charAt(0); // = 'T' أو نستخدم substring للحصول على أجزاء أكبر من النصوص: "Hello world".substring(0, 5); // = "Hello" length تعتبر خاصية، لذلك لا تستخدم الأقواس في النهاية: "Hello".length; // = 5 نستخدم null للإشارة للفارغ أو غير الموجود، بينما نستخدم undefined للإشارة لقيمة غير منشأة أو غير موجودة حاليا (مثل تعريف متغير وعدم إعطائه قيمة). القيم false، null، undefined، NaN، 0 ،”” كلها قيم خاطئة (تستخدم كقيمة منطقية خطأ) والباقي صحيح. المتغيرات، المصفوفات، والكائنات يتم تعريف المتغيرات باستخدام كلمة var. جافا سكريبت ديناميكية النوع، حيث لا يجب عليك تحديد نوع المتغير عند تعريفه، ولإعطاء قيمة للمتغير نستخدم = كما في المثال التالي: var someVar = 5; عند عدم استخدام كلمة var لن يظهر لك خطأ، ولكن في هذه الحالة فإن المتغير يكون مستواه على نطاق الوصول العام Global scope ولن يكون على المستوى الذي تم تعريفه فقط. someOtherVar = 10; المتغيرات التي لا تأخذ قيمة عند تعريفها تكون بقيمة undefined تلقائيا: var someThirdVar; // = undefined لتعريف أكثر من متغير في نفس السطر نفصل بين المتغيرات بفاصلة عادية: var someFourthVar = 2، someFifthVar = 4; نستطيع اختصار كتابة العمليات الحسابية بالشكل التالي: someVar += 5; // هذا يعادل someVar = someVar + 5; someVar is 10 now someVar *= 10; // someVar = 100 someVar++; // someVar = 101 someVar--; // back = 100 المصفوفات عبارة عن قائمة من القيم المرتبة من أي نوع: var myArray = ["Hello"، 45، true]; نستطيع الوصول لمحتويات المصفوفة باستخدام الأقواس المعكوفة والفهرس. فهرس المصفوفات يبدأ من صفر: myArray[1]; // = 45 المصفوفات غير ثابتة وذات حجم متغير: myArray.push("World"); myArray.length; // = 4 للتعديل أو الإضافة في موقع معين في المصفوفة: myArray[3] = "Hello"; لتعريف قاموس (Hash): var myObj = {key1: "Hello"، key2: "World"}; المفاتيح في القاموس عبارة عن نص، أو مُعرف صحيح، والقيم تأخذ أي نوع: var myObj = {myKey: "myValue"، "my other key": 4}; للوصول إلى قيمة باستخدام مفتاح والأقواس المعكوفة: myObj["my other key"]; // = 4 أو باستخدام صيغة النقطة والمُعِرف الذي يمثل المفتاح: myObj.myKey; // = "myValue" الكائنات في جافا سكريبت غير ثابتة وقابلة للتعديل: myObj.myThirdKey = true; إذا حاولت الوصول لقيمة غير موجودة في القاموس، ستكون النتيجة المرجعة undefined: myObj.myFourthKey; // = undefined جمل التحكم والمنطق جملة if: var count = 1; if (count == 3){ // ستُنفَّذ هذه الشفرةإذا كانت قيمة المتغير تساوي 3 } else if (count == 4){ // ستُنفَّذ هذه الشفرةإذا كانت قيمة المتغير تساوي 4 } else { // ستُنفَّذ هذه الشفرة في حالة عدم تحقق أي شرط سابق } جملة while: while (true){ // جملة تكرار غير منتهية } جملة do تشبه جملة while إلا أنها تُكرَّر مرة واحدة على الأقل: var input; do { input = getInput(); } while (!isValid(input)) جملة For تشبه الموجودة في لغة سي وجافا: for (var i = 0; i < 5; i++){ // ستُنفَّذ هذه الشفرة خمس مرات } توقف جملة التكرار باستخدام break مع تحديد اسم جملة التكرار التي نريد وقفها: outer: for (var i = 0; i < 10; i++) { for (var j = 0; j < 10; j++) { if (i == 5 && j ==5) { break outer; } } } تسمح لنا جملة for/in بالمرور على خصائص ومحتويات الكائن. في المثال التالي نقوم بالمرور على محتوى قاموس وحفظ النتيجة في متغير: var description = ""; var person = {fname:"Paul"، lname:"Ken"، age:18}; for (var x in person){ description += person[x] + " "; } // description = 'Paul Ken 18 ' العملية المنطقية and تُمَثَلْ ب && والعملية or تُمَثَلْ ب ||: if (house.size == "big" && house.colour == "blue"){ house.contains = "bear"; } if (colour == "red" || colour == "blue"){ // colour is either red or blue } نستفيد من && و || في تحديد القيم التلقائية كما في المثال التالي: var name = otherName || "default"; جملة switch تفحص المساواة باستخدام ===، استخدم break بعد كل حالة فحص وإلا سيتم تنفيذ حالة case الصحيحة التالية أيضا: grade = 'B'; switch (grade) { case 'A': console.log("Great job"); break; case 'B': console.log("OK job"); break; case 'C': console.log("You can do better"); break; default: console.log("Oy vey"); break; } الدوال، نطاق الوصول وClosures تُعرَّف الدوال في جافا سكريبت باستخدام كلمة function: function myFunction(thing){ return thing.toUpperCase(); } myFunction("foo"); // = "FOO" لابد الانتباه أن تضع القيمة المرجعة في نفس السطر الموجودة به كلمة return، إذا لم يكن كذلك، ستكون النتيجة المرجعة undefined بسبب الإضافة التلقائية للفاصلة المنقوطة عند كل سطر جديد (وقد نوهنا لهذه النقطة في البداية). function myFunction(){ return // الفاصلة المنقوطة مضافة تلقائيا هنا {thisIsAn: 'object literal'} } myFunction(); // = undefined يُتعامل مع الدوال في جافا سكريبت بوصفها كائنات، وهذا يعني أنك تستطيع تمرير الدالة معاملا لدالة أخرى، أو قيمة لمتغير. تُستخدَم الدالة myFunction في معالجة حدث في المثال التالي، حيث سيتم تنفيذها بعد فترة زمنية محددة: function myFunction(){ } // ينتُج عن السطر التالي تنفيذ الدالة أعلاه بعد 5 ثوان setTimeout(myFunction، 5000); ملاحظة: الدالة setTimeout ليست جزءًا من جافا سكريبت، ولكنها مقدمة من قبل المتصفحات و Node.js. وظيفة setInterval أيضا مقدمة من قبل المتصفحات. function myFunction(){ } setInterval(myFunction، 5000); ليس من الشرط تحديد اسم الدالة، ونستطيع كتابة الدالة دون اسم في المكان الذي يتم تمرير قيمتها المُرجعة فيه بالطريقة التالية: setTimeout(function(){ }, 5000); تمتلك جافا سكريبت نطاقاً وظيفياً، حيث لكل دالة نطاقها الخاص، بينما الكتل الأخرى لا تشاركها هذا النطاق. if (true){ var i = 5; } i; // = 5 إن كتبنا الشفرة في المثال السابق داخل دالة فإن قيمة المتغير i تساوي 5 على عكس ما تتوقعه في النطاق الكتلي، بمعنى أن المتغيرات مُشاهدَة ونستطيع الوصول إليها على مستوى الدالة بغض النظر عن مكان تعريفها داخل هذه الدالة. وهذا يشير إلى نمط متعارف عليه يمنع المتغيرات المؤقتة من الظهور في نطاق الوصول العام. وللتوضيح على ما سبق، في المثال التالي، يبقى المتغير temporary داخل نطاق الدالة المُعرف فيها، أما المتغيرات في النطاق العام مثل permanent فنستطيع الوصول إليه باستخدام الكائن العام والمسمى في كل المتصفحات ب window وتكون صيغة الوصول للمتغير هكذا window.permanent. الكائن ذو النطاق العام يختلف اسمه في البيئات التي لا علاقة لها بالمتصفحات مثل Node.js. (function(){ var temporary = 5; window.permanent = 10; })(); temporary; // raises ReferenceError permanent; // = 10 من أقوى خصائص لغة جافا سكريبت وجود ما يسمى بclosures ، حيث إذا كانت دالة مُعرفة داخل دالة أخرى، فإن الدالة الداخلية تمتلك الوصول لكافة المتغيرات الخاصة بالدالة الخارجية حتى بعد خروجها وانتهائها. في المثال التالي، فإن استدعاء الدالة setTimeout سيتم تنفيذها مباشرة بعد استدعاء الدالة الخارجية sayHelloInFiveSeconds والتي ستنتهي مباشرة. ومن ثم سوف يبدأ العد حتى 5 ثوان لاستدعاء الوظيفة الداخلية، وعند انتهاء المدة، وعلى الرغم من خروج وانتهاء الدالة الخارجية، إلا أنه سيتم تنفيذ الداخلية بنجاح وسيتم الوصول للمتغير prompt دون مشاكل. function sayHelloInFiveSeconds(name){ var prompt = "Hello، " + name + "!"; function inner(){ alert(prompt); } setTimeout(inner، 5000); } // سيتم طباعة "مرحبا أدم" بعد 5 ثواني sayHelloInFiveSeconds("Adam"); المشيّدات Constructors والنماذج الأولية Prototypes يمكن للكائنات أن تحتوي على دوال، كما في المثال التالي: var myObj = { myFunc: function(){ return "Hello world!"; } }; myObj.myFunc(); // = "Hello world!" عندما يتم استدعاء دوال معرَّفة في كائن، فإن هذه الدوال تستطيع الوصول للكائن التي عُرِّفت فيه باستخدام كلمة this كما في المثال التالي: myObj = { myString: "Hello world!"، myFunc: function(){ return this.myString; } }; myObj.myFunc(); // = "Hello world!" الدالة myFunc لا تعمل إذا لم يتم استدعاؤها في سياق الكائن الذي تتصل به، لاحظ في المثال التالي: var myFunc = myObj.myFunc; myFunc(); // = undefined نستطيع ربط دالة بكائن والوصول لمتغيرات هذا الكائن بواسطة this على الرغم من أن هذه الدالة لم تُعرَّف مع تعريف بالكائن. var myOtherFunc = function(){ return this.myString.toUpperCase(); } myObj.myOtherFunc = myOtherFunc; myObj.myOtherFunc(); // = "HELLO WORLD!" نستطيع أيضا تحديد سياق الدالة لتنفيذها من خلاله وذلك عن طريق استدعاء الوظيفة باستخدام call او apply. var anotherFunc = function(s){ return this.myString + s; } anotherFunc.call(myObj، " And Hello Moon!"); // = "Hello World! And Hello Moon!" استخدمنا في المثال السابق الدالة call. تؤدّي الدالة apply نفس الغرض ولكننا نمرر لها مصفوفة معاملات، وهذا يفيدنا في حالة التعامل مع دالة تقبل مجموعة من المعاملات. anotherFunc.apply(myObj، [" And Hello Sun!"]); // = "Hello World! And Hello Sun!" Math.min(42، 6، 27); // = 6 Math.min([42، 6، 27]); // = NaN (uh-oh!) Math.min.apply(Math، [42، 6، 27]); // = 6 لاحظ أننا عند استخدام apply و call قمنا بتمرير السياق الذي نريده من خلال myObj. إذا أردنا أن نُثبت السياق الذي نريد تنفيذ الدالة من خلاله، فإننا نستخدم bind عوضا عن ذلك. var boundFunc = anotherFunc.bind(myObj); boundFunc(" And Hello Saturn!"); // = "Hello World! And Hello Saturn!" نستطيع استخدام bind لتطبيق دالة جزئيا، انظر المثال التالي: var product = function(a، b){ return a * b; } var doubler = product.bind(this، 2); doubler(8); // = 16 عند استدعاء دالة بواسطة الكلمة new فإن كائناً جديداً يتم إنشاؤه وسوف يكون متاحا للدالة بواسطة كلمة this. الدوال التي صُممت للاستدعاء بهذه الطريقة تسمى المشيّدات constructors. var MyConstructor = function(){ this.myNumber = 5; } myNewObj = new MyConstructor(); // = {myNumber: 5} myNewObj.myNumber; // = 5 على خلاف لغات البرمجة الكائنية الأخرى، جافا سكريبت لا تحتوي على مفهوم العيّنة Instance أو “الكائن المتولد من الفئة عند التشغيل”. تُقدم جافا سكريبت المفاهيم الكائنية مثل التوليد والوراثة من خلال مفهوم واحد يسمى النموذج الأولي Prototype. كل كائن في الجافا سكريبت يحتوي على نموذج أولي. عندما تقوم بمحاولة استخدام لخاصية غير موجودة في كائن معين، فإن مفسر جافا سكريبت سوف ينظر في النموذج الأولي للكائن. تجعلك بعض تطبيقات الجافا سكريبت تصل لنموذج الكائن بواسطة الخاصية “proto“. على الرغم من أن هذه الطريقة مفيدة في شرح مفهوم النموذج الأولي، إلا أنها ليست الطريقة المعيارية لذلك، وسوف نشرح الطريقة الصحيحة لهذا الأمر لاحقا. var myObj = { myString: "Hello world!" }; var myPrototype = { meaningOfLife: 42، myFunc: function(){ return this.myString.toLowerCase() } }; myObj.__proto__ = myPrototype; myObj.meaningOfLife; // = 42 myObj.myFunc(); // = "hello world!" في حال لم تكن الخاصية موجودة في النموذج الأولي، فإن المفسر يبحث في نموذج النموذج وهكذا. myPrototype.__proto__ = { myBoolean: true }; myObj.myBoolean; // = true لا يوجد نُسَخْ عند استخدام النموذج، حيث إن كل كائن يقوم بالتأشير للنموذج الخاص به، وهذا يعني أن أي تغيير على النموذج سوف ينعكس في كل مكان آخر. myPrototype.meaningOfLife = 43; myObj.meaningOfLife; // = 43 جملة for/in تسمح بالمرور على خصائص كائن، مرورا بسلسلة النماذج الأولية حتى الوصول إلى نموذج فارغ. for (var x in myObj){ console.log(myObj[x]); } ///prints: // Hello world! // 42 // [Function: myFunc] للمرور على خصائص الكائن دون النموذج، نستخدم وظيفة hasOwnProperty كما في المثال التالي: for (var x in myObj){ if (myObj.hasOwnProperty(x)){ console.log(myObj[x]); } } ///prints: // Hello world! كما ذكرنا سابقا، فإن استخدام “proto” في تعريف نموذج كائن هي طريقة غير معيارية، ولا يوجد طريقة لتغيير نموذج أولي لكائن موجود. على الرغم من ذلك، توجد طريقتان لإنشاء كائن مع نموذج مُعطى. الأولى هي استخدام Object.create: var myObj = Object.create(myPrototype); myObj.meaningOfLife; // = 43 الطريقة الثانية – مضمونة أكثر - باستخدام المشيّدات. تمتلك المشيّدات خاصية تسمى prototype تُحدَّد عند إنشاء كائن جدي باستخدام كلمة new، المثال التالي يشرح هذا الأمر: MyConstructor.prototype = { myNumber: 5، getMyNumber: function(){ return this.myNumber; } }; var myNewObj2 = new MyConstructor(); myNewObj2.getMyNumber(); // = 5 myNewObj2.myNumber = 6 myNewObj2.getMyNumber(); // = 6 توجد لدى أنواع البيانات مثل النصوص والأرقام مشيّدات تقوم بإنشاء كائنات تعادل الكائنات المنشأة بطريقة عادية. عدا أنها ليست متماثلة تماما! var myNumber = 12; var myNumberObj = new Number(12); myNumber == myNumberObj; // = true typeof myNumber; // = 'number' typeof myNumberObj; // = 'object' myNumber === myNumberObj; // = false if (0){ //لن تُنفَّذ هذه الشفرة لأن قيمة الصفر خاطئة } if (new Number(0)){ //سوف تُنفَّذ هذه الشفرة لأن الرقم في الشرط عبارة عن كائن وليس نوع رقم، والكائنات دائما ذات قيمة منطقية صحيحة } الكائنات المغلفة أو العادية تتشارك في النموذج الأولي الخاص بنوعها، فمثلا، نستطيع إضافة خاصية على النموذج الخاص بنوع string بهدف الحصول على الحرف الأول من النص، كما في المثال التالي: String.prototype.firstCharacter = function(){ return this.charAt(0); } "abc".firstCharacter(); // = "a" تُستخدَم الخاصية السابقة غالباً في ما يُعرَف بالملْء المتعدّد Polyfilling والتي تُطَبِقْ مميزات أحدث من جافا سكريبت في مجموعة قديمة من نُسخ جافا سكريبت بهدف استخدام هذه المميزات الحديثة في بيئات قديمة مثل المتصفحات المنتهية تاريخا. ملاحظة: تنفيذ Object.create قد يكون غير متاح في بعض التطبيقات، ولكننا نستطيع استخدام الملْء المتعدّد لتعويض هذا الغياب كالتالي: if (Object.create === undefined){ //في حالة كانت موجودة لا تعدل عليها Object.create = function(proto){ // أنشئ مشيّدًا مؤقتا باستخدام النموذج الأولي المناسب var Constructor = function(){}; Constructor.prototype = proto; return new Constructor(); } } ترجمة – بتصرّف – للمقال Learn X in Y minutes Where X=javascript.1 نقطة
-
"الفُرص تفضّل العقل المستعدّ" لويس باستور. أحد أهداف الشركات التي تنضم إلى Techstars ومسرّعات أخرى هو الحصول على التّمويل. تأتي معظم الشركات وهي مركّزة على تسريع مشروعها ومن ثم تأمين رأس المال لتسريع نموّها. وحقيقة الأمر أن معظم الشركات الناشئة بحاجة إلى أن تحصل على تمويل حتى تنمو وتتحول إلى شركاتٍ حقيقيّة. ومن غير المرجّح أن يجني أي منّا المال إن لم تقم شركتك بالنمو، لذلك نحن نرغب أن تحصل الشركات على دعمٍ ماديّ. ولكننا نرى أخطاءً متكررة مع الشركات التي تتسرع في البحث عن استثمار، ينتهي بحرمانها من ذلك التمويل. وهذه 9 أخطاء يجب الحذر منها عند البحث عن تمويل لمشروعك: 1- قلة التحضير حتى تكون جاهزًا للحصول على استثمار يجب أن تمتلك معرفة قويّة بالمشكلة التي تقوم بحلّها: لماذا شرعت بالعمل على هذا المشروع، البيئة التي سيتنافس فيها مشروعك، العملاء، فرص السوق، التنافسية، قنوات التوزيع، التسعير، معدل ما يتم استهلاكه شهريًا، والعديد من الأمور الأخرى. سيوجّه المستثمرون المحتملون لك كمًا هائلًا من الأسئلة، وفي حال لم تكن مستعدًّا بشكل كافٍ سيظهر ذلك، ويُفشل فرصتك. 2- قلة الاجتذاب traction يحصل عددٌ قليل جدًا من الشركات على تمويل دون امتلاكها لعامل الاجتذاب traction. ما لم تكن رائد أعمال مُتسلسل سبق له أن أطلق عدّة شركات ناشئة ناجحة فإن المُستثمرين سيطالبونك ببعض الاجتذاب أو بعدد مُعيّن من المستخدمين. وهذا لا يعني امتلاكك لمنتجٍ مثاليّ مناسب للسوق، بل يعني أنّه هناك مشكلة ما، وحلّك/منتجك قادر على معالجتها. 3- لم تكن تبحث عن استثمار لم تكن تفكر بالحصول على استثمار، ولكنّك التقيت بعض المستثمرين الذين قالوا أنه عليك القيام بذلك، وأيّد ذلك رياديون آخرون من حولك الأمر. فيخطر على بالك بأنك لن تخسر شيئًا وتقرر بأنك ستسعى للحصول على استثمار. ولكنه خطأ كبير. أنت لست مستعدًا، لم تجهّز لذلك، أو تخطط له. لا تقم بالبحث عن استثمار بناءً على طلب غيرك. تحكّم بمصيرك من خلال التحضير، قم بالانتهاء بجميع الخطوات اللازمة ومن ثم اشرع في البحث عن الاستثمار. لن يرفض المستثمرون مقابلتك في حال رفضت عرضهم عندما لم تكن مستعدًا له. 4- ملاحقة الأشخاص غير المناسبين هذا خطأ فادح، فالمستثمرون مختلفون، ويهتمّون بقطاعات مختلفة. كما يكتبون شيكات بأحجام مختلفة أيضًا. ومجرّد كون أحدهم مستثمرًا لا يعني بالضرورة أنه المستثمر المناسب لك. من المهم أن تقوم بإجراء بحث كامل كي تفهم ما يعجب هذا المستثمر، ولماذا أنت خيارٌ مناسبٌ له. كما أن الحصول على تقديمٍ من شخص يعرفك ويعرف المستثمر هو أمر بذات الأهمية. 5- عدم تقديم مشروعك للمستثمرين بطريقةٍ صحيحة يختلف المستثمرون الملائكة (Angels) عن مستثمري رؤوس الأموال الصغيرة (micro VCs) ومستثمري رؤوس المال المُخاطر (VCs) من حيث أهدافهم وأساليبهم، وبالتالي كيفيّة مفاتحتهم وعرض مشروعك أمامهم. قد يرغب المستثمر الملاك باجتماعين ليكتب لك شيكًا بقيمة 25-50 ألف دولار، أما مستثمر رؤوس الأموال الصغيرة الذي يكتب عادة شيكًا بقيمة 100-250 ألف قد تُضطر مقابلته لمدة شهر دون أن تحصل بالضرورة على التمويل، أما شركات استثمار المال المُخاطر VC فيأخذون الوقت الأطول، ويكتبون الشيكات الأكبر، ويفضّلون أن تكون لك دورات استثمارية، ويتسلّمون مناصب في مجالس إدارة الشّركات التي يُموّلونها. إن لم تعرف كيف تفاتح كل فئة من المستثمرين بشكلٍ صحيح، سوف تهدر الوقت ولن تحصل على النتيجة المرغوبة. 6- عدم امتلاكك استراتيجية شاملة حتى لو كنت تعلم أي المُستثمرين ستلاحق ولماذا ستستهدفهم، فأنت ما تزال بحاجة إلى استراتيجية، تقوم بتفصيل عملية الحصول على الاستثمار بشكل كامل، مَن عليك مقابلته أولًا، ومن يجب مقابلته لاحقًا. هل عليك الحصول على بضعة آلاف من الدولارات من المستثمرين الملائكة أولًا؟ أم تتوجه مباشرة إلى مستثمري المال الجرئي VCs؟ من المهم حقًا اتخاذ القرارات الصحيحة حول استراتيجية تمويلك، خصيصًا إذا كانت تجربتك الأولى. فقد يقلل عدم امتلاكك لخطة من فرص حصولك على رأس المال الكافي لنمو مشروعك. 7- مشكلة "أنا شخص مميز" بالتأكيد أنت مميز، وأنا كذلك، ألسنا جميعنا مميزون؟. عندما يذهب أحدهم إلى كازينو للقمار، يجول في باله أن جميع من حوله هم خاسرون، إلا هو، فهو فائز. وهذا أمر محزن، لأنك كريادي أعمال أنت مميز حقًا، جميعنا كذلك، نحن مجموعة من البشر التي تتميّز بالجنون وبالشجاعة. ولكن هذا رهان خاسر عندما يتعلق بالتمويل، ولكي تنجح، عليك الاعتماد على تحضيرك. 8- عدم إدراك أنك في سباق سينتشر الخبر سريعًا عندما تبدأ بالبحث عن استثمار، فالمستثمرون بالنهاية هم أشخاصٌ عاديون ويتحدثون مع بعضهم، ليس لأنهم أشخاص سيئون أو ضدك بالضرورة، ولكن من الطبيعي أن يتبادل العاملون في أي مجال الملاحظات والآراء مع بعضهم البعض، ومستثمرو رؤوس الأموال ليسوا باستثناء. عندما ستبدأ رحلتك للحصول على استثمار فيتوجب عليك القيام بذلك بسرعة، بعد ترتيب المحادثات التي ستجريها. عندما تبدأ عليك إكمال السباق حتى تنتهي أو حتى تتخذ قرارًا بالتوقف لأنك لا تحصل على النتيجة التي تريدها. أدرك أن هذا هو السباق قبل أن تخوضه. 9- نفاد الفرص قد يكون التّشبيه التالي مضحكًا، ولكنه منطقيٌ جدًا. في بداية العملية أنت تمتلك مسدسًا ممتلئًا، وتبدأ بإطلاق الرصاصات والقيام بتلك الأحاديث الرائعة. ولكن عند نقطةٍ ما، وخصيصًا في المجالات الضّيّقة، تجد أنك قد تحدثت مع الجميع، ولم يتبق أحد. فقد قمت بإطلاق كل رصاصاتك، ومسدسك الآن فارغ. الجانب السّيئ هو أنك التقيت كل المستثمرين، دون أن يكتب لك أي منهم شيكًا، ولا تستطيع مقابلتهم مجددًا الشهر القادم. ولكن الجانب المُشرق هو أنك تستطيع الذهاب إليهم مجددًا بعد 6 أشهر، لتريهم تطوّرك، وفي حال نجحت في ذلك ستحصل على شيك هذه المرة. إعادة ملء المسدس يتطلب وقتًا. والرصاصات الوحيدة المسموح بها هنا، هي تلك التي تعبر عن وجود جذب حقيقي لمنتجك. كيف ومتى عليك البحث عن استثمار كيف يمكن الفوز بذلك والحصول على الدعم يتلخّص في أمرين: التحضير، والاجتذاب traction. قم بترتيب كل أمورك، أوراقك، عرضك لمشروعك، استراتيجية الحصول على الاستثمار الخاصة بك، مع من ستتحدث ولماذا، من سيقدمك لمن، إلخ. كن على أهبة الاستعداد. ولكن حتى إن كنت جاهزًا قد لا يكفي في وقتنا الحالي، فنرى أن تمويل الأفكار يقل باستمرار. حيث يرغب المستثمرون برؤية اجتذاب مبكر، كمؤشر على أن فكرتك ليست عظيمة فقط، بل أنك قمت بالتحدث مع عملاء، وببناء منتج قادر على العمل، وتملك نوعًا من الاجتذاب. أي أنه لديك دليل على أنه باستطاعتك القيام بالأمر وأن الفكرة ستنجح. وفي حال وجدت ذلك مخيفًا ومعقدًا، احصل على المساعدة. تحدث إلى زملاء من رياديي الأعمال الذين قاموا بذلك مسبقًا. تقدم إلى شركة Techstars وبإمكاننا مساعدتك بتسريع مشروعك والحصول على التمويل. فكر مطوّلًا بالتمويل، حضّر، كن رصينًا، ثم فز. ترجمة -وبتصرّف- للمقال 9 Seed Funding Gotchas لصاحبه Alex Iskold1 نقطة
-
مقدّمة نظرية كائن جافاسكريبت هو كيان لديه خاصيّات. كلّ خاصيّة عبارة عن زوج مفتاح وقيمة. المفتاح هو اسم الخاصيّة. يمكن أن تكون قيمة الخاصيّة بيانات (عددا، سلسلة محارف، …إلخ.) أو دالة. يُطلَق على الخاصيّة عندما تكون قيمتها دالة الاسم تابع Method. يُنشَأ كائن حرفي Object literal في جافاسكريبت بتحديد خاصيّاته ضمن زوج من الأقواس المعكوفة. const myObject = { property1: value1, property2: value2, // ... , method1(/* ... */) { // ... }, method2(/* ... */) { // ... } // ... }; myObject.property1 = newValue; // يعيّن القيمة الجديدة للخاصيّة property1 في الكائن myObject console.log(myObject.property1); // يعرض قيمة الخاصيّة property1 في الكائن myObject myObject.method1(...); // استدعاء التابع method1 في myObject تمثّل الكلمة المفتاحية this في تابع الكائن الذي يُستدعَى فيه التابع. تعرّف لغة البرمجة سلفا كائنات عدّة للاستفادة منها مثل console و Math. مقدّمة ما هو الكائن؟ انظر إلى الكائنات في معناها غير البرمجي، مثل قلم. يمكن أن يكون للقلم ألوان عدّة، يصنعه أشخاص متعدّدون، أطراف متنوّعة وخاصيّات أخرى كثيرة. على نحو مشابه، الكائن في البرمجة هو كيان لديه خاصيّات. تعرّف كل خاصيّة ميزة في الكائن. يمكن أن تكون الخاصيّة بيانات مرتبطة بالكائن (لون القلم) أو إجراء (قدرة القلم على الكتابة). ما علاقة هذا بالشفرة؟ البرمجة كائنية التوجّه Object-oriented programming (أو OOP اختصارا) هي طريقة لكتابة البرامج باستخدام الكائنات. يكتُب المبرمج - عند اتّباع هذه الطريقة - الكائنات، ينشئها ويعدّل عليها؛ تشكلّ الكائنات البرنامج. ** تغيّر البرمجة كائنية التوجّه الطريقة التي تُكتَب وتُنظَّم بها البرامج. كتبنا في الفصول السابقة برامج تعتمد على الدوالّ، وهي طريقة برمجيّة تُسمَّى البرمجة الإجرائية Procedural programming. فلنكتشف الآن كيف نكتب شفرة كائنية التوجّه. جافاسكريبت والكائنات تدعم جافاسكريبت، مثل لغات برمجة أخرى، البرمجة بالكائنات. كما توفّر كائنات معرَّفة مسبقا مع إتاحة الفرصة لإنشاء كائنات جديدة. إنشاء كائن في ما يلي تمثيل جافاسكريبت لقلم حبر جاف أزرق اللون علامته التجارية Bic. const pen = { type: "حبر جاف", color: "أزرق", brand: "Bic" }; يمكن إنشاء كائنات جافاسكريبت، كما ذكرنا سابقا، بسهولة بتعيين خاصيّات الكائن ضمن زوج أقواس معكوفة {...}. كلّ خاصيّة هي زوج من المفاتيح والقيم. يُسمَّى الكائن المعرَّف سابقا بالكائن الحَرْفي Object literal. ملحوظة: النقطة الفاصلة ; بعد زوج الأقواس اختيارية، إلا أنه من الآمن إضافتها على كلّ حال. تعرِّف الشفرةُ أعلاه متغيّرا يُسمَّى pen قيمته كائن، يمكننا القول إذن إن pen كائن. لهذا الكائن ثلاث خاصيّات هي: type (النوع)، color (اللون) وbrand (العلامة التجارية). لكلّ خاصيّة اسمٌ وقيمة، كما أنها متبوعة بفاصلة لاتينية , (ما عدا الخاصيّة الأخيرة) الوصول إلى خاصيّات الكائن يمكن الوصول إلى قيم الخاصيّات بعد إنشاء الكائن بالتنويت النقطي Dot notation مثل myObject.myProperty. const pen = { type: "حبر جاف", color: "أزرق", brand: "Bic" }; console.log(pen.type); // "حبر جاف" console.log(pen.color); // "أزرق" console.log(pen.brand); // "Bic" الوصول إلى خاصيّة كائن هو عبارة Expression تنتج قيمة. يمكن تضمين هذه العبارة في عبارات أكثر تعقيدا. يوضّح المثال التالي كيفية عرض خاصيّات القلم السابق في تعليمة واحدة: const pen = { type: "حبر جاف", color: "أزرق", brand: "Bic" }; console.log(`أكتب بقلم ${pen.type} لونه ${pen.color} وعلامته التجارية ${pen.brand}`); التعديل على كائن يمكن تعديل قيم الخاصيّات في كائن بعد إنشائه بالصيغة myObject.myProperty = newValue. const pen = { type: "حبر جاف", color: "أزرق", brand: "Bic" }; pen.color = "أحمر"; // تغيير لون القلم console.log(`أكتب بقلم ${pen.type} لونه ${pen.color} وعلامته التجارية ${pen.brand}`); توفّر جافاسكريبت إمكانية الإضافة الديناميكية لخاصيّات جديدة لكائن أنشأته قبْلا: const pen = { type: "حبر جاف", color: "أزرق", brand: "Bic" }; pen.price = "2.5"; // تعيين خاصية لسعر القلم console.log(`يبلغ سعر قلمي ${pen.price}`); البرمجة بالكائنات تعلّم الكثير من الكتب والدورات البرمجة كائنية التوجّه عبر أمثلة عن الحيوانات، السيّارات أو الحسابات المصرفية. فلنجرّب أمرا ألطف ولننشئ لعبة تقمّص أدوار Role playing game مصغَّرة باستخدام الكائنات. تُعرَّف كلّ شخصية في ألعاب تقمّص اﻷدوار بصفات مميَّزة عدّة مثل القوّة، القدرة على التحمّل والذكاء. في ما يلي لقطة شاشة للعبة تقمّص أدوار شهيرة على الإنترنت. سيكون للشخصيّات - في مثالنا الأبسط كثيرا - ثلاثُ صفات مميّزة: الاسم Name، الصّحة Health (عدد نقاط الحياة)، القوة Strength. مثال ساذج فلنقدّم أورورا، الشخصيّة الأولى في لعبتنا لتقمّص الأدوار: const aurora = { name: "أورورا", health: 150, strength: 25 }; للكائن aurora ثلاث خاصيّات: health، name وstrength. ملاحظة: يمكن - كما ترى في المثال أعلاه - إسناد أعداد، سلاسل محارف وحتى كائنات أخرى إلى خاصيّات الكائنات. تستعدّ أورورا للبدء في سلسلة من المغامرات العظيمة التي ستحدّث بعض منها خاصيّات الشخصيّة. تأمل المثال التالي: const aurora = { name: "أورورا", health: 150, strength: 25 }; console.log(`يوجد لدى ${aurora.name} نقاط قوة قدرها ${aurora.health} وقوة تبلغ ${aurora.strength}`); // أصاب سهم أورورا وبالتالي تقل نقاط الحياة aurora.health -= 20; // تتجهّز أورورا بقلادة قوة aurora.strength += 10; console.log(`يوجد لدى ${aurora.name} نقاط قوة قدرها ${aurora.health} وقوة تبلغ ${aurora.strength}`); التعريف بالتوابع احتجنا في الأمثلة السابقة إلى كتابة تعليمات console.log طويلة في كلّ مرة نريد عرض حالة الشخصية. توجد طريقة أنسب للوصول إلى هذا الغرض. إضافة تابع لكائن تأمل المثال التالي: const aurora = { name: "أورورا", health: 150, strength: 25 }; // ترجع وصف الشخصية function describe(character) { return `يوجد لدى ${character.name} نقاط صحة قدرها ${character.health} وقوة تبلغ ${character.strength}`; } console.log(describe(aurora)); معامل الدالة describe() هو كائن. تصل الدالة إلى خاصيّات الكائن وتنشئ سلسلة المحارف التي تصف الشخصية. أدناه مقاربة بديلة تستخدم الدالة describe() داخل الكائن. const aurora = { name: "أورورا", health: 150, strength: 25, // ترجع وصف الشخصية function describe(character) { return `يوجد لدى ${character.name} نقاط صحة قدرها ${character.health} وقوة تبلغ ${character.strength}`; } }; console.log(aurora.describe()); يتوفّر الكائن الآن على خاصيّة جديدة: describe(). قيمة هذه الخاصيّة دالة تُرجِع وصفا نصيًّا للكائن. نتيجة التنفيذ مطابقة تماما لما سبق. تُسمّى خاصيّة كائن عندما تكون قيمتها دالة بالتابع. تُستخدَم التوابع لتعريف إجراءات على كائن. يضيف التابع سلوكا إلى الكائن. استدعاء تابع في كائن فلنتأمل السطر الأخير من المثال السابق: console.log(aurora.describe()); نستخدم العبارة aurora.describe() لعرض وصف الشخصية بدلا من describe(aurora)، وهنا فرق جوهري. تستدعي العبارة describe(aurora) الدالة describe() مع تمرير الكائن aurora في المعطيات. الدالة خارجة عن الكائن. هذا مثال على البرمجة الإجرائية. تستدعي العبارة aurora.describe() الدالة describe() في الكائن aurora. الدالة خاصيّة من خاصيّات الكائن: تابع. هذا مثال على البرمجة كائنية التوجه. صيغة استدعاء التابع myMethod() في myObject هي myObject.myMethod(). تنبيه: تذكّر الأقواس، حتى وإن كانت خاوية، عند استدعاء تابع. الكلمة المفتاحية this تأمل جيّدا متن التابع describe() في المثال التالي: const aurora = { name: "أورورا", health: 150, strength: 25, // ترجع وصف الشخصية describe() { return `يوجد لدى ${this.name} نقاط صحة قدرها ${this.health} وقوة تبلغ ${this.strength}`; } }; سترى كلمة مفتاحية جديدة: this. تُعيَّن هذه الكلمة المفتاحية تلقائيا داخل تابع في جافاسكريبت وتمثّل الكائن الذي استُدعِي فيه التابع. لا يستقبل التابع describe() أي معاملات. يستخدم التابع this للوصول إلى خاصيّات الكائن الذي استُدعِي فيه. الكائنات المعرَّفة مسبقا في جافاسكريبت تتوفّر جافاسكريبت على كائنات عدّة معرَّفة مسبقا تخدم أغراضا متفرّقة. رأينا في ما مضى بعضا منها: يمنح الكائن console الوصول إلى بيئة الطرفية. التعليمة console.log() هي في الواقع استدعاء لتابع. يحوي الكائن Math خاصيّات رياضية كثيرة. على سبيل المثال، تُرجع الخاصيّة Math.PI قيمة تقريبية للعدد π، ويرجع التابع Math.random() عددا عشوائيا بين 0 و1. حان وقت كتابة الشفرة! إضافة تجربة الشخصية حسّن برنامج لعبة تقمّص الأدوار بإضافة خاصيّة التجربة؛ على أن يكون اسمها xp وقيمتها الابتدائية 0. يجب أن تظهر التجربة ضمن وصف الشخصية. // للإنجاز: إنشاء الكائن character هنا. // أصاب سهم أورورا وبالتالي تقل نقاط الحياة aurora.health -= 20; // تتجهّز أورورا بقلادة قوة aurora.strength += 10; // تعلّمت أورورا مهارة جديدة aurora.xp += 15; console.log(aurora.describe()); نمذجة Modeling كلب أكمل البرنامج التالي لإضافة تعريف بالكائن dog (كلب). // للإنجاز: أنشئ الكائن dog هنا console.log(`${dog.name} كلب نوعه ${dog.species} يبلغ طوله ${dog.size}`); console.log(`انظر هرّة! ${dog.name} ينبح: ${dog.bark()}`); نمذجة دائرة أكمل البرنامج التالي لإضافة تعريف الكائن circle (دائرة). يُدخل الزائر قيمة شعاع الدائرة const r = Number(prompt("أدخل قيمة شعاع الدائرة:")); // للإنجاز: أنشئ تعريف الدائرة هنا console.log(`يبلغ محيط الدائرة ${circle.circumference()}`); console.log(`تبلغ مساحة الدائرة ${circle.area()}`); نمذجة حساب مصرفي أنشئ برنامجا ينشئ كائن account يمثّل حسابا مصرفيا لديه الميزات التالية: خاصيّة name قيمتها “أحمد”. خاصيّة balance قيمتها 0. تابع credit تضيف القيمة (سالبة أو موجبة) المُمرَّرة في المعطى إلى رصيد الحساب balance. تابع describe يُرجع وصف الحساب. استخدم هذا الكائن لعرض وصف حساب مصرفي، أضف 250 إلى رصيده، اسحب منه 80 ثم اعرض وصفه مرة أخرى. تحصُل على الآتي عند عرض وصف البرنامج في المرة الأولى: “المالك: أحمد، الرصيد: 0” وعلى ما يلي في المرة الثانية: “المالك: أحمد، الرصيد: 170” ترجمة - بتصرّف - للفصل Create your first objects من كتاب The JS Way.1 نقطة
-
ما هي JSON؟ كلمة JSON و تلفظ جيسون هي اختصار ل JavaScript Object Notation. سميت بهذا الاسم لأن لغة جافا سكربت(javascript) كانت أول لغة تستفيد من هذه الصيغة. JSON هي طريقة لتخزين المصفوفات (arrays) و الكائنات (objects) بقيم نصية (string)، و تستخدم بشكل أساسي في نقل البيانات وأقل عرضة للخطر و أسهل من طرق أخرى كطريقة xml. تستخدم عادةً عندما يطلب جزء من تطبيق الويب بعض المعلومات من الخادم (server) من دون إعادة تحميل الصفحة. عادة تتم هذه العملية عن طريق جافا سكربت وطلبات AJAX. منذ النسخة 5.2.0، لغة PHP أصبحت قادرة على تحويل الكائنات والمصفوفات إلى JSON. وقد كانت إضافة رائعة لهذه اللغة. إذا كنت تعمل مع PHP لفترة من الزمن ففي الغالب أنك قمت باستعمال دالة ()serialize لعرض كائنات PHP كنصوص، و تستخدم لتحويل كائنات PHP إلى نصوص، و يمكنك فيما بعد استخدام دالة ()unserialize لتحويل هذا النص إلى الحالة السابقة بالقيم الأصلية. وليس فقط لغة PHP التي يمكن أن تتعامل مع JSON بل معظم لغات البرمجة يمكنها التعامل مع JSON وتحويل بياناتها إلى JSON. صيغة JSON {"name":"Lushui","species":"Panda","diet":"Green Things","age":7,"colours":["red","brown","white"]} افتراضيًا يتم تخزين JSON بلا أي فراغات (white space) مما يجعل قراءة JSON صعبة قليلًا، من أجل توفير الذاكرة عند نقل البيانات، لكن يمكنك أن تضع مهما كان من فراغات أو أسطر لجعلها مقروءة بالنسبة لك. لكن هل من المعقول أن نقوم بوضع فراغات في هذ الملف يدويًا إذا كان لدينا العديد من الأسطر، هناك العديد من الأدوات التي تتوفر على الإنترنت التي تقوم بتجميل ملف JSON ليصبح أكثر قابلية للقراءة. لنقم بإضافة بعض الفراغات: { "name": "Lushui", "species": "Panda", "diet": "Green Things", "age": 7, "colours": ["red", "brown", "white"] } كما ترى في هذا المثال أنه لدينا عدد من المفاتيح والقيم. كل مفتاح يجب أن تكون له قيمة مقابلة، إذا كنت قد تعاملت مع جافا سكربت من قبل فسوف ترى أن JSON لا تختلف كثيرًا عن جافا سكربت. var lushui = { name: 'Lushui', species: 'Panda', diet: 'Green Things', age: 7, colours: ['red', 'brown', 'white'] }; في جافا سكربت يتم تعيين هذا الكائن لمتغير كالتالي: var lushui = { .. }; لكن JSON هي صيغة لنقل البيانات، وليست لغة برمجة، لا تملك أي مفاهيم برمجية لذلك لا نحتاج إلى المتغيرات أو ما شابه في JSON. في جافا سكربت وفي JSON الكائنات يتم احتوائها داخل { } وكل مفتاح له قيمة، في جافا سكربت المفاتيح لا تتطلب وضعها بين إشارتي " " لأنها تمثل متغيرات. في جافا سكربت و JSON المفتاح و قيمته يفصل بينهما بـ ":" و كل مفتاح و قيمته مفصولان عن المفاتيح و القيم الآخرى بـ "," . JSON تدعم أنواع القيم التالية: Double Float String Boolean Array Object Null القيم العددية تمثل بلا إشارتي " " ، القيم المنطقية تمثل بـ true أو false و بلا إشارتي " " كما PHP ، و يجب التشديد مرة أخرى أن النصوص تمثل بإشارتي " " . القيمة null تعمل كعملها في php وتمثل في JSON بوضع الكلمة فقط غير محاطة بأي شيء. المصفوفات في JSON وجافا سكربت هي نفسها. // JavaScript ['red', 'brown', 'white'] ["red", "brown", "white"] لاحظ أنني لم أضع تعليق قبل المصفوفة الثانية، لأن JSON لا تدعم التعليق بسبب أنها تستخدم لنقل البيانات وليس هناك حاجة للتعليق لأنك لا تكتب أوامر برمجية لأنك لو عدت لملف JSON لاحقًا فكل ما فيه بيانات سوف تعرفها عند قراءتها مباشرةً. JSON تدعم المصفوفات و الكائنات المتداخلة. { "an_object": { "an_array_of_objects": [ { "The": "secret" }, { "is": "that" }, { "I": "still" }, { "love": "shoes!" } ] } } لدينا في المثال السابق كائن JSON يحتوي كائن آخر يحتوي مصفوفة من الكائنات. JSON و PHP كما ذكرت سابقًا، منذ النسخة 5.2.0 وفرت الدعم لتحويل البيانات إلى JSON والآن سوف نلقي نظرة على هذه الميزة في PHP عن قرب. لتحويل قيمة في PHP إلى JSON فقط نحتاج إلى دالة ()json_encode كما التالي: <?php $truth = array('panda' => 'Awesome!'); echo json_encode($truth); نتيجة تنفيذ التعليمات السابقة. {"panda":"Awesome!"} رائع هذا بالضبط ما كما نريده، لنقم الآن بتحويل هذه البيانات إلى مرة آخرى إلى صيغة مفهومة من قبل PHP. <?php $truth = json_decode('{"panda":"Awesome!"}'); echo $truth['panda']; لنلقي نظرة على النتيجة؟ Fatal error: Cannot use object of type stdClass as array in ... كما ترى، دالة ()json_decode لا تتحول إلى مصفوفة PHP. بدلًا من ذلك تستخدم كائن stdClass لتمثيل بياناتنا، لنصل إلى بياناتنا بشكل صحيح سندخل إلى خصائص هذا الكائن بهذه الطريقة. <?php $truth = json_decode('{"panda":"Awesome!"}'); echo $truth->panda; // Awesome! لكن إذا ما زلت ترغب في الحصول على هذه البيانات كمصفوفة فقط أضف وسيط آخر إلى هذه الدالة وهو true. <?php $truth = json_decode('{"panda":"Awesome!"}', true); echo $truth['panda']; // Awesome! ترجمة –وبتصرّف- للمقال Laravel 4 Primer: JSON لصاحبه Dayle Rees1 نقطة
-
بما أنّ JSON مشتقة من لغة JavaScript البرمجية، فمن الطبيعي إذًا أن تُستخدم كتنسيق للبيانات في هذه اللغة. JSON هي اختصار لـ JavaScript Object Notation (تنويت كائنات JavaScript) وتلفظ غالبًا كما يلفظ اسم (Jason). يمكن استخدام JSON في: تخزين البيانات. إنشاء بنى المعلومات من خلال المعلومات التي يدخلها المستخدم. نقل البيانات من الخادوم إلى العميل، ومن العميل إلى الخادوم، ومن العميل إلى العميل. ترتيب البيانات والتحقق منها. يمثّل هذا المقال مقدّمة للعمل على JSON من خلال لغة JavaScript، ويجب أن تكون مطّلعًا على هذه اللغة لتحصل على الفائدة المرجوة من المقال. صيغة JSON صيغة JSON مشتقة من صيغة الكائنات في JavaScript، ولكنّها صيغة نصّية بالكامل، وهي عبارة عن أزواج من المفاتيح والقيم التي تحاط عادة بأقواس معقوفة. عادة ما تخزّن كائنات JSON في ملف بامتداد .json ولكن يمكن أن تجد هذه الكائنات ضمن سياق البرنامج. تكون ملفات .json بالصيغة التالية: { "first_name" : "Sammy", "last_name" : "Shark", "online" : true } إما إن كانت كائنات JSON موجودة في ملف بامتداد .js أو .html فستكون على اﻷغلب مسندة إلى متغير وبالصورة التالية: var sammy = { "first_name" : "Sammy", "last_name" : "Shark", "online" : true } إضافة إلى ذلك، يمكن أن ترى JSON على هيئة سلسلة نصية لا عنصر وذلك ضمن شيفرة JavaScript، ويمكن كتابة الصيغة في سطر واحد كما يلي: var sammy = '{"first_name" : "Sammy", "last_name" : "Shark", "location" : "Ocean"}'; تحويل كائنات JSON إلى سلاسل نصّية مفيد في نقل البيانات بصورة سريعة. مقارنة JSON مع كائنات JavaScript من المهمّ جدًّا الانتباه إلى أنّ JSON قد طُوّرت لكي تستخدم من قبل أي لغة برمجية، في حين أن التعامل مع كائنات JavaScript يكون بواسطة هذه اللغة حصرًا. أما بالنسبة إلى الصياغة، فإن كائنات JavaScript مشابهة لـ JSON، ولكن الفرق هو أنّ المفاتيح في كائنات JavaScript ليست سلاسل نصّية ضمن علامات اقتباس، إضافة إلى أنّه يمكن استخدام الدوال كقيم في هذه الكائنات. لنأخذ المثال التالي لكائن JavaScript الخاص بالمستخدم Sammy Shark والمتّصل حاليًا بالإنترنت: var user = { first_name: "Sammy", last_name : "Shark", online : true, full_name : function() { return this.first_name + " " + this.last_name; } }; من الواضح جدًّا أن هذا الكائن مشابه جدًّا لكائن JSON، ولكن لا وجود لعلامات الاقتباس حول أيٍّ من المفاتيح (first_name, last_name, online, أو full_name)، إضافة إلى أنّ قيمة المفتاح الأخير عبارة عن دالّة. يمكن استخدام التنويت النقطي للوصول إلى البيانات الموجودة في كائن JavaScript السابق، فلاستدعاء قيمة الاسم الأول نستخدم الصيغة: user.first_name وسنحصل على سلسلة نصّية، أما لو أردنا الوصول إلى الاسم الكامل، ونظرًا لكون القيمة دالّة، فستكون صيغة الاستدعاء بالصورة التالية: user.full_name(). كائنات JavaScript موجودة فقط ضمن هذه اللغة، لذا إن كنت بحاجة للوصول إلى البيانات عن طريق لغات برمجية أخرى، فعليك حينئذ استخدام JSON لتخزين البيانات. الوصول إلى بيانات JSON يمكن الوصول إلى بيانات JSON بنفس الطريقة المتّبعة في كائنات JavaScript، ولتوضيح ذلك لاحظ المثال التالي: var sammy = { "first_name" : "Sammy", "last_name" : "Shark", "online" : true } لتتمكن من الوصول إلى أيّ من القيم السابقة يمكن استخدام التنويت النقطي بالصورة التالية: sammy.first_name sammy.last_name sammy.online يأتي اسم المتغير sammy في البداية متبوعًا بنقطة متبوعة بالمفتاح الذي ترغب في الوصول إليه. فمثلًا، لإطلاق مربع تنبيه يعرض القيمة المرتبطة بالمفتاح first_name يمكن استدعاء دالّة alert() في JavaScript بالشكل التالي: alert(sammy.first_name); Output Sammy كذلك يمكن استخدام الأقواس المربعة [] للوصول إلى البيانات في JSON، وذلك بكتابة اسم المفتاح ضمن علامتي اقتباس محاطًا بقوسين مربعين. فيصبح المثال السابق بالشكل التالي: alert(sammy["online"]); Output true وفي حال استخدام المصفوفات المتشعبة Nested Arrays يجب حينئذ استدعاء رقم العنصر ضمن المصفوفة. لنأخذ المثال التالي: var user_profile = { "username" : "SammyShark", "social_media" : [ { "description" : "twitter", "link" : "https://twitter.com/digitalocean" }, { "description" : "facebook", "link" : "https://www.facebook.com/DigitalOceanCloudHosting" }, { "description" : "github", "link" : "https://github.com/digitalocean" } ] } لتتمكن من الوصول إلى السلسلة النصية facebook يجب عليك استدعاء العنصر ضمن المصفوفة مع استخدام النقطة وبالصورة التالية: alert(user_profile.social_media[1].description); Output facebook لاحظ أنّنا نستخدم نقطة إضافية للوصول إلى العنصر المتشعّب ضمن المصفوفة. بعض الدوال التي تساعد في التعامل مع JSON سنستعرض دالّتين مهمّتين في التعامل مع بيانات JSON، الأولى تعمل على تحويل البيانات إلى سلاسل نصية والأخرى تقوم بتحليلها. إن إمكانية تحويل JSON من كائن إلى سلسلة نصّية مفيد جدًّا في تحويل البيانات وتخزينها. JSON.stringify() تحوّل هذه الدالة الكائن إلى سلسلة JSON نصية. يمكن الاستفادة من السلاسل النصّية لتحويل البيانات من العميل إلى الخادوم وذلك من خلال خزن المعلومات أو تمريرها بصورة سهلة وسريعة. فعلى سبيل المثال، يمكنك مثلًا الحصول على الإعدادات الخاصّة بالمستخدم من طرف العميل ثم إرسالها إلى الخادوم، وفي وقت لاحق يمكنك قراءة تلك المعلومات وتحليلها بواسطة دالّة JSON.parse() واستخدام البيانات حسب الحاجة. في المثال التالي نسند كائن JSON إلى المتغير obj، ثم نحوّله إلى سلسلة نصية من خلال تمريره إلى الدالة JSON.stringify() وإسناد القيمة إلى المتغيّر s: var obj = {"first_name" : "Sammy", "last_name" : "Shark", "location" : "Ocean"} var s = JSON.stringify(obj) والآن يمكن التعامل مع المتغيّر s والذي يضمّ معلومات JSON على هيئة سلسلة نصّية. '{"first_name" : "Sammy", "last_name" : "Shark", "location" : "Ocean"}' JSON.parse() قلنا أنّ السلاسل النصية مفيدة في نقل المعلومات، ولكن يجب أن تتوفّر إمكانية تحويل هذه السلاسل مرّة أخرى إلى كائنات JSON سواء من طرف العميل أو الخادوم. يمكن تحويل السلال النصّية إلى كائنات باستخدام الدالة eval() ولكن هذه الطريقة غير آمنة، لذا سنستخدم الدالة JSON.parse() بدلًا عنها. لتحويل السلسلة النصّية في المثال السابق إلى كائن JSON نقوم بتمرير المتغيّر s إلى الدالّة وإسناد القيمة المستحصلة إلى متغيّر جديد: var o = JSON.parse(s) أصبح لدينا الآن الكائن o وهو مطابق تمامًا للعنصر obj. لتوضيح الفكرة بشكل أكبر سنأخذ المثال التالي والذي نستخدم فيه دالة JSON.parse() في ملف HMTL. <p id="user">Name: Sammy Shark<br>Location: Ocean</p> <script> var s = '{"first_name" : "Sammy", "last_name" : "Shark", "location" : "Ocean"}'; var obj = JSON.parse(s); document.getElementById("user").innerHTML = "Name: " + obj.first_name + " " + obj.last_name + "<br>" + "Location: " + obj.location; </script> Output Name: Sammy Shark Location: Ocean لاحظ كيف حوّلنا السلسلة النصّية s إلى كائن JSON يمكن استدعاء القيم التي يتضمّنها وتصييرها على صفحة الإنترنت. الخلاصة JSON هي الصيغة الافتراضية التي تستخدم في JavaScript ويمكن تضمين هذه الصيغة في العديد من اللغات البرمجية الشائعة. ويمكنك الاطلاع على اللغات التي تدعم هذه الصيغة من خلال الموقع الإلكتروني الخاص بهذه الصيغة. ونظرًا لصغر حجم JSON وسهولة نقل المعلومات بين لغات البرمجة والأنظمة المختلفة، تستخدم هذه الصيغة بصورة واسعة في الواجهات البرمجية APIs، مثل واجهة Twitter البرمجية. تجدر الإشارة إلى أنّك لن تنشئ ملفات .json بنفسك على الأغلب بل ستحصل عليها من مصادر أخرى، مثل ملفات CSV التي تستخدم لتخزين البيانات المجدولة، أو ملفات XML أو غيرها. وسواء أكتبت JSON بنفسك أو حصلت عليها من مصدر آخر، يمكن التأكد من صحّة الصيغة التي كتبتها باستخدام الأداة JSONLint. ترجمة - وبتصرّف - للمقال How To Work with JSON in JavaScript لصاحبته Lisa Tagliaferri.1 نقطة
-
يشيع استخدام صيغة Comma-separated values) CSV؛ قيم معزولة بفاصلة) لتخزين بيانات مُجدوَلة مثل تلك المصدَّرة من قاعدة بيانات أو ورقة حسابات. تمكن قراءة المستندات باستخدام واجهة FileReader البرمجية HTML، دون الحاجة للتخاطب مع أي خادوم Server أو سند خلفي Backend. سنرى في هذا الدّرس كيفيّة قراءة ملفات CSV في صفحة وِب باستخدام JavaScript وذلك بالاعتماد على محلّل Parser يتخاطب مع واجهة FileReader، هذا المحلّل هو Papa Parse. يتطلّب هذا الدرس معرفة جيّدة بجافاسكريبت ومكتبة jQuery. لماذا نستخدم Papa Parse يدعم محلّل Papa Parse المتصفحات الحديثة وبه الكثير من الميزات: مفتوح المصدر، مجاني وتُضاف إليه ميزات جديدة باستمرار؛ سريع، يمكنه تحليل ملايين البيانات ويدعم التشعّب التعدّدي Multi-threading؛ لا يعتمد على مكتبات خارجية؛ يدعم ترميزات Encoding مختلفة؛ يمكنه تخطّي التعليقات يتجنّب انهيار المتصفّح باستخدام التدفقات Streams للحصول على البيانات الخام. نهدف في هذا الدرس إلى قراءة البيانات من ملفّ CSV يحمّله الزائر عن طريق المتصفّح، نحلّل هذه البيانات ثم نعرضها في جدول HTML. يمكنك بعد ذلك استخدام التخزين المحلّي Local storage لديمومة البيانات أو إرسالها إلى خادوم لتخزينها في قاعدة بيانات. توجد الشفرة الكاملة لهذا الدرس في الملف المرفق. سنشرح في الفقرات الموالية أهم الخطوات. تهيئة استمارة HTML الخطوة الأولى هي كتابة شفرة HTML المسؤولة عن الاستمارة Form التي سيُحمّل المستخدم عن طريقها ملف CSV. <form class="form-inline"> <div class="form-group"> <label for="files">Upload a CSV formatted file:</label> <input type="file" id="files" class="form-control" accept=".csv" required /> </div> <div class="form-group"> <button type="submit" id="submit" class="btn btn-primary">Submit</button> </div> </form> جعلنا حقل الإدخال Input مطلوبًا كما يظهر في الشفرة أعلاه required، كما أنه لا يقبل سوى الملفات بصيغة CSV: accept=".csv" استقبال البيانات وتحليلها يُحدَّد ملف CSV في حقل الإدخال عندما ينقر المستخدم على الزّر “إرسال”. نستخدم jQuey - عند النقر على زرّ الإرسال - لتحليل الملف الذي حمّله المستخدم: $('#submit').on("click",function(e){ e.preventDefault(); $('#files').parse({ config: { delimiter: "auto", complete: buildTable, }, before: function(file, inputElem) { //console.log("Parsing file...", file); }, error: function(err, file) { //console.log("ERROR:", err, file); }, complete: function() { //console.log("Done with all files"); } }); }); الشفرة كما يظهر بسيطة. نبدأ أولا بضبط بعض المعطيات Parameters التي يحتاجها Papa parse باستخدام الكائن config. يتوفّر Papa parse أيضا على توابع لدورة حياة الملف يمكن استخدامها إن اقتضت الضرورة: before: دالة تُنفَّذ قبل بدء تحليل الملف. error: دالة تُنفَّذ عند وجود خطأ في تحليل الملف. complete: دالة تُنفَّذ بعد اكتمال تحليل الملف. لا تتلقّى هذه الدالة أية بيانات، وبالتالي يجب استخدام الدالة في المعطى complete إن كنت تريد معالجة البيانات التي تحصّل عليها المحلّل، وهو ما سنفعله. تتضمّن معطيات الكائن config المذكور أعلاه: المحرف المستخدَم للفصل بين القيم delimiter الذي ضبطناه على القيمة auto لكي يستكشف المحلّل تلقائيًا المحرف المستخدم. دالة تُنفَّذ بعد اكتمال تحليل الملف يحدّدها المعطى complete في الكائن config. أعطينا القيمة buildTable لهذا المعطى، وهو اسم دالة سنعرّفها لاحقا. تستقبل الدالة buildTable نتيجة تحليل الملف في أول معطى (results)، وهو كائن يأخذ الهيكلة التاليّة: { data: // مصفوفة بالبيانات بعد التحليل errors: // مصفوفة بالأخطاء التي قد تكون حصلت أثناء تحليل الملف meta: // كائن يتضمّن معلومات إضافية } تستقبل الدالة buildTable الكائن results وتستخدم البيانات results.data لإنشاء جدول تعرضه في صفحة الوب: function buildTable(results){ var markup = "<table class='table'>"; var data = results.data; for(i=0;i<data.length;i++){ markup+= "<tr>"; var row = data[i]; var cells = row.join(",").split(","); for(j=0;j<cells.length;j++){ markup+= "<td>"; markup+= cells[j]; markup+= "</th>"; } markup+= "</tr>"; } markup+= "</table>"; $("#app").html(markup); } ترجمة - بتصرف - للمقال Reading csv file using javascript لصاحبه Arkaprava Majumder. لتحميل الملف المرفق انقر هنا.1 نقطة
-
يوفّر الكائن Math في جافا سكريبت الكثير من الدوال والقيم منتشرة الاستخدام في الحساب والرياضيات. مثلا، إن أردنا الحصول على قيمة الثابت π (باي) الذي هو النسبة بين محيط دائرة وقطرها فيمكننا ذلك باستخدام القيمة Math.PI. من أكثر دوال الكائن Math شيوعا الدالة Math.max (والدالة المقابلة لها Math.min)؛ فمن الشائع أن تواجه مجموعةً من الأرقام وعليك معرفة أكبر أو أصغر رقم فيها، وصحيحٌ أنَّ بإمكانك استخدام معامل رياضي في JavaScript لمعرفة الإجابة، أو عبر استعمال سلسلة من عبارات if الشرطية، لكن هاتين الدالتين أكثر مرونةً وكفاءة. الدالتان Math.max وMath.min، على النقيض من الدوال التي تكتبها بنفسك في JavaScript، مبنيتان في أساس لغة JavaScript وهما جزءٌ من الكائن الساكن (static object) الخاص بالدوال الرياضية Math، وهو ما يعني أن بالإمكان استعمال دوال هذا الكائن في أيّ مكان من التطبيق أو المشروع دون تهيئة كائن خاص بها. تقبل هاتان الدالتان مجموعةً من الأرقام وسائط لها، إذ تُعيد الدالة Math.max أكبر رقم في المجموعة. جرّب مثلًا التعليمة البرمجية الآتية في console في المتصفح: Math.max(5, 10, 11, 3, 22); > 22 ملاحظة: إذا وضعت أي نوعٍ غير رقمي من القيم فستكون النتيجة هي NaN والذي يعني Not A Number (أي أن المدخلات أو المخرجات ليس رقمية). لاحظ أنَّ بإمكاننا تمرير متغيرات أو خاصيات (properties) تابعة لأحد الكائنات (object) إلى الدالة Math.max: let orbitalPeriod = new Object(); orbitalPeriod.Mercury = 87.97, orbitalPeriod.Venus = 224.70, orbitalPeriod.Mars = 686.98; Math.max(orbitalPeriod.Mercury, orbitalPeriod.Venus, orbitalPeriod.Mars) > 686.98 أحد الأمور الذي لا تستطيع الدالة Math.max فعلها هو العثور على أكبر قيمة في المصفوفة، وهو ما دعا في الماضي إلى استخدام حلقات التكرار ومقارنة كل القيم في ما بينها (عبر إحدى الخوارزميات المعروفة) وتخزين أكبر قيمة؛ إلا أن الأمر تغيّر مع ظهور المتصفحات الحديثة التي تدعم معيار EmacScript 6، والتي تمكّن من استعمال معامل باسم spread، وهو عبارة عن ثلاثة نقاط ... توضع أمام المصفوفة أثناء تمريرها للدالة، مما يختصر العملية كثيرًا: let orbitalPeriods = [87.97, 224.70, 686.98]; longestOrbit = Math.max(... orbitalPeriods); يُعرَف التأثير الذي يُحدثه المعامل Spread على المصفوفة باسم التوزيع Expension. يُكافئ تمرير مصفوفة موّزّعة تمرير جميع عناصرها على هيئة مجموعة أرقام؛ أي أن الكتابتين أدناه متكافئتان: Math.max(5, 10, 11, 3, 22); Math.max(... [5, 10, 11, 3, 22]); تُستعمل الدالة Math.max أيضًا للاختيار بين رقمين (إما/أو)، فلو كنّا نحتاج إلى قياس عرض الشاشة فسنستعمل: let screenWidth = Math.max(screen.width, 0); يجب أن تكون قيمة المتغير screenWidth النهائية رقميةً: فإما أن تساوي عرض الشاشة، أو إذا لم نستطع الحصول على تلك القيمة أو كانت غير رقمية، فالناتج 0. الحصول على أصغر رقم في المجموعة الدالة Math.min تعمل عكس عمل الدالة Math.max، فبتمرير مجموعة من القيم إليها ستُعيد الدالة Math.min أصغرها. Math.min(0.139, 0.15, 1); > 0.139 تُستعمَل الدالة Math.min عادةً لتعريف ما هي الحدود أو الشروط الدنيا، فلو كانت لدينا كرةٌ تتحرك داخل مستطيل، وكان الجانب الأيمن للمستطيل موجودًا على بعد 500 بكسل من إطار العرض، ولا نريد أن تخرج الكرة من المستطيل عند ارتطام جانبها الأيمن (ball.rigth) بحافة المستطيل (500)، فسنكتب: let collide = Math.min(ball.right,500); أحببتُ أن أنوِّه إلى إمكانية «توزيع» القيم الموجودة في مصفوفة داخل الدالة Math.min، فلو كانت لدينا مصفوفةٌ باسم bugSizes وأردنا معرفة أدنى قيمة فيها، فيمكننا كتابة: Math.min(... bigSizes) يمكننا بشكلٍ بديلٍ استخدام apply للحصول على نفس النتيجة، وهذه الطريقة مدعومةٌ دعمًا أفضل في المتصفحات: Math.min.apply(null, bigSizes); يمكن استعمال apply مع الدالة Math.max أيضًا. ترجمة – بتصرّف – للمقال To the Max: Using Math.min and .max لصاحبه Dudley Storey.1 نقطة
-
لا يجب أن تبدأ دائمًا بالتطوير باستعمال إطار عمل JavaScript، لكن هنالك حالات يكون فيها استعمال إطار العمل أمرًا منطقيًا. منذ فترةٍ كتبتُ مقالةً بعنوان «لماذا يدفعنا التطوير بلغة JavaScript إلى حافة الجنون!» والتي زارها الكثيرون، وظهر التساؤلان الآتيان ردًا عليها: - متى يجب أن نستخدم إطار عمل؟ - إذا لم نستعمل إطار عمل، فكيف نبدأ؟ سأحاول في هذه المقالة الإجابة على التساؤل الأول، أما سؤال كيفية البدء إذا لم نستعمل إطار عمل فهو سؤالٌ أكبر، ويحتاج تفصيلًا أكثر. بدأتُ العمل منذ عدِّة سنوات في شركة (لن أسميها هنا)، والتي تستطيع أن تطلب منها إنشاء أي شيء غريب يمكن تخيله، وستصنعه لك خلال فترةٍ وجيزة. كان للشركة هامش ربحٍ كبير، وتجني أموالًا طائلة، وتعلمتُ الكثير عن إدارة الأعمال منها، لكنني تعلمتُ أيضًا بعض الأمور عن الأنظمة. كانت واجهة موقع الشركة الإلكتروني معقدةً! ولهذا السبب بدأ موقع الشركة في بدايات 2000 بالتحول إلى تطبيقٍ ذي صفحةٍ واحدة، حتى قبل انتشار فكرة التطبيقات ذات الصفحة الواحدة (single page application). كانت شيفرات JavaScript التي تشغل موقعهم معقدةً جدًا، وكانوا نادرًا ما يوظفون مبرمجين، واختاروا إطار عمل YUI بدلًا من jQuery لأنه كان شائعًا في تلك الفترة، ثم اشتقوا (fork) شيفرة YUI مما جعل التعامل معها وصيانتها أمرًا صعبًا جدًا. ولسببٍ أجهله، كانوا يكتبون شيفرات JavaScript بشكلٍ شبيهٍ بشيفرات Visual Basic. كانوا أيضًا يستعملون نظامًا لإدارة الإصدارات (version control system) من الثمانينات الذي كانت آلية حماية الملفات من التعديل فيه هي قفلها (file locks) والتي تستطيع بسهولة تجاوزها. سكربت البناء الذي كانوا يستعملونه هو شخصٌ اسمه Ed، فلتحويل الشيفرة إلى الخادوم الإنتاجي سيكون عليك أن تطبع قائمةً بالملفات التي عدَّلتَها وتسلمها لذاك الشخص، ثم سيبحث عن تلك الملفات وينسخها يدويًا إلى كل خادوم على حدة. كان السند الخلفي (backend) للموقع هو حاسوبٌ قديمٌ يُشغِّل برمجيات مكتوبة في سبعينيات القرن الماضي، وكانت تُحدَّث بيئة التطوير المشتركة يدويًا من قِبل المطورين، متى أرادوا ذلك. إذا كنتَ تضحك الآن على حالهم وتظن أن هؤلاء الأشخاص أغبياء، فأظن أنَّ الوقتَ مناسبٌ لأشير إلى أنهم لم يعانوا من انقطاعاتٍ في الخدمة، وكانوا يُصدرون ميزاتٍ جديدة دوريًّا، ويجنون أموالًا طائلة تزداد عامًا بعد عامًا. لذا أظن أنهم يضحكون الآن خلال طريقهم إلى البنك ليستلموا أرباحهم. هل تتلقى أجرًا لقاء كتابتك للشيفرات؟ إذًا أنت تعمل لدى شركة. وعندما تقرر الشركة كيف تُنفِق ميزانية المطورين، فلن يكون منطقيًا أن تنفق مالًا لكتابة البرمجيات «بالطريقة الصحيحة». الفكرة التي أحاول إيصالها هنا هي أنَّ حال الشركة السابقة قد يبدو بائسًا بالنسبة إلى مطوري البرمجيات، لكنه منطقيٌ جدًا وجيد بالنسبة إلى أصحاب تلك الشركة الذين يهتمون بالربح. استخدام إطار عمل JavaScript قد لا يكون خيارًا استراتيجيًا للشركات حتى لو كان حالها سيئًا كالشركة التي نتحدث عنها. إذًا، كيف يجب أن تتابع الشركة السابقة بتطوير برمجياتها؟ كيف ستقرر الشركة أنها بحاجة إلى استخدام إطار عمل؟ شرحتُ سابقًا في مقالة «لماذا يدفعنا التطوير بلغة JavaScript إلى حافة الجنون!» أنَّ من غير المنطقي البدء بتطوير البرمجيات انطلاقًا من إطار عمل. لنفترض وجود شيءٍ شبيهٍ بإطار Angular عند نشأة الشركة السابقة؛ فهل كان عليهم استخدام إطار عمل؟ هل يجب عليهم استخدام إطار عمل في هذه الفترة؟ عندما تختار الشركة إطار عمل لتستعمله لتطوير برمجياتها، فهنالك كلف ومخاطر: - ماذا لو اختفى دعم إطار العمل خلال خمس سنوات؟ هل يمكن أن تتحمل الشركة عبء صيانة إطار العمل بنفسها؟ هل يتوافر في فريق العمل أشخاصٌ لهم خبرات في هذا المجال؟ الجواب هو النفي لأغلبية الشركات، ولا نُغفِل أنَّ الكثير من أطر العمل Frameworks تختفي فجأةً. عليك أن تجري مع التيار وتخمِّن إن كانت الزيادة في الإنتاجية الآتية من اختيار إطار عمل تستحق الوقت والكلفة اللازمة للتحويل إلى إطارٍ آخر لاحقًا، أو أنَّها تستحق كلفة التعامل مع برمجيات غير مدعومة لسنوات في نفس الوقت الذي تحاول فيه توفير ميزانية كافية للتحويل إلى إطارٍ جديد. إذا كانت شيفرات برمجيتك قليلة نسبيًا وكنت تعمل في شركة وتحذف كميةً لا بأس بها من الشيفرات وتُعيد كتابتها (كثير منا يفعل ذلك لكنهم لا يعترفون)، فأرى أنَّ من المناسب استعمال إطار عمل. أما لو كانت شيفرات برمجيتك كثيرة جدًا، وكنت تنظر إلى خطتك التي وضعتها للسنوات الخمسة القادمة ورأيتها مليئةً بالميزات الجديدة التي ستكوِّن جزءًا أساسيًا من شركتك، فإن اختيار إطار عمل الذي سينتهي دعمه خلال خمسة سنوات هو رهانٌ خاسر، والطريقة الوحيدة التي ستجعلك تختار واحدًا هي التفكير بأجوبةٍ للأسئلة المتبقية … - كم ستخسر من إنتاجية مطوريك حتى يتعلموا إطار العمل الجديد؟ إذا كنت تنتقل إلى إطارٍ وليكن Angular (وما لم توظِّف مطورين يعرفون Angular من قبل ويلمّون بأحدث المعلومات) فستنفق مالًا لتدريب فريق التطوير وسيضيّع المطورون الأشهر القادمة يسألون «كيف أفعل ذلك في Angular؟» حتى لو كانوا يفعلون نفس الأمر تمامًا باستخدام jQuery وشيفرات JavaScript البسيطة دون أدنى تفكير. - هل يمكننا بناء هذه الميزة التي تجعلنا نجني مالًا أكثر بنفس مقدار الوقت اللازم لتعلم إطار العمل؟ الجواب لأغلبية الشركات الربحية هو «نعم». - هل سيسمح لنا إطار العمل بجني المزيد من المال بجعلنا نُنشِئ الميزات الجديدة بوتيرة أسرع في المستقبل؟ نظريًا: هذه هي الفائدة المرجوة من إطار العمل. إذ ستحصل على فائدة أكبر من إطار العمل عندما يكون فريقك كبيرًا، وشيفرات مشروعك كثيرة، وتريد تسريع وتيرة تطوير الميزات الجديدة. لكن لاحظ أنَّك تستطيع تطوير بعض البرمجيات بسهولة ولن تستفيد فيها من التحول إلى إطار عمل. حسنًا، ربما تظن أنَّ هذا قرارٌ صعبٌ، إلا أنه في الواقع عكس ذلك لأغلبية الشركات. - الشركات الصغيرة وسريعة التغيرات تقع في الزاوية العليا اليسرى من المخطط السابق، فإذا كانت شيفرات برنامجك تتغير بسرعة فلن يكون من الخطر التغيير إلى إطار عمل آخر. فلو كنت تضيف الميزات يمنةً ويسرةً لأنك لم تعلم أيها يجني مالًا بعد، فلن تهتم إن «مات» إطار العمل الذي تستخدمه، لأنك ستحذف تلك الميزات والأجزاء من الشيفرات على أيّة حال. إذا كانت إنتاجيتك أكبر عندما تستعمل إطار عمل، وكنت تعمل لدى شركةٍ ناشئةٍ فسأقول أنَّ من الصواب استعمال إطار عمل، مع الأخذ بالحسبان أنَّ أغلبية الأشخاص تقل إنتاجيتهم عندما يستعملون إطار عمل لكنهم لا يعترفون بذلك. - تتواجد الشركات الصغيرة وذات معدل التغيير البطيء في الطرف السفلي اليساري من المخطط، وتكون إما شركات صغيرة تقليدية التي لا تُمثِّل البرمجيات مكوِّنًا أساسيًا من طريقة عملها، أو شركات البرمجيات الصغيرة. إذا كنت مبرمجًا تعمل لدى شركة صغيرة، فلا تستعمل إطار Angular أو React أو غيرهما. وإنما استخدم المكتبات المستقرة والثابتة والتي تعمل على جميع المتصفحات. فلو كنت تعمل في شركةٍ صغيرةٍ، فأرى أنَّ مخاطر استعمال إطار عمل تفوق ميزاته. - الشركات الكبيرة وذات معدل التغيير السريع تتواجد في القسم العلوي الأيمن من المخطط، وهي الشركات التي تكون البرمجيات مكوِّنًا أساسيًا فيها، أي أنهم يضيفون الميزات كثيرًا ويحذفون أجزاءً كبيرةً من الشيفرات ويعيدون كتابتها (حتى لو لم يعترفوا بذلك)، ولديهم فرق برمجية كبيرة، والميزات الجديدة التي يُضيفونها ستدر عليهم مالًا. لذا من المنطقي أن يدرِّبوا فِرَق البرمجة عندهم لاستعمال إطار عمل، لكي يبدأ الجميع من نفس المكان ولتُكتَب الميزات بوتيرة أسرع. إذا كانت شركتك ذات دخلٍ كبير، فستقل مخاطر فقدان دعم إطار العمل مع مرور الزمن، لأنك عندما كنت تختار ما هو إطار العمل الذي ستعمل عليه فستأخذ بالحسبان الدعم الطويل له. أما لو كنت تعمل في شركةٍ كبيرةٍ وتجني أموالًا طائلة وكانت البرمجيات من أساس عملك، فمن المنطقي أن تكتب إطار عمل خاص بك مثل Facebook و Google … - الشركات الكبيرة وذات معدل التغيير البطيء تقع في الركن السفلي اليميني من المخطط. وتنتمي الشركة التي تحدثنا عنها في بداية المقالة إلى هذا النوع، ولن يكون الخيار الصائب واضحًا هنا. فليس مجال عمل الشركة هو البرمجيات، لكن البرمجيات هي جزءٌ أساسيٌ نظام عمل الشركة. لن تتغير الشركة بسرعة، لكن الميزات الجديدة ستساعد الزبائن بشراء المزيد من المنتجات. مثاليًا، يمكنك أن تبني على إطار عمل الذي سيبقى حوالي 50 سنة، وهذا أمرٌ معقولٌ بالنسبة إلى شركةٍ تستعمل برمجيات وشيفرات عمرها 40 سنة. لكن هذا ليس موجودًا، لذا قد تفكر ببناء إطار عمل خاص بك، لأنك ستتأكد أنك لن تقع في فخ أطر العمل الميتة بعد 10 سنوات. لذا يجب أن تنشئ كل شيء من الصفر، وسترى أنَّ نفقات إنشاء ذلك قليلةٌ مقارنةً بالربح خلال 50 سنة … إذًا، هل يجب أن تنتقل الشركة إلى إطار عمل؟ لا يوجد جواب سهل! فعندما كنتُ مطورًا أعمل عندهم وكنت أفكر عن البرمجيات فقط، فكان الجواب الجلي بالنسبة لي هو: بالطبع يجب أن ينتقلوا لاستخدام Angular! لكن عندما بدأتُ شركتي الخاصة، فأصبحتُ أرى البرمجيات من زاويةٍ أخرى، لذا لن يكون الخيار سهلًا. توقف برهةً وفكِّر بعمق قبل الالتزام بإطار عمل، وإذا كنتَ صاحب قرار التحول إلى إطار عمل في حال استعملتك الشركة كمستشار، فأسدِ خدمةٍ إلى الشركة، وانزع عنك نظارات المبرمج، وضع نظارات مدير الأعمال. ترجمة -وبتصرّف- للمقال Should You Ever Use a JS Framework? لصاحبه Sean Fioritto1 نقطة