Эвалюцыя CI у камандзе мабільнай распрацоўкі

Сёння большасць праграмных прадуктаў распрацоўваюцца ў камандах. Умовы поспеху каманднай распрацоўкі можна прадставіць у выглядзе простай схемы.

Эвалюцыя CI у камандзе мабільнай распрацоўкі

Напісаўшы код, вы павінны пераканацца, што ён:

  1. Працуе.
  2. Нічога не ламае, у тым ліку код, які напісалі вашыя калегі.

Калі абедзве ўмовы выконваюцца, то вы на шляху да поспеху. Каб лёгка правяраць гэтыя ўмовы і не згортваць з выгоднага шляху, прыдумалі Continuous Integration.

CI - гэта працоўны працэс, пры якім вы як мага часцей інтэгруеце свой код у агульны код прадукта. І не проста інтэгруецеся, а яшчэ і ўвесь час правяраеце, што ўсё працуе. Бо правяраць трэба шмат і часта, варта задумацца аб аўтаматызацыі. Можна ўсё правяраць на ручной цязе, але не варта, і вось чаму.

  • Людзі дарагія. Гадзіна працы любога праграміста каштуе даражэй, чым гадзіна працы любога сервера.
  • Людзі памыляюцца. Таму могуць узнікнуць сітуацыі, калі запусцілі тэсты не на той галінцы або сабралі не той коміт для тэсціроўшчыкаў.
  • Людзі лянуюцца. Перыядычна, калі я заканчваю якую-небудзь задачу, у мяне ўзнікае думка: «Ды што тут правяраць? Я напісаў два радкі — стопудава ўсё працуе!» Думаю, некаторым з вас такія думкі таксама часам прыходзяць у галаву. Але правяраць трэба заўжды.

Як укаранялі і развівалі Continuous Integration у камандзе мабільнай распрацоўкі Авіта, як дайшлі ад 0 да 450 зборак у дзень, і што білд-машыны збіраюць 200 гадзін у дзень, распавядае Мікалай Несцераў (nnesterov) - удзельнік усіх эвалюцыйных зменаў CI/CD Android-прыкладанні.

Аповяд пабудаваны на прыкладзе Android-каманды, але большасць падыходаў дастасавальныя і на iOS таксама.


Калісьці даўно ў Android-камандзе Авіта працаваў адзін чалавек. Яму па азначэнні нічога з Continuous Integration было не трэба: інтэгравацца няма з кім.

Але дадатак расло, з'яўлялася ўсё больш і больш новых задач, адпаведна, расла каманда. У нейкі момант прыйшоў час больш фармальна наладзіць працэс інтэграцыі кода. Было вырашана выкарыстоўваць Git flow.

Эвалюцыя CI у камандзе мабільнай распрацоўкі

Канцэпцыя Git flow вядомая: у праекце ёсць адна агульная галіна develop, а для кожнай новай фічы распрацоўнікі зразаюць асобную галінку, камяцяць у яе, пушаць, і, калі жадаюць уліць свой код у галінку develop, адчыняюць pull request. Для абмену ведамі і абмеркавання падыходаў мы ўвялі code review, гэта значыць калегі павінны праверыць і пацвердзіць код адно аднаго.

Праверкі

Глядзець код вачыма - гэта крута, але недастаткова. Таму ўводзяцца аўтаматычныя праверкі.

  • Перш за ўсё правяраем зборку АРК.
  • шмат Junit-тэстаў.
  • Лічым code coverage, раз ужо запускаем тэсты.

Каб зразумець, як трэба запускаць гэтыя праверкі, паглядзім на працэс распрацоўкі ў Авіта.

Схематычна яго можна ўявіць так:

  • Распрацоўнік піша код на сваім ноўтбуку. Можна запусціць праверкі інтэграцыі прама тут - альбо комміт-хукам, альбо проста ганяць праверкі ў фоне.
  • Пасля таго, як распрацоўнік запушыў код, ён адчыняе pull request. Каб яго код патрапіў у галінку develop, неабходна мінуць code review і сабраць патрэбную колькасць пацверджанняў. Можна ўключыць праверкі і білды тут: пакуль не ўсе білды паспяховыя, pull request зліць нельга.
  • Пасля таго, як pull request зліты і код патрапіў у develop, можна абраць зручны час: напрыклад, уначы, калі ўсе серверы вольныя, і ганяць праверкі колькі ўлезе.

