Mobil geliştirme ekibinde CI'nın evrimi

Günümüzde çoğu yazılım ürünü ekipler halinde geliştirilmektedir. Başarılı ekip gelişiminin koşulları basit bir diyagram şeklinde gösterilebilir.

Mobil geliştirme ekibinde CI'nın evrimi

Kodunuzu yazdıktan sonra aşağıdakilerden emin olmanız gerekir:

  1. Çalışıyor.
  2. Meslektaşlarınızın yazdığı kod dahil hiçbir şeyi bozmaz.

Her iki koşul da karşılanırsa başarıya giden yoldasınız demektir. Bu koşulları kolayca kontrol etmek ve karlı yoldan sapmamak için Sürekli Entegrasyon'u ortaya çıkardık.

CI, kodunuzu mümkün olduğunca sık genel ürün koduna entegre ettiğiniz bir iş akışıdır. Ve sadece entegre olmakla kalmıyor, aynı zamanda her şeyin çalışıp çalışmadığını da sürekli kontrol ediyorsunuz. Çok ve sık kontrol etmeniz gerektiğinden otomasyonu düşünmeye değer. Her şeyi manuel olarak kontrol edebilirsiniz, ancak yapmamalısınız ve işte nedeni.

  • sevgili insanlar. Herhangi bir programcının bir saatlik çalışması, herhangi bir sunucunun bir saatlik çalışmasından daha pahalıdır.
  • İnsanlar hata yapar. Bu nedenle, testlerin yanlış dalda çalıştırıldığı veya test uzmanları için yanlış işlemin derlendiği durumlar ortaya çıkabilir.
  • İnsanlar tembeldir. Zaman zaman bir görevi bitirdiğimde şu düşünce ortaya çıkıyor: “Kontrol edilecek ne var? İki satır yazdım - her şey çalışıyor! Bazılarınızın da zaman zaman bu tür düşüncelere sahip olduğunu düşünüyorum. Ama her zaman kontrol etmelisin.

Nikolai Nesterov, Avito mobil geliştirme ekibinde Sürekli Entegrasyon'un nasıl uygulandığını ve geliştirildiğini, günde 0 yapıdan 450 yapıya nasıl çıktıklarını ve yapı makinelerinin günde 200 saat montaj yaptığını söylüyor (Nnesterov) CI/CD Android uygulamasının tüm evrimsel değişikliklerinin bir katılımcısıdır.

Hikaye bir Android komutu örneğine dayanmaktadır, ancak yaklaşımların çoğu iOS'ta da geçerlidir.


Bir zamanlar Avito Android ekibinde bir kişi çalışıyordu. Tanım gereği Sürekli Entegrasyon'dan hiçbir şeye ihtiyacı yoktu: Entegre olacak kimse yoktu.

Ancak uygulama büyüdü, giderek daha fazla yeni görev ortaya çıktı ve ekip de buna göre büyüdü. Bir noktada, daha resmi olarak bir kod entegrasyon süreci oluşturmanın zamanı gelmiştir. Git akışının kullanılmasına karar verildi.

Mobil geliştirme ekibinde CI'nın evrimi

Git akışı kavramı iyi bilinmektedir: Bir projenin ortak bir geliştirme dalı vardır ve her yeni özellik için geliştiriciler ayrı bir dal keser, onu taahhüt eder, iter ve kodlarını geliştirme dalıyla birleştirmek istediklerinde bir dal açarlar. çekme isteği. Bilgiyi paylaşmak ve yaklaşımları tartışmak için kod incelemesini başlattık; yani iş arkadaşlarının birbirlerinin kodunu kontrol etmesi ve onaylaması gerekiyor.

çekler

Kodu gözlerinizle görmek güzel ama yeterli değil. Bu nedenle otomatik kontroller getiriliyor.

  • Öncelikle kontrol ediyoruz ARK montajı.
  • Много Junit testleri.
  • Kod kapsamını dikkate alıyoruz, çünkü testler yürütüyoruz.

Bu kontrollerin nasıl yapılması gerektiğini anlamak için Avito'daki geliştirme sürecine bakalım.

