CI:s evolution inom mobilutvecklingsteam

Idag utvecklas de flesta programvaruprodukter i team. Villkoren för framgÄngsrik teamutveckling kan sammanfattas i en enkel schema.

CI:s evolution inom mobilutvecklingsteam

NÀr du har skrivit koden mÄste du se till att den:

  1. Fungerar.
  2. Inte bryter nÄgot, inklusive koden som dina kollegor har skrivit.

Om bÄda villkoren Àr uppfyllda Àr du pÄ vÀg mot framgÄng. För att enkelt kunna kontrollera dessa villkor och inte avvika frÄn den lönsamma vÀgen, har Continuous Integration utvecklats.

CI Àr en arbetsprocess dÀr du sÄ ofta som möjligt integrerar din kod med den gemensamma koden för produkten. Och inte bara integrerar, utan ocksÄ stÀndigt kontrollerar att allt fungerar. Eftersom det Àr mycket som behöver kontrolleras och ofta, Àr det vÀrt att tÀnka pÄ automatisering. Man kan göra allt manuellt, men det Àr inte att rekommendera, och hÀr Àr varför.

  • MĂ€nniskor Ă€r dyra. En timme arbete för en programmerare kostar mer Ă€n en timme arbete för en server.
  • MĂ€nniskor gör misstag. DĂ€rför kan det uppstĂ„ situationer nĂ€r tester körs pĂ„ fel gren eller nĂ€r fel begcommit har byggts för testarna.
  • MĂ€nniskor Ă€r lata. Periodvis, nĂ€r jag avslutar en uppgift, har jag tanken: "Vad ska jag ens kontrollera? Jag har skrivit tvĂ„ rader – det fungerar garanterat!" Jag tror att nĂ„gra av er ocksĂ„ ibland fĂ„r sĂ„dana tankar. Men man mĂ„ste alltid kontrollera.

Hur Continuous Integration implementerades och utvecklades i Avitos mobila utvecklingsteam, hur man gick frĂ„n 0 till 450 byggningar per dag, och vad byggmaskinerna samlar in 200 timmar per dag, berĂ€ttar Nikolai Nesterov (nnesterov) – deltagare i alla evolutionĂ€ra förĂ€ndringar av CI/CD Android-applikationen.

BerÀttelsen baseras pÄ exemplet av Android-teamet, men de flesta metoder Àr ocksÄ tillÀmpliga pÄ iOS.

Spela video

En gÄng i tiden arbetade bara en person i Avitos Android-team. För honom behövdes ingenting frÄn Continuous Integration, eftersom det inte fanns nÄgon att integrera med.

Men applikationen vÀxte, fler och fler nya uppgifter dök upp, och dÀrmed vÀxte teamet. Vid en viss tidpunkt kom tiden att mer formellt organisera kodintegrationsprocessen. Det beslutades att anvÀnda Git flow.

CI:s evolution inom mobilutvecklingsteam

Git flow-konceptet Àr vÀlkÀnt: i projektet finns en gemensam branch, develop, och för varje ny funktion skapar utvecklarna en separat branch, gör sina commits, pushar och nÀr de vill föra in sin kod i develop-branchen öppnar de en pull request. För kunskapsutbyte och diskussion av metoder har vi infört code review, vilket innebÀr att kollegor mÄste granska och bekrÀfta varandras kod.

Kontroller

Att se pÄ koden Àr bra, men otillrÀckligt. DÀrför införs automatiska kontroller.

  • Först kontrollerar vi ARC-byggnaden.
  • MĂ„nga Junit-tester.
  • Vi berĂ€knar code coverage, eftersom vi kör tester.

För att förstÄ hur dessa kontroller ska köras, lÄt oss titta pÄ utvecklingsprocessen pÄ Avito.

