لوحة المتصدرين
المحتوى الأكثر حصولًا على سمعة جيدة
المحتوى الأعلى تقييمًا في 03/26/15 في كل الموقع
-
بدأنا في الجزء الأول من سلسلة مقالات "كيف تُصبح مُستقلًّا ناجحًا" بتعريف مفهوم العمل المُستقل ووضحنا أبرز ميزاته باستخدام الإنترنت، ثم ختمنا بقائمة غنية بأشهر منصات العمل للمُستقلين على الصعيدين العربي والعالمي. سننطلق معكم الآن إلى العمل الجاد حيث سنبدأ بالخطوات العملية الأولى في "العمل المُستقل" عبر توسعنا في مجموعة من الأساسيات الصحيحة التي يجب ألّا يغفلها أي مُستقل. الأدوات اللازمة للعمل المُستقل تحتاج كعامل مُستقل من خلال الإنترنت إلى مجموعة الأدوات الأساسية التالية: 1- حاسوب: حاسوب مكتبي أو محمول يُلبي الغرض بحده الأدنى. 2- اتصال بالإنترنت: العمل سيعتمد بشكل أساسي على وجود شبكة الإنترنت. 3- برامج سطح مكتب: يجب أن يحوي جهاز المُستقل مجموعة البرامج التالية: - برنامج تحرير نصوص. - برنامج ضغط وفك ضغط الملفات. - أي برامج أو تطبيقات أخرى خاصة قد تحتاجها لتلبية أعمالك (فالمُصمم سيحتاج برامج خاصة بالتصميم، وصانع الفيديوهات سيحتاج برامج خاصة بتحرير الفيديو ... وهكذا). 4- هاتف محمول: تحتاج للهاتف المحمول لإثبات حسابك في بعض المواقع التي تتطلب ذلك، ومن النادر أن تحتاجه للتواصل، فمنصات العمل الحُر عبر الإنترنت توفر لمُرتاديها وسائل اتصال مُختلفة فيما بينهم وبحسب سياسات عملها فإنها لا تسمح بأن يتم التواصل خارج نطاقها ضمانًا لحقوق الجميع. 5- حساب مصرفي: يتوجب امتلاك حساب مصرفي لتحصيل الأرباح ومُتابعة الأمور المالية. تلميح: يُعدّ Paypal من أهم المصارف الإلكترونية على مستوى العالم، وتوفر خدماته مُعظم المواقع الإلكترونية التي تتعامل بالخدمات والبيع والشراء كمواقع الأعمال للمُستقلين وأيضًا مواقع التجارة الإلكترونية كوسيلة مُباشرة للشراء وتحصيل الأموال. ملحوظة: للمُستقلين المُقيمين في دول عربية يُحظّر عنها استخدام خدمات Paypal بالإمكان استخدام وسائل أخرى لتحصيل أرباحهم: - عبر الحوالات المصرفية والتي توفرها بعض المواقع عند وصول المبالغ إلى حدود مُعينة. - من خلال طلب تحويل الأرباح عبر خدمات مثل Western Union و Money gram التي لها مكاتب وشُركاء في مُعظم دول العالم. - عبر الاستعانة بالوكلاء أو الوسطاء الموثوقين. ... وغيرها من الوسائل. للأسف الشّديد، عامل تحصيل الأموال قد يكون مُسببًا مُباشرًا لعزوف الكثير من المُستقلين المُقيمين في دول مُعينة مُتعرضة حكوماتها لعقوبات اقتصادية وتُحظر عنها العديد من الخدمات العالمية، علمًا بأن هؤلاء الأفراد هُم الأكثر حاجة للعمل المُستقل كنتيجة لضعف اقتصادات بلادهم ونمو مُعدلات البطالة ... على هؤلاء الأفراد أن لا يتركوا لديهم أبدًا أي مكان للإحباط وأن يبدؤوا أعمالهم مُستغلين أولًا المنصات العربية التي تعمل كبدائل جيّدة لهم وأيضًا وسائل الدفع الشرعية البديلة المُتوفرة" انطلق! (الأساس الصحيح)إن البداية الفعلية لأي عمل تأتي باتخاذ جرأة الخطوة الأولى للانطلاق ثُم تأسيس ملامح هذا العمل في الخطوة التالية، وعلى المُستقلين عمومًا والعاملين من خلال الإنترنت تحديدًا التركيز أكثر من غيرهم على مجموعة من التفاصيل في سبيل استقطاب الزبائن. أمور يبحث عنها أصحاب العمل "لا تغفلها أبدًا"من الجيّد أن نضع أنفسنا مكان أصحاب العمل ونتخيّل أفكارهم ورغباتهم وكيفية اختيارهم للمُستقلين كي نُقدّم بالفعل أساليب مُقنعة لهم ومُحرضة على الاختيار، والتالي قائمة بأبرز تلك الأمور: 1- الأشخاص الحقيقيين: من الطبيعي فإن الإنسان يميل إلى الأشخاص الحقيقيين وخاصة في التعاملات المالية، لذا على المُستقلين عدم إغفال هذا الجانب أبدًا فهم أحوج من غيرهم إلى بناء الثقة والمصداقية مع الآخرين، لذا عليك كمُستقل أن تتعامل من خلال الإنترنت بشخصيتك الواقعية وذلك عبر: - التعامل باسمك الحقيقي - صورة شخصية حقيقية (أو صورة مُعبرة على أقل تقدير) 2- أصحاب الخبرات: يميل الباحثون عن المُستقلين إلى الأشخاص أصحاب الخبرات العالية والمُتخصصين بمجالاتهم، لذا احرص على أن تُعرّف عن خبراتك وإمكانياتك بشكل جيّد. تلميح: احرص على عدم المُبالغة في التوسّع بخبراتك وخصصها بقدر المُستطاع، أيضًا ابتعد كُل البُعد عن ذكر أمور لا تُتقنها لأن ذلك سيعود عليك بشكل سلبي وسيضر بسمعتك وسمعة عملك. 3- الأعلى تقييمًا: الكُل يبحث عن الناجحين -حقيقة- لذلك احرص بشكل دائم على تأدية المهام المُكلف بها بأقصى جودة وخدمة مُمكنة للحصول على أعلى التقييمات. تلميح: عدم وجود أي تقييم يُعدّ السبب الرئيسي لتأخر الحصول على أول عميل للمُسجلين الجُدد، لذلك قد تنظر إلى مُستقلين هُم أقل منك خبرة لكن أعمالهم تُطلب بشكل كبير بسبب أن لديهم تقييمات وظهور مُرتفع. لا تدع الأمر يُحبطك فالجميع مر برحلة الحصول على العميل الأول (سنحدثك عنها لاحقًا). 4- أصحاب التعليقات الإيجابية: لن يتردد صاحب العمل قبل التعامل معك في البحث عن التعليقات التي تركها زبائنك السابقين في تقييمهم لأعمالك، لذا احرص بشكل كبير على الاهتمام بأي زبون لديك ولا بأس في الطلب منه في نهاية العمل وبشكل لطيف بأن يترك تعليق يُقيّم به العمل المُنجز. 5- أصحاب الملفات التعريفية الشخصية "البروفايلات - profiles" المُقنعة: - عرّف عن نفسك جيّدًا وخاطب بشكل سليم صاحب العمل بالأمور التي ستقدمها له - ضمّن في خطابك دعوة لطيفة للتعاون - ضع صورة مُناسبة - قُم بالإشارة إلى أهم أعمالك السابقة التي تعتز بها 6- أصحاب الأعمال النوعية: لا تغفل على الإطلاق وضع مجموعة من أهم أعمالك ضمن معرض الأعمال الخاص بك على حسابك في منصة العمل المُستقل. تلميح: ابتعد عن الكمية وركّز على النوعية عند عرضك للأعمال، واحرص كُل الحرص في الابتعاد كلّيّة عن أي نسخ أو وضع أعمال ليست بحقوقك. 7- أصحاب الأسعار المُناسبة: السعر أحد الأمور الأساسية التي ينظر إليها صاحب العمل بعين الاعتبار عند اختياره بين عروض المُستقلين، لذا احرص على اختيار سعر مُناسب لعملك. تلميح: لا يُقصد هُنا وضع أقل سعر بل اختيار أفضل سعر مُمكن دون مُبالغة (قد يكون أفضل سعر تجده مُناسب لعملك أعلى من الميزانية الموضوعة من صاحب العمل. لا بأس بوضعه مع تبرير السبب بشكل مُقنع لصاحب العمل). 8- المُتابعون: المُستقلون المُتصلون بشكل دائم والحريصون على مُتابعة زبائنهم بالمُستجدات باستمرار والرد على استفساراتهم بشكل سريع ووافٍ قبل التعاقد هُم عُرضة للاختيار والأكثر طلبًا لخدماتهم. روّج لنفسك كمُستقلمن الجيّد عدم الاعتماد بشكل مُطلق على منصات العمل ذاتها من خلال طرحها لأعمالك، ويجب التفكير دومًا في كيفية زيادة الطلب على خدماتك، أو زيادة كمية بيع مُنتجاتك الجاهزة. التالي قائمة بأبرز الوسائل التي بإمكانك إتباعها 1- الشبكات الاجتماعية أولويةلم يعد يخفى على أحد أهمية الشبكات الاجتماعية بكونها وسيطًا حقيقيًّا فعّالًا في إيجاد قاعدة من الأشخاص المُهتمين وأيضًا للترويج عن أي عمل، كنصيحة احرص بشكل أساسي أن يكون لديك حساب فعّال على تويتر قدّم من خلاله نصائح للآخرين بحسب اهتماماتك والأمور التي تتقنها بشكل جيّد. اجعل نفسك مُساعدًا حقيقيًّا لهم وروّج ضمن منشوراتك (تغريداتك) عن خدماتك التي تسعى إلى تقديمها بشكل مأجور أو مُنتجاتك التي تعرضها للبيع (كتاب إلكتروني – سلسلة تعليمية – تصاميم جاهزة .... الخ) وستلحظ تدريجيًا مع الوقت نمو في مُعدل الطلب على خدماتك. استفد من شبكة فيس بوك في دعوة أصدقائك وأصدقاء أصدقائك ومعارفك الذين قد تجد لديهم اهتمام بخدماتك أو مُنتجاتك بأن تدعوهم للاطلاع عليها وتطلب منهم بأسلوب لطيف أن ينشروها بدورهم لمن يجدوا لديهم اهتمام في نوعية خدماتك. لا بأس بأن يكون لديك حسابات على أي شبكات اجتماعية أخرى تُعرّف من خلالها الآخرين عن الأمور التي تُجيدها. 2- دوّنأثبت للتدوين قيمة عظيمة ساعدت الكثيرين في بناء أسمائهم ورفعت درجة انتشارهم على مستوى الإنترنت. من المُفيد أن يكون لديك مدونة خاصة (ليست بالضرورة أن تكون مأجورة حيث بإمكانك الاستفادة من إنشاء مدونة مجانية عبر الاستعانة بخدمات عديدة مُتوفرة على الشبكة كخدمة "وورد بريس" على سبيل المثال رابط: ar.wordpress.com). أكتب في مدونتك عن أمور تُناسب اهتماماتك وتُقدّم نصائح حقيقيّة وواظب على الكتابة، ثُم أشر بشكل واضح إلى خدماتك أو مُنتجاتك المأجورة وأشر بروابطها على منصات العمل المُستقل. 3- تابع واستغل الفُرصمن الطبيعي أن تعترضك كمُستقل فُرص مُتكررة على الدوام، ومن الجيّد أن تكون جاهزًا لاستغلالها، ولعل أفضل الطرق هو بالتوجه بشكل مُباشر للتعريف بنفسك ومهاراتك وطرحها مع أعمالك للمُهتمين الباحثين عن خدمات "منصات العمل الحُر كمنصة مُستقل mostaql.com من شركة حسوب على سبيل المثال وفّرت هذا الأمر بشكل مُناسب ويخدم طرفي العمل". أفضل الطرق لإيجاد العُملاءالتالي قائمة بأفضل الطرق التي يُمكن إتباعها للبحث عن العُملاء: 1- العلاقات العامّة: من المُفيد أن تُحيط نفسك كمُستقل بشبكة واسعة من العلاقات التي ستجلب لك عُملاء. 2- شارك في الأحداث الاجتماعية المُتخصصة /مُؤتمرات – ندوات - start up weekend../ وتعرّف على المُشاركين وعرفهم بنفسك وبعملك المُستقل. 3- استخدم البريد الإلكتروني في الترويج المُباشر عن أعمالك للزملاء السابقين وممن تجدهم مُهتمين دون إغراق أو إزعاج. 4- ضع إعلانات ترويجية في المدونات والمجلات المُتخصصة. 5- اجعل مساحة من وقت يومك لمُتابعة طلبات أصحاب المشاريع وتقديم العروض. تابع منتديات بعض المواقع المُستقلة وساهم بالترويج عن نفسك بشكل غير مُباشر عبر مُساعدتك للآخرين في الرد على استفساراتهم أو تقديم النصائح لهم وأيضًا تقييم أعمالهم. جميعها أمور ستعود عليك بالفائدة. أخيرًا فإن أفضل الطرق للترويج لاسمك كمُستقل مُرتبطة بشكل مُباشر بسمعة عملك لذا احرص كل الحرص على التركيز على العمل الدقيق المُتقن وستجد بأن عُملائك قد أصبحوا بمثابة مُدراء تسويق لعملك. في المقالات القادمة سنُعرّج على مواضيع مُرتبطة بأفضل الطرق لتوجيه العروض والعمل، مشاكل العمل المُستقل إضافة إلى أنسب الطرق لإدارة وقتك كمُستقل.1 نقطة
-
في سلسلة من عدة أجزاء سنناقش موضوعًا نظريًّا يُعتبر من أساسيّات هندسة البرامج، وهو أنماط التصميم (Design Patterns)، وسنعتمد لغة JavaScript في نقاشنا لتصاعد شعبيّتها ومرونتها التي تسمح لنا ببناء مشاريعنا وفق أنماط متنوّعة مما سيُسهّل علينا شرح موضوع السّلسلة ما هي أنماط التصميم؟عندما تبدأ بتعلّم البرمجة، فغالبًا ما يكون اهتمامك مُنصبًّا على أن يكون البرنامج قادرًا على إنجاز المهمّة الّتي تريدها قبل كل شيء، أمّا بعد أن تتطوّر مهاراتك، فسينتقل اهتمامك إلى مواضيع أكثر عمقًا، وستبدأ بطرح بعض الأسئلة على نفسك، حتّى قبل أن تبدأ بكتابة البرنامج، من هذه الأسئلة: كيف أبني برنامجي بحيث يسهُل تحسينه فيما بعد؟كيف أتأكّد أن برنامجي سيبقى يؤدّي ما يُتوقّع منه حتّى وإن قمت بتعديل أجزاء منه بعد زيادة تعقيده؟كيف أبني برنامجي بحيث أستطيع إعادة استخدام أجزاء منه في برامج أخرى في المستقبل؟كيف أجعل برنامجي يستخدم أجزاء من مشاريع أخرى كتبها مطوّرون آخرون؟الإجابة على هذه الأسئلة هي واحدة دومًا: اختر نمط التصميم المناسب لمشروعك. لم نُعرِّف بعدُ مفهوم نمط التّصميم، لكنّنا بدأنا نُكوّن فكرة عنه. نمط التّصميم هو وصف لطريقة مُعيّنة في حلّ مشكلة برمجيّة ما، فالعديد من المُشكلات البرمجيّة يمكن حلّها بأكثر من طريقة، ولكلّ طريقة مساوئ ومحاسن، وبعضها قد يكون أكثر مُناسبةً للمشروع الحاليّ، واختيار نمط التصميم المُناسب سيضمن استمرار تطوّر المشروع بسهولة وربّما يُفيدنا في عزل أجزاء منه لإعادة استخدامها في مشاريع أخرى بحيث لا نُضطَّر لكتابتها مرارًا. أغلب الظنّ أنّك تستخدم واحدًا أو أكثر من أنماط التّصميم وإن لم تعرف ما هي أنماط التّصميم بمعناها النّظريّ، فإنشاء أصناف (classes) لمفاهيم مُجرّدة في اللّغات الكائنيّة التّوجّه (object-oriented) وإنشاء نُسخ عنها (instances) وتوزيع هذه الأصناف في ملفّات مستقلّة، هو في الواقع نمط من أنماط التّصميم. يُرجى الانتباه إلى أن التّطبيق العمليّ لأنماط التّصميم يفرض على المطوّر دمج أكثر من نمط معًا وشرحنا لأحدها لا يمكن أن يخلو من استخدام لأنماط أخرى كما سيتبيّن لك بعد انتهاء السّلسلة، إذ يمكن مثلًا إنشاء وحدة (module) تُصدِّر صنفًا (class) وهذا يعني أنّنا استخدمنا نمطين اثنين (نمط الوحدات، ونمط مُشيّد الكائنات constructor) في وقت واحد. نمط الوحدات (Module Pattern)بغرض تبسيط الأمور، سنبدأ بتوضيح أحد أنماط التّصميم الشّائعة في JavaScript، وهو ما يُعرف بنمط الوحدات (module pattern)، والتي ازدادت شعبيّة بعد ظهور Node.js وما أحدثته من تأثير انتقل حتّى إلى أساليب بناء وتصميم المكتبات البرمجيّة الّتي تستهدف المُتصفّحات. الوحدات هي أجزاء مُستقلّة ومعزولة من النّص البرمجيّ للمشروع توفّر مهمّة مُعيّنة، الأمر الّذي يجعل الهدف من كل وحدة واضحًا ومحدّدًا ويُجنّب المشروع الفوضى التي تنتج عن كتابة كامل النّصّ البرمجيّ في كتلة واحدة متداخلة يصعب معها تنقيحه وصيانته. فصل الأجزاء هذا ليس الفائدة الوحيدة الّتي يُقدّمها نمط الوحدات، إذ من خلاله يمكن مُحاكاة مفهوم المكوّنات السّرّيّة (private) والعلنيّة (public) وحماية بعض محتويات الوحدة من الوصول إليها من خارجها في JavaScript، وذلك بإخفائها ضمن الوحدة والامتناع عن تصديرها الأمر الذي يجعل الوصول إليها من خارج الوحدة مستحيلًا كما سنوضّح بعد قليل. تتوفّر في عالم JavaScript أشكال مختلفة لتصميم الوحدات، منها: الكائنات الحرفيّة (object literals)الدّوالّ المغلقة المجهولة (anonymous closures)وحدات CommonJSوحدات AMDوحدات ECMAScript 6الشّكل الأول ربّما هو أبسط الأشكال وأكثرها بدائيّة، وهو يعني ببساطة إنشاء كائن باستخدام صياغة القوسين المعكوفين {} يضمّ خصائص ووظائف متعلّقة بمهمّة واحدة لعزلها وتسهيل استخدامها: var userSettings = { preferences: { privacy: "strict", language: "ar", showEmail: false, available: true, }, updatePreferences: function(newPrefs) { this.preferences = newPrefs; } }بعض خبراء JavaScript لا يعتبرون هذا النّمط وحدةً حقيقيّة لبساطته الشّديدة، فمن الواضح أنّ هذا النّمط أبسط من حاجات التّطبيقات المعقّدة، فغالبًا ما يكون توزيع الوحدات على ملفّات منفصلة أمرًا مرغوبًا أثناء تطوير التّطبيقات ولهذا نحتاج إلى وسيلة لاستيراد هذه الملفّات وتصديرها بما يسمح باستخدام وحدة واقعة في ملفّ من ملفّ آخر، ولهذا الغرض طوّر مجتمع JavaScript خلال الأعوام الماضية أساليب قياسيّة اتّفق على استخدامها على الرّغم من أن اللّغة ذاتها لم تقدّم مفهوم الوحدات إلّا في الإصدار الأخير (ES6)، والذي استلهم من الأساليب السّابقة أصلًا؛ كما أنّنا قد نرغب بحماية كائن مثل preferences في مثالنا السّابق من تعديله بصورة مباشرة. الشّكل الثّاني هو أسلوب أكثر تطوّرًا لإنشاء الوحدات، ويحتاج فهمه إلى فهم معنى الدّوال المُغلقة (closures)، فإذا كانت لدينا دالّة تُعيد عند استدعائها دالّة أخرى، فإنّنا ندعو الدّالة الأخيرة دالّة مُغلقة، ويتاح لهذه الدّالة الوصول إلى المتّغيّرات الّتي كانت مفروضة في الدّالة الأولى حتّى عندما تُستدعى من خارجها: function addNumberToN(n) { return function(number) { return n + number; } } var addTo2 = addNumberToN(2); var five = addTo2(3); // 5هذه الخاصيّة في JavaScript تسمح لنا بعزل المتّغيّرات (encapsulation) ضمن الدّالة الخارجيّة مع الاحتفاظ بإمكانيّة الوصول إليها من الدّوال والكائنات الفرعيّة، الأمر الذي يحاكي مفهوم خصوصيّة المتغيّرات في لغات البرمجة الأخرى (access modifiers). لنفترض مثلًا أنّنا نريد أن نقوم بإنشاء عدّاد لعدد النّقرات على زرّ معيّن في تطبيقنا، ولا نريد الاحتفاظ بهذه القيمة في النّطاق العامّ لأنّ هذا قد يعرّضها للتّعارض من أسماء مُتغيّرات أخرى أو يجعلها قابلة للتّعديل من إضافات خارجيّة في المتصفّح، لهذا نقوم بإنشاء دالّة مُغلقة تُحيط بهذه القيمة: function() { var counter = 0; return { increaseCounter: function() { counter++; } } }وبهذا نكون قد قيّدنا إمكانيّة تعديل قيمة المتغيّر بزيادته فقط، وعبر الدّالة increaseCounter() فقط. لا يمكن استخدام الدّالّة increaseCounter() إلا بعد استدعاء الدّالة المجهولة (anonymous) الّتي تُحيط بها، ويتمّ هذا كما يلي: (function() { var counter = 0; return { increaseCounter: function() { counter++; } } })()لتُصبح الدّالة increaseCounter() مُتاحة في النّطاق العامّ، وبهذا نكون حصلنا على شكل بدائي لفكرة "تصدير الوحدات" (module exports). لنستعرض الآن الأساليب الأخرى لإنشاء الوحدات، ولعلّ أكثر هذه الأساليب شيوعًا أسلوب CommonJS المُعتمد في Node.js، والذي يُتيح استيراد الوحدات باستخدام الدّالّة require(): var UrlMaker = require("./url-maker"); var url_maker = new UrlMaker("Hello World!"); var url = url_maker.make(); console.log(url); // hello-world;وأمّا تصدير الوحدات لإتاحة استخدامها، فيتم بإسناد الخصائص إلى الكائن module.exports، كما في الملفّ url-maker.js الموجود في مسار العمل الحالي: module.exports = function UrlMaker(string) { return { make: function() { return string.toLowerCase().replace(/\s+/gi, "-").replace(/[!?*%$#@`]/gi, "") } } }لا يقتصر استخدام أسلوب CommonJS على بيئة Node.js، بل يمكن نقله إلى المتصفّحات باستخدام برامج مثل Browserify. من الأساليب الشائعة لإنشاء الوحدات كذلك نمط وحدات AMD (اختصارًا لـAsynchronous Module Definition) ولعلّه يُستخدم بكثرة مع مكتبة require.js في المتصفّحات والّتي تسمح بتحميل الوحدات (الموزّعة كلّ منها على ملفّ منفصل) عند الحاجة إليها، إذ يتمّ التّصريح عن كلّ وحدة وما تعتمد عليه من وحدات أخرى وتقوم require.js بتلبية هذه المتطلبات بتحميل ملفّات الوحدات المنفصلة. في المثال التّالي، نُصرّح عن حاجة موقعنا لمكتبتي jQuery وUnderscore ووحدة أخرى قمنا بإنشائها بأنفسنا: require(["jquery", "underscore", "user_profile"], function($, _, UserProfile) { var user = new UserProfile(); user.firstName = $("#form input[name='first']").text(); user.lastName = $("#form input[name='last']").text(); user.username = $("#form input[name='username']").text(); // ... })ويتمّ التّصريح عن الوحدة user_profile في ملفّ منفصل باسم موافق: define(function() { function Profile() { /* ... */ } return Profile; })يوفّر الإصدار الجديد من JavaScript (ES6) دعمًا أساسيًّا لتعريف الوحدات واستيرادها وتصديرها، وسنتطرّق له بالتّفصيل في الجزء القادم من سلسلة التّعريف بميزات ES6 الجديدة، لكنّ لا بأس من أن نتعرّف عليه سريعًا: import { jQuery as $ } from "/jquery.js"; import { Profile as UserProfile } from "/user.js"; var user = new UserProfile(); user.firstName = $("#form input[name='first']").text(); // ...وتُنشئ الوحدة وتُصدَّر في الملفّ user.js: class Profile { constructor() { // ... } validate() { // ... } } export { Profile };فوائد استخدام الوحداتلنُلخِّص إذن فوائد الوحدات: تنظيم النّصّ البرمجيّ للمشاريع الضّخمة بحيث يسهل فهم بنية البرنامج وتنقيحه ومتابعة صيانته في المستقبل.إدارة المُتطلّبات (dependencies): توضيح العلاقة بين مكوّنات المشروع، بحيث نستطيع إدارة ما تتطلّبه كلّ وحدة وتحميل هذه المتطلّبات آليًّا بالتّرتيب الصّحيح بدل الحاجة إلى التّصريح عن روابط المكتبات الخارجيّة في الصّفحة الرئيسيّة للموقع وإعادة ترتيبها كلّ ما تطلّب الأمر إضافة مكتبة جديدة تعتمد على أخرى.العزل (encapsulation): حماية أجزاء من المشروع من العبث بها سهوًا أو من نصوص برمجيّة خارجيّة، وذلك بعزلها ضمن نطاق فرعيّ خلافًا لتركها في النّطاق العامّ. ففي الحالة الطّبيعيّة تكون متغّيرات JavaScript المفروضة في النّطاق العامّ مُتاحة لأي دالّة، وأما عند فرض هذه المُتغيّرات ضمن الوحدات، فإنّ الوصول إليها يُصبح محدودًا بما هو داخل الوحدة ذاتها، ويتمّ ذلك باستغلال مفهوم النّطاقات (scopes) في JavaScript وإحاطة هذه المتغيّرات بدالّة تُغلّفها بنطاق فرعيّ ثمّ إعادة كائن يحوي فقط الخصائص الّتي نريد إتاحتها للعموم.متى أستخدم هذا النّمط؟يُنصح باستعمال هذا النّمط في المشاريع الضّخمة كتطبيقات الويب المُعقّدة الّتي تعمل في المتصفّح، إذ تكون الحاجة مُلحّة لتجزئة المشروع وتطوير كلّ جزء بصورة مستقلّة ثم ربط هذه الأجزاء مع بعضها إمّا بهدف تسهيل تطوير المشروع أو إدارة المتطلّبات بحيث تُجلَب عند الحاجة إليها نظرًا لكبر حجمها أو تأثيرها على أداء التّطبيق، كما يُنصح باستخدامه عند الحاجة لعزل تفاصيل الوحدة عن النّطاق العامّ. المصادر: كتاب JavaScript Design Patterns لمؤلّفه Addy OsmaniJavaScript Module Pattern: In-Depthوثائق require.jsوثائق Node.js1 نقطة
-
في سلسلة من عدة أجزاء سنناقش موضوعًا نظريًّا يُعتبر من أساسيّات هندسة البرامج، وهو أنماط التصميم (Design Patterns)، وسنعتمد لغة JavaScript في نقاشنا لتصاعد شعبيّتها ومرونتها التي تسمح لنا ببناء مشاريعنا وفق أنماط متنوّعة مما سيُسهّل علينا شرح موضوع السّلسلة نمط المُشيِّد (Constructor)يشيع استخدام المُشيّدات في اللغات الكائنيّة التّوجّه، حيث تُستخدم لإنشاء نُسخ (instances) من الأصناف (classes)، ومع أنّ JavaScript ليست لغةً كائنيّة التّوجّه بالمعنى التّقليديّ، إلّا أنّها تسمح بإنشاء نُسخ عن كائنات باستخدام بالمُشيّدات، ويمكن لأيّ دالّة أن تُستخدم كمُشيّد، وذلك بأن نُسبقها بالكلمة new، ولتوضيح هذا النّمط سنقوم بإنشاء مُنبّه (كالّذي تضبطه للاستيقاظ في هاتفك) يمكن ضبطه إلى تاريخ ووقت معيّنين ثمّ تفعيله أو تعطيله حسب الرّغبة: function Alarm(when) { this.setAt = when; this.enable = function() { var startAfter = new Date(this.setAt) - new Date; console.log("Alarm will wake you up after " + startAfter/1000 + " seconds"); this.timeout = setTimeout(function() { console.log("Wake up!"); }, startAfter); } this.disable = function() { if (this.timeout) { clearTimeout(this.timeout); delete this.timeout; console.log("Alarm diabled"); } } } var a = new Alarm("2015-03-19 5:58 PM"); a.enable() // Alarm will wake you up after 8.982 seconds // After a few seconds: // Wake up!في المثال السّابق نُسمّي الدّالة Alarm() مُشيّدًا (constructor)، والكائن a نُسخة (instance). لاحظ أنّ Alarm في المثال السّابق ليست سوى دالّة (function)، فهي ليست صنفًا كما في لغات أخرى مثل Java وC++، إذ تُعتبر الدّوال في JavaScript مكوّنًا من الدّرجة الأولى وتُعامل كما يُعامل أيّ كائن، وهكذا يمكن استخدامها كمشيّد لكائن آخر ممّا يسمح بمحاكاة مفهوم الأصناف الّذي لم يُضَف إلّا مؤخّرًا في JavaScript. من عيوب المِثال السّابق إسناد الدّوال الّتي ستعمل عمل الوظائف (methods) إلى النُسخة ذاتها عند إنشائها، وهذا يعني تكرار محتوى الدّوال في الذّاكرة مع كلّ نسخة جديدة من الكائن Alarm، بينما يمكننا توفير هذا الاستهلاك غير المُبرّر للذّاكرة بإسناد الدّوال إلى النّموذج البدئيّ للكائن (أي إلى Alarm.prototype) مما يسمح بمشاركتها بين كل نسخ الكائن، لتقوم الآلة الافتراضيّة بتنفيذ النّصّ البرمجيّ للدّالّة ذاتها بسياق النّسخة (instance context) الّتي استدعت الدّالة، أي إنّ this تُشير ضمن الدّالة عند تنفيذها إلى النُسخةَ المنشأة وليس الصّنف؛ بالطّبع ليس من المرغوب تطبيق الفكرة ذاتها على المُتغيّرات الأخرى مثل setAt، لأنّه من البديهيّ أن تختلف قيمتها بين نسخة وأخرى. لنُعد كتابة المثال السّابق بصورة أفضل: function Alarm(when) { this.setAt = when; } Alarm.prototype.enable = function() { var startAfter = new Date(this.setAt) - new Date; console.log("Alarm will wake you up after " + startAfter/1000 + " seconds"); this.timeout = setTimeout(function() { console.log("Wake up!"); }, startAfter); } Alarm.prototype.disable = function() { if (this.timeout) { clearTimeout(this.timeout); delete this.timeout; console.log("Alarm diabled"); } } var a = new Alarm("2015-03-19 6:21 PM"); a.enable(); // Alarm will wake you up after 30.243 seconds // After 30 seconds... // Wake up!هذا الأسلوب في إنشاء الأصناف شائع جدًّا، وهو يتطلّب فهمًا دقيقًا لآليّة الوراثة في JavaScript؛ إذ يُبنى كلّ كائنٍ فيها على كائن آخر يُسمّى النّموذج البدئيّ (prototype)، ويقوم هذا الكائن الأخير على كائن ثالث أعلى منه في السّلسلة هو نموذجه البدئيّ، وهكذا حتّى نصل إلى null الّذي ليس له نموذج بدئيّ بحسب تعريف اللّغة. في مثالنا السّابق الكائن Alarm.prototype هو النّموذج البدئيّ للكائن a، وهذا يعني أنّ كل الخواصّ المُسندة إلى Alarm.prototype وما فوقه ستكون مُتاحة للكائن a، ولو كتابنا برنامجًا مُشابهًا بـJava لقُلنا إنّ Alarm صنفٌ وإنّ a نُسخة عن هذا الصّنف (instance). عندما نحاول الوصول إلى الخاصّة a.setAt، فإنّ مُفسِّر JavaScript يبدأ بالبحث عن هذه الخاصّة من أدنى سلسلة الوراثة، أي من الكائن a ذاته، فإنّ وجدها قرأها وأعاد قيمتها، وإلّا تابع البحث صعودًا إلى النّموذج البدئيّ وهكذا... وطبيعة JavaScript هذه هي ما سمح لنا بإسناد الوظيفتين enable وdisable إلى Alarm.prototype مطمئنّين إلى أنّها ستكون مُتاحة عند قراءة a.enable() وa.disable(). يمكن التأكّد من النّموذج البدئيّ للكائن a كما يلي: Object.getPrototypeOf(a) == Alarm.prototype; // trueالأصناف في ECMAScript 6يُقدّم الإصدار الأحدث من JavaScript مفهوم الأصناف (classes) بصورته التّقليديّة المعروفة في اللّغات الأخرى، إلّا أنّه ليس سوى أسلوب آخر لصياغة النّماذج البدئيّة (أو ما يُسمّى syntactic sugar)، وهذا يعني أنّه نموذج الوراثة في JavaScript لم يتغيّر. يمكننا إعادة كتابة المثال السّابق بصياغة الأصناف في ES6 كما يلي: class Alarm { constructor(when) { this.startAt = when; } enable() { var startAfter = new Date(this.setAt) - new Date; console.log("Alarm will wake you up after " + startAfter/1000 + " seconds"); this.timeout = setTimeout(function() { console.log("Wake up!"); }, startAfter); } disable() { if (this.timeout) { clearTimeout(this.timeout); delete this.timeout; console.log("Alarm diabled"); } } }وستُسند الدّوال enable() وdisable() إلى Alarm.prototype تمامًا كما في المثال الذي سبقه. يُذكر أنّ استخدام new ليست الطّريقة الوحيدة لتشييد الكائنات، إذ يمكن استخدام الوظيفة Object.create() لتُعطي النّتيجة ذاتها: var a = Object.create(Alarm.prototype); Object.getPrototypeOf(a) == Alarm.prototype; // trueإسناد الخواصّ إلى الكائناتJavaScript لغة ديناميكية، وهذا يعني أنّه يمكن إضافة وحذف الخواصّ من الكائنات وتعديل نماذجها البدئيّة أثناء التّنفيذ، وهذا ما يمنحها القسم الأكبر من مرونتها ويجعلها مناسبة للاستخدام في بيئة مُعقّدة مثل بيئة الويب، وليس من الغرابة أن توفّر اللّغة وسائل متعدّدة لإسناد الخصائص إلى الكائنات لتلبية الحاجات المتنوّعة لتطبيقات الويب. ماذا لو أردنا تغيير قيمة المنبّه في مثالنا السّابق بعد تفعيله؟ لربّما ترادونا للوهلة الأولى إمكانيّة تغيير قيمة الخاصّة setAt بالطّريقة التّقليدية: a.setAt = "2016-03-03 03:03 PM"; // or a["setAt"] = "2016-03-03 03:03 PM";لكنّ نتيجة هذا الفعل لن تكون كما يُتوقّع، فلو عدنا للمثال السابق وتمعّنا في خواصّه، للاحظنا عيبًا في كيفيّة عمل المُنبّه، إذ إنّ الخاصّة setAt مكشوفة ويمكن تغيير قيمتها في أيّ وقت، حتى بعد تفعيل المُنبّه، إلّا أنّ تغييرها بعدئذٍ لن يغيّر اللّحظة الحقيقيّة الّتي سينطلق فيها المنبّه كما يتضّح لنا عند قراءة النّصّ البرمجيّ، ولذا فنحن هنا أمام حلّين: إمّا منع تغيير قيمة الخاصّة setAt وجعلها للقراءة فقط بعد إنشاء المُنبّه، أو إيقاف المنبّه وإعادة ضبطه في كلّ مرّة تُغيّر فيها قيمة الخاصّة setAt، وكلا الحلّين متاحان إذا كنّا على علم بأساليب إسناد الخصائص في JavaScript. توفّر اللّغة الوظيفة Object.defineProperty() الّتي تسمح بتعريف خواصّ لكائن ما مع إمكانيّة التّحكم بتفاصيل هذه الخاصّة، ومن هذه التّفاصيل: هل الخاصّة قابلة للكتابة؟ (writable)هل يجب المرور على هذه الخاصّة عند سرد خواصّ الكائن؟ (enumerable)ما الذي يحدث عند إسناد قيمة للخاصّة؟ (set)ما الذي يحدث عند قراءة قيمة الخاصّة؟ (get)وبهذا يمكننا بسهولة منع تغيير قيمة الخاصّة setAt بعد إسنادها: function Alarm(when) { Object.defineProperty(this, "setAt", { value: when, writable: false }) } Alarm.prototype.enable = function() { var startAfter = new Date(this.setAt) - new Date; console.log("Alarm will wake you up after " + startAfter/1000 + " seconds"); this.timeout = setTimeout(function() { console.log("Wake up!"); }, startAfter); } Alarm.prototype.disable = function() { if (this.timeout) { clearTimeout(this.timeout); delete this.timeout; console.log("Alarm diabled"); } } var a = new Alarm("2015-03-19 7:51 PM"); a.setAt = new Date("2016-03-19"); console.log(a.setAt); // "2015-03-19 7:51 PM"لاحظ أنّ قيمة setAt لم تتغيّر. هذا حلّ جيّد، لكن سيكون من الأفضل السّماح للمُستخدم بتعديل قيمة المنبّه، وعندها سنلجأ لإيقاف المنّبه وإعادة ضبطه كما يلي: function Alarm(when) { var _hidden_value = new Date(when); Object.defineProperty(this, "setAt", { set: function(newValue) { _hidden_value = new Date(newValue); if (this.timeout) { this.disable(); console.log("Alarm changed to " + newValue); console.log("You need to re-enable the alarm for changes to take effect"); } }, get: function() { return _hidden_value; } }) } Alarm.prototype.enable = function() { var startAfter = new Date(this.setAt) - new Date; console.log("Alarm will wake you up after " + startAfter/1000 + " seconds"); this.timeout = setTimeout(function() { console.log("Wake up!"); }, startAfter); } Alarm.prototype.disable = function() { if (this.timeout) { clearTimeout(this.timeout); delete this.timeout; console.log("Alarm diabled"); } } var a = new Alarm("2016-03-03 03:03 PM") a.enable(); // Alarm will wake you up after 30221933.66 seconds a.setAt = "2015-03-19 8:05 PM"; // Alarm changed to 2015-03-19 8:05 PM // You need to re-enable the alarm for changes to take effect a.enable() // Alarm will wake you up after 20.225 seconds // After 20 seconds... // Wake up!لاحظ أنّنا سنحتاج إلى مُتغيّر سرِّيِّ (_hidden_value) نُخزّن فيه القيمة الفعليّة لوقت التّنبيه. متى أستخدم هذا النّمط؟نمط المُشيّد لا يحتكر بنية مشروعك عند استخدامه؛ معنى هذا أنّه لا شيء يمنعك من استخدام نمط المُشيّد مع أي نمط آخر عند الحاجة لذلك، فيمكن (بل يشيع كثيرًا) استخدام المُشيّدات ضمن الوحدات (modules) ثمّ تصديرها لاستخدامها من موضع آخر في المشروع، ومثال ذلك أشياء مثل EventEmitter وStreams في Node.js. كما يمكن بناء أنماط أخرى سنتعرّف عليها لاحقًا على أساس المُشيِّدات مثل نمط الكائن المُتفرّد (Singleton) ونمط المُراقِب (Observer pattern). المصادر: شبكة مُطوّري موزيلّا: Inheritance and the prototype chainكتاب JavaScript Design Patterns لمؤلّفه Addy Osmani1 نقطة
-
لِمَاذا قد تودُّ تشغيل Nginx و Apache معًافي الواقع يعتبر كلٌّ من nginx و apache عبارة عن خواديم ويب فعّالة للعمل. حاليًّا يحتل Apache المرتبة الأولى في مجال إدارة الخواديم منذ إطلاقه للعموم في 2006، nginx يصعد بقوة في شتّى أرجاء العالم وهو الآن يحتل المرتبة الثانية في خواديم الويب التي تدير المواقع النشطة. الأسباب وراء شعبية كلّ خادوم واضحة: قوة apache وسرعة nginx المعروفتان لدى الجميع. وعلى كلّ حال، فإن كلًّا من الخادومين يمتلكان نقاط ضعف – apache يستهلك الذاكرة بشراهة، بينما nginx -الذي يؤدي عملًا ممتازًا مع الملفات الثابتة(static files)- يحتاج مساعدة php-fpm أو وحدات مشابهة للتعامل مع المحتوى الديناميكي. على كلّ حال، يمكن لأي شخص أن يدمج الخادومين للحصول على فعالية ممتازة، مع استخدام nginx كخادوم ويب للملفات الثابتة بالواجهة (front-end) و apache ليعالج العمليات بالخلفية (back-end). التثبيتلتطبيق الخطوات الموجودة في هذا الدّرس ستحتاج إلى امتلاك صلاحيات المستخدم الجذر root على خادومك الافتراضي الخاص. لإنشاء مستخدم يمتلك صلاحيات الجذر، تابع الخطوتيّن الثالثة والرابعة من دليل تثبيت خادوم أوبونتو الشامل. تثبيت nginxلكي نبدأ العمل، سنحتاج إلى تثبيت وإعداد nginx الذي سيخدم واجهة موقعنا. يمكن تثبيته باستخدام apt-get عبر الأمر التالي: sudo apt-get install nginx بمجرد أن يتم التثبيت، يمكنك أن تبدأ بإعداد المضيف الوهمي (virtual host) لكي يتم تشغيله بواجهة الموقع. هناك بضع تغييرات إضافية علينا عملها في الإعدادات. إعداد nginxافتح إعدادات nginx عن طريق الأمر: sudo nano /etc/nginx/sites-available/exampleالإعدادات التالية ستسمح لك باستخدام nginx كخادوم لواجهة الموقع. هذه الإعدادات مشابهة للإعدادات الافتراضية، تفاصيلها تجدها تحتها. server { listen 80; root /var/www/; index index.php index.html index.htm; server_name example.com; location / { try_files $uri $uri/ /index.php; } location ~ \.php$ { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header Host $host; proxy_pass http://127.0.0.1:8080; } location ~ /\.ht { deny all; } }هذه هي التغييرات التي تم عملها على الإعدادات: مسار الجذر تم تغييره إلى مسار الويب الحالي. ملف index.php تم إضافته إلى سطر الفهرس. دالة try_files ستحاول القيام بتخديم الزوار مهما كانت الصفحات التي يطلبونها. إذا كان nginx غير قادرٍ على فعل ذلك، حينها يتم إرسال الملف إلى الوسيط (proxy). دالة proxy_pass تسمح لـ nginx أن يتعرف على مسار الخادوم الوسيط. "location ~ /\.ht {" تمنع الموقع من الوصول إلى جميع ملفات .htaccess إذا كان مسار الجذر الخاص بـ Apache يتعارض مع ذاك الخاص بـnginx. هذه الإعدادات تقوم بإعداد نظامٍ صغير حيث يتم توجيه جميع الملفات التي نهايتها .php إلى خادوم apache ليعالجها بالخلفية والذي سيعمل على المنفذ 8080. لتفعيل المضيف الوهمي: sudo ln -s /etc/nginx/sites-available/example /etc/nginx/sites-enabled/exampleبالإضافة إلى ذلك، علينا حذف إعداد nginx الافتراضي: sudo rm /etc/nginx/sites-enabled/defaultالخطوة التالية ستكون تثبيت وإعداد apache. تثبيت Apacheبعد أنّ انتهينا من nginx، حان الوقت لتثبيت واجهة موقعنا الخلفية، apache: sudo apt-get install apache2بما أنه لم يتم تشغيل nginx بعد، فإنّ Apache سيعمل المنفذ 80. إعداد Apacheسنحتاج إلى إعداد apache لجعله يدير الواجهة الخلفية لموقعنا، والذي كما قلنا سابقًا، سيعمل على المنفذ 8080. افتح ملف منافذ apache للبدأ في إعداده ليستخدم المنفذ الصحيح عبر الأمر: sudo nano /etc/apache2/ports.confابحث وغيّر السطور التّالية لجعل apache يعمل على المنفذ 8080 والقابل للوصول من المضيف المحلي (localhost) فقط: NameVirtualHost 127.0.0.1:8080 Listen 127.0.0.1:8080احفظ الملف واخرج. بعد ذلك قمّ بإنشاء ملف مضيف وهمي عبر نسخ تخطيط الملف من ملف apache الافتراضي عبر الأمر: sudo cp /etc/apache2/sites-available/default /etc/apache2/sites-available/example sudo nano /etc/apache2/sites-available/exampleالمشكلة الرئيسية التي يجب حلّها هنا هي أنه يجب أن يتم إعادة ضبط المضيف الوهمي مُجدّدًا لكي يعمل على المنفذ 8080 (عوضًا عن المنفذ الافتراضي الذي هو 80 والذي يعمل عليه nginx). يجب أن يبدو السطر المطلوب هكذا: <VirtualHost 127.0.0.1:8080>تأكّد من أن مسار الجذر صحيح. احفظ الملف واخرج منه وقم بتفعيل المضيف الوهمي: sudo a2ensite exampleقبل البدء باختبار الأشياء، نحتاج إلى دعم apache بملحق php. ثبّته عبر الأمر: sudo apt-get install php5قم بإعادة تشغيل كلٍ من الخادومين للتأكد من عمل التغييرات: sudo service apache2 restart sudo service nginx restartإنهاء العمليّةلقد قمنا بإعداد خادومنا الشخصي الوهمي الخاص (VPS) ليتم تشغيل nginx في واجهة موقعنا وapache ليعالج الطلبات المتعلقة بـ php في الخلفية. الذهاب إلى نطاقنا الرئيسي (domain) الآن سيأخذنا إلى الصفحة الافتراضية لموقعنا. يمكننا التحقق مما إذا كان يتم توجيه المعلومات إلى apache عبر تشغيل سكربت PHP شائع الاستخدام. اذهب وأنشء ملف php.info عبر: sudo nano /var/www/info.phpوالصق الشفرة التالية داخله: <? phpinfo( ); ?>احفظ الملف واخرج. زيارة domain/info.php الخاص بك يجب أن يعرض لك شاشة معلومات php، وسيكون بمقدورك رؤية أنه قد تم معالجة الطلب بواسطة apache أخيرًا، يمكنك رؤية أيٍّ من المنافذ مفتوح وأيّ التطبيقات التي تعمل على كلّ واحدٍ منها عبر كتابة هذا الأمر: sudo netstat -pluntترجمة -وبتصرّف- للمقال How To Configure Nginx as a Reverse Proxy for Apache لصاحبته Etel Sverdlov1 نقطة
-
مع أنه لا يلزم التعارف عبر المنصة أي تحريم لأي علاقة خارجها ، إلا أن الأمر له منحى آخر ، فلا يؤمن أحدكم حتى يحب لأخيه ما يحب لنفسه ، وعامل الناس كما تحب أن يعاملوك ، فالأمر سيكون له أذى معنوي ، طبق الأمر على نفسك ، لو أنك تعمل كوسيط بالعمولة بين زبون و مخدم ، ثم عرفت بعد ذلك أن المخدم تواصل مع الزبون ليتخلص من العمولة ، هل سيكون الأمر طبيعياً لك ، أم أنك ستجد في نفسك كثيراً على المخدم وربما على الزبون ولكن بدرجة أخف ، لهذا الأمر من الناحية الشرعية لا يوجد ما يحرم ذلك ، إلا من باب عدم أذية الآخرين ، لكن الأمر متعلق بأخلاقيات العمل. خذ هذه القصة حصلت معي شخصياً : أحد زملاء المهنة المستقلين اضطر للسفر ، فأوكلني بمتابعة زبائنه خلال فترة غيابه ، فتعرفت على بعضهم وسيرت له الأمور ، بعد مدة من الزمان ، جاء شخص وذكر لي أن لديه زبون من طرفه وطلب مني أن أنتفع منهم ، طبعاً هو لا يريد عمولة هو فقط فاعل خير ، لأكتشف أن الزبون الجديد ، هو أحد زبائن صاحبي ، أي أن الزبون وصلني من طريق لا علاقة لصاحبي به. فما استطعت إلا أن اتصل بصاحبي وذكرت له القصة ليس استسماحاً لتخديم الزبون ، إذ أني رفضت تخديم الزبون ابتداءً مراعاة لشعور صاحبي ، فقال لي انتفع منه واعتبره زبونك بكل رحابة صدر وطيب خاطر ، فقلت له لا ، لن أقدم له خدمة إلا في حال انقطعت علاقتكم مع بعض وتوقف التعامل . الشاهد : تخيل السيناريو الآخر ، أني قدمت الخدمة دون علمه ، ثم عرف ، ألن يجد في نفسه ، وينشر بين الناس أني خنته وسرقت زبونه ، مع أني لم أفعل. وعليه أنصح إن كان ولا بد من التعامل المباشر ، أن يتم بعلم إدارة المنصة وقبولهم بذلك ، لأنهم ربما لو علموا بالأمر وخصوصاً إن كانت شروط الاستخدام تنص على ذلك ، فإن النتائج قد تكون مضرة بكما ، فتكسب زبون وتوفر عمولة بينما تخسر كل الزبائن الجدد .1 نقطة
-
هناك اعتقاد خاطئ بين العديد من مطوّري الويب أن CSS هي الطريقة الوحيدة للقيام بالتحريك Animations. برزت CSS بقوة كأكثر نظام مُدلّل خلال سنوات وحتى الآن، وتحدّث المطوّرون باستمرار حول متانتها وتوافقها مع الهواتف. CSS جيدة لكنها ليست أفضل من جافاسكربت. هناك بعض الأساطير حول CSS قادت المطوّرين بشكل استباقي لتبنّي هذا النظام (أي CSS) والتخلي عن كلٍّ من جافاسكربت والتحريك الخاصّ بها. ما يحيّر المطوّرين هو الاستخدام الفعّال لـ CSS، فبينما يقومون بإدارة التفاعل بين العناصر من داخل CSS، يُجبرون أنفسهم أيضًا على جعل مشروعهم متوافقًا مع Internet Explorer 8 و 9، وأخيرًا، يتجنّبون التحريك الجاهز الذي لا يتوفر إلا عن طريق جافاسكربت. يهدف هذا المقال لدحض بعض الأساطير حول CSS وكشف جميع المشكلات الأساسية التي بالكاد يتحدث الناس عنها بسبب إعجابهم بـ CSS. يهدف المقال إلى رفع معرفتك ووعيك بفوائد استخدام جافاسكربت، حتى يمكنك بسهولة التخلص من المواقف التي تثير غضبك. لذا، دون مزيد من الإطالة دعونا نتناقش حول كل منهم بالتفصيل. 1. jQueryدعونا نبدأ بالأساسيات، يتم الربط بين جافاسكربت ومكتبة jQuery بشكل خاطئ . فالتحريك المُصمَّم بجافاسكربت سريع ومرن، بينما المُصمَّم بـ jQuery بطيء. السبب أنه -وبرغم مواصفات jQuery القوية- إلّا أنها لم تهدف بشكل رئيسي لتنفيذ التحريك. هناك العديد من الأسباب لدعم هذا: لا يمكن لمكتبة jQuery ببساطة أن تتوقف عن تحطيم التنسيق (layout thrashing) نظرًا لهيكلتها البرمجية التي تخدم عددًا من الأغراض غير التحريك. هذا بشكل عام يسبب تقطّعًا في المراحل الأولى من التحريك.الذاكرة التي تستهلكها jQuery دومًا تُحفّز جمع القمامة (Garbage Collection) مما يؤدي إلى تجمّد التحريك. ونظرًا لـ جمع القمامة، يمكن للمرء أن يواجه تقطّعًا أثناء التحريك.تم تصميم jQuery لتستخدم set_interval() وليس طلب إطار الحركة (Request Animation Frame - RAF). عندما لا يكون طلب إطار الحركة موجودًا فيمكن أن ينتج عن ذلك تحريكات بعدد إطارات منخفض (جودة ودقة الحركة تعتمد على عدد الإطارات التي تظهر في الثانية، العدد المثالي هو 60 إطار في الثانية).2. فقر التحكم بالتدوير وتحديد الموقعمن الميزات الأساسية الضرورية أثناء تنفيذ التحريك استخدام المُتحكّمات لـ: التحريك animation، التدوير rotation، وتحديد المواقع positioning. في CSS، تم تكديس جميع هذه الدوالّ في خاصية معروفة هي tranform. هذه الخاصية تُسبب مشاكل عند تحريك شيء ما بطريقة فريدة عن طريق عنصر مشترك. على سبيل المثال، إن أردت تحريك “التدوير” rotation و”التكبير” scaling بشكل منفصل، وباستخدام أزمنة مختلفة، فهذا مُمكن فقط عن طريق جافاسكربت ﻷنها تُمكّنك من استخدام حِيل متنوعة، وهذه غير مسموحة في CSS. هذه إحدى مساوئ CSS. هي جيدة من أجل مشاريع تتطلب تحريكاتٍ بسيطة وليس من أجل المشاريع التي تتطلب اندماج تصميمٍ بتحريكاتٍ كبيرة. 3. الأداء مع مكتبتيّ Velocity وGSAPVelocity وGSAP هما المكتبتان الرائدتان والأكثر شعبية في جافاسكربت. كلاهما يعمل مع jQuery أو بدونها. عندما يتم استخدام أيّ من هاتين المكتبتين جنبًا إلى جنب مع jQuery فلا يحدث أي تدهورأو تباطؤ في الأداء لأنهما تعملان بشكل منفصل عن تحريكات jQuery الأساسية. ويمكن أيضًا استخدام هاتين المكتبتين بسهولة عندما لا تكون مكتبة jQuery موجودة في الصفحة. وهذا يبين بوضوح أنه بدلًا من ربط جميع أنواع استدعاءات التحريك في عنصر jQuery مشترك يمكنك بشكل مباشر تمرير العنصر المراد إلى استدعاء الحركة كما هو مبين أدناه. /* Working without jQuery */ Velocity(element, { opacity: 0.4 }, 900); // Velocity TweenMax.to(element, 1, { opacity: 0.4 }); // GSAP في المثال السابق، يمكنك ملاحظة أن Velocity تستخدم نفس الصيغة حتى عندما لا يتم استخدام jQuery. قامت فقط بإزاحة جميع العناصر تجاه اليمين لترك مساحة للعناصر المستهدفة. بالمقابل، في GSAP تم استخدام تصميم كائني التوجه (عن طريق استدعاء كائن يمثّل صنف Class) جنبًا إلى جنب مع دالّة بسيطة ثابتة. بهذه الطريقة المستخدم يملك تحكم كامل بعملية الحركة. 4. معامل وحدة معالجة الرسوم (GPU)عندما تكون وحدة معالجة رسوم GPU مُحسّنة بشكل كامل، عندها ستكون عظيمة لأداء مهام متنوعة كالتعامل مع مصفوفات التحويل transform والشفافية opacity، لهذا السبب أول ما تفعله جميع المتصفحات المتطورة هو تفريغ هذه المهام من وحدة المعالجة المركزية CPU إلى وحدة معالجة الرسوم GPU. الهدف الأساسي هو فصل جميع العناصر المتحركة إلى طبقات خاصة بها في وحدة معالجة الرسوم ﻷنه فور انتهاء النظام من إنشاء طبقات وحدة معالجة الرسوم لا يُظهر النظام أي اهتمام بتحريك البكسلات وجمعهم معًا. لهذا لا يوجد حاجة بتاتًا لحساب كل بكسل بشكل مستمر. بدلًا من ذلك يمكن تحريك بكسل واحد فوق الآخر وتوفير كثير من الوقت. ملاحظة: لا حاجة لإعطاء كل عنصر طبقته الخاصة نظرًا لذاكرة الفيديو المحدودة في وحدة معالجة الرسوم. فإذا نفدت الذاكرة سيفسد كل شيء. من ناحية أخرى، إذا قمتَ بتعريف التحريك في CSS عندئذ ستكون مهمة المتصفح أن يحدد طبقة وحدة معالجة الرسوم لكل عنصر وسيحصل انقسام بسبب ذلك. مع ذلك، يمكنك عمل هذا الأمر عن طريق جافاسكربت أيضًا. كل ما تحتاجه هو تحديد التحويل transform مع خاصية 3D (تمامًا مثل translate3d() و matrix3d()) لجعل المُتصفح يعلم عن عملية إنشاء طبقات وحدة معالجة الرسوم للعنصر المستهدف. لذا، فمن الواضح أن وحدة معالجة الرسوم لا توفّر زيادة السرعة لـ CSS فقط بل لجافاسكربت أيضًا. 5. قوة تحريك جافاسكربتلدى جافاسكربت كل الإمكانيات للفوز بمقارنة الأداء مع CSS. جافاسكربت هي أسرع. لكن إلى أي حدّ يمكن أن تكون أسرع؟ بدايةً هي مرنة بما فيه الكفاية لإنشاء عرض تحريك ثلاثيّ الأبعاد 3D ملفت للنظر، الذي يمكن أن تراه عبر WebGL. وجافاسكربت سريعة بشكلٍ كافٍ لبناء دعاية وسائط متعددة، والتي كان من الممكن تطويرها باستخدام Flash أو After Effects. وبالتأكيد بناء عالم افتراضي باستخدام جافاسكربت بمساعدة Canvas. بقدر ما تكون مكتبات التحريك هي المعنية في هذا المقال، فإن الحديث الآن عن توثيق مكتبتيّ Transit و Velocity غير مبرر على الإطلاق. لمزيد من التوضيح لهذه النقطة، قمنا بطرح قائمة تحسينات يمكن فقط للتحريك المبنيّ بجافاسكربت أن يؤديها: مزامنة DOMالتخزين المؤقت للخصائص عبر سلسلة من الاستدعاءات، للتخفيف من استعلامات DOMالتخزين المؤقت لنسب تحويل الواحداتخلاصةنجد بوضوح كيف أن النقاط المذكورة أعلاه تسلط الضوء على براعة التحريك المبنيّ على جافاسكربت بالمقارنة مع المبنيّ على CSS. ولكن هل هذا يعني أن تحريك CSS “سيّء”؟ بالتأكيد لا. هو جيّد لأداء تحريك بسيط. لكن لمرونة وقدرات فريدة أعلى، يجب أن تأخذ جافاسكربت بعين الاعتبار. ترجمة -وبتصرفّ- للمقال CSS Vs JavaScript Myths Fall to Pieces1 نقطة