شفرتنا كانت غابة من جمل if-else: كيف أنقذتنا ‘جداول البحث’ (Lookup Tables) من جحيم المنطق المتشعب؟

يا جماعة الخير، السلام عليكم ورحمة الله.

اسمحولي اليوم أحكيلكم قصة صارت معي قبل كم سنة، قصة بتوجّع القلب وبتعلّم بنفس الوقت. كنا شغالين على نظام إدارة محتوى كبير، نظام فيه صلاحيات مستخدمين معقدة شوي: فيه المدير (Admin)، والمحرر (Editor)، والكاتب (Author)، والمراجع (Reviewer)، والزائر (Visitor)… والقائمة تطول. في بداية المشروع، الأمور كانت بسيطة، “إذا كان المستخدم مدير، أعطه كل الصلاحيات، وإلا…”، وهكذا.

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

في يوم من الأيام، كنت قاعد مع فنجان القهوة الصباحي، وبحاول أضيف صلاحية جديدة للمراجع، ولقيت حالي ضايع بين عشرات الـ if المتداخلة. وقتها قلت لحالي: “يا أبو عمر، لهون وبس! لازم نلاقي حل جذري. الشغلانة هاي مش لازم تكون هيك”. ومن هنا بدأت رحلة البحث عن الخلاص، وكان الخلاص على يد بطل بسيط اسمه “جدول البحث” أو الـ Lookup Table.

الكارثة: ما هي مشكلة غابة الـ if-else؟

خلونا نكون صريحين، كلنا بنستخدم جمل if-else أو switch، وهي جزء أساسي من أي لغة برمجة. لكن المشكلة تبدأ عندما تتحول من أداة مفيدة إلى وحش يلتهم مقروئية الكود وسهولة صيانته.

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


function getPermissions(role) {
  if (role === 'admin') {
    return ['create', 'read', 'update', 'delete', 'publish', 'manage_users'];
  } else if (role === 'editor') {
    return ['create', 'read', 'update', 'publish'];
  } else if (role === 'author') {
    return ['create', 'read', 'update'];
  } else if (role === 'reviewer') {
    return ['read', 'approve_content'];
  } else if (role === 'visitor') {
    return ['read'];
  } else {
    // الحالة الافتراضية
    return [];
  }
}

للوهلة الأولى، قد يبدو الكود منطقياً. لكن فكروا معي في هذه النقاط:

  • صعوبة القراءة: كلما زادت الأدوار، زاد طول الدالة وأصبحت قراءتها وفهمها مهمة شاقة.
  • صعوبة الصيانة: ماذا لو أردنا إضافة دور جديد مثل “مساعد محرر” (sub-editor)؟ ستحتاج إلى تعديل الكود نفسه، إضافة else if جديدة، وإعادة اختبار كل شيء. هذا يتعارض مع مبدأ (Open/Closed Principle) الذي يقول أن الكود يجب أن يكون مفتوحًا للإضافة، مغلقًا للتعديل.
  • عرضة للأخطاء: مع كل تعديل في منطق الدالة، هناك فرصة لارتكاب خطأ قد يؤثر على جميع الأدوار الأخرى.
  • تكرار المنطق: قد تجد نفسك تكرر نفس المنطق في أماكن مختلفة من النظام للتعامل مع هذه الأدوار.

المنقذ: جداول البحث (Lookup Tables)

هنا يأتي دور البطل. جدول البحث هو ببساطة هيكل بيانات (مثل كائن/Object أو خريطة/Map أو حتى مصفوفة/Array) يفصل “البيانات” عن “المنطق”. بدلاً من كتابة منطق معقد لتحديد نتيجة بناءً-على مُدخل، نقوم بتخزين كل المدخلات والنتائج المحتملة في جدول، ثم نستخدم المُدخل كمفتاح للبحث عن النتيجة مباشرة.

الشغلة مش سحر، هي مجرد تنظيم. دعونا نعيد كتابة الدالة السابقة باستخدام جدول بحث.