Det kan schematiskt representeras sÄ hÀr:

  • Utvecklaren skriver kod pĂ„ sin dator. Det Ă€r möjligt att köra integrationskontroller hĂ€r — antingen via commit-hook eller bara köra kontrollerna i bakgrunden.
  • NĂ€r utvecklaren har pushat koden öppnar han en pull request. För att hans kod ska hamna i develop-branchen mĂ„ste han klara code review och fĂ„ tillrĂ€ckligt med bekrĂ€ftelser. Kontroller och byggen kan aktiveras hĂ€r: medan inte alla byggen Ă€r framgĂ„ngsrika kan inte pull request slĂ„s ihop.
  • NĂ€r pull requesten har slagits ihop och koden har hamnat i develop kan man vĂ€lja ett lĂ€mpligt tillfĂ€lle: till exempel pĂ„ natten, nĂ€r alla servrar Ă€r lediga, och köra kontroller hur mycket som helst.

Att köra kontroller pÄ sin dator gillade ingen. NÀr utvecklaren har slutfört sin funktion vill han snabbt push-a den och öppna en pull request. Om det vid den tidpunkten körs nÄgra lÄnga kontroller Àr det inte bara obehagligt utan saktar ocksÄ ner utvecklingen: medan datorn kontrollerar nÄgot kan han inte arbeta normalt.

Vi gillade mycket att köra kontroller pÄ natten, eftersom det finns gott om tid och servrar, man kan verkligen ta sig tid. Men tyvÀrr, nÀr funktionens kod har kommit in i develop har utvecklaren mycket mindre motivation att fixa de fel som CI har hittat. Jag fÄngade mig sjÀlv dÄ och dÄ nÀr jag tittade pÄ alla hittade fel i morgonrapporten och tÀnkte att jag skulle fixa dem senare, eftersom det just nu ligger en fantastisk ny uppgift i Jira som jag verkligen vill börja arbeta med.

Om kontroller blockerar pull requesten, finns det motivation nog, eftersom medan byggena inte Àr gröna, kommer koden inte in i develop, vilket innebÀr att uppgiften inte kommer att bli slutförd.

Till slut valde vi en strategi dĂ€r vi kör en maximal uppsĂ€ttning tester pĂ„ natten, och de mest kritiska och framför allt snabba testerna kör vi vid pull request. Men vi stannar inte dĂ€r — samtidigt optimerar vi hastigheten pĂ„ testerna sĂ„ att vi kan flytta dem frĂ„n nattlĂ€ge till pull request-tester.

Vid den tiden gick alla vĂ„ra byggen tillrĂ€ckligt snabbt, sĂ„ vi aktiverade bara blockeraren för pull request-bygget av ARC, Junit-tester och berĂ€kning av kodtĂ€ckning. Vi aktiverade det, funderade — och beslutade oss för att avstĂ„ frĂ„n kodtĂ€ckning, eftersom vi ansĂ„g att det inte var nödvĂ€ndigt.

Det tog oss tvÄ dagar att konfigurera grundlÀggande CI (denna tidsuppskattning Àr ungefÀrlig och behövs för perspektivet).

Efter det började vi tĂ€nka vidare — testerar vi överhuvudtaget korrekt? Kör vi byggen vid pull request pĂ„ rĂ€tt sĂ€tt?

Vi körde bygget pÄ den senaste commit av grenen frÄn vilken pull requesten öppnades. Men testerna av denna commit kan bara visa att den kod som utvecklaren skrivit fungerar. De bevisar inte att han eller hon inte bröt nÄgot. Egentligen mÄste vi kontrollera tillstÄndet pÄ utvecklingsgrenen efter att funktionen har blivit integrerad.

CI:s evolution inom mobilutvecklingsteam

För detta skrev vi ett enkelt bash-skript. premerge.sh:

#!/usr/bin/env bash

set -e

git fetch origin develop

git merge origin/develop

HÀr dras helt enkelt de senaste Àndringarna frÄn utvecklingsgrenen och slÄs samman med den aktuella grenen. Vi lade till skriptet premerge.sh som det första steget av alla byggen och började kontrollera just det vi vill, det vill sÀga integrationen.

Det tog tre dagar att lokalisera problemen, hitta lösningen och skriva detta skript.

Applikationen utvecklades, uppgifterna blev fler, teamet vÀxte, och ibland började premerge.sh att svika oss. Konfliktande Àndringar trÀngde in i utvecklingsgrenen och bröt bygget.

