Εξέλιξη του CI στην ομάδα ανάπτυξης κινητής τηλεφωνίας

Σήμερα, τα περισσότερα προϊόντα λογισμικού αναπτύσσονται σε ομάδες. Οι προϋποθέσεις για την επιτυχή ανάπτυξη της ομάδας μπορούν να αναπαρασταθούν με τη μορφή ενός απλού διαγράμματος.

Εξέλιξη του CI στην ομάδα ανάπτυξης κινητής τηλεφωνίας

Αφού γράψετε τον κωδικό σας, πρέπει να βεβαιωθείτε ότι:

  1. Работает.
  2. Δεν σπάει τίποτα, συμπεριλαμβανομένου του κώδικα που έγραψαν οι συνάδελφοί σας.

Εάν πληρούνται και οι δύο προϋποθέσεις, τότε είστε στο δρόμο της επιτυχίας. Για να ελέγξουμε εύκολα αυτές τις συνθήκες και να μην παρεκκλίνουμε από την κερδοφόρα πορεία, καταλήξαμε στη Συνεχή Ενσωμάτωση.

Το CI είναι μια ροή εργασίας όπου ενσωματώνετε τον κωδικό σας στον συνολικό κωδικό προϊόντος όσο πιο συχνά γίνεται. Και δεν ενσωματώνετε απλώς, αλλά και ελέγχετε συνεχώς ότι όλα λειτουργούν. Δεδομένου ότι πρέπει να ελέγχετε πολύ και συχνά, αξίζει να σκεφτείτε την αυτοματοποίηση. Μπορείτε να ελέγξετε τα πάντα χειροκίνητα, αλλά δεν πρέπει, και να γιατί.

  • Αγαπητοί άνθρωποι. Μια ώρα εργασίας οποιουδήποτε προγραμματιστή είναι πιο ακριβή από μια ώρα εργασίας οποιουδήποτε διακομιστή.
  • Οι άνθρωποι κάνουν λάθη. Επομένως, μπορεί να προκύψουν καταστάσεις όταν οι δοκιμές εκτελέστηκαν σε λάθος κλάδο ή η λανθασμένη δέσμευση μεταγλωττίστηκε για τους δοκιμαστές.
  • Οι άνθρωποι είναι τεμπέληδες. Από καιρό σε καιρό, όταν τελειώνω μια εργασία, μου έρχεται η σκέψη: «Τι υπάρχει να ελέγξω; Έγραψα δύο γραμμές - όλα λειτουργούν! Νομίζω ότι και κάποιοι από εσάς κάνετε μερικές φορές τέτοιες σκέψεις. Αλλά πρέπει πάντα να ελέγχετε.

Πώς εφαρμόστηκε και αναπτύχθηκε το Continuous Integration στην ομάδα ανάπτυξης κινητής τηλεφωνίας Avito, πώς έφτασε από 0 σε 450 κατασκευές την ημέρα και ότι οι μηχανές κατασκευής συναρμολογούνται 200 ​​ώρες την ημέρα, λέει ο Nikolai Nesterov (nnesterov) συμμετέχει σε όλες τις εξελικτικές αλλαγές της εφαρμογής CI/CD Android.

Η ιστορία βασίζεται στο παράδειγμα μιας εντολής Android, αλλά οι περισσότερες προσεγγίσεις ισχύουν και στο iOS.


Μια φορά κι έναν καιρό, ένα άτομο εργαζόταν στην ομάδα του Avito Android. Εξ ορισμού, δεν χρειαζόταν τίποτα από τη Συνεχή Ενσωμάτωση: δεν υπήρχε κανένας για να ενσωματωθεί.

Αλλά η εφαρμογή μεγάλωσε, όλο και περισσότερες νέες εργασίες εμφανίστηκαν και η ομάδα μεγάλωσε ανάλογα. Κάποια στιγμή, είναι καιρός να καθιερωθεί πιο επίσημα μια διαδικασία ενοποίησης κώδικα. Αποφασίστηκε να χρησιμοποιηθεί το Git flow.

Εξέλιξη του CI στην ομάδα ανάπτυξης κινητής τηλεφωνίας

Η έννοια της ροής Git είναι ευρέως γνωστή: ένα έργο έχει έναν κοινό κλάδο ανάπτυξης και για κάθε νέο χαρακτηριστικό, οι προγραμματιστές κόβουν έναν ξεχωριστό κλάδο, δεσμεύονται σε αυτό, πιέζουν και όταν θέλουν να συγχωνεύσουν τον κώδικά τους στον κλάδο ανάπτυξης, ανοίγουν ένα αίτημα έλξης. Για να μοιραστούμε γνώσεις και να συζητήσουμε προσεγγίσεις, εισαγάγαμε την αναθεώρηση κώδικα, δηλαδή, οι συνάδελφοι πρέπει να ελέγχουν και να επιβεβαιώνουν ο ένας τον κώδικα του άλλου.

Έλεγχοι

Το να βλέπεις κώδικα με τα μάτια σου είναι ωραίο, αλλά δεν αρκεί. Ως εκ τούτου, εισάγονται αυτόματοι έλεγχοι.

  • Πρώτα απ 'όλα, ελέγχουμε Συναρμολόγηση ARK.
  • Πολλά Δοκιμές Junit.
  • Λαμβάνουμε υπόψη την κάλυψη κωδικού, αφού κάνουμε δοκιμές.

Για να κατανοήσουμε πώς πρέπει να εκτελούνται αυτοί οι έλεγχοι, ας δούμε τη διαδικασία ανάπτυξης στο Avito.

