تطور CI في فريق تطوير الهاتف المحمول

اليوم، يتم تطوير معظم منتجات البرمجيات في فرق. يمكن تمثيل شروط التطوير الناجح للفريق في شكل رسم تخطيطي بسيط.

تطور CI في فريق تطوير الهاتف المحمول

بمجرد كتابة الكود الخاص بك، عليك التأكد من أنه:

  1. إنه يعمل.
  2. إنه لا يكسر أي شيء، بما في ذلك الكود الذي كتبه زملائك.

إذا توفرت كلا الشرطين، فأنت على طريق النجاح. ولتسهيل التحقق من هذه الشروط وعدم الانحراف عن المسار المربح، توصلنا إلى التكامل المستمر.

CI عبارة عن سير عمل حيث تقوم بدمج الكود الخاص بك في كود المنتج الإجمالي كلما كان ذلك ممكنًا. وأنت لا تقوم بالتكامل فحسب، بل تتحقق أيضًا باستمرار من أن كل شيء يعمل. نظرًا لأنك تحتاج إلى التحقق كثيرًا وفي كثير من الأحيان، فمن المفيد التفكير في الأتمتة. يمكنك التحقق من كل شيء يدويًا، ولكن لا ينبغي عليك ذلك، وإليك السبب.

  • يا شعبنا العزيز. ساعة عمل أي مبرمج أغلى من ساعة عمل أي خادم.
  • الناس يخطئون. لذلك، قد تنشأ مواقف عند إجراء الاختبارات على الفرع الخطأ أو عند تجميع الالتزام الخاطئ للمختبرين.
  • الناس كسالى. من وقت لآخر، عندما أنهي مهمة ما، تخطر على بالي فكرة: "ما الذي يجب التحقق منه؟ كتبت سطرين - كل شيء يعمل! أعتقد أن بعضكم أيضًا تراوده أحيانًا مثل هذه الأفكار. ولكن يجب عليك التحقق دائما.

يقول نيكولاي نيستيروف: كيف تم تنفيذ التكامل المستمر وتطويره في فريق تطوير الأجهزة المحمولة Avito، وكيف انتقلوا من 0 إلى 450 نسخة يوميًا، وكيف يتم تجميع آلات البناء 200 ساعة يوميًا (نيستيروف) هو أحد المشاركين في جميع التغييرات التطورية لتطبيق CI/CD Android.

تستند القصة إلى مثال أمر Android، ولكن معظم الأساليب قابلة للتطبيق على نظام التشغيل iOS أيضًا.


ذات مرة، عمل شخص واحد في فريق Avito Android. بحكم التعريف، لم يكن بحاجة إلى أي شيء من التكامل المستمر: لم يكن هناك من يتكامل معه.

لكن التطبيق نما، وظهرت المزيد والمزيد من المهام الجديدة، ونما الفريق وفقًا لذلك. في مرحلة ما، حان الوقت لإنشاء عملية تكامل التعليمات البرمجية بشكل أكثر رسمية. تقرر استخدام Gitflow.

تطور CI في فريق تطوير الهاتف المحمول

مفهوم تدفق Git معروف جيدًا: يحتوي المشروع على فرع تطوير مشترك واحد، ولكل ميزة جديدة، يقوم المطورون بقطع فرع منفصل، والالتزام به، والدفع، وعندما يريدون دمج التعليمات البرمجية الخاصة بهم في فرع التطوير، افتح طلب سحب. لمشاركة المعرفة ومناقشة الأساليب، قدمنا ​​مراجعة التعليمات البرمجية، أي أنه يجب على الزملاء التحقق من رموز بعضهم البعض والتأكد منها.

الشيكات

إن رؤية الكود بعينيك أمر رائع، ولكنه ليس كافيًا. ولذلك، يتم تقديم الشيكات التلقائية.

  • أولا وقبل كل شيء، نتحقق تجميع آرك.
  • كثير اختبارات جونيت.
  • نحن نعتبر تغطية التعليمات البرمجية، لأننا نجري الاختبارات.

لفهم كيفية إجراء هذه الاختبارات، دعونا نلقي نظرة على عملية التطوير في Avito.

ويمكن تمثيلها بشكل تخطيطي مثل هذا:

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

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