Şematik olarak şu şekilde temsil edilebilir:

  • Bir geliştirici dizüstü bilgisayarına kod yazıyor. Entegrasyon kontrollerini tam burada çalıştırabilirsiniz; bir taahhüt kancasıyla veya kontrolleri arka planda çalıştırabilirsiniz.
  • Geliştirici kodu gönderdikten sonra bir çekme isteği açar. Kodunun geliştirme dalına dahil edilebilmesi için kod incelemesinden geçilmesi ve gerekli sayıda onayın toplanması gerekir. Denetimleri ve derlemeleri buradan etkinleştirebilirsiniz: tüm derlemeler başarılı olana kadar çekme isteği birleştirilemez.
  • Çekme isteği birleştirildikten ve kod geliştirmeye dahil edildikten sonra, uygun bir zaman seçebilirsiniz: örneğin gece, tüm sunucuların boş olduğu zaman ve istediğiniz kadar kontrol çalıştırın.

Kimse dizüstü bilgisayarında tarama yapmaktan hoşlanmazdı. Bir geliştirici bir özelliği bitirdiğinde, onu hızlı bir şekilde itmek ve bir çekme isteği açmak ister. Şu anda bazı uzun kontroller başlatılırsa, bu sadece çok hoş olmakla kalmaz, aynı zamanda gelişimi de yavaşlatır: dizüstü bilgisayar bir şeyi kontrol ederken, üzerinde normal şekilde çalışmak imkansızdır.

Geceleri kontrol yapmayı gerçekten sevdik, çünkü çok fazla zaman ve sunucu var, etrafta dolaşabilirsiniz. Ancak maalesef özellik kodu geliştirilmeye başladığında geliştiricinin CI'nın bulduğu hataları düzeltme konusunda çok daha az motivasyonu olur. Sabah raporunda bulunan tüm hatalara baktığımda onları bir gün sonra düzelteceğimi düşünürken kendimi periyodik olarak yakaladım, çünkü artık Jira'da yapmaya başlamak istediğim yeni ve harika bir görev var.

Kontroller bir çekme isteğini engellerse, yeterli motivasyon vardır, çünkü yapılar yeşile dönene kadar kod geliştirmeye geçmeyecektir, bu da görevin tamamlanmayacağı anlamına gelir.

Sonuç olarak şu stratejiyi seçtik: Geceleri mümkün olan maksimum sayıda kontrol gerçekleştiriyoruz ve bunların en kritiklerini ve en önemlisi en hızlılarını bir çekme isteği üzerine başlatıyoruz. Ancak burada durmuyoruz; paralel olarak kontrollerin hızını, onları gece modundan çekme isteği kontrollerine aktaracak şekilde optimize ediyoruz.

O zamanlar tüm derlemelerimiz oldukça hızlı bir şekilde tamamlanıyordu, bu nedenle çekme isteğini engelleyici olarak ARK yapısını, Junit testlerini ve kod kapsamı hesaplamalarını dahil ettik. Açtık, düşündük ve ihtiyacımız olmadığını düşündüğümüz için kod kapsamından vazgeçtik.

Temel CI'yi tamamen kurmamız iki günümüzü aldı (bundan sonra zaman tahmini yaklaşıktır, ölçek için gereklidir).

Ondan sonra daha fazla düşünmeye başladık - doğru kontrol ediyor muyuz? Çekme istekleri üzerine derlemeleri doğru şekilde çalıştırıyor muyuz?

Çekme isteğinin açıldığı şubenin son commit'inde derlemeye başladık. Ancak bu işlemin testleri yalnızca geliştiricinin yazdığı kodun çalıştığını gösterebilir. Ama hiçbir şeyi kırmadığını kanıtlamıyorlar. Aslında, bir özellik birleştirildikten sonra geliştirme dalının durumunu kontrol etmeniz gerekir.

Mobil geliştirme ekibinde CI'nın evrimi

Bunu yapmak için basit bir bash betiği yazdık premerge.sh:

#!/usr/bin/env bash

set -e

git fetch origin develop

git merge origin/develop

Burada, geliştirmedeki en son değişikliklerin tümü basitçe yukarı çekilir ve mevcut şubeye birleştirilir. Premerge.sh betiğini tüm derlemelerde ilk adım olarak ekledik ve tam olarak ne istediğimizi kontrol etmeye başladık. bütünleşme.

Sorunun yerelleştirilmesi, çözüm bulunması ve bu senaryonun yazılması üç gün sürdü.

Uygulama gelişti, giderek daha fazla görev ortaya çıktı, ekip büyüdü ve premerge.sh bazen bizi hayal kırıklığına uğratmaya başladı. Develop'ta yapıyı bozan çelişkili değişiklikler vardı.