Μπορεί να αναπαρασταθεί σχηματικά ως εξής:

  • Ένας προγραμματιστής γράφει κώδικα στο φορητό υπολογιστή του. Μπορείτε να εκτελέσετε ελέγχους ενσωμάτωσης εδώ - είτε με ένα άγκιστρο δέσμευσης είτε απλώς να εκτελέσετε ελέγχους στο παρασκήνιο.
  • Αφού ο προγραμματιστής έχει προωθήσει τον κώδικα, ανοίγει ένα αίτημα έλξης. Για να συμπεριληφθεί ο κώδικάς του στον κλάδο ανάπτυξης, είναι απαραίτητο να υποβληθείτε σε έλεγχο κώδικα και να συλλέξετε τον απαιτούμενο αριθμό επιβεβαιώσεων. Μπορείτε να ενεργοποιήσετε τους ελέγχους και τις εκδόσεις εδώ: μέχρι να είναι επιτυχείς όλες οι εκδόσεις, το αίτημα έλξης δεν μπορεί να συγχωνευθεί.
  • Αφού συγχωνευθεί το αίτημα έλξης και ο κώδικας συμπεριληφθεί στην ανάπτυξη, μπορείτε να επιλέξετε μια βολική ώρα: για παράδειγμα, τη νύχτα, όταν όλοι οι διακομιστές είναι ελεύθεροι και να εκτελέσετε όσους ελέγχους θέλετε.

Σε κανέναν δεν άρεσε η εκτέλεση σαρώσεων στον φορητό υπολογιστή του. Όταν ένας προγραμματιστής έχει ολοκληρώσει μια δυνατότητα, θέλει να την προωθήσει γρήγορα και να ανοίξει ένα αίτημα έλξης. Εάν αυτή τη στιγμή ξεκινήσουν κάποιοι μεγάλοι έλεγχοι, αυτό όχι μόνο δεν είναι πολύ ευχάριστο, αλλά και επιβραδύνει την ανάπτυξη: ενώ ο φορητός υπολογιστής ελέγχει κάτι, είναι αδύνατο να εργαστείτε κανονικά σε αυτό.

Μας άρεσε πολύ η εκτέλεση επιταγών τη νύχτα, επειδή υπάρχει πολύς χρόνος και διακομιστές, μπορείτε να περιπλανηθείτε. Όμως, δυστυχώς, όταν ο κώδικας χαρακτηριστικών μπαίνει σε ανάπτυξη, ο προγραμματιστής έχει πολύ λιγότερα κίνητρα για να διορθώσει τα σφάλματα που εντόπισε το CI. Περιοδικά έπιανα τον εαυτό μου να σκέφτεται όταν κοιτούσα όλα τα σφάλματα που βρέθηκαν στην πρωινή αναφορά ότι θα τα διόρθωνα κάποια μέρα αργότερα, γιατί τώρα υπάρχει μια υπέροχη νέα εργασία στο Jira που απλά θέλω να ξεκινήσω να κάνω.

Εάν οι έλεγχοι μπλοκάρουν ένα αίτημα έλξης, τότε υπάρχει αρκετό κίνητρο, γιατί μέχρι να γίνουν πράσινες οι εκδόσεις, ο κώδικας δεν θα μπει στην ανάπτυξη, πράγμα που σημαίνει ότι η εργασία δεν θα ολοκληρωθεί.

Ως αποτέλεσμα, επιλέξαμε την ακόλουθη στρατηγική: εκτελούμε το μέγιστο δυνατό σύνολο ελέγχων τη νύχτα και εκτελούμε τους πιο κρίσιμους από αυτούς και, κυρίως, τους πιο γρήγορους σε ένα αίτημα έλξης. Αλλά δεν σταματάμε εκεί - παράλληλα, βελτιστοποιούμε την ταχύτητα των ελέγχων, ώστε να τους μεταφέρουμε από τη νυχτερινή λειτουργία σε ελέγχους αιτημάτων.

Εκείνη την εποχή, όλες οι κατασκευές μας ολοκληρώθηκαν αρκετά γρήγορα, επομένως απλώς συμπεριλάβαμε την κατασκευή ARK, τις δοκιμές Junit και τους υπολογισμούς κάλυψης κώδικα ως αποκλεισμό για το αίτημα έλξης. Το ενεργοποιήσαμε, το σκεφτήκαμε και εγκαταλείψαμε την κάλυψη κωδικού επειδή πιστεύαμε ότι δεν το χρειαζόμασταν.

Μας πήρε δύο ημέρες για να ρυθμίσουμε πλήρως το βασικό CI (εφεξής η εκτίμηση χρόνου είναι κατά προσέγγιση, που απαιτείται για κλίμακα).

Μετά από αυτό, αρχίσαμε να σκεφτόμαστε περαιτέρω - μήπως καν ελέγχουμε σωστά; Εκτελούμε σωστά builds σε αιτήματα έλξης;

Ξεκινήσαμε την κατασκευή στο τελευταίο commit του κλάδου από το οποίο άνοιξε το αίτημα έλξης. Αλλά οι δοκιμές αυτής της δέσμευσης μπορούν μόνο να δείξουν ότι ο κώδικας που έγραψε ο προγραμματιστής λειτουργεί. Δεν αποδεικνύουν όμως ότι δεν έσπασε τίποτα. Στην πραγματικότητα, πρέπει να ελέγξετε την κατάσταση του κλάδου ανάπτυξης μετά τη συγχώνευση μιας δυνατότητας σε αυτήν.

Εξέλιξη του CI στην ομάδα ανάπτυξης κινητής τηλεφωνίας

Για να γίνει αυτό, γράψαμε ένα απλό σενάριο bash premerge.sh:

#!/usr/bin/env bash

set -e

git fetch origin develop

git merge origin/develop

Εδώ όλες οι τελευταίες αλλαγές από την ανάπτυξη απλώς ανασύρονται και συγχωνεύονται στον τρέχοντα κλάδο. Προσθέσαμε το σενάριο premerge.sh ως το πρώτο βήμα σε όλες τις εκδόσεις και αρχίσαμε να ελέγχουμε τι ακριβώς θέλουμε, δηλαδή ενσωμάτωση.

Χρειάστηκαν τρεις ημέρες για να εντοπιστεί το πρόβλημα, να βρεθεί μια λύση και να γραφτεί αυτό το σενάριο.

Η εφαρμογή αναπτύχθηκε, όλο και περισσότερες εργασίες εμφανίζονταν, η ομάδα μεγάλωνε και το premerge.sh μερικές φορές άρχισε να μας απογοητεύει. Το Develop είχε αντικρουόμενες αλλαγές που έσπασαν την κατασκευή.