لقد أحببنا حقًا إجراء عمليات التحقق ليلاً، نظرًا لوجود الكثير من الوقت والخوادم، حيث يمكنك التجول. ولكن، لسوء الحظ، عندما يبدأ تطوير كود الميزة، يكون لدى المطور حافز أقل بكثير لإصلاح الأخطاء التي اكتشفها CI. لقد وجدت نفسي أفكر بشكل دوري عندما نظرت إلى جميع الأخطاء الموجودة في التقرير الصباحي بأنني سأصلحها يومًا ما في وقت لاحق، لأنه توجد الآن مهمة جديدة رائعة في Jira أريد فقط البدء في تنفيذها.

إذا حظرت عمليات التحقق طلب سحب، فهذا يعني أن هناك حافزًا كافيًا، لأنه حتى تتحول البنيات إلى اللون الأخضر، فلن يتم تطوير الكود، مما يعني أن المهمة لن تكتمل.

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

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

لقد استغرق الأمر منا يومين لإعداد CI الأساسي بالكامل (يشار إليه فيما يلي بتقدير الوقت تقريبي، وهو ضروري للقياس).

بعد ذلك، بدأنا في التفكير أكثر - هل نتحقق بشكل صحيح؟ هل نقوم بتشغيل بنيات على طلبات السحب بشكل صحيح؟

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

تطور CI في فريق تطوير الهاتف المحمول

للقيام بذلك، كتبنا نص باش بسيط premerge.sh:

#!/usr/bin/env bash

set -e

git fetch origin develop

git merge origin/develop

هنا يتم ببساطة سحب جميع التغييرات الأخيرة من التطوير ودمجها في الفرع الحالي. أضفنا البرنامج النصي premerge.sh كخطوة أولى في جميع الإصدارات وبدأنا في التحقق مما نريده بالضبط دمج.

استغرق الأمر ثلاثة أيام لترجمة المشكلة وإيجاد حل وكتابة هذا البرنامج النصي.

تم تطوير التطبيق، وظهرت المزيد والمزيد من المهام، ونما الفريق، وبدأ premerge.sh أحيانًا في خذلاننا. كان لدى التطوير تغييرات متضاربة أدت إلى كسر البناء.

مثال لكيفية حدوث ذلك:

تطور CI في فريق تطوير الهاتف المحمول

يبدأ مطوران العمل في الوقت نفسه على الميزتين A وB. ويكتشف مطور الميزة A ميزة غير مستخدمة في المشروع answer() ويزيله مثل فتى الكشافة الجيد. وفي الوقت نفسه، يضيف مطور الميزة (ب) استدعاءً جديدًا لهذه الوظيفة في فرعه.

ينهي المطورون عملهم ويفتحون طلب سحب في نفس الوقت. يتم إطلاق الإصدارات، ويقوم premerge.sh بالتحقق من طلبات السحب فيما يتعلق بأحدث حالة تطوير - تكون جميع عمليات التحقق باللون الأخضر. بعد ذلك، يتم دمج طلب السحب للميزة A، ويتم دمج طلب السحب للميزة B... Boom! قم بتطوير الفواصل لأن كود التطوير يحتوي على استدعاء لوظيفة غير موجودة.

تطور CI في فريق تطوير الهاتف المحمول

عندما لا يتطور، فهو كذلك كارثة محلية. لا يمكن للفريق بأكمله جمع أي شيء وتقديمه للاختبار.

لقد حدث أنني عملت في أغلب الأحيان في مهام البنية التحتية: التحليلات والشبكات وقواعد البيانات. أي أنني أنا من كتب تلك الوظائف والفئات التي يستخدمها المطورون الآخرون. ولهذا السبب، وجدت نفسي في مواقف مماثلة في كثير من الأحيان. حتى أنني كنت أعلق هذه الصورة لفترة من الوقت.

تطور CI في فريق تطوير الهاتف المحمول

وبما أن هذا لا يناسبنا، فقد بدأنا في استكشاف الخيارات حول كيفية منع ذلك.

كيف لا تنكسر

الخيار الأول: إعادة بناء جميع طلبات السحب عند تحديث التطوير. إذا كان طلب السحب مع الميزة A، في مثالنا، هو أول طلب يتم تضمينه في التطوير، فستتم إعادة بناء طلب السحب الخاص بالميزة B، وبالتالي، ستفشل عمليات التحقق بسبب خطأ في الترجمة.

