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

سارة محمد2

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

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

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

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

    2

كل منشورات العضو سارة محمد2

  1. يمكن أن تقوم SVG بأكثر بكثير من مجرد عرض الصور الثابتة، إذ تعد إمكانياتها الحركيّة واحدة من أكثر مميزاتها قوةً، مما يعطيها مزايا فريدة عن صيغ الصور الأخرى، وهي أحد الأسباب العديدة التي تجعل SVG أفضل من الصور النقطية، بما فيها GIF. ولكن هذا، بالطبع، ينطبق فقط على الصور التي تعد مرشحةً جيدةً لتكون SVG، مثل: table { width: 100%; } thead { vertical-align: middle; text-align: center; } td, th { border: 1px solid #dddddd; text-align: right; padding: 8px; text-align: inherit; } tr:nth-child(even) { background-color: #dddddd; } الشعارات، الصور غير المعقدة، المعتمدة على الأشعة، أدوات التحكم بواجهة المستخدم، الرسوم البيانية، والأيقونات. بالطبع، إذا كان لديك صورة أكثر ملاءمةً للصيغة النقطية – مثل الصور الفوتوغرافية أو الرسومات المعقدة جدًا المعتمدة على الأشعة (والتي من الطبيعي أن تكون كبيرة الحجم جدًا مثل صور SVG)، فعليك استخدام صيغة الصور النقطية بدلاً منها. لا يجب أن تكون الصورة مرشّحاً جيداً لـ SVG فقط، ولكن يجب أن يكون SVG مرشّحاً جيداً للصورة. فمثلًا، إذا كان حجم الصورة صغير جداً كصور PNG، يجب استخدام PNG، وتقديم إصدارات/معاملات دقة مختلفة للصورة باستخدام srcset أو <picture>، بالاعتماد على ما تعمل عليه وتحاول تحقيقه. عمومًا، الصور المذكورة أعلاه هي عادةً مرشّحات مثالية لـ SVG. وإذا كنت ستحرّك أيًا منها، فإنّ الطريقة المعقولة للقيام بذلك هي إنشاء صورك المتحركة عن طريق تحريك شيفرة SVG. ومع ذلك، في الأسبوع الماضي، ظهر رابطًا منبثقًا في يوميات حسابي على التويتر يشير إلى مجموعة من الأيقونات المتحركة كـ GIF. إنّ أول ما مرّ في ذهني عندما رأيتهم بأنّهم كانوا مرشحين مثاليين لـ SVG ويجب أن يتم إنشاؤهم كصور SVG، وليس صور GIF. في العديد من الحالات يمكنك استبدال صور GIF بصور SVG بالفعل، تمامًا كما يمكن أن تستبدلها بتنسيقات الصور النقطية الأخرى لمرشّحين مثل تلك المذكورة أعلاه. إنّ القدرة على تحريك صور SVG هي ما يمنحها هذه الميزة والقدرة. وهذا ينطبق على عناصر أكثر من الأيقونات المتحركة. لذا، لهذا السبب أعتقد أنّه يجب عليك استخدام SVG بدلًا من صور GIF كلما استطعت. جودة الصورة الميزة الأولى لاستخدام SVG بدلًا من GIF - أو أية صيغة صورة لهذه المسألة - هي - كما هو متوقع - ميزة SVG الأولى: استقلالية الدقة. ستبدو صورة SVG فائقة الوضوح عند أي دقة للشاشة، بغض النظر عن حجمها. في حين أن صور GIF - صيغة الصورة النقطية - لا تظهر كذلك. حاول تكبير الصفحة التي تحتوي على صورة GIF وشاهد كيف ستبدو صورة الـ GIF منقطة ومحتوياتها غير واضحة. مثلّا، يبدو تسجيل GIF التالي لحركة صورة SVG جيدًا بهذا الحجم الصغير: يؤدي تكبير الصفحة عدّة مرات إلى جعل الصورة غيرَ واضحةٍ وتصبح حواف ومنحنيات العناصر الداخلية مسننةً، كما تشاهد في الصورة أدناه: بينما إذا قمت بالتحقق من عرض SVG التجريبي وتكبير الصفحة، فإن محتوى SVG سيبقى واضحًا وصافيًا بغض النظر عن مقدار التكبير. لتوفر صورًا واضحةً للشاشات عالية الدقة عند استخدام صيغة صورة نقطية مثل GIF، تحتاج إلى استخدام <picture> أو srcset وتشغيل الصور بسياقات مختلفة. بالطبع، كلما زادت دقة الصورة، زاد حجم الملف. مع صور GIF، سيصل حجم الملف لحجمٍ كبير بشكلٍ هائل. لكننا سنصل إلى ذلك في غضون دقيقة، كذلك، فإنّ استخدام صور GIF عالي الدقة وعرضها بحجمٍ أصغر للهواتف المحمولة يعد أمرًا سيئًا بالنسبة للأداء، لذا لا تفعل ذلك. عندما تنشئ أيقونات أو صور GIF متحركة، أبعادها ثابتةٌ. غيّر الأبعاد أو كبّر وصغّر الصفحة، وستحصل على صورة غير واضحة. أمّا مع SVG، ستتخلص من مشكلة الحجم، وستحصل على وضوحٍ دائم. يمكنك إنشاء صور SVG صغيرة وتغيير أبعادها وفق احتياجاتك دون التضحية بوضوح الصورة. نتيجة صورة GIF صورة SVG متحركة GIF مثل تنسيقات الصور الأخرى تمامًا، غير مستقلة الدقة، ولذا ستبدو غير واضحة عند تغيير حجمها أو عرضها بدقة أعلى صورة SVG قابلة لتغيير الحجم ومستقلة الدقة، وستبدو واضحةً بأي دقة شاشة الألوان والشفافية ربما يكون السبب الأول لتبتعد عن التعامل مع صور GIF هو الطريقة التي يتعامل بها مع الشفافية، خاصةً عندما يتم عرض الصورة على خلفية غير الخلفية البيضاء. هذه مشكلة تظهر غالبًا عند استخدام أيقونات GIF (سواءً كانت متحركة أم لا)، عندما يتم إنشاء الأيقونات عادةً بخلفيات شفافة. مثلًا، فكر مليّا بالدائرة التالية المحاطة بحدّ، أُنشئت كصورة SVG (يسار) وGIF بخلفية شفافة (يمين). المشكلة واضحة بمجرد النظر إلى الصورتين: تحتوي دائرة GIF على حواف رمادية حول حدّها. إذا كنت لا تعاينها في المتصفح، فقد لا يكون التأثير مرئيًا لك لأنّه من الممكن ألا يتم تطبيق أنماط الشكل. فيما يلي لقطة توضح المشكلة (على اليمين): يحدث هذا لأن الشفافية في صور GIF ثنائية. هذا يعني أن كل بكسل إما يعمل أو لا يعمل؛ البكسل سيظهر إما شفافًا أو ممتلئًا بشكلٍ كامل. وهذا بدوره يعني أنّ الانتقال بين اللون الأمامي ولون الخلفية ليس سلسًا، والتشوهات الناتجة تظهر بسبب تردد العينات غير المناسب، والمعروفة باسم التعرج. عندما لا يكون الخط مستقيمًا تمامًا، فإنّه يتسبب بأن تكون بعض البكسلات (حول الحواف) شفافة جزئيًا وممتلئة جزئيًا ، لذلك يحتاج البرنامج إلى معرفة اللون الذي يجب استخدامه لهذه البكسلات. تأثير الهالة "ناتج عن كل البكسلات التي كانت ممتلئة أكثر من 50٪ امتلاءً كاملاً وتحمل لون الخلفية بدلاً من اللون الذي تم تنقيطه" كريس ليلي. لذلك يكون هذا التأثير عادةً ناتجًا عن تلوث البكسل من لون الخلفية التي تتكون الصورة على أساسه مقارنةً بما هي عليه عند إنشائها/حفظها في محرر الرسومات. عادةً ما يحاط التعرج بمكافح تعرج، ولكن هذا ليس بالأمر البسيط عندما تكون الشفافية ثنائية: حلّ هذه المشكلة هو الشفافية المتغيرة، والمعروفة باسم قناة ألفا، والتي تسمح بدرجات متفاوتة من الشفافية وبالتالي انتقالًا أكثرَ سلاسةٍ بين اللون الأمامي ولون الخلفية، وهذا غير متوفر في GIF؛ وبالتالي، هذا يسبب مشكلة تأثير الهالة. تظهر الصور ذات تأثير الهالة أفضل عادةً عند استخدامها مع خلفيات بيضاء؛ أي لون خلفية آخر عالي التباين سيجعلها تبدو مشوهةً. لست متأكدةً تمامًا مما إذا كانت هناك طريقة لحل هذه المشكلة، لكنني لم أجد بعد صورة GIF ذات خلفية شفافة وحواف منحنية لم تكن بها هذه المشكلة. لقد رأيت الأشكال المستطيلة تعاني منها أيضًا. إذا كنت ترغب في استخدام صورتك/أيقونتك على خلفية غير بيضاء - مثلًا، على خلفية تذييل داكنة، قد يكون هذا لوحده يبعدك عن التعامل مع GIF، ولكن هناك أسباب أخرى تجعل استخدام SVG أفضل من GIF أيضًا، والتي سنغطيها في الأقسام التالية. ملاحظة: إذا كنت تقرأ هذه المقالة باستخدام المتصفح ولكنك لا ترى الحواف في الصورة الأولى على شاشة أصغر، فحاول تكبير الصفحة لترى التأثير. لماذا من الممكن ألا تكون قادرًا على رؤية الحواف على أحجام أصغر؟ الإجابة هي: ينعّم المتصفح الحواف كجزءٍ من عملية تغيير حجم الصورة. هل هذا يعني أنّه يمكنك استخدام هذا للتخلص من الحواف والاستمرار باستخدام GIF؟ نعم تستطيع. ولكن للقيام بذلك، يجب عليك استخدام صور GIF بحجم أكبر بكثير من الحجم الذي تريد أن تكون الصورة به، ثم تغيير حجمها. هذا يعني أيضًا أنك ستعرض صورًا للمستخدمين أكبر بكثير مما يحتاجون إليه، وبالتالي استهلاك المزيد من النطاق الترددي على الهاتف المحمول، بالإضافة إلى الإضرار بالحجم العام للصفحة وأدائها. رجاءً لا تفعل ذلك. نتيجة صورة GIF صورة SVG متحركة صور GIF قادرة على الشفافية الثنائية فقط. يسبب هذا التشوهات، المعروفة باسم تأثير الهالة التي تظهر كلما تمّ استخدام الصورة أو الأيقونة مع خلفية غير بيضاء كلما كان تباين لون الخلفية مع الصورة أعلى، كان تأثير الهالة أكثر وضوحًا مما يجعل الأيقونات غير قابلة للاستخدام عمليًا. تأتي صور SVG مع قناة ألفا ولا تعاني من أيّة مشاكل عند استخدامها مع ألوان خلفية مختلفة. تقنيات الصور المتحركة وأداؤها يمكنك تحريك صور SVG باستخدام CSS أو جافاسكربت أو SMIL، وتمنحك كلٌّ منها مستوىً مختلفًا من التحكم يمكنك الاستفادة منه لإنشاء جميع أنواع الصور المتحركة على عناصر SVG. لا توجد "تقنيات" لتحريك صور GIF. يتم تحريكها من خلال عرض سلسلة من الصور - صورة لكل إطار - بشكلٍ تسلسلي، بأسلوبٍ ثابتٍ وسرعةٍ ثابتةٍ. تعلم أنّ هذه الطريقة التي تعمل بها صور GIF فقط. ومن المؤكد أنّه يمكنك الإبداع مع أيقوناتك قبل تحويلها إلى صور GIF ثم "تسجيل" الحركات وتحويلها إلى GIF، ولكن ما مدى جودة مظهرها؟ وما مدى السيطرة على وقت الحركة التي ستحصل عليها بعد ذلك؟ لا شيء. لن تبدو الحركة سلسةً ما لم تتأكد من أن لديك 60 إطارًا على الأقل - أي 60 صورة - في الثانية لإنشاء صورتك الـ GIF. بينما مع SVG، فإنّ الحصول على صورٍ متحركةٍ سلسةٍ أسهل وأبسط بكثير من خلال الاستفادة من تحسينات المتصفح. حجم صور GIF أكبر من حجم صور PNG أو JPEG، وكلما طالت مدة حركة صورتك، زاد حجمها. ماذا لو أردت الآن تشغيل صورتك المتحركة لمدة 5 إلى 6 دقائق على الأقل؟ ماذا لو أردت تشغيلها لفترة أطول؟ ستحصل على الصورة. لنلقِ نظرةً أكثر تحديدًا على مثالٍ بسيط. يوجد أدناه صورتان: صورة SVG متحركة على اليسار وصورة GIF متحركة على اليمين. يتغير لون المستطيل في كلتا الصورتين بفترة ست ثوانٍ. يوجد العديد من الأشياء لملاحظتها هنا: تبدو صور GIF المتحركة سلسةً، لكن إذا ألقيت نظرةً قريبةً ستلاحظ أنّ مستطيل SVG يمر بمجموعة أكبر من الألوان عندما ينتقل من اللون الأولي إلى اللون النهائي. عدد الألوان التي يمر بها GIF محدودًا بعدد الإطارات. في الصورة أعلاه، تمر صورة الـ GIF بـ 60 إطارًا، أي 60 لونًا، بينما يمر SVG عبر الطيف بأكمله بين ظل اللون الوردي المستخدم واللون الأخضر النهائي. بالنسبة لتكرار الصور المتحركة مثل هذه، من الأفضل عمومًا تجنب قفزة اللون الظاهرة في الصورة المتحركة أعلاه، وإنشاء الصورة المتحركة بحيث تنعكس ما إن تصل إلى اللون الأخضر؛ بهذه الطريقة، ستنتقل بسلاسة إلى اللون الوردي ثم تبدأ الجولة الثانية من الصورة المتحركة من هناك أيضًا، مع تجنب قفزة الألوان القبيحة. مع CSS، يمكنك عكس حركة الصورة باستخدام قيمة اتجاه الحركة alternate. ولكن مع GIF، ستحتاج إلى العمل على عدد إطاراتك وربما ينتهي بك الأمر إلى مضاعفتهم لتحقيق ذلك؛ سيؤدي هذا بالطبع إلى زيادة حجم الصورة أيضًا. أحجام الصورتين الظاهرتين في الأعلى: حجم صورة GIF هو 21.23 كيلوبايت حجم صورة SVG هو 0.355 كيلوبايت هذا ليس فرقًا بسيطًا. ولكننا نعلم جميعًا أنه يمكننا تحسين صورنا. لذلك دعونا نفعل ذلك. يؤدي تحسين SVG باستخدام واجهة المستخدم الرسومية SVGO بالسحب والإفلات إلى تقليل حجم ملف الـ SVG إلى 0.249 كيلوبايت. لتحسين صورة الـ GIF، يمكنك استخدام واحدة من العديد من أدوات تحسين GIF عبر الإنترنت. لقد استخدمت ezgif.com لتحسين الصورة أعلاه. (توجد أدوات أخرى أيضًا؛ مثل gifsicle.) انخفض حجم الملف إلى 19.91 كيلوبايت. هناك العديد من الخيارات التي يمكنك الاختيار من بينها عند تحسين صور GIF. قمت بتحسين الصورة أعلاه بحيث يبقى عدد الإطارات نفسه، باستخدام ضغط Lossy GIF، الذي "يمكن أن يقلل من حجم ملف GIF المتحرك بنسبة 30 ٪ - 50 ٪ بتكلفة بعض التدرج / التشويش". يمكنك أيضًا تحسينها عن طريق إزالة كل إطار ذو الرقم n؛ مما يمكن أن يقلل من حجم الملف إلى أبعد حد، ولكن على حساب حركة الصورة التي لم تعد سلسةً بعد الآن. وفي حالة الصور المتحركة مثل الحالة المدروسة الآن، فإن إزالة الإطارات سيجعل التغيير في اللون "سريعًا" وملاحظًا. تتوفر أيضًا خيارات أخرى للتحسين مثل تقليل الألوان (الذي لن يكون مناسبًا للصور المتحركة المعتمدة على الألوان هنا) وخفض الشفافية. يمكنك معرفة المزيد حول هذه الخيارات في صفحة التحسين في موقع ezgif.com. للتلخيص: إذا كنت أردت أن تكون صورك الـ GIF المتحركة سلسةً، ستحتاج إلى المزيد من الإطارات في الثانية، وسيؤدي ذلك بالتالي إلى زيادة حجم الملف كثيرًا. بينما مع SVG، من المحتمل أن تحتفظ بحجم ملف أصغر بكثير. المثال أعلاه صغيرٌ، وأنا متأكد من وجود أمثلة أفضل، ولكني أردت أن يوضح المثال البسيط الفرق بين الصيغتين. حتى إذا كنت تحرّك المستطيل أعلاه باستخدام جافاسكربت أو حتى إطار عمل جافاسكربت — نظرًا لأن الصور المتحركة SVG لا تعمل في متصفح IE، مثلًا، من المحتمل أن يكون حجم ملف إطار العمل المقترن بحجم SVG أصغر أو يساوي على الأقل حجم صورة GIF. مثلًا، باستخدام GreenSock’s TweenLite، سيكون حجم SVG مع المكتبة المدمجة أقل من 13 كيلو بايت (والذي لا يزال أقل من حجم GIF)، إذ انّ حجم TweenLite المصغر هو 12 كيلو بايت. إذا انتهى بك الأمر إلى حجمٍ مساوٍ لحجم GIF، فإن الفوائد الأخرى لـ SVG ستزيد من الحجم وستحصل على المزيد منه. توجد بعض مكتبات جافاسكربت الأخرى التي تركز على مهام حركة معينة في وقت واحد، وتأتي بأحجام ملفات صغيرة بشكلٍ ممتاز (أصغر من 5 كيلوبايت)، مثل Segment التي تستخدم لتحريك مسارات SVG لإنشاء تأثيرات رسم خطية. حجم Segment المصغر هو 2.72 كيلو بايت. هذا ليس سيئًا للغاية، أليس كذلك؟ يمكن أن يكون هناك استثناءات، لذلك يجب عليك دائمًا الاختبار. ولكن بالنظر إلى طبيعة صور GIF وكيفية عملها، فمن المحتمل أن تجد أن SVG يُعدُّ خيارًا أفضل في معظم الحالات. ملاحظة: أداء SVG ليس في أفضل حالاته اليوم، ولكن نأمل أن يتغير هذا في المستقبل. توفر متصفحات IE/MS Edge أفضل أداء لعرض SVG بين جميع المتصفحات اليوم. على الرغم من ذلك، ستظل صور SVG المتحركة تبدو أفضل من صور GIF المتحركة، خاصةً عند التعامل مع الصور ذات الحركة الطويلة، لأنّ حجم ملف GIF - بافتراض تسجيلها بمعدل 60 إطارًا في الثانية - سيكون له تأثيرًا سلبيًا على الأداء العام للصفحة. تقدم المكتبات مثل GreenSock أداءً رائعًا أيضًا. نتيجة صورة GIF صورة SVG متحركة - صور GIF أكبر حجمًا عمومًا من صور SVG. حركة الصورة الأكثر تعقيدًا والأطول مدةً، تتطلّب عدد إطارات أكبر لإنشائها ولهذا يكون حجم الملف أكبر ويؤثر سلبًا على الأداء - ما لم تعمل حركة الصورة بمعدل 60 إطارًا في الثانية، فإنّ الحركة ستصبح مسننة وغير سلسة. أيضًا زيادة عدد الإطارات في الثانية سيؤدي إلى زيادة حجم الملف خاصةً للحركات الطويلة نتيجة: سيكون هناك حل بسيط يجب القيام به. إمّا أن تكون حركة صورة GIF ناعمة وسيتأثر الأداء وحجم الملف الكلي وحجم الصفحة بشكلٍ سلبي، أو ستعاني الصورة المتحركة GIF من إطارات أقل. سيتم المخاطرة بأحد أشكال الأداء في كلا الحالتين تستفيد صور SVG من تحسينات المتصفح عند تحريك العناصر. على الرغم من أنّ أداء المتصفح على عناصر SVG لا تزال في أفضل حالاتها، إلا أنّ الصور المتحركة ستبقى تعمل بشكلٍ جيد بدون الحاجة لتقديم تنازلات في أداء الصفحة لا يزال حجم ملف SVG معقولًا جدًا، إن لم يكن صغيرًا جدًا، مقارنةً بـ GIF، حتى عندما قد نحتاج إلى مكتبات معينة للصور المتحركة لإنشاء صور متحركة عابرة للمتصفحات إصلاح وتعديل الصور المتحركة إنّه من المحزن أن تستخدم صور GIF. ستحتاج إلى استخدام محرر رسومات مثل Photoshop أو Illustrator أو After Effects، على سبيل المثال لا الحصر. وإذا كنت مثلي، فلن يكون محرر الرسومات المكان الذي تصقل فيه مهاراتك، وستشعر أكثر أنّك في مكانك الصحيح أكثر عند إجراء تعديلات في الشيفرة، وليس في برامج تحرير الرسومات. ما الذي يحدث إذا كنت ترغب في تغيير توقيت صورتك المتحركة؟ أو إذا كنت تريد تغيير وظائف التوقيت لعنصرٍ واحدٍ أو عدة عناصر داخل صورتك؟ أو إذا كنت ترغب في تغيير الاتجاه الذي يتحرك فيه عنصرٍ ما؟ ماذا لو كنت تريد تغيير التأثير بالكامل وجعل العناصر في صورتك تفعل شيئًا مختلفًا تمامًا؟ ستحتاج إلى إعادة إنشاء الصورة أو الأيقونة مرةً أخرى. يتطلب منك أي تغيير الانتقال إلى محرر الرسومات والعمل مع الإطارات وواجهة المستخدم المعتمدة على الإطار. سيكون ذلك بمثابة تعذيب للمطورين، ومهمةً مستحيلةً لأولئك الذين لا يعرفون طريقتنا بالتعامل مع هذه المحررات بشكلٍ كافٍ لإجراء هذه التغييرات. مع SVG، فإن إجراء أي نوع من التغيير على الصورة المتحركة (الصور المتحركة) لا يُعدُّ سوى بضعة أسطر من الشيفرة. نتيجة (من وجهة نظر المطور) صورة GIF صورة SVG متحركة إصلاح وتعديل الصور المتحركة GIF يتطلّب إعادة إنشاء الصورة أو اللجوء إلى واجهة المستخدم في محرر الرسومات المعتمد على الإطارات للقيام بذلك، ويعدّ هذا مشكلة للمطورين في مواجهة التصميم عادةً، يمكن أن تتغير صور SVG ويتم التحكم بها بشكلٍ صحيح داخل شيفرة SVG - أو في أي مكان تم تعريف الصور المتحركة به، باستخدام عدة سطور من الشيفرة. حجم الملف، ووقت تحميل الصفحة والأداء في القسم السابق، ركزنا على أداء الصور المتحركة نفسها. في هذا المثال، أريد إلقاء بعض الضوء على أداء الصفحة ككل وكيفية تأثرها باختيار صيغة الصورة الذي تقوم به. في الحقيقة: كلما زاد حجم الملف، زاد التأثير السلبي على وقت تحميل الصفحة والأداء. بأخذ ذلك بالحسبان، لنرى كيف يمكن أن يساعد استخدام SVG بدلاً من GIF في تحسين إجمالي وقت تحميل الصفحة من خلال النظر إلى مثالٍ أكثر واقعيةٍ وعمليةٍ. في حديثي الأول عن SVG، منذ 18 شهرًا، ذكرت كيف يمكن استخدام SVG لاستبدال صور GIF المتحركة وكيف تؤدي إلى تحسين أداء الصفحة بشكلٍ عام. في ذلك الحديث، قدمت مثالًا واقعيًا لصفحة ويب واقعية استفادت مما توفره SVG وحصلت على الفوائد: الصفحة الرئيسية لـ Sprout. تحتوي صفحة الرئيسية لـ Sprout على صورتين متحركتين تم إنشاؤهما في البداية وعرضهما بشكل صور GIF. قبل عامين، كتب Mike Fortress مقالًا في مدونة Oak، يوضح فيه كيف قاموا بإعادة إنشاء صور GIF متحركة، خاصةً مخطط GIF (انظر الصورة أدناه) كصورة SVG متحركة. يشارك Mike في مقالته بعض الأفكار المثيرة للاهتمام حول أدائهم الجديد للصفحة كنتيجةٍ للتغيير إلى SVG: إنّه بالفعل فرقٌ كبيرً. مخطط Sprout هو المرشّح المثالي لـ SVG. لا يوجد سبب لتحريكها عن طريق تحويل الصور المتحركة إلى تسجيل GIF، عندما يمكن لـ SVG أن تحقق الكثير من الفوائد. يدرك Jake Archibald قوة صور SVG المتحركة أيضًا ، ويستخدمها لإنشاء الرسوم التوضيحية التفاعلية وتحريكها لاستكمال مقالاته. مقاله كتاب الطبخ دون اتصال يعتبر مثالًا ممتازًا (وبالمناسبة مقالًا ممتازًا). هل كان بإمكانه استخدام صور GIF للقيام بذلك؟ بالتأكيد. ولكن بالنظر إلى عدد الصور التي استخدمها، كان من الممكن أن تزيد صور GIF بسهولة الحجم الكلي للصفحة إلى 2 ميغابايت أو أكثر، بحيث يكون حجم كل GIF على الأقل مئات الكيلوبايت؛ في حين أن صفحة الويب بأكملها تبلغ حاليًا 128 كيلو بايت فقط مع جميع صور SVG المضمنة داخليًا، لأنّه يمكنك إعادة استخدام العناصر في SVG، لذا فإن أيّة عناصر متكررة لن تتسبب فقط في أن الصفحة بأكملها ستستعمل برنامج gzip كثيرًا، ولكن لكل صفحة سيصبح الحجم الكلي لصور SVG أصغر. الآن هذا رائع! سأبقي حالتي حول تحميل الصفحة والأداء هنا. ولكن لا يزال من المهم الإشارة إلى أنّه يمكن أن يكون هناك استثناءات. مرةً أخرى، في معظم الحالات، من المحتمل أن تجد أن SVG أفضل من GIF، لكنك ستحتاج دائمًا إلى الاختبار على أي حال. نتيجة صورة GIF صورة SVG متحركة صور GIF أكبر حجمًا بشكلٍ عامٍ من صور SVG مع الحركات المضافة لهم. وهذا يؤثر سلبًا على حجم الصفحة الكلّي ووقت التحميل والأداء. يمكن أن تُستعمل صور SVG وأن يُعاد استخدامها، مما يجعل حجم الملف أصغر عمومًا من GIF وهذا يحسّن من وقت تحميل الصفحة والأداء دعم المتصفح ربما تكون الميزة الوحيدة المتفوقة لصور GIF على صور SVG هي دعم المتصفح. تعمل صور GIF إلى حدٍ كبير في كل مكان، في حين أن دعم SVG أقل انتشارًا. على الرغم من أن لدينا العديد من الطرق لتوفير النسخ الاحتياطية للمتصفحات غير الداعمة - ويجب ألا يعوق دعم المتصفح الحالي أي شخص عن استخدام SVG، إنّ الصور الاحتياطية، إذا تم توفيرها كـ PNG أو JPG، ستكون ثابتة وبدون حركة. بالطبع ، يمكنك دائمًا تقديم GIF كخطوة احتياطية لـ SVG، ولكن يجب مراعاة الاعتبارات والعيوب المذكورة سابقًا. نتيجة صورة GIF صورة SVG متحركة تعمل صور GIF تقريبًا في كل مكان صور SVG يدعمها عدد أقل من المتصفحات، لكنها تأتي مع طرق كثيرة لتوفير صور احتياطية للمتصفحات التي لا تدعمها مخاوف سهولة الوصول (a11y#) انقل شيئًا ما إلى صفحة، أو أيّ مكان، لهذه القضية، لقد أضفت للتو تسليةً - شيءٌ ما من المؤكد أنّه سيجذب انتباه المستخدم بمجرد أن يبدأ التحرك. هكذا يعمل الدماغ البشري ببساطة. يعدُّ هذا أيضًا أحد الأسباب التي تركز عليها لافتات الإعلانات - وهي مبنية على - تركيزٍ قوي على الصور المتحركة. وهذا هو السبب في أنّ لافتات الإعلانات المتحركة مزعجةٌ للغاية. إنها تشتت الانتباه، خاصةً عندما تحاول أداء مهمة على صفحة تتطلب اهتمامك بالكامل، مثل قراءة مقال. تخيّل الآن صفحة بها مجموعة من الأيقونات المتحركة (أو الصور) التي لن تتوقف عن الحركة بغض النظر عما تفعله. لم نعد نتحدث عن صورة أو صورتين على الصفحة الرئيسية أو داخل مقالة هنا؛ نحن نتحدث عن متحكمات وعناصر واجهة المستخدم، والأيقونات الأصغر التي من المحتمل أن تكون موجودة في أماكن متعددة على الصفحة، وعلى صفحات متعددة. ما لم يكن من المفترض أن تكون الأيقونة عبارة عن رسوم متحركة بشكلٍ غير محدود - مثلًا، إذا كانت عبارة عن دوران متحرك أثناء مرحلة انتظار غير نشطة للمستخدم، فمن المحتمل أن تسبب مشكلة، وتصبح مصدر إزعاجٍ أكثر من كونها "شيئًا جميلًا". في الواقع، يمكن أن يصبح الأمر أكثر إزعاجًا لبعض الناس، لأن الحركة المستمرة يمكن أن تجعل بعض الناس حرفيًا يشعرون بالمرض. تناقش المصممة ومستشارة صور الويب المتحركة Val Head في مقالتها "تصميم رسوم متحركة للويب أكثر أمانًا من أجل حساسية الحركة" تأثيرات الصور المتحركة المفرطة الاستخدام في الويب على الأشخاص الذين يعانون من اضطرابات الدهليزية المتسببة بصريًا (منجم التركيز): تخيّل الآن ما إذا كانت الصور المتحركة لا تنتهي … مضاعفات مزدوجة. تشرح مقالة Val المشكلة بمزيدٍ من التفصيل، حيث تجمع ردود فعل من شخصين يواجهان هذه المشاكل بالفعل ويشاركان تجربتهما مع الصور المتحركة بأمثلةٍ مختلفةٍ. أحد الحلول التي يمكن أن تساعد في تجنب هذه المشاكل هو تزويد المستخدم بالقدرة على التحكم في الصور المتحركة حتى يتمكنوا من إيقافها عندما تصبح مزعجةً. يمكنك القيام بذلك باستخدام SVG. يمكنك التحكم بشكلٍ كاملٍ في الصور المتحركة وتشغيلها مرةً واحدة أو مرتين عند تحميل الصفحة - إذا كنت تحتاج حقًا إلى تشغيلها بمجرد قيام المستخدم "بالدخول" إلى صفحتك، ثم إظهارها عند تمرير مؤشر الفأرة لمرات متتالية، باستخدام سطورٍ قليلةٍ من الـ CSS أو جافاسكربت. لا تحتاج إلى المئات أو الآلاف من أسطر CSS أو جافاسكربت لإنشاء صورةٍ متحركةٍ للأيقونة، إلا إذا كانت أيقونتك مشهدًا معقدًا بالفعل فيها الكثير من المكونات المتحركة. لكنني أعتقد أنّه في هذه الحالة، لم تعد تمثل "أيقونةً" بعد الآن، وأنّها أصبحت عبارةً عن صورةٍ عاديةٍ أكثر. يمكنك الوصول إلى أقصى قدر من التحكم في إعادة التشغيل، والسرعة لكل تشغيلٍ لاحقٍ، وأكثر من ذلك بكثير، بفرض، بالطبع، أنّك تستخدم جافاسكربت للحصول على هذا المستوى من التحكم. أو يمكنك إضافة تبديل لمنح المستخدم القدرة على إيقاف تشغيل الصور المتحركة بلا حدود. لا يمكنك فعل ذلك باستخدام GIF … إلا إذا اخترت استبدال GIF بصورة ثابتة عند إجراء تبديلٍ معينٍ. قد يجادل البعض بأنّه يمكنك عرض نسخة ثابتة من الصورة – مثل صورة PNG مثلًا، ثم توفير إصدار GIF عند تمرير مؤشر الفأرة. ولكن هذا يسبب بعض المشاكل: إذا كانت الصورَ مضمنةٌ، فستحتاج إلى استبدال هذه الصور باستخدام جافاسكربت. هذا الإجراء لا يتطلب أي جافا سكربت إذا كنت تستخدم SVG. إذا كانت الصور عبارة عن صور أمامية (مضمنة في HTML باستخدام <img>)، وتحتاج إلى استبدال هذه الصور، فسينتهي بك الأمر إلى مضاعفة كمية طلبات HTTP لكلّ صورة. وإذا كانت صور الخلفية مضمنة في صفحة الأنماط (هذا غير مستحسن)، فإنّ الصور (خاصةً صور GIF) ستزيد حجم صفحة الأنماط وبالتالي تزيد الوقت الإجمالي لحظر عرض الصفحة. إذا كنت تبدّل/ عندما تبدّل مصادر الصورة عند تمرير مؤشر الفأرة، فهناك وميض ملحوظ بين الصورة الأولى والثانية في الاتصالات البطيئة. اتصالي بطيء؛ أحيانًا اتصال 3G بطيء، ولم أتذكر بعد وقتًا تم فيه استبدال صورة بأخرى عند تمرير مؤشر الفأرة، أو تم تغيير حجم منفذ العرض، أو أي شيء آخر، ولم أشاهد هذا الوميض. يزداد هذا الموقف سوءًا عندما تكون الصورة الثانية (GIF التي تحمّل عند تمرير مؤشر الفأرة) كبيرة الحجم إلى حدٍ ما — سيكون هناك وميض، تتبعه صورةً متحركةٌ بطيئةٌ غير متقنةٍ لـ GIF أثناء تحميلها بالكامل. هذا ليس جذابًا أبدًا. لذا، نعم، يمكنك تبديل مصادر الصورة للتحكم إذا أو عندما تشتغل الصور المتحركة GIF أو متى يتم ذلك، لكنك تفقد التحكم الدقيق في GIF وتؤثر على تجربة المستخدم مع واجهة المستخدم. يمكنك أيضًا التحكم في عدد المرات التي يتم فيها تشغيل الصور المتحركة في GIF - وهو أمرٌ رائعٌ، لكن هذا يعني أن الصور المتحركة ستعمل فقط عددًا محددًا من المرات. ثم لإعادة تشغيل الصور المتحركة عند تفاعل المستخدم، ستحتاج إلى اللجوء إلى الأسلوب أعلاه مع صور متعددة. يمكن تحقيق الصور المتعددة التي تحتاج إلى إصلاح، وطلبات HTTP المتعددة، والحل العام المُستهلَك غير الأمثل بصورة SVG واحدة. ضمّن صورة SVG واحدة على الصفحة. أنشئ الصورة المتحركة بالطريقة التي تريدها/تحتاجها. (أو أنشئ الحركة قبل تضمين الصورة.) شغّل وأوقف وتحكّم بالصورة المتحركة. وأمنح المستخدم القدرة على التحكم فيها أيضًا. لا توجد طلبات HTTP إضافية لكل صورة، ولا صيانة معقدة للخط الزمني للصورة المتحركة في محرر الرسومات، ولا توجد أي مخاوف تتعلق بسهولة الوصول أو مشاكل لا يمكن تجنبها ببضعة سطور من التعليمات البرمجية. نتيجة صورة GIF صورة SVG متحركة صور GIF لا يمكن إيقافها من قبل المستخدم بدون طلب صور إضافية وطلبات HTTP إضافية. لا تتم السيطرة بشكلٍ كاملٍ حتى يتم ذلك يمكن تخصيص صور SVG المتحركة بشكلٍ كامل لذا يمكن تفعيلهم وتعطيلهم والتحكم بهم من قبل المستخدم بدون الحاجة إلى طرق مستهلَكة سهولة الوصول إلى المحتوى صورة GIF صورة SVG متحركة صور GIF سهلة الوصول مثل صور PNG وJPEG باستخدام قيمة الخاصية `alt` لوصفهم. لا يمكن تمييز المحتوى الموجود داخل الصورة أو إتاحته مباشرةً لقارئات الشاشة بما يتجاوز الوصف العام للصورة يمكن الوصول إلى صور SVG ودلالتها. يمكن أيضًا وصف المحتوى المتحرك داخل الصورة وجعله قابلًا للقراءة من قِبل قارئات الشاشة باستخدام عناصر سهولة الوصول المدمجة في SVG، كما يمكن تحسينها باستخدام أدوار ARIA وخاصيّاتها أيضًا. (يمكنك أن تقرأ [هنا](https://www.sitepoint.com/tips-accessible-svg/) كل شيء عن جعل SVG قابلة للوصول) التفاعل لا يوجد الكثير لإضافته هنا، ولكن الحقيقة أنّه يمكنك التفاعل مع العناصر الفردية داخل SVG، أثناء أو قبل أو بعد تحريك الصورة، لكن هذا غير ممكن مع GIF. لذا، إذا كنت تستخدم GIF، فستفقد القدرة على فعل أي شيء يتجاوز تشغيل الصور المتحركة أو إيقافها، وحتى هذا لم يتم تنفيذه فعلاً باستخدام الـ SVG، كما رأينا، ولكن يتم تحقيق ذلك عن طريق مبادلة GIF بالخارج ببديلٍ ثابت. حتى تغيير ألوان العناصر داخل GIF سيتطلب صورًا إضافية للقيام بذلك. هذه ميزة أخرى لاستخدام SVG بدلاً من GIF. نتيجة صورة GIF صورة SVG متحركة لا يمكن أن تكون الحركات المحددة في صور GIF تفاعلية، لا يمكنك التفاعل مع العناصر الفردية داخل عنصر GIF، ولا يمكنك إنشاء روابط خارج العناصر الفردية أيضًا. محتوى SVG تفاعلي بالكامل. يمكنك إنشاء التفاعلات مثل تمرير ماوس الفأرة والضغط (والمزيد) التي تستجيب لها العناصر الفردية داخل صورة SVG. استجابة وتكيّف الصور المتحركة إنّ القدرة على تحريك صورة SVG مباشرةً من الشيفرة، بالإضافة إلى معالجة العديد من خاصياتها، تعطي وتضيف ميزةً أخرى على الصور المتحركة المعتمدة على GIF: القدرة على إنشاء صور متحركة جيدة الأداء، سريعة الاستجابة وقابلة للتكيّف، دون إضافة أي طلبات HTTP إضافية باستخدام بضعة أسطر من الشيفرة وبأحجام ملفات أصغر. كتبت سارة دراسنر مقالةً في مجلة Smashing Magazine تُظهر طرقًا مختلفة لتحريك SVG sprites. تتمثل إحدى هذه الطرق في وجود "مشاهد" متعددة داخل الـ SVG، وتحريكها باستخدام CSS، ثم تغيير "عرض" الـ SVG - عن طريق تغيير قيمة خاصية الـ viewBox - لإظهار مشهدٍ واحدٍ في وقتٍ واحدٍ، اعتمادًا على حجم منفذ العرض الحالي ومساحة الشاشة المتاحة. إذا كنت ترغب في إنشاء نفس الحركات باستخدام صور GIF، فستفقد إمكانيات التحكم في الصور المتحركة، كما ستحتاج إلى صور متعددة ربما تكون أكبر (في حجم الملف) من صورة الـ SVG الواحدة. ولكن إذا كنت لا ترغب في استخدام شيفرة SVG المتحركة، فيمكنك دائمًا إنشاء SVG sprite وتحريكه بالطريقة التي يمكنك بها تحريك أي صيغة صورة آخرى - باستخدام ()steps وعدة أسطر CSS. تتحدث سارة أيضًا عن هذه التقنية في مقالتها. لا يحتاج تحريك صور SVG أن يكون معقدًا، وهو يقدم أداءً أفضل بشكلٍ عام. نتيجة صورة GIF صورة SVG متحركة بما أنّه لا يمكن التحكم بالمحتوى داخل صورة GIF بالشيفرة، فلا يمكن جعل الصور المتحركة تتكيف أو تستجيب لتغيّرات منفذ العرض أو السياق بدون اللجوء إلى فصل الصور. بما أنّه يمكن تحريك محتوى SVG بشكلٍ مباشر باستخدام الشيفرة، فإنّه يمكن تعديل المحتوى والحركات بحيث يستجيب و/أو يتكيّف مع سياقات وأحجام منافذ عرض مختلفة، بدون الحاجة إلى اللجوء إلى أي أصول إضافية. كلمات أخيرة تتمتع صور GIF بدعم جيد جدًا للمتصفح، نعم، ولكن مزايا صور SVG تفوق مزاياها في جميع الجوانب تقريبًا. قد تكون هناك استثناءات، وفي هذه الحالات، تستخدم صور GIF بالتأكيد أو أي صيغة صور آخرى تقدم عملًا أفضل من SVG. قد تستخدم حتى فيديو أو HTML5 Canvas أو أيًا كان. يمكن أن توفر SVG الكثير من مزايا الأداء إلى القائمة عند موازنتها مع صيغ الصور الأخرى، وخاصةً GIF. وبالتالي، وبالنظر إلى كل ما سبق، أوصي بأنه في أي مكان يمكن استخدام SVG للصور المتحركة، يجب تجنّب استخدام صور GIF. أنت حر بالطبع في تجاهل توصيتي لكنك ستتخلى عن المزايا الكثيرة التي توفرها صور SVG المتحركة. ما لم توفر صور GIF الكثير من المزايا على صور SVG التي لا تحقق دعم المتصفح IE8 وأقل منه، فإنني أعتقد أن صور SVG ينبغي أن تكون هي السبيل للانطلاق. بعض المصادر لمساعدتك على البدء مع صور SVG المتحركة: عالم الصور المتحركة SVG. عدة طرق مختلفة لاستخدام SVG sprites في الصور المتحركة. إنشاء الصور المتحركة مع SVG. لدى GreenSock مجموعة من المقالات المفيدة حول تحريك SVG. Snap.svg ويُعرف أيضًا بأنّه "مكتبة jQuery للـ SVG". الصور المتحركة SVG باستخدام CSS وSnap.SVG. تصميم وتحريك صور SVG مع CSS. رسم خط متحرك في SVG. أرجو أن تكون قد وجدت هذه المقالة مفيدةً. شكرًا للقراءة. ترجمة -وبتصرف- للمقال Animated SVG vs GIF [CAGEMATCH]‎ لصاحبته Sara Soueidan
  2. يعدُّ التحضير لأسئلة المقابلة في مجال هندسة البرمجيات عملًا بدوام كامل تقريبًا، إذ هناك مصادر لا حصر لها على الإنترنت وغالبًا ما تكون هائلة عندما تبدأ العملية، ومن الطبيعي أن تكون متوترًا وخائفًا عند التقدم لمنصبٍ ما، لأنك تواجه خطر الحكم والرفض وهذا يكفي لإثارة قلق أي شخص. ومع ذلك فإن أفضل طريقة لتهدئة أعصابك هي الاستعداد الكامل حتى تعرف أنك تعطي نفسك أفضل فرصة للحصول على وظيفتك المثالية، ستقلل الممارسة والتحضير من الإحساس بالغموض وتساعد على تحضير نفسك للنجاح. إذا كنت مهندس برمجيات متخرج وتستعدّ لمقابلات العمل الأولى لك، فإليك المجالات المختلفة التي يجب التركيز عليها. أسئلة حول المعلومات الأساسية الخاصة بك يجب أن تكون مستعدًا للإجابة على الأسئلة المتعلقة بمعلوماتك الأساسية، خبرتك، مشاريعك السابقة ومعرفتك. تكون هذه الأسئلة عادةً مفتوحة وتمنحك فرصةً جيدةً لاختيار ما الذي تريد التحدث عنه، بعض الأمثلة على هذه الأسئلة يمكن أن تكون: أخبرني عن مشروع عملت عليه، وما الذي جعلك تستمتع أو لا تستمتع؟ أخبرني ماذا تعلّمت من العمل على هذا المشروع هل يمكنك التحدّث عن بعض الصعوبات التي واجهتها؟ كيف نسّقت المهام بين أعضاء الفريق؟ إذا قمت بإعادة هذا المشروع ثانيةً، هل ستفعل شيء ما بشكلٍ مختلفٍ؟ يمكنك التحدّث عن المشاريع التي عملت عليها خلال فترات التدريب أو خلال توظيفك في خبرة عملية أو خلال العمل في مقرر جامعي اعتمادًا على خبرتك، أيّ تجربة مررت بها لها قيمتها فلا تستخف بالمعرفة التي اكتسبتها من خلالها، عند الحديث عن تلك المشاريع السابقة ستكون الإجابة رائعة عندما تتضمن وصف وأهداف المشروع وأصحاب المصلحة فيه وتأثيره أو إجابة على الأسئلة "ماذا"، "مَن"، "كيف" و"لماذا". سيساعدك هذا في إثبات أنَّ لديك فهمًا جيدًا للعملية بأكملها وليس فقط للجانب التقني للأمور. ومن الجيّد أن تُدرج مقاييس النجاح إذا كانت ذات صلة، مثلًا: "هذا ساعد الناس على القيام بالمهمة x بشكلٍ أسهل"، "قمت بأتمتة هذه العملية مما وفر مقدارًا من الوقت للفريق" وغير ذلك. هذا يُظهر مدى اهتمامك بتأثير عملك. حتى لو كان هناك شيئًا يبدو عديم الأهمية بالنسبة لك، تذكر أن الشخص الذي يقابلك لا يعرف عنك شيئًا، إنّهم يبدؤون بصفحة فارغة بالكامل ولديهم فترة زمنية قصيرة ليفهموا كيف تتفاعل مع الأشخاص، ما الذي يثيرك في عملك وكيف تهدف لتحقيق النجاح. اغتنم الفرصة للتفكير في خبراتك وتحديد مجالات النمو للحديث عنها. يدرك المقابِلون أنّ لا أحد مثالي لكنهم يقدرون عقلية النمو. هل حددت بعض العمليات التي يمكن ضبطها؟ ربما كان تواصلك كان يمكن أن يكون أفضل في حالة معينة؟ أسئلة حول الشركة سيسألك المقابِلون سؤالًا اعتياديًّا عن العوامل التي جذبتك إلى الشركة وإلى المنصب الذي تتقدم إليه، من الضروري القيام ببعض الأبحاث حول الشركة مسبقًا وتحضير إجابات للأسئلة مثل: ما الذي يثير اهتمامك في صناعتهم؟ ما الذي جعلك مهتمًا بالشركة؟ ما الذي تتوقع تحقيقه من خلال العمل هناك؟ كيف تتناسب معرفتك مع ما يقومون به؟ ما الذي جعلك تعتقد أنك ستكون مناسبًا لثقافتهم؟ المعرفة المسبقة حول المنتجات التي يبنونها يمكن أن تأخذك شوطًا طويلًا، يتضمن ذلك فهم فضاء المنتج والاطّلاع قليلًا على مجموعة التقنيات. إذ أستفيد عادةً من الاستعدادات للمقابلة كفرصة لتعلّم شيء جديد وفهم ما إذا كنت مهتمًا بالمساهمة في ذلك. بعدها أكون قادرًا على طرح المزيد من الأسئلة ذات الصلة في المقابلة، بالإضافة إلى ذلك أجد أنّه من الأسهل بكثير أن أكون ناجحًا في مجال يثير اهتمامي. لا تقلق بشأن عدم معرفة جميع التقنيات التي يستخدموها. الانفتاح حول ما لا تعرفه (حتى الآن) يبدو جيدًا لمعظم المقابِلين. إظهار الاهتمام بتعلّم مجالهم حتى قبل توفير الوظيفة يبدو أفضل. بالنسبة للأسئلة الثقافية، يتوقع المقابِل أن يرى كيف تتفاعل مع الأشخاص الآخرين. إذا كانت لديك تجربة تدريب، فقد يسألونك عن كيفية تعاونك مع زملائك. مثلًا الوصول إلى المساعدة عندما تحتاجها، قضاء بعض الوقت في مساعدة الآخرين، التغلب على التحديات وتلقي أو تقديم التغذية الراجعة هي بعض مجالات المواضيع المحتملة. أسئلة المقابلة العامة بالنسبة للجانب التقني للأشياء فإنَّ إدراك مبادئ تطوير البرمجيات مثل البرمجة كائنية التوجه والتطوير الموجه بالاختبار والتركيب المتواصل وأنماط التصميم والتحكم بالنسخة هو أمرٌ أساسيٌّ. قد تكون محتاج أيضًا لتعلّم أساسيّات الشبكات أو قواعد البيانات أو الأنظمة حسب طبيعة المنصب الذي تتقدم له. اقرأ وصف الوظيفة بدقة، وحضّر نفسك لتكون قادرًا على إعطاء التعريفات والتحدّث حول المزايا الأساسية. قد لا تملك خبرة عمليّة، ولكن من الجيد أن تكون قادرًا على شرح لماذا هذه التقنيات مهمة ومناقشة بعض اتجاهات الصناعة. ليس عليك أن تعرف كل المتطلبات الموجودة في وصف العمل. أخبرني مرشدي الأول أنّني يجب أن أتقدّم لمنصب ما بالاعتماد على ما الذي أريد أن أكون عليه، بدلًا من الذي أنا حاليًا عليه. إذا كان لديك القليل من وقت الفراغ، فإن محاولة بناء بعض المشاريع الجانبية الصغيرة لتحسين معرفتك بتقنية جيدة هي فكرة رائعة أيضًا. حل المشاكل يأتي هنا الجزء الذي يقلق معظم الأشخاص بسببه. جلسات "حل المشاكل"، التي تختبر فهمك لبنى المعطيات والخوارزميات والتعقيد. خلال مرحلة التحضير هناك مواد غير محدودة على الإنترنت تساعدك على التحضير. الكتاب التقليدي الذي يعطّل العملية ويوفر المشاكل والحلول هو كتاب Cracking the Coding Interview لـ Gayle Laakmann McDowell. المصادر على الإنترنت مثل LeetCode وHackerRank هي بدائل جيّدة. يجب عليك معرفة ما هي الأعمال الأفضل لك بينما أنت تدرس. شخصيًّا أفضّل حل المشاكل والتحديات الصغيرة، مثل code katas أو advent of code. ومع ذلك يمكن أن يكون مضيعة للوقت. لذا عندما أريد أن أتعلّم أسرع، أجد الحلول على الإنترنت وأطبّقها بنفسي لفهم الخوارزمية. هناك الكثير من مقاطع الفيديو على اليوتيوب تشرح كيفية عمل خوارزمية معينة يمكنك أن تستخدمها. عندما تطبّق حلّ ما، خذ بعض الوقت لتقوم بدفعه (push) إلى حسابك على Github. لن يكون مفيدًا فقط إذا احتجت إليه مرة أخرى لاحقًا، لكن سيساعدك أيضًا في بناء معرض أعمالك. خلال المقابلة نفسها تأكد من أنّك فهمت المشكلة بشكلٍ كامل. اطلب من الشخص الذي يقابلك توضيح الأسئلة للتأكد من أنّك تعرف المطلوب منك. لا تنتقل إلى كتابة الشيفرة بدون أن يكون لديك معلومات كافية. مثلًا، يجب أن تتأكد من أنّك تعرف من أين تقرأ الدخل، ما هو تنسيق الدخل وحجم البيانات. ابدأ مع حل "القوة العنيفة" (brute force) ولا تفكر في الأداء بعد. اتركه بسيطًا. اشرح للمقابِل طريقة تفكيرك واذكر أنّك ستجرب حل القوة العنيفة أولًا. لا تقلل من صعوبة المهمة. فحتى الاختبارات التي تبدو بسيطة مثل اختبار FizzBuzz) يمكن أن تعطي انطباعًا سريعًا عن كيفية تحليل المشكلة وفهمها. يبدأ عادةً الاختبار يبدأ بسيطًا ويتقدم تدريجيًا. اذكر أيّة افتراضات تقوم بها. إذا كنت تستخدم توابع مكتبة للغةٍ ما من اختيارك، اسأل إذا كان يجب عليك تنفيذها. مثلًا الترتيب متوفر في معظم لغات البرمجة. بينما تتابع حل المشكلة، اشرح كيف تنقل بياناتك وأين تخزّنها وكيف تعالجها. يوضح هذا أنّك تفهم جيّدًا البيانات التي تتعامل معها ولا تحاول فقط تجربة الأشياء التي رأيتها حولك. يمكنك تقسيم مشكلتك إلى دوال أصغر بأسماء واضحة ثم المضي قدمًا والبدء بتنفيذ كلّ منها. غالبًا، يتوقع منك المقابِلون تنفيذ الحل البسيط أولًا، ثم سيسألونك عن التعقيد. حاول تحديد الحلقات المضمنة، والعمليات لحساب التعقيد. أبقِ تعقيد المساحة والزمن في عقلك. ما مقدار الذاكرة التي تحتاجها لتخزين الأشياء مقارنةً بدخلك وكم عدد العمليات التي تحتاج أن تقوم بها لتحصل على النتيجة. ذكّر نفسك بدرجة تعقيد الخوارزميات القياسية مثل خوارزمية الترتيب والبحث وغيرها ثم حاول معرفة أين يمكن تحسين الأشياء. ربما يمكنك استخدام بنية معطيات مختلفة؟ المصفوفات المترابطة (HashMaps) والمجموعات والقوائم المرتبطة هي بُنى نموذجية تستخدم لتحسين التعقيد اعتمادًا على المشكلة. من الجيد أن تكون هذه البنى بين يديك لتستخدمها في المشكلة الصحيحة. إذا كنت تعرف المشكلة والحل الأكثر فعاليةً مسبقًا، تابع العمل ولكن خذ بعض الوقت لشرح سبب كونه الحل الأمثل. إذا أبدى المقابِل أي رأي فكر بها جيّدًا. في معظم الأحيان، يكون المقابل يعرف الحل مسبقًا ويريد أن يساعدك لذا فإنّ اقتراحاته تستحق التفكير. ماذا لو لم تحلّ المشكلة؟ هل يعني هذا أنّك فشلت في المقابلة؟ ليس بالضرورة. المقابِل مهتم أكثر بطريقة تفكيرك. من تجربتي يركز المقابِلون على: ماذا تفعل عندما تكون عالقًا؟ هل أنت قادر على توضيح لماذا أنت عالقٌ، هل سيثقون بك عند إعطائك مهمة ويعرفون أنّك ستطلب المساعدة عندما تحتاجها؟ هل أنت قادر على فهم عمل بنى المعطيات أو هل تستخدمهم كمربع أسود؟ مثلًا استخدام المصفوفات المترابطة بدون سبب معيّن لذلك أو بدون توضيح لماذا يحسّن استخدامها من الأداء؟ هل أنت تتواصل جيّدًا بشكلٍ عامٍ؟ هل تتقبّل التغذية الراجعة أو تتحمس لحلك فقط؟ هل أحرزت أيّ تقدّم خلال المقابلة؟ هل يمكنك أن تعمل تحت الضغط أو تتوقف نهائيًا؟ أسئلة حول المقابِلين من الجيّد أن تحضّر بعض الأسئلة للمقابِلين أيضًا. تذكّر أنّه من المهم معرفة ما إذا كانت الشركة مناسبة لك أم لا. كلّما ازدادت المعلومات التي تعرفها، كان من الأسهل عليك اتخاذ القرار. عادةً أحضّر بعض الأسئلة للمقابلة مسبقًا، مثل: كيف تُنظَّم فرق الهندسة؟ كيف توزَّع المهام على الفريق؟ كيف يمكنك اختبار منتجاتك؟ ما الفريق الذي يحتمل أن أعمل معه؟ كيف تدعمون الأشخاص أثناء التدريب؟ كم يستغرق عادةً الشخص الجديد للتدريب؟ ما الذي يمكن أن يكون مثالًا لمهمة أعمل عليها؟ ما هي التقنيات الرئيسية التي تستخدمونها لهذا المشروع؟ ما الفرص المتاحة للعمل على مشاريع مختلفة؟ كيف يمكنك إجراء مراجعات الأداء؟ كيف يبدو التقدم الوظيفي لهذا المنصب تحديدًا؟ فكّر في يوم عملك المثالي - ما الذي تريد أن تعرفه عنه؟ يقيّم الأشخاص المختلفون أشياء مختلفة في العمل. مثلًا، قد تفضّل بيئة متغيرة ديناميكية توفر مزيدًا من الحرية، أو قد تشعر بالإنتاجية في بيئة أكثر تنظيمًا. قد ترغب في العمل بطريقةٍ استقلاليةٍ أو تفضّل أن تكون جزءًا من فريق. إنّها فكرةٌ جيّدة أن تعرف البيئة التي تساعدك على أداء الأفضل وتبحث عن الشركات التي تمنحك هذه الفرصة. إذا شعرت بأن المقابِل قد غطّى معظم أسئلتك فلست مضطرًا لأن تسأل لمجرد النقاش فقط. طريقة التفكير مهمة بالطبع، تعد مهاراتك التقنية مهمة جدًا لمقابلات هندسة البرمجيات، ولكن لا تقلل من أهمية مهاراتك الشخصية. سيعمل معك الأشخاص يوميًا لذا يجب أن يشعروا بأنّك شخص لطيف للعمل معه. هناك جزء كبير من العمل لا يتعلق بكتابتك للشيفرة البرمجية، إنّما بالتعاون مع المبادئ والفرق الأخرى. جمع وفهم المتطلبات، والقدرة على التعبير عن المشكلة بطرق تقنية وطرق غير تقنية، إبلاغ أصحاب المصلحة حول التقدم والمشاكل ليست سوى جزء منها. إذا كنت تعتقد أنّ لديك مصدر قوة في شخصيتك فحاول أن تظهر ذلك خلال العملية. اهدف للتحسين المستمر لا تنسَ أن إجراء المقابلات، مثله مثل أي شيء آخر، هو مهارة تتحسن مع الخبرة. لا تقلق بشأن الفشل، ركّز على ما تعلمته والقيام بأداء أفضل في المرة القادمة. عندما تكتسب بعض الخبرة ستصبح أقل توترًا وبالتالي سيكون من الأسهل أن تنجح. إنّها عملية من التطوير المستمر، يجب أن تتحسن في كل مرة تجري فيها مقابلة، لذا استمر في التحضير وفي تحسين مهارات التواصل لديك ومهاراتك التقنية. البحث الصحيح عن المعلومات هو المفتاح للتحضير الجيّد، ومراجع مثل موقع Quora أو حتى غوغل فقط هي مصادر جيّدة لأسئلة المقابلة الشائعة للشركات. قد تكون كل هذه المعلومات هائلة، لكنك لن تُسأل كل هذه الأسئلة في كل مقابلة. حاولت أن أجمع الأشياء المختلفة التي لاحظتها حتى الآن لأعطيك بعض المجالات لتستكشفها. القليل من التحضير المركّز يقطع شوطًا طويلًا، لكن لا تبالغ فيه. من السهل أن تفكر كثيرًا في مقابلة وتربط نفسك بعقد. حظًا سعيدًا، اذهب إلى هناك وكن رائعًا! هل لديك أيّة خطوات أخرى تستخدمها أثناء التحضير؟ شاركها معنا في التعليقات. ترجمة -وبتصرف- للمقال How to prepare for software engineering interview questions‎ لصاحبته Sofia Tzima
  3. لنستخدم CSS لرسم شخصية بيماكس (Baymax) من فيلم Big Hero 6. سنحرّك في هذا المنشور صورة خلفية، بالإضافة إلى تأثير حركة بتوقيت دقيق، ونقوم بإجراء عرض تجريبي CSS من عنصر HTML واحد. تجربة حية. عنصر واحد سنكون قادرين باستخدام العنصر الزائف على إنشاء أجزاء الوجه بعنصر HTML واحد. <div class="baymax"></div> التصميم لضبط المرحلة سنضيف تدرّجًا دقيقًا للشاشة لجعلها تبدو كرأس أبيض منحنٍ. سنستخدم لهذا تدرجًا شعاعيًا على عنصر body. body { background: radial-gradient(circle at center, #fff, #fff 50%, #aaa); background-size: 100% 100%; background-repeat: no-repeat; height: 100vh; } بعد ذلك نضع الوجه في مركز الصفحة. الفم خط أسود بسيط، وسنقوم بذلك باستخدام الخاصية border. .baymax { border-bottom: 1.5em solid #000; position: absolute; top: 50%; left: 50%; width: 50%; transform: translate(-50%, -40%); } تقوم الخاصية الأولى بتعيين إطار سفلي أسود بعرض 1.5em. ثمَّ يتموضع الخط باستخدام الموضع المطلق، فيندفع إلى الأسفل 50% ويتحرك من اليسار 50%. قيم الـ 50% هي بالنسبة إلى حجم العنصر الحاوي (body). المشكلة التي نواجهها الآن هي أنَّ العنصر يبدأ من منتصف طول وعرض الشاشة. إنَّه خارج المركز. لموازنة ذلك، نستخدم تحويلًا لسحب العنصر 50% يسارًا من عرضه، وإلى الأعلى 40% من عرضه. عند هذه المرحلة يصبح الفم في المركز على هذا النحو: إضافة العينين سنستخدم العناصر الزائفة before وafter لإضافة العينين إلى الوجه. لن يحتاج هذا إلى أي عنصر HTML إضافي وتتم معالجته بالكامل باستخدام CSS. .baymax::before { background: #000; border-radius: 50%; content: ""; position: absolute; width: 12em; height: 12em; left: -9em; top: -6em; transform: skewX(-4deg); } .baymax::after { background: #000; border-radius: 50%; content: ""; position: absolute; width: 12em; height: 12em; right: -9em; top: -6em; transform: skewX(4deg); } كل من هذه العناصر الزائفة لها خلفية سوداء، وحواف دائرية -border-radius: 50%; لجعلها دائرية. كلّ منها متموضع في نهاية الفم، وأخيرًا لها تحوّل skew لجعلها تبدو كأنَّها مائلة قليلًا للخلف. ستظهر النتيجة كما يلي: البطارية منخفضة هناك مشهدٌ مضحك في الفيلم حيث تنخفض بطارية بيماكس. فيترنَّح وتتدلَّى جفونه. يمكننا استخدام مزيج من الحركات والتدرّجات في الخلفية لإحداث التأثير. نريد أولًا أن نعطي الخلفية لونين. أسود لجزء العين المفتوح، وأبيض للجفن. يحتاج الجزء الأبيض أن يتموضع خارج العينين في البداية، ثمَّ سنحركه لجعل الجفون تتدلَّى. .baymax::before { background: linear-gradient(to bottom, #efefef, #efefef 50%, #000 50%, #000); background-position: 0 -100%; background-size: 200% 200%; ... } .baymax::after { background: linear-gradient(to bottom, #efefef, #efefef 50%, #000 50%, #000); background-position: 0 -100%; background-size: 200% 200%; ... } نحن الآن نضيف تدرّجًا خطيًّا في الخلفية، فنجعله ضعف ارتفاع الحاوية، ثم نحدد موضعه لذا يصبح النصف العلوي خارج الحاوية. مع وجود تدرّجات للخلفية في مكانين، يمكننا أن نضيف حركة keyframes للتحكم في حركة الجفون. @keyframes blink { 0%, 50% { background-position: 0 100%; } 85%, 95% { background-position: 0 75%; } 100% { background-position: 0 100%; } } قاعدة keyframes في الحركات هي طريقة لوصف سلسلة من الإطارات، باستخدام النسبة المئوية. تعود النسبة المئوية لمدى استمرار الحركة، لذا فإنَّ النسبة المئوية 50% منتصف الطريق عبر الحركة. بهذه الطريقة يمكننا ضبط الخلفية للبقاء مستيقظين حتى منتصف الحركة، ثمَّ بين الإطار 50% والإطار85%، تتحرك للأسفل، وثمَّ تستقر في نهاية الحركة. الخطوة التالية هي إخبار العناصر الزائفة أن تستخدم إطارات الحركة هذه. أضف خاصية animation للأنماط الحالية. .baymax::before { animation: blink 6s infinite; ... } .baymax::after { animation: blink 6s 0.1s infinite; ... } أخبرنا المتصفح هنا أن يستخدم حركة blink على كل عنصر. وضبطنا مدة الحركة إلى 6 ثواني وستستمر بشكلٍ لا نهائي. خاصية واحدة إضافية في المثال الثاني: تخبر المدة 0.1s بعد 6s المتصفح أن تتأخر الحركة لـ0.1 ثانية. يخلق هذا تأثير إغلاق العين الثانية بتأخيرٍ عن الأولى. وذلك يضيف التأثير المتدلي والمتعب ويجعلها تبدو أكثر واقعيةً. يجب أن تظهر النتيجة النهائية كما في الصورة: يمكنك مشاهدة تجربة حية. المتصفحات حذفت في أمثلة الشفرة أيّ بادئات معتادة webkit- وmoz-. لكن خاصيّات transform وanimation يجب أن تكون مسبوقة، وأنصحك باستخدام شيء ما مثل Autoprefixer لهذا. نسخة gif قابلة للمشاركة إليك نسخة gif متحركة يمكنك مشاركتها على الإنترنت بسهولة: ترجمة -وبتصرف- للمقال Baymax in CSS
  4. كلنا نعلم أنّ الاستعانة بفريق خارجي لتطوير البرمجيات هو كارثة على وشك الحدوث. أولًا، تجد شركة تعدك بكل ما ترغب به للمنتج من تسليم في الوقت المحدد، وكلفة ضمن الميزانية، وجودة عالية، وواجهة مستخدم جميلة، وتقنيات متطورة، ودعم طويل الأمد خالٍ من المتاعب، لذا ترسل الدفعة الأولى وتبدأ رحلتك. بالكاد يفهم الفريق احتياجاتك، والجودة سيئة، وتُنتهك كل توقعاتك حول الزمن والميزانية بشدّة، ويرتفع مستوى الإحباط. والجزء "الأفضل" هو أنّه لا يمكنك الابتعاد وإلا ستخسر كل الأموال التي أنفقتها وستضطر أن تبدأ من الصفر. يجب أن تبقى "متزوجًا" من هذا الفريق لأنّه لا يمكنك تحمّل "الطلاق". هل هناك طريقة للاستعانة بفريق خارجي لتطوير البرمجيات بشكلٍ صحيح؟ نعم، من الممكن القيام بذلك بشكلٍ صحيح وخالٍ من المتاعب، ولكن يجب أن تكون مستعدًا لتغيّر فلسفة إدارتك. المبدأ الأساسي هنا هو: يجب عليك أن تناقش مخاوفك مع الفريق الخارجي الذي تستعين به بشكلٍ علني ومتكرر، و يجب أن يناقشوا معك المشاكل والمخاطر بشكلٍ علني ومتكرر. هذان عاملان أساسيان للنجاح في الاستعانة بفريق خارجي لتطوير البرمجيات يتم إهمالهما في كثير من الأحيان. لقد تعلّمت هذا المبدأ من Wei Liao Zi. قال في كتاب كلاسيكيات الإستراتيجية العسكرية للصين القديمة الصفحة 239: دعني أوضّح بعض الأمثلة العملية لكوارث الاستعانة بفريق خارجي لتطوير البرمجيات وشرح كيف يمكن تجنبها باتّباع مبدأ عمره 2500 سنة. يستغرق الأمر إلى الأبد وأنا تجاوزت الميزانية دائمًا يكون المنتج جاهزًا بنسبة 95%، ولديك دائمًا شيء ما غير منفَّذ أو معطوب. لقد أنجزوا الكثير من العمل، ودفعت الكثير من المال، ولكن المنتج الجاهز للسوق لم يصل بعد. يستغرق أسبوعًا بعد أسبوع وشهرًا بعد شهر؛ دائمًا هناك أعمال متأخرة، وأنت لا يمكنك إنهاء ذلك ببساطة. لقد بدأت برؤية هذا المشروع في كوابيسك، والفريق لم يعد يساعد بعد ذلك. كيف يبدو هذا؟ مألوفًا؟ أرجو أن تدرك أنّه بغض النظر عن نوع العقد الذي وقّعت عليه مع الفريق الخارجي لتطوير البرمجيات، وعدد الجداول الزمنية التي حددتها، وعدد الوعود التي قطعت لك، يريدون الاحتفاظ بك كعميل إلى الأبد. بالطبع طالما لديك شيء في حسابك المصرفي. تريد أن ينجح عملك ويزدهر، صحيح؟ إنّهم يريدون نفس ذلك لعملهم. نجاحك يعني منتجًا تم إنهاؤه وإطلاقه للمستخدمين النهائيين. نجاحهم يعني عمليةً لا نهائية من كتابة البرامج لك. هناك القليل جدًا من القواسم المشتركة بين هذين الهدفين. أودّ حتى أن أقول أنّهم متناقضين مع بعضهم بعضًا - عندما تنجح، يفشلون. سيخبرونك بالطبع أّنهم يريدون إنهاء هذا المنتج لك والحصول على عقود جديدة في المستقبل. سيقولون أنّ الدافع الأساسي هو جعلك سعيدًا والحصول على توصية جيّدة. سيؤكدون لك أنّ رضا العميل أهم من المال، لكن أقترح عليك أن تكون قويّا بما يكفي لتواجه الواقع، كل هذه أكاذيب. أغلب المشاريع المستعان بها بفريق خارجي لتطوير البرمجيات تفشل. الغالبية العظمى (انظر تقرير شاوس الأخير). يدرك مطورو البرمجيات هذا أفضل منك، لأنّهم في معظم الأحيان يشاهدون كيف يحصل هذا كل يوم. ومشروعك ليس استثناءً. لذلك، دعنا ننسى هذه الوعود الجميلة ونركز على الواقع القبيح - اعتمد على نفسك. بأخذ المبدأ الذي ذكرته في الأعلى بالحسبان، إليك نصيحتي: تأكّد من أنّ الفريق يتفهّم وقتك الفعلي، وميزانيتك، ومجالك، وقيود مجالك عواقب انتهاكها. يتعلّق هذا بالجزء الأول من المبدأ - يجب عليك أن تناقش مخاوفك بشكلٍ علني ومتكرر -. الذي يحدث عادةً أنّ فريق الخارجي المستعان به يبقى غير مدركًا لوضع العمل الحقيقي ويسمع فقط عبارة "أحتاج إلى هذا في أسرع وقت ممكن" مرّةً كل يومين. "أسرع وقت ممكن" هو ليس موعدًا نهائيًا. علاوةً على ذلك، إنّه فقط بديل مثبّط للغاية لمرحلة رئيسية حقيقية. عندما لا يعرف الفريق متى تحتاج المنتج بالضبط، ما الذي يجب أن يكون جاهزًا بحلول ذلك التاريخ، ولماذا، فيبدأ العمل ضدك. التركيز هنا على "لماذا". بالنسبة لمعظم أصحاب الأعمال، من الصعب الإجابة على هذا السؤال. لماذا تحتاج أن يكون المنتج جاهزًا بحلول الأول من حزيران؟ لأنّك سئمت من الانتظار فقط؟ هذه ليست إجابة معقولة. أنت سئمت من ذلك ولكن لا يزال لديك أموالًا في حسابك المصرفي. سيستمرون في إصدار الفواتير لك، ولن يحترمونك. لن يعاملوك كرجل أعمال قوي وموجّه نحو تحقيق الأهداف. إمّا أنّك لست ذكيًا بما يكفي لتحديد القيود الزمنية أو أنّك تخفيها عن الفريق. في كلتا الحالتين لن يقدّروا هذا السلوك. فيما يلي تحديد قيود الوقت والتكاليف بشكلٍ صحيح: يجب أن تكون الميزات A و B و D جاهزة قبل الأول من حزيران، لأنّ حملتنا التسويقية تبدأ في الخامس من حزيران. إذا لم يكونوا جاهزين، سأخسر 25000$ من تكاليف التسويق. إذا حدث هذا سأضطر إلى تخفيض ميزانية التطوير الشهرية إلى النصف. عندما تسمع شركة الاستعانة بفريق خارجي لتطوير البرمجيات، شريكتك، هذا التعريف للموعد النهائي، تصبح شريكًا حقيقيًا لك الآن. الآن أهدافها تتماشى مع أهدافك. إذا تمّ تأخير المرحلة الرئيسية، ستعاني وسيفهمون لماذا بالضبط. إلى جانب ذلك، يرون كيف ستُنقل معاناتك إليهم أيضًا. توقف عن مطالبتهم بإنهاء كل شيء بأسرع وقت ممكن. توقف عن الاتصال بهم مرتين في اليوم والصراخ لساعة بسبب أدائهم الضعيف. توقف عن استخدام اللغة في رسائل البريد الإلكتروني للعمل. توقف عن القيام بكل هذا الضجيج. إنّه لا يساعدك على أيّ حال. علاوةً على ذلك، لا يؤدي هذا إلا إلى جعل الوضع يزداد سوءًا، لأنّك تفقد احترامك وقد بدأوا في معاملتك كبقرةٍ حلوب - بل بالأحرى شخص غبي وعاطفي. بدلًا من ذلك، قم بأداء واجبك وحدد مراحلك الرئيسية الواقعية. فكّر بوقتك الحقيقي، ومجالك، وحدود ميزانيتك. دوّنهم بجمل قصيرة ومختصرة جدًا. تأكّد من أنّ قيودك واقعية ووصفها يجيب على السؤال الرئيسي - لماذا -. لماذا تحتاج هذا بحلول الأول من حزيران؟ لماذا تريد أن تنفق أقل من 50000$؟ لماذا تحتاج أن تكون كل الميزات الخمسة موجودة في النسخة 1.0؟ لماذا تريد لتطبيق الويب الخاص بك أن يكون جاهزًا لمعالجة 1000 جلسة متزامنة؟ لماذا تحتاج إلى تطبيق للهاتف في الإصدار الأول؟ أجب نفسك وتأكّد من أنّ أجوبتك مفهومة من قبل شركة الاستعانة بفريق خارجي. لا تخفي هذه المعلومات. المنتج سيء جدًا تريد أن يبدو تطبيق الويب الخاص بك مثل Pinterest، يتفاعل سريعًا، ويكون سهل الاستخدام، ويجعلك فخورًا عندما تعرضه على أصدقاءك. لكن المنتج الذي بنوه لك سيء، وبطيء، ولأكون صريحًا، قبيح. تطلب منهم أن يفعلوا شيئًا ما بشأنه، ويستمروا في إعطائك الوعود. يستمر المشروع في استهلاك أموالك وتنمو ميزانيته، لكن المظهر والإحساس لا يتحسّن. إنّه بعيد جدًا عن Pinterest. ينمو الإحباط ولا تشاهد أي طريقة معقولة للخروج من هذا. النصيحة الوحيدة التي تتلقاها من أصدقائك هي أن تعيد تنفيذ كل المشروع من الصفر مع فريق تطوير ويب جديد. كيف يبدو هذا؟ أراهن أنّه مألوفًا. أعتقد أنّ السبب الرئيسي للطريق المسدود في هذا الموقف هو الخوف من الصراع. تحاول في المراحل الأولى من المشروع أن تفعل كل ما تستطيع للحفاظ على علاقة جيدة مع شركة الاستعانة بفريق خارجي وعدم الإساءة إلى أيّ شخص. لا تريد أن تتحكم في عمل أي شخص لأنّهم قد يعدونها إهانة. لا تريد أن تعبّر عن مخاوفك بشأن الجودة لأنّها قد تثبّط همّة الفريق. أنت فقط تأمل أنّهم سيحسّنون المنتج في المستقبل، لكن عندما يأتي المستقبل، يكون متأخرًا جدًا. مجددًا، مع أخذ المبدأ القديم بعين الاعتبار، أنصحك بأن تقوم بإجراء روتيني من اليوم الأول للمشروع للتحقق من نتائجهم والتعبير عن مخاوفك. في مشاريعنا في Zerocracy نطلب من عملاءنا أن يكونوا موجودين في GitHub، ويراجعوا إصداراتنا بشكلٍ متكرر، ويبلغونا عن أيّة تناقضات موجودة كمشكلات (issues) في GitHub. نشجّع رعاة المشروع أن يكونوا متشائمين وسلبيين بشأن جودتنا منذ بداية المشروع. نحن ندرك أن هذه الطريقة يمكننا بها تقليل خطر "الإحباط المتراكم". حاول أن تفعل الشيء ذاته في مشروعك الذي تمّ به الاستعانة بفريق خارجي. لا تخف من الإساءة إليهم. النقد التكراري والتدريجي منهجية أكثر صحةً من السلام الخالي من ردود الفعل والذي ينتهي بالحرب. ابحث عن طريقة ليبقى الفريق المستعان على درايةٍ برأيك حول نتائجه بشكلٍ منتظم. لا تحاول أن تكون لطيفًا لتحافظ على مشروعك.أنت تقدّم لنفسك معروفًا سيئًا. بدلًا من ذلك، كن منفتحًا بشأن مخاوفك. تذكر الجزء الأول من المبدأ أعلاه - يجب عليك أن تناقش مخاوفك بشكلٍ علني ومتكرر. هذه هي الطريقة التي سيستقر بها المشروع وتقلّ بها المخاطر. أيضًا، هناك ممارسة جيّدة جدًا، من وقت لآخر، وهي دعوة المراجعين التقنيين ليعطوا آراءً مستقلة حول المنتج قيد التطوير. اقرأ مشاركتي الأخرى حول هذا الموضوع: هل تحتاج لمراجعات تقنية مستقلة؟. لا يمكنني الاعتماد على وعودهم تتصل بهم، وتضعون الخطط، وتوضّحون المراحل الرئيسية، وتعرّفون الميزات، وتحددون الأولويات، وتتفقون على الجودة، ثمّ تنهي الاتصال. خلال أيّام قليلة، تدرك أنّه كان مضيعة للوقت. إنّهم لا يحافظون على وعودهم لأنّ هناك دائمًا شيء ما جديد يحدث. شخصٌ ما مريض، خادمٌ معطل، بعض أجزاء البرنامج غير صالحة للعمل، بعض الشيفرة لم تعد تعمل، وما إلى ذلك. تتصل مجددًا، تعبّر عن إحباطك، وتوجّه اتهامات قوية، وتعيد هيكلة المراحل، وتعيد تعريف الميزات، وتعيد تحديد الأولويات، وخلال عدّة أيّام تبدأ من جديد. كنت هناك، وقمت بذلك؟ هل يبدو هذا مألوفًا؟ من خلال تجربتي، فإنّ سبب عدم القدرة على التنبؤ وعدم موثوقية الفريق الخارجي في معظم الحالات هو راعي المشروع. يحدث هذا عندما لا تستمع إليهم أو يخشون أن يقولوا لك الحقيقة، والذي هو عادةً نفس الشيء. يطلق البعض على هذا "التطوير المُقاد بالخوف". يخاف الفريق منك، ولكي يحتفظ الفريق بك كعميل يدفع له المال، يضطر أن يكذب عليك. في الأساس، يخبرونك بما تريد أن تسمعه - أنّ نهاية المشروع قريبة، والأخطاء الموجودة حاليًا سهلة الإصلاح، وأنّ مشاكل الأداء بسيطة، وأنّ جودة المعمارية رائعة، وأنّ الفريق متحمس جدًا للعمل معك. عندما تسمع أي مما سبق، اسأل نفسك - هل تشجعهم على قول الحقيقة؟ هل تكافؤهم على إعطائك أخبارًا سيئة لكن صادقة؟ بالإشارة إلى المبدأ الأساسي المذكور أعلاه، مجددًا، أنصحك بالتأكد من أنّ منطقك في المكافآت والعقوبات شفاف لشريكك، الفريق الخارجي، ويستند إلى أهداف المشروع، وفقًا للمبدأ الأساسي وليس لمشاعرك الشخصية. في إحدى منشوراتي السابقة، كتبت أنّ العميل السعيد هو هدف خاطئ لفريق تطوير البرمجيات. العميل الذي يدعم هذا الهدف هو عميل رهيب محكوم عليه بفشل المشروع. إذا كافأت فريقك عندما يُشعرك بالسعادة بالأخبار الجيّدة، فأنت تدرّبهم على الكذب عليك. إذا كنت تتوقع منهم أخبارًا جيّدة، فأنت لا تشجعهم على إخبارك بالحقيقة وعلى القيام بما هو جيّد للمشروع، ليس لك شخصيًّا. أنت لا تشجعهم على الجدال معك. بكلماتٍ أخرى، أنت تخنق قناة المعلومات التي من المفترض أن تأتي إليك من الأشخاص الذين يعملون معك. أنت تعزل نفسك، والفريق بدأ بالعمل ضدك، ليس معك. إليك نصيحةً عمليّةً. أولًا، أعلن عن أهدافك وقيودك المعقولة بانتظام، كما شرحت أعلاه. تأكّد من فهم الفريق لخطط عملك و"لماذا" الأسباب الكامنة وراءها. ثانيًا، اسأل أعضاء الفريق بانتظام عن المخاطر والمشاكل. اسألهم لماذا يعتقدون أن أهداف المشروع قد تتعرض للخطر. ومن الأفضل أن تدعهم يوثّقوا المخاطر بانتظام ويبلغوك بها. كافئهم على صدقهم في قائمة المخاطر هذه. جرّب ذلك وستُفاجأ بعدد الأشياء المثيرة للاهتمام التي ستتضمنها قائمة المخاطر. ترجمة -وبتصرف- للمقال How to Avoid a Software Outsourcing Disaster لصاحبه Yegor Bugayenko
  5. ASP.NET Core هي إطار عمل مفتوح المصدر وعالي الأداء لإنشاء تطبيقات ويب حديثة، ومن المفترض أن يكون النسخة الأفضل من إطار العمل ASP.NET لمايكروسوفت. تمَّ إصداره عام 2016، ويمكن تشغيله على العديد من أنظمة التشغيل مثل لينكس وmacOS، مما يتيح للمطورين استهداف نظام تشغيل معين للتطوير اعتمادًا على متطلبات التصميم. يستطيع المطور باستخدام ASP.NET Core بناء أي نوع من تطبيقات الويب أو الخدمات بغض النظر عن التعقيد والحجم. يمكن للمطورين أيضًا استخدام صفحات Razor لإنشاء تصميم يركز على الصفحة يعمل أعلى النمط التقليدي MVC (اختصارًا للعبارة Model-View-Controller). يوفر ASP.NET Core المرونة للتكامل مع أي إطار عمل للواجهة الأمامية للتعامل مع العمليات المنطقية من طرف العميل أو استخدام خدمة ويب. مثلًا، بإمكانك بناء واجهة برمجية RESTful مع ASP.NET Core واستخدامها ببساطة مع أطر عمل جافاسكربت مثل Angular، React و Vue.js. ستعدّ في هذا الدرس تطبيق ASP.NET Core وتنشره ليكون جاهزًا للإطلاق مع خادم MySQL على أوبنتو 18.04 باستخدام Nginx. ستنشر تطبيق ASP.NET Core تجريبي مماثل للتطبيق من توثيق مايكروسوفت والمُستضاف على GitHub. بمجرد أن يتم النشر، سيسمح لك التطبيق التجريبي بإنشاء قائمة أفلام وتخزينها في قاعدة البيانات. ستكون قادرًا على إنشاء، وقراءة، وتحديث، وحذف سجلات من قاعدة البيانات. يمكنك بدلًا من ذلك استخدام هذا الدرس لتنشر تطبيق ASP.NET Core خاص بك؛ من الممكن أن تحتاج إلى تنفيذ خطواتٍ إضافيةٍ تتضمن إنشاء ملف تهجير (migration) جديد إلى قاعدة البيانات الخاصة بك. المتطلبات الأساسية ستحتاج لما يلي لاتباع هذا الدرس: خادم أوبنتو 18.04 تم ضبطه باستخدام دليل التهيئة الأولية لخادم أوبنتو 18.04، متضمنًا مستخدمًا عاديًا مع وصول sudo وجدار حماية. خادم Nginx مثبَّت باتباع الخطوات كيفية تثبيت Nginx على أوبنتو 18.04. خادم ويب Nginx آمن. بإمكانك اتباع درس كيف تؤمّن خادم Nginx بشهادة Let's Encrypt في أوبنتو للقيام بذلك. ضبط سجلَّي الـ DNS لخادمك. يمكنك اتّباع هذه المقدمة إلى DigitalOcean DNS للتفاصيل حول كيفية إضافتها. سجل A مع إشارة اسم النطاق الخاص بك your-domain إلى عنوان IP العام للخادم. سجل A مع إشارة اسم النطاق الخاص بك مسبوقًا بـ www www.your-domain. إلى عنوان IP العام للخادم. نظام إدارة قواعد البيانات MySQL مثبَّت باتباع خطوات كيف تثبّت الإصدار الأخير من MySQL على أوبنتو 18.0. الخطوة 1: تثبيت مُشِّغل NET Core. الآني مُشِّغل NET Core. الآني (أي NET Core runtime.) مطلوب لتشغيل تطبيق NET Core.، لذا يجب البدء بتثبيته على جهازك. تحتاج أولًا لتسجيل مفتاح مايكروسوفت ومستودع المنتج. بعد ذلك ستثبّت الاعتماديات (dependencies) المطلوبة. أولًا، سجّل الدخول كمستخدم مُنشأ حديثًا، وتأكّد من أنَّك في المجلد الجذر: $ cd ~ ثمّ نفّذ الأمر التالي لتسجيل مفتاح مايكروسوفت ومستودع المنتج: $ wget -q https://packages.microsoft.com/config/ubuntu/18.04/packages-microsoft-prod.deb استخدم dpkg مع الراية i- لتثبيت الملف المحدد: $ sudo dpkg -i packages-microsoft-prod.deb لتسهيل تثبيت الحزم الأخرى الضرورية لتطبيقك، ستثبّت مستودع universe باستخدام الأمر التالي: $ sudo add-apt-repository universe ثمّ ثبّت حزمة apt-transport لتسمح باستخدام المستودعات التي يتم الوصول إليها عبر بروتوكول HTTP الآمن: $ sudo apt install apt-transport-https نفِّذ الأمر التالي لتنزيل قائمة الحزم من المستودعات وتحديثها للحصول على معلومات حول أحدث إصدارات الحزم واعتمادياتها: $ sudo apt update أخيرًا، يمكنك تثبيت SDK لمشغّل NET. الآني عبر الأمر: $ sudo apt install dotnet-sdk-2.2 ستُعرض تفاصيل ما سيجري تنزيله ويُطلب تأكيد ذلك عبر الضغط على Y أي yes للمتابعة. لقد انتهيت الآن من تثبيت SDK لمشغّل NET Core. الآني على الخادم، وأنت جاهز تقريبًا لتنزيل التطبيق التجريبي من Github لضبط إعدادات النشر. لكن أولًا يجب إنشاء قاعدة بيانات التطبيق. الخطوة 2: إنشاء مستخدم MySQL وقاعدة بيانات ستنشئ في هذا الجزء مستخدم على خادم MySQL، وقاعدة بيانات للتطبيق، وتمنح جميع الصلاحيات الضرورية للمستخدم الجديد ليتصل بقاعدة البيانات من تطبيقك. تحتاج لتبدأ إلى الوصول لـMySQL العميل باستخدام حساب MySQL الجذر كما هو موضح هنا: $ mysql -u root -p سيُطلب منك إدخال كلمة سر الحساب الجذر الذي تمّ إعداده ضمن درس المتطلبات الأساسية. ثم أنشئ قاعدة بيانات MySQL للتطبيق باستخدام الأمر: mysql> CREATE DATABASE MovieAppDb; ستشاهد الخرج التالي في سطر الأوامر: Output Query OK, 1 row affected (0.03 sec) لقد أنشأت الآن قاعدة البيانات بنجاح، بعد ذلك ستُنشئ مستخدم MySQL جديد، وتربطه بقاعدة البيانات التي أُنشئت حديثًا، وتمنحه جميع الصلاحيات. نفّذ الأمر التالي لتُنشئ مستخدم MySQL وكلمة مرور. تذكّر أن تغيّر اسم المستخدم وكلمة المرور ليصبحوا أكثر أمانًا: mysql> CREATE USER 'movie-admin'@'localhost' IDENTIFIED BY 'password'; ستشاهد الخرج التالي: Output Query OK, 0 rows affected (0.02 sec) يحتاج مستخدم MySQL إلى الإذن المناسب للوصول إلى قاعدة بيانات أو تنفيذ إجراء محدد عليها، حاليًا لا يملك المستخدم movie-admin الإذن المناسب على قاعدة بيانات التطبيق. سنغيّر ذلك بتنفيذ الأمر التالي لمنح حق الوصول للمستخدم movie-admin إلى قاعدة البيانات MovieAppDb: mysql> GRANT ALL PRIVILEGES ON MovieAppDb.* TO 'movie-admin'@'localhost'; ستشاهد الخرج التالي: Output Query OK, 0 rows affected (0.01 sec) يمكنك الآن إعادة تحميل جداول الصلاحيات بتشغيل الأمر التالي لتطبيق التغييرات التي قمت بها باستخدام عبارة التدفق: mysql> FLUSH PRIVILEGES; ستشاهد الخرج التالي: Output Query OK, 0 rows affected (0.00 sec) لقد أنشأت مستخدم جديد ومنحه الصلاحيات. لتختبر فيما إذا تمّ الأمر بشكلٍ صحيحٍ، أغلق MySQL العميل: mysql> quit; ثمّ سجّل الدخول مجددًا باستخدام بيانات الاعتماد لمستخدم MySQL الذي أنشأته وأدخل كلمة المرور المناسبة عندما تُطلب منك: $ mysql -u movie-admin -p للتأكد من أن المستخدم movie-admin يمكنه الوصول إلى قاعدة البيانات المُنشأة، تحقق باستخدام الأمر: mysql> SHOW DATABASES; الآن ستشاهد جدول MovieAppDb ضمن قائمة الخرج: Output +--------------------+ | Database | +--------------------+ | MovieAppDb | | information_schema | +--------------------+ 2 rows in set (0.01 sec) الآن، أغلق MySQL العميل: mysql> quit; لقد أنشأت قاعدة بيانات، ومستخدم MySQL جديد للتطبيق التجريبي، ومنحت المستخدم الجديد الصلاحيات الصحيحة للوصول إلى قاعدة البيانات. في الجزء التالي، ستبدأ بضبط التطبيق التجريبي. الخطوة 3: ضبط التطبيق التجريبي وبيانات اعتماد قاعدة البيانات كما ذُكر سابقًا، ستنشر تطبيق ASP.NET Core موجود. تم بناء هذا التطبيق لإنشاء قائمة أفلام باستخدام نمط التصميم (Model-View-Controller) لضمان وجود الهيكل المناسب والفصل بين الاهتمامات. لإنشاء أو إضافة فيلم جديد إلى القائمة، سيملأ المستخدم حقول النموذج بالتفاصيل المناسبة ويضغط على زر إنشاء لإرسال التفاصيل إلى المتحكم (controller). عند ذلك يستقبل المتحكم طلب POST HTTP مع التفاصيل المرسلة وتبقى البيانات في قاعدة البيانات من خلال النموذج (model). ستستخدم Git لسحب (pull) الشيفرة المصدرية لهذا التطبيق التجريبي من GitHub وحفظه في مجلد جديد. يمكنك أيضًا تحميل تطبيق بديل إذا كنت ستنشر تطبيقًا مختلفًا. للبدء، أنشئ مجلدًا جديدًا باسم movie-app من الطرفية (terminal) باستخدام الأمر التالي: $ sudo mkdir -p /var/www/movie-app سيكون هذا المجلد بمثابة المجلد الجذر لتطبيقك. بعد ذلك، عدّل مالك ومجموعة المجلد للسماح لحساب المستخدم العادي بالعمل على ملفات المشروع: $ sudo chown sammy:sammy /var/www/movie-app استبدل sammy باسم المستخدم العادي الذي يملك صلاحيات sudo. يمكنك الآن الانتقال إلى المجلد الأب ونسخ (clone) التطبيق من Github: $ cd /var/www $ git clone https://github.com/do-community/movie-app-list.git movie-app ستشاهد الخرج التالي: Output Cloning into 'movie-app'… remote: Enumerating objects: 91, done. remote: Counting objects: 100% (91/91), done. remote: Compressing objects: 100% (73/73), done. remote: Total 91 (delta 13), reused 91 (delta 13), pack-reused 0 Unpacking objects: 100% (91/91), done. لقد نسخت التطبيق التجريبي بنجاح من GitHub، لذا ستكون الخطوة التالية هي إنشاء اتصال ناجح بقاعدة بيانات التطبيق. ستقوم بذلك عن طريق تعديل خاصية ConnectionStrings ضمن ملف appsettings.json وإضافة تفاصيل قاعدة البيانات. غيّر المجلد ضمن التطبيق: $ cd movie-app ثم افتح الملف للتعديل: $ sudo nano appsettings.json أضف بيانات اعتماد قاعدة البيانات في ملف appsettings.json: { "Logging": { "LogLevel": { "Default": "Warning" } }, "AllowedHosts": "*", "ConnectionStrings": { "MovieContext": "Server=localhost;User Id=movie-admin;Password=password;Database=MovieAppDb" } } بوضع هذه البيانات بطريقةٍ صحيحة فقد أنشأت اتصالًا ناجحًا بقاعدة البيانات. الآن اضغط CTRL+X لحفظ تغييرات الملف واضغط Y للتأكيد. ثم اضغط ENTER لإغلاق الصفحة. تستخدم تطبيقات ASP.NET Core مكتبة NET. قياسية تسمّى Entity Framework (EF) Core لإدارة التفاعل مع قاعدة البيانات. Entity Framework Core هي إصدار خفيف عابر للمنصات (cross-platform) من التقنية الشائعة للوصول إلى بيانات Entity Framework. إنّها تقنية ربط الكائنات بالعلاقات (ORM) التي تتيح لمطوري NET. العمل مع قاعدة البيانات باستخدام أي مزود قاعدة بيانات، مثل MySQL. يمكنك الآن تحديث قاعدة بياناتك مع الجداول من التطبيق التجريبي المنسوخ. نفّذ الأمر التالي لهذا الغرض: $ dotnet ef database update سيحدّث هذا الأمر قاعدة البيانات ويُنشئ المخططات المناسبة. الآن، لتبني المشروع وكلّ اعتمادياته، نفّذ الأمر التالي: $ dotnet build ستشاهد خرجًا مشابهًا للتالي: Output Microsoft (R) Build Engine version 16.1.76+g14b0a930a7 for .NET Core Copyright (C) Microsoft Corporation. All rights reserved. Restore completed in 95.09 ms for /var/www/movie-app/MvcMovie.csproj. MvcMovie -> /var/www/movie-app/bin/Debug/netcoreapp2.2/MvcMovie.dll MvcMovie -> /var/www/movie-app/bin/Debug/netcoreapp2.2/MvcMovie.Views.dll Build succeeded. 0 Warning(s) 0 Error(s) Time Elapsed 00:00:01.91 سيؤدي هذا إلى بناء المشروع وتثبيت أيّة اعتماديات خارجية (third-party dependencies) مذكورة في ملف project.assets.json، ولكن لن يكون التطبيق جاهزًا للنشر بعد. نفّذ الأمر التالي ليصبح التطبيق جاهزًا للنشر: $ dotnet publish ستشاهد التالي: Output Microsoft (R) Build Engine version 16.1.76+g14b0a930a7 for .NET Core Copyright (C) Microsoft Corporation. All rights reserved. Restore completed in 89.62 ms for /var/www/movie-app/MvcMovie.csproj. MvcMovie -> /var/www/movie-app/bin/Debug/netcoreapp2.2/MvcMovie.dll MvcMovie -> /var/www/movie-app/bin/Debug/netcoreapp2.2/MvcMovie.Views.dll MvcMovie -> /var/www/movie-app/bin/Debug/netcoreapp2.2/publish/ هذا سيُحزّم التطبيق ويترجمه، ويقرأ اعتمادياته، وينشر مجموعة الملفات الناتجة في مجلد للنشر، ويُنتج ملف dll. عابر للمنصات يستخدم مشغّل NET Core. الآني المثبّت لتشغيل التطبيق. بتثبيت الاعتماديات، وإنشاء اتصال بقاعدة البيانات، وتحديث قاعدة البيانات بالجداول الضرورية، ونشرها للإنتاج، تكون قد أكملت ضبط التطبيق التجريبي. في الخطوة التالية ستضبط إعدادات خادم الويب لجعل التطبيق متاحًا وآمنًا على نطاقك. الخطوة 4: ضبط إعدادات خادم الويب الآن وبعد اتّباع درس كيف تؤمّن خادم Nginx بشهادة Let's Encrypt ستحصل على كتلة الخادم لنطاقك في ‎/etc/nginx/sites-available/your_domain مع توجيه server_name الذي تمّ تعيينه بالفعل بشكلٍ مناسب. في هذه الخطوة ستعدّل كتلة الخادم هذه لتقوم بضبط Nginx كوكيل (proxy) عكسي لتطبيقك. الوكيل العكسي هو خادم يقع أمام خوادم الويب ويعيد توجيه كل طلب من مستعرض الويب إلى خوادم الويب هذه. إنّه يستقبل كل الطلبات من الشبكة ويعيد توجيهها إلى خادم ويب مختلف. في حالة تطبيق ASP.NET Core، يعدّ خادم الويب Kestrel هو الخادم المفضّل المضمّن افتراضيًا، وهذا ممتاز لتقديم المحتوى الديناميكي من تطبيق ASP.NET Core لكونه يوفر أداءً أفضل لمعالجة الطلبات وقد صُمم لجعل ASP.NET أسرع قدر الإمكان. ومع ذلك لا يعد Kestrel خادم ويب كامل المواصفات لأنه لا يمكنه إدارة الأمان وتقديم الملفات الثابتة، ولهذا يُستحسن دائمًا تشغيله خلف خادم ويب. للبدء، تأكد من أنّك داخل المجلد الجذر للخادم: $ cd ~ افتح كتلة الخادم للتعديل بهذا الأمر: $ sudo nano /etc/nginx/sites-available/your_domain كما هو مفصّل في الخطوة 4 من درس كيف تؤمّن خادم Nginx بشهادة Let's Encrypt، إذا اخترت الخيار 2، فإنَّ برنامج Certbot سيضبط تلقائيًا كتلة الخادم هذه لإعادة توجيه حركة مرور HTTP إلى HTTPS مع بعض التعديلات فقط. تابع الإعدادات بضبط أول كتلتين في الملف لتصل إلى ما يلي في ملف ‎/etc/nginx/sites-available/your-domain: server { server_name your-domain www.your-domain; location / { proxy_pass http://localhost:5000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection keep-alive; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } listen [::]:443 ssl ipv6only=on; # managed by Certbot listen 443 ssl; # managed by Certbot ssl_certificate /etc/letsencrypt/live/your-domain/fullchain.pem; # managed by Certbot ssl_certificate_key /etc/letsencrypt/live/your-domain/privkey.pem; # managed by Certbot include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot } … هذه الإعدادات في كتلة الخادم ستطلب من خادم Nginx التنصّت على المنفذ 443، الذي هو المنفذ القياسي للمواقع التي تستخدم SSL. بالإضافة إلى ذلك سيقبل Nginx حركة المرور العامة على المنفذ 443 ويعيد توجيه كل طلب مطابق إلى خادم Kestrel المدمج http://localhost:5000. أخيرًا، بعد كتلة الخادم التي عدلتها في الملف، تأكّد من أنّ كتلة الخادم الثانية في الملف ‎/etc/nginx/sites-available/your-domain تبدو كالتالي: … server { if ($host = www.your-domain) { return 301 https://$host$request_uri; } # managed by Certbot if ($host = your-domain) { return 301 https://$host$request_uri; } # managed by Certbot listen 80; listen [::]:80; server_name your-domain www.your-domain; return 404; # managed by Certbot } ستعيد كتلة الخادم توجيه كل الطلبات إلى https://your-domain وhttps://www.your-domain لوصول HTTPS آمن. بعد ذلك، دع Nginx يعكس التغييرات التي قمت بها على كتلة الخادم بتنفيذ الأمر: $ sudo nginx -s reload بعد إكمال إعداد خادم Nginx، تمّ ضبط الخادم بالكامل لإعادة توجيه جميع طلبات HTTPS الموجهة إلى https://your-domain على تطبيق ASP.NET Core الذي يعمل على الخادم Kestrel إلى http://localhost:5000. ولكن لم يتم ضبط Nginx ليدير إجراء الخادم Kestrel. ستستخدم وظائف systemd لمعالجة هذا والتأكّد من أنّ عملية Kestrel تعمل في الخلفية. ستسمح لك ملفات Systemd بأن تدير إجراءًا من خلال توفير وظائف البدء، والإيقاف، وإعادة التشغيل، والدخول، حالما تنشئ إجراء عمل يدعى وحدة. انتقل ضمن مجلد systemd: $ cd /etc/systemd/systems أنشئ ملفًا جديدًا للتعديل: $ sudo nano movie.service وأضف المحتوى التالي له: [Unit] Description=Movie app [Service] WorkingDirectory=/var/www/movie-app ExecStart=/usr/bin/dotnet /var/www/movie-app/bin/Debug/netcoreapp2.2/publish/MvcMovie.dll Restart=always RestartSec=10 SyslogIdentifier=movie User=sammy Environment=ASPNETCORE_ENVIRONMENT=Production Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false [Install] WantedBy=multi-user.target يحدد ملف الإعداد موقع مجلد المشروع مع WorkingDirectory وأمر التنفيذ في بداية العملية في ExecStart. بالإضافة إلى ذلك، لقد اعتدت على استخدام توجيه RestartSec لوصف متى سيتم إعادة تشغيل خدمة systemd إذا تعطلت خدمة مشغّل NET. الآني. الآن، احفظ الملف وفعّل خدمة movie المنشأة حديثًا مع الأمر: $ sudo systemctl enable movie.service بعد ذلك، تابع لتشغيل الخدمة والتحقق من أنّها تعمل عند التشغيل: $ sudo systemctl start movie.service ثمّ تفحّص حالتها: $ sudo systemctl status movie.service ستشاهد الخرج التالي: Output movie.service - Movie app Loaded: loaded (/etc/systemd/system/movie.service; enabled; vendor preset: enabled) Active: active (running) since Sun 2019-06-23 04:51:28 UTC; 11s ago Main PID: 6038 (dotnet) Tasks: 16 (limit: 1152) CGroup: /system.slice/movie.service └─6038 /usr/bin/dotnet /var/www/movie-app/bin/Debug/netcoreapp2.2/publish/MvcMovie.dll يعطيك هذا الخرج نظرةً عامةً عن الحالة الراهنة لخدمة movie.service المنشأة لتحافظ على التطبيق شغّالًا. تشير إلى أنّ الخدمة شغّالة وفعّالة حاليًا. انتقل إلى https://your-domain من متصفحك لتشغيل التطبيق واختباره. ستشاهد الصفحة الرئيسية للتطبيق التجريبي- تطبيق قائمة الأفلام. مع الخادم الوكيل العكسي وKestrel الذي تتم إدارته باستخدام systemd، تم ضبط تطبيق الويب بالكامل ويمكن الوصول إليه من المتصفح. خاتمة نشرت في هذا الدرس تطبيق ASP.NET Core على خادم أوبنتو. وقمت بتثبيت خادم MySQL واستخدمته لاستمرار البيانات وإدارتها، واستخدمت خادم الويب Nginx كوكيل عكسي لخدمة تطبيقك. بعد هذا الدرس، إذا كنت مهتمًا ببناء تطبيق ويب تفاعلي باستخدام #C بدلًا من جافاسكربت، يمكنك تجربة إطار العمل Blazor لواجهة المستخدم للويب من مايكروسوفت. إنّه واجهة المستخدم للويب تعتمد على المكونات ومقادة بالأحداث لتحقيق المنطق من جهة العميل في تطبيق ASP.NET Core. إذا كنت ترغب بنشر تطبيقك، ستحتاج إلى أخذ الإجراءات الأخرى بالحسبان لنشر تطبيقك. الشيفرة المصدرية الكاملة لهذا التطبيق التجريبي تجدها هنا على GitHub. ترجمة -وبتصرف- للمقال How To Deploy an ASP.NET Core Application with MySQL Server Using Nginx on Ubuntu 18.04 لصاحبه Oluyemi Olususi
  6. تعدّ الصيانة هي الميزة الأكثر قيمةً لتطوير البرمجيات الحديثة. يمكن تعريف قابلية الصيانة بشكلٍ أساسيّ بأنّها وقت العمل اللازم لمطور جديد حتى يتعلم البرنامج قبل أن يتمكن من البدء في إجراء تغييرات مهمة فيه. كلما طال الوقت، انخفضت الصيانة. يقترب هذا الشرط الزمني في بعض المشاريع من اللانهاية، مما يعني أنه غير قابل للصيانة حرفيًا. أعتقد أن هناك سبعة أخطاء أساسية وقاتلة تجعل برنامجنا غير قابلٍ للإصلاح وإليك هذه الأخطاء. الأنماط المضادة لسوء الحظ، لغات البرمجة التي نستخدمها مرنة جدًا. إنها تسمح بالكثير وتمنع القليل جدًا. مثلًا، لا تعارض لغة جافا وضع التطبيق بالكامل في "صنف" واحد مع عدة آلاف تابع. تقنيًا، سيتم ترجمة التطبيق وتشغيله. ولكن هذا نمط مضاد معروف يدعى God object. وبالتالي، فإن النمط المضاد هو طريقة مقبولة تقنيًا لتصميم الأشياء التي يُتفق عليها عمومًا أنها خاطئة. هناك العديد من الأنماط المضادة (anti-pattern) في كل لغة. وجودها في منتجك يشبه وجود الورم في الكائن الحي. بمجرد أن يبدأ في النمو، يصبح من الصعب جدًا إيقافه. وفي النهاية، يموت الجسم بأكمله. في النهاية، يصبح البرنامج بأكمله غير قابلِ للإصلاح ويجب إعادة كتابته. بمجرد السماح لبعض الأنماط المضادة في المنتج، ستحصل في النهاية على المزيد منها، وسينمو "الورم" فقط. يعدُّ هذا صحيح خاصةً بالنسبة للغات البرمجية كائنية التوجه (Java، و C ++، و Ruby وPython) ويرجع ذلك غالبًا إلى أنها ترث العديد من اللغات الإجرائية (C، Fortran وCOBOL) ولأن مطوري OOP يميلون للتفكير بطريقة إجرائية وضرورية. على كلّ حال، بالإضافة إلى قائمة الأنماط المضادة المعروفة الموجودة، أنا أعدّ أيضًا أنَّ هذه الأشياء القليلة منهجيات تشفير سيئة. اقتراحي العملي الوحيد هنا هو القراءة والتعلّم. ربما تساعدك هذه الكتب أو كتاب "Elegant Objects" في ذلك. حاول دائمًا أن تشك في جودة برنامجك، ولا تكتفي بأن "يعمل فقط". كما هو الحال مع السرطان، كلما تم تشخيصه أبكر، كانت فرصة النجاة أكبر. تغييرات لا يمكن تعقبها عندما أنظر إلى سجل الإيداع (commit) يجب أن أكون قادرًا على توضيح كل تغيير، ما الذي تغير، ومن قام بالتغيير، ولماذا تم إجراء التغيير. إضافةً لذلك، يجب قياس الوقت اللازم للحصول على إجابات هذه الأسئلة الثلاثة بالثواني. ولكن في معظم المشاريع لا يتم تطبيق ذلك. إليكم بعض التوصيات العملية: استخدم الملاحظات دائمًا بغض النظر عن مدى صغر حجم المشروع أو الفريق، حتى لو كنت فيه لوحدك فقط، أنشئ ملاحظات (مشكلات GitHub) لكل مشكلة تحلّها. اشرح المشكلة باختصار في الملاحظة ووثّق ما تفكر به هناك. استخدم الملاحظة كمخزن مؤقت لجميع المعلومات المتعلقة بالمشكلة. انشر كل شيء يمكن أن يكون له أي فائدة مستقبلًا، عندما يحاول شخص ما فهم ما هي "تلك الالتزامات الغريبة القليلة". أضف مراجعًا للملاحظات في الإيداعات لا داعٍ للقول أنّه يجب أن يكون لكل إيداع (commit) رسالة. الالتزامات بدون رسائل تعتبر ممارسة سيئة جداً؛ لن أناقش لماذا. ولكن الرسالة بمفردها لا تعد كافية. يجب أن تبدأ كل رسالة برقم الملاحظة التي تعمل عليها. سيقوم GitHub (أنا متأكد من أنك تستخدمه) بربط الالتزامات والملاحظات تلقائيًا، مما يزيد من إمكانية تتبع التغييرات. لا تحذف أي شيء يسمح لنا Git بالقيام برفع (push) "قسري" يقوم بالكتابة فوق كامل الفرع (branch) الذي كان موجودًا سابقًا على الخادم. هذا مجرد مثال واحد على كيفية إتلاف سجل التطوير. شاهدت عدة مرات أشخاصًا يحذفون تعليقاتهم في مناقشات GitHub لجعل الملاحظات تبدو أكثر "نظافة". هذا خطأ، لا تقم أبدًا بحذف أي شيء. حافظ على سجلك بغض النظر عن مدى السوء (أو الفوضوية) التي قد تبدو لك الآن. الإصدارات المخصصة يجب أن يُحزَّم كل جزء من البرنامج قبل أن يتم تسليمه إلى المستخدم النهائي. إذا كنت تتعامل مع مكتبة جافا، فيجب أن تُحزَّم كملف ‎.jar ويتم تصديرها إلى مستودع ما؛ إذا كان تطبيق ويب، فيجب نشره على المنصة، وما إلى ذلك. بغض النظر عن صغر حجم المنتج أو كِبره، فهناك دائمًا إجراء معياري يختبر ويُحزِّم وينشر. سيكون الحل المثالي هو أتمتة هذا الإجراء بحيث يكون من الممكن تنفيذه من سطر الأوامر باستخدام أمر واحد $ ./release.sh ... DONE (took 98.7s) معظم المشاريع بعيدة عن ذلك، إذ تتضمن عملية إصدارها دائمًا بعض السحر، فيتعين على الشخص المسؤول عن المشروع (المعروف أيضًا باسم DevOp) النقر فوق بعض الأزرار هنا وهناك، وتسجيل الدخول إلى مكان ما، والتحقق من بعض المقاييس، وما إلى ذلك. لا تزال عملية الإصدار المخصص هذه خطأً نموذجيًا في صناعة الهندسة البرمجية بأكملها. يمكنني هنا تقديم نصيحة عملية واحدة فقط: "الأتمتة"، أنا أستخدم rultor.com من أجل ذلك، لكن يمكنك استخدام أي أدوات تريدها. المهم أن يكون الإجراء بأكمله مؤتمتًا بالكامل ويمكن تنفيذه من سطر الأوامر. تحليل ثابت طوعي التحليل الثابت هو ما يجعل شيفرتنا تبدو أفضل. وبجعلها تبدو أفضل، فإننا حتمًا نجعلها تعمل بشكل أفضل. لكن هذا يحدث فقط عندما يضطر الفريق بأكمله إلى اتباع القواعد التي يحددها المحلل (أو المحللون) الثابت (static analyzer). لقد كتبت عن ذلك في التحكم الصارم لجودة شيفرة الجافا. يمكنني استخدام qulice.com في مشاريع Java و rubocop.com في Ruby، وهناك العديد من الأدوات المشابهة لكل لغة تقريبًا. يمكنك استخدام أيّا منها، ولكن اجعله إلزاميًا، في معظم المشاريع التي يستخدم فيها التحليل الثابت، يبني المطورون تقارير جيدة المظهر ويواصلون كتابة الشيفرة بالطريقة التي استخدموها من قبل. لا يتم بمثل هذه المنهجية "التلقائية" تقديم أيّة إضافات للمشروع. وعلاوة على ذلك، فإنّها تخلق وَهمْ الجودة. ما أقوله هو أن التحليل الثابت يجب أن يكون خطوة إلزامية عند الإعداد للنشر. لا يمكن أن تتم عملية بناء المشروع في حال انتهاك أي قاعدة من قواعد التحليل الثابت. تغطية اختبار غير معروف ببساطة، تغطية الاختبار هي درجة اختبار البرنامج من خلال اختبارات الوحدة أو التجميع. كلما زادت التغطية، تم تنفيذ "كمية" أكبر من الشيفرة أثناء إجراء الاختبارات. من الواضح أن التغطية الأعلى أمر جيد. لكن الكثير من مطوري المشاريع لا يعرفون مقدار تغطية مشاريعهم ولا يعتمدون هذا المقياس. قد يكون لديهم بعض الاختبارات، لكن لا أحد يعرف مدى عمق اختبارهم للبرنامج وماهي الأجزاء التي لم يتم اختبارها منه على الإطلاق. هذه الحالة أسوأ بكثير من تغطية الاختبارات المنخفضة التي يتم قياسها وإبلاغ الجميع بها. التغطية العالية (High coverage) لا تضمن الجودة العالية لكن التغطية غير المعروفة (unknown coverage) هي مؤشر واضح لمشاكل الصيانة. عندما يدخل مُطور جديد للمشروع، يجب أن يكون قادرًا على إجراء بعض التغييرات ومعرفة مدى تأثر التغطية بها. من الناحية المثالية، يجب فحص تغطية الاختبار بنفس طريقة التحليل الثابت، ويجب أن يفشل البناء إذا كانت أقل من عتبة محددة مسبقًا (عادة ما تكون حوالي 80 بالمائة). تطوير دون توقف ما أقصده بدون توقف هو أنه بدون مراحل وإصدارات. بغض النظر عن نوع البرنامج الذي تكتبه، يجب عليك إصداره وتعديله بشكل متكرر. مشروع بدون سجل إصدار واضح هو فوضى يتعذر إصلاحها. هذا في الغالب لأن الصيانة تدور حول القدرة على الفهم عند قراءة شيفرتك. عندما أنظر إلى الشيفرة المصدرية وسجل الالتزام والإصدار، يجب أن أكون قادرًا على معرفة ما كان يقصده كاتبها أو كاتبوها، وما الذي كان يفعله المشروع قبل عام، وإلى أين يتوجه الآن، وما هي خريطة التوجه الخاصة به، وغير ذلك. يجب أن تكون كل هذه المعلومات في الشيفرة المصدرية، والأهم من ذلك، في سجل Git. وسوم Git وملاحظات إصدار Github هما أداتان قويتان توفران لي هذه المعلومات. استخدمها إلى أقصى حد. ولا تنسَ أن كل إصدار ثنائي للمنتج يجب أن يكون متاحًا للتحميل المباشر. يجب أن أكون قادرًا على تنزيل الإصدار 0.1.3 واختباره مباشرةً، حتى لو كان المشروع يعمل على الإصدار 3.4 في الوقت الحالي. الواجهات غير الموثّقة كل جزء من البرنامج لديه واجهات يُفترض أن يُستَخدم من خلالها. إذا كان البرنامج عبارة عن مدير الحزم Ruby gem، فهناك أصناف وطرائق سأستخدمها بوصفي مستخدم نهائي لها. وإذا كان أحد تطبيقات الويب، فهناك صفحات ويب سيراها المستخدم النهائي ويتحكم بها لاستخدام التطبيق. يحتوي كل مشروع برمجي على واجهات، ويجب أن تكون موثّقةً بعناية. مثل كل شيء سابق، فإنَّ هذا أيضًا له علاقة بالصيانة. بوصفي مبرمجًا جديدًا في مشروع ما، سأبدأ في التعرف عليه من واجهاته. ويجب أن أكون قادرًا على فهم ما يفعله ومحاولة استخدامه بنفسي. أنا أتحدث هنا عن التوثيق للمستخدمين، وليس للمطورين. بشكلٍ عام، أنا ضد التوثيق داخل البرنامج. وأتفق تمامًا مع Agile Manifesto- بأن عمل البرنامج أهم بكثير من الوثائق الشاملة. لكن هذا لا يشير إلى التوثيق "الخارجي"، التي يفترض أن يقرأه المستخدمون، وليس المطورون. لذلك يجب توثيق تفاعل المستخدم النهائي مع البرنامج بشكل واضح. إذا كان برنامجك عبارة عن مكتبة، فإن مستخدميها النهائيين الذين سيستخدمونها هم من مطوري البرامج - لا يساهمون فيها ولكن يستخدمونها ببساطة كـ"الصندوق الأسود". هذه هي المعايير المستخدمة لتقييم المشاريع المفتوحة المصدر التي دخلت المنافسة على الجائزة لدينا. ترجمة -وبتصرف- للمقال Seven Deadly Sins of a Software Project لصاحبه Yegor Bugayenko.
  7. أصبحت لغة 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
  8. كتبت قبل بضع سنوات عن المراجعات التقنية المستقلة التي يجب أن يمر بها أي مشروع برمجي بشكل منتظم للتأكد من أنَّ كل شيء تحت السيطرة. ونوّهت مؤخرًا أنه لا يوجد عذر لعدم القيام بها. بالإضافة إلى ذلك، كلما زادت ثقتنا بالمبرمجين، زادت حاجتنا إلى مراجعة مشاريعهم بانتظام. فيما يلي ملخص بسيط لما يجب أن يتضمنه تقرير المراجع. حاولت أن أتطرق إلى هذا الموضوع في بضعة محادثات مؤخرًا مثل: اجعل العملاء يثقون بك في BDMSummit 2017، كيف تكون صادقًا وتحافظ على العميل في PMCon Kharkiv 2017، كيفية تجنب كارثة الاستعانة بمصادر خارجية في Kyiv Outsourcing Forum 2017. وأيضًا، هناك عدد من منشورات المدونة على نفس المنوال، بما في ذلك الأخطاء السبع القاتلة لمشروع برمجيات، وكيفية تجنب كارثة الاستعانة بمصادر خارجية للبرامج، وكيف تنجو من الاستعانة بمصادر خارجية للبرامج. أخيرًا، فيما يلي قائمة كاملة تقريبًا من الأشياء التي يجب أن يتضمنها التقرير الجيد. بشكل أساسي هي قائمة بالأسئلة التي يجب على المُراجع الإجابة عليها. عندما يتم جمع كل الإجابات، يكون التقرير جاهزًا. أهم الأسئلة تمَّ طرحها أوّلاً: هل إجراء الإصدار موثَّق، وآلي، وهل يعمل؟ هل الإصدارات تتجدد بشكل منتظم، على الأقل مرة أسبوعيًا؟ ما حجم الديون التقنية (الأشياء التي يجب إصلاحها "لاحقًا")؟ هل خط التسليم موثوقًا بما يكفي لاستبعاد الأخطاء؟ هل الشيفرة نظيفة؟ كم عدد النماذج المضادّة التي تظهر؟ هل تمَّ تسجيل جميع الأخطاء والميزات كملاحظات؟ هل تم تغطية الشيفرة الأساسية بوحدات اختبار، وهل التغطية مرئية؟ هل تم توقيع اتفاقيات "العمل من أجل التوظيف" مع جميع المطورين؟ هل تم توثيق القرارات التقنية الهيكلية الرئيسية؟ هل التحليل الثابت موضع التنفيذ ومُلزَم لإجراء تغييرات جديدة؟ هل التكاملات المستمرة موضع التنفيذ، وهل تؤخذ تقاريرها في الحسبان؟ هل الفرع الرئيسي (master branch) للقراءة فقط؟ هل يتم جمع المقاييس البرمجية ومراجعتها بانتظام؟ هل مستودع الشيفرة المصدرية يخضع لملكية العميل؟ هل متطلبات التوثيق قصيرة ومحدَّثة؟ هل تحتوي الفئات والطرق والتوابع الرئيسية على توثيق مضمَّن في الشيفرة؟ هل مخلفات مستودع الشيفرة المصدرية مجانية؟ هل تم توثيق واجهات UI/UX؟ هل سجلات الإنتاج مرئية وتتم مراجعتها بانتظام؟ ما مدى استجابة الفريق للملاحظات؟ هل لدى Git تاريخ واضح للتغيرات الموثَّقة؟ بشكلٍ أساسي، هذا تجميع قصير جدًا لأهم الأشياء التي يمكنك العثور عليها في CMMI. إنها تتطلب كل هذا، بالإضافة لقائمة كبيرة من الأشياء الأخرى موجودة في الأعلى. لكن المشروع الصغير لا يحتاج إلى جميع الأسئلة المذكورة. قائمتي أقصر، وأنا متأكد من أنها ستكون كافية لمعظم القرَّاء. بكل الأحوال، يمكنك مشاهدة التقارير التي يقوم المتطوعون بإنشائها للمشاركين في جائزة جودة البرمجيات، إذ يقومون بتحليل المشاريع مفتوحة المصدر والإبلاغ بشكلٍ مختصر عن المشكلات التي يجدونها. أعتقد أنهم يحاولون الإجابة عن نفس مجموعة الأسئلة السابقة تمامًا. ترجمة -وبتصرف- للمقال Software Project Review Checklist لصاحبه Yegor Bugayenko
  9. الواجهة البرمجية 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
  10. 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
  11. إحدى أسوأ الأسرار التي تمَّ الاحتفاظ بها حول 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
  12. قال لي أحد أصدقائي عندما اتصل بي البارحة: "اسمع، يا صديقي، لقد وثقت بهم لأكثر من عام - لقد كنّا شركاء، وكانوا يبرمجون كل شيء بالوقت الذي كنت أنا مشغولًا في تطوير الأعمال، والآن استقالوا ولم يتبقَ لي شيئًا، ما الذي يتوجب عليَّ فعلهُ بكل ملفات JavaScript هذه؟ كيف لي أن أتأكد بأنَّ هذه الملفات ملكي؟ بالإضافة لذلك، لا يريدون التعاون معي، أشعر بأنني رهين تصرفهم هذا، من فضلك، ساعدني". فكان جوابي له: "ماذا يمكنني أن أقول؟ لقد فات الأوان يا صديقي، ولكن الخبر السّار هو أنك لست أول من واجه هذه المشكلة". السيناريو النموذجي لوصف المشكلة "الثقة، الدفع، الخسارة". أولًا ستثق في مبرمجيك، وسيكونون شركاء لك تؤمن بعملهم، وتشعر بأنّك متأكدًا أنَّك قد اخترت الأفضل، سيظهرون لك ثقةً كبيرةً جدًا، وستشعر بالحماس عندما تنظر إلى سيرهم الذاتية، إنهم يعرفون جافاسكربت و DevOps و GitHub وحتى البيانات الضخمة، إنّهم بالتأكيد الأفضل لك، بالإضافة إلى ذلك، لديهم خبرة في هذا العمل لمدة عشر سنوات، فما الذي تحتاجه أكثر من ذلك، صحيح؟ ثانيًا أنت تدفع لهم، وإلا ما الذي يدفعهم للعمل، صحيح؟ إنَّ الموهبة الحقيقية باهظة الثمن، كلنا نعرف ذلك، إنّك تدفع لهم بانتظام مقابل الوقت الذي يقضونه في العمل على مشروعك. ستشعر بالحماس لرؤية أموالك تتحول إلى برمجيات تعمل، سيوفرون نسخًا جديدة بانتظام، يوجد هناك بعض الأخطاء، لكن من الطبيعي أن تظهر الأخطاء، صحيح؟ إنهم يقومون بشرح كل شيء لك وأنت تستمر في الدفع لهم. أخيرًا ستخسر عندما تدرك أنَّ هذا البرنامج يعود لهم وليس لك، وبأنَّهم قد استقالوا بسبب بعض أسباب العمل ولم يتبقَ لك شيء، أنت لا تستطيع فهم هذه الملفات، وأصلًا لا تملكها إنَّما هي موجودة في مكان ما في مستودع المبرمجين على منصة Git. توظف المزيد من الأشخاص لمساعدتك على حفظ ما تبقى من البرنامج، لكنهم سيخبرونك أنَّ الوقت قد حان لبدء كل شيء من الصفر. ستُحبط بشكلٍ هائل، وستكون مستعدًا للعودة إلى الخطوة الأولى - لأنك تثق بهؤلاء الموظفين الجدد، فإنهم بالتأكيد سيبدون صادقين، وليسوا مثل المحتالين السابقين. هل يبدو هذا مألوفًا؟ بالطبع أنت تتساءل، ما البديل؟ لا تثق، وبدلًا من ذلك، استعن بخبير مستقل قبل البدء بمشروع ما، بحيث يقوم بشكل منتظم (مثاليًا، كل أسبوعين) بمراجعة كل ما يفعله الموظفين الجدد ويقوم بإبلاغك أين وكيف قد تخسر. سيحافظ هذا الخبير على قائمة بالمخاطر المتوقعة، وأنت بدورك ستتخذ الإجراءات الوقائية اللازمة. لا تثق بنا نحن معشر المبرمجين، فإننا أذكياءٌ وكسولون ومدللون، لذا ستخسر دون جدال. ترجمة -وبتصرف- للمقال ‎Trust. Pay. Lose لصاحبه Yegor Bugayenko
  13. أتاح لي العمل في موزيلا وقتًا كافيًا للنظر في الواجهات البرمجية 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
  14. هل لديك فريق من المبرمجين المميزين والمتحمسين؟ بالطبع قد اخترتهم بعناية من بين مئات المرشحين، هل هم متحمسون للمنتج؟ بالتأكيد، إنهم يستخدمون أحدث التقنيات، ولا ينامون أبدًا، ويكادون لا يأكلون أو يشربون أي شيء باستثناء القهوة، هل يؤمنون بنجاح عملك؟ لا شك في ذلك. إنهم يعيشون ويتنفسون كل هذه الميزات، الإصدارات، والتسليم المستمر (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
  15. أهلاً سومة، نحتاج في هذه الحالة إلى ثلاث حلقات 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] بالتوفيق...
  16. وعليكم السلام ورحمة الله، يجب أن تراعي قائمة الخطوات التالية عند نقل موقعك من استضافة إلى أخرى: 1- اختر شركة استضافة معروفة تغطي احتياجاتك. 2- حدد بعناية موقع السيرفر.إما اختيار استضافة جديدة موجودة في نفس البلد مثل بلدك السابق أو ضعه في البلد الرئيسي للجمهور المستهدف. 3- قم بتحميل ملفات الموقع عبر FTP على الاستضافة الجديدة وقم بإعداد قاعدة البيانات الخاصة بك. وتأكد من أن كل شيء يعمل بشكل جيد على الاستضافة الجديدة. 4-قم بإعداد كافة حسابات البريد الإلكتروني وحسابات ftp لتعمل بشكل صحيح على الاستضافة الجديدة قبل بدء البث المباشر. 5- تحميل مرة أخرى على الاستضافة الجديدة الملفات التي تم تغييرها منذ الخطوة 3. تحقق أيضا إذا كانت قاعدة البيانات تحتاج إلى تحديث. 6- غيّر سجلات نظام أسماء النطاقات من خلال التحديث إلى Nameservers أو A Records الجديدة حتى يشير الدومين إلى الاستضافة الجديدة. 7- أزل موقعك الإلكتروني من شركة الاستضافة القديمة بعد يومين من اكتمال النقل. بالتوفيق...
  17. أهلاً وسهلاً بك، بالطبع يمكن العمل في العديد من المواقع وأشهرها منصات العمل التابعة لشركة حسوب (مستقل وخمسات) بالإضافة إلى العديد من المواقع الأخرى مثل http://shoghlonline.com/ أنصح بمتابعة هذه المواقع والاطلاع على فرص فيها فهناك الكثير من الفرص المتاحة يومياً بالتوفيق...
  18. وعليكم السلام ورحمة اللّه وبركاته أهلاً بك، هناك الكثير من منصات العمل الحر العربية التي تتيح لك العمل عن طريق الإنترنت وأشهرها المنصات التابعة لشركة حسوب (مستقل وخمسات) حيث يوجد الكثير من الفرص الجديدة يومياً فما عليك سوى التسجيل في الموقع والتقدم لفرص العمل الموجودة. كما يمكنك أيضاً الاطّلاع على الفرص الموجودة في موقع شغل أونلاين http://shoghlonline.com/. وماعليك سوى زيارة هذه المواقع لتتعرف عليها أكثر وتعرف طرق الدفع المتوفرة في كل منها. بالتوفيق...
  19. وعليكم السلام ورحمة اللّه وبركاته، يمكنك الاستفادة من المواقع التالية للحصول على 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 أتمنى أن أكون قد أفدتك بالتوفيق ...
  20. وعليكم السلام ورحمة الله، إذا أردت أن يبقى اللون نفسه بعد التحديث بإمكانك اتباع إحدى الطريقتين: - إما تحفظ اللون في متغير تبقى قيمته مادام الزائر يتصفح الموقع ولم يغلق المتصفح، وعندما يغلق المتصفح تعود القيمة إلى الافتراضية وذلك باستخدام مفهوم الجلسة session - أو تحفظ اللون في متغير يتم حفظه في ملف الcookie ويكون له مدة محددة تحددها له في البرمجة (شهر مثلاً) ويحافظ هذا المتغير على قيمته حتى لو فتح المستخدم من متصفح آخر على نفس الجهاز وبعد انتهاء المدة التي حددتها يعود المتغير للقيمة الافتراضية وذلك باستخدام مفهوم cookies أتمنى أن أكون قد أفدتك بالتوفيق...
  21. أهلاً بك، بإمكانك تعريف المتحول أنه float وجمعه إلى متحول float آخر كي تظهر النتيجة بالفاصلة وأيضاً عند إنقاص عددين في java تظهر النتيجة بالسالب مثلاً إذا كتبت الكود التالي: float a = 7; float b = 10; System.out.println(a+b); System.out.println(a-b); تكون النتيجة بالشكل: 17.0 -3.0
  22. أهلاً سلمى، الحد الأدنى من المتطلبات لتشغيل الفوتوشوب: - معالج Intel®‎ أو AMD مع دعم ‎64-bit بسرعة 2 غيغاهرتز أو معالج أسرع - 2 غيغابايت أو أكثر من ذاكرة الوصول العشوائي (RAM) (من المستحسن توفر سعة 8 غيغابايت) - مساحة فارغة قدرها 3.1 غيغابايت أو أكثر على القرص الثابت لتثبيت 64 بت. - شاشة عرض بدقة 1024‏x‏ 768 (‏من المستحسن استخدام شاشة عرض بدقة 1280 × ‏800‏) لذا فإن المواصفات التي ذكرتيها جيدة وتفي بالغرض بالتوفيق...
  23. أهلاً محمد، Dart لغة برمجة جديدة تم تطويرها بواسطة Google في عام 2007، ولكن إطلاقها المستقر جاء إلى الوجود في عام 2017 وتعتبر Dart لغة برمجة جديدة تماماً وهي تصبح ذات شعبية كبيرة يوماً بعد يوم. عادةً عندما يتعلق الأمر بتطوير التطبيق من جانب العميل، فإن Javascript هي الخيار المثالي. ولكن مثل جميع لغات البرمجة، فإن لديها أيضاً الكثير من المشاكل. لذلك فقد جاءت لغة Dart لتصبح هي الخيار الأول البديل. تعتبر Dart من اللغات السهلة التعلم وهي مفيدة لك سواء كنت مطور تطبيقات جوال أو مطور ويب أو مطور تطبيقات سطح مكتب. لا يوجد الكثير من الشروحات باللغة العربية لها، بإمكانك الاطلاع على هذه الشروحات: https://3alam.pro/rahiche/series/dart-programming-course وبإمكانك الاطّلاع على شرح تفصيلي في الموقع الرسمي للغة: https://www.dartlang.org/
  24. أهلاً نور، JPG(Joint Photographic Experts Group):صيغة صور تم إيجادها عام 1986 وهي تستهلك مساحة تخزين قليلة جداً وسريعة التحميل والتنزيل ويمكن أن تدعم ملايين الألوان وتعمل بشكل جيد في مواقع الويب كما أنها تستخدم أسوب lossy ضغط البيانات مما يعني أنه عند ضغط البيانات يتم حذف المعلومات غير الضرورية أي أن بعض الجودة ستفقد أو تتعرض للخطر عندما يتم تحويل أي ملف إلى JPG. يُنصح باستخدامها في موقع الويب كصيغة للصور ما لم تكن بحاجة إلى الشفافية أو تحتوي على نصوص فيها أو متحركة PNG(Portable Network Graphics) : تم اختراعها عام 1995 يمكنك استخدامها في موقعك إذا لم يكن لديك مشكلة بخصوص الحجم حيث أن حجمها أكبر من JPG كونها تستخدم أسلوب lossless لضغط البيانات أي يتم ضغطها دون فقدان أي بيانات وهي مثالية للرسومات التفصيلية أما صيغة webp حديثة قد طورتها غوغل عام 2010 وهي مدعومة من معظم المتصفحات مثل chrome,opera... وبدأ دعمها حديثاً في firefox ولكن لا يُنصح باستخدامها لضمان ظهور الصورة عند جميع المستخدمين
  25. أهلاً أحمد، قبل البدء بتعلم البرمجة يجب عليك أن تحدد ماهو هدفك من تعلمها حتى تستطيع معرفة لغة البرمجة التي يجب أن تبدأ بها فإذا كنت تريد تطوير تطبيقات الويب ستتعلم لغة PHP مثلاً وإذا أردت تطوير تطبيقات الأندرويد قد تتعلم Java لذا فإن الخطوة الأولى هي تحديد هدفك حتى نستطيع مساعدتك بشروحات تخص اللغة بالتوفيق
×
×
  • أضف...