Ένα παράδειγμα για το πώς συμβαίνει αυτό:

Εξέλιξη του CI στην ομάδα ανάπτυξης κινητής τηλεφωνίας

Δύο προγραμματιστές αρχίζουν ταυτόχρονα να εργάζονται στα χαρακτηριστικά Α και Β. Ο προγραμματιστής του χαρακτηριστικού Α ανακαλύπτει ένα χαρακτηριστικό που δεν χρησιμοποιείται στο έργο answer() και, σαν καλός πρόσκοπος, το αφαιρεί. Ταυτόχρονα, ο προγραμματιστής της δυνατότητας Β προσθέτει μια νέα κλήση σε αυτή τη λειτουργία στον κλάδο του.

Οι προγραμματιστές ολοκληρώνουν την εργασία τους και ανοίγουν ταυτόχρονα ένα αίτημα έλξης. Οι εκδόσεις ξεκινούν, το premerge.sh ελέγχει και τα δύο αιτήματα έλξης σχετικά με την τελευταία κατάσταση ανάπτυξης - όλοι οι έλεγχοι είναι πράσινοι. Μετά από αυτό, το αίτημα έλξης του χαρακτηριστικού Α συγχωνεύεται, το αίτημα έλξης του στοιχείου Β συγχωνεύεται... Boom! Αναπτύξτε διακοπές επειδή ο κώδικας ανάπτυξης περιέχει μια κλήση σε μια ανύπαρκτη συνάρτηση.

Εξέλιξη του CI στην ομάδα ανάπτυξης κινητής τηλεφωνίας

Όταν δεν πρόκειται να αναπτυχθεί, είναι τοπική καταστροφή. Ολόκληρη η ομάδα δεν μπορεί να συλλέξει τίποτα και να το υποβάλει για δοκιμή.

Έτυχε να δούλευα πιο συχνά σε εργασίες υποδομής: αναλυτικά στοιχεία, δίκτυο, βάσεις δεδομένων. Δηλαδή, έγραψα αυτές τις λειτουργίες και τις κλάσεις που χρησιμοποιούν άλλοι προγραμματιστές. Εξαιτίας αυτού, βρέθηκα πολύ συχνά σε παρόμοιες καταστάσεις. Είχα ακόμη και αυτή τη φωτογραφία κρεμασμένη για λίγο.

Εξέλιξη του CI στην ομάδα ανάπτυξης κινητής τηλεφωνίας

Επειδή αυτό δεν μας ταίριαζε, αρχίσαμε να διερευνούμε επιλογές για το πώς να το αποτρέψουμε.

Πώς να μην σπάσει αναπτύξει

Η πρώτη επιλογή: αναδημιουργήστε όλα τα αιτήματα έλξης κατά την ανάπτυξη της ενημέρωσης. Εάν, στο παράδειγμά μας, το αίτημα έλξης με χαρακτηριστικό Α είναι το πρώτο που περιλαμβάνεται στην ανάπτυξη, το αίτημα έλξης του χαρακτηριστικού Β θα ξαναδημιουργηθεί και, κατά συνέπεια, οι έλεγχοι θα αποτύχουν λόγω σφάλματος μεταγλώττισης.

Για να καταλάβετε πόσο χρόνο θα πάρει αυτό, εξετάστε ένα παράδειγμα με δύο PR. Ανοίγουμε δύο PR: δύο εκδόσεις, δύο σειρές ελέγχων. Αφού το πρώτο PR συγχωνευθεί σε ανάπτυξη, το δεύτερο πρέπει να ξαναχτιστεί. Συνολικά, δύο PR απαιτούν τρεις σειρές ελέγχων: 2 + 1 = 3.

Καταρχήν, είναι μια χαρά. Αλλά κοιτάξαμε τα στατιστικά στοιχεία και η τυπική κατάσταση στην ομάδα μας ήταν 10 ανοιχτά PR, και μετά ο αριθμός των ελέγχων είναι το άθροισμα της προόδου: 10 + 9 +... + 1 = 55. Δηλαδή, να δεχθούμε 10 PRs, πρέπει να ξαναχτίσετε 55 φορές. Και αυτό είναι σε ιδανική περίπτωση, όταν όλοι οι έλεγχοι περνούν την πρώτη φορά, όταν κανείς δεν ανοίγει ένα πρόσθετο αίτημα έλξης ενώ αυτές οι ντουζίνες βρίσκονται υπό επεξεργασία.

Φανταστείτε τον εαυτό σας ως προγραμματιστή που πρέπει να είναι ο πρώτος που θα κάνει κλικ στο κουμπί "συγχώνευση", γιατί αν κάποιος γείτονας το κάνει αυτό, τότε θα πρέπει να περιμένετε μέχρι να περάσουν ξανά όλες οι εκδόσεις... Όχι, αυτό δεν θα λειτουργήσει , θα επιβραδύνει σοβαρά την ανάπτυξη.

Δεύτερος πιθανός τρόπος: συλλογή αιτημάτων έλξης μετά από έλεγχο κώδικα. Δηλαδή, ανοίγεις ένα αίτημα έλξης, συλλέγεις τον απαιτούμενο αριθμό εγκρίσεων από συναδέλφους, διορθώνεις ό,τι χρειάζεται και μετά ξεκινάς τις εκδόσεις. Εάν είναι επιτυχείς, το αίτημα έλξης συγχωνεύεται στην ανάπτυξη. Σε αυτήν την περίπτωση, δεν υπάρχουν επιπλέον επανεκκινήσεις, αλλά η ανάδραση επιβραδύνεται πολύ. Ως προγραμματιστής, όταν ανοίγω ένα αίτημα έλξης, θέλω αμέσως να δω αν θα λειτουργήσει. Για παράδειγμα, εάν μια δοκιμή αποτύχει, πρέπει να τη διορθώσετε γρήγορα. Σε περίπτωση καθυστερημένης κατασκευής, η ανατροφοδότηση επιβραδύνεται, και επομένως ολόκληρη η ανάπτυξη. Ούτε αυτό μας ταίριαζε.

