«تثبيت بالمسامير» و«الترميز الثابت» هما مصطلحان عاميان يعنيان التثبيت الصارم للقيم مباشرة في كود البرنامج، بدلاً من نقلها إلى الإعدادات أو التهيئة. الترميز الثابت هو أحد أشهر الأنماط المعاكسة في التطوير لأنه يقلل من مرونة الكود وإمكانية إعادة استخدامه. وفقاً لـ Refactoring Guru، فإن الترميز الثابت يعقد الاختبار والصيانة وتكيف التطبيق مع البيئات المختلفة. الاستخدام الواعي للثوابت بدلاً من الترميز الثابت هو علامة على معمارية ناضجة.
الخلاصة
الترميز الثابت (تثبيت بالمسامير) — تضمين قيمة محددة في كود البرنامج بحيث يتطلب تغييرها تعديل الكود المصدري وإعادة ترجمة التطبيق. استعارة «تثبيت بالمسامير» تعكس الجوهر بدقة: القيمة مثبتة بشكل دائم، ولا يمكن فصلها عن الكود إلا بجهد.
مثال على الترميز الثابت — عنوان URL لخادم مكتوب كسلسلة نصية مباشرة في جسم دالة. إذا انتقل الخادم إلى عنوان آخر، يحتاج المطور إلى البحث عن السلسلة في الكود، تغييرها، إعادة بناء التطبيق، وإصدار نسخة جديدة. في تطبيق ذي معمارية صحيحة، سيكون عنوان URL هذا موجوداً في ملف تهيئة، أو متغير بيئة، أو خدمة تهيئة.
مصطلح «تثبيت بالمسامير» أكثر شحنة عاطفية: فهو يؤكد أن القيمة مُدرجة بشكل دائم دون إمكانية استبدال سريع. في البيئة الناطقة بالروسية، يُستخدم كلا التعبيرين كـ مرادفين كاملين بدلالة سلبية. أحياناً يُسمى الترميز الثابت بسخرية «ثابت مستخرج في ثابت منفصل من ثابت».
الترميز الثابت هو نمط معاكس لأنه ينتهك مبادئ قابلية الصيانة والاختبار والتوسع. في الكود حيث القيم «مثبتة بالمسامير»، أي تغيير في البيئة أو التصميم أو المنطق يتطلب بحثاً يدوياً واستبدالاً في الكود المصدري. هذا يزيد من خطر الأخطاء ويبطئ التطوير.
دعنا نفحص العواقب المحددة للترميز الثابت باستخدام تطبيق جوال نموذجي كمثال. إذا كان هامش كل الأزرار محدداً كرقم في الكود بدلاً من مورد، فإن تغيير التصميم يتطلب البحث عن كل الحالات واستبدالها. إذا كان عنوان URL للنقطة الطرفية مثبتاً بشكل ثابت، فإن التبديل بين البيئات (dev، stage، prod) مستحيل دون إعادة بناء.
| العاقبة | الوصف | مستوى الأهمية |
|---|---|---|
| صعوبة الصيانة | التغيير يتطلب بحثاً في كل الكود | عالٍ |
| أخطاء النسخ | لا يتم العثور على كل الحالات واستبدالها | عالٍ |
| استحالة الاختبار | لا يمكن استبدال بيانات الاختبار | متوسط |
| مشاكل التعريب | النصوص في الكود لا تترجم | متوسط |
| تعقيد مراجعة الكود | المراجع يجب أن يتذكر كل السياقات | منخفض |
دالة تستخدم أرقاماً سحرية وسلاسل نصية مثبتة بشكل ثابت — مثال كلاسيكي على الترميز الثابت. بعد شهر، لن يتذكر المؤلف ما تعنيه 18 و0.07 و2.5. بعد عام، لن يجرؤ أحد في الفريق على تغيير هذه الأرقام خوفاً من كسر المنطق. استخراج القيم إلى ثوابت مسماة يجعل الكود موثقاً ذاتياً.
// Bad: magic numbers and strings
fun calculatePrice(base: Double): Double {
val tax = base * 0.07
val tip = base * 0.15
val discount = if (base > 100) 10 else 0
return base + tax + tip - discount
}
عنوان URL مثبت بشكل ثابت لقاعدة البيانات لن يسمح بتشغيل الاختبارات على قاعدة بيانات محلية في الذاكرة. سيضطر المطور إلى تشغيل خادم كامل أو تعديل الكود قبل الاختبار. نقل التهيئة خارج الكود يحل المشكلة: الاختبارات تستخدم معاملات اختبار، والإنتاج يستخدم المعاملات الحقيقية، والكود لا يتغير.
الترميز الثابت نمط معاكس، لكن توجد استثناءات مشروعة حيث تكون القيمة المثبتة بشكل ثابت مقبولة بل ومفضلة. الحد يمر عبر محور قابلية التغيير: إذا كانت القيمة لا تتغير أبداً أو نادراً ضمن دورة حياة التطبيق، يمكن تثبيتها. إذا كان من الممكن أن تتغير، فانقلها إلى التهيئة.
الثوابت الرياضية والفيزيائية — باي، تسارع الجاذبية، عدد الميلي ثانية في الثانية — آمنة للترميز الثابت. هي محددة بالطبيعة أو المعايير ولن تتغير. أحجام المصفوفات الثابتة المحددة بالمواصفات يمكن تثبيتها أيضاً، ولكن مع تعليق حول أصل الرقم.
عدد الميلي ثانية في الثانية هو ثابت مستقر محدد بمعيار الوقت. لا معنى لنقله إلى ملف تهيئة لأنه لن يتغير أبداً. ولكن حتى هذه الثوابت من الأفضل تعريفها باسم واضح حتى لا يحتوي الكود على «أرقام سحرية»: بدلاً من 1000، اكتب MILLISECONDS_IN_SECOND.
// Justified hardcode: stable constants
private const val MILLIS_IN_SECOND = 1000
private const val LOGIN_TIMEOUT_SECONDS = 30
fun formatDuration(ms: Long): String {
val seconds = ms / MILLIS_IN_SECOND
return "${seconds} sec."
}
توجد عدة طرق مجربة لتجنب الترميز الثابت، كل منها مناسب لنوعه من القيم. يعتمد اختيار البديل على مدى تكرار تغيير القيمة ومن يغيرها: المطور، أو مدير العمليات، أو المستخدم النهائي.
لعناوين URL للخوادم، مفاتيح API، وأعلام الميزات، استخدم ملفات التهيئة بتنسيقات JSON أو YAML أو TOML. في Android، يشمل ذلك build.gradle مع buildConfigField أو res/values/config.xml. في iOS، Info.plist أو xcconfig. يتم تضمين ملفات التهيئة مع التطبيق لكنها قد تختلف باختلاف أنماط البناء.
للمعلومات السرية (الرموز، كلمات المرور) ومعاملات البيئة، استخدم متغيرات البيئة. هي لا تصل إلى المستودع ويمكن أن تختلف على خوادم dev وstage وprod. في تطوير التطبيقات الجوالة، غالباً ما تُحاكى متغيرات البيئة عبر أنماط بناء Xcode أو build flavors في Gradle.
النصوص، الألوان، الأحجام، والصور يجب وضعها في ملفات الموارد: strings.xml في Android، Localizable.strings في iOS، ملفات ARB في Flutter. هذا يبسط التعريب، التكيف مع الشاشات المختلفة، والوضع الداكن. تغيير نص في الموارد لا يتطلب إعادة كتابة الكود.
<!-- Android: res/values/strings.xml -->
<resources>
<string name="app_name">MyApp</string>
<string name="api_base_url">https://api.example.com</string>
</resources>
للخدمات والموفرين، استخدم حقن التبعيات عبر Dagger أو Hilt أو Koin في Android، وSwinject في iOS. أطر عمل DI تسمح بتبديل التطبيقات أثناء التشغيل — للاختبارات، للبيئات المختلفة، للمستخدمين المختلفين. هذا هو أعلى مستوى من التجريد، حيث يتم استبدال «تثبيت» القيمة بحقن خارجي.
إعادة هيكلة الترميز الثابت هي عملية استخراج القيم المثبتة بشكل ثابت إلى تهيئة أو موارد. إنها واحدة من أكثر عمليات إعادة الهيكلة أماناً إذا نُفذت بشكل منهجي. التسلسل التالي يناسب أي لغة ومنصة.
يمكن إجراء البحث عبر بيئة التطوير (بحث في المشروع) أو بنص برمجي. ابحث عن السلاسل النصية، عناوين URL، القيم الرقمية، الأحجام، والمهل الزمنية. انتبه بشكل خاص للقيم المكررة: إذا ظهر نفس الرقم في خمسة أماكن، فهو مرشح للاستخراج إلى ثابت. استخدم grep أو البحث المدمج في IDEA / Xcode.
لكل قيمة تم العثور عليها، أنشئ ثابتاً باسم ذي معنى. جَمّع الثوابت حسب الوحدات أو الفئات. يجب أن يشرح الاسم ما تعنيه القيمة، وليس كيف تُستخدم: API_TIMEOUT، وليس TIMEOUT_30. بعد الاستبدال، لا يجب أن يبقى أي رقم في الكود دون شرح.
// Before: magic number 0.4
let cardHeight = screenHeight * 0.4
// After: named constant
private let cardHeightRatio: CGFloat = 0.4
let cardHeight = screenHeight * cardHeightRatio
إذا كانت القيمة يمكن أن تتغير بين مرات البناء أو البيئات، انقلها إلى ملف تهيئة أو موارد التطبيق. للنصوص، استخدم ملفات التعريب. لعناوين URL، استخدم build config أو xcconfig. للأبعاد، استخدم ملفات الموارد (dimens.xml في Android). تحقق من أن التطبيق يبني ويعمل بشكل صحيح بعد الاستخراج.
بعد إعادة الهيكلة، اكتب اختباراً يتحقق من أن التهيئة تُحمّل بشكل صحيح وأن القيم تتوافق مع المتوقع. إذا غيّر شخص ما ملف التهيئة في المستقبل، سيشير الاختبار إلى التناقض. اختبار التهيئة هو طريقة سريعة وموثوقة لمنع الانتكاس.
بعد النقل إلى التهيئة، تحقق من أن كل الأماكن التي استخدمت القيمة القديمة تشير الآن إلى مصدر واحد. أزل الكود المُعلق والثوابت القديمة التي لم تعد مستخدمة. أنهِ إعادة الهيكلة بإيداع مع رسالة تصف أي القيم تم نقلها وإلى أين.
الأسئلة الشائعة
الترميز الثابت — كتابة قيمة بشكل صارم في الكود المصدري بدلاً من وضعها في التهيئة أو الموارد. هذا يجعل الكود أقل مرونة وأكثر صعوبة في الصيانة.
الترميز الثابت يعقد تغيير سلوك التطبيق، يعيق الاختبار، يخلق تكراراً، ويزيد من خطر أخطاء النسخ. تغيير قيمة مثبتة بشكل ثابت يتطلب إعادة بناء وإعادة إصدار التطبيق.
مقبول للثوابت الرياضية، القيم المستقرة التي لا تتغير خلال دورة حياة التطبيق، والنماذج الأولية المؤقتة. في الإنتاج، حتى الثوابت يجب استخراجها في متغيرات مسماة.
ابحث عن كل الأرقام السحرية باستخدام البحث، استبدلها بـ ثوابت مسماة أو انقلها إلى ملف تهيئة. اكتب اختباراً يتحقق من تحميل التهيئة. أزل المكررات وأجرِ إيداعاً مع وصف التغييرات.
الثابت هو قيمة مسماة في الكود يمكن تغييرها في مكان واحد. الترميز الثابت هو قيم غير مسماة منتشرة في الكود. الممارسة الجيدة: استخدم دائماً ثوابت مسماة بأسماء ذات معنى.
الخلاصة
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.