كان كودنا يثق بالمدخلات ثقة عمياء: كيف أنقذتنا ‘البرمجة الدفاعية’ من جحيم الأخطاء؟

يا جماعة الخير، السلام عليكم ورحمة الله. اسمحولي أحكيلكم قصة صارت معي ومع فريقي قبل كم سنة، قصة علّمتنا درس ما بننساه للموت.

كنا شغالين على نظام إدارة محتوى (CMS) لعميل مهم جداً، وكان باقي على موعد الإطلاق أقل من أسبوع. سهرانين ليل نهار، والقهوة صارت صديقتنا الصدوقة، والعيون حمرا من كثر التحديق في الشاشات. في ليلة من الليالي، واحنا بنعمل آخر الاختبارات، فجأة… النظام كله “ضرب”. الشاشة البيضاء المشؤومة، ورسائل خطأ غريبة بتطلع من كل مكان. يا ساتر!

صار كل واحد فينا يضرب أخماس بأسداس. “شو اللي صار؟”، “الكود كان شغال قبل شوي!”، “يمكن من السيرفر؟”. قضينا ساعات طويلة، وساعات مرعبة بمعنى الكلمة، واحنا بننبش في الكود سطر سطر. العميل على التلفون كل نص ساعة، والضغط النفسي وصل مراحل ما يعلم فيها إلا ربنا.

بعد بحث مضنٍ، اكتشفنا المصيبة. المشكلة كانت في دالة بسيطة جداً، دالة مسؤولة عن عرض اسم المستخدم في لوحة التحكم. أحد المختبرين، يمكن بمزح أو عن طريق الخطأ، أدخل في حقل “الاسم الأول” رمز تعبيري (emoji) 👩‍💻 مع شوية رموز غريبة. الكود تبعنا، بكل سذاجة وبراءة، أخذ هذا المدخل “زي ما هو” وحاول يمرره لدالة ثانية بتتعامل مع النصوص بطريقة معينة، وهاي الدالة ما كانت مستعدة لهيك نوع من المدخلات… فانهارت. وبما أنه هذا الاسم كان لازم ينعرض في كل مكان، انهار النظام كله وراها.

وقتها، وقفت صافن وحكيت جملة للفريق بعدها صارت شعارنا: “يا جماعة، كودنا أهبل! بيصدق كل شي بينعطى إله. لازم نعلّمه يشك ويدافع عن حاله”. ومن هنا، بدأت رحلتنا الحقيقية مع ما يسمى بـ “البرمجة الدفاعية”.

ما هي البرمجة الدفاعية (Defensive Programming)؟

ببساطة يا خال، البرمجة الدفاعية هي عقلية وأسلوب في كتابة الكود. هي أنك تبرمج وأنت حاطط في بالك أسوأ الاحتمالات. زي سواق السيارة المحترف، هو ما بيفترض إنه كل اللي حواليه سواقين محترفين زيه، بالعكس، هو بيتوقع إنه ممكن أي حدا يكسر عليه، أو يضرب بريك فجأة، أو ما يعطي إشارة. هو دايماً مستعد للخطأ من الآخرين.

في البرمجة، “الآخرون” هم: المستخدمين، واجهات برمجة التطبيقات (APIs) الخارجية، قواعد البيانات، أي مصدر بيانات خارج عن سيطرة الكود تبعك المباشرة. البرمجة الدفاعية تعني أنك تبني “حصوناً” و”دفاعات” داخل الكود تبعك لحمايته من هذه المدخلات غير المتوقعة أو الخبيثة.

فكر فيها كأنك بتبني قلعة. ما بتكتفي ببناء جدران قوية وبس، لأ، بتحفر خندق، وبتحط أبراج مراقبة، وحراس على البوابات. الحراس هدول هم الكود الدفاعي تبعك، اللي بفحصوا كل حدا بحاول يدخل القلعة.

ليش البرمجة الدفاعية مهمة لهالدرجة؟

