Tizim dizayni kursi · 2-mavzu · DEEP / SENIOR
TuzdiDinMuhammad

Modular Monolith — Senior chuqurlik

Bu — 2-mavzuning 2-qatlami. Core darslikni o‘qib bo‘lgan deb hisoblanadi. Bu yerda eng chuqur narsalar: modul chegarasini compile-time majburlash, modullararo aloqa, alohida sxema va ACID ustunligi, vertical slice, strangler fig bilan ajratish va qachon modular monolith yutishi — junior’dan seniorgacha.

Daraja: SeniorMavzular: chegara majburlash · ACID · stranglerOld shart: 2-mavzu (Core)

Bu qatlamda nima bor

Core darslik asoslarni berdi. Bu Deep qatlam senior darajadagi chuqur mexanikani ochadi: modul chegarasini bounded context bo‘yicha chizish va uni compile-time (public API + lint/arch test) majburlash, modullararo aloqa (interfeys vs ichki event), alohida sxema va bitta ACID tranzaksiya ustunligi, vertical slice tuzilma, strangler fig bilan mikroservisga ajratish, hamda qachon modular monolith to‘g‘ri tanlov ekani. Oxirida — yig‘ma reference va senior cheklist.

01
Deep · Boundary

Modul chegarasi

bounded context · koheziya
📦

Core’da "chegarani majburla" dedik. Senior savoli — chegara qayerdan o‘tadi? Noto‘g‘ri modul chegarasi monolitni "big ball of mud"ga aylantiradi.

Modul = bounded context

Modul chegarasi tasodifan emas — u biznes subdomeni / bounded context (15-mavzu) bo‘yicha o‘tadi: Buyurtma, To‘lov, Inventar. Bu — mikroservis chegarasi bilan bir xil (6-bo‘limda ko‘ramiz: shuning uchun ko‘chirish oson).

Bitta jarayon (monolit) Buyurtma To‘lov Inventar Yetkazish
Bitta deploy birligi ichida — aniq modul chegaralari
Ikki mezon

Yuqori koh'eziya: birga o‘zgaradigan kod bitta modulda. Past bog‘lanish: modullar orasidagi bog‘liqlik minimal va faqat ochiq interfeys orqali. Va bog‘liqlik siklsiz (A→B→A bo‘lmasin) — aks holda ular aslida bitta modul.

02
Deep · Enforce

Chegarani compile-time majburlash

public API · lint/arch test
🚧

Modul chegarasi hujjatda emas, kompilyatorda majburlanishi kerak — aks holda vaqt o‘tib buziladi ("shunchaki bu importni qo‘shaman").

Public API — barrel export

Har modul faqat o‘z shartnomasini ochadi (bitta index.ts), ichki fayllarini yashiradi. Boshqa modul faqat shu ochiq yuzaga murojaat qiladi:

// Har modul FAQAT o'z public shartnomasini ochadi (barrel: index.ts)
// payments/index.ts  <-- yagona kirish nuqtasi
export { PaymentApi } from "./payment.api";      // ochiq interfeys
export type { PaymentResult } from "./contracts"; // ochiq DTO
// payment.service.ts, payment.entity.ts -> EKSPORT QILINMAYDI (ichki)

Architectural fitness function — buzilishni avtomatik ushlash

Chegarani lint qoidasi/arxitektura testi bilan majburla — kimdir boshqa modulning ichki qismiga kirsa, CI buzadi:

// ESLint bilan modul chegarasini MAJBURLASH (eslint-plugin-boundaries)
// .eslintrc — modul ICHKI qismiga to'g'ridan-to'g'ri kirish TAQIQLANADI
"rules": {
  "boundaries/element-types": ["error", {
    "default": "disallow",
    "rules": [
      { "from": "orders", "allow": ["orders", "shared", "payments-api"] }
      //  Buyurtma faqat To'lovning PUBLIC API'siga kira oladi,
      //  uning ichki fayllariga (payments/internal/*) EMAS
    ]
  }]
}
Nega bu hal qiluvchi

Modular monolith modul chegarasi bilan tirik yoki o‘lik bo‘ladi. Chegara faqat "kelishuv" bo‘lsa — deadline bosimida buziladi va monolit "loyga" aylanadi. Compile-time majburlash (lint/test) uni haqiqiy tutadi. Bu — modular monolithni oddiy monolitdan ajratadigan yagona narsa.

03
Deep · Comms

Modullararo aloqa

interfeys vs ichki event
🔗