Запускаць праверкі на сваім наўтбуку нікому не спадабалася. Калі распрацоўшчык скончыў фічу, ён хоча барзджэй яе запушыць і адкрыць pull request. Калі ў гэты момант запускаюцца нейкія доўгія праверкі, гэта не толькі не вельмі прыемна, але і запавольвае распрацоўку: пакуль наўтбук нешта правярае, на ім немагчыма нармальна працаваць.

Запускаць праверкі ноччу нам вельмі спадабалася, таму што часу і сервераў шмат, можна разгуляцца. Але, нажаль, калі код фічы патрапіў у develop, у распрацоўніка ўжо значна менш матывацыі правіць памылкі, якія знайшоў CI. Я перыядычна лавіў сябе на думцы, калі глядзеў у ранішняй справаздачы на ​​ўсе знойдзеныя памылкі, што папраўлю іх калі-небудзь пазней, таму што цяпер у Jira ляжыць крутая новая задача, якую так і жадаецца пачаць рабіць.

Калі праверкі блакуюць pull request, то матывацыі дастаткова, таму што пакуль білды не пазелянеюць, код не трапіць у develop, а, значыць, задача не будзе завершана.

У выніку мы абралі такую ​​стратэгію: уначы ганяем максімальна магчымы набор праверак, а самыя крытычныя з іх і, самае галоўнае хуткія, запускаем на pull request. Але на гэтым не спыняемся - паралельна аптымізуем хуткасць праходжання праверак так, каб перавесці іх з начнога рэжыму ў праверкі на pull request.

На той момант усе нашы зборкі праходзілі досыць хутка, таму мы проста ўлучылі блокерам да pull request зборку АРК, Junit-тэсты і разлік code coverage. Уключылі, падумалі і адмовіліся ад code coverage, таму што палічылі, што ён нам не патрэбны.

На ўсю наладу базавага CI у нас сышло два дні (тут і далей часавая ацэнка прыкладная, патрэбная для маштабу).

Пасля гэтага сталі думаць далей - а ці правільна мы наогул правяраем? Ці правільна мы запускаем білды на pull request?

Мы запускалі зборку на апошнім коміце галінкі, з якой адчынены pull request. Але праверкі гэтага комміта могуць паказаць толькі тое, што той код, які напісаў распрацоўшчык, працуе. Але яны не даказваюць, што ён нічога не зламаў. Насамрэч трэба правяраць стан галінкі develop пасля таго, як у яе будзе ўліта фіча.

Эвалюцыя CI у камандзе мабільнай распрацоўкі

Для гэтага мы напісалі просты bash-скрыпт premerge.sh:

#!/usr/bin/env bash

set -e

git fetch origin develop

git merge origin/develop

Тут проста падцягваюцца ўсе самыя свежыя змены з develop і ўліваюцца ў бягучую галінку. Мы дадалі скрыпт premerge.sh першым крокам усіх білдаў і сталі правяраць менавіта тое, што мы жадаем, гэта значыць інтэграцыю.

На лакалізацыю праблемы, пошук рашэння і напісанне гэтага скрыпту спатрэбілася тры дні.

Прыкладанне развівалася, задач з'яўлялася ўсё больш, расла каманда, і premerge.sh часам пачаў нас падводзіць. У develop пранікалі канфліктуючыя змены, якія ламалі зборку.

Прыклад таго, як гэта адбываецца:

Эвалюцыя CI у камандзе мабільнай распрацоўкі

Два распрацоўніка адначасова пачынаюць пілаваць фічы A і B. Распрацоўнік фічы A выяўляе ў праекце невыкарыстоўваную функцыю answer() і, як добры байскаўт, выдаляе яе. Пры гэтым распрацоўнік фічы B у сваёй галінцы дадае новы выклік гэтай функцыі.

