6-bo‘lim

Dasturiy arxitektura

Qatlamli, monolit va mikroservis arxitekturalar, bog'liqlik va yaxlitlik, arxitektura qarorlarini hujjatlashtirish.

🕑 10 daqiqa o‘qish 📄 993 so‘z 👁 7 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Arxitektura nima?
  2. Ikki asosiy tushuncha
  3. Qatlamli arxitektura
  4. Monolit va mikroservislar
  5. Modulli monolit
  6. Boshqa arxitektura uslublari
  7. Olti burchakli (portlar va adapterlar)
  8. Hodisalarga asoslangan arxitektura
  9. Arxitektura qarorlarini hujjatlashtirish
  10. Arxitektura xatolari
  11. Xulosa

Arxitektura - tizimning eng qimmat o'zgaradigan qarorlari to'plami. Kodni har kuni o'zgartirish mumkin; arxitekturani esa - deyarli hech qachon.

Arxitektura nima? #

Ta'rif

Dasturiy arxitektura - tizimning asosiy komponentlari, ular orasidagi munosabatlar va ularni belgilaydigan prinsiplar.

Amaliy ta'rif: *"arxitektura - keyinchalik o'zgartirish qiyin bo'lgan qarorlar."*

Qarorlarning o'zgartirish narxi Arxitektura qarorlari monolit yoki mikroservis, SQL yoki NoSQL, sinxron yoki asinxron Dizayn qarorlari klasslar tuzilishi, naqshlar, interfeyslar Kod qarorlari o'zgaruvchi nomi, tsikl turi, formatlash Juda qimmat Arzon Yuqoridagi qarorlarga ko'proq vaqt ajrating
Arxitektura xatosini kod bilan tuzatib bo'lmaydi

Ikki asosiy tushuncha #

Yaxshi arxitekturaning ikki mezoni Yuqori bog'liqlik - yomon Bittasini o'zgartirsangiz - hammasi buziladi Past bog'liqlik - yaxshi Har birini alohida o'zgartirish mumkin Oltin qoida Modullar orasida past bog'liqlik (loose coupling) Modul ichida yuqori yaxlitlik (high cohesion)
Bu ikki tushuncha barcha arxitektura qarorlarining asosi
PHP
// Yuqori bog'liqlik - yomon
class BuyurtmaServisi
{
    public function yarating(array $malumot): void
    {
        $pdo = new PDO('mysql:host=localhost;dbname=dokon', 'root', '');
        $pdo->exec("INSERT INTO buyurtmalar ...");

        mail($malumot['email'], 'Buyurtma', 'Rahmat!');

        file_put_contents('/var/log/buyurtma.log', date('c') . " yaratildi\n", FILE_APPEND);
    }
}

Bu klass hamma narsani biladi: baza turini, ulanish ma'lumotlarini, email yuborish usulini, jurnal fayli joylashuvini.

Uni testlab bo'lmaydi, baza yoki email provayderini almashtirib bo'lmaydi.

PHP
// Past bog'liqlik - yaxshi
class BuyurtmaServisi
{
    public function __construct(
        private BuyurtmaRepozitoriyInterfeysi $repozitoriy,
        private XabarnomaInterfeysi $xabarnoma,
        private LoggerInterface $jurnal,
    ) {}

    public function yarating(BuyurtmaSorovi $sorov): Buyurtma
    {
        $buyurtma = $this->repozitoriy->saqlang(
            Buyurtma::yangi($sorov->mijozId, $sorov->elementlar)
        );

        $this->xabarnoma->yuboring(
            $sorov->email,
            new BuyurtmaYaratildi($buyurtma)
        );

        $this->jurnal->info('Buyurtma yaratildi', ['id' => $buyurtma->id]);

        return $buyurtma;
    }
}
Endi nima o'zgardi?
  • Baza turini almashtirish - faqat repozitoriy o'zgaradi
  • Email o'rniga SMS - faqat xabarnoma o'zgaradi
  • Test yozish - soxta obyektlar beriladi, haqiqiy baza kerak emas
  • Klass nima qilishini bildiradi, qanday qilishini emas

Qatlamli arxitektura #

Eng keng tarqalgan tuzilma.

Qatlamli arxitektura Taqdimot qatlami Kontrollerlar, shablonlar, API endpointlari Biznes mantiq qatlami Servislar, biznes qoidalari, domen modellari Ma'lumotga kirish qatlami Repozitoriylar, ORM, so'rovlar Ma'lumotlar bazasi Qatlamni chetlab o'tish TAQIQLANADI
Har bir qatlam faqat quyidagisi bilan gaplashadi
PHP
// Taqdimot qatlami
class BuyurtmaKontrolleri
{
    public function __construct(private BuyurtmaServisi $servis) {}

