{"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\/sq\/blog\/administrirovanie\/evolyutsiya-ci-v-komande-mobilnoj-razrabotki","title":{"rendered":"Evolucioni i CI n\u00eb ekipin e zhvillimit t\u00eb mobil\u00ebve","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Sot tani shumica e produkteve softuerike zhvillohen n\u00eb ekipe. Kushtet e suksesit t\u00eb zhvillimit n\u00eb grup mund t\u00eb paraqiten si nj\u00eb skem\u00eb e thjesht\u00eb.<\/p>\n<p><img decoding=\"async\" alt=\"Evolucioni i CI n\u00eb ekipin e zhvillimit t\u00eb mobil\u00ebve\" src=\"\/wp-content\/uploads\/2019\/04\/b283cfd7772d8f479be0754ebbe51b19.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPasi t\u00eb keni shkruar kodin, duhet t\u00eb siguroheni q\u00eb ai:<\/p>\n<ol>\n<li>Funksionon.<\/li>\n<li>Nuk prish asgj\u00eb, duke p\u00ebrfshir\u00eb kodin q\u00eb kan\u00eb shkruar koleg\u00ebt tuaj.<\/li>\n<\/ol>\n<p>\nN\u00ebse t\u00eb dy kushtet jan\u00eb plot\u00ebsuar, at\u00ebher\u00eb jeni n\u00eb rrug\u00ebn drejt suksesit. P\u00ebr t\u00eb kontrolluar leht\u00ebsisht k\u00ebto kushte dhe p\u00ebr t\u00eb mos dal\u00eb nga rruga e favorshme, u shpik Continuous Integration.<\/p>\n<p>CI \u00ebsht\u00eb nj\u00eb proces pune ku ju integroheni sa m\u00eb shpesh q\u00eb t\u00eb jet\u00eb e mundur me kodin tuaj n\u00eb kodin e p\u00ebrgjithsh\u00ebm t\u00eb produktit. Dhe jo vet\u00ebm q\u00eb integroni, por gjithashtu kontrolloni vazhdimisht q\u00eb gjith\u00e7ka funksionon. Duke pasur parasysh se duhet t\u00eb kontrolloni shum\u00eb dhe shpesh, ia vlen t\u00eb mendoni p\u00ebr automatizimin. Mund ta kontrolloni gjith\u00e7ka manualisht, por nuk ja vlen, dhe ja pse.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<ul>\n<li><strong>Njer\u00ebzit jan\u00eb t\u00eb shtrenjt\u00eb<\/strong>. Nj\u00eb or\u00eb pune e \u00e7do programuesi kushton m\u00eb shum\u00eb se nj\u00eb or\u00eb pune e \u00e7do serveri.<\/li>\n<li><strong>Njer\u00ebzit gabojn\u00eb<\/strong>. Prandaj mund t\u00eb ndodhin situata kur testet jan\u00eb ekzekutuar n\u00eb deg\u00ebn e gabuar ose \u00ebsht\u00eb grumbulluar komiti i gabuar p\u00ebr testuesit.<\/li>\n<li><strong>Njer\u00ebzit jan\u00eb t\u00eb p\u00ebrtac\u00eb<\/strong>. Her\u00eb pas here, kur p\u00ebrfundoj nj\u00eb detyr\u00eb, kam mendimin: \"\u00c7far\u00eb t\u00eb kontrolloj k\u00ebtu? Kam shkruar dy tregues \u2014 me siguri gjith\u00e7ka funksionon!\" Mendoj se disa nga ju ndoshta ndiheni k\u00ebshtu her\u00eb pas here. Por kontrolli duhet t\u00eb b\u00ebhet gjithmon\u00eb.<\/li>\n<\/ul>\n<p>\nSi u implementua dhe u zhvillua Continuous Integration n\u00eb ekipin e zhvillimit t\u00eb telefonit celular t\u00eb Avito, si kaluan nga 0 n\u00eb 450 nd\u00ebrtime n\u00eb dit\u00eb, dhe \u00e7far\u00eb nd\u00ebrtojn\u00eb makinat e nd\u00ebrtimit q\u00eb realizojn\u00eb 200 or\u00eb n\u00eb dit\u00eb, tregon Nikolai Nesterov (<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/users\/nnesterov\/\" class=\"user_link\">nnesterov<\/a><\/noindex>) \u2014 pjes\u00ebmarr\u00ebs n\u00eb t\u00eb gjitha ndryshimet evolucionare CI\/CD t\u00eb aplikacionit Android.<\/p>\n<p>Rr\u00ebfimi \u00ebsht\u00eb nd\u00ebrtuar mbi shembujt e ekipit Android, por shumica e qasjeve jan\u00eb t\u00eb aplikueshme gjithashtu n\u00eb iOS.<\/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=\"Luaj videon\" loading=\"lazy\" width=\"480\" height=\"360\" style=\"width:100%;height:auto;\">\r\n        <div class=\"play-button\"><\/div>\r\n    <\/div><\/center><br \/>\nDikur, n\u00eb ekipin Android t\u00eb Avito punonte nj\u00eb person. Po ashtu, ai sipas definicionit nuk kishte nevoj\u00eb p\u00ebr asgj\u00eb nga Continuous Integration: nuk kishte me k\u00eb t\u00eb integrohej.<\/p>\n<p>Por aplikacioni po rritej, duke u shtuar gjithnj\u00eb e m\u00eb shum\u00eb detyra, p\u00ebr pasoj\u00eb, ekipi po rritej. N\u00eb nj\u00eb moment erdhi koha p\u00ebr t\u00eb organizuar m\u00eb formalisht procesin e integrimit t\u00eb kodit. U vendos t\u00eb p\u00ebrdoret Git flow.<\/p>\n<p><img decoding=\"async\" alt=\"Evolucioni i CI n\u00eb ekipin e zhvillimit t\u00eb mobil\u00ebve\" src=\"\/wp-content\/uploads\/2019\/04\/f433effc5ab5a59de3d6bd20a7a87057.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nKoncepcioni Git flow \u00ebsht\u00eb i njohur: n\u00eb projekt ekziston nj\u00eb deg\u00eb e p\u00ebrbashk\u00ebt develop, dhe p\u00ebr \u00e7do karakteristik\u00eb t\u00eb re, zhvilluesit krijojn\u00eb nj\u00eb deg\u00eb t\u00eb ve\u00e7ant\u00eb, angazhojn\u00eb n\u00eb t\u00eb, e d\u00ebrgojn\u00eb, dhe, kur d\u00ebshirojn\u00eb t\u00eb integrojn\u00eb kodin e tyre n\u00eb deg\u00ebn develop, hapin nj\u00eb pull request. P\u00ebr t\u00eb ndar\u00eb njohuri dhe p\u00ebr t\u00eb diskutuar qasjet, ne kemi futur rishikimin e kodit, q\u00eb do t\u00eb thot\u00eb se koleg\u00ebt duhet t\u00eb verifikojn\u00eb dhe t\u00eb konfirmojn\u00eb kodin e nj\u00ebri-tjetrit.<\/p>\n<h2>Kontrollet<\/h2>\n<p>\nT\u00eb shoh\u00ebsh kodin me syt\u00eb e tua \u00ebsht\u00eb e shk\u00eblqyer, por nuk \u00ebsht\u00eb e mjaftueshme. Prandaj, futen kontrollime automatike.<\/p>\n<ul>\n<li>S\u00eb pari kontrollojm\u00eb <strong>nd\u00ebrtimin e ARC<\/strong>.<\/li>\n<li>Shum\u00eb <strong>teste Junit<\/strong>.<\/li>\n<li><strong>Llogarisim mbulimin e kodit<\/strong>, p\u00ebrderisa ne jemi duke ekzekutuar testet.<\/li>\n<\/ul>\n<p>\nP\u00ebr t\u00eb kuptuar se si duhet t\u00eb ekzekuton k\u00ebto kontrolle, do t\u00eb shohim procesin e zhvillimit n\u00eb Avito.<\/p>\n<p>N\u00eb m\u00ebnyr\u00eb skematike mund ta paraqesim k\u00ebshtu:<\/p>\n<ul>\n<li>Zhvilluesi shkruan kodin n\u00eb laptopin e tij. Mund t\u00eb ekzekutoj\u00eb kontrollime integrimi pik\u00ebrisht k\u00ebtu \u2014 ose me nj\u00eb hook komit, ose thjesht duke drejtuar kontrollet n\u00eb sfond.<\/li>\n<li>Pas q\u00eb zhvilluesi ka d\u00ebrguar kodin, ai hap nj\u00eb pull request. Q\u00eb kodi i tij t\u00eb kaloj\u00eb n\u00eb deg\u00ebn develop, \u00ebsht\u00eb e domosdoshme t\u00eb kaloj\u00eb rishikimin e kodit dhe t\u00eb mbledh\u00eb numrin e nevojsh\u00ebm t\u00eb konfirmimeve. Mund t\u00eb p\u00ebrfshijm\u00eb kontroll dhe nd\u00ebrtime k\u00ebtu: derisa t\u00eb gjitha nd\u00ebrtimet t\u00eb mos jen\u00eb t\u00eb suksesshme, pull request nuk mund t\u00eb integrohet.<\/li>\n<li>Pas q\u00eb pull request \u00ebsht\u00eb integruar dhe kodi ka shkuar n\u00eb develop, mund t\u00eb zgjedhim nj\u00eb koh\u00eb t\u00eb p\u00ebrshtatshme: p\u00ebr shembull, nat\u00ebn, kur t\u00eb gjitha serverat jan\u00eb t\u00eb lir\u00eb, dhe t\u00eb ekzekutojm\u00eb kontrollet sa m\u00eb shum\u00eb q\u00eb t\u00eb mundemi.<\/li>\n<\/ul>\n<p>\nAskush nuk e p\u00eblqeu t\u00eb ekzekutonte kontrollet n\u00eb laptopin e tij. Kur zhvilluesi p\u00ebrfundoi karakteristik\u00ebn, ai d\u00ebshiron ta d\u00ebrgoj\u00eb sa m\u00eb shpejt dhe t\u00eb hap\u00eb pull request-in. N\u00ebse n\u00eb at\u00eb moment jan\u00eb duke u ekzekutuar kontrolle t\u00eb gjata, kjo jo vet\u00ebm q\u00eb nuk \u00ebsht\u00eb e k\u00ebndshme, por gjithashtu ngadal\u00ebson zhvillimin: derisa laptopi t\u00eb kryej\u00eb di\u00e7ka, \u00ebsht\u00eb e pamundur t\u00eb punosh normalisht.<\/p>\n<p>Na p\u00eblqeu shum\u00eb t\u00eb ekzekutojm\u00eb kontrollet nat\u00ebn, sepse ka shum\u00eb koh\u00eb dhe server\u00eb, mund t\u00eb kemi hap\u00ebsir\u00eb. Por, fatkeq\u00ebsisht, kur kodi i karakteristik\u00ebs kalon n\u00eb develop, zhvilluesi tashm\u00eb ka shum\u00eb m\u00eb pak motivim p\u00ebr t\u00eb rregulluar gabimet q\u00eb CI ka gjetur. Her\u00eb pas here, gjeja se shihja n\u00eb raportin e m\u00ebngjesit p\u00ebr t\u00eb gjitha gabimet e gjetura, se do t'i rregulloja ndonj\u00ebher\u00eb m\u00eb von\u00eb, sepse tani n\u00eb Jira ka nj\u00eb detyr\u00eb t\u00eb re t\u00eb shk\u00eblqyer, t\u00eb cil\u00ebn e d\u00ebshiroj shum\u00eb ta filloj.<\/p>\n<p>N\u00ebse kontrollet bllokojn\u00eb pull request-in, at\u00ebher\u00eb motivimi \u00ebsht\u00eb mjaftuesh\u00ebm, sepse derisa nd\u00ebrtimet t\u00eb mos b\u00ebhen t\u00eb gjelbra, kodi nuk do t\u00eb kaloj\u00eb n\u00eb develop, dhe k\u00ebshtu, detyra nuk do t\u00eb p\u00ebrfundoj\u00eb.<\/p>\n<p>N\u00eb fund, ne zgjodh\u00ebm nj\u00eb strategji t\u00eb till\u00eb: nat\u00ebn ekzekutojm\u00eb numrin maksimal t\u00eb kontrollove t\u00eb mundshme, nd\u00ebrsa m\u00eb kritik\u00ebt dhe, m\u00eb e r\u00ebnd\u00ebsishmja, m\u00eb t\u00eb shpejt\u00ebt, i nisem n\u00eb pull request. Por nuk ndalemi k\u00ebtu \u2014 paralelisht optimizojm\u00eb sh brend\u00ebsin\u00eb e kontrollove p\u00ebr t\u2019i kaluar nga m\u00ebnyra nat\u00ebr n\u00eb kontrollime n\u00eb pull request.<\/p>\n<p>N\u00eb at\u00eb koh\u00eb, t\u00eb gjitha build-\u00ebt tona kalonin mjaft shpejt, prandaj thjesht ne aktivizuam si bllokues p\u00ebr pull request build-in ARK, testet Junit dhe llogaritjen e mbulimit t\u00eb kodit. Aktivizuam, menduam \u2014 dhe u ndal\u00ebm nga mbulimi i kodit, sepse e konsideruam se nuk na nevojitej.<\/p>\n<p><strong><em>P\u00ebr t\u00eb konfiguruar CI-n\u00eb bazike na duhej dy dit\u00eb (k\u00ebtu dhe m\u00eb pas vler\u00ebsimi temporal \u00ebsht\u00eb p\u00ebraf\u00ebrsisht, e nevojshme p\u00ebr shkak t\u00eb p\u00ebrmas\u00ebs). <\/em><\/strong><\/p>\n<p>Pas k\u00ebsaj, filluam t\u00eb mendojm\u00eb m\u00eb tej \u2014 a e kontrollojm\u00eb sakt\u00ebsisht? A i nis\u00ebm build-\u00ebt n\u00eb pull request?<\/p>\n<p>Ne i nis\u00ebm build-in n\u00eb commit-in m\u00eb t\u00eb fundit t\u00eb deg\u00ebs, nga e cila u hap pull request. Por kontrollimet e k\u00ebtij commit-i mund t\u00eb tregojn\u00eb vet\u00ebm at\u00eb q\u00eb kodi, q\u00eb ka shkruar zhvilluesi, funksionon. Por ato nuk provojn\u00eb se ai nuk ka prishur asgj\u00eb. N\u00eb t\u00eb v\u00ebrtet\u00eb, duhet t\u00eb kontrollojm\u00eb gjendjen e deg\u00ebs develop pasi t\u00eb jet\u00eb integruar karakteristika.<\/p>\n<p><img decoding=\"async\" alt=\"Evolucioni i CI n\u00eb ekipin e zhvillimit t\u00eb mobil\u00ebve\" src=\"\/wp-content\/uploads\/2019\/04\/c1a179b68b02c04031177f9bf51a81ed.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nP\u00ebr k\u00ebt\u00eb shkruam nj\u00eb skenar t\u00eb thjesht\u00eb bash <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>\nK\u00ebtu thjesht t\u00ebrheqim t\u00eb gjitha ndryshimet m\u00eb t\u00eb fresk\u00ebta nga develop dhe i inkuadrojm\u00eb n\u00eb deg\u00ebn aktuale. E shtuam skenarin premerge.sh si hapin e par\u00eb t\u00eb t\u00eb gjith\u00eb build-\u00ebve dhe filluam t\u00eb kontrollojm\u00eb at\u00eb q\u00eb d\u00ebshirojm\u00eb, pra <strong>integrimin<\/strong>.<\/p>\n<p><strong><em>P\u00ebr lokalizimin e problemeve, gjetjen e zgjidhjes dhe shkruajten e k\u00ebtij skenari na duhej tri dit\u00eb.<\/em><\/strong><\/p>\n<p>Aplikacioni po zhvillohej, detyrat po rriteshin gjithnj\u00eb e m\u00eb shum\u00eb, ekipi po zgjerohej, dhe premerge.sh ndonj\u00ebher\u00eb filloi t\u00eb na d\u00ebshtoj\u00eb. Ndryshime konfliktuale po dep\u00ebrtonin n\u00eb develop, t\u00eb cilat prisnin build-in.<\/p>\n<p>Nj\u00eb shembull se si ndodh kjo:<\/p>\n<p><img decoding=\"async\" alt=\"Evolucioni i CI n\u00eb ekipin e zhvillimit t\u00eb mobil\u00ebve\" src=\"\/wp-content\/uploads\/2019\/04\/6762d9ce4e431549455c49f2317a8f20.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDy zhvillues nj\u00ebkoh\u00ebsisht fillojn\u00eb t\u00eb zhvillojn\u00eb karakteristikat A dhe B. Zhvilluesi i karakteristik\u00ebs A zbulohet n\u00eb projekt nj\u00eb funksion t\u00eb pa p\u00ebrdorur <code>answer()<\/code> dhe, si nj\u00eb skaut i mir\u00eb, e fshin at\u00eb. Nd\u00ebrkoh\u00eb, zhvilluesi i karakteristik\u00ebs B n\u00eb deg\u00ebn e tij shton nj\u00eb thirrje t\u00eb re p\u00ebr k\u00ebt\u00eb funksion.<\/p>\n<p>Zhvilluesit p\u00ebrfundojn\u00eb pun\u00ebn dhe n\u00eb t\u00eb nj\u00ebjt\u00ebn koh\u00eb hapin pull request. Nisin build-et, premerge.sh kontrollon t\u00eb dy pull request-i n\u00eb lidhje me gjendjen e fresk\u00ebt t\u00eb develop \u2014 t\u00eb gjitha kontrollimet jan\u00eb t\u00eb gjelbra. Pas k\u00ebsaj, b\u00ebhet bashkimi i pull request-it t\u00eb karakteristik\u00ebs A, dhe bashkimi i pull request-it t\u00eb karakteristik\u00ebs B\u2026 Bum! Develop prishet, sepse n\u00eb kodin e develop ka nj\u00eb thirrje p\u00ebr nj\u00eb funksion q\u00eb nuk ekziston.<\/p>\n<p><img decoding=\"async\" alt=\"Evolucioni i CI n\u00eb ekipin e zhvillimit t\u00eb mobil\u00ebve\" src=\"\/wp-content\/uploads\/2019\/04\/0261dcc9f7f2e5e018ab136081b4679b.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nKur develop nuk grumbullohet, kjo <strong>katastrof\u00eb lokale<\/strong>. E gjith\u00eb ekipi nuk mund t\u00eb mbledh\u00eb asgj\u00eb dhe ta d\u00ebrgoj\u00eb p\u00ebr testim.<\/p>\n<p>Ka ndodhur q\u00eb un\u00eb shpesh merresha me detyra infrastrukturore: analitika, rrjeti, bazat e t\u00eb dh\u00ebnave. Q\u00eb do t\u00eb thot\u00eb, un\u00eb shkrova ato funksione dhe klasa q\u00eb p\u00ebrdorin zhvillues t\u00eb tjer\u00eb. Shkaku i k\u00ebsaj, un\u00eb shpesh p\u00ebrballesha me situata t\u00eb tilla. Madje, nj\u00eb koh\u00eb t\u00eb gjat\u00eb kisha nj\u00eb fotografi t\u00eb till\u00eb t\u00eb varur.<\/p>\n<p><img decoding=\"async\" alt=\"Evolucioni i CI n\u00eb ekipin e zhvillimit t\u00eb mobil\u00ebve\" src=\"\/wp-content\/uploads\/2019\/04\/0eb1aadd05b33ce995027ab52d5c1e53.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPasi ky nuk na k\u00ebnaqte, ne filluam t\u00eb shqyrtonim mund\u00ebsi p\u00ebr ta parandaluar k\u00ebt\u00eb.<\/p>\n<h2>Si t\u00eb mos e d\u00ebmtojm\u00eb develop<\/h2>\n<p>\nMund\u00ebsia e par\u00eb: <strong>t\u00eb ripaketojm\u00eb t\u00eb gjitha pull request pas p\u00ebrdit\u00ebsimit t\u00eb develop. <\/strong>N\u00eb shembullin ton\u00eb, n\u00ebse pull request me ve\u00e7orin\u00eb A i pari futet n\u00eb develop, at\u00ebher\u00eb pull request i ve\u00e7oris\u00eb B do t\u00eb ripaketohet, dhe, p\u00ebr rrjedhoj\u00eb, kontrollimet nuk do t\u00eb kalojn\u00eb p\u00ebr shkak t\u00eb gabimit t\u00eb kompilimit.<\/p>\n<p>P\u00ebr t\u00eb kuptuar se sa koh\u00eb do t\u00eb duhej p\u00ebr k\u00ebt\u00eb, le t\u00eb shqyrtojm\u00eb nj\u00eb shembull me dy PR. Hidhni nj\u00eb sy dy PR: dy nd\u00ebrtime, dy nisje kontrollesh. Pasi PR i par\u00eb \u00ebsht\u00eb i integruar n\u00eb develop, duhet t\u00eb ripaketohet i dyti. Pra, n\u00eb total, p\u00ebr dy PR ne kemi tre nisma kontrollesh: 2 + 1 = 3.<\/p>\n<p>N\u00eb p\u00ebrgjith\u00ebsi, \u00ebsht\u00eb n\u00eb rregull. Por ne e shqyrtuam statistik\u00ebn dhe situata tipike n\u00eb ekipin ton\u00eb ishte 10 PR t\u00eb hapura, dhe at\u00ebher\u00eb numri i kontrolleve \u00ebsht\u00eb shumimi i progresionit: 10 + 9 +\u2026 + 1 = 55. Pra, p\u00ebr t\u00eb pranuar 10 PR, duhet t\u00eb ripaketohet 55 her\u00eb. Dhe kjo \u00ebsht\u00eb n\u00eb situat\u00ebn ideale, kur t\u00eb gjitha kontrollimet kalojn\u00eb me her\u00ebn e par\u00eb, kur askush nuk hap nj\u00eb pull request shtes\u00eb, nd\u00ebrsa po p\u00ebrpunohen ato dhjet\u00eb.<\/p>\n<p>Imagjinoni veten si nj\u00eb zhvillues q\u00eb duhet t\u00eb arrij\u00eb t\u00eb klikohet n\u00eb butonin \"merge\" i pari, sepse n\u00ebse e b\u00ebn fqinja, do t\u00eb pres\u00eb derisa t\u00eb kalojn\u00eb t\u00eb gjitha nd\u00ebrtimet nga e para\u2026 Jo, k\u00ebshtu nuk do t\u00eb shkoj\u00eb, do ta ngadal\u00ebsoj\u00eb seriozisht zhvillimin.<\/p>\n<p>M\u00ebnyra e dyt\u00eb e mundshme: <strong>t\u00eb nd\u00ebrtojm\u00eb pull request pas rishikimit t\u00eb kodit. <\/strong>Pra, hapni nj\u00eb pull request, mbledhni numrin e nevojsh\u00ebm t\u00eb miratimeve nga koleg\u00ebt, rregulloni \u00e7far\u00eb \u00ebsht\u00eb e nevojshme, pas k\u00ebsaj filloni nd\u00ebrtimet. N\u00ebse ato jan\u00eb t\u00eb suksesshme, pull request e integruar me develop. N\u00eb k\u00ebt\u00eb rast nuk ka ripaketime t\u00eb tjera, por feedback-u ngadal\u00ebsohet ndjesh\u00ebm. Un\u00eb, si zhvillues, kur hap pull request, menj\u00ebher\u00eb dua t\u00eb shoh a po nd\u00ebrtohet. P\u00ebr shembull, n\u00ebse ndonj\u00eb test ka d\u00ebshtuar, duhet ta rregulloj\u00eb shpejt. N\u00eb rastin e nd\u00ebrtimit t\u00eb vonuar, feedback-u ngadal\u00ebsohet, dhe k\u00ebshtu e gjith\u00eb zhvillimi. Kjo gjithashtu nuk na k\u00ebnaqte.<\/p>\n<p>S\u00eb fundi, mbeti vet\u00ebm mund\u00ebsia e tret\u00eb - <strong>t\u00eb krijohet nj\u00eb vet\u00eb.<\/strong>. T\u00eb gjith\u00eb kodi yn\u00eb, t\u00eb gjith\u00eb burimet tona ruhen n\u00eb depo n\u00eb serverin Bitbucket. Si rezultat, na duhej t\u00eb zhvillonim nj\u00eb plugin p\u00ebr Bitbucket.<\/p>\n<p><img decoding=\"async\" alt=\"Evolucioni i CI n\u00eb ekipin e zhvillimit t\u00eb mobil\u00ebve\" src=\"\/wp-content\/uploads\/2019\/04\/5e4b1f770ea1a3449b616c3101640294.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nKy ky\u00e7ja e k\u00ebtij plugin-i \u00ebsht\u00eb t\u00eb rimarr\u00eb mekanizmin e bashkimit t\u00eb k\u00ebrkesave t\u00eb t\u00ebrheqjes. Fillimi \u00ebsht\u00eb standard: hapet PR, aktivizohen t\u00eb gjitha nd\u00ebrtimet, kalon n\u00ebp\u00ebr shqyrtimin e kodit. Por pasi shqyrtimi i kodit t\u00eb kaloj\u00eb, dhe zhvilluesi vendos t\u00eb klikoj\u00eb \"bashko\", plugin-i kontrollon se n\u00eb lidhje me cilin gjendje t\u00eb zhvillimit jan\u00eb kryer verifikimet. N\u00ebse pas nd\u00ebrtimit zhvillimi ka arritur t\u00eb p\u00ebrdit\u00ebsohet, plugin-i nuk do lejoj\u00eb q\u00eb nj\u00eb k\u00ebrkes\u00eb e till\u00eb t\u00eb t\u00ebrhiqet n\u00eb deg\u00ebn kryesore. Ai thjesht do t\u00eb rishikoj\u00eb nd\u00ebrtimet n\u00eb lidhje me zhvillimin m\u00eb t\u00eb ri.<\/p>\n<p><img decoding=\"async\" alt=\"Evolucioni i CI n\u00eb ekipin e zhvillimit t\u00eb mobil\u00ebve\" src=\"\/wp-content\/uploads\/2019\/04\/0edee880e1f2d286a0c64033103ac136.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nN\u00eb shembullin ton\u00eb me ndryshime konfliktuese, k\u00ebto nd\u00ebrtime nuk do t\u00eb kalonin p\u00ebr shkak t\u00eb nj\u00eb gabimi kompilimi. Si rezultat, zhvilluesi i karakteristik\u00ebs B do t\u00eb duhet t\u00eb rregulloj\u00eb kodin, t\u00eb rinis\u00eb testet, at\u00ebher\u00eb plugin do t\u00eb aplikoj\u00eb automatikisht k\u00ebrkes\u00ebn p\u00ebr t\u00ebrheqje.<\/p>\n<p>Para zbatimit t\u00eb k\u00ebtij plugin, kishim mesatarisht 2.7 aktivizime t\u00eb testeve p\u00ebr nj\u00eb k\u00ebrkes\u00eb t\u00eb t\u00ebrheqjes. Me pluginin, b\u00ebhet 3.6 aktivizime. Kjo na k\u00ebnaq.<\/p>\n<p>Vlen t\u00eb theksohet se ky plugin ka nj\u00eb mang\u00ebsi: ai rinis nd\u00ebrtimin vet\u00ebm nj\u00eb her\u00eb. K\u00ebshtu q\u00eb gjithsesi mbetet nj\u00eb hap\u00ebsir\u00eb e vog\u00ebl, p\u00ebrmes s\u00eb cil\u00ebs mund t\u00eb kalojn\u00eb ndryshime konfliktuese n\u00eb zhvillim. Por probabiliteti i k\u00ebsaj \u00ebsht\u00eb i ul\u00ebt, dhe ne u vendos\u00ebm p\u00ebr k\u00ebt\u00eb kompromis mes numrit t\u00eb aktivizimeve dhe probabilitetit t\u00eb d\u00ebshtimit. N\u00eb dy vitet e fundit ndodhi vet\u00ebm nj\u00eb her\u00eb, k\u00ebshtu q\u00eb ndoshta nuk ishte kot.<\/p>\n<p><strong><em>Krijimi i versionit t\u00eb par\u00eb t\u00eb plugin p\u00ebr Bitbucket na mori dy jav\u00eb. <\/em><\/strong><\/p>\n<h3>Kontrollime t\u00eb reja<\/h3>\n<p>\nNd\u00ebrkoh\u00eb, ekipi yn\u00eb vijonte t\u00eb rritej. U shtuan kontrolle t\u00eb reja.<\/p>\n<p>Menduam: pse t\u00eb riparojm\u00eb gabimet, kur mund t'i parandalojm\u00eb ato? Dhe p\u00ebr k\u00ebt\u00eb implementuam <strong>analiz\u00ebn statike t\u00eb kodit<\/strong>. Filluam me lint, i cili \u00ebsht\u00eb pjes\u00eb e Android SDK. Por n\u00eb at\u00eb koh\u00eb ai nuk dinte aspak t\u00eb punonte me kodin Kotlin, dhe ne tashm\u00eb kishim 75% t\u00eb aplikacionit t\u00eb shkruar n\u00eb Kotlin. Prandaj lint-i u plot\u00ebsua me kontrollet e <strong>Android Studio.<\/strong><\/p>\n<p>P\u00ebr k\u00ebt\u00eb na duhej t\u00eb b\u00ebnim disa manovra drastike: t\u00eb merrnim Android Studio, ta paketojm\u00eb at\u00eb n\u00eb Docker dhe ta aktivizonim n\u00eb CI me nj\u00eb monitor virtual, q\u00eb ajo t\u00eb mendonte se ishte aktivizuar n\u00eb nj\u00eb laptop t\u00eb v\u00ebrtet\u00eb. Por kjo funksiononte.<\/p>\n<p>Po ashtu, n\u00eb k\u00ebt\u00eb koh\u00eb filluam t\u00eb shkruajm\u00eb shum\u00eb <strong>teste instrumental<\/strong> dhe implementuam <strong>testimin e shkrepjes<\/strong>Ky \u00ebsht\u00eb kur gjenerohet nj\u00eb skrinshot referenc\u00eb p\u00ebr nj\u00eb pamje t\u00eb vog\u00ebl t\u00eb ve\u00e7ant\u00eb, dhe testi p\u00ebrfshin marrjen e nj\u00eb skrinshoti nga pamja dhe krahasimin me referenc\u00ebn pik\u00eb p\u00ebr pik\u00eb. N\u00ebse ka ndonj\u00eb ndryshim, do t\u00eb thot\u00eb q\u00eb ndonj\u00ebher\u00eb formati \u00ebsht\u00eb keq ose di\u00e7ka nuk \u00ebsht\u00eb n\u00eb rregull me stilin.<\/p>\n<p>Por testet instrumentation dhe testet e skrinshot-it duhet t\u00eb ekzekutohen n\u00eb pajisje: n\u00eb emulator\u00eb ose n\u00eb pajisje reale. Duke marr\u00eb parasysh se ka shum\u00eb teste dhe ato gjenerohen shpesh, na nevojitet nj\u00eb ferm\u00eb e t\u00ebr\u00eb. T\u00eb krijosh ferm\u00ebn t\u00ebnde \u00ebsht\u00eb shum\u00eb pun\u00eb, prandaj gjet\u00ebm nj\u00eb opsion t\u00eb gatsh\u00ebm \u2014 Firebase Test Lab.<\/p>\n<h3>Firebase Test Lab<\/h3>\n<p>\nI zgjodh\u00ebm sepse Firebase \u00ebsht\u00eb nj\u00eb produkt i Google, pra duhet t\u00eb jet\u00eb i besuesh\u00ebm dhe me siguri nuk do t\u00eb vdes\u00eb kurr\u00eb. \u00c7mimet jan\u00eb t\u00eb arsyeshme: 5$ p\u00ebr or\u00eb n\u00eb pajisje reale, 1$ p\u00ebr or\u00eb n\u00eb emulator.<\/p>\n<p><strong><em>Deri n\u00eb implementimin e Firebase Test Lab n\u00eb CI-n\u00eb ton\u00eb, kaluan p\u00ebraf\u00ebrsisht tri jav\u00eb.<\/em><\/strong><\/p>\n<p>Por ekipi vazhdonte t\u00eb rritej, dhe Firebase, fatkeq\u00ebsisht, filloi t\u00eb na l\u00ebr\u00eb pas. N\u00eb at\u00eb koh\u00eb nuk kishte asnj\u00eb SLA. Ndonj\u00ebher\u00eb Firebase na detyronte t\u00eb prisnim p\u00ebr t\u00eb l\u00ebshuar numrin e nevojsh\u00ebm t\u00eb pajisjeve p\u00ebr testet, dhe nuk i fillonte menj\u00ebher\u00eb si\u00e7 do t\u00eb donim. Pritja n\u00eb radh\u00eb zgjaste deri n\u00eb gjysm\u00eb ore, dhe kjo ishte shum\u00eb e gjat\u00eb. Testet instrumentation ekzekutoheshin n\u00eb \u00e7do PR, dhe vonesat e ngadal\u00ebsonin zhvillimin, pastaj erdhi edhe hesap p\u00ebr muajin me nj\u00eb shum\u00eb t\u00eb madhe. N\u00eb p\u00ebrgjith\u00ebsi, u vendos t\u00eb largohemi nga Firebase dhe t\u00eb zhvillojm\u00eb in-house, pasi ekipi ishte mjaft i rritur.<\/p>\n<h3>Docker + Python + bash<\/h3>\n<p>\nMarr\u00ebm docker, e vendos\u00ebm brenda emulator\u00ebt, shkruam nj\u00eb program t\u00eb thjesht\u00eb n\u00eb Python q\u00eb, n\u00eb momentin e duhur, ngre numrin e nevojsh\u00ebm t\u00eb emulator\u00ebve n\u00eb versionin e duhur dhe kur \u00ebsht\u00eb e nevojshme, i ndalon ata. Dhe, natyrisht, disa skenar\u00eb bash \u2014 ku tjet\u00ebr mund t\u00eb shkojm\u00eb pa to?<\/p>\n<p><strong><em>P\u00ebr krijimin e ambientit ton\u00eb t\u00eb testimit kaluan pes\u00eb jav\u00eb.<\/em><\/strong><\/p>\n<p>Si rezultat, p\u00ebr \u00e7do pull request kishte nj\u00eb list\u00eb t\u00eb gjer\u00eb, bllokuese p\u00ebr bashkimin, t\u00eb kontrollimeve:<\/p>\n<ul>\n<li>Nd\u00ebrtimi i ARK;<\/li>\n<li>Testet Junit;<\/li>\n<li>Lint;<\/li>\n<li>Kontrollet e Android Studio;<\/li>\n<li>Testet e Instrumentacionit;<\/li>\n<li>Testet e Skreenit.<\/li>\n<\/ul>\n<p>\nKjo parandalonte shum\u00eb mund\u00ebsi defektesh. Teknikisht gjith\u00e7ka funksiononte, por zhvilluesit ankonin se prisnin rezultatet shum\u00eb gjat\u00eb.<\/p>\n<p>\u00c7far\u00eb do t\u00eb thot\u00eb shum\u00eb gjat\u00eb? Ne analizuam t\u00eb dh\u00ebnat nga Bitbucket dhe TeamCity n\u00eb sistemin e analiz\u00ebs dhe kuptuam se <strong>koha mesatare e pritjes \u00ebsht\u00eb 45 minuta<\/strong>. K\u00ebshtu, nj\u00eb zhvillues, duke hapur kujtesat e t\u00ebrheqjes, mesatarisht pret rezultatet e nd\u00ebrrimeve p\u00ebr 45 minuta. Sipas mendimit tim, kjo \u00ebsht\u00eb shum\u00eb, dhe nuk mund t\u00eb punojm\u00eb k\u00ebshtu.<\/p>\n<p>Sigurisht, vendos\u00ebm t\u00eb p\u00ebrshpejtojm\u00eb t\u00eb gjitha nd\u00ebrtimet tona.<\/p>\n<h2>Po p\u00ebrshpejtohemi<\/h2>\n<p>\nDuke par\u00eb se shpesh nd\u00ebrtimet ishin n\u00eb pritje, ne filluam <strong>t\u00eb blinim paisje t\u00eb reja<\/strong> \u2014 zhvillimi ekstensiv \u00ebsht\u00eb m\u00eb i leht\u00eb. Nd\u00ebrtimet nuk q\u00ebndrojn\u00eb m\u00eb n\u00eb pritje, por koha e pritjes u ul vet\u00ebm pak, sepse disa kontrolle veten e tyre kan\u00eb marr\u00eb shum\u00eb koh\u00eb.<\/p>\n<h3>Hiqni kontrollet shum\u00eb t\u00eb gjata<\/h3>\n<p>\nContinuous Integration yn\u00eb mund t\u00eb kap\u00eb k\u00ebto lloje gabimesh dhe problemesh.<\/p>\n<ul>\n<li><strong>Nuk nd\u00ebrtohet<\/strong>. CI mund t\u00eb kap\u00eb nj\u00eb gabim p\u00ebrmbledhjeje kur p\u00ebr shkak t\u00eb ndryshimeve konfliktuese di\u00e7ka nuk nd\u00ebrtohet. Si\u00e7 e thash\u00eb, at\u00ebher\u00eb askush nuk mund t\u00eb nd\u00ebrtoj\u00eb asgj\u00eb, zhvillimi ndalet dhe t\u00eb gjith\u00eb nervozohen.<\/li>\n<li><strong>Gabimi n\u00eb sjellje<\/strong>. P\u00ebr shembull, kur aplikacioni nd\u00ebrtohet, por bie kur shtypni butonin, ose butoni nuk funksionon fare. Kjo \u00ebsht\u00eb e keqe, sepse nj\u00eb gabim i till\u00eb mund t\u00eb arrij\u00eb te p\u00ebrdoruesi.<\/li>\n<li><strong>Gabimi n\u00eb dizajn<\/strong>. P\u00ebr shembull, butoni funksionon, por \u00ebsht\u00eb zhvendosur 10 piksel nga e majta.<\/li>\n<li><strong>Rritja e borxhit teknik<\/strong>.<\/li>\n<\/ul>\n<p>\nDuke e par\u00eb k\u00ebt\u00eb list\u00eb, ne kuptuam se kritike ishin vet\u00ebm dy pika t\u00eb para. K\u00ebto probleme ne duam t'i kapim n\u00eb radh\u00eb t\u00eb par\u00eb. Gabimet n\u00eb dizajn zbulohen n\u00eb faz\u00ebn e kontrollit t\u00eb dizajnit dhe at\u00ebher\u00eb jan\u00eb leht\u00eb t\u00eb rregullohen. Puna me borxhin teknik k\u00ebrkon nj\u00eb proces dhe planifikim t\u00eb ve\u00e7ant\u00eb, k\u00ebshtu q\u00eb vendos\u00ebm t\u00eb mos e kontrollojm\u00eb at\u00eb n\u00eb pull request.<\/p>\n<p>Duke u bazuar n\u00eb k\u00ebt\u00eb klasifikim, ne rishikuam t\u00eb gjith\u00eb list\u00ebn e kontrolleve. <strong>Fshim\u00eb Lint<\/strong> dhe e transferuam n\u00eb nat\u00eb: thjesht p\u00ebr t\u00eb kuptuar se sa probleme ka n\u00eb projekt. Me borxhin teknik vendos\u00ebm t\u00eb punojm\u00eb ve\u00e7mas, dhe <strong>n\u00eb kontrollet e Android Studio ne u larguam fare<\/strong>. Android Studio n\u00eb Docker p\u00ebr t\u00eb ekzekutuar inspektimet duket interesante, por sjell shum\u00eb probleme n\u00eb mb\u00ebshtetje. \u00c7do azhurnim versionesh t\u00eb Android Studio \u2014 \u00ebsht\u00eb nj\u00eb luft\u00eb me gabime t\u00eb paqart\u00eb. Po ashtu e nd\u00ebrlikuar ishte mbajtja e testeve t\u00eb screenshot, sepse biblioteka nuk funksiononte shum\u00eb stabilisht, kishte rastet e gabimeve false. <strong>Ne hoq\u00ebm testet e screenshot nga lista e kontrolleve<\/strong>.<\/p>\n<p>N\u00eb p\u00ebrfundim, na mbet\u00ebn:<\/p>\n<ul>\n<li>Nd\u00ebrtimi i ARK;<\/li>\n<li>Testet Junit;<\/li>\n<li>Testet e Instrumentimit.<\/li>\n<\/ul>\n<h3>Gradle remote cache<\/h3>\n<p>\nPa kontrolle t\u00eb r\u00ebnda, gjith\u00e7ka u p\u00ebrmir\u00ebsua. Por nuk ka kufi p\u00ebr p\u00ebrsosm\u00ebri!<\/p>\n<p>Aplikacioni yn\u00eb tashm\u00eb ishte ndar\u00eb n\u00eb rreth 150 module gradle. Zakonisht n\u00eb nj\u00eb rast t\u00eb till\u00eb funksionon mir\u00eb Gradle remote cache, dhe vendos\u00ebm ta provonim at\u00eb.<\/p>\n<p>Gradle remote cache \u2014 \u00ebsht\u00eb nj\u00eb sh\u00ebrbim q\u00eb mund t\u00eb ruaj\u00eb artefaktet e nd\u00ebrtimit p\u00ebr detyra t\u00eb caktuara n\u00eb module t\u00eb ve\u00e7anta. Gradle, n\u00eb vend q\u00eb t\u00eb kompilohet realisht kodin, i drejtohet remote cache p\u00ebrmes HTTP dhe pyet n\u00ebse dikush e ka ekzekutuar tashm\u00eb k\u00ebt\u00eb detyr\u00eb. N\u00ebse po, thjesht shkarkon rezultatin.<\/p>\n<p><strong><em>T\u00eb nis\u00ebsh Gradle remote cache \u00ebsht\u00eb e leht\u00eb, sepse Gradle ofron nj\u00eb imazh Docker. Ne arrijm\u00eb ta b\u00ebjm\u00eb k\u00ebt\u00eb brenda tre or\u00ebve.<\/em><\/strong><\/p>\n<p>Thjesht duhej t\u00eb niste Docker dhe t\u00eb shkruante nj\u00eb rresht n\u00eb projekt. Por ndon\u00ebse mund t\u00eb niset shpejt, p\u00ebr t\u00eb punuar si\u00e7 duhet do t\u00eb k\u00ebrkohet nj\u00eb koh\u00eb e konsiderueshme.<\/p>\n<p>M\u00eb posht\u00eb \u00ebsht\u00eb grafiku i humbjeve t\u00eb caches.<\/p>\n<p><img decoding=\"async\" alt=\"Evolucioni i CI n\u00eb ekipin e zhvillimit t\u00eb mobil\u00ebve\" src=\"\/wp-content\/uploads\/2019\/04\/458ef23b5506b04f3bd385be0c18607a.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nFillimisht, p\u00ebrqindja e humbjeve nga cache ishte rreth 65. Pasi kaluan tri jav\u00eb, arrit\u00ebm ta ulinim k\u00ebt\u00eb vler\u00eb n\u00eb 20%. U duk se detyrat q\u00eb nd\u00ebrtone aplikacionin Android kan\u00eb var\u00ebsit\u00eb tranzitive t\u00eb \u00e7uditshme q\u00eb e b\u00ebn\u00eb Gradle t\u00eb humbas\u00eb nga cache.<\/p>\n<p>Duke e aktivizuar cache, ne e p\u00ebrshpejtuam nd\u00ebrtimin ndjesh\u00ebm. Por p\u00ebrve\u00e7 nd\u00ebrtimit, gjithashtu ekzekutohen testet e instrumentalizmit, dhe ato zgjatin shum\u00eb. Ndoshta, nuk \u00ebsht\u00eb e nevojshme t\u00eb ekzekutohen t\u00eb gjitha testet p\u00ebr \u00e7do pull request. P\u00ebr ta zbuluar k\u00ebt\u00eb, p\u00ebrdorim analiz\u00ebn e ndikimit.<\/p>\n<h3>Analiza e ndikimit<\/h3>\n<p>\nN\u00eb pull request ne mbledhim git diff dhe gjejm\u00eb modulo t\u00eb ndryshuara Gradle.<\/p>\n<p><img decoding=\"async\" alt=\"Evolucioni i CI n\u00eb ekipin e zhvillimit t\u00eb mobil\u00ebve\" src=\"\/wp-content\/uploads\/2019\/04\/471ca37206a0da4d5741c8ee1dbb7f03.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nKa kuptim t\u00eb ekzekutohen vet\u00ebm ato teste t\u00eb instrumentalizmit q\u00eb kontrollojn\u00eb modulet e ndryshuara dhe t\u00eb gjitha modulet q\u00eb varen prej tyre. Testet p\u00ebr modulet fqinj nuk ka kuptim t\u00eb ekzekutohen: atje nuk \u00ebsht\u00eb ndryshuar kod, prandaj nuk mund t\u00eb ket\u00eb ndonj\u00eb d\u00ebshtim.<\/p>\n<p>Me testet e instrumentalizmit nuk \u00ebsht\u00eb kaq e thjesht\u00eb, sepse ato duhet t\u00eb ndodhen n\u00eb modulin m\u00eb t\u00eb lart\u00eb t\u00eb aplikacionit. Ne aplikuam nj\u00eb heuristik\u00eb me analiz\u00ebn e bytecode p\u00ebr t\u00eb kuptuar se cilit modul i p\u00ebrket \u00e7do test.<\/p>\n<p><strong><em>Modernizimi i funksionimit t\u00eb testeve t\u00eb instrumentalizmit p\u00ebr t\u00eb kontrolluar vet\u00ebm modulet e angazhuara, zgjati rreth tet\u00eb jav\u00eb.<\/em><\/strong><\/p>\n<p>Masat p\u00ebr p\u00ebrshpejtimin e verifikimeve dhan\u00eb rezultat. Nga 45 minuta arrit\u00ebm n\u00eb rreth 15. Nj\u00eb \u00e7erek ore p\u00ebr t\u00eb pritur nd\u00ebrtimin tani \u00ebsht\u00eb normale.<\/p>\n<p>Por tani zhvilluesit kan\u00eb filluar t\u00eb ankohen se nuk e kuptojn\u00eb se cilat nd\u00ebrtime jan\u00eb duke u ekzekutuar, ku mund t\u00eb shohin log-un, pse nd\u00ebrtimi \u00ebsht\u00eb i kuq, cili test ka d\u00ebshtuar, etj.<\/p>\n<p><img decoding=\"async\" alt=\"Evolucioni i CI n\u00eb ekipin e zhvillimit t\u00eb mobil\u00ebve\" src=\"\/wp-content\/uploads\/2019\/04\/aa76151174cd4e5a45ff281818e312f5.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nProblemet me feedback-in ngadal\u00ebsojn\u00eb zhvillimin, prandaj kemi b\u00ebr\u00eb p\u00ebrpjekje p\u00ebr t\u00eb siguruar informacion sa m\u00eb t\u00eb qart\u00eb dhe t\u00eb detajuar p\u00ebr \u00e7do PR dhe nd\u00ebrtim. Filluam me komentet n\u00eb Bitbucket p\u00ebr PR duke sh\u00ebnuar se cili nd\u00ebrtim d\u00ebshton dhe pse, shkruam mesazhe t\u00eb drejtp\u00ebrdrejta n\u00eb Slack. N\u00eb fund, krijuam nj\u00eb dashboard p\u00ebr faqen e PR me nj\u00eb list\u00eb t\u00eb t\u00eb gjitha nd\u00ebrtimeve q\u00eb aktualisht jan\u00eb duke u ekzekutuar dhe statusit t\u00eb tyre: n\u00eb radh\u00eb, duke u ekzekutuar, d\u00ebshtuar ose p\u00ebrfunduar. Mund t\u00eb klikoni n\u00eb nd\u00ebrtim dhe t\u00eb hyni n\u00eb logun e tij.<\/p>\n<p><img decoding=\"async\" alt=\"Evolucioni i CI n\u00eb ekipin e zhvillimit t\u00eb mobil\u00ebve\" src=\"\/wp-content\/uploads\/2019\/04\/2d16b7a6b6d23e23903d291ef1526999.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n<strong><em>I jan\u00eb kushtuar gjasht\u00eb jav\u00eb feedback-ut t\u00eb detajuar.<\/em><\/strong><\/p>\n<h2>Planet<\/h2>\n<p>\nT\u00eb kalojm\u00eb n\u00eb historin\u00eb m\u00eb t\u00eb re. Duke zgjidhur \u00e7\u00ebshtjen e feedback-ut, arrit\u00ebm n\u00eb nj\u00eb nivel t\u00eb ri \u2014 vendos\u00ebm t\u00eb nd\u00ebrtojm\u00eb ferm\u00ebn ton\u00eb t\u00eb emulator\u00ebve. Kur ka shum\u00eb teste dhe emulator\u00eb, \u00ebsht\u00eb e v\u00ebshtir\u00eb t\u00eb menaxhohen. N\u00eb fund, t\u00eb gjith\u00eb emulator\u00ebt tan\u00eb u transferuan n\u00eb nj\u00eb klas\u00ebr k8s me menaxhim t\u00eb fleksibilizuar t\u00eb burimeve.<\/p>\n<p>P\u00ebr m\u00eb tep\u00ebr, ka planifikime t\u00eb tjera.<\/p>\n<ul>\n<li><strong>T\u00eb kthejm\u00eb Lint<\/strong> (dhe analizimin tjet\u00ebr statik). Ne tashm\u00eb jemi duke punuar n\u00eb k\u00ebt\u00eb drejtim.<\/li>\n<li>T\u00eb ekzekutojm\u00eb si bllokues p\u00ebr PR t\u00eb gjitha <strong>testet end-to-end<\/strong> n\u00eb t\u00eb gjitha versionet e SDK.<\/li>\n<\/ul>\n<p>\nDhe k\u00ebshtu, kemi ndjekur historin\u00eb e zhvillimit t\u00eb Continuous Integration n\u00eb Avito. Tani dua t\u00eb jap disa k\u00ebshilla nga pik\u00ebpamja e nj\u00eb personi me p\u00ebrvoj\u00eb.<\/p>\n<h1>K\u00ebshillat<\/h1>\n<p>\nN\u00ebse do t\u00eb mund t\u00eb jepja vet\u00ebm nj\u00eb k\u00ebshill\u00eb, do t\u00eb ishte kjo:<\/p>\n<blockquote><p>Ju lutem, tregoni kujdes me skenaret shell!<\/p><\/blockquote>\n<p>\nBash \u2014 \u00ebsht\u00eb nj\u00eb mjet shum\u00eb fleksib\u00ebl dhe i fuqish\u00ebm, \u00ebsht\u00eb shum\u00eb i leht\u00eb dhe i shpejt\u00eb p\u00ebr t\u00eb shkruar skenare. Por mund t\u00eb bini n\u00eb kurth, dhe fatkeq\u00ebsisht ne kemi r\u00ebn\u00eb n\u00eb t\u00eb.<\/p>\n<p>Ofrimi filloi me skenare t\u00eb thjeshta, t\u00eb cilat ekzekutoheshin n\u00eb mjetet tona t\u00eb nd\u00ebrtimit:<\/p>\n<pre><code class=\"bash\">#!\/usr\/bin\/env bash\n.\/gradlew assembleDebug<\/code><\/pre>\n<p>\nPor, si\u00e7 dihet, gjith\u00e7ka zhvillohet dhe komplikohet me koh\u00ebn \u2014 le t\u00eb ekzekutojm\u00eb nj\u00eb skenar nga nj\u00eb tjet\u00ebr, le t'i kalojm\u00eb disa parametra aty \u2014 n\u00eb fund, na duhej t\u00eb shkruanim nj\u00eb funksion q\u00eb p\u00ebrcakton se n\u00eb cilin nivel t\u00eb thell\u00ebsis\u00eb bash jemi tani p\u00ebr t\u00eb vendosur citatet e duhura, n\u00eb m\u00ebnyr\u00eb q\u00eb t\u00eb gjith\u00eb t\u00eb niseshin.<\/p>\n<p><img decoding=\"async\" alt=\"Evolucioni i CI n\u00eb ekipin e zhvillimit t\u00eb mobil\u00ebve\" src=\"\/wp-content\/uploads\/2019\/04\/244a574f7b5d3b4fc77cfc4ccda2db69.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nMund ta imagjinoni sa pun\u00eb k\u00ebrkoi zhvillimi i till\u00eb i skenar\u00ebve. Ju rekomandoj t\u00eb mos binni n\u00eb k\u00ebt\u00eb kurth.<\/p>\n<p>\u00c7far\u00eb mund t\u00eb z\u00ebvend\u00ebsoj\u00eb?<\/p>\n<ul>\n<li>\u00c7do gjuh\u00eb skenari. T\u00eb shkruash n\u00eb <strong>Python ose Kotlin Script<\/strong> \u00ebsht\u00eb m\u00eb e leht\u00eb, sepse \u00ebsht\u00eb programim dhe jo skenare.<\/li>\n<li>Ose t\u00eb p\u00ebrshkruani t\u00eb gjith\u00eb logjik\u00ebn e nd\u00ebrtimit n\u00eb form\u00ebn e <strong>detyrave t\u00eb personalizuara gradle<\/strong> p\u00ebr projektin tuaj.<\/li>\n<\/ul>\n<p>\nNe vendos\u00ebm t\u00eb zgjedhim opsionin e dyt\u00eb, dhe tani po hiqim gradualisht t\u00eb gjitha skenaret bash dhe po shkruajm\u00eb shum\u00eb detyra gradle t\u00eb personalizuara.<\/p>\n<p><strong>K\u00ebshilla Nr. 2: t\u00eb mbani infrastruktur\u00ebn n\u00eb kod.<\/strong><\/p>\n<p>Esht\u00eb e p\u00ebrshtatshme kur konfigurimi i Continuous Integration nuk ruhet n\u00eb nd\u00ebrfaqen e p\u00ebrdoruesit t\u00eb Jenkins ose TeamCity etj., por si skedar\u00eb t\u00eb tekstit direkt n\u00eb repozitorin\u00eb e projektit. Kjo ofron versionim. Nuk do t\u00eb jet\u00eb e v\u00ebshtir\u00eb t\u00eb rikthehesh ose t\u00eb nd\u00ebrtohesh kodin n\u00eb nj\u00eb deg\u00eb tjet\u00ebr.<\/p>\n<p>Skripti mund t\u00eb ruhet n\u00eb projekt. Por \u00e7far\u00eb t\u00eb b\u00ebjm\u00eb me mjedisin?<\/p>\n<p><strong>K\u00ebshilla Nr. 3: Docker mund t\u00eb ndihmoj\u00eb me mjedisin.<\/strong><\/p>\n<p>Sigurisht q\u00eb do t\u00eb ndihmoj\u00eb zhvilluesit Android, ndoshta p\u00ebr iOS ndonj\u00ebher\u00eb jo, fatkeq\u00ebsisht.<\/p>\n<p>Ky \u00ebsht\u00eb nj\u00eb shembull i nj\u00eb docker-file t\u00eb thjesht\u00eb, i cili p\u00ebrmban jdk dhe android-sdk:<\/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# Shkarko Android SDK\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# Instaloni Android Build Tool dhe Bibliotekat\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>\nK\u00ebtu shkrova k\u00ebt\u00eb docker-file (do t'ju them n\u00eb sekret, mund ta anashkaloni dhe ta shkarkoni nj\u00eb t\u00eb gatshme nga GitHub) dhe duke nd\u00ebrtuar imazhin, merrni nj\u00eb makin\u00eb virtuale, n\u00eb t\u00eb cil\u00ebn mund t\u00eb nd\u00ebrtoni aplikacionin dhe t\u00eb ekzekutoni testet Junit.<\/p>\n<p>Dy argumentet kryesore pse kjo ka kuptim: shkall\u00ebzueshm\u00ebria dhe p\u00ebrs\u00ebritshm\u00ebria. Me p\u00ebrdorimin e docker, mund t\u00eb ngrini shpejt nj\u00eb duzin\u00eb agjent\u00ebsh t\u00eb nd\u00ebrtimit, t\u00eb cil\u00ebt do t\u00eb ken\u00eb t\u00eb nj\u00ebjtin mjedis si m\u00eb par\u00eb. Kjo e leht\u00ebson shum\u00eb jet\u00ebn e inxhinier\u00ebve CI. T\u00eb fut\u00ebsh android-sdk n\u00eb docker \u00ebsht\u00eb shum\u00eb e thjesht\u00eb, me emulator\u00ebt \u00ebsht\u00eb pak m\u00eb e komplikuar: do t'ju duhet t\u00eb punoni pak (ose p\u00ebrs\u00ebri t\u00eb shkarkoni nj\u00eb t\u00eb gatshme nga GitHub).<\/p>\n<p><strong>K\u00ebshilla Nr. 4: mos harroni se kontrollet nuk b\u00ebhen p\u00ebr kontrolle, por p\u00ebr njer\u00ebzit.<\/strong><\/p>\n<p>P\u00ebr zhvilluesit, nj\u00eb feedback i shpejt\u00eb dhe, m\u00eb e r\u00ebnd\u00ebsishmja, i kuptuesh\u00ebm \u00ebsht\u00eb shum\u00eb i r\u00ebnd\u00ebsish\u00ebm: \u00e7far\u00eb ka d\u00ebshtuar, cila test ka r\u00ebn\u00eb, ku t\u00eb shikoni build-logun.<\/p>\n<p><strong>K\u00ebshilla Nr. 5: jini pragmatik\u00eb n\u00eb zhvillimin e Continuous Integration.<\/strong><\/p>\n<p>Kuptoni qart\u00eb se cilat lloje gabimesh d\u00ebshironi t\u00eb parandaloni, sa burime, koh\u00eb dhe koh\u00eb makinerie jeni t\u00eb gatsh\u00ebm t\u00eb investoni. Kontrollimet shum\u00eb t\u00eb gjata mund t\u00eb zgjidhen, p\u00ebr shembull, gjat\u00eb nat\u00ebs. Nd\u00ebrsa p\u00ebr ato q\u00eb kapin gabime jo shum\u00eb t\u00eb r\u00ebnd\u00ebsishme, mund t\u00eb hiqen krejt\u00ebsisht.<\/p>\n<p><strong>K\u00ebshilla Nr. 6: p\u00ebrdorni mjete t\u00eb gatshme.<\/strong><\/p>\n<p>Aktualisht ka shum\u00eb kompani q\u00eb ofrojn\u00eb CI n\u00eb cloud.<\/p>\n<p><img decoding=\"async\" alt=\"Evolucioni i CI n\u00eb ekipin e zhvillimit t\u00eb mobil\u00ebve\" src=\"\/wp-content\/uploads\/2019\/04\/e57aabd49ec01d14e83b64331fd84ec5.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nP\u00ebr ekipet e vogla, kjo \u00ebsht\u00eb nj\u00eb zgjidhje e mir\u00eb. Nuk nevojitet mb\u00ebshtetje, thjesht paguani pak para, grumbulloni aplikacionin tuaj dhe madje drejtoni teste instrumentimi.<\/p>\n<p><strong>K\u00ebshilla Nr. 7: n\u00eb nj\u00eb ekip t\u00eb madh, \u00ebsht\u00eb m\u00eb e leverdishme t\u00eb keni zgjidhje in-house.<\/strong><\/p>\n<p>Por her\u00ebt apo von\u00eb, me rritjen e ekipit, do t\u00eb b\u00ebhen m\u00eb t\u00eb leverdishme zgjidhjet in-house. Me k\u00ebto zgjidhje ka nj\u00eb moment. N\u00eb ekonomi ka ligjin e kthimeve n\u00eb r\u00ebnie: n\u00eb \u00e7do projekt, \u00e7do p\u00ebrmir\u00ebsim m\u00eb i vog\u00ebl b\u00ebhet gjithnj\u00eb e m\u00eb i v\u00ebshtir\u00eb dhe k\u00ebrkon gjithnj\u00eb e m\u00eb shum\u00eb investime.<\/p>\n<p>Ekonomia p\u00ebrshkruan gjith\u00eb jet\u00ebn ton\u00eb, p\u00ebrfshir\u00eb Integrimin e Vazhdur. Kam nd\u00ebrtuar nj\u00eb grafik t\u00eb shpenzimeve t\u00eb pun\u00ebs p\u00ebr \u00e7do faz\u00eb t\u00eb zhvillimit t\u00eb Integrimit ton\u00eb t\u00eb Vazhdur.<\/p>\n<p><img decoding=\"async\" alt=\"Evolucioni i CI n\u00eb ekipin e zhvillimit t\u00eb mobil\u00ebve\" src=\"\/wp-content\/uploads\/2019\/04\/97bf8bff64f3ac9ae587fae195251da2.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDhe \u00ebsht\u00eb e qart\u00eb se \u00e7do p\u00ebrmir\u00ebsim b\u00ebhet gjithnj\u00eb e m\u00eb i v\u00ebshtir\u00eb. Duke par\u00eb k\u00ebt\u00eb grafik, mund t\u00eb kuptohet se zhvillimi i Integrimit t\u00eb Vazhdur duhet t\u00eb jet\u00eb n\u00eb p\u00ebrputhje me rritjen e madh\u00ebsis\u00eb s\u00eb ekipit. P\u00ebr nj\u00eb ekip prej dy personash, shpenzimi i 50 dit\u00ebve p\u00ebr zhvillimin e nj\u00eb ferme t\u00eb brendshme t\u00eb emulator\u00ebve \u00ebsht\u00eb nj\u00eb ide e keqe. Por gjithashtu, p\u00ebr nj\u00eb ekip t\u00eb madh, t\u00eb mos merresh me Integrimin e Vazhdur \u00ebsht\u00eb gjithashtu nj\u00eb ide e keqe, sepse do t\u00eb shpenzohet m\u00eb shum\u00eb koh\u00eb p\u00ebr t\u00eb zgjidhur problemet e integrimit, riparimin e komunikimeve, etj.<\/p>\n<p>Filluam duke th\u00ebn\u00eb se automatizimi \u00ebsht\u00eb i nevojsh\u00ebm, sepse njer\u00ebzit jan\u00eb t\u00eb shtrenjt\u00eb, ata gabojn\u00eb dhe jan\u00eb t\u00eb len\u00eb. Por automatizuesit jan\u00eb gjithashtu njer\u00ebz. Prandaj, t\u00eb gjitha k\u00ebto probleme i p\u00ebrkasin edhe automatizimit.<\/p>\n<ul>\n<li>T\u00eb automatizosh \u00ebsht\u00eb e kushtueshme. Kujtojeni grafik\u00ebn e shpenzimeve t\u00eb pun\u00ebs.<\/li>\n<li>Gjat\u00eb automatizimit, njer\u00ebzit gabojn\u00eb.<\/li>\n<li>Ndonj\u00ebher\u00eb \u00ebsht\u00eb shum\u00eb dembel p\u00ebr t\u00eb automatizuar, sepse gjith\u00e7ka funksionon. Pse t\u00eb p\u00ebrmir\u00ebsosh di\u00e7ka tjet\u00ebr, pse t\u00eb b\u00ebsh t\u00eb gjith\u00eb k\u00ebt\u00eb Integrim t\u00eb Vazhdur?<\/li>\n<\/ul>\n<p>\nPor kam nj\u00eb statistik\u00eb: n\u00eb 20% t\u00eb nd\u00ebrtimeve kapen gabime. Dhe kjo ndodh jo sepse zhvilluesit tan\u00eb shkruajn\u00eb keq kodin. Kjo ndodh sepse zhvilluesit jan\u00eb t\u00eb sigurt se, n\u00ebse ata b\u00ebjn\u00eb ndonj\u00eb gabim, ai nuk do t\u00eb shkoj\u00eb n\u00eb develop, por do t\u00eb kapet nga kontrollet automatizuar. K\u00ebshtu q\u00eb, zhvilluesit mund t\u00eb shpenzojn\u00eb m\u00eb shum\u00eb koh\u00eb duke shkruar kod dhe duke u angazhuar me gj\u00ebra interesante, e jo duke e b\u00ebr\u00eb ndonj\u00eb gj\u00eb n\u00eb m\u00ebnyr\u00eb lokale dhe duke kontrolluar.<\/p>\n<p><strong>Meruni me Integrimin e Vazhdur. Por n\u00eb m\u00ebnyr\u00eb t\u00eb arsyeshme.<\/strong><\/p>\n<blockquote><p>P\u00ebr m\u00eb tep\u00ebr, Nikolaj Nesterov jo vet\u00ebm q\u00eb b\u00ebn prezantime fantastike, por gjithashtu \u00ebsht\u00eb an\u00ebtar i komitetit programor <noindex><a rel=\"nofollow\" href=\"https:\/\/appsconf.ru\/moscow\/2019\">AppsConf<\/a><\/noindex> dhe ndihmon t\u00eb tjer\u00ebt t\u00eb p\u00ebrgatisin p\u00ebr ju prezantime dometh\u00ebn\u00ebse. Pluralitetin dhe dobishm\u00ebrin\u00eb e programit t\u00eb konferenc\u00ebs s\u00eb ardhshme mund ta vler\u00ebsoni nga temat n\u00eb <noindex><a rel=\"nofollow\" href=\"https:\/\/appsconf.ru\/moscow\/2019\/schedule\">orarin<\/a><\/noindex>. Dhe p\u00ebr m\u00eb shum\u00eb detaje, erdhni m\u00eb 22-23 prill n\u00eb Infopran\u00ebs.<\/p><\/blockquote>\n<p>Burimi: <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.2 - 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\/sq\/blog\/administrirovanie\/evolyutsiya-ci-v-komande-mobilnoj-razrabotki\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.2\" \/>\n\t\t<meta property=\"og:locale\" content=\"sq_AL\" \/>\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\/sq\/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\udd47Evolucioni i CI n\u00eb ekipin e zhvillimit celular | ProHoster","description":"Sot do t\u00eb thot\u00eb sot shumica e produkteve software zhvillohen n\u00eb ekipe.","canonical_url":"https:\/\/prohoster.info\/sq\/blog\/administrirovanie\/evolyutsiya-ci-v-komande-mobilnoj-razrabotki","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"sq_AL","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\/sq\/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\/sq\/wp-json\/wp\/v2\/posts\/31304","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/comments?post=31304"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/posts\/31304\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/media\/23270"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/media?parent=31304"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/categories?post=31304"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/tags?post=31304"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}