يا جماعة الخير، السلام عليكم ورحمة الله وبركاته. اسمحولي اليوم أحكيلكم قصة صارت معي زمان، في بداياتي في عالم البرمجة، قبل ما يصير الشيب هاد يغزو لحيتي. كنا شغالين على نظام مالي لأحد العملاء، نظام حساس جدًا، الغلطة فيه بتكلف مصاري ووقت. وفي ليلة من الليالي، وإحنا بنعمل آخر الاختبارات قبل التسليم، ضرب النظام!
توقف كل شيء، ورسالة خطأ غامضة ظهرت على الشاشة. قضينا ساعات، والله يا جماعة القهوة بطلت تجيب نتيجة، وإحنا بنحاول نعرف شو المشكلة. بعد تنقيب عميق في الكود، زي اللي بنقب عن آثار، لقينا السطر المسبب للمشكلة. كان سطر بسيط جدًا:
if (transaction.status == 7) {
// ... do something critical
}
وقفنا كلنا وسألنا نفس السؤال اللي ما إله جواب مباشر: “شو يعني status يساوي 7؟”. لا تعليقات، لا توثيق، ولا أي إشي يدل على معنى الرقم 7. المبرمج الأصلي اللي كتب هالكود كان قد ترك الشركة من شهور. عشنا لحظات من الجحيم البرمجي وإحنا بنجرب ونخمّن. هل 7 يعني “مكتمل”؟ “ملغي”؟ “قيد المراجعة”؟ بعد ما قلبنا الدنيا وقرأنا أكواد قديمة، اكتشفنا إنه 7 كان يعني “معاملة تحتاج موافقة يدوية خاصة”. تغيير بسيط في منطق العمل في مكان آخر من النظام خلى هالحالة تظهر بشكل غير متوقع وتسبب الكارثة.
في هذيك الليلة، أقسمت إني ما أرجع أستخدم “رقم سحري” في كودي مرة ثانية. ومن يومها، وأنا بعتبرها من الخطايا البرمجية الكبرى. هالقصه هي مدخلنا لموضوع اليوم: الأرقام السحرية وكيف “الثوابت المسماة” هي المنقذ.
ما هي “الأرقام السحرية” (Magic Numbers)؟ ولماذا هي سيئة؟
ببساطة، الرقم السحري هو أي رقم (أو حتى نص) تستخدمه في الكود مباشرةً بدون ما تعرّف معناه. هو رقم له معنى “سحري” خاص لا يعرفه إلا الساحر (المبرمج) الذي كتبه في البداية. وبعد فترة، حتى الساحر نفسه بينسى سحره!
المشكلة في الأرقام السحرية تتلخص في عدة نقاط قاتلة:
- صعوبة القراءة (Readability): الكود يصبح مثل الطلاسم. بدل ما تقرأ جملة مفهومة مثل
if (user.role == USER_ROLE_ADMIN)، أنت تقرأ شيئًا غامضًا مثلif (user.role == 1). - صعوبة الصيانة (Maintainability): تخيل لو الرقم
7في قصتنا كان مستخدم في 20 مكان مختلف في النظام. والآن قررنا نغير قيمته إلى8. ستحتاج إلى البحث عن كل مرة ظهر فيها الرقم 7 والتأكد من أنك تغيره في السياق الصحيح فقط. عملية مرهقة وخطيرة جدًا. - مصدر للأخطاء (Bugs): من السهل جدًا أن تخطئ في كتابة رقم (تكتب
8بدل7). لكن من الصعب أن تخطئ في كتابة اسم ثابت واضح مثلTRANSACTION_NEEDS_APPROVAL، لأن محرر الأكواد سيساعدك في الإكمال التلقائي. - لا يوجد مصدر واحد للحقيقة (Single Source of Truth): المعنى الحقيقي للرقم يعيش فقط في عقل المبرمج أو في تعليق بجانب السطر (وهذا إذا كنت محظوظًا). هذا ليس مكانًا آمنًا للمعلومات الهامة.
الحل المنقذ: الثوابت المسماة (Named Constants)
الحل بسيط وأنيق جدًا: لا تستخدم الرقم مباشرةً، بل أعطه اسمًا ذا معنى وخزّنه في “ثابت” (Constant). الثابت هو متغير لا يمكن تغيير قيمته بعد تعريفه.
دعونا نعيد كتابة المثال الكارثي من قصتي بالطريقة الصحيحة. لنفترض أننا نستخدم لغة JavaScript:
مثال عملي: قبل وبعد
الكود السيء (مع أرقام سحرية):
function processTransaction(transaction) {
if (transaction.status === 1) {
console.log("المعاملة قيد الانتظار...");
} else if (transaction.status === 2) {
console.log("المعاملة مكتملة.");
} else if (transaction.status === 3) {
console.log("المعاملة ملغاة.");
} else if (transaction.status === 7) {
// هذا هو الرقم الغامض من قصتنا
console.log("المعاملة تحتاج موافقة يدوية!");
}
}
الكود النظيف (باستخدام الثوابت المسماة):
// تعريف الثوابت في مكان مركزي واحد، ربما في ملف خاص اسمه constants.js
const TRANSACTION_STATUS = {
PENDING: 1,
COMPLETED: 2,
CANCELLED: 3,
NEEDS_MANUAL_APPROVAL: 7, // الآن المعنى واضح ومركزي
};
function processTransaction(transaction) {
if (transaction.status === TRANSACTION_STATUS.PENDING) {
console.log("المعاملة قيد الانتظار...");
} else if (transaction.status === TRANSACTION_STATUS.COMPLETED) {
console.log("المعاملة مكتملة.");
} else if (transaction.status === TRANSACTION_STATUS.CANCELLED) {
console.log("المعاملة ملغاة.");
} else if (transaction.status === TRANSACTION_STATUS.NEEDS_MANUAL_APPROVAL) {
console.log("المعاملة تحتاج موافقة يدوية!");
}
}
شايفين الفرق؟ الكود الثاني يحكي قصة بنفسه. أصبح “يوثق نفسه بنفسه” (self-documenting). لو جاء مبرمج جديد بعد سنة، سيفهم فورًا ماذا يعني كل شرط. وإذا أردنا تغيير قيمة “ملغي” من 3 إلى 99، نغيرها في مكان واحد فقط وهو TRANSACTION_STATUS.CANCELLED وينتهي الأمر.
أين نضع هذه الثوابت؟
هذا سؤال مهم. أفضل الممارسات تقترح وضعها في مكان مركزي حسب حجم مشروعك:
- لملف واحد: يمكنك تعريفها في أعلى الملف الذي يستخدمها.
- لمكون أو وحدة (Module): يمكنك وضعها في ملف خاص بالثوابت داخل هذا المكون، مثل
user.constants.js. - للمشروع بأكمله: يمكنك إنشاء ملف عام مثل
src/config/constants.jsوتصدير الثوابت منه واستيرادها في أي مكان تحتاجه. هذه هي الطريقة الأكثر شيوعًا ونظافة في المشاريع الكبيرة.
نصائح من خبرة أبو عمر
على مدار سنوات عملي، تعلمت بعض الدروس عن هذا الموضوع، واسمحوا لي أشارككم إياها:
- التزم بأسلوب تسمية موحد: العرف السائد في معظم اللغات هو كتابة أسماء الثوابت بأحرف كبيرة وربط الكلمات بشرطة سفلية (
SCREAMING_SNAKE_CASE). مثال:MAX_LOGIN_ATTEMPTS. هذا يجعل تمييزها عن المتغيرات العادية سهلاً جدًا. - لا تكن كسولاً: عندما ترى رقمًا سحريًا في كود تراجعه أو تعدل عليه، لا تتجاهله وتقول “مش شغلي”. خذ دقيقتين من وقتك، عرّف ثابتًا باسم مناسب، واستبدل الرقم به. هذه هي “قاعدة الكشافة”: اترك المكان دائمًا أنظف مما وجدته.
- استخدم Enums إن وجدت: في لغات مثل TypeScript أو Java أو C# أو Python، يوجد مفهوم أجمل وأقوى من الثوابت العادية وهو الـ
Enum(Enumerations). الـ Enums توفر أمانًا أكبر من ناحية النوع (Type Safety) وتجعل الكود أكثر تنظيمًا. مثال سريع في TypeScript:enum OrderStatus { Pending = "PENDING", Shipped = "SHIPPED", Cancelled = "CANCELLED", } // Usage let myOrderStatus: OrderStatus = OrderStatus.Shipped; - ليست كل الأرقام “سحرية”: من المهم أن نميز. هناك أرقام مقبولة عالميًا ولا تحتاج لثوابت.
على سبيل المثال، الأرقام
0و1و-1في سياقات محددة جدًا ليست سحرية. مثلاً في حلقة تكرارfor (let i = 0; ...)، أو للوصول لأول عنصر في مصفوفةarray[0]، أو عند التحقق من نتيجةindexOfالتي تعيد-1إذا لم تجد العنصر. السياق هو الملك هنا.
الخلاصة: الكود يجب أن يحكي قصته
في النهاية يا جماعة، البرمجة ليست مجرد كتابة أوامر يفهمها الكمبيوتر. هي بالدرجة الأولى كتابة تعليمات يفهمها البشر (زملاؤك في الفريق، وأنت نفسك في المستقبل). الأرقام السحرية تجعل الكود همهمة غير مفهومة، بينما الثوابت المسماة تحوله إلى قصة واضحة ومقروءة.
نصيحتي الأخيرة لكم: في المرة القادمة التي تمتد فيها يدك لكتابة رقم عشوائي في الكود، توقف لحظة واسأل نفسك: “هل سيفهم المبرمج القادم ماذا يعني هذا الرقم بعد ستة أشهر؟”. إذا كان الجواب “لا”، فأنت تعرف ما عليك فعله. استثمر ثلاثين ثانية الآن لتعريف ثابت، وستوفر على نفسك وعلى فريقك ساعات من الألم في المستقبل. 💡
دمتم مبدعين، وكودكم نظيفًا دائمًا.