Распрацоўнікі сканчаюць працу і ў адзін і той жа час адчыняюць pull request. Запускаюцца білды, premerge.sh правярае абодва pull request адносна свежага стану develop - усе праверкі зялёныя. Пасля гэтага здаецца pull request фічы A, знікае pull request фічы B… Бум! Develop ламаецца, таму што ў кодзе develop ёсць выклік неіснуючай функцыі.

Эвалюцыя CI у камандзе мабільнай распрацоўкі

Калі не збіраецца develop, гэта лакальная катастрофа. Уся каманда нічога не можа сабраць і аддаць на тэсціраванне.

Так атрымалася, што я найчасцей займаўся інфраструктурнымі задачамі: аналітыка, сетка, базы дадзеных. Гэта значыць, менавіта я пісаў тыя функцыі і класы, якія выкарыстоўваюць іншыя распрацоўшчыкі. З-за гэтага я вельмі часта пападаў у падобныя сітуацыі. У мяне нават адзін час вісела такая карцінка.

Эвалюцыя CI у камандзе мабільнай распрацоўкі

Паколькі гэта нас не задавальняла, мы пачалі прапрацоўваць варыянты, як гэта прадухіліць.

Як не ламаць develop

Першы варыянт: перазбіраць усе pull request пры абнаўленні develop. Калі ў нашым прыкладзе pull request з фічай A першы патрапіць у develop, pull request фічы B перазбярэцца, і, адпаведна, праверкі не пройдуць з-за памылкі кампіляцыі.

Каб зразумець, колькі часу на гэта спатрэбіцца, разгледзім прыклад з двума PR. Адкрываем два PR: два білды, два запускі праверак. Пасля таго, як першы PR уліты ў develop, другі трэба перасабраць. Разам, на два PR сыходзіць тры запуску праверак: 2 + 1 = 3.

У прынцыпе, нармальна. Але мы паглядзелі статыстыку, і тыповай сітуацыяй у нашай камандзе было 10 адкрытых PR, а тады колькасць праверак - гэта сума прагрэсіі: 10 + 9 + ... + 1 = 55. Гэта значыць каб прыняць 10 PR, трэба перасабраць 55 разоў. І гэта ў ідэальнай сітуацыі, калі ўсе праверкі праходзяць з першага разу, калі ніхто не адчыняе дадатковы pull request, пакуль апрацоўваецца гэты дзясятак.

Уявіце сябе распрацоўшчыкам, якому трэба паспець націснуць на кнопку "merge" першым, таму што калі гэта зробіць сусед, то давядзецца чакаць, пакуль усе зборкі пройдуць зноўку… Не, так не пойдзе, гэта сур'ёзна запаволіць распрацоўку.

Другі магчымы спосаб: збіраць pull request пасля code review. Гэта значыць адкрываеце pull request, збіраеце патрэбную колькасць апрувоў ад калег, выпраўляеце што трэба, пасля гэтага запускаеце білды. Калі яны паспяховыя, pull request зліваецца з develop. У гэтым выпадку дадатковых перазапускаў няма, але моцна запавольваецца зваротная сувязь. Я, як распрацоўшчык, адчыняючы pull request, адразу жадаю бачыць, ці збіраецца ён. Напрыклад, калі зваліўся нейкі тэст, трэба яго хутка паправіць. У выпадку адкладзенай зборкі запавольваецца зваротная сувязь, а значыць, і ўся распрацоўка. Нас гэта таксама не задавальняла.

У выніку застаўся толькі трэці варыянт. раварыць. Увесь наш код, усе нашы зыходнікі захоўваюцца ў рэпазітары ў Bitbucket-серверы. Адпаведна, нам прыйшлося распрацаваць убудову для Bitbucket.

Эвалюцыя CI у камандзе мабільнай распрацоўкі

Гэты плягін перавызначае механізм зліцця pull request'аў. Пачатак стандартны: адчыняецца PR, запускаюцца ўсе зборкі, праходзіць code review. Але пасля таго, як code review пройдзены, і распрацоўнік вырашае націснуць на "merge", убудова правярае, адносна якога стану develop запускаліся праверкі. Калі пасля білдаў develop паспеў абнавіцца, убудова не дазволіць уліць такі pull request у асноўную галінку. Ён проста перазапусціць білды адносна свежага develop.

