يا جماعة الخير، السلام عليكم. معكم أخوكم أبو عمر.
قبل كم يوم، كنت براجع كود كتبه مبرمج جديد في الفريق. فتحت الملف، وإذ بي أرى دالة (function) طويلة، شكلها غريب. كل سطر يدخل لجوا أكثر من اللي قبله، كأنها رأس سهم متجه لليمين أو هرم مقلوب على جنبه. تنهدت وقلت في نفسي: “يا ساتر! رجعنا لهي القصة”.
هذا المشهد أعادني سنوات للوراء، لأول مشروع كبير اشتغلت عليه. كنت متحمسًا جدًا، وكتبت كودًا يفعل العجائب، لكن… كان بنفس هذا الشكل الهرمي. أتذكر ليلة قضيتها أحاول إصلاح خطأ بسيط في هذا الكود؛ كنت كلما دخلت في شرط if، أضيع أكثر. شعرت كأنني في متاهة لا نهاية لها. يومها، قررت أن هذا الأسلوب في الكتابة، والذي أسميه “الكود السهمي” أو “هرم الجحيم”، يجب أن ينتهي. ومن هنا بدأت رحلتي مع مفهوم بسيط لكنه ثوري: شروط الحماية (Guard Clauses).
في هذه المقالة، سآخذكم معي في هذه الرحلة، لنرى كيف يمكننا التخلص من هذه الأهرامات البرمجية ونكتب كودًا نظيفًا، مرتبًا، ومريحًا للعين والعقل.
ما هو “الكود السهمي” أو “هرم الشروط”؟
ببساطة، “الكود السهمي” (Arrow Code) هو نتيجة استخدام جمل if متداخلة بكثرة. كل شرط جديد يضيف مسافة بادئة (indentation) جديدة، مما يجعل الكود يتجه قطريًا عبر الشاشة، مثل رأس السهم. هذا الأسلوب، وإن كان يعمل من الناحية التقنية، إلا أنه كارثة من ناحية جودة الكود.
مثال على الكود السهمي (Pyramid of Doom)
تخيل أنك تكتب دالة لمعالجة طلب شراء في متجر إلكتروني. قبل معالجة الطلب، عليك التحقق من عدة أمور: هل المستخدم موجود؟ هل هو نشط؟ هل الطلب موجود؟ هل حالة الطلب تسمح بالمعالجة؟ إلخ. بالطريقة التقليدية، قد يبدو الكود هكذا (سأستخدم لغة تشبه Python للتوضيح):
def process_order(user, order):
# المستوى الأول من التداخل
if user is not None:
# المستوى الثاني
if user.is_active:
# المستوى الثالث
if order is not None:
# المستوى الرابع
if order.status == "pending":
# المستوى الخامس!
if len(order.items) > 0:
# --- المنطق الأساسي للدالة مدفون هنا ---
print("جاري معالجة الطلب...")
# ... كود معالجة الطلب الفعلي ...
return "تمت المعالجة بنجاح"
else:
print("خطأ: الطلب فارغ.")
return None
else:
print("خطأ: حالة الطلب ليست 'معلقة'.")
return None
else:
print("خطأ: الطلب غير موجود.")
return None
else:
print("خطأ: المستخدم غير نشط.")
return None
else:
print("خطأ: المستخدم غير موجود.")
return None
شو هاد يا عمي؟ انظر إلى هذا الهرم! المنطق الأساسي للدالة، وهو أهم جزء، مدفون في أعماق 5 مستويات من التداخل. هذا الكود يعاني من عدة مشاكل:
- صعوبة القراءة: تحتاج إلى تتبع كل الشروط في عقلك لتفهم متى سيتم تنفيذ المنطق الأساسي.
- صعوبة الصيانة: ماذا لو أردت إضافة شرط جديد؟ ستحتاج إلى إضافة مستوى آخر من التداخل، مما يزيد الطين بلة.
- صعوبة تصحيح الأخطاء (Debugging): إذا رجعت الدالة
None، عليك تتبع كل مساراتelseلتعرف أين حدثت المشكلة بالزبط. - الحمل المعرفي العالي (High Cognitive Load): يتطلب فهم هذا الكود جهدًا ذهنيًا كبيرًا، وهو آخر شيء نريده كمبرمجين.
المنقذ: شروط الحماية (Guard Clauses)
شروط الحماية هي تقنية بسيطة جدًا تعتمد على مبدأ “اخرج مبكرًا” (Exit Early). بدلًا من تداخل الشروط للوصول إلى “المسار السعيد” (Happy Path) – أي المسار الذي يتم فيه تنفيذ المنطق الرئيسي – نقوم بعكس المنطق.
الفكرة هي أن تتحقق من كل الشروط “السيئة” أو الحالات الاستثنائية في بداية الدالة. إذا تحقق أي من هذه الشروط، أوقف التنفيذ فورًا وأرجع خطأ أو قيمة مناسبة. بهذا، أنت “تحمي” باقي الكود من التنفيذ في ظروف غير صالحة.
نفس المثال بعد استخدام شروط الحماية
دعونا نعيد كتابة الدالة السابقة باستخدام هذا المفهوم السحري. انظر كيف سيصبح الكود مسطحًا وواضحًا:
def process_order_clean(user, order):
# شرط الحماية الأول: التحقق من المستخدم
if user is None:
print("خطأ: المستخدم غير موجود.")
return None
# شرط الحماية الثاني: التحقق من نشاط المستخدم
if not user.is_active:
print("خطأ: المستخدم غير نشط.")
return None
# شرط الحماية الثالث: التحقق من الطلب
if order is None:
print("خطأ: الطلب غير موجود.")
return None
# شرط الحماية الرابع: التحقق من حالة الطلب
if order.status != "pending":
print("خطأ: حالة الطلب ليست 'معلقة'.")
return None
# شرط الحماية الخامس: التحقق من وجود منتجات
if len(order.items) == 0:
print("خطأ: الطلب فارغ.")
return None
# --- المسار السعيد (Happy Path) ---
# المنطق الأساسي واضح ومكشوف وبدون أي تداخل
print("جاري معالجة الطلب...")
# ... كود معالجة الطلب الفعلي ...
return "تمت المعالجة بنجاح"
فرق شاسع، أليس كذلك؟ الكود الآن يقرأ مثل قائمة تحقق (checklist). كل شرط يفشل يخرجك من الدالة فورًا. أما إذا نجحت كل الشروط، فإنك تصل إلى المنطق الأساسي في نهاية الدالة، وهو الآن واضح تمامًا وموجود على المستوى الأول من الكود، بدون أي مسافات بادئة غير ضرورية.
نصائح أبو عمر الذهبية لاستخدام شروط الحماية
من خبرتي، هذه التقنية أكثر من مجرد ترتيب للكود. إنها طريقة تفكير تساعدك على بناء برمجيات أقوى وأكثر متانة. إليكم بعض النصائح العملية:
1. افشل بسرعة، وافشل بوضوح (Fail Fast, Fail Loud)
مبدأ شروط الحماية هو اكتشاف المشكلة في أسرع وقت ممكن. بدلًا من إرجاع null أو قيمة غامضة، فكر في إطلاق استثناء (Throwing an Exception) مع رسالة واضحة. هذا يجعل تصحيح الأخطاء أسهل بكثير لأن البرنامج سيتوقف عند نقطة الخطأ بالضبط مع شرح للمشكلة.
مثال: بدلًا من
return "خطأ: المستخدم غير موجود"، يمكنك استخدامthrow new InvalidArgumentException("المستخدم لا يمكن أن يكون فارغًا"). هذا يمنع الكود الذي استدعى دالتك من الاستمرار ببيانات خاطئة.
2. حافظ على بساطة الشروط
يجب أن يكون شرط الحماية بسيطًا وواضحًا، يتحقق من شيء واحد فقط. إذا كان شرط التحقق نفسه معقدًا (مثلاً: if (user.hasPermission('edit') && !user.isBlocked() && user.lastLogin > 30_days_ago))، فمن الأفضل استخلاص هذا المنطق في دالة منفصلة لها اسم معبر.
# قبل: شرط معقد
if not (user.hasPermission('edit') and not user.isBlocked()):
return "Error: Permission denied"
# بعد: شرط بسيط باستخدام دالة مساعدة
def can_user_edit(user):
return user.hasPermission('edit') and not user.isBlocked()
if not can_user_edit(user):
return "Error: Permission denied"
هذا يجعل الكود يقرأ كأنه جملة إنجليزية (أو عربية!).
3. ركز على “المسار السعيد”
الهدف النهائي هو جعل المنطق الأساسي لدالتك (المسار السعيد) هو بطل المشهد. بعد أن تزيل كل الحالات الشاذة في البداية، يجب أن يكون ما تبقى من الكود هو صلب الموضوع، واضحًا ومباشرًا. هذا يسهل على أي مبرمج آخر (أو أنت في المستقبل) فهم الغرض الرئيسي للدالة من أول نظرة.
4. لا تخف من تعدد نقاط الخروج (Multiple Return Statements)
بعض المدارس القديمة في البرمجة كانت تصر على أن الدالة يجب أن يكون لها نقطة خروج واحدة فقط (return واحدة في النهاية). هذه القاعدة لا تنطبق بقوة في البرمجة الحديثة، خاصة مع وجود شروط الحماية. تعدد نقاط الخروج المبكرة يجعل الكود أنظف وأكثر قابلية للقراءة. لا تتردد في استخدام return كلما احتجت للخروج مبكرًا.
الخلاصة: من كود معكرونة إلى طبق لازانيا مرتب 🍝➡️ lasagna 😋
الكود السهمي أو هرم الشروط يشبه طبق معكرونة (سباغيتي) معقد ومتشابك، يصعب معرفة بدايته من نهايته. أما الكود الذي يستخدم شروط الحماية، فهو أشبه بطبق لازانيا شهي ومرتب، كل طبقة فيه واضحة ومستقلة، مما يسهل التعامل معه وتذوقه (أو قراءته!).
في المرة القادمة التي تجد فيها نفسك تكتب if داخل if، توقف لحظة. اسأل نفسك: “هل يمكنني عكس هذا الشرط واستخدام شرط حماية للخروج مبكرًا؟”. في 99% من الحالات، ستكون الإجابة “نعم”، وستشكر نفسك لاحقًا على هذا القرار.
تبني هذه العادة البسيطة سيغير طريقة كتابتك للكود إلى الأبد، وسيجعل زملاءك في الفريق يحبون مراجعة الكود الذي تكتبه. تذكر دائمًا: الكود النظيف ليس رفاهية، بل هو ضرورة لبناء برمجيات قوية ومستدامة. 🚀
ودمتم سالمين يا جماعة.