الجزء 11: التكامل والتسليم المستمر
مقدمة إلى CI/CD
إيصال البرمجيات إلى الإنتاج
كتابة الشيفرة ليست سوى البداية. لا تكتسب البرمجيات أهميتها إلا عندما تصل إلى الإنتاج وتقدّم قيمة لمستخدمين حقيقيين. بعد الإطلاق، ينتقل العمل إلى ما يدعم المنتج حقاً: عمليات موثوقة، وإصدارات مستمرة، وتعاون فعّال لتنمية النظام وتحسينه مع مرور الوقت.
لقد استخدمنا GitHub بالفعل لتخزين شيفرتنا المصدرية، لكن ماذا يحدث عندما نعمل ضمن فريق يضم مزيداً من المطوّرين؟
قد تنشأ مشكلات كثيرة عند مشاركة عدة مطوّرين. قد تعمل البرمجيات بشكل جيد على جهازي أنا، لكن ربما يستخدم بعض المطوّرين الآخرين نظام تشغيل مختلفاً أو إصدارات مختلفة من المكتبات. ليس غريباً أن تعمل الشيفرة بشكل جيد على جهاز مطوّر واحد بينما لا يستطيع مطوّر آخر حتى تشغيلها. يُسمى هذا غالباً مشكلة «تعمل على جهازي».
وهناك مشكلات أكثر تعقيداً. إذا كان مطوّران يعملان على تغييرات ولم يتفقا على طريقة للنشر إلى الإنتاج، فمن الذي ستُنشر تغييراته؟ وكيف يمكن منع تغييرات أحد المطوّرين من الكتابة فوق تغييرات الآخر؟
في هذا الجزء، سنستعرض طرقاً للعمل معاً وبناء البرمجيات ونشرها بطريقة محددة بدقة، بحيث يكون واضحاً تماماً ما سيحدث في أي ظرف من الظروف.
بعض المصطلحات المفيدة
في هذا الجزء سنستخدم بعض المصطلحات التي قد لا تكون مألوفة لك أو قد لا يكون لديك فهم جيد لها. سنناقش بعض هذه المصطلحات هنا. حتى إذا كنت تعرف هذه المصطلحات، اقرأ هذا القسم حتى نكون على وفاق عند استخدامها في هذا الجزء.
الفروع
يتيح Git وجود نسخ أو مسارات أو إصدارات متعددة من الشيفرة جنباً إلى جنب دون أن تكتب إحداها فوق الأخرى. عند إنشاء مستودع لأول مرة، ستكون أمام الفرع الرئيسي (نسميه عادةً في Git main أو master، لكن هذا يختلف في المشاريع الأقدم). هذا جيد إذا كان هناك مطوّر واحد فقط للمشروع وكان يعمل على ميزة واحدة في كل مرة.
تصبح الفروع مفيدة عندما تزداد هذه البيئة تعقيداً. في هذا السياق، يمكن أن يكون لكل مطوّر فرع واحد أو أكثر. كل فرع هو فعلياً نسخة من الفرع الرئيسي مع بعض التغييرات التي تجعله يتشعّب عنه. وبمجرد أن تصبح الميزة أو التغيير في الفرع جاهزاً، يمكن دمجه مرة أخرى في الفرع الرئيسي، لتصبح تلك الميزة أو ذلك التغيير جزءاً من البرمجيات الرئيسية فعلياً. بهذه الطريقة، يمكن لكل مطوّر العمل على مجموعته الخاصة من التغييرات دون التأثير على أي مطوّر آخر حتى تصبح التغييرات جاهزة.
لكن بمجرد أن يدمج أحد المطوّرين تغييراته في الفرع الرئيسي، ماذا يحدث لفروع المطوّرين الآخرين؟ إنها الآن تتشعّب عن نسخة أقدم من الفرع الرئيسي. كيف سيعرف المطوّر صاحب الفرع المتأخر ما إذا كانت تغييراته متوافقة مع الحالة الحالية للفرع الرئيسي؟ هذا أحد الأسئلة الأساسية التي سنحاول الإجابة عنها في هذا الجزء.
يمكنك قراءة المزيد عن الفروع مثلاً من هنا.
طلب السحب
في GitHub، غالباً ما يحدث دمج فرع مرة أخرى في الفرع الرئيسي للبرمجيات باستخدام آلية تُسمى طلب السحب (pull request)، حيث يطلب المطوّر الذي أجرى بعض التغييرات دمج هذه التغييرات في الفرع الرئيسي. وبمجرد إنشاء طلب السحب، أو PR كما يُسمى غالباً، أو فتحه، يتحقق مطوّر آخر من أن كل شيء على ما يرام ويدمج طلب الـ PR.
البناء
لمصطلح «البناء» (build) معانٍ مختلفة في لغات مختلفة. في بعض اللغات المفسَّرة مثل Python أو Ruby، لا حاجة فعلياً إلى خطوة بناء على الإطلاق.
عموماً، عندما نتحدث عن البناء فإننا نعني تهيئة البرمجيات لتعمل على المنصة التي يُقصد تشغيلها عليها. قد يعني هذا، مثلاً، أنه إذا كتبت تطبيقك بـ TypeScript وكنت تنوي تشغيله على Node، فإن خطوة البناء قد تكون تحويل TypeScript إلى JavaScript.
تكون هذه الخطوة أكثر تعقيداً بكثير (وإلزامية) في اللغات المترجمة مثل C وRust حيث يجب ترجمة الشيفرة إلى ملف تنفيذي.
في الجزء 7 ألقينا نظرة على ESBuild، وهي إحدى الأدوات الأكثر استخداماً لبناء نسخة إنتاجية من React أو أي قاعدة شيفرة أخرى للواجهة الأمامية بـ JavaScript أو TypeScript.
النشر
يشير النشر إلى وضع البرمجيات حيث ينبغي أن تكون ليستخدمها المستخدم النهائي. في حالة المكتبات، قد يعني هذا ببساطة دفع حزمة npm إلى أرشيف حزم (مثل npmjs.com) حيث يمكن للمستخدمين الآخرين العثور عليها وتضمينها في برمجياتهم.
قد يختلف نشر خدمة (مثل تطبيق ويب) في التعقيد. في الجزء 3 تضمّن سير عمل النشر لدينا تشغيل بعض السكربتات يدوياً ودفع شيفرة المستودع إلى خدمة استضافة Fly.io أو Render.
في هذا الجزء، سنطوّر «خط أنابيب نشر» بسيطاً ينشر كل commit من شيفرتك تلقائياً إلى Fly.io أو Render إذا لم تُفسد الشيفرة المُودَعة أي شيء.
يمكن أن تكون عمليات النشر أكثر تعقيداً بكثير، خاصة إذا أضفنا متطلبات مثل «يجب أن تكون البرمجيات متاحة في جميع الأوقات أثناء النشر» (النشر دون توقف) أو إذا كان علينا مراعاة أمور مثل ترحيلات قواعد البيانات. لن نغطي عمليات النشر المعقدة كهذه في هذا الجزء، لكن من المهم معرفة أنها موجودة.
ما هو CI؟
قد يختلف التعريف الصارم لـ CI (التكامل المستمر) والطريقة التي يُستخدم بها المصطلح في الصناعة أحياناً. من المناقشات المؤثرة وإن كانت مبكرة نوعاً ما (كُتبت في 2006 بالفعل) حول الموضوع ما ورد في مدونة مارتن فاولر.
بالمعنى الدقيق، يشير CI إلى دمج تغييرات المطوّرين في الفرع الرئيسي بشكل متكرر، بل إن ويكيبيديا تقترح حتى بشكل مفيد: «عدة مرات في اليوم». هذا صحيح عادةً، لكن عندما نشير إلى CI في الصناعة، فإننا غالباً ما نتحدث عمّا يحدث بعد الدمج الفعلي.
من المحتمل أننا نريد القيام ببعض هذه الخطوات:
- Lint: إبقاء شيفرتنا نظيفة وقابلة للصيانة ومتوافقة مع الدمج
- البناء: جمع كل شيفرتنا معاً في حزمة برمجيات قابلة للتشغيل
- الاختبار: التأكد من أننا لا نكسر الميزات الموجودة
- التغليف: تجميع كل شيء في دفعة يسهل نقلها
- النشر: إتاحته للعالم
سنناقش كل خطوة من هذه الخطوات (ومتى تكون مناسبة) بمزيد من التفصيل لاحقاً. المهم أن نتذكر أن هذه العملية يجب أن تكون محددة بدقة.
عادةً ما تعمل التعريفات الصارمة كقيد على الإبداع/سرعة التطوير. لكن هذا لا ينبغي أن يكون صحيحاً عادةً بالنسبة لـ CI. يجب إعداد هذا الصرامة بطريقة تتيح تطويراً أسهل وعملاً جماعياً أفضل. استخدام نظام CI جيد (مثل GitHub Actions الذي سنغطيه في هذا الجزء) سيتيح لنا فعل كل هذا تلقائياً بشكل سحري.
التغليف والنشر كجزء من CI
قد يكون من الجدير بالملاحظة أن التغليف وخاصة النشر لا يُعتبران أحياناً ضمن نطاق CI. سنضيفهما هنا لأنه في العالم الحقيقي من المنطقي جمعهما معاً. يرجع ذلك جزئياً إلى أنهما منطقيان في سياق التدفق وخط الأنابيب (أريد إيصال شيفرتي إلى المستخدمين)، وجزئياً لأن هذين هما في الواقع نقطة الفشل الأكثر ترجيحاً.
غالباً ما يكون التغليف مجالاً تظهر فيه المشكلات في CI لأنه ليس شيئاً يُختبر عادةً محلياً. من المنطقي اختبار تغليف المشروع أثناء سير عمل CI حتى لو لم نفعل أي شيء بالحزمة الناتجة. في بعض سير العمل، قد نختبر حتى الحزم المبنية بالفعل. هذا يضمن لنا أننا اختبرنا الشيفرة بالصيغة نفسها التي ستُنشر إلى الإنتاج.
وماذا عن النشر إذن؟ سنتحدث عن الاتساق وقابلية التكرار بإسهاب في الأقسام القادمة، لكننا سنذكر هنا أننا نريد عملية تبدو متطابقة دائماً، سواء كنا نشغّل الاختبارات على فرع تطوير أو على الفرع الرئيسي. بل قد تكون العملية حرفياً هي نفسها مع فحص واحد فقط في النهاية لتحديد ما إذا كنا على الفرع الرئيسي ونحتاج إلى إجراء عملية نشر. في هذا السياق، من المنطقي تضمين النشر في عملية CI لأننا سنصونه في الوقت نفسه الذي نعمل فيه على CI.
هل هذا الأمر المتعلق بـ CD ذو صلة؟
يُستخدم مصطلحا التسليم المستمر والنشر المستمر (وكلاهما اختصاره CD) غالباً عندما يتحدث المرء عن CI يتولى أيضاً عمليات النشر. لن نُشعرك بالملل بالتعريف الدقيق (يمكنك استخدام مثلاً ويكيبيديا أو تدوينة أخرى لمارتن فاولر) لكن عموماً، نشير بـ CD إلى الممارسة التي يُحافظ فيها على الفرع الرئيسي قابلاً للنشر في جميع الأوقات. وعموماً، يقترن هذا أيضاً بشكل متكرر بعمليات نشر آلية تُفعَّل عند الدمج في الفرع الرئيسي.
وماذا عن المنطقة الغامضة بين CI وCD؟ إذا كان لدينا، مثلاً، اختبارات يجب تشغيلها قبل أن يمكن دمج أي شيفرة جديدة في الفرع الرئيسي، فهل هذا CI لأننا نقوم بعمليات دمج متكررة في الفرع الرئيسي، أم هو CD لأننا نتأكد من أن الفرع الرئيسي قابل للنشر دائماً؟
إذن، بعض المفاهيم تتجاوز غالباً الخط الفاصل بين CI وCD، وكما ناقشنا أعلاه، يصبح من المنطقي أحياناً اعتبار النشر بمثابة CD كجزء من CI. لهذا السبب سترى غالباً إشارات إلى CI/CD لوصف العملية بأكملها. سنستخدم المصطلحين «CI» و«CI/CD» بالتبادل في هذا الجزء.
لماذا هو مهم؟
تحدثنا أعلاه عن مشكلة «تعمل على جهازي» ونشر تغييرات متعددة، لكن ماذا عن مشكلات أخرى؟ ماذا لو أودعت Alice مباشرة في الفرع الرئيسي؟ ماذا لو استخدم Bob فرعاً لكنه لم يكلف نفسه عناء تشغيل الاختبارات قبل الدمج؟ ماذا لو حاول Charlie بناء البرمجيات للإنتاج لكنه فعل ذلك بمعاملات خاطئة؟
باستخدام التكامل المستمر وطرق عمل منهجية، يمكننا تجنب هذه الأمور.
- يمكننا منع الـ commits مباشرة إلى الفرع الرئيسي
- يمكننا تشغيل عملية CI على جميع طلبات السحب (PRs) الموجّهة إلى الفرع الرئيسي والسماح بعمليات الدمج فقط عند تحقق الشروط المطلوبة، مثل نجاح الاختبارات
- يمكننا بناء حزمنا للإنتاج في البيئة المعروفة لنظام CI
وهناك مزايا أخرى لتوسيع هذا الإعداد:
- إذا استخدمنا CI/CD مع النشر في كل مرة يحدث فيها دمج في الفرع الرئيسي، فإننا نعرف أن الشيفرة ستعمل دائماً في الإنتاج
- إذا سمحنا بعمليات الدمج فقط عندما يكون الفرع محدثاً وفق الفرع الرئيسي، فيمكننا التأكد من أن المطوّرين المختلفين لا يكتبون فوق تغييرات بعضهم بعضاً
لاحظ أننا نفترض في هذا الجزء أن الفرع main يحتوي على الشيفرة التي تعمل في الإنتاج. هناك العديد من سير العمل المختلفة التي يمكن استخدامها مع Git، فمثلاً في بعض الحالات قد يكون هناك فرع إصدار محدد يحتوي على الشيفرة التي تعمل في الإنتاج.
مبادئ مهمة
من المهم أن نتذكر أن CI/CD ليس الهدف. الهدف هو تطوير برمجيات أفضل وأسرع مع أخطاء أقل قابلة للوقاية وتعاون أفضل بين الفريق.
ولهذه الغاية، ينبغي دائماً تهيئة CI وفق المهمة المطروحة والمشروع نفسه. وينبغي إبقاء الهدف النهائي في الاعتبار في جميع الأوقات. يمكنك التفكير في CI كإجابة عن هذه الأسئلة:
- كيف نتأكد من تشغيل الاختبارات على كل الشيفرة التي ستُنشر؟
- كيف نتأكد من أن الفرع الرئيسي قابل للنشر في جميع الأوقات؟
- كيف نضمن أن عمليات البناء ستكون متسقة وستعمل دائماً على المنصة التي ستُنشر إليها؟
- كيف نتأكد من أن التغييرات لا تكتب فوق بعضها بعضاً؟
- كيف نجعل عمليات النشر تحدث بنقرة زر أو تلقائياً عند الدمج في الفرع الرئيسي؟
توجد حتى أدلة علمية على الفوائد العديدة لاستخدام CI/CD. وفقاً لدراسة كبيرة وردت في كتاب Accelerate: The Science of Lean Software and DevOps: Building and Scaling High Performing Technology Organizations، فإن استخدام CI/CD يرتبط ارتباطاً قوياً بنجاح المؤسسات (مثل تحسين الربحية وجودة المنتج، وزيادة الحصة السوقية، وتقصير الوقت حتى الوصول إلى السوق). بل إن CI/CD يجعل المطوّرين أكثر سعادة عبر تقليل معدل إرهاقهم. النتائج الملخصة في الكتاب وردت أيضاً في مقالات علمية مثل هذه.
سلوك موثّق
هناك نكتة قديمة تقول إن الخطأ ليس سوى «ميزة غير موثقة». نود تجنب ذلك. نود تجنب أي مواقف لا نعرف فيها النتيجة الدقيقة. على سبيل المثال، إذا اعتمدنا على تصنيف (label) على طلب سحب لتحديد ما إذا كان الإصدار «رئيسياً» (major) أو «ثانوياً» (minor) أو «تصحيحياً» (patch) (سنغطي معاني هذه المصطلحات لاحقاً)، فمن المهم أن نعرف ما يحدث إذا نسي مطوّر وضع تصنيف على طلبه. ماذا لو وضع تصنيفاً بعد بدء عملية البناء/الاختبار؟ ماذا يحدث إذا غيّر المطوّر التصنيف في منتصف الطريق، فأي التصنيفين هو الذي يُصدر فعلاً؟
من الممكن تغطية كل الحالات التي يمكنك التفكير فيها ومع ذلك تبقى ثغرات حيث سيفعل المطوّر شيئاً «إبداعياً» لم تفكر فيه، لذا من المهم أن تفشل العملية بأمان في هذه الحالة.
على سبيل المثال، إذا كانت لدينا الحالة المذكورة أعلاه حيث يتغير التصنيف في منتصف عملية البناء. إذا لم نفكر في هذا مسبقاً، فقد يكون من الأفضل إفشال البناء وتنبيه المستخدم إذا حدث شيء لم نكن نتوقعه. البديل، حيث ننشر نوع الإصدار الخاطئ على أي حال، قد يؤدي إلى مشكلات أكبر، لذا فإن الإفشال وإخطار المطوّر هو الطريق الأكثر أماناً للخروج من هذا الموقف.
اعرف أن الشيء نفسه يحدث في كل مرة
قد تكون لدينا أفضل اختبارات يمكن تخيلها لبرمجياتنا، اختبارات تلتقط كل مشكلة ممكنة. هذا رائع، لكنها بلا فائدة إذا لم نشغّلها على الشيفرة قبل نشرها.
نحتاج إلى ضمان تشغيل الاختبارات ونحتاج إلى التأكد من أنها تعمل على الشيفرة التي ستُنشر فعلاً. على سبيل المثال، لا فائدة إذا كانت الاختبارات تُشغَّل فقط على فرع Alice إذا كانت ستفشل بعد الدمج في الفرع الرئيسي. نحن ننشر من الفرع الرئيسي، لذا نحتاج إلى التأكد من تشغيل الاختبارات على نسخة من الفرع الرئيسي مع دمج تغييرات Alice فيه.
يقودنا هذا إلى مفهوم بالغ الأهمية. نحتاج إلى التأكد من أن الشيء نفسه يحدث في كل مرة. أو بالأحرى أن المهام المطلوبة كلها تُنفَّذ وبالترتيب الصحيح.
إبقاء الشيفرة قابلة للنشر دائماً
وجود شيفرة قابلة للنشر دائماً يجعل الحياة أسهل. هذا صحيح بشكل خاص عندما يحتوي الفرع الرئيسي على الشيفرة العاملة في بيئة الإنتاج. على سبيل المثال، إذا اكتُشف خطأ ويجب إصلاحه، يمكنك سحب نسخة من الفرع الرئيسي (مع العلم أنها الشيفرة العاملة في الإنتاج)، وإصلاح الخطأ، وإنشاء طلب سحب للعودة إلى الفرع الرئيسي. هذا مباشر نسبياً.
أما إذا كان الفرع الرئيسي والإنتاج مختلفين جداً والفرع الرئيسي غير قابل للنشر، فسيتعين عليك معرفة أي شيفرة تعمل في الإنتاج فعلاً، وسحب نسخة منها، وإصلاح الخطأ، وإيجاد طريقة لدفعها مرة أخرى، ثم معرفة كيفية نشر ذلك الـ commit تحديداً. هذا ليس جيداً وسيتعين أن يكون سير عمل مختلفاً تماماً عن النشر العادي.
معرفة الشيفرة المنشورة (sha sum/version)
غالباً ما يكون من المهم معرفة ما يعمل فعلاً في الإنتاج. من الناحية المثالية، وكما ناقشنا أعلاه، سيكون لدينا الفرع الرئيسي عاملاً في الإنتاج. وهذا ليس ممكناً دائماً. أحياناً نعتزم وجود الفرع الرئيسي في الإنتاج لكن يفشل البناء، وأحياناً نجمع عدة تغييرات معاً ونريد نشرها كلها دفعة واحدة.
ما نحتاجه في هذه الحالات (وهو فكرة جيدة عموماً) هو معرفة أي شيفرة تعمل في الإنتاج بدقة. أحياناً يمكن فعل ذلك برقم إصدار، وأحياناً يكون من المفيد إرفاق قيمة sha للـ commit (تجزئة (hash) تعرّف ذلك الـ commit تحديداً في git بشكل فريد) بالشيفرة. سنناقش الإصدارات بمزيد من التفصيل لاحقاً قليلاً في هذا الجزء.
ويكون الأمر أكثر فائدة إذا جمعنا معلومات الإصدار مع سجل بجميع الإصدارات. إذا اكتشفنا، مثلاً، أن commit معيناً قد أدخل خطأً، يمكننا معرفة وقت إصداره بدقة وعدد المستخدمين المتأثرين. يكون هذا مفيداً بشكل خاص عندما يكون ذلك الخطأ قد كتب بيانات سيئة في قاعدة البيانات. سنكون حينها قادرين على تتبع أين ذهبت تلك البيانات السيئة بناءً على الوقت.
أنواع إعداد CI
لتلبية بعض المتطلبات المذكورة أعلاه، نريد تخصيص خادم منفصل لتشغيل مهام التكامل المستمر. وجود خادم منفصل لهذا الغرض يقلل من خطر أن يتداخل شيء آخر مع عملية CI/CD ويجعلها غير قابلة للتنبؤ.
هناك خياران: استضافة خادمنا الخاص أو استخدام خدمة سحابية.
Jenkins (وإعدادات الاستضافة الذاتية الأخرى)
من بين خيارات الاستضافة الذاتية، يُعد Jenkins الأكثر شيوعاً. إنه مرن للغاية وهناك إضافات لكل شيء تقريباً (باستثناء ذلك الشيء الوحيد الذي تريد فعله). هذا خيار رائع لكثير من التطبيقات، فاستخدام إعداد مستضاف ذاتياً يعني أن البيئة بأكملها تحت سيطرتك، ويمكن التحكم في عدد الموارد، ولا تُكشف الأسرار (سنوضح المزيد عن الأمان في أقسام لاحقة من هذا الجزء) لأي شخص آخر، ويمكنك فعل أي شيء تريد على العتاد.
لسوء الحظ، هناك أيضاً جانب سلبي. إعداد Jenkins معقد نوعاً ما. إنه مرن جداً لكن هذا يعني أن هناك غالباً قدراً لا بأس به من الشيفرة النمطية/القوالب لجعل عمليات البناء تعمل. وبالنسبة لـ Jenkins تحديداً، يعني هذا أيضاً أنه يجب إعداد CI/CD بلغة Jenkins الخاصة بالمجال. وهناك أيضاً مخاطر أعطال العتاد التي قد تكون مشكلة إذا كان الإعداد يُستخدم بكثافة.
في خيارات الاستضافة الذاتية، عادةً ما تعتمد الفوترة على العتاد. أنت تدفع مقابل الخادم. وما تفعله على الخادم لا يغيّر الفوترة.
GitHub Actions والحلول السحابية الأخرى
في إعداد مستضاف سحابياً، لا داعي للقلق بشأن تهيئة البيئة. إنها موجودة، وكل ما عليك فعله هو إخبارها بما يجب فعله. يتضمن فعل ذلك عادةً وضع ملف في مستودعك ثم إخبار نظام CI بقراءة الملف (أو بفحص مستودعك بحثاً عن ذلك الملف تحديداً).
غالباً ما تكون تهيئة CI الفعلية للخيارات السحابية أبسط قليلاً، على الأقل إذا بقيت ضمن ما يُعتبر استخداماً «عاديًا». وإذا أردت فعل شيء أكثر خصوصية قليلاً، فقد تصبح الخيارات السحابية أكثر محدودية، أو قد تجد صعوبة في أداء تلك المهمة المحددة التي لم تُبنَ المنصة السحابية من أجلها.
في هذا الجزء، سننظر في حالة استخدام عادية إلى حد كبير. قد تستفيد الإعدادات الأكثر تعقيداً، مثلاً، من موارد عتاد محددة، مثل وحدة معالجة رسومات (GPU).
بصرف النظر عن مسألة التهيئة المذكورة أعلاه، غالباً ما تكون هناك قيود على الموارد في المنصات السحابية. في إعداد مستضاف ذاتياً، إذا كان البناء بطيئاً، يمكنك ببساطة الحصول على خادم أكبر وإغراقه بمزيد من الموارد. أما في الخيارات السحابية، فقد لا يكون هذا ممكناً. على سبيل المثال، في الطبقة المجانية من GitHub Actions، تحتوي العقد التي ستعمل عليها عمليات البناء على 4 وحدات vCPU و16GB من الذاكرة العشوائية.
تُحاسب الخيارات السحابية عادةً أيضاً حسب وقت البناء، وهو أمر يستحق النظر.
لماذا نختار أحدهما على الآخر
عموماً، إذا كان لديك مشروع برمجيات صغير إلى متوسط لا يتضمن أي متطلبات خاصة (مثل الحاجة إلى بطاقة رسومات لتشغيل الاختبارات)، فمن المحتمل أن يكون الحل السحابي هو الأفضل. التهيئة بسيطة ولا تحتاج إلى عناء أو تكلفة إعداد نظامك الخاص. وبالنسبة للمشاريع الأصغر خاصةً، ينبغي أن يكون هذا أرخص.
أما المشاريع الأكبر حيث تكون هناك حاجة إلى مزيد من الموارد، أو الشركات الأكبر حيث توجد فرق ومشاريع متعددة يمكنها الاستفادة منه، فمن المحتمل أن يكون إعداد CI المستضاف ذاتياً هو الطريق الأنسب.
أصبحت الخصوصية عاملاً أكثر بروزاً بكثير في قرارات CI. يدمج العديد من مزوّدي CI السحابيين الآن ميزات مدعومة بالذكاء الاصطناعي تحلل سجلات البناء ومخرجات الاختبار وبيانات المستودع الوصفية. وبينما يقدم البائعون خيارات إلغاء الاشتراك وحمايات تعاقدية، فإن بعض المؤسسات لا ترتاح لأي وصول طرف ثالث إلى الشيفرة الداخلية أو مخرجات البناء.
يتجنب CI المستضاف ذاتياً هذا الأمر تماماً عبر إبقاء جميع السجلات والمخرجات وبيانات خط الأنابيب داخل بنيتك التحتية الخاصة. وبالنسبة للشركات ذات قواعد صارمة بشأن موقع البيانات، أو الملكية الفكرية الحساسة، أو الالتزامات التنظيمية، غالباً ما يكون هذا المستوى من التحكم ميزة حاسمة، حتى عندما يكون CI السحابي أكثر ملاءمة من الناحية الأخرى.
لماذا نستخدم GitHub Actions في هذه الدورة
في هذه الدورة، سنستخدم GitHub Actions. إنه خيار واضح لأننا نستخدم GitHub على أي حال. يمكننا الحصول على حل CI قوي يعمل فوراً دون أي عناء إعداد خادم أو تهيئة خدمة سحابية تابعة لطرف ثالث.
إلى جانب سهولة البدء باستخدامه، يُعد GitHub Actions خياراً جيداً من نواحٍ أخرى. قد يكون أفضل حل سحابي في الوقت الحالي. وقد اكتسب شعبية كبيرة منذ إطلاقه الأول في نوفمبر 2019.
1. تمرين تسخيني