"12 faktorli" dastur
Tags: 12factor, software, saas, methodology
Published: 2023-10-27 14:23:16

Ushbu maqolada dasturiy ta'minotni muvofaqiyatli ishlab chiqish uchun ishlatiladigan metodologiyalardan biri bilan tanishamiz.
> _Diskleymer_: This is the Uzbek translation of https://12factor.net. Tarjimasi chiqmagan inglizcha so'zlar oxiriga "*" belgisi qo'yilgan

**"12 faktor"** - bu dasturiy ta'monot ishlab chiqish metodologiyasi bo'lib, u bizga quyidagi qulayliklarni beradi:

1. **Dasturni ishga tushirish uchun deklarativ ko'rsatmalar** - bu loyihaga yangi qo'shiluvchilar uchun jarayonni tez va oson qiladi;
2. **Dasturni operatsion tizimi bilan kam aloqadorligi** - bu dasturni istalgan muhitda ishlashini ta'minlaydi
3. **Bulutli platformalarda joylashtirish uchun mos** - bu serverlar va tizim adminstratorlariga bo'lgan ehtiyojni bartaraf etadi;
4. **`dev` va `prod` orasidagi farqni kamaytirish** - bu yangi fichalarni tezkorlik bilan qo'shishga imkon beradi;
5. Kam harakat va harajat bilan dasturni kengaytirishga yordam beradi.

SaaS (software-as-a-service), ya'ni xizmat ko'rinishidagi dasturiy ta'minot ishlab chiqaruvchi injiner yoki shunaqa dasturlarni deploy* qiluvchi devops dasturchi ushbu metodologiyani bilishi maqsadga muvofiq.

12 faktor quyidagilardan iborat:

1. Kod bazasi
2. Dependency'lar*
3. Konfiguratsiya
4. Yordamchi xizmatlar
5. Build, release, run*
6. Protses
7. Port orqali bog'lash
8. Bir vaqtda ishga tushirish (concurrency)
9. Ishga tushirish/tugatish
10. `dev` va `prod` yaqinligi
11. Loglar
12. Admin protseslar