Ως αποτέλεσμα, έμεινε μόνο η τρίτη επιλογή - ποδήλατο. Όλος ο κώδικάς μας, όλες οι πηγές μας αποθηκεύονται σε ένα αποθετήριο στον διακομιστή Bitbucket. Αντίστοιχα, έπρεπε να αναπτύξουμε ένα πρόσθετο για το Bitbucket.

Εξέλιξη του CI στην ομάδα ανάπτυξης κινητής τηλεφωνίας

Αυτό το πρόσθετο παρακάμπτει τον μηχανισμό συγχώνευσης αιτημάτων έλξης. Η αρχή είναι τυπική: το PR ανοίγει, όλες οι συναρμολογήσεις ξεκινούν, η αναθεώρηση του κώδικα ολοκληρώνεται. Όμως, αφού ολοκληρωθεί η αναθεώρηση του κώδικα και ο προγραμματιστής αποφασίσει να κάνει κλικ στο "συγχώνευση", το πρόσθετο ελέγχει σε ποια κατάσταση ανάπτυξης εκτελέστηκαν οι έλεγχοι. Εάν η ανάπτυξη έχει ενημερωθεί μετά τις εκδόσεις, η προσθήκη δεν θα επιτρέψει τη συγχώνευση ενός τέτοιου αιτήματος έλξης στον κύριο κλάδο. Απλώς θα επανεκκινήσει τις εκδόσεις μιας σχετικά πρόσφατης εξέλιξης.

Εξέλιξη του CI στην ομάδα ανάπτυξης κινητής τηλεφωνίας

Στο παράδειγμά μας με αντικρουόμενες αλλαγές, τέτοιες εκδόσεις θα αποτύχουν λόγω σφάλματος μεταγλώττισης. Αντίστοιχα, ο προγραμματιστής της δυνατότητας Β θα πρέπει να διορθώσει τον κώδικα, να επανεκκινήσει τους ελέγχους και, στη συνέχεια, το πρόσθετο θα εφαρμόσει αυτόματα το αίτημα έλξης.

Πριν από την εφαρμογή αυτής της προσθήκης, είχαμε κατά μέσο όρο 2,7 εκτελέσεις ελέγχου ανά αίτημα έλξης. Με το πρόσθετο υπήρξαν 3,6 εκκινήσεις. Αυτό μας ταίριαζε.

Αξίζει να σημειωθεί ότι αυτό το πρόσθετο έχει ένα μειονέκτημα: κάνει επανεκκίνηση της κατασκευής μόνο μία φορά. Δηλαδή, υπάρχει ακόμα ένα μικρό παράθυρο μέσα από το οποίο μπορούν να αναπτυχθούν αντικρουόμενες αλλαγές. Αλλά η πιθανότητα να συμβεί αυτό είναι χαμηλή, και κάναμε αυτόν τον συμβιβασμό μεταξύ του αριθμού των εκκινήσεων και της πιθανότητας αποτυχίας. Σε δύο χρόνια πυροβόλησε μόνο μία φορά, οπότε μάλλον δεν ήταν μάταιο.

Μας πήρε δύο εβδομάδες για να γράψουμε την πρώτη έκδοση του πρόσθετου Bitbucket.

Νέοι έλεγχοι

Εν τω μεταξύ, η ομάδα μας συνέχισε να μεγαλώνει. Προστέθηκαν νέες επιταγές.

Σκεφτήκαμε: γιατί να κάνουμε λάθη αν μπορούν να προληφθούν; Και γι' αυτό εφάρμοσαν ανάλυση στατικού κώδικα. Ξεκινήσαμε με το lint, το οποίο περιλαμβάνεται στο Android SDK. Αλλά εκείνη την εποχή δεν ήξερε καθόλου πώς να δουλεύει με τον κώδικα Kotlin και είχαμε ήδη το 75% της εφαρμογής γραμμένο σε Kotlin. Ως εκ τούτου, προστέθηκαν ενσωματωμένα στο χνούδι Έλεγχοι Android Studio.

Για να γίνει αυτό, χρειάστηκε να κάνουμε πολλές διαστροφές: να πάρουμε το Android Studio, να το συσκευάσουμε στο Docker και να το εκτελέσουμε σε CI με μια εικονική οθόνη, έτσι ώστε να πιστεύει ότι τρέχει σε πραγματικό φορητό υπολογιστή. Αλλά λειτούργησε.

Ήταν επίσης σε αυτό το διάστημα που ξεκινήσαμε να γράφουμε πολύ δοκιμές οργάνων και εφαρμόστηκε δοκιμή στιγμιότυπου οθόνης. Αυτό συμβαίνει όταν δημιουργείται ένα στιγμιότυπο οθόνης αναφοράς για μια ξεχωριστή μικρή προβολή και η δοκιμή συνίσταται στη λήψη ενός στιγμιότυπου οθόνης από την προβολή και στη σύγκριση με το τυπικό απευθείας pixel προς pixel. Αν υπάρχει ασυμφωνία, σημαίνει ότι κάπου έχει πάει στραβά η διάταξη ή κάτι δεν πάει καλά στα στυλ.

Αλλά οι δοκιμές οργάνων και οι δοκιμές στιγμιότυπων οθόνης πρέπει να εκτελούνται σε συσκευές: σε εξομοιωτές ή σε πραγματικές συσκευές. Λαμβάνοντας υπόψη ότι υπάρχουν πολλές δοκιμές και γίνονται συχνά, χρειάζεται μια ολόκληρη φάρμα. Το να ξεκινήσετε τη δική σας φάρμα είναι πολύ εντατική, οπότε βρήκαμε μια έτοιμη επιλογή - το Firebase Test Lab.

Εργαστήριο δοκιμών Firebase

Επιλέχθηκε επειδή το Firebase είναι προϊόν της Google, που σημαίνει ότι θα πρέπει να είναι αξιόπιστο και απίθανο να πεθάνει ποτέ. Οι τιμές είναι λογικές: 5 $ ανά ώρα λειτουργίας μιας πραγματικής συσκευής, 1 $ ανά ώρα λειτουργίας ενός εξομοιωτή.