Ett exempel pÄ hur detta sker:

CI:s evolution inom mobilutvecklingsteam

TvÄ utvecklare börjar samtidigt arbeta med funktionerna A och B. Utvecklaren av funktion A upptÀcker en oanvÀnd funktion i projektet, answer() och, som en bra scout, tar bort den. Samtidigt lÀgger utvecklaren av funktion B till ett nytt anrop av denna funktion i sin gren.

Utvecklarna avslutar sitt arbete och öppnar samtidigt en pull request. Byggen startar, premerge.sh kontrollerar bĂ„da pull requesterna mot det aktuella tillstĂ„ndet pĂ„ utvecklingsgrenen — alla tester Ă€r gröna. Efter det merges pull request A, pull request B... Boom! Utvecklingsgrenen kraschade, eftersom det finns ett anrop av en icke-existerande funktion i koden.

CI:s evolution inom mobilutvecklingsteam

NÀr utvecklingsgrenen inte gÄr att bygga, lokal katastrof. Hela teamet kan inte samla nÄgot och ge det för testning.

SÄ blev det att jag oftast Àgnade mig Ät infrastrukturuppgifter: analys, nÀtverk, databaser. Det var jag som skrev de funktioner och klasser som andra utvecklare anvÀnder. DÀrför hamnade jag ofta i liknande situationer. Jag hade till och med en tid bild pÄ det hÀr.

CI:s evolution inom mobilutvecklingsteam

Eftersom detta inte passade oss började vi arbeta pÄ alternativ för hur vi kunde förhindra det.

Hur man inte bryter develop

Första alternativet: Äterkompilera alla pull requests vid uppdatering av develop. Om i vÄrt exempel pull request med funktion A först gÄr in i develop, kommer pull request för funktion B att Äterkompileras, och dÀrmed kommer kontrollerna att misslyckas pÄ grund av kompilationsfel.

För att förstÄ hur mycket tid detta kommer att ta, lÄt oss titta pÄ ett exempel med tvÄ PR. Vi öppnar tvÄ PR: tvÄ byggen, tvÄ körningar av kontroller. Efter att den första PR har slagits samman med develop mÄste den andra Äterkompileras. Totalt tar det tre körningar av kontroller för tvÄ PR: 2 + 1 = 3.

I princip okej. Men vi tittade pĂ„ statistiken, och en typisk situation i vĂ„rt team var 10 öppna PR, dĂ„ blir antalet kontroller summan av progressionen: 10 + 9 + 
 + 1 = 55. Det vill sĂ€ga för att godkĂ€nna 10 PR mĂ„ste man Ă„terkompilera 55 gĂ„nger. Och det Ă€r i en ideal situation, dĂ€r alla kontroller gĂ„r igenom pĂ„ första försöket, dĂ€r ingen öppnar nĂ„gon ytterligare pull request medan denna tio stycken bearbetas.

FörestÀll dig att du Àr en utvecklare som mÄste hinna trycka pÄ knappen "merge" först, för om det görs av grannen sÄ fÄr man vÀnta pÄ att alla byggen ska genomföras igen... Nej, sÄ hÀr kan vi inte ha det, det kommer allvarligt att fördröja utvecklingen.

Andra möjliga sÀttet: kompilera pull request efter code review. Det vill sÀga du öppnar en pull request, samlar in det nödvÀndiga antalet godkÀnnanden frÄn kollegor, ÄtgÀrdar vad som behövs, och först dÄ kör du byggen. Om de Àr framgÄngsrika, slÄs pull request ihop med develop. I detta fall finns det inga ytterligare omstarter, men feedbacken blir betydligt lÄngsammare. Jag, som utvecklare, vill direkt se om min pull request kan byggas. Till exempel, om ett test misslyckas, behöver jag snabbt fixa det. I hÀndelse av försenad kompilering sÀnks feedbacken, vilket ocksÄ sÀnker hela utvecklingen. Det passade oss inte heller.

