استراتيجيات النشر والتسليم التدريجي

النشر مقابل الإصدار

18 دقيقة الدرس 1 من 28

النشر مقابل الإصدار

من أقوى الأفكار التي أفرزتها ثقافة هندسة الشركات الكبرى في العقد الماضي فكرة تبدو في ظاهرها بسيطة: نشر الكود وإصدار ميزة فعلٌ منفصلٌ تمامًا عن الآخر، والخلط بينهما هو الجذر الخفي لعدد مفاجئ من حوادث التوقف عن العمل، والإطلاقات الفاشلة، وعمليات التراجع في منتصف الليل.

في جوجل وميتا ونتفليكس وأمازون، يصل كود جديد إلى خوادم الإنتاج عشرات أو مئات المرات يوميًا. لكن المستخدمين لا يرون ميزة ما إلا حين تقرر الشركة بوعي إظهارها لهم. هذه الفجوة — بين حلول الملف التنفيذي على الجهاز وقدرة المستخدم على استخدامه — هي المساحة التي يعيش فيها التسليم التدريجي الحديث.

ما الذي يعنيه "النشر" فعلًا

النشر هو الفعل الميكانيكي المتمثل في إيصال الكود الجديد إلى البنية التحتية للإنتاج. الحزمة — صورة Docker، أو ملف ثنائي مُجمَّع، أو ملف ZIP للـ Lambda — تنتقل من نظام CI إلى بيئة التشغيل. تملك هذه العملية الفريقُ الهندسي، وتقودها الأتمتة، والمثالي أن تكون غير مرئية للمستخدمين.

الخصائص الرئيسية لعملية نشر منظَّمة:

  • مؤتمتة بالكامل — لا أحد ينقر على زر في الإنتاج.
  • مثالية (Idempotent) — تشغيلها مرتين يترك النظام في الحالة ذاتها.
  • قابلة للتدقيق — كل عملية نشر مُسمَّاة بـ SHA للإيداع، ومعرّف بناء، والمسؤول عن النشر، وطابع زمني.
  • قابلة للعكس — يمكن للنظام بلوغ الحالة الجيدة السابقة خلال نافزة زمنية محددة (أقل من 5 دقائق للخدمات عديمة الحالة في الغالب).

ما الذي يعنيه "الإصدار" فعلًا

الإصدار قرار تجاري: اللحظة التي تصبح فيها ميزة ما مرئية لبعض المستخدمين أو جميعهم. يمتلك الإصدار مدير المنتج، أو فريق الطرح في السوق، أو مهندس موثوقية الموقع الذي يحرس ميزانية الخطأ. وينطوي على التوقيت، والتسويق، والمراجعة القانونية، والاستعداد الدعمي، واختيار السكان التجريبيين — ولا علاقة لأي من ذلك بـ Git.

لأن الإصدار فعل تجاري، فيجب أن يكون قابلًا للتحكم في وقت التشغيل، لا مُخبَّأً في الملف الثنائي. الآلية التي تجعل ذلك ممكنًا هي علامة الميزة (feature flag)، وتُعرف أيضًا بالمبدّل أو البوابة. يُشحن الكود مع السلوك الجديد خلف علامة؛ العلامة مُغلقة بالافتراضي؛ والمنتج يفتحها حين يحين الوقت المناسب.

الرؤية الجوهرية: حين يكون النشر والإصدار متشابكَين، كل عملية نشر حدثُ خطر. فصلهما يجعل عمليات النشر مملّةً والإصدارات مقبضًا تجاريًا — لا حريقًا ينبغي إطفاؤه.

لماذا ربط النشر بالإصدار خطير

في النظام المتشابك، فور حلول الكود الجديد في الإنتاج يرى كل مستخدم السلوك الجديد. هذا يولّد ثلاث مشكلات مترابطة:

  1. نصف قطر التأثير 100٪. إن كان في الكود الجديد خلل كامن، كل طلب يصطدم به في آن واحد. يستقبل مهندس الدوام تنبيهات قبل أن تنتهي قناة النشر من طباعة كلمة "نجاح".
  2. التراجع هو المسار الوحيد للتعافي. لأنك لا تستطيع إيقاف الميزة دون التراجع عن الكود، عملية التراجع تلغي كل العمل الهندسي — والتراجع نفسه ينطوي على مخاطر (تغييرات المخطط، الطلبات المعلّقة، إبطال التخزين المؤقت).
  3. توقيت الإصدار رهينة للهندسة. إن أراد المنتج الإطلاق في التاسعة صباحًا يوم الاثنين لأقصى تأثير تسويقي، يجب على الهندسة النشر في تلك اللحظة بالذات — إدخال تغيير على نظام في ذروة الحركة، مع الفريق بأكمله في حالة ترقّب.
