Drejtori i operacioneve të portalit Banki.ru, Andrei Nikolskyi, fol në konferencën e vitit të kaluar. për shërbimet jetimore: si të identifikoni një jetimore në infrastrukturë, çfarë është keq për shërbimet jetimore, çfarë të bëni me to, dhe si të veproni nëse asgjë tjetër nuk ndihmon.
Poshtë është versioni tekstual i raportit.

Përshëndetje, kolegë! Emri im është Andrei, drejtoj operacionet në kompaninë Banki.ru.
Kemi shërbime të mëdha, që janë shërbime monolite, kemi shërbime në një kuptim më klasik, gjithashtu dhe shumë të vogla. Në terminologjinë time punuese, them se nëse shërbimi ë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.
Avantazhet e shërbimeve
Do të kalojë shpejt për avantazhet e shërbimeve.

E para — shkallëzimi. Mund të bëni shpejt dicka në shërbim dhe të filloni në prodhim. Ju erdhi trafiku, ju e klonuat shërbimin. Ju erdhi edhe një trafik, ju e klonuat përsëri dhe me këtë jetoni. Ky është një bonus i mirë, dhe, në parim, kur filluam, ai konsiderohej nga ne si më i rëndësishmi, pse e bëjmë këtë gjithë.

E dyta, zhvillimi i izoluar, kur keni disa ekipe zhvillimi, disa zhvillues të ndryshëm në çdo ekip, dhe çdo ekip punon në shërbimin e vet.
Me ekipet ndodhin nuanca. Çdo zhvillues është i ndryshëm. Dhe ekzistojnë, për shembull, . E pashë për herë të parë këtë nga Maksim Dorofeev. Ndonjëherë njerëz-mushkë ka në disa ekipe, dhe në disa nuk ka. Kjo i bën shërbimet e ndryshme që përdoren në kompaninë më pak të barabarta.

Shikoni imazhin: ky është një zhvillues i shkëlqyer, ai ka duar të mëdha, mund të bëjë shumë. Problemi kryesor është nga vijnë këto duar.

Shërbimet ofrojnë mundësinë për të përdorur gjuhë të ndryshme programuese, më të përshtatshme për detyra të ndryshme. Një shërbim në Go, ndonjë në Erlang, ndonjë në Ruby, diçka në PHP, diçka në Python. Në përgjithësi, mund të shtriheni shumë gjerë. Këtu ka disa nuanca.

Arkitektura e orientuar ndaj shërbimeve — kjo është para së gjithash për devops. Pra, nëse nuk keni automatizim, nuk keni procesin e vendosjes, nëse e konfiguroni manualisht, konfigurimet tuaja mund të ndryshojnë nga instanca e shërbimit në instancën tjetër, dhe ju duhet të shkoni atje të bëni diçka, atëherë jeni në ferr.
Për shembull, nëse keni 20 shërbime dhe duhet t'i publikoni manualisht, do të keni 20 konsola dhe do të shtypni "enter" njëkohësisht, si ninja. Kjo nuk është shumë mirë.
Nëse keni një shërbim pas testimit (nëse ka testim, natyrisht), dhe duhet ta përmirësoni pak që të funksionojë në prodhim, kam edhe për ju lajme të këqija.
Nëse mbështeteni në shërbime specifike të Amazonit dhe punoni në Rusi, atëherë dy muaj më parë keni thënë po ashtu: "Gjithçka po digjet, unë jam mirë, gjithçka është në rregull."

Ne përdorim Ansible për automatizimin e deploy-it, Puppet për konvergjencë, Bamboo për automatizimin e publikimit dhe Confluence për ta dokumentuar gjithçka në njëfarë mënyre.
Nuk do të ndalem shumë në këtë temë, sepse raporti është më shumë për praktikat e bashkëpunimit se sa për zbatimin teknik.

