سارة محمد2

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

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

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

  • Days Won

    2

السُّمعة بالموقع

10 جيدة
  1. أصبحت لغة Go -التي هي لغة برمجية عاميّة الغرض- واحدةً من لغات البرمجة الأكثر شعبيةً لتطوير الواجهة الخلفية. بالتركيز على البساطة، فإنَّ مصممي لغة Go ابتكروا لغةً سهلة التعلّم وأسرع من العديد من اللغات الأخرى لتطبيقات الويب، مستفيدين من الميزات الفعّالة مثل قدرتها على التعامل مع عدة طلبات في وقت واحد بسبب تزامنها. لهذا السبب، سيكون نشر تطبيق ويب بلغة Go مفيدًا للعديد من مطوري الواجهة الخلفية. Nginx هو أحد أشهر خوادم الويب في العالم نظرًا لاستخدامه الخفيف للموارد وموثوقيته في حال وجود حمل زائد. تعتمد العديد من المواقع الضخمة والأكثر زيارةً على Nginx لتقدّم محتواها. في النشر، غالبًا ما يُستخدم Nginx موازن حمل(load balancer) أو وكيل عكسي (reverse proxy) لزيادة الأمان وجعل التطبيق أكثر قوة. بالتزامن مع لغة Go لتطوير الواجهة الخلفية في الويب، يمكن لخادم Nginx تقديم تطبيق ويب سريع وقوي. ستتعلم في هذا الدرس كيفية بناء تطبيق ويب Hello World بلغة Go وننشره على خادم أوبنتو 18.04 مستخدمين Nginx كخادم عكسي. المتطلبات الأساسية لمتابعة هذا الدرس، ستحتاج إلى ما يلي: خادم أوبنتو 18.04 تم ضبطه باتباع التهيئة الأولية لخادم أوبنتو 18.04، متضمنًا مستخدمًا عاديًا بصلاحيات sudo وجدار حماية. يجب أن تكون لغة Go مثبّتة على حاسوبك. خادم Nginx مثبّت باتّباع الدرس كيف تثبّت خادم Nginx على أوبنتو 18.04. لا تتبع الخطوة 5 - إعداد كتل الخادم؛ ستنشئ كتلة خادم Nginx لاحقًا في هذا الدرس. اسم نطاق يشير إلى خادمك. سنستخدم your_domain في هذا الدرس. هذا ضروري للحصول على شهادة SSL لموقعك، حتى يمكنك أن تقدّم تطبيقك بأمان مع تشفير TLS. بالإضافة إلى ذلك، لتحقيق نشر بدرجة الإنتاج لتطبيق الويب Go، من المهم أن تحافظ على خادمك آمنًا بتثبيت شهادة TLS/SSL. أرشح لك هذه الخطوة بشدة. لتؤمّن تطبيق الويب Go، اتّبع كيف تؤمّن خادم Nginx بشهادة Let's Encrypt على أوبنتو بعد الخطوة 3 من هذا الدرس لتحصل على شهادة TLS/SSL مجانية. الخطوة 1: بناء تطبيق ويب بلغة البرمجة Go في هذه الخطوة، ستبني نموذج تطبيق ويب بلغة Go يعرض عبارة Hello World على نطاقك your_domain ويقوم بتحيّة المستخدم على الرابط your_domain/greet/. إذا كنت تريد تعلّم المزيد من أساسيات البرمجة في Go، تفحّص مقالتنا كيف تكتب برنامجك الأول بلغة Go. بدايةً، أنشئ مجلد جديد في مجلد GOPATH ليتضمن الملف المصدري. يمكنك تسمية المجلد بأي اسم تريده، ولكن في هذا الدرس سنستخدم اسم go-web: $ mkdir $GOPATH/go-web باتّباع بنية الملف المقترحة في درس فهم، تنصيب وتهيئة بيئة عمل لغة البرمجة Go، سيعطي هذا مجلدك المسار ‎~/go/go-web: بعد ذلك، نفّذ التعليمة التالية لتغيّر المجلد إلى مجلدك الذي أنشأته حديثًا في GOPATH: $ cd $GOPATH/go-web استخدم محرر النصوص nano أو المحرر المفضل لك لإنشاء ملف باسم main.go، والذي سيتضمن الشيفرة المصدرية لتطبيقك الويب: $ nano main.go لإنشاء وظيفة التطبيق Hello World، أضف شيفرة Go التالية إلى ملف main.go المنشأ حديثًا: package main import ( "fmt" "net/http" ) func main() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello World") }) http.HandleFunc("/greet/", func(w http.ResponseWriter, r *http.Request) { name := r.URL.Path[len("/greet/"):] fmt.Fprintf(w, "Hello %s\n", name) }) http.ListenAndServe(":9990", nil) } لنتعرّف الآن على ما سيفعله جزء الشيفرة السابق، بدءًا من السطر الأول. كتبت أولًا نقطة الدخول إلى تطبيقك: package main … تخبر تعليمة package main مُصرِّف Go أن يصرّف هذا الملف على أنّه برنامجٌ تنفيذي بدلًا من أن يكون مكتبة مشتركة (shared library). ثمّ لديك تعليمات import: … import ( "fmt" "net/http" ) … يستورد هذا الجزء الوحدات الضرورية لعمل هذه الشيفرة، والتي تشمل حزمة fmt القياسية وحزمة net/http لخادم الويب الخاص بك. يُنشئ الجزء التالي مسارك الأول في الدالة main والتي هي نقطة الدخول لأي تطبيق Go: … func main () { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello World") }) … } … أنشئ المسار الأب / ضمن الدالة func main، التي ستعيد النص Hello World عندما تُطلب. كما هو موضح في الجزء التالي فإنّ المسار الثاني يقبل معاملًا في الرابط (URL parameter)، في هذه الحالة اسمًا، لعرضه مصحوبًا بالتحية. … func main () { … http.HandleFunc("/greet/", func(w http.ResponseWriter, r *http.Request) { name := r.URL.Path[len("/greet/"):] fmt.Fprintf(w, "Hello %s\n", name) }) … } … يستخدم هذا URL.Path الخاص بلغة Go لتخزين القيمة مباشرةً بعد /greet/ وتمريرها كاسم من معامل الرابط. أخيرًا، هيّئ الخادم: … func main () { … http.ListenAndServe(":9990", nil) } يشغّل الجزء السابق الخادم ويعرض تطبيقك عبر المنفذ 9990 باستخدام خادم http المدمج بلغة Go. احفظ الملف وأغلق المحرر النصي بمجرد الانتهاء من فحص الشيفرة في main.go. بعد ذلك، ابنِ الملف الثنائي القابل للتنفيذ لتطبيقك باستخدام الأمر: $ go build main.go التعليمة السابقة ستصرِّف الملف main.go لإنتاج ملف قابل للتنفيذ باسم main. لقد أنشأت نموذج تطبيق ويب بلغة Go. بعد ذلك، ستنشئ ملف وحدة systemd ليبقى تطبيقك شغّالًا في الخلفية حتى عندما لا تصل إلى خادمك. الخطوة 2: إنشاء ملف وحدة Systemd في هذه الخطوة، ستنشئ ملف وحدة systemd ليبقى تطبيقك شغّالًا في الخلفية حتى عندما يسجّل المستخدم خروجه من الخادم. سيجعل هذا تطبيقك ثابتًا، مما يجعلك أقرب بخطوة للنشر على مستوى الإنتاج. بدايةً، أنشئ ملفًا جديدًا في مجلد ‎/lib/systemd/system باسم goweb.service باستخدام محرر النصوص nano أو محرر النصوص المفضّل لك: $ sudo nano /lib/systemd/system/goweb.service لضبط معاملات الخدمة، أضف الجزء التالي في الملف. [Unit] Description=goweb [Service] Type=simple Restart=always RestartSec=5s ExecStart=/home/user/go/go-web/main [Install] WantedBy=multi-user.target يحدّد المتغير ExecStart=/home/user/go/go-web/main أنَّ نقطة الدخول لهذه الخدمة عبر الملف main القابل للتنفيذ الموجود في المجلد ‎/home/user/go/go-web، إذ user هو اسم المستخدم لحساب المستخدم العادي الذي يملك صلاحيات sudo على الخادم. Restart=always تضمن أنَّ systemd سيحاول دائمًا أن يعيد تشغيل البرنامج إذا توقف. في السطر التالي، RestartSec=5s يضبط وقت انتظار لخمس ثوانٍ بين محاولات إعادة التشغيل. يحدِّد WantedBy=multi-user.target في أي حالة سيفعّل الخادم الخدمة. احفظ وأغلق الملف. بعد أن كتبت ملف وحدة الخدمة، شغّل خدمة الويب Go باستخدام الأمر: $ sudo service goweb start للتأكّد فيما إذا كانت الخدمة شغّالة، استخدم الأمر التالي: $ sudo service goweb status ستستقبل الخرج التالي: Output ● goweb.service - goweb Loaded: loaded (/lib/systemd/system/goweb.service; disabled; vendor preset: enabled) Active: active (running) since Wed 2019-07-17 23:28:57 UTC; 6s ago Main PID: 1891 (main) Tasks: 4 (limit: 1152) CGroup: /system.slice/goweb.service └─1891 /home/user/go/go-web/main لتتعلم المزيد عن العمل مع ملف وحدة systemd، ألقِ نظرة على فهم وحدات وملفات وحدة Systemd. الآن بعد أن أصبح لديك تطبيقًا شغّالًا، يمكنك ضبط الوكيل العكسي Nginx. الخطوة 3: ضبط وكيل عكسي مع Nginx ستنشئ في هذه الخطوة كتلة خادم Nginx وستضبط الوكيل العكسي Nginx لتعرض تطبيقك على الإنترنت. أولًا، غيّر مجلد العمل الخاص بك إلى مجلد sites-available على الخادم Nginx: $ cd /etc/nginx/sites-available أنشئ ملفًا جديدًا باسم النطاق الذي تريد عرض تطبيقك عليه. سيستخدم هذا الدرس الملف your_domain: $ sudo nano your_domain أضف الأسطر التالية إلى الملف لوضع الإعدادات لـ your_domain: server { server_name your_domain www.your_domain; location / { proxy_pass http://localhost:9990; } } كتلة الخادم Nginx تستخدم proxy_pass لتقديم تطبيق الويب Go على عنوان IP لخادمك المشار إليه على أنّه مضيف محلي localhost لتشغيله على المنفذ 9990 . يشير server_name إلى اسم النطاق المعيّن لعنوان IP الخاص بك، في هذه الحالة your_domain وwww.your_domain. بعد ذلك، أنشئ رابطًا رمزيًا لإعدادات Nginx هذه في مجلد sites-enabled بتشغيل الأمر التالي: $ sudo ln -s /etc/nginx/sites-available/your_domain /etc/nginx/sites-enabled/your_domain الرابط الرمزي هو اختصار لملف في موقع آخر. يشير الاختصار المُنشأ حديثًا إلى الملف الأصلي للتكيّف مع التحديثات عند إجراء التعديلات عليه. يتطلب Nginx نسخة من الإعدادات في كلا المجلدين. بعدها، أعد تحميل إعدادات Nginx بتشغيل تعليمة إعادة التحميل: $ sudo nginx -s reload لتتأكد أن نشرك يعمل، قم بزيارة http://your_domain في متصفحك، إذ ستتم تحيتك بسلسلة نصية Hello World. ملاحظة: كما ذُكر في قسم المتطلبات الأساسية، يُنصح في هذه النقطة أن يتم تفعيل SSL/TLS على خادمك. سيضمن ذلك تشفير جميع الاتصالات بين التطبيق وزوّاره، وهو أمر مهم بشكلٍ خاص إذا طلب التطبيق معلومات حساسة مثل تسجيل الدخول أو كلمة المرور. اتّبع الآن درس كيف تؤمّن خادم Nginx بشهادة Let's Encrypt على أوبنتو لتحصل على شهادة SSL مجانية لخادم Nginx على أوبنتو 18.04. بعد أن تحصل على شهادات SSL/TLS خاصة بك، عُد وأكمل هذا الدرس. ضبطت الآن الوكيل العكسي Nginx لتعرض تطبيقك على اسم النطاق الخاص بك، وقمت بتأمين تطبيق الويب Go مع SSL/TLS. في الخطوة التالية، ستختبر تطبيقك عبر اتصالٍ آمن. الخطوة 4: اختبار التطبيق في هذه الخطوة، ستختبر تطبيقك عبر اتصالٍ آمن لتتأكد من أنَّ كل شيء يعمل. افتح متصفح الويب المفضل لك، وقم بزيارة https://your_domain: ستستقبل رسالة Hello World بسيطة. استقبال هذه الرسالة عند استخدام https://‎ في الرابط يشير إلى أنَّ التطبيق يُعرض عبر اتصالٍ آمن. بعد ذلك، حاول زيارة المسار الثاني https://your_domain/greet/your-name مستبدلًا بالعبارة your-name أيّ اسم آخر تريد أن يلقي عليه تطبيقك التحيّة: سيعيد التطبيق تحيّة بسيطة مع your-name، الذي يعتمد على المعامل الممرّر للرابط. حالما تستقبل هذه النتائج، تكون قد نشرت تطبيق ويب Go بنجاح. خاتمة في هذا الدرس، أنشأت تطبيق ويب بسيط بلغة Go مستخدمًا مكاتبها القياسية، وقمت بضبط وكيل عكسي مستخدمًا Nginx، واستخدمت شهادة SSL على نطاقك لتأمين تطبيقك. لتتعلّم المزيد حول Go، تفحّص توثيقها الرسمي. بإمكانك أيضًا أن تلقي نظرة على قسم لغة GO لتتعلم المزيد حول البرمجة بهذه اللغة الفعالة. ترجمة -وبتصرف- للمقال How To Deploy a Go Web Application Using Nginx on Ubuntu 18.04 لصاحبه Michael Okoh
  2. كتبت قبل بضع سنوات عن المراجعات التقنية المستقلة التي يجب أن يمر بها أي مشروع برمجي بشكل منتظم للتأكد من أنَّ كل شيء تحت السيطرة. ونوّهت مؤخرًا أنه لا يوجد عذر لعدم القيام بها. بالإضافة إلى ذلك، كلما زادت ثقتنا بالمبرمجين، زادت حاجتنا إلى مراجعة مشاريعهم بانتظام. فيما يلي ملخص بسيط لما يجب أن يتضمنه تقرير المراجع. حاولت أن أتطرق إلى هذا الموضوع في بضعة محادثات مؤخرًا مثل: اجعل العملاء يثقون بك في BDMSummit 2017، كيف تكون صادقًا وتحافظ على العميل في PMCon Kharkiv 2017، كيفية تجنب كارثة الاستعانة بمصادر خارجية في Kyiv Outsourcing Forum 2017. وأيضًا، هناك عدد من منشورات المدونة على نفس المنوال، بما في ذلك الأخطاء السبع القاتلة لمشروع برمجيات، وكيفية تجنب كارثة الاستعانة بمصادر خارجية للبرامج، وكيف تنجو من الاستعانة بمصادر خارجية للبرامج. أخيرًا، فيما يلي قائمة كاملة تقريبًا من الأشياء التي يجب أن يتضمنها التقرير الجيد. بشكل أساسي هي قائمة بالأسئلة التي يجب على المُراجع الإجابة عليها. عندما يتم جمع كل الإجابات، يكون التقرير جاهزًا. أهم الأسئلة تمَّ طرحها أوّلاً: هل إجراء الإصدار موثَّق، وآلي، وهل يعمل؟ هل الإصدارات تتجدد بشكل منتظم، على الأقل مرة أسبوعيًا؟ ما حجم الديون التقنية (الأشياء التي يجب إصلاحها "لاحقًا")؟ هل خط التسليم موثوقًا بما يكفي لاستبعاد الأخطاء؟ هل الشيفرة نظيفة؟ كم عدد النماذج المضادّة التي تظهر؟ هل تمَّ تسجيل جميع الأخطاء والميزات كملاحظات؟ هل تم تغطية الشيفرة الأساسية بوحدات اختبار، وهل التغطية مرئية؟ هل تم توقيع اتفاقيات "العمل من أجل التوظيف" مع جميع المطورين؟ هل تم توثيق القرارات التقنية الهيكلية الرئيسية؟ هل التحليل الثابت موضع التنفيذ ومُلزَم لإجراء تغييرات جديدة؟ هل التكاملات المستمرة موضع التنفيذ، وهل تؤخذ تقاريرها في الحسبان؟ هل الفرع الرئيسي (master branch) للقراءة فقط؟ هل يتم جمع المقاييس البرمجية ومراجعتها بانتظام؟ هل مستودع الشيفرة المصدرية يخضع لملكية العميل؟ هل متطلبات التوثيق قصيرة ومحدَّثة؟ هل تحتوي الفئات والطرق والتوابع الرئيسية على توثيق مضمَّن في الشيفرة؟ هل مخلفات مستودع الشيفرة المصدرية مجانية؟ هل تم توثيق واجهات UI/UX؟ هل سجلات الإنتاج مرئية وتتم مراجعتها بانتظام؟ ما مدى استجابة الفريق للملاحظات؟ هل لدى Git تاريخ واضح للتغيرات الموثَّقة؟ بشكلٍ أساسي، هذا تجميع قصير جدًا لأهم الأشياء التي يمكنك العثور عليها في CMMI. إنها تتطلب كل هذا، بالإضافة لقائمة كبيرة من الأشياء الأخرى موجودة في الأعلى. لكن المشروع الصغير لا يحتاج إلى جميع الأسئلة المذكورة. قائمتي أقصر، وأنا متأكد من أنها ستكون كافية لمعظم القرَّاء. بكل الأحوال، يمكنك مشاهدة التقارير التي يقوم المتطوعون بإنشائها للمشاركين في جائزة جودة البرمجيات، إذ يقومون بتحليل المشاريع مفتوحة المصدر والإبلاغ بشكلٍ مختصر عن المشكلات التي يجدونها. أعتقد أنهم يحاولون الإجابة عن نفس مجموعة الأسئلة السابقة تمامًا. ترجمة -وبتصرف- للمقال Software Project Review Checklist لصاحبه Yegor Bugayenko
  3. الواجهة البرمجية Promise رائعة ويمكنك جعلها مذهلة باستخدام async و await. إنّ الشيفرة المتزامنة سهلة التتبع والتنقيح إلا أنّ الشيفرة غير المتزامنة أفضل بشكل عام من حيث الأداء والمرونة، فلماذا "توقف العرض" بينما بإمكانك استقبال الكثير من الطلبات في وقت واحد ثمّ معالجة كلٍّ منها عندما يصبح جاهزًا؟ مع العديد من الواجهات البرمجية API الجديدة التي تم تحقيقها مع مبدأ الوعد، إذ أصبحت الوعود جزءًا كبيرًا في عالم الجافاسكربت. لنلقِ نظرة على كيفية استخدام الواجهة البرمجية للوعود. الوعود قيد التطبيق الواجهة البرمجية XMLHttpRequest غير متزامنة ولكنها لا تستخدم الواجهة البرمجية Promises. هناك عدة واجهات برمجية أصلية تستخدم الوعود الآن، مثل: Battery API. fetch API (بديل XHR) الواجهة البرمجية ServiceWorker ستصبح الوعود أكثر شيوعًا، لذا من المهم أن يعتاد عليها جميع مطوري الواجهات الأمامية، وتجدر الإشارة إلى أنّ Node.js هي منصة أخرى للوعود. (يبدو هذا واضحًا، كما الواجهة البرمجية Promise ميزة أساسية في اللغة). من المحتمل أن يكون اختبار الوعود أسهل مما تعتقد لأنه يمكنك استخدام setTimeout كـ "مهمة" لك غير متزامنة. استخدام Promise الأساسي يجب أن يستخدم الباني new Promise()‎ فقط للمهام الغير متزامنة الموروثة، مثل استخدام setTimeout أو XMLHttpRequest. يتم إنشاء وعدًا جديدًا باستخدام الكلمة المفتاحية new ويتم تمرير توابع resolve و reject لردّ النداء المزوَّد: var p = new Promise(function(resolve, reject) { // ...القيام بمهمة غير متزامنة وثم if(/* شرط جيد */) { resolve('Success!'); } else { reject('Failure!'); } }); p.then(function(result) { /* القيام بفعل ما مع النتيجة */ }).catch(function() { /* خطأ :( */ }).finally(function() { /* تنفّذ بغض النظر عن النجاح أو الفشل */ }); يعود الأمر للمطور فيما إذا كان يريد استدعاء resolve أو reject يدويًا ضمن جسم رد النداء اعتمادًا على نتيجة المهمة المعطاة. مثال واقعي لتحويل XMLHttpRequest إلى مهمة تعتمد على الوعد: // من وعود جاك أرشيبالد والعودة // http://www.html5rocks.com/en/tutorials/es6/promises/#toc-promisifying-xmlhttprequest function get(url) { //إعادة وعد جديد. return new Promise(function(resolve, reject) { // XHR القيام بالعمل الاعتيادي لـ var req = new XMLHttpRequest(); req.open('GET', url); req.onload = function() { // هذا يتم استدعاؤه حتى في حالة 404 // لذا اختبر الحالة if (req.status == 200) { // قم بإنهاء الوعد مع نص الرد resolve(req.response); } else { // وإلا ارفض مع نص الحالة // والذي نأمل أن يكون خطأ ذو معنى reject(Error(req.statusText)); } }; // معالجة أخطاء الشبكة req.onerror = function() { reject(Error("Network Error")); }; // القيام بالطلب req.send(); }); } // استخدمه! get('story.json').then(function(response) { console.log("Success!", response); }, function(error) { console.error("Failed!", error); }); إذا كان من الممكن اتخاذ إجراء غير متزامن قد لا تحتاج إلى إكمال المهام غير المتزامنة ضمن الوعد، لكن سيكون الأفضل هو أن تكون القيمة المعادة وعدًا لذا يمكنك أن تعدّ كم عدد الوعود التي حصلت عليها من تابع معطى. في تلك الحالة يمكنك ببساطة استدعاء Promise.resolve()‎ أو Promise.reject()‎ بدون استخدام الكلمة المفتاحية new. مثلًا: var userCache = {}; function getUserDetail(username) { // في كلتا الحالتين، تم إضافته إلى الذاكرة أو لا، سيتم إعادة وعد if (userCache[username]) { // new إعادة وعد بدون الكلمة المفتاحية return Promise.resolve(userCache[username]); } // لتحصل على المعلومات fetch استخدم الواجهة البرمجية // وعدًا fetch تعيد return fetch('users/' + username + '.json') .then(function(result) { userCache[username] = result; return result; }) .catch(function() { throw new Error('Could not find user: ' + username); }); } بما أن القيمة المعادة هي وعد لذا يمكنك استخدام التوابع then و catch عليها. then كل كائنات الوعد تملك التابع then الذي يسمح لك بالتفاعل مع الوعد. رد النداء الأول لتابع then يستدعي النتيجة المعطاة له عن طريق استدعاء ()resolve: new Promise(function(resolve, reject) { // setTimeout حدث زائف غير متزامن باستخدام setTimeout(function() { resolve(10); }, 3000); }) .then(function(result) { console.log(result); }); // console من الطرفية // 10 رد النداء لـ then يتم تشغيله عندما ينتهي الوعد. يمكنك أيضًا أن تسلسل ردود النداء للتابع then: new Promise(function(resolve, reject) { // setTimeout حدث زائف غير متزامن باستخدام setTimeout(function() { resolve(10); }, 3000); }) .then(function(num) { console.log('first then: ', num); return num * 2; }) .then(function(num) { console.log('second then: ', num); return num * 2; }) .then(function(num) { console.log('last then: ', num);}); // من الـ console // first then: 10 // second then: 20 // last then: 40 كل then تستقبل القيمة المعادة من استدعاء then السابق. إذا أُنهي الوعد قبل أن يتم استدعاء التابع then مجددًا، يتم إيقاف رد النداء مباشرةً. إذا تم رفض الوعد ثم استدعاء التابع then بعد الرفض، لا يتم استدعاء رد النداء أبدًا. catch يتم استدعاء رد النداء catch عندما يُرفض الوعد: new Promise(function(resolve, reject) { // setTimeout حدث زائف غير متزامن باستخدام setTimeout(function() { reject('Done!'); }, 3000); }) .then(function(e) { console.log('done', e); }) .catch(function(e) { console.log('catch: ', e); }); // console من الطرفية // 'catch: Done!' ما تمرره لتابع reject يعود لك ولكن النمط المعتاد هو إرسال Error لـ catch: reject(Error('Data could not be found')); finally رد النداء المعرّف حديثًا finally يتم استدعاؤه بغض النظر عن النجاح أو الفشل: (new Promise((resolve, reject) => { reject("Nope"); })) .then(() => { console.log("success") }) .catch(() => { console.log("fail") }) .finally(res => { console.log("finally") }); // >> fail // >> finally Promise.all فكر بمحمّلات الجافاسكربت: يوجد أوقات يتم فيها تشغيل عدة تفاعلات غير متزامنة وتريد الاستجابة عندما تكتمل جميعها، هنا يأتي دور التابع Promise.all، هذا التابع يأخذ مصفوفة من الوعود ويعطيك رد نداء واحد فقط عند إنهاء جميع الوعود. Promise.all([promise1, promise2]).then(function(results) { // كلا الوعدين تم إنهاؤهما }) .catch(function(error) { // تم رفض وعد واحد أو أكثر }); الطريقة المثالية للتفكير بـ Promise.all هي إطلاق عدة طلبات AJAX (باستخدام fetch) في نفس الوقت. var request1 = fetch('/users.json'); var request2 = fetch('/articles.json'); Promise.all([request1, request2]).then(function(results) { // كلا الوعدين تم تنفيذهما }); يمكنك أن تدمج عدة واجهات برمجية مثل fetch والواجهة البرمجية Battery بما أنّها تعيد وعودًا. Promise.all([fetch('/users.json'), navigator.getBattery()]).then(function(results) { // كلا الوعدين تم تنفيذهما }); التعامل مع الرفض صعب بالطبع. إذا تم رفض أيّ وعد سيتم إطلاق catch للرفض الأول: var req1 = new Promise(function(resolve, reject) { // setTimeout حدث زائف غير متزامن باستخدام setTimeout(function() { resolve('First!'); }, 4000); }); var req2 = new Promise(function(resolve, reject) { // setTimeout حدث زائف غير متزامن باستخدام setTimeout(function() { reject('Second!'); }, 3000); }); Promise.all([req1, req2]).then(function(results) { console.log('Then: ', results); }).catch(function(err) { console.log('Catch: ', err); }); // console من الـ // Catch: Second! ستكون Promise.all مفيدة أكثر للواجهات البرمجية التي تتجه لاستخدام الوعود. Promise.race تعدّ الدالة Promise.race مفيدة فبدلًا من أن يتم الانتظار حتى إنهاء جميع الوعود أو رفضها تقوم بتشغيل أيّ وعد في المصفوفة تم إنهاؤه أو رفضه. var req1 = new Promise(function(resolve, reject) { // setTimeout حدث زائف غير متزامن باستخدام setTimeout(function() { resolve('First!'); }, 8000); }); var req2 = new Promise(function(resolve, reject) { // setTimeout حدث زائف غير متزامن باستخدام setTimeout(function() { resolve('Second!'); }, 3000); }); Promise.race([req1, req2]).then(function(one) { console.log('Then: ', one); }).catch(function(one, two) { console.log('Catch: ', one); }); // console من الـ // Then: Second! يمكن أن تشغّل حالة الاستخدام طلبًا إلى مصدر أوليّ ومصدر ثانوي (في حال عدم توفر الأوليّ والثانوي). اعتد على الوعود كانت الوعود موضوعًا مثيرًا للاهتمام خلال السنوات القليلة الماضية (أو خلال السنوات العشرة الأخيرة إذا كنت مستخدم مجموعة أدوات Dojo) وانتقلت من كونها نمط في إطار عمل جافاسكربت إلى كونها من أساس اللغة. وربما من الأفضل افتراض أنك ستشاهد معظم الواجهات البرمجية الجديدة في جافاسكربت يتم تنفيذها بنمط يعتمد على الوعد، وهذا أمر ممتاز. إنّ المطورين قادرون على تجنب جحيم رد النداء وتمرير التفاعلات غير المتزامنة مثل أيّ متغير آخر. تستغرق الوعود بعض الوقت لتكون الأدوات الأصلية وقد حان الوقت لتعلّمها. يمكنك في أي وقت الرجوع إلى توثيق الكائن Promise في موسوعة حسوب كما ننصحك أيضًا بقراءة صفحة «استخدام الوعود» بعد هذه المقالة مباشرةً لوضع ما تعلمته موضع التطبيق. ترجمة -وبتصرف- للمقال JavaScript Promise API لصاحبه David Walsh
  4. Nginx خادم ويب قوي ووكيل عكسي (reverse proxy) يُستخدم لتقديم العديد من المواقع الأكثر شهرةً في العالم. سنوضّح في هذا الدليل كيفية ترقية Nginx الموجود القابل للتنفيذ، بدون قطع اتصالات العميل. المتطلبات الأساسية قبل البدء في هذا الدليل، يجب أن يكون لديك مستخدم غير جذر على خادمك، تمَّ إعداده مع صلاحيات sudo. ستحتاج أيضًا أن يكون لديك خادم Nginx مثبَّتًا. إذا كنت تستخدم أبنتو 14.04، يمكنك تعلّم كيفية ضبط مستخدم بصلاحيات sudo هنا. يمكنك تثبيت Nginx باتّباع هذا الدليل. إذا كنت تستخدم CentOS 7، يمكنك الحصول على ضبط المستخدم بصلاحيات sudo عبر هذا الدليل، متّبعًا هذا الدليل لتثبّت Nginx. كيف تعمل الترقية يعمل Nginx على إنشاء إجراء سيّد أو رئيسي (master process) عندما تبدأ الخدمة. ويشغّل الإجراء السيّد بدوره إجراء تابع (worker process) أو أكثر تتعامل مع اتصالات العميل الفعلية. تم تصميم Nginx لأداء إجراءات معينة عندما يتلقّى إشارات محددة من المدير. يمنحك الفرصة باستخدام هذه الإشارات لتقوم بترقيته أو ترقية إعداداته الموجودة بسهولة، بدون قطع اتصالات العميل. هناك سكربتات (scripts) معينة للخدمة مزوّدة من قِبل القائمين على صيانة حزمة التوزيع ستوفر القدرة على الاستخدام مع الترقيات التقليدية. لكن توفر الترقية يدويًا المزيد من المرونة في المنهجية وتسمح لك بمراجعة الترقية للتراجع بسرعة إذا كان هناك مشاكل. هذا أيضًا سيوفر خيارًا للترقية بأمان إذا قمت بتثبيت Nginx من المصدر أو باستخدام طريقة لا توفر هذه الإمكانية. ستُستخدم الإشارات التالية: USR2: تولّد هذه مجموعة جديدة من إجراءات السيد/التابع بدون التأثير على المجموعة القديمة. WINCH: تخبر هذه الإجراء السيد لـNginx أن يوقف أغراض التابع المرتبطة بأمان. HUP: تخبر هذه الإجراء السيد لـNginx أن يعيد قراءة ملفات إعداداته ويستبدل إجراءات التابع بتلك المرتبطة بالإعدادات الجديدة. إذا كان هناك سيد قديم وجديد قيد التشغيل، فإنَّ إرسال هذا إلى السيد القديم سيولّد توابعًا باستخدام إعداداتهم الأصليّة. QUIT: توقف هذه تشغيل السيّد وتوابعه بأمان. TERM: تهيئ هذه إيقاف تشغيل سريع للسيّد وتوابعه. KILL: توقف هذه السيّد وتوابعه بدون أيّ تنظيف. إيجاد معرّفات إجراء Nginx لإرسال إشارات إلى الإجراءات المختلفة، نحتاج إلى معرفة معرّف الإجراء (PID) المستهدف. هناك طريقتان سهلتان لإيجاد هذا. أولًا، يمكنك استخدام الأداة ps وثمّ grep لـNginx بين النتائج. هذا بسيط ويسمح لك برؤية إجراءات السيّد والتابع: $ ps aux | grep nginx output root 10846 0.0 0.3 47564 3280 ? S 13:26 0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf nginx 10847 0.0 0.1 47936 1908 ? S 13:26 0:00 nginx: worker process user 10961 0.0 0.0 112640 964 pts/0 S+ 13:53 0:00 grep --color=auto nginx يحتوي العمود الثاني على معرّفات الإجراءات المُختارة. المميز هو معرّف الإجراء. يوضّح العمود الأخير أنَّ النتيجة الأولى هي الإجراء السيّد لـNginx. طريقة أخرى لإيجاد معرّف الإجراء السيّد لـNginx وهي طباعة محتويات ملف ‎/run/nginx.pid: $ cat /run/nginx.pid output 10846 إذا كان هناك إجراءين سيّد لـNginx قيد التشغيل، سينتقل الإجراء القديم إلى run/nginx.pid.oldbin/. توليد مجموعة سيّد/توابع جديدة الخطوة الأولى لتحديث ملفنا القابل للتنفيذ بأمان هي في الواقع تحديث ملفك الثنائي.قم بذلك باستخدام أيّ طريقة مناسبة لتثبيت Nginx لديك، سواء من خلال مدير الحزمة أو التثبيت المصدري. بعد وضع الملف الثنائي الجديد في مكانه، يمكنك توليد مجموعة ثانية من إجراءات السيّد/التابع التي تستخدم الملف الجديد القابل للتنفيذ. يمكنك القيام بذلك إمّا بإرسال إشارة USR2 مباشرةً إلى رقم المعرّف الذي استعلمت عنه (تأكّد هنا من استبدال معرّف الإجراء السيّد بمعرّف الإجراء السيّد الخاص بخادمك Nginx): $ sudo kill -s USR2 10846 او يمكنك قراءة واستبدال القيمة المخزّنة في ملف PID مباشرةً باستخدام أمر كهذا: $ sudo kill -s USR2 `cat /run/nginx.pid` إذا تفحّصت إجراءاتك الحاليّة، ستشاهد أنّ لديك الآن مجموعتان من إجراءات السيّد/التوابع لـNginx: $ ps aux | grep nginx output root 10846 0.0 0.3 47564 3280 ? S 13:26 0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf nginx 10847 0.0 0.1 47936 1908 ? S 13:26 0:00 nginx: worker process root 11003 0.0 0.3 47564 3132 ? S 13:56 0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf nginx 11004 0.0 0.1 47936 1912 ? S 13:56 0:00 nginx: worker process user 11031 0.0 0.0 112640 960 pts/0 S+ 14:01 0:00 grep --color=auto nginx يمكنك أيضًا أن تشاهد أنَّ ملف run/nginx.pid/ الأصلي قد انتقل إلى run/nginx.pid.oldbin/ ومعرّف الإجراء السيّد الجديد كُتبَ في الملف run/nginx.pid/: $ tail -n +1 /run/nginx.pid* output ==> /run/nginx.pid <== 11003 ==> /run/nginx.pid.oldbin <== 10846 يمكنك الآن إرسال إشارات إلى أيّ من الإجراءين السيّدين مستخدمًا المعرّفات الموجودة في هذه الملفات. عند هذه النقطة، فإن مجموعتي السيّد/التابع شغّالتين وقادرتين على تلبية طلبات العميل. تستخدم المجموعة الأولى الملف الأصلي القابل للتنفيذ والإعدادات الأصلية لـNginx وتستخدم المجموعة الثانية الإصدارات الأحدث. يمكنهم الاستمرار في العمل جنبًا إلى جنب، لكن يجب أن نبدأ في الانتقال إلى المجموعة جديدة من أجل الاتساق. إيقاف تشغيل توابع السيّد الأول للبدء بالانتقال إلى المجموعة الجديدة، فإنَّ أول شيء يمكننا القيام به هو إيقاف الإجراءات توابع السيّد الأصلي. سينهي التوابع الأصليين معالجة كل اتصالاتهم الحالية ثمَّ يخرجون. أوقف توابع المجموعة الأصلية بإصدار إشارة WINCH إلى إجرائهم السيّد: $ sudo kill -s WINCH `cat /run/nginx.pid.oldbin` سيتيح ذلك لتوابع السيّد الجديد أن يتعاملوا مع اتصالات العميل الجديدة بمفردهم. سيظلّ الإجراء السيّد القديم قيد التشغيل، لكن بدون توابع: $ ps aux | grep nginx output root 10846 0.0 0.3 47564 3280 ? S 13:26 0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf root 11003 0.0 0.3 47564 3132 ? S 13:56 0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf nginx 11004 0.0 0.1 47936 1912 ? S 13:56 0:00 nginx: worker process user 11089 0.0 0.0 112640 964 pts/0 R+ 14:13 0:00 grep --color=auto nginx يتيح هذا لك مراجعة التوابع الجدد لأنّهم يقبلون الاتصالات بشكلٍ منفصل مع الحفاظ على قابلية العودة إلى الملف القديم القابل للتنفيذ إذا كان هناك خطأٌ ما. تقييم النتيجة واتخاذ الخطوات التالية عند هذه النقطة يجب اختبار النظام ومراجعته للتأكّد من عدم وجود بوادر مشاكل. يمكنك ترك الإعدادات في هذه الحالة طالما ترغب بالتأكّد من أنّ الملف الجديد القابل للتنفيذ لـNginx خالٍ من الأخطاء وقادر على التعامل مع حركة المرور الخاصة بك. ستعتمد خطوتك التالية تمامًا على ما إذا كنت تواجه مشاكل. إذا كانت الترقية ناجحة، أكمل الانتقال إذا لم تواجه أيّ مشاكل مع توابع مجموعتك الجديدة، يمكنك إيقاف تشغيل الإجراء السيّد القديم بأمان. للقيام بذلك، فقط أرسل الإشارة QUIT إلى السيّد القديم: sudo kill -s QUIT `cat /run/nginx.pid.oldbin` سيُغلَق الإجراء السيّد القديم بأمان، تاركًا فقط مجموعتك الجديدة من السيّد/التوابع لـNginx. عند هذه النقطة، تكون قد حدّثت الملف الثنائي الموجود لـNginx بأمان بدون مقاطعة اتصالات العميل. إذا واجهت مشاكل في التوابع الجديدة، عُد إلى الملف الثنائي القديم إذا لاحظت وجود مشاكل في مجموعة التوابع الجديدة، يمكنك العودة إلى الملف الثنائي والإعدادات القديمة. وهذا ممكن خلال الجلسة نفسها. أفضل طريقة للقيام بذلك هي إعادة تشغيل توابع السيّد القديم بإرسال إشارة HUP له. عادةً، عندما ترسل إشارة HUP للسيّد في Nginx، يعيد قراءة ملفات إعداداته ويشغّل توابعًا جديدة. لكن عندما يكون الهدف سيّد أقدم، فقط يولّد توابعًا جديدة باستخدام إعدادات العمل الأصلية: $ sudo kill -s HUP `cat /run/nginx.pid.oldbin` يجب أن تعود الآن ليكون لديك مجموعتين من إجراءات السيّد/التابع: $ ps aux | grep nginx output root 10846 0.0 0.3 47564 3280 ? S 13:26 0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf root 11003 0.0 0.3 47564 3132 ? S 13:56 0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf nginx 11004 0.0 0.1 47936 1912 ? S 13:56 0:00 nginx: worker process nginx 19918 0.0 0.1 47936 1900 ? S 14:47 0:00 nginx: worker process user 19920 0.0 0.0 112640 964 pts/0 R+ 14:48 0:00 grep --color=auto nginx ترتبط التوابع الجديدة بالتابع القديم. عند هذه النقطة فإنَّ توابع المجموعتين سيقبلون اتصالات العميل. أوقف الآن الإجراء السيّد الجديد الذي يحوي أخطاء وتوابعه بإرسال إشارة QUIT: $ sudo kill -s QUIT `cat /run/nginx.pid` يجب أن تعود للسيّد والتوابع القديمين: $ ps aux | grep nginx output root 10846 0.0 0.3 47564 3280 ? S 13:26 0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf nginx 19918 0.0 0.1 47936 1900 ? S 14:47 0:00 nginx: worker process user 19935 0.0 0.0 112640 964 pts/0 R+ 14:50 0:00 grep --color=auto nginx سيستعيد السيّد الأصلي ملف run/nginx.pid/ لمعرّفه. إذا لم يعمل ما سبق لأي سبب من الأسباب، يمكنك أن تحاول فقط إرسال إشارة TERM للسيّد الجديد للخادم، وهذا يجب أن تتهيأ عملية إيقاف التشغيل. ويجب أن يوقف هذا السيّد الجديد وأي تابع من توابعه أثناء البحث التلقائي عن السيّد القديم لبدء إجراءات التابع الخاص به. إذا كان هناك مشاكل خطيرة والتوابع بهم أخطاء ولم يتم إنهاؤهم، يمكنك إرسال إشارة KILL لكلٍّ منهم للتنظيف. يجب أن يكون هذا كحل أخير لأنّه سيؤدي إلى قطع الاتصالات. بعد الانتقال مرة أخرى إلى الملف الثنائي القديم، تذكّر أنّه لا يزال لديك الإصدار الجديد مثبّتًا على نظامك. يجب أن تزيل الإصدار الذي يحوي مشاكل وتعود لإصدارك السابق حتى يعمل Nginx بدون أيّة مشاكل عند إعادة التشغيل. خاتمة يجب أن تكون الآن قادرًا على نقل أجهزتك بسلاسة من ملف ثنائي لـNginx إلى آخر. إنَّ قدرة Nginx على التعامل مع مجموعتي سيّد/توابع مع المحافظة على معلومات علاقاتهم تتيح لنا القدرة على ترقية برنامج الخادم بدون أن يصبح جهاز الخادم في وضع عدم الاتصال. ترجمة -وبتصرف- للمقال How To Upgrade Nginx In-Place Without Dropping Client Connections لصاحبه Justin Ellingwood
  5. إحدى أسوأ الأسرار التي تمَّ الاحتفاظ بها حول AJAX على الويب هو أنّ الواجهة البرمجية (API) الأساسية لها، XMLHttpRequest، لم توجد للغرض الذي نستخدمه الآن. لقد قمنا بعمل جيد في إنشاء واجهة برمجية جيّدة باستخدام الكائن XHR ولكننا نعرف أنه يمكننا القيام بعمل أفضل. نحن نبذل الجهود لتحقيق الأفضل الذي هو الواجهة البرمجية fetch. لنأخذ فكرة عامة عن التابع window.fetch الجديد، المتوفر الآن في Firefox و Chrome Canary. الكائن XMLHttpRequest إنَّ كائن XHR معقد قليلًا برأيي ولا أريد أن أبدأ بشرح لماذا "XML" تُكتب بأحرف كبيرة بينما "Http" تُكتب بأسلوب سنام الجمل. على أيّة حال، لنلاحظ كيف نستخدم XHR. // فوضى XHR فقط الحصول على if (window.XMLHttpRequest) { // موزيلا، سفاري... request = new XMLHttpRequest(); } else if (window.ActiveXObject) { // إنترنت إكسبلورر try { request = new ActiveXObject('Msxml2.XMLHTTP'); } catch (e) { try { request = new ActiveXObject('Microsoft.XMLHTTP'); } catch (e) {} } } // فتح، إرسال request.open('GET', 'https://davidwalsh.name/ajax-endpoint', true); request.send(null); بالطبع إنَّ أطر عمل جافاسكربت الخاصة بنا تجعل XHR أكثر متعة للعمل، ولكن ما نراه في الأعلى هو مثال بسيط على فوضى XHR. استخدام fetch الأساسي تم توفير دالة fetch في نطاق window العام، الوسيط الأول له هو الرابط URL: // الرابط (إلزامي)، الخيارات (اختيارية) fetch('https://davidwalsh.name/some/url', { method: 'get' }).then(function(response) { }).catch(function(err) { // خطأ :( }); وهذا يشبه إلى حد بعيد الواجهة البرمجية Battery المحدّثة، إذ تستخدم الواجهة البرمجية fetch الوعود في جافاسكربت لمعالجة النتائج/ردود النداء: // معالجة رد بسيط fetch('https://davidwalsh.name/some/url').then(function(response) { }).catch(function(err) { // خطأ :( }); // "تسلسل لمعالجة أكثر "تطورًا fetch('https://davidwalsh.name/some/url').then(function(response) { return //... }).then(function(returnedValue) { // ... }).catch(function(err) { // خطأ :( }); إذا لم تكن معتادًا على استخدام then، يجب أن تعتاد عليه لأنها ستنتشر قريبًا في كلّ مكان. ترويسات الطلب القدرة على ضبط ترويسات الطلب هي أمر مهم في مرونة الطلب. يمكنك العمل مع ترويسات الطلب بتنفيذ new Headers()‎: // إنشاء كائن ترويسة فارغ var headers = new Headers(); // إضافة بعض الترويسات headers.append('Content-Type', 'text/plain'); headers.append('X-My-Custom-Header', 'CustomValue'); // للترويسة set و get و check قيم headers.has('Content-Type'); // true headers.get('Content-Type'); // "text/plain" headers.set('Content-Type', 'application/json'); // حذف ترويسة headers.delete('X-My-Custom-Header'); // إضافة قيم ابتدائية var headers = new Headers({ 'Content-Type': 'text/plain', 'X-My-Custom-Header': 'CustomValue' }); يمكنك استخدام التوابع append و has و get و set و delete لتعديل ترويسات الطلب. لاستخدام ترويسات الطلب أنشئ الكائن Request: var request = new Request('https://davidwalsh.name/some-url', { headers: new Headers({ 'Content-Type': 'text/plain' }) }); fetch(request).then(function() { /* معالجة الرد*/ }); لنطّلع على عمل الكائنين Response و Request. الكائن Request يمثّل الكائن Request جزء الطلب عند استدعاء التابع fetch، يمكنك إنشاء طلبات مخصصة ومتطورة بتمرير الكائن Request للتابع fetch: method (الطريقة): يمكن أن تكون GET أو POST أو PUT أو DELETE أو HEAD url (الرابط): رابط الطلب headers (الترويسة): ترتبط مع الكائن Headers referrer (المرجع): مرجع الطلب mode (النمط): يكون cors أو no-cors أو same-origin credentials (بيانات الاعتماد): هل تعمل ملفات تعريف الارتباط (cookies) مع الطلب؟ وتأخذ إحدى القيمتين omit، أو same-origin. redirect (إعادة التوجيه): يمكن أن يأخذ القيمة follow أو error أو manual. integrity (التكامل): قيمة تكامل المصدر الفرعي. cache (التخزين المؤقت): وضع التخزين المؤقت ويمكن أن يأخذ إحدى القيم default أو reload أو no-cache عينة عن استخدام الكائن Request: var request = new Request('https://davidwalsh.name/users.json', { method: 'POST', mode: 'cors', redirect: 'follow', headers: new Headers({ 'Content-Type': 'text/plain' }) }); // الآن استخدمه fetch(request).then(function() { /* معالجة الرد */ }); الوسيط الأول URL هو فقط الوسيط الإلزامي، وكل خاصية تصبح للقراءة فقط حالما يتم إنشاء نسخة من الكائن Request، ومن المهم أن نلاحظ أن الكائن Request يملك التابع clone المهم عند استخدام fetch ضمن الواجهة البرمجية Service Worker -- يعد الكائن Request مجرًى ولهذا يجب أن يتم نسخه عند تمريره إلى استدعاء آخر للتابع fetch. بصمة التابع fetch ولكن نفس استخدام الكائن Request لذا يمكنك القيام بما يلي: fetch('https://davidwalsh.name/users.json', { method: 'POST', mode: 'cors', redirect: 'follow', headers: new Headers({ 'Content-Type': 'text/plain' }) }).then(function() { /* معالجة الرد */ }); من المحتمل أن تستخدم نسخًا من الكائن Request فقط ضمن Service Workers بما أن الكائن Request والتابع fetch يؤديان نفس الوظيفة. الكائن Response التابع then الذي يخص fetch مزود بالكائن Response ولكن يمكنك أيضًا إنشاء كائنات Response بنفسك -- حالة أخرى قد تواجهها عند استخدام service workers. يمكنك ضبط ما يلي عند استخدام الكائن Response: type (النوع): يمكن أن يكون basic أو cors url (الرابط) useFinalURL (استخدام الرابط النهائي): قيمة منطقية للرابط url إذا كان رابطًا نهائيًا أم لا status (الحالة): رمز الحالة (مثلًا 200، 400) ok: قيمة منطقية للاستجابة الناجحة (الحالة في المجال بين 200- 299) statusText (نص الحالة): نص يعبّر عن الحالة وفقًا للرمز (مثلًا: OK) headers (الترويسة): كائن Headers المرتبط بالاستجابة // service worker أنشئ ردك لاختبار // جديد (الجسم، الخيارات) Response كائن var response = new Response('.....', { ok: false, status: 404, url: '/' }); // Response يجلب مجدَّدًا نسخة من الكائن fetch الذي يخص then التابع fetch('https://davidwalsh.name/') .then(function(responseObj) { console.log('status: ', responseObj.status); }); يوفر الكائن Response أيضًا الطرائق التالية: clone()‎: تُنشئ نسخة من الكائن Response ()error: تعيد كائن Response جديد مرتبط مع خطأ في الشبكة ()redirect: تنشئ استجابة جديدة مع رابط URL مختلف ()arrayBuffer: تعيد وعدًا يُقبل (resolve) مع ArrayBuffer ()blob: تعيد وعدًا يُقبل (resolve) مع Blob ()formData: تعيد وعدًا يُقبل (resolve) مع كائن FormData ()json: تعيد وعدًا يُقبل (resolve) مع كائن JSON ()text: تعيد وعدًا يُقبل (resolve) مع القيمة النصية USVString التعامل مع JSON بفرض أنّك أنشأت طلب لـJSON -- معلومات نتيجة ردود النداء لديها التابع json لتحويل البيانات الخام إلى كائن جافاسكربت: fetch('https://davidwalsh.name/demo/arsenal.json').then(function(response) { // JSON التحويل إلى return response.json(); }).then(function(j) { // هو كائن جافاسكربت j console.log(j); }); بالطبع هذا سهل JSON.parse(jsonString) لكن طريقة json تعد اختصارًا سهلًا. التعامل مع استجابات Text/HTML الأساسية ليست دائما JSON هي صيغة رد الطلب المرغوبة لذا إليك كيف نجعل الاستجابة على شكل نص أو HTML: fetch('/next/page') .then(function(response) { return response.text(); }).then(function(text) { // <!DOCTYPE .... console.log(text); }); بإمكانك الحصول على استجابة نصية عبر تسلسل طريقة then للوعد مع طريقة text()‎. التعامل مع استجابات بشكل بيانات ثنائية إذا كنت ترغب مثلًا بتحميل صورة باستخدام التابع fetch فإن هذا سيكون مختلفًا. fetch('https://davidwalsh.name/flowers.jpg') .then(function(response) { return response.blob(); }) .then(function(imageBlob) { document.querySelector('img').src = URL.createObjectURL(imageBlob); }); يأخذ التابع blob()‎ تدفق الاستجابة وتقرأه حتى يكتمل. الحصول على بيانات النموذج استخدام آخر شائع للـAJAX وهو إرسال بيانات نموذج، وإليك كيف يمكن أن نستخدم التابع fetch للحصول على بيانات نموذج مرسلة بالطريقة POST: fetch('https://davidwalsh.name/submit', { method: 'post', body: new FormData(document.getElementById('comment-form')) }); وإذا أردت إرسال البيانات بصيغة JSON إلى الخادم: fetch('https://davidwalsh.name/submit-json', { method: 'post', body: JSON.stringify({ email: document.getElementById('email').value, answer: document.getElementById('answer').value }) }); سهل جدًا ومريح للعينين أيضًا. قصة لم تُكتب رغم أن fetch هي واجهة برمجية سهلة الاستخدام، إلا أنّ الواجهة البرمجية الحالية لا تسمح بإلغاء الطلب مما يجعلها غير مستخدمة لكثير من المطورين. إن الواجهة البرمجية fetch الجديدة تبدو أفضل وأسهل استخدامًا من XHR. وبعد كل ذلك تمّ إنشاؤها حتى نتمكّن من استخدام AJAX بالطريقة الصحيحة. تملك fetch فوائد الخبرات السابقة، ولا أطيق الانتظار حتى يتم استخدامها على نطاق واسع. ترجمة -وبتصرف- للمقال ‎fetch API لصاحبه David Walsh
  6. قال لي أحد أصدقائي عندما اتصل بي البارحة: "اسمع، يا صديقي، لقد وثقت بهم لأكثر من عام - لقد كنّا شركاء، وكانوا يبرمجون كل شيء بالوقت الذي كنت أنا مشغولًا في تطوير الأعمال، والآن استقالوا ولم يتبقَ لي شيئًا، ما الذي يتوجب عليَّ فعلهُ بكل ملفات JavaScript هذه؟ كيف لي أن أتأكد بأنَّ هذه الملفات ملكي؟ بالإضافة لذلك، لا يريدون التعاون معي، أشعر بأنني رهين تصرفهم هذا، من فضلك، ساعدني". فكان جوابي له: "ماذا يمكنني أن أقول؟ لقد فات الأوان يا صديقي، ولكن الخبر السّار هو أنك لست أول من واجه هذه المشكلة". السيناريو النموذجي لوصف المشكلة "الثقة، الدفع، الخسارة". أولًا ستثق في مبرمجيك، وسيكونون شركاء لك تؤمن بعملهم، وتشعر بأنّك متأكدًا أنَّك قد اخترت الأفضل، سيظهرون لك ثقةً كبيرةً جدًا، وستشعر بالحماس عندما تنظر إلى سيرهم الذاتية، إنهم يعرفون جافاسكربت و DevOps و GitHub وحتى البيانات الضخمة، إنّهم بالتأكيد الأفضل لك، بالإضافة إلى ذلك، لديهم خبرة في هذا العمل لمدة عشر سنوات، فما الذي تحتاجه أكثر من ذلك، صحيح؟ ثانيًا أنت تدفع لهم، وإلا ما الذي يدفعهم للعمل، صحيح؟ إنَّ الموهبة الحقيقية باهظة الثمن، كلنا نعرف ذلك، إنّك تدفع لهم بانتظام مقابل الوقت الذي يقضونه في العمل على مشروعك. ستشعر بالحماس لرؤية أموالك تتحول إلى برمجيات تعمل، سيوفرون نسخًا جديدة بانتظام، يوجد هناك بعض الأخطاء، لكن من الطبيعي أن تظهر الأخطاء، صحيح؟ إنهم يقومون بشرح كل شيء لك وأنت تستمر في الدفع لهم. أخيرًا ستخسر عندما تدرك أنَّ هذا البرنامج يعود لهم وليس لك، وبأنَّهم قد استقالوا بسبب بعض أسباب العمل ولم يتبقَ لك شيء، أنت لا تستطيع فهم هذه الملفات، وأصلًا لا تملكها إنَّما هي موجودة في مكان ما في مستودع المبرمجين على منصة Git. توظف المزيد من الأشخاص لمساعدتك على حفظ ما تبقى من البرنامج، لكنهم سيخبرونك أنَّ الوقت قد حان لبدء كل شيء من الصفر. ستُحبط بشكلٍ هائل، وستكون مستعدًا للعودة إلى الخطوة الأولى - لأنك تثق بهؤلاء الموظفين الجدد، فإنهم بالتأكيد سيبدون صادقين، وليسوا مثل المحتالين السابقين. هل يبدو هذا مألوفًا؟ بالطبع أنت تتساءل، ما البديل؟ لا تثق، وبدلًا من ذلك، استعن بخبير مستقل قبل البدء بمشروع ما، بحيث يقوم بشكل منتظم (مثاليًا، كل أسبوعين) بمراجعة كل ما يفعله الموظفين الجدد ويقوم بإبلاغك أين وكيف قد تخسر. سيحافظ هذا الخبير على قائمة بالمخاطر المتوقعة، وأنت بدورك ستتخذ الإجراءات الوقائية اللازمة. لا تثق بنا نحن معشر المبرمجين، فإننا أذكياءٌ وكسولون ومدللون، لذا ستخسر دون جدال. ترجمة -وبتصرف- للمقال ‎Trust. Pay. Lose لصاحبه Yegor Bugayenko
  7. أتاح لي العمل في موزيلا وقتًا كافيًا للنظر في الواجهات البرمجية API الجديدة، وإحداها هي الواجهة البرمجية Battery. لقد كتبت سابقًا عن الواجهة البرمجية Battery عندما كانت واجهة برمجية جديدة في المتصفحات ولكنها تغيرت لاحقًا وأصبحت واجهة برمجية يعتمد تنفيذها على الوعود ومتوفرة فقط في متصفح غوغل كروم. لنأخذ نظرة عن كيفية استخدام الواجهة البرمجية الجديدة. بإمكانك الاطلاع على النسخة التجريبية. الوظيفة التي نحتاجها ما تزال موجودة لدى الكائن navigator ولكنها الآن على شكل تابع يدعى getBattery: navigator.getBattery().then(function(result) {}); يعيد استدعاء التابع getBattery وعدًا ورد النداء الممرّر لـ then يُعطى كائن BatteryManager يوفر المعلومات التالية كمثال: // النتيجة BatteryManagery { charging: false, chargingTime: Infinity, dischargingTime: 8940, level: 0.59, onchargingchange: null, onchargingtimechange: null, ondischargingtimechange: null, onlevelchange: null } بإمكانك الاطلاع على النسخة التجريبية. إنّ الواجهة البرمجية الجديدة مختلفة في طريقة التنفيذ ولكنها مشابهة في النتيجة. تذكّر أنّ الواجهة البرمجية القديمة لديها مشاكل مع بطاريات أجهزة ماك ولا يبدو أنّ هذا قد تغيّر. من الصعب مراعاة بادئات المتصفحات المختلفة ولكن حصلنا على نتيجة مقبولة تقريبًا ولكنها تصبح فاشلة تمامًا عندما تتغير المنهجية بالكامل. نأمل أن يكون مالكي المتصفحات الأخرى سريعي التحديث لنحصل مجددًا على واجهة تطبيق موحدة البادئات للمتصفح. ترجمة -وبتصرف- للمقال JavaScript Battery API: Promises‎ لصاحبه David Walsh
  8. هل لديك فريق من المبرمجين المميزين والمتحمسين؟ بالطبع قد اخترتهم بعناية من بين مئات المرشحين، هل هم متحمسون للمنتج؟ بالتأكيد، إنهم يستخدمون أحدث التقنيات، ولا ينامون أبدًا، ويكادون لا يأكلون أو يشربون أي شيء باستثناء القهوة، هل يؤمنون بنجاح عملك؟ لا شك في ذلك. إنهم يعيشون ويتنفسون كل هذه الميزات، الإصدارات، والتسليم المستمر (continuous delivery)، تجربة المستخدم، وغيرها. هل أنت متأكد من أنهم يطورون المنتج بشكل صحيح؟ حسنًا، نعم، أنت متأكد تمامًا؛ لم لا؟ هل يبدو هذا الصوت مألوفًا؟ لا يمكنني حساب عدد المرات التي سمعت فيها هذه القصص من قِبَل مؤسِسي الشركات الناشئة. معظمهم يفضلون فرقهم حتى يأتي ذلك اليوم الذي يلجؤون فيه لتوظيف فريق جديد. قد يكون هناك العديد من الأسباب المحتملة لمثل هذا الفشل التام، ولكن أحد هذه الأسباب هو الافتقار إلى التنظيم والمنهجية والمراجعات التقنية المستقلة. لا شيء يمكنه أن يحد من تطور الفريق أكثر من عدم الاهتمام بإنجازاته. ومن ناحية أخرى، يُعَد التنسيق المنتظم لنتائجه التي توصل لها وتوقعات الجودة الخاصة بك أحد العوامل الرئيسية التي ستضمن النجاح التقني لشركتك الناشئة. سأُلخِّص فيما يلي تجربتي في تنظيم مثل هذه المراجعات التقنية. تتم المراجعة المستقلة عندما تطلب من شخص خارج فريقك الاطلاع على شيفرتك المصدرية والمصادر التقنية الأخرى وإعطائك رأيًا موضوعيًا بشأنها. ينبغي على كل فريق برمجيات حديث أيضًا استخدام مراجعات للشيفرات الداخلية (internal code reviews)، وهذا شيء مختلف تمامًا. تحدث المراجعة الداخلية عندما يعرض أحد المبرمجين الشيفرة الخاصة به على أعضاء الفريق الآخرين ويسألهم عن رأيهم. يعتبر هذا نشاطًا يوميًا ولا علاقة له بالمراجعات المستقلة. يتم إجراء مراجعة مستقلة بواسطة مبرمج لا يعرف شيئًا عن فريقك. ينضم إلى الفريق، ويتحقق من الشيفرة في مستودعك، ويقضي بضعة ساعات (أو أيام) في النظر إليها والتفكير بها ويحاول فهم ما الذي تفعله. ثمَّ، يخبرك ما هو الخطأ وأين. يشرح كيف يمكنه تحسينه بشكل أفضل، وأين سيجري التغيير، وما الذي سيفعله بدلًا من ذلك. ثمَّ تدفع له ويغادر. قد لا تشاهده أبدًا مرةً أخرى، لكن استنتاجاته واقتراحاته تساعدك على التحقق من صحة الشيفرة الخاصة بك وتقييم أداء فريقك بشكل صحيح. في Zerocracy، نقوم بمراجعات مستقلة لكل مشروع من مشاريعنا، وهذه قائمة بالمبادئ التي نستخدمها: اجعل المراجعات المستقلة منهجية هذه هي القاعدة الأولى والأكثر أهمية - نظّم المراجعات التقنية باستمرار. بالإضافة لذلك، أبلغ فريقك بالجدول الزمني، واجعله مستعدًا للمراجعات. وفقًا لتجربتي، تعدّ مرة واحدة في الشهر ممارسة جيدة. يجب أن تستغرق المراجعة الكاملة من ساعتين إلى ثماني ساعات وفقًا لحجم شيفرتك المصدرية. لا تقضِ أكثر من ثماني ساعات في مراجعة الشيفرة؛ ليس هناك فائدة من التعمق في الشيفرة خلال المراجعات المستقلة. ادفع لإيجاد الأخطاء نحن دائمًا ندفع ثمنًا للأخطاء، وليس للوقت الذي نقضيه في العثور عليها. نطلب من مراجعينا الاطلاع على الشيفرة والإبلاغ عن أكبر عدد من الأخطاء التي نظن أننا بحاجتها. لكل خطأ، ندفع ثمن 15 دقيقة لوقتهم. بمعنى آخر، نفترض أن المراجع الجيد يمكنه العثور على ما يقارب أربع مشكلات ويبلغ عنها في ساعة واحدة. على سبيل المثال، مراجع يقبض 150 دولارًا في الساعة (قد يختلف الأجر في البلاد العربية). نوظفه ونطلب منه أن يجد أخطر 20 مشكلة حرجة يمكنه أن يكتشفها ويبلغ عنها. تقديرنا هو أنه ينبغي أن يقضي خمس ساعات في هذا العمل. وبالتالي، سوف يحصل على 750 دولارًا عندما يكون لدينا 20 خطأ في نظام التتبع الخاص بنا والذي أبلغنا عنه. إذا وجد عددًا أقل، فسيحصل على أموال أقل نسبيًا. سيساعدك جدول الدفع هذا في جعل المراجع يركز على الهدف الرئيسي لعملية المراجعة – وهو العثور على المشكلات والإبلاغ عنها. لا توجد أهداف أخرى. الشيء الوحيد الذي تهتم أنت به هو معرفة ما هي المشاكل المتعلقة بحلك التقني الحالي. هذا هو ما تدفع مقابله. وظّف الأفضل وادفع أكثر تخبرني تجربتي أن وظيفة المُرَاجع المستقل مهمة للغاية. إنّه ليس مجرد مبرمج بل هو أكثر من ذلك، إنّه مهندس قادر على النظر إلى الحل من مستوى تجريدي عالٍ للغاية، وفي نفس الوقت يهتم بالتفاصيل كثيرًا؛ يجب أن يكون بارعًا في تصميم الأنظمة المماثلة؛ و يعرف كيفية كشف الخطأ والإبلاغ عنه وتزويدك بتفاصيل كافية؛ يجب أن يفهم مجال عملك وما إلى ذلك؛ إلى جانب كل ذلك، ينبغي أن يكون متحمسًا لمساعدتك. أنت لا توظفه للعمل بدوام كامل وإنّما فقط عمل لبضع ساعات. نصيحتي هي محاولة الحصول على أفضل الأشخاص، ودفع أجورهم بقدر ما يطلبون، وعادةً ما يكون أكثر من 100 دولار في الساعة. لا تتفاوض، فقط ادفع. إنّها مجرد بضعة مئات من الدولارات، لكن تأثير مساهمتهم هذه سيكون هائلًا. ملاحظة: قد تختلف الأسعار في الوطن العربي ويمكن أن تكون أقل مما ذُكِر آنفًا. اسأل وتوقع النقد إنّه خطأ شائع أن تسأل مراجعًا، "هل تعجبك الشيفرة الخاصة بنا؟" لا تتوقع منه أن يخبرك كم أن الشيفرة الخاصة بك ممتازة. ليس هذا ما تدفع مقابله، فأنت لديك فعليًا فريق كامل من المبرمجين لتشجيعك. يمكنهم إخبارك الكثير عن الشيفرة التي يكتبونها ومدى روعتها. لا تريد سماع ذلك مرة أخرى من المراجع. بدلًا من ذلك، أنت تريد أن تعرف ما هو الخطأ وماذا تحتاج لإصلاحه. وفقًا لما سبق، يجب أن تكون أسئلتك مثل، "ما هي المشكلات التي تعتقد أنه يتعين علينا حلّها أولًا؟" سيحاول بعض المراجعين إقناعك بتعليقات إيجابية لكن تجاهل هذا الإطراء وأَعِدهُم إلى الهدف الرئيسي - وهو الأخطاء. الجدول الزمني للدفع الموضح أعلاه يجب أن يساعدك بذلك. غيّر المراجعين باستمرار حاول ألا تستخدم المراجع نفسه أكثر من مرة في نفس المشروع (أعني في الشيفرة الأساسية نفسها). أعتقد أنَّ السبب هنا واضح، لكن دعني أعيد التأكيد: لا تحتاج أن يكون مراجعك لطيفًا معك وأن يخبرك بمدى جودة الشيفرة. إنما تريده أن يكون موضوعيًا ويركز على المشكلات، وليس على الجوانب الجيدة. إذا وظّفت نفس الشخص مرارًا وتكرارًا، فسوف تجعله مرتبط نفسيًا بالشيفرة المصدرية. لقد شاهدها مرة واحدة؛ والآن سيراها مرة أخرى. لقد أخبرك بالفعل عن بعض المشاكل، والآن عليه أن يعيدها مرة أخرى. لن يشعر بالراحة عند القيام بذلك. بدلًا من ذلك، سيبدأ بالشعور كأنه عضو في الفريق وسيشعر بالمسؤولية تجاه الشيفرة المصدرية وأخطائها. سيبدأ مثله مثل أي عضو آخر في الفريق، في إخفاء المشكلات بدلًا من الكشف عنها. إذن، استشر شخصًا جديدًا لكل مراجعة تقنية مستقلة جديدة. كن لطيفًا وصادقًا مع فريقك يمكن أن تكون المراجعات المستقلة مزعجة بالنسبة للمبرمجين لديك. قد يعتقدون بأنك لا تثق بهم. قد يشعرون أنك لا تحترمهم كأخصائيين تقنيين. ربما يقررون أنك تستعد لطردهم جميعًا وأنّك تبحث حاليًا عن أشخاص جدد. هذا الأمر ممكن جدًا ويعطي تأثيرًا جانبيًا مدمرًا للغاية في المراجعة المستقلة. كيف يمكن تجنب ذلك؟ لا أستطيع أن أقدم لك نصيحة شاملة، لكن أَفضل اقتراح يمكنني تقديمه هو: أن نكون صادقين معهم. أخبرهم أن جودة المنتج أمر خطير بالنسبة لك ولعملك. اشرح لهم أنَّ الشركة تدفع لهم مقابل عملهم وأنّه من أجل الحفاظ على استمرارية الرواتب، عليك التشديد على مراقبة الجودة بشكل منتظم، موضوعي، مستقل وصادق. في النهاية، إذا تمكنت من تنظيم المراجعات كما توضح هذه المقالة، فسيكون الفريق ممتنًا جدًا لك. سيحصلون على الكثير من الآراء والأفكار الجديدة من كل مراجعة وسيطلبون منك تكرارها باستمرار. راجع من اليوم الأول لا تنتظر حتى نهاية المشروع، لقد رأيت هذا الخطأ عدة مرات. كثيرًا ما يعتقد مؤسسو الشركات الناشئة أنّه يجب ألا يشتتوا انتباه فريقهم حتى يتم الانتهاء من المنتج ويصبح جاهزًا للسوق. يعتقدون أنّه يجب عليهم أن يسمحوا للفريق بالعمل على تحقيق مراحل المشروع والاعتناء بالجودة لاحقًا، "عندما يكون لدينا مليون زائر يوميًا" لن يأتي هذا اليوم أبدًا إذا سمحت لفريقك بالاستمرار بدون إدارة. ابدأ في إجراء مراجعات مستقلة من اللحظة التي يُرفع فيها الملف الأول على مستودع Git. وحتى يصبح المستودع كبيرًا بدرجة كافية، ربما تنفق 300 دولار مرة واحدة شهريًا لتلقي رأي موضوعي ومستقل بشأن جودته. هل سيدمر هذا ميزانيتك؟ امنع النقاشات، واطلب تقاريرًا رسمية لا تدع المراجعين يتحدثون إلى الفريق. إذا قمت بذلك، فإن فكرة المراجعة المستقلة ستنهار بالكامل. إذا كان المُراجع قادرًا على طرح أسئلته بطريقة غير رسمية ومناقشة تصميم النظام الخاص بك مع المبرمجين لديك، فستعجبه إجاباتهم ويمضي قدمًا. لكن باعتبارك مالكًا للشركة ستبقى بالمستوى نفسه الذي كنت به قبل المراجعة. الهدف من المراجعة ليس إسعاد المراجع وإنما العكس تمامًا. أنت تريد إرباكه، فإذا كان في حيرةٍ حيال وجود خطأ في التصميم، سيشعر بضرورة الإبلاغ عن الخطأ الموجود. يجب أن تعبّر الشيفرة المصدرية عن نفسها، ويجب أن يفهم أي شخص غريب (المراجع) كيف تعمل هذه الشيفرة بسهولة. إذا لم يكن الأمر كذلك، فهناك شيء خاطئ يجب إصلاحه. التعامل مع أي سؤال كأنه خطأ لا تتوقع أن ينتج المراجع أي أخطاء في الوظائف، مثل "أنقر على هذا الزر فيتوقف النظام". نادرًا ما يحدث هذا، إن حدث. فريقك جيد جدًا في اكتشاف هذه المشكلات وحلها. والمراجعات المستقلة ليست حول هذا النوع من الأخطاء. الهدف الرئيسي من المراجعة المستقلة هو اكتشاف الأخطاء في الهيكلية والتصميم. قد يعمل المنتج الخاص بك، ولكن قد يكون هناك عيوب خطيرة في هيكلية التصميم تُعيقك، مثلًا، من التعامل مع النمو الهائل في حركة البيانات على شبكة الويب. سيساعدك مراجع مستقل في العثور على هذه العيوب ومعالجتها في وقت أقرب. من أجل الحصول على هذا النوع من الأخطاء من المراجع، يجب عليك تشجيعه على الإبلاغ عن أي شيء لا يعجبه - استخدام التكنولوجيا بدون دافع، والافتقار إلى التوثيق، والهدف غير الواضح لملف، وعدم وجود وحدة اختبار، وغير ذلك. تذكر، المراجع ليس عضوًا في فريقك ولديه أفكاره الخاصة حول التقنيات التي تستخدمها والتطوير البرمجي بشكل عام. عليك أن تهتم بمطابقة وجهة نظره مع فريقك. بعد ذلك، عليك الاهتمام بإصلاح جميع حالات عدم التطابق الضرورية. راجع كل شيء، وليس فقط الشيفرة المصدرية دع المراجع الخاص بك ينظر إلى جميع المصادر التقنية التي لديك، وليس فقط ملفات شيفرة المصدر (‎.java ، .rb ، .php، وما إلى ذلك)؛ امنحه حق الوصول إلى مخطط قاعدة البيانات، ولوحة التكامل المستمر، وبناء البيئة، نظام تتبع المشكلات، الخطط والجداول الزمنية، وجداول الأعمال، وتقارير التشغيل، وخط النشر، وسجلات الإنتاج، وتقارير أخطاء العملاء، والإحصاءات، وغيرها. كل شيء يمكن أن يساعده في فهم كيفية عمل نظامك، والأهم من ذلك، أين وكيف ينهار، إنه أمر مفيد للغاية. لا تجعل معرفة المراجع تقتصر على الشيفرة المصدرية فقط - فهذا ببساطة لا يكفي، دعه يطّلع على المشروع بالكامل، وسوف تحصل على تقرير أكثر تفصيلًا واحترافيةً. تابع كيفية حل التناقضات بمجرد حصولك على تقرير من المُراجع، تأكد من أنَّ أكثر المشاكل أهمية ستدخل مباشرًة إلى عمل فريقك. تأكد من عنونتها وإنهائها. هذا لا يعني أنه يجب عليك إصلاحها جميعًا والاستماع إلى كل ما يقوله المراجع. بالطبع لا، المهندس هو الذي يدير العمل، وليس المراجع. يجب أن يقرر المهندس الخاص بك ما هو الصحيح وما هو الخطأ في التنفيذ التقني للمنتج. ولكن من المهم أن تجعله يحل جميع المخاطر التي طرحها المراجع. ستحصل في كثير من الأحيان منه على إجابات مثل هذه الإجابة: "نحن لا نهتم بذلك الآن"، "لن نصلحه حتى الإصدار التالي،" أو "إنه مخطئ! نحن نفعلها بشكل أفضل." هذه الإجابات صالحة تمامًا، ويمكن أن تحصل عليها (المراجعون أشخاص ويخطئون أيضًا). ستساعدك الإجابات التي تم إيجادها على فهم ما يفعله فريقك ومدى فهمهم لعملهم. إذا كان بإمكانك تزويدنا بالمزيد من الاقتراحات، بناءً على تجربتك فيرجى نشرها في التعليقات وسأضيفها إلى القائمة. ترجمة -وبتصرف- للمقال You Do Need Independent Technical Reviews!‎ لصاحبه Yegor Bugayenko
  9. أهلاً سومة، نحتاج في هذه الحالة إلى ثلاث حلقات for للمرور على كافة الشعب بفرض أن لدينا x تخصص ،y قسم ،z شعبة تكون الخوارزمية بالشكل: sum = 0; for(i=1,i<=x,i++) for(j=1, j<=y,j++) for(m=1,m<=z,m++) sum = sum + number of students in class[x][y][z] بالتوفيق...
  10. وعليكم السلام ورحمة الله، يجب أن تراعي قائمة الخطوات التالية عند نقل موقعك من استضافة إلى أخرى: 1- اختر شركة استضافة معروفة تغطي احتياجاتك. 2- حدد بعناية موقع السيرفر.إما اختيار استضافة جديدة موجودة في نفس البلد مثل بلدك السابق أو ضعه في البلد الرئيسي للجمهور المستهدف. 3- قم بتحميل ملفات الموقع عبر FTP على الاستضافة الجديدة وقم بإعداد قاعدة البيانات الخاصة بك. وتأكد من أن كل شيء يعمل بشكل جيد على الاستضافة الجديدة. 4-قم بإعداد كافة حسابات البريد الإلكتروني وحسابات ftp لتعمل بشكل صحيح على الاستضافة الجديدة قبل بدء البث المباشر. 5- تحميل مرة أخرى على الاستضافة الجديدة الملفات التي تم تغييرها منذ الخطوة 3. تحقق أيضا إذا كانت قاعدة البيانات تحتاج إلى تحديث. 6- غيّر سجلات نظام أسماء النطاقات من خلال التحديث إلى Nameservers أو A Records الجديدة حتى يشير الدومين إلى الاستضافة الجديدة. 7- أزل موقعك الإلكتروني من شركة الاستضافة القديمة بعد يومين من اكتمال النقل. بالتوفيق...
  11. أهلاً وسهلاً بك، بالطبع يمكن العمل في العديد من المواقع وأشهرها منصات العمل التابعة لشركة حسوب (مستقل وخمسات) بالإضافة إلى العديد من المواقع الأخرى مثل http://shoghlonline.com/ أنصح بمتابعة هذه المواقع والاطلاع على فرص فيها فهناك الكثير من الفرص المتاحة يومياً بالتوفيق...
  12. وعليكم السلام ورحمة اللّه وبركاته أهلاً بك، هناك الكثير من منصات العمل الحر العربية التي تتيح لك العمل عن طريق الإنترنت وأشهرها المنصات التابعة لشركة حسوب (مستقل وخمسات) حيث يوجد الكثير من الفرص الجديدة يومياً فما عليك سوى التسجيل في الموقع والتقدم لفرص العمل الموجودة. كما يمكنك أيضاً الاطّلاع على الفرص الموجودة في موقع شغل أونلاين http://shoghlonline.com/. وماعليك سوى زيارة هذه المواقع لتتعرف عليها أكثر وتعرف طرق الدفع المتوفرة في كل منها. بالتوفيق...
  13. وعليكم السلام ورحمة اللّه وبركاته، يمكنك الاستفادة من المواقع التالية للحصول على dataset: https://datamarket.com/data/list/?q=&fbclid=IwAR2hsqBMIh9uYWTw71Sj0mt_D7KXaZnnMlv1gbbeGMCQKUnIqRm1QdbdWXk https://www.kdnuggets.com/datasets/index.html?fbclid=IwAR3_5YCoHXE8nU2OZMBlPa5orAv7k9AZMdkFoIIjpUzIU5vkFA-5XZOpQWg يمكنك مثلاً أن تختاري العمل على dataset للأحرف العربية تحصلين عليها من أحد الرابطين: 1- https://archive.ics.uci.edu/ml/datasets/Spoken+Arabic+Digit?fbclid=IwAR0-gIYJeU_VFyDw-_QY6P_C0-pGjBRY087lTUBlhbdFMJ1aPgck9QaFHZ0 2- https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4786757/?fbclid=IwAR1lqi1R_Ou7wsdaWdy04pkxX4vlPVq2S4BxrGdK7lvj5z1vBuWTEpHw8zg أتمنى أن أكون قد أفدتك بالتوفيق ...
  14. وعليكم السلام ورحمة الله، إذا أردت أن يبقى اللون نفسه بعد التحديث بإمكانك اتباع إحدى الطريقتين: - إما تحفظ اللون في متغير تبقى قيمته مادام الزائر يتصفح الموقع ولم يغلق المتصفح، وعندما يغلق المتصفح تعود القيمة إلى الافتراضية وذلك باستخدام مفهوم الجلسة session - أو تحفظ اللون في متغير يتم حفظه في ملف الcookie ويكون له مدة محددة تحددها له في البرمجة (شهر مثلاً) ويحافظ هذا المتغير على قيمته حتى لو فتح المستخدم من متصفح آخر على نفس الجهاز وبعد انتهاء المدة التي حددتها يعود المتغير للقيمة الافتراضية وذلك باستخدام مفهوم cookies أتمنى أن أكون قد أفدتك بالتوفيق...
  15. أهلاً بك، بإمكانك تعريف المتحول أنه float وجمعه إلى متحول float آخر كي تظهر النتيجة بالفاصلة وأيضاً عند إنقاص عددين في java تظهر النتيجة بالسالب مثلاً إذا كتبت الكود التالي: float a = 7; float b = 10; System.out.println(a+b); System.out.println(a-b); تكون النتيجة بالشكل: 17.0 -3.0