لفهم المدة التي سيستغرقها ذلك، فكر في مثال مع اثنين من العلاقات العامة. نفتح اثنين من العلاقات العامة: بنيتان، وعمليتان من الشيكات. بعد دمج العلاقات العامة الأولى في التطوير، يجب إعادة بناء الثانية. في المجمل، يتطلب ممثلان رئيسيان ثلاث عمليات فحص: 2 + 1 = 3.

من حيث المبدأ، لا بأس. لكننا نظرنا إلى الإحصائيات، وكان الوضع النموذجي في فريقنا هو 10 نقاط وصول مفتوحة، ومن ثم فإن عدد الشيكات هو مجموع التقدم: 10 + 9 +... + 1 = 55. أي قبول 10 أيها العلاقات العامة، أنت بحاجة إلى إعادة البناء 55 مرة. وهذا هو الوضع المثالي، عندما تمر جميع الشيكات في المرة الأولى، عندما لا يفتح أحد طلب سحب إضافي أثناء معالجة هذه العشرات.

تخيل نفسك كمطور يحتاج إلى أن يكون أول من ينقر على زر "الدمج"، لأنه إذا قام أحد الجيران بذلك، فسيتعين عليك الانتظار حتى تتم جميع الإصدارات مرة أخرى... لا، لن ينجح هذا ، فإنه سوف يبطئ التنمية بشكل خطير.

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

ونتيجة لذلك، بقي الخيار الثالث فقط - ركوب الدراجات. يتم تخزين كل التعليمات البرمجية الخاصة بنا وجميع مصادرنا في مستودع على خادم Bitbucket. وفقًا لذلك، كان علينا تطوير مكون إضافي لـ Bitbucket.

تطور CI في فريق تطوير الهاتف المحمول

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

تطور CI في فريق تطوير الهاتف المحمول

في مثالنا الذي يتضمن تغييرات متعارضة، ستفشل هذه الإصدارات بسبب خطأ في الترجمة. وفقًا لذلك، سيتعين على مطور الميزة B تصحيح الكود، وإعادة تشغيل عمليات التحقق، ثم سيقوم المكون الإضافي تلقائيًا بتطبيق طلب السحب.

قبل تنفيذ هذا البرنامج المساعد، بلغ متوسط ​​عدد عمليات المراجعة 2,7 لكل طلب سحب. مع البرنامج المساعد كان هناك 3,6 عملية إطلاق. هذا يناسبنا.

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

لقد استغرق الأمر منا أسبوعين لكتابة الإصدار الأول من البرنامج المساعد Bitbucket.

الشيكات الجديدة

وفي الوقت نفسه، واصل فريقنا النمو. تمت إضافة شيكات جديدة.

لقد فكرنا: لماذا نرتكب الأخطاء إذا كان من الممكن منعها؟ ولهذا السبب قاموا بتنفيذها تحليل الكود الثابت. لقد بدأنا باستخدام الوبر المضمن في Android SDK. ولكن في ذلك الوقت لم يكن يعرف كيفية العمل مع كود Kotlin على الإطلاق، وكان لدينا بالفعل 75٪ من التطبيق مكتوبًا بلغة Kotlin. لذلك، تمت إضافة تلك المضمنة إلى الوبر الشيكات الروبوت ستوديو.

للقيام بذلك، كان علينا القيام بالكثير من الانحراف: أخذ Android Studio، وحزمه في Docker وتشغيله على CI باستخدام شاشة افتراضية، بحيث يعتقد أنه يعمل على كمبيوتر محمول حقيقي. لكنها نجحت.

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

ولكن يجب إجراء اختبارات الأجهزة واختبارات لقطات الشاشة على الأجهزة: على أجهزة محاكاة أو على أجهزة حقيقية. وبالنظر إلى أن هناك الكثير من الاختبارات ويتم إجراؤها بشكل متكرر، هناك حاجة إلى مزرعة كاملة. يتطلب إنشاء مزرعتك الخاصة عمالة كثيفة للغاية، لذلك وجدنا خيارًا جاهزًا - Firebase Test Lab.

مختبر اختبار Firebase

تم اختياره لأن Firebase هو أحد منتجات Google، مما يعني أنه يجب أن يكون موثوقًا به ومن غير المرجح أن يتوقف أبدًا. الأسعار معقولة: 5 دولارات لكل ساعة تشغيل لجهاز حقيقي، و1 دولار لكل ساعة تشغيل لجهاز محاكاة.