Modullar bitta jarayonda, lekin ular qanday gaplashadi? Ikki usul bor — va tanlov kelajakdagi mikroservisga ko‘chirish osonligini belgilaydi.

// 1) TO'G'RIDAN-TO'G'RI — public interfeys orqali (sinxron, oddiy)
class OrderService {
  constructor(private payments: PaymentApi) {}   // faqat PUBLIC API'ga bog'liq
  async confirm(id: string) {
    await this.payments.charge(id);               // to'g'ridan-to'g'ri chaqiruv (bir jarayon)
  }
}

// 2) ICHKI EVENT — bo'shashtirish uchun (async, in-process event bus)
this.eventBus.publish(new OrderConfirmed(order.id));   // Buyurtma e'lon qiladi
@OnEvent("order.confirmed")                            // Yetkazish tinglaydi
handle(e: OrderConfirmed) { this.scheduleDelivery(e.orderId); }
// modullar bir-birini BILMAYDI -> keyin mikroservisga ko'chirish oson
To‘g‘ridan-to‘g‘ri chaqiruvIchki event
Bog‘lanishZichroq (interfeysga)Bo‘sh (bir-birini bilmaydi)
UslubSinxron, soddaAsinxron, moslashuvchan
QachonJavob darhol kerak"Sodir bo‘ldi" xabari, yon ta’sir
Ko‘chirishREST/gRPC ga aylanadiMessage broker’ga aylanadi (deyarli tekin)
Muhim taqiq — umumiy entity

Modullar bir-birining entity/jadvalini to‘g‘ridan-to‘g‘ri ishlatmasligi kerak — faqat DTO/shartnoma orqali. Buyurtma moduli To‘lov modulining Payment entity’sini import qilsa — chegara buzildi, ko‘chirish imkonsiz bo‘ladi.

04
Deep · Data

Ma‘lumot va tranzaksiya

alohida sxema · ACID
🗃️

Modular monolithning eng katta yutug‘i — ma’lumot. Bitta DB’da, lekin toza chegaralar bilan — mikroservisning ko‘p og‘rig‘isiz.

Bitta DB, alohida sxema

  • Har modul o‘z jadvallariga egalik qiladi — boshqa modul ularga to‘g‘ridan-to‘g‘ri tegmaydi (sxema/nom-fazo bilan ajrat).
  • Modullar aro FK yo‘q (yoki faqat mantiqiy) — jadval bog‘liqligi chegarani buzadi va kelajakda ajratishni imkonsiz qiladi.
  • Cross-module JOIN qilma — boshqa modul ma’lumoti kerak bo‘lsa, uning public APIsidan so‘ra.
Katta yutuq — bitta ACID tranzaksiya

Mikroservisda bir amal ko‘p servisga tegsa — Saga, kompensatsiya, eventual consistency (13-mavzu — murakkab). Modular monolithda hammasi bitta jarayon, bitta DB: oddiy BEGIN…COMMIT hammasini atomik qiladi. Bu — ulkan soddalik, va aynan shuning uchun ko‘p loyiha uchun modular monolith to‘g‘ri tanlov.

Kelajakka tayyorlik

Agar modul kelajakda ajratilsa — uning jadvallari allaqachon alohida sxemada, FK’siz, o‘z API’si ortida. Ya’ni ajratish mexanik, arxitekturani qayta yozish emas.

05
Deep · Structure

Vertical slice tuzilma

mini clean-arch
🍰

Kodni texnik qatlam bo‘yicha (controllers/, services/) emas, modul (vertical slice) bo‘yicha tashkil qil — bu screaming architecture (15-mavzu) modular monolithda.

Har modul — o‘z ichida to‘liq (domain + application + infrastructure), va o‘z index.ts public API’si bilan. Bu tuzilma modul mustaqilligini ko‘rsatadi va ajratishni osonlashtiradi:

src/
  modules/
    orders/               # <-- MODUL = vertical slice (o'z mini clean-arch, 15-mavzu)
      domain/       # Order entity, qoidalar
      application/  # use case'lar
      infrastructure/ # repo, controller
      index.ts      # <-- PUBLIC API (barrel) — faqat shu ochiq
    payments/
      domain/ application/ infrastructure/ index.ts
    inventory/
      ...
  shared/                 # umumiy kernel (juda kam, ehtiyotkorlik bilan)
Har modul — mini Clean Architecture

15-mavzu (Clean Architecture) modul ichida yashaydi: har modulning o‘z domeni (sof qoidalar), use case’lari va infratuzilma adapter’lari bor. Modular monolith — bu tashqi tuzilma; Clean Architecture — ichki tuzilma. Ikkalasi birga: modullar aro toza chegara + modul ichida toza qatlamlar.