Эвалюцыя CI у камандзе мабільнай распрацоўкі

У нашым прыкладзе з канфліктуючымі зменамі такія білды не пройдуць з-за памылкі кампіляцыі. Адпаведна, распрацоўніку фічы B прыйдзецца паправіць код, перазапусціць праверкі, тады плягін аўтаматычна прыменіць pull request.

Да ўкаранення гэтага плагіна ў нас у сярэднім было 2,7 запуску праверкі на адзін pull request. З убудовай стала 3,6 запуску. Нас гэта задаволіла.

Варта адзначыць, што ў гэтага плагіна ёсць недахоп: ён перазапускае білд толькі адзін раз. Гэта значыць усё роўна застаецца маленькае акенца, праз якое ў develop могуць патрапіць канфліктуючыя змены. Але верагоднасць гэтага невысокая, і мы пайшлі на гэты кампраміс паміж колькасцю запускаў і верагоднасцю паломкі. За два гады стрэліла толькі адзін раз, таму, напэўна, не дарма.

На напісанне першай версіі плагіна для Bitbucket у нас сышло два тыдні.

Новыя праверкі

Тым часам, наша каманда працягвала расці. Дадаваліся новыя праверкі.

Мы падумалі: навошта правіць памылкі, калі іх можна прадухіляць? І таму ўкаранілі статычны аналіз кода. Пачалі з lint, які ўваходзіць у Android SDK. Але ён у той час зусім не ўмеў працаваць з Kotlin-кодам, а ў нас ужо 75% прыкладанні было напісана на Kotlin. Таму да lint дадаліся ўбудаваныя Android Studio checks.

Для гэтага прыйшлося моцна перакруціцца: узяць Android Studio, запакаваць яе ў Docker і запускаць на CI з віртуальным маніторам, каб яна думала, што запушчана на рэальным наўтбуку. Але гэта працавала.

Таксама ў гэты час мы пачалі пісаць шмат instrumentation тэстаў і ўкаранілі скрыншотнае тэсціраванне. Гэта калі генеруецца эталонны скрыншот для асобнай маленькай люхты, а тэст складаецца ў тым, што з люшка здымаецца скрыншот і параўноўваецца з эталонам прама папіксэльна. Калі ёсць разыходжанне, значыць, недзе паехала вёрстка ці нешта не так у стылях.

Але instrumentation тэсты і скрыншотныя тэсты трэба запускаць на прыладах: на эмулятарах ці на рэальных дэвайсах. Улічваючы, што тэстаў шмат, і яны ганяюцца часта, патрэбна цэлая ферма. Заводзіць сваю ферму занадта працаёмка, таму мы знайшлі гатовы варыянт – Firebase Test Lab.

Firebase Test Lab

Быў абраны, таму што Firebase – прадукт Google, гэта значыць павінен быць надзейным і ці наўрад калі-небудзь памрэ. Кошты дэмакратычныя: 5 $ за гадзіну працы рэальнай прылады, 1 $ за гадзіну працы эмулятара.

На ўкараненне Firebase Test Lab у наш CI сышло прыкладна тры тыдні.

Але каманда працягвала расці, і Firebase нас, нажаль, пачаў падводзіць. На той момант у яго не было ніякага SLA. Часам Firebase прымушаў чакаць, пакуль вызваліцца патрэбная колькасць дэвайсаў для тэстаў, а не пачынаў іх выконваць тут жа, як мы гэтага хацелі. Чаканне ў чарзе займала да паўгадзіны, а гэта вельмі доўга. Instrumentation тэсты ганяліся на кожным PR, затрымкі вельмі запавольвалі распрацоўку, а потым яшчэ прыйшоў рахунак за месяц з круглай сумай. Увогуле, вырашана было адмовіцца ад Firebase і пілаваць in-house, раз ужо каманда дастаткова вырасла.

Docker + Python + bash

