Mobil appok automata disztribúciója

Hogyan gyorsítottuk a teszt és release folyamatainkat

A Mitóban folyamatosan törekszünk arra, hogy egyre jobban, hatékonyabban dolgozzunk, webes és mobil app projektekben egyaránt. Vannak saját termékeink is, amiről itt olvashatsz bővebben, de alapvetően ügyfeleknek dolgozunk, így lényegében nem egy, hanem rengeteg különböző termék fejlesztésében veszünk részt — ezeken belül a csapatok felépítése nagyjából megegyezik, de sok minden más pedig eltér, legyen szó például a release ciklusok hosszáról vagy a végfelhasználók számáról. Emiatt egy kicsit nehezített ugyan a pálya, de nem megoldhatatlan, hogy egységes módszertant és folyamatokat alakítsunk ki.

Mobil appoknál már régóta az automatizált build, test és deploy folyamat bevezetése lebegett a szemünk előtt. Az automatizálásnak rengeteg előnye van, de többek közt olyan apróságnak tűnő, viszont baromi sok időt elfecsérlő helyzetekre is megoldást ad, mint hogy a projektmenedzsereinknek ne kelljen akár naponta többször is a fejlesztőket azzal piszkálniuk, hogy készítsenek egy újabb buildet, amit tesztelhetünk és kiküldhetünk az ügyfélnek.

Pár hónapig eltartott ugyan, de sikerült találnunk egy egészen jónak tűnő megoldást.

A 65+ fős fejlesztőcsapatunk ügyfeleink szerinti bontásban 10–12 fős teamekből áll, amiken belül vegyesen, különböző területeket fednek le a kompetenciák, így pl. a Deutsche Telekom csapatban iOS, Android, valamint frontend és backend fejlesztők is találhatóak, míg a Wizz Air csapatban nincs backend feladat, tehát ott nincs ilyen pozíció sem. Az ügyfelekkel a fejlesztői múlttal rendelkező Tech PM-ek (Technical Project Manager) tartják a kapcsolatot, ők felelnek a projektek határidőre és megfelelő minőségben történő szállításáért, és persze hozzájuk esnek be a különböző kérések is — így pl. azok, amikor akár több funkció párhuzamos fejlesztése mellett/alatt/közben felmerül az igény az egyik tesztelésére. Habár feature branchekben dolgozunk már egy ideje, mindig sok időt vitt el a buildek összeállítása és elkészítése. Ezt szó szerint kell érteni, tehát tényleg rengeteg percet, heti szinten több órát vitt el emberenként ez a feladat, és a köztes időben megakadt a munka, amíg buildelt a gép, nem lehetett mással foglalkozni. Ezeket az órákat pedig lehetne értelmesebben is eltölteni, úgyhogy elővettük a régóta hangoztatott, de a gyakorlatban csak éppen hogy használt varázsigét, ami nem mást, mint:

continuous integration!

Automata build folyamat

Több irányból is nekifutottunk a probléma megoldásának, de előtte egy kis áttekintés, hogy is dolgozunk.

Gitlabot használunk nagyjából a 3-as verzió megjelenése, 2012 óta. Ez akkoriban még egy nagyon buta, nagyon egyszerű Github ripoff volt, de azóta elég sok energiát raktak bele, mostanra már egy teljeskörű és ingyenes Github alternatíva lett. A Gitlab mellett anyagi és biztonsági megfontolások miatt is döntöttünk, és végül egyáltalán nem bántuk meg (pár szám a méretek érzékeltetésére: 200+ user, 80+ group, 900+ projekt). A Gitlabnak már egy ideje van beépített CI megoldása is, erre kezdtük el felhúzni a saját megoldásainkat, így a mobil appok automata tesztjét is. Web appoknál terítéken van ugyan a Continuous Delivery bevezetése is, de egyelőre ebbe az irányba még nem mentünk el — amint release-eljük az első, valóban és rendesen microservice alapú projektünket, amit már Dockerben tudunk hostolni és teljeskörűen lefedünk unit-, ill. automata tesztekkel, akkor ott már lesz talán értelme, de ettől még a biztonság továbbra is hatalmas betűkkel villog a fejünk felett. Na de erről majd egy következő postban részletesebben is írunk.

