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

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

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

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

في صباح اليوم التالي، بعد ليلة بيضاء وعيون حمراء، جمعت الفريق وقلت لهم جملة لن أنساها: “يا جماعة، الكود تاعنا زي الطفل الصغير، بصدّق كل إشي بنحكيله. لازم نعلّمه يحكي ‘لأ’، لازم نخليه ‘ابن بلد’ وقد حاله، ما يثق بأي حدا غريب”. كان ذلك اليوم هو درسنا الأول الحقيقي في “البرمجة الدفاعية” (Defensive Programming).

ما هي البرمجة الدفاعية؟ تخيلها كقلعة محصنة

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

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

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

لماذا نقع في فخ “الكود المتفائل” أصلاً؟

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

  • ضغط الوقت والمواعيد النهائية: عندما تكون في سباق مع الزمن، فإن أسهل طريق هو كتابة “الكود السعيد” (Happy Path Code) الذي يفترض أن كل شيء سيسير على ما يرام.
  • قلة الخبرة: المبرمجون المبتدئون يركزون عادةً على جعل الكود يعمل في الحالة المثالية، وقد لا يفكرون في كل السيناريوهات الشاذة المحتملة.
  • الثقة المفرطة في الطبقات الأخرى: من السهل أن نقول “فريق الواجهة الأمامية سيهتم بالتحقق من المدخلات” أو “الخدمة الأخرى مضمونة ولن ترسل بيانات خاطئة”. هذه الثقة هي نقطة ضعف قاتلة.
  • التركيز على الميزات الجديدة: غالباً ما يتم إعطاء الأولوية لإضافة ميزات جديدة على حساب تحصين الميزات الحالية.

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

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

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

1. لا تثق بأي أحد (Trust No One)

هذا هو المبدأ الذهبي. لا تفترض أبداً أن البيانات التي تتلقاها صحيحة أو آمنة، حتى لو كانت قادمة من جزء آخر من نظامك أنت. تحقق من:

  • مدخلات المستخدم: المصدر الأكثر شيوعاً للمشاكل.
  • ردود واجهات برمجة التطبيقات (APIs): الخدمات الخارجية يمكن أن تتغير، أو تتعطل، أو ترسل بيانات غير متوقعة.
  • البيانات من قاعدة البيانات: قد يكون قد تم إدخال بيانات تالفة في الماضي أو عن طريق عملية أخرى.
  • ملفات الإعدادات (Config files): قد يقوم شخص ما بتعديلها بشكل خاطئ.

2. تحقق من كل شيء (Validate Everything)

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

النسخة الساذجة (المتفائلة):

function calculateTotalNaive(price, quantity) {
  // ماذا لو كان السعر نصاً؟ أو الكمية سالبة؟
  return price * quantity;
}

// سيناريوهات كارثية
calculateTotalNaive("مئة", 2);   // NaN (Not a Number)
calculateTotalNaive(50, -1);    // -50 (منطقياً غير صحيح)
calculateTotalNaive(50, null);  // 0 (قد لا يكون هذا هو السلوك المتوقع)

النسخة الدفاعية:

function calculateTotalDefensive(price, quantity) {
  // التحقق من نوع وصحة السعر
  if (typeof price !== 'number' || price <= 0 || !Number.isFinite(price)) {
    throw new Error('السعر غير صالح. يجب أن يكون رقماً موجباً.');
  }

  // التحقق من نوع وصحة الكمية
  if (!Number.isInteger(quantity) || quantity < 0) {
    throw new Error('الكمية غير صالحة. يجب أن تكون عدداً صحيحاً غير سالب.');
  }

  return price * quantity;
}

// الآن، الدالة محصنة
try {
  calculateTotalDefensive("مئة", 2);
} catch (e) {
  console.error(e.message); // "السعر غير صالح. يجب أن يكون رقماً موجباً."
}

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