Bunun nasıl gerçekleştiğine dair bir örnek:

Mobil geliştirme ekibinde CI'nın evrimi

İki geliştirici aynı anda A ve B özellikleri üzerinde çalışmaya başlar. A özelliğinin geliştiricisi projede kullanılmayan bir özellik keşfeder answer() ve iyi bir izci gibi onu ortadan kaldırır. Aynı zamanda B özelliğinin geliştiricisi kendi dalında bu fonksiyona yeni bir çağrı ekler.

Geliştiriciler işlerini bitirip aynı anda bir çekme isteği açarlar. Yapılar başlatılır, premerge.sh en son geliştirme durumuyla ilgili her iki çekme isteğini de kontrol eder - tüm kontroller yeşildir. Daha sonra A özelliğinin çekme isteği birleştirilir, B özelliğinin çekme isteği birleştirilir... Boom! Geliştirme kodu var olmayan bir işleve çağrı içerdiğinden, aralar geliştirin.

Mobil geliştirme ekibinde CI'nın evrimi

Gelişmediği zaman, yerel felaket. Tüm ekip hiçbir şeyi toplayıp teste gönderemez.

Öyle oldu ki, çoğunlukla altyapı görevleri üzerinde çalıştım: analitik, ağ, veritabanları. Yani diğer geliştiricilerin kullandığı işlevleri ve sınıfları yazan bendim. Bu nedenle kendimi sık sık benzer durumların içinde buldum. Hatta bu resmi bir süreliğine orada asılı tuttum.

Mobil geliştirme ekibinde CI'nın evrimi

Bu bize yakışmadığı için bunu nasıl engelleyebiliriz diye seçenekleri araştırmaya başladık.

Gelişim nasıl kırılmaz?

İlk seçenek: Geliştirmeyi güncellerken tüm çekme isteklerini yeniden oluşturun. Örneğimizde A özelliğine sahip çekme isteği geliştirmeye dahil edilecek ilk istekse, B özelliğinin çekme isteği yeniden oluşturulacak ve buna göre derleme hatası nedeniyle kontroller başarısız olacaktır.

Bunun ne kadar süreceğini anlamak için iki PR içeren bir örneği düşünün. İki PR açıyoruz: iki yapı, iki kontrol çalışması. İlk PR geliştirmeyle birleştirildikten sonra ikincisinin yeniden oluşturulması gerekir. Toplamda, iki PR üç kontrol çalıştırması gerektirir: 2 + 1 = 3.

Prensip olarak sorun değil. Ancak istatistiklere baktık ve ekibimizdeki tipik durumun 10 açık PR olduğunu ve ardından kontrol sayısı ilerlemenin toplamı olduğunu gördük: 10 + 9 +... + 1 = 55. Yani 10'u kabul etmek. PR'ler, 55 kez yeniden inşa etmeniz gerekir. Ve bu, tüm kontrollerin ilk seferde geçtiği, bu düzinelerce işlenirken kimsenin ek bir çekme isteği açmadığı ideal bir durumdur.

Kendinizi "birleştir" düğmesine ilk basan kişi olması gereken bir geliştirici olarak hayal edin, çünkü eğer bir komşunuz bunu yaparsa, tüm yapılar yeniden tamamlanana kadar beklemek zorunda kalacaksınız... Hayır, bu işe yaramayacak gelişimi ciddi şekilde yavaşlatacaktır.

İkinci olası yol: Kod incelemesinden sonra çekme isteklerini toplayın. Yani, bir çekme isteği açarsınız, meslektaşlarınızdan gerekli sayıda onayı toplarsınız, gerekenleri düzeltirsiniz ve ardından yapıları başlatırsınız. Başarılı olmaları durumunda çekme isteği geliştirmeyle birleştirilir. Bu durumda ek yeniden başlatma olmaz, ancak geri bildirim büyük ölçüde yavaşlar. Bir geliştirici olarak, bir çekme isteği açtığımda hemen işe yarayıp yaramayacağını görmek isterim. Örneğin, bir test başarısız olursa bunu hızlı bir şekilde düzeltmeniz gerekir. Gecikmiş bir derleme durumunda geri bildirim ve dolayısıyla tüm geliştirme yavaşlar. Bu da bize yakışmadı.