Χρειάστηκαν περίπου τρεις εβδομάδες για την εφαρμογή του Firebase Test Lab στο CI μας.

Αλλά η ομάδα συνέχισε να αναπτύσσεται και το Firebase, δυστυχώς, άρχισε να μας απογοητεύει. Τότε δεν είχε κανένα SLA. Μερικές φορές το Firebase μας έκανε να περιμένουμε έως ότου ο απαιτούμενος αριθμός συσκευών ήταν ελεύθερος για δοκιμές και δεν ξεκινούσε να τις εκτελεί αμέσως, όπως θέλαμε. Η αναμονή στην ουρά κράτησε έως και μισή ώρα, που είναι πολύ μεγάλο χρονικό διάστημα. Έγιναν δοκιμές οργάνων σε κάθε PR, οι καθυστερήσεις επιβράδυναν πραγματικά την ανάπτυξη και στη συνέχεια ο μηνιαίος λογαριασμός ήρθε με ένα στρογγυλό ποσό. Σε γενικές γραμμές, αποφασίστηκε να εγκαταλείψει το Firebase και να εργαστεί εντός της εταιρείας, καθώς η ομάδα είχε μεγαλώσει αρκετά.

Docker + Python + bash

Πήραμε το Docker, βάλαμε εξομοιωτές σε αυτό, γράψαμε ένα απλό πρόγραμμα στην Python, το οποίο την κατάλληλη στιγμή εμφανίζει τον απαιτούμενο αριθμό εξομοιωτών στην απαιτούμενη έκδοση και τους σταματά όταν χρειάζεται. Και, φυσικά, μερικά σενάρια bash - πού θα ήμασταν χωρίς αυτά;

Χρειάστηκαν πέντε εβδομάδες για να δημιουργήσουμε το δικό μας περιβάλλον δοκιμής.

Ως αποτέλεσμα, για κάθε αίτημα έλξης υπήρχε μια εκτενής λίστα ελέγχων αποκλεισμού συγχώνευσης:

  • Συναρμολόγηση ARK?
  • Δοκιμές Junit;
  • Στουπί;
  • Έλεγχοι Android Studio.
  • Δοκιμές οργάνων;
  • Δοκιμές στιγμιότυπου οθόνης.

Αυτό απέτρεψε πολλές πιθανές βλάβες. Τεχνικά όλα λειτούργησαν, αλλά οι προγραμματιστές παραπονέθηκαν ότι η αναμονή για τα αποτελέσματα ήταν πολύ μεγάλη.

Πόσο καιρό είναι πάρα πολύ; Ανεβάσαμε δεδομένα από το Bitbucket και το TeamCity στο σύστημα ανάλυσης και το συνειδητοποιήσαμε μέσος χρόνος αναμονής 45 λεπτά. Δηλαδή, ένας προγραμματιστής, όταν ανοίγει ένα αίτημα έλξης, περιμένει κατά μέσο όρο 45 λεπτά για τα αποτελέσματα κατασκευής. Κατά τη γνώμη μου, αυτά είναι πολλά και δεν μπορείς να λειτουργήσεις έτσι.

Φυσικά, αποφασίσαμε να επιταχύνουμε όλες τις κατασκευές μας.

Ας επιταχύνουμε

Βλέποντας ότι οι κατασκευές συχνά στέκονται σε μια ουρά, το πρώτο πράγμα που κάνουμε είναι αγόρασε περισσότερο υλικό — η εκτεταμένη ανάπτυξη είναι η απλούστερη. Οι κατασκευές σταμάτησαν να βρίσκονται στην ουρά, αλλά ο χρόνος αναμονής μειώθηκε ελαφρώς, επειδή ορισμένοι έλεγχοι από μόνες τους χρειάστηκαν πολύ χρόνο.

Κατάργηση ελέγχων που διαρκούν πολύ

Η Συνεχής ολοκλήρωσή μας θα μπορούσε να εντοπίσει αυτούς τους τύπους σφαλμάτων και προβλημάτων.

  • Δεν πρόκειται να. Το CI μπορεί να εντοπίσει ένα σφάλμα μεταγλώττισης όταν κάτι δεν δημιουργείται λόγω αντικρουόμενων αλλαγών. Όπως είπα ήδη, τότε κανείς δεν μπορεί να συναρμολογήσει τίποτα, η ανάπτυξη σταματά και όλοι γίνονται νευρικοί.
  • Σφάλμα στη συμπεριφορά. Για παράδειγμα, όταν η εφαρμογή είναι κατασκευασμένη, αλλά διακόπτεται όταν πατάτε ένα κουμπί ή το κουμπί δεν πατιέται καθόλου. Αυτό είναι κακό γιατί ένα τέτοιο σφάλμα μπορεί να φτάσει στον χρήστη.
  • Σφάλμα στη διάταξη. Για παράδειγμα, γίνεται κλικ σε ένα κουμπί, αλλά έχει μετακινηθεί 10 pixel προς τα αριστερά.
  • Αύξηση τεχνικού χρέους.

Αφού εξετάσαμε αυτή τη λίστα, συνειδητοποιήσαμε ότι μόνο τα δύο πρώτα σημεία είναι κρίσιμα. Θέλουμε πρώτα να πιάσουμε τέτοια προβλήματα. Σφάλματα στη διάταξη ανακαλύπτονται στο στάδιο σχεδιασμού-επισκόπησης και μπορούν εύκολα να διορθωθούν στη συνέχεια. Η αντιμετώπιση του τεχνικού χρέους απαιτεί ξεχωριστή διαδικασία και προγραμματισμό, γι' αυτό αποφασίσαμε να μην το δοκιμάσουμε κατόπιν αιτήματος έλξης.

