أعلام الميزات في Swift: كيفية تشغيل الميزات بدون بناء جديد ودون كسر الإنتاج
تخيل: لقد أطلقت سمة داكنة جديدة، والمستخدمون يكتبون أن النص أصبح غير قابل للقراءة. أو أضفت خوارزمية توصيات معقدة تعمل ببطء على أجهزة iPhone القديمة. في السيناريو التقليدي، تقوم بتعديل الكود، وبناء الإصدار، واجتياز المراجعة، وانتظار متجر التطبيقات - يوم أو أكثر. كل هذا الوقت، الخلل يعيش في الإنتاج.
أعلام الميزات (أو مفاتيح التبديل للميزات) هي تقنية تسمح لك بتشغيل وإيقاف وظائف التطبيق دون نشر كود جديد. في جوهرها، هي عبارات شرطية تتحقق من قيمة العلم، ويتم تخزين القيمة عن بُعد - على الخادم أو في التكوين عن بُعد. مفتاح واحد - وتظهر الميزة للجميع أو تختفي في ثوانٍ.
في هذه المقالة، سنناقش كيفية دمج أعلام الميزات في Swift، وما هي الأنماط التي يجب استخدامها، وكيف لا تطلق النار على قدمك. هيا بنا!
لماذا نحتاج أعلام الميزات في تطوير iOS
يعتقد الكثيرون أن أعلام الميزات مخصصة فقط لاختبارات A/B. في الواقع، هناك سيناريوهات أكثر بكثير:
- الإصدارات التجريبية (canary releases) - تقوم بتشغيل ميزة جديدة لـ 5% من المستخدمين، وتراقب الأعطال، وإذا كان كل شيء على ما يرام - تنشرها للجميع.
- مفاتيح القتل (kill switches) - إذا حدث خطأ ما، يمكنك ببساطة إيقاف الوظيفة عن بُعد دون التراجع عن الإصدار.
- الطرح التدريجي - تظهر الميزة أولاً لنظام iOS 17+، ثم للإصدارات الأقدم.
- الميزات المدفوعة - تخفي الوظائف المميزة خلف اشتراك، وتدير الأعلام على الخادم الخلفي.
- التجارب واختبارات A/B - تختبر الفرضيات على مستخدمين حقيقيين دون إنشاء فروع منفصلة.
هذا مهم بشكل خاص لمشاريع Swift، حيث يتم بناء الملف الثنائي مرة واحدة ثم يبقى في المتجر. بدون أعلام الميزات، لن تتمكن من الاستجابة بسرعة للمشاكل - فقط من خلال إصدار جديد.
هندسة أعلام الميزات في Swift
التنفيذ البسيط هو قاموس [String: Bool] يأتي من الخادم. ولكن في مشروع إنتاجي، من الأفضل إنشاء تجريد مناسب. إليك المكونات الرئيسية:
- FeatureFlagProvider - مصدر البيانات (التكوين عن بُعد، واجهة برمجة التطبيقات الخاصة بك، ملف محلي).
- FeatureFlagManager - كائن مفرد أو خدمة تخزن الأعلام مؤقتًا وتقدمها للعروض.
- FeatureFlagKey - تعداد بمفاتيح محددة النوع لتجنب نشر السلاسل النصية في الكود.
دعنا نكتب تنفيذًا بسيطًا ولكنه عملي بلغة Swift.
الخطوة 1: تعريف تعداد بالمفاتيح
enum FeatureFlagKey: String, CaseIterable { case darkMode = "dark_mode" case newOnboarding = "new_onboarding" case premiumAnalytics = "premium_analytics" case experimentalFeed = "experimental_feed"}استخدام التعداد بدلاً من السلاسل النصية يضمن عدم حدوث أخطاء إملائية في اسم العلم. CaseIterable سيكون مفيدًا لشاشة التصحيح.
الخطوة 2: المزود - الحصول على الأعلام من Firebase Remote Config
import FirebaseRemoteConfig
final class RemoteConfigProvider: FeatureFlagProvider { private let remoteConfig = RemoteConfig.remoteConfig() func fetchFlags(completion: @escaping ([String: Bool]) -> Void) { remoteConfig.fetch(withExpirationDuration: 3600) { status, error in if status == .success { self.remoteConfig.activate { _, _ in let flags = FeatureFlagKey.allCases.reduce(into: [String: Bool]()) { result, key in result[key.rawValue] = self.remoteConfig.configValue(forKey: key.rawValue).boolValue } completion(flags) } } else { print("Failed to fetch remote config: \\(error?.localizedDescription ?? "")")