3. افشل بأمان ورشاقة (Fail Gracefully)

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

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

4. حافظ على بساطة الكود (Keep It Simple)

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

نصائح من مطبخ أبو عمر 🛠️

عبر سنوات من العمل في هذا المجال، تعلمت بعض الحيل والأساليب التي أصبحت جزءاً لا يتجزأ من عملي اليومي. إليكم بعضها:

  • “اكتب الكود وكأن المبرمج اللي هيجي بعدك شخص عنيف وعصبي ويعرف وين بتسكن”: هذه المقولة الساخرة تحمل حقيقة عميقة. اكتب كوداً واضحاً ومحصناً ليس فقط من أجلك، بل من أجل أي شخص سيضطر للتعامل مع هذا الكود في المستقبل (وقد يكون هذا الشخص هو أنت بعد ستة أشهر!).
  • لا تعيد اختراع العجلة للتحقق من الصحة: هناك مكتبات رائعة ومختبرة بشكل مكثف للتحقق من صحة البيانات. بدلاً من كتابة شروط `if` لا نهاية لها، استخدم مكتبات مثل Zod أو Joi في عالم JavaScript/TypeScript، أو Pydantic في عالم Python. هذه الأدوات تجعل عملية التحقق أسهل وأكثر قوة.
  • استخدم التأكيدات (Assertions) أثناء التطوير: التأكيدات هي أدوات للتحقق من الافتراضات التي تضعها داخل الكود الخاص بك والتي “يجب” أن تكون صحيحة دائماً. على سبيل المثال، إذا كانت دالة تتوقع أن تتلقى كائناً غير فارغ، يمكنك وضع تأكيد في بدايتها.
    // مثال بسيط في Python
    def process_user(user):
        assert user is not None, "User object cannot be None"
        # ... باقي الكود
        

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

  • الاختبارات الآلية هي شبكة الأمان الخاصة بك: الاختبارات الوحدوية (Unit Tests) واختبارات التكامل (Integration Tests) ليست رفاهية. إنها جزء أساسي من البرمجة الدفاعية. اكتب اختبارات لا تغطي “المسار السعيد” فحسب، بل تغطي أيضاً كل الحالات الشاذة التي يمكنك التفكير فيها: مدخلات فارغة، أنواع بيانات خاطئة، قيم سالبة، نصوص طويلة جداً، إلخ.

الخلاصة: حصّن كودك، ونَم قرير العين 💪

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

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

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

أبو عمر

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

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

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

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

آخر المدونات

اختبارات الاداء والجودة

كانت تغطية اختباراتنا 100% لكنها كذبة: كيف أنقذنا “الاختبار الطفري” من جحيم الثقة الزائفة؟

كنا نظن أن تغطية اختبارات بنسبة 100% هي درعنا الواقي، لكنها كانت ثقة زائفة. أشارككم قصة كيف كشف "الاختبار الطفري" (Mutation Testing) ضعف اختباراتنا وأنقذ...

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

كانت بيئة التطوير لدينا كلاً في وادٍ: كيف أنقذتنا ‘حاويات التطوير’ (Dev Containers) من جحيم ‘إنها تعمل على جهازي’؟

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

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

كانت نماذج بياناتنا في حرب أهلية: كيف أنقذ نمط CQRS نظامنا من جحيم تضارب القراءة والكتابة؟

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

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

كانت قوائمنا تربك المستخدمين: كيف أنقذنا ‘قانون هيك’ (Hick’s Law) من جحيم شلل الاختيار؟

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

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

كانت تقاريرنا تتجمد: كيف أنقذتنا ‘المشاهد المادية’ (Materialized Views) من جحيم الاستعلامات التحليلية؟

هل تعاني من تقارير ولوحات معلومات بطيئة تتجمد عند كل تحديث؟ في هذه المقالة، أسرد لكم قصة حقيقية من تجربتي كمبرمج وكيف كانت "المشاهد المادية"...

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