Qanday qilib biz Kubernetes ichida bulutli FaaS yaratdik va Tinkoff xakatonida g'olib chiqdik

Qanday qilib biz Kubernetes ichida bulutli FaaS yaratdik va Tinkoff xakatonida g'olib chiqdik
O'tgan yildan boshlab kompaniyamiz xakatonlarni tashkil qilishni boshladi. Birinchi bunday tanlov juda muvaffaqiyatli bo'ldi, biz bu haqda yozgan edik maqola. Ikkinchi hakathon 2019-yil fevral oyida bo‘lib o‘tdi va undan kam muvaffaqiyat qozonmadi. Yaqinda o'tkazish maqsadlari haqida yozgan tashkilotchi.

Ishtirokchilarga uni amalga oshirish uchun texnologiya to'plamini tanlashda to'liq erkinlik bilan juda qiziqarli topshiriq berildi. Ilovalarning tez oqimi bilan ishlaydigan, og'ir yuklarga bardosh beradigan va tizimning o'zi osonlik bilan kengaytirilishi mumkin bo'lgan mijozlarni baholash funktsiyalarini qulay joylashtirish uchun qaror qabul qilish platformasini amalga oshirish kerak edi.

Vazifa ahamiyatsiz emas va uni ko'p jihatdan hal qilish mumkin, chunki biz ishtirokchilar loyihalarining yakuniy taqdimotlarini namoyish qilish paytida amin bo'ldik. Hackathonda 6 kishidan iborat 5 ta jamoa bor edi, barcha ishtirokchilarning yaxshi loyihalari bor edi, ammo bizning platformamiz eng raqobatbardosh bo'lib chiqdi. Bizda juda qiziqarli loyiha bor, men ushbu maqolada gaplashmoqchiman.

Bizning yechimimiz Kubernetes ichidagi Serversiz arxitekturaga asoslangan platforma bo'lib, ishlab chiqarishga yangi xususiyatlarni olib kirish vaqtini qisqartiradi. Bu tahlilchilarga o'zlari uchun qulay muhitda kod yozish va uni muhandislar va ishlab chiquvchilar ishtirokisiz ishlab chiqarishga joylashtirish imkonini beradi.

Gol urish nima

Tinkoff.ru, ko'plab zamonaviy kompaniyalar singari, mijozlar reytingiga ega. Skoring - bu ma'lumotlarni tahlil qilishning statistik usullariga asoslangan mijozlarni baholash tizimi.

Masalan, mijoz unga kredit berish yoki bizda yakka tartibdagi tadbirkor hisobini ochish iltimosi bilan bizga murojaat qiladi. Agar biz unga kredit berishni rejalashtirmoqchi bo'lsak, unda biz uning to'lov qobiliyatini baholashimiz kerak va agar hisob qaydnomasi yakka tartibdagi tadbirkor bo'lsa, u holda mijoz firibgarlik operatsiyalarini amalga oshirmasligiga ishonch hosil qilishimiz kerak.

Bunday qarorlarni qabul qilish uchun asos bo'lib, dasturning o'zidan ma'lumotlarni ham, bizning saqlashimizdagi ma'lumotlarni ham tahlil qiladigan matematik modellardir. Hisoblashdan tashqari shunga o'xshash statistik usullardan mijozlarimiz uchun yangi mahsulotlar bo'yicha individual tavsiyalar yaratish xizmatida ham foydalanish mumkin.

Bunday baholash usuli turli xil kirish ma'lumotlarini qabul qilishi mumkin. Va ma'lum bir nuqtada biz kirishga yangi parametr qo'shishimiz mumkin, bu tarixiy ma'lumotlar bo'yicha tahlil natijalariga asoslanib, xizmatdan foydalanishning konvertatsiya tezligini oshiradi.

Biz mijozlar bilan munosabatlar haqida juda ko'p ma'lumotlarga egamiz va bu ma'lumotlarning hajmi doimiy ravishda o'sib bormoqda. Ballar ishlashi uchun ma'lumotlarni qayta ishlash qoidalari (yoki matematik modellar)ni ham talab qiladi, bu sizga kimga arizani ma'qullash, kimni rad etish va kimga yana bir nechta mahsulotni taklif qilish, ularning potentsial qiziqishlarini baholashni tezda hal qilish imkonini beradi.