Sonuç olarak geriye yalnızca üçüncü seçenek kaldı: bisiklet. Tüm kodlarımız, tüm kaynaklarımız Bitbucket sunucusundaki bir depoda saklanır. Buna göre Bitbucket için bir eklenti geliştirmemiz gerekiyordu.

Mobil geliştirme ekibinde CI'nın evrimi

Bu eklenti, çekme isteği birleştirme mekanizmasını geçersiz kılar. Başlangıç ​​standarttır: PR açılır, tüm derlemeler başlatılır, kod incelemesi tamamlanır. Ancak kod incelemesi tamamlandıktan ve geliştirici "birleştir" seçeneğine tıklamaya karar verdikten sonra eklenti, kontrollerin hangi geliştirme durumuna göre çalıştırıldığını kontrol eder. Geliştirme derlemelerden sonra güncellendiyse, eklenti böyle bir çekme isteğinin ana dalla birleştirilmesine izin vermeyecektir. Nispeten yeni bir geliştirmenin yapılarını yeniden başlatacak.

Mobil geliştirme ekibinde CI'nın evrimi

Çakışan değişikliklerin olduğu örneğimizde, bu tür yapılar bir derleme hatası nedeniyle başarısız olacaktır. Buna göre, B özelliğinin geliştiricisinin kodu düzeltmesi, kontrolleri yeniden başlatması gerekecek, ardından eklenti otomatik olarak çekme isteğini uygulayacaktır.

Bu eklentiyi uygulamadan önce çekme isteği başına ortalama 2,7 inceleme çalıştırması elde ettik. Eklentiyle birlikte 3,6 lansman yapıldı. Bu bize yakıştı.

Bu eklentinin bir dezavantajı olduğunu belirtmekte fayda var: derlemeyi yalnızca bir kez yeniden başlatır. Yani, çelişkili değişikliklerin gelişebileceği küçük bir pencere hala var. Ancak bunun olasılığı düşüktür ve biz bu dengelemeyi başlangıç ​​sayısı ile başarısızlık olasılığı arasında yaptık. İki yıl içinde yalnızca bir kez ateşlendi, yani muhtemelen boşuna değildi.

Bitbucket eklentisinin ilk versiyonunu yazmamız iki haftamızı aldı.

Yeni çekler

Bu arada ekibimiz büyümeye devam etti. Yeni kontroller eklendi.

Şöyle düşündük: Eğer önlenebilecekse neden hata yapalım? İşte bu yüzden uyguladılar statik kod analizi. Android SDK'da bulunan lint ile başladık. Ancak o zamanlar Kotlin koduyla nasıl çalışılacağını hiç bilmiyordu ve zaten uygulamanın %75'i Kotlin'de yazılmıştı. Bu nedenle tüy bırakmayanlara yerleşik olanlar eklendi Android Studio kontrol eder.

Bunu yapmak için çok fazla saptırma yapmak zorunda kaldık: Android Studio'yu alıp Docker'da paketleyin ve sanal bir monitörle CI'da çalıştırın, böylece gerçek bir dizüstü bilgisayarda çalıştığını düşünsün. Ama işe yaradı.

Bu dönemde çok fazla yazmaya başladık enstrümantasyon testleri ve uygulandı ekran görüntüsü testi. Bu, ayrı bir küçük görünüm için bir referans ekran görüntüsünün oluşturulduğu zamandır ve test, görünümden bir ekran görüntüsü alıp bunu standartla doğrudan piksel piksel karşılaştırmaktan oluşur. Bir tutarsızlık varsa, bu, düzenin bir yerde yanlış gittiği veya stillerde bir şeylerin yanlış olduğu anlamına gelir.

Ancak enstrümantasyon testlerinin ve ekran görüntüsü testlerinin cihazlarda, emülatörlerde veya gerçek cihazlarda çalıştırılması gerekir. Testlerin çok fazla olduğunu ve sık sık yapıldığını düşünürsek bütün bir çiftliğe ihtiyaç var. Kendi çiftliğinizi kurmak çok emek yoğun olduğundan hazır bir seçenek bulduk: Firebase Test Laboratuvarı.

Firebase Test Laboratuvarı

Firebase'in bir Google ürünü olması, yani güvenilir olması ve hiçbir zaman ölme ihtimalinin düşük olması gerektiği için seçildi. Fiyatlar makul: Gerçek bir cihazın saatlik çalışması başına 5 ABD Doları, bir emülatörün saatlik çalışması başına 1 ABD Doları.