    public function yarating(Request $sorov): Response
    {
        $malumot = $sorov->validate([
            'mahsulot_id' => 'required|integer',
            'soni'        => 'required|integer|min:1',
        ]);

        $buyurtma = $this->servis->yarating(
            BuyurtmaSorovi::sorovdan($malumot)
        );

        return new JsonResponse(['id' => $buyurtma->id], 201);
    }
}

// Biznes mantiq qatlami
class BuyurtmaServisi
{
    public function __construct(
        private BuyurtmaRepozitoriyInterfeysi $buyurtmalar,
        private MahsulotRepozitoriyInterfeysi $mahsulotlar,
    ) {}

    public function yarating(BuyurtmaSorovi $sorov): Buyurtma
    {
        $mahsulot = $this->mahsulotlar->toping($sorov->mahsulotId);

        if ($mahsulot === null) {
            throw new MahsulotTopilmadi($sorov->mahsulotId);
        }

        if (!$mahsulot->zaxiraYetarlimi($sorov->soni)) {
            throw new ZaxiraYetarliEmas($mahsulot, $sorov->soni);
        }

        return $this->buyurtmalar->saqlang(
            Buyurtma::yangi($sorov->mijozId, $mahsulot, $sorov->soni)
        );
    }
}

// Ma'lumotga kirish qatlami
class MysqlBuyurtmaRepozitoriy implements BuyurtmaRepozitoriyInterfeysi
{
    public function __construct(private PDO $pdo) {}

    public function saqlang(Buyurtma $buyurtma): Buyurtma
    {
        $stmt = $this->pdo->prepare(
            'INSERT INTO buyurtmalar (mijoz_id, jami, holat) VALUES (?, ?, ?)'
        );
        $stmt->execute([$buyurtma->mijozId, $buyurtma->jami, $buyurtma->holat]);

        return $buyurtma->idBilan((int) $this->pdo->lastInsertId());
    }
}
Qatlamlarni chetlab o'tmang
PHP
// XATO: kontroller to'g'ridan-to'g'ri bazaga murojaat qilyapti
class BuyurtmaKontrolleri
{
    public function korsating(int $id): Response
    {
        $pdo = new PDO(/* ... */);
        $buyurtma = $pdo->query("SELECT * FROM buyurtmalar WHERE id = $id");
        // ...
    }
}

Bir marta shunday qilinsa, keyingi safar ham qilinadi. Olti oydan keyin qatlamlar butunlay yo'qoladi.

Monolit va mikroservislar #

Ikki yondashuv Monolit Katalog Savat Buyurtma To'lov Bitta ma'lumotlar bazasi Bitta jarayon, bitta deploy + Sodda, tez, arzon - Katta bo'lganda og'irlashadi Mikroservislar Katalog o'z bazasi Savat o'z bazasi Buyurtma o'z bazasi To'lov o'z bazasi Alohida jarayonlar, alohida deploy + Mustaqil masshtablanadi - Murakkab infratuzilma
Mikroservislar - tashkiliy muammoning texnik yechimi
MonolitMikroservislar
BoshlashOsonQiyin
DeployBittaO'nlab
MasshtablashButun tizimFaqat kerakli qism
TexnologiyaBittaHar xil bo'lishi mumkin
NosozlikButun tizimFaqat bitta xizmat
TranzaksiyaOddiyJuda murakkab
Nosozlikni topishOsonQiyin (taqsimlangan)
JamoaBittaHar xizmatga alohida
InfratuzilmaSoddaKubernetes, monitoring, service mesh
Mikroservislardan boshlamang

Yangi loyihada mikroservis arxitekturasini tanlash - eng ko'p uchraydigan xatolardan biri.

Nima uchun?

  1. Boshida domen chegaralari noma'lum - xizmatlarni noto'g'ri bo'lasiz
  2. Taqsimlangan tizimning murakkabligi ulkan: tarmoq xatolari, izchillik, monitoring
  3. Kichik jamoa buni qo'llab-quvvatlay olmaydi

To'g'ri yo'l: yaxshi modullashtirilgan monolitdan boshlang. Chegaralar aniq bo'lgach, kerakli qismlarni ajratib chiqarasiz.

Bu "modulli monolit" yondashuvi deb ataladi.

Mikroservislar qachon oqlanadi?
  • Jamoa 50+ dasturchidan iborat va bir-biriga xalaqit beryapti
  • Ba'zi qismlar boshqalardan 10-100 barobar ko'proq yuk oladi
  • Turli qismlar uchun turli texnologiya kerak
  • Alohida deploy tsikllari zarur
  • Sizda kuchli DevOps madaniyati bor