ممكن حدا يحكي: “طيب يا أبو عمر، ليش هالوجع الراس كله؟ ما أنا بكتب كود شغال وزي الفل”. والجواب بسيط: الكود اللي “شغال” في الظروف المثالية هو قنبلة موقوتة في العالم الحقيقي. أهمية البرمجة الدفاعية بتتلخص في نقاط جوهرية:

  • تقليل الأخطاء (Bugs): معظم الأخطاء الكارثية تأتي من حالات لم يتوقعها المبرمج. البرمجة الدفاعية تجبرك على التفكير في هذه الحالات ومعالجتها مسبقاً.
  • زيادة صلابة النظام (Robustness): بدلاً من أن ينهار تطبيقك بالكامل عند حدوث خطأ غير متوقع، يمكنه التعامل مع الخطأ برشاقة، ربما بعرض رسالة لطيفة للمستخدم وتسجيل الخطأ للمطورين، ويكمل شغله.
  • تحسين الأمان (Security): كثير من الثغرات الأمنية المشهورة مثل حقن SQL (SQL Injection) أو Cross-Site Scripting (XSS) هي نتيجة مباشرة للثقة العمياء في مدخلات المستخدم. التحقق من المدخلات هو خط الدفاع الأول ضد هذه الهجمات.
  • توفير الوقت والجهد على المدى الطويل: قضاء ساعة إضافية في كتابة كود دفاعي اليوم، يوفر عليك أياماً من تصحيح الأخطاء في منتصف الليل وضغط العملاء في المستقبل. صدقني، وقت المبرمج أغلى من الذهب.

مبادئ أساسية في البرمجة الدفاعية (مع أمثلة)

طيب، كيف نطبق هالحكي على أرض الواقع؟ الموضوع مش تعقيد، هو مجموعة مبادئ وعادات بتتبناها وأنت بتكتب الكود.

1. لا تثق بأي مدخلات خارجية أبداً (The Golden Rule)

هذه هي القاعدة الذهبية. أي شيء يأتي من خارج نطاق دالتك الحالية هو “مشتبه به” حتى يثبت العكس. هذا يشمل:

  • مدخلات المستخدم من النماذج (Forms).
  • البيانات القادمة من استدعاءات API.
  • البيانات التي تقرأها من قاعدة البيانات (نعم، حتى قاعدة البيانات!).
  • البيانات من ملفات أو أي مصدر خارجي.

مثال: دالة حساب الخصم

لنفترض أن لدينا دالة بسيطة تحسب السعر بعد الخصم.

الكود الساذج (يثق بالمدخلات):

// JavaScript
function calculateDiscount(price, discountPercentage) {
  // ماذا لو كانت discountPercentage نصاً أو قيمة سالبة؟
  const discountAmount = price * (discountPercentage / 100);
  return price - discountAmount;
}

// calculateDiscount(100, "خمسين"); // -> NaN (Not a Number) - مشكلة!
// calculateDiscount(100, 150); // -> -50 - مشكلة أكبر!

الكود الدفاعي:

// JavaScript
function calculateDiscount(price, discountPercentage) {
  // 1. التحقق من الأنواع
  if (typeof price !== 'number' || typeof discountPercentage !== 'number') {
    throw new Error("المدخلات يجب أن تكون أرقاماً.");
  }
  // 2. التحقق من النطاق المنطقي
  if (price <= 0 || discountPercentage  100) {
    throw new Error("المدخلات خارج النطاق المنطقي.");
  }

  const discountAmount = price * (discountPercentage / 100);
  return price - discountAmount;
}

try {
    const finalPrice = calculateDiscount(100, 150);
    console.log(finalPrice);
} catch (error) {
    console.error("حدث خطأ: " + error.message); // تعامل مع الخطأ برشاقة
}

لاحظ كيف أصبح الكود الآن صلباً ومستعداً للتعامل مع المدخلات الخاطئة بدلاً من إرجاع نتائج كارثية بصمت.

2. تحقق من كل شيء وفشل مبكراً (Validate Everything & Fail Fast)

