Drejtori i operacioneve të portalit Banki.ru, Andrei Nikolsky, foli në konferencën e vitit të kaluar për shërbimet jetimë: si të identifikoni një jetim në infrastrukturë, çfarë janë të këqija shërbimet jetimë, çfarë të bëni me to dhe si të veproni nëse asgjë nuk ndihmon.
Poshtë është versione tekstuale e raportit.

Përshëndetje kolegë! Emri im është Andrei, udhëheq operacionet në kompaninë Banki.ru.
Ne kemi shërbime të mëdha, kjo është si monolitshërbime, kemi shërbime në një kuptim më klasik, dhe kemi të vogla tërësisht. Në terminologjinë time të punës, them që nëse një shërbim është i thjeshtë dhe i vogël, atëherë ai është mikro, dhe nëse ai nuk është shumë i thjeshtë dhe nuk është i vogël, atëherë ai është thjesht një shërbim.
Pikat pozitive të shërbimeve
Do të kaloj shpejt mbi pikat pozitive të shërbimeve.

E para — shkallëzimi. Mund të bëni diçka shpejt në shërbim dhe të nisni në prodhim. Ju erdhën trafiku, e klonuat shërbimin. Ju erdhën edhe më shumë trafik, e klonuat përsëri dhe me këtë jetoni. Ky është një bonus i shkëlqyer, dhe, në thelb, kur filluam, ai konsiderohej nga ne si më i rëndësishmi, përse e bëjmë të gjithë këtë.

Në të dytën, zhvillimi i izoluar, kur keni disa ekipe zhvillimi, disa zhvillues të ndryshëm në çdo ekip, dhe çdo ekip punon për shërbimin e vet.
Ka një nuancë me ekipet. Zhvilluesit janë të ndryshëm. Disa janë, për shembull, . E kam parë për herë të parë tek Maksim Dorofeev. Ndonjëherë njerëzit e veçantë janë në disa ekipe, ndërsa në disa të tjera nuk janë. Kjo e bën shërbimet e ndryshme që përdoren në kompani paksa të papajtueshme.

Shikoni këtë imazh: ky është një zhvillues i mirë, ka duar të mëdha, mund të bëjë shumë. Problemi kryesor është se nga e kanë këto duar.

Shërbimet ofrojnë mundësinë për të përdorur gjuhë të ndryshme programimi, më të përshtatshme për detyra të ndryshme. Disa shërbime në Go, disa në Erlang, disa në Ruby, disa në PHP, disa në Python. Në përgjithësi, mund të zhvilloni një shumëllojshmëri të gjerë. Këtu gjithashtu ka nuanca.

Arkitektura e orientuar nga shërbimet — për të gjithë befasinë e devops. Kështu që, nëse nuk keni automatizim, nuk keni proces deploji, dhe nëse konfigurimet tuaja ndryshojnë nga instanca në instancë manualisht, ju ndiheni si në ferr.
Për shembull, nëse keni 20 shërbime dhe duhet t'i depiloni manualisht, do të keni 20 konsola, duke shtypur «enter» në të njëjtën kohë si ninja. Kjo nuk është shumë mirë.
Nëse shërbimi juaj ka kaluar testimin (nëse ka testim, natyrisht), dhe duhet ta përmirësoni që të funksionojë në prodhim, kam edhe disa lajme të këqija për ju.
Nëse mbështeteni në shërbime specifike të Amazonit dhe punoni në Rusi, atëherë dy muaj më parë, ndoshta keni thënë: «Të gjitha rreth meje po digjen, unë jam mirë, gjithçka është shkëlqyese».

Ne përdorim Ansible për automatizimin e ndërtimit, Puppet për ngushtimin, Bamboo për automatizimin e depolit, dhe Confluence për të gjitha këto dokumentuar disi.
Nuk do të ndalem në këtë temë sepse prezantimi është më shumë rreth praktikave të bashkëpunimit dhe jo për realizimin teknik.