استغرق تنفيذ Firebase Test Lab في CI لدينا ما يقرب من ثلاثة أسابيع.

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

دوكر + بايثون + باش

لقد أخذنا Docker، وقمنا بحشو المحاكيات فيه، وكتبنا برنامجًا بسيطًا بلغة Python، والذي يقوم في اللحظة المناسبة بإحضار العدد المطلوب من المحاكيات في الإصدار المطلوب وإيقافها عند الضرورة. وبطبيعة الحال، بضعة نصوص باش - أين سنكون بدونهم؟

استغرق الأمر خمسة أسابيع لإنشاء بيئة الاختبار الخاصة بنا.

ونتيجة لذلك، كان هناك قائمة شاملة من عمليات التحقق من حظر الدمج لكل طلب سحب:

  • تجميع آرك؛
  • اختبارات جونيت؛
  • لينت؛
  • فحوصات Android Studio؛
  • اختبارات الأجهزة؛
  • اختبارات لقطة الشاشة.

هذا منع العديد من الأعطال المحتملة. من الناحية الفنية، نجح كل شيء، لكن المطورين اشتكوا من أن انتظار النتائج كان طويلاً للغاية.

ما هي مدة طويلة جدا؟ لقد قمنا بتحميل البيانات من Bitbucket وTeamCity إلى نظام التحليل وأدركنا ذلك متوسط ​​وقت الانتظار 45 دقيقة. أي أن المطور، عند فتح طلب سحب، ينتظر في المتوسط ​​45 دقيقة للحصول على نتائج البناء. في رأيي هذا كثير ولا يمكنك العمل بهذه الطريقة.

وبطبيعة الحال، قررنا تسريع جميع بنياتنا.

دعونا تسريع

نظرًا لأن التصميمات غالبًا ما تقف في قائمة الانتظار، فإن أول شيء نفعله هو اشترى المزيد من الأجهزة — التطوير الشامل هو الأبسط. توقفت الإصدارات عن الوقوف في قائمة الانتظار، لكن وقت الانتظار انخفض قليلاً فقط، لأن بعض عمليات التحقق نفسها تستغرق وقتًا طويلاً جدًا.

إزالة الشيكات التي تستغرق وقتا طويلا

يمكن أن يؤدي تكاملنا المستمر إلى اكتشاف هذه الأنواع من الأخطاء والمشكلات.

  • لست ذاهبآ إلى. يمكن لـ CI اكتشاف خطأ في الترجمة عندما لا يتم إنشاء شيء ما بسبب التغييرات المتعارضة. كما قلت، فلا يمكن لأحد أن يجمع أي شيء، ويتوقف التطوير، ويتوتر الجميع.
  • الخلل في السلوك. على سبيل المثال، عندما يتم إنشاء التطبيق، ولكنه يتعطل عند الضغط على زر، أو عند عدم الضغط على الزر على الإطلاق. وهذا أمر سيء لأن مثل هذا الخطأ يمكن أن يصل إلى المستخدم.
  • خطأ في التخطيط. على سبيل المثال، يتم النقر فوق زر، ولكنه يتحرك بمقدار 10 بكسل إلى اليسار.
  • زيادة الديون الفنية.

بعد النظر إلى هذه القائمة، أدركنا أن النقطتين الأوليين فقط هما المهمتان. نريد أن نكتشف مثل هذه المشاكل أولاً. يتم اكتشاف الأخطاء الموجودة في التخطيط في مرحلة مراجعة التصميم ويمكن تصحيحها بسهولة بعد ذلك. يتطلب التعامل مع الديون الفنية عملية وتخطيطًا منفصلين، لذلك قررنا عدم اختباره عند طلب السحب.

وبناء على هذا التصنيف قمنا بتعديل قائمة الشيكات بأكملها. شطب لينت وأجلت إطلاقه بين عشية وضحاها: فقط حتى تتمكن من إنتاج تقرير عن عدد المشاكل الموجودة في المشروع. اتفقنا على العمل بشكل منفصل مع الديون الفنية، و تم التخلي تمامًا عن عمليات فحص Android Studio. يبدو Android Studio في Docker لإجراء عمليات الفحص مثيرًا للاهتمام، ولكنه يسبب الكثير من المتاعب في الدعم. أي تحديث لإصدارات Android Studio يعني صراعًا مع الأخطاء غير المفهومة. كان من الصعب أيضًا دعم اختبارات لقطات الشاشة، لأن المكتبة لم تكن مستقرة جدًا وكانت هناك نتائج إيجابية كاذبة. تمت إزالة اختبارات لقطة الشاشة من قائمة التحقق.

