Git وتدفقات العمل التعاونية

التطوير القائم على الجذع وأعلام الميزات

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

التطوير القائم على الجذع وأعلام الميزات

قارن الدرس السابق بين استراتيجيات التفريع جنبًا إلى جنب. يتعمق هذا الدرس في إحداها — التطوير القائم على الجذع (TBD) — ويقرنها بالتقنية التي تجعلها آمنة على نطاق واسع: أعلام الميزات. هذان الأسلوبان معًا هما الطريقة التي تطرح بها شركات Google وMeta وNetflix عشرات التغييرات على الإنتاج كل يوم دون أي فروع ميزات تعيش لأسابيع.

ما معنى التطوير القائم على الجذع فعلًا

في TBD، يدمج كل مهندس الكود في فرع مشترك واحد — يُسمى عادةً main أو trunk — مرة على الأقل يوميًا. لا توجد فروع ميزات طويلة الأمد. الفرع، إن وُجد أصلًا، يعيش لساعات لا لأيام. وفور اكتماله (حتى جزئيًا) يُدمج في الجذع.

يبدو هذا متهورًا. الواقع أنه العكس تمامًا. يفرض انضباط الدمج المتكرر ثلاثة أمور:

  • تظهر التعارضات فورًا. عندما تنتظر أسبوعين للدمج، تواجه تعارضًا بآلاف الأسطر. عندما تدمج يوميًا، تكون التعارضات بسيطة.
  • تعمل CI على كود متكامل حقيقي. مجموعة اختبار تعمل على فرعك فقط لا تكتشف أخطاء التكامل.
  • يشترك الفريق في حقيقة واحدة. لا يوجد "سندمج بعد الإصدار". الجميع ينظر دائمًا إلى نفس قاعدة الكود.
نتيجة أبحاث DORA: الفرق الهندسية المتميزة (تلك التي تنشر عدة مرات يوميًا بمعدل فشل منخفض) تمارس التطوير القائم على الجذع تقريبًا بشكل شبه حصري. وجد تقرير DORA 2023 أن TBD هو أحد أقوى المنبئات بأداء تسليم البرمجيات — أكثر من حجم الفريق أو اللغة أو مزود السحابة.

الفروع قصيرة الأمد: الاستثناء المسموح به

يسمح TBD الصافي بصفر فروع — كل commit يذهب مباشرةً إلى main. عمليًا، تستخدم معظم الفرق متغيرًا معتدلًا: فروع ميزات قصيرة الأمد لا تعيش أكثر من يوم أو يومين وتمر عبر pull request قبل الدمج. يُسمى هذا أحيانًا "TBD على نطاق واسع".

القواعد التي تجعل الفروع قصيرة الأمد آمنة:

  1. انشئ الفرع دائمًا من أحدث commit في main — أبدًا من فرع آخر.
  2. ادمج (أو أعد التأسيس) من main إلى فرعك مرة يوميًا على الأقل إن عاش الفرع أكثر من 24 ساعة.
  3. احرص على أن يكون الـ PR صغيرًا بما يكفي للمراجعة في أقل من 30 دقيقة. إن كانت الميزة كبيرة جدًا، قسّمها إلى شرائح قابلة للدمج بشكل مستقل — كل منها خلف علم ميزة.
  4. احذف الفرع فورًا بعد الدمج. لا فروع معلقة على origin.
# فرع يُنشأ ويُعمل عليه ويُدمج في يوم واحد git switch -c feat/add-rate-limiter main # ... التنفيذ والـ commit ... git fetch origin main git rebase origin/main # ابقَ متزامنًا مع الجذع git push -u origin feat/add-rate-limiter # PR يُفتح → يُراجع → يُوافق عليه → يُدمج → يُحذف الفرع git push origin --delete feat/add-rate-limiter
احذف الفروع تلقائيًا عند الدمج. في GitHub، فعّل "Automatically delete head branches" في إعدادات المستودع. في GitLab، ضع علامة على "Delete source branch" عند إنشاء merge requests. هذا يفرض الانضباط على مستوى المنصة — لا يستطيع المهندسون ترك فروع قديمة مفتوحة بالخطأ.

المشكلة الجوهرية التي يكشفها TBD

إن لم يكن بإمكانك امتلاك فروع طويلة الأمد، كيف تطرح ميزة تستغرق أسبوعين للبناء؟ لا يمكنك إخفاؤها في فرع. لا يمكنك رفض الدمج حتى تنتهي. الجواب هو: تدمج باستمرار، لكنك تتحكم في وقت تشغيل الكود. هذه هي مهمة أعلام الميزات.