Një herë kemi pasur probleme, ku Puppet në server punon me Ruby 2, ndërsa një aplikacion është shkruar për Ruby 1.8, dhe ata nuk funksionojnë së bashku. Ndodhin disa probleme. Kur ju nevojitet të mbani disa versione të Ruby në një makinë, zakonisht filloni të hasni probleme.
Ne, për shembull, japim një ambient për çdo zhvillues, ku ka përafërsisht gjithçka që kemi, të gjitha shërbimet që mund të zhvillohen, në mënyrë që ai të ketë një ambient të izoluar, ku mund të bëjë eksperimente dhe ta ndërtojë ashtu siç dëshiron.
Ndonjëherë, nevojitet ndonjë paketë e përpiluar posaçërisht me mbështetje për diçka të veçantë. Kjo është mjaft e komplikuar. Dëgjova një prezantim ku një imazh Docker ka peshë 45 GB. Në Linux është pak më e lehtë, është më pak, por për të gjitha raste, nuk do të ketë vend të mjaftueshëm.
Po ashtu, hasen varësi kontradiktore, kur një pjesë e projektit varet nga një bibliotekë me një version, ndërsa një pjesë tjetër nga një version tjetër, dhe bibliotekat nuk instalohen dot së bashku.

Kemi faqet dhe shërbimet në PHP 5.6, na vjen turp për to, por çfarë mund të bëjmë. Kjo është një platformë e përbashkët për ne. Kemi fqinjë dhe shërbime në PHP 7, më shumë se ato, për to nuk ndiejmë turp. Dhe çdo zhvillues ka bazën e tij, ku ai gëzohet që punon.
Nëse shkruani në kompani në një gjuhë, atëherë tre virtuale për zhvilluesin tingëllojnë normal. Nëse keni gjuhë të ndryshme programimi, situata bëhet më e komplikuar.

Ju shfaqen faqet dhe shërbimet në këtë gjuhë, në këtë tjetër, pastaj një platformë për Go, një tjetër për Ruby, ndonjë Redis më vete. E gjithë kjo përfundon si një fushë e madhe për mbështetje, dhe gjithnjë diçka nga këto mund të prishet.

Prandaj ne zëvendësuam mundësitë e gjuhës së programimit me përdorimin e framework-ëve të ndryshëm, sepse framework-ët në PHP janë mjaft të ndryshëm, ata kanë mundësi të ndryshme, komunitete të ndryshme, mbështetje të ndryshme. Dhe mund të shkruani një shërbim në mënyrë që të keni diçka të gatshme për të.
Çdo shërbim ka ekipin e tij

Avantazhi ynë kryesor, i cili është kristalizuar gjatë disa viteve, është se çdo shërbim ka ekipin e tij. Kjo është e përshtatshme për projekte të mëdha dhe mund të kursejë kohë në dokumentim, menaxherët e njohin mirë projektin e tyre.
Detyrat nga mbështetja mund të shpërndahen lehtësisht. Për shembull, nëse shërbimi i sigurimeve ka probleme. Menjëherë ekipi që merret me sigurimet do të shkojë për ta riparuar.
Tipare të reja realizohen shpejt, sepse kur keni një shërbim të atomar, mund të integjoni diçka operativisht brenda tij.
Dhe kur e prisni shërbimin tuaj, gjë që ndodh padyshim, nuk e preken shërbimet e të tjerëve; zhvilluesit nga ekipet e tjera nuk ju vijnë me shkopinj dhe nuk thonë: 'Ah, ah, jo kështu'.

Si gjithmonë, ka nuanca. Ne kemi ekipe të stabilizuara, menaxherët janë fort të lidhur me ekipin. Ka dokumente të qarta, menaxherët e mbikëqyrin këtë proces ngushtësisht. Çdo ekip me menaxherin ka disa shërbime dhe ka një pikë të saktë të kompetencës.
Nëse ekipet janë të lëvizshme (kjo përdoret ndonjëherë), ka një metodë të mirë që quhet 'harta yjore'.

Ju keni një listë shërbimesh dhe njerëzish. Ylli do të thotë se personi është ekspert në këtë shërbim, ndërsa libri do të thotë se personi po studion këtë shërbim. Detyra e personit është të marrë librin dhe ta kthejë në yll. Nëse përkundrejt shërbimit nuk ka asgjë të shkruar, atëherë fillojnë problemet, për të cilat do të flas më vonë.
Si shfaqen shërbimet jetimë?

