لماذا يجب ألا تعيد بناء التطبيق للإنتاج أبدًا
منذ بضعة أسابيع، واجه فريق أعمل معه مشكلة غريبة. بيئة الاختبار (staging) اجتازت جميع الاختبارات. وافق فريق ضمان الجودة. أعطى مالك المنتج الضوء الأخضر. ولكن عندما نشروا التطبيق في الإنتاج، بدأ المستخدمون يرون أخطاءً لم تظهر مطلقًا أثناء الاختبار.
قضى الفريق يومين في تصحيح الأخطاء. قارنوا ملفات الإعدادات، وتأكدوا من متغيرات البيئة، وراجعوا تغييرات الكود. بدا كل شيء متطابقًا. أخيرًا، لاحظ أحدهم أن الطوابع الزمنية للبناء (build timestamps) كانت مختلفة. الأرتيفاكت (artifact) الذي يعمل في الإنتاج لم يكن نفس الأرتيفاكت الذي اجتاز جميع تلك الاختبارات في بيئة الاختبار.
هذه قصة تتكرر عبر الفرق كل يوم. السبب الجذري دائمًا هو نفسه تقريبًا: في مكان ما بين بيئة الاختبار والإنتاج، قرر شخص ما إعادة بناء التطبيق بدلاً من ترقية الأرتيفاكت الموجود.
المساران: إعادة البناء مقابل الترقية
كل خط أنابيب لتسليم البرمجيات يحتوي على بيئات متعددة. بيئة التطوير لتجربة الميزات الجديدة. بيئة الاختبار للتحقق من قبل ضمان الجودة أو مالكي المنتج. الإنتاج حيث يتفاعل المستخدمون الحقيقيون مع تطبيقك.
عندما تحتاج إلى نقل أرتيفاكت من بيئة إلى التي تليها، أمامك خياران.
إعادة البناء تعني أخذ الكود المصدري من commit معين وتشغيل عملية البناء مرة أخرى للبيئة المستهدفة. يقوم خط الأنابيب بسحب الكود، وتنزيل التبعيات، وتجميع التطبيق، وإنتاج أرتيفاكت جديد.
الرسم البياني التالي يوضح المسارين ونتائجهما:
الترقية تعني أخذ الأرتيفاكت الموجود بالفعل في سجل الأرتيفاكتات (registry)، والذي تم بناؤه والتحقق منه بالفعل في بيئة سابقة، ووضع علامة عليه كموافق عليه للبيئة التالية. لا بناء جديد. لا تجميع جديد. مجرد تغيير في البيانات الوصفية (metadata) يقول "هذا الأرتيفاكت مسموح به الآن في الإنتاج".
يبدو هذان الأسلوبان متشابهين، لكنهما ينتجان نتائج مختلفة جوهريًا.
الخطر الخفي لإعادة البناء
عندما تعيد بناء التطبيق للإنتاج، فأنت تنشئ أرتيفاكت جديدًا. له معرف بناء (build ID) مختلف. طابع زمني مختلف. والأهم من ذلك، أن التبعيات التي تم تنزيلها أثناء هذا البناء الجديد قد تكون مختلفة عن تلك المستخدمة في بناء بيئة الاختبار.
تأمل ما يحدث عندما يقوم خط البناء بتشغيل npm install أو pip install أو go mod download. هذه الأوامر تتصل بمستودعات بعيدة لجلب الحزم. إذا قام أحد صانعي الحزمة بدفع تحديث ثانوي بين بناء بيئة الاختبار وبناء الإنتاج، فإن أرتيفاكت الإنتاج سيتضمن هذا التحديث. حتى لو كان التغيير متوافقًا مع الإصدارات السابقة من الناحية الفنية، فإنه يُحدث فرقًا بين ما اختبرته وما تقوم بتشغيله في الإنتاج.
نفس الخطر ينطبق على أدوات البناء الخاصة بك. إذا قام نظام CI بتحديث إصدار المترجم، أو الصورة الأساسية (base image)، أو أدوات البناء بين عمليات البناء، يمكن أن يتغير المخرَج بطرق خفية. الكود الذي تم تجميعه بشكل جيد أثناء بناء بيئة الاختبار قد ينتج تعليمات آلية مختلفة أثناء بناء الإنتاج.
أنت تفقد اليقين بأن ما تم اختباره هو ما يعمل في الإنتاج. تنتقل من الثقة إلى الأمل.
لماذا تعمل الترقية بشكل أفضل
الترقية تزيل هذا الشك. يتم بناء الأرتيفاكت مرة واحدة، وتخزينه في السجل، والتحقق منه في بيئة الاختبار. عندما يجتاز جميع الفحوصات، تقوم بترقيته إلى الإنتاج عن طريق تحديث بياناته الوصفية أو علاماته (tags). لا تجميع جديد. لا تنزيل تبعيات جديد. نفس البايتات التي عملت في بيئة الاختبار تعمل الآن في الإنتاج.
عمليًا، تعمل الترقية عادةً من خلال وضع العلامات (tagging). في سجل الحاويات، قد يكون لديك صورة موسومة بـ staging. بعد التحقق، تضيف علامة production لنفس الصورة. الصورة نفسها لا تتغير. فقط التسميات تتغير. نظام النشر الخاص بك يراقب علامة production ويسحب الصورة عند ظهورها.
هذا الأسلوب يبسط أيضًا عملية التراجع (rollbacks). إذا تسبب الإصدار الجديد في مشاكل في الإنتاج، فأنت تشير مرة أخرى إلى الأرتيفاكت الذي تمت ترقيته سابقًا. لا تحتاج إلى إعادة البناء من commit قديم، على أمل أن التبعيات وأدوات البناء من ثلاثة أشهر مضت لا تزال متاحة. الأرتيفاكت القديم موجود بالفعل في سجلك، تمامًا كما كان عندما تمت ترقيته من قبل.
التحقق لا يزال يحدث قبل الترقية
الترقية لا تعني تخطي التحقق. قبل أن ينتقل الأرتيفاكت من بيئة الاختبار إلى الإنتاج، يجب أن يجتاز مجموعة محددة من الاختبارات. اختبارات الوحدة، واختبارات التكامل، وأي فحوصات خاصة بالبيئة تكون منطقية لتطبيقك. هذه الاختبارات تُجرى على الأرتيفاكت في بيئة الاختبار. إذا نجحت، يتم ترقية الأرتيفاكت. إذا فشلت، يبقى الأرتيفاكت في بيئة الاختبار، ويقوم الفريق بإصلاح الكود المصدري، وإعادة البناء، وبدء عملية التحقق مرة أخرى.
الفرق الرئيسي هو أن التحقق والترقية يستخدمان نفس الأرتيفاكت. أنت لا تختبر إصدارًا وتنشر آخر.
متى قد تكون إعادة البناء ضرورية
هناك حالات مشروعة تكون فيها إعادة البناء هي الخيار الصحيح. إذا كان الأرتيفاكت الخاص بك يتضمن إعدادات خاصة بالبيئة يجب تضمينها في البناء، فقد تحتاج إلى بنائات منفصلة لكل بيئة. إذا كانت متطلبات الامتثال لديك تتطلب أن يتم بناء أرتيفاكتات الإنتاج في خط أنابيب منفصل وأكثر أمانًا، فقد تضطر إلى إعادة البناء.
لكن هذه الحالات هي استثناءات، وليست القاعدة. معظم الفرق يمكنها فصل الإعدادات عن الكود. معظم متطلبات الامتثال يمكن تلبيتها عن طريق توقيع الأرتيفاكتات بعد الترقية بدلاً من إعادة بنائها. إذا وجدت نفسك تعيد بناء التطبيق للإنتاج بانتظام، اسأل ما إذا كان السبب ضرورة تقنية أم مجرد عادة.
قائمة تحقق عملية لترقية الأرتيفاكتات
قبل إعداد سير عمل الترقية، تحقق من هذه النقاط:
- عملية البناء الخاصة بك تنتج أرتيفاكت واحدًا يعمل عبر البيئات
- سجل الأرتيفاكتات يدعم وضع العلامات أو تحديث البيانات الوصفية دون إعادة رفع
- نظام النشر الخاص بك يمكنه مراقبة تغييرات العلامات وتشغيل عمليات النشر
- عملية التراجع الخاصة بك تشير إلى الأرتيفاكتات التي تمت ترقيتها سابقًا، وليس إلى commits قديمة
- فريقك يفهم أن "الترقية" تعني تغيير البيانات الوصفية، وليس إعادة البناء
الخلاصة الملموسة
القرار بين إعادة البناء والترقية يتلخص في سؤال واحد: هل تريد أن تكون متأكدًا أن ما اختبرته هو ما نشرته، أم تريد أن تأمل أن البناء الجديد ينتج نفس النتيجة؟
الترقية تمنحك اليقين. إعادة البناء تمنحك الأمل. في الإنتاج، اليقين أهم من الأمل. ابنِ مرة واحدة، وتحقق بدقة، ورقّ بثقة. المستخدمون سيشكرونك، وجلسات تصحيح الأخطاء ستكون أقصر.