البحث في الموقع
المحتوى عن 'متانة البرامج'.
-
يُعَد عمل البرنامج صحيحًا إذا أنجز المَهمَّة المُوكَلة إليه بصورةٍ صائبة، بينما يُعَد البرنامج متينًا robust إذا عالَج قِيم المُدخَلات غير الصالحة أو غيرها من المواقف غير المُتوقَّعة على نحوٍ مقبولٍ، فمثلًا إذا صُمِّم برنامج لقراءة مجموعةٍ من الأعداد المدخَلة من قِبل المستخدِم ثم طباعتها بصورةٍ مرتّبة، فسيعمل البرنامج بصورةٍ صحيحةٍ إذا أعاد حاصل المجموع الصحيح لأي أعدادٍ مدخَلةٍ، بينما سيكون متينًا إذا طُبعت رسالة خطأ مع المدخَلات غير العددية أو تم تجاهلها؛ أما البرامج غير المتينة فقد تنهار في هذه الحالة أو تعطي خرجًا غير مقبول. لابدّ لأي برنامجٍ أن يعمل بصورةٍ صحيحة؛ فما الفائدة إذًا من برنامج ترتيب sorting لا ينجز عملية الترتيب بصورة سليمة؟ وليس من الضروري دائمًا أن يكون البرنامج متينًا بالكامل، فذلك يعتمد على المستخدم وطريقة استخدامه؛ فمثلًا لا يُشترط لبرنامج مساعدة صغيرٍ كتبته لنفسك أن يكون متينًا. يعتمد عملُ المبرمِج على توصيف specification ما يُفترَض أن يعمل به البرنامج، ويصح عمل المبرمِج إذا توافق البرنامج مع توصيفه، ولكن هل يعني ذلك أن البرنامج نفسه سيكون صحيحًا؟ وماذا لو كان التوصيف غير صحيح أو غير كامل؟ في الواقع، يُعرَّف البرنامج الصحيح على أنه تنفيذ implementation صحيح لتوصيف صحيح وكاملٍ؛ الأمر الذي ينقلنا إلى السؤال عمَّا إذا ما كان التوصيف يعبِّر عن نية مستخدمي البرنامج ورغباتهم تعبيرًا صحيحًا أم لا؛ إلا أن هذا السؤال يقع خارج مجال علوم الحاسوب. قصص مرعبة لقد حظى معظم مستخدمي الحاسوب بتجربةٍ مع تعطل البرامج أثناء تشغيلها أو حتى انهيارها بالكامل، فعادةً ما تسبب تلك المشاكل الضجر للمستخدمين، كما قد تتسبب أيضًا في نتائج أخطر من ذلك بكثيرٍ مثل خسارة عملٍ مهم أو خسارة نقود؛ فببساطة عندما تُسند مهمات جدية للحاسوب، فسيتوقع أن تكون توابع فشلها بنفس جدية تلك المهمات. منذ عشرين عامًا، فشلت بعثتي فضاء إلى المريخ بتكاليف تصل إلى ملايين الدولارات، ورجح أن سبب الفشل في كلتا الحالتين كان نتيجةً لمشاكل برمجية، ومع ذلك لم تكن المشكلة بسبب برنامج مكتوب بطريقة خاطئة، ففي سبتمبر 1999، احترقت مركبة المريخ المناخية المدارية Mars Climate Orbiter في الغلاف الجوي للمريخ، وذلك نتيجةً لإدخال البيانات بوحدة القياس الإنجليزية مثل القدم والرطل إلى برنامج حاسوب صُمم لاستقبال قياسات بوحدات قياس النظام العالمي مثل السنتيمتر والجرام؛ كما تحطمت بعد أشهر قليلة مركبة الهبوط على قطب المريخ Mars Polar Lander، وذلك لأن البرنامج أغلق محركات الهبوط قبل الهبوط الفعلي للمركبة، إذ صُمِّم البرنامج ليغلق المحركات عندما يستشعر أي ارتطام أثناء هبوط المركبة الفضائية، واتضح بعد ذلك أن معدات الهبوط اهتزت بصورة شديدة حتى فُعِّل نظام الارتطام، وعليه أُغلِقت المحركات بينما كانت المركبة ما تزال مرتفعةً عن الأرض، الأمر الذي أدى لسقوطها على سطح المريخ. فإذا كان البرنامج أكثر متانةً، لَفحَص ارتفاعها عن الأرض قبل أن يغلق المحركات. وهناك حكاياتٌ أخرى بنفس المأساوية تسببت فيها برامج لا تعمل بصورة صحيحة، أو رديئة لا تعمل بكفاءةٍ جيدة؛ وفيما يلي بعضًا من الحوادث القليلة المسرودة في كتاب "أخلاقيات الحاسوب Computer Ethics" للكاتبين Tom Forester وPerry Morrison، والذي يُناقِشان فيه قضايا أخلاقية مختلفة تتعلّق بالحوسبة، وسنذكر منها الآتي: تسببت جرعة إشعاع مفرطة في عاميْ 1985 و1986 في قتل شخص وإصابة آخرين أثناء خضعوهم لعلاج إشعاعيٍ نتيجة لبرمجة آلة الإشعاع الحاسوبية بصورة خاطئة؛ كما تَعرّض حوالي 1000 مصاب بالسرطان لجرعات إشعاع أقلّ من الموصوفة لهم بحوالي 30% بسبب خطأ برمجي آخر في عام 1992، أي بعد 6 سنوات من الحالة السابقة تقريبًا. حذَف حاسوب في بنك نيويورك معاملات جارية بسبب خطأ برمجي، الأمر الذي استغرق قرابة 24 ساعة لإصلاح المشكلة، وحينها دفع البنك فائدة تقدر بـحوالي 5,000,000 دولار على المدفوعات التي اقترضها لتغطية المشكلة، وذلك في عام 1985. اكتُشف خطأ خلال محاكاة برمجة نظام التوجيه بالقصور الذاتي المستخدم في مقاتلة F-16، الأمر الذي كان سيتسبب في قلب الطائرة رأسًا على عقب بعد عبورها لخط الاستواء، كما فُقد مكوك الفضاء Mariner 18 بسبب خطأ برمجي في سطر واحد من برنامج تشغيله، وكذلك تجاوزت كبسولة الفضاء Gemini V موقع هبوطها المقرر بمائة ميل، حيث نسي المبرمج أن يأخذ في حسبانه دوران الأرض. في عام 1990، تعطلت خدمة هاتف AT&T في الولايات المتحدة الأمريكية بعد اكتشاف خطأ برمجي في نسختها المحدثة. بالطبع، هناك مشاكلٌ أخرى أحدث من ذلك، فمثلًا ساهم خطأ برمجي في أحد أكبر انقطاعات التيار الكهربي في التاريخ في شمال شرق أمريكا عام 2003، وفي عام 2006 تأخرت طائرة Airbus A380 بسبب مشاكل عدم توافُق البرمجيات، حيث كلَّفتها خسائر تصل إلى بلايين الدولارات، كما أدى خطأ برمجي في عام 2007 إلى تَوقُّف الآلاف من الطائرات في مطار Los Angeles الدولي، كما تسبَّب خطأ في برنامج تداول آلي في انخفاض مؤشِّر داو جونز الصناعي بحوالي 1000 نقطة، وذلك في مايو 2010. هذه بعض الأمثلة القليلة، فمن المعروف أن المشاكل البرمجية تنتشر بكثرة، وعلينا نحن المبرمجين أن نفهَم سبب ذلك وما الذي يمكن أن نفعله حِيال ذلك؟ المنقذ جافا وفقًا لمطوري لغة جافا، يعود سبب المشكلة إلى طريقة تصميم اللغات البرمجية ذاتها، ولهذا صُممت جافا بطريقة توفِّر حمايةً من تلك النوعية من الأخطاء. قد تتساءل عن كيف يمكن لخاصيةٍ في اللغة أن تمنع حدوث مثل تلك الأخطاء؟ ولهذا دعنا نفحَص بعض الأمثلة. لا تتطلب بعض لغات البرمجة تعريف المتغيرات قبل استخدامها، حيث يُنشَئ المتغير تلقائيًا عندما تستخدمه لأول مرة ضِمن برنامج كُتب بإحدى تلك اللغات، وقد ترى أن ذلك مناسبٌ أكثر من تعريف عن كلِّ متغير على حدة، الأمر الذي قد يكون صحيحًا أحيانًا، إلا أنه قد يؤدِّي إلى نتائج مؤسفة، فقد يَتسبَّب خطأ إملائي في إنشاء متغير جديد مثلًا دون أي نية لذلك؛ وفي الواقع، يقال أن خطأ مماثلًا كان هو المسئول عن فقدان سفينة فضاء؛ فلتُكتَب حلقة عدِّ بلغة FORTRAN مثلًا؛ فسيُستخدَم الأمر DO 20 I = 1,5، ولمَّا كانت المسافات غير مهمة بلغة FORTRAN، فستكافئ التعليمَة السابقة الأمر DO20I=1,5، بينما يمثل الأمر DO20I=1.5 (في حال استبدلنا الفاصلة بنقطةٍ) تعليمة إسناد assignment، فتسند القيمة 1.5 إلى متغير اسمه DO20I، يمكنك ملاحظة كيف تسبب استبدالٌ غير مقصود في تعليمة مماثلة إلى انفجار الصاروخ أثناء الاقلاع؛ ونظرًا لأن لغة FORTRAN لا تتطلب تعريفًا للمتغيرات، فسيقبل المحرر تعليمةً مثل DO20I=1.5، وينشِئ متغيرًا جديدًا اسمه DO20I، بينما إذا كانت FORTRAN تتطلب تعريف المتغيِّرات أولًا، فسيُظهر المحرِّر رسالة خطأ، كون المتغير DO20I لم يُعرَّف بَعد. عمومًا، تتطلب غالبية لغات البرمجة حاليًا تعريف المتغيرات قبل استخدامها، وبالرغم من ذلك ما تزال هناك خاصيات أخرى يكثر استخدامها رغم أنها قد تتسبب في حدوث المشكلات؛ وقد ألغت جافا بعضًا من تلك الخاصيات. وبينما يشكو بعض المبرمجين من أن ذلك يقلل من قوة وكفاءة اللغة، إلا أن هذا النقد قد يكون عادلًا إلى حدٍ ما، إذ تستحق زيادة أمن ومتانة اللغة تلك التكلفة في غالبية الأحوال، فأفضل دفاع ضد بعض الأخطاء هو تصميم اللغة بصورةٍ يستحِيل معها حدوث تلك الأخطاء من الأساس. في حالات أخرى، لا يسهل التخلص من الخطأ بصورةٍ كاملة، وعندها تصمَّم لغة البرمجة بطريقةٍ تمكنها من اكتشاف تلك الأخطاء عندما تحدث بصورة تلقائية، وتمنعها من التسبب في حدوث المشاكل البرمجية؛ حيث تنبه المبرمج إلى وجود خطأ برمجي ينبغي تصحيحه؛ ولنفحَص مجموعةً من الحالات التي اتبعها مصمِّمي جافا. تتكون أي مصفوفةٍ من عدد محدَّد من العناصر، بحيث تُرقم من الصفر إلى قيمة عظمى معينة، وبالطبع من الخطأ استخدام عنصر مصفوفة من خارج ذلك النطاق؛ ولهذا تكتشف جافا أي محاولة لفعل ذلك بصورةٍ تلقائيةٍ، بينما تُلقِي بعض لغات البرمجة الأخرى مثل C وC++ مسؤولية التأكد من استخدام العنصر ضمن النطاق المسموح به للمبرمِج. سَنفترِض أن لدينا مصفوفةً A تتكون من ثلاثة عناصر A[0] وA[1] وA[2]، أي أن عناصر مثل A[3] وA[4] تشير إلى مواضع تقع خارج المصفوفة؛ بلغة جافا، ستُكتشف أي محاولةٍ لتخزين بياناتٍ في العنصر A[3] بصورةٍ تلقائية، ولا ينتهي البرنامج إلا إذا التقط catching الخطأ كما ناقشنا في القسم 3.7؛ أما بلغتي C وC++، فسيخزِّن الحاسوب البيانات في موضع في الذاكرة رغم أنه لا يُعَد جزءًا من المصفوفة، ولأن معرفة الغرض من موضعٍ معينٍ في الذاكرة غير ممكنٍ، فلن نتوقَّع النتائج، إلا أنها قد تكون أكثر خطورةً بكثيرٍ من مجرد انتهاء البرنامج (سنناقش لاحقًا في هذا القسم مثال خطأ تجاوز سعة المُخزِّن المؤقَّت buffer overflow). تُعَد المؤشرات pointers في العموم مصدرًا شائعًا للأخطاء البرمجية، ويحمل أي متغيِّر كائني النوع object type في جافا مؤشرًا يشير إما إلى كائن أو قيمة خاصة null، وبهذا يكتشف النظام أي محاولةٍ تستخدم القيمة الخاصة null على أنها مؤشر إلى كائن فعلي، بينما في المقابل، تلقي بعض لغات البرمجة الأخرى مسئولية تجنب أخطاء المؤشر الفارغ null pointer على المبرمج، وفي الواقع نُفذ implement المؤشر الفارغ بحواسيب ماكنتوش Macintosh على أنه مؤشر إلى موضع الذاكرة 0؛ ولسوء الحظ كانت تلك الحواسيب تُخزِّن بعض بيانات النظام المهمة ضمن تلك المواضع، وكان من الممكن لأي برنامج أن يستخدم مؤشرًا فارغًا ليعدّل القيم المُخزَّنة بالقرب من الموضع 0 في الذاكرة، الأمر الذي قد يؤدي إلى انهيار النظام بالكامل، وهي نتيجة أسوأ بكثير من مجرد انهيار برنامجٍ واحدٍ بكل تأكيد. يَحدُث نوع آخر من أخطاء المؤشر عندما يُضبط مؤشر إلى كائن من غير النوع الصحيح أو إلى جزء من الذاكرة لا يَحمل كائنًا صالحًا من الأساس، وهذا النوع من الأخطاء لا يحدث في جافا لأنها لا تسمح للمبرمجين بالتعامل مع المؤشِّرات تعاملًا مباشرًا، بينما في المقابل، تسمح بعض لغات البرمجة الأخرى بضبط مؤشر معين، بحيث يشير إلى أي موضع في الذاكرة؛ وإذا حدث ذلك بطريقةٍ خاطئة، فإنه قد يؤدي إلى نتائج غير متوقعة. تسريب الذاكرة memory leak هو نوع آخر من الأخطاء غير الممكنة في لغة جافا، فعندما لا يوجد أي مؤشِّرٍ آخر إلى كائن معين، فسيحرر جامع المهملات garbage collector ذلك الكائن وتصبح المساحة التي احتلها قابلةً لإعادة الاستخدام مرةً أخرى؛ بينما في لغات أخرى، تقع مسؤولية تحرير الذاكرة غير المُستخدَمة على عاتق المبرمج، وإذا فشل المبرمج في ذلك، فستتراكم الذاكرة غير المستخدمة، بحيث تترك مساحةً أقل للبرامج والبيانات. يُقال إن أغلب برامج نظام التشغيل ويندوز Windows القديمة تعاني كثيرًا من مشكلات تسريب الذاكرة، الأمر الذي يتسبب في نفاذ ذاكرة الحاسوب بعد أيام قليلة من الاستخدام، ولذلك تصبح إعادة تشغيل الحاسوب عمليةً ضروريةً. علاوةً على ذلك، وُجد أن الكثير من البرامج تعاني من أخطاء تجاوز سعة المخزّن المؤقَّت وكثيرًا ما تُذاع أخبار عن تلك الأخطاء، حيث ترتبط كتيرًا بالمشاكل المتعلقة بأمن الشبكة network security، فعندما يَستقبِل حاسوب ما بياناتٍ من حاسوبٍ آخر عبر الشبكة، فستُخزن تلك البيانات في مخزن مؤقت buffer، إذ تستطيع البرامج أن تخصِّص أجزاءً من الذاكرة للمخزنات المؤقتة لكي تحمل البيانات التي يُتوقَّع أن تستقبلها؛ حيث تَحدث أخطاء تجاوز سعة المخزن المؤقت عندما يَستقبل بيانات حجمها أكبر من سعته، وهنا يَطرح السؤال التالي نفسه: ماذا يحدث في تلك الحالة؟ إذا اكتشف هذا البرنامج أو برنامج الاتصال الشبكي ذلك الخطأ، فستفشل عملية نقل البيانات عبر الشبكة، بينما تَقَع المشكلة الحقيقية عندما لا يكتشف البرنامج حدوث ذلك؛ وفي تلك الحالة سيستمر البرنامج في تخزين البيانات في الذاكرة حتى بعد امتلاء المخزن المؤقت، وبالتالي ستُخزَّن البيانات الإضافية في مكانٍ في الذاكرة لم يَكُن مُخصصا ليكون جزءًا من المخزِّن المؤقت؛ وقد يُستخدم ذلك المكان لبعض الأغراض الأخرى، أو قد يحتوي على بيانات مهمة، أو على أجزاء من البرنامج نفسه، وهنا تكمن المشاكل الأمنية الحقيقية. لنفترض أن خطأ تجاوز سعة المخزِّن المؤقّت قد استبدَل بعض البيانات الإضافية المستقبَلة عبر الشبكة بأجزاء من البرنامج نفسه، فعندما يُنفِّذ البرنامج ذلك الجزء من البرنامج المستبدَل، فإنه سينفِّذ البيانات المستقبَلة من حاسوبٍ آخر، وقد تحتوي تلك البيانات على أي شيء قد يتسبب في انهيار الحاسوب أو التحكم به، وإذا عثر مبرمج ضار malicious على خطأ من ذلك النوع في برنامج يعمل عبر الشبكة؛ فسيستغله ليخدع الحواسيب الأخرى لكي تنفَّذ برامجه. أما بالنسبة للبرامج المكتوبة بالكامل بلغة جافا، فإن أخطاء تجاوز سعة المخزِّن المؤقت غير ممكنة؛ وذلك لأن اللغة لا توفِّر أي طريقة لتخزين البيانات في مواضع الذاكرة غير المخصصة لها، ولكي تفعل ذلك، ستحتاج إلى مؤشِّر يشير إلى موضع غير مخصَّص في الذاكرة، أو يشير إلى موضع مصفوفة يقع خارج نطاقها المسموح به؛ وكما أوضحنا سابقًا، لا تسمح جافا بوقوع أي من الأمرين، ومع ذلك ربما ما تزال هناك بعض الأخطاء في تصنيفات جافا القياسية Java standard classes، لأن بعض التوابع methods ضمن تلك التصنيفات تُكتب بلغة سي بدلًا من جافا. يتضح لنا الآن أن تصميم لغة البرمجة قد يساعد على منع الأخطاء أو اكتشافها عند حدوثها. على الرغم من أنه قد يقيِّد بعضًا مما يفعله المبرمِج أو يتطلّب إجراء اختبارات، مثل فحص ما إذا كان المؤشر فارغًا أم لا، وهو ما يستغرق وقتًا أطول للمعالجة، ويرى بعض المبرمجين أن التضحية بالقوة والكفاءة تكلفة كبيرة لزيادة الحماية، وقد يصح ذلك في بعض التطبيقات، إلا أن هناك الكثير من المواقف الأخرى التي تكون فيها الأولوية للحماية والأمن، إذ صُممت لغة جافا لتلك المواقف. مشاكل متبقية بجافا اختار مصممي جافا ألا تُحدَّد الأخطاء المتعلقة بالحسابات العددية بصورةٍ تلقائية؛ فمثلاً بلغة جافا، تُمثِّل أي قيمةٍ من نوع int عددًا ثنائيًا 32 bits يمكِنه أن يحمل ما يصل إلى أكثر بقليل من أربعة بلايين قيمة مختلفة، إذ تتراوح قيم النوع int من -2147483648 إلى 2147483647، فماذا يحدث إذًا عندما تقع نتيجة حسبةٍ معينةٍ خارج ذلك النطاق؟ فمثلًا، ما هو مجموع 2147483647+1؟ أو ما هو حاصل ضرب 2000000000*2؟ في الحالتين، لا تُمثَّل النتيجة الصحيحة حسابيًا مثل قيمة من النوع int، إذ يشار إلى ذلك عادةً باسم تجاوز المتغير العددي integer overflow، وهو ما ينبغي أن يُعامل مثل نوع من الخطأ، ومع ذلك لا تُحدِّد جافا هذا النوع من الأخطاء بصورةٍ تلقائية، إذ تعيد جافا العدد -2147483648 مثلًا، مثل قيمةٍ لحاصل مجموع 2147483647+1، أي أنها تُحوِّل القيم الأكبر من 2147483647 إلى قيم سالبة. انظر إلى مسألة 3N+1، والتي ناقشناها سابقًا في القسم الفرعي 3.2.2، يحسب البرنامج التالي متتاليةً محددةً من الأعداد الصحيحة بدءًا من عددٍ صحيحٍ موجب N: while ( N != 1 ) { if ( N % 2 == 0 ) // If N is even... N = N / 2; else N = 3 * N + 1; System.out.println(N); } إذا كانت قيمة N كبيرةً جدًا، فستجد هنا مشكلة؛ إذ لن تكون قيمة 3N+1 صحيحةٌ رياضيًا نتيجةً لحدوث ما يعرف بتجاوز المتغيِّر العددي، وستظهر المشكلة تحديدًا عندما تزيد قيمة 3N+1 عن 2147483647 أي عندما تزيد قيمة N عن 2147483646/3. ولكي نُصحِّح ذلك الخطأ، لابد أن نفحص تلك الاحتمالية أولًا كالتالي: while ( N != 1 ) { if ( N % 2 == 0 ) // If N is even... N = N / 2; else { if (N > 2147483646/3) { System.out.println("Sorry, but the value of N has become"); System.out.println("too large for your computer!"); break; } N = 3 * N + 1; } System.out.println(N); } لا يمكننا أن نختبر الآتي if (3*N+1 > 2147483647) بصورةٍ مباشرة، فمن المُلاحظ أن المشكلة هنا ليست في وجود خطأ في خوارزمية حساب قيم متتالية الأعداد 3N+1، وإنما تكمن في عدم إمكانية تنفيذ الخوارزمية باستخدام نوع عددي صحيح 32 Bits، وبينما تتجاهل الكثير من البرامج هذا النوع من المشكلات، فقد ثَبتَت مسؤولية تجاوز المتغير العددي عن عدد لا بأس به من مشكلات فشل الحواسيب، ولذلك لابد لأي برنامجٍ متينٍ وضع تلك الاحتمالية في الحسبان؛ إذ عُدَت المشكلة البرمجية Y2K سيئة السمعة في بداية عام 2000 نوعًا من تلك الأخطاء. تعاني الأعداد من النوع double من مشكلاتٍ أكثر، كما تتواجد أيضًا مشكلة تجاوز المتغير العددي والتي تحدث عندما يتعدَّى ناتج حسبة معينة النطاق المسموح به للنوع double، أي 1.7*10^308. وبخلاف النوع int، لا تتحوَّل الأعداد في تلك الحالة إلى قيمٍ سالبةٍ، وإنما تعيد البرامج عندها قيمًا خاصةً ليس لها أيّ معنى عددي مكافئٍ، حيث تُمثِّل القيم الخاصة الآتية: Double.POSITIVE_INFINITY. Double.NEGATIVE_INFINITY. الأعداد من خارج النطاق المسموح به، بحيث يعيد الناتج 20*1e308 القيمة Double.POSITIVE_INFINITY، كما تمثِّل القيمة الخاصة Double.NaN النتائج غير المعرَّفة أو غير الصالحة، حيث تكون نتيجة قسمة صفر على صفر أو حساب الجذر التربيعي لعددٍ سالبٍ مثلًا مساويةً للقيمة Double.Nan، ويُمكِنك استدعاء الدالة Double.isNaN(x) لتَختبِر إذا ما كان عددٌ معينٌ x يحتوي على القيمة الخاصة Double.Nan أم لا. إلى جانب ما سبق، هناك جانب آخر من التعقيد يكمن في أن غالبية الأعداد الحقيقية تمثَّل بصورةٍ تقريبية فقط؛ وذلك لأنها تحتوي على عدد لا نهائي من الأرقام العشرية، حيث تصِل دقة الأرقام العشرية في النوع double إلى 15 رقم، فالعدد الحقيقي 1/3 هو الرقم المكرر …0.3333333333، فلا يمكن تمثيله بدقة متناهية باستخدام عدد محدود من الأرقام، ولذلك فإن الحسابات المتضمنة لأعداد حقيقية ليست دقيقةً تمامًا. في الواقع، يُعَد علم التحليل العددي numerical analysis أحد علوم الحاسوب المخصَّصة لدراسة الخوارزميات التي تتعامل مع الأعداد الحقيقية، إذًا لا تُحدِّد جافا جميع أنواع الأخطاء الممكنة تلقائيًا، وحتى عندما تكتشف الخطأ بصورةٍ تلقائيةِ فسيبلَّغ عن الخطأ ويُغلق النظام بصورةٍ افتراضية، وهو تصرُّف لا يصدر عن برنامج يتمتع بالمتانة الكافية، فما يزال المبرمج بحاجةٍ إلى تعلم التقنيات اللازمة ليتجنب الأخطاء ويتعامل معها، وهو موضوع الأقسام الثلاثة القادمة. ترجمة -بتصرّف- للقسم Section 1: Introduction to Correctness and Robustness من فصل Chapter 8: Correctness, Robustness, Efficiency من كتاب Introduction to Programming Using Java. اقرأ أيضًا المقال السابق: المصفوفات ثنائية البعد Two-dimensional Arrays في جافا كيفية إنشاء عدة خيوط وفهم التزامن في جافا