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

Rama Alkhayer

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

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

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

آخر الزوار

لوحة آخر الزوار معطلة ولن تظهر للأعضاء

إنجازات Rama Alkhayer

عضو مساهم

عضو مساهم (2/3)

13

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

  1. تعتمد قدرة الحاسب على أداء مهامٍ معقدة على دمج التعليمات البسيطة ضمن بنى تحكمٍ. هناك 6 بنى تحكم كهذه في جافا، تستخدم لتحديد تدفق التحكم الطبيعي في البرنامج وتكفي ثلاث منها لكتابة برامج قادرة على أداء أيّة مهمة.بنى التحكم الستّ هي: الكتلة (block) وحلقة while وحلقة do..while وحلقة for وتعليمة if وتعليمة switch. تُعدّ كلّ واحدة من البنى السابقة "تعليمةً" مفردة، لكنها في الواقع تعليمة بنيوية قد تحتوي بداخلها تعليمة أو أكثر. الكتل الكتلة (Blocks) هي الشكل الأبسط للتعليمات البنيوية، وتهدف إلى تجميع سلسلة من التعليمات في تعليمة واحدة. تأخذ الكتلة الشكل التالي: { // ضع التعليمات هنا } بكلمات أخرى، تتألف الكتلة من سلسلة من التعليمات المُغلّفة بين قوسين من الشكل "{ }". يمكن ألّا تحتوي الكتلة أيّة تعليمة، وتدعى عندئذٍ بالكتلة الفارغة (empty block) ومن الوارد أن تلزمك أحيانًا. تتألف الكتلة الفارغة من زوج فارغ من الأقواس فقط. عادةً ما ترد كتل التعليمات ضمن تعليمات أخرى وتهدف إلى تجميع عدة تعليمات معًا في وحدةٍ واحدة. يمكنك في الحقيقة استخدام كتل التعليمات أينما وردت تعليمةٌ. بيد أنّ من الواجب استخدامها في حالة البرامج الفرعية -لاحظ استخدامنا لها سابقًا في حالة البرنامج الفرعي main . البرنامج الفرعيّ هو كتلةٌ بالتعريف، نظرًا لكونه سلسلةً من التعليمات المغلّفة ضمن زوج من الأقواس. من الجدير بالذكر هنا أنّ لغة البرمجة جافا هي لغةٌ حرة التنسيق وهذا يعني عدم وجود قواعد صياغة تحدد كيفيّة ترتيب اللغة على الصفحة. يمكنك إن أردت، على سبيل المثال، كتابة كتلةٍ كاملة على سطر واحد. مع ذلك، ينبغي عليك، اتباعًا لممارسات البرمجة الفضلى، تنظيم برنامجك على نحوٍ يجعل قراءته وفهمه أسهل ما يمكن. يقتضي هذا في الحالة العامة كتابةً تعليمةٍ واحدة فقط في السطر واستخدام المسافات البادئة للإشارة إلى التعليمات المُحتواة ضمن بنى التحكم. سيُستخدم التنسيق هذا في جميع أمثلة الكتاب.إليك مثالين عن الكتل: { System.out.print("الجواب هو: "); System.out.println(ans); } { // ‫تستبدل هذه الكتلة بين قيمتي المتغيرين x و y int temp; // مُتغير مؤقت لاستخدامه ضمن هذه الكتلة temp = x; // ‫احفظ نسخةً عن x صمن temp. x = y; // انسخ قيمة‫ y إلى x. y = temp; // ‫انسخ قيمة temp إلى y. } قمنا في المثال الثاني بالتصريح عن المتغيّر temp ضمن الكتلة. التصريح عن متغيّرٍ ضمن كتلةٍ أمرٌ جائزٌ لا بل ومستحسنٌ أيضًا لا سيما إن كان استخدام المتغير مقتصرًا على تلك الكتلة. لا يمكن الوصول للمتغير المُصرّح عنه ضمن كتلة خارجها ولا يكون مرئيًّا إلا فيها. عندما ينفّذ الحاسوب تعليمة التصريح عن متغيّر، يخصص موضعًا في الذاكرة لتخزين قيمة هذا المتغيّر (نظريًّا على الأقل). عندما تنتهي الكتلة، يتم التخلّص من موضع الذاكرة ذاك ليصبح مُتاحًا للاستخدام مجددًا. يقال أنّ هذا المتغير "محلّي" ضمن الكتلة. هناك مفهوم أكثر شمولًا يُصطلح على تسميته مجال المُعرّف (scope of an identifier). مجال المُعرّف هو جزء من البرنامج يكون فيه المعرّف صالحًا. يقتصر مجال المتغيّر المُعرّف ضمن كتلة على الكتلة نفسها، وعلى نحوٍ أدق، يقتصر مجال المتغيّر المعرّف ضمن كتلة على الجزء من الكتلة الذي يلي التصريح عنه. حلقة while الأساسيّة لا تؤثر تعليمة الكتلة بحدّ ذاتها على تدفق التحكم في البرنامج على عكس بنى التحكم الخمس المتبقية. تُصنّف هذه البنى إلى نوعين: تعليمات الحلقات وتعليمات التفريع. في الواقع، لا تحتاج لغة البرمجة عامّة الغرض سوى إلى بنية تحكم واحدة من كل نوعٍ وكل ما سواهما هو بغرض التسهيل والتبسيط ليس إلّا. سنتطرق في هذا القسم إلى حلقة while وتعليمة if ونؤجل الحديث عن بنى التحكم الثلاث المتبقية إلى أقسام لاحقة. تُستخدم حلقة while لتكرار تعليمة معيّنة مرة بعد مرة. من غير المرجّح أنّك ستحتاج تكرار العملية إلى الأبد، لكنّه أمرٌ ممكن ويدعى الحلقة اللانهائية وهو غير محبّذ في الحالة العامة. هناك قصة قديمة عن رائدة علوم الحاسوب غريس موراي هوبر التي قرأت التعليمات على علبة الشامبو وكانت تنصّ على: " ارغي، اشطفي، كرري العمليّة." اتبعت غريس التعليمات حسب قولها وانتهى بها الأمر بعلبة شامبو فارغة. روت غريس القصة كمزحة حول اتباع الحواسيب للتعليمات بدون تفكير. توخيًّا للدقة، نقول أنّ حلقة while تُكرر التعليمة مرةً بعد مرة طالما أنّ قيمة شرطٍ محدّدٍ هي true. تأخذ حلقة while الشكل الآتي: while (تعبير منطقي) //ضع تعليماتك هنا نظرًا لأنّه من الممكن والمرّجح أن التعليمة هي كتلة تعليمات، تأخذ معظم حلقات while الشكل الآتي: while (تعبير منطقي) { //ضع تعليماتك هنا } يظّن بعض المبرمجين أنّ من الواجب تضمين الأقواس دائمًا لضرورات تنسيقية حتى لو كانت ستُغلّف تعليمةً واحدة فحسب، لكننا لن نتبع هذه النصيحة في الكتاب. أمّا دلالة تعليمة while فهي كما يلي: عندما يصادف الحاسوب تعليمة while، يقوم بتقييم التعبير المنطقي لينتج عن ذلك قيمة إما ture أو false. إذا كانت القيمة false، يتجاوز الحاسوب بقيّة حلقة while ويتابع تنفيذ الأمر الذي يليها في البرنامج. أمّا إذا كانت قيمة التعبير ture، ينفّذ الحاسوب التعليمة أو كتلة التعليمات الواردة ضمن الحلقة. بعدئذٍ، يعود الحاسوب إلى بداية حلقة while ويكرر العملية (أي يعاود تقييم التعبير المنطقي، يُنهي التنفيذ إذا كانت قيمته false، ويستمر إذا ما كانت ture). تتكرر العملية مرةً بعد مرةٍ بعد مرة حتى تصبح قيمة التعبير false عند قيام الحاسوب بتقييمه. إن لم نصل لهذه النتيجة، فستستمر الحلقة إلى الأبد.إليك مثالًا عن حلقة while بسيطة تطبع الأرقام 1، 2، 3، 4، 5: int number; // ‫العدد المراد طباعته. number = 1; // ‫ابدأ من الرقم 1. while ( number < 6 ) { // ‫تابع طالما أن العدد أصغر من 6. System.out.println(number); number = number + 1; // ‫انتقل للعدد التالي. } System.out.println("انتهى التنفيذ"); ترجمة -بتصرّف- للقسم Section 2: Algorithm Development من فصل Chapter 3: Programming in the Small II: Control من كتاب Introduction to Programming Using Java.
  2. يُعرَّف البرنامج بأنّه سلسلة من التعليمات التي يستطيع الحاسب تنفيذها لأداء مهمّةٍ ما. تبدو فكرةٍ بسيطةٍ للغاية، لكن حتى يتمكن الحاسب من الاستفادة من التعليمات، يجب أن تكون هذه التعليمات مكتوبةً بصيغةٍ يستطيع الحاسب استخدامها. هذا يحتّم استخدام لغات البرمجة لكتابة هذه البرامج. تختلف لغات البرمجة عن اللغات البشرية العادية بكونها واضحةً كليًّا، وهي حازمةٌ للغاية فيما هو مسموح أو غير مسموح في البرنامج. تدعى القواعد التي تُحدد ما هو مسموح بصياغة اللغة (Syntax). تُوصّف قواعد الصياغة المفردات الأساسية للغة وكيفيّة بناء البرامج باستخدام أشياء كالحلقات والأفرع والبرامج الفرعية. يُعرّف البرنامج صحيح الصياغة بأنّه البرنامج الذي يمكن تصريفه أو ترجمته بنجاحٍ؛ تُرفض البرامج التي تحتوي على أخطاء صياغة (ولعلّ هذا يترافق مع رسالة خطأ مفيدة تساعدك في حل المشكلة). لذا، لكي تكون مُبرمجًا ناجحًا، عليك أن تكتسب معرفة مُفصّلة بصياغة لغة البرمجة التي ستستخدمها. بيد أنّ الصياغة هي مجرّد جانب من الأمر. ليس كافيًا أن تكتب برنامجًا يعمل، أنت تريد برنامجًا يعمل، ويقدّم نتيجة صحيحة. بكلمات أخرى، يجب أن يكون "معنى" البرنامج سليمًا. يُشار إلى معنى البرنامج بمصطلح "الدلالة اللفظيّة" (Semantics). بكلمات أدق، تُحدّد الدلالةُ اللفظية للغة البرمجة مجموعة القواعد التي تحدد معنى البرنامج المكتوب بتلك اللغة. يُعرّف البرنامج صحيح الدلالة بأنه البرنامج الذي يقوم بما تريد له أن يقوم به. أبعد من ذلك، يمكن للبرنامج أن يكون صحيح الصياغة والدّلالة إلا أنّ هذا لا ينفي كونه برنامجًا سيئًا. إذ أنّ استخدام اللغة على نحو صحيح لا يكافئ استخدامها على نحو مفيد. على سبيل المثال، يمتاز البرنامج الجيد بأسلوب كتابةٍ، أي أنّه يُكتب بطريقةٍ تجعل من السهل قراءته وفهمه عبر اتباع أعرافٍ معروفةٍ لدى المبرمجين الآخرين. كما أنّ البرنامج الجيّد يمتاز بتصميم شامل مفهوم للقرّاء البشريين. لا يكترث الحاسب لأمور كهذه البتة، إلّا أنها بالغة الأهمية لقارئ بشري. يُشار عادةً إلى الجوانب هذه من البرمجة بمصطلح التأويل أو التداوليات (pragmatics). (سنستخدم التعبير الأكثر شيوعًا "أسلوب" [style].) عندما نتطرّق لميزة جديدة في اللغة، سنشرح الصياغة والدلالة وبعضًا من تداوليات تلك الميزة. عليك أوّلًا أن تحفظ الصياغة، وهذا الجانب السهل من الموضوع. ثمّ عليك فهم الدلالة عبر متابعة الأمثلة المطروحة، والتأكد من أنك تدرك كيفيّة عملها، والأفضل من ذلك أن تكتب برامج قصيرةً بنفسك لاختبارك فهمك. وعليك أن تحاول إدراك واستيعاب التداوليات، ونعني تعلّم كيفية استخدام ميزة اللغة على نحوٍ سليمٍ وذلك بأسلوبٍ يُكسبك احترام باقي المبرمجين. لا شكّ أنّ كونك معتادًا على جميع الميزات الفردية للغة لا يعني أنّك أصبحت مُبرمجًا. لا زال عليك تعلّم كيفية بناء برامج معقدة لحل مسائل بعينها. وستحتاج في هذا الأمر إلى الخبرة والذوق. ستجد في هذا الكتاب تلميحات حول تطوير البرمجيات. نبدأ رحلتنا في اكتشاف جافا بمسألة أضحت عُرفًا في بدايات كهذه: كتابةُ برنامج يعرض الرسالة "مرحبًا أيها العالم!". قد تبدو مسألة هامشيّة، لكن قدرتك على جعل الحاسب يقوم بذلك هي خطوةٌ أولى كبيرة في تعلم لغة برمجة جديدة (خاصةً إذا ما كانت لغتك الأولى)، وهي تعنى فهمك للعملية الأساسيّة التالية: جلب نص البرنامج إلى الحاسب. تصريف البرنامج، ومن ثمّ تنفيذ البرنامج المُصرّف. سيتطلب الأمر في الغالب عدّة محاولات لتتمكن من القيام بذلك في المرة الأولى. لن نتعمّق في تفاصيل كيفية القيام بكلّ من تلك الخطوات هنا، الأمر يتعلق بجهاز حاسبك وبيئة برمجة جافا التي تستخدمها. انظر القسم 2.6 لمعلومات حول إنشاء وتنفيذ برامج جافا في بيئات برمجة معينة. لكن بشكلٍ عام، ستكتب البرنامج باستخدام محرر نصوص ما وتحفظ البرنامج في ملف. ثم ستستخدم أمرًا في محاولةٍ لتصريف الملف، فإمّا أن تحصل على رسالة مفادها أنّ البرنامج يحتوي على أخطاء صياغة، أو تحصل على نسخةٍ مُصرّفة إلى شيفرة جافا الثّمانيّة، وليس إلى لغة الآلة. أخيرًا، يمكنك تنفيذ البرنامج المصرف عبر استخدام الأمر المناسب. في الواقع، ستستخدم من أجل لغة جافا مُفسرًا لتنفيذ شيفرة جافا الثمانية. قد تؤتمت بيئة البرمجة التي اخترتها بعضًا من الخطوات عوضًا عنك. على سبيل المثال، عادةً ما تتمّ خطوة التصريف أوتوماتيكيًا لكن كن متأكدًا أن الخطوات الثلاث نفسها تجري دومًا وراء الكواليس. إليك برنامج جافا يعرض الرسالة "مرحبًا أيها العالم!". لا عليك إن لم تفهم كل ما يجري هنا الآن، حيث لن نتطرق لبعض مفاهيمه حتى بضع فصول من الآن. /** برنامج لعرض الرسالة * ‫ التالية "مرحبًا أيها العالم!" */ public class HelloWorld { public static void main(String[] args) { System.out.println("!‏مرحبًا أيها العالم"); } } // HelloWorld نهاية الصنف الأمر الذي يعرض الرسالة في الحقيقة هو: System.out.println("!مرحبًا أيها العالم"); الأمر السّابق مثالٌ عن تعليمة استدعاء برنامج فرعيّ إذ تستخدم "برنامجًا فرعيًّا مُدمجًا" (built-in subroutine) يُدعى System.out.println لأداء العمل الحقيقيّ. تذكّر أنّ البرنامج الفرعيّ يتألّف من تعليمات لأداء مهمةٍ ما وقد جُمّعت معًا ومُنحت اسمًا. يمكن استخدام هذا الاسم لاستدعاء البرنامج الفرعيّ متى ما احتجنا أداء تلك المهمة. البرنامج الفرعي المدمج هو برنامجٌ فرعيّ مُعرّف مسبقًا كجزء من اللغة وبذلك يكون متاحًا للاستخدام افتراضيًّا في أي برنامج. عندما تُنفّذ هذا البرنامج، تُعرض الرسالة "مرحبًا أيها العالم" (بدون علامتي الاقتباس اللاتينية) على الخرج القياسي. مع الأسف لا أستطيع شرح معنى الخرج القياسي بالضبط. يُفترض أن تعمل جافا على العديد من المنصات المختلفة، ويعني الخرج القياسي أمرًا مختلفًا على كلّ منها. على أيّة حال، يمكنك أن تتوقع ظهور الرسالة في مكان ملائم أو غير ملائم. (إن كنت تستخدم واجهة أوامر سطرية، كتلك الموجودة في أدوات تطوير جافا التي تقدّمها شركة أوراكل، فعندما تكتب الأمر لإخبار الحاسب بتنفيذ البرنامج سيطبع الحاسب خرج البرنامج – الرسالة "مرحبًا أيها العالم!"- على السطر التالي. بيد أنّه في بيئة تطوير متكاملة مثل Eclipse، قد يظهر الخرج في واحدةٍ من نوافذ البيئة.) لا بدّ أنك تشعر بالفضول حيال ما تبقى من أشياء في البرنامج أعلاه. يتألف جزء منه من تعليقاتٍ (comments). يتجاهل الحاسب كليًّا جميع التعليقات في البرنامج، وتقتصر أهميّة وجودها على القراء البشريين فقط. هذا لا يعني أنّها غير مهمّة. يُفترض أن يستطيع الناس كما الحواسيب قراءة البرامج، وقد يكون البرنامج بدون التعليقات صعب الفهم عليهم. يوجد نوعان من التعليقات في جافا. يبدأ النوع الأول بالشريطتين // ويمتد حتى نهاية السطر. يوجد تعليق من هذا الشكل في السطر الأخير من البرنامج أعلاه. يتجاهل الحاسب الشريطتين // وكل ما يليهما على السطر نفسه. من جهة أخرى، يبدأ النوع الثاني من التعليقات بشريطة ونجمة /* وينتهي بشريطة ونجمة */ ويمكن أن يمتد ليشمل عدة أسطر. تُمثل الأسطر الثلاث الأولى من البرنامج مثالًا عن هذا النوع من التعليقات. (للتعليق الذي يبدأ بشريطة ونجمتين /**، كالمذكور أعلاه، معنى خاص؛ حيث أنه تعليق خاص بتوثيق جافا Javadoc ويمكن استخدامه لتوليد توثيق للبرنامج. انظر القسم الفرعي 4.6.5). كل ما عدا ذلك في البرنامج تفرضه قواعد صياغة جافا. تتمُّ البرمجة كاملةً في جافا ضمن "أصناف". ينصّ السطر الأول في البرنامج أعلاه (دون التعليق) أنّ هذا الصنف يدعى HelloWorld. إضافةً لكونه اسم الصنف، يُمثّل الاسم "HelloWorld" اسم البرنامج أيضًا. ليس كل برنامجٍ صنفًا. لتحديد البرنامج، يجب أن يتضمن الصنف برنامجًا فرعيًّا يدعى main وذلك بتعريفٍ يأخذ الشكل الآتي: public static void main(String[] args) { **تعليمات** } عندما تطلب من مُفسّر جافا أن ينفّذ البرنامج، يستدعي المُفسّر البرنامج الفرعيّ main()‎، وبذلك تُنفّذ التعليمات التي يحتويها. تُؤلّف هذه التعليمات النص البرمجيّ الذي يخبر الحاسب بالضبط بما سيقوم به عند تنفيذ البرنامج. يستطيع البرنامج main()‎ استدعاء برامج فرعيّة أخرى مُعرّفة في الصنف نفسه أو حتى في أصنافٍ أخرى، لكن البرنامج main()‎ هو من يحدّد كيفية وترتيب استخدام البرامج الفرعيّة الأخرى. تعني الكلمة public في السطر الأول من التابع ‎main‎‎()‎ أنّ هذا البرنامج (routine) يمكن استدعاؤه من خارج البرنامج. هذا الأمر بالغُ الأهميّة إذ أنّ البرنامج main()‎ يُستدعى من قبل مُفسّر جافا الذي هو أحيانًا خارجيّ بالنسبة للبرنامج نفسه. ما تبقى من السطر الأول من البرنامج أصعب من أن يُفسّر في الوقت الحالي، فكر بالأمر الآن على أنّه مجرّد صياغة ضرورية. البرنامج الفرعيّ هو مجموعةٌ من الأوامر التي تملي ما يجب القيام به، ويتألف في جافا من سلسلة من التعليمات المحاطة بقوسين من الشكل { }. استخدمنا هنا الكلمة «تعليمات» (statements) نيابةً عن التعليمات الفعلية في الحيز المخصص لها ضمن البرنامج. سنستخدم الترجمة العربية في الشيفرات باستمرار في هذا الكتاب للإشارة إلى حيّز ينوب عنه وصفه وتحتاج لكتابته فعلًا عندما تقوم بالبرمجة. كما أشرنا أعلاه، لا يتواجد البرنامج الفرعي بمفرده بل يكون جزءًا من "صنف". يُعرف البرنامج من خلال صنفٍ عام يأخذ الشكل التالي: تصريحات حزم اختيارية استيراد حزم اختيارية public class اسم البرنامج { تصريحات اختيارية لمتغيرات وبرامج فرعية public static void main(String[] args) { تعليمات برمجية } تصريحات اختيارية لمتغيرات وبرامج فرعية } يتعلق أول سطرَين باستخدام الحزم (packages). تُعرّف الحزمة بأنها مجموعة من الأصناف وستتعلم المزيد عنها في القسم 2.4 إلّا أنّ أمثلتنا في بادئ الأمر لن تستخدمها. يُمثل اسم البرنامج في السطر الذي يبدأ بالكلمات المفتاحية public class اسم البرنامج واسم الصنف في آنٍ معًا. تذكر أن استخدامنا لكلمة اسم البرنامج هو نيابةً عن الاسم الفعلي. إن كان اسم الصنف HelloWorld، عند ذلك يجب حفظ الصنف في ملفٍّ يحمل الاسم HelloWorld.java. عند تصريف هذا الملف، يتولد ملف جديد يحمل الاسم HelloWorld.class. يحتوي ملف الصنف هذا على ترجمة البرنامج إلى شيفرة جافا الثمانيّة والتي يمكن تنفيذها باستخدام مفسر جافا. يُدعى الملف HelloWorld.java بالشيفرة المصدرية (source code) للبرنامج. تحتاج لتنفيذ البرنامج إلى ملف class المُصرّف فقط وليس الشيفرة المصدرية. لا أهمية لتنسيق هيئة البرنامج على الصفحة كاستخدام الأسطر الفارغة والمسافات البادئة فهي ليست جزءًا من صياغة أو دلالة اللغة. لا يأبه الحاسب لهيئة البرنامج ولن يتغيّر شيءٌ حتى لو كتبت برنامجك على سطرٍ واحد. بيد أنّ هيئة البرنامج وتنسيق كتابته مهمّ للقراء البشريين، وهنالك ضوابط تنسيق محددة يتبعها معظم المبرمجين. لاحظ أيضًا أنه وفقًا لتوصيف الصياغة أعلاه، يمكن أن يحتوي البرنامج على برامج فرعية أخرى إلى جانب البرنامج الفرعيّ main()‎ إضافةٍ إلى ما يدعى بتصريح المتغيرات. ستتعلم المزيد عن كل هذا لاحقًا في الفصل 4. ترجمة -بتصرّف- للقسم Section 2.1 The Basic Java Application من فصل Chapter 2: Programming in the Small I: Names and Things من كتاب Introduction to Programming Using Java.
  3. يمكن وصل الحواسيب مع بعضها البعض في شبكات (networks). يستطيع الحاسب على الشبكة أن يتواصل مع الحواسيب الأخرى على نفس الشبكة عبر تبادل البيانات والملفات أو إرسال واستقبال الرسائل. يمكن حتى للحواسيب على شبكة ما أن تتعاون معًا في إجراء حسابات ضخمة. في يومنا هذا، تتصل ملايين الحواسيب في أنحاء العالم بشبكة عملاقة واحدة تدعى الإنترنت (Internet). تتصل حواسيب جديدة إلى الإنترنت في كل يوم، عبر اتصالات لاسلكية واتصالات فيزيائية باستخدام تقنيات مختلفة مثل خط المشترك الرقمي (DSL)، مودمات الكابل التلفزيوني (Cable modems) والإيثرنت (Ethernet). هناك بروتوكولات مُفصّلة للتواصل عبر الإنترنت. يُعرّف البروتوكول ببساطة على أنه توصيف مُفصل لكيفية إجراء الاتصالات. لكي يتسنى لحاسوبين التواصل معًا أصلًا، عليهما استخدام نفس البروتوكولات. البرتوكولان الأساسيّان على شبكة الإنترنت هما بروتوكول الإنترنت IP (مختصر للعبارة Internet Protocol) والذي يوّصف كيفية نقل البيانات فيزيائيًّا من حاسب إلى آخر، وبروتوكول التحكم بالنقل TCP (مختصر للعبارة Transmission Control Protocol) والذي يضمن أنّ البيانات المرسلة باستخدام IP استُقبلت كاملةّ وخاليةً من الأخطاء. يُؤمِّن هذان البروتوكولان، واللذان يشار لهما معًا بالمصطلح TCP/IP، أساس التواصل هذا. تستخدم البروتوكولات الأخرى TCP/IP لإرسال أنواع مختلفةٍ من المعلومات مثل صفحات الويب، البريد الإلكتروني، وملفات البيانات. تجري جميع عمليات الاتصال على شبكة الإنترنت على هيئة رُزم (packets). تتألف الرزمة من بعض البيانات المُرسلة من حاسب إلى آخر، مضافًا إليها معلومات العنونة التي تشير إلى الموضع من شبكة الإنترنت الذي يفترض أن تذهب تلك البيانات إليه. فكّر بالرزمة وكأنها ظرف بريدي يحمل العنوان ويحتوي رسالة بداخله. (تمثل الرسالة البيانات المراد إرسالها.) تتضمن الرزمة أيضًا عنوان استجابة (return address) أي عنوان المرسل. يمكن للرزمة أن تحمل كمية محدودة من البيانات فقط، ويجب تقسيم الرسائل الأطول إلى عدة رزم يتم إرسالها عندئذ على الشبكة بشكلٍ فرديّ وإعادة تجميعها عند وصولها إلى وجهتها. يمتلك كل حاسبٍ على شبكة الإنترنت عنوان IP (أي IP address). هذا العنوان هو رقمٌ يُميّز هذا الحاسب على نحوٍ فريد عن جميع الحواسيب الأخرى على شبكة الإنترنت. (في الحقيقة، ادعاء التّفرّد هذا غير حقيقيّ كليًّا، لكن الفكرة الأساسيّة صحيحة، أما الحقيقة الكاملة فمعقّدة بعض الشيء.) يستخدم عنوان IP لعنونة الرزم. يمكن للحاسب إرسال البيانات إلى حاسب آخر على شبكة الإنترنت فقط إذا ما كان يعرف عنوان IP لذاك الأخير. نظرًا لأنّ الناس يُفضّلون استخدام الأسماء عوضًا عن الأرقام، لذا تُميّز معظم الحواسب أيضًا بأسماء تدعى أسماء النطاق (domain names). على سبيل المثال، يمتلك الحاسب الرئيسي لقسم الرياضيات في جامعة هوبارت وويليام سميث اسم النطاق math.hws.edu. (تُستخدم أسماء النطاق للسهولة فقط، ما زال حاسبك يحتاج لمعرفة عنوان IP قبل أن يستطيع التواصل. هناك حواسيب على شبكة الإنترنت مهمّتها ترجمة أسماء النطاق إلى عناوين IP. عندما تستخدم اسم نطاق، يحتاج حاسوبك إلى إرسال رسالة إلى خادم أسماء النطاق للبحث عن عنوان IP الموافق. بعدئذٍ، يستخدم حاسبك عنوان IP بدلًا من اسم النطاق، للتواصل مع الحاسب الآخر.) يُؤمِّن الإنترنت عددًا من الخدمات للحواسيب المتصلة به (وبالطبع لمستخدمي تلك الحواسيب). تستخدم هذه الخدمات TCP/IP لإرسال أنواع مختلفة من البيانات عبر الإنترنت. من أكثر تلك الخدمات شيوعًا، الرسائل الفورية، مشاركة الملفات، البريد الإلكتروني والشبكة العنكبوتية العالمية. لكل خدمة بروتوكولاتها الخاصة التي تستخدمها للتحكم بنقل البيانات عبر الشبكة. لكلّ خدمةٍ أيضًا ما يشبه واجهة مستخدم تسمح للمستخدم بمعاينة، وإرسال، واستقبال البيانات من خلال الخدمة. على سبيل المثال، تستخدم خدمة البريد الإلكتروني بروتوكولًا يعرف باسم بروتوكول نقل البريد البسيط (Simple Mail Transfer Protocol ويختصر إلى SMTP) لنقل رسائل البريد الإلكتروني من حاسبٍ إلى آخر. تستخدم بروتوكولات أخرى، مثل POP و IMAP، لجلب الرسائل من حساب البريد الإلكتروني ليتسنى للمستلم قراءتها. بيد أنّ الشخص الذي يستخدم البريد الإلكتروني لا يحتاج لفهم أو حتى معرفة وجود هذه البروتوكولات. وتقوم، عوضًا عن ذلك، برامج الحاسب باستخدام هذه البروتوكولات وراء الكواليس لإرسال واستقبال رسائل البريد الإلكتروني. تؤمن هذه البرامج للمستخدم واجهة مستخدم سهلة الاستخدام تخفي خلفها بروتوكولات الشبكة. تكاد الشبكة العنكبوتية العالمية تكون أكثر خدمات الشبكة تشويقًا، إذ تسمح لك بطلب صفحات من المعلومات المُخزَّنَة على حواسيب في جميع أرجاء الإنترنت. يمكن أن تحتوي صفحة الويب على روابط لصفحات أخرى على الحاسب نفسه الذي حصلت منه على الصفحة أو على حواسيب أخرى في أي مكان من العالم. يُطلق على الحاسب الذي يخزن صفحات المعلومات هذه باسم مخدِّم أو خادم ويب (web server). يُمثّل نوعٌ من البرنامج يدعى بمتصفحات الويب (web browser) واجهة المستخدم لخدمة الويب هذه. نذكر من أكثر متصفحات الويب شعبية: Microsoft Edge، و Internet Explorer، وفايرفوكس، وكروم، وسفاري. تستخدم متصفح الويب لطلب صفحةٍ من المعلومات. يرسل المتصفح طلبًا لتلك الصفحة إلى الحاسب الذي يختزنها، وعند استلام ردّ من ذاك الحاسب، يعرض متصفح الويب الصفحة لك في هيئة مُنسّقة ومرّتبة. متصفح الويب هو مجرد واجهة مستخدم للويب. يستخدم متصفح الويب وراء الكواليس بروتوكولًا يدعى بروتوكول نقل النصوص الفائقة HTTP (اختصارًا للعبارة HyperText Transfer Protocol) لإرسال طلب كل صفحة واستقبال الاستجابة من خادم الويب. ليس هذا فحسب، قد تفكر الآن، هل لكل هذا علاقةٌ بجافا؟ في الحقيقة، جافا مترافقة بقوة مع شبكة الإنترنت والشبكة العنكبوتية العالمية. كان من أكبر نقاط قوة جافا في بداية صدورها هو قدرتها على كتابة البريمجات (applets). البريمج هو برنامج صغير يُرسل عبر شبكة الإنترنت ويُنفّذ على صفحة ويب. منحت البريمجات لصفحات الويب القدرة على أداء مهام معقدة وإجراء تفاعلات معقدة مع المستخدم. مع الأسف، فقد عانت البريمجات من العديد من المشاكل ومن ثم توقف استخدامها وظهرت الآن خيارات أخرى لتنفيذ البرامج على صفحات الويب. رغم أنّ البريمجات تُمثّل جانبًا واحدًا من علاقة جافا بالإنترنت. يمكن استخدام جافا لكتابة تطبيقات معقدة مستقلة لا تعتمد على متصفح ويب. الكثير من هذه التطبيقات مرتبطة بالشبكة. على سبيل المثال، تستخدم الكثير من أكبر وأعقد مواقع الويب برمجيات خادم ويب مكتوبةً بلغة جافا. تتضمن الجافا دعمًا ممتازًا لبروتوكولات الشبكة، كما أنّ استقلالها عن المنصة يسمح بكتابة برامج شبكية تعمل على أنواع مختلفة كثيرة من الحواسيب. ستتعلم المزيد حول دعم جافا للشبكة لاحقًا من هذه السلسلة. لا يُمثل دعم جافا للشبكة ميزتها الوحيدة. إلّا أنّ الكثير من لغات البرمجة الجيدة اندثرت بعد اختراعها بفترة وجيزة. تحلّت جافا بالحظ الوفير لتستغل شعبية الإنترنت الكثيفة والمتزايدة. مع نضوج جافا، وصلت تطبيقاتها لمستوً يتعدى شبكة الإنترنت بكثير. تأتي النسخة المعيارية من جافا بدعم مسبق للكثير من التقنيات، كالتشفير، وضغط البيانات، ومعالجة الصوت، والرسوميات ثلاثية الأبعاد. كما كتب المبرمجون مكتبات جافا لتؤمن مقدرات إضافية. يمكن تطوير أنظمة معقدة عالية الأداء باستخدام جافا. على سبيل المثال، هادوب (Hadoop)، وهو نظام لمعالجة البيانات على نطاق واسع، مكتوب بلغة جافا. تستخدم كل من ياهو، وفيسبوك والكثير من مواقع الويب الأخرى نظام Hadoop لمعالجة كميات البيانات الضخمة التي يولدوها مستخدمو تلك المنصات. أبعد من ذلك، لا يقتصر استخدام جافا على الحواسيب التقليدية. يمكن استخدام جافا لكتابة برامج للهواتف الذكية (ولكن ليس لهواتف iPhone). حيث أنّ جافا هي لغة التطوير الأساسية للأجهزة التي تعمل بنظام آندرويد. (يستخدم نظام آندرويد نسخة شركة غوغل من جافا ولا يستخدم نفس مكونات واجهة المستخدم الرسومية كما في جافا المعيارية.) كما أن جافا هي لغة البرمجة المستخدمة في قارئ الكتب الإلكترونية Amazon Kindle وفي الميزات التفاعلية على أقراص الفيديو Blu-Ray. في وقتنا هذا، تحتل جافة مرتبةً متقدمة بين أكثر لغات البرمجة شعبية وأوسعها استخدامًا. إنّها خيار جيد تقريبًا في أي مشروع برمجي يُقصد له العمل على أكثر من نوع من أجهزة الحواسيب كما أنها خيار منطقي حتى في حالة البرامج التي ستعمل على جهاز واحد. من المرجّح أنّها ما تزال لغة البرمجة الأكثر تدريسًا في الكليّات والجامعات. إنّها مشابهة لحد كبير للكثير من لغات البرمجة الشائعة، مثل C++‎ و JavaScript، و Python لدرجة أنّ معرفتك بك ستمنحك بداية جيدة لتعلم هذه اللغات أيضًا. عمومًا، فإنّ تعلّم جافا هو نقطة انطلاق رائعة على طريقك لتصبح مبرمجًا خبيرًا. نأمل أنك ستستمتع بهذه الرحلة. ترجمة وبتصرف للفصل The Internet and Beyond من كتاب Introduction to Programming Using Java
  4. لم يتسنى للناس العاديين، ومن ضمنهم معظم المبرمجين، الاقتراب من الحواسيب في الفترة التي تلت صدورها لأول مرة، إذ كانت الحواسيب محتجزةً في غرفٍ مقفلة مع مرافقين يرتدون اللباس الأبيض يأخذون برنامجك وبياناتك، ويقومون بتغذيتها للحاسوب، ومن ثم يعيدون لك استجابة الحاسوب بعد فترة معينة من الزمن. عند إدخال مفهوم "مشاركة الوقت" (timesharing) للحاسوب، وهو عملية تبديل الحاسوب لانتباهه بسرعة من شخص لآخر، وذلك في ستينيات القرن الماضي، أصبح بإمكان عدة أشخاص التفاعل مع الحاسوب في الوقت ذاته. في نظام معتمد على مشاركة الوقت، يجلس المستخدمون أمام "طرفيّة" (terminal) ويرسلون الأوامر إلى الحاسوب، ويرد الحاسوب بكتابة استجابته. استخدمت الحواسيب الشخصية الأولى أيضًا الأوامر المكتوبة والاستجابات، إلّا أنّ هناك في كل مرة شخص واحد معنيّ يستخدم الحاسوب. هذا النوع من التفاعل بين المستخدم والحاسوب يدعى بواجهة سطر الأوامر (Command-line interface). يتفاعل بالطبع معظم الناس في يومنا هذا مع الحواسيب بطريقة مختلفة كليًّا حيث يستخدمون واجهة مستخدم رسومية (Graphical User Interface، واختصارًا GUI). يرسم الحاسوب مكوّنات الواجهة على الشاشة، وتتضمن المكونات أشياء مثل النوافذ (windows) وأشرطة التمرير (scroll bars) والقوائم (menus) والأزرار (buttons) والأيقونات (icons). عادةً ما تُستخدم الفأرة للتحكم بهذه المكوّنات، أو في حالة شاشات اللّمس، تستخدم أصابعك. لا شكّ أنّك مطّلع على أساسيّات واجهات المستخدم الرسومية، هذا بالطبع ما لم تكن قد انتقلت عبر الزمن من السبعينيات. أصبح الكثير من مكوّنات واجهة GUI معياريًّا إلى حد كبير. نعني بذلك أنّ لهذه المكوّنات مظهرًا وسلوكًا متشابهًا على الكثير من منصات الحاسوب المختلفة ومن ضمنها أنظمة ماك وويندوز ولينكس. تستطيع برامج جافا -والتي يُفترض أن تُنفَّذ على الكثير من المنصات المختلفة بدون إجراء تعديل على البرنامج- استخدام جميع مكوّنات GUI المعياريَّة. قد يختلف مظهر هذه المكوّنات بين منصةٍ وأخرى، إلّا أنَّ وظيفتها متطابقةٌ على أي حاسوب يُنفّذ البرنامج عليه. تجد أدناه صورةً لبرنامج جافا بسيطٍ جدًا يوضّح بضع من المكوّنات المعياريّة لواجهة GUI. عندما يُنفّذ البرنامج، ستفتح نافذةٌ شبيهة بالصورة التي تظهر هنا على شاشة الحاسوب. هناك أربعة مكوّنات في النافذة يستطيع المستخدم التفاعل معها: زر، مربّع تأشير (checkbox)، حقل نصّي (text field) وقائمة منبثقة (pop-up menu). هناك بضعة مكوّنات أخرى في النافذة، التّسميات (labels) ذاتها هي مكوّنات (على الرغم من أنّك لا تستطيع التفاعل معها). النصف الأيمن من النافذة عبارةٌ عن مكوّن مساحة نصيّة (text area) يستطيع عرض عدّةٍ أسطر من النص. يظهر مكوّن شريط التّمرير جنبًا إلى جنب مع المساحة النصيّة عندما يصبح عدد أسطر النصّ أكبر من أن يتّسع في المساحة النصيّة. في الحقيقة، وفقًا لمصطلحات جافا، تُعدّ النافذة بأكملها "مكوّنًا". (إذا أردت تنفيذ هذا البرنامج، فالشيفرة المصدريّة، الملف GUIDemo.java، متوفرّة على الشبكة. لمزيد من المعلومات حول استخدامه والأمثلة الأخرى في هذا الكتاب، انظر القسم 2.6) تتضمّن جافا في الواقع ثلاث مجموعات كاملة من مكوّنات الواجهة الرسومية GUI. الأولى هي مجموعة أدوات النوافذ المجرّدة (Abstract Windowing Toolkit أو اختصارًا AWT)، وقد أصبحت متوفرة مع صدور النسخة الأصليّة من جافا. أمّا المجموعة الثانية وتُعرف باسم Swing فقد طُرحت مع النسخة 1.2 من جافا لتصبح بعدئذٍ المجموعة المعياريّة لأدوات GUI لسنوات عديدة. أما مجموعة الأدوات الثالثة وتدعى JavaFX فقد أصبحت جزءًا معياريًّا من جافا في نسختها الثامنة (لكنّها حُذفت مؤخّرًا ولذا تتطلّب تثبيتًا منفصلًا في بعض نسخ جافا). على الرغم من أنّك ما زلت قادرًا على استخدام كلٍّ من Swing وAWT، إلّا أنّه يُراد بمجموعة JavaFX أن تكون الوسيلة الحديثة لكتابة تطبيقات GUI. يتناول هذا الكتاب شرح JavaFX حصرًا. (إذا أردت تعلّم Swing، ألقِ نظرةً على النسخة السابقة من هذا الكتاب.) عندما يتفاعل المستخدم مع مكوّنات GUI، تولِّد أحداثًا (Events). على سبيل المثال، النقر على زر الضغط (push button) يولِّد حدثًا، والضغط على مفتاح من لوحة المفاتيح يولّد حدثًا. في كل مرة يتوّلد فيها حدث، تُرسل رسالة إلى البرنامج تخبره أنّ حدثًا قد جرى ويستجيب البرنامج وفقاً لبرنامجه. في واقع الأمر، يتألف برنامج GUI النمطي من "معالجات أحداث" (event handlers) تخبر البرنامج بكيفيّة الاستجابة إلى أنواع مختلفة من الأحداث. في المثال أعلاه، بُرمج البرنامج ليستجيب لكل حدث بعرض رسالةٍ في المساحة النصيّة. في مثال أكثر واقعيّة، يتوجّب على معالجات الأحداث القيام بأكثر من مجرد ذلك. استخدام المصطلح "رسالة" هنا مُتعمّد. كما رأيت في القسم السابق، تُرسل الرسائل إلى الكائنات. في الواقع، تُحقّق مكوّنات GUI على أنها كائنات. تتضمن جافا العديد من الأصناف المعرّفة مسبقًا والتي تُمثّل أنواعًا مختلفة من مكوّنات GUI. بعض هذه الأصناف عبارةٌ عن أصناف فرعيّةٍ من أصناف أخرى. إليك مخطّطًا يوضح فقط بعضًا من صفوف JavaFX GUI وعلاقاتها: لا تقلق حيال التفاصيل في الوقت الحاضر، لكن حاول أن تفهم كيف تُستخدم البرمجة كائنيّة التوجه والوراثة هنا. لاحظ أنّ جميع أصناف الواجهة GUI الموضحة هنا هي أصناف فرعيّة، إما بشكلٍ مباشرٍ أو غير مباشر، من الصنف الرئيسي Control والذي يُمثل الصفات العامة المشتركة بين الكثير من مُكوّنات JavaFX. في المخطط، لدى اثنين من الأصناف المتفرِّعة مباشرًة من الصنف Control أصنافًا فرعيّة بدورها. جُمع الصنف TextField والصنف TextArea واللذان يشتركان بأنماط سلوك محددّة معًا كصنفين فرعيين للصنف TextInputControl. وعلى غرار ذلك، نجد أنّ الصنفين Button و CheckBox هما صنفان فرعيّان من الصنف ButtonBase الذي يُمثّل الخصائص المشتركة لكل من الأزرار ومربعات التأشير. (بالمناسبة، فإنّ الصنف ComboBox هو الصنف الذي يُمثّل القوائم المنبثقة.) ربما ترى من هذا النقاش المقتضب كيف أنّ برمجة واجهات المستخدم الرسومية يستغّلُ التصميم كائني التوجّه بفعاليّة. والواقع أنّ واجهات المستخدم الرسومية بكائناتها المرئيّة هي عامل رئيسي ساهم في شعبيّة البرمجة كائنية التوجّه. تُعدّ البرمجة بمكوّنات واجهات المستخدم الرسومية والأحداث واحدًا من أكثر جوانب جافا متعةً وأهميةً. على أيّة حال، سنقضي بضع فصول مع الأساسيّات قبل العودة إلى هذا الموضوع في الفصل السادس. ترجمة وبتصرف للفصل The Modern User Interface من كتاب Introduction to Programming Using Java
  5. يجب إجراء تصميم للبرامج، فلا يمكن لأحدٍ أن يجلس ببساطةٍ أمام الحاسوب ويُؤلف برنامجًا معقدًا. يُهتَّم فرع هندسة البرمجيات (software engineering) ببناء برامج صحيحة، فعَّالة ومكتوبة على نحوٍ سليم. يحاول مهندس البرمجيات استخدام أساليب مقبولة ومُثبتة لتحليل المسألة لكي يتم حلها ومن ثم تصميم برنامج لحل تلك المسألة. خلال سبعينيات وبداية ثمانينيات القرن الماضي، كانت المنهجية الأساسية في هندسة البرمجيات هي "البرمجة البنيوية" (structured programming). يعتمد أسلوب البرمجة البنيوية لتصميم البرامج على النصيحة الآتية: لحل مسألة ضخمة، جزِّئها إلى عدة أجزاء ثم اعمل على كلّ جزءٍ على حدة. لحل كل جزء، عالجه كما لو مسألةً جديدة يمكن أن تُجزّأ بدورها إلى مسائل أصغر. ستصل في نهاية المطاف إلى مسائل يُمكن حلّها مباشرةً بدون تفكيكها. يُدعى هذا الأسلوب بالبرمجة التنازلية (top-down programming) أي منهج من الأعلى إلى الأسفل. ليس هناك من خطبٍ بالبرمجة التنازلية فهو أسلوب مفيدٌ وغالبًا ما يُعتمَد في حل المسائل بيد أنّه ناقص. أولًا، يتعامل كليًا تقريبًا مع إنتاج التعليمات اللازمة لحل المسألة. لكن مع مرور الوقت، أدرك الناس أن تصميم بنى البيانات للبرنامج لا يقلّ أهمية عن تصميم البرامج الفرعية وبنى التحكم. لا تُقدم البرمجة التنازلية الاهتمام المُلائم للبيانات التي يتلاعب بها البرنامج. المشكلة الثانية باستخدام البرمجة التنازلية الصارمة هي أنَّها تجعل من الصعب إعادة استخدام العمل المنجز في مشاريع أخرى. عند البدء بمسألة ما وتقسيمها إلى أجزاء مناسبة، تميل البرمجة التنازلية إلى أن تفضي لحل حصري بالمسألة. من غير المحتمل أن تستطيع أخذ كتلة ضخمة من البرمجة من برنامج آخر واستخدامها في مشروعك، ستحتاج على الأقل إلى تعديلات كثيفة. إن الحصول على برامج عالية الجودة أمر صعبٌ ومُكلف لذا يحرص المبرمجون ومن يوظِّفهم على إعادة استخدام أعمالهم السابقة. لذا، يُدمج التصميم التنازلي غالبًا في الممارسة العملية مع التصميم التصاعدي (bottom-up design) أي من الأسفل إلى الأعلى. في التصميم التصاعدي، تبدأ من الأسفل بمسائل تعرف مسبقًا كيفية حلها (وقد يكون لديك في متناول يدك مُكوّن برمجي قابل لإعادة الاستخدام فيها). من هناك، تستطيع العمل تصاعدياً نحو حلّ للمسألة الكلية. ينبغي أن تكون المكونات القابلة لإعادة الاستخدام "مقولبة" قدر الإمكان. الوحدة (module) هي إحدى مكونات نظام ضخم تتفاعل مع بقية النظام بأسلوب بسيط، واضح المعالم ومباشر. تكمن الفكرة في إمكانية "وصل" الوحدة بالنظام. لا يهتم النظام ككل بالتفاصيل التي تجري داخل الوحدة طالما أن الوحدة تؤدي الدور الذي أُسند لها على نحوٍ صحيح. يُدعى هذا بإخفاء المعلومات (information hiding) وهو أحد أهم مبادئ هندسة البرمجيات. تتضمن إحدى الصيغ الشائعة للوحدات البرمجية بعض البيانات، إضافةً إلى بعض البرامج الفرعية لمعالجة تلك البيانات. على سبيل المثال، قد تتضمن وحدة قائمة المراسلات البريدية قائمة بالأسماء والعناوين إضافة إلى برنامج فرعي لإضافة اسم جديد وبرنامج فرعي لطباعة التسميات البريدية، وغيرها. في وحدات كهذه، غالبًا تكون البيانات نفسها مخبأة داخل الوحدة، فلا يستطيع البرنامج الذي يستخدم الوحدة معالجة البيانات إلا على نحو غير مباشر من خلال استدعاء البرامج الفرعية التي تُقدّمها الوحدة. يحمي هذا الأمر البيانات نظرًا لأنه من غير الممكن التلاعب بها إلا عبر وسائل معروفة ومُحددة بدقة. كما يجعل من السهل للبرامج استخدام الوحدة حيث لا داعي للقلق حيال تفاصيل كيفية تمثيل البيانات. المعلومات أو التفاصيل المتعلقة بتمثيل البيانات مُخبأة. أصبحت الوحدات التي تستطيع دعم هذا النوع من تخبئة المعلومات واسعة الانتشار بين لغات البرمجة في بداية ثمانينيات القرن الماضي. منذ ذلك الحين، سيطرت صيغة أكثر تقدمًا من الفكرة ذاتها على هندسة البرمجيات. يُدعى هذا الأسلوب الأخير بالبرمجة كائنية التوجه (object-oriented programming، وغالبًا ما يختصر إلى OOP). يتمحور مفهوم البرمجة كائنية التوجه حول الكائن (object)، والذي يمثِّل نوعًا من الوحدات التي تتضمن بيانات وبرامج فرعية. وجهة النظر في البرمجة كائنية التوجه هي أن الكائن هو كيان مُكتفٍ ذاتيًّا فلديه حالة (state) داخلية (هي البيانات التي يتضمنها) وقادر على الاستجابة للرسائل (استدعاءات البرامج الفرعية الموجودة ضمنه). يتضمن كائن قائمة المراسلات البريدية على سبيل المثال حالةً تتألف من قائمة من الأسماء والعناوين. إذا أرسلت له رسالة تُخبره فيها بإضافة اسم، يستجيب عبر تعديل حالته لتعكس التغيير الذي طلبته. إذا أرسلت له رسالة تخبره فيها بطباعة نفسه، يستجيب عبر طباعة قائمته من الأسماء والعناوين. تهدف مقاربة البرمجة كائنية التوجه في هندسة البرمجيات إلى البدء بتعريف الكائنات المشمولة في مسألة ما والرسائل الذي ينبغي على تلك الكائنات الاستجابة لها. يكون البرنامج الناتج هو مجموعة من الكائنات، لكل منها بياناته ومجموعة خاصة من المسؤوليات. تتفاعل الكائنات عبر إرسال الرسائل بين بعضها. لا يستخدم أسلوب البرمجة التنازلية في التصميم واسع النطاق لبرنامج كهذا وقد يعاني الأشخاص المعتادون على البرامج التقليدية من صعوبة في الاعتياد على البرمجة كائنية التوجه. على أية حال، يدّعي الأشخاص الذين يستخدمون البرمجة كائنية التوجه أنها تميل لكونها نموذجًا أفضل للآلية التي يعمل بها العالم الحقيقي بأكمله، وأنها نتيجة لذلك، أسهل في الكتابة والفهم وأوفر حظًّا في أن تكون صحيحة. ربما تظن أن الكائنات تعرف كيف تستجيب لرسائل بعينها. قد تستجيب الكائنات المختلفة إلى نفس الرسالة بطرائق مختلفة. على سبيل المثال، فقد ينتج عن الرسالة "طباعة" نتائج مختلفة كليًا وفق الكائن الذي تُرسَل إليه. تدعى هذه الخاصية التي تسمح للكائنات المختلفة بالاستجابة لنفس الرسالة بطرائق مختلفة بالتعدديّة الشكلية (polymorphism). من الشائع أن تشترك الكائنات بسماتٍ أو "تشابه عائلي". تنتمي الكائنات التي تحتوي النوع نفسه من البيانات وتستجيب للرسائل نفسها بالطريقة نفسها إلى صنف (class) واحد. (في البرمجة الفعلية، يكون الصنف نوعًا أوليًّا، أي أنَّنا ننشئ صنفًا ومن ثم يُنشَأ كائن أو أكثر بالاعتماد على ذاك الصنف بعدِّه قالبًا). لكن يمكن للكائنات أن تكون متشابهةً بدون أن تكون مشتقة كم الصنف نفسه تمامًا. على سبيل المثال، تخيّل برنامج رسمٍ يسمح للمستخدم برسم خطوط، ومستطيلات، وأشكال بيضوية، ومضلّعاتٍ، ومنحنيات على الشاشة. يمكن تمثيل كل كائن مرئي على الشاشة بكائن برمجي في البرنامج. سيتضمن البرنامج خمسة أصناف من الكائنات، يقابل كلٌّ منها نوعًا من الكائنات المرئية التي يمكن رسمها. ستتبع جميع الخطوط إلى صنف واحد، وجميع المستطيلات إلى صنف آخر مختلف، وقس على ذلك. ثمة بوضوح قرابة بين تلك الأصناف حيث تمثل جميعها "كائنات قابلة للرسم". من المتوقع على سبيل المثال أن تستجيب جميع هذه الأصناف إلى رسالة "ارسم نفسك". هناك مستوى آخر للتجميع يعتمد على البيانات اللازمة لتمثيل كل نوع من الكائنات. هذا المستوى، وإن كان أقل بديهية إلا أنه مفيد جدًا في البرنامج. يمكننا تجميع المضلعات والمنحنيات معًا ضمن "كائنات متعددة النقاط"، بينما تندرج الخطوط والمستطيلات والمنحنات ضمن "كائنات ذات نقطتين." (يُحدد الخط بنقطتين تمثلان نهايتيه، والمستطيل باثنتين من زواياه، والمنحني بزاويتين من المستطيل الذي يحتويه. نتحدث عن المستطيلات ذات الأضلاع العمودية والأفقية والتي يمكن تحديدها بنقطتين فقط. وهذا هو المعنى الشائع لكلمة مستطيل في برامج الرسم.) يمكننا تمثيل هذه العلاقات بالرسم البياني التالي: يُمثل كلّ من "الكائن القابل للرسم" DrawableObject، و"الكائن متعدد النقاط" MultipointObject و"الكائن ثنائي النقاط" TwoPointObject أصنافًا في البرنامج. يكون كلّ من "الكائن متعدد النقاط" MultipointObject و"الكائن ثنائي النقاط" TwoPointObject صنفين فرعيين من "الكائن القابل للرسم" DrawableObject. يمثّل الصنف "خط" Line صنفًا فرعيًا من الصنف TwoPointObject "الكائن ثنائي النقاط" وعليه (على نحوٍ غير مباشر) من الصنف DrawableObject "كائن قابل للرسم". يُقال أنّ الصنف المتفرِّع من صنف ما يرث صفات ذاك الصنف. يمكن للصنف الفرعي أن يضيف على ما ورثه من أبيه، ويمكنه حتى أن يعيد تعريف جزء مما ورثه (عبر تعريف استجابة مختلفة لبعض الرسائل). على أية حال، تُمثَّل الخطوط والمستطيلات وما إلى هنالك كائنات قابلة للرسم ويعبر الصنف DrawableObject "كائن قابل للرسم" عن هذه العلاقة. تُعدّ الوراثة وسيلة فعالة لتنظيم البرنامج. كما أنَّها ذات صلة بمسألة إعادة استخدام المكونات البرمجية. الصنف هو أقصى مكون يمكن إعادة استخدامه. إن كان يناسب حاجة البرنامج الذي تحاول كتابته بالضبط، يمكنك إعادة استخدامه مباشرةً. وإن كان يناسب برنامجك إلى حد بعيد، يمكنك إعادة استخدامه عبر تعريف صنف فرعي وإجراء التغييرات اللازمة فقط لجعله ملائمًا لحاجاتك. وهكذا، تقصد البرمجة كائنية التوجه أن تكون أداة رفيعة لتطوير البرامج وحلًّا جزئيًّا لمسألة إعادة استخدام البرمجيات. تمثل الكائنات، والأصناف، والبرمجة كائنية التوجه عمومًا أفكارًا رئيسية في هذا الكتاب يلهج بذكرها وشرحها دومًا، وستبدأ باستخدام الكائنات المدمجة في لغة جافا في الفصل التالي، وتبدأ في الفصل الخامس بإنشاء صفوف وكائنات جديدة وخاصة بك. ترجمة وبتصرف للفصل Objects and Object-oriented Programming من كتاب Introduction to Programming Using Java
  6. هناك جانبان أساسيان للبرمجة: البيانات (data) والتعليمات (instructions). للعمل مع البيانات، تحتاج إلى فهم المُتغيّرات (variables) والأنواع (types)؛ أمّا للعمل مع التعليمات عليك فهم بنى التحكم (control structures) والبرامج الفرعيّة (subroutines). ستقضي الجزء الأكبر من بداية هذه السلسلة، مدخل إلى جافا، في التعرف على هذه المفاهيم. المُتغيّر (variable) هو مجرد موقع في الذّاكرة (أو عدة مواقع متتالية تُعامل وكأنها وحدةٌ واحدة) يُمنح اسمًا لتسهيل الإشارة إليه واستخدامه ضمن برنامجٍ. على المبرمج القلق فقط حيال الاسم، وتقع مسؤولية تتبع موقع الذاكرة على عاتق المُصرّف (compiler). بصفتك مُبرمجًا، ستحتاج فقط إلى تذكّر أنّ الاسم يُشير إلى ما يشبه صندوقًا يحتضن البيانات في الذاكرة، على الرغم أنك غير مضطرٍ لمعرفة أين يقع هذا الصندوق بالضبط في الذاكرة. في جافا والعديد غيرها من لغات البرمجة، يكون لكلّ متغيّر نوعٌ يُشير إلى نوع البيانات التي يمكنه الاحتفاظ بها. قد يحتفظ نوع من المتغيرات بالأعداد الصحيحة (integers) – مثل 3، أو 7-، أو 0 – بينما يحتفظ نوع آخرٌ بأعداد عشرية (floating point) وهي الأعداد ذات الفواصل العشرية، مثل 3.14، أو 2.7-، أو 17.0. نعم، يميّز الحاسوب بوضوح بين العدد الصحيح 17 والعدد ذي الفاصلة العشرية 17.0؛ تبدو هاتان القيمتان مختلفتين تمامًا داخل الحاسوب. يمكن أن يكون هناك أيضًا أنواع للمحارف (characters) مثل: 'A'، ';' وغيرها، والسلاسل النصية (strings) مثل: " مرحبًا "، " قد تتضمّن السلسة النصية العديد من المحارف "، وغيرها. وهنالك أنواعٌ أقل شيوعًا مثل التواريخ، الألوان، الأصوات أو أي نوع من البيانات قد يحتاج البرنامج تخزينها. تتضمن لغات البرمجة دائمًا أوامر لجلب البيانات من وإلى المتغيرات وأداء العمليات الحسابيات على هذه البيانات. على سبيل المثال، تُخبر عبارة الإسناد التالي -والتي قد ترد في برنامج جافا- الحاسوبَ بأن يأخذ العدد المُخزّن في المُتغيّر المُسمّى principal، ويضرب ذاك العدد بالقيمة 0.07 ويخزّن النتيجة في المُتغيّر المُسمّى interest: interest = principal * 0.07; هنالك أيضًا "أوامر دخل" لجلب البيانات من المستخدم أو من الملفات المخزَّنة على الحاسوب، وهنالك "أوامر خرج" لإرسال البيانات في الاتجاه المعاكس. هذه الأوامر الأساسيّة الخاصّة بنقل البيانات من مكانٍ إلى آخر وأداء الحسابات هي عناصر البناء الأساسية لجميع البرامج. تُجمع عناصر البناء هذه لتُكوِّن برامج معقدةً باستخدام بنى التحكم والبرامج الفرعيّة. البرنامج هو عبارة عن سلسلة من التعليمات. في تدفق التحكم العادي، يُنفّذ الحاسوب التعليمات وفقًا لترتيب ورودها في البرنامج، واحدةً تلو الأخرى. إلّا أنّ نموذج العمل هذا محدودٌ جدًا، إذ سرعان ما يُنفِّذ الحاسوب التعليمات المراد تنفيذها ولكن مع بنى التحكم (Control structures)، التي هي تعليمات خاصة، يمكن تغيير تدفق تنفيذ الشيفرة. هناك نوعان أساسيّان لبنى التحكم هذه: الحلقات (Loops)، تسمح بتكرار تنفيذ سلسلة من التعليمات مرارًا وتكرارًا، والتّفرعات (branches)، والتي تسمح للحاسوب بالاختيار بين مساري عمل مختلفين أو أكثر من خلال اختبار شروطٍ أثناء تنفيذ البرنامج. على سبيل المثال، قد يكون الشرط كالتالي: إذا كانت قيمة المُتغيّر principal أكبر من 10000، يُحسب عندئذٍ المُتغيّر interest بضرب قيمة principal بالقيمة 0.05؛ وإلا يُحسَب interest بضرب قيمة principal بالقيمة 0.04. يحتاج البرنامج إلى وسيلة للتعبير عن قرارٍ كهذا. في لغة جافا، يُعبّر عما سبق بعبارة if الشرطية التالية: if (principal > 10000) interest = principal * 0.05; else interest = principal * 0.04; (لا تقلق بشأن التّفاصيل الآن. تذكر فقط أن الحاسوب يستطيع اختبار شرطٍ وتحديد ما سيقوم به لاحقًا بناءً على نتيجة ذاك الاختبار.) تُستخدَم الحلقات loops عندما يلزم أداء المهمة ذاتها أكثر من مرة. على سبيل المثال، إذا أردت طباعة تسميةٍ بريدية (mailing label) لكل واحد من الأسماء على قائمة المراسلات، قد يخطر لك التالي: "أحضر الاسم الأول والعنوان واطبع التسمية، أحضر الاسم الثاني والعنوان واطبع التسمية، أحضر الاسم الثالث والعنوان واطبع التسمية.." لكن سرعان ما ستدرك أنّ خطتك غير عمليّة وقد تفشل إن لم تكن تعرف مُسبقًا عدد الأسماء لديك. قد ترغب عوضًا عن ذلك بقول شيء من هذا القبيل: "طالما أن هنالك المزيد من الأسماء التي تحتاج المعالجة، أحضر الاسم التالي والعنوان واطبع التسمية." يُمكن استخدام الحلقة في البرنامج للتعبير عن تكرارٍ كهذا. البرامج الضخمة مُعقَّدة لدرجة تجعل من المستحيل كتابتها إن لم يكن ثمة طريقة لتجزئتها إلى "كتل" تسهل إدارتها. تُؤمن البرامج الفرعية (subroutine) وسيلةً لأداء ذلك. يتألف البرنامج الفرعي من التعليمات اللازمة لأداء مهمةٍ ما وقد جُمعت معًا كوحدةٍ منفردة ومُنحت اسمًا مميِّزًا. يمكن استخدام هذا الاسم بديلًا عن مجموعة التعليمات بأكملها. على سبيل المثال، افرض أنّ إحدى المهام التي يحتاج برنامجك أداءها هي رسم منزلٍ على الشاشة. يمكنك كتابة التعليمات اللازمة، وجمعها في برنامج فرعيّ ومن ثم منح ذلك البرنامج الفرعي اسمًا ملائمًا ولنقل drawHouse()‎. عند ذلك، تستطيع عند حاجتك لرسم منزلٍ في أي مكان من البرنامج أداء ذلك باستخدام أمر واحدٍ كالتالي: drawHouse(); وسيكون له نفس المفعول فيما لو كررت جميع تعليمات رسم المنزل في كل مرة. لا تقتصر إيجابية الأمر على توفير كتابة بعض الأسطر حيث يساعد تنظيم برنامجك ضمن برامج فرعية على تنظيم أفكارك وجهود تصميم برنامجك. عند كتابتك البرنامج الفرعيّ الخاصة برسم المنزل، تستطيع التركيز على مسألة رسم المنزل دون القلق حينها على بقية البرنامج. وحالما تنتهي من كتابة البرنامج الفرعي، يمكنك نسيان تفاصيل رسم المنازل كليًّا، لقد تم حل تلك المشكلة ولديك برنامج فرعي يقوم بها عوضًا عنك. يصبح البرنامج الفرعي جزءًا ضمنيًا من اللغة التي تستطيع استخدامها دون التفكير حول تفاصيل ما يدور "ضمن" البرنامج الفرعي. تُمثل المتغيرات والأنواع، والحلقات، والتّفرعات والبرامج الفرعية أساس ما نصطلح تسميته "البرمجة التقليدية" (traditional programming)، غير أنّه مع ازدياد حجم البرامج، نحتاج أيضًا إلى بنى إضافية لتساعدنا في التعامل مع تعقيد هذه البرامج. أحد أكثر هذه الأدوات فعالية هي "البرمجية كائنية التوجه" (object-oriented programming) وسنتطرق لها في القسم التالي. ترجمة وبتصرف للفصل Fundamental Building Blocks of Programs من كتاب Introduction to Programming Using Java
  7. تتألّف لغة الآلة من تعليماتٍ بسيطةٍ جدًا يُمكن تنفيذها مباشرةً من قبل وحدة المعالجةِ المركزيّة للحاسوب. رغم ذلك، فإنّ جميع البرامج تقريبًا مكتوبةٌ بلغات برمجة عالية المستوى (high-level programming languages) مثل جافا أو بايثون أو C++‎. لا يُمكن تنفيذ البرنامج المكتوب بلغة برمجةٍ عالية المستوى مباشرةً على أيّ حاسوب. يجب أوّلًا أن يُترجم إلى لغة الآلة. يُمكن إجراء التّرجمة هذه من قبل برنامجٍ يُدعى المُصرّف (Compiler). يأخذ المُصرّف برنامجًا مكتوبًا بلغة برمجةٍ عالية المستوى ويترجمه إلى برنامج قابلٍ للتّنفيذ بلغة الآلة. حالما تنتهي التّرجمة، يُمكن تنفيذ البرنامج المُترجم إلى لغة الآلة في أي وقتٍ ولأيّ عددٍ من المرات على نوعٍ واحد من الحواسيب (نظرًا لأنّ لكلّ نوعٍ من الحواسيب لغة آلةٍ فريدةٌ خاصةٌ به). إذا ما أُريد للبرنامج أن يُنفّذ على نوع حواسيب مختلف، يجب إعادة ترجمته إلى لغة الآلة الموائمة باستخدام مُصرّف مختلف. هنالك بديلٌ لترجمة البرامج المكتوبة بلغاتٍ عالية المستوى. عوضًا عن استخدام المُصرّف الذي يُترجم البرنامج دفعةً واحدة، يمكنك استخدام المُفسّر (Interpreter) الذي يترجمه تعليمةً تلو تعليمةٍ حسب الحاجة. المُفسّر هو برنامج يعمل بنفس آلية عمل وحدة المعالجة المركزيّة، عبر ما يشبه دورة جلب وتنفيذ خاصّة به. لتنفيذ برنامجٍ ما، يقوم المُفسّر بتشغيل حلقةٍ يقوم فيها بقراءة تعليمة واحدةٍ من البرنامج، تحديد ما يلزم لتنفيذ هذه التّعليمة، ومن ثم تنفيذ أوامر لغة الآلة الموافقة. (يُشبه المُصرّف المُترجم البشريّ الذي يترجم كتابًا كاملًا من لغة إلى أخرى مما يُنتج كتابًا جديدًا في اللغة الهدف. أما المُفسّر فيقابل المُفسّر البشري الذي يترجم خطابًا في الأمم المتحدة من لغة إلى أخرى في الوقت ذاته الذي يُلقى فيه الخطاب.) أحد استخدامات المفسّرات هو تنفيذ البرامج المكتوبة بلغات عالية المستوى. تُنفَّذ لغة البرمجة Lisp، على سبيل المثال، باستخدام مفسّر وليس مُصرّف. على أيّة حال، للمفسّرات غرضٌ آخر: تسمح المفسّرات لك باستخدام برنامج بلغة الآلة مُخصّص لنوع حواسيب معين على نوع آخر مختلفٍ كليًّا. على سبيل المثال، كان Commodore 64 أو "C64" أحد الحواسيب المنزليّة الأولى. وعلى الرغم من أنّك لن تجد C64 متوفرًا الآن في الأسواق، إلا أنّك تستطيع العثور على برامج محاكية له تعمل على حواسيب أخرى أو حتى ضمن مُتصفحات الويب. يستطيع محاكٍ كهذا تنفيذ برامج الحاسوب C64 عبر العمل كمفسّر للغة آلة C64. اختار مصممو جافا استخدام مزيج بين التّصريف والتّفسير. تُصرّف البرامج المكتوبة بلغة جافا إلى لغة آلة، لكنها لغة آلة لحاسوبٍ غير موجود في الواقع. يُعرف هذا الحاسوب الافتراضي المزعوم بآلة جافا الافتراضيّة (Java Virtual Machine)، أو JVM. تُدعى لغة الآلة الخاصّة بآلة جافا الافتراضيّة بشيفرة جافا الثُّمانيّة أو جافا بايتكود (Java bytecode). لا يوجد سببٌ يمنع استخدام شيفرة جافا الثُّمانيَّة أو لغة البايتكود كلغة آلة لحاسوبٍ حقيقيٍّ بدلًا من الحاسوب الافتراضي. إلّا أنّ استخدام الآلة الافتراضيّة يفتح الطريق أمام أهم نقاط قوّة وشعبيّة جافا ألا وهي إمكانيّة استخدام هذه الشّيفرة على أي حاسوب. جلّ ما سيحتاجه هذا الحاسوب هو مفسّر لشيفرة جافا الثُّمانيَّة. يُحاكي مفسّر كهذا آلة جافا الافتراضيّة كما يُحاكي محاكي C64 حاسوبَ Commodore 64 الأصلي. يُستخدم مصطلح آلة جافا الافتراضيّة أيضًا للإشارة إلى برنامج مفسّر شيفرة البايتكود الذي سيقوم بعمليّة المحاكاة، لذا نقول أنّ الحاسوب سيحتاج إلى آلة جافا الافتراضيّة لكي يُنفّذ برامج جافا. من الأدقّ – تقنيًّا – القول أنّ المفسّر يعمل على تحقيق أو تنفيذ (implement) آلة جافا الافتراضيّة بدلًا من القول أنّ المفسّر هو آلة جافا الافتراضيّة. نحتاج بالطّبع إلى مفسّر مختلف لشيفرة جافا بايتكود من أجل كل نوعٍ من الحواسيب، لكن ما أن يتوفّر مفسّر شيفرة جافا بايتكود على حاسوبٍ ما حتّى يتسنّى له تنفيذ أيّ برنامج مكتوب بلغة جافا بايتكود، ويمكن تنفيذ هذا البرنامج نفسه على أيّ حاسوبٍ يمتلك مفسّرًا مشابهًا. هذه واحدةٌ من أهم ميّزات جافا: يمكن تنفيذ البرنامج المُصرّف ذاته على عدّة أنواعٍ مختلفةٍ من الحواسيب. قد تتساءل الآن، لم استخدام شيفرة جافا بايتكود من الأصل؟ لم لا نقوم فقط بتوزيع برنامج جافا الأصلي وندعُ كل مستخدمٍ يُصرّفه إلى لغة الحاسوب الذي يريد تشغيل البرنامج عليه؟ هناك عدّة أسبابٍ. بادئ ذي بدء، على المُصرّف أن يفهم جافا، والتي هي لغةٌ معقّدةٌ عالية المستوى. المُصرّف بحدِّ ذاته برنامج معقّد. بالمقابل، مُفسّر شيفرة جافا بايتكود هو برنامج بسيط صغيرٌ نسبيًّا. تجعل هذه الحقيقةُ كتابةَ مفسّر شيفرة بايتكود لأي حاسوب جديد أمرًا أكثر سهولةً؛ وما أن يتمّ ذلك حتى يصبح هذا الحاسوب قادرًا على تنفيذ أي برنامج جافا مُصرّف. بينما تكون كتابة مُصرّف جافا لذلك الحاسوب نفسه أمرًا أصعب بكثير. علاوةً على ذلك، يُفترض أنّ بعض برامج جافا سيتمّ تنزيلها عبر شبكة. يؤدي هذا إلى مخاوف أمنيّة بديهية: أنت لا ترغب بالتأكيد بتنزيل وتنفيذ برنامج قد يتسبب بأذية لحاسوبك أو ملفاتك. يؤدي مُفسّر الشّيفرة بايتكود دور مخزنٍ مؤقّت (buffer) بينك وبين البرنامج الذي قمت بتنزيله. أنت في الحقيقة تُنفّذ برنامج المُفسّر، الأمر الذي يُنفّذ البرنامج المُحمّل على نحوٍ غير مباشر. يُمكن للمُفسّر أن يحميك من الأنشطة الخطرة المُحتملة من طرف هذا البرنامج. انتُقِدت جافا عندما كانت لغةً حديثةً العهد لأنها بطيئة: نظرًا لأن شيفرة جافا بايتكود تُنفّذ من قبل مُفسّر، كان يبدو أنّ برامج شيفرة جافا بايتكود لا يمكن لها أبدًا أن تُنفّذ بسرعة البرامج المُصرّفة إلى لغة آلة أصيلة (يُقصد بها لغة الآلة الحقيقيّة للحاسوب الذي يُنفّذ البرنامج عليه). مع ذلك، حُلّت هذه المشكلة إلى حدٍّ كبير باستخدام المُصرّفات في الوقت المُناسب (Just-in-time compilers) لتنفيذ شيفرة جافا بايتكود. يترجم المُصرّف في الوقت المناسب شيفرة جافا بايتكود إلى لغة آلة أصيلة وذلك أثناء تنفيذ البرنامج. يكون دخل المُصرّف في الوقت المناسب – كما أيّ مُفسّر عادي- عبارةً عن برنامج شيفرة جافا بايتكود ومهمّته هي تنفيذ هذا البرنامج. إلّا أنه أثناء تنفيذ البرنامج، يترجم أيضًا أجزاء منه إلى لغة الآلة. يُمكن عندئذٍ للأجزاء المترجمة من البرنامج أن تُنفّذ على نحو أسرع بكثيرٍ من الزمن اللازم لتفسيرها. نظرًا لأنّ بعض أجزاء البرنامج تُنفّذ عادةً مرّاتٍ كثيرة أثناء تنفيذ البرنامج، يُمكن للمصرف في الوقت المناسب أن يزيد من سرعة زمن التنفيذ الكلّي. يجدرُ بالذكر أنّ لا يوجد رابطٌ بالضرورة بين جافا وشيفرة جافا بايتكود. يمكن بالتأكيد تصريف برنامج مكتوب بلغة جافا إلى لغة الآلة لحاسوب حقيقيّ. ويمكن تصريف البرامج المكتوبة بلغات أخرى إلى شيفرة جافا بايتكود. بيد أنّ اتحاد جافا وشيفرة جافا الثمانيّة مستقلٌّ عن المنصة، آمن، ومتوافق مع الشبكة ويسمح لك في الوقت ذااته بالبرمجة بلغة حديثة عالية المستوى وكائنيّة التّوجّه. في السنوات الأخيرة الماضية، غدا شائعًا إحداثُ لغات برمجة جديدة أو إصدارات من لغات قديمة تُصرّف إلى شيفرة جافا بايتكود. يمكن لبرامج الشيفرة الثمانية المُصرّفة أن تُنفّذ على آلة جافا الافتراضيّة المعياريّة. من اللغات الحديثة التي طُوّرت خصيصًا لبرمجة آلة جافا الافتراضيّة نذكرُ: Scala، و Groovy، و Clojure و Processing. بينما Jython وJRuby هما الإصداران من لغتين قديمتين هما Python و Ruby اللذان يستهدفان آلة جافا الافتراضية. تسمح هذه اللغات بالاستفادة من مزايا آلة جافا الافتراضية وفي الوقت ذاته تجنّب بعض التفاصيل التقنية للغة جافا. في الحقيقة، إنّ استخدام لغات أخرى مع آلة جافا الافتراضيّة أصبح مهمًا للدرجة التي استدعت إضافة عدّة ميزات جديدة إلى آلة جافا الافتراضيّة خصيصًا لإضافة دعم أفضل لبعض هذه اللغات. بدورها، فتحت هذه التحسينات في آلة جافا الافتراضيّة المجال أمام ميزات جديدة في جافا. يجدر أيضًا أن نذكر أنّ الجزء الأصعب بحقٍّ في الاستقلالية عن المنصة هو تأمين "واجهة مستخدم رسوميّة" (Graphical User Interface) تتضمن نوافذ، وأزرارًا وغيرها يمكنها العمل على جميع المنصات التي تدعم جافا. سنتطرق للمزيد حول هذا لاحقًا. ترجمة -وبتصرف- للفصل The Java Virtual Machine من الكتاب Introduction to Programming Using Java
  8. تقضي وحدة المعالجة المركزيّة أغلب وقتها في جلب التّعليمات من الذّاكرة وتنفيذها. بيد أنّ وحدة المعالجة المركزيّة والذّاكرة الرّئيسيّة هما اثنان فقط من مكوّنات النّظام الحاسوبي الحقيقي. يتألّف النّظام الكامل من أجهزة أخرى مثل: القرص الصّلب (hard disk) أو وسيط التّخزين ذو الحالة الثابتة (solid state drive أو SSD) لتخزين ملفّات البرامج والبيانات. لاحظ أن الذّاكرة الرّئيسيّة تحتفظ بكميّة صغيرة نسبيًّا من المعلومات وتحتفظ بها طالما هناك تغذية كهربائيّة. يُستخدم القرص الصّلب أو وسيط التّخزين ذو الحالة الثّابتة للتّخزين الدّائم لكميّات ضخمة من المعلومات لكن يجب تحميل البرامج منه إلى الذّاكرة الرّئيسيّة قبل أن يتمّ تنفيذها فعليًّا. يُخزّن القرص الصّلب البيانات على قرص مغناطيسي دوّار، بينما يُمثّل وسيط التّخزين ذو الحالة الثّابتة ssd جهازًا إلكترونيًّا صرفًا بدون أيّ أجزاء متحرّكة. لوحة المفاتيح والفأرة لدخل المستخدم. الشّاشة والطّابعة لعرض خرج الحاسوب. جهاز إخراج صوت للسّماح للحاسوب بتشغيل أصوات. واجهة شبكة للسماح للحاسوب بالتّواصل مع الحواسيب الأخرى المتّصلة به على الشبكة، سواء سلكيًّا أو لاسلكيًّا. الماسحة لتحويل الصور إلى أرقام ثنائيّة مُرمّزة يمكن تخزينها وتعديلها على الحاسوب. قائمة الأجهزة هذه لا نهاية لها وتُبنى الأنظمة الحاسوبية على نحوٍ يجعل توسعتها بإضافة أجهزة جديدةٍ أمرًا سهلًا. يتوجّب على وحدة المعالجة المركزيّة بطريقةٍ ما التّواصل مع جميع هذه الأجهزة والتّحكم بها وتقوم بذلك من خلال تنفيذ تعليمات لغة الآلة فقط – في الواقع، إنّ تنفيذ تعليمات لغة الآلة هو الأمر الوحيد الذي تستطيع وحدة المعالجة المركزيّة فعله. يسير الأمر على النّحو الآتي: لكل جهازٍ في النّظام هناك تعريفٌ (device driver) خاصّ به هو عبارةٌ عن برمجيّة تُنفّذها وحدة المعالجة المركزيّة عندما تتعامل مع هذا الجهاز. عادةً ما تكون هناك خطوتان عند تركيب جهازٍ جديد على النظام: توصيل الجهاز فيزيائيًّا مع الحاسوب وتثبيت برمجية التّعريف الخاصّة بهذا الجهاز. يكون الجهاز عديم الجدوى بدون هذا التّعريف نظرًا لأنّ وحدة المعالجة المركزيّة غير قادرةٍ على التّواصل معه بدونه. يُنظّم النّظام الحاسوبي عادةً بوصل تلك الأجهزة مع ناقلٍ (Bus) أو أكثر. يُمثّل النّاقل مجموعةً من الأسلاك التي تنقل أنواعًا مختلفةً من المعلومات بين الأجهزة المتّصلة بها. تنقلُ تلك الأسلاك البيانات، والعناوين، وإشارات التّحكم. يُوجّه العنوان البيانات إلى جهازٍ معيّن وربّما إلى تسجيلةٍ أو موضع بعينه ضمن ذلك الجهاز. تستخدم الأجهزةُ، على سبيل المثال، إشارات التّحكم لتنبيه بعضها إلى توفّر بيانات جاهزةٍ لها على ناقل البيانات. يمكن تمثيل نظام حاسوبي بسيط كما يلي: تستطيع الأجهزة مثل لوحة المفاتيح، الفأرة، وواجهة الشّبكة أن تُنتج الدّخل الذي ستعالجه وحدة المعالجة المركزيّة. كيف تعرف وحدة المعالجة المركزيّة أنّ البيانات قد وصلت؟ من خلال فكرةٍ بسيطةٍ – وإن كانت غير مُرضِية – وهي أن تقوم وحدة المعالجة المركزيّة بالتّفحص المستمر لوجود بيانات واردة؛ وحالما تجد البيانات، تُعالجها فورًا. ولمّا كانت وحدة المعالجة المركزيّة "تجسّ" أجهزة الدّخل باستمرار لتفقّد ما إذا كان لديها بيانات دخلٍ تريد الإبلاغ عنها، فقد دُعيت هذه العمليّة بالجسّ (polling). لسوء الحظّ، رغم بساطة عمليّة الجسّ إلّا أنّها غير فعالّةٍ أبدًا حيث تُضيع وحدة المعالجة المركزيّة الكثير الكثير من الوقت في انتظار الدّخل فقط. لتجنّب عدم الفعاليّة بهذه العملية، تُستخدَم المُقاطعات (Interrupts) بدلًا من الجسّ. المقاطعة هي إشارةٌ من جهازٍ ما إلى وحدة المعالجة المركزيّة. تستجيب وحدة المعالجة المركزيّة لإشارة المقاطعة بوضع ما تفعله جانبًا للرّد على المقاطعة. تعود وحدة المعالجة المركزيّة لإتمام ما كانت تقوم به قبل حدوث المقاطعة بعد أن تنتهي من معالجتها. على سبيل المثال، عندما تضغط مفتاحًا على لوحة مفاتيح حاسوبك، تُرسل مقاطعة لوحة مفاتيح إلى وحدة المعالجة المركزيّة. تستجيب وحدة المعالجة المركزيّة إلى هذه الإشارة بمقاطعة ما تفعله، وقراءة المفتاح الذي قمت بضغطه، ومعالجته ومن ثمّ العودة إلى المهمّة التي كانت تقوم بأدائها قبل ضغطك للمفتاح. عليك أن تفهم أنّ هذه العمليّة آليّة بالكامل. يُرسل الجهاز إشارة مقاطعة من خلال تمرير تيّار كهربائي في السلك. تُبنى وحدة المعالجة المركزيّة بحيث تحفظ قدرًا كافيًا من المعلومات حول ما تقوم به عندما يُمرّر تيّار كهربائي في ذاك السّلك لتستطيع العودة إلى المرحلة نفسها لاحقًا. تشمل هذه المعلومات محتويات التّسجيلات الدّاخليّة المهمّة مثل عدّاد البرنامج. تقوم عندها وحدة المعالجة المركزيّة بالقفز إلى موقعٍ مُحدّدٍ مسبقًا في الذاكرة وتبدأ بتنفيذ التّعليمات المُخزّنة هناك. تُشكّل هذه التّعليمات مُعالج المُقاطعة (interrupt handler) الذي يقوم بالمعالجة الضّروريّة للاستجابة للمقاطعة. معالج المقاطعة هو جزءٌ من برمجية تعريف الجهاز الذي أرسل إشارة المقاطعة. في نهاية معالج المقاطعة، هناك تعليمة تخبر وحدة المعالجة المركزيّة بالعودة إلى مهمّتها السّابقة قبل المقاطعة، تقوم وحدة المعالجة المركزيّة بذلك من خلال استعادة حالتها السّابقة التي قامت بحفظها. تسمح المقاطعات لوحدة المعالجة المركزيّة بالتعامل مع الأحداث غير المتزامنة. في دورة الجلب والتّنفيذ المُنتظمة، تحدث الأشياء بترتيب مُسبق التّحديد؛ كل ما يجري تنفيذه "مُتزامنٌ" مع كل شيء آخر. تُمكّن المقاطعاتُ وحدةَ المعالجة المركزيّة من التعامل بفعاليّة مع الأحداث التي تحدث على نحوٍ "غير متزامن" أو – بكلمات أخرى – في أوقات يتعذّر التّنبؤ بها. كمثالٍ آخر عن كيفيّة استخدام المقاطعات، تخيّل ماذا يحدث عندما تحتاج وحدة المعالجة المركزيّة النّفاذ إلى بيانات مُخزّنة على القرص الصّلب. لا تستطيع وحدة المعالجة المركزيّة النّفاذ مباشرةً للبيانات إلّا إذا كانت الأخيرة في الذّاكرة الرّئيسيّة. يجب نسخ البيانات من القرص إلى الذّاكرة الرّئيسيّة قبل أن يتسنّى النّفاذ إليها. لسوء الحظ، فالقرص الصّلب بطيء للغاية مقارنةً بسرعة عمل وحدة المعالجة المركزيّة. عندما تحتاج وحدة المعالجة المركزيّة بياناتٍ من القرص، تُرسل إشارةً إلى القرص الصلب تخبره ليُحدّد موضع البيانات ويقوم بتجهيزها. تُرسل هذه الإشارة على نحوٍ متزامن تحت إشراف برنامجٍ عاديٍّ. تقوم وحدة المعالجة المركزيّة بعد ذلك بتنفيذ مهمّة أخرى عوضًا عن انتظار القرص الصّلب لوقتٍ طويل يتعذّر تقديره بدقّة. ما أن ينتهي القرص الصّلب من تجهيز البيانات المطلوبة، يُرسل إشارة مقاطعةٍ لوحدة المعالجة المركزيّة. يستطيع عندئذ معالج المقاطعة قراءةَ البيانات المطلوبة. قد تلاحظ أنّ هذا كلّه منطقيّ فقط عندما يكون لدى وحدة المعالجة المركزيّة عدة مهامٍ تنتظر تأديتها. فلا ضير إن قضت وحدة المعالجة المركزيّة وقتها تجسّ تفحصًّا لوجود دخلٍ أو بانتظار انتهاء عمليات محرك القرص الصلب إن لم يكن لديها شيء أفضل للقيام به. تعتمد جميع الحواسيب الحديثة على تعدّد المهام (multitasking) لأداء عدّة مهامٍ في آن واحد. قد يستخدمُ عدّة مستخدمين نفس الحاسوب. لمّا كانت وحدة المعالجة المركزيّة سريعةً للغاية، يمكنها بسهولةٍ وفعاليّة التّنقل بين المستخدمين مُكرّسة جزءًا من الثّانية لكلٍّ منهم في دوره. يُدعى تطبيق تعدّد المهام هذا بالمشاركة الزّمنيّة (timesharing). لكنّ هذا لا يمنع حاسوبًا حديثًا بمستخدم واحدٍ من استخدام تعدّد المهام. على سبيل المثال، قد يقوم المستخدم بقراءة مستندٍ بينما تعرض السّاعة الوقت على الشّاشة باستمرار أو يتمّ تحميل ملفٍ عبر الشّبكة. تُدعى كلُّ مهمةٍ فريدة من المهام التي تعمل عليها وحدة المعالجة المركزيّة بالخيط (thread أو العمليّة [Process]) – هناك فروق تقنيّة بين الخيوط والعمليّات لكنّها ليست ذات أهمية هنا على نظرًا لأنّ الخيوط فقط هي المُعتمدة في لغة جافا. تستطيع العديد من وحدات المعالجة المركزيّة تنفيذ أكثر من خيط في آن واحد حقًا. تحتوي وحدات المعالجة المركزيّة كهذه عدّة أنوية (core) تُنفّذ كلّ واحدة منها خيطًا مع العلم أنّ هناك حدًّا عدد الخيوط التي يمكن تنفيذها في آن واحد. ولمّا كان المُرجّح وجود خيوط أكثر ممّا يمكن تنفيذه في آن واحد، ينبغي على الحاسوب نقل التّنفيذ من خيط لآخر تمامًا كما يقوم حاسوب المشاركة الزّمنية بنقل التّنفيذ من مستخدمٍ لآخر. في الحالة العامّة، يستمرُّ الخيط الذي يجري تنفيذه بالعمل حتى يحدث أحد الأمور التّالية: قد يتنازل الخيط طوعًا عن سيطرته على النّواة ليمنح الخيوط الأخرى فرصةَ تنفيذ. قد يضطر الخيط لانتظار حصول حدثٍ غير متزامن. على سبيل المثال، قد يطلب الخيط بعض البيانات من القرص الصّلب أو يضطّر لانتظار أن يضغط المستخدم مفتاحًا. يُقال عن الخيط أثناء انتظاره أنّه محجوب (blocked) وتستطيع الخيوط الأخرى، في حال وجودها، أن تدخل التّنفيذ. عند حصول الحدث، تقوم مقاطعةٌ بإيقاظ الخيط لاستئناف تنفيذه. قد يستنفذ الخيط حصّته الزّمنية المخصّصة ويُعلّق مؤقتًا للسّماح بتنفيذ الخيوط الأخرى. تستطيع معظم الحواسيب تعليق خيطٍ قسريًّا بهذه الطريقة، يقال عندئذٍ أنّ هذه الحواسيب تستخدم تعدّد المهام الاستباقي (preemptive multitasking). يحتاج الحاسوب للقيام بتعدّد المهام الاستباقي إلى جهاز مؤقّت زمنيٍ خاص يُولّد مقاطعةً عند فواصل زمنيّة مُنتظمة، 100 مرةٍ في الثّانية مثلًا. عندما تحدث مقاطعة المؤقّت، يتسنّى لوحدة المعالجة المركزيّة الانتقال من خيطٍ إلى آخر بغضّ النّظر عن حالة أو حاجة الخيط الذي يجري تنفيذه. تستخدم جميع الحواسيب الحديثة المكتبيّة منها والمحمولة وحتّى الهواتف الذكيّة والأجهزة اللّوحية تعددَ المهام الاستباقي. لا حاجةَ للمستخدم العاديّ، بل وللمبرمج العاديّ أيضًا، للتّعامل مع المقاطعات ومعالجات المقاطعات. يمكن لهما التّركيز على المهام المختلفة التي يريدان للحاسوب أن يقوم بأدائها بصرف النّظر عن تفاصيل إدارة الحاسوب لعمليّة تنفيذ كل هذه المهام. في الحقيقة، يستطيع معظم المستخدمين – وبعض المبرمجين – تجاهل الخيوط وتعدد المهام كليًّا. على أيّة حال، فقد ازدادت أهميّة الخيوط مع ازدياد قدرة الحواسيب واستثمارها لمفهومي تعدد المهام وتعدد المعالجات. وفي واقع الأمر، أصبحت القدرة على العمل مع الخيوط مهارةً مهنيّةً أساسيّة للمبرمجين. لحسن الحظ، تُقدم جافا دعمًا جيّدًا للخيوط، إذ ضُمّنت الأخيرة في لغة البرمجة جافا على أنّها مفهومٌ برمجيٌّ أساسي. سنتناول البرمجة باستخدام الخيوط في الفصل 12. وعلى نفس المقدار من الأهميّة، في جافا والبرمجة الحديثة على حدٍّ سواء، نجد مفهوم الأحداث غير المتزامنة. وفي حين لا يضطّر المبرمجون للتّعامل مع المقاطعات مباشرةً، يجدون أنفسهم باستمرار وهم يكتبون معالجات أحداث (Event Handler). تُستدعى معالجات الأحداث، كما معالجات المقاطعات، على نحو غير متزامن عند حصول أحداث معينة. تختلف البرمجة المقادة بالأحداث (event-driven programming) هذه كليًّا عن البرمجة التّزامنيّة المباشرة التّقليديّة. سنبدأ أولًا بالبرمجة التقليدية التي لا تزال مستخدمة في برمجة المهام المفردة، ثمّ سنعود إلى الخيوط والأحداث لاحقًا بدءًا من الفصل 6. ولأن الشّيء بالشّيء يُذكر، فالبرمجيّة التي تقوم بجميع عمليّات معالجة المقاطعات وتتولّى التّواصل مع المستخدم وأجهزة العتاديّات، كما تضبط أيّ خيط يُسمح بتنفيذه تُدعى بنظام التّشغيل (Operating System). نظام التّشغيل هو البرمجيّة الجوهريّة الأساسيّة التي لا يستطيع الحاسوب أن يعمل بدونها. أمّا البرامج الأخرى، كمعالجات النّصوص ومتصفّحات الويب، فهي معتمدةٌ كليًّا ومنوطةٌ بنظام التشغيل. نذكر من أنظمة التّشغيل الشّائعة للحواسيب لينوكس (Linux)، ويندوز (Windows)، وماك (Mac OS) ومن أنظمة تشغيل الهواتف الذكية والأجهزة اللّوحية آندرويد (Android) و iOS. ترجمة -وبتصرف- للفصل Asynchronous Events: Polling Loops and Interrupts من الكتاب Introduction to Programming Using Java
  9. الحاسوب نظامٌ مُعقّد مؤلّفٌ من العديد من المُكوّنات المختلفة. إلّا أنَّ هناك مُكوّنًًا فريدًا يقوم بالحوسبةِ الفعليّة، هذا المُكوّن هو وحدة المعالجة المركزيّة (Central Processing Unit) أو (CPU) وهو للحاسوب كالدّماغ للإنسان. في الحواسيب المكتبيّة الحديثة، تكون وحدة المعالجة المركزيّة عبارةً عن "رقاقةٍ" (Chip) لا يتجاوز حجمها إنشًا مُربّعًا (7 سنتيمترات مُربّعةً). مهمّةُ وحدة المعالجة المركزيّة هي تنفيذ البرامج. يتألّف البرنامج (Program) من قائمةٍ من تعليماتٍ واضحة لا لبس فيها يجبُ على الحاسوب اتّباعها آليًّا. صُمّم الحاسوب لتنفيذ التّعليمات المكتوبة بنوعٍ بسيطٍ من اللغات تدعى لغةَ الآلة (Machine Language). يملك كلُّ نوعٍ من الحواسيب لغة آلة خاصة به، ويستطيع الحاسوب تنفيذ البرنامج مباشرةً فقط إذا كان هذا البرنامج مكتوبًا بلغة الآلة المذكورة. يستطيع الحاسوب تنفيذ البرامج المكتوبة باستخدام لغاتٍ أخرى بعد أن تُترجم تلك البرامج إلى لغة الآلة حصرًا. عندما تُنفّذ وحدة المعالجة المركزيّة برنامجاً ما، يُخزّن هذا البرنامج في ذاكرة الحاسوب الرّئيسيّة (تدعى أيضًا ذاكرة الوصول العشوائي [Random Access Memory] أو RAM). بالإضافة إلى البرنامج الذي يجري تنفيذه، تحتفظ الذّاكرة أيضًا بالبيانات التي يقوم هذا البرنامج باستخدمها أو معالجتها. تتألّف الذّاكرة الرّئيسية من مُتتالية من المواقع (Location)؛ هذه المواقع مُرقّمةٌ ويُعبّر الرقم التّسلسليّ للموقع عن عنوانه (Address). يسمح العنوان بانتقاء معلومةٍ بعينها من بين ملايين المعلومات المُخزّنة في الذّاكرة. عندما تحتاج وحدة المعالجة المركزيّة إلى الوصول إلى تعليمة برنامج ما أو جزء من بياناته في موقع معيّن من الذّاكرة، تُرسل عنوان تلك المعلومة على شكلِ إشارةٍ إلى الذّاكرة. تستجيب الذّاكرة بإرسال القيمة المحتواة في ذاك العنوان. تُخزّن وحدة المعالجة المركزيّة المعلومات في الذّاكرة من خلال تحديد المعلومة المُراد تخزينها وعنوان الموقع المُراد تخزينها فيه. أمّا على مستوى لغة الآلة، فإنّ عمل وحدة المعالجة المركزيّة واضحٌ وبسيط إلى حدٍّ كبير على الرّغم من تعقيد تفاصيله. تُنفّذ وحدة المعالجة المركزيّة البرنامجَ المُخزّن على شكل متتاليةٍ من تعليمات لغة الآلة المُخزَّنة في الذّاكرة الرّئيسيّة وذلك بقراءة التّعليمة، أو جلبها (Fetch)، ومن ثُمّ تنفيذها (Execute)، مرارًا وتكرارًا. تُدعى العمليّة المُتمثّلة بجلب التّعليمة وتنفيذها، ثم جلب تعليمة أخرى وتنفيذها وهكذا إلى ما لا نهاية بدورة الجلب والتّنفيذ (fetch-and-execute cycle). هذه العمليّة هي جُلّ ما تقوم به وحدة المعالجة المركزيّة باستثناءٍ وحيد سنتناوله في القسم التّالي. يُصبح هذا الأمر أكثر تعقيدّا في الحواسيب الحديثة حيث تتألّف رقاقة المعالجة هذه الأيام من عدّة "أنوية" (core) تسمح بتنفيذ عدة تعليمات في آنٍ معًا. كما سُرّع الوصول للذّاكرة الرّئيسيّة من خلال الذّاكرة المخبئيّة (cache) التي صُمّمت للاحتفاظ بالبيانات والتّعليمات التي من المُرجّح أن تحتاجها وحدة المعالجة المركزيّة في وقتٍ قريب. على أيّة حال، لا تُغيّر هذه التّعقيدات من الوظيفة الأساسيّة لوحدة المعالجة المركزيّة. تنطوي وحدة المعالجة المركزيّة على وحدة الحساب والمنطق (Arithmetic Logic Unit أو ALU) والتي تُمثّل الجزء الذي يقوم بالعمليّات الرّياضيّة كالجمع والطّرح. كما تحتفظ وحدة المعالجة المركزيّة بعدد صغير من المسجّلات (register) تُمثّل هذه الأخيرة وحدات ذاكرة صغيرة قادرة على تخزين رقم واحد. قد تتوفّر وحدة المعالجة المركزيّة النموذجيّةُ على 16 أو 32 مسجلًا مُتعدّد الأغراض (general purpose)، وهي أحد أنواع الذاكرة، إذ تحتفظ هذه المسجلات بقيم البيانات المُتاحة للمعالجة مباشرةً وتُشير العديد من تعليمات لغة الآلة إلى هذه المسجلات. على سبيل المثال، قد تكون هناك تعليمة تأخذ رقمين من مسجلين مُحدّدين، تجمع هذين الرقمين (باستخدام وحدة الحساب والمنطق)، وتُخزّن النّتيجة في مسجل جديد. وقد تكون هناك تعليمات لنسخ قيم البيانات من الذّاكرة الرّئيسيّة إلى مسجل ما أو من مسجل إلى الذّاكرة الرّئيسيّة. كما تحتوي وحدة المعالجة المركزيّة على مُسجلات ذات أغراض خاصة (special purpose). أهمّ هذه المسجلات هو عدّاد البرنامج (program counter أو PC). تعتمد وحدة المعالجة المركزيّة على عدّاد البرنامج لتعقّب التّعليمة التي تُنفّذها من البرنامج. يُخزّن عدّاد البرنامج عنوان الذّاكرة للتّعليمة التّالية التي يتوجّب على وحدة المعالجة المركزيّة تنفيذها. تفحص وحدةُ المعالجة المركزيّة عدّادَ البرنامج في بداية كل دورة جلب وتنفيذ لمعرفة التّعليمة الواجب جلبها. يُحدَّث عدّادُ البرنامج خلال كل دورة جلب وتنفيذ للإشارة إلى التّعليمة الواجب تنفيذها في الدّورة التّالية والتي - عادةً ولكن ليس دائمًا - ما تكون التّعليمة التي تعقب التّعليمة الحاليّة في البرنامج. تُعدّل بعض لغات الآلة القيم المُخزّنة في عدّاد البرنامج على نحوٍ يسمح للحاسوب أن "يقفز" (jump) من نقطةٍ ما من البرنامج إلى نقطةٍ أخرى؛ هذا الأمر جوهريّ لتطبيق ميّزات برمجية تُعرف بالحلقات والفروع ستُناقَش في الجزء 1.4. يُنفّذ الحاسوب برامج لغة الآلة آليًّا دون الحاجة إلى فهمها أو التّفكير فيها ويعود هذا الأمر ببساطةٍ إلى طريقة التّركيب الفعليّة لهذه البرامج. هذا المفهوم ليس سهلًا. الحاسوبُ آلةٌ مبنيّة من ملايين المُبدّلات الصّغيرة والتي تدعى ترانزستورات (Transistor). تتميّز الترانزستورات بإمكانية توصيلها على نحوٍ يسمح أن يتحكّم خرج أحد هذه التّرانزستورات بترانزستور آخر (تشغيله أو إيقافه). بينما يقوم الحاسوب بالحوسبة، تقوم هذه المُبدّلات بتشغيل وإيقاف تشغيل بعضها بعضًا وفق نمطٍ تُمليه كلٍّ من طريقة وصلها ببعضها بعضًا من جهة والبرنامج الذي ينفذّه الحاسوب من جهة أخرى. تُمثّل تعليمات لغة الآلة على شكل أرقام ثنائيّة. يتألّف الرّقم الثّنائيّ من حالتين لا ثالث لهما: صفر وواحد. يُطلق على كلِّ صفر أو واحد تسمية بت (Bit). إذًا فلغة الآلة ما هي إلّا متتالية من الأصفار والواحدات. تُرمّز كل متتالية محدّدة تعليمة مُحدّدةً بعينها. تُرمّز البيانات التي يُعالجها الحاسوب أيضًا كأرقام ثنائيّة. في الحواسيب الحديثة، يحتفظ كل موقعٍ في الذّاكرة ببايت (Byte) والذي يُمثّل متتاليةً من ثمانية بتّات. عادةً ما تتألّف البيانات أو تعليمة لغة الآلة من عدّة بايتات مُخزّنة في مواضع متعاقبة من الذاكرة. على سبيل المثال، قد يقرأ الحاسوب فعليّا أربعة أو ثمانية بايتات عند قراءته تعليمةً واحدةً من الذّاكرة؛ ويكون عنوان الذّاكرة للتّعليمة هو عنوان أول بايت من تلك البايتات. يستطيع الحاسوب العمل مباشرةً مع الأرقام الثنائيّة لأن المبدّلات قادرةٌ على تمثيل هكذا أرقامٍ بسهولة: تشغيل التّرانزستور لتمثيل الرقم واحد؛ وإيقافه لتمثيل الرقم صفر. تُخزّن تعليمات لغة الآلة في الذّاكرة على شكل أنماطٍ من المبدّلات المُشغّلة أو المتوقّفة. عندما تُحمّل تعليمة لغة الآلة إلى وحدة المعالجة المركزيّة، فإنّ ما يحصل في الحقيقة هو تشغيل أو إيقاف مُبدّلات معينة وفقًا للنّمط الذي يُرمّز تلك التّعليمة. بُنيَت وحدة المعالجة المركزيّة للاستجابة لهذا النّمط بتنفيذ التّعليمة التي يُرمّزها ويُمكّنها من ذلك كونُ جميع المبدّلات في وحدة المعالجة المركزيّة موصولةً معًا. إذًا، عليك فهم ما يلي حول كيفيّة عمل الحاسوب: تحتفظ الذّاكرة الرّئيسيّة ببرامج وبيانات لغة الآلة. تُرمَّز كلٌّ من هاتين الأخيرتين كأرقام ثنائيّة. تجلب وحدة المعالجة المركزيّة تعليمات لغة الآلة من الذّاكرة واحدةً تلو الأخرى وتُنفّذها. تُؤدّي وحدة المعالجة المركزيّة مهامًّا صغيرةً جدًا وفقًا لكل تعليمة، مثل جمع عددين أو نقل البيانات من وإلى الذاكرة. تقوم وحدة المعالجة المركزيّة بكلّ هذا آليًّا بدون التّفكير فيه أو فهم الهدف منه لهذا يتوّجب على البرنامج الذي سيُنفّذ أن يكون مُتقنًا، كاملًا بكل تفاصيله، وخاليًا من أيّ لبس لأن وحدة المعالجة المركزيّة عاجزةٌ إلّا عن تنفيذه تمامًا كما هو مكتوب. إليك رؤيةً تخطيطيّة لهذه المرحلة من فهمنا للحاسوب: ترجمة -وبتصرف- للقسم The Fetch and Execute Cycle: Machine Language من الكتاب Introduction to Programming Using Java
  10. يُخفّض الضّغط من أوقات الاستجابة من خلال تقليص حجم استجابة HTTP. يُعدُّ Gzip طريقةَ الضّغط الأكثر شيوعًا وفعاليّةً في الوقت الحاضر و عادةً ما يُقلّص حجم الاستجابة بما يقارب 70%. في عام 2009، كانت 90% من حركة البيانات على الإنترنت تعبر من خلال متصفّحات تدعم Gzip. أمّا اليوم: يمكنك القيام بذلك على خادم مبنيٍّ على Apache من خلال الملف ‎.htaccess: # BEGIN GZIP <ifmodule mod_deflate.c> AddOutputFilterByType DEFLATE text/text text/html text/plain text/xml text/css application/x-javascript application/javascript </ifmodule> # END GZIP يُمثّل ما سبق قائمةً بأنواع MIME التي سيُطبّق عليها الضّغط حينئذٍ. يمكنك التعديل على هذه القائمة كما ترى مناسبًا لتشمل جميع أصولك النّصيّة التي ستخدّمها: يُقدّم مشروع HTML5 Boilerplate إعدادات الخواديم لجميع الخواديم الشائعة. هذه هي نسخة المشروع لملف htaccess. <IfModule mod_filter.c> AddOutputFilterByType DEFLATE "application/atom+xml" \ "application/javascript" \ "application/json" \ "application/ld+json" \ "application/manifest+json" \ "application/rdf+xml" \ "application/rss+xml" \ "application/schema+json" \ "application/vnd.geo+json" \ "application/vnd.ms-fontobject" \ "application/x-font-ttf" \ "application/x-javascript" \ "application/x-web-app-manifest+json" \ "application/xhtml+xml" \ "application/xml" \ "font/eot" \ "font/opentype" \ "image/bmp" \ "image/svg+xml" \ "image/vnd.microsoft.icon" \ "image/x-icon" \ "text/cache-manifest" \ "text/css" \ "text/html" \ "text/javascript" \ "text/plain" \ "text/vcard" \ "text/vnd.rim.location.xloc" \ "text/vtt" \ "text/x-component" \ "text/x-cross-domain-policy" \ "text/xml" </IfModule> ترجمة -وبتصرف- للمقال Active Gzip Compression لصاحبه Chris Coyier
  11. تُعرّف Node.js بأنّها منصّة JavaScript للبرمجة عامّة الأغراض تسمح للمستخدمين ببناء تطبيقات شبكيّة بسرعة. تجعل Node.js عمليّة التّطوير أكثر اتّساقًا وتكاملًا وذلك بتسخير ميّزات JavaScript في كلٍّ من الواجهة الأماميّة (front end) والواجهة الخلفيّة (backend). سنعرض لك في هذا الدّليل كيفيّة البدء بمنصة Node.js على نظام خادم أبونتو 18.04. المتطلبات يفترض هذا الدّليل أنك تستخدم أبونتو 18.04. قبل أن تبدأ، يجب أن يتوفّر لديك على نظامك حساب مستخدم غير جذر (non-root) ذا امتيازات sudo. يمكنك تعلُّم كيفيّة القيام بهذا من خلال اتّباع خطوات دليل إعداد الخادم الابتدائي لنظام أبونتو 18.04. تثبيت إصدار التوزيعة المستقرة (Distro-Stable) في أبونتو يتضمّن أبونتو 18.04 في مستودعاته الافتراضيّة إصدارًا من Node.js يُمكن استخدامه للحصول على تجربة مُتّسقة على عدّة أنظمة. حتى كتابة هذا الدّليل، فإن الإصدار المتوفّر في المستودعات هو 8.10.0. هذا الإصدار ليس الأحدث، لكنّه مُستقّرٌ وكافٍ لإجراء تجارب سريعةٍ مع اللغة. للحصول على هذا الإصدار، يمكنك استخدام مدير الحزمة apt. قم بتحديث فهرس الحزمة المحليّة لديك بكتابة الأمر التالي: sudo apt update قم بتثبيت Node.js من المستودعات: sudo apt install nodejs إذا لبّت الحزمة الموجودة في المستودعات حاجتك، فهذا كل ما تحتاج القيام به لإعداد Node.js. في معظم الحالات، قد ترغب في تثبيت مدير الحزم الخاصّ بالمنصة (Node.js package manager أو npm). يمكنك القيام بذلك بكتابة التّالي: sudo apt install npm سيسمح ما سبق لك بتثبيت وحدات وحزم لاستخدامها مع Node.js. نظرًا لوجود تعارضٍ مع حزمة أخرى، يُدعى الملفّ التّنفيذيّ المُحمّل من مستودعات أبونتو nodejs بدلًا من node. تذكّر هذا الأمر جيدًا عند تشغيلك للبرمجيّة. للتّحقق من إصدار Node.js المُثبّت لديك بعد هذه الخطوات الأوليّة، قم بكتابة الأمر التّالي: nodejs -v بعد أن تتأكد من إصدار Node.js المُثبّت لديك من مستودعات أبونتو، تستطيع حينها أن تقرر إذا ما كنت تريد العمل مع إصدارات مُغايرة، أرشفة حزم مختلفة أو مدير إصدار آخر. سنناقش هذه العناصر فيما يلي كما سنعرض سُبلًا أكثر مرونةً وحداثةً للتّثبيت. التّثبيت باستخدام أرشيف الحزم الشّخصي PPA للحصول على إصداراتٍ أحدث من Node.js، يمكنك إضافة أرشيف الحزم الشّخصي المُدار من قبل NodeSource. يحتوي هذا الأرشيف على إصدارات أحدث مما هو موجود في مستودعات أبونتو الرّسميّة. كما سيسمح لك بالاختيار من باقة إصدارات أوسع تتراوح بين Node.js v8.x (المدعومة حتى نهاية العام الجاري)، الإصدار ذي الدّعم الطّويل الأمد الحالي Node.js v10.x، والإصدار الحالي Node.js v12.x. قم أوّلًا بتثبيت PPA لتستطيع الوصول إلى محتوياته. من الدّليل الرّئيسيّ لديك، استخدم curl لجلب البرنامج النّصي لتّثبيت الإصدار المُفضّل لديك، لا تنسَ استبدال ‎10.x بالسّلسلة الخاصة بالإصدار الذي تريده إن لم يكن هو المطلوب: cd ~ curl -sL https://deb.nodesource.com/setup_10.x -o nodesource_setup.sh يمكنك فحص محتويات هذا البرنامج النّصّي من خلال فتحه باستخدامnano أو باستخدام محرّرك النّصّي المُفضّل: nano nodesource_setup.sh قم بتنفيذ البرنامج النّصّي ضمن امتيازات sudo: sudo bash nodesource_setup.sh سيُضاف أرشيف الحزم الشخصي هذا إلى إعداداتك وستُحدّث خابية الحزم المحليّة لديك تلقائيًّا. بعد تنفيذ نص التثبيت من Nodesource، يمكنك تثبيت حزمة Node.js بنفس الطريقة المذكورة أعلاه: sudo apt install nodejs للتّحقق من إصدار Node.js المُثبّت لديك بعد هذه الخطوات الأوليّة، قم بكتابة الأمر التّالي: nodejs -v وسترى خرجًا مشابهًا للتّالي: v10.14.0 nvmتتضمّن حزمة nodejs الملف الثنائي nodejs بالإضافة إلى npm. لذلك، فلست بحاجةٍ لتثبيت npm على حدة. يستخدم npm ملف إعدادات في دليلك الرّئيسيّ لتعقّب التّحديثات. سيُنشَئ هذا الملف عند المرّة الأولى التي تقوم بها بتشغيل npm. قم بتنفيذ هذا الأمر للتّحقق أنّ npm مُثبّتة بالفعل وإنشاء ملف الإعدادت هذا: npm -v وسترى خرجًا مشابهًا للتّالي: 6.4.1 لكي يتسنّى لبعض حزم npm أن تعمل (تتطلّب تلك الحزم على سبيل المثال ترجمة الشّيفرة البرمجيّة من المصدر)، أنت بحاجةٍ لتثبيت حزمة build-essential: sudo apt install build-essential أصبح لديك الآن الأدوات الضّروريّة للعمل مع حزم npm التي تتطلّب ترجمة الشيفرة البرمجيّة من المصدر. التثبيت باستخدام NVM كبديلٍ عن تثبيت Node.js باستخدام apt، يمكنك استخدام أداة nvm، هذه الأداة هي مدير إصدارات المنصة (Node.js Version Manager). عوضًا عن العمل على مستوى نظام التشغيل، تعمل nvm على مستوى مجلد مستقلٍّ داخل مجلدك الرّئيسيّ. هذا يعني أنّ بإمكانك تثبيت عدّة إصدارات قائمة بحدّ ذاتها من Node.js ضمن المجلد الرّئيسيّ دون التّأثير على النّظام بأكمله. يسمح لك ضبط بيئتك باستخدام nvm بالوصول إلى أحدث إصدارات Node.js وفي الوقت ذاته الإبقاء على الإصدارات السابقة وإدارتها بفعاليّة. إنّها وسيلة مختلفةٌ كليًّا عن apt كما أنّ إصدارات Node.js التي تديرها باستخدام nvm مميّزة عن تلك التي تديرها باستخدام apt. يمكنك استخدام curl لتنزيل البرنامج النّصي الخاص بتثبيت nvm من صفحة المشروع على GitHub. لاحظ أنّ رقم الإصدار قد يختلف عمّا هو موجود في هذا الدّليل: curl -sL https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh -o install_nvm.sh تفحّص البرنامج النّصي للتّثبيت باستخدامnano: nano install_nvm.sh قم بتنفيذ البرنامج النّصي باستخدام bash: bash install_nvm.sh سيثبِّت الأمر السّابق البرمجيّة في مجلد فرعيّ من المجلد الرئيسي ضمن الملف ‎~/.nvm كما سيضيف الأسطر اللازمة إلى الملف ‎~/.profile لاستخدام الملف المذكور. لتستطيع النّفاذ إلى قدرات nvm الوظيفيّة، ستحتاج إما لتسجيل الخروج ومن ثمّ تسجيل الدّخول مرة أخرى أو إعادة تحميل الملف ~/.profile باستخدام الأمر source وذلك حتى تدرك الجلسة الحاليّة التّغييرات التي أحدثتها. source ~/.profile الآن بعد أن قمت بتثبيت nvm، يمكنك تثبيت إصدارات معزولةٍ من Node.js. للحصول على معلومات حول إصدارات Node.js المتوفّرة، نفذ الأمر التّالي: nvm ls-remote سيظهر لك خرجٌ مشابهٌ لما يلي: ... v10.15.3 (Latest LTS: Dubnium) v11.0.0 v11.1.0 v11.2.0 v11.3.0 v11.4.0 v11.5.0 v11.6.0 v11.7.0 v11.8.0 v11.9.0 v11.10.0 v11.10.1 v11.11.0 v11.12.0 v11.13.0 v11.14.0 v11.15.0 v12.0.0 v12.1.0 v12.2.0 كما ترى، الإصدار ذو الدّعم الطّويل الأمد الحالي عند كتابة هذا الدّليل هو v10.15.3، يمكنك تثبيته من خلال الأمر التّالي: nvm install 10.15.3 عادة ما تُبدّل nvm لاستخدام الإصدار الأحدث. يمكنك أن تحدّد الإصدار الذي قمت بتحميله توًّا لتستخدمه nvm من خلال الأمر: nvm use 10.15.3 عندما تُثبّت Node.js باستخدام nvm، فإنّ الملف التنفيذي يحمل الاسم node. يمكنك معرفة الإصدار الذي تستخدمه الصّدفة (Shell) لديك من خلال الأمر التّالي: node -v وسيكون الخرج: v10.15.3 إذا كان لديك أكثر من إصدار Node.js، يمكنك معاينتها بكتابة الأمر: nvm ls إذا رغبت بتحديد أحد هذه الإصدارات كافتراضيّ، نفذ الأمر التالي: nvm alias default 10.15.3 سيتم اختيار هذا الإصدار تلقائيًّا عند الشّروع في جلسةٍ جديدة. يمكنك أيضًا الإشارة إلى الإصدار باسم بديل (Alias) كما يلي: nvm use default يقوم كل إصدار من Node.js بتعقب حزمه ويتوفر لديه npm خاصّ لإدارة هذه الحزم. يمكنك استخدام npm لتثبيت حزم إلى دليل مشروع Node.js وهو ‎./node_modules. استخدم الصّياغة التّالية لتثبيت الوحدة express: npm install express إذا أردت تثبيت الوحدة على نحوٍ عموميٍّ (Global) لجعلها متاحةً للمشاريع الأخرى باستخدام الإصدار نفسه من Node.js، يمكنك إضافة الراية ‎-g: npm install -g express سيقوم الأمر السّابق بتثبيت الحزمة في: ~/.nvm/versions/node/node_version/lib/node_modules/express سيسمح لك تثبيت الوحدة على نحوٍ عموميٍّ بتنفيذ أوامر من سطر الأوامر، لكن سيكون عليك ربط الحزمة في النّطاق الخاص بك لطلبها من داخل برنامج ما: npm link express يمكنك الاطلاع على المزيد من الخيارات التي يوفرها nvm بكتابة الأمر التالي: nvm help حذف منصة Node.js يمكنك حذف Node.js باستخدام apt أو apt تبعًا للإصدار الذي تريد حذفه. لحذف إصدار التّوزيعة المستقرّة، عليك أن تستخدم الأداة apt على مستوى النّظام. لحذف إصدار التّوزيعة المستقرّة، استخدم الأمر الآتي: sudo apt remove nodejs سيحذف هذا الأمرُ الحزمةَ ويحتفظ بملفات الإعدادات. قد تكون هذه الملفات ذات فائدة لك إذا ما رغبت بتثبيت الحزمة مرة أخرى بعد مرور الوقت. إن لم ترد الاحتفاظ بملف الإعدادات لاستخدامه لاحقًا، قم بتنفيذ الأمر التالي: sudo apt purge nodejs سيقوم هذا الأمر بإلغاء تثبيت الحزمة وحذف ملفات الإعدادات المرافقة لها. كخطوة أخيرة، يمكنك حذف جميع الحزم غير المستخدمة والتي تم تثبيتها تلقائيًّا مع الحزم التي قمت بحذفها توًّا باستخدام الأمر التالي: sudo apt autoremove لإلغاء تثبيت إصدار قمت بتفعليه باستخدام nvm ، تحقق أولًّا فيما إذا كان الإصدار المعنيّ هو الإصدار النشط حاليًّا: nvm current إذا لم يكن الإصدار المستهدف هو الإصدار النّشط حاليًّا، نفذ الأمر التّالي: nvm uninstall node_version سيقوم هذا الأمر بإلغاء تثبيت الإصدار المختار من Node.js. أمّا إذا كان الإصدار الذي ترغب بحذفه هو الإصدار النشط، عليك أولًا إلغاء تفعيل nvm لتمكين التّغييرات التي ستقوم بإجرائها: nvm deactivate يمكنك الآن إلغاء تثبيت الإصدار الحالي باستخدام أمر uninstall المستخدم أعلاه والذي سيقوم بحذف جميع الملفات المرافقة للإصدار المعني من Node.js ما عدا الملفات المخبّأة والتي يمكن استخدامها لاحقًا لإعادة التّثبيت. الخاتمة هناك بالفعل العديد من الطّرق للبدء باستخدام Node.js على خادم أبونتو 18.04. عادةً ما تملي الظروف أيًّا من الطرق المذكورة أعلاه هي الأفضل. وفي حين أنّ استخدام الإصدار الموجود في مستودع أبونتو هو الخيار الأسهل، يُقدّم استخدام nvm خيارات ومرونةً أكثر. ترجمة -وبتصرف- للمقال How To Install Node.js on Ubuntu 18.04 لصاحبيه Brennen Bearnes و Kathleen Juell
  12. يمثّل كلٌّ من الضّغط والتّصغيرأمرًا تقوم بتنفيذه على الأصول الموجودة في موقعك (مثل ملفات css. وملفات js.). تستطيع من خلال كِلَيهما تقليص حجم الملف وبالتّالي جعلَه أكثر فعاليّةً في عبور الشبكة بين الخواديم والمتصفّحات. بكلمات أخرى، يصبح الأداء أفضل بتقليص حجم أصولك. تمثّل الشبكة نقطةَ اختناقٍ لسرعة الويب. لهذا السّبب، يساعد تخفيض حجم الملف وتقليصه في تفادي تحميل عبء زائد على الشّبكة. لكنّهما - أي الضغط والتصغير - يختلفان عن بعضهما بوضوح. إن كنت لا تعرف هذا بالفعل، فالأمر يستحق الاطّلاع. يقوم التّصغير بأمورٍ مثل حذف الفواصل، وحذف التّعليقات، وحذف الفواصل المنقوطة غير الضّروريّة وتقليل طول الرّموز السّت عشريّة وغيرها من الأمور المشابهة. يبقى الملف شيفرةً صالحةً تمامًا. لن ترغبَ في محاولة قراءتها أو العمل عليها، لكنها لا تخرق أيًّا من القواعد. يستطيع المتصفّح قراءتها واستخدامها كما هو الحال في الملف الأصليّ. يُنشئ التّصغير ملفًا جديدًا تقومُ أنتَ باستخدامه في نهاية المطاف. على سبيل المثال، تستطيع إنشاء ملف style.css لتعمل عليه، ومن ثمّ بإمكانك تصغيره إلى style.min.css. يتحرّى الضّغط جميع المقاطع المكرّرة ويستبدلها بمؤشّرات إلى موضع الورود الأول للمقطع المعنيّ. قدّمت جوليا إيفانز Julia Evans طريقةً رائعة لفهم ما سبق (راجع منشورها والفيديو). إليك الفقرة الأولى من القصيدة: .red { color: red; } Once upon a midnight dreary, while I {pon}dered weak an{d wea}{ry,} Over many{ a }quaint{ and }curious volume of forgotten lore, W{hile I }nodded, n{ear}ly napping, su{dde}n{ly }th{ere} ca{me }a t{apping,} As{ of }so{me o}ne gent{ly }r{apping, }{rapping} at my chamb{er }door. `'Tis{ some }visitor,'{ I }mu{tte}r{ed, }`t{apping at my chamber door} - O{nly th}is,{ and }no{thi}{ng }m{ore}. وَجد gzip أن النّصّ الوارد ضمن أقواس متعرّجة هو نصٌّ مكرّر. لهذا السبب، سيُستبدل بمؤشّر يستهلك مساحةً أقل مما يستهلكه النّصّ نفسه. تظهر فعاليّة هذا الأمر في إنقاص حجم الملف، خاصّةً في حالة الشّيفرة البرمجيّة على اعتبار أنّها تحتوي بطبيعتها على الكثير من المقاطع المكرّرة. تخيّل فقط عدد مرّات ورود ‎<div في ملف HTML أو عدد مرّات ورود { في ملف CSS. يمكنك إنشاء إصدارات مضغوطة من الملفات، على سبيل المثال style.css.zip لكنّك نادرًا ما ستضطّر لذلك ولن يعرف المتصفّح ماذا يفعل بهذه الإصدارات. تتّم عمليّة الضّغط على الويب من قبل الخادم مباشرةً ذلك إذا ما قمت بإعداده للقيام بها. حالما تُطبّق الإعدادات، يحدث الضّغط تلقائيًّا ولا حاجةَ بك للقيام بأي عمل آخر. يضغط الخادم الملف ويرسله عبر الشبكة مضغوطًا. يستقبل المتصفح الملف ويفكّ ضغطه قبل استخدامه. لم أسمع قطُّ أحدًا يذكر أعباء عمليّتَي الضّغط وفكّ الضّغط، لذا سأفترض أنّها مهملةٌ وأنّ فوائدها تفوقُ أعباءها بكثيرٍ. يجري عادةً أتمتة عملية الضغط عبر أدوات البناء مثل Gulp مما يسهل عليك العملية. إليك كيفيّة تفعيل عمليّة الضّغط على خادم Apache من خلال استخدام الوحدة mod_deflate . كما يّقدّم H5BP إعدادات الخواديم لجميع الخواديم الشّائعة التي تدعم الضّغط. مثال سنستخدم ملف CSS من Bootstrap على اعتباره مرجعًا شائعًا. ستُوفّر ما يقارب 17% عند تصغير ملف CSS، أو 85% عند ضغطه أو 86% عند قيامك بكليهما. الوضع المثاليّ عند التأكد من عمل كلِّ شيءٍ كما ينبغي من خلال أدوات المطور (DevTools) موضّح كما يلي: الضّغط أكثر فعاليّة، لكنّ القيام بكليهما هو الأفضل بالمطلق. تُخفّض عمليّة الضّغط حجم الملف أكثر بخمسة أضعاف من عمليّة التّصغير. لكنّك تحصل على دفعة صغيرة إضافيّة عند القيام بالتّصغير أيضًا. هناك أيضًا دليلٌ على أنّ المتصفّحات تقرأ وتحلّل الملف المُصغّر أسرع: شرَعَت مايكروسوفت هي الأخرى بتحسين مُحلّلاتها لهذا الأمر: يندرج التّخزين المؤقّت للأصول في هذا السّياق أيضًا حيث لا يوجد ما هو أسرع من مُتصفّح لا يحتاج إلى طلب الأصول على الإطلاق. يوجد الكثير من المعلومات حول هذا الموضوع على الوِيب (أو في الكتب)، وقد نقوم بنشر مقال حول هذا الموضوع قريبًا. ترجمة -وبتصرف- للمقال The Difference Between Minification and Gzipping لصاحبه Chris Coyier
  13. نحتاج إلى كلٍّ من جافا (Java) وآلة جافا الوهميّة (Java Virtual Machine) لتشغيل العديد من البرمجيّات مثل Tomcat، و Jetty، و Glassfish، و Cassandra، و Jenkins. سنتعلم في هذا الدّليل كيفية تثبيت إصدارات مختلفة من (Java Runtime Environment (JRE و (Java Developer Kit (JDK باستخدام apt. سنثبِّت OpenJDK بالإضافة إلى الحزم الرّسميّة من موقع Oracle، سنختار بعدئذٍ الإصدار الذي تريد استخدامه لمشروعك. ستستطيع عند الانتهاء من استخدام JDK لتطوير البرمجيّات أو استخدام Java Runtime لتنفيذ البرمجيّات. المتطلبات ستحتاج لمتابعة هذا الدّليل إلى: خادم أبنتو 18.04 سبق إعداده باتّباع خطوات دليل إعداد الخادم الابتدائي، وهذا يتضمّن سحاب مستخدم غير جذر (non-root) ذا امتيازات sudo وجدارًا ناريًّا. تثبيت JRE/JDK الافتراضيّة الخيار الأسهل عند تثبيت جافا هو استخدام الإصدارات المُضمّنة مع أبنتو. يتضمّن أوبنتو 18.04 افتراضيًّا Open JDK والتي هي تنويعة مفتوحة المصدر من JRE و JDK. لتثبيت الإصدار 11 من OpenJDK، قُم أوّلًا بتحديث فهرس الحزمة: sudo apt update تحقّق بعد ذلك إذا ما كانت جافا مُثبّتةً بالفعل: java -version إذا لم تكن جافا مُثبّتةً، سترى الخرج التّالي: Output Command 'java' not found, but can be installed with: apt install default-jre apt install openjdk-11-jre-headless apt install openjdk-8-jre-headless apt install openjdk-9-jre-headless نفّذ الأمر التّالي لتثبيت OpenJDK: sudo apt install default-jre سيُثبّت هذا الأمر بيئة التشغيل الآني لجافا (JRE اختصار للعبارة Java Runtime Environment) التي ستسمح لك بتشغيل جميع برمجيّات جافا تقريبًا. تحقّق من التّثبيت باستخدام: java -version سترى الخرج التّالي: Output openjdk version "11.0.3" 2019-04-16 OpenJDK Runtime Environment (build 11.0.3+7-Ubuntu-1ubuntu218.04.1) OpenJDK 64-Bit Server VM (build 11.0.3+7-Ubuntu-1ubuntu218.04.1, mixed mode, sharing) قد تحتاج إلى أدوات جافا التطويرية (JDK اختصار للعبارة Java Development Kit) إلى جانب JRE إذا أردت ترجمة وتشغيل بعض البرمجيّات المعتمدة على جافا. لتثبيت JDK، قم بتنفيذ الأمر التّالي: sudo apt install default-jdk سيثبت هذا الأمر JRE أيضًا. تحقّق من تثبيت JDK من خلال تفحّص إصدار مصرِّف جافا javac: javac -version سترى الخرج التّالي: javac 11.0.3 سنعمل الآن على تحديد الإصدار الذي نريد تثبيته من OpenJDK. تثبيت إصدارات محددة من OpenJDK بالإضافة إلى تثبيت حزمة OpenJDK الافتراضية، يمكنك أيضًا تثبيت إصدارات مختلفة من OpenJDK. ستتعلّم في هذا الدّليل تثبيت الإصدارين الحاليّ والسّابق من الإصدارات ذات الدّعم الطّويل الأمد. OpenJDK 8 جافا 8 هي إحدى الإصدارات ذات الدّعم الطّويل الأمد من Oracle. على الرّغم من انتهاء صيانتها العامّة منذ كانون الثّاني من هذا العام إلّا أن التّحديثات العامّة للإصدارات الشّخصيّة وإصدارات التّطوير مستمرّة حتى كانون الأوّل 2020. لتثبيت OpenJDK 8، قم بتنفيذ الأمر التّالي: sudo apt install openjdk-8-jdk تحقّق من التّثبيت من خلال الأمر: java -version سيظهر لك الخرج التّالي: Output openjdk version "1.8.0_162" OpenJDK Runtime Environment (build 1.8.0_162-8u162-b12-1-b12) OpenJDK 64-Bit Server VM (build 25.162-b12, mixed mode) من المُمكن تثبيت JRE فقط من خلال تنفيذ الأمر sudo apt install openjdk-8-jre. OpenJDK 11 جافا 11 هي الإصدار الحاليّ ذي الدّعم الدّعم الطّويل الأمد ومن المُتوقّع أن يستمرّ دعمها حتّى العام 2022 . لتثبيت OpenJDK 11، قم بتنفيذ الأمر التّالي: sudo apt install openjdk-11-jdk لتثبيت JRE فقط، استخدم الأمر التّالي: sudo apt install openjdk-11-jre سنقوم الآن بتثبيت حزم JDK و JRE الرّسميّة من Oracle. تثبيت Oracle JDK إذا أردت تثبيت Oracle JDK، الإصدار الرّسمي الذي توزعه Oracle، ستحتاج لإضافة مستودع حزمة جديد للإصدار الذي ترغب باستخدامه. لتثبيت جافا 8، قم أولًا بإضافة مستودع حزمته: sudo add-apt-repository ppa:webupd8team/java عند إضافة المستودع، سترى رسالةً كهذه: Output Oracle Java (JDK) Installer (automatically downloads and installs Oracle JDK8). There are no actuJava files in this PPA. Important -> Why Oracle Java 7 And 6 Installers No Longer Work: http://www.webupd8.org/2017/06/why-oracl e-java-7-and-6-installers-no.html Update: Oracle Java 9 has reached end of life: http://www.oracle.com/technetwork/java/javase/downloads/j dk9-downloads-3848520.html The PPA supports Ubuntu 18.04, 17.10, 16.04, 14.04 and 12.04. More info (and Ubuntu installation instructions): - for Oracle Java 8: http://www.webupd8.org/2012/09/install-oracle-java-8-in-ubuntu-via-ppa.html Debian installation instructions: - Oracle Java 8: http://www.webupd8.org/2014/03/how-to-install-oracle-java-8-in-debian.html For Oracle Java 10, see a different PPA: https://www.linuxuprising.com/2018/04/install-oracle-java-10-in-ubuntu-or.html More info: https://launchpad.net/~webupd8team/+archive/ubuntu/java Press [ENTER] to continue or Ctrl-c to cancel adding it. اضغط ENTER للاستمرار ثمّ قُم بتحديث قائمة الحزم: sudo apt update حالما تُحدَّث القائمة، قُم بتثبيت جافا 8: sudo apt install oracle-java8-installer سيُنزّل نظامك JDK من Oracle ويطلب منك قبول اتفاقيّة التّرخيص. قُم بالموافقة على الاتفاقيّة وسيبدأ تثبيت JDK. سننظر الآن إلى إمكانيّة اختيار إصدار جافا الذي ترغب باستخدامه. إدارة جافا قد يتوفّر لديك عدّة إصدارات جافا مُثبّتةٍ على خادمٍ واحد. يمكنك إعداد أيٍّ من هذه الإصدارات ليكون الافتراضي لديك أو استخدام سطر الأوامر من خلال الأمرupdate-alternatives: sudo update-alternatives --config java إذا ثبَّت جميع إصدارات جافا في هذا الدّليل، سيبدو الخرج لديك كالتّالي: Output There are 3 choices for the alternative java (providing /usr/bin/java). Selection Path Priority Status ------------------------------------------------------------ * 0 /usr/lib/jvm/java-11-openjdk-amd64/bin/java 1101 auto mode 1 /usr/lib/jvm/java-11-openjdk-amd64/bin/java 1101 manual mode 2 /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java 1081 manual mode 3 /usr/lib/jvm/java-8-oracle/jre/bin/java 1081 manual mode اختر الرّقم الموافق لإصدار جافا الذي ترغب في استخدامه افتراضيّا، أو اضغط ENTER لترك الإعدادت على ما هي عليه. يمكنك القيام بهذا لأوامر جافا أخرى، مثل المترجم (javac): sudo update-alternatives --config javac نذكر على سبيل المثال لا الحصر من بعض الأوامر الأخرى التي يمكنك تنفيذ ما سبق عليها: keytool، Javadoc و jarsigner. تعيين متغير البيئة JAVA_HOME تستخدم العديد من البرامج المكتوبة باستخدام لغة جافا مُتغيّر البيئة JAVA_HOME لتحديد مسار تثبيت جافا. لتعيين مُتغيّر البيئة هذا، حدّد أولًا أين ثُبتّت جافا. استخدم الأمر update-alternatives كما يلي: sudo update-alternatives --config java سيعرض لك هذا الأمر جميع تثبيات جافا لديك مع مسار كلٍّ منها: There are 3 choices for the alternative java (providing /usr/bin/java). Selection Path Priority Status ------------------------------------------------------------ * 0 /usr/lib/jvm/java-11-openjdk-amd64/bin/java 1101 auto mode 1 /usr/lib/jvm/java-11-openjdk-amd64/bin/java 1101 manual mode 2 /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java 1081 manual mode 3 /usr/lib/jvm/java-8-oracle/jre/bin/java 1081 manual mode Press <enter> to keep the current choice[*], or type selection number: في حالتنا هذه، فإنّ مسارات التّثبيت هي كالتّالي: OpenJDK 11 على المسار ‎/usr/lib/jvm/java-11-openjdk-amd64/bin/java. OpenJDK 8 على المسار ‎/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java. Oracle Java 8 على المسار ‎/usr/lib/jvm/java-8-oracle/jre/bin/java. قُم بنسخ مسار الإصدار المفضّل لديك ثم افتح الملف ‎/etc/environment باستخدام nano أو محرّر النّصوص الذي تفضّله: sudo nano /etc/environment أَضِف السطر التّالي في نهاية هذا الملف وتأكّد من استبدال المسار الملّون بالمسار الذي قمت أنت بنسخه: JAVA_HOME="/usr/lib/jvm/java-11-openjdk-amd64/bin/" سيضبط تعديل هذا الملف مسار JAVA_HOME لجميع المستخدمين على نظامك. احفظ تعديلاتك على الملف وأغلق المُحرّر. أعِد تحميل هذا الملف لتطبيق التعديلات على جلستك الحاليّة: source /etc/environment تحقّق من تعيين مُتغيّر البيئة: echo $JAVA_HOME سترى المسار الذي قمت بتعيينه منذ قليل: Output /usr/lib/jvm/java-11-openjdk-amd64/bin/ سيحتاج المستخدمون الآخرون إلى تنفيذ الأمر source /etc/environment أو تسجيل الخروج وإعادة تسجيل الدخول ليصبح هذا الضّبط نافذ المفعول. خاتمة قمتَ في هذا الدّليل بتثبيت عدة إصدارات من جافا وتعلّمت كيفيّة إدارة هذه الإصدارات. يمكنك الآن تثبيت برمجيات تعمل على Java مثل Tomcat، أو Jetty، أو Glassfish، أو Cassandra، أو Jenkins. ترجمة -وبتصرف- للمقال How To Install Java with apt on Ubuntu 18.04 لصاحبه Koen Vlaswinkel
×
×
  • أضف...