Till slut kvarstod bara det tredje alternativet - att cykla. All vÄr kod, alla vÄra kÀllkoder lagras i ett repository pÄ Bitbucket-servern. DÀrför var vi tvungna att utveckla en plugin för Bitbucket.

CI:s evolution inom mobilutvecklingsteam

Denna plugin överskrider sammanslagningsmetoden för pull requestar. Den standardmÀssiga processen inleds: en PR öppnas, alla byggen körs och en kodgranskning utförs. Men efter att kodgranskningen har slutförts och utvecklaren bestÀmmer sig för att klicka pÄ 'merge', kontrollerar pluginen vilket tillstÄnd develop som testerna kördes mot. Om develop har uppdaterats efter byggena tillÄter pluginen inte att sÄdana pull requestar slÄs samman med huvudgrenen. Den startar helt enkelt om byggena mot det nya develop.

CI:s evolution inom mobilutvecklingsteam

I vÄrt exempel med konfliktfyllda Àndringar kommer sÄdana byggen inte att passera pÄ grund av kompilatorfel. DÀrför mÄste utvecklaren av funktion B rÀtta koden och starta om testerna, sÄ tillÀmpas pull requesten automatiskt av pluginen.

Innan vi implementerade denna plugin hade vi i genomsnitt 2,7 tester som kördes per pull request. Med pluginen blev det 3,6 tester. Det var vi nöjda med.

Det Àr vÀrt att notera att denna plugin har en nackdel: den startar om bygget endast en gÄng. Det finns alltsÄ fortfarande en liten möjlighet för konfliktfyllda Àndringar att komma in i develop. Men sannolikheten för detta Àr lÄg, och vi accepterade denna kompromiss mellan antalet körningar och risken för problem. Under tvÄ Är intrÀffade det bara en gÄng, sÄ kanske var det inte förgÀves.

Det tog oss tvÄ veckor att skriva den första versionen av pluggen för Bitbucket.

Nya tester

Under tiden fortsatte vÄrt team att vÀxa. Nya tester lades till.

Vi tÀnkte: varför ÄtgÀrda fel nÀr vi kan förhindra dem? Och dÀrför implementerade vi statisk kodanalys. Vi började med lint, som ingÄr i Android SDK. Men dÄ kunde den helt och hÄllet inte arbeta med Kotlin-kod, och vi hade redan 75% av applikationen skriven i Kotlin. DÀrför lades inbyggda till Android Studio checks.

För detta behövde vi verkligen vrida och vÀnda: ta Android Studio, paketera den i Docker och köra den pÄ CI med en virtuell skÀrm, sÄ att den trodde att den kördes pÄ en riktig bÀrbar dator. Men det fungerade.

Samtidigt började vi ocksÄ skriva mÄnga instrumentation-tester och implementerade screenshot-testning.Det hÀr Àr nÀr en referensskÀrmdump genereras för en separat liten vy, och testet gÄr ut pÄ att ta en skÀrmdump frÄn vyn och jÀmföra den pixel för pixel med referensen. Om det finns avvikelser betyder det att layouten har blivit fel eller att nÄgot inte stÀmmer med stilarna.

Men instrumentationstester och skĂ€rmdumpstester mĂ„ste köras pĂ„ enheter: pĂ„ emulatorer eller pĂ„ verkliga enheter. Med tanke pĂ„ att det finns mĂ„nga tester som körs ofta behövs en hel farm. Att upprĂ€tta sin egen farm Ă€r för arbetskrĂ€vande, sĂ„ vi hittade ett fĂ€rdigt alternativ — Firebase Test Lab.

Firebase Test Lab

Valdes eftersom Firebase Àr en produkt frÄn Google, vilket innebÀr att den bör vara pÄlitlig och knappast kommer att dö ut. Priserna Àr överkomliga: 5 $ per timme för en verklig enhet, 1 $ per timme för en emulator.

Implementeringen av Firebase Test Lab i vÄr CI tog ungefÀr tre veckor.