مبدأ “الفشل المبكر” يعني أنه من الأفضل أن يتوقف الكود وينهار فور اكتشاف مشكلة، بدلاً من أن يكمل عمله ببيانات فاسدة قد تسبب مشاكل أكبر وأكثر غموضاً في مكان آخر من النظام. هذا يجعل تتبع الأخطاء أسهل بكثير.

مثال: عرض بيانات المستخدم

الكود غير الدفاعي:

# Python
def display_user_greeting(user):
  # ماذا لو كان الـ user هو None؟ سيحدث انهيار هنا
  print(f"مرحباً, {user['name']}!") 

# display_user_greeting(None) # -> TypeError: 'NoneType' is not subscriptable

الكود الدفاعي (Fail Fast):

# Python
def display_user_greeting(user):
  # افشل فوراً إذا كان الشرط الأساسي غير متحقق
  if not user or 'name' not in user:
    print("لا يمكن عرض الترحيب: بيانات المستخدم غير مكتملة.")
    return # أو ارمِ استثناءً (raise an exception)

  print(f"مرحباً, {user['name']}!")

display_user_greeting(None) # يطبع رسالة واضحة ولا ينهار
display_user_greeting({'email': 'test@test.com'}) # يطبع رسالة واضحة ولا ينهار

3. تعامل مع الأخطاء بذكاء (Graceful Error Handling)

البرمجة الدفاعية لا تعني فقط رمي الأخطاء (throwing errors)، بل أيضاً التقاطها والتعامل معها بطريقة ذكية. أسوأ شيء يمكن أن تفعله هو “ابتلاع” الخطأ وكأنه لم يحدث.

تجنب تماماً هذا الكود الكارثي، اللي بنسميه “حط الوسخ تحت السجادة”:

// JavaScript
try {
  // ... كود قد يسبب خطأ ...
} catch (error) {
  // لا تفعل شيئاً! هذه جريمة برمجية.
}

بدلاً من ذلك، عند التقاط خطأ:

  1. سجّل الخطأ (Log the error): سجله في ملف أو خدمة تتبع أخطاء. هذا لك أنت كمطور لتصحيحه لاحقاً.
  2. أبلغ المستخدم (Inform the user): اعرض رسالة واضحة وسهلة الفهم للمستخدم (وليس رسالة الخطأ التقنية!).
  3. استعد الحالة (Recover if possible): هل يمكنك إعادة المحاولة؟ هل يمكنك استخدام قيمة افتراضية؟

نصائح من مطبخ أبو عمر البرمجي

عبر السنين، ومع كثرة الوقعات اللي وقعناها، تجمعت عندي شوية نصائح عملية بحب أشاركها معكم:

  • قاعدة “الثلاثي المشبوه”: دائماً، ودائماً، ودائماً كن متشككاً من ثلاثة أشياء: مدخلات المستخدم، استجابات الـ API، والبيانات من قاعدة البيانات. لا تفترض أبداً أنها ستكون بالشكل أو النوع الذي تتوقعه.
  • استخدم التأكيدات (Assertions): في لغات كثيرة، يوجد مفهوم الـ `assert`. هذا الأمر يشبه حارساً داخلياً يتأكد من صحة الافتراضات داخل الكود الخاص بك أثناء مرحلة التطوير. إذا كان الشرط خطأ، ينهار البرنامج فوراً. هذا ممتاز لاكتشاف الأخطاء المنطقية مبكراً.
  • “الكود اللي ما بتفهمه، ما بتأمنله”: عند استخدام مكتبة برمجية خارجية، اقرأ توثيقها جيداً، خاصة الجزء المتعلق بمعالجة الأخطاء. لا تنسخ وتلصق حلولاً من الإنترنت بدون فهم كامل لما تفعله.
  • اجعل القيم الافتراضية صديقك: عند تعريف الدوال أو التعامل مع الإعدادات، فإن توفير قيم افتراضية منطقية يمكن أن يمنع عدداً كبيراً من الأخطاء المتعلقة بالقيم الفارغة (`null` أو `undefined`).

الخلاصة: برمج كأن الجميع يحاول كسر كودك 🛡️

