{"id":31304,"date":"2019-10-31T21:40:34","date_gmt":"2019-10-31T18:40:34","guid":{"rendered":"https:\/\/prohoster.info\/blog\/evolyutsiya-ci-v-komande-mobilnoj-razrabotki\/"},"modified":"2019-10-31T21:40:34","modified_gmt":"2019-10-31T18:40:34","slug":"evolyutsiya-ci-v-komande-mobilnoj-razrabotki","status":"publish","type":"post","link":"https:\/\/prohoster.info\/hu\/blog\/administrirovanie\/evolyutsiya-ci-v-komande-mobilnoj-razrabotki","title":{"rendered":"A CI fejl\u0151d\u00e9se a mobilfejleszt\u0151 csapatban","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Ma a legt\u00f6bb szoftverterm\u00e9ket csapatokban fejlesztenek. A csapatmunk\u00e1s fejleszt\u00e9s siker\u00e9nek felt\u00e9teleit egy egyszer\u0171 s\u00e9m\u00e1ban lehet \u00e1br\u00e1zolni.<\/p>\n<p><img decoding=\"async\" alt=\"A CI fejl\u0151d\u00e9se a mobilfejleszt\u0151 csapatban\" src=\"\/wp-content\/uploads\/2019\/04\/b283cfd7772d8f479be0754ebbe51b19.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nA k\u00f3d meg\u00edr\u00e1sa ut\u00e1n meg kell gy\u0151z\u0151dni arr\u00f3l, hogy:<\/p>\n<ol>\n<li>M\u0171k\u00f6dik.<\/li>\n<li>Nem t\u00f6r el semmit, bele\u00e9rtve a koll\u00e9g\u00e1k \u00e1ltal \u00edrt k\u00f3dot is.<\/li>\n<\/ol>\n<p>\nHa mindk\u00e9t felt\u00e9tel teljes\u00fcl, akkor \u00faton vagy a siker fel\u00e9. Ahhoz, hogy ezeket a felt\u00e9teleket k\u00f6nnyen ellen\u0151rizhess\u00fck \u00e9s ne t\u00e9rj\u00fcnk le a kedvez\u0151 \u00fatr\u00f3l, kital\u00e1lt\u00e1k a folyamatos integr\u00e1ci\u00f3t.<\/p>\n<p>A CI egy olyan munkafolyamat, amely sor\u00e1n a lehet\u0151 leggyakrabban integr\u00e1lod a k\u00f3dot a term\u00e9k k\u00f6z\u00f6s k\u00f3dj\u00e1ba. R\u00e1ad\u00e1sul nemcsak integr\u00e1lod, hanem folyamatosan ellen\u0151rz\u00f6d is, hogy minden m\u0171k\u00f6dik. Mivel sok mindent kell gyakran ellen\u0151rizni, \u00e9rdemes elgondolkodni az automatiz\u00e1l\u00e1son. Minden tesztet lehet manu\u00e1lisan is v\u00e9gezni, de nem \u00e9rdemes, \u00e9s itt van, mi\u00e9rt.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<ul>\n<li><strong>Az emberek dr\u00e1g\u00e1k<\/strong>. B\u00e1rmely programoz\u00f3 \u00f3rad\u00edja dr\u00e1g\u00e1bb, mint b\u00e1rmely szerver \u00f3rad\u00edja.<\/li>\n<li><strong>Az emberek hib\u00e1znak<\/strong>. Ez\u00e9rt el\u0151fordulhat, hogy olyan \u00e1gon futtatnak teszteket, ami nem a megfelel\u0151 \u00e1g, vagy nem a megfelel\u0151 commitot gy\u0171jt\u00f6tt\u00e9k \u00f6ssze a tesztel\u0151knek.<\/li>\n<li><strong>Az emberek lust\u00e1k<\/strong>. Id\u0151nk\u00e9nt, amikor befejezek egy feladatot, az jut eszembe: 'De h\u00e1t mit kell itt ellen\u0151rizni? K\u00e9t sort \u00edrtam \u2014 biztos, hogy minden m\u0171k\u00f6dik!' Gondolom, hogy n\u00e9h\u00e1nyotoknak is id\u0151nk\u00e9nt hasonl\u00f3 gondolatai akadnak. De mindig ellen\u0151rizni kell.<\/li>\n<\/ul>\n<p>\nHogyan vezett\u00fck be \u00e9s fejlesztett\u00fck a folyamatos integr\u00e1ci\u00f3t a Avito mobilfejleszt\u0151 csapat\u00e1ban, hogyan jutottunk el a napi 450 buildig, \u00e9s hogy a build g\u00e9pek naponta 200 \u00f3r\u00e1t gy\u0171jtenek, arr\u00f3l Nikolai Nesterov (<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/users\/nnesterov\/\" class=\"user_link\">nnesterov<\/a><\/noindex>) besz\u00e9l, aki r\u00e9szt vett a CI\/CD Android alkalmaz\u00e1s evol\u00faci\u00f3s v\u00e1ltoz\u00e1saiban.<\/p>\n<p>A besz\u00e1mol\u00f3 az Android csapat p\u00e9ld\u00e1j\u00e1n alapul, de a legt\u00f6bb megk\u00f6zel\u00edt\u00e9s az iOS-re is alkalmazhat\u00f3.<\/p>\n<p><center><div class=\"youtube-placeholder\" data-id=\"lz8MNATTUCU\" onclick=\"loadVideo(this)\">\r\n        <img decoding=\"async\" src=\"https:\/\/img.youtube.com\/vi\/lz8MNATTUCU\/hqdefault.jpg\" alt=\"Vide\u00f3 lej\u00e1tsz\u00e1sa\" loading=\"lazy\" width=\"480\" height=\"360\" style=\"width:100%;height:auto;\">\r\n        <div class=\"play-button\"><\/div>\r\n    <\/div><\/center><br \/>\nR\u00e9ges-r\u00e9gen az Avito Android csapat\u00e1ban egyetlen ember dolgozott. Neki alapvet\u0151en semmire sem volt sz\u00fcks\u00e9ge a folyamatos integr\u00e1ci\u00f3hoz: nem volt kivel integr\u00e1lni.<\/p>\n<p>De az alkalmaz\u00e1s n\u0151tt, egyre t\u00f6bb \u00faj feladat jelentkezett, ennek megfelel\u0151en a csapat is b\u0151v\u00fclt. Egy id\u0151 ut\u00e1n elj\u00f6tt az id\u0151, hogy form\u00e1lisan rendbe tegy\u00fck a k\u00f3dintegr\u00e1l\u00e1si folyamatot. \u00dagy d\u00f6nt\u00f6ttek, hogy a Git flow-t fogj\u00e1k haszn\u00e1lni.<\/p>\n<p><img decoding=\"async\" alt=\"A CI fejl\u0151d\u00e9se a mobilfejleszt\u0151 csapatban\" src=\"\/wp-content\/uploads\/2019\/04\/f433effc5ab5a59de3d6bd20a7a87057.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nA Git flow concept is well-known: in a project, there is a single common branch develop, and for each new feature, developers create a separate branch, commit to it, push, and when they want to merge their code into the develop branch, they open a pull request. To facilitate knowledge sharing and discuss approaches, we introduced code reviews, meaning colleagues must check and approve each other's code.<\/p>\n<h2>Ellen\u0151rz\u00e9sek<\/h2>\n<p>\nA k\u00f3dot m\u00e1s szemsz\u00f6gb\u0151l n\u00e9zni nagyszer\u0171, de nem el\u00e9g. Ez\u00e9rt automatikus ellen\u0151rz\u00e9seket vezet\u00fcnk be.<\/p>\n<ul>\n<li>Els\u0151 l\u00e9p\u00e9sk\u00e9nt ellen\u0151rizz\u00fck <strong>az ARC-\u00f6ssze\u00e1ll\u00edt\u00e1st<\/strong>.<\/li>\n<li>Sok <strong>Junit-teszt<\/strong>.<\/li>\n<li><strong>Sz\u00e1m\u00edtjuk a code coverage-t<\/strong>, hiszen futtatjuk a teszteket.<\/li>\n<\/ul>\n<p>\nAhhoz, hogy meg\u00e9rts\u00fck, hogyan kellene futtatni ezeket az ellen\u0151rz\u00e9seket, n\u00e9zz\u00fck meg a fejleszt\u00e9si folyamatot az Aviton\u00e1l.<\/p>\n<p>S\u00e9m\u00e1j\u00e1ban ezt \u00edgy lehet \u00e1br\u00e1zolni:<\/p>\n<ul>\n<li>A fejleszt\u0151 a saj\u00e1t laptopj\u00e1n \u00edrja a k\u00f3dot. Itt is futtathat\u00f3k az integr\u00e1ci\u00f3s ellen\u0151rz\u00e9sek \u2013 vagy commit hook-kal, vagy egyszer\u0171en a h\u00e1tt\u00e9rben.<\/li>\n<li>Miut\u00e1n a fejleszt\u0151 felt\u00f6lt\u00f6tte a k\u00f3dot, megnyit egy pull request-t. Ahhoz, hogy a k\u00f3dja beker\u00fclj\u00f6n a develop \u00e1gba, el kell v\u00e9gezni a code review-t \u00e9s meg kell szerezni a sz\u00fcks\u00e9ges mennyis\u00e9g\u0171 meger\u0151s\u00edt\u00e9st. Itt is lehet\u0151s\u00e9g van az ellen\u0151rz\u00e9sek \u00e9s build-ek aktiv\u00e1l\u00e1s\u00e1ra: am\u00edg az \u00f6sszes build nem sikeres, a pull request nem olvadhat be.<\/li>\n<li>Miut\u00e1n a pull request beolvadt \u00e9s a k\u00f3d beker\u00fclt a develop-ba, el lehet v\u00e1lasztani egy megfelel\u0151 id\u0151pontot: p\u00e9ld\u00e1ul \u00e9jjel, amikor minden szerver szabad, \u00e9s futtathat\u00f3k az ellen\u0151rz\u00e9sek, amennyiben sz\u00fcks\u00e9ges.<\/li>\n<\/ul>\n<p>\nA saj\u00e1t laptopon v\u00e9gzett ellen\u0151rz\u00e9seket senki sem szerette. Amikor a fejleszt\u0151 befejezi a funkci\u00f3t, gyorsan szeretn\u00e9 felt\u00f6lteni \u00e9s megnyitni a pull request-t. Ha ebben a pillanatban hosszabb ellen\u0151rz\u00e9sek indulnak, az nemcsak kellemetlen, hanem lelass\u00edtja a fejleszt\u00e9st is: m\u00edg a laptop valamit ellen\u0151riz, nem lehet norm\u00e1lisan dolgozni rajta.<\/p>\n<p>Nagyon tetszett az ellen\u0151rz\u00e9sek \u00e9jszaki futtat\u00e1sa, mert sok id\u0151 \u00e9s szerver \u00e1ll rendelkez\u00e9sre, \u00fagyhogy teret adhatunk magunknak. De sajnos, amikor a funkci\u00f3 k\u00f3dja beker\u00fclt a develop-ba, a fejleszt\u0151nek m\u00e1r sokkal kevesebb motiv\u00e1ci\u00f3ja van kijav\u00edtani azokat a hib\u00e1kat, amelyeket a CI tal\u00e1lt. Id\u0151nk\u00e9nt \u00e9szrevettem magamon, amikor a reggeli jelent\u00e9sben a megtal\u00e1lt hib\u00e1kra n\u00e9ztem, hogy k\u00e9s\u0151bb jav\u00edtom meg \u0151ket, mert most a Jir\u00e1ban van egy szuper \u00faj feladat, amit nagyon szeretn\u00e9k elkezdeni.<\/p>\n<p>Ha az ellen\u0151rz\u00e9sek blokkolj\u00e1k a pull request-et, akkor elegend\u0151 a motiv\u00e1ci\u00f3, mert am\u00edg a build-ek nem z\u00f6ld\u00fclnek, a k\u00f3d nem ker\u00fcl be a develop-ba, \u00edgy a feladat nem fejez\u0151dik be.<\/p>\n<p>V\u00e9g\u00fcl egy olyan strat\u00e9gi\u00e1t v\u00e1lasztottunk, hogy \u00e9jjel a lehet\u0151 legnagyobb ellen\u0151rz\u00e9scsomagot futtatjuk, a legkritikusabb \u00e9s leggyorsabb teszteket pedig a pull requestre ind\u00edtjuk. De ezzel nem \u00e1llunk meg \u2014 p\u00e1rhuzamosan optimaliz\u00e1ljuk az ellen\u0151rz\u00e9sek \u00e1tfut\u00e1si sebess\u00e9g\u00e9t, hogy \u00e1t tudjuk vinni azokat az \u00e9jszakai \u00fczemm\u00f3db\u00f3l a pull requestes ellen\u0151rz\u00e9sekbe.<\/p>\n<p>Abban az id\u0151ben minden build\u00fcnk viszonylag gyorsan ment, ez\u00e9rt egyszer\u0171en csak aktiv\u00e1ltuk a pull request blokkol\u00f3jak\u00e9nt az ARC buildet, a Junit-teszteket \u00e9s a code coverage-t. Aktiv\u00e1ltuk, gondoltunk egyet \u2014 \u00e9s lemondtunk a code coverage-r\u0151l, mert azt gondoltuk, hogy nincs r\u00e1 sz\u00fcks\u00e9g\u00fcnk.<\/p>\n<p><strong><em>A alap CI be\u00e1ll\u00edt\u00e1s\u00e1ra k\u00e9t napot sz\u00e1ntunk (itt \u00e9s a tov\u00e1bbiakban az id\u0151beli \u00e9rt\u00e9kel\u00e9s k\u00f6r\u00fclbel\u00fcl, a l\u00e9pt\u00e9khez sz\u00fcks\u00e9ges). <\/em><\/strong><\/p>\n<p>Ezut\u00e1n elkezdt\u00fcnk tov\u00e1bb gondolkodni \u2014 vajon helyesen ellen\u0151rizz\u00fck-e? Helyesen ind\u00edtjuk-e a buildet pull requestn\u00e9l?<\/p>\n<p>A legutols\u00f3 commiton ind\u00edtottuk a buildet arr\u00f3l a \u00e1gr\u00f3l, amelyb\u0151l a pull request k\u00e9sz\u00fclt. De ennek a commitnak az ellen\u0151rz\u00e9se csak azt mutatja, hogy a fejleszt\u0151 \u00e1ltal \u00edrt k\u00f3d m\u0171k\u00f6dik. De ez nem bizony\u00edtja, hogy nem t\u00f6rt\u00e9nt k\u00e1r. Val\u00f3j\u00e1ban a develop \u00e1g \u00e1llapot\u00e1t kell ellen\u0151rizni azut\u00e1n, hogy a funkci\u00f3 be lett olvasztva.<\/p>\n<p><img decoding=\"async\" alt=\"A CI fejl\u0151d\u00e9se a mobilfejleszt\u0151 csapatban\" src=\"\/wp-content\/uploads\/2019\/04\/c1a179b68b02c04031177f9bf51a81ed.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEhhez \u00edrtunk egy egyszer\u0171 bash-skriptet <strong>premerge.sh:<\/strong><\/p>\n<pre><code class=\"bash\">#!\/usr\/bin\/env bash\n\nset -e\n\ngit fetch origin develop\n\ngit merge origin\/develop<\/code><\/pre>\n<p>\nItt egyszer\u0171en leh\u00fazzuk a legfrissebb v\u00e1ltoztat\u00e1sokat a develop-b\u00f3l, \u00e9s beolvasztjuk az aktu\u00e1lis \u00e1gba. Az \u00f6sszes build els\u0151 l\u00e9p\u00e9sek\u00e9nt hozz\u00e1adtuk a premerge.sh skriptet, \u00e9s elkezdt\u00fck ellen\u0151rizni pontosan azt, amit szeretn\u00e9nk, nevezetesen a <strong>integr\u00e1ci\u00f3t<\/strong>.<\/p>\n<p><strong><em>A probl\u00e9m\u00e1k lokaliz\u00e1l\u00e1s\u00e1ra, a megold\u00e1s keres\u00e9s\u00e9re \u00e9s a skript meg\u00edr\u00e1s\u00e1ra h\u00e1rom napunk ment r\u00e1.<\/em><\/strong><\/p>\n<p>Az alkalmaz\u00e1s fejl\u0151d\u00f6tt, egyre t\u00f6bb feladat jelentkezett, a csapat n\u0151tt, \u00e9s a premerge.sh n\u00e9ha kezdett minket cserben hagyni. A develop-ba konflikt\u00e1l\u00f3 v\u00e1ltoztat\u00e1sok ker\u00fcltek be, amelyek \u00f6sszet\u00f6rt\u00e9k a buildet.<\/p>\n<p>P\u00e9lda arra, hogyan t\u00f6rt\u00e9nik ez:<\/p>\n<p><img decoding=\"async\" alt=\"A CI fejl\u0151d\u00e9se a mobilfejleszt\u0151 csapatban\" src=\"\/wp-content\/uploads\/2019\/04\/6762d9ce4e431549455c49f2317a8f20.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nK\u00e9t fejleszt\u0151 egyszerre elkezd dolgozni A \u00e9s B funkci\u00f3kon. Az A funkci\u00f3 fejleszt\u0151je felfedez egy nem haszn\u00e1lt funkci\u00f3t a projektben, <code>answer()<\/code> \u00e9s, mint j\u00f3 cserk\u00e9sz, t\u00f6rli azt. K\u00f6zben a B funkci\u00f3 fejleszt\u0151je az \u0151 \u00e1g\u00e1ban \u00faj h\u00edv\u00e1st ad hozz\u00e1 ehhez a funkci\u00f3hoz.<\/p>\n<p>A fejleszt\u0151k befejezik a munk\u00e1t, \u00e9s egyszerre ind\u00edtj\u00e1k el a pull requestet. A build elindul, a premerge.sh ellen\u0151rzi mindk\u00e9t pull requestet a legfrissebb develop \u00e1llapot\u00e1hoz k\u00e9pest \u2014 minden ellen\u0151rz\u00e9s z\u00f6ld. Ezt k\u00f6vet\u0151en az A funkci\u00f3 pull requestje beolvad, majd a B funkci\u00f3 pull requestje is\u2026 Bumm! A develop \u00f6sszet\u00f6rik, mert a develop k\u00f3dban van egy nem l\u00e9tez\u0151 funkci\u00f3h\u00edv\u00e1s.<\/p>\n<p><img decoding=\"async\" alt=\"A CI fejl\u0151d\u00e9se a mobilfejleszt\u0151 csapatban\" src=\"\/wp-content\/uploads\/2019\/04\/0261dcc9f7f2e5e018ab136081b4679b.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAmikor a develop nem \u00e9p\u00fcl, az <strong>helyi katasztr\u00f3fa<\/strong>. Az eg\u00e9sz csapat nem tud semmit \u00f6ssze\u00e1ll\u00edtani \u00e9s tesztel\u00e9sre \u00e1tadni.<\/p>\n<p>\u00dagy alakult, hogy \u00e9n f\u0151leg infrastruktur\u00e1lis feladatokkal foglalkoztam: analitika, h\u00e1l\u00f3zat, adatb\u00e1zisok. Vagyis \u00e9n \u00edrtam azokat a funkci\u00f3kat \u00e9s oszt\u00e1lyokat, amelyeket m\u00e1s fejleszt\u0151k haszn\u00e1lnak. Emiatt nagyon gyakran ker\u00fcltem hasonl\u00f3 helyzetekbe. Volt id\u0151, amikor egy ilyen k\u00e9p l\u00f3gott a k\u00e9perny\u0151m\u00f6n.<\/p>\n<p><img decoding=\"async\" alt=\"A CI fejl\u0151d\u00e9se a mobilfejleszt\u0151 csapatban\" src=\"\/wp-content\/uploads\/2019\/04\/0eb1aadd05b33ce995027ab52d5c1e53.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nMivel ez nek\u00fcnk nem volt megfelel\u0151, elkezdt\u00fck kidolgozni a lehet\u0151s\u00e9geket, hogyan lehet ezt megel\u0151zni.<\/p>\n<h2>Hogyan ne t\u00f6rj\u00fck \u00f6ssze a develop-ot<\/h2>\n<p>\nAz els\u0151 lehet\u0151s\u00e9g: <strong>\u00fajra kell \u00e9p\u00edteni az \u00f6sszes pull requestet a develop friss\u00edt\u00e9sekor. <\/strong>Ha a mi p\u00e9ld\u00e1nkban az A funkci\u00f3 pull requestje el\u0151sz\u00f6r ker\u00fcl a develop-ra, akkor a B funkci\u00f3 pull requestje \u00fajra\u00e9p\u00fcl, \u00e9s ennek megfelel\u0151en a tesztek nem fognak \u00e1tmenni a ford\u00edt\u00e1si hib\u00e1k miatt.<\/p>\n<p>Ahhoz, hogy meg\u00e9rts\u00fck, mennyi id\u0151t vesz ez ig\u00e9nybe, vegy\u00fcnk egy p\u00e9ld\u00e1t k\u00e9t PR-ra. Megnyitunk k\u00e9t PR-t: k\u00e9t build, k\u00e9t tesztfuttat\u00e1s. Miut\u00e1n az els\u0151 PR-t beolvasztott\u00e1k a develop-ba, a m\u00e1sodikat \u00fajra kell \u00e9p\u00edteni. \u00d6sszess\u00e9g\u00e9ben k\u00e9t PR miatt h\u00e1romszor futnak a tesztek: 2 + 1 = 3.<\/p>\n<p>Alapvet\u0151en rendben van. De megn\u00e9zt\u00fck a statisztik\u00e1t, \u00e9s a csapatunk tipikus helyzete 10 nyitott PR volt, akkor a tesztek sz\u00e1ma a sorozatok \u00f6sszege: 10 + 9 + ... + 1 = 55. Teh\u00e1t ahhoz, hogy 10 PR-t elfogadjunk, 55 alkalommal kell \u00fajra\u00e9p\u00edteni. \u00c9s ez ide\u00e1lis helyzetben van, amikor minden teszt el\u0151sz\u00f6r \u00e1tmegy, amikor senki sem nyit meg tov\u00e1bbi pull requestet, m\u00edg ez a t\u00edz feldolgoz\u00e1sra v\u00e1r.<\/p>\n<p>K\u00e9pzelje el, hogy \u00d6n egy fejleszt\u0151, aki igyekszik els\u0151k\u00e9nt r\u00e1kattintani a \u201emerge\u201d gombra, mert ha ezt a szomsz\u00e9d csin\u00e1lja, akkor meg kell v\u00e1rni, am\u00edg az \u00f6sszes \u00e9p\u00edt\u00e9s \u00fajra \u00e1tmegy... Nem, ez \u00edgy nem megy, ez komolyan lelass\u00edtja a fejleszt\u00e9st.<\/p>\n<p>A m\u00e1sodik lehets\u00e9ges m\u00f3d: <strong>a pull requesteket a k\u00f3dellen\u0151rz\u00e9s ut\u00e1n \u00e9p\u00edtj\u00fck. <\/strong>Teh\u00e1t megnyit egy pull requestet, \u00f6sszegy\u0171jti a sz\u00fcks\u00e9ges sz\u00e1m\u00fa j\u00f3v\u00e1hagy\u00e1st a koll\u00e9g\u00e1kt\u00f3l, jav\u00edtja, amire sz\u00fcks\u00e9ges, majd elind\u00edtja a build-eket. Ha azok sikeresek, a pull request \u00f6sszeolvad a develop-val. Ebben az esetben nincs tov\u00e1bbi \u00fajraind\u00edt\u00e1s, de jelent\u0151sen lelassul a visszajelz\u00e9s. Fejleszt\u0151k\u00e9nt, amikor megnyitok egy pull requestet, azonnal l\u00e1tni szeretn\u00e9m, hogy \u00f6ssze\u00e1ll-e. P\u00e9ld\u00e1ul, ha egy teszt megbukik, azt gyorsan meg kell jav\u00edtani. A halogatott \u00e9p\u00edt\u00e9ssel lassul a visszajelz\u00e9s, \u00edgy az eg\u00e9sz fejleszt\u00e9s is.<\/p>\n<p>Ennek eredm\u00e9nyek\u00e9nt csak a harmadik lehet\u0151s\u00e9g maradt \u2014 <strong>kerek\u00edteni<\/strong>Az \u00f6sszes k\u00f3dunk, minden forr\u00e1sunk a Bitbucket szerveren t\u00e1rol\u00f3dik. Ennek megfelel\u0151en fejleszten\u00fcnk kellett egy plugint a Bitbuckethez.<\/p>\n<p><img decoding=\"async\" alt=\"A CI fejl\u0151d\u00e9se a mobilfejleszt\u0151 csapatban\" src=\"\/wp-content\/uploads\/2019\/04\/5e4b1f770ea1a3449b616c3101640294.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEz a b\u0151v\u00edtm\u00e9ny fel\u00fcl\u00edrja a pull-k\u00e9relmek \u00f6sszevon\u00e1s\u00e1nak mechanizmus\u00e1t. Az alap\u00e9rtelmezett folyamat a k\u00f6vetkez\u0151: megny\u00edlik egy PR, elindulnak az \u00f6sszes build, \u00e9s elv\u00e9gzik a k\u00f3dellen\u0151rz\u00e9st. De miut\u00e1n a k\u00f3dellen\u0151rz\u00e9st elv\u00e9gezt\u00e9k, \u00e9s a fejleszt\u0151 \u00fagy d\u00f6nt, hogy r\u00e1kattint a \u201emerge\u201d gombra, a b\u0151v\u00edtm\u00e9ny ellen\u0151rzi, hogy a build-ekhez viszony\u00edtva a develop \u00e1llapot\u00e1t figyelembe vett\u00e9k-e. Ha a build-ek ut\u00e1n a develop friss\u00fclt, a b\u0151v\u00edtm\u00e9ny nem engedi, hogy ilyen pull-k\u00e9relmet egyes\u00edtsenek a f\u0151 \u00e1gba. Egyszer\u0171en \u00fajraind\u00edtja a build-eket a friss develop szerint.<\/p>\n<p><img decoding=\"async\" alt=\"A CI fejl\u0151d\u00e9se a mobilfejleszt\u0151 csapatban\" src=\"\/wp-content\/uploads\/2019\/04\/0edee880e1f2d286a0c64033103ac136.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nA konfliktusos v\u00e1ltoz\u00e1sokkal kapcsolatos p\u00e9ld\u00e1nkban az ilyen buildek nem fognak siker\u00fclni a ford\u00edt\u00e1si hiba miatt. Ennek megfelel\u0151en a B funkci\u00f3 fejleszt\u0151j\u00e9nek ki kell jav\u00edtania a k\u00f3dot, \u00fajra kell ind\u00edtania a vizsg\u00e1latokat, akkor a plugin automatikusan alkalmazni fogja a pull requestet.<\/p>\n<p>A plugin bevezet\u00e9se el\u0151tt \u00e1tlagosan 2,7 vizsg\u00e1lati ind\u00edt\u00e1sunk volt egy pull requestre. A pluginnal 3,6 lett. Ez kiel\u00e9g\u00edt\u0151 volt sz\u00e1munkra.<\/p>\n<p>\u00c9rdemes megjegyezni, hogy ennek a pluginnek van egy h\u00e1tr\u00e1nya: csak egyszer ind\u00edtja \u00fajra a buildet. Teh\u00e1t m\u00e9g mindig van egy kis ablak, amin kereszt\u00fcl konfliktusos v\u00e1ltoz\u00e1sok ker\u00fclhetnek a developba. De ennek a val\u00f3sz\u00edn\u0171s\u00e9ge alacsony, \u00e9s mi ezt a kompromisszumot k\u00f6t\u00f6tt\u00fck a fut\u00e1sok sz\u00e1m\u00e1nak \u00e9s a hib\u00e1sod\u00e1s val\u00f3sz\u00edn\u0171s\u00e9g\u00e9nek cs\u00f6kkent\u00e9se \u00e9rdek\u00e9ben. K\u00e9t \u00e9v alatt csak egyszer fordult el\u0151, teh\u00e1t val\u00f3sz\u00edn\u0171leg nem hi\u00e1ba.<\/p>\n<p><strong><em>Az els\u0151 verzi\u00f3 meg\u00edr\u00e1sa a Bitbucket plugin sz\u00e1m\u00e1ra k\u00e9t h\u00e9tig tartott. <\/em><\/strong><\/p>\n<h3>\u00daj ellen\u0151rz\u00e9sek<\/h3>\n<p>\nK\u00f6zben a csapatunk folyamatosan n\u0151tt. \u00daj ellen\u0151rz\u00e9sek ker\u00fcltek bevezet\u00e9sre.<\/p>\n<p>Arra gondoltunk: mi\u00e9rt jav\u00edtsuk ki a hib\u00e1kat, ha megel\u0151zni is lehet \u0151ket? Ez\u00e9rt bevezett\u00fck <strong>a k\u00f3d statikus elemz\u00e9s\u00e9t<\/strong>. A lint haszn\u00e1lat\u00e1val kezdt\u00fck, amely az Android SDK r\u00e9sze. De akkoriban egy\u00e1ltal\u00e1n nem tudott m\u0171k\u00f6dni a Kotlin k\u00f3ddal, \u00e9s a mi alkalmaz\u00e1sunk 75%-\u00e1t m\u00e1r Kotlin nyelven \u00edrt\u00e1k. Ez\u00e9rt a linthez hozz\u00e1adtuk az integr\u00e1lt <strong>Android Studio ellen\u0151rz\u00e9seit.<\/strong><\/p>\n<p>Ehhez el\u00e9gg\u00e9 kreat\u00edvnak kellett lenn\u00fcnk: az Android Studi\u00f3t Dockerbe kellett csomagolnunk, \u00e9s CI k\u00f6rnyezetben virtu\u00e1lis monitorral kellett futtatnunk, hogy azt higgye, hogy egy val\u00f3di laptopon fut. De m\u0171k\u00f6d\u00f6tt.<\/p>\n<p>Ezen a h\u00e9ten elkezdt\u00fcnk sok <strong>instrument\u00e1ci\u00f3s tesztet<\/strong> \u00edrni, \u00e9s bevezett\u00fck <strong>a k\u00e9perny\u0151k\u00e9p tesztel\u00e9st.<\/strong>. Ez az, amikor egy referencia k\u00e9perny\u0151k\u00e9pet gener\u00e1lnak egy k\u00fcl\u00f6n kis n\u00e9zethez, \u00e9s a teszt abban \u00e1ll, hogy a n\u00e9zetr\u0151l k\u00e9perny\u0151k\u00e9pet k\u00e9sz\u00edtenek, \u00e9s pixelr\u0151l pixelre \u00f6sszehasonl\u00edtj\u00e1k a referenci\u00e1val. Ha elt\u00e9r\u00e9s van, az azt jelenti, hogy valahol elcs\u00faszott a layout vagy valami nem stimmel a st\u00edlusokkal.<\/p>\n<p>De az instrumentation \u00e9s k\u00e9perny\u0151k\u00e9pes teszteket eszk\u00f6z\u00f6k\u00f6n kell futtatni: emul\u00e1torokon vagy val\u00f3di eszk\u00f6z\u00f6k\u00f6n. Mivel sok teszt van, \u00e9s gyakran futtatj\u00e1k \u0151ket, eg\u00e9sz farmra van sz\u00fcks\u00e9g. Saj\u00e1t farmot l\u00e9trehozni t\u00fal munkaig\u00e9nyes, ez\u00e9rt tal\u00e1ltunk egy k\u00e9sz megold\u00e1st - a Firebase Test Labot.<\/p>\n<h3>Firebase Test Lab<\/h3>\n<p>\nA Firebase-t v\u00e1lasztottuk, mert ez a Google term\u00e9ke, teh\u00e1t megb\u00edzhat\u00f3nak kell lennie, \u00e9s val\u00f3sz\u00edn\u0171leg sosem sz\u0171nik meg. Az \u00e1rak kedvez\u0151ek: 5 $ egy \u00f3ra val\u00f3di eszk\u00f6z haszn\u00e1lat\u00e9rt, 1 $ egy \u00f3ra emul\u00e1tor haszn\u00e1lat\u00e9rt.<\/p>\n<p><strong><em>A Firebase Test Lab integr\u00e1l\u00e1s\u00e1ra a CI-nkben k\u00f6r\u00fclbel\u00fcl h\u00e1rom h\u00e9t ment el.<\/em><\/strong><\/p>\n<p>De a csapat tov\u00e1bb n\u0151tt, \u00e9s sajnos a Firebase elkezdett minket cserbenhagyni. Akkoriban nem volt semmilyen SLA. N\u00e9ha a Firebase megk\u00f6vetelte, hogy v\u00e1rjunk, am\u00edg felszabadul a sz\u00fcks\u00e9ges sz\u00e1m\u00fa eszk\u00f6z a tesztekhez, \u00e9s nem kezdte el azokat azonnal, ahogy azt szerett\u00fck volna. A v\u00e1rakoz\u00e1s ak\u00e1r f\u00e9l \u00f3r\u00e1ig is eltartott, ami nagyon hossz\u00fa. Az instrumentation tesztek minden PR-n\u00e9l futottak, a k\u00e9sleked\u00e9sek nagyon lelass\u00edtott\u00e1k a fejleszt\u00e9st, azt\u00e1n meg j\u00f6tt a havi sz\u00e1mla egy kerek \u00f6sszeggel. V\u00e9g\u00fcl \u00fagy d\u00f6nt\u00f6tt\u00fcnk, hogy lemondunk a Firebase-r\u0151l, \u00e9s in-house fejleszt\u00fcnk, mivel a csapat el\u00e9g nagyra n\u0151tt.<\/p>\n<h3>Docker + Python + bash<\/h3>\n<p>\nDocker-t haszn\u00e1ltunk, beletett\u00fck az emul\u00e1torokat, \u00edrtunk egy egyszer\u0171 programot Python-ban, ami a megfelel\u0151 id\u0151pontban elind\u00edtja a sz\u00fcks\u00e9ges sz\u00e1m\u00fa emul\u00e1tort a megfelel\u0151 verzi\u00f3ban, amikor pedig le kell \u00e1ll\u00edtani \u0151ket. \u00c9s persze, p\u00e1r bash-script - hov\u00e1 is menn\u00e9nk n\u00e9lk\u00fcl\u00fck?<\/p>\n<p><strong><em>A saj\u00e1t tesztk\u00f6rnyezet l\u00e9trehoz\u00e1sa \u00f6t hetet vett ig\u00e9nybe.<\/em><\/strong><\/p>\n<p>Ennek eredm\u00e9nyek\u00e9nt minden pull request-hez egy \u00e1tfog\u00f3, az egyes\u00fcl\u00e9st blokkol\u00f3 ellen\u0151rz\u00e9si lista tartozott:<\/p>\n<ul>\n<li>ARK \u00e9p\u00edt\u00e9s;<\/li>\n<li>Junit-tesztek;<\/li>\n<li>Lint;<\/li>\n<li>Android Studio ellen\u0151rz\u00e9sek;<\/li>\n<li>Instrumentation tesztek;<\/li>\n<li>K\u00e9perny\u0151k\u00e9pes tesztek.<\/li>\n<\/ul>\n<p>\nEz sok lehets\u00e9ges hiba megel\u0151z\u00e9s\u00e9t tette lehet\u0151v\u00e9. Technikailag minden j\u00f3l m\u0171k\u00f6d\u00f6tt, de a fejleszt\u0151k panaszkodtak, hogy t\u00fal hossz\u00fa ideig kell v\u00e1rniuk az eredm\u00e9nyekre.<\/p>\n<p>T\u00fal hossz\u00fa - ez mennyi? Kib\u00e1ny\u00e1sztuk az adatokat a Bitbucketb\u0151l \u00e9s a TeamCityb\u0151l egy elemz\u0151 rendszerbe, \u00e9s r\u00e1j\u00f6tt\u00fcnk, hogy <strong>az \u00e1tlagos v\u00e1rakoz\u00e1si id\u0151 45 perc<\/strong>. Vagyis a fejleszt\u0151, amikor megnyit egy pull request-et, \u00e1tlagosan 45 percet v\u00e1r az \u00e9p\u00edtkez\u00e9si eredm\u00e9nyekre. V\u00e9lem\u00e9nyem szerint ez nagyon sok, \u00e9s \u00edgy nem lehet dolgozni.<\/p>\n<p>Term\u00e9szetesen, \u00fagy d\u00f6nt\u00f6tt\u00fcnk, hogy felgyors\u00edtjuk az \u00f6sszes build\u00fcnket.<\/p>\n<h2>Gyors\u00edtunk<\/h2>\n<p>\nL\u00e1tva, hogy gyakran a buildjeink v\u00e1rakoz\u00e1si sorban \u00e1llnak, el\u0151sz\u00f6r is <strong>b\u0151v\u00edtett\u00fck a hardver\u00fcnket<\/strong> \u2014 az extenz\u00edv fejleszt\u00e9s a legegyszer\u0171bb. A buildjeink t\u00f6bb\u00e9 nem \u00e1llnak a sorban, de a v\u00e1rakoz\u00e1si id\u0151 csak egy kicsit cs\u00f6kkent, mert egyes ellen\u0151rz\u00e9sek maguk is nagyon hossz\u00fa ideig tartanak.<\/p>\n<h3>Elt\u00e1vol\u00edtjuk a t\u00fal hossz\u00fa ellen\u0151rz\u00e9seket<\/h3>\n<p>\nA Continuous Integration rendszer\u00fcnk k\u00e9pes lenne \u00e9szlelni az ilyen t\u00edpus\u00fa hib\u00e1kat \u00e9s probl\u00e9m\u00e1kat.<\/p>\n<ul>\n<li><strong>Nem \u00e9p\u00fcl fel<\/strong>. A CI \u00e9szlelheti a ford\u00edt\u00e1si hib\u00e1t, amikor a konfliktusos m\u00f3dos\u00edt\u00e1sok miatt valami nem \u00e9p\u00fcl fel. Ahogy m\u00e1r mondtam, ilyenkor senki sem tud semmit \u00f6sszerakni, a fejleszt\u00e9s meg\u00e1ll, \u00e9s mindenki idegeskedik.<\/li>\n<li><strong>Hiba a viselked\u00e9sben<\/strong>. P\u00e9ld\u00e1ul, amikor az alkalmaz\u00e1s fel\u00e9p\u00fcl, de egy gomb megnyom\u00e1sakor \u00f6sszeomlik, vagy a gomb egy\u00e1ltal\u00e1n nem m\u0171k\u00f6dik. Ez rossz, mert egy ilyen hiba eljuthat a felhaszn\u00e1l\u00f3hoz.<\/li>\n<li><strong>Hiba a diz\u00e1jnban<\/strong>. P\u00e9ld\u00e1ul, a gomb m\u0171k\u00f6dik, de 10 pixelre elmozdult balra.<\/li>\n<li><strong>N\u00f6vekv\u0151 technikai ad\u00f3ss\u00e1g<\/strong>.<\/li>\n<\/ul>\n<p>\nEzt a list\u00e1t n\u00e9zve r\u00e1j\u00f6tt\u00fcnk, hogy az els\u0151 k\u00e9t pont kritikus. Az ilyen probl\u00e9m\u00e1kat szeretn\u00e9nk els\u0151k\u00e9nt \u00e9szlelni. A diz\u00e1jn-ellen\u0151rz\u00e9s sor\u00e1n \u00e9szlelt hib\u00e1k k\u00f6nnyen jav\u00edthat\u00f3k. A technikai ad\u00f3ss\u00e1ggal val\u00f3 munka k\u00fcl\u00f6n folyamatot \u00e9s tervez\u00e9st ig\u00e9nyel, ez\u00e9rt \u00fagy d\u00f6nt\u00f6tt\u00fcnk, hogy nem ellen\u0151rizz\u00fck a pull requestben.<\/p>\n<p>Ebb\u0151l a klasszifik\u00e1ci\u00f3b\u00f3l kiindulva \u00e1tn\u00e9zt\u00fck az \u00f6sszes ellen\u0151rz\u00e9st. <strong>Kih\u00faztuk a Lintrt<\/strong> \u00e9s \u00e1thelyezt\u00fck az \u00e9jszakai fut\u00e1sra: csak hogy jelent\u00e9st adjon arr\u00f3l, h\u00e1ny probl\u00e9ma van a projektben. A technikai ad\u00f3ss\u00e1ggal k\u00fcl\u00f6n foglalkozunk, \u00e9s <strong>az Android Studio ellen\u0151rz\u00e9seir\u0151l teljesen lemondtunk<\/strong>. Az Android Studio Dockerben t\u00f6rt\u00e9n\u0151 haszn\u00e1lata az ellen\u0151rz\u00e9sekhez \u00e9rdekesnek t\u0171nik, de sok kellemetlens\u00e9get okoz a t\u00e1mogat\u00e1sban. B\u00e1rmilyen friss\u00edt\u00e9s az Android Studio verzi\u00f3j\u00e1b\u00f3l egy harc a megmagyar\u00e1zhatatlan hib\u00e1kkal. Ugyanakkor a k\u00e9perny\u0151k\u00e9pes tesztek t\u00e1mogat\u00e1sa is neh\u00e9zkes volt, mert a k\u00f6nyvt\u00e1r nem m\u0171k\u00f6d\u00f6tt t\u00fal stabilan, el\u0151fordultak hamis riaszt\u00e1sok. <strong>A k\u00e9perny\u0151k\u00e9pes teszteket elt\u00e1vol\u00edtottuk az ellen\u0151rz\u00e9sek list\u00e1j\u00e1b\u00f3l<\/strong>.<\/p>\n<p>V\u00e9g\u00fcl maradt nek\u00fcnk:<\/p>\n<ul>\n<li>ARK \u00e9p\u00edt\u00e9s;<\/li>\n<li>Junit-tesztek;<\/li>\n<li>Instrumentation tesztek.<\/li>\n<\/ul>\n<h3>Gradle t\u00e1voli gyors\u00edt\u00f3t\u00e1r<\/h3>\n<p>\nS\u00falyos ellen\u0151rz\u00e9sek n\u00e9lk\u00fcl minden jobb lett. De a t\u00f6k\u00e9letess\u00e9gnek nincs hat\u00e1ra!<\/p>\n<p>Alkalmaz\u00e1sunk m\u00e1r k\u00f6r\u00fclbel\u00fcl 150 gradle modulra volt bontva. Ilyen esetben a Gradle t\u00e1voli gyors\u00edt\u00f3t\u00e1r \u00e1ltal\u00e1ban j\u00f3l m\u0171k\u00f6dik, \u00e9s \u00fagy d\u00f6nt\u00f6tt\u00fcnk, hogy kipr\u00f3b\u00e1ljuk.<\/p>\n<p>A Gradle t\u00e1voli gyors\u00edt\u00f3t\u00e1r egy olyan szolg\u00e1ltat\u00e1s, amely k\u00e9pes t\u00e1rolni a build-artifaktumokat k\u00fcl\u00f6nb\u00f6z\u0151 feladatokhoz k\u00fcl\u00f6nb\u00f6z\u0151 modulokban. A Gradle ahelyett, hogy val\u00f3ban leford\u00edtan\u00e1 a k\u00f3dot, HTTP-n kereszt\u00fcl megkeresi a t\u00e1voli gyors\u00edt\u00f3t\u00e1rat, \u00e9s megk\u00e9rdezi, hogy valaki m\u00e1r v\u00e9grehajtotta-e ezt a feladatot. Ha igen, egyszer\u0171en let\u00f6lti az eredm\u00e9nyt.<\/p>\n<p><strong><em>A Gradle t\u00e1voli gyors\u00edt\u00f3t\u00e1r elind\u00edt\u00e1sa k\u00f6nny\u0171, mert a Gradle Docker k\u00e9pet biztos\u00edt. Siker\u00fclt ezt megval\u00f3s\u00edtanunk h\u00e1rom \u00f3ra alatt.<\/em><\/strong><\/p>\n<p>Csak annyit kellett tenn\u00fcnk, hogy elind\u00edtjuk a Dockert, \u00e9s be\u00edrunk egy sort a projektbe. De b\u00e1r gyorsan elind\u00edthat\u00f3, ahhoz, hogy j\u00f3l m\u0171k\u00f6dj\u00f6n, el\u00e9g sok id\u0151re van sz\u00fcks\u00e9g.<\/p>\n<p>Al\u00e1bb a cache hi\u00e1nyz\u00e1sainak grafikonja.<\/p>\n<p><img decoding=\"async\" alt=\"A CI fejl\u0151d\u00e9se a mobilfejleszt\u0151 csapatban\" src=\"\/wp-content\/uploads\/2019\/04\/458ef23b5506b04f3bd385be0c18607a.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nA legels\u0151 h\u00f3napban a cache hi\u00e1nyz\u00e1sok ar\u00e1nya k\u00f6r\u00fclbel\u00fcl 65% volt. H\u00e1rom h\u00e9t alatt ezt az \u00e9rt\u00e9ket 20%-ra siker\u00fclt cs\u00f6kkenteni. Kider\u00fclt, hogy az Android alkalmaz\u00e1s \u00e1ltal \u00f6sszegy\u0171jt\u00f6tt feladatok furcsa tranzit\u00edv f\u00fcgg\u0151s\u00e9gekkel rendelkeznek, amelyek miatt a Gradle elszalasztotta a gyors\u00edt\u00f3t\u00e1rt.<\/p>\n<p>A gyors\u00edt\u00f3t\u00e1r csatlakoztat\u00e1s\u00e1val nagym\u00e9rt\u00e9kben felgyors\u00edtottuk a buildet. De a build mellett m\u00e9g futnak az instrument\u00e1ci\u00f3s tesztek is, amelyek hossz\u00fa id\u0151t vesznek ig\u00e9nybe. Lehet, hogy nem kell minden tesztet futtatni minden egyes pull request sor\u00e1n. Ennek a kider\u00edt\u00e9s\u00e9re hat\u00e1svizsg\u00e1latot alkalmazunk.<\/p>\n<h3>Hat\u00e1svizsg\u00e1lat<\/h3>\n<p>\nA pull requesten csin\u00e1lunk egy git diff-et, \u00e9s megtal\u00e1ljuk a megv\u00e1ltozott Gradle modulokat.<\/p>\n<p><img decoding=\"async\" alt=\"A CI fejl\u0151d\u00e9se a mobilfejleszt\u0151 csapatban\" src=\"\/wp-content\/uploads\/2019\/04\/471ca37206a0da4d5741c8ee1dbb7f03.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nCsak azokat az instrument\u00e1ci\u00f3s teszteket \u00e9rdemes futtatni, amelyek a megv\u00e1ltozott modulokat ellen\u0151rzik, \u00e9s minden olyan modult, amelyt\u0151l f\u00fcggenek. A szomsz\u00e9dos modulok tesztjeit nem \u00e9rdemes futtatni: ott a k\u00f3d nem v\u00e1ltozott, \u00e9s semmi sem tud elromlani.<\/p>\n<p>Az instrument\u00e1ci\u00f3s tesztekkel nem olyan egyszer\u0171 a helyzet, mert ezeknek a legfels\u0151 modulban, az Application modulban kell lenni\u00fck. Heurisztik\u00e1t alkalmaztunk a bytecode elemz\u00e9s\u00e9vel, hogy meg\u00e9rts\u00fck, melyik modulhoz tartozik minden teszt.<\/p>\n<p><strong><em>Az instrument\u00e1ci\u00f3s tesztek munk\u00e1j\u00e1nak moderniz\u00e1l\u00e1sa, hogy csak a haszn\u00e1lt modulokat ellen\u0151rizz\u00e9k, k\u00f6r\u00fclbel\u00fcl nyolc h\u00e9tig tartott.<\/em><\/strong><\/p>\n<p>A tesztellen\u0151rz\u00e9sek felgyors\u00edt\u00e1sa \u00e9rdek\u00e9ben tett int\u00e9zked\u00e9sek sikeresen m\u0171k\u00f6dtek. 45 percr\u0151l k\u00f6r\u00fclbel\u00fcl 15 percre cs\u00f6kkentett\u00fck az id\u0151t. Negyed \u00f3ra v\u00e1rakoz\u00e1s m\u00e1r elfogadhat\u00f3 a build sor\u00e1n.<\/p>\n<p>De most a fejleszt\u0151k elkezdtek panaszkodni, hogy nem vil\u00e1gos sz\u00e1mukra, mely build-ek futnak, hol n\u00e9zhetik meg a logokat, mi\u00e9rt piros a build, melyik teszt bukott el stb.<\/p>\n<p><img decoding=\"async\" alt=\"A CI fejl\u0151d\u00e9se a mobilfejleszt\u0151 csapatban\" src=\"\/wp-content\/uploads\/2019\/04\/aa76151174cd4e5a45ff281818e312f5.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nA visszajelz\u00e9si probl\u00e9m\u00e1k lass\u00edtj\u00e1k a fejleszt\u00e9st, ez\u00e9rt igyekezt\u00fcnk a lehet\u0151 leg\u00e9rthet\u0151bb \u00e9s r\u00e9szletesebb inform\u00e1ci\u00f3t biztos\u00edtani minden PR-r\u0151l \u00e9s buildr\u0151l. Elkezd\u0151d\u00f6tt a Bitbucket PR kommentjeivel, amelyekben jelezt\u00fck, hogy melyik build hib\u00e1zott \u00e9s mi\u00e9rt, \u00e9s c\u00edmzett \u00fczeneteket \u00edrtunk a Slack-en. V\u00e9g\u00fcl l\u00e9trehoztunk egy PR dashboardot, ahol minden aktu\u00e1lisan fut\u00f3 build list\u00e1ja \u00e9s azok \u00e1llapota: v\u00e1rakozik, fut, hib\u00e1s vagy befejez\u0151d\u00f6tt. Kattinthat\u00f3 a build, \u00e9s megnyithat\u00f3k a napl\u00f3i.<\/p>\n<p><img decoding=\"async\" alt=\"A CI fejl\u0151d\u00e9se a mobilfejleszt\u0151 csapatban\" src=\"\/wp-content\/uploads\/2019\/04\/2d16b7a6b6d23e23903d291ef1526999.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n<strong><em>A r\u00e9szletes visszajelz\u00e9s elk\u00e9sz\u00edt\u00e9s\u00e9re hat h\u00e9tig volt sz\u00fcks\u00e9g.<\/em><\/strong><\/p>\n<h2>Tervek<\/h2>\n<p>\nT\u00e9rj\u00fcnk \u00e1t a leg\u00fajabb t\u00f6rt\u00e9n\u00e9sekre. A visszajelz\u00e9sek rendez\u00e9s\u00e9vel \u00faj szintre l\u00e9pt\u00fcnk \u2014 \u00fagy d\u00f6nt\u00f6tt\u00fcnk, hogy \u00e9p\u00edt\u00fcnk egy emulator farmot. Amikor sok teszt \u00e9s emulator van, neh\u00e9z \u0151ket kezelni. V\u00e9g\u00fcl minden emulatorunk k8s klaszterre k\u00f6lt\u00f6z\u00f6tt, rugalmas er\u0151forr\u00e1s-kezel\u00e9ssel.<\/p>\n<p>Ezen k\u00edv\u00fcl m\u00e1s tervek is vannak.<\/p>\n<ul>\n<li><strong>Lint vissza\u00e1ll\u00edt\u00e1sa<\/strong> (\u00e9s m\u00e1s statikus elemz\u00e9s). M\u00e1r dolgozunk ebben az ir\u00e1nyban.<\/li>\n<li>Minden PR blokkol\u00f3 alatt futtassuk az \u00f6sszes <strong>end-to-end tesztet<\/strong> az SDK minden verzi\u00f3j\u00e1n.<\/li>\n<\/ul>\n<p>\nTeh\u00e1t nyomon k\u00f6vett\u00fck a folyamatos integr\u00e1ci\u00f3 fejl\u0151d\u00e9s\u00e9t az Avito-n\u00e1l. Most pedig szeretn\u00e9k n\u00e9h\u00e1ny tan\u00e1csot adni a tapasztalataink alapj\u00e1n.<\/p>\n<h1>Tan\u00e1csok<\/h1>\n<p>\nHa csak egy tan\u00e1csot adhatn\u00e9k, az ez lenne:<\/p>\n<blockquote><p>K\u00e9rlek, l\u00e9gy \u00f3vatos a shell szkriptekkel!<\/p><\/blockquote>\n<p>\nA Bash egy nagyon rugalmas \u00e9s hat\u00e9kony eszk\u00f6z, amellyel nagyon gyorsan \u00e9s k\u00e9nyelmesen lehet szkripteket \u00edrni. De csapd\u00e1ba lehet esni vele, \u00e9s sajnos mi is beleest\u00fcnk.<\/p>\n<p>Minden egyszer\u0171 szkripttel kezd\u0151d\u00f6tt, amelyeket a build g\u00e9peinken futtattunk:<\/p>\n<pre><code class=\"bash\">#!\/usr\/bin\/env bash\n.\/gradlew assembleDebug<\/code><\/pre>\n<p>\nDe mint tudjuk, minden id\u0151vel fejl\u0151dik \u00e9s bonyol\u00f3dik \u2014 ind\u00edtsunk egy szkriptet a m\u00e1sikb\u00f3l, adjunk \u00e1t valamilyen param\u00e9tert \u2014 v\u00e9g\u00fcl meg kellett \u00edrni egy olyan funkci\u00f3t, amely meghat\u00e1rozza, hogy milyen szint\u0171 a bash-be\u00e1gyaz\u00e1s, ahol jelenleg tartunk, hogy a megfelel\u0151 id\u00e9z\u0151jeleket betehess\u00fck, hogy mindez elinduljon.<\/p>\n<p><img decoding=\"async\" alt=\"A CI fejl\u0151d\u00e9se a mobilfejleszt\u0151 csapatban\" src=\"\/wp-content\/uploads\/2019\/04\/244a574f7b5d3b4fc77cfc4ccda2db69.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEl tudod k\u00e9pzelni az ilyen szkriptek fejleszt\u00e9s\u00e9hez sz\u00fcks\u00e9ges er\u0151forr\u00e1st. Azt tan\u00e1csolom, ne ess ebbe a csapd\u00e1ba.<\/p>\n<p>Mivel lehet helyettes\u00edteni?<\/p>\n<ul>\n<li>B\u00e1rmely szkriptnyelvvel. A <strong>Python vagy Kotlin Script<\/strong> haszn\u00e1lata k\u00e9nyelmesebb, mert ez programoz\u00e1s, nem szkriptek.<\/li>\n<li>Vagy az \u00f6sszes build logik\u00e1j\u00e1t le\u00edrhatod <strong>Custom gradle tasks<\/strong> a projekted sz\u00e1m\u00e1ra.<\/li>\n<\/ul>\n<p>\nA m\u00e1sodik lehet\u0151s\u00e9get v\u00e1lasztottuk, \u00e9s most fokozatosan elt\u00e1vol\u00edtjuk az \u00f6sszes bash szkriptet, sok egyedi gradle feladatot \u00edrunk.<\/p>\n<p><strong>Tan\u00e1cs \u21162: tartsd az infrastrukt\u00far\u00e1t k\u00f3d form\u00e1j\u00e1ban.<\/strong><\/p>\n<p>K\u00e9nyelmes, amikor a folyamatos integr\u00e1ci\u00f3 be\u00e1ll\u00edt\u00e1sa nem a Jenkins vagy TeamCity UI-j\u00e1ban, hanem sz\u00f6veges f\u00e1jlok form\u00e1j\u00e1ban van a projekt t\u00e1rol\u00f3j\u00e1ban. Ez lehet\u0151v\u00e9 teszi a verzi\u00f3kezel\u00e9st. Nem neh\u00e9z visszag\u00f6rgetni vagy k\u00f3dot ford\u00edtani egy m\u00e1sik \u00e1gon.<\/p>\n<p>A szkriptek a projektben t\u00e1rolhat\u00f3k. De mi legyen a k\u00f6rnyezettel?<\/p>\n<p><strong>3. tan\u00e1cs: a Docker seg\u00edthet a k\u00f6rnyezettel.<\/strong><\/p>\n<p>Az Android fejleszt\u0151knek biztosan seg\u00edt, az iOS eset\u00e9ben sajnos m\u00e9g nem.<\/p>\n<p>Ez egy p\u00e9lda egy egyszer\u0171 docker f\u00e1jlra, amely tartalmaz egy jdk-t \u00e9s android-sdk-t:<\/p>\n<pre><code class=\"plaintext\">FROM openjdk:8\n\nENV SDK_URL=\"https:\/\/dl.google.com\/android\/repository\/sdk-tools-linux-3859397.zip\" \n    ANDROID_HOME=\"\/usr\/local\/android-sdk\" \n    ANDROID_VERSION=26 \n    ANDROID_BUILD_TOOLS_VERSION=26.0.2\n\n# T\u00f6ltse le az Android SDK-t\nRUN mkdir \"$ANDROID_HOME\" .android \n    &amp;&amp; cd \"$ANDROID_HOME\" \n    &amp;&amp; curl -o sdk.zip $SDK_URL \n    &amp;&amp; unzip sdk.zip \n    &amp;&amp; rm sdk.zip \n    &amp;&amp; yes | $ANDROID_HOME\/tools\/bin\/sdkmanager --licenses\n\n# Telep\u00edtse az Android Build Tool-t \u00e9s k\u00f6nyvt\u00e1rakat\nRUN $ANDROID_HOME\/tools\/bin\/sdkmanager --update\nRUN $ANDROID_HOME\/tools\/bin\/sdkmanager \"build-tools;${ANDROID_BUILD_TOOLS_VERSION}\" \n    \"platforms;android-${ANDROID_VERSION}\" \n    \"platform-tools\"\n\nRUN mkdir \/application\nWORKDIR \/application\n<\/code><\/pre>\n<p>\nMeg\u00edrtam ezt a docker f\u00e1jlt (titokban mondom, nem is musz\u00e1j meg\u00edrni, el\u00e9g, ha let\u00f6lt egy k\u00e9sz verzi\u00f3t GitHub-r\u00f3l), \u00e9s a k\u00e9p elk\u00e9sz\u00edt\u00e9s\u00e9vel egy virtu\u00e1lis g\u00e9pet kapsz, amelyen k\u00e9pes leszel az alkalmaz\u00e1s ford\u00edt\u00e1s\u00e1ra \u00e9s Junit tesztek futtat\u00e1s\u00e1ra.<\/p>\n<p>K\u00e9t f\u0151 \u00e9rv, ami\u00e9rt \u00e9rdemes ezt megtenni: sk\u00e1l\u00e1zhat\u00f3s\u00e1g \u00e9s megism\u00e9telhet\u0151s\u00e9g. A docker haszn\u00e1lat\u00e1val gyorsan felemelhetsz egy tucat \u00e9p\u00edt\u00e9si \u00fcgyn\u00f6k\u00f6t, amelyek pontosan ugyanazt a k\u00f6rnyezetet fogj\u00e1k birtokolni, mint kor\u00e1bban. Ez nagyon megk\u00f6nny\u00edti a CI m\u00e9rn\u00f6k\u00f6k \u00e9let\u00e9t. Az android-sdk dockerbe helyez\u00e9se igaz\u00e1n egyszer\u0171, az emul\u00e1torok viszont kicsit bonyolultabbak: kiss\u00e9 meg kell izzadni (vagy megint let\u00f6ltheted a k\u00e9sz verzi\u00f3t GitHub-r\u00f3l).<\/p>\n<p><strong>4. tan\u00e1cs: ne feledd, hogy a ellen\u0151rz\u00e9sek nem a tesztek miatt t\u00f6rt\u00e9nnek, hanem az emberek\u00e9rt.<\/strong><\/p>\n<p>A fejleszt\u0151knek nagyon fontos a gyors \u00e9s, ami a legfontosabb, vil\u00e1gos visszajelz\u00e9s: mi romlott el, melyik teszt bukott meg, hol n\u00e9zhetik meg a build logot.<\/p>\n<p><strong>5. tan\u00e1cs: legy\u00e9l pragmatikus a folyamatos integr\u00e1ci\u00f3 fejleszt\u00e9s\u00e9ben.<\/strong><\/p>\n<p>\u00c9rtsd meg vil\u00e1gosan, milyen t\u00edpus\u00fa hib\u00e1kat szeretn\u00e9l megel\u0151zni, mennyit vagy k\u00e9sz k\u00f6lteni forr\u00e1sokban, id\u0151ben, g\u00e9pi id\u0151ben. A t\u00fal hossz\u00fa ellen\u0151rz\u00e9seket p\u00e9ld\u00e1ul \u00e9jszak\u00e1ra pontosan el lehet halasztani. Az olyanokt\u00f3l, amelyek nem igaz\u00e1n fontos hib\u00e1kat \u00e9szlelnek, pedig teljesen el lehet tekinteni.<\/p>\n<p><strong>6. tan\u00e1cs: haszn\u00e1lj k\u00e9sz eszk\u00f6z\u00f6ket.<\/strong><\/p>\n<p>Jelenleg sok c\u00e9g k\u00edn\u00e1l felh\u0151 alap\u00fa CI-t.<\/p>\n<p><img decoding=\"async\" alt=\"A CI fejl\u0151d\u00e9se a mobilfejleszt\u0151 csapatban\" src=\"\/wp-content\/uploads\/2019\/04\/e57aabd49ec01d14e83b64331fd84ec5.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nKis csapatok sz\u00e1m\u00e1ra ez egy j\u00f3 megold\u00e1s. Nincs sz\u00fcks\u00e9g semmilyen karbantart\u00e1sra, csak fizess egy kicsit, \u00e9p\u00edtsd meg az alkalmaz\u00e1sodat \u00e9s m\u00e9g futtathatsz teljes\u00edtm\u00e9nyteszteket is.<\/p>\n<p><strong>7. tipp: nagyobb csapatn\u00e1l \u00e9rdemesebb h\u00e1zon bel\u00fcli megold\u00e1sokat v\u00e1lasztani.<\/strong><\/p>\n<p>De el\u0151bb-ut\u00f3bb, a csapat n\u00f6veked\u00e9s\u00e9vel, a h\u00e1zon bel\u00fcli megold\u00e1sok lesznek a kedvez\u0151bbek. E megold\u00e1sokhoz viszont van egy megfontoland\u00f3 t\u00e9nyez\u0151. A gazdas\u00e1gban l\u00e9tezik a cs\u00f6kken\u0151 megt\u00e9r\u00fcl\u00e9s t\u00f6rv\u00e9nye: b\u00e1rmely projekt eset\u00e9ben minden \u00fajabb fejleszt\u00e9s egyre nehezebb, egyre nagyobb befektet\u00e9st ig\u00e9nyel.<\/p>\n<p>A gazdas\u00e1g minden \u00e9let\u00fcnket le\u00edrja, bele\u00e9rtve a Folyamatos Integr\u00e1ci\u00f3t is. K\u00e9sz\u00edtettem egy grafikont a munkaer\u0151ig\u00e9nyr\u0151l a Folyamatos Integr\u00e1ci\u00f3 fejl\u0151d\u00e9s\u00e9nek minden szakasz\u00e1ban.<\/p>\n<p><img decoding=\"async\" alt=\"A CI fejl\u0151d\u00e9se a mobilfejleszt\u0151 csapatban\" src=\"\/wp-content\/uploads\/2019\/04\/97bf8bff64f3ac9ae587fae195251da2.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nL\u00e1that\u00f3, hogy b\u00e1rmilyen fejleszt\u00e9s egyre nehezebb\u00e9 v\u00e1lik. E grafikon alapj\u00e1n k\u00f6nnyen meg\u00e9rthet\u0151, hogy a Folyamatos Integr\u00e1ci\u00f3t a csapat m\u00e9ret\u00e9nek n\u00f6veked\u00e9s\u00e9vel \u00f6sszhangban kell fejleszteni. K\u00e9t f\u0151b\u0151l \u00e1ll\u00f3 csapatnak k\u00f6r\u00fclbel\u00fcl 50 napot elt\u00f6lteni egy bels\u0151 emul\u00e1tor farm fejleszt\u00e9s\u00e9vel \u2013 nem t\u00fal j\u00f3 \u00f6tlet. De a nagy csapat sz\u00e1m\u00e1ra sem j\u00f3 megold\u00e1s, ha nem foglalkoznak a Folyamatos Integr\u00e1ci\u00f3val, mert az integr\u00e1ci\u00f3s probl\u00e9m\u00e1kra, a kommunik\u00e1ci\u00f3 jav\u00edt\u00e1s\u00e1ra \u00e9s egyebekre m\u00e9g t\u00f6bb id\u0151t em\u00e9szt fel.<\/p>\n<p>Az automatiz\u00e1l\u00e1sra az\u00e9rt volt sz\u00fcks\u00e9g, mert az emberek dr\u00e1g\u00e1k, hib\u00e1znak \u00e9s lust\u00e1k. De az automatiz\u00e1l\u00e1st is emberek v\u00e9gzik. Ez\u00e9rt ugyanezek a probl\u00e9m\u00e1k az automatiz\u00e1l\u00e1sra is vonatkoznak.<\/p>\n<ul>\n<li>Az automatiz\u00e1l\u00e1s k\u00f6lts\u00e9ges. Eml\u00e9kezz vissza a munkaer\u0151ig\u00e9ny grafikonra.<\/li>\n<li>Automatiz\u00e1l\u00e1skor az emberek hib\u00e1znak.<\/li>\n<li>N\u00e9ha nagyon lusta az automatiz\u00e1l\u00e1s, mert am\u00fagy is j\u00f3l m\u0171k\u00f6dik minden. Mi\u00e9rt kellene tov\u00e1bb jav\u00edtani, mi\u00e9rt mindez a Folyamatos Integr\u00e1ci\u00f3?<\/li>\n<\/ul>\n<p>\nDe van egy statisztik\u00e1m: a buildjeink 20%-\u00e1ban hib\u00e1k \u00fctnek fel. Ez nem az\u00e9rt t\u00f6rt\u00e9nik, mert a fejleszt\u0151ink rosszul \u00edrj\u00e1k a k\u00f3dot. Az\u00e9rt t\u00f6rt\u00e9nik, mert a fejleszt\u0151k biztosak abban, hogy ha hib\u00e1t k\u00f6vetnek el, az nem ker\u00fcl a develop-ba, hanem az automatiz\u00e1lt ellen\u0151rz\u00e9sek elkapj\u00e1k. Ennek megfelel\u0151en a fejleszt\u0151k t\u00f6bb id\u0151t t\u00f6lthetnek a k\u00f3d \u00edr\u00e1s\u00e1val \u00e9s \u00e9rdekes dolgokkal, nem pedig azzal, hogy helyben futtassanak valamit \u00e9s ellen\u0151rizz\u00e9k.<\/p>\n<p><strong>Foglalkozz a Folyamatos Integr\u00e1ci\u00f3val. De m\u00e9rt\u00e9kkel.<\/strong><\/p>\n<blockquote><p>Egy\u00e9bk\u00e9nt Nyikol\u00e1j Nyeztyerov nemcsak remek el\u0151ad\u00e1sokat tart, hanem a programbizotts\u00e1g tagja is, <noindex><a rel=\"nofollow\" href=\"https:\/\/appsconf.ru\/moscow\/2019\">AppsConf<\/a><\/noindex> \u00e9s seg\u00edt m\u00e1soknak tartalmas el\u0151ad\u00e1sokat k\u00e9sz\u00edteni neked. A legut\u00f3bbi konferencia programj\u00e1nak teljess\u00e9g\u00e9t \u00e9s hasznoss\u00e1g\u00e1t a <noindex><a rel=\"nofollow\" href=\"https:\/\/appsconf.ru\/moscow\/2019\/schedule\">menetrendben<\/a><\/noindex>. A r\u00e9szletek\u00e9rt gyere el \u00e1prilis 22-23-\u00e1n az Infopr\u00f3t\u00e9rbe.<\/p><\/blockquote>\n<p>Forr\u00e1s: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/oleg-bunin\/blog\/447608\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0421\u0435\u0433\u043e\u0434\u043d\u044f \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u044b\u0445 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u043e\u0432 \u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0432 \u043a\u043e\u043c\u0430\u043d\u0434\u0430\u0445. \u0423\u0441\u043b\u043e\u0432\u0438\u044f \u0443\u0441\u043f\u0435\u0445\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u043e\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0432 \u0432\u0438\u0434\u0435 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0441\u0445\u0435\u043c\u044b. \u041d\u0430\u043f\u0438\u0441\u0430\u0432 \u043a\u043e\u0434, \u0432\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u043e\u043d: \u0420\u0430\u0431\u043e\u0442\u0430\u0435\u0442. \u041d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u043b\u043e\u043c\u0430\u0435\u0442, \u0432 \u0442\u043e\u043c \u0447\u0438\u0441\u043b\u0435 \u043a\u043e\u0434, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0430\u043f\u0438\u0441\u0430\u043b\u0438 \u0432\u0430\u0448\u0438 \u043a\u043e\u043b\u043b\u0435\u0433\u0438. \u0415\u0441\u043b\u0438 \u043e\u0431\u0430 \u0443\u0441\u043b\u043e\u0432\u0438\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442\u0441\u044f, \u0442\u043e \u0432\u044b \u043d\u0430 \u043f\u0443\u0442\u0438 \u043a \u0443\u0441\u043f\u0435\u0445\u0443. \u0427\u0442\u043e\u0431\u044b \u043b\u0435\u0433\u043a\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u044d\u0442\u0438 \u0443\u0441\u043b\u043e\u0432\u0438\u044f \u0438 \u043d\u0435 \u0441\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0442\u044c \u0441 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":23270,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-31304","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.3 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u0421\u0435\u0433\u043e\u0434\u043d\u044f \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u044b\u0445 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u043e\u0432 \u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0432 \u043a\u043e\u043c\u0430\u043d\u0434\u0430\u0445.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/hu\/blog\/administrirovanie\/evolyutsiya-ci-v-komande-mobilnoj-razrabotki\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.3\" \/>\n\t\t<meta property=\"og:locale\" content=\"hu_HU\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u042d\u0432\u043e\u043b\u044e\u0446\u0438\u044f CI \u0432 \u043a\u043e\u043c\u0430\u043d\u0434\u0435 \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0421\u0435\u0433\u043e\u0434\u043d\u044f \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u044b\u0445 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u043e\u0432 \u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0432 \u043a\u043e\u043c\u0430\u043d\u0434\u0430\u0445.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/hu\/blog\/administrirovanie\/evolyutsiya-ci-v-komande-mobilnoj-razrabotki\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-31T18:40:34+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T18:40:34+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47A CI evol\u00faci\u00f3ja a mobilfejleszt\u0151 csapatban | ProHoster","description":"Ma a legt\u00f6bb szoftverterm\u00e9k csapatokban k\u00e9sz\u00fcl.","canonical_url":"https:\/\/prohoster.info\/hu\/blog\/administrirovanie\/evolyutsiya-ci-v-komande-mobilnoj-razrabotki","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"hu_HU","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u042d\u0432\u043e\u043b\u044e\u0446\u0438\u044f CI \u0432 \u043a\u043e\u043c\u0430\u043d\u0434\u0435 \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 | ProHoster","og:description":"\u0421\u0435\u0433\u043e\u0434\u043d\u044f \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u044b\u0445 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u043e\u0432 \u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0432 \u043a\u043e\u043c\u0430\u043d\u0434\u0430\u0445.","og:url":"https:\/\/prohoster.info\/hu\/blog\/administrirovanie\/evolyutsiya-ci-v-komande-mobilnoj-razrabotki","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-10-31T18:40:34+00:00","article:modified_time":"2019-10-31T18:40:34+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"31304","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-21 05:30:21","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 03:19:49","updated":"2026-01-21 05:30:21","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/hu\/wp-json\/wp\/v2\/posts\/31304","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/hu\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/hu\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/hu\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/hu\/wp-json\/wp\/v2\/comments?post=31304"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/hu\/wp-json\/wp\/v2\/posts\/31304\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/hu\/wp-json\/wp\/v2\/media\/23270"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/hu\/wp-json\/wp\/v2\/media?parent=31304"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/hu\/wp-json\/wp\/v2\/categories?post=31304"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/hu\/wp-json\/wp\/v2\/tags?post=31304"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}