ونتيجة لذلك بقي لنا:

  • تجميع آرك؛
  • اختبارات جونيت؛
  • اختبارات الأجهزة.

Gradle ذاكرة التخزين المؤقت عن بعد

وبدون فحوصات ثقيلة، أصبح كل شيء أفضل. ولكن ليس هناك حد للكمال!

تم بالفعل تقسيم تطبيقنا إلى حوالي 150 وحدة نمطية. عادةً ما تعمل ذاكرة التخزين المؤقت البعيدة لـ Gradle بشكل جيد في هذه الحالة، لذلك قررنا تجربتها.

ذاكرة التخزين المؤقت عن بعد لـ Gradle هي خدمة يمكنها تخزين عناصر البناء مؤقتًا للمهام الفردية في الوحدات النمطية الفردية. يستخدم Gradle، بدلاً من تجميع التعليمات البرمجية فعليًا، HTTP للطرق على ذاكرة التخزين المؤقت البعيدة والسؤال عما إذا كان شخص ما قد قام بالفعل بهذه المهمة. إذا كانت الإجابة بنعم، فإنه ببساطة يقوم بتنزيل النتيجة.

يعد تشغيل ذاكرة التخزين المؤقت البعيدة لـ Gradle أمرًا سهلاً لأن Gradle يوفر صورة Docker. تمكنا من القيام بذلك في ثلاث ساعات.

كل ما عليك فعله هو تشغيل Docker وكتابة سطر واحد في المشروع. ولكن على الرغم من إمكانية إطلاقه بسرعة، إلا أن الأمر سيستغرق الكثير من الوقت حتى يعمل كل شيء بشكل جيد.

يوجد أدناه الرسم البياني لذاكرة التخزين المؤقت المفقودة.

تطور CI في فريق تطوير الهاتف المحمول

في البداية، كانت نسبة فقدان ذاكرة التخزين المؤقت حوالي 65. وبعد ثلاثة أسابيع، تمكنا من زيادة هذه القيمة إلى 20٪. اتضح أن المهام التي يجمعها تطبيق Android لها تبعيات متعدية غريبة، مما أدى إلى فقدان Gradle لذاكرة التخزين المؤقت.

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

تحليل التأثير

بناءً على طلب السحب، نقوم بجمع git diff والعثور على وحدات Gradle المعدلة.

تطور CI في فريق تطوير الهاتف المحمول

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

اختبارات الأجهزة ليست بهذه البساطة، لأنها يجب أن تكون موجودة في وحدة التطبيق ذات المستوى الأعلى. استخدمنا الاستدلال مع تحليل الرمز الثانوي لفهم الوحدة النمطية التي ينتمي إليها كل اختبار.

استغرق تحديث تشغيل اختبارات الأجهزة بحيث يتم اختبار الوحدات المعنية فقط حوالي ثمانية أسابيع.

وقد نجحت التدابير الرامية إلى تسريع عمليات التفتيش. من 45 دقيقة ارتفعنا إلى حوالي 15 دقيقة. ومن الطبيعي بالفعل الانتظار لمدة ربع ساعة حتى يتم البناء.

ولكن الآن بدأ المطورون في الشكوى من أنهم لا يفهمون أي الإصدارات يتم إطلاقها، وأين يمكن رؤية السجل، ولماذا يكون الإصدار أحمر، وأي اختبار فشل، وما إلى ذلك.

تطور CI في فريق تطوير الهاتف المحمول

تؤدي مشكلات التعليقات إلى إبطاء عملية التطوير، لذلك حاولنا تقديم المعلومات الأكثر وضوحًا وتفصيلاً حول كل عملية علاقات عامة وبناء. لقد بدأنا بتعليقات في Bitbucket للعلاقات العامة، تشير إلى الإصدار الذي فشل وسبب فشله، وكتبنا رسائل مستهدفة في Slack. في النهاية، قمنا بإنشاء لوحة معلومات العلاقات العامة للصفحة مع قائمة بجميع الإصدارات قيد التشغيل حاليًا وحالتها: في قائمة الانتظار، أو قيد التشغيل، أو معطلة، أو مكتملة. يمكنك النقر فوق البناء والوصول إلى السجل الخاص به.