Firebase Test Lab'ın CI'mıza uygulanması yaklaşık üç hafta sürdü.

Ancak ekip büyümeye devam etti ve Firebase ne yazık ki bizi hayal kırıklığına uğratmaya başladı. O zamanlar herhangi bir SLA'sı yoktu. Bazen Firebase, gerekli sayıda cihazın testler için serbest kalmasını bekletti ve istediğimiz gibi hemen çalıştırmaya başlamadı. Sırada beklemek yarım saat kadar sürdü ki bu çok uzun bir süre. Her PR'de enstrümantasyon testleri yapıldı, gecikmeler geliştirmeyi gerçekten yavaşlattı ve ardından aylık faturanın tamamı geldi. Genel olarak, ekip yeterince büyüdüğü için Firebase'den vazgeçilip şirket içinde çalışmaya karar verildi.

Docker + Python + bash

Docker'ı aldık, içine emülatörler doldurduk, Python'da gerekli sayıda emülatörü doğru sürümde başlatan ve gerektiğinde durduran basit bir program yazdık. Ve elbette birkaç bash betiği - onlar olmasaydı nerede olurduk?

Kendi test ortamımızı oluşturmak beş hafta sürdü.

Sonuç olarak, her çekme isteği için kapsamlı bir birleştirme engelleme kontrol listesi vardı:

  • ARK montajı;
  • Junit testleri;
  • tüysüz;
  • Android Studio kontrolleri;
  • Enstrümantasyon testleri;
  • Ekran görüntüsü testleri.

Bu sayede birçok olası arızanın önüne geçildi. Teknik olarak her şey işe yaradı ancak geliştiriciler sonuçların beklenmesinin çok uzun olduğundan şikayetçiydi.

Ne kadar süre çok uzun? Bitbucket ve TeamCity'den gelen verileri analiz sistemine yükledik ve şunu fark ettik: ortalama bekleme süresi 45 dakika. Yani bir geliştirici, bir çekme isteği açarken derleme sonuçları için ortalama 45 dakika bekler. Bana göre bu çok fazla ve bu şekilde çalışamazsınız.

Tabii ki tüm inşaatlarımızı hızlandırmaya karar verdik.

Hadi hızlanalım

Yapıların sıklıkla kuyrukta durduğunu görünce yaptığımız ilk şey daha fazla donanım satın aldım — kapsamlı geliştirme en basitidir. Yapılar sıraya girmeyi bıraktı, ancak bazı kontrollerin kendisi çok uzun zaman aldığından bekleme süresi yalnızca biraz azaldı.

Çok uzun süren çeklerin kaldırılması

Sürekli Entegrasyonumuz bu tür hataları ve sorunları tespit edebilir.

  • gitmiyorum. Çakışan değişiklikler nedeniyle bir şey oluşturulamadığında CI bir derleme hatası yakalayabilir. Daha önce de söylediğim gibi o zaman kimse hiçbir şeyi birleştiremez, gelişme durur ve herkes tedirgin olur.
  • Davranışta hata. Örneğin, uygulama derlendiğinde ancak bir düğmeye bastığınızda çöktüğünde veya düğmeye hiç basılmadığında. Bu kötü çünkü böyle bir hata kullanıcıya ulaşabilir.
  • Düzende hata. Örneğin, bir düğmeye tıklandı ancak 10 piksel sola taşındı.
  • Teknik borç artışı.

Bu listeye baktıktan sonra sadece ilk iki noktanın kritik olduğunu fark ettik. Bu tür sorunları öncelikle yakalamak istiyoruz. Mizanpajdaki hatalar tasarım inceleme aşamasında keşfedilir ve daha sonra kolayca düzeltilebilir. Teknik borçla uğraşmak ayrı bir süreç ve planlama gerektirdiğinden, çekme talebi üzerine bunu test etmemeye karar verdik.

Bu sınıflandırmaya dayanarak tüm çek listesini salladık. Lint'in üzerini çizdim ve lansmanını bir geceye erteledi: sırf projede ne kadar sorun olduğuna dair bir rapor hazırlamak için. Teknik borçla ayrı çalışma konusunda anlaştık ve Android Studio kontrolleri tamamen terk edildi. Denetimleri çalıştırmak için Docker'daki Android Studio ilginç geliyor ancak destek konusunda birçok soruna neden oluyor. Android Studio sürümlerine yapılacak herhangi bir güncelleme, anlaşılmaz hatalarla mücadele anlamına gelir. Ekran görüntüsü testlerini desteklemek de zordu çünkü kitaplık çok kararlı değildi ve yanlış pozitifler vardı. Ekran görüntüsü testleri kontrol listesinden kaldırıldı.