Problemi i parë, mënyra e parë për të pasur një shërbim jetim në infrastrukturën tuaj — është largimi i njerëzve. A ka ndodhur ndonjëherë që afatet të vijnë në biznes para se të vlerësohen detyrat? Nd sometimes ndodhin herë që afatet janë të ngurta dhe nuk ka kohë për dokumentacionin. "Duhet ta dorëzojmë shërbimin në prodhim, pastaj do ta shkruajmë më tej."
Nëse ekipi është i vogël, ndonjëherë ndodh që në të ketë një zhvillues i cili shkruan gjithçka, të tjerët janë në mbështetje. "Unë kam shkruar arkitekturën bazë, ti tani lërës interface-të." Pastaj në një moment, për shembull, menaxheri ikën. Dhe në këtë periudhë, kur menaxheri ka ikur dhe nuk është emëruar një i ri, zhvilluesit vetë vendosin se në cilin drejtim shkon shërbimi, çfarë ndodh. Dhe siç e dimë (kthehemi disa diapozitiva mbrapa), në disa ekipe ka njerëz të veçantë, ndonjëherë një lider ekipi i tillë. Pastaj ai jep dorëheqjen, dhe ne marrim një shërbim jetim.

Në të njëjtën kohë, detyrat nga mbështetje dhe nga biznesi nuk zhduken, ato mbeten në bllokun e punëve. Nëse gjatë zhvillimit të shërbimit ka pasur ndonjë gabim arkitekturor, ato gjithashtu mbeten në bllokun e punëve. Shërbimi po degradon ngadalë.
Si ta identifikosh një jetim?
Ky list e përshkruan mirë situatën. Kush ka gjetur ndonjë gjë në infrastrukturën e vet?

Për workaround të dokumentuar: ka një shërbim dhe, në përgjithësi, ai funksionon, ai ka një manual me dy faqe për si të punosh me të, por si funksionon brenda, askush nuk e di.
Ose, p.sh., ka ndonjë shkurtesë të lidhjeve. Ne, për shembull, tani kemi në përdorim tre shkurtesa lidhjesh për qëllime të ndryshme në shërbime të ndryshme. Këto janë pasojat e këtij procesi.

Tani do të jem kapiteni i evidentës. Çfarë duhet të bëni? Së pari, duhet ta kaloni shërbimin te një menaxher tjetër, një ekip tjetër. Nëse lideri i ekipit tuaj nuk është pushuar ende, atëherë në këtë ekip tjetër, kur e kuptoni se shërbimi është si një jetim, duhet të përfshini dikë që e kupton diçka në të.
Gjërat kryesore: ju duhet të keni procedura të shkruara me gjak për kalimin e shërbimit. Në rastin tonë, kështu e ndjek zakonisht unë, sepse më duhet që gjithçka të funksionojë. Menaxherët duan që kjo të dorëzohet shpejt, dhe çfarë do të ndodhë me të pas kësaj, nuk është kaq e rëndësishme për ta.

Një mënyrë tjetër për ta bërë një shërbim jetim është: "Do ta bëjmë në aoutsourcing, kështu do të jetë më shpejt, dhe më pas do ta kalojmë në ekip." Është e qartë se të gjithë kanë ndonjë plan në ekip, radhë. Shpesh klienti biznesor mendon se në aoutsourcing do të bëjnë ashtu siç bën ekipi teknik që është në kompaninë. Megjithatë, motivatorët e tyre janë të ndryshëm. Në aoutsourcing ndodhin zgjidhje teknologjike të çuditshme dhe zgjidhje algoritmike të çuditshme.

Për shembull, ne kishim një shërbim ku Sphinx ishte në vende të ndryshme të papritura. Më vonë do të tregoj se çfarë duhej të bëja.
Te outsourcer-ët ndodhin framework-e të shkruara vetë. Kjo është thjesht PHP i pastër me kopim e ngjitje nga projekti i mëparshëm, ku mund të gjesh çdo gjë. Kosto të mëdha në skriptet e deploy-it, kur ju nevojiten disa skripte të komplikuara Bash për të ndërruar disa rreshta në ndonjë skedar, dhe në të njëjtën kohë këto skripte deploy-i thirren nga ndonjë skript tjetër. Në përfundim, ju ndërroni sistemin e deploy-it, zgjidhni diçka tjetër, dhe hup, shërbimi juaj nuk punon. Sepse aty duhej të vendosni edhe 8 lidhje mes dosjeve të ndryshme. Ose ndodhin raste kur një mijë regjistrime punojnë, ndërsa njëqind mijë nuk funksionojnë më.
Do të vazhdoj të udhëheq. Pranimi i shërbimit nga outsourci është një procedurë e domosdoshme. A ka pasur ndokënd që shërbimi nga outsourci vjen dhe askush nuk e pranon? Nuk është aq popullor, sigurisht, sa shërbimi jetim, por prapë.