Узялі docker, запхнулі ў яго эмулятары, напісалі простую праграму на Python, якая ў патрэбны момант паднімае патрэбную колькасць эмулятараў у патрэбнай версіі а калі трэба іх спыняе. І, вядома, пару bash-скрыптоў - куды ж без іх?

На стварэнне ўласнага тэставага асяроддзя спатрэбілася пяць тыдняў.

У выніку на кожны pull request прыходзіўся шырокі, блакавальны зліццё, спіс праверак:

  • Зборка АРК;
  • Junit-тэсты;
  • Lint;
  • Android Studio checks;
  • Instrumentation тэсты;
  • Screenshot тэсты.

Гэта прадухіляла шмат магчымых паломак. Тэхнічна ўсё працавала, але распрацоўшчыкі скардзіліся, што чакаць вынікаў занадта доўга.

Занадта доўга - гэта колькі? Мы выгрузілі дадзеныя з Bitbucket і TeamCity у сістэму аналізу і зразумелі, што сярэдні час чакання 45 хвілін. Гэта значыць распрацоўшчык, адчыняючы pull request у сярэднім чакае вынікі білдаў 45 хвілін. На маю думку, гэта вельмі шмат, і так працаваць нельга.

Вядома, мы вырашылі паскорыць усе нашыя білды.

Паскараемся

Убачыўшы, што часта білды стаяць у чарзе, мы перш за ўсё дакупілі жалеза - Экстэнсіўнае развіццё самае простае. Білды перасталі стаяць у чарзе, але час чакання знізіўся толькі крыху, таму што некаторыя праверкі самі па сабе ганяліся вельмі доўга.

Прыбіраны занадта доўгія праверкі

Наш Continuous Integration мог адлавіць такія тыпы памылак і праблем.

  • Не збіраецца. CI можа злавіць памылку кампіляцыі, калі з-за канфліктуючых зменаў нешта не збіраецца. Як я ўжо казаў, тады ніхто нічога не можа сабраць, распрацоўка ўстае, і ўсё нярвуюцца.
  • Баг у паводзінах. Напрыклад, калі дадатак збіраецца, але пры націску на кнопку падае, ці кнопка наогул не націскаецца. Гэта дрэнна, таму што такі баг можа дабрацца да карыстальніка.
  • Баг у вёрстцы. Напрыклад, кнопка націскаецца, але з'ехала на 10 пікселяў налева.
  • Павелічэнне тэхдоўгу.

Паглядзеўшы на гэты спіс, мы зразумелі, што крытычнымі з'яўляюцца толькі першыя два пункты. Такія праблемы мы жадаем адлоўліваць у першую чаргу. Багі ў вёрстцы выяўляюцца на этапе design-review і тады ж лёгка выпраўляюцца. Праца з тэхдоўгам патрабуе асобнага працэсу і планавання, таму мы вырашылі не правяраць яго на pull request.

Зыходзячы з гэтай класіфікацыі, мы ператрэслі ўвесь спіс праверак. Выкраслілі Lint і перанеслі яго запуск на ноч: проста каб ён выдаваў справаздачу, колькі праблем у праекце. З тэхдоўгам мы дамовіліся працаваць асобна, а ад Android Studio checks адмовіліся зусім. Android Studio у Docker для запуску інспекцый гучыць цікава, але дастаўляе шмат непрыемнасцяў у падтрымцы. Любое абнаўленне версій Android Studio - гэта барацьба з незразумелымі багамі. Таксама складана было падтрымліваць скрыншотныя тэсты, таму што бібліятэка працавала не вельмі стабільна, бывалі ілжывыя спрацоўванні. Скрыншотныя тэсты прыбралі са спісу праверак.

У выніку ў нас засталіся:

  • Зборка АРК;
  • Junit-тэсты;
  • Instrumentation tests.

Gradle remote cache

Без цяжкіх праверак усё стала лепей. Але няма мяжы дасканаласці!

Наша дадатак ўжо было разбіта на прыкладна 150 gradle модуляў. Звычайна ў такім разе добра працуе Gradle remote cache, і мы вырашылі яго паспрабаваць.

