إنّ التكامل المستمر (Continuous integration) سهل للغاية. نزّل خدمة الأتمتة مفتوحة المصدر Jenkins، وثبّتها، وأنشئ وظيفة، وانقر على الزر، ثم احصل على رسالة بريد إلكتروني جميلة تفيد بأن إنشاءك مكسور أو معطّل (أفترض أن إنشاءك تلقائي). بعد ذلك، أصلح الاختبارات التي لا تعمل (أفترض كذلك أن لديك اختبارات)، واحصل على رسالة بريد إلكتروني أجمل تفيد أن إنشاءك على ما يرام.
بعد ذلك، غرّد حول الموضوع مدعيا أن فريقك يستخدم التكامل المستمر.
ثم في غضون أسابيع قليلة، ابدأ في فلترة تنبيهات Jenkins إلى مجلدها الخاص لكي لا تستمرّ بإزعاجك. على أي حال، ليس لدى فريقك الوقت أو الرغبة لإصلاح جميع اختبارات الوحدة في كل مرة يعطّلها شخص ما.
بعد كل شيء، نعلم جميعًا أن اختبارات الوحدة لا تناسب فريقًا يعمل وفق مواعيد نهائية محدّدة، أليس كذلك؟ هذا خطأ. يمكن للتكامل المستمر أن يعمل في هذه الظروف بل ويجب أن يعمل فيها.
ما هو التكامل المستمر؟
في الوقت الحاضر، تُطوّر البرمجيات في فرق نعمل على تطوير فروعٍ للميزات وعزل التعديلات أثناء تطويرها. ثم ندمج الفروع في فرع رئيسي master
. وبعد كل عملية دمج، يُختبر المنتج بالكامل، وتُنفّذ جميع اختبارات الوحدة والتكامل المتاحة. وهذا ما يسمى «التكامل المستمر» (continuous integration ويعرف أيضا بالاختصار "CI").
في بعض الأحيان، تفشل بعض الاختبارات. عندما يحدث ذلك، نقول إن "البناءات مكسورة". مثل هذا الفشل هو أحد الآثار الجانبية الإيجابية لمراقبة الجودة لأنه يعطي تنبيهًا بعلامة حمراء فور حدوث خطأ ما. هذه ممارسة معروفة في تطوير البرمجيات، عندما يصبح إصلاح هذا الخطأ أولوية قصوى للمتسبّب فيه وللفريق بأكمله. إذ يتوجّب إصلاح الخطأ مباشرة بعد أن يرسل خادم التكامل المستمر تنبيهًا بالعلامة الحمراء.
هناك بعض الأدوات الجيدة المتاحة في السوق، والتي تُؤتمت إجراءات DevOps. بعضها مفتوح المصدر يمكنك تنزيله وتثبيته على الخوادم الخاصة بك. نذكر منها على سبيل المثال: Jenkins و Go و CruiseControl. وبعضها الآخر متاح كخدمات سحابية، مثل: Travis و Shippable و Wercker وغيرها الكثير.
لماذا لم يعد التكامل المستمر صالحًا؟
إن التكامل المستمر رائعٌ، ولكن في أغلب الأحيان كلما كان الفريق أكبر (وقاعدة الشيفرة كذلك)، كلما تعطلت الإنشاءات وكلما طالت المدة لإصلاحها. لقد رأيت العديد من الأمثلة يبدأ فيها فريق يعمل بجِدٍّ بتجاهل التنبيهات الحمراء، التي يرسلها Jenkins. بعد بضعة أسابيع، يصبح الفريق ببساطة غير قادر على إصلاح جميع الأخطاء في الوقت المناسب. وهذا، في الغالب، لأن العمل له أولويات أخرى. إذ لا يفهم مالكو المنتجات أهمية "البنية النظيفة" ولا يمكن للمدراء التقنيين شراء الوقت لتثبيت اختبارات الوحدة. كما أن الشيفرة المكسورة تكون أصلا في الفرع الرئيسي master
، و في معظم الحالات، تكون قد نُشرت بالفعل على الإنتاج وسُلّمت للمستخدمين النهائيين. فما الحاجة إذن لإصلاح الاختبارات إذا كان العمل قد سُلّم فعليًا؟
اقتباسلا يفهم مالكو المنتجات أهمية "البنية النظيفة" ولا يمكن للمدراء التقنيين شراء الوقت لتثبيت اختبارات الوحدة
لا تأخذ معظم فرق التطوير تنبيهات التكامل المستمر على محمل الجد. لا تمثّل Jenkins أو Travis بالنسبة لهم سوى مجرد أدوات لطيفة لا تلعب أي دور في عملية التطوير والتسليم بأكملها. بغض النظر عن ما يقوله خادم التكامل المستمر، مازلنا نقدم ميزات جديدة للمستخدمين النهائيين. ونترك إصلاح إنشائنا إلى وقت لاحق. وهذا منطقي بالنسبة لي.
ما هو الحل؟
منذ بضع سنوات، نشرت مقالًا بعنوان "منع التعارضات في مشاريع PHP الموزّعة والمرنة". اقترحت في المقالة حلولًا لهذه الإشكالات في Subversion و PHP.
منذ ذلك الوقت، استخدمت هذا النهج تجريبيًا في عدد من المشاريع مفتوحة المصدر وبعض المشاريع التجارية أيضا في PHP وجافا وروبي وجافاسكريبت و Git و Subversion. في جميع الحالات، كانت تجربتي إيجابية، ولهذا السبب رأى rultor.com النور لاحقًا.
لذلك، فإن الحل بسيط للغاية: احظُر على أي شخص دمج أي شيء في الفرع الرئيسي master وأنشئ سكريبتًا يمكن لأي شخص استدعاؤه. سيقوم السكريبت بعمليات الدمج والاختبار والتنفيذ. لن تكون لدى السكريبت أي استثناءات. فإذا انكسر أي فرع في اختبار واحد، سيرفض الفرع بأكمله.
بمعنى آخر، يجب أن تظهر تلك العلامة الحمراء للتنبيه قبل أن تنتقل الشيفرة إلى الفرع الرئيسي master
. ويجب أن يتحمّل مسؤولية الاختبارات المكسورة من تسبّب فيها.
لنفترض أنّني أقوم بتطوير ميزة في فرعي الخاص. انتهيت من التطوير وكسرت بعض الاختبارات عن طريق الخطأ. يحدث ذلك، فنحن جميعا نرتكب أخطاء. ولكن لا يمكنني دمج تعديلاتي في Master
. سيرفض Git ببساطة تنفيذ الأمر push
لأنني لا أملك الأذونات المناسبة. كل ما يمكنني فعله هو أن أستدعي السكريبت السحري، وأطلب منه دمج فرعي الخاص. سيحاول السكريبت الدمج، ولكن قبل الدخول إلى الرئيسية، ستشغّل جميع الاختبارات. وإذا كُسِر أي منها، سيكون الرفض نتيجة حتمية. لن تُدمج التعديلات التي أجريتها وأصبح لزامًا عليّ إصلاحها قبل استدعاء السكريبت مرة أخرى.
قد يؤدي هذا النهج في البداية إلى إبطاء عملية التطوير، لأن على الجميع بدء كتابة تعليمات برمجية أنظف. ولكن في النهاية، فإن هذه الطريقة تؤتي ثمارها.
إنشاءات ما قبل الإقلاع
تقدم بعض خوادم التكامل المستمرّ CI ميزة "إنشاءات ما قبل الإقلاع"، وهذا يعني اختبار الفروع قبل دمجها في master
رئيسي. لدى Travis، على سبيل المثال، هذه الميزة المفيدة للغاية. عندما تقوم بإيداع جديد في فرع ما، يحاول Travis إنشاءه على الفور، ويُبلغ عبر طلبات الإضافة في GitHub عن أي مشاكل قد تحدث.
انتبه، فإنشاءات ما قبل الإقلاع لا تندمج. دورها فقط هو التحقّق مما إذا كان فرعك الخاصّ نظيفًا. بعد الدمج، يمكن بسهولة كسر الفرع الرئيسي master
. لذا، فهذه الآلية لا تضمن أنه لا أحد يستطيع الإيداع بشكل مباشر، والتسبب بكسر عن طريق الخطأ. تبقى عمليات الإنشاء قبل الإقلاع تدبيرًا وقائيًا، لكنها لا تحل المشكلة تمامًا.
موقع Rultor.com
من أجل البدء في العمل وفق ما هو موضح أعلاه، كل ما عليك فعله هو إلغاء أذونات الكتابة في الفرع الرئيسي master
(أو /trunk
، في Subversion).
لسوء الحظ، هذا غير ممكن في GitHub. الحل الوحيد هو العمل من خلال الفروع وطلبات السحب فقط. ما عليك سوى إزالة الجميع من قائمة المتعاونين (collaborators) وسيكون عليهم إرسال تعديلاتهم من خلال طلبات السحب.
بعد ذلك، ابدأ في استخدام موقع rultor.com الذي سيساعدك على اختبار كل طلب للإضافة ودمجه ودفعه. في الأساس، Rultor هو السيناريو الذي كنا نتحدث عنه أعلاه، وهو متاح كخدمة سحابية مجانية.
ترجمة -وبتصرف- للمقال Master Branch Must Be Read-Only لصاحبه Yegor Bugayenko
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.