كان كودنا قلعة من زجاج: كيف أنقذتنا ‘البرمجة الدفاعية’ من جحيم الانهيارات غير المتوقعة؟

ليلة لا تُنسى: عندما تحولت القلعة إلى زجاج

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

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

بعد ساعات من التوتر والبحث في سجلات الأخطاء (Logs)، اكتشفنا الكارثة. أحد المستخدمين، بطريقة ما، أدخل قيمة غير متوقعة في حقل غير مهم نسبياً. قيمة لم نكن نتوقعها، قيمة “فارغة” (null) تسللت عبر طبقات النظام كالفيروس، وصولاً إلى دالة حساسة لم تكن مستعدة للتعامل معها، مما أدى إلى انهيار تسلسلي شلّ النظام بأكمله. كان الموقف “اشي بيشل” (شيء يثير الجنون).

تلك الليلة كانت درساً قاسياً، لكنها كانت أيضاً نقطة تحول. تعلمنا بالطريقة الصعبة أن كتابة كود “يعمل” في الظروف المثالية لا يكفي. يجب أن نكتب كوداً “يصمد” في أسوأ الظروف. ومن هنا بدأت رحلتنا الحقيقية مع ما يسمى بـ “البرمجة الدفاعية” (Defensive Programming).

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

تخيل أنك تقود سيارتك في شارع مزدحم. هل تفترض أن كل السائقين الآخرين محترفون وسيلتزمون بالقوانين 100%؟ بالطبع لا. السائق الحذِر (الدفاعي) يتوقع الأسوأ: قد يتجاوز أحدهم الإشارة الحمراء، أو يغير مساره فجأة بدون إشارة. لذلك، يترك مسافة أمان، ينظر في المرايا باستمرار، ويكون مستعداً للضغط على المكابح في أي لحظة.

البرمجة الدفاعية هي نفس العقلية، لكن في عالم الكود. إنها فلسفة تقوم على مبدأ “لا تثق بأي شيء”. لا تثق بمدخلات المستخدم، لا تثق بالبيانات القادمة من واجهة برمجية أخرى (API)، لا تثق حتى بأجزاء أخرى من الكود الذي كتبته أنت وفريقك! الهدف هو بناء برمجيات قوية تستطيع التعامل مع الظروف غير المتوقعة بأمان، بدلاً من الانهيار عند أول مشكلة.

البرمجة الدفاعية ليست مجرد مجموعة من التقنيات، بل هي عقلية ومسؤولية تقع على عاتق كل مبرمج يسعى لكتابة كود احترافي وموثوق.

أسلحة أبو عمر في ترسانة البرمجة الدفاعية

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

1. التحقق من المدخلات (Input Validation): لا تثق بأحد!

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

مثال عملي (JavaScript):

لنفترض أن لدينا دالة تقوم بحجز موعد لمستخدم. النسخة “الساذجة” قد تبدو هكذا:

// النسخة الساذجة (قلعة من زجاج)
function bookAppointment(userId, date) {
  // ... منطق حجز الموعد مباشرة باستخدام userId و date
  console.log(`تم حجز موعد للمستخدم ${userId} في تاريخ ${date.toISOString()}`);
}

// استدعاء قد يسبب كارثة
bookAppointment(null, "2023-10-27"); // 😱 ماذا سيحدث؟

هنا، إذا تم تمرير `userId` كـ `null` أو `date` كنص غير صالح، قد تنهار الدالة أو تسجل بيانات فاسدة في قاعدة البيانات. النسخة “الدفاعية” ستكون مختلفة تماماً:

// النسخة الدفاعية (حصن منيع)
function bookAppointmentDefensive(userId, date) {
  // 1. التحقق من وجود ونوعية المدخلات (Pre-conditions)
  if (!userId || typeof userId !== 'string' || userId.trim() === '') {
    throw new Error("معرّف المستخدم غير صالح.");
  }

  // 2. التحقق من أن التاريخ هو كائن تاريخ صالح
  if (!(date instanceof Date) || isNaN(date)) {
    throw new Error("صيغة التاريخ غير صالحة.");
  }
  
  // 3. التحقق من منطق العمل (Business Logic Validation)
  const today = new Date();
  today.setHours(0, 0, 0, 0); // تجاهل الوقت
  if (date < today) {
    throw new Error("لا يمكن حجز موعد في الماضي.");
  }

  // الآن فقط، بعد كل الفحوصات، يمكننا الوثوق بالبيانات
  console.log(`تم حجز موعد للمستخدم ${userId} في تاريخ ${date.toISOString()}`);
  // ... منطق حجز الموعد الفعلي
}

// استدعاء آمن
try {
  bookAppointmentDefensive("user-123", new Date("2024-05-20")); // يعمل بنجاح
  bookAppointmentDefensive(null, new Date()); // سيطلق خطأ يمكن معالجته
} catch (error) {
  console.error("فشل حجز الموعد:", error.message);
}

2. معالجة الأخطاء بذكاء: مش كل مصيبة بدها فضيحة!

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

  • الفشل الصامت (Fail-Silent): تسجيل الخطأ في الخلفية والمتابعة بقيمة افتراضية. مفيد في الحالات غير الحرجة.
  • الفشل الآمن (Fail-Safe): إعادة النظام إلى حالة آمنة. مثلاً، في نظام مالي، إذا فشلت عملية تحويل، يجب إلغاء العملية بالكامل بدلاً من خصم المبلغ من طرف وعدم إضافته للطرف الآخر.
  • إعلام المستخدم: عرض رسالة واضحة ومفيدة للمستخدم تشرح المشكلة وكيف يمكن حلها، بدلاً من عرض رسالة خطأ تقنية غامضة.

