{"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 aplikacioneve","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Sot, shumica e produkteve softuerike zhvillohen n\u00eb ekipe. Kushtet p\u00ebr suksesin e zhvillimit n\u00eb grup mund t\u00eb p\u00ebrshkruhen me nj\u00eb skem\u00eb t\u00eb thjesht\u00eb.<\/p>\n<p><img decoding=\"async\" alt=\"Evolucioni i CI n\u00eb ekipin e zhvillimit t\u00eb aplikacioneve\" 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 d\u00ebmton asgj\u00eb, p\u00ebrfshir\u00eb kodin q\u00eb kan\u00eb shkruar koleg\u00ebt tuaj.<\/li>\n<\/ol>\n<p>\nN\u00ebse t\u00eb dy kushtet p\u00ebrmbushen, at\u00ebher\u00eb jeni n\u00eb rrug\u00ebn e duhur p\u00ebr sukses. P\u00ebr t\u00eb kontrolluar leht\u00ebsisht k\u00ebto kushte dhe p\u00ebr t\u00eb mos devijuar nga rruga e duhur, u shpik Continuous Integration.<\/p>\n<p>CI \u00ebsht\u00eb nj\u00eb proces pune, ku ju integroheni sa m\u00eb shpesh n\u00eb kodin e p\u00ebrbashk\u00ebt t\u00eb produktit. Dhe jo thjesht integroidi, por gjithashtu kontrolloni vazhdimisht q\u00eb gjith\u00e7ka t\u00eb funksionoj\u00eb. Duke qen\u00eb se duhet t\u00eb kontrolloni shum\u00eb dhe shpesh, \u00ebsht\u00eb e men\u00e7ur t\u00eb mendoni p\u00ebr automatizimin. Mund t\u00eb kontrolloni gjith\u00e7ka me dor\u00eb, por nuk ia 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>. \u00c7mimi i pun\u00ebs s\u00eb \u00e7do programuesi \u00ebsht\u00eb m\u00eb i lart\u00eb se \u00e7mimi i pun\u00ebs s\u00eb \u00e7do serveri.<\/li>\n<li><strong>Njer\u00ebzit b\u00ebjn\u00eb gabime<\/strong>. Prandaj mund t\u00eb lindin situata ku jan\u00eb ekzekutuar teste n\u00eb deg\u00ebn e gabuar apo jan\u00eb nd\u00ebrtuar komitete t\u00eb gabuara p\u00ebr testuesit.<\/li>\n<li><strong>Njer\u00ebzit jan\u00eb t\u00eb dembel\u00eb<\/strong>. Her\u00eb pas here, kur p\u00ebrfundoj nj\u00eb detyr\u00eb, m\u00eb vjen n\u00eb mendje: \u00ab\u00c7far\u00eb ka p\u00ebr t\u00eb kontrolluar k\u00ebtu? Kam shkruar dy rreshta \u2014 sigurisht q\u00eb punon!\u00bb Mendoj se disa prej jush ndoshta ndjejn\u00eb t\u00eb nj\u00ebjtat mendime her\u00eb pas here. Por duhet t\u00eb kontrolloni gjithmon\u00eb.<\/li>\n<\/ul>\n<p>\nSi implementuam dhe zhvilluam Continuous Integration n\u00eb ekipin e zhvillimit t\u00eb aplikacioneve mobile t\u00eb Avito, si arrit\u00ebm nga 0 n\u00eb 450 nd\u00ebrtime n\u00eb dit\u00eb, dhe \u00e7far\u00eb nd\u00ebrtimi makinat mbledhin 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 t\u00eb CI\/CD p\u00ebr aplikacionin Android.<\/p>\n<p>Rr\u00ebfimi \u00ebsht\u00eb i nd\u00ebrtuar mbi shembuj nga ekipi Android, por shumica e qasjeve jan\u00eb gjithashtu t\u00eb aplikueshme dhe 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 shum\u00eb koh\u00eb m\u00eb par\u00eb, n\u00eb ekipin Android t\u00eb Avito punonte nj\u00eb person. Nga definicioni, ai nuk kishte nevoj\u00eb p\u00ebr asgj\u00eb nga Continuous Integration: nuk kishte asnj\u00eb me t\u00eb cilin t\u00eb integrohej.<\/p>\n<p>Por aplikacioni u rrit, shfaqeshin gjithnj\u00eb e m\u00eb shum\u00eb detyra t\u00eb reja, p\u00ebr pasoj\u00eb rritej ekipi. N\u00eb nj\u00eb \u00e7ast, erdhi koha p\u00ebr t\u00eb organizuar m\u00eb formalisht procesin e integrimit t\u00eb kodit. U vendos t\u00eb p\u00ebrdorej Git flow.<\/p>\n<p><img decoding=\"async\" alt=\"Evolucioni i CI n\u00eb ekipin e zhvillimit t\u00eb aplikacioneve\" src=\"\/wp-content\/uploads\/2019\/04\/f433effc5ab5a59de3d6bd20a7a87057.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nKoncepcioni i Git flow \u00ebsht\u00eb i njohur: n\u00eb projekt ka nj\u00eb deg\u00eb t\u00eb zakonshme develop, dhe p\u00ebr \u00e7do karakteristik\u00eb t\u00eb re, zhvilluesit krijojn\u00eb nj\u00eb deg\u00eb t\u00eb ve\u00e7ant\u00eb, e komitojn\u00eb aty, e pushojn\u00eb, dhe, kur duan t\u00eb integrojn\u00eb kodin e tyre n\u00eb deg\u00ebn develop, hapin nj\u00eb pull request. P\u00ebr t'u shk\u00ebmbyer dije dhe p\u00ebr t\u00eb diskutuar qasje, kemi futur kontrollin e kodit, q\u00eb do t\u00eb thot\u00eb q\u00eb koleg\u00ebt duhet t\u00eb verifikojn\u00eb dhe t\u00eb konfirmojn\u00eb kodin e nj\u00ebri-tjetrit.<\/p>\n<h2>Kontrolli<\/h2>\n<p>\nT\u00eb shikosh kodin me sy \u00ebsht\u00eb e shk\u00eblqyer, por e pamjaftueshme. Prandaj futen kontrollet 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>, q\u00eb t\u00eb p\u00ebrfitojm\u00eb nga testet.<\/li>\n<\/ul>\n<p>\nP\u00ebr t\u00eb kuptuar se si duhet t\u00eb ekzekutohen k\u00ebto kontrolle, do t\u00eb shikojm\u00eb 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 nd\u00ebrlidhen kontrollet e integrimit k\u00ebtu \u2014 ose me nj\u00eb hook komiti, ose thjesht duke e ekzekutuar kontrollin n\u00eb sfond.<\/li>\n<li>Pas pushimit t\u00eb kodit nga zhvilluesi, ai hap nj\u00eb pull request. P\u00ebr t\u00eb kaluar kodin e tij n\u00eb deg\u00ebn develop, \u00ebsht\u00eb e nevojshme t\u00eb kalojm\u00eb kontrollin e kodit dhe t\u00eb grumbullojm\u00eb numrin e duhur t\u00eb konfirmimeve. Mund t\u00eb aktivizoni kontrollet dhe nd\u00ebrtimet k\u00ebtu: derisa t\u00eb mos jen\u00eb t\u00eb suksesshme t\u00eb gjitha nd\u00ebrtimet, pull request-i nuk mund t\u00eb bashkohet.<\/li>\n<li>Pasi q\u00eb pull request-i \u00ebsht\u00eb lidhur dhe kodi ka kaluar n\u00eb develop, mund t\u00eb zgjedh\u00ebsh nj\u00eb koh\u00eb t\u00eb p\u00ebrshtatshme: p\u00ebr shembull, nat\u00ebn, kur t\u00eb gjitha server\u00ebt jan\u00eb t\u00eb lir\u00eb, dhe t\u00eb b\u00ebsh kontrollet sa t\u00eb duash.<\/li>\n<\/ul>\n<p>\nAskush nuk e p\u00eblqeu t\u00eb ekzekutoj\u00eb kontrollin n\u00eb laptopin e tij. Kur zhvilluesi p\u00ebrfundon nj\u00eb funksionalitet, ai d\u00ebshiron ta d\u00ebrgoj\u00eb sa m\u00eb shpejt dhe t\u00eb hap\u00eb nj\u00eb pull request. N\u00ebse n\u00eb at\u00eb moment nisin disa verifikime t\u00eb gjata, kjo jo vet\u00ebm q\u00eb nuk \u00ebsht\u00eb shum\u00eb e k\u00ebndshme, por edhe ngadal\u00ebson zhvillimin: nd\u00ebrsa laptopi b\u00ebn kontrolle, \u00ebsht\u00eb e pamundur t\u00eb punosh normalisht.<\/p>\n<p>Na p\u00eblqeu shum\u00eb t\u00eb b\u00ebnim kontrollet nat\u00ebn, sepse ka shum\u00eb koh\u00eb dhe server\u00eb, mund t\u00eb shfryt\u00ebzojm\u00eb sa t\u00eb duam. Por, fatkeq\u00ebsisht, kur kodi i funksionalitetit ka kaluar n\u00eb develop, zhvilluesi tashm\u00eb ka shum\u00eb m\u00eb pak motivim p\u00ebr t\u00eb rregulluar gabimet q\u00eb gjeti CI. Her\u00eb pas here e kapja veten duke menduar, kur shikoja n\u00eb raportin e m\u00ebngjesit p\u00ebr t\u00eb gjitha gabimet e gjetura, se do t\u2019i rregulloja ato ndonj\u00ebher\u00eb m\u00eb von\u00eb, sepse tani n\u00eb Jira ka nj\u00eb detyr\u00eb t\u00eb re super q\u00eb e d\u00ebshiroj t\u00eb filloj ta b\u00ebj.<\/p>\n<p>N\u00ebse kontrollet bllokojn\u00eb pull request-in, at\u00ebher\u00eb motivimi \u00ebsht\u00eb i mjaftuesh\u00ebm, sepse derisa nd\u00ebrtimet t\u00eb mos b\u00ebhen t\u00eb gjelbra, kodi nuk do t\u00eb kaloj\u00eb n\u00eb develop, e pra, detyra nuk do t\u00eb p\u00ebrfundoj\u00eb.<\/p>\n<p>N\u00eb fund, ne zgjodh\u00ebm nj\u00eb strategji t\u00eb till\u00eb: gjat\u00eb nat\u00ebs realizojm\u00eb sa m\u00eb shum\u00eb kontrolle t\u00eb mundshme, dhe verifikimet m\u00eb kritike dhe, mbi t\u00eb gjitha, ato q\u00eb jan\u00eb t\u00eb shpejta, i ekzekutojm\u00eb n\u00eb pull request. Por nuk ndalemi k\u00ebtu - paralelisht optimizojm\u00eb shpejt\u00ebsin\u00eb e kalimit t\u00eb kontrolleve n\u00eb m\u00ebnyr\u00eb q\u00eb t'i transferojm\u00eb ato nga moda e nat\u00ebs n\u00eb kontrollet p\u00ebr pull request.<\/p>\n<p>N\u00eb at\u00eb koh\u00eb, t\u00eb gjitha nd\u00ebrtimet tona kalonin mjaft shpejt, prandaj thjesht aktivizuam bllokuesin p\u00ebr pull request nd\u00ebrtimin ARK, testet Junit dhe llogaritjen e mbulimit t\u00eb kodit. Aktivizuam, menduam - dhe u dor\u00ebzuam nga mbulimi i kodit, sepse menduam se nuk na duhet.<\/p>\n<p><strong><em>P\u00ebr konfigurimin e baz\u00ebs CI, kemi nevojitur dy dit\u00eb (k\u00ebtu dhe m\u00eb tej, vler\u00ebsimi temporal \u00ebsht\u00eb p\u00ebraf\u00ebrsisht, nevojitet p\u00ebr shkall\u00ebn). <\/em><\/strong><\/p>\n<p>Pas k\u00ebsaj filluam t\u00eb mendojm\u00eb m\u00eb tej - a e kontrollojm\u00eb sakt\u00ebsisht? A e ekzekutojm\u00eb nd\u00ebrtimin n\u00eb pull request si\u00e7 duhet?<\/p>\n<p>Ne realizonim nd\u00ebrtimin n\u00eb commitin e fundit t\u00eb deg\u00ebs nga e cila ishte hapur pull request. Por kontrollimet e k\u00ebtij commit tregojn\u00eb vet\u00ebm se ai kod q\u00eb zhvilluesi shkroi punon. Por ato nuk d\u00ebshmojn\u00eb se ai nuk ka thyer asgj\u00eb. N\u00eb fakt, duhet t\u00eb kontrollojm\u00eb gjendjen e deg\u00ebs develop pasi q\u00eb ve\u00e7oria t\u00eb jet\u00eb e integruar n\u00eb t\u00eb.<\/p>\n<p><img decoding=\"async\" alt=\"Evolucioni i CI n\u00eb ekipin e zhvillimit t\u00eb aplikacioneve\" src=\"\/wp-content\/uploads\/2019\/04\/c1a179b68b02c04031177f9bf51a81ed.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nP\u00ebr k\u00ebt\u00eb shkak, ne kemi shkruar nj\u00eb skript 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 ndodhin t\u00eb gjitha ndryshimet m\u00eb t\u00eb reja nga develop dhe p\u00ebrfshihen n\u00eb deg\u00ebn aktuale. Ne e kemi shtuar skriptin premerge.sh si hapin e par\u00eb t\u00eb t\u00eb gjitha nd\u00ebrtimeve dhe kemi filluar t\u00eb kontrollojm\u00eb sakt\u00ebsisht at\u00eb q\u00eb duam, pra <strong>integrimin.<\/strong>.<\/p>\n<p><strong><em>P\u00ebr lokalizimin e problemeve, k\u00ebrkimin e zgjidhjeve dhe shkruajn\u00eb k\u00ebt\u00eb skript, kaluan tre dit\u00eb.<\/em><\/strong><\/p>\n<p>Aplikacioni u zhvillua, detyrat e reja rriteshin, ekipi u rrit, dhe premerge.sh filloi ndonj\u00ebher\u00eb t\u00eb na zhg\u00ebnjente. Ndryshimet konfliktuese hynin n\u00eb develop dhe thyenin nd\u00ebrtimin.<\/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 aplikacioneve\" src=\"\/wp-content\/uploads\/2019\/04\/6762d9ce4e431549455c49f2317a8f20.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDy zhvillues fillojn\u00eb t\u00eb punojn\u00eb nj\u00ebkoh\u00ebsisht n\u00eb funksionet A dhe B. Zhvilluesi i funksionit A zbulon nj\u00eb funksion t\u00eb pap\u00ebrdorur n\u00eb projekt <code>answer()<\/code> dhe, si nj\u00eb skaut i mir\u00eb, e fshin at\u00eb. Nd\u00ebrkoh\u00eb, zhvilluesi i funksionit 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. Nd\u00ebrtimet fillojn\u00eb, premerge.sh kontrollon t\u00eb dy pull request-et n\u00eb raport me gjendjen e fresk\u00ebt t\u00eb develop \u2014 t\u00eb gjitha kontrollet jan\u00eb t\u00eb gjelbra. Pas k\u00ebsaj, m\u00ebrgjohet pull request-i i funksionit A, m\u00ebrgjohet pull request-i i funksionit B\u2026 Bam! Develop thyhet, sepse n\u00eb kodin 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 aplikacioneve\" src=\"\/wp-content\/uploads\/2019\/04\/0261dcc9f7f2e5e018ab136081b4679b.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nKur nuk arrihet t\u00eb zhvillohet, kjo \u00ebsht\u00eb <strong>nj\u00eb katastrof\u00eb lokale<\/strong>. Ekipi i t\u00ebr\u00eb nuk mund t\u00eb mbledh\u00eb asgj\u00eb dhe ta dor\u00ebzoj\u00eb p\u00ebr testim.<\/p>\n<p>A ka ndodhur q\u00eb un\u00eb shpesh kam punuar n\u00eb detyra infrastrukturore: analiza, rrjeti, bazat e t\u00eb dh\u00ebnave. N\u00eb kuptimin q\u00eb un\u00eb shkruaja ato funksione dhe klasa q\u00eb p\u00ebrdorin zhvilluesit e tjer\u00eb. P\u00ebr k\u00ebt\u00eb arsye, shpesh kam r\u00ebn\u00eb n\u00eb situata t\u00eb ngjashme. Madje, nj\u00eb periudh\u00eb, kisha nj\u00eb imazh t\u00eb till\u00eb t\u00eb varur.<\/p>\n<p><img decoding=\"async\" alt=\"Evolucioni i CI n\u00eb ekipin e zhvillimit t\u00eb aplikacioneve\" src=\"\/wp-content\/uploads\/2019\/04\/0eb1aadd05b33ce995027ab52d5c1e53.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPasi kjo nuk na k\u00ebnaqte, filluam t\u00eb shqyrtonim mund\u00ebsi se si ta parandalojm\u00eb k\u00ebt\u00eb.<\/p>\n<h2>Si t\u00eb mos prishim zhvillimin<\/h2>\n<p>\nMund\u00ebsia e par\u00eb: <strong>r\u00ebnd\u00ebsia e rikonstruimit t\u00eb t\u00eb gjith\u00eb k\u00ebrkesave t\u00eb integrimit gjat\u00eb p\u00ebrdit\u00ebsimit t\u00eb zhvillimit. <\/strong>N\u00eb shembullin ton\u00eb, n\u00ebse k\u00ebrkesa e integrimit p\u00ebr karakteristik\u00ebn A do t\u00eb jet\u00eb e para n\u00eb zhvillim, k\u00ebrkesa e karakteristik\u00ebs B do t\u00eb rikonstruohet, dhe, p\u00ebr rrjedhoj\u00eb, verifikimet nuk do t\u00eb kalojn\u00eb p\u00ebr shkak t\u00eb gabimit t\u00eb kompilim.<\/p>\n<p>P\u00ebr t\u00eb kuptuar sa koh\u00eb do t\u00eb duhen p\u00ebr k\u00ebt\u00eb, le t\u00eb shqyrtojm\u00eb nj\u00eb shembull me dy PR. Hapim dy PR: dy nd\u00ebrtime, dy kthime verifikimesh. Pas p\u00ebrfshirjes s\u00eb PR t\u00eb par\u00eb n\u00eb zhvillim, e dyta duhet t\u00eb rikonstruohet. Pra, p\u00ebr dy PR ne nevojitim tre kthime verifikimesh: 2 + 1 = 3.<\/p>\n<p>N\u00eb thelb, \u00ebsht\u00eb n\u00eb rregull. Por ne shikuam statistikat, dhe situata tipike n\u00eb ekipin ton\u00eb kishte 10 PR t\u00eb hapura, dhe numri i verifikimeve \u00ebsht\u00eb shuma e progresionit: 10 + 9 +\u2026 + 1 = 55. Pra, p\u00ebr t\u00eb pranuar 10 PR, duhet t\u00eb rikomandojm\u00eb 55 her\u00eb. Dhe kjo \u00ebsht\u00eb n\u00eb situat\u00ebn ideale, kur t\u00eb gjitha verifikimet kalojn\u00eb p\u00ebr her\u00eb t\u00eb par\u00eb, kur askush nuk hap nj\u00eb pull request shtes\u00eb gjat\u00eb procesimit t\u00eb k\u00ebtyre dhjet\u00eb.<\/p>\n<p>Imagjinoni veten si nj\u00eb zhvillues q\u00eb duhet t\u00eb p\u00ebrpiqet t\u00eb shtyp\u00eb butonin 'merge' i pari, sepse n\u00ebse e b\u00ebn fqinj\u00eb, do t\u00eb duhet t\u00eb pres\u00eb derisa t\u00eb kalojn\u00eb t\u00eb gjitha nd\u00ebrtimet p\u00ebrs\u00ebri... Jo, k\u00ebshtu nuk shkon, kjo do ta ngadal\u00ebsonte seriozisht zhvillimin.<\/p>\n<p>Nj\u00eb mund\u00ebsi tjet\u00ebr: <strong>t\u00eb nd\u00ebrtojm\u00eb pull request pas shqyrtimit t\u00eb kodit. <\/strong>Pra ndaj, hapni nj\u00eb pull request, mblidhni numrin e nevojsh\u00ebm t\u00eb aprovimeve nga koleg\u00ebt, realizoni ndryshimet e nevojshme, dhe pastaj filloni nd\u00ebrtimet. N\u00ebse ato jan\u00eb t\u00eb suksesshme, pull request-i bashkohet me develop. N\u00eb k\u00ebt\u00eb rast, nuk ka nevoj\u00eb p\u00ebr ringjallje t\u00eb m\u00ebtejshme, por ngadal\u00ebson shum\u00eb reagimin. Un\u00eb, si zhvillues, kur hap nj\u00eb pull request, dua t\u00eb shoh menj\u00ebher\u00eb n\u00ebse ai nd\u00ebrtokohet. P\u00ebr shembull, n\u00ebse ndonj\u00eb test d\u00ebshton, duhet ta riparoj shpejt. N\u00eb rastin e nd\u00ebrtimit t\u00eb vonuar, reagimi ngadal\u00ebsohet, \u00e7ka do t\u00eb thot\u00eb se e gjith\u00eb zhvillimi po ngadal\u00ebsohet. Kjo gjithashtu nuk na p\u00ebrmbushte.<\/p>\n<p>M\u00eb n\u00eb fund, mbeti vet\u00ebm varianti i tret\u00eb \u2014 <strong>t\u00eb riciklohet<\/strong>. I gjith\u00eb kodi yn\u00eb, t\u00eb gjitha burimet tona ruhen n\u00eb nj\u00eb depozit\u00eb n\u00eb serverin Bitbucket. Prandaj, 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 aplikacioneve\" src=\"\/wp-content\/uploads\/2019\/04\/5e4b1f770ea1a3449b616c3101640294.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n\u042d\u0442\u043e\u0442 \u043f\u043b\u0430\u0433\u0438\u043d \u043f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0441\u043b\u0438\u044f\u043d\u0438\u044f pull request&#8217;\u043e\u0432. \u041d\u0430\u0447\u0430\u043b\u043e \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0435: \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442\u0441\u044f PR, \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u044e\u0442\u0441\u044f \u0432\u0441\u0435 \u0441\u0431\u043e\u0440\u043a\u0438, \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442 code review. \u041d\u043e \u043f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a code review \u043f\u0440\u043e\u0439\u0434\u0435\u043d, \u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0440\u0435\u0448\u0430\u0435\u0442 \u043d\u0430\u0436\u0430\u0442\u044c \u043d\u0430 \u00abmerge\u00bb, \u043f\u043b\u0430\u0433\u0438\u043d \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442, \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043a\u0430\u043a\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f develop \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u043b\u0438\u0441\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438. \u0415\u0441\u043b\u0438 \u043f\u043e\u0441\u043b\u0435 \u0431\u0438\u043b\u0434\u043e\u0432 develop \u0443\u0441\u043f\u0435\u043b \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c\u0441\u044f, \u043f\u043b\u0430\u0433\u0438\u043d \u043d\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u0432\u043b\u0438\u0442\u044c \u0442\u0430\u043a\u043e\u0439 pull request \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u0443\u044e \u0432\u0435\u0442\u043a\u0443. \u041e\u043d \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442 \u0431\u0438\u043b\u0434\u044b \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0441\u0432\u0435\u0436\u0435\u0433\u043e develop.<\/p>\n<p><img decoding=\"async\" alt=\"Evolucioni i CI n\u00eb ekipin e zhvillimit t\u00eb aplikacioneve\" 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 kalojn\u00eb p\u00ebr shkak t\u00eb nj\u00eb gabimi n\u00eb kompilim. Prandaj, zhvilluesi i ve\u00e7oris\u00eb B do t\u00eb duhet t\u00eb rregulloj\u00eb kodin, t\u00eb rilan\u00e7oj\u00eb kontrollimet, at\u00ebher\u00eb plugin automatikisht do t\u00eb aplikoj\u00eb k\u00ebrkes\u00ebn p\u00ebr t\u00ebrheqje.<\/p>\n<p>Para p\u00ebrdorimit t\u00eb k\u00ebtij plani, kishim mesatarisht 2,7 lan\u00e7ime kontrolli p\u00ebr \u00e7do k\u00ebrkes\u00eb t\u00ebrheqjeje. Me pluginin, tani kemi 3,6 lan\u00e7ime. Kjo na p\u00ebrshtatet.<\/p>\n<p>\u00cbsht\u00eb e r\u00ebnd\u00ebsishme t\u00eb theksohet se ky plug-in ka nj\u00eb disavantazh: ai rikthen nd\u00ebrtimin vet\u00ebm nj\u00eb her\u00eb. Kjo do t\u00eb thot\u00eb se ende ka nj\u00eb dritare t\u00eb vog\u00ebl p\u00ebrmes s\u00eb cil\u00ebs mund t\u00eb kalojn\u00eb ndryshime konfliktuale n\u00eb develop. Por probabiliteti i k\u00ebsaj \u00ebsht\u00eb i ul\u00ebt, dhe ne b\u00ebm\u00eb k\u00ebt\u00eb kompromis midis numrit t\u00eb ekzekutimeve dhe probabilitetit t\u00eb d\u00ebshtimit. Gjat\u00eb dy viteve ndodhi vet\u00ebm nj\u00ebher\u00eb, k\u00ebshtu q\u00eb ndoshta nuk ishte kot.<\/p>\n<p><strong><em>Na u desh\u00ebn dy jav\u00eb p\u00ebr t\u00eb shkruar versionin e par\u00eb t\u00eb plug-in-it p\u00ebr Bitbucket. <\/em><\/strong><\/p>\n<h3>Kontrollime t\u00eb reja<\/h3>\n<p>\nNd\u00ebrkoh\u00eb, ekipi yn\u00eb vazhdoi t\u00eb rritej. U shtuan kontrollime t\u00eb reja.<\/p>\n<p>Menduam: p\u00ebrse t\u00eb riparojm\u00eb gabimet, n\u00ebse mund t'i parandalojm\u00eb ato? Dhe prandaj implementuam <strong>analiz\u00ebn statike t\u00eb kodit<\/strong>. Filluam me lint, q\u00eb \u00ebsht\u00eb pjes\u00eb e Android SDK. Por n\u00eb at\u00eb koh\u00eb nuk dinte t\u00eb punonte me kodin Kotlin, dhe ne kishim tashm\u00eb 75% t\u00eb aplikacionit t\u00eb shkruar n\u00eb Kotlin. Prandaj, lint-it iu shtuan <strong>kontrollimet e Android Studio.<\/strong><\/p>\n<p>P\u00ebr k\u00ebt\u00eb na duhej t\u00eb shtremb\u00ebronim shum\u00eb: t\u00eb marrim Android Studio, ta paketojm\u00eb n\u00eb Docker dhe ta ekzekutojm\u00eb n\u00eb CI me nj\u00eb monitor virtual, p\u00ebr ta b\u00ebr\u00eb ta mendoj\u00eb se \u00ebsht\u00eb hapur n\u00eb nj\u00eb laptop t\u00eb v\u00ebrtet\u00eb. Por kjo funksiononte.<\/p>\n<p>Gjithashtu gjat\u00eb k\u00ebsaj kohe filluam t\u00eb shkruajm\u00eb shum\u00eb <strong>teste instrumentation<\/strong> dhe implementuam <strong>testimi me skrinshot<\/strong>. Kjo \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 q\u00eb t\u00eb merret nj\u00eb skrinshot nga pamja dhe t\u00eb krahasohet me referenc\u00ebn piksel p\u00ebr piksel. N\u00ebse ka ndonj\u00eb dallim, at\u00ebher\u00eb ndonj\u00ebher\u00eb dizajni ka devijuar ose di\u00e7ka nuk \u00ebsht\u00eb n\u00eb rregull me stilet.<\/p>\n<p>Por testet e instrumentimit dhe testet me skrinshot duhet t\u00eb ekzekutohen n\u00eb pajisje: n\u00eb emulator\u00eb ose n\u00eb pajisje t\u00eb v\u00ebrteta. Duke marr\u00eb parasysh se ka shum\u00eb teste dhe ato ekzekutohen shpesh, nevojitet nj\u00eb ferm\u00eb e t\u00ebr\u00eb. T\u00eb krijosh ferm\u00ebn t\u00ebnde \u00ebsht\u00eb shum\u00eb e lodhshme, prandaj ne gjet\u00ebm nj\u00eb variant t\u00eb gatsh\u00ebm \u2014 Firebase Test Lab.<\/p>\n<h3>Firebase Test Lab<\/h3>\n<p>\nu zgjodh sepse Firebase \u00ebsht\u00eb nj\u00eb produkt i Google, pra duhet t\u00eb jet\u00eb i besuesh\u00ebm dhe \u00ebsht\u00eb e dyshimt\u00eb q\u00eb do t\u00eb shuhet ndonj\u00ebher\u00eb. \u00c7mimet jan\u00eb t\u00eb arsyeshme: 5$ p\u00ebr \u00e7do or\u00eb pun\u00eb t\u00eb nj\u00eb pajisjeje reale, 1$ p\u00ebr \u00e7do or\u00eb pun\u00eb t\u00eb nj\u00eb emulatori.<\/p>\n<p><strong><em>Implementimi i Firebase Test Lab n\u00eb CI-n\u00eb ton\u00eb zuri rreth tre jav\u00eb.<\/em><\/strong><\/p>\n<p>Por megjithat\u00eb, ekipi vazhdoi t\u00eb rritet, dhe Firebase, fatkeq\u00ebsisht, filloi t\u00eb na jap\u00eb probleme. N\u00eb at\u00eb koh\u00eb, ai nuk kishte asnj\u00eb SLA. Ndodhte q\u00eb Firebase na b\u00ebnte t\u00eb prisnim derisa t\u00eb lironte numrin e nevojsh\u00ebm t\u00eb pajisjeve p\u00ebr testim, dhe nuk nisi menj\u00ebher\u00eb si\u00e7 d\u00ebshironim. Pritja n\u00eb radh\u00eb zgjaste deri n\u00eb gjysm\u00eb ore, q\u00eb ishte tep\u00ebr e gjat\u00eb. Testet e Instrumentacionit kryheshin n\u00eb \u00e7do PR, vonesat e ngadal\u00ebsuan zhvillimin, dhe m\u00eb pas erdhi faturimi p\u00ebr muajin me nj\u00eb shum\u00eb t\u00eb madhe. N\u00eb p\u00ebrgjith\u00ebsi, u vendos q\u00eb t\u00eb hiqnim dor\u00eb nga Firebase dhe t\u00eb zhvillonim n\u00eb sht\u00ebpi, duke qen\u00eb se ekipi kishte arritur nj\u00eb madh\u00ebsi t\u00eb mjaftueshme.<\/p>\n<h3>Docker + Python + bash<\/h3>\n<p>\nMorr\u00ebm docker, vendos\u00ebm n\u00eb t\u00eb emulator\u00ebt, shkruam nj\u00eb program t\u00eb thjesht\u00eb n\u00eb Python, i cili n\u00eb momentin e duhur aktivizon numrin e nevojsh\u00ebm t\u00eb emulator\u00ebve n\u00eb versionin e duhur dhe kur \u00ebsht\u00eb e nevojshme i ndalon. Dhe, sigurisht, disa skripte bash \u2014 ku mund t\u00eb shkoj\u00eb pa to?<\/p>\n<p><strong><em>Krijimi i nj\u00eb mjedisi testimi t\u00eb vet \u00ebsht\u00eb marr\u00eb pes\u00eb jav\u00eb.<\/em><\/strong><\/p>\n<p>Si rezultat, p\u00ebr \u00e7do k\u00ebrkes\u00eb p\u00ebr t\u00ebrheqje kishte nj\u00eb list\u00eb t\u00eb gjer\u00eb dhe bllokuese t\u00eb kontrollit:<\/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 Screenshot.<\/li>\n<\/ul>\n<p>\nKjo parandaloi shum\u00eb prishje t\u00eb mundshme. Teknikisht gjith\u00e7ka funksiononte, por zhvilluesit ankohej se pritja p\u00ebr rezultatet ishte tep\u00ebr e gjat\u00eb.<\/p>\n<p>Sa e gjat\u00eb \u00ebsht\u00eb 'tep\u00ebr e gjat\u00eb'? Ne e eksportuam 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>. Pra, zhvilluesi, kur hap nj\u00eb pull request, mesatarisht pret rezultatet e nd\u00ebrtimit p\u00ebr 45 minuta. N\u00eb mendimin tim, kjo \u00ebsht\u00eb shum\u00eb, dhe nuk mund t\u00eb punojm\u00eb k\u00ebshtu.<\/p>\n<p>Sigurisht, ne vendos\u00ebm t\u00eb p\u00ebrshpejtojm\u00eb t\u00eb gjitha nd\u00ebrtimet tona.<\/p>\n<h2>Po e p\u00ebrshpejtojm\u00eb<\/h2>\n<p>\nDuke par\u00eb se nd\u00ebrtimet shpesh ishin n\u00eb pritje, ne s\u00eb pari <strong>blem\u00eb pajisje shtes\u00eb<\/strong> \u2014 zgjerimi intensiv \u00ebsht\u00eb m\u00eb e thjesht\u00eb. Nd\u00ebrtimet nuk ishin m\u00eb n\u00eb pritje, por koha e pritjes u ul vet\u00ebm pak, sepse disa kontrolle vet\u00eb zgjatnin shum\u00eb.<\/p>\n<h3>Eliminojm\u00eb kontrollet shum\u00eb t\u00eb gjata<\/h3>\n<p>\nIntegrimi yn\u00eb i vazhduesh\u00ebm mund t\u00eb kapte k\u00ebto lloje gabimesh dhe problem.<\/p>\n<ul>\n<li><strong>Nuk po nd\u00ebrtohet<\/strong>. CI mund t\u00eb kap\u00eb nj\u00eb gabim kompilimi, kur p\u00ebr shkak t\u00eb ndryshimeve konfuze di\u00e7ka nuk nd\u00ebrtohet. Si\u00e7 e thash\u00eb, at\u00ebher\u00eb askush nuk mund t\u00eb nd\u00ebrtoj\u00eb asgj\u00eb, zhvillimi ndalon, dhe t\u00eb gjith\u00eb jan\u00eb t\u00eb shqet\u00ebsuar.<\/li>\n<li><strong>Gabim n\u00eb sjellje<\/strong>. P\u00ebr shembull, kur aplikacioni nd\u00ebrtohet, por kur klikoni n\u00eb buton bie, ose butoni nuk reagon 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\u00ebzhvendosur 10 piksele n\u00eb t\u00eb majt\u00eb.<\/li>\n<li><strong>Rritja e borxhit teknik<\/strong>.<\/li>\n<\/ul>\n<p>\nDuke par\u00eb k\u00ebt\u00eb list\u00eb, kuptuam se vet\u00ebm dy pikat e para jan\u00eb kritike. K\u00ebto probleme duam t'i kapim n\u00eb radh\u00eb t\u00eb par\u00eb. Gabimet n\u00eb dizajn zbulohet n\u00eb faz\u00ebn e shqyrtimit t\u00eb projektit dhe at\u00ebher\u00eb jan\u00eb leht\u00ebsisht t\u00eb rregullueshme. Puna me borxhin teknik k\u00ebrkon nj\u00eb proces dhe planifikim t\u00eb ve\u00e7ant\u00eb, prandaj vendos\u00ebm t\u00eb mos e kontrollonim at\u00eb n\u00eb pull request.<\/p>\n<p>Duke u nisur nga kjo klasifikim, ne rishikoi t\u00eb gjith\u00eb list\u00ebn e kontrollit. <strong>E hoq\u00ebm Lint<\/strong> dhe e transferuam ekzekutimin e tij p\u00ebr nat\u00ebn: thjesht q\u00eb t\u00eb jepte nj\u00eb raport p\u00ebr numrin e problemeve n\u00eb projekt. Me borxhin teknik u dakorduam t\u00eb punojm\u00eb ve\u00e7mas, dhe <strong>i hoq\u00ebm krejt\u00ebsisht Android Studio checks<\/strong>. Android Studio n\u00eb Docker p\u00ebr t\u00eb ekzekutuar inspektime ting\u00ebllon interesante, por sjell shum\u00eb probleme n\u00eb mb\u00ebshtetje. \u00c7do p\u00ebrdit\u00ebsim i versioneve t\u00eb Android Studio \u00ebsht\u00eb nj\u00eb luft\u00eb me p\u00ebrfundime t\u00eb paqarta. Po ashtu, ishte e v\u00ebshtir\u00eb t\u00eb mbaheshin testet e ekranit, sepse biblioteka nuk punonte shum\u00eb stabilisht, ndodhnin goditje t\u00eb gabuara. <strong>Testet e ekranit jan\u00eb hequr nga lista e verifikimeve.<\/strong>.<\/p>\n<p>N\u00eb fund 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>Cache i larg\u00ebt i Gradle.<\/h3>\n<p>\nPa verifikime t\u00eb r\u00ebnda, \u00e7do gj\u00eb u b\u00eb m\u00eb mir\u00eb. Por nuk ka kufij p\u00ebr p\u00ebrsosm\u00ebri!<\/p>\n<p>Aplikacioni yn\u00eb tashm\u00eb ishte i ndar\u00eb n\u00eb rreth 150 modulet gradle. Zakonisht n\u00eb nj\u00eb rast t\u00eb till\u00eb, cache i larg\u00ebt i Gradle punon mir\u00eb, prandaj vendos\u00ebm ta provojm\u00eb at\u00eb.<\/p>\n<p>Cache i larg\u00ebt i Gradle \u00ebsht\u00eb nj\u00eb sh\u00ebrbim q\u00eb mund t\u00eb ruaj\u00eb artefaktet e nd\u00ebrtimit p\u00ebr detyra t\u00eb ve\u00e7anta n\u00eb modulet e ve\u00e7anta. Gradle, n\u00eb vend q\u00eb t\u00eb kompilonte n\u00eb t\u00eb v\u00ebrtet\u00eb kodin, godet cache-in e larg\u00ebt p\u00ebrmes HTTP dhe pyet n\u00ebse dikush e ka kryer tashm\u00eb k\u00ebt\u00eb detyr\u00eb. N\u00ebse po, thjesht shkarkon rezultatin.<\/p>\n<p><strong><em>T\u00eb nis\u00ebsh cache-in e larg\u00ebt t\u00eb Gradle \u00ebsht\u00eb e leht\u00eb, sepse Gradle ofron nj\u00eb imazh Docker. Na arriti ta b\u00ebnim k\u00ebt\u00eb p\u00ebr tre or\u00eb.<\/em><\/strong><\/p>\n<p>Mjaftonte t\u00eb nisje Docker dhe t\u00eb shkruaje nj\u00eb rresht n\u00eb projekt. Megjithat\u00eb, megjith\u00ebse mund ta fillosh shpejt, p\u00ebr t\u00eb siguruar q\u00eb gjith\u00e7ka t\u00eb funksionoj\u00eb mir\u00eb do t\u00eb k\u00ebrkoj\u00eb mjaft koh\u00eb.<\/p>\n<p>M\u00eb posht\u00eb \u00ebsht\u00eb grafiku i humbjeve t\u00eb cache-it.<\/p>\n<p><img decoding=\"async\" alt=\"Evolucioni i CI n\u00eb ekipin e zhvillimit t\u00eb aplikacioneve\" src=\"\/wp-content\/uploads\/2019\/04\/458ef23b5506b04f3bd385be0c18607a.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nN\u00eb fillim, p\u00ebrqindja e humbjeve t\u00eb cache-it ishte af\u00ebrsisht 65. Pas tri jav\u00ebsh, arrit\u00ebm ta ulim k\u00ebt\u00eb vler\u00eb n\u00eb 20%. Doli se detyrat q\u00eb mblidhte aplikacioni Android kishin var\u00ebsi tranzitive t\u00eb \u00e7uditshme, p\u00ebr shkak t\u00eb t\u00eb cilave Gradle humbiste nga cache-i.<\/p>\n<p>Duke lidhur cache-in, ne ndjesh\u00ebm p\u00ebrshpejtuam nd\u00ebrtimin. Por p\u00ebrve\u00e7 nd\u00ebrtimit, po ekzekutohen gjithashtu testet e instrumentation-it, t\u00eb cilat k\u00ebrkojn\u00eb koh\u00eb t\u00eb gjat\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 modul\u00ebt e Gradle q\u00eb jan\u00eb ndryshuar.<\/p>\n<p><img decoding=\"async\" alt=\"Evolucioni i CI n\u00eb ekipin e zhvillimit t\u00eb aplikacioneve\" 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 instrumentation-it q\u00eb kontrollojn\u00eb modul\u00ebt e ndryshuar dhe t\u00eb gjith\u00eb modul\u00ebt q\u00eb varen nga ata. Nuk ka kuptim t\u00eb ekzekutohen testet p\u00ebr modulet fqinj: aty nuk ka ndryshuar kodi dhe asgj\u00eb nuk mund t\u00eb prishet.<\/p>\n<p>Me testet e instrumentation nuk \u00ebsht\u00eb aq e thjesht\u00eb, pasi ato duhet t\u00eb jen\u00eb n\u00eb modulin m\u00eb t\u00eb lart\u00eb t\u00eb aplikacionit. Ne kemi aplikuar nj\u00eb heuristik\u00eb me analiz\u00ebn e byte-code p\u00ebr t\u00eb kuptuar se cili modul i p\u00ebrket \u00e7donj\u00ebri test.<\/p>\n<p><strong><em>Modernizimi i funksionimit t\u00eb testeve t\u00eb instrumentation, n\u00eb m\u00ebnyr\u00eb q\u00eb ato t\u00eb kontrollonin vet\u00ebm modul\u00ebt e angazhuar, zuri rreth tet\u00eb jav\u00eb.<\/em><\/strong><\/p>\n<p>Masat p\u00ebr shkurtimin e verifikimeve funksionuan me sukses. Nga 45 minuta, arrit\u00ebm p\u00ebraf\u00ebrsisht n\u00eb 15. Nj\u00eb \u00e7erek ore p\u00ebr t\u00eb pritur nd\u00ebrtimin tani \u00ebsht\u00eb normale.<\/p>\n<p>Por tani zhvilluesit filluan t\u00eb ankoheshin se nuk ishte e qart\u00eb se cilat nd\u00ebrtime po ekzekutoheshin, ku t\u00eb shihnin logun, pse nd\u00ebrtimi ishte i kuq, cili test kishte d\u00ebshtuar, etj.<\/p>\n<p><img decoding=\"async\" alt=\"Evolucioni i CI n\u00eb ekipin e zhvillimit t\u00eb aplikacioneve\" src=\"\/wp-content\/uploads\/2019\/04\/aa76151174cd4e5a45ff281818e312f5.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nProblemet me informacionin e kthyer ngadal\u00ebsojn\u00eb zhvillimin, prandaj ne p\u00ebrpiqeshim t\u00eb ofronim informacionin m\u00eb t\u00eb kuptuesh\u00ebm dhe t\u00eb detajuar p\u00ebr \u00e7do PR dhe nd\u00ebrtim. Filluam me komente n\u00eb Bitbucket p\u00ebr PR duke treguar se cili nd\u00ebrtim kishte d\u00ebshtuar dhe pse, dhe d\u00ebrguam mesazhe adresore 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 po ekzekutohen aktualisht dhe gjendjen e tyre: n\u00eb radh\u00eb, ekzekutohet, ka d\u00ebshtuar ose ka p\u00ebrfunduar. Mund t\u00eb klikoni n\u00eb nd\u00ebrtim dhe t\u00eb shkoni n\u00eb logun e tij.<\/p>\n<p><img decoding=\"async\" alt=\"Evolucioni i CI n\u00eb ekipin e zhvillimit t\u00eb aplikacioneve\" src=\"\/wp-content\/uploads\/2019\/04\/2d16b7a6b6d23e23903d291ef1526999.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n<strong><em>I ishte shpenzuar gjasht\u00eb jav\u00eb p\u00ebr nj\u00eb feedback 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. Pas zgjidhjes s\u00eb \u00e7\u00ebshtjes s\u00eb 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 emulatoreve. Kur ka shum\u00eb teste dhe emulatore, \u00ebsht\u00eb e v\u00ebshtir\u00eb t\u00eb menaxhohen ato. Si rezultat, t\u00eb gjith\u00eb emulator\u00ebt tan\u00eb u zhvendos\u00ebn n\u00eb klastrin k8s me menaxhim fleksib\u00ebl t\u00eb burimeve.<\/p>\n<p>P\u00ebrve\u00e7 k\u00ebsaj, ka edhe plane t\u00eb tjera.<\/p>\n<ul>\n<li><strong>Kthe Lint<\/strong> (dhe analiz\u00ebn e tjera statike). Ne tashm\u00eb po punojm\u00eb n\u00eb k\u00ebt\u00eb drejtim.<\/li>\n<li>T\u00eb ekzekutojm\u00eb t\u00eb gjitha <strong>testet end-to-end<\/strong> n\u00eb t\u00eb gjitha versionet e SDK.<\/li>\n<\/ul>\n<p>\nPra, ndoq\u00ebm historin\u00eb e zhvillimit t\u00eb Continuous Integration n\u00eb Avito. Tani dua t\u00eb jap disa k\u00ebshilla nga k\u00ebndv\u00ebshtrimi i nj\u00eb profesionisti.<\/p>\n<h1>K\u00ebshilla<\/h1>\n<p>\nN\u00ebse do t\u00eb mund t\u00eb jap vet\u00ebm nj\u00eb k\u00ebshill\u00eb, kjo do t\u00eb ishte:<\/p>\n<blockquote><p>Ju lutem, kini kujdes me skriptet shell!<\/p><\/blockquote>\n<p>\nBash \u00ebsht\u00eb nj\u00eb mjet shum\u00eb fleksib\u00ebl dhe i fuqish\u00ebm, \u00ebsht\u00eb shum\u00eb e leht\u00eb dhe e shpejt\u00eb p\u00ebr t\u00eb shkruar skripte me t\u00eb. Por mund t\u00eb bjer\u00eb n\u00eb kurthe, dhe ne, fatkeq\u00ebsisht, r\u00ebn\u00eb n\u00eb t\u00eb.<\/p>\n<p>K\u00ebtu filloi gjith\u00e7ka me skriptet e thjeshta, t\u00eb cilat ekzekutoheshin n\u00eb makinat tona t\u00eb nd\u00ebrtimit:<\/p>\n<pre><code class=\"bash\">#!\/usr\/bin\/env bash\n.\/gradlew assembleDebug<\/code><\/pre>\n<p>\nMegjith\u00ebse, si\u00e7 dihet, gjith\u00e7ka zhvillohet dhe komplikohet me kalimin e koh\u00ebs - le t\u00eb ekzekutojm\u00eb nj\u00eb skript nga i tjet\u00ebr, le t\u00eb kalojm\u00eb disa parametra aty - n\u00eb fund, duhej t\u00eb shkruhej nj\u00eb funksion q\u00eb p\u00ebrcakton se n\u00eb cilin nivel t\u00eb thell\u00ebsis\u00eb s\u00eb bash-it ndodhemi tani p\u00ebr t\u00eb vendosur thonjzat e nevojsh\u00ebm p\u00ebr ta ekzekutuar.<\/p>\n<p><img decoding=\"async\" alt=\"Evolucioni i CI n\u00eb ekipin e zhvillimit t\u00eb aplikacioneve\" src=\"\/wp-content\/uploads\/2019\/04\/244a574f7b5d3b4fc77cfc4ccda2db69.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nA mund ta imagjinoni pun\u00ebn e domosdoshme p\u00ebr zhvillimin e atyre skripteve. K\u00ebshilloj t\u00eb mos bini n\u00eb k\u00ebt\u00eb kurth.<\/p>\n<p>\u00c7far\u00eb mund t\u00eb p\u00ebrdoret si z\u00ebvend\u00ebsim?<\/p>\n<ul>\n<li>\u00c7do gjuh\u00eb skriptimi. T\u00eb shkruash n\u00eb <strong>Python ose Kotlin Script<\/strong> \u00ebsht\u00eb m\u00eb e p\u00ebrshtatshme sepse kjo \u00ebsht\u00eb programim, jo skriptime.<\/li>\n<li>Ose t\u00eb p\u00ebrshkruani t\u00eb gjitha logjikat e nd\u00ebrtimit n\u00eb form\u00ebn e <strong>Custom gradle tasks<\/strong> p\u00ebr projektin tuaj.<\/li>\n<\/ul>\n<p>\nNe vendos\u00ebm t\u00eb zgjedhim variantin e dyt\u00eb dhe tani po fshijm\u00eb me kujdes t\u00eb gjith\u00eb skriptet bash dhe po shkruajm\u00eb shum\u00eb gradle-tasks t\u00eb personalizuara.<\/p>\n<p><strong>K\u00ebshilla \u21162: mbani infrastruktur\u00ebn n\u00eb kod.<\/strong><\/p>\n<p>\u00cbsht\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 n\u00eb form\u00ebn e skedar\u00ebve tekstual\u00eb direkt n\u00eb repositorin e projektit. Kjo ofron versionim. Nuk do t\u00eb jet\u00eb e v\u00ebshtir\u00eb t\u00eb rikthehesh ose t\u00eb ndash kodin n\u00eb nj\u00eb deg\u00eb tjet\u00ebr.<\/p>\n<p>Skriptet mund t\u00eb ruhen n\u00eb projekt. Por \u00e7far\u00eb t\u00eb b\u00ebjm\u00eb me ambientin?<\/p>\n<p><strong>K\u00ebshilla \u21163: Docker mund t\u00eb ndihmoj\u00eb me ambientin.<\/strong><\/p>\n<p>P\u00ebr zhvilluesit Android, ai padyshim do t\u00eb ndihmoj\u00eb, p\u00ebr iOS, fatkeq\u00ebsisht, ende jo.<\/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 Librarit\u00eb\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>\nDuke shkruar k\u00ebt\u00eb docker file (do t'ju tregoj nj\u00eb sekret, nuk \u00ebsht\u00eb e nevojshme ta shkruani, mund ta shkarkoni nj\u00eb t\u00eb gatsh\u00ebm nga GitHub) dhe duke nd\u00ebrtuar imazhin, ju merrni nj\u00eb makin\u00eb virtuale, n\u00eb t\u00eb cil\u00ebn mund t\u00eb nd\u00ebrtoni aplikacione dhe t\u00eb ekzekutoni testet Junit.<\/p>\n<p>Dy argumentet kryesore pse ka kuptim: shkall\u00ebzueshm\u00ebria dhe p\u00ebrs\u00ebritshm\u00ebria. Me p\u00ebrdorimin e Docker-it, mund t\u00eb ngrini shpejt nj\u00eb duzin\u00eb agjent\u00ebsh nd\u00ebrtimi, t\u00eb cil\u00ebt do t\u00eb ken\u00eb t\u00eb nj\u00ebjt\u00ebn mjedis si ai i m\u00ebparshmi. Kjo leht\u00ebson shum\u00eb jet\u00ebn e inxhinier\u00ebve CI. T\u00eb vendosni android-sdk n\u00eb Docker \u00ebsht\u00eb shum\u00eb e thjesht\u00eb, me emulator\u00ebt pak m\u00eb t\u00eb nd\u00ebrlikuar: do t'ju duhet t\u00eb b\u00ebni pak p\u00ebrpjekje (ose s\u00ebrish t\u00eb shkarkoni nj\u00eb projekt t\u00eb gatsh\u00ebm nga GitHub).<\/p>\n<p><strong>K\u00ebshilla nr. 4: mos harroni se kontrollimet b\u00ebhen jo p\u00ebr shkak t\u00eb kontrollimeve, por p\u00ebr njer\u00ebzit.<\/strong><\/p>\n<p>P\u00ebr zhvilluesit, feedback-i i shpejt\u00eb dhe, mbi t\u00eb gjitha, i qart\u00eb \u00ebsht\u00eb shum\u00eb i r\u00ebnd\u00ebsish\u00ebm: \u00e7far\u00eb ka shkuar keq, cili test ka d\u00ebshtuar, ku mund t\u00eb shihni log-un e nd\u00ebrtimit.<\/p>\n<p><strong>K\u00ebshilla nr. 5: jini pragmatik n\u00eb zhvillimin e Integrimit t\u00eb Vazhdush\u00ebm.<\/strong><\/p>\n<p>Kuptoni qart\u00eb cil\u00ebt lloje gabimesh d\u00ebshironi t\u00eb parandaloni, sa resurse, koh\u00eb dhe koh\u00eb makinerike jeni t\u00eb gatsh\u00ebm t\u00eb shpenzoni. Kontrollimet shum\u00eb t\u00eb gjata mund, p\u00ebr shembull, t\u00eb zhvendosen p\u00ebr n\u00eb nat\u00eb. Nd\u00ebrsa nga ato q\u00eb kapin gabime t\u00eb par\u00ebnd\u00ebsishme, mund t\u00eb hiqni dor\u00eb plot\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 aplikacioneve\" 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 ka nevoj\u00eb t\u00eb mbani asgj\u00eb, thjesht paguani pak para, ngjitni aplikacionin tuaj dhe madje realizoni teste t\u00eb instrumentimit.<\/p>\n<p><strong>K\u00ebshilla \u21167: n\u00eb nj\u00eb ekip t\u00eb madh, zgjidhjet in-house jan\u00eb m\u00eb t\u00eb favorshme.<\/strong><\/p>\n<p>Mir\u00ebpo, her\u00eb pas here, me rritjen e ekipit, zgjidhjet in-house do t\u00eb b\u00ebhen m\u00eb t\u00eb favorshme. Ka nj\u00eb moment me k\u00ebto zgjidhje. N\u00eb ekonomi, ekziston ligji i kthimit n\u00eb r\u00ebnie: n\u00eb \u00e7do projekt, \u00e7do p\u00ebrmir\u00ebsim tjet\u00ebr b\u00ebhet gjithnj\u00eb e m\u00eb i v\u00ebshtir\u00eb, 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 Vazhdimsh\u00ebm. Kam nd\u00ebrtuar nj\u00eb grafik t\u00eb burimeve t\u00eb pun\u00ebs p\u00ebr \u00e7do faz\u00eb t\u00eb zhvillimit t\u00eb Integrimit ton\u00eb t\u00eb Vazhdimsh\u00ebm.<\/p>\n<p><img decoding=\"async\" alt=\"Evolucioni i CI n\u00eb ekipin e zhvillimit t\u00eb aplikacioneve\" src=\"\/wp-content\/uploads\/2019\/04\/97bf8bff64f3ac9ae587fae195251da2.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n\u00cbsht\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 Vazhdimsh\u00ebm 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, t\u00eb shpenzosh 50 dit\u00eb n\u00eb zhvillimin e nj\u00eb ferme t\u00eb brendshme t\u00eb simulator\u00ebve \u2014 \u00ebsht\u00eb ide e keqe. Por po ashtu, p\u00ebr nj\u00eb ekip t\u00eb madh, t\u00eb mos merresh fare me Integrimin e Vazhdimsh\u00ebm \u2014 \u00ebsht\u00eb gjithashtu nj\u00eb ide e keqe, sepse do t\u00eb shpenzosh edhe m\u00eb shum\u00eb koh\u00eb n\u00eb problemet e integrimit, riparimin e komunikimeve etj.<\/p>\n<p>Ne filluam duke e kuptuar se automatizimi \u00ebsht\u00eb i nevojsh\u00ebm, sepse njer\u00ebzit kushtojn\u00eb, ata gabojn\u00eb dhe jan\u00eb leniv. Por automatizimin e b\u00ebjn\u00eb gjithashtu njer\u00ebzit. Prandaj, t\u00eb gjitha k\u00ebto probleme i p\u00ebrkasin edhe automatizimit.<\/p>\n<ul>\n<li>Automatizimi \u00ebsht\u00eb i kushtuesh\u00ebm. Kujtoni grafik\u00ebt e konsumit t\u00eb pun\u00ebs.<\/li>\n<li>Gjat\u00eb automatizimit, njer\u00ebzit gabojn\u00eb.<\/li>\n<li>Ndonj\u00ebher\u00eb \u00ebsht\u00eb shum\u00eb leni p\u00ebr t\u00eb automatizuar, sepse gjith\u00e7ka funksionon si\u00e7 duhet. Pse duhet t\u00eb p\u00ebrmir\u00ebsojm\u00eb edhe di\u00e7ka tjet\u00ebr, pse t\u00eb gjith\u00eb ky Continuous Integration?<\/li>\n<\/ul>\n<p>\nPor kam statistik\u00eb: n\u00eb 20% t\u00eb kompilimeve zbulojm\u00eb gabime. Dhe kjo nuk ndodh sepse zhvilluesit tan\u00eb shkruajn\u00eb keq kodin. Kjo ndodh sepse zhvilluesit jan\u00eb t\u00eb bindur se, n\u00ebse ata b\u00ebjn\u00eb ndonj\u00eb gabim, ai nuk do t\u00eb shkoj\u00eb n\u00eb develop, do t\u00eb zbulohen nga kontrollet automatike. Prandaj, zhvilluesit mund t\u00eb shpenzojn\u00eb m\u00eb shum\u00eb koh\u00eb n\u00eb shkruarjen e kodit dhe gj\u00ebrat interesante, e jo t\u00eb testojn\u00eb di\u00e7ka lokalisht.<\/p>\n<p><strong>Merrni me Continuous Integration. Por me mas\u00eb.<\/strong><\/p>\n<blockquote><p>P\u00ebr m\u00eb tep\u00ebr, Nikolai Nesterov jo vet\u00ebm q\u00eb b\u00ebn prezantime t\u00eb shk\u00eblqyera, por \u00ebsht\u00eb gjithashtu pjes\u00eb e komitetit organizativ <noindex><a rel=\"nofollow\" href=\"https:\/\/appsconf.ru\/moscow\/2019\">AppsConf<\/a><\/noindex> dhe ndihmon t\u00eb tjer\u00ebt p\u00ebr t\u00eb p\u00ebrgatitur prezantime informuese p\u00ebr ju. Plot\u00ebsin\u00eb 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\">planin<\/a><\/noindex>. Dhe p\u00ebr detajet e tjera, erdhni m\u00eb 22-23 Prill n\u00eb Infop\u00ebrmbytjen.<\/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.0.1 - 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. \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\" \/>\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.0.1\" \/>\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. \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\" \/>\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 t\u00eb celular\u00ebve | ProHoster","description":"Sot, shumica e produkteve software zhvillohen n\u00eb grupe. Kushtet e suksesit t\u00eb zhvillimit n\u00eb ekip mund t\u00eb paraqiten n\u00eb nj\u00eb skem\u00eb t\u00eb thjesht\u00eb. Pasi t\u00eb keni shkruar kodin, duhet t\u00eb siguroheni se ai: Funksionon. Nuk d\u00ebmton asgj\u00eb, p\u00ebrfshir\u00eb kodin q\u00eb kan\u00eb shkruar koleg\u00ebt tuaj. N\u00ebse t\u00eb dy kushtet plot\u00ebsohen, at\u00ebher\u00eb jeni n\u00eb rrug\u00ebn e suksesit. P\u00ebr t\u00eb verifikuar leht\u00ebsisht k\u00ebto kushte dhe p\u00ebr t\u00eb mos u devijuar nga...","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. \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","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}]}}