Με βάση αυτή την ταξινόμηση, ανακινήσαμε ολόκληρη τη λίστα των επιταγών. Διαγραμμένο Lint και ανέβαλε την έναρξή του μέσα σε μια νύχτα: μόνο και μόνο για να παράγει μια αναφορά για το πόσα προβλήματα υπήρχαν στο έργο. Συμφωνήσαμε να εργαστούμε ξεχωριστά με το τεχνικό χρέος, και Οι έλεγχοι του Android Studio εγκαταλείφθηκαν εντελώς. Το Android Studio στο Docker για την εκτέλεση επιθεωρήσεων ακούγεται ενδιαφέρον, αλλά προκαλεί πολλά προβλήματα στην υποστήριξη. Οποιαδήποτε ενημέρωση στις εκδόσεις Android Studio σημαίνει αγώνα με ακατανόητα σφάλματα. Ήταν επίσης δύσκολο να υποστηριχθούν δοκιμές στιγμιότυπων οθόνης, επειδή η βιβλιοθήκη δεν ήταν πολύ σταθερή και υπήρχαν ψευδώς θετικά αποτελέσματα. Οι δοκιμές στιγμιότυπου οθόνης έχουν αφαιρεθεί από τη λίστα ελέγχου.

Ως αποτέλεσμα, μας έμειναν:

  • Συναρμολόγηση ARK?
  • Δοκιμές Junit;
  • Δοκιμές οργάνων.

Gradle απομακρυσμένη κρυφή μνήμη

Χωρίς βαρείς ελέγχους, όλα έγιναν καλύτερα. Αλλά δεν υπάρχει όριο στην τελειότητα!

Η εφαρμογή μας είχε ήδη χωριστεί σε περίπου 150 gradle modules. Η απομακρυσμένη κρυφή μνήμη Gradle συνήθως λειτουργεί καλά σε αυτήν την περίπτωση, οπότε αποφασίσαμε να τη δοκιμάσουμε.

Η απομακρυσμένη κρυφή μνήμη Gradle είναι μια υπηρεσία που μπορεί να αποθηκεύσει στην κρυφή μνήμη τεχνουργήματα κατασκευής για μεμονωμένες εργασίες σε μεμονωμένες μονάδες. Ο Gradle, αντί να μεταγλωττίσει πραγματικά τον κώδικα, χρησιμοποιεί το HTTP για να χτυπήσει την απομακρυσμένη κρυφή μνήμη και να ρωτήσει εάν κάποιος έχει ήδη εκτελέσει αυτήν την εργασία. Αν ναι, απλά κατεβάζει το αποτέλεσμα.

Η εκτέλεση της απομακρυσμένης κρυφής μνήμης Gradle είναι εύκολη επειδή το Gradle παρέχει μια εικόνα Docker. Το καταφέραμε σε τρεις ώρες.

Το μόνο που έπρεπε να κάνετε ήταν να εκκινήσετε το Docker και να γράψετε μια γραμμή στο έργο. Αλλά αν και μπορεί να ξεκινήσει γρήγορα, θα χρειαστεί πολύς χρόνος για να λειτουργήσουν όλα καλά.

Παρακάτω είναι το γράφημα που λείπει από την προσωρινή μνήμη.

Εξέλιξη του CI στην ομάδα ανάπτυξης κινητής τηλεφωνίας

Στην αρχή, το ποσοστό των αστοχιών της προσωρινής μνήμης ήταν περίπου 65. Μετά από τρεις εβδομάδες, καταφέραμε να αυξήσουμε αυτήν την τιμή στο 20%. Αποδείχθηκε ότι οι εργασίες που συλλέγει η εφαρμογή Android έχουν περίεργες μεταβατικές εξαρτήσεις, λόγω των οποίων ο Gradle έχασε την προσωρινή μνήμη.

Με τη σύνδεση της προσωρινής μνήμης, επιταχύναμε πολύ την κατασκευή. Εκτός όμως από τη συναρμολόγηση, υπάρχουν και δοκιμές οργάνων και χρειάζονται πολύ χρόνο. Ίσως δεν χρειάζεται να εκτελούνται όλες οι δοκιμές για κάθε αίτημα έλξης. Για να το μάθουμε, χρησιμοποιούμε ανάλυση επιπτώσεων.

Ανάλυση επιπτώσεων

Σε ένα αίτημα έλξης, συλλέγουμε το git diff και βρίσκουμε τις τροποποιημένες μονάδες Gradle.

Εξέλιξη του CI στην ομάδα ανάπτυξης κινητής τηλεφωνίας

Είναι λογικό να εκτελούνται μόνο δοκιμές οργάνων που ελέγχουν τις αλλαγμένες μονάδες και όλες τις μονάδες που εξαρτώνται από αυτές. Δεν έχει νόημα η εκτέλεση δοκιμών για γειτονικές ενότητες: ο κώδικας εκεί δεν έχει αλλάξει και τίποτα δεν μπορεί να σπάσει.

Οι δοκιμές οργάνων δεν είναι τόσο απλές, επειδή πρέπει να βρίσκονται στην ενότητα Εφαρμογής ανώτατου επιπέδου. Χρησιμοποιήσαμε ευρετικά με ανάλυση bytecode για να κατανοήσουμε σε ποια ενότητα ανήκει κάθε δοκιμή.

Η αναβάθμιση της λειτουργίας των δοκιμών οργάνων έτσι ώστε να δοκιμάζουν μόνο τις εμπλεκόμενες ενότητες χρειάστηκε περίπου οκτώ εβδομάδες.

Τα μέτρα για την επιτάχυνση των επιθεωρήσεων λειτούργησαν με επιτυχία. Από τα 45 λεπτά ανεβήκαμε περίπου στα 15. Είναι ήδη φυσιολογικό να περιμένεις ένα τέταρτο της ώρας για μια κατασκευή.

Αλλά τώρα οι προγραμματιστές έχουν αρχίσει να παραπονιούνται ότι δεν καταλαβαίνουν ποιες εκδόσεις κυκλοφορούν, πού να δουν το αρχείο καταγραφής, γιατί η έκδοση είναι κόκκινη, ποια δοκιμή απέτυχε κ.λπ.

Εξέλιξη του CI στην ομάδα ανάπτυξης κινητής τηλεφωνίας