Shërbimi ka nevojë të kontrollohet, shërbimi ka nevojë për rishikim, duhet të ndryshoni fjalëkalimet. Kemi pasur një rast kur na është dhënë një shërbim, aty admin kishte: "if login == 'admin' && password == 'admin'...", e shkruar direkt në kod. Ne po mendojmë, a e shkruajnë këtë njerëzit në vitin 2018?
Testimi i kapacitetit të ruajtjes — gjithashtu një gjë e nevojshme. Duhet të shikoni se çfarë do ndodhë me njëqind mijë regjistrime, edhe para se ta lansoni këtë shërbim në prodhim.

Të dërgoni shërbimin për rieditje nuk duhet të jetë një turp. Kur thoni: "Ne nuk do ta pranojmë këtë shërbim, kemi 20 detyra, bëni ato, pastaj do ta pranojmë", është në rregull. Ndjenja e fajit nuk duhet të ju bëjë të ndiheni keq për t'i vendosur menaxherit një barrë, ose që biznesi do të shpenzojë para. Biznesi do të shpenzojë më shumë më vonë.
Kemi pasur një rast kur vendosëm të realizojmë një projekt pilot në outsourcim.

Ai u dorëzua në kohë, dhe ky ishte kriteri i vetëm i cilësisë. Prandaj bëmë një projekt pilot të ri, tashmë madje jo krejt pilot. Këto shërbime u pranuan, në mënyrë administrative thanë, ja kodi juaj, ja ekipi, ja menaxheri juaj. Shërbimet në të vërtetë filluan të sillnin fitim. Për më tepër, ata mbetën ende si jetimë, askush nuk e kupton se si funksionojnë, dhe menaxherët përpiqen të largohet nga detyrat e tyre.

Ka edhe një koncept të shkëlqyer — zhvillimi gueril. Kur ndonjë departament, zakonisht ky është departamenti i marketingut, dëshiron të testojë një hipotezë dhe porosit një shërbim të tërë në outsourcing. Një trafik fillon të vërshojë, ata mbyllin dokumentet, nënshkruajnë aktet me kontraktorin, hyjnë në funksionim dhe thonë: «Djem, kemi një shërbim këtu, tashmë ka trafik, na sjell para, le ta pranojmë». Ne themi: «Oop, si ndodhi kjo».

Dhe një mënyrë tjetër për të marrë shërbimin jetim: kur një skuadër papritmas është e ngarkuar, menaxhmenti thotë: "Le të kalojmë shërbimin e kësaj skuadre te një skuadër tjetër, sepse ka më pak ngarkesë". Pastaj e kalojmë te skuadra e tretë dhe ndryshojmë menaxherin. Dhe përfundimisht, na del përsëri si jetim.
Cila është problema me jetimët?

Kush nuk e di, është anija e ngritur në Suedi Wasa, e famshme për atë që u mbyt pesë minuta pas daljes në ujë. Dhe mbretit të Suedisë, përveç kësaj, nuk i hodhi askënd në burg për këtë. Ajo u ndërtua nga dy breza inxhinierësh që nuk dinin të ndanin anije të tilla. Efekti i ligjshëm.
Anija mund të ishte mbytur, për shembull, kur mbreti po udhëtonte diku në një stuhi. Por kështu, u mbyt menjëherë, sipas metodologjisë agile është mirë — të dështosh herët.
Nëse dështuam herët, zakonisht nuk ka probleme. Për shembull, gjatë pranimit dërguam për përmirësim. Por nëse dështuam tashmë në prodhim, kur janë investuar para, atëherë mund të ketë probleme. Pasojat, siç quhen në biznes.
Cfarë rrezikshmërie kanë shërbimet jetimë:
- Shërbimi mund të prishet papritmas.
- Shërbimi merr shumë kohë për tu riparuar ose nuk riparohet fare.
- Problem z sigurinë.
- Probleme me përmirësime dhe përditësime.
- Nëse një shërbim i rëndësishëm prish, reputacioni i kompanisë dëmtohet.
Çfarë të bëjmë me shërbimet jetimë?