Gradle remote cache - гэта сэрвіс, які можа кэшаваць артэфакты зборкі для асобных задач у асобных модулях. Gradle, замест таго каб рэальна кампіляваць код, па HTTP стукаецца ў remote cache і пытаецца, ці выконваў хтосьці ўжо гэтую цягу. Калі так, проста спампоўвае вынік.

Запусціць Gradle remote cache лёгка, таму што Gradle дае Docker-выява. Нам удалося гэта зрабіць за тры гадзіны.

Усяго-то трэба было запусціць Docker і прапісаць адзін радок у праекце. Але хоць запусціць яго можна хутка, каб усё працавала добра, спатрэбіцца дастаткова шмат часу.

Ніжэй графік cache misses.

Эвалюцыя CI у камандзе мабільнай распрацоўкі

У самым пачатку працэнт промахаў міма кэша быў каля 65. Праз тры тыдні ўдалося давесці гэтае значэнне да 20%. Аказалася, што цягі, якія збірае Android дадатак, маюць дзіўныя транзітыўныя залежнасці, з-за якіх Gradle прамахваўся міма кэша.

Падлучыўшы кэш, мы моцна паскорылі зборку. Але акрамя зборкі яшчэ ганяюцца instrumentation тэсты, а ганяюцца яны доўга. Магчыма, ня ўсе тэсты трэба ганяць на кожны pull request. Каб гэта высветліць, выкарыстоўваем імпакт аналіз.

Імпакт аналіз

На pull request мы збіраем git diff і знаходзім змененыя модулі Gradle.

Эвалюцыя CI у камандзе мабільнай распрацоўкі

Мае сэнс запускаць толькі тыя instrumentation тэсты, якія правяраюць змененыя модулі і ўсе модулі, якія ад іх залежаць. Тэсты для суседніх модуляў запускаць сэнсу няма: тамака не змяніўся код, і нічога не можа зламацца.

З instrumentation тэстамі не ўсё так проста, таму што яны павінны знаходзіцца ў самым верхнеўзроўневым модулі Application. Мы ўжылі эўрыстыкі з аналізам байт-кода, каб зразумець, да якога модулю адносіцца кожны тэст.

Мадэрнізацыя працы instrumentation тэстаў, каб яны правяралі толькі задзейнічаныя модулі, заняла каля васьмі тыдняў.

Меры па паскарэнні праверак паспяхова спрацавалі. З 45 хвілін мы дайшлі прыкладна да 15. Чвэрць гадзіны чакаць білд ужо нармальна.

Але зараз распрацоўшчыкі пачалі скардзіцца, што ім незразумела, якія білды запускаюцца, дзе лог паглядзець, чаму білд чырвоны, які тэст упаў і г.д.

Эвалюцыя CI у камандзе мабільнай распрацоўкі

Праблемы са зваротнай сувяззю запавольваюць распрацоўку, таму мы пастараліся забяспечыць максімальна зразумелую і падрабязную інфармацыю аб кожным PR і білдзе. Пачалі з каментароў у Bitbucket да PR з указаннем, які білд упаў і чаму, пісалі адрасныя паведамленні ў Slack. У рэшце рэшт зрабілі для старонкі PR dashboard са спісам усіх білдаў, якія зараз запускаюцца і іх станам: у чарзе, запускаецца, упаў ці завяршыўся. Можна клікнуць на білд і патрапіць на яго лог.

Эвалюцыя CI у камандзе мабільнай распрацоўкі

На падрабязную зваротную сувязь было затрачана шэсць тыдняў.

Планы

Пераходзім да найноўшай гісторыі. Вырашыўшы пытанне зваротнай сувязі, мы выйшлі на новы ўзровень - вырашылі пабудаваць сваю ферму эмулятараў. Калі тэстаў і эмулятараў шмат, імі складана кіраваць. У выніку ўсе нашы эмулятары пераехалі ў k8s-кластар з гнуткім кіраваннем рэсурсаў.

Акрамя таго, ёсць і іншыя планы.

  • Вярнуць Lint (І іншы статычны аналіз). Мы ўжо працуем у гэтым напрамку.
  • Запускаць на PR блокерам усё end-to-end тэсты на ўсіх версіях SDK.