فخ النشر في منتصف الليل: تجدول كثير من الفرق عمليات النشر في الساعة الثانية صباحًا لتقليل تأثير المستخدم. هذا عرَضٌ للتشابك بين النشر والإصدار. يُجبر المهندسين على العمل ليلًا، ويُقلل فريق الاستجابة خلال النشر، ويحمل الخطر ذاته — مع أناس أقل صحوين للتعامل معه. أصلح التشابك، لا الساعة.

ميكانيكا الفصل

يستخدم التطبيق العملي علامةَ ميزة تُقيَّم عند وقت الطلب. يحدث فحص العلامة في كود التطبيق ويقرأ قيمتها من مخزن علامات مركزي — نظام مُصمَّم لذلك مثل LaunchDarkly أو Flagsmith أو Unleash أو خدمة محلية مبنية على Redis. يُقرأ المخزن عند كل طلب (مع تخزين مؤقت عدواني)؛ تغيير قيمة العلامة يصل إلى جميع الخوادم في ثوانٍ دون نشر جديد.

Deploy vs Release — decoupled flow CI / CD Pipeline Production Servers (code) deploy Flag Store new_checkout: OFF (Redis / LaunchDarkly) Product Manager flips flag ON reads flag Users see old UI Users see new UI flag=OFF flag=ON time Deploy (code lands) Release (flag flipped)
النشر يضع الكود على الخوادم (الهندسة)؛ الإصدار يكشف الميزة للمستخدمين (المنتج). الفجوة بينهما يتحكم فيها مفتاح الميزة.

تطبيق عملي لمفتاح ميزة بسيط

لا تحتاج منصة علامات تجارية للبدء. النمط أدناه يستخدم متغيرات البيئة للتوضيح، ثم يُظهر الخطوة التالية نحو مخزن علامات حقيقي.

# ── أبسط علامة ممكنة: متغير بيئة يُقرأ عند بدء التشغيل ────────────────────── # app/config.py (مثال Python / FastAPI) import os FEATURE_NEW_CHECKOUT = os.getenv("FEATURE_NEW_CHECKOUT", "false").lower() == "true" # في معالج المسار: # if FEATURE_NEW_CHECKOUT: # return new_checkout_handler(request) # return legacy_checkout_handler(request) # المشكلة: تغيير هذه العلامة يتطلب إعادة نشر — لا تزال مقيّدة! # الحل: انقل قيمة العلامة إلى مخزن يُقرأ في وقت التشغيل. # ── علامة مخزّنة في Redis تُقرأ عند كل طلب ────────────────────────────────── # redis-cli SET feature:new_checkout false # لاحقًا، يقرر المنتج الإطلاق: SET feature:new_checkout true # لا حاجة لـ TTL — هذه البيانات مستمرة عمدًا # ── التطبيق يقرأ العلامة لكل طلب (كود Python تقريبي) ──────────────────────── # import redis # r = redis.Redis(host="redis-flags.internal", decode_responses=True) # # def is_enabled(flag_name: str, default: bool = False) -> bool: # val = r.get(f"feature:{flag_name}") # if val is None: # return default # return val.lower() == "true" # # if is_enabled("new_checkout"): # return new_checkout_handler(request)
خزِّن نتائج قراءة العلامات مؤقتًا. قراءة Redis عند كل طلب HTTP تضيف زمن استجابة. استخدم تخزينًا مؤقتًا محليًا داخل العملية بـ TTL قصير (5 إلى 30 ثانية عادةً). هذا يعني أن تغييرات العلامة تصل إلى جميع الخوادم خلال 30 ثانية — مقبول لمعظم حالات الاستخدام، وأسرع بكثير من أي نشر.

التكامل مع GitOps: العلامات كتهيئة

