يا جماعة الخير، السلام عليكم ورحمة الله.
قبل كم سنة، كنت شغال على مشروع صيانة لنظام قديم شوي، نظام إدارة محتوى لإحدى الشركات. الكود كان زي خريطة كنز قديمة، مكتوبة بلغة ما حدا فاهمها. المهم، كان في “بَغ” (bug) محيّر: بعض المستخدمين اللي صلاحياتهم “محرر” ما كانوا قادرين يوصلوا لصفحات معينة المفروض يشوفوها.
قعدت يومين كاملين، وأنا بلف وبدور في هالكود، بحاول أفهم منطق الصلاحيات. كل ما أفتح ملف، ألاقي شرط زي هيك:
if (user.status == 2 && user.level > 4) {
// do something...
}
شو يعني status == 2؟ وشو قصة level > 4؟ ما في أي توثيق، والمبرمج الأصلي سافر على المريخ شكله. بعد تنبيش وحفر وتحليل لقاعدة البيانات، اكتشفت إنه `status 2` يعني “مستخدم فعال” (Active User)، و `level 4` هو مستوى صلاحيات “المشاهد” (Viewer). يعني الشرط كان بيمنع أي حدا مستواه أعلى من 4 (اللي هم المحررين والمدراء) من تنفيذ الإجراء. كان الخطأ بسيطاً، المفروض يكون user.level >= 4.
هالحكي كلّفني يومين من الصداع والقهوة المرة. والمشكلة كلها؟ أرقام يتيمة مرمية بنص الكود، لا إلها معنى واضح ولا أصل. هاي هي يا جماعة “الأرقام السحرية” (Magic Numbers)، واليوم بدنا نحكي كيف ننهي قصتها ونكتب كود نظيف ومفهوم للكل.
شو قصة “الأرقام السحرية” (Magic Numbers)؟
ببساطة، الرقم السحري هو أي رقم (أو حتى نص) بتستخدمه في الكود بدون ما تعرّف عن معناه بشكل صريح. هو رقم بيظهر “من العدم” زي السحر، وما حدا بيعرف شو وظيفته إلا اللي كتبه (ويمكن حتى هو ينسى بعد أسبوع!).
خلينا نشوف أمثلة بسيطة عشان الصورة توضح:
مثال 1: صلاحيات المستخدم
كود مليان سحر:
function canEditArticle(user) {
// 1 is Admin, 2 is Editor
if (user.role === 1 || user.role === 2) {
return true;
}
return false;
}
لاحظ الرقمين 1 و 2. بدون التعليق اللي فوقهم (واللي ممكن يكون مش موجود أو قديم)، مستحيل تعرف شو معناهم. ولو احتجت تضيف صلاحية جديدة، راح تضطر تعدل على كل مكان استخدمت فيه هاي الأرقام.
مثال 2: حسابات مالية
كود غامض:
function calculateTotalPrice(price, quantity) {
const total = price * quantity;
const totalWithTax = total + (total * 0.16); // ما هذا الرقم؟
return totalWithTax;
}
الرقم 0.16 هون هو رقم سحري. هل هو ضريبة القيمة المضافة؟ هل هو عمولة؟ ولو تغيرت نسبة الضريبة في المستقبل، كم ملف راح تضطر تفتحه وتعدل فيه هذا الرقم؟
ليش الأرقام السحرية كابوس حقيقي؟
ممكن تحكي: “يا أبو عمر، مكبّر الموضوع. أنا فاهم كودي والحمد لله”. المشكلة يا صديقي مش فيك اليوم، المشكلة فيك أنت بعد ست شهور، أو في زميلك الجديد اللي راح يشتغل على نفس المشروع. الأرقام السحرية بتسبب ثلاث مشاكل رئيسية:
- قلة الوضوح (Poor Readability): الكود بصير صعب القراءة والفهم. بدل ما الكود يشرح نفسه بنفسه، بيتحول لأحجية. أنت بتجبر اللي بيقرأ الكود إنه “يخمّن” المقصد من ورا هاي الأرقام.
- صعوبة الصيانة (Hard to Maintain): زي ما شفنا في مثال الضريبة، لو احتجت تعدّل قيمة مستخدمة في 10 أماكن مختلفة، راح تضطر تعدلها 10 مرات. ولو نسيت مكان واحد، مبروك! صار عندك “بَغ” جديد. هذا اسمه “صداع الصيانة”.
- مصدر للأخطاء (Error-Prone): البشر بخطئوا. ممكن بسهولة تكتب
0.15بدل0.16بالخطأ في مكان ما، أوrole == 3بدلrole == 2. هاي الأخطاء صعب جداً تلاقيها وقت المراجعة (Code Review) لأنها مجرد أرقام.
نصيحة من أبو عمر: دايماً اكتب كودك وكأن الشخص اللي راح يجي بعدك عشان يكمله هو قاتل متسلسل يعرف وين بتسكن. خليه مبسوط وراضي عنك وعن وضوح كودك!
الحل: كيف نتخلص من السحر ونرجع للواقع؟
الحمد لله، الحل بسيط ومنطقي جداً. الفكرة كلها هي إنك تعطي هاي الأرقام الغامضة أسماء واضحة ومعبرة. هيك الكود بصير يحكي قصته بنفسه. فيه عدة طرق لتحقيق هالشي.
1. استخدام الثوابت (Constants)
هاي أبسط وأشهر طريقة. بدل ما تستخدم الرقم مباشرة، عرّفه كـ “ثابت” (Constant) في بداية الملف أو في مكان مركزي.
قبل (مع السحر):
function calculateDiscount(cartValue) {
if (cartValue > 1000) {
return cartValue * 0.15; // 15% discount
}
return 0;
}
بعد (كود واضح):
const MIN_CART_VALUE_FOR_DISCOUNT = 1000;
const DISCOUNT_RATE = 0.15;
function calculateDiscount(cartValue) {
if (cartValue > MIN_CART_VALUE_FOR_DISCOUNT) {
return cartValue * DISCOUNT_RATE;
}
return 0;
}
شوف الفرق! صار الكود مقروء زي اللغة الإنجليزية. أي حدا بيقرأه بيفهم إنه إذا قيمة السلة تجاوزت حد معين، بنطبق عليها نسبة خصم معينة. ولو احتجت تعدل نسبة الخصم، بتعدلها بمكان واحد فقط. سهل ومباشر.
2. استخدام التعدادات (Enums)
لما يكون عندك مجموعة من القيم الثابتة اللي مرتبطة ببعض (زي صلاحيات المستخدم، حالات الطلب، ألوان المنتج)، الأفضل تستخدم “التعداد” أو الـ Enum. هاي بتنظم الكود أكثر.
قبل (مع السحر):
function handleOrderStatus(order) {
if (order.status === 0) { // Pending
// ...
} else if (order.status === 1) { // Shipped
// ...
} else if (order.status === 2) { // Delivered
// ...
} else if (order.status === 3) { // Cancelled
// ...
}
}
بعد (باستخدام Enum في TypeScript/Java أو ما يشابهها):
enum OrderStatus {
Pending, // 0
Shipped, // 1
Delivered, // 2
Cancelled, // 3
}
function handleOrderStatus(order) {
if (order.status === OrderStatus.Pending) {
// ...
} else if (order.status === OrderStatus.Shipped) {
// ...
}
// ... and so on
}
هون صار الكود مش بس مقروء، صار كمان آمن. لو حاولت تقارن الحالة مع رقم غلط (مثلاً order.status === 5)، مترجم اللغة (Compiler) أو الأدوات المساعدة راح تنبهك للخطأ. ما في مجال للتخمين.
3. ملفات الإعدادات (Configuration Files)
بعض الأرقام مش مجرد ثوابت برمجية، بل هي “إعدادات” ممكن تتغير بين بيئة التطوير (Development) والبيئة الحقيقية (Production). أمثلة على ذلك:
- عدد الاتصالات المسموح بها لقاعدة البيانات.
- مهلة انتهاء الجلسة (Session Timeout).
- عنوان الـ API الخارجي.
- مفاتيح الـ API.
هاي القيم مكانها مش في الكود مباشرة، بل في ملفات إعدادات خارجية (مثل .env, config.json, appsettings.json). هذا الأسلوب بخلي تطبيقك مرن وآمن.
مثال (ملف .env):
SESSION_TIMEOUT_SECONDS=86400
DATABASE_MAX_CONNECTIONS=50
في الكود (مثال بـ Node.js):
const SESSION_TIMEOUT = process.env.SESSION_TIMEOUT_SECONDS;
const MAX_CONNECTIONS = process.env.DATABASE_MAX_CONNECTIONS;
// ...
// Now use these variables instead of hardcoded numbers
// ...
هيك بتقدر تعدل الإعدادات بدون ما تلمس الكود البرمجي أو تعيد بناء التطبيق كله.
الخلاصة: اجعل كودك يتحدث عن نفسه 🗣️
يا جماعة، البرمجة مش بس كتابة أوامر للكمبيوتر، هي شكل من أشكال التواصل مع المبرمجين الآخرين (ومع نفسك في المستقبل). كل ما كان كودك أوضح وأسهل للفهم، كل ما كانت حياتك وحياة فريقك أسهل.
التخلص من الأرقام السحرية هو خطوة أساسية على طريق كتابة “الكود النظيف” (Clean Code). القاعدة بسيطة جداً:
إذا كان الرقم يحمل معنى يتجاوز قيمته العددية، فهو يستحق اسماً.
لا تستهينوا بهي العادة. دقيقة إضافية تقضيها في تعريف ثابت اليوم، قد توفر عليك ساعات طويلة من تصحيح الأخطاء والصداع في المستقبل. خلوا كودكم واضح، صريح، ويحكي قصته بنفسه.
يعطيكم ألف عافية، وبالتوفيق في رحلتكم البرمجية! 👋