مثال عملي (Python): جلب بيانات من API قد يكون غير متاح.

import requests
import json

# النسخة الساذجة
def get_user_profile_naive(user_id):
    response = requests.get(f"https://api.example.com/users/{user_id}")
    return response.json() # إذا فشل الطلب، سينهار البرنامج هنا

# النسخة الدفاعية
def get_user_profile_defensive(user_id):
    try:
        response = requests.get(f"https://api.example.com/users/{user_id}", timeout=5)
        
        # التحقق من أن الطلب نجح (e.g., 200 OK)
        response.raise_for_status() # يطلق خطأ إذا كان كود الحالة 4xx أو 5xx

        return response.json()

    except requests.exceptions.RequestException as e:
        # API غير متاح أو هناك مشكلة في الشبكة
        print(f"خطأ في الشبكة: {e}")
        # يمكننا إرجاع بيانات من الكاش أو قيمة افتراضية
        return {"name": "مستخدم غير معروف", "error": "لا يمكن الوصول للخدمة حالياً"}
    except json.JSONDecodeError:
        # API أرجع بيانات غير صالغة (ليست JSON)
        print("خطأ: استجابة غير صالحة من الخادم")
        return {"name": "مستخدم غير معروف", "error": "خطأ في بيانات الخادم"}

لاحظ كيف أن النسخة الدفاعية لا تنهار، بل تتعامل مع فشل الشبكة أو البيانات الفاسدة، وتقدم بديلاً معقولاً.

3. استخدام التأكيدات (Assertions): الفحص الداخلي للقلعة

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

الفكرة هي: “أنا، كمبرمج، متأكد 100% أن هذه القيمة يجب أن تكون موجبة في هذه المرحلة. إذا لم تكن كذلك، فهناك خطأ فادح في منطق البرنامج يجب إصلاحه فوراً”.

مثال عملي (Python):

def calculate_discount(price, discount_percentage):
    # نتحقق من المدخلات القادمة من الخارج
    if price < 0:
        raise ValueError("السعر لا يمكن أن يكون سالباً")
    
    # ... حسابات داخلية ...
    final_price = price * (1 - discount_percentage)
    
    # تأكيد (Assertion) للتحقق من منطقنا الداخلي
    # من المستحيل منطقياً أن يكون السعر النهائي أعلى من الأصلي
    assert final_price <= price, "خطأ منطقي فادح: السعر بعد الخصم أعلى من الأصلي!"
    
    return final_price

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

4. مبدأ الامتياز الأقل (Principle of Least Privilege)

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

نصيحة من أبو عمر: بدلاً من تمرير كائن `User` الكامل (بما فيه كلمة المرور والبريد الإلكتروني وكل شيء) إلى دالة كل ما تحتاجه هو عرض اسم المستخدم، مرّر لها اسم المستخدم فقط (`user.name`). هذا يقلل من الآثار الجانبية غير المتوقعة ويجعل من الصعب على خطأ في دالة صغيرة أن يفسد بيانات حساسة في مكان آخر.

خلاصة الكلام ونصيحة من القلب

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

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

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

خلي كودك حصن منيع، مش قلعة من قزاز. وسلامتكم! 💪

أبو عمر

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

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

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

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

آخر المدونات

أتمتة العمليات

كانت بيئاتنا غير متطابقة: كيف أنقذنا “الكود كبنية تحتية” (IaC) من جحيم “لكنه يعمل على جهازي”؟

أتذكر تلك الليلة جيدًا، ليلة كادت أن تودي بمشروعنا إلى الهاوية بسبب جملة واحدة: "بس شغّال عندي!". في هذه المقالة، سأشارككم يا جماعة كيف انتقلنا...

18 مايو، 2026 قراءة المزيد
​معمارية البرمجيات

المعمارية الموجهة بالأحداث (EDA): طوق النجاة الذي أنقذنا من جحيم الخدمات المتشابكة

كانت خدماتنا متشابكة كخيوط العنكبوت، أي تغيير صغير كان يهدد بانهيار النظام بأكمله. في هذه المقالة، أروي لكم كـ "أبو عمر" كيف أنقذتنا المعمارية الموجهة...

18 مايو، 2026 قراءة المزيد
تجربة المستخدم والابداع البصري

كان تطبيقنا حصناً منيعاً: كيف أنقذتنا ‘الوصولية الرقمية’ (a11y) من جحيم استبعاد المستخدمين؟

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

18 مايو، 2026 قراءة المزيد
برمجة وقواعد بيانات

كانت صفحاتنا تُحمّل ببطء قاتل: كيف أنقذنا ‘التحميل المسبق’ (Eager Loading) من جحيم استعلامات N+1؟

أشارككم قصة حقيقية من قلب المعركة البرمجية، كيف اكتشفنا عدوًا خفيًا يسمى "N+1 Query" كان يلتهم أداء تطبيقنا، وكيف كان "التحميل المسبق" (Eager Loading) هو...

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

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

أشارككم قصة حقيقية من واقع تجربتي كمبرمج، حيث كانت فواتير الخوادم تستنزف ميزانيتنا. اكتشفوا معنا كيف كانت بنية "الحوسبة بدون خوادم" أو Serverless طوق النجاة...

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