Vazifani bajarish uchun biz allaqachon qaror qabul qilishning maxsus tizimidan foydalanamiz IBM WebSphere ILOG JRules BRMS, bu tahlilchilar, texnologlar va ishlab chiquvchilar tomonidan belgilangan qoidalarga asoslanib, mijozga ma'lum bir bank mahsulotini tasdiqlash yoki rad etish to'g'risida qaror qabul qiladi.

Bozorda ko'plab tayyor echimlar mavjud, ular ham baholash modellari, ham qaror qabul qilish tizimlarining o'zlari. Biz kompaniyamizda ushbu tizimlardan birini ishlatamiz. Ammo biznes o'sib bormoqda, diversifikatsiya qilinmoqda, mijozlar soni ham, taklif qilinadigan mahsulotlar soni ham ko'paymoqda va shu bilan birga, mavjud qarorlarni qabul qilish jarayonini qanday yaxshilash bo'yicha g'oyalar paydo bo'lmoqda. Albatta, mavjud tizim bilan ishlaydigan odamlar uni qanday qilib sodda, yaxshiroq va qulayroq qilish haqida ko'p fikrlarga ega, ammo ba'zida tashqaridan kelgan g'oyalar foydali bo'ladi. New Hackathon asosli g'oyalarni to'plash maqsadida tashkil etilgan.

Vazifa

Xakaton 23-fevral kuni bo‘lib o‘tdi. Ishtirokchilarga jangovar vazifa taklif qilindi: bir qator shartlarga javob berishi kerak bo'lgan qarorlar qabul qilish tizimini ishlab chiqish.

Bizga mavjud tizim qanday ishlashi va uning ishlashi davomida qanday qiyinchiliklar yuzaga kelishi, shuningdek, ishlab chiqilgan platforma qanday biznes maqsadlarini ko‘zlashi kerakligi haqida ma’lumot berildi. Tahlilchilarning ish kodi imkon qadar tezroq ishlab chiqarishga kirishi uchun tizim qoidalarni ishlab chiqish uchun tez bozorga chiqish vaqtiga ega bo'lishi kerak. Kiruvchi arizalar oqimi uchun qaror qabul qilish vaqti minimal bo'lishi kerak. Shuningdek, ishlab chiqilayotgan tizim mijozga kompaniyaning boshqa mahsulotlarini, agar ular biz tomonimizdan ma'qullangan bo'lsa va mijozdan potentsial qiziqishga ega bo'lsa, sotib olish imkoniyatini berish uchun o'zaro savdo imkoniyatlariga ega bo'lishi kerak.

Bir kechada ishlab chiqarishga tayyor bo'lgan loyihani yozishning iloji yo'qligi aniq va butun tizimni qamrab olish juda qiyin, shuning uchun bizdan hech bo'lmaganda bir qismini amalga oshirishni so'rashdi. Prototip qondirishi kerak bo'lgan bir qator talablar o'rnatildi. Ikkalasini ham barcha talablarni to'liq qamrab olishga va ishlab chiqilayotgan platformaning alohida bo'limlari ustida batafsil ishlashga harakat qilish mumkin edi.

Texnologiyaga kelsak, barcha ishtirokchilarga to'liq tanlash erkinligi berildi. Har qanday tushuncha va texnologiyalardan foydalanish mumkin edi: ma'lumotlar oqimi, mashinani o'rganish, voqealar manbasi, katta ma'lumotlar va boshqalar.

Bizning yechimimiz

Bir oz aqliy hujumdan so'ng, biz FaaS yechimi vazifani bajarish uchun ideal bo'lishiga qaror qildik.

Ushbu yechim uchun ishlab chiqilayotgan qaror qabul qilish tizimining qoidalarini amalga oshirish uchun mos Serversiz ramkani topish kerak edi. Tinkoff infratuzilmani boshqarish uchun Kubernetes-dan faol foydalanayotganligi sababli, biz unga asoslangan bir nechta tayyor echimlarni ko'rib chiqdik; bu haqda keyinroq aytib beraman.