Men teamet fortsatte att vÀxa, och tyvÀrr började Firebase svika oss. Vid den tidpunkten hade den inga SLA:er. Ibland tvingade Firebase oss att vÀnta pÄ att rÀtt antal enheter skulle bli tillgÀngliga för tester, istÀllet för att köra dem direkt som vi ville. VÀntetiden i kön kunde ta upp till en halvtimme, vilket Àr mycket lÀnge. Instrumentationstester kördes pÄ varje PR, och fördröjningarna bromsade ner utvecklingen, och sedan fick vi en mÄnadsrÀkning som var ganska hög. Sammanfattningsvis beslutades det att avstÄ frÄn Firebase och utveckla in-house, eftersom teamet hade blivit tillrÀckligt stort.

Docker + Python + bash

Vi tog docker, stoppade in emulatorerna i den, och skrev ett enkelt program i Python som nĂ€r det behövdes startar ett visst antal emulatorer i rĂ€tt version och nĂ€r vi behöver stoppar dem. Och sĂ„klart, nĂ„gra bash-skript — hur skulle vi klara oss utan dem?

Det tog fem veckor att skapa vÄr egen testmiljö.

Som resultat hade varje pull request en omfattande, blockerande lista med kontroller:

  • Bygg av APK;
  • Junit-tester;
  • Lint;
  • Android Studio-kontroller;
  • Instrumentationstester;
  • SkĂ€rmdumpstester.

Detta förhindrade mÄnga möjliga fel. Tekniskt sett fungerade allt, men utvecklarna klagade pÄ att det tog för lÄng tid att fÄ resultat.

För lĂ„ng tid — hur lĂ„ng tid Ă€r det? Vi extraherade data frĂ„n Bitbucket och TeamCity till ett analysystem och insĂ„g att den genomsnittliga vĂ€ntetiden var 45 minuter. Det betyder att en utvecklare i genomsnitt vĂ€ntar 45 minuter pĂ„ byggresultaten nĂ€r de öppnar en pull request. Enligt min mening Ă€r det alldeles för mycket och sĂ„ kan vi inte arbeta.

SjÀlvklart bestÀmde vi oss för att snabba upp alla vÄra byggprocesser.

Vi accelererar

NĂ€r vi sĂ„g att byggen ofta stod i kö, började vi först och frĂ€mst köpa mer hĂ„rdvara — extensiv utveckling Ă€r det enklaste. Byggen slutade stĂ„ i kö, men vĂ€ntetiden minskade bara lite, eftersom vissa kontroller sjĂ€lva tog vĂ€ldigt lĂ„ng tid.

Vi tar bort alltför lÄnga kontroller

VÄr Continuous Integration kunde fÄnga sÄdana typer av fel och problem.

  • Kan inte byggas. CI kan fĂ„nga ett kompilationsfel nĂ€r inget kan byggas pĂ„ grund av konflikterande förĂ€ndringar. Som jag redan nĂ€mnt kan ingen bygga nĂ„got, utvecklingen stannar av, och alla Ă€r nervösa.
  • Fel i beteende. Till exempel nĂ€r applikationen byggs, men den kraschar nĂ€r man trycker pĂ„ en knapp, eller knappen gĂ„r överhuvudtaget inte att trycka pĂ„. Det Ă€r dĂ„ligt, eftersom sĂ„dana fel kan nĂ„ anvĂ€ndaren.
  • Fel i layout. Till exempel nĂ€r knappen gĂ„r att trycka pĂ„, men den har förflyttats 10 pixlar Ă„t vĂ€nster.
  • Ökning av teknisk skuld.

Genom att titta pÄ denna lista insÄg vi att endast de första tvÄ punkterna Àr kritiska. Dessa problem vill vi fÄnga först och frÀmst. Layoutfel upptÀcktes under design-granskningen och kan lÀtt rÀttas till dÄ. Arbetet med teknisk skuld krÀver en separat process och planering, dÀrför bestÀmde vi oss för att inte kontrollera det pÄ pull request.