Na ka ndodhur, për shembull, problemi që Puppet në server punon me Ruby 2, ndërsa një aplikacion është shkruar për Ruby 1.8, dhe ata nuk punojnë së bashku. Kjo ndodh për shkak të ndonjë defekti. Dhe kur ju nevojitet të mbani disa versione të Ruby në një makinë, zakonisht fillojnë problemet.
Për shembull, ne i japim çdo zhvilluesi një platformë në të cilën ka gjithçka që ne kemi, të gjitha shërbimet që mund të zhvillohen, për të pasur një ambient të izoluar ku ai mund ta prishë dhe ta ndërtojë sipas dëshirës.
Ndonjëherë, nevojitet ndonjë paketë e kompiluar veçmas me mbështetje për ndonjë funksionalitet aty. Kjo është mjaft serioze. Ndiqa një raport ku imazhi i docker-it pesha 45 GB. Në Linux, sigurisht, është më e lehtë, aty është më e vogël, por prapëseprapë, nuk do të ketë hapësirë të mjaftueshme.
Po, ndodhin ndonjëherë varësi kontradiktore, kur një pjesë e projektit varet nga një version i një biblioteke, ndërsa një pjesë tjetër nga një version tjetër, dhe bibliotekat nuk instalohen së bashku në asnjë mënyrë.

Ne kemi faqe dhe shërbime në PHP 5.6, për të cilat ndjehemi të turpëruar, por çfarë të bëjmë? Kjo është një platformë për ne. Ka faqe dhe shërbime në PHP 7, ato janë më të shumta dhe për to nuk ndjehemi të turpëruar. Çdo zhvillues ka bazën e tij ku gëzohet duke punuar.
Nëse punoni në një kompani me një gjuhë, atëherë tri maqinë virtuale për çdo zhvillues është një gjë normale. Nëse keni gjuhë programimi të ndryshme, situata bëhet më e komplikuar.

Ju njohni se juaj faqet dhe shërbimet e lidhura krijojnë një hapësirë për mbështetje, dhe gjithmonë ka diçka që mund të prishët nga ato.

Prandaj ne zëvendësuam karakteristikat e gjuhës së programimit me përdorimin e framework-eve të ndryshme, pasi framework-et për PHP janë mjaft të ndryshme dhe ofrojnë mundësi të ndryshme, komunitet të ndryshëm, dhe mbështetje të ndryshme. Kështu mund të shkruani një shërbim në mënyrë që të keni tashmë diçka të gatshme për të.
Çdo shërbim ka ekipin e vet

Avantazhi ynë kryesor, i cili është formuar gjatë disa viteve, është se çdo shërbim ka ekipin e vet. Kjo është e dobishme për një projekt të madh, sepse mund të kurseni kohë në dokumentacion, menaxherët e njohin mirë projektin e tyre.
Detyrat e mbështetjes mund të shpërndahen lehtësisht. Për shembull, nëse një shërbim sigurie prishet. Menjëherë ekipi që merret me sigurimin fillon ta riparojë.
Funksionet e reja krijohen shpejt, sepse kur keni një shërbim atomar, mund të rishikoni diçka me shpejtësi.
Dhe kur prishet shërbimi juaj, që është e pashmangshme, nuk ndikon në shërbimet e tjera, dhe zhvilluesit nga ekipet e tjera nuk vijnë te ju me shkopinj dhe nuk thonë: “O jo, mos e bëj kështu”.

Si gjithmonë, ka nuanca. Ne kemi ekipe të stabilizuara, menaxherët janë të angazhuar ngushtë me ekipet. Ka dokumente të qarta, menaxherët e ndjekin ngushtësisht të gjitha ato. Çdo ekip me menaxherin ka disa shërbime, dhe ka një pikë të caktuar kompetence.
Nëse ekipet janë të lëvizshme (ndodhin edhe këto ndonjëherë), ka një metodë të mirë e quajtur "hartë yjesh".

Ju keni një listë shërbimesh dhe njerëzish. Ylli do të thotë që një person është ekspert në këtë shërbim, libri do të thotë që një person po studion këtë shërbim. Detyra e personit – është të ndryshojë librin për një yll. Dhe nëse ndaj shërbimit nuk është shkruar asgjë, atëherë fillojnë problemet, mbi të cilat do të flas më tej.
Si shfaqen shërbimet jetimë?