Visszatérve a mobil appokra: a buildelést magát elkezdtük kiszervezni dedikált gépekre, ún. buildboxokra, amik automatikusan elvégzik a feladatot. Röviden így néz ki a folyamat:

  • 1–1 dedikált gépünk van iOS-re és Androidra.
  • Mindkettőhöz csatlakoztattunk tesztkészülékeket (ezeket nem használjuk máshol, nem húzzuk ki, folyamatosan elérhetőek).
  • Gitlab CI runnerek futnak a gépeken, ezeknek jelez a Gitlab, ha friss commit érkezett valamelyik repóba.
  • A runner elindít egy VM-et, lehúzza a kódot, feltelepíti a podokat/gemeket
  • Elkészíti a buildet.
  • Feltölti a buildet Gitlabnak, így az utólag is elérhető, letölthető, pl. a QA csapat által.
  • Lefuttatja a SonarQube elemzést.
  • Lefuttatja a unit teszteket.
  • Lefuttatja a Calabash teszteket szimulátoron és az eszközökön.
  • Android esetén feltölti Fabric Betara, iOS-en pedig TestFlightra a buildet

Innentől kezdve pedig pár perc, és megjelenik a frissítés a projekthez hozzáadott emberek telefonján. MAGIC! :) Imádjuk is az egészet, de egyáltalán nem volt könnyű eljutni idáig, sokat kísérleteztünk a lépésekkel. Természetesen nem tartunk ott, mint pl. a LinkedIn, és nem is feltétlenül akarunk odáig eljutni, de az irány nagyon jó, és az eddigi tapasztalataink pozitívak. A rendszer pedig skálázható, ha erőforrásproblémánk merülne fel a jövőben a projektek megnövekedett száma miatt, akkor egyszerűen csak be kellene állítani újabb gépeket a poolba.


Fabric/TestFlight

iOS

Régen minden jobb volt, ugye, így a TestFlight is, használtuk is rendesen, egészen addig, amíg meg nem vette az Apple — egy ideig nem is nagyon volt megfelelő alternatíva, talán csak a HockeyApp, de hatalmas űr tátongott ezen a piacon. Mióta az Apple megfelelően integrálta a TestFlightot, azóta mi is újra felszálltunk erre a vonatra, és a Fastlane ügyes kis tooljai segítségével automatizálva, konzolból érjük el.

Android

A Crashlytics nagy kedvenc volt mindig is (nemcsak Android, hanem iOS appokhoz is), és mióta a Twitter megvette, átnevezte és kibővítette a funkcióit, azóta még jobban imádjuk, és most már nemcsak a crashek feltérképezése miatt, hanem analitikai eszközként és beta csatornaként egyaránt. Teljesen jól használható és átláható, pl. lehet beta tesztelő csoportokat is készíteni, ahol is mi minden esetben létrehozunk egy “internal”, valamint egy “external” groupot, az előbbibe magunkat vesszük fel (PM, fejlesztők, tesztelő), utóbbiba pedig az ügyfele(ke)t. A használathoz csak egy email címre van szükség, így alacsony a belépési küszöb. Persze a Play Store-os Alpha/Beta channel is megfelelő, azzal is lehetne automatikusan megoldani a feltöltést, használtuk is már, azonban valamiért nekünk és az ügyfeleinknek is jobban bevált a Fabric.

Branching

Fentebb már említettem, hogy feature branchinget használunk, de az automatizálás miatt bevezettünk még egyéb branching szabályokat is. Ez a következőképpen néz ki:

(Ez most száraz lesz, úgyhogy akit kevésbé érdekel, ugorjon nyugodtan a végére)