تطور CI في فريق تطوير الهاتف المحمول

تم قضاء ستة أسابيع في الحصول على تعليقات مفصلة.

خطط

دعنا ننتقل إلى التاريخ الحديث. بعد حل مشكلة التعليقات، وصلنا إلى مستوى جديد - قررنا بناء مزرعة المحاكيات الخاصة بنا. عندما يكون هناك العديد من الاختبارات والمحاكيات، فمن الصعب إدارتها. ونتيجة لذلك، انتقلت جميع برامج المحاكاة لدينا إلى مجموعة k8s التي تتمتع بإدارة مرنة للموارد.

وبالإضافة إلى ذلك، هناك خطط أخرى.

  • عودة الوبر (وغيرها من التحليلات الثابتة). ونحن نعمل بالفعل في هذا الاتجاه.
  • تشغيل كل شيء على مانع العلاقات العامة اختبارات نهاية إلى نهاية على كافة إصدارات SDK.

لذلك، قمنا بتتبع تاريخ تطور التكامل المستمر في Avito. الآن أريد أن أقدم بعض النصائح من وجهة نظر ذات خبرة.

Советы

لو كان بوسعي تقديم نصيحة واحدة فقط لكانت كالتالي:

يرجى توخي الحذر مع نصوص شل!

Bash هي أداة مرنة وقوية جدًا، وهي مريحة جدًا وسريعة لكتابة البرامج النصية. لكن من الممكن أن تقع معه في فخ، وللأسف وقعنا فيه.

بدأ كل شيء بنصوص بسيطة تم تشغيلها على آلات البناء الخاصة بنا:

#!/usr/bin/env bash
./gradlew assembleDebug

ولكن، كما تعلم، كل شيء يتطور ويصبح أكثر تعقيدًا بمرور الوقت - فلنقم بتشغيل برنامج نصي من آخر، ولنمرر بعض المعلمات هناك - في النهاية كان علينا كتابة دالة تحدد مستوى تداخل bash الذي نحن فيه الآن لإدراج علامات الاقتباس اللازمة، لبدء كل شيء.

تطور CI في فريق تطوير الهاتف المحمول

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

ما الذي يمكن استبداله؟

  • أي لغة البرمجة النصية. اكتب ل بايثون أو كوتلين النصي أكثر ملاءمة لأنها البرمجة، وليس البرامج النصية.
  • أو قم بوصف كل منطق البناء في النموذج مهام gradle المخصصة لمشروعك.

قررنا اختيار الخيار الثاني، والآن نقوم بحذف جميع نصوص bash بشكل منهجي ونكتب الكثير من المهام المخصصة.

نصيحة رقم 2: قم بتخزين البنية التحتية في الكود.

يكون الأمر مناسبًا عندما لا يتم تخزين إعداد التكامل المستمر في واجهة المستخدم الخاصة بـ Jenkins أو TeamCity، وما إلى ذلك، ولكن في شكل ملفات نصية مباشرة في مستودع المشروع. وهذا يعطي إمكانية الإصدار. لن يكون من الصعب التراجع أو إنشاء الكود على فرع آخر.

يمكن تخزين البرامج النصية في المشروع. ماذا تفعل مع البيئة؟

نصيحة رقم 3: يمكن لـ Docker المساعدة في البيئة.

من المؤكد أنه سيساعد مطوري Android؛ لسوء الحظ، ليس لدى iOS واحد حتى الآن.

هذا مثال لملف عامل إرساء بسيط يحتوي على jdk وandroid-sdk:

FROM openjdk:8

ENV SDK_URL="https://dl.google.com/android/repository/sdk-tools-linux-3859397.zip" 
    ANDROID_HOME="/usr/local/android-sdk" 
    ANDROID_VERSION=26 
    ANDROID_BUILD_TOOLS_VERSION=26.0.2

# Download Android SDK
RUN mkdir "$ANDROID_HOME" .android 
    && cd "$ANDROID_HOME" 
    && curl -o sdk.zip $SDK_URL 
    && unzip sdk.zip 
    && rm sdk.zip 
    && yes | $ANDROID_HOME/tools/bin/sdkmanager --licenses