Такім чынам, мы прасачылі гісторыю развіцця Continuous Integration у Авіта. Цяпер хачу даць некалькі парадаў з пункту гледжання бывалага.

Саветы

Калі б я мог даць толькі адну параду, гэта была б гэтая:

Калі ласка, будзьце асцярожней з shell-скрыптамі!

Bash — вельмі гнуткая і магутная прылада, на ім вельмі зручна і хутка пісаць скрыпты. Але з ім можна патрапіць у пастку, і мы, нажаль, у яе патрапілі.

Пачыналася ўсё з простых скрыптоў, якія запускаліся на нашых білд-машынах:

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

Але, як вядома, усё з часам развіваецца і ўскладняецца - давайце запусцім адзін скрыпт з іншага, давайце перададзім туды нейкія параметры - у выніку прыйшлося напісаць функцыю, якая вызначае, на якім узроўні ўкладзенасці bash мы зараз знаходзімся, каб падставіць патрэбныя двукоссі, каб гэта ўсё запусцілася.

Эвалюцыя CI у камандзе мабільнай распрацоўкі

Можаце ўявіць сабе працавыдаткі на развіццё такіх скрыптоў. Раю не пападаць у гэтую пастку.

Чым можна замяніць?

  • Любой скрыптовай мовай. Пісаць на Python або Kotlin Script зручней, таму што гэта праграмаванне, а не скрыпты.
  • Або апісаць усю логіку білдаў у выглядзе Custom gradle tasks для вашага праекта.

Мы вырашылі абраць другі варыянт, і зараз планамерна выдаляем усе bash-скрыпты і пішам шмат кастамных gradle-тасок.

Савет №2: захоўваць інфраструктуру ў кодзе.

Зручна, калі настройка Continuous Integration захоўваецца не ў UI-інтэрфейсе Jenkins або TeamCity і да т.п., а ў выглядзе тэкставых файлаў прама ў рэпазітары праекта. Гэта дае версіянальнасць. Будзе не цяжка адкаціцца або сабраць код на іншай галінцы.

Скрыпты можна захоўваць у праекце. А што рабіць з асяроддзем?

Савет №3: з асяроддзем можа дапамагчы Docker.

Android-распрацоўнікам ён сапраўды дапаможа, iOS пакуль няма, нажаль.

Гэта прыклад простага docker-файла, які змяшчае jdk і android-sdk:

FROM openjdk:8

ENV SDK_URL="https://dl.google.com/android/repository/sdk-tools-linux-3859397.zip" 
    ANDROID_HOME="/usr/local/android-sdk" 
    ANDROID_VERSION=26 
    ANDROID_BUILD_TOOLS_VERSION=26.0.2

# Download Android SDK
RUN mkdir "$ANDROID_HOME" .android 
    && cd "$ANDROID_HOME" 
    && curl -o sdk.zip $SDK_URL 
    && unzip sdk.zip 
    && rm sdk.zip 
    && yes | $ANDROID_HOME/tools/bin/sdkmanager --licenses

# Install Android Build Tool and Libraries
RUN $ANDROID_HOME/tools/bin/sdkmanager --update
RUN $ANDROID_HOME/tools/bin/sdkmanager "build-tools;${ANDROID_BUILD_TOOLS_VERSION}" 
    "platforms;android-${ANDROID_VERSION}" 
    "platform-tools"

RUN mkdir /application
WORKDIR /application

Напісаўшы гэты docker-файл (скажу па сакрэце, яго можна не пісаць, а сцягнуць гатовы з GitHub) і сабраўшы выяву, вы атрымліваеце віртуальную машыну, на якой зможаце збіраць прыкладанне і запускаць Junit-тэсты.

Два галоўныя аргументы, чаму гэта мае сэнс: маштабаванасць і паўтаральнасць. З выкарыстаннем docker можна хутка падняць дзясятак білд-агентаў, якія будуць мець сапраўды такое ж асяроддзе, як і ранейшы. Гэта вельмі палягчае жыццё CI-інжынераў. Запіхнуць android-sdk у docker зусім проста, з эмулятарамі ледзь складаней: прыйдзецца крыху паднапружыцца (ну, ці зноў з GitHub спампаваць гатовае).