Problemi i parë, mënyra e parë për të krijuar një shërbim jetim në infrastrukturë është shkarkimi i punonjësve. A ndodhi ndonjëherë që afatet të vijnë nga biznesi përpara se të vlerësoheshin detyrat? Ndonjëherë ndodh që afatet janë të ngurta dhe nuk ka kohë për dokumentacion. "Duhet të dorëzojmë shërbimin në prodhim, pastaj do ta shkruajmë më shumë."
Nëse ekipi është i vogël, ndodh që në të ketë një zhvillues që shkruan gjithçka, ndërsa të tjerët janë në mbështetje. "Unë kam shkruar arkitekturën kryesore, që ti të bësh ndërfaqet." Pastaj, në ndonjë moment, menaxheri, për shembull, largohet. Dhe në këtë periudhë, kur menaxheri është larguar dhe nuk është caktuar ende një i ri, zhvilluesit vetë vendosin se ku po shkon shërbimi, çfarë po ndodh atje. Siç e dimë (të kthehemi disa faqe mbrapa), në disa ekipe ka njerëz që janë të veçantë, ndonjëherë ndonjë udhëheqës i ekipit si "njeri i veçantë". Pastaj ai largohet, dhe ne përfundojmë me një shërbim jetim.

Megjithatë, detyrat nga mbështetja dhe biznesi nuk zhduken, ato grumbullohen në bllokun e prapmbarimit. Nëse gjatë zhvillimit të shërbimit kishte ndonjë gabim arkitekturor, ato gjithashtu grumbullohen në bllokun e prapmbarimit. Shërbimi po degredon ngadalë.
Si ta identifikoni një jetim?
Ky listë e përshkruan mirë situatën. Kushprekuar diçka të njohur në infrastrukturën e tij?

Për workaround-et e dokumentuara: ka një shërbim dhe, në tërësi, ai funksionon, ka një manual dy faqesh se si të punoni me të, por si funksionon brenda, askush nuk e di.
Ose, për shembull, ka ndonjë redhë linkesh. Në rastin tonë, tani po përdorim tre redha linkesh për qëllime të ndryshme në shërbime të ndryshme. Këto janë pasojat e kësaj.

Tani do të jem kapiteni i dukshëm. Çfarë duhet të ndërmerret? Së pari, shërbimi duhet t'i kalojë një menaxheri tjetër, një ekipi tjetër. Nëse lideri juaj i ekipit nuk ka dhënë dorëheqje akoma, atëherë në këtë ekip tjetër, kur e kuptoni se shërbimi i ngjan një jetimi, duhet të përfshihet ndonjë që të paktën di diçka për të.
Gjëja kryesore: duhet të keni procedura të shkruara me gjak për kalimin. Në rastin tonë, zakonisht përkujdesem për këtë, sepse duhet që gjithçka të funksionojë. Menaxherëve iu nevojitet që kjo të dorëzohet shpejt, dhe se çfarë do të ndodhë më pas, nuk është më aq e rëndësishme për ta.

Një mënyrë tjetër për të krijuar një shërbim të pamatur është, "Do ta bëjmë në outsourcë, do të jetë më shpejt, dhe më pas do t'ia kalojmë ekipit". Është e qartë që të gjithë kanë ndonjë plan në ekip, një radhë. Shpesh klienti biznesor mendon se outsourcing-u do të bëjë punën si departamenti teknik që ka kompania. Megjithatë, motivet e tyre janë të ndryshme. Në outsourcing ka zgjidhje teknologjike dhe algoritmike të çuditshme.

Ne, për shembull, kishim një shërbim ku kishte Sphinx në vende të papritura. Do flas më vonë për atë që na u detyrua të bëjmë.
Oferuesit e outsourcing-ut shpesh kanë framework të shkruar vetë. Është thjesht PHP i pastër me kopjen e kodit nga projekti i kaluar, ku mund të gjesh çdo lloj. Ka një numër të madh "patchesh" në skriptet e dërgimit, kur ju nevojitet të ndryshoni disa rreshta në ndonjë skedar me skripta të komplikuara Bash, ndërkohë që këto skripta dërgimi thirren nga ndonjë skript tjetër. Në fund, ndryshoni sistemin e dërgimit, zgjidhni diçka tjetër, dhe papritmas shërbimi juaj nuk funksionon. Sepse duhej vendosur ende 8 lidhje midis dosjeve të ndryshme. Ose ndodh që një mijë regjistrime funksionojnë, por njëqind mijë nuk funksionojnë.
Do të vazhdoj të udhëheq. Pranimi i shërbimit nga outsourcing është një procedurë e detyrueshme. A ka pasur ndokush që shërbimi nga outsourcing arrin dhe nuk pranohet? Nuk është kaq e njohur si shërbimi i pamatur, por megjithatë.