Eng samarali yechimni topish uchun biz ishlab chiqilayotgan mahsulotga uning foydalanuvchilari nazari bilan qaradik. Tizimimizning asosiy foydalanuvchilari qoidalarni ishlab chiqish bilan shug'ullanadigan tahlilchilardir. Qoidalar serverga joylashtirilishi yoki bizning holatimizda bo'lgani kabi, keyinchalik qaror qabul qilish uchun bulutda joylashtirilishi kerak. Tahlilchi nuqtai nazaridan, ish jarayoni quyidagicha ko'rinadi:

  1. Tahlilchi ombordan olingan ma'lumotlar asosida skript, qoida yoki ML modelini yozadi. Hackathon doirasida biz Mongodb-dan foydalanishga qaror qildik, ammo bu erda ma'lumotlarni saqlash tizimini tanlash muhim emas.
  2. Tarixiy ma'lumotlar bo'yicha ishlab chiqilgan qoidalarni sinab ko'rgandan so'ng, tahlilchi o'z kodini administrator paneliga yuklaydi.
  3. Versiyalashni ta'minlash uchun barcha kod Git omborlariga o'tadi.
  4. Administrator paneli orqali kodni bulutda alohida funktsional Serversiz modul sifatida joylashtirish mumkin bo'ladi.

