أعلام الميزات ليست أداة التحكم الوحيدة في الإصدار التي تحتاجها
فريق عمل معه ذات مرة أمضى ثلاثة أشهر في بناء تدفق دفع جديد. كان الكود مكتملاً، وتم اختباره في بيئة التدريج (staging)، ودمج في الفرع الرئيسي خلف علم ميزة (feature flag). عندما قاموا أخيرًا بتشغيل العلم لـ 5% من المستخدمين، أعاد مزود الدفع أخطاءً لم يروها من قبل في بيئة التدريج. سمح لهم العلم بإيقاف التشغيل في ثوانٍ. لكن السؤال الحقيقي كان: هل كان يجب أن يكون هذا الكود في الإنتاج أساسًا؟
أعلام الميزات قوية. إنها تسمح لك بنشر كود غير نشط بعد، واختباره في الإنتاج مع حركة مرور حقيقية، وطرح التغييرات تدريجيًا. لكنها ليست حلاً شاملاً. أحيانًا يكون الفرع (branch) أفضل. وأحيانًا تكون البيئة المنفصلة أكثر منطقية. وأحيانًا تحتاج إلى الثلاثة معًا.
السؤال الأول الذي يجب الإجابة عليه هو: ما الذي تحاول تحقيقه بالفعل من خلال تأخير أو تقييد الوصول إلى ميزة جديدة؟
متى تستخدم الفرع
الفروع موجودة لعزل العمل قيد التطوير. إذا كانت الميزة غير مكتملة ولا يمكن تشغيلها دون كسر التطبيق، أبقها في فرع. يبقى الكود خارج الفرع الرئيسي تمامًا. لا أحد ينشره عن طريق الخطأ. ولا أحد يضطر إلى تذكر وجود علم.
هذا هو أبسط أشكال التحكم. يعمل جيدًا للميزات التي لا تزال قيد البناء، خاصة عندما يعمل عدة مطورين على أجزاء مختلفة. يبقى الفرع الرئيسي نظيفًا. يدمج الفريق فقط عندما تكون الميزة مكتملة ومراجعة.
لكن للفروع حدود. بمجرد دمج الكود، تفقد القدرة على التحكم في تفعيله. الميزة إما في الفرع الرئيسي أو لا. لا يوجد حل وسط. وهنا يأتي دور أعلام الميزات.
متى تستخدم علم الميزة
تتحكم أعلام الميزات في السلوك بعد دمج الكود. الكود موجود في الفرع الرئيسي، ومنشور في الإنتاج، لكنه غير نشط لجميع المستخدمين. يمكنك تشغيله لنسبة صغيرة، أو للمختبرين الداخليين، أو لظروف محددة.
هذا مفيد عندما تكون الميزة مكتملة وظيفيًا ولكنك لست مستعدًا لكشفها للجميع. ربما تريد التحقق من الاستقرار تحت حركة مرور حقيقية. ربما تحتاج إلى مراقبة معدلات الأخطاء قبل الطرح الكامل. ربما تريد زيادة التعرض تدريجيًا على مدى عدة أيام.
تساعد أعلام الميزات أيضًا في التراجع. إذا حدث خطأ ما، تقوم بإيقاف العلم بدلاً من التراجع عن النشر. هذا أسرع وأكثر أمانًا من التراجع عن الكود، خاصة عندما يتضمن النشر ترحيلات قاعدة بيانات أو تغييرات أخرى لا رجعة فيها.
لكن أعلام الميزات ليست مجانية. إنها تزيد من تعقيد قاعدة الكود. كل علم هو فرع if-else يجب صيانته واختباره وإزالته في النهاية. كثرة الأعلام التي تبقى لفترة طويلة تخلق ديونًا تقنية. الفرق التي تتراكم لديها مئات الأعلام القديمة ينتهي بها الأمر بكود يصعب قراءته ويصعب تصحيح أخطائه.
متى تستخدم بيئة منفصلة
تمنحك بيئة التدريج (staging) مكانًا للاختبار قبل الإنتاج. إنها معزولة عن المستخدمين الحقيقيين. يمكنك تشغيل اختبارات التكامل، وضمان الجودة اليدوي، والاختبار الاستكشافي دون التأثير على أي شخص.
المشكلة هي أن بيئة التدريج ليست مطابقة للإنتاج أبدًا. أنماط حركة المرور مختلفة. أحجام البيانات أصغر. لا يمكن تكرار سلوك المستخدم الحقيقي. بعض المشكلات تظهر فقط تحت حمل الإنتاج، مع بيانات الإنتاج، أو مع تكوين البنية التحتية الدقيق الذي لا تملكه بيئة التدريج.
لهذا السبب تكمل أعلام الميزات والبيئات بعضها البعض. استخدم بيئة التدريج للاختبار المبكر. استخدم أعلام الميزات للتحقق في الإنتاج. إنها ليست بدائل. إنها طبقتان من الأمان.
ميزة كبيرة تغير تدفقًا أساسيًا - مثل استبدال نظام دفع أو إعادة تصميم صفحة تسجيل الدخول - يجب أن تمر عبر بيئة التدريج أولاً. بمجرد أن تنجح هناك، يمكنك نشرها خلف علم في الإنتاج وزيادة التعرض تدريجيًا.
الجمع بين الفرع والبيئة والعلم
عمليًا، تستخدم العديد من الفرق الثلاثة معًا. إليك نمط شائع:
- العمل على ميزة كبيرة في فرع منفصل.
- دمج الفرع في الفرع الرئيسي مع إيقاف تشغيل العلم.
- النشر إلى بيئة التدريج، واختبار الميزة عن طريق تمكين العلم في بيئة التدريج.
- النشر إلى الإنتاج مع بقاء العلم متوقفًا.
- تمكين العلم للمستخدمين الداخليين أو نسبة صغيرة.
- زيادة النسبة تدريجيًا بناءً على المراقبة.
- إزالة العلم بمجرد طرح الميزة بالكامل واستقرارها.
هذا النمط شائع في الفرق التي تتبع التطوير القائم على الفرع الرئيسي (trunk-based development). الفرع الرئيسي دائمًا قابل للنشر. يتم تقسيم الميزات الكبيرة إلى أجزاء أصغر، كل جزء يتحكم به علم. يدمج الفريق بشكل متكرر، وينشر كثيرًا، ويستخدم الأعلام للتحكم فيما يراه المستخدمون.
متى تكون أعلام الميزات الخيار الخاطئ
أعلام الميزات ليست دائمًا أفضل أداة. ضع في اعتبارك هذه المواقف:
- الميزة غير قابلة للتشغيل. إذا كان الكود لا يترجم، أو يفشل في الاختبارات، أو يتعطل عند بدء التشغيل، لا تدمجه. أبقِه في فرع حتى يعمل.
- التغيير كبير جدًا بحيث لا يمكن التحكم به بعلم واحد. علم يقوم بتبديل نظام فرعي بأكمله يصعب اختباره ومخاطرة في تشغيله. قسم الميزة إلى أجزاء أصغر، لكل منها علمها الخاص، أو استخدم بيئة للتحقق الأولي.
- يستخدم الفريق الأعلام لتجنب القرارات. إذا كان العلم موجودًا لأنه لا أحد يريد أن يقرر ما إذا كانت الميزة جاهزة، فهذه مشكلة عملية، وليست مشكلة أداة. يجب أن تمكن الأعلام من الحصول على ردود فعل أسرع، وليس تأخير المحادثات الصعبة.
- سيبقى العلم إلى الأبد. بعض الفرق تبقي الأعلام إلى أجل غير مسمى لأن إزالتها تبدو محفوفة بالمخاطر. هذه علامة على أن العلم كان سيئ التصميم أو أن الفريق يفتقر إلى الثقة في عملية الإصدار الخاصة به. يجب أن يكون لكل علم تاريخ إزالة مخطط له.
قائمة مرجعية عملية لاختيار ضوابط الإصدار
| الموقف | التحكم الموصى به |
|---|---|
| الميزة غير مكتملة ولا يمكن تشغيلها | فرع |
| الميزة مكتملة ولكنها تحتاج إلى تحقق في الإنتاج | علم ميزة |
| الميزة تحتاج إلى اختبار معزول قبل الإنتاج | بيئة تدريج |
| الميزة كبيرة وتغير السلوك الأساسي | تدريج أولاً، ثم علم |
| الفريق يمارس التطوير القائم على الفرع الرئيسي | مزيج فرع + علم |
| الميزة صغيرة ومنخفضة المخاطر | علم ميزة أو نشر مباشر |
هذا ليس جدولًا صارمًا. كل فريق لديه قدرة مختلفة على تحمل المخاطر وبنية تحتية مختلفة. استخدمه كنقطة انطلاق للنقاش، وليس ككتاب قواعد.
شجرة القرار أدناه تلخص الأسئلة الرئيسية والضوابط الموصى بها.
الهدف الحقيقي
أعلام الميزات والفروع والبيئات هي أدوات. الهدف ليس استخدامها جميعًا. الهدف هو شحن البرامج بأمان والحصول على ردود فعل سريعة.
استراتيجية إصدار جيدة تسمح لك بالنشر كثيرًا، والاختبار في الإنتاج بمخاطر محكومة، وإيقاف التشغيل عندما يحدث خطأ ما. لا تسمح لك بتأجيل القرارات أو تراكم الميزات نصف المكتملة في الإنتاج.
ابدأ بفهم ما تحاول التحكم فيه. ثم اختر الأداة المناسبة. وعندما تستخدم علم ميزة، تذكر إزالته. أفضل علم هو الذي لم يعد موجودًا.