Shërbimi duhet të kontrollohet, shërbimi duhet të rishikohet, duhet të ndryshohen fjalëkalimet. Ne patëm një rast kur na u dha një shërbim, atje admin ishte "if login == 'admin' && password == 'admin'...", e shkruar direkt në kod. Ne mendojmë, a e shkruajnë njerëzit këtë në vitin 2018?
Testimi i kapacitetit të ruajtjes është gjithashtu diçka e nevojshme. Duhet të shikoni se çfarë do të ndodhë me njëqind mijë regjistrime, para se ta lëshoni këtë shërbim diku në prodhim.

Të dërgosh shërbimin për rregullim nuk duhet të jetë diçka për t'u turpëruar. Kur thoni: "Ne nuk do ta pranojmë këtë shërbim, kemi 20 detyrime, bëni ato, pastaj do ta pranojmë", është normale. Konsensusi nuk duhet të ndiejë faj që do të vendosë menaxherin në siklet, apo që biznesi do të harxhojë para. Në fakt, biznesi do të harxhojë më shumë më vonë.
Kemi pasur një rast kur vendosëm të bëjmë një projekt pilot në outsourcing.

Ai u dorëzua në kohë, dhe kjo ishte kriteri i vetëm i cilësisë. Prandaj bënë një tjetër projekt pilot, tashmë jo krejtësisht pilot. Këto shërbime u miratuan, u tha në mënyrë administrative, ja kodo juaj, ja ekipi juaj, ja menaxheri juaj. Shërbimet me të vërtetë filluan të sjellin fitim. Megjithatë, në fakt ato mbetën sërish jetima, askush nuk e kupton se si funksionojnë, dhe menaxherët me çdo mënyrë distancohen nga detyrat e tyre.

Ka një koncept tjetër të shkëlqyer - zhvillimi partizanik. Kur një departament, zakonisht ai i marketingut, dëshiron të verifikojë një hipotezë dhe porosit një shërbim krejtësisht në outsorcing. Ai fillon të tërheqë trafik, ata përfundojnë dokumentet, nënshkruajnë aktet me kontraktuesin, shkojnë në funksionim dhe thonë: "Djem, kemi një shërbim këtu, ka trafik, na sjell para, le të pranojmë atë". Ne themi: "Oh, si ka mundësi kështu?".

Dhe një tjetër mënyrë për të marrë një shërbim jetim: kur një ekip papritmas ngarkohet, drejtoria thotë: "Le të kalojmë shërbimin e këtij ekipi tek një ekip tjetër, që ka një ngarkesë më të vogël". Pastaj e kalojmë tek ekipi i tretë, dhe menaxherin e ndryshojmë. Dhe përfundimisht, kemi përsëri një jetim.
Cila është problemi me jetimët?

Kush nuk e di, kjo është anija linjare Wasa, e cila u ndërtua në Suedi, e famshme për faktin se u mbyt 5 minuta pas lanës. Dhe mbreti i Suedisë, për siguri, nuk ekzekutoi askënd për këtë. Ajo u ndërtua nga dy breza inxhinierësh që nuk dinin të ndërtonin anije të tillë. Një efekt i natyrshëm.
Anija mund të ishte mbytur, për shembull, shumë më keq, nëse do të kishte pasur mbretin duke udhëtuar diku në një stuhi. Por kështu, u mbyt menjëherë, sipas metodës Agile kjo është mirë - dështimi i hershëm.
Nëse kemi dështuar herët, zakonisht nuk ka probleme. Për shembull, gjatë pranimitt, e dërgojmë për përmirësim. Por nëse dështojmë tashmë në prodhim, kur janë investuar para, mund të kenë probleme. Pasojat, siç i quajnë ata në biznes.
Cilat janë rreziqet e shërbimeve jetimë:
- Shërbimi mund të dështojë papritur.
- Shërbimi bëhet i prishur për një kohë të gjatë ose nuk riparohet fare.
- Probleme me sigurinë.
- Probleme me përmirësimet dhe përditësimet.
- Nëse dështojnë një shërbim të rëndësishëm, vuan reputacioni i kompanisë.
Çfarë të bëjmë me shërbimet jetimë?