Agar bu shartlar bajarilmasa - monolit yaxshiroq.

Modulli monolit #

Natija
manba/
├── Modullar/
│   ├── Katalog/
│   │   ├── Domen/
│   │   ├── Ilova/
│   │   ├── Infratuzilma/
│   │   └── KatalogAPI.php      ← faqat shu orqali murojaat
│   ├── Savat/
│   │   ├── Domen/
│   │   ├── Ilova/
│   │   └── SavatAPI.php
│   └── Buyurtma/
│       ├── Domen/
│       ├── Ilova/
│       └── BuyurtmaAPI.php
└── Umumiy/
PHP
// XATO: modul ichki qismiga to'g'ridan-to'g'ri murojaat
use App\Modullar\Katalog\Domen\Mahsulot;
use App\Modullar\Katalog\Infratuzilma\MysqlMahsulotRepozitoriy;

// TO'G'RI: faqat ochiq API orqali
use App\Modullar\Katalog\KatalogAPI;

class SavatServisi
{
    public function __construct(private KatalogAPI $katalog) {}

    public function qoshing(int $mahsulotId, int $soni): void
    {
        $mahsulot = $this->katalog->mahsulotMalumoti($mahsulotId);
        // ...
    }
}
Modulli monolitning afzalligi

Siz mikroservislarning tashkiliy foydasini olasiz (aniq chegaralar, mustaqil jamoalar), lekin texnik murakkabligini olmaysiz.

Keyinchalik biror modulni alohida xizmatga ajratish kerak bo'lsa - chegaralar allaqachon tayyor.

Boshqa arxitektura uslublari #

Olti burchakli (portlar va adapterlar) #

Olti burchakli arxitektura Domen biznes mantiq tashqi dunyoni bilmaydi Veb kontroller CLI buyruq Test MySQL Email xizmati To'lov API Kiruvchi adapterlar Chiquvchi adapterlar
Domen markazda, tashqi tizimlar almashtiriladigan adapterlar
Asosiy g'oya

Biznes mantiq hech qanday tashqi texnologiyani bilmaydi.

U MySQL yoki PostgreSQL ekanini, HTTP yoki CLI orqali chaqirilishini bilmaydi. Faqat interfeyslar bilan ishlaydi.

Natijada: testlash oson, texnologiya almashtirish arzon.

Hodisalarga asoslangan arxitektura #

PHP
// Buyurtma yaratilganda hodisa e'lon qilinadi
class BuyurtmaServisi
{
    public function yarating(BuyurtmaSorovi $sorov): Buyurtma
    {
        $buyurtma = $this->repozitoriy->saqlang(/* ... */);

        $this->hodisalar->elon(new BuyurtmaYaratildi($buyurtma));

        return $buyurtma;
    }
}

// Turli tinglovchilar mustaqil javob beradi
class EmailYuboruvchi
{
    public function buyurtmaYaratildi(BuyurtmaYaratildi $hodisa): void
    {
        $this->pochta->yuboring(/* ... */);
    }
}

class ZaxiraYangilovchi
{
    public function buyurtmaYaratildi(BuyurtmaYaratildi $hodisa): void
    {
        $this->ombor->kamaytiring(/* ... */);
    }
}

class StatistikaYozuvchi
{
    public function buyurtmaYaratildi(BuyurtmaYaratildi $hodisa): void
    {
        $this->hisoblagich->oshiring('buyurtmalar');
    }
}
Nima yutuq beradi?

Yangi xatti-harakat qo'shish uchun BuyurtmaServisi ni o'zgartirish shart emas - shunchaki yangi tinglovchi qo'shiladi.

Kamchiligi: oqimni kuzatish qiyinlashadi. "Bu email qayerdan yuborildi?" degan savolga javob topish uchun barcha tinglovchilarni ko'rish kerak.

Arxitektura qarorlarini hujjatlashtirish #

MARKDOWN
# ADR-007: Savat ma'lumotini Redis da saqlash

**Sana:** 2026-08-12
**Holat:** Qabul qilindi
**Qaror qabul qiluvchilar:** Husanboy (arxitektor), Jasur (backend)

## Kontekst

Savat ma'lumoti hozir MySQL da saqlanadi. Yuk oshgani sari
`savat_elementlari` jadvaliga yozish sekinlashmoqda.

O'lchovlar:
- Savatga qo'shish: o'rtacha 180 ms
- Cho'qqi paytida: 900 ms gacha
- Savat ma'lumoti 90% hollarda 24 soatdan ko'p yashamaydi