Master — Örök életű branch

Minden esetben a master branchről élesítünk, és mindig készítünk egy taget az aktuális állapotról, hogy könnyebben elő lehessen szedni a régi release-eket.

Hotfixes — Rövid élettartalmú branch

Ha az éles verzión azonnali javítást kell eszközölni, akkor származtatunk egy {ticketNumber}-hotfix-problema-neve elnevezésű branchet az aktuális masterből, elvégezzük a javítást, majd a módosításokat visszavezetjük master branchre és így élesítjük.

Ezt követően a develop branchre is átvezetjük, ill. ha szükséges, akkor onnan a többi branchre (feature/demo branches).

Mergelés után töröljük a branchet.

Develop — Örök életű branch

Itt mindig az aktuális éles verzió található, kiegészítve azokkal a feature-ökkel amik biztosan kimennek a következő élesítésnél. Ebből származtatjuk a feature és demo brancheinket.

Feature branches — változó életartalmú branchek

Ebből korlátlan darabszámú lehet, általában minden JIRA tickethez létrehozzunk egyet, így az elnevezése: {ticketNumber}-feature-neve

Elsősorban az aktuális development ágból származtatjuk, de előfordulhat, hogy egy másik feature-re dependál a feladat, ez esetben feature branchből is létrehozható. Amint a feature bekerül a development ágba, a branch törölhető válik.

Amennyiben olyan feature-t fejlesztünk amit biztosan élesítünk a következő alkalommal, úgy nyugodtan visszamergelhető a development ágra (pl.: nem top prior bugfixek)

Demo branches — változó életartalmú branchek

Ezeket az branch-eket használjuk az automatikus scriptek futtatására. Például: Fabric Beta élesítés, Amazon Test Cloud feltöltés, TestFlight feltöltés, stb-stb…

Az elnevezésüket az aktuális CI scriptek határozzák meg, de általában {serviceName}-{appVersion}, pl.: fabric-1.5.2. vagy {serviceName}-{flavor}-{appVersion} pl.: fabric-uat-1.5.2

Mindig az aktuális develop branch-ből származtatjuk, majd beledobáljuk a kész feature-öket, amit be szeretnénk mutatni az ügyfélnek, vagy tesztelni szeretnénk Amazon Cloudon.

Egy-egy demo branch-ből több verzió is lehet egy időben, de release-t követően ezeket érdemes törölni és amennyiben szükséges a friss develop branchből újakat létrehozni.


Release folyamat

  • Származtatunk a development ágból egy új demo branchet
  • Bepakoljuk a szükséges feature setet.
  • Lefuttatjuk az automata teszteket, valamint megtörténik a manuális tesztelés is.
  • Ügyfél jóváhagyást követően, bemergeljük a demo branchet a develop ágba.
  • A development ágból átrakjuk a masterre.
  • A masteren készítünk egy tag-et az aktuális állapotból.
  • Töröljük az érintett feature branch-eket.

(Azért a demo branchből célszerű release-elni, mert ott már végig verekedtük magunkat a feature branchek és a develop branch mergelésén, és biztosan a tesztelt állapot kerül rá a develop ágra).


Összefoglaló

A branching policy talán első ránézésre egy kicsit bonyolultnak tűnhet, viszont kellő odafigyeléssel rendkívül hatékonnyá teszi a dolgunkat. A bevezetés óta a buildelést teljesenkörűen le tudtuk delegálni a buildboxokra, és nem a fejlesztőknek kell ezzel foglalkozniuk, mert elég csak egy adott nevű branchet bepusholni, és a gépek azonnal munkába lépnek. Projektenként eltérő a teljes build idő, de még egy tesztekkel rendesen megpakolt, nagy kódbázisú projekt is pushtól számított 25 percen belül elérhetővé válik minden tesztelő készülékén.

(A post írásában közreműködtek a mobil és lead fejlesztőink.)