Sonuç olarak elimizde şunlar kaldı:

  • ARK montajı;
  • Junit testleri;
  • Enstrümantasyon testleri.

Gradle uzaktan önbelleği

Ağır kontroller olmadan her şey daha iyi hale geldi. Ancak mükemmelliğin sınırı yoktur!

Uygulamamız zaten yaklaşık 150 gradle modülüne bölünmüştü. Gradle uzaktan önbelleği genellikle bu durumda iyi çalışır, bu yüzden denemeye karar verdik.

Gradle uzaktan önbellek, bireysel modüllerdeki bireysel görevler için derleme yapıtlarını önbelleğe alabilen bir hizmettir. Gradle, kodu gerçekten derlemek yerine, uzak önbelleği açmak ve birisinin bu görevi daha önce gerçekleştirip gerçekleştirmediğini sormak için HTTP'yi kullanır. Eğer evet ise, sadece sonucu indirir.

Gradle uzak önbelleğini çalıştırmak kolaydır çünkü Gradle bir Docker görüntüsü sağlar. Bunu üç saatte başardık.

Tek yapmanız gereken Docker'ı başlatmak ve projeye bir satır yazmaktı. Ancak hızlı bir şekilde başlatılabilse de her şeyin yolunda gitmesi oldukça uzun zaman alacak.

Aşağıda önbellek eksikleri grafiği bulunmaktadır.

Mobil geliştirme ekibinde CI'nın evrimi

Başlangıçta, önbellek kayıplarının yüzdesi yaklaşık 65 civarındaydı. Üç hafta sonra bu değeri %20'ye çıkarmayı başardık. Android uygulamasının topladığı görevlerin, Gradle'ın önbelleği kaçırdığı için garip geçişli bağımlılıklara sahip olduğu ortaya çıktı.

Önbelleği bağlayarak derlemeyi büyük ölçüde hızlandırdık. Ancak montajın yanı sıra enstrümantasyon testleri de var ve bunlar uzun zaman alıyor. Belki de her çekme isteği için tüm testlerin yapılması gerekmeyebilir. Bunu öğrenmek için etki analizini kullanıyoruz.

Etki analizi

Bir çekme isteği üzerine git diff'i topluyoruz ve değiştirilmiş Gradle modüllerini buluyoruz.

Mobil geliştirme ekibinde CI'nın evrimi

Yalnızca değiştirilen modülleri ve bunlara bağlı tüm modülleri kontrol eden enstrümantasyon testlerini çalıştırmak mantıklıdır. Komşu modüller için testler yapmanın bir anlamı yok: oradaki kod değişmedi ve hiçbir şey bozulamaz.

Enstrümantasyon testleri o kadar basit değildir çünkü bunların en üst düzey Uygulama modülünde yer alması gerekir. Her testin hangi modüle ait olduğunu anlamak için bayt kodu analiziyle buluşsal yöntemlerden yararlandık.

Enstrümantasyon testlerinin işleyişinin, yalnızca ilgili modülleri test edecek şekilde yükseltilmesi yaklaşık sekiz hafta sürdü.

Denetimleri hızlandırmaya yönelik tedbirler başarıyla işe yaradı. 45 dakikadan 15 dakikaya çıktık. İnşaat için çeyrek saat beklemek zaten normal.

Ancak artık geliştiriciler hangi yapıların başlatıldığını, günlüğün nerede görüleceğini, yapının neden kırmızı olduğunu, hangi testin başarısız olduğunu vb. anlamadıklarından şikayet etmeye başladılar.

Mobil geliştirme ekibinde CI'nın evrimi

Geri bildirimle ilgili sorunlar geliştirmeyi yavaşlatır, bu nedenle her PR ve yapı hakkında mümkün olduğunca net ve ayrıntılı bilgi sağlamaya çalıştık. Hangi yapının başarısız olduğunu ve nedenini belirten Bitbucket'teki halkla ilişkiler yorumlarıyla başladık ve Slack'te hedeflenen mesajlar yazdık. Sonunda, şu anda çalışmakta olan tüm yapıların ve durumlarının (sıraya alınmış, çalışıyor, çökmüş veya tamamlanmış) listesini içeren sayfa için bir PR kontrol paneli oluşturduk. Yapıya tıklayıp günlüğüne ulaşabilirsiniz.