UtifrÄn denna klassificering gick vi igenom hela listan med kontroller. Vi strök Lint och flyttade dess körning till natten: bara för att den skulle ge rapporten om hur mÄnga problem som finns i projektet. Med teknisk skuld kom vi överens om att arbeta separat, och vi avstod frÄn Android Studio-kontroller helt. Android Studio i Docker för att köra inspektioner lÄter intressant, men ger mÄnga problem med underhÄllet. Varje uppdatering av versioner av Android Studio innebÀr en kamp med oförklarliga fel. Det var ocksÄ svÄrt att stödja skÀrmbildstester, eftersom biblioteket fungerade inte sÀrskilt stabilt, det förekom falska positiva. Vi tog bort skÀrmbildstester frÄn kontrollistan.

Till slut har vi kvar:

  • Bygg av APK;
  • Junit-tester;
  • Instrumentation tests.

Gradle remote cache

Utan tunga kontroller har allt blivit bÀttre. Men det finns ingen grÀns för perfektion!

VÄr applikation var redan uppdelad i cirka 150 gradle-moduler. Vanligtvis fungerar Gradle remote cache bra i sÄdana fall, och vi bestÀmde oss för att prova det.

Gradle remote cache Àr en tjÀnst som kan cachelager byggartefakter för enskilda uppgifter i specifika moduler. Gradle kontrollerar istÀllet för att faktiskt kompilera koden, via HTTP, i remote cache om nÄgon redan har kört den hÀr uppgiften. Om sÄ Àr fallet, laddar den helt enkelt ner resultatet.

Att starta Gradle remote cache Àr enkelt, eftersom Gradle tillhandahÄller en Docker-bild. Vi lyckades göra detta pÄ tre timmar.

Det behövdes bara att starta Docker och skriva en rad i projektet. Men Àven om det gÄr snabbt att starta, krÀvs det ganska mycket tid för att allt ska fungera bra.

Nedan finns en graf över cache misses.

CI:s evolution inom mobilutvecklingsteam

I början var andelen cache misses cirka 65%. Efter tre veckor lyckades vi sÀnka detta vÀrde till 20%. Det visade sig att uppgifterna som Android-applikationen bygger hade konstiga transitiva beroenden, vilket gjorde att Gradle missade cachen.

Genom att ansluta cachen lyckades vi avsevÀrt pÄskynda bygget. Men förutom bygget körs ocksÄ instrumentation tester, och de tar lÄng tid att köra. Kanske behöver vi inte köra alla tester pÄ varje pull request. För att ta reda pÄ detta anvÀnder vi pÄverkananalys.

PÄverkananalys

PÄ pull request samlar vi git diff och hittar de Àndrade Gradle-modulerna.

CI:s evolution inom mobilutvecklingsteam

Det Àr meningsfullt att bara köra de instrumentation tester som kontrollerar de Àndrade modulerna och alla moduler som beror pÄ dem. Att köra tester för angrÀnsande moduler Àr inte meningsfullt: dÀr har inget kod Àndrats, och ingenting kan gÄ sönder.

Med instrumentation tester Àr det inte sÄ enkelt, eftersom de mÄste befinna sig i den översta applikationsmodulen. Vi anvÀnde en heuristik baserad pÄ bytekodanalys för att förstÄ vilken modul varje test tillhör.

Modernisering av arbetet med instrumentation tester, för att de endast ska kontrollera involverade moduler, tog ungefÀr Ätta veckor.

ÅtgĂ€rderna för att pĂ„skynda kontrollerna fungerade framgĂ„ngsrikt. Vi gick frĂ„n 45 minuter ner till cirka 15. Att vĂ€nta en kvarts timme pĂ„ bygget Ă€r redan acceptabelt.

Men nu har utvecklarna börjat klaga pÄ att de inte förstÄr vilka byggen som körs, var de kan se loggar, varför bygget Àr rött, vilket test som misslyckades etc.

CI:s evolution inom mobilutvecklingsteam

Problem med Äterkoppling fördröjer utvecklingen, dÀrför har vi strÀvat efter att tillhandahÄlla sÄ tydlig och detaljerad information som möjligt om varje PR och build. Vi började med kommentarer i Bitbucket för PR dÀr vi angav vilken build som misslyckades och varför, samt skickade riktade meddelanden i Slack. Till slut skapade vi en PR-dashboard som visar en lista över alla builds som för nÀrvarande körs och deras status: i kö, körs, misslyckad eller avslutad. Man kan klicka pÄ en build och komma till dess logg.

