شفرتي كانت كابوساً: كيف أنقذني مبدأ ‘لا تكرر نفسك’ (DRY) من جحيم التحديثات؟

“يا ويلي… كل هذا الشغل عشان أغير سطر واحد؟”

أهلاً بكم يا جماعة، معكم أخوكم أبو عمر.

قبل سنوات، في بداية مسيرتي المهنية، كنت أعمل على نظام تقارير لأحد العملاء. كان النظام بسيطاً في فكرته: اسحب بيانات المبيعات من قاعدة البيانات واعرضها في ثلاثة أشكال مختلفة: صفحة ويب (HTML)، ملف PDF للطباعة، وملف CSV للتصدير إلى Excel. في ذلك الوقت، وبحكم قلة الخبرة والحماس لتسليم المشروع بسرعة، فعلت ما يفعله الكثيرون: كتبت الكود الخاص بجلب البيانات وتحليلها لتقرير الويب. وعندما جاء وقت عمل تقرير الPDF، قلت لنفسي: “ليش أغلب حالي؟ خلص، انسخ والصق!”. وهكذا فعلت، نسخت نفس الكود مع تعديلات طفيفة ليناسب الـPDF. ثم كررت نفس المأساة مع تقرير الـCSV.

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

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

هذه التجربة المؤلمة كانت أول درس حقيقي لي عن أهمية مبدأ “لا تكرر نفسك” أو ما يُعرف بـ DRY (Don’t Repeat Yourself).

ما هو مبدأ DRY بالضبط؟ وليش هو مهم؟

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

باللغة العامية البسيطة، يعني: لا تنسخ وتلصق الكود! إذا وجدت نفسك تكتب نفس المنطق البرمجي في مكانين أو أكثر، توقف فوراً. أنت على وشك أن تزرع قنبلة موقوتة في مشروعك ستنفجر في وجهك مع أول طلب تعديل.

الهدف من DRY ليس فقط تجنب تكرار الكود، بل تكرار “المعرفة” أو “المنطق”. قد يكون هذا المنطق هو:

  • خوارزمية معينة (مثل حساب سعر بعد الخصم).
  • قواعد التحقق من صحة البيانات (مثل التحقق من أن البريد الإلكتروني صحيح).
  • نصوص ثابتة أو إعدادات (مثل رابط API أو مفتاح تشفير).

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

الكود الرطب (WET): الوجه الآخر للكابوس

في عالم البرمجة، هناك مصطلح فكاهي مقابل لـ DRY وهو WET، والذي يرمز إلى “Write Everything Twice” (اكتب كل شيء مرتين) أو “We Enjoy Typing” (نحن نستمتع بالكتابة). الكود الرطب هو الكود المليء بالتكرار. وهو، كما اكتشفت بالطريقة الصعبة، مصدر للمشاكل التي لا تنتهي:

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

كيف تطبق مبدأ DRY عملياً؟ (دليل أبو عمر)

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

1. الدوال (Functions): أبسط أشكال DRY

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

مثال: قبل DRY (كود مكرر)

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

// في سلة التسوق
let price1 = 100;
let taxRate = 0.15;
let finalPrice1 = price1 + (price1 * taxRate);
console.log(`السعر النهائي: ${finalPrice1}`);

// في صفحة الفاتورة
let price2 = 250;
// نسيت أن أعرّف الضريبة هنا! أو ربما استخدمت قيمة مختلفة بالخطأ
// let taxRate = 0.15; 
let finalPrice2 = price2 + (price2 * 0.15); // استخدام قيمة ثابتة هنا هو خطأ آخر
console.log(`السعر الإجمالي في الفاتورة: ${finalPrice2}`);

مثال: بعد DRY (استخدام دالة)

نستخرج هذا المنطق في دالة واحدة مركزية.

const TAX_RATE = 0.15; // تعريف الضريبة في مكان واحد!

function calculateFinalPrice(price) {
  if (price <= 0) {
    return 0;
  }
  return price + (price * TAX_RATE);
}

// في سلة التسوق
let price1 = 100;
let finalPrice1 = calculateFinalPrice(price1);
console.log(`السعر النهائي: ${finalPrice1}`);

// في صفحة الفاتورة
let price2 = 250;
let finalPrice2 = calculateFinalPrice(price2);
console.log(`السعر الإجمالي في الفاتورة: ${finalPrice2}`);

الآن، إذا تغيرت نسبة الضريبة، كل ما عليك فعله هو تعديل قيمة المتغير TAX_RATE في مكان واحد فقط. بسيط، أليس كذلك؟

2. الأصناف (Classes) والوراثة (Inheritance)

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

مثال: في نظام إدارة محتوى، قد يكون لديك `Admin`, `Editor`, `Viewer`. جميعهم “مستخدمون” ويشتركون في خصائص مثل الاسم والبريد الإلكتروني، وربما دالة لتغيير كلمة المرور.

# بدلاً من تعريف كل صنف من الصفر
# نستخدم صنفاً أساسياً (Base Class)