أعلام الميزات: فصل النشر عن الإصدار

علم الميزة (يُسمى أيضًا feature toggle أو feature gate) هو شرط في الكود يقرر في وقت التشغيل ما إذا كانت الميزة نشطة. يُنشر الكود إلى الإنتاج باستمرار؛ العلم يتحكم في من يراها ومتى.

هذا هو النموذج الذهني الأساسي: النشر حدث تقني (الكود يصل إلى الخوادم)؛ الإصدار حدث تجاري (المستخدمون يرون الميزة). يفصل TBD + الأعلام بينهما تمامًا. يمكنك النشر 50 مرة يوميًا بينما تطرح ميزة لـ 1% من المستخدمين يوم الثلاثاء الساعة العاشرة صباحًا عندما يكون فريق الدعم مستعدًا.

Deploy vs Release decoupled by feature flags Deploy #1 Deploy #2 Deploy #3 Deploy #4 Deploy #5 flag OFF — الكود ينشر لكن الميزة مخفية flag ON — الإصدار! النشر مستمر — الإصدار متعمّد time → 1% users 100% users طرح تدريجي بعد الإصدار
تحدث عمليات النشر باستمرار؛ علم الميزة يتحكم في وقت إصدار الميزة ولمن.

أنواع الأعلام التي تحتاج معرفتها

ليست جميع الأعلام متشابهة. استخدام النوع الخاطئ في السياق الخاطئ يُسبب ديون تقنية ومخاطر تشغيلية:

  • أعلام الإصدار — قصيرة الأمد؛ تخفي الميزات الجارية. احذفها فور اكتمال الطرح. هذه هي العمود الفقري لـ TBD.
  • أعلام التجربة (A/B) — توجه المستخدمين إلى نسخة A أو B؛ مقاسة بالتحليلات. تعيش طوال التجربة ثم تُحذف.
  • أعلام العمليات — قواطع دائرة ومفاتيح إيقاف. "عطّل محرك التوصيات إذا كانت خدمة ML محملة زيادة." طويلة الأمد وتُعامل كبنود في كتب التشغيل.
  • أعلام الصلاحيات — تقييد الميزات حسب شريحة المستخدم أو الجغرافيا أو الخطة. قد تكون منطق تجاري دائم.
ديون الأعلام تُدمر قواعد الكود. العلم الذي لا يُحذف بعد الطرح هو فرع دائم في منطقك. لدى Google أدوات داخلية تفتح تلقائيًا بلاغات عندما يتجاوز عمر العلم 90 يومًا والكود مطروح بالكامل. عامل تنظيف الأعلام كمهمة هندسية أساسية، ليس فكرة لاحقة.

تطبيق الأعلام: من البسيط إلى مستوى الإنتاج

في أبسط مستوياتها، العلم مجرد فحص متغير بيئة. هذا يصلح لأعلام العمليات والإصدارات المبكرة:

# .env أو إعداد البيئة FEATURE_NEW_CHECKOUT=true # مثال Python import os def render_checkout(user): if os.getenv("FEATURE_NEW_CHECKOUT") == "true": return new_checkout_flow(user) return legacy_checkout_flow(user)

للاستهداف على مستوى المستخدم — النوع المطلوب لاختبارات A/B أو الطرح التدريجي — تحتاج خدمة تقييم أعلام. الخيار المفتوح المصدر القياسي في الصناعة هو OpenFeature (مشروع CNCF) مقرونًا بخلفية مثل Flagd أو خدمة مُستضافة مثل LaunchDarkly. إليك إعداد flagd واقعي:

# flagd/flags.json — يُقيَّم على الخادم، يُعاد تحميله تلقائيًا { "flags": { "new-checkout-ui": { "state": "ENABLED", "variants": { "on": true, "off": false }, "defaultVariant": "off", "targeting": { "if": [ { "in": [ { "var": "email" }, ["alice@example.com", "beta@example.com"] ] }, "on", { "fractionalEvaluation": [ { "cat": ["new-checkout-ui", { "var": "userId" }] }, ["on", 10], ["off", 90] ] } ] } } } }