CI:s evolution inom mobilutvecklingsteam

Det har tagit sex veckor att fÄ detaljerad Äterkoppling.

Planer

Vi gÄr vidare till den senaste historien. Efter att ha löst frÄgan om Äterkoppling, har vi nÄtt en ny nivÄ - vi har beslutat att bygga vÄr egen emulatorfarm. NÀr det finns mÄnga tester och emulatorer blir det svÄrt att hantera dem. Resultatet blev att alla vÄra emulatorer flyttade till en k8s-kluster med flexibel resursförvaltning.

Dessutom finns det andra planer.

  • ÅterstĂ€ll Lint (och annan statisk analys). Vi arbetar redan pĂ„ detta.
  • Kör alla end-to-end tester pĂ„ alla versioner av SDK.

SÄ, vi har spÄrat utvecklingen av Continuous Integration pÄ Avito. Nu vill jag ge nÄgra rÄd frÄn en erfaren.

Tips

Om jag bara kunde ge ett rÄd, skulle det vara detta:

Var snÀll och var försiktig med shell-skript!

Bash Àr ett mycket flexibelt och kraftfullt verktyg, det Àr mycket bekvÀmt och snabbt att skriva skript pÄ. Men man kan falla i fÀllan, och tyvÀrr har vi gjort det.

Det började med enkla skript som kördes pÄ vÄra byggmaskiner:

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

Men, som bekant, utvecklas allt med tiden och blir mer komplext - lÄt oss köra ett skript frÄn ett annat, lÄt oss vidarebefordra nÄgra parametrar - i slutÀndan var vi tvungna att skriva en funktion som bestÀmmer vilken nivÄ av inbÀddning vi befinner oss pÄ, sÄ att vi kan sÀtta in rÀtt citattecken sÄ att allt kan starta.

CI:s evolution inom mobilutvecklingsteam

Kan du förestÀlla dig arbetsinsatsen för att utveckla sÄdana skript? Jag rekommenderar att undvika den hÀr fÀllan.

Vad kan man ersÀtta det med?

  • Vilket skriptsprĂ„k som helst. Det Ă€r bekvĂ€mare att skriva pĂ„ Python eller Kotlin Script eftersom det Ă€r programmering, inte skript.
  • Eller beskriva all logik i byggen i form av Custom gradle tasks för ditt projekt.

Vi valde den andra varianten och nu tar vi systematiskt bort alla bash-skript och skriver mÄnga anpassade gradle-tasks.

RÄd nr 2: Spara infrastrukturen i kod.

Det Àr praktiskt nÀr instÀllningen för Continuous Integration inte lagras i UI-grÀnssnittet i Jenkins, TeamCity och liknande, utan som textfiler direkt i projektets repository. Detta ger versionshantering. Det blir inte svÄrt att ÄtergÄ eller bygga koden pÄ en annan gren.

Skript kan lagras i projektet. Men vad gör man med miljön?

Tips #3: Docker kan hjÀlpa med miljön.

Det kommer definitivt att hjÀlpa Android-utvecklare, tyvÀrr inte iOS.

Detta Àr ett exempel pÄ en enkel dockerfil som innehÄller jdk och 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

# Ladda ner 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

# Installera Android Build Tool och bibliotek
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

Genom att skriva denna dockerfil (jag sÀger i hemlighet att man kan hoppa över den och ladda ner en fÀrdig frÄn GitHub) och bygga en bild fÄr du en virtuell maskin dÀr du kan bygga applikationen och köra Junit-tester.

De tvÄ huvudargumenten till varför detta Àr meningsfullt Àr skalbarhet och repetitivitet. Med docker kan man snabbt sÀtta upp ett dussin byggagenter som har precis samma miljö som den tidigare. Detta underlÀttar verkligen livet för CI-ingenjörer. Att packa android-sdk i docker Àr ganska enkelt, men med emulatorer Àr det lite mer komplicerat: man fÄr jobba lite mer (eller Äterigen ladda ner en fÀrdig frÄn GitHub).