في النهاية، البرمجة الدفاعية ليست تشاؤماً أو وسوسة، بل هي علامة على الاحترافية والنضج البرمجي. هي التحول من عقلية “يا رب الكود يشتغل” إلى عقلية “أنا أعرف أن كودي سيصمد”. إنها الممارسة التي تميز بين من يكتب سطوراً برمجية، وبين من يبني أنظمة قوية وموثوقة.

لذلك في المرة القادمة التي تكتب فيها دالة، اسأل نفسك: “ما هي أغبى وأسوأ طريقة يمكن أن يستخدم بها أحدهم هذه الدالة؟”. ثم اكتب كودك ليصمد أمام هذه الطريقة. وقتها فقط، يمكنك أن تنام قرير العين، وأنت تعلم أن “قلعتك” البرمجية محمية جيداً.

بالتوفيق يا أبطال البرمجة! 💪

أبو عمر

سجل دخولك لعمل نقاش تفاعلي

كافة المحادثات خاصة ولا يتم عرضها على الموقع نهائياً

آراء من النقاشات

لا توجد آراء منشورة بعد. كن أول من يشارك رأيه!

آخر المدونات

تجربة المستخدم والابداع البصري

من الشاشات البيضاء إلى الحوار: فن تصميم حالات الواجهة (Loading, Empty, Error)

في هذا المقال، يأخذكم أبو عمر في رحلة من تجربته كمطور فلسطيني، ليكشف أسرار تصميم حالات الواجهة (التحميل، الفراغ، والخطأ). تعلم كيف تحول الشاشات الصامتة...

21 مايو، 2026 قراءة المزيد
الحوسبة السحابية

كنا ندفع ثمن الخوادم الخاملة: كيف أنقذتنا ‘الحوسبة بلا خوادم’ (Serverless) من جحيم التكاليف المهدرة؟

في هذه المقالة، أشارككم قصة حقيقية من تجربتي كمطور برمجيات عن كيفية انتقالنا من الخوادم التقليدية باهظة الثمن إلى معمارية الحوسبة بلا خوادم (Serverless). سنغوص...

21 مايو، 2026 قراءة المزيد
التوسع والأداء العالي والأحمال

كانت طلباتنا تتعثر في أوقات الذروة: كيف أنقذتنا ‘طوابير الرسائل’ (Message Queues) من جحيم الاختناقات؟

أشارككم قصة حقيقية من قلب المعركة البرمجية، كيف كاد تطبيقنا أن ينهار تحت ضغط المستخدمين في يوم إطلاق مهم، وكيف كانت "طوابير الرسائل" (Message Queues)...

21 مايو، 2026 قراءة المزيد
التكنلوجيا المالية Fintech

كانت بياناتنا المالية سجينة البنوك: كيف حررتها واجهات ‘الصيرفة المفتوحة’ (Open Banking)؟

من واقع تجربتي كمبرمج، كانت بياناتنا المالية حبيسة جدران البنوك الرقمية. في هذه المقالة، أسرد لكم كيف حولت واجهات برمجة التطبيقات للصيرفة المفتوحة (Open Banking)...

21 مايو، 2026 قراءة المزيد
البنية التحتية وإدارة السيرفرات

كانت سجلاتنا متناثرة وضائعة: كيف أنقذنا التجميع المركزي (ELK/Loki) من جحيم تتبع الأخطاء؟

أشارككم قصة حقيقية من قلب المعركة البرمجية، كيف انتقلنا من فوضى السجلات المتناثرة على عشرات الخوادم إلى نظام مركزي أنقذنا من جحيم تتبع الأخطاء. مقالة...

21 مايو، 2026 قراءة المزيد
ادارة الفرق والتنمية البشرية

كانت ساحة لتبادل الاتهامات: كيف أنقذتنا ‘ثقافة ما بعد الحوادث عديمة اللوم’ من جحيم الخوف؟

من واقع تجربتي كمبرمج، تحولت اجتماعات مراجعة الحوادث التقنية من جلسات لوم واتهامات إلى بيئة آمنة للتعلم والنمو. في هذه المقالة، أشارككم كيف يمكن لـ...

21 مايو، 2026 قراءة المزيد
البودكاست