class User:
    def __init__(self, name, email):
        self.name = name
        self.email = email

    def change_password(self, new_password):
        print(f"Password changed for {self.name}")
        # ... منطق تغيير كلمة المرور

# الآن الأصناف الأخرى ترث من الصنف الأساسي
class Admin(User):
    def delete_article(self, article_id):
        print(f"Admin {self.name} deleted article {article_id}")

class Editor(User):
    def edit_article(self, article_id):
        print(f"Editor {self.name} edited article {article_id}")

# كل من Admin و Editor يمتلك دالة change_password تلقائياً
admin_user = Admin("أبو عمر", "admin@example.com")
admin_user.change_password("new_secret_pass") # تعمل بشكل ممتاز!

هنا، منطق `change_password` موجود في مكان واحد فقط (الصنف User)، مما يمنع تكراره ويضمن اتساقه.

3. ملفات الإعدادات (Configuration Files)

لا تكتب القيم الثابتة (مثل مفاتيح الـ API، وسلاسل الاتصال بقواعد البيانات، والألوان الأساسية في التصميم) مباشرة في الكود. هذا يسمى “Hardcoding” وهو عدو لدود لـ DRY.

نصيحة من خبرتي: ضع كل هذه القيم في ملف إعدادات مركزي (مثل config.js, .env, settings.py). هذا يجعل تعديلها مستقبلاً أمراً سهلاً، خاصة عند نقل المشروع بين بيئات مختلفة (تطوير، اختبار، إنتاج).

مثال بسيط لملف config.js:

export const API_CONFIG = {
  BASE_URL: 'https://api.example.com/v1',
  TIMEOUT: 5000, // 5 ثواني
};

export const THEME_COLORS = {
  PRIMARY: '#005f73',
  SECONDARY: '#0a9396',
};

ثم في أي مكان في الكود، يمكنك استيراد هذه القيم واستخدامها بدلاً من كتابتها يدوياً.

4. مكونات الواجهة الأمامية (Frontend Components)

إذا كنت مطور واجهات أمامية، فإن أطر العمل الحديثة مثل React, Vue, Angular مبنية أساساً على مبدأ DRY. الزر، حقل الإدخال، بطاقة المنتج… كلها يجب أن تكون مكونات قابلة لإعادة الاستخدام.

لا تقم بنسخ ولصق كود HTML و CSS لزر في 20 صفحة مختلفة. أنشئ مكون <CustomButton> مرة واحدة، وقم بتخصيصه عبر الخصائص (props)، واستخدمه في كل مكان. إذا أردت تغيير تصميم كل الأزرار في موقعك، ستعدل ملفاً واحداً فقط.

تحذير: لا تقع في فخ “الجفاف المفرط” (Over-Abstraction)

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

لهذا السبب، أحب اتباع “قاعدة الثلاثة” (The Rule of Three):

  1. المرة الأولى: اكتب الكود.
  2. المرة الثانية: إذا احتجته مرة أخرى، لا بأس، انسخه مؤقتاً (خاصة إذا كنت في عجلة من أمرك).
  3. المرة الثالثة: إذا احتجت نفس الكود للمرة الثالثة، هنا يجب أن تتوقف. لقد حان الوقت لإعادة الهيكلة (Refactoring) واستخراج هذا الكود المكرر في دالة أو صنف خاص به.

هذه القاعدة تمنعك من التجريد المبكر (premature abstraction)، والذي يمكن أن يكون مضيعة للوقت ويجعل الكود أصعب في الفهم.

الخلاصة: DRY هو عقلية وليس مجرد تقنية 💡

في النهاية، مبدأ “لا تكرر نفسك” هو أكثر من مجرد مجموعة من التقنيات؛ إنه طريقة تفكير. قبل أن تكتب أي سطر كود، اسأل نفسك:

  • هل كتبت شيئاً كهذا من قبل؟
  • هل من المحتمل أن أحتاج هذا المنطق في مكان آخر مستقبلاً؟
  • هل يمكنني جعل هذا الكود عاماً وقابلاً لإعادة الاستخدام؟

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

نصيحة أخيرة من أبو عمر: عامل الكود الخاص بك كحديقة مرتبة، وليس كمخزن فوضوي. كل دالة وكل صنف هو أداة في مكانها الصحيح، جاهزة للاستخدام عند الحاجة. لا ترمِ أدواتك المكررة في كل مكان، لأنك ستتعب كثيراً عندما تبحث عنها لاحقاً. ✅

أتمنى أن تكون هذه المقالة قد أفادتكم. بالتوفيق في رحلتكم البرمجية!

أبو عمر

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

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

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

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

آخر المدونات

​معمارية البرمجيات

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

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

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

واجهاتي كانت فوضى بصرية: كيف أنقذني ‘نظام التصميم’ (Design System) من جحيم عدم الاتساق؟

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

29 مارس، 2026 قراءة المزيد
التوظيف وبناء الهوية التقنية

ملفي الشخصي على GitHub كان صامتاً: كيف حولتني المساهمات في المشاريع المفتوحة المصدر من مبرمج مجهول إلى مرشح مطلوب؟

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

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