تُخزِّن الفرق الناضجة تعريفات علاماتها في Git جنبًا إلى جنب مع مانيفستات الخدمة. يحمل ConfigMap في Kubernetes أو ملف Helm values القيم الافتراضية للعلامات؛ يُهيَّأ مخزن العلامات منها عند النشر. يمنحك ذلك سجلًا كاملًا قابلًا للتدقيق لكل تغيير في حالة العلامة عبر عملية مراجعة طلب السحب العادية، لا واجهة ويب منفصلة لا يتذكرها أحد للمراجعة.

# ── Helm values.yaml — قيم افتراضية للعلامات مُدمجة في الـ chart ───────────── featureFlags: new_checkout: false redesigned_search: false new_pricing_engine: true # أُطلق الربع الماضي، الآن افتراضي مفعَّل # ── ConfigMap في Kubernetes يُصدره Helm ────────────────────────────────────── apiVersion: v1 kind: ConfigMap metadata: name: feature-flags namespace: checkout data: new_checkout: "false" redesigned_search: "false" new_pricing_engine: "true" # ── التطبيق يقرأ ConfigMap عبر وحدة تخزين مُثبَّتة ────────────────────────── # يُثبَّت ConfigMap في /etc/flags/ # يقرأ التطبيق /etc/flags/new_checkout عند بدء التشغيل # Kubernetes لا يُعيد تحميل ConfigMaps المُثبَّتة تلقائيًا؛ # استخدم حاوية جانبية sidecar أو SDK علامات صحيح للتحديثات الحية.

أنماط الفشل في الإنتاج

حتى مع الفصل النظيف، تظهر أنماط الفشل التالية بانتظام في الإنتاج:

  • انفجار العلامات. تتراكم الفرق مئات العلامات القديمة التي لم تُحذف بعد إطلاق ناجح. كل منها فرع شرطي يجب اختباره، ومصدر محتمل للأخطاء. فرض سياسة TTL: العلامات الأكبر من 90 يومًا دون تغييرات في الحالة تُحذف تلقائيًا أو ترفع تنبيهًا.
  • انقطاع مخزن العلامات. ماذا يحدث إن توقف مخزن العلاماتك؟ إن فشل التطبيق مُغلقًا (يُعيد خطأ)، يتحول انقطاع المخزن إلى انقطاع كلي للخدمة. حدِّد دائمًا قيمة افتراضية معقولة وأخفق نحو المسار الآمن. لميزة جديدة غير مُتحقق منها، المسار الآمن هو الإغلاق.
  • اختبار الكود المظلم. الكود الذي يُشحن خلف علامة لكن لا يُختبر في حالة الإغلاق قد يتراكم عليه عفن التبعيات. شغِّل مجموعة اختبارات التكامل مع العلامات مفتوحة ومغلقة في CI — توفر معظم مكتبات العلامات مساعد اختبار يتجاوز المخزن.
  • الاقتران بالمخطط. يمكن للعلامة أن تُبوِّب منطق الواجهة والتطبيق، لكن ليس تغييرات مخطط قاعدة البيانات. إن كانت ميزتك الجديدة تتطلب عمودًا جديدًا، يجب إضافة ذلك العمود في نشر سابق (بقيمة افتراضية) قبل أن تتمكن من تبويب الميزة. هذا هو نمط Expand-Contract الذي يُغطيه درس لاحق.
قاعدة نتفليكس وأمازون: أي ميزة تعمل على 100٪ من الحركة لأكثر من 30 يومًا دون مشاكل يجب إزالة علامتها وحذف فرع الكود الميت. شحن سلوك جديد هو الهدف؛ تشابك العلامات الدائم هو النمط المضاد.

الخلاصة

فصل النشر عن الإصدار ليس تقنية DevOps — بل فلسفة تغير صاحب المخاطرة وتوقيتها. تمتلك الهندسة النشر: يجب أن يكون مؤتمتًا وسريعًا وقابلًا للعكس. يمتلك المنتج الإصدار: يجب أن يكون متعمدًا وقابلًا للقياس وقابلًا للعكس دون حادثة هندسية. علامات الميزات هي الآلية التي تجعل كليهما ممكنَين في آن واحد. كل موضوع لاحق في هذا البرنامج التعليمي — عمليات النشر المتدحرجة، والإصدارات الكناري، والتجارب A/B — هو تفصيل لهذه الفكرة الأساسية الواحدة.