لماذا ترتيب النشر أهم من خط الأنابيب الخاص بك
لديك إصدار جديد من تطبيقك جاهز. خط الأنابيب أخضر. الفريق يراقب. تضغط على زر النشر. بعد دقائق، تبدأ الأخطاء في الظهور في السجلات. يبلغ المستخدمون أنهم لا يستطيعون إتمام عمليات الشراء. يقول فريق قاعدة البيانات إن تغيير المخطط (schema) تم تطبيقه بعد بدء تشغيل التطبيق، وليس قبله.
هذا السيناريو ليس نادرًا. يحدث لأن النشر نادرًا ما يتعلق بتطبيق واحد يقوم بشيء واحد. إنه يتعلق بكيفية اتصال ذلك التطبيق بكل شيء آخر يعتمد عليه. فهم تلك الاتصالات - والمخاطر التي تحملها - هو ما يفصل بين النشر السلس وحادثة إنتاجية.
التبعيات ليست مجرد كود
تطبيق حديث لا يعمل بمفرده أبدًا تقريبًا. يقرأ من قاعدة بيانات. يستدعي واجهة برمجة تطبيقات (API) لمعالجة المدفوعات. يستخدم مكتبة طرف ثالث لتغيير حجم الصور. يعتمد على قائمة انتظار رسائل لإرسال الإشعارات. كل من هذه العناصر هو تبعية (dependency)، وكل منها يمكن أن يتعطل عند نشر إصدار جديد.
التبعية الأكثر شيوعًا هي قاعدة البيانات. يخزن تطبيقك بيانات المستخدم في PostgreSQL أو MySQL. عندما تنشر إصدارًا جديدًا، يقرأ هذا الإصدار البيانات ويكتبها بشكل مختلف عن الإصدار القديم. ربما كان الإصدار القديم يخزن عنوان المستخدم في عمود واحد، والإصدار الجديد يقسمه إلى شارع ومدينة ورمز بريدي. إذا بدأ الإصدار الجديد في العمل قبل تحديث مخطط قاعدة البيانات، فسيفشل في قراءة البيانات الموجودة. هذا تغيير مكسّر (breaking change) - الإصداران القديم والجديد غير متوافقين مع بعضهما البعض.
تشمل التبعيات أيضًا واجهات برمجة التطبيقات من فرق أخرى أو خدمات خارجية. تخيل أن تطبيقك يستدعي واجهة برمجة تطبيقات للدفع. يتوقع الإصدار الجديد استجابة بتنسيق JSON مختلف. إذا لم يتم تحديث واجهة برمجة التطبيقات هذه بعد، فسيستقبل تطبيقك بيانات لا يمكنه تحليلها، وستفشل المعاملات. المشكلة هي أنك لا تتحكم دائمًا في وقت تغيير واجهة برمجة التطبيقات تلك. قد يكون لفريق آخر جدول النشر الخاص به، وقد لا يعرفون أن تطبيقك يعتمد على تنسيق استجابة معين.
المكتبات والحزم من طرف ثالث هي أيضًا تبعيات. عندما تقوم بتحديث مكتبة من الإصدار 1.0 إلى 2.0، قد يتم إعادة تسمية الدوال أو تغيير توقيعاتها. إذا كان تطبيقك لا يزال يستدعي اسم الدالة القديم، فسيحدث خطأ في الكود أثناء وقت التشغيل. لهذا السبب تقوم الفرق الناضجة بتتبع تبعياتها بوضوح - في ملفات مثل requirements.txt أو package.json أو go.mod - وتختبر إصدارات المكتبات الجديدة قبل استخدامها في الإنتاج.
المخاطر الخفية: ترتيب النشر
تؤثر التبعيات بشكل مباشر على الترتيب الذي تنشر به الأشياء. إذا كان التطبيق (أ) يعتمد على قاعدة بيانات تحتاج إلى تغيير في المخطط، فيجب عليك تحديث قاعدة البيانات أولاً، ثم نشر التطبيق (أ). إذا كان التطبيق (ب) يستدعي واجهة برمجة تطبيقات من التطبيق (ج)، فيجب عليك نشر التطبيق (ج) أولاً، ثم التطبيق (ب). هذا الترتيب مهم لأنه إذا قمت بعكسه، فسيبحث التطبيق المنشور حديثًا عن بيانات أو خدمات غير متوفرة بعد. والنتيجة هي أخطاء أو طلبات فاشلة أو تطبيق معطل تمامًا.
يُظهر مخطط التسلسل التالي ترتيب النشر الصحيح وما يحدث عند عكسه:
يزداد الخطر مع عدد التبعيات. كلما زادت الخدمات التي تحتاج إلى التزامن، زادت احتمالية عدم تطابق إحداها. الفريق الذي يتعامل مع هذا بشكل جيد يقوم برسم خريطة لجميع التبعيات قبل النشر، ويؤكد الترتيب الصحيح، ويعد خطة تراجع (rollback plan) في حالة عدم تطابق شيء ما. كما يستخدمون تقنيات مثل التوافق العكسي (backward compatibility) - جعل الإصدار الجديد لا يزال يعمل مع الإصدار القديم - لتقليل مخاطر التغييرات المكسّرة.
التغييرات المكسّرة ليست واضحة دائمًا
التغيير المكسّر لا يجب أن يكون دراماتيكيًا. يمكن أن يكون خفيًا. على سبيل المثال، قد يبدأ إصدار جديد من تطبيقك في إرسال حقل إضافي في طلب إلى واجهة برمجة تطبيقات داخلية. الخدمة المستقبلة تتجاهل الحقول غير المعروفة، لذلك يبدو كل شيء على ما يرام. ولكن بعد بضعة أسابيع، يتم تحديث تلك الخدمة المستقبلة، وهي الآن تتوقع وجود ذلك الحقل الإضافي. الإصدار القديم من تطبيقك، الذي لا يزال قيد التشغيل في بعض البيئات، يتوقف عن العمل. العطل مؤجل، ومن الصعب تتبع السبب الجذري.
لهذا السبب، فإن رسم خرائط التبعيات ليس نشاطًا لمرة واحدة. يجب تحديثه مع تطور النظام. في كل مرة يتم فيها إضافة تبعية جديدة أو تغيير تبعية موجودة، يتغير ترتيب النشر وملف المخاطر أيضًا.
كيفية تقليل مخاطر التبعيات
هناك خطوات عملية يمكنك اتخاذها لجعل عمليات النشر أكثر أمانًا عند وجود تبعيات.
أولاً، وثّق تبعياتك. هذا لا يعني كتابة مستند طويل لا يقرأه أحد. يعني وجود سجل واضح وقابل للقراءة آليًا لما يعتمد عليه تطبيقك وما يعتمد عليه. يمكن أن تساعد أدوات مثل رسوم بيانية التبعيات (dependency graphs) أو كتالوجات الخدمات أو حتى ملف README بسيط في مستودعك.
ثانيًا، اختبر التكامل، وليس الوحدة فقط. اختبارات الوحدة التي تسخر (mock) كل خدمة خارجية لن تكتشف المشكلات الناتجة عن سلوك التبعية الحقيقي. اختبارات التكامل التي تعمل مقابل قواعد البيانات الفعلية أو واجهات برمجة التطبيقات أو قوائم انتظار الرسائل ستكشف المشكلات قبل وصولها إلى الإنتاج.
ثالثًا، استخدم أعلام الميزات (feature flags) أو واجهات برمجة التطبيقات ذات الإصدارات (versioned APIs) للحفاظ على التوافق العكسي. إذا كان بإمكان إصدارك الجديد الاستمرار في خدمة الطلبات من العملاء القدامى، فستكون لديك مرونة أكبر في ترتيب النشر. يمكنك نشر الإصدار الجديد أولاً، والتحقق من أنه يعمل، ثم تحديث الخدمات التابعة.
رابعًا، مارس التراجع. اعرف بالضبط ما يجب فعله إذا فشل النشر بسبب عدم تطابق التبعية. هل يمكنك التراجع عن تغيير مخطط قاعدة البيانات؟ هل يمكنك توجيه التطبيق مرة أخرى إلى إصدار واجهة برمجة التطبيقات القديم؟ وجود خطة تراجع مختبرة يقلل الضغط أثناء النشر.
على سبيل المثال، يفرض نص برمجي بسيط للنشر المتسلسل الترتيب الصحيح ويتوقف عند الفشل:
#!/bin/bash
# deploy.sh - فرض ترتيب النشر الصحيح
set -e # الخروج عند أي خطأ
echo "الخطوة 1: نشر مخطط قاعدة البيانات"
./deploy_database.sh || { echo "فشل نشر قاعدة البيانات. إحباط."; exit 1; }
echo "الخطوة 2: نشر واجهة برمجة التطبيقات الخلفية"
./deploy_api.sh || { echo "فشل نشر API. جاري التراجع عن قاعدة البيانات..."; ./rollback_database.sh; exit 1; }
echo "الخطوة 3: نشر الواجهة الأمامية"
./deploy_frontend.sh || { echo "فشل نشر الواجهة الأمامية. جاري التراجع عن API وقاعدة البيانات..."; ./rollback_api.sh; ./rollback_database.sh; exit 1; }
echo "تمت جميع عمليات النشر بنجاح."
قائمة مراجعة عملية قبل نشرك التالي
قبل النشر، راجع قائمة المراجعة القصيرة هذه:
- هل قمت بإدراج كل تبعية يستخدمها تطبيقك (قاعدة بيانات، API، مكتبة)؟
- هل تعرف ترتيب النشر الصحيح لكل تبعية؟
- هل اختبرت الإصدار الجديد مقابل الإصدارات الفعلية لتلك التبعيات؟
- هل هناك خطة تراجع لكل تبعية قد تتعطل؟
- هل قمت بإبلاغ ترتيب النشر لكل فريق يمتلك تبعية؟
هذه القائمة ليست شاملة، لكنها تغطي نقاط الفشل الأكثر شيوعًا. إذا كان بإمكانك الإجابة بنعم على جميع الأسئلة الخمسة، فأنت في وضع أفضل بكثير من معظم الفرق.
الخلاصة
النشر لا يتعلق فقط بدفع الكود. إنه يتعلق بإدارة العلاقات بين تطبيقك وكل ما يتصل به. تحدد التبعيات ترتيب النشر، وخطر الفشل، وصعوبة التعافي. الفريق الذي يفهم تبعياته ويخطط لها سيواجه حوادث أقل، وتعافيًا أسرع، وثقة أكبر في كل إصدار. خط الأنابيب مهم، لكن خريطة التبعيات هي ما يمنع خط الأنابيب من التحول إلى تدريب على إطفاء الحرائق.