06
Deep · Evolve

Strangler fig bilan ajratish

strangler · ACL
🌳

Modular monolithning kuchi — u sizni qamamaydi. Ehtiyoj tug‘ilsa, modulni strangler fig naqshi bilan mikroservisga ajratasan.

Strangler fig — bosqichma-bosqich ajratish

Butun tizimni qayta yozish o‘rniga — bitta modulni o‘z chegarasi bo‘yicha ajratib, uning trafigini asta yangi servisga yo‘naltirasan. Modul chegarasi aniq bo‘lgani uchun (2, 4-bo‘limlar) — bu mexanik jarayon:

Buyurtma To‘lov Inventar ajrat To‘lov servisi (alohida)
Strangler fig: modul chegarasi bo‘yicha bittalab ajratish
Anti-corruption layer

Ajratishda anti-corruption layer (ACL) qo‘y: yangi servis va qolgan monolit orasida tarjimon qatlam — biri ikkinchisining modelini "ifloslantirmasin". Public API allaqachon shartnoma bo‘lgani uchun, ACL tabiiy o‘rnashadi.

07
Deep · When

Qachon modular monolith yutadi

trade-off
⚖️

Senior haqiqat: aksariyat loyihaga mikroservis kerak emas. Modular monolith — ko‘pincha eng oqilona tanlov, ayniqsa boshlanishda.

Modular monolith yutadi
  • Bitta deploy, sodda operatsiya — bitta artefakt, mesh/discovery yo‘q
  • Bitta ACID tranzaksiya — Saga murakkabligi yo‘q (4-bo‘lim)
  • Oson debug/test — bitta jarayon, tarmoq yo‘q
  • Arzon refactoring — chegaralarni bir repoda qayta chizish oson
  • Optionality — keyin kerak bo‘lsa, ajratasan (strangler)
Cheklovlari
  • Yagona deploy birligi — kichik o‘zgarish uchun ham butunni deploy
  • All-or-nothing masshtab — bitta modul emas, butunini masshtablaysan
  • Yagona texnologiya — hamma modul bir stack
  • Jamoa masshtabi — juda katta jamoada deploy to‘qnashuvi
To‘g‘ri yo‘l

Modular monolithdan boshla (toza chegaralar bilan). Faqat haqiqiy og‘riq paydo bo‘lganda (bitta modul mustaqil masshtab talab qilsa, jamoa deploy uchun to‘qnashsa) — o‘sha bitta modulni ajrat. "Mikroservis birinchi"dan qoch — u ko‘p loyihani keraksiz murakkablikka cho‘ktiradi. Chegaralar toza bo‘lsa, kechikish bepul.

08
Deep · Reference

Yig‘ma reference va senior cheklist

Modular monolith — yig‘ma reference

QismAmaliyotBo‘lim
Modul chegarasiBounded context bo‘yicha, koh'eziya/bog‘lanish1
Chegara majburlashPublic API (barrel) + lint/arch test2
Modullararo aloqaPublic interfeys yoki ichki event (umumiy entity yo‘q)3
Ma‘lumotAlohida sxema, FK/JOIN yo‘q, bitta ACID tranzaksiya4
TuzilmaVertical slice, har modul mini clean-arch5
EvolyutsiyaStrangler fig + ACL bilan ajratish6

Senior tayyorlik cheklisti

Savol / amaliyotBo‘lim
Modul chegaralarini bounded context bo‘yicha chizaman (koh'eziya/past bog‘lanish, siklsiz)1
Chegarani public API + lint/arch test bilan compile-time majburlayman2
Modullar aro faqat interfeys/event bilan gaplashaman; umumiy entity ishlatmayman3
Har modulga alohida sxema; modullar aro FK/JOIN yo‘q; ACID tranzaksiya ustunligini ishlataman4
Kodni vertical slice bo‘yicha, har modul mini clean-arch qilib tashkil qilaman5
Kerak bo‘lganda modulni strangler fig + ACL bilan ajrataman6
Mikroservisga o‘tish ehtiyojini to‘g‘ri baholayman (default — modular monolith)7

Bu 2-mavzuning Deep/Senior qatlami edi — Core bilan birga, Modular Monolith endi to‘liq.

Bog‘liq mavzular: 1-mavzu (Microservices — keyingi qadam), 3 (Event-Driven — ichki event), 13 (Distributed Transactions — nega monolit soddaroq), 15 (Clean Architecture — modul ichi).