مقدمة
الكود يُقرأ أكثر بكثير مما يُكتب: ستقرؤه أنت بعد شهرين، وزملاؤك، ومراجعو الكود. «الكود النظيف» ليس ذوقاً شخصياً بل مجموعة عادات تقلل الأخطاء وتسرّع التعديل. هذا الدرس يركز على أكثرها أثراً.
أهداف التعلم
- اختيار أسماء تكشف النية.
- تقسيم الدوال الطويلة إلى دوال صغيرة بمسؤولية واحدة.
- تقليل التداخل (Nesting) بالعودة المبكرة.
- كتابة تعليقات مفيدة بدل التعليقات المكررة للكود.
1. الأسماء تكشف النية
قبل:
function calc(a, b, t) {
const r = t ? a * b * 0.85 : a * b;
return r;
}
بعد:
const MEMBER_DISCOUNT = 0.15;
function orderTotal(unitPrice, quantity, isMember) {
const subtotal = unitPrice * quantity;
return isMember ? subtotal * (1 - MEMBER_DISCOUNT) : subtotal;
}
الاسم orderTotal يجيب عن «ماذا تفعل الدالة؟»، والثابت MEMBER_DISCOUNT يزيل «الرقم السحري» 0.85 ويجعل تغييره في مكان واحد.
قواعد سريعة: الدوال أفعال (sendEmail)، والمتغيرات أسماء (activeUsers)، والقيم المنطقية أسئلة (isValid, hasAccess). تجنب الاختصارات غير المعروفة.
2. دالة واحدة، مهمة واحدة
دالة تقرأ ملفاً وتتحقق من البيانات وتحسب وتكتب تقريراً يصعب اختبارها وتعديلها. قسّمها:
def load_orders(path: str) -> list[dict]:
with open(path, encoding="utf-8") as f:
return json.load(f)
def valid_orders(orders: list[dict]) -> list[dict]:
return [o for o in orders if o.get("quantity", 0) > 0]
def revenue(orders: list[dict]) -> float:
return sum(o["price"] * o["quantity"] for o in orders)
def report(path: str) -> str:
orders = valid_orders(load_orders(path))
return f"الإيراد: {revenue(orders):.2f}"
الآن يمكن اختبار revenue دون ملفات، وتغيير مصدر البيانات دون لمس الحساب.
3. العودة المبكرة بدل التداخل العميق
قبل:
def can_post(user):
if user:
if user.email_verified:
if not user.is_banned:
return True
return False
بعد:
def can_post(user) -> bool:
if not user:
return False
if not user.email_verified:
return False
return not user.is_banned
كل شرط يُستبعد مبكراً، والمسار الرئيسي يبقى على يسار الصفحة (أو يمينها في العربية!).
4. تعليقات تشرح «لماذا» لا «ماذا»
تعليق سيئ: i += 1 # زيادة i بواحد — يكرر الكود.
تعليق جيد:
# نستخدم bcrypt بتكلفة 12 بدل 10: قيست على خادمنا فاستغرقت ~250ms،
# وهو حد مقبول لتسجيل الدخول ويبطئ هجمات التخمين كثيراً.
BCRYPT_COST = 12
إن احتجت تعليقاً يشرح ماذا يفعل الكود، فغالباً يحتاج الكود نفسه اسماً أوضح أو دالة مستقلة.
5. لا تكرر نفسك — لكن بحكمة
إن نسخت المنطق نفسه في ثلاثة أماكن، فالتعديل القادم سيُنسى في أحدها. استخرجه إلى دالة. لكن لا تدمج كودين متشابهين ظاهرياً يخدمان أسباباً مختلفة؛ التكرار أهون من تجريد خاطئ.
تمرين عملي
خذ دالة طويلة من مشروع قديم لك (40 سطراً أو أكثر) وطبّق عليها:
- أعد تسمية ثلاثة متغيرات على الأقل بأسماء أوضح.
- استخرج دالتين صغيرتين على الأقل.
- استبدل كل رقم سحري بثابت مسمى.
- اكتب اختباراً بسيطاً قبل التعديل وبعده للتأكد أن السلوك لم يتغير.
أخطاء شائعة
- إعادة الهيكلة دون اختبارات: قد تغير السلوك دون أن تلاحظ.
- التجريد المبكر: طبقات وواجهات لحالة واحدة فقط تزيد التعقيد.
- أسماء طويلة بلا معنى:
dataManagerHelperUtilلا يخبرك بشيء. - تعليقات قديمة: تعليق لا يطابق الكود أسوأ من غياب التعليق؛ حدّثه أو احذفه.
الخلاصة
اختر أسماء تكشف النية، اجعل كل دالة تؤدي مهمة واحدة، قلل التداخل بالعودة المبكرة، واكتب تعليقات تشرح الأسباب. وغيّر الكود بخطوات صغيرة محمية بالاختبارات.
مصادر مقترحة
- كتاب Clean Code لـ Robert C. Martin (مع قراءة نقدية لبعض أمثلته).
- كتاب Refactoring لـ Martin Fowler.
- كتاب A Philosophy of Software Design لـ John Ousterhout.