Mijozlarning dastlabki ma'lumotlari dastlabki so'rovni ombordagi ma'lumotlar bilan boyitish uchun mo'ljallangan ixtisoslashtirilgan boyitish xizmati orqali o'tishi kerak. Ushbu xizmatni yagona ma'lumotlar tuzilmasini saqlab qolish uchun yagona ombor bilan ishlaydigan (tahlilchi qoidalarni ishlab chiqishda ma'lumotlarni oladi) ishlaydigan tarzda amalga oshirish muhim edi.

Hackathondan oldin ham biz foydalanadigan Serversiz ramkaga qaror qildik. Bugungi kunda bozorda ushbu yondashuvni amalga oshiradigan juda ko'p texnologiyalar mavjud. Kubernetes arxitekturasidagi eng mashhur echimlar: Fission, Open FaaS va Kubeless. Hatto bor ularning tavsifi va qiyosiy tahlili bilan yaxshi maqola.

Barcha ijobiy va salbiy tomonlarini ko'rib chiqqach, biz tanladik Maqsad. Ushbu Serversiz ramkani boshqarish juda oson va vazifa talablariga javob beradi.

Fission bilan ishlash uchun siz ikkita asosiy tushunchani tushunishingiz kerak: funktsiya va atrof-muhit. Funktsiya - bu Fission muhiti mavjud bo'lgan tillardan birida yozilgan kod qismi. Ushbu doirada amalga oshirilgan muhitlar ro'yxati Python, JS, Go, JVM va boshqa ko'plab mashhur tillar va texnologiyalarni o'z ichiga oladi.

Fission shuningdek, arxivga oldindan qadoqlangan bir nechta fayllarga bo'lingan funktsiyalarni bajarishga qodir. Kubernetes klasteridagi Fission ning ishlashi ramkaning o'zi tomonidan boshqariladigan maxsus podlar tomonidan ta'minlanadi. Klaster podlari bilan o'zaro ishlash uchun har bir funktsiyaga o'z marshruti tayinlanishi kerak va POST so'rovi bo'lsa, GET parametrlarini yoki so'rov tanasini o'tkazishingiz mumkin.

Natijada, biz tahlilchilarga muhandislar va ishlab chiquvchilar ishtirokisiz ishlab chiqilgan qoidalar skriptlarini joylashtirish imkonini beradigan yechim olishni rejalashtirdik. Ta'riflangan yondashuv, shuningdek, ishlab chiquvchilar uchun tahlilchi kodini boshqa tilga qayta yozish zaruratini ham yo'q qiladi. Masalan, biz foydalanadigan hozirgi qarorlar tizimi uchun biz qoidalarni yuqori darajada ixtisoslashgan texnologiyalar va tillarda yozishimiz kerak, ularning ko'lami juda cheklangan, shuningdek, dastur serveriga kuchli bog'liqlik mavjud, chunki barcha bank qoidalari loyihalari yagona muhitda joylashtiriladi. Natijada, yangi qoidalarni o'rnatish uchun butun tizimni chiqarish kerak.

Bizning taklif qilayotgan yechimimizda qoidalarni chiqarishning hojati yo'q; kodni bir tugmani bosish orqali osongina joylashtirish mumkin. Shuningdek, Kubernetes-da infratuzilmani boshqarish yuklash va masshtablash haqida o'ylamaslikka imkon beradi, bunday muammolar qutidan tashqarida hal qilinadi. Va yagona ma'lumotlar omboridan foydalanish real vaqt rejimidagi ma'lumotlarni tarixiy ma'lumotlar bilan solishtirish zaruratini yo'q qiladi, bu esa tahlilchining ishini soddalashtiradi.

Bizda nima bor

Biz xakatonga tayyor yechim bilan kelganimiz uchun (fantaziyalarimizda), biz qilishimiz kerak bo'lgan narsa barcha fikrlarimizni kod satrlariga aylantirish edi.

Har qanday xakatonda muvaffaqiyat kaliti tayyorgarlik va yaxshi yozilgan rejadir. Shuning uchun, biz qilgan birinchi narsa tizim arxitekturamiz qanday modullardan iborat bo'lishini va qanday texnologiyalardan foydalanishimizni hal qilish edi.

Loyihamizning arxitekturasi quyidagicha edi:

Qanday qilib biz Kubernetes ichida bulutli FaaS yaratdik va Tinkoff xakatonida g'olib chiqdik
Ushbu diagrammada ikkita kirish nuqtasi, tahlilchi (tizimimizning asosiy foydalanuvchisi) va mijoz ko'rsatilgan.

Ish jarayoni shunday tuzilgan. Tahlilchi o'z modeli uchun qoida funksiyasi va ma'lumotlarni boyitish funksiyasini ishlab chiqadi, kodini Git omborida saqlaydi va administrator ilovasi orqali o'z modelini bulutga joylashtiradi. Keling, o'rnatilgan funktsiya qanday chaqirilishini ko'rib chiqaylik va mijozlardan kiruvchi so'rovlar bo'yicha qaror qabul qilaylik:

  1. Mijoz veb-saytdagi shaklni to'ldiradi va so'rovini nazoratchiga yuboradi. Qaror qabul qilinishi kerak bo'lgan ariza tizimga kiritiladi va ma'lumotlar bazasida asl shaklida qayd etiladi.
  2. Keyinchalik, agar kerak bo'lsa, xom so'rov boyitish uchun yuboriladi. Siz dastlabki so'rovni tashqi xizmatlardan ham, xotiradan ham ma'lumotlar bilan to'ldirishingiz mumkin. Olingan boyitilgan so'rov ham ma'lumotlar bazasida saqlanadi.
  3. Tahlilchi funksiyasi ishga tushiriladi, u boyitilgan so'rovni kirish sifatida qabul qiladi va yechimni ishlab chiqaradi, u ham xotiraga yoziladi.

JSON hujjatlari ko'rinishidagi ma'lumotlarning hujjatga yo'naltirilgan saqlanishi tufayli biz MongoDB-dan tizimimizda saqlash sifatida foydalanishga qaror qildik, chunki boyitish xizmatlari, shu jumladan asl so'rov barcha ma'lumotlarni REST kontrollerlari orqali jamlagan.

Shunday qilib, platformani amalga oshirish uchun bizda XNUMX soat vaqt bor edi. Biz rollarni juda muvaffaqiyatli taqsimladik, har bir jamoa a'zosi loyihamizda o'z mas'uliyat sohasiga ega edi:

  1. Tahlilchining ishi uchun ma'mur panellari, ular orqali u yozma skriptlar versiyalarini boshqarish tizimidan qoidalarni yuklab olishi, kiritilgan ma'lumotlarni boyitish variantlarini tanlashi va qoidalar skriptlarini onlayn tahrirlashi mumkin edi.
  2. Backend administratori, shu jumladan front uchun REST API va VCS bilan integratsiya.
  3. Google Cloud-da infratuzilmani o'rnatish va manba ma'lumotlarini boyitish xizmatini ishlab chiqish.
  4. Qoidalarni keyinchalik joylashtirish uchun administrator ilovasini Serversiz ramka bilan integratsiyalash moduli.
  5. Butun tizimning ishlashini sinab ko'rish qoidalarining skriptlari va yakuniy namoyish uchun kiruvchi ilovalar (qabul qilingan qarorlar) bo'yicha tahlillarni yig'ish.

Tartibda boshlaymiz.

Bizning old tomonimiz Angular 7 da bank UI Kit yordamida yozilgan. Administrator panelining oxirgi versiyasi quyidagicha ko'rinishga ega edi:

Qanday qilib biz Kubernetes ichida bulutli FaaS yaratdik va Tinkoff xakatonida g'olib chiqdik
Vaqt oz bo'lgani uchun biz faqat asosiy funksiyalarni amalga oshirishga harakat qildik. Kubernetes klasterida funktsiyani o'rnatish uchun voqeani (bulutda qoida joylashtirilishi kerak bo'lgan xizmat) va qaror qabul qilish mantiqini amalga oshiradigan funktsiya kodini tanlash kerak edi. Tanlangan xizmat uchun qoidani har bir joylashtirish uchun biz ushbu hodisa jurnalini yozdik. Administrator panelida siz barcha voqealar jurnallarini ko'rishingiz mumkin.

Barcha funktsiya kodi masofaviy Git omborida saqlangan, u ham boshqaruv panelida o'rnatilishi kerak edi. Kodni versiya qilish uchun barcha funktsiyalar omborning turli bo'limlarida saqlangan. Administrator paneli, shuningdek, yozma skriptlarga tuzatishlar kiritish imkoniyatini beradi, shuning uchun ishlab chiqarishga funktsiyani qo'llashdan oldin siz nafaqat yozma kodni tekshirishingiz, balki kerakli o'zgarishlarni ham kiritishingiz mumkin.

Qanday qilib biz Kubernetes ichida bulutli FaaS yaratdik va Tinkoff xakatonida g'olib chiqdik
Qoidalar funktsiyalaridan tashqari, biz manba ma'lumotlarini boyitish funktsiyalaridan foydalangan holda bosqichma-bosqich boyitish imkoniyatini ham amalga oshirdik, ularning kodi ma'lumotlar omboriga kirish, uchinchi tomon xizmatlariga qo'ng'iroq qilish va dastlabki hisob-kitoblarni amalga oshirish mumkin bo'lgan skriptlar edi. . Bizning yechimimizni namoyish qilish uchun biz so'rovni qoldirgan mijozning zodiak belgisini hisoblab chiqdik va uchinchi tomon REST xizmatidan foydalangan holda uning uyali aloqa operatorini aniqladik.

Platformaning orqa qismi Java-da yozilgan va Spring Boot ilovasi sifatida amalga oshirilgan. Biz dastlab administrator ma'lumotlarini saqlash uchun Postgres-dan foydalanishni rejalashtirgan edik, ammo xakatonning bir qismi sifatida vaqtni tejash uchun o'zimizni oddiy H2 bilan cheklashga qaror qildik. Backendda Bitbucket bilan integratsiya so'rovlarni boyitish funktsiyalari va qoida skriptlarini versiyalash uchun amalga oshirildi. Masofaviy Git omborlari bilan integratsiya qilish uchun biz foydalandik JGit kutubxonasi, bu CLI buyruqlari ustidan o'rashning bir turi bo'lib, qulay dasturiy ta'minot interfeysi yordamida har qanday git ko'rsatmalarini bajarishga imkon beradi. Shunday qilib, bizda boyitish funktsiyalari va qoidalari uchun ikkita alohida ombor mavjud edi va barcha skriptlar kataloglarga bo'lingan. UI orqali omborning o'zboshimchalik bilan bo'linmasi skriptining so'nggi topshirig'ini tanlash mumkin edi. Administrator paneli orqali kodga o'zgartirishlar kiritilganda, o'zgartirilgan kodning majburiyatlari masofaviy omborlarda yaratildi.

Bizning fikrimizni amalga oshirish uchun bizga mos infratuzilma kerak edi. Biz Kubernetes klasterimizni bulutda joylashtirishga qaror qildik. Bizning tanlovimiz Google Cloud Platform edi. Fission serversiz ramka biz Gcloud-da joylashtirgan Kubernetes klasteriga o'rnatildi. Dastlab, manba ma'lumotlarini boyitish xizmati k8s klasteridagi Podga o'ralgan alohida Java ilovasi sifatida amalga oshirildi. Ammo xakaton o'rtasida loyihamizning dastlabki namoyishidan so'ng, bizga kiruvchi ilovalarning xom ma'lumotlarini qanday boyitishni tanlash imkoniyatini taqdim etish uchun Enrichment xizmatini yanada moslashuvchan qilish tavsiya qilindi. Va bizda boyitish xizmatini Serversiz qilishdan boshqa ilojimiz yo'q edi.

Fission bilan ishlash uchun biz Kubernetes CLI tepasiga o'rnatilishi kerak bo'lgan Fission CLI-dan foydalandik. Funksiyalarni k8s klasteriga joylashtirish juda oddiy; siz faqat ichki marshrutni belgilashingiz va klasterdan tashqariga kirish kerak bo'lsa, kiruvchi trafikni ta'minlash uchun funksiyaga kirishingiz kerak. Bitta funktsiyani o'rnatish odatda 10 soniyadan ko'proq vaqtni oladi.

Loyihaning yakuniy taqdimoti va xulosasi

Tizimimiz qanday ishlashini ko'rsatish uchun biz masofaviy serverga oddiy shaklni joylashtirdik, unda siz bank mahsulotlaridan biriga ariza topshirishingiz mumkin. Talab qilish uchun siz o'zingizning bosh harflaringizni, tug'ilgan kuningizni va telefon raqamingizni kiritishingiz kerak edi.

Mijoz shaklidagi ma'lumotlar nazoratchiga o'tdi, u bir vaqtning o'zida barcha mavjud qoidalar bo'yicha so'rovlarni yubordi, oldindan belgilangan shartlarga muvofiq ma'lumotlarni boyitib, ularni umumiy xotirada saqlaydi. Hammasi bo'lib, biz kiruvchi ilovalar bo'yicha qaror qabul qiladigan uchta funktsiyani va ma'lumotlarni boyitish bo'yicha 4 ta xizmatlarni ishlatdik. Arizani topshirgandan so'ng, mijoz bizning qarorimizni oldi:

Qanday qilib biz Kubernetes ichida bulutli FaaS yaratdik va Tinkoff xakatonida g'olib chiqdik
Rad etish yoki tasdiqlashdan tashqari, mijoz boshqa mahsulotlar ro'yxatini ham oldi, biz parallel ravishda yuborgan so'rovlar. Shunday qilib, biz platformamizda o'zaro savdo imkoniyatini namoyish etdik.

Hammasi bo'lib 3 ta soxta bank mahsuloti mavjud edi:

  • Kredit.
  • O'yinchoq
  • Ipoteka.

Namoyish davomida biz har bir xizmat uchun tayyorlangan funksiyalar va boyitish skriptlarini joylashtirdik.

Har bir qoida o'ziga xos kirish ma'lumotlar to'plamini talab qiladi. Shunday qilib, ipotekani tasdiqlash uchun biz mijozning zodiak belgisini hisoblab chiqdik va buni oy taqvimi mantig'i bilan bog'ladik. O'yinchoqni tasdiqlash uchun biz mijozning voyaga etganligini tekshirdik va kredit berish uchun uyali aloqa operatorini aniqlash uchun tashqi ochiq xizmatga so'rov yubordik va bu haqda qaror qabul qilindi.

Namoyishimizni qiziqarli va interaktiv qilishga harakat qildik, hozir bo'lgan har bir kishi bizning formamizga kirib, ularga bizning uydirma xizmatlarimiz mavjudligini tekshirishi mumkin edi. Taqdimot oxirida biz qabul qilingan arizalar tahlilini namoyish qildik, bu bizning xizmatimizdan qancha odam foydalangani, ma'qullanganlar va rad etilganlar sonini ko'rsatdi.

Onlayn tahlillarni to'plash uchun biz qo'shimcha ravishda ochiq manbali BI vositasini o'rnatdik Metabaza va uni saqlash birligimizga vidaladi. Metabaza sizga bizni qiziqtirgan ma'lumotlar bo'yicha tahliliy ekranlarni yaratishga imkon beradi; siz shunchaki ma'lumotlar bazasiga ulanishni ro'yxatdan o'tkazishingiz, jadvallarni tanlashingiz kerak (bizning holatlarimizda, biz MongoDB-dan foydalanganimiz uchun ma'lumotlar to'plami) va bizni qiziqtirgan sohalarni belgilashingiz kerak. .

Natijada biz qaror qabul qilish platformasining yaxshi prototipini oldik va namoyish davomida har bir tinglovchi uning ishlashini shaxsan tekshirishi mumkin edi. Qiziqarli yechim, tayyor prototip va muvaffaqiyatli namoyish boshqa jamoalarning kuchli raqobatiga qaramay, g'alaba qozonishimizga imkon berdi. Ishonchim komilki, har bir jamoaning loyihasi bo'yicha qiziqarli maqola ham yozilishi mumkin.

Manba: www.habr.com

a Izoh qo'shish