## 1. Kodbaza
"12 faktorli" dastur albatta versiya nazorati orqali ishlab chiqiladi. Bunda kodlarni `repo`da saqlaymiz. Repo - bu kodlarimizni vaqt davomida o'zgarishini yozib boruvchi ma'mumotlar bazasi. Misol uchun [Git](https://git-scm.com). Kodbaza va dastur orasidagi bog'liqliklarni quyidagicha ko'rish mumkin:

1. Agar kodbaza ko'p bo'lsa, unda biz dastur emas **distributed system** qilayapmiz. Undagi har bir element alohida dastur va ularni har birini "12 faktor" asosida ishlab chiqamiz;
2. Agar ko'plab dasturlar bir xil kodbazadan foydalanayotgan bo'lsa bu "12 faktorni" buzilishiga olib keladi. Bunday holatda kodlarni kutubxona ko'rinishida **dependency manager*** orqali ishlatish kerak bo'ladi. Misol uchun [npm](https://npmjs.com).

Bitta dasturda bitta kodbaza bo'ladi, lekin uni bemalol hohlagancha deploy* qilsa bo'ladi. **Deploy** - bu dasturni biror mashinada ishga tushirish hisoblanadi. Masalan, React.js'da qilingan vebsaytni [Vercel](https://vercel.com)'da deploy qilish mumkin. Bundan tashqari turli mashinalarda dasturning turli versiyalari deploy qilinishi mumkin.

## 2. Dependency'lar
**Dependency**lar - bu dasturdagi bir-biriga bog'liq komponentlar majmui. Bu komponentlarni bevosita e'lon qilib qo'yish va izolyatsiya qilish zarur. Ko'p holatlarda dependency'larni e'lon qilish uchun har til/texnologiyaning o'zini package* sistemasi bo'ladi. Misol uchun **Node.js** da **npm**. Bunda `package.json` faylda barcha dependency'lar ro'yhati kiritiladi. Bu bizga loyihani ishga tushirish uchun kerakli dependency'larni osonlik bilan o'rnatish imkonini beradi.

Bundan tashqari dasturimizning dependency'lari faqat dasturning o'zidan boshqarilishi zarur. Masalan, sizning komputeringizda `curl` o'rnatilgan va siz dasturda uni ishlatdingiz, lekin uni deklaratsiya qilmadingiz. Endi biror hamkasbingiz dasturni ishlatishda muammoga duch keldi, chunki unda `curl` yo'q. Yana ham muhimi, har bir dependency deklaratsiyasi o'zi bilan birga versiyasini ham bildirishi kerak. Chunki masalan `npm i express` bizga hozir `4.18.2` versiyani beradi va dastur shu versiya bilan ishlaydi. Lekin biror vaqtdan keyin bu buyruq boshqa versiyani olib kelishi mumkin va bu dastur notog'ri ishlashiga sabab bo'ladi.

## 3. Konfiguratsiya
Dastur konfigurtasiyasi (qisqa qilib konfig) turli xil deploy'larda turlicha bo'lishi mumkin, masalan `staging`, `production`, `dev`. Konfig o'z ichiga quyidagilarni oladi:

1. Ma'lumotlar bazasi, Redis yoki boshqa shunga o'xshash yordamchi xizmatlar uchun maxfiy kalitlar;
2. Tashqi xizmatlar uchun maxfiy kalitlar, misol uchun Amazon S3 yoki Telegram Bot tokeni;
3. Dasturni deploy qilish uchun turli argumentlar, misol uchun host va port.

Ba'zi dasturlarda bunaqa ma'lumotlar kodni ichida bo'ladi (_hardcode_), bu esa "12 faktorni" qo'pol buzish hisoblanadi! Bunday ma'lumotlar **environment** _(dastur ishga tushuvchi muhit)_ da saqlanishi zarur. Yoki bo'lmasa alohida konfig faylda saqlash kerak, misol uchun `.env` yoku `config.yml`. Bu fayllar Git'ga yuborilmaydi, ya'ni har bir deploy uchun alohida yoziladi. Muhimi kodga aralashmaydi.

## 4. Yordamchi xizmatlar
Yordamchi xizmat - bu dastur o'z faoliyati davomida internet orqali bog'lanib, biror amaliyotni bajaruvchi yoki ma'lumot oluvchi tashqi resurs hisoblanadi. Misol qilib ma'lumotlar bazasi (MySQL, MongoDB), _message/queue_* tizimlar (RabbitMQ), SMTP xizmatlar (mailing* uchun) yoki kesh tizimlari (Redis, Memcached) kabilarni ko'rsatish mumkin.

Bu xizmatlarni odatda dasturni deploy qilgan devops mutaxasislani o'zlari sozlashadi. Lokal deploy qilishdan tashqari 3-tomon servislaridan ham foydalaniladi, masalan SMTP yoki xatira uchun _API_*lar.

"12 faktor"li dasturlar lokal va 3-tomon xizmatlarini birdek ishlata olishi kerak, ya'ni masalan databaza lokal deploy qilingan bo'lsa ham, 3-tomon servisi orqali olingan bo'lsa ham birdek ishlay olishi kerak. Bunda o'sha resursni konfiglarida dastur bog'lanishi uchun URL yoki shunga o'shash parametrlar bo'ladi.

## 5. Build, release, run
Kodimiz deploy qilish uchun 3 ta bosqichdan o'tadi:

1. **Build**, bunda kod ishlashi uchun barcha _dependency_'lar o'rnatiladi va ishga tushirsa bo'ladigan formatda keltiriladi (_executable_ yoki script);
2. **Release**, bunda `build`dagi dastur olinadi va konfiglar bilan ta'minlanadi. Natijada dasturimiz ishga tushirishga tayyor bo'ladi.
3. **Run** yani ishlatish, bunda dastur kerakli muhitda ishga tushiriladi.

"12 faktorli" dasturlarda bu 3 ta bosqich albatta alohida ajratilishi kerak. Ya'ni masalan _runtime_ da kodga o'zgartirish kiritib bo'lmasligi kerak.
Bundan tashqari har bir release uchun noyob _id_ yoki _teg_ qo'yish kelgusida rollback* qilish imkonini beradi. Rollback - bu biror xatolik tufayli dasturni avvalgi versiyasiga qaytarish hisoblanadi. Masalan, dasturni Docker image* qilib build qilish mumkin va unga teg beramiz. [DockerHub](https://hub.docker.com)'dagi image'larni teglari bilan ko'rgan bo'lishingiz kerak. [Caprover](https://caprover.com) orqali Docker image'larni deploy qilish mumkin va unda rollback funksiyasi ham bor. 

## 6. Protses
Dastur bitta muhitda bir yoki bir nechta protses bo'lib ishlaydi. Oddiy holatda bu bitta executable* fayl yoki skript bo'ladi.

"12 faktorli" dasturda state* bo'lmaydi, ya'ni hech qanday data saqlamaydi. Agar data saqlash kerak bo'lsa yordamchi xizmatlardan foydalanadi, masalan databaza.
Vaqtinchalik saqlash uchun ma'lumotlarni faylsistemada saqlab turish mumkin. Masalan bitta `.jpg` faylni internetdan yuklab olib, uni ustida amal bajarib, `S3`'ga yuklab, foydalanuvchiga `URL`ni yuborib, keyin faylni o'chirib yuborish. Bunda fayl kelajakda saqlanib qolishi uchun zarurat yo'q.

Ba'zida web serverda "user session" yoki Telegram Bot'dagi session*ni saqlab qo'yamiz. Bu in-memory saqlash bo'lib, "12 faktor"ni buzish hisoblanadi.

## 7. Port orqali bog'lash
Web dasturlar ko'p holatlarda vebserver ichida alohida "konteyner" bo'lib ishlaydi. Bu dasturni portable*, ya'ni qulay qiladi. Bunda dastur tashqi serverning biror parametriga bog'liq bo'lmasligi kerak. Aksincha uni ixtiyoriy port orqali ishlatishning iloji bo'lishi kerak. Masalan, siz Node.js'da server qildingiz va "srazi" uni 3 ta instance*da ishlatmoqchisiz. Ularni 3001, 3002 va 3003 portlarda ishga tushirasiz va serverdagi 80 portga kelgan so'rovlarni ushbu instance'larga bo'lib berasiz. Buni hozirgi kundagi odatiy implementatsiya sifatida ko'rishimiz mumkin.

Bundan tashqari yordamchi xizmatlarni ham port orqali bog'lash mumkin. Bunda URL orqali asosiy dastur yordamchi dasturga so'rov yuboradi.

## 8. Concurrency
"12 faktorli" dasturlarni concurrency* orqali scale-out* qilish mumkin va bu horizontal scaling. Concurrency deganda bir yoki bir nercha vazifani bir vaqtda bajarilishi tushuniladi. "Scaling" esa dasturni kengaytirish, uni katta miqdordagi bosimni ko'tara olishini ta'minlashni bildiradi. 

Protseslar asosiy o'yin qatnashchilari bo'lib, uning turlariga qarab o'z dasturimizni loyihalashtiramiz. Turlari deganda thread* (potok), protses yoki worker kabilarni tushunishimiz mumkin. Misol uchun, HTTP so'rovni protses bilan handle* qilsak, ko'p vaqt oladigan vazifalarni worker bilan amalga oshiramiz.
Bundan tashqari queue* tizimini implementatsiya qilib ham dasturni responsiveness*ini oshirish mumkin. Queue - bu vazifalarni navbatga qo'shib qo'yib, FIFO tartibida bajarishdir.

## 9. Disposability
Dastur tez ishga tushishi va zararsiz to'xtashi kerak. Bu bizga tezroq deploy qilish va konfiglarni o'zgartirish imkonini beradi. Protses `SIGTERM` (signal terminate) olganda `graceful shutdown` qilishi kerak. Graceful shutdown - bu dastur vazifa olishni to'xtatib, bajarayotgan vazifalarni tugatib, tashqi resurslar bilan aloqani uzib talofatlarsiz to'xtashidir. Dastur qachon va qanday signal qabul qiladi? Signalni komputerdagi servis menejer beradi, misol uchun systemd yoki deylik Docker.

Worker protses uchun graceful shutdown qilish birmuncha qiyin. Bunda worker uchun topshiriq qaytadan queue'ga qaytarilishi kerak va keyin worker(lar) vazifasini to'xtatishi mumkin bo'ladi. Bu huddi databazadagi transaksiyaga o'xshaydi, agar muammo bo'lsa terminate qilish kerak. Bundan tashqari dasturning faqat `master` protsesi signalni qabul qiladi, bu degani boshqa slave fork*larni graceful shutdown qilish kerak bo'ladi. Ko'proq o'qish uchun ["Crash-only design"](http://lwn.net/Articles/191059)ni o'qishingiz mumkin.

## 10. `dev` va `prod` yaqinligi
`dev` va `prod` orasidagi farq biz uchun minusga ishlaydi. Yomon alomatlar:

- `dev`dan `prod`ga chiqish uchun dasturchi ko'p vaqt sarflaydi;
- Injiner kod yozadi, devops uni deploy qiladi;
- `dev` va `prod`dagi ishlatilgan texnologiyalar farq qiladi.

Agar bu alomatlar sizning ish joyingizda bo'lsa, ishlar chatoq. Chunki bular unumdorlikni tushirib yuboradi va dasturni ishlab chiqish jarayonini sekinlashtitadi.

Biz daploy muhitidagi yordamchi resurslar uchun abstraktsiyalar yozamiz, lekin bu resurslar farq qilgani uchun bizga ko'zlanganidek yordam bermaydi. Shunda ham abstraktsiyalar muhim, chunki ular boshqa yordamchi xizmatga o'tganimizda ko'plab bosh og'riqlarimizni kamaytiradi.

## 11. Loglar
 Loglar bizga dasturni harakterini ko'rsatib beradi. Loglarga qarab dastur o'tmishda va hozir qanday ishlayotganini ko'ra olamiz. Loglar vebserverlarda asosan faylga yoziladi, lekin bu shunchaki logni saqlash formati xolos.

Loglar shunchaki `.logfile` deb nomlanuvchi fayl emas, ular aslida ma'lumotlar oqimi (stream*). Stream dasturdan real vaqt davomida kelib turadi va biz uni monitor qila olamiz. Dastur loglarni saqlab qo'yish haqida qayg'urmasligi kerak, shunchaki ularni stream qilib `stdout`ga berib tursa bo'lgani. Local deployda dasturchi loglarni terminal orqali real vaqtda ko'rib turadi, prod'da esa `stdout`dagi loglar tashqaridan olib turiladi va uzoq muddatga saqlab qo'yiladi. Bu yerdan esa kelajakda analiz, hodisalarni vaqt bo'yicha o'zgarishi va shunga o'xshash ma'lumotlar hosil qilinadi.

## 12. Admin protseslar
Ba'zida asosiy dastur ishlab turgan protsesdan boshqa, bir martalik vazifani bajarish uchun protses ochishga to'g'ri keladi. Masalan, databazaga migratsiyalarni qo'llash, REPL ishga tushirish yoki biror skript faylni yurgizish. Bunda bir martalik admin protseslar asosiy uzoq muddat ishlaydigan protsesniki bilan bir xil muhitda ishlashi kerak. Bundan tashqari, admin protses kod bilan birga bo'lishi kerak va yangilanishi, chunki sinxronlik bilan muammo chiqishi mumkin.
"12 faktor" metogologiyasi har doim REPL uchun supporti bor tillar/texnologiyalarni avzal ko'radi, chunki ularda admin protseslarni ishga tushirish oson kechadi.

## Xulosa
Umuman olganda, "12 faktor" dasturiy ta'minotni ishlab chiqish, deploy qilish, monitoring va kengaytirish uchun muhim ko'rsatmalar to'plami bo'lib, muvofaqiyatli dasturlar uchun dasturulamal sifatida e'tirof qilsa bo'ladi.

Asosiy manba: https://12factor.net