Mobil geliştirme ekibinde CI'nın evrimi

Ayrıntılı geri bildirime altı hafta harcandı.

Planlar

Yakın tarihe geçelim. Geri bildirim sorununu çözdükten sonra yeni bir seviyeye ulaştık; kendi emülatör çiftliğimizi kurmaya karar verdik. Çok sayıda test ve emülatör olduğunda bunların yönetilmesi zordur. Sonuç olarak tüm emülatörlerimiz esnek kaynak yönetimine sahip k8s kümesine taşındı.

Ayrıca başka planlar da var.

  • Geri Dönüş Tüyü (ve diğer statik analizler). Zaten bu yönde çalışıyoruz.
  • Her şeyi bir PR engelleyicide çalıştırın uçtan uca testler tüm SDK sürümlerinde.

Böylece Avito'da Sürekli Entegrasyonun gelişim tarihinin izini sürdük. Şimdi tecrübeli bir bakış açısıyla bazı tavsiyeler vermek istiyorum.

Советы

Tek bir tavsiye verecek olsam o da şu olurdu:

Lütfen kabuk komut dosyalarına dikkat edin!

Bash çok esnek ve güçlü bir araçtır, komut dosyaları yazmak çok kullanışlı ve hızlıdır. Ama bununla tuzağa düşebilirsiniz ve ne yazık ki biz de tuzağa düştük.

Her şey yapım makinelerimizde çalışan basit komut dosyalarıyla başladı:

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

Ancak, bildiğiniz gibi, zamanla her şey gelişir ve daha karmaşık hale gelir - hadi bir betiği diğerinden çalıştıralım, oraya bazı parametreler aktaralım - sonunda şu anda hangi bash yerleştirme düzeyinde sıralı olduğumuzu belirleyen bir fonksiyon yazmamız gerekiyordu. Her şeyi başlatmak için gerekli alıntıları eklemek için.

Mobil geliştirme ekibinde CI'nın evrimi

Bu tür senaryoların geliştirilmesi için gereken işçilik maliyetlerini tahmin edebilirsiniz. Bu tuzağa düşmemenizi tavsiye ederim.

Ne değiştirilebilir?

  • Herhangi bir betik dili. Şuraya yaz: Python veya Kotlin Komut Dosyası daha kullanışlıdır çünkü bu komut dosyaları değil, programlamadır.
  • Veya formdaki tüm yapı mantığını açıklayın Özel kepçe görevleri projeniz için.

İkinci seçeneği seçmeye karar verdik ve şimdi sistematik olarak tüm bash betiklerini siliyoruz ve birçok özel gradle görevi yazıyoruz.

İpucu #2: Altyapıyı kodda saklayın.

Sürekli Entegrasyon ayarının Jenkins veya TeamCity vb. kullanıcı arayüzü arayüzünde değil, doğrudan proje deposundaki metin dosyaları biçiminde saklanması kullanışlıdır. Bu versiyonlanabilirlik sağlar. Kodu geri almak veya başka bir dalda oluşturmak zor olmayacaktır.

Komut dosyaları bir projede saklanabilir. Çevre ile ne yapmalı?

İpucu #3: Docker çevreye yardımcı olabilir.

Kesinlikle Android geliştiricilerine yardımcı olacaktır; ne yazık ki iOS'ta henüz bir özellik yok.

Bu, jdk ve Android-sdk içeren basit bir liman işçisi dosyası örneğidir:

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

Bu Docker dosyasını yazdıktan sonra (size bir sır vereceğim, yazmanıza gerek yok, sadece GitHub'dan hazır olarak çekin) ve görüntüyü birleştirdikten sonra, uygulamayı oluşturabileceğiniz sanal bir makineye sahip olursunuz. ve Junit testlerini çalıştırın.

Bunun anlamlı olmasının iki ana nedeni ölçeklenebilirlik ve tekrarlanabilirliktir. Docker'ı kullanarak, öncekiyle tamamen aynı ortama sahip olacak bir düzine yapı aracısını hızlı bir şekilde oluşturabilirsiniz. Bu, CI mühendislerinin hayatını çok daha kolay hale getiriyor. Android SDK'yı docker'a itmek oldukça kolaydır, ancak emülatörlerde bu biraz daha zordur: biraz daha fazla çalışmanız (veya bitmiş olanı GitHub'dan tekrar indirmeniz) gerekecektir.