Të përsëris, çfarë të bëjmë. Së pari, duhet të ketë dokumentacion. 7 vjet në Banki.ru më kanë mësuar se testuesit nuk duhet të besojnë fjalët e zhvilluesve, dhe operimi nuk duhet të besojë askënd. Duhet të kontrolloni.

Së dyti, duhet të shkruhen skemat e bashkëpunimit, sepse ndodh që shërbimet që priten jo shumë mirë kanë varësi për të cilat askush nuk ka thënë asgjë. Për shembull, zhvilluesit vendosën shërbimin në çelësin e tyre për ndonjë gjë si Yandex.Maps ose Dadata. Ju mbaroi limiti falas, gjithçka dështoi, dhe ju nuk e dini se çfarë ndodhi. Të gjitha këto pengesa duhet të përshkruhen: në shërbim përdoret Dadata, Sms, ose diçka tjetër.

Së treti, puna me borxhin teknik. Kur bëni disa zgjidhje improvizimi ose pranoni një shërbim dhe thoni se duhet bërë diçka, duhet të ndihmoni që kjo të bëhet. Sepse më vonë mund të ndodhë që një gropë e vogël të mos jetë aq e vogël dhe ju të bini brenda.
Kishim kemi pasur një histori me detyrat arkitekturore pikërisht për Sphinx. Në një nga shërbimet, Sphinx përdorej për të futur lista. Thjesht një listë me paginacion, por përveç kësaj, ajo riindeksohej çdo natë. Ajo ishte ndërtuar nga dy indekse: një indeks i madh që riindeksohej çdo natë, dhe kishte gjithashtu një indeks të vogël që ishte lidhur me të. Çdo ditë, me një probabilitet prej 50%, ose do të kishte një problem, ose jo; kur bëhej përdorimi, indeksi thyhej dhe lajmet tona ndalnin së rinovari në faqen kryesore. Në fillim, kjo zgjaste 5 minuta, derisa indeksi të riindeksohej, pastaj indeksi u rrit, dhe në një moment ai filloi të riindeksohej për 40 minuta. Kur e hoqëm këtë, ne morëm frymë lehtësimi, sepse ishte e qartë që do të kalonte pak kohë dhe indeksi ynë do të riindeksohej gjatë tërë ditës. Kjo do të ishte një dështim për portalin tonë, tetë orë pa lajme — gjithçka, biznesi ndalonte.
Plani i punës me shërbimin shpërfillës

Në të vërtetë, është shumë e vështirë ta bësh këtë, sepse DevOps është për komunikimin. Dëshiron të jesh në marrëdhënie të mira me kolegët e tu, dhe kur i godet ata me procedurat si me një shkop, ata mund të ndihen në mënyrë të dyshimtë për ata që bëjnë kështu.
Përveç këtyre pikave, ka edhe një gjë të rëndësishme: për çdo shërbim specifik, për çdo pjesë të veprimit të deploy-it, duhet të ketë njerëz specifikë përgjegjës. Kur nuk ka njerëz dhe duhet të angazhosh njerëz të tjerë, duke studiuar gjithë këtë çështje, bëhet e vështirë.

Nëse kjo nuk ndihmon dhe shërbimi jetim mbetet akoma jetim, askush nuk dëshiron ta marrë, dokumentacioni nuk shkruhet, ekipi që është thirrur për këtë shërbim refuzon të bëjë diçka, ka një mënyrë të thjeshtë – ta rinovosh gjithçka.
Do thotë se merr kërkesat për shërbimin përsëri dhe shkruan një shërbim të ri, më të mirë, në një platformë më të mirë, pa zgjidhje teknologjike të çuditshme. Dhe migron mbi të në kohë reale.

