فن التصحيح (Debugging)
مقدمة
انتهيت من كتابة الكود، شغلته وظهر خطأ — ماذا الآن؟ كثير من المبتدئين يتوقفون عند هذه النقطة، يحدقون في الشاشة بلا حيلة. التصحيح (Debug) هو أحد أهم المهارات الأساسية في البرمجة، بل أهم من كتابة الكود نفسه. لأن كتابة الكود تشغل 30% فقط من وقت التطوير، والـ 70% المتبقية تُقضى في فهم المشكلة وتحديد الأخطاء والتحقق من الإصلاح.
ماذا ستتعلم في هذا المقال؟
بعد إتمام هذا الفصل، ستكتسب:
- عقلية التصحيح: بناء طريقة منهجية لتحديد المشاكل، بدلاً من "التخمين"
- قدرة قراءة الأخطاء: فهم رسائل الخطأ وتحديد المشكلة بسرعة من تتبع الاستدعاءات
- أساليب التصحيح الكلاسيكية: إتقان التقسيم الثنائي، البط المطاطي، إعادة الإنتاج الأدنى وغيرها
- مهارة استخدام الأدوات: التعرف على سيناريوهات استخدام نقاط التوقف، سجلات التنفيذ، وتصحيح الشبكة
- التصحيح بمساعدة الذكاء الاصطناعي: تعلم استخدام الذكاء الاصطناعي لتسريع التصحيح دون الاعتماد عليه
| الفصل | المحتوى | المفهوم الأساسي |
|---|---|---|
| الفصل 1 | قراءة رسائل الخطأ | أنواع الأخطاء، تتبع الاستدعاءات |
| الفصل 2 | أساليب التصحيح الكلاسيكية | التقسيم الثنائي، البط المطاطي، إعادة الإنتاج الأدنى |
| الفصل 3 | صندوق أدوات التصحيح | نقاط التوقف، السجلات، التقاط الشبكة |
| الفصل 4 | التصحيح في عصر الذكاء الاصطناعي | مساعدة الذكاء الاصطناعي + الحكم البشري |
| الفصل 5 | عقلية وعادات التصحيح | البرمجة الدفاعية، سجلات التصحيح |
0. نظرة عامة: التصحيح منهج علمي
التصحيح ليس "حظاً"، بل عملية علمية دقيقة. منهجية الفيزيائيين في التجارب تنطبق تماماً على التصحيح:
- مراقبة الظاهرة: ما المشكلة في البرنامج؟ ما الخطأ الذي ظهر؟
- طرح فرضية: ما السبب المحتمل؟
- تصميم تجربة: كيف نتحقق من هذه الفرضية؟
- التحقق من النتيجة: إذا كانت الفرضية صحيحة فنصلح، وإلا نطرح فرضية أخرى
القاعدة الذهبية للتصحيح
- أعِد الإنتاج أولاً، ثم أصلح: خطأ لا يمكن إعادة إنتاجه بشكل مستقر، لن تعرف إن كنت أصلحته فعلاً
- غيّر متغيراً واحداً فقط في كل مرة: إذا غيّرت عدة أشياء معاً، لن تعرف أي تغيير حل المشكلة
- ثق بالدليل، لا بالحدس: عندما تعتقد "لا يمكن أن تكون المشكلة هنا"، فعادةً تكون هنا بالضبط
- ما الذي تغير مؤخراً؟: 80% من الأخطاء سببها تغييرات حديثة
1. قراءة رسائل الخطأ: الخطأ ليس عدوك، بل دليل
أكثر خطأ يرتكبه المبتدئون: الهلع عند رؤية خطأ وإغلاقه أو تجاهله. في الواقع، رسالة الخطأ هي البرنامج يخبرك أين المشكلة — إنه أفضل صديق لك.
1.1 الأنواع الثلاثة الرئيسية للأخطاء
| النوع | متى يظهر | مثال | الخطورة |
|---|---|---|---|
| خطأ نحوي | يظهر قبل تشغيل الكود | قوس مفقود، كلمة مفتاحية خاطئة | الأسهل إصلاحاً |
| خطأ وقت التشغيل | الكود يتعطل عند سطر معين | الوصول لمتغير غير موجود، القسمة على صفر | صعوبة متوسطة |
| خطأ منطقي | الكود يعمل لكن النتيجة خاطئة | صيغة حسابية خاطئة، شرط معكوس | الأصعب اكتشافاً |
1.2 كيف تقرأ تتبع الخطأ
باستخدام JavaScript كمثال، رسالة خطأ نموذجية:
TypeError: Cannot read properties of undefined (reading 'name')
at getUserName (app.js:15:23)
at handleClick (app.js:42:10)
at HTMLButtonElement.<anonymous> (app.js:58:5)اقرأ من الأعلى للأسفل:
- السطر الأول: نوع الخطأ + وصف الخطأ →
TypeError، محاولة قراءة خاصيةnameمنundefined - السطر الثاني: الدالة وموقع الخطأ → دالة
getUserName، السطر 15 العمود 23 فيapp.js - الأسطر التالية: سلسلة الاستدعاءات → من استدعى هذه الدالة؟
handleClick→ حدث نقر الزر
قاعدة لقراءة تتبع الخطأ
ابحث عن السبب من الأعلى للأسفل، وابحث عن المصدر من الأسفل للأعلى. السطر الأول يخبرك "ما الخطأ"، والسطر الأخير يخبرك "من أين بدأ".
1.3 مرجع سريع للأخطاء الشائعة
| اسم الخطأ | المعنى | الأسباب الشائعة |
|---|---|---|
SyntaxError | خطأ نحوي | أقواس غير متطابقة، فاصلة مفقودة |
TypeError | خطأ نوع | العمل على undefined/null |
ReferenceError | خطأ مرجعي | استخدام متغير غير مُعلن |
RangeError | خطأ نطاق | فهرس خارج الحدود، عودية عميقة جداً |
NetworkError | خطأ شبكة | فشل طلب API، مشاكل CORS |
404 Not Found | المورد غير موجود | URL خاطئ، ملف محذوف |
500 Internal Server Error | خطأ داخلي في الخادم | كود الواجهة الخلفية تعطل |
1.4 مقارنة مع أخطاء Python
تتبع Python يُقرأ بعكس JavaScript — من الأسفل للأعلى:
Traceback (most recent call last):
File "main.py", line 10, in <module>
result = calculate(data)
File "main.py", line 5, in calculate
return data["price"] * data["quantity"]
KeyError: 'quantity'السطر الأخير هو سبب الخطأ: KeyError: 'quantity'، القاموس لا يحتوي على المفتاح quantity.
لغات مختلفة، نفس المنهج
مهما كانت اللغة، رسائل الخطأ تحتوي دائماً على ثلاث معلومات أساسية: ما الخطأ (النوع)، أين (الملف والسطر)، لماذا (الوصف). تعلم استخراج هذه المعلومات الثلاث وستتمكن من قراءة أخطاء أي لغة.
2. أساليب التصحيح الكلاسيكية: حكمة الأجيال السابقة
هذه الأساليب لا تحتاج أي أدوات، فقط عقلك. إنها أساس كل تقنيات التصحيح المتقدمة.
2.1 التصحيح بالتقسيم الثنائي
الفكرة الأساسية: تقليص نطاق المشكلة للنصف، ثم للنصف، حتى الوصول للجذر.
السيناريو: الكود طويل ولا تعرف أي جزء به خطأ.
الخطوات:
- أضف
console.log(أوprint) في منتصف الكود - إذا كان الخطأ قبل المنتصف → المشكلة في النصف العلوي
- إذا كان الخطأ بعد المنتصف → المشكلة في النصف السفلي
- كرر الخطوات أعلاه مع النصف الذي به المشكلة
100 سطر كود به خطأ
↓ أضف log عند السطر 50
المشكلة بين السطرين 50-100
↓ أضف log عند السطر 75
المشكلة بين السطرين 50-75
↓ أضف log عند السطر 62
المشكلة بين السطرين 60-62!قوة التقسيم الثنائي
مع 100 سطر كود، تحتاج 7 تكرارات فقط (log₂100 ≈ 7) لتحديد السطر بدقة. ومع 1000 سطر تحتاج 10 فقط.
2.2 طريقة البط المطاطي
الفكرة الأساسية: اشرح المشكلة سطراً بسطر لشخص آخر (أو بطة مطاطية)، وأثناء الشرح ستكتشف الخطأ بنفسك.
لماذا تنجح؟ لأن "كتابة الكود" و"شرح الكود" يستخدمان مناطق مختلفة من الدماغ. عندما تُجبر على وصف كل خطوة منطقية بالكلمات، ستظهر الافتراضات التي "كنت تعتقد أنها صحيحة".
طريقة التطبيق:
- افتح الكود الذي به المشكلة
- اشرح سطراً بسطر: "ماذا يفعل هذا السطر؟ لماذا يفعله هكذا؟"
- عندما تقول "همم، هنا يجب أن يكون... انتظر"، غالباً يكون الخطأ هناك
2.3 إعادة الإنتاج الأدنى
الفكرة الأساسية: تبسيط المشكلة المعقدة إلى الحد الأدنى، مع الاحتفاظ فقط بالكود اللازم لتشغيل الخطأ.
لماذا هو مهم؟
- في النظم المعقدة، قد يكون الخطأ "مخفياً" بواسطة كود آخر
- إعادة الإنتاج الأدنى تزيل عوامل التشويش وتجعل المشكلة واضحة
- كما تُسهّل طلب المساعدة — لا أحد يريد مراجعة 500 سطر كود
الخطوات:
- أنشئ ملفاً فارغاً جديداً
- انسخ فقط الكود المتعلق بالمشكلة
- قلّص تدريجياً حتى يختفي الخطأ عند حذف أي سطر
- ما تبقى هو جذر الخطأ
2.4 طريقة التراجع (Git Bisect)
الفكرة الأساسية: إذا كان الكود "كان يعمل سابقاً والآن لا يعمل"، ابحث عن commit الذي أدخل المشكلة.
# أداة البحث الثنائي المدمجة في Git
git bisect start
git bisect bad # حدد النسخة الحالية بأن بها خطأ
git bisect good abc123 # حدد نسخة قديمة كانت تعمل
# سيبدّل Git تلقائياً إلى commit في المنتصف، اختبره وأخبره good أو bad
# بعد تكرار بضع مرات ستجد commit الذي أدخل الخطأدليل اختيار طريقة التصحيح
| الحالة | الطريقة الموصى بها |
|---|---|
| لا أعرف أي جزء من الكود به خطأ | التقسيم الثنائي |
| المنطق يبدو صحيحاً لكن النتيجة خاطئة | البط المطاطي |
| خطأ في نظام معقد | إعادة الإنتاج الأدنى |
| "كان يعمل ثم تعطل فجأة" | التراجع / Git Bisect |
3. صندوق أدوات التصحيح: الأدوات المناسبة تضاعف الكفاءة
المنهجية هي الأساس، لكن الأدوات الجيدة تضاعف كفاءة التصحيح.
3.1 console.log / print: الأبسط والأكثر عملية
السيناريو: التحقق السريع من قيم المتغيرات وتأكيد أين وصل تنفيذ الكود.
// JavaScript
console.log('تم استدعاء الدالة، المعاملات هي:', data)
console.log('نتيجة الحساب:', result)
console.table(arrayData) // عرض المصفوفات/الكائنات في جدول# Python
print(f"القيمة الحالية: {value}")
print(f"النوع: {type(data)}") # التحقق من نوع البياناتتقنيات متقدمة:
| الطريقة | الاستخدام |
|---|---|
console.log() | مخرجات عادية |
console.warn() | تحذير أصفر، سهل الإيجاد بين السجلات الكثيرة |
console.error() | خطأ أحمر |
console.table() | عرض المصفوفات والكائنات في جدول |
console.time() / console.timeEnd() | قياس وقت تنفيذ الكود |
console.trace() | طباعة تتبع الاستدعاءات |
3.2 التصحيح بنقاط التوقف: تنفيذ سطراً بسطر
السيناريو: منطق معقد يحتاج تتبع خطوة بخطوة.
في المتصفح (Chrome DevTools):
- افتح أدوات المطور (F12) → لوحة Sources
- ابحث عن ملف المصدر، انقر على رقم السطر لوضع نقطة توقف
- فعّل العملية ذات الصلة، سيتوقف الكود عند نقطة التوقف
- استخدم أزرار التحكم للتنفيذ خطوة بخطوة:
- متابعة (F8): التشغيل لنقطة التوقف التالية
- خطوة فوق (F10): تنفيذ السطر الحالي دون الدخول في الدوال
- خطوة داخل (F11): الدخول داخل الدالة
- خطوة خارج (Shift+F11): الخروج من الدالة الحالية
في VS Code:
- انقر يسار رقم السطر لوضع نقطة توقف (نقطة حمراء)
- اضغط F5 لبدء التصحيح
- راجع القيم الحالية لجميع المتغيرات في لوحة "Variables"
- أضف التعابير التي تهمك في لوحة "Watch"
نقاط التوقف مقابل console.log
console.log مناسب للتحقق السريع، يُحذف بعد الاستخدام. نقاط التوقف مناسبة لتحليل المنطق المعقد بعمق. الاثنان لا يحل محل أحدهما الآخر بل يكمّلانه.
3.3 تصحيح الشبكة: مشاكل بين الواجهة الأمامية والخلفية
السيناريو: الصفحة لا تُعرض بشكل صحيح، لكن لست متأكداً هل المشكلة من الواجهة الأمامية أم من البيانات المُعادة من الخلفية.
Chrome DevTools → لوحة Network:
| ما تراقبه | ما يمكنك اكتشافه |
|---|---|
| رمز الحالة | 404 (عنوان خاطئ)، 500 (خادم معطل)، 403 (بدون صلاحية) |
| معاملات الطلب | هل البيانات المرسلة من الواجهة الأمامية صحيحة |
| بيانات الاستجابة | هل تنسيق البيانات المُعادة من الخلفية صحيح |
| وقت الطلب | أي واجهة بطيئة جداً وتبطئ الصفحة |
| ترويسات الطلب | هل تم إرسال Token؟ هل Content-Type صحيح |
قاعدة ذكرية: راجع رمز الحالة أولاً، ثم معاملات الطلب، وأخيراً بيانات الاستجابة.
3.4 مرجع سريع لأدوات التصحيح
| نوع المشكلة | الأداة الموصى بها |
|---|---|
| قيمة متغير خاطئة | console.log / نقطة توقف |
| ترتيب تنفيذ المنطق خاطئ | نقطة توقف |
| فشل طلب API | لوحة Network |
| أنماط الصفحة خاطئة | لوحة Elements (فحص CSS) |
| مشاكل الأداء | لوحة Performance / console.time |
| تسرب الذاكرة | لوحة Memory |
4. التصحيح في عصر الذكاء الاصطناعي: اجعل الذكاء الاصطناعي مساعداً لك
أدوات الذكاء الاصطناعي (ChatGPT, Claude, Cursor, إلخ) يمكنها تسريع التصحيح بشكل كبير، لكن بشرط أن تعرف كيف تستخدمها.
4.1 فيما يبرع الذكاء الاصطناعي؟
| يبرع الذكاء الاصطناعي في | لا يبرع في |
|---|---|
| شرح معنى رسائل الخطأ | فهم منطق عملك |
| تقديم حلول للمشاكل الشائعة | الحكم على الحل الأنسب لمشروعك |
| توليد أجزاء كود للتصحيح | إعادة إنتاج أخطاء تحدث فقط في بيئات محددة |
| تحليل المشاكل المحتملة في الكود | فهم سياق الأنظمة المعقدة |
4.2 الطريقة الصحيحة لطرح الأسئلة على الذكاء الاصطناعي
سؤال سيء:
"الكود الخاص بي به خطأ، ساعدني في مراجعته"
سؤال جيد:
"أكتب مكون نموذج بلغة React، وعند الإرسال يظهر الخطأ
TypeError: Cannot read properties of undefined (reading 'email'). إليك الكود ذو الصلة: [ألصق الكود]. لقد تأكدت أن تنسيق البيانات المُعادة من API صحيح، المشكلة على الأرجح في معالجة البيانات في الواجهة الأمامية."
قالب للسؤال:
1. ماذا أفعل: [السياق]
2. السلوك المتوقع: [ما يجب أن يحدث]
3. السلوك الفعلي: [ما يحدث فعلاً]
4. رسالة الخطأ: [الخطأ الكامل]
5. الكود ذو الصلة: [ألصق الكود]
6. ما جربته: [ما استبعدته]4.3 فخاخ التصحيح بالذكاء الاصطناعي
ثلاث فخاخ للتصحيح بالذكاء الاصطناعي
- قد "يتحدث بثقة عن أشياء خاطئة": الحل الذي يقدمه قد يبدو معقولاً لكنه خاطئ تماماً. تحقق دائماً بنفسك.
- لا يعرف سياقك: لا يعرف هيكل مشروعك، إصدارات التبعيات، أو بيئة التشغيل. عليك تزويده بسياق كافٍ.
- الاعتماد المفرط يُضعف قدرتك على التصحيح: إذا مررت كل خطأ مباشرة للذكاء الاصطناعي، لن تتعلم التصحيح بنفسك أبداً. ننصح بالتحليل لمدة 5 دقائق قبل طلب المساعدة من الذكاء الاصطناعي.
4.4 المزيج المثالي: الذكاء الاصطناعي + الإنسان
تصادف خطأ
↓
الخطوة 1: اقرأ رسالة الخطأ بنفسك (1 دقيقة)
↓
الخطوة 2: اطرح فرضية (2 دقيقة)
↓
الخطوة 3: تحقق من الفرضية بسرعة (2 دقيقة)
↓
هل علقت؟ → أرسل رسالة الخطأ + الكود + تحليلك للذكاء الاصطناعي
↓
الذكاء الاصطناعي يقترح → تحكم على مدى معقوليته → تحقق5. عقلية وعادات التصحيح: من "إطفاء الحرائق" إلى "منعها"
أفضل تصحيح هو الذي لا تحتاجه. العادات الجيدة تقلل الأخطاء من الجذور.
5.1 البرمجة الدفاعية
الفكرة الأساسية: عند كتابة الكود، افترض أن "كل شيء قد يفشل" واستعد الحماية مسبقاً.
// سيء: افتراض أن data موجود دائماً
const name = data.user.name
// جيد: كتابة دفاعية
const name = data?.user?.name ?? 'مستخدم غير معروف'# سيء: افتراض أن الملف يمكن فتحه دائماً
content = open('config.json').read()
# جيد: كتابة دفاعية
try:
content = open('config.json').read()
except FileNotFoundError:
print("ملف التهيئة غير موجود، استخدام التهيئة الافتراضية")
content = '{}'5.2 كتابة سجلات جيدة
السجلات (logs) هي مفتاح "التصحيح بعد الحدث". في بيئة الإنتاج لا يمكنك وضع نقاط توقف، بل تعتمد فقط على السجلات.
| مستوى السجل | الاستخدام | مثال |
|---|---|---|
| DEBUG | معلومات تفصيلية أثناء التطوير | قيم المتغيرات، معاملات الدوال |
| INFO | التدفق الطبيعي للأعمال | "تسجيل دخول ناجح"، "تم إنشاء طلب" |
| WARN | لا يؤثر على الوظيفة لكن يحتاج انتباهاً | "فشل في الذاكرة المؤقتة"، "إعادة المحاولة الثانية" |
| ERROR | حدث خطأ يحتاج معالجة | "فشل الاتصال بقاعدة البيانات"، "انتهت مهلة API" |
معايير السجل الجيد
السجل الجيد يجب أن يجيب: متى، أين، ماذا حدث، ما البيانات المهمة.
[2025-01-15 14:30:22] [ERROR] [OrderService] فشل إنشاء الطلب
معرف المستخدم: 12345، معرف المنتج: 67890، السبب: نفد المخزون5.3 قائمة فحص التصحيح
عند مواجهة خطأ، اتبع هذا الترتيب:
- اقرأ رسالة الخطأ: نوع الخطأ، الملف، رقم السطر
- ما الذي تغير مؤخراً؟: استخدم
git diffلمراجعة التغييرات الحديثة - هل يمكن إعادة إنتاجه؟: ابحث عن خطوات إعادة إنتاج مستقرة
- قلّص النطاق: استخدم التقسيم الثنائي أو إعادة الإنتاج الأدنى
- اطرح فرضية وتحقق منها: غيّر متغيراً واحداً فقط في كل مرة
- اختبار الانحدار بعد الإصلاح: تأكد أن الإصلاح لم يُدخل مشاكل جديدة
5.4 أخطاء شائعة يقع فيها المبتدئون
| الفخ | التصرف الصحيح |
|---|---|
| البدء بتعديل الكود دون قراءة الخطأ | اقرأ رسالة الخطأ كاملة أولاً |
| تغيير عدة أماكن في وقت واحد | غيّر مكاناً واحداً فقط، تحقق ثم انتقل للتالي |
| عمل commit دون اختبار بعد التعديل | شغّل الاختبارات بعد كل تعديل |
| الاختبار على جهازك فقط | ضع في اعتبارك بيئات مختلفة (متصفحات، أنظمة، شبكات) |
| عدم تنظيف console.log بعد التصحيح | احذف كل كود التصحيح قبل عمل commit |
| إعادة التشغيل/إعادة التثبيت عند حدوث مشاكل | افهم السبب أولاً، إعادة التشغيل حل مؤقت فقط |
6. الخلاصة
التصحيح حرفة تحتاج ممارسة مقصودة. لنراجع النقاط الرئيسية:
- التصحيح منهج علمي: مراقبة → فرضية → تجربة → تحقق، وليس حظاً
- رسائل الخطأ أصدقاؤك: تعلم استخراج "ما الخطأ، أين، لماذا"
- الأساليب الكلاسيكية لا تبلى: التقسيم الثنائي، البط المطاطي، إعادة الإنتاج الأدنى أساس كل تصحيح
- استخدم الأدوات المناسبة لكل موقف: console.log للتحقق السريع، نقاط التوقف للتحليل العميق، Network لفحص الواجهات
- الذكاء الاصطناعي مساعد وليس عكازاً: حلل بنفسك أولاً، اطلب المساعدة ثانياً، وتحقق بنفسك أخيراً
- الوقاية خير من العلاج: البرمجة الدفاعية وعادات السجلات الجيدة تقلل الأخطاء من الجذور
تذكر هذا
كل خطأ هو فرصة للتعلم. كل خطأ تصلحه يبني قدرتك على "التعرف على الأنماط" — في المرة القادمة عندما تواجه مشكلة مشابهة، ستحدد السبب بشكل أسرع.
قراءات إضافية
- توثيق Chrome DevTools الرسمي — دليل شامل لأدوات تصحيح المتصفح
- VS Code Debugging — درس التصحيح بنقاط التوقف في VS Code
- How to Debug Anything — منهجية تصحيح منهجية