ترويض الكود المتمرد: أعلام الميزات في مشاريع Kotlin

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

مقدمة: لماذا تفسد الميزات الإصدارات؟

\n

كل مطور واجه مرة على الأقل موقفًا تكون فيه وظيفة جديدة رائعة جاهزة، لكن لا يمكن إصدارها. إما أنها لم تجتاز اختبار ضمان الجودة الكامل، أو لم يقم فريق التسويق بعد بإعداد اللافتات، أو ببساطة الخوف من الضغط على زر "نشر" مساء الجمعة. في هذه اللحظة، نبدأ عادةً بكتابة if، أو تبديل BuildConfig، أو الأسوأ من ذلك، التعليق على الكود.

\n

هل هذا مألوف؟ مرحبًا بك في عالم أعلام الميزات (أو مفاتيح الميزات). إنها ليست مجرد "شيء معماري آخر". إنها طوق النجاة الخاص بك الذي يسمح لك بنشر الكود في بيئة الإنتاج، ولكن تفعيله فقط للمختارين. في هذه المقالة، سنشرح كيفية تنفيذ أعلام الميزات في مشاريع Kotlin - من الحلول البسيطة إلى الأنظمة المتقدمة. ونعم، سيكون هناك الكثير من الكود.

\n\n

ما هو علم الميزة ولماذا تحتاجه؟

\n

علم الميزة (المعروف أيضًا بمفتاح الميزة) هو مفتاح تبديل برمجي يسمح لك بتشغيل أو إيقاف تشغيل وظيفة ما دون تغيير الكود أو إعادة النشر. تخيل أنه يمكنك تحميل خوارزمية توصيات جديدة إلى بيئة الإنتاج، ولكن جعلها نشطة فقط لـ 5% من المستخدمين. أو تشغيلها فقط لموظفي الشركة للاختبار الداخلي. رائع، أليس كذلك؟

\n

إليك بعض السيناريوهات التي لا غنى فيها عن أعلام الميزات:

\n
    \n
  • الإصدارات التجريبية (Canary releases): نشر ميزة جديدة على 1% من الخوادم، مراقبة الأخطاء وزيادة النسبة تدريجيًا.
  • \n
  • اختبار A/B: التحقق من أي إصدار من واجهة المستخدم يحقق تحويلًا أفضل، دون نسخ المشروع بأكمله.
  • \n
  • مفتاح الإيقاف (Kill switch): إذا بدأت الميزة الجديدة في استهلاك الذاكرة أو تسببت في خطأ، يمكنك ببساطة إيقاف تشغيلها بحركة واحدة (أو طلب API).
  • \n
  • فصل الإصدار عن النشر: الكود منشور، لكن الميزة "نائمة" حتى تاريخ X.
  • \n
\n

في Kotlin، الذي يُستخدم بنشاط لكل من الواجهة الخلفية (Ktor, Spring Boot) وتطبيقات الهاتف المحمول (Android)، تصبح أعلام الميزات ذات صلة خاصة بسبب الكتابة الصارمة ومتطلبات نقاء الكود.

\n\n

الهندسة المعمارية: كيف لا تحول الأعلام إلى معكرونة (سباغيتي)

\n

أكبر خطأ يرتكبه المبتدئون هو نثر if (flag.isEnabled()) { ... } else { ... } في جميع أنحاء المشروع. يؤدي هذا إلى عدم القدرة بعد شهر على فهم أي فروع الكود حية وأيها ميتة. نحتاج إلى إدارة الميزات، وليس مفاتيح تبديل عشوائية.

\n

تعتمد الهندسة المعمارية الجيدة على مبدأ عكس التبعيات. يجب ألا يعرف كود عملك من أين تأتي قيمة العلم (من ملف، قاعدة بيانات، أو خدمة خارجية). إنه يسأل ببساطة: "مرحبًا، FeatureFlagService، هل الميزة new_checkout مفعلة؟"

\n

لننظر في نهجين: بسيط (للمشاريع الصغيرة) ومتقدم (للخدمات المصغرة و Kubernetes).

\n\n

1. النهج البسيط: التكوين و Enum

\n

إذا كنت بحاجة إلى البدء بسرعة ولا تقوم ببناء نظام بملايين الطلبات في الثانية، يمكنك الاكتفاء بـ enum class بسيط وملف تكوين (مثل application.conf لـ Ktor أو application.yml لـ Spring).

\n

لننشئ enum لجميع الميزات:

\n
enum class Feature(val key: String) {\n    NEW_PAYMENT_FLOW("feature.new-payment-flow"),\n    DARK_MODE("feature.dark-mode"),\n    SMART_SEARCH("feature.smart-search")\n}
\n

الآن الخدمة التي تقرأ التكوين:

\n
class FeatureFlagService(private val config: Map<String, Boolean>) {\n\n    fun isEnabled(feature: Feature): Boolean {\n        return config.getOrDefault(feature.key, false)\n    }\n\n    // لاختبارات A/B يمكن إضافة التوزيع العشوائي\n    fun isEnabledForUser(feature: Feature, userId: String): Boolean {\n        if (!isEnabled(feature)) return false\n        // تجزئة بسيطة للتقسيم إلى مجموعات\n        val group = userId.hashCode() % 100\n        return group < 50 // 50% من المستخدمين                

المدونات

توصيات الكتب