4. İpucu: Denetimlerin denetim olsun diye değil, insanlar için yapıldığını unutmayın.

Geliştiriciler için hızlı ve en önemlisi net geri bildirim çok önemlidir: ne bozuldu, hangi test başarısız oldu, derleme günlüğünü nerede görebilirim.

İpucu 5: Sürekli Entegrasyonu geliştirirken pragmatik olun.

Ne tür hataları önlemek istediğinizi, ne kadar kaynak, zaman ve bilgisayar zamanı harcamak istediğinizi açıkça anlayın. Örneğin çok uzun süren çekler bir gecede ertelenebilir. Ve çok önemli olmayan hataları yakalayanlar tamamen terk edilmelidir.

İpucu 6: Hazır araçları kullanın.

Artık bulut CI sağlayan birçok şirket var.

Mobil geliştirme ekibinde CI'nın evrimi

Bu küçük ekipler için iyi bir çözümdür. Hiçbir şeyi desteklemenize gerek yok, sadece biraz para ödeyin, uygulamanızı oluşturun ve hatta enstrümantasyon testleri yapın.

İpucu #7: Büyük bir ekipte şirket içi çözümler daha karlıdır.

Ancak ekip büyüdükçe er ya da geç şirket içi çözümler daha karlı hale gelecektir. Bu kararlarla ilgili bir sorun var. Ekonomide azalan getiriler yasası vardır: Herhangi bir projede, sonraki her iyileştirme giderek daha zorlaşır ve giderek daha fazla yatırım gerektirir.

Ekonomi, Sürekli Entegrasyon da dahil olmak üzere tüm yaşamımızı tanımlar. Sürekli Entegrasyonumuzun gelişiminin her aşaması için bir işçilik maliyetleri çizelgesi oluşturdum.

Mobil geliştirme ekibinde CI'nın evrimi

Herhangi bir iyileştirmenin giderek daha zor hale geldiği açıktır. Bu grafiğe baktığınızda ekip büyüklüğünün büyümesine göre Sürekli Entegrasyonun geliştirilmesi gerektiğini anlayabilirsiniz. İki kişilik bir ekip için, dahili bir emülatör çiftliği geliştirmek için 50 gün harcamak vasat bir fikir. Ancak aynı zamanda büyük bir ekip için Sürekli Entegrasyon yapmamak da kötü bir fikirdir çünkü entegrasyon sorunları, iletişimi düzeltmek vb. daha da fazla zaman alacaktır.

İnsanların pahalı olması, hata yapması ve tembel olması nedeniyle otomasyonun gerekli olduğu düşüncesiyle yola çıktık. Ancak insanlar aynı zamanda otomatikleşiyor. Bu nedenle aynı sorunların tümü otomasyon için de geçerlidir.

  • Otomasyon pahalıdır. Çalışma programını hatırlayın.
  • Otomasyon söz konusu olduğunda insanlar hata yapar.
  • Bazen otomatikleştirmek çok tembellik olur çünkü her şey bu şekilde çalışır. Neden başka bir şeyi geliştirelim, neden tüm bu Sürekli Entegrasyon?

Ancak istatistiklerim var: montajların %20'sinde hatalar tespit ediliyor. Bunun nedeni geliştiricilerimizin kötü kod yazmaları değildir. Bunun nedeni, geliştiricilerin bir hata yapmaları durumunda bunun geliştirmeyle sonuçlanmayacağından, otomatik kontrollerle tespit edileceğinden emin olmalarıdır. Buna göre geliştiriciler, bir şeyi yerel olarak çalıştırmak ve test etmek yerine kod yazmaya ve ilginç şeyler yazmaya daha fazla zaman ayırabilirler.

Sürekli Entegrasyon Uygulayın. Ama ölçülü olarak.

Bu arada, Nikolai Nesterov sadece kendisi harika raporlar vermekle kalmıyor, aynı zamanda program komitesinin de bir üyesi AppsConf başkalarının sizin için anlamlı konuşmalar hazırlamasına yardımcı olur. Bir sonraki konferans programının bütünlüğü ve kullanışlılığı aşağıdaki konulara göre değerlendirilebilir: takvim. Ayrıntılar için 22-23 Nisan'da Infospace'e gelin.

Kaynak: habr.com

Yorum ekle