# Install Android Build Tool and Libraries
RUN $ANDROID_HOME/tools/bin/sdkmanager --update
RUN $ANDROID_HOME/tools/bin/sdkmanager "build-tools;${ANDROID_BUILD_TOOLS_VERSION}" 
    "platforms;android-${ANDROID_VERSION}" 
    "platform-tools"

RUN mkdir /application
WORKDIR /application

بعد كتابة ملف Docker هذا (سأخبرك بسر، ليس عليك كتابته، ولكن فقط اسحبه جاهزًا من GitHub) وقم بتجميع الصورة، تحصل على جهاز افتراضي يمكنك إنشاء التطبيق عليه وتشغيل اختبارات Junit.

السببان الرئيسيان وراء كون ذلك منطقيًا هما قابلية التوسع والتكرار. باستخدام عامل الإرساء، يمكنك بسرعة رفع عشرات من وكلاء البناء الذين سيكون لديهم نفس البيئة تمامًا مثل البيئة السابقة. وهذا يجعل حياة مهندسي CI أسهل كثيرًا. من السهل جدًا دفع Android-sdk إلى عامل الإرساء، ولكن مع المحاكيات يكون الأمر أكثر صعوبة بعض الشيء: سيتعين عليك العمل بجهد أكبر قليلاً (أو تنزيل الإصدار النهائي من GitHub مرة أخرى).

نصيحة رقم 4: لا تنس أن التفتيش لا يتم من أجل التفتيش، بل من أجل الناس.

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

النصيحة رقم 5: كن عمليًا عند تطوير التكامل المستمر.

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

نصيحة رقم 6: استخدم الأدوات الجاهزة.

هناك العديد من الشركات التي توفر الآن Cloud CI.

تطور CI في فريق تطوير الهاتف المحمول

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

نصيحة رقم 7: في فريق كبير، تكون الحلول الداخلية أكثر ربحية.

ولكن عاجلاً أم آجلاً، مع نمو الفريق، ستصبح الحلول الداخلية أكثر ربحية. هناك مشكلة واحدة في هذه القرارات. هناك قانون تناقص العائدات في الاقتصاد: في أي مشروع، يصبح كل تحسين لاحق أكثر صعوبة ويتطلب المزيد والمزيد من الاستثمار.

يصف الاقتصاد حياتنا بأكملها، بما في ذلك التكامل المستمر. لقد قمت ببناء جدول لتكاليف العمالة لكل مرحلة من مراحل تطوير التكامل المستمر لدينا.

تطور CI في فريق تطوير الهاتف المحمول

ومن الواضح أن أي تحسن أصبح أكثر صعوبة. بالنظر إلى هذا الرسم البياني، يمكنك أن تفهم أن التكامل المستمر يحتاج إلى التطوير وفقًا لنمو حجم الفريق. بالنسبة لفريق مكون من شخصين، يعد قضاء 50 يومًا في تطوير مزرعة محاكاة داخلية فكرة متواضعة. ولكن في الوقت نفسه، بالنسبة لفريق كبير، فإن عدم القيام بالتكامل المستمر على الإطلاق يعد أيضًا فكرة سيئة، لأن مشاكل التكامل وإصلاح الاتصالات وما إلى ذلك. وسوف يستغرق المزيد من الوقت.

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

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

لكن لدي إحصائيات: تم اكتشاف الأخطاء في 20٪ من التجميعات. وهذا ليس لأن مطورينا يكتبون التعليمات البرمجية بشكل سيء. وذلك لأن المطورين واثقون من أنهم إذا ارتكبوا بعض الأخطاء، فلن ينتهي الأمر بالتطوير، بل سيتم اكتشافها من خلال عمليات الفحص الآلي. وفقًا لذلك، يمكن للمطورين قضاء المزيد من الوقت في كتابة التعليمات البرمجية والأشياء المثيرة للاهتمام، بدلاً من تشغيل شيء ما واختباره محليًا.

ممارسة التكامل المستمر. ولكن باعتدال.

بالمناسبة، لا يقدم نيكولاي نيستيروف تقارير رائعة بنفسه فحسب، بل هو أيضًا عضو في لجنة البرنامج AppsConf ويساعد الآخرين على إعداد خطابات ذات معنى لك. يمكن تقييم مدى اكتمال وفائدة برنامج المؤتمر القادم من خلال المواضيع الموجودة في برنامج. وللحصول على التفاصيل، تفضل بزيارة Infospace يومي 22 و23 أبريل.

المصدر: www.habr.com

إضافة تعليق