يُقدّم هذا الإعداد واجهة الدفع الجديدة لمستخدمَين تجريبيَّين محددَين، ولـ 10% عشوائية من الجميع — مع ثبات التقسيم العشوائي (يحصل نفس المستخدم دائمًا على نفس النسخة لأن مفتاح الهاش يتضمن اسم العلم). يُعاد تحميل الملف تلقائيًا؛ لا حاجة لإعادة التشغيل لتغيير نسبة الطرح.

نمط Strangler Fig مع الأعلام

إعادة الهيكلة الكبيرة — استبدال معالج دفع، إعادة كتابة خدمة مصادقة — تتم بأمان مع نمط Strangler Fig: شغّل مسارَي الكود القديم والجديد بالتوازي، وجّه نسبة متزايدة من الحركة إلى المسار الجديد عبر علم، واستبعد المسار القديم فقط عندما يعالج الجديد 100% من الحركة لفترة مستدامة. العلم هو رافعة التراجع في كل خطوة.

Strangler Fig progressive migration via feature flag Incoming Request Feature Flag 10% → new Legacy Service 90% traffic New Service 10% traffic Response to User حوّل العلم تدريجيًا: 10% → 25% → 50% → 100% → سحب القديم Strangler Fig: ترحيل تدريجي للحركة
يحوّل العلم الحركة تدريجيًا من الخدمة القديمة إلى الجديدة، مع إمكانية التراجع الفوري عند أي نسبة.

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

يفشل TBD والأعلام بطرق يمكن التنبؤ بها. معرفتها يتيح لك تجنبها:

  • الـ commit مباشرةً على الجذع دون اجتياز CI. يتطلب TBD خط CI سريعًا وموثوقًا كجهاز مناعي. إن كان CI غير موثوق أو بطيئًا (أكثر من 10 دقائق)، سيتجاوزه المهندسون. استثمر في سرعة الاختبار أولًا.
  • الأعلام في الطبقة الخاطئة. علم يُقيَّم في ثلاث خدمات مختلفة بنتائج غير متسقة أسوأ من لا علم. قيّم الأعلام مرة واحدة (من جانب الخادم، في API gateway أو SDK مشترك) وأرسل النتيجة إلى المراحل التالية.
  • لا رصد لحالة الأعلام. عند وقوع حادثة، تحتاج معرفة أي الأعلام كانت نشطة للمستخدمين المتضررين فورًا. أرسل نتيجة تقييم العلم كحقل سجل هيكلي أو سمة trace على كل طلب.
  • تضخم الأعلام. 500 علم نشط في قاعدة كود دون سجلات ملكية. عيّن مالكًا وتاريخ انتهاء لكل علم عند الإنشاء. أتمتة التذكيرات.
اختبر حالتَي العلم في CI. يجب أن تنجح مجموعة اختباراتك مع العلم مفعّلًا ومع العلم مُعطّلًا. نمط شائع هو إجراء الاختبارات بالقيمتين، أو تشغيل المجموعة الكاملة مرتين في الخط — مرة مع إجبار العلم على التفعيل ومرة على التعطيل. يكتشف هذا الحالة التي يتعطل فيها المسار المُعطَّل بصمت لأن أحدًا لم يختبره.

الصورة الكاملة: يوم في حياة المهندس

مهندس أول في فريق TBD يعمل على ميزة دفع جديدة يفعل ما يلي: ينشئ فرعًا من main، يكتب شريحة أولى نحيفة (ترحيل قاعدة البيانات والمسار خلف العلم)، يفتح PR في نفس اليوم، يُدمج. العلم مُغلق. في اليوم التالي: ينشئ فرعًا جديدًا من أحدث main، يضيف طبقة الواجهة خلف نفس العلم، يُدمج بنهاية اليوم. العلم لا يزال مُغلقًا. اليوم الثالث: منطق الخلفية مكتمل، مُدمج، اختبارات شاملة مضافة. العلم يُفعَّل لبيئة QA. اليوم الرابع: العلم يُفعَّل لـ 5% من حركة الإنتاج. المؤشرات تبدو جيدة. اليوم الخامس: 100%. اليوم السادس: PR لحذف العلم ومسار الكود القديم. يُدمج. تم. لم تعش الميزة في فرع أكثر من 24 ساعة، رغم أنها استغرقت خمسة أيام للبناء بأمان.

هذا هو الانضباط الذي يتيح للفرق النشر بلا خوف. الفرع قصير؛ المخاطرة تُدار بالعلم. هذه هي الفكرة بأكملها.