Τα προβλήματα με την ανατροφοδότηση επιβραδύνουν την ανάπτυξη, επομένως προσπαθήσαμε να παρέχουμε όσο το δυνατόν πιο σαφείς και λεπτομερείς πληροφορίες για κάθε PR και κατασκευή. Ξεκινήσαμε με σχόλια στο Bitbucket στο PR, υποδεικνύοντας ποια έκδοση απέτυχε και γιατί, και γράψαμε στοχευμένα μηνύματα στο Slack. Στο τέλος, δημιουργήσαμε έναν πίνακα εργαλείων δημοσίων σχέσεων για τη σελίδα με μια λίστα με όλες τις εκδόσεις που εκτελούνται αυτήν τη στιγμή και την κατάστασή τους: βρίσκονται σε ουρά, εκτελούνται, καταρρεύσαν ή ολοκληρώθηκαν. Μπορείτε να κάνετε κλικ στην κατασκευή και να μεταβείτε στο αρχείο καταγραφής της.

Εξέλιξη του CI στην ομάδα ανάπτυξης κινητής τηλεφωνίας

Έξι εβδομάδες δαπανήθηκαν για λεπτομερή ανατροφοδότηση.

Σχέδια

Ας περάσουμε στην πρόσφατη ιστορία. Έχοντας επιλύσει το ζήτημα των σχολίων, φτάσαμε σε ένα νέο επίπεδο - αποφασίσαμε να δημιουργήσουμε τη δική μας φάρμα εξομοιωτών. Όταν υπάρχουν πολλά τεστ και εξομοιωτές, είναι δύσκολο να τα διαχειριστείς. Ως αποτέλεσμα, όλοι οι εξομοιωτές μας μετακινήθηκαν στο σύμπλεγμα k8s με ευέλικτη διαχείριση πόρων.

Επιπλέον, υπάρχουν και άλλα σχέδια.

  • Επιστρέψτε το Lint (και άλλη στατική ανάλυση). Ήδη εργαζόμαστε προς αυτή την κατεύθυνση.
  • Εκτελέστε τα πάντα σε έναν αποκλεισμό δημοσίων σχέσεων δοκιμές από άκρο σε άκρο σε όλες τις εκδόσεις SDK.

Έτσι, παρακολουθήσαμε την ιστορία της ανάπτυξης του Continuous Integration στο Avito. Τώρα θέλω να δώσω μερικές συμβουλές από έμπειρη σκοπιά.

Советы

Αν μπορούσα να δώσω μόνο μια συμβουλή θα ήταν η εξής:

Να είστε προσεκτικοί με τα σενάρια κελύφους!

Το Bash είναι ένα πολύ ευέλικτο και ισχυρό εργαλείο, είναι πολύ βολικό και γρήγορο στη σύνταξη σεναρίων. Αλλά μπορείς να πέσεις σε παγίδα με αυτό και, δυστυχώς, πέσαμε σε αυτήν.

Όλα ξεκίνησαν με απλά σενάρια που έτρεχαν στις μηχανές κατασκευής μας:

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

Αλλά, όπως γνωρίζετε, όλα εξελίσσονται και γίνονται πιο περίπλοκα με την πάροδο του χρόνου - ας τρέξουμε ένα σενάριο από το άλλο, ας περάσουμε κάποιες παραμέτρους εκεί - στο τέλος έπρεπε να γράψουμε μια συνάρτηση που καθορίζει σε ποιο επίπεδο bash nesting βρισκόμαστε τώρα στη σειρά να εισαγάγετε τα απαραίτητα εισαγωγικά, για να ξεκινήσετε όλα.

Εξέλιξη του CI στην ομάδα ανάπτυξης κινητής τηλεφωνίας

Μπορείτε να φανταστείτε το κόστος εργασίας για την ανάπτυξη τέτοιων σεναρίων. Σας συμβουλεύω να μην πέσετε σε αυτή την παγίδα.

Τι μπορεί να αντικατασταθεί;

  • Οποιαδήποτε γλώσσα σεναρίου. Γράφω σε Python ή Kotlin Script πιο βολικό γιατί είναι προγραμματισμός, όχι σενάρια.
  • Ή περιγράψτε όλη τη λογική κατασκευής στη φόρμα Προσαρμοσμένες εργασίες βαθμονόμησης για το έργο σας.

Αποφασίσαμε να επιλέξουμε τη δεύτερη επιλογή και τώρα διαγράφουμε συστηματικά όλα τα σενάρια bash και γράφουμε πολλές προσαρμοσμένες εργασίες gradle.

Συμβουλή #2: Αποθηκεύστε την υποδομή σε κώδικα.

Είναι βολικό όταν η ρύθμιση Continuous Integration δεν αποθηκεύεται στη διεπαφή διεπαφής χρήστη του Jenkins ή του TeamCity κ.λπ., αλλά με τη μορφή αρχείων κειμένου απευθείας στο χώρο αποθήκευσης του έργου. Αυτό δίνει δυνατότητα έκδοσης. Δεν θα είναι δύσκολο να επαναφέρετε ή να δημιουργήσετε τον κώδικα σε άλλο κλάδο.

Τα σενάρια μπορούν να αποθηκευτούν σε ένα έργο. Τι να κάνετε με το περιβάλλον;

Συμβουλή #3: Το Docker μπορεί να βοηθήσει με το περιβάλλον.

Σίγουρα θα βοηθήσει τους προγραμματιστές Android· δυστυχώς το iOS δεν έχει ακόμη.

Αυτό είναι ένα παράδειγμα απλού αρχείου docker που περιέχει 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.

Οι δύο κύριοι λόγοι για τους οποίους αυτό έχει νόημα είναι η επεκτασιμότητα και η επαναληψιμότητα. Χρησιμοποιώντας το docker, μπορείτε να αυξήσετε γρήγορα μια ντουζίνα build agents που θα έχουν ακριβώς το ίδιο περιβάλλον με το προηγούμενο. Αυτό κάνει τη ζωή των μηχανικών CI πολύ πιο εύκολη. Είναι πολύ εύκολο να ωθήσετε το android-sdk στο docker, αλλά με τους εξομοιωτές είναι λίγο πιο δύσκολο: θα πρέπει να εργαστείτε λίγο πιο σκληρά (ή να κατεβάσετε ξανά το ολοκληρωμένο από το GitHub).