Tips #4: Glöm inte att tester görs inte för testernas skull, utan för mÀnniskorna.

Utvecklare vÀrdesÀtter snabb och, framför allt, tydlig Äterkoppling: vad som har gÄtt fel, vilket test som misslyckades, var de kan se byggloggen.

Tips #5: Var pragmatisk i utvecklingen av Continuous Integration.

Ha en klar förstÄelse för vilken typ av fel du vill förebygga, hur mycket resurser, tid och maskintid du Àr beredd att investera. För lÄngvariga tester kan man till exempel schemalÀgga dem pÄ natten. Och de tester som fÄngar mindre viktiga fel kan helt enkelt tas bort.

Tips #6: AnvÀnd fÀrdiga verktyg.

Det finns nu mÄnga företag som erbjuder molnbaserad CI.

CI:s evolution inom mobilutvecklingsteam

För smÄ team Àr detta en bra lösning. Du behöver inte underhÄlla nÄgot, bara betala lite pengar, bygga din applikation och till och med köra instrumenteringstester.

Tips 7: i ett stort team Àr in-house-lösningar mer lönsamma.

Men förr eller senare, med teamets tillvÀxt, blir in-house-lösningar mer fördelaktiga. Det finns en aspekt med dessa lösningar. Inom ekonomin finns en lag om avtagande avkastning: i vilket projekt som helst blir varje efterföljande förbÀttring allt svÄrare och krÀver allt mer investeringar.

Ekonomin beskriver hela vÄrt liv, inklusive Continuous Integration. Jag har byggt en graf över arbetsinsatsen för varje steg i utvecklingen av vÄr Continuous Integration.

CI:s evolution inom mobilutvecklingsteam

Det Àr tydligt att varje förbÀttring blir allt svÄrare. Genom att titta pÄ denna graf kan man förstÄ att utvecklingen av Continuous Integration mÄste ske i takt med att teamets storlek vÀxer. För ett team pÄ tvÄ personer Àr det inte sÄ bra idé att spendera 50 dagar pÄ att utveckla en intern emulatorfarm. Men samtidigt Àr det ocksÄ en dÄlig idé för ett stort team att helt lÀmna Continuous Integration Ät sidan, eftersom mer tid kommer att gÄ Ät till integrationsproblem, att fixa kommunikation etc.

Vi började med att automation Àr nödvÀndig eftersom mÀnniskor Àr dyra, de gör misstag och Àr lata. Men de som automatiserar Àr ocksÄ mÀnniskor. DÀrför gÀller samma problem Àven för automation.

  • Att automatisera Ă€r dyrt. TĂ€nk pĂ„ grafen över arbetsinsatsen.
  • Vid automation gör mĂ€nniskor misstag.
  • Att automatisera Ă€r ibland vĂ€ldigt trĂ„kigt, eftersom allt redan fungerar. Varför förbĂ€ttra nĂ„got, varför all denna Continuous Integration?

Men jag har statistik: 20% av byggen fÄngar buggar. Och detta hÀnder inte för att vÄra utvecklare skriver dÄlig kod. Det beror pÄ att utvecklarna Àr sÀkra pÄ att om de gör nÄgot misstag, kommer det inte att hamna i utvecklingsgrenen, det kommer att upptÀckas av automatiserade tester. DÀrför kan utvecklarna lÀgga mer tid pÄ att skriva kod och intressanta saker, istÀllet för att köra och kontrollera nÄgot lokalt.

Syssla med Continuous Integration. Men i mÄttliga mÀngder.

För övrigt gör Nikolay Nesterov inte bara fantastiska föredrag sjÀlv, utan ingÄr ocksÄ i programkommittén AppsConf och hjÀlper andra att förbereda meningsfulla presentationer för er. Hela programmet för nÀsta konferens kan bedömas utifrÄn Àmnena i schemat. För mer information, kom till Infoprime den 22-23 april.

KĂ€lla: habr.com

Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar đŸ”„ Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar | ProHoster