Kemi pasur një situatë ku morëm një shërbim në Yii 1 dhe kuptuam se nuk mund ta zhvillonim më tej, sepse na mbaruan zhvilluesit që dijnë të shkruajnë mirë në Yii 1. Të gjithë zhvilluesit dinë të shkruajnë mirë në Symfony 3. Çfarë të bëjmë? Rezervuam kohë, formuam një ekip, caktuam një menaxher, rishkruam projektin dhe gradualisht e kaluam trafikun mbi të.
Pas kësaj, mund të fshijmë shërbimin e vjetër. Kjo është procedura ime e preferuar, kur duhet të marrësh dhe të fshish një shërbim nga sistemi i menaxhimit të konfigurimeve dhe pastaj të shohësh nëse të gjitha makinat në prodhim janë fikur, që zhvilluesit të mos kenë mbetur asnjë gjurmë. Repository në git mbetet.
Kjo është gjithçka për të cilën doja të flisja, jam i gatshëm të diskutoj, tema është shumë e diskutueshme, shumë njerëz kanë notuar në të.
Në slajdë u fol për unifikimin e gjuhëve. Si shembull ishte përmasimi i imazheve. A është me të vërtetë e nevojshme të kalosh vetëm në një gjuhë? Sepse përmasimi i një fotografie në PHP, mund të bëhej me të vërtetë edhe në Golang.
Në të vërtetë, kjo nuk është e domosdoshme, ashtu siç nuk janë të gjitha praktikat. Ndoshta në disa raste, madje edhe e padëshirueshme. Por duhet të kuptoni se, nëse keni 50 njerëz në departamentin tuaj teknik, prej të cilëve 45 janë PHP programues, 3 janë devops që dinë Python, Ansible, Puppet dhe gjëra të tjera, dhe vetëm një të tillë shkruan një shërbim në Go për rregullimin e imazheve, atëherë, kur ai largohet, eksperienca largohet me të. Dhe për më tepër, do t'ju duhet të kërkoni një zhvillues specifik në treg që di këtë gjuhë, veçanërisht nëse është e rrallë. Pra, nga pikëpamja organizative, kjo është problematike. Nga pikëpamja e devops, nuk do t'ju nevojitet thjesht të klononi një grup të gatshëm playbook-ash që përdorni për të shkarkuar shërbimet, por do t'ju duhet t'i shkruani ato nga e para.
Ne aktualisht po zhvillojmë një shërbim në Node.js, dhe kjo do të jetë pikërisht një platformë e veçantë për secilin programues me gjuhën e vet. Por ne u ulëm dhe menduam që loja ia vlen. Pra, kjo është një çështje për të menduar dhe diskutuar.
Si i monitoroni shërbimet tuaja? Si i mbledhni dhe ndihmoni logët?
Ne mbledhim logët në Elasticsearch dhe i vendosim në Kibana, dhe në varësi të faktit nëse është prodhim ose mjedise testimi, aty përdoren mbledhës të ndryshëm. Diku është Lumberjack, diku tjetër diçka tjetër, tani nuk e mbaj mend. Ka edhe disa vende në shërbime të caktuara ku vendosim Telegraf dhe e dërgojmë ndonjëherë diku tjetër në mënyrë të veçantë.
Si të jetosh me Puppet dhe Ansible në të njëjtin mjedis?
Në të vërtetë, tani kemi dy mjedise, një është Puppet, tjetra Ansible. Po punojmë për t’i hibridizuar ato. Ansible është një mjedis i mirë për konfigurimin e parë, Puppet është diçka e keqe për konfigurimin fillestar, sepse kërkon punë manuale direkt me platformën, dhe Puppet siguron konvergjencën e konfigurimit. Kjo do të thotë se platforma e mbështet veten në gjendjen aktuale, ndërsa për të mbajtur një makinë të hibridizuar në gjendjen aktuale, duhet t'i ekzekutoni vazhdimisht playbook-at me ndonjë periudhë. Kjo është dallimi.
Si e mbani kompatibilitetin? Keni konfigurime në Ansible dhe Puppet?
Kjo është një dhimbje e madhe për ne, mbajmë kompatibilitetin me duar dhe mendojmë se si të kalojmë nga e gjithë kjo diku. Ndodhemi në situatën ku Puppet instalon paketa dhe mban disa lidhje, ndërsa Ansible, për shembull, instalon kod dhe përshtat konfigurimet e reja të aplikacioneve aty.
Në prezantim u diskutuan versionet e ndryshme të Ruby. Çfarë zgjidhje?
Ne u përballëm me këtë në një vend dhe na duhet ta kemi gjithmonë në mendje. Ne thjesht e kemi çaktivizuar atë pjesë që punonte me atë Ruby që ishte jo-kompatibël me aplikacionet dhe e mbajtëm atë veçmas.
Ky vit konferenca do të mbahet më 7 dhjetor në "Tehnopolis". Deri më 11 nëntor pranojmë aplikime për referate. nëse dëshironi të flisni.
Regjistrimi për pjesëmarrësit është e hapur, bashkohuni!
Burimi: habr.com