## Ko'rib chiqilgan variantlar

1. **MySQL da qoldirish + indekslar** - qisman yordam beradi, lekin
   yozish yuki qoladi
2. **Redis** - tez, TTL qo'llab-quvvatlaydi
3. **Brauzer localStorage** - qurilmalar orasida sinxronlashmaydi

## Qaror

Savat ma'lumotini **Redis** da saqlaymiz, TTL 30 kun.

Buyurtma berilganda ma'lumot MySQL ga ko'chiriladi.

## Oqibatlari

**Ijobiy:**
- Savat amallari 5-10 ms
- MySQL yuki kamayadi
- TTL avtomatik tozalash

**Salbiy:**
- Yangi infratuzilma komponenti (Redis klasteri)
- Redis o'chsa savatlar yo'qoladi (qabul qilamiz)
- Jamoa Redis ni o'rganishi kerak

## Muqobil yo'l

Redis ishlamasa, MySQL ga qaytish uchun `SavatOmborInterfeysi`
saqlanadi.
ADR nima uchun kerak?

Bir yildan keyin yangi dasturchi so'raydi: "nima uchun savat Redis da? MySQL da bo'lgani yaxshiroq emasmi?"

ADR shu savolga javob beradi va bir xil bahsni qayta boshlashning oldini oladi.

Har bir muhim arxitektura qarori uchun bittadan ADR yozing.

Arxitektura xatolari #

Umumiy xatolar
XatoOqibati
Erta optimizatsiyaKerak bo'lmagan murakkablik
Kech arxitekturaTexnik qarz, qayta yozish
Modaga ergashish"Hamma mikroservis ishlatadi"
Universal yechimHar bir vaziyatga bir xil naqsh
HujjatsizlikBilim faqat bir odamning boshida
Ortiqcha abstraksiya5 qatlam interfeys, bitta amalga oshirish
Katta qayta yozish"Noldan yozamiz" - deyarli har doim muvaffaqiyatsiz
Ortiqcha abstraksiya
PHP
// Bitta amalga oshirish uchun uchta qatlam
interface FoydalanuvchiFabrikasiInterfeysi { }
abstract class AbstraktFoydalanuvchiFabrikasi implements FoydalanuvchiFabrikasiInterfeysi { }
class OddiyFoydalanuvchiFabrikasi extends AbstraktFoydalanuvchiFabrikasi { }

Interfeys hozir kerak bo'lganda yarating, "kelajakda kerak bo'lar" degan taxmin bilan emas.

Ikkinchi amalga oshirish paydo bo'lganda interfeys chiqarish - 5 daqiqalik ish.

Amaliy topshiriq
  1. Yuqoridagi "yuqori bog'liqlik" misolini past bog'liqlikka aylantiring.
  2. O'z loyihangizni qatlamlarga bo'ling va sxemasini chizing.
  3. Qatlam chegarasi buzilgan joyni toping.
  4. Monolit va mikroservis afzalliklarini jadval qilib yozing.
  5. Onlayn do'kon uchun modulli monolit tuzilmasini loyihalang.
  6. Har bir modul uchun ochiq API metodlarini yozing.
  7. Olti burchakli arxitektura uchun uchta interfeys yozing.
  8. Hodisalarga asoslangan yondashuv bilan bitta stsenariy yozing.
  9. Uchta ADR yozing: baza tanlovi, autentifikatsiya, kesh.
  10. Loyihangizdagi ortiqcha abstraksiyani toping va soddalashtiring.

Xulosa #

  • Arxitektura - keyinchalik o'zgartirish qiyin bo'lgan qarorlar.
  • Ikki asosiy mezon: modullar orasida past bog'liqlik, modul ichida yuqori yaxlitlik.
  • Qatlamli arxitektura - eng keng tarqalgan; qatlamlarni chetlab o'tmang.
  • Monolit - deyarli har doim to'g'ri boshlang'ich tanlov.
  • Mikroservislar tashkiliy muammoni hal qiladi, texnik murakkablik qo'shadi.
  • Modulli monolit - ikkalasining o'rtasidagi eng amaliy yechim.
  • Olti burchakli arxitektura domen mantiqini texnologiyadan ajratadi.
  • Hodisalar yangi xatti-harakatni mavjud kodni o'zgartirmasdan qo'shish imkonini beradi.
  • ADR yozing - bir xil bahsni qayta boshlamaslik uchun.
  • Erta optimizatsiya va ortiqcha abstraksiya dan qoching.

Keyingi bo'limda loyihalash naqshlarini o'rganamiz.

Xatolik topdingizmi?

Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.