پروگرامنگ میں جادو کوئی استعارہ نہیں بلکہ ایک قطعی اصطلاح ہے جو ان اقدار (نمبر، سٹرنگ، جھنڈے) کو ظاہر کرتی ہے جن کا مطلب سیاق و سباق سے واضح نہیں ہوتا اور سمجھنے کے لیے بیرونی علم کی ضرورت ہوتی ہے۔ جادو کی سب سے عام قسم جادوئی نمبر ہیں: عددی مستقل جو بغیر کسی وضاحت کے براہ راست کوڈ میں لکھے جاتے ہیں کہ یہ خاص قدر کیوں چنی گئی۔ SonarSource کوڈ کوالٹی رپورٹ (2025) کے مطابق، تمام جامد تجزیہ کار انتباہات کا تقریباً 8 فیصد غیر واضح لفظی اقدار سے متعلق ہے۔ جادوئی اقدار کوڈ کو نازک بناتی ہیں: تبدیلی کے لیے تمام مقامات تلاش کرنے پڑتے ہیں، اور ایک نیا ڈویلپر نہیں سمجھ پاتا کہ نمبر کو چھوا جا سکتا ہے یا یہ سسٹم کے کام کرنے کے لیے اہم ہے۔
اہم نکات
جادو سورس کوڈ میں کوئی بھی قدر ہے جس کا مطلب اضافی ڈومین علم کے بغیر واضح نہ ہو۔ یہ اصطلاح کمیونٹی میں قائم ہے: اگر کوئی ڈویلپر کسی نمبر کو دیکھتا ہے اور نہیں بتا سکتا کہ یہ کہاں سے آیا — تو یہ جادو ہے۔
جادو کئی اقسام کا ہوتا ہے: عددی (جادوئی نمبر)، سٹرنگ (جادوئی سٹرنگ)، بولین (جادوئی جھنڈے)، اور ترتیب (ہارڈکوڈڈ پیرامیٹر جو سیٹنگز میں ہونے چاہئیں)۔ چاروں اقسام ایک مسئلہ شیئر کرتی ہیں: جب کوئی ضرورت بدلتی ہے، ڈویلپر کو وہ ہر جگہ تلاش کرنی ہوتی ہے جہاں قدر استعمال ہوئی ہے اور انہیں دستی طور پر بدلنا ہوتا ہے۔ ایک بھی مقام چھوٹنے پر بگ پیدا ہوتا ہے۔
JetBrains کوڈ کوالٹی سروے (2025) کے مطابق، 73 فیصد ڈویلپر جادوئی نمبر کو کم کوڈ کوالٹی کا اشارہ سمجھتے ہیں، جبکہ 41 فیصد تسلیم کرتے ہیں کہ وہ کبھی کبھار انہیں چھوڑ دیتے ہیں۔ بنیادی وجہ جلدی ہے: “میں بعد میں مستقل ڈال دوں گا” — لیکن وہ بعد میں کبھی نہیں آتا، اور ایک ماہ بعد نمبر 0.85 بغیر وضاحت کے طریقہ کار کے وسط میں رہ جاتا ہے۔
اہم قاعدہ: 0، 1، true، false اور خالی سٹرنگ کے علاوہ ہر لفظی قدر کو نامزد مستقل میں نکالنا چاہیے۔ استثناء: کاؤنٹر میں اضافہ (i + 1)، ریاضیاتی صفر (0 کی جانچ)، اور جمع کرنے والوں کی ابتدائی قدریں۔ باقی سب نام رکھنے کے لیے امیدوار ہیں۔
جادوئی نمبر ایک عددی لفظی قدر ہے جس کی قدر سیاق و سباق سے واضح نہیں ہوتی۔ ایک کلاسک مثال: ٹائم آؤٹ سے متعلق کوڈ میں 86400۔ ڈویلپر نمبر دیکھتا ہے اور اندازہ لگانا چاہیے کہ یہ ایک دن میں سیکنڈز کی تعداد ہے۔ اگر وہ غلطی کر کے 84600 لکھتا ہے، تو بگ پکڑنا مشکل ہو گا کیونکہ ٹائم آؤٹ 18 منٹ پہلے فعال ہو جائے گا۔
جادوئی نمبر خطرناک کیوں ہیں: پہلا، وہ پڑھنے کی صلاحیت کو نقصان پہنچاتے ہیں۔ نمبر 1024 کا مطلب کلو بائٹ سائز، صفحہ بندی کی حد، یا اشیاء کی زیادہ سے زیادہ تعداد ہو سکتی ہے۔ سیاق و سباق کے بغیر — یہ صرف ایک نمبر ہے۔ دوسرا، وہ تکرار پیدا کرتے ہیں: اگر 1024 پانچ جگہوں پر استعمال ہوا ہے، تو جب حد بدل کر 2048 ہوتی ہے، ڈویلپر کو پانچوں تلاش کر کے بدلنے ہوتے ہیں۔ اگر ایک جگہ چھوٹ گئی، تو سسٹم غلط طریقے سے کام کرتا ہے لیکن واضح غلطی کے بغیر۔
// before - magic in its pure form
fun calculateTimeout(base: Int): Int {
return base * 3 + 5000
}
// after - values replaced with constants
private const val RETRY_MULTIPLIER = 3
private const val BASE_TIMEOUT_MS = 5000
fun calculateTimeout(base: Int): Int {
return base * RETRY_MULTIPLIER + BASE_TIMEOUT_MS
}
تیسرا خطرہ ہے جانچ کی ناممکنیت۔ اگر حد کی قدر لفظی کے طور پر ہارڈکوڈ ہے، تو جانچ اسے حدی حالات جانچنے کے لیے اوور رائڈ نہیں کر سکتی۔ companion object یا ترتیب فائل میں نکالا گیا مستقل کوڈ کو قابل جانچ بناتا ہے: جانچ ایک مختلف قدر رکھ کر حد پر سسٹم کے رویے کی جانچ کرتی ہے۔
ایک عادت بنائیں: جب بھی آپ 0، 1، 100 یا 2 کے علاوہ کوئی نمبر لکھیں — رکیں اور سوچیں کہ کیا اسے مستقل میں نکالنا چاہیے۔ اگر نمبر کاروباری منطق (حد، دہلیز، ٹائم آؤٹ، سائز) سے متعلق ہے — تو بغیر تردد کے نکالیں۔ اگر نمبر ریاضیاتی مستقل (pi، e) ہے — تو معیاری لائبریری استعمال کریں (Math.PI، Math.E)۔
جادوئی سٹرنگ سٹرنگ لفظی قدریں ہیں جو مستقل یا وسائل میں نکالے بغیر کوڈ میں شامل کی جاتی ہیں۔ عام مثالیں: اینڈ پوائنٹ URL، SharedPreferences کی چابیاں، Intent Actions، bundle چابیاں، فائل کے نام اور SQL سوالیہ۔
جادوئی سٹرنگ کا خطرہ مرتبہ وقت جانچ کی کمی ہے۔ سٹرنگ “user_prefs” میں ٹائپو رن ٹائم تک نہیں پکڑا جائے گا۔ اگر سٹرنگ دس جگہوں پر استعمال ہوتی ہے اور ڈویلپر ان میں سے ایک میں “user_pref” (s کے بغیر) لکھتا ہے — تو ایپ کریش نہیں ہوتی، لیکن ڈیٹا محفوظ نہیں ہوتا۔ ایسا بگ مہینوں پروڈکشن میں رہ سکتا ہے کیونکہ یہ کریش کا سبب نہیں بنتا۔
Android منصوبوں کے لیے، جادوئی سٹرنگ کو وسائل (strings.xml، arrays.xml) یا companion object میں مستقل میں نکالنا چاہیے۔ iOS کے لیے — سٹرنگ وسائل (Localizable.strings) یا enum مستقل میں۔ بیک اینڈ کے لیے — ترتیب فائلوں (.env، application.properties) میں۔ کوئی چابی، URL یا راستہ کوڈ میں سٹرنگ لفظی کے طور پر نہیں دکھنا چاہیے۔
// before - magic strings across the class
let prefs = UserDefaults.standard
prefs.set(token, forKey: "auth_token")
prefs.set(userId, forKey: "current_user_id")
// after - strings extracted to enum
enum PrefKeys: String {
case authToken = "auth_token"
case currentUserId = "current_user_id"
}
prefs.set(token, forKey: PrefKeys.authToken.rawValue)
prefs.set(userId, forKey: PrefKeys.currentUserId.rawValue)
ان سٹرنگ پر خاص توجہ دیں جو دہرائی جاتی ہیں۔ اگر ایک ہی چابی “user_settings” تین فائلوں میں نظر آتی ہے — 99 فیصد امکان ہے کہ آخرکار ان میں سے ایک میں ٹائپو ہو گا۔ enum یا مستقل میں نکالنا ضمانت دیتا ہے کہ تمام حوالہ جات ایک ہی قدر استعمال کریں۔
جادوئی جھنڈے بولین پیرامیٹر ہیں جن کا مطلب کال سیاق و سباق سے واضح نہیں ہوتا۔ ایک کلاسک اینٹی پیٹرن: بغیر وضاحت کے کسی طریقہ کار میں true یا false بھیجنا کہ یہ جھنڈا اصل میں کیا فعال یا غیر فعال کرتا ہے۔
مثال: userDao.fetch(includeDeleted = false)۔ ڈویلپر false دیکھتا ہے اور نہیں بتا سکتا کہ اس کا مطلب “حذف شدہ شامل نہ کریں” ہے یا “فعال شامل نہ کریں”۔ ایک ماہ بعد، false true میں بدل جاتا ہے، اور آؤٹ پٹ میں حذف شدہ ریکارڈ ظاہر ہونے لگتے ہیں۔ بگ صرف پروڈکشن میں دریافت ہوتا ہے۔
حل ہے بولین جھنڈوں کو enum یا sealed کلاس سے بدلنا۔ Boolean پیرامیٹر کی بجائے، UserFilter.includeDeleted یا UserFilter.activeOnly استعمال کریں۔ اس طرح کوڈ اپنی نیت کو دستاویز کرتا ہے، اور IDE خودکار تکمیل کے دوران دستیاب اختیارات تجویز کرتا ہے۔
اگر بولین جھنڈا کئی تہوں سے گزرتا ہے — تو یہ ایک اور اشارہ ہے کہ تجرید غلط ہے۔ تین سطحوں کی کالوں کے ذریعے جھنڈا گھسیٹنے کی بجائے، سوچیں کہ کیا فلٹر کا انتخاب اوپری سطح پر کیا جانا چاہیے اور تیار ترتیب کے طور پر بھیجا جانا چاہیے۔ کوڈ میں جتنے کم بولین جھنڈے ہوں گے — اتنا کم جادو۔
ایک قاعدہ اپنائیں: کوئی بولین پیرامیٹر بغیر نامزد دلیل کے طریقہ کار میں نہیں بھیجا جاتا (اگر زبان نامزد دلائل کو سپورٹ کرتی ہے)۔ Kotlin اور Swift میں، یہ ضرورت خود بخود پوری ہوتی ہے۔ Java میں، true/false کی بجائے Builder یا enum مستقل استعمال کریں۔
جادوئی اقدار کی تلاش جامد تجزیہ کاروں کے ذریعے خودکار ہوتی ہے جو غیر متوقع مقامات پر لفظی اقدار کا پتہ لگانے کے لیے ترتیب دیئے جاتے ہیں۔ ہر زبان حسب ضرورت استثناؤں کے ساتھ اپنے اوزار فراہم کرتی ہے۔
| اوزار | زبانیں | قاعدہ |
|---|---|---|
| SonarQube | Java، Kotlin، Swift، Python، JS | MagicNumber، HardcodedString |
| ESLint | JavaScript، TypeScript | no-magic-numbers، no-hardcoded-strings |
| Detekt | Kotlin | MagicNumber، ComplexCondition |
| SwiftLint | Swift | magic_number (opt-in) |
| PMD | Java، Apex، PLSQL | MagicNumber (قابل ترتیب اجازت یافتہ فہرست) |
| PhpStorm معائنہ | PHP | NumericLiteralWithContext (بلٹ ان معائنہ) |
استثناؤں کی ترتیب بہت اہم ہے — اس کے بغیر، تجزیہ کار ہر اضافہ (-1، +1) اور ریاضیاتی صفر پر نشان لگائے گا۔ SonarQube کے لیے، اجازت یافتہ نمبروں کی فہرست: 0، 1، -1، 2 (دگنا کرنے کے لیے)، 100 (فیصد)، 60 اور 24 (وقت)۔ دیگر تمام اقدار کے لیے — public static final (Java) یا const val (Kotlin) modifier کے ساتھ نامزد مستقل کی ضرورت ہے۔
CI سطح کے تجزیہ کے لیے، انتباہ کے طور پر جادو کی جانچ کرنے والا مرحلہ شامل کریں لیکن تعمیر کو مسدود نہ کریں۔ پہلی رن پرانی کوڈ میں سینکڑوں انتباہ دکھائے گی۔ آہستہ آہستہ، ٹکٹ بہ ٹکٹ، کوڈ کو مستقل میں منتقل کریں اور معیار کی حد بڑھائیں۔ جب جادوئی نمبروں کی تعداد 10 سے کم ہو جائے — تو قاعدہ کو تعمیر کی غلطی کے طور پر فعال کریں۔
جادو کی ریفیکٹرنگ سب سے محفوظ کارروائیوں میں سے ایک ہے: لفظی کو مستقل سے بدلنے سے کوڈ کا رویہ نہیں بدلتا۔ پھر بھی، نقطہ نظر منظم ہونا چاہیے تاکہ پوشیدہ انحصار چھوٹ نہ جائیں (مثال کے طور پر، اگر ایک ہی جادوئی نمبر غیر متعلقہ سیاق و سباق میں استعمال ہوتا ہے لیکن اتفاقاً قدر ایک جیسی ہے)۔
مرحلہ وار عمل: جادوئی قدر کی تمام موجودگیاں تلاش کریں، ہر ایک کا سیاق و سباق سمجھیں، مختلف مستقل میں تقسیم کریں (چاہے قدریں مماثل ہوں — سیاق و سباق مختلف ہیں، اور مستقل کے مختلف نام ہونے چاہئیں)، لفظی کو مستقل سے بدلیں، جانچ کے ذریعے تصدیق کریں۔ مرحلہ 2 میں غلطی سب سے عام ہے: دو مختلف تصورات (ملی سیکنڈ میں ٹائم آؤٹ اور بائٹ میں حد) عددی طور پر مماثل ہو سکتے ہیں (مثال کے طور پر، 5000)، لیکن معنوی طور پر یہ مختلف مقداریں ہیں اور انہیں ایک مستقل میں یکجا نہیں کیا جا سکتا۔
// before - same number in different contexts
public class Config {
public void setupCache() {
cache.setMaxSize(5000); // 5 MB
}
public void setupTimeout() {
client.setReadTimeout(5000); // 5 seconds
}
}
// after - different constants for different contexts
public class Config {
private static final int CACHE_MAX_SIZE_MB = 5;
private static final int READ_TIMEOUT_SECONDS = 5;
public void setupCache() {
cache.setMaxSize(CACHE_MAX_SIZE_MB * 1024 * 1024);
}
public void setupTimeout() {
client.setReadTimeout(
READ_TIMEOUT_SECONDS * 1000
);
}
}
نئے کوڈ کے لیے، قاعدہ آسان ہے: 0، 1، -1، true، false، null اور خالی سٹرنگ کے علاوہ کوئی بھی لفظی مستقل میں نکالا جاتا ہے۔ استثناء: ریاضیاتی مستقل (ہمیشہ معیاری لائبریری استعمال کریں)، جانچ کا ڈیٹا (لفظی جانچ میں رہ سکتے ہیں لیکن وضاحتی متغیر نام کے ساتھ)، اور اضافے کے لیے حدی قدریں (لوپ میں i + 1 ٹھیک ہے)۔
اکثر پوچھے گئے سوالات
ہاں، 100 بھی جادوئی نمبر ہے اگر بغیر سیاق و سباق کے استعمال کیا جائے۔ 100 کی بجائے، MAX_PERCENT یا PROBABILITY_SCALE لکھیں۔ استثناء: جب 100 سیاق و سباق میں واضح طور پر فیصد ہو (مثال کے طور پر، فیصد حساب کے فارمولے میں)، لیکن اس صورت میں بھی مستقل پڑھنے کی اہلیت کو بہتر بناتا ہے۔
جانچ میں بھی نامزد متغیر استعمال کرنا بہتر ہے۔ assertEquals(42, result) کی بجائے، val expected = 42; assertEquals(expected, result) لکھیں۔ استثناء: حدی قدروں کی جانچ (0، null، خالی سٹرنگ) — انہیں لفظی کے طور پر چھوڑا جا سکتا ہے کیونکہ وہ جانچ کے سیاق و سباق میں پڑھنے کے قابل ہیں۔
ہاں، UI سے متعلق نمبر (سائز، حاشیہ، حرکت پذیری کی مدت) وسائل (dimens.xml، integers.xml) میں ہونے چاہئیں۔ کاروباری مستقل (ٹائم آؤٹ، حدود) — companion object یا ترتیب فائل میں۔ اہم معیار: اگر کوئی نمبر منطق کو بدلے بغیر بدل سکتا ہے — تو یہ ایک وسیلہ ہے۔
MagicNumber قاعدہ کے ساتھ SonarQube یا no-magic-numbers کے ساتھ ESLint چلائیں۔ رپورٹ حاصل کریں، استعمال کی تعدد کے مطابق ترتیب دیں، اور ان نمبروں سے شروع کریں جو تین یا زیادہ جگہوں پر ظاہر ہوتے ہیں۔ وہ مستقل میں نکالنے کے لیے سب سے زیادہ ممکنہ امیدوار ہیں۔
نہیں۔ قابل قبول لفظی: 0، 1، -1 (اضافہ/کمی، خالی جانچ)، true، false، null، خالی سٹرنگ۔ باقی سب کو نام رکھنے کی ضرورت ہے۔ اگر نمبر 0 خالی جانچ کے طور پر استعمال نہیں ہوا (مثال کے طور پر، 0 جڑ کے زمرے کا ID ہے)، تو 0 بھی مستقل ہونا چاہیے: ROOT_CATEGORY_ID = 0۔
خلاصہ
ہم ایک موبائل ایپلیکیشن ٹرنکی تیار کریں گے
IT Sectr 2017 سے اسٹارٹ اپس اور کاروبار کے لیے iOS اور Android ایپلیکیشنز بناتا ہے۔ ہم آپ کو مشورہ دیں گے اور بہترین حل تجویز کریں گے۔
مزید پڑھیں