Συμβουλή Νο 4: μην ξεχνάτε ότι οι επιθεωρήσεις δεν γίνονται για χάρη των επιθεωρήσεων, αλλά για τους ανθρώπους.

Η γρήγορη και, κυρίως, σαφής ανατροφοδότηση είναι πολύ σημαντική για τους προγραμματιστές: τι χάλασε, ποια δοκιμή απέτυχε, πού μπορώ να δω το buildlog.

Συμβουλή #5: Να είστε ρεαλιστές όταν αναπτύσσετε τη Συνεχή Ενσωμάτωση.

Κατανοήστε ξεκάθαρα ποιους τύπους σφαλμάτων θέλετε να αποτρέψετε, πόσους πόρους, χρόνο και χρόνο υπολογιστή είστε διατεθειμένοι να ξοδέψετε. Οι έλεγχοι που διαρκούν πολύ μπορούν, για παράδειγμα, να αναβληθούν κατά τη διάρκεια της νύχτας. Και όσα από αυτά πιάνουν όχι πολύ σημαντικά λάθη θα πρέπει να εγκαταλειφθούν εντελώς.

Συμβουλή #6: Χρησιμοποιήστε έτοιμα εργαλεία.

Υπάρχουν πολλές εταιρείες τώρα που παρέχουν cloud CI.

Εξέλιξη του CI στην ομάδα ανάπτυξης κινητής τηλεφωνίας

Αυτή είναι μια καλή λύση για μικρές ομάδες. Δεν χρειάζεται να υποστηρίξετε τίποτα, απλώς πληρώστε λίγα χρήματα, δημιουργήστε την εφαρμογή σας και εκτελέστε ακόμη και δοκιμές οργάνων.

Συμβουλή #7: Σε μια μεγάλη ομάδα, οι εσωτερικές λύσεις είναι πιο κερδοφόρες.

Αλλά αργά ή γρήγορα, καθώς η ομάδα μεγαλώνει, οι εσωτερικές λύσεις θα γίνουν πιο κερδοφόρες. Υπάρχει ένα πρόβλημα με αυτές τις αποφάσεις. Υπάρχει ένας νόμος φθίνουσας απόδοσης στα οικονομικά: σε κάθε έργο, κάθε επόμενη βελτίωση είναι όλο και πιο δύσκολη και απαιτεί όλο και περισσότερες επενδύσεις.

Τα Οικονομικά περιγράφουν ολόκληρη τη ζωή μας, συμπεριλαμβανομένης της Συνεχούς Ενσωμάτωσης. Έφτιαξα ένα χρονοδιάγραμμα κόστους εργασίας για κάθε στάδιο ανάπτυξης της Συνεχούς Ενσωμάτωσης.

Εξέλιξη του CI στην ομάδα ανάπτυξης κινητής τηλεφωνίας

Είναι σαφές ότι η όποια βελτίωση γίνεται όλο και πιο δύσκολη. Κοιτάζοντας αυτό το γράφημα, μπορείτε να καταλάβετε ότι η Συνεχής Ενοποίηση πρέπει να αναπτυχθεί σύμφωνα με την αύξηση του μεγέθους της ομάδας. Για μια ομάδα δύο ατόμων, οι δαπάνες 50 ημερών για την ανάπτυξη μιας εσωτερικής φάρμας εξομοιωτών είναι μια μέτρια ιδέα. Αλλά την ίδια στιγμή, για μια μεγάλη ομάδα, το να μην κάνει καθόλου Συνεχής Ενσωμάτωση είναι επίσης κακή ιδέα, επειδή προβλήματα ενσωμάτωσης, επιδιόρθωση επικοινωνίας κ.λπ. θα πάρει ακόμη περισσότερο χρόνο.

Ξεκινήσαμε με την ιδέα ότι χρειάζεται αυτοματοποίηση γιατί οι άνθρωποι είναι ακριβοί, κάνουν λάθη και τεμπέληδες. Αλλά και οι άνθρωποι αυτοματοποιούνται. Επομένως, όλα τα ίδια προβλήματα ισχύουν για την αυτοματοποίηση.

  • Ο αυτοματισμός είναι ακριβός. Θυμηθείτε το πρόγραμμα εργασίας.
  • Όσον αφορά την αυτοματοποίηση, οι άνθρωποι κάνουν λάθη.
  • Μερικές φορές είναι πολύ τεμπέλης η αυτοματοποίηση, γιατί όλα λειτουργούν έτσι. Γιατί να βελτιώσετε οτιδήποτε άλλο, γιατί όλη αυτή η Συνεχής Ένταξη;

Αλλά έχω στατιστικά στοιχεία: τα σφάλματα καταγράφονται στο 20% των συναρμολογήσεων. Και αυτό δεν συμβαίνει επειδή οι προγραμματιστές μας γράφουν κακώς τον κώδικα. Αυτό συμβαίνει επειδή οι προγραμματιστές είναι βέβαιοι ότι εάν κάνουν κάποιο λάθος, δεν θα καταλήξει στην ανάπτυξη, θα συλληφθεί από αυτοματοποιημένους ελέγχους. Αντίστοιχα, οι προγραμματιστές μπορούν να αφιερώσουν περισσότερο χρόνο γράφοντας κώδικα και ενδιαφέροντα πράγματα, αντί να τρέχουν και να δοκιμάζουν κάτι τοπικά.

Εξασκηθείτε στη Συνεχή Ενσωμάτωση. Αλλά με μέτρο.

Παρεμπιπτόντως, ο Νικολάι Νεστέροφ όχι μόνο δίνει εξαιρετικές αναφορές ο ίδιος, αλλά είναι και μέλος της επιτροπής προγράμματος AppsConf και βοηθά τους άλλους να προετοιμάσουν ουσιαστικές ομιλίες για εσάς. Η πληρότητα και η χρησιμότητα του επόμενου προγράμματος συνεδρίου μπορεί να αξιολογηθεί με βάση τα θέματα στο πρόγραμμα. Και για λεπτομέρειες, ελάτε στο Infospace στις 22-23 Απριλίου.

Πηγή: www.habr.com

Προσθέστε ένα σχόλιο