مثال بعد الإنقاذ: الكود النظيف

سنقوم بإنشاء كائن (Object) بسيط يمثل جدول البحث الخاص بنا، حيث يكون “اسم الدور” هو المفتاح (key)، و”مصفوفة الصلاحيات” هي القيمة (value).


const permissionsByRole = {
  admin: ['create', 'read', 'update', 'delete', 'publish', 'manage_users'],
  editor: ['create', 'read', 'update', 'publish'],
  author: ['create', 'read', 'update'],
  reviewer: ['read', 'approve_content'],
  visitor: ['read'],
};

function getPermissions(role) {
  // ابحث عن الدور في الجدول، وإذا لم تجده، أرجع مصفوفة فارغة
  return permissionsByRole[role] || [];
}

شايفين الفرق؟ يا إلهي على الراحة النفسية! انظروا ماذا كسبنا:

  1. مقروئية عالية: الآن، الصلاحيات أصبحت “بيانات” واضحة ومرتبة. يمكنك أن ترى جميع الأدوار وصلاحياتها في مكان واحد وبنظرة واحدة.
  2. صيانة سهلة جدًا: هل تريد إضافة دور “مساعد محرر”؟ ببساطة أضف سطراً جديداً إلى كائن permissionsByRole. أنت لا تلمس منطق الدالة على الإطلاق!
    
    const permissionsByRole = {
      // ... الأدوار السابقة
      'sub-editor': ['read', 'update_drafts'],
    };
        
  3. قابلية للتوسع: يمكنك إضافة مئة دور جديد، والدالة getPermissions ستبقى كما هي، سطر واحد من الكود.
  4. فصل الاهتمامات (Separation of Concerns): لقد فصلنا “بيانات الصلاحيات” عن “منطق الحصول على الصلاحيات”. هذا يجعل الكود أكثر تنظيمًا ويمكن نقل كائن الصلاحيات إلى ملف إعدادات (config) منفصل أو حتى جلبه من قاعدة بيانات.

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

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

1. ليس فقط للكائنات (Objects)

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

تخيل أن لديك حالات بناءً على أرقام (0, 1, 2). يمكنك استخدام مصفوفة كجدول بحث: const statuses = ['Pending', 'Approved', 'Rejected']; const statusText = statuses[statusCode];

2. تعامل مع الحالات غير الموجودة (Default Cases)

ماذا يحدث إذا تم تمرير دور غير موجود في جدول البحث؟ في مثالنا، استخدمنا || [] لإرجاع مصفوفة فارغة كقيمة افتراضية. هذا مهم جدًا لتجنب الأخطاء (مثل undefined) وجعل دالتك أكثر قوة ومتانة.

3. عندما يصبح الجدول معقدًا جدًا

في بعض الأحيان، لا تكون القيمة مجرد بيانات بسيطة، بل قد تكون دالة بحد ذاتها! وهذا نمط قوي جدًا يسمى “نمط الإستراتيجية” (Strategy Pattern).

لنفترض أن لكل دور طريقة مختلفة لحساب المكافأة:


// الطريقة القديمة (if-else)
function calculateBonus(employee) {
    if (employee.role === 'manager') {
        return employee.salary * 0.2;
    } else if (employee.role === 'developer') {
        return employee.salary * 0.1;
    } // ... وهكذا
}

// طريقة جدول البحث بالدوال
const bonusStrategies = {
    manager: (salary) => salary * 0.2,
    developer: (salary) => salary * 0.1,
    intern: () => 100, // مكافأة ثابتة
};

function calculateBonus(employee) {
    const strategy = bonusStrategies[employee.role];
    return strategy ? strategy(employee.salary) : 0;
}

هنا، جدول البحث لا يخزن قيمًا، بل يخزن “سلوكيات” (دوال). هذا نمط متقدم وقوي للغاية.

4. لا تفرط في الاستخدام