Савет №4: не забывацца, што праверкі робяцца не дзеля праверак, а для людзей.

Распрацоўнікам вельмі важная хуткая і, самае галоўнае, зразумелая зваротная сувязь: што ў іх зламалася, які тэст упаў, дзе білдлог паглядзець.

Савет №5: будзьце прагматычныя пры развіцці Continuous Integration.

Выразна разумейце, якія тыпы памылак жадаеце прадухіліць, колькі гатовыя выдаткаваць рэсурсаў, чакай, машыннага часу. Занадта доўгія праверкі можна, напрыклад, перанесці на ноч. А ад тых з іх, якія ловяць не надта важныя памылкі, зусім адмовіцца.

Савет №6: карыстайцеся гатовымі інструментамі.

Цяпер ёсць шмат кампаній, якія падаюць хмарны CI.

Эвалюцыя CI у камандзе мабільнай распрацоўкі

Для маленькіх каманд гэта добрае выйсце. Не трэба нічога падтрымліваць, проста плаціце крыху грошай, збіраеце сваё прыкладанне і нават ганяеце instrumentation tests.

Савет №7: у вялікай камандзе больш выгадна in-house рашэння.

Але рана ці позна, з ростам каманды стануць больш выгаднымі in-house рашэнні. З гэтымі рашэннямі ёсць адзін момант. У эканоміцы ёсць закон змяншальнай аддачы: у любым праекце кожнае наступнае паляпшэнне даецца ўсё цяжэй, патрабуе ўсё больш і больш інвестыцый.

Эканоміка апісвае ўсё нашае жыццё, у тым ліку Continuous Integration. Я пабудаваў графік працавыдаткаў на кожны этап развіцця нашага Continuous Integration.

Эвалюцыя CI у камандзе мабільнай распрацоўкі

Відаць, што любое паляпшэнне даецца ўсё цяжэй і цяжэй. Гледзячы на ​​гэты графік, можна зразумець, што развіваць Continuous Integration трэба ўзгоднена з ростам памеру каманды. Для каманды з двух чалавек марнаваць 50 дзён на распрацоўку ўнутранай фермы эмулятараў – так сабе ідэя. Але пры гэтым для вялікай каманды зусім не займацца Continuous Integration – таксама дрэнная ідэя, таму што на праблемы інтэграцыі, папраўку камунікацыі і да т.п. спатрэбіцца яшчэ больш часу.

Мы пачалі з таго, што аўтаматызацыя патрэбная, таму што людзі дарагія, яны памыляюцца і лянуюцца. Але аўтаматызуюць таксама людзі. Таму ўсе гэтыя ж праблемы адносяцца і да аўтаматызацыі.

  • Аўтаматызаваць дорага. Успомніце графік працавыдаткаў.
  • Пры аўтаматызацыі людзі памыляюцца.
  • Аўтаматызаваць часам вельмі лянота, таму што і так усё працуе. Навошта яшчэ нешта паляпшаць, навошта ўвесь гэты Continuous Integration?

Але ў мяне ёсьць статыстыка: у 20% зборак ловяцца памылкі. І гэта адбываецца не таму, што нашы распрацоўшчыкі дрэнна пішуць код. Гэта таму, што распрацоўшчыкі ўпэўненыя, што, калі яны дапусцяць нейкую памылку, яна не трапіць у develop, яе зловяць аўтаматызаваныя праверкі. Адпаведна, распрацоўшчыкі могуць марнаваць больш часу на напісанне кода і цікавыя штукі, а не лакальна нешта ганяць і правяраць.

Займайцеся Continuous Integration. Але ў меру.

Дарэчы, Мікалай Несцераў не толькі сам робіць класныя даклады, а яшчэ ўваходзіць у праграмны камітэт. AppsConf і дапамагае іншым рыхтаваць для вас змястоўныя выступы. Паўнату і карыснасць праграмы бліжэйшай канферэнцыі можна ацаніць па тэмах у раскладзе. А па падрабязнасці прыходзьце 22-23 красавіка ў Інфапрасторы.

Крыніца: habr.com

Дадаць каментар