Dua herë po e përsëris se çfarë duhet bërë. Së pari, duhet të ketë dokumentacion. 7 vjet në Banki.ru më mësuan se testuesit nuk duhet të besojnë verbërisht zhvilluesve, dhe operimi nuk duhet të besojë askujt verbërisht. Duhet të kontrollohet.

Së dyti, duhet të shkruhen skemat e bashkëpunimit, sepse ndonjëherë ndodhin situata ku shërbimet, të cilat nuk pranohen shumë mirë, kanë varësi për të cilat askush nuk ka folur. Për shembull, zhvilluesit mund të kenë vendosur një shërbim në çelësin e tyre për ndonjë nga shërbimet e Hartave të Yandex ose Dadata. Nëse përfundoni limitin e lirë, gjithçka do të dështojë, dhe ju nuk do të dini se çfarë ndodhi. Të gjitha këto pengesa duhet të përshkruhen: në shërbim përdoret Dadata, Sms, diçka tjetër.

Së treti, puna me borxhin teknik. Kur bëni ndonjë zgjidhje provizore ose pranoni një shërbim dhe thoni se diçka duhet bërë, duhet të mbani mend se duhet të ndjekni 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 saj.
Me detyrat arkitektonike, patëm një histori saktësisht për Sphinx. Në një nga shërbimet, Sphinx u përdor për të futur lista. Thjesht një listë me paginim, por ndërkohë ri-indeksohej çdo natë. Ishte krijuar nga dy indekse: një indeks i madh që ri-indeksohej çdo natë dhe gjithashtu kishte një indeks të vogël që lidhej me të. Çdo ditë, me një probabilitet prej 50%, ose do të ndodhte një problem, ose jo; me lançimin, indeksi dështonte dhe lajmet tona ndalonin së përditësuari në faqen kryesore. Në fillim, kjo merrte 5 minuta, derisa indeksi ri-indeksohej, më pas indeksi u zgjat, dhe në një moment filloi të ri-indeksohej për 40 minuta. Kur ne e hoqëm këtë, u lehtësuam sepse ishte e qartë se pas pak kohësh, indeksi ynë do të ri-indeksohej gjatë gjithë ditës. Kjo do të ishte një dështim për portalin tonë, tetë orë pa lajme — gjithçka, biznesi do të ndalej.
Plani i punës me shërbimin jetim

Në të vërtetë, është shumë e vështirë të 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, por kur i godet kolegët dhe menaxherët me rregullat, ata mund të ndiejnë ndjenja kontradiktore ndaj atyre që bëjnë kështu.
Përveç të gjitha këtyre pikave, ka një gjë tjetër të rëndësishme: për çdo shërbim konkret, për çdo pjesë specifike të procedurës së implikimit, duhet të përgjigjen persona të caktuar. Kur nuk ka njerëz dhe duhet të angazhohen disa njerëz të tjerë, për të studiuar gjithë këtë, bëhet e vështirë.

Nëse gjithçka kjo nuk ndihmoi, dhe shërbimi jetim juaj është ende një jetim, askush nuk e do atë, dokumentacioni nuk shkruhet, skuadra e cila u thirr për këtë shërbim refuzon të bëjë diçka, ka një mënyrë të thjeshtë — të riparoni gjithçka.
Pra, merrni kërkesat për shërbimin nga e para dhe shkruani një shërbim të ri, më të mirë, në një platformë më të mirë, pa zgjidhje teknologjike të çuditshme. Dhe migroni në të gjatë funksionimit.

Kemi pasur një situatë ku morëm një shërbim në Yii 1 dhe e kuptuam se nuk mund ta zhvillonim më tutje, sepse na janë mbaruar programuesit që dinë të shkruajnë mirë në Yii 1. Të gjithë programuesit dinë të shkruajnë mirë në Symfony 3. Çfarë të bëjmë? Mësojmë kohë, caktojmë një skuadër, caktojmë një menaxher, rishkruajmë projektin dhe ngadalë kalojmë trafikun tek ai.
Pas kësaj, shërbimi i vjetër mund të fshihet. Kjo është procedura ime e preferuar, kur nga sistemi i menaxhimit të konfigurimeve duhet të heqim një shërbim dhe pastaj të shohim që të gjitha njësitë në prodhim janë ndalur, që të mos mbetet asnjë gjurmë për programuesit. Depozita në git mbetet.
Këto janë gjithçka që doja të flisja, jam i gatshëm të diskutoj, tema është e diskutueshme, shumë janë inkuadruar në të.
Në slajdët ishte e thënë se keni unifikuar gjuhët. Si shembull ishte për rikonfigurimin e imazheve. Po vërtet është e nevojshme të ngulitet deri në një gjuhë të vetme? Sepse rikonfigurimi i imazheve në PHP, në fakt, mund të bëhej edhe në Golang.
Në të vërtetë, kjo nuk është e domosdoshme, siç është rasti me të gjitha praktikat. Ndoshta në disa raste, madje nuk preferohet. Por duhet të kuptoni se nëse keni 50 njerëz në departamentin teknik dhe 45 prej tyre janë PHP, 3 janë DevOps që dinë të punojnë me Python, Ansible, Puppet dhe ndonjë gjë tjetër, dhe vetëm një prej tyre shkruan ndonjë shërbim për rrezolucionin e imazheve në Go, atëherë, kur ai largohet, ekspertiza largohet me të. Dhe në këtë rast do t'ju duhet të kërkoni një zhvillues specifik në treg që di këtë gjuhë, sidomos nëse është e rrallë. Kështu që, nga pikëpamja organizative, kjo është problematike. Nga pikëpamja DevOps, ju do të kërkoni jo vetëm të klononi ndonjë grup të gatshëm playbook-esh që përdorni për të krijuar shërbimet, por do t'ju duhet ti shkruani ato nga e para.
Tani po krijojmë një shërbim në Node.js, dhe kjo do të jetë një platformë për secilin zhvillues me gjuhën e tij të veçantë. Por u ulëm dhe mendojmë se luhet vërtet një lojë. Pra, ky është një pyetje për të menduar.
Si i monitoroni shërbimet tuaja? Si i mbledhni dhe ndihmoni loget?
Ne i mbledhim loget në Elasticsearch dhe i ruajmë në Kibana, dhe në varësi të faktit nëse është prodhim apo ambient provash, aty përdoren mbledhës të ndryshëm. Diku përdoret Lumberjack, diku tjetër nuk e mbaj mend. Ka gjithashtu disa vendndodhje në shërbime të caktuara ku instalojmë Telegraf dhe e dërgojmë ndryshe.
Si të jetoni me Puppet dhe Ansible në një ambient të vetëm?
Në të vërtetë, tani kemi dy ambiente, një është Puppet, tjetra Ansible. Po punojmë për t'i hibridizuar ata. Ansible është një ambient i mirë për konfigurimin fillestar, Puppet është një gjë 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 mban veten në gjendje të përditësuar, por për të mbajtur një makinë të instaluar me Ansible në gjendje të përditësuar, duhet të ekzekutoni playbook-et me ndonjë periodicitet. Kjo është dallimi.
Si e mbani përputhshmërinë? A keni konfigurime si në Ansible ashtu edhe në Puppet?
Kjo është një dhimbje e madhe për ne; po mbështesim përshtatshmërinë manualisht dhe po mendojmë se si mund të kalojmë nga kjo situatë diku tjetër. Tani, Puppet instalon paketat dhe mban disa lidhje, ndërsa Ansible, për shembull, instalon kodin dhe përshtat konfigurimet e reja të aplikacioneve.
Në prezantim kishte informacion për versionet e ndryshme të Ruby. Cila është zgjidhja?
Ne e kemi përjetuar këtë në një vend, dhe na duhet ta mbajmë gjithmonë në mendje. Ne thjesht ndaluam atë pjesë që punonte me atë Ruby, e cila ishte e papajtueshme me aplikacionet, dhe e mbajtëm veçmas.
Të këtij viti konferenca do të mbahet më 7 dhjetor në "Teknopolis". Deri më 11 nëntor pranojmë aplikime për referate. nëse dëshironi të flisni.
Regjistrimi për pjesëmarrësit është hapur, bashkohuni!
Burimi: habr.com