زي ما بحكوها، “كل شي بزيد عن حده بنقلب ضده”. إذا كان لديك شرطان فقط (if-else بسيطة)، فلا داعي لتعقيد الأمور وإنشاء جدول بحث. استخدم هذه التقنية عندما يكون لديك 3 حالات أو أكثر، أو عندما تتوقع أن هذه الحالات ستزيد في المستقبل. الهدف هو التبسيط وليس التعقيد.

الخلاصة: اكتب كودًا يريحك ويريح من بعدك

في النهاية يا أحباب، البرمجة ليست فقط في كتابة كود يعمل. البرمجة الحقيقية هي كتابة كود واضح، منظم، وسهل الصيانة. الانتقال من غابة if-else إلى جدول بحث منظم ليس مجرد “إعادة هيكلة” (refactoring)، بل هو تغيير في طريقة التفكير: من التفكير في “المنطق والإجراءات” إلى التفكير في “البيانات والعلاقات”.

في المرة القادمة التي تجد فيها نفسك تكتب else if للمرة الثالثة أو الرابعة في نفس الكتلة البرمجية، توقف للحظة. خذ نفسًا عميقًا، اشرب فنجان شاي بالنعناع، واسأل نفسك: “هل يمكن لجدول بحث أن ينقذني من هذا الجحيم؟” في معظم الأحيان، ستكون الإجابة نعم. 👍

كودك هو بيتك الثاني، فحافظ عليه نظيفًا ومرتبًا. صدقني، “أنت” المستقبلي، وزملاؤك في الفريق، سيدعون لك بالخير. بالتوفيق!

أبو عمر

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

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

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

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

آخر المدونات

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

كان النشر يتطلب اجتماعًا: كيف حررتنا ‘العمليات عبر المحادثة’ (ChatOps) من جحيم الأوامر الطرفية؟

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

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

تحديث نظامنا القديم كان كابوساً: كيف أنقذنا نمط ‘الخنق التدريجي’ (Strangler Fig) من جحيم إعادة البناء الكارثية؟

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

23 أبريل، 2026 قراءة المزيد
ذكاء اصطناعي

نماذجنا اللغوية كانت تهذي: كيف أنقذنا ‘التوليد المعزز بالاسترجاع’ (RAG) من جحيم الإجابات الخاطئة؟

أشارككم قصة من أرض الواقع، كيف واجهنا مشكلة "هلوسة" نماذج الذكاء الاصطناعي وكيف كانت تقنية RAG طوق النجاة. سنتعمق في هذه التقنية، من المفهوم إلى...

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

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

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

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

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

أنا أبو عمر، وأروي لكم كيف تحول طلب بسيط لتغيير لون زر إلى كابوس استمر أسبوعاً، وكيف كانت "رموز التصميم" (Design Tokens) هي طوق النجاة...

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

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

أتذكر ذلك اليوم جيداً، كنا نطلق ميزة جديدة والصفحة أبطأ من السلحفاة. اكتشفنا أننا نرسل آلاف الاستعلامات لقاعدة البيانات بسبب مشكلة بسيطة تُدعى N+1. في...

23 أبريل، 2026 قراءة المزيد
الشبكات والـ APIs

خدماتنا المصغرة كانت فوضى من نقاط النهاية: كيف أنقذتنا ‘بوابة الواجهة البرمجية’ (API Gateway) من جحيم الإدارة المعقدة؟

أشارككم قصة حقيقية من قلب المعركة البرمجية، كيف انتقلنا من فوضى إدارة الخدمات المصغرة (Microservices) إلى نظام متكامل ومنظم. اكتشفوا معنا كيف كانت "بوابة الواجهة...

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

أسرارنا كانت مكشوفة للجميع: كيف أنقذتنا ‘إدارة الهوية والوصول’ (IAM) من جحيم الأذونات الفضفاضة؟

في عالم الحوسبة السحابية، الأمان ليس رفاهية. أشارككم قصة حقيقية عن كارثة كادت أن تدمر مشروعنا، وكيف كانت "إدارة الهوية والوصول" (IAM) هي طوق النجاة...

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