Bu darsda nima bor
1–4-qismlar Clean Architecture’ni noldan quradi: nega kerak, bog‘liqlik qoidasi, qatlamlar va NestJS Ports & Adapters implementatsiya. 5–6-qismlar — Dependency Inversion (butun arxitekturaning yuragi) va foydalar/tanqid (pragmatik qo‘llash). 7-qism qachon kerakligini va bu kursda o‘rgangan hamma narsaning shu tuzilma ichida birlashishini ko‘rsatadi. Bu — 15 mavzuli tizim dizayni kursining yakuni.
Nega kerak — chirmashgan kod
Oddiy o‘xshatish: yaxshi bino loyihasida tashuvchi devorlar (biznes mohiyati) o‘zgarmaydi, lekin oboy, mebel, santexnika (framework, DB) istalgan vaqt almashtiriladi. Yomon loyihada esa oboy devorni ushlab turadi — birini o‘zgartirsang, hammasi qulaydi.
Odatiy kodda biznes mantig‘i framework va bazaga chirmashib ketadi: buyurtma qoidalari NestJS controller ichida, to‘g‘ridan-to‘g‘ri Prisma’ga bog‘langan.
1. "Buyurtmani bekor qilish mumkinmi?" degan biznes qoidasini test qilish uchun — ishlayotgan DB va HTTP kerak (sekin, mo‘rt).
2. Bazani almashtirmoqchisan (Prisma → boshqa) — biznes kodni ham qayta yozasan.
3. Framework yangilansa — hamma joyda buziladi.
4. Biznes qoidalari controller, servis, DB’ga tarqalgan — qayerdaligini topib bo‘lmaydi.
Kodni shunday tashkil qil: biznes mantig‘i markazda, mustaqil; framework, DB, UI — tashqarida, almashtiriladigan detallar. Asosiy qoida: bog‘liqliklar ichkariga, biznesga qaraydi — biznes DB’ga bog‘liq emas, aksincha DB biznesga (interfeys orqali) bog‘lanadi.
Asosiy g‘oya — bog‘liqlik ichkariga
Clean Architecture (Robert C. Martin) — konsentrik doiralar. Yagona qoida: manba kodi bog‘liqliklari ichkariga qaraydi (The Dependency Rule).
Ichki qatlamlar tashqi qatlamlar haqida hech narsa bilmaydi. Domain — Prisma, NestJS, HTTP mavjudligini ham bilmaydi. Tashqi qatlamlar (DB, web) esa ichki qatlamga bog‘lanadi. Bu — arxitekturaning butun mohiyati.
Bir xil g‘oya turli nomlar bilan: Clean Architecture (Uncle Bob), Hexagonal / Ports & Adapters (Cockburn), Onion Architecture (Palermo). Hammasi bir tamoyilga tayanadi: biznes markazda, detallar tashqarida.
Qatlamlar — har biri nima
Har qatlam aniq javobgarlikka ega:
| Qatlam | Nima | Bilmasligi kerak |
|---|---|---|
| Domain (Entities) | Sof biznes qoidalari va obyektlar — yurak | Framework, DB, HTTP — hech narsa |
| Use Cases (Application) | Ilova mantig‘i; entity’larni muvofiqlashtiradi; kerakli interfeys (port)larni belgilaydi | Prisma, Express, konkret DB |
| Interface Adapters | Controller (HTTP→use case), repository implementatsiyasi, presenter | — |
| Infrastructure | DB (Prisma), web (NestJS), tashqi API — almashtiriladigan detallar | — |
Domain — "buyurtma qanday ishlaydi" (sof qoidalar). Use case — "buyurtmani bekor qilish jarayoni" (mantiq oqimi). Adapter — "HTTP so‘rovni use case’ga aylantirish" yoki "domenni Prisma’ga saqlash". Infrastructure — Prisma, NestJS o‘zi. Ichkariga qarab: qoidalar → jarayon → tarjima → detal.
NestJS — Ports & Adapters
port · adapter · DIBuni amalga oshiruvchi mexanizm — Ports & Adapters: use case interfeysga (port) bog‘lanadi, infratuzilma esa uni amalga oshiradi (adapter). NestJS DI ularni ulaydi.
1 · Domain — sof qoidalar
// DOMAIN — sof biznes qoidalari, framework/DB YO'Q
export class Order {
constructor(
public readonly id: string,
public status: "draft" | "confirmed" | "cancelled",
private items: OrderItem[],
) {}
cancel() { // biznes qoidasi shu yerda -> DB'siz, HTTP'siz test qilinadi
if (this.status === "confirmed") throw new Error("Tasdiqlangan buyurtma bekor bo'lmaydi");
this.status = "cancelled";
}
}
2 · Port + Use Case — interfeysga bog‘liq
// PORT — use case KERAK bo'lgan interfeys (biznes tomonda aniqlanadi)
export abstract class OrderRepository {
abstract findById(id: string): Promise<Order | null>;
abstract save(order: Order): Promise<void>;
}
// USE CASE — PORT'ga bog'liq, Prisma'ni BILMAYDI
@Injectable()
export class CancelOrderUseCase {
constructor(private readonly orders: OrderRepository) {} // interfeys, konkret emas!
async execute(orderId: string) {
const order = await this.orders.findById(orderId);
if (!order) throw new NotFoundException();
order.cancel(); // domen qoidasi
await this.orders.save(order);
}
}
3 · Adapter + DI — infratuzilma portni amalga oshiradi
// ADAPTER — infratuzilma; PORT'ni Prisma bilan amalga oshiradi (tashqi qatlam)
@Injectable()
export class PrismaOrderRepository extends OrderRepository {
constructor(private prisma: PrismaService) { super(); }
async findById(id: string): Promise<Order | null> {
const row = await this.prisma.order.findUnique({ where: { id } });
return row ? new Order(row.id, row.status as any, row.items) : null; // DB -> domen
}
async save(order: Order): Promise<void> {
await this.prisma.order.update({ where: { id: order.id }, data: { status: order.status } });
}
}
// NestJS DI — interfeysga konkret implementatsiyani bog'laymiz
@Module({
providers: [
CancelOrderUseCase,
{ provide: OrderRepository, useClass: PrismaOrderRepository }, // port -> adapter
],
})
export class OrdersModule {}
CancelOrderUseCase Prisma’ni umuman bilmaydi — u faqat OrderRepository interfeysini biladi. Prisma’ni InMemoryOrderRepository bilan almashtirsang — use case va domen o‘zgarmaydi. Test uchun ham xuddi shunday: DB’siz, mock repository bilan biznes qoidasini sinaysan.
Dependency Inversion (yuragi)
DIP · abstraksiyaButun arxitektura bitta prinsipga tayanadi — Dependency Inversion Principle (DIP), SOLID’dagi "D". Buni tushunsang — hammasini tushunasan.
Tabiiy bog‘liqlikni "ag‘darish"
Tabiiy holatda biznes mantig‘i DB’ga bog‘lanadi (biznes → Prisma). DIP buni ag‘daradi: ikkalasi ham biznes belgilagan interfeysga bog‘lanadi. Endi DB biznesga bog‘liq, aksincha emas:
Yuqori daraja (biznes) va past daraja (DB) endi bir-biriga emas, abstraksiyaga (interfeys) bog‘lanadi. Va o‘sha interfeysni biznes belgilaydi (o‘ziga nima kerakligini). Shu tufayli detallar (DB, framework) chinakam almashtiriladigan bo‘ladi.
DIP: "abstraksiyaga bog‘lan, konkretga emas." Va abstraksiyani ehtiyoj egasi (biznes) belgilaydi, uni ta’minlovchi (DB) emas. Butun Clean Architecture — shu prinsipning tizimli qo‘llanilishi.
Foydalari va tanqid
pragmatik qo‘llashClean Architecture kuchli, lekin bepul emas. Senior uning foydasini ham, narxini ham ko‘radi va mutanosib qo‘llaydi.
Foydalari
- Testlanadigan — biznes qoidasini DB/HTTP’siz, mock port bilan sinaysan
- Almashtiriladigan infratuzilma — DB, framework, tashqi API — detal
- Biznes mantig‘i markazda, aniq — tarqoq emas
- Framework’dan mustaqil — yangilanish/almashtirish yadroga tegmaydi
Narxi / tanqid
- Boilerplate — ko‘proq fayl, interfeys, mapping
- Bilvositalik — kod o‘qishda "sakrash" ortadi
- Oddiy CRUD uchun ortiqcha — over-engineering xavfi
- Qatlamlar aro mapping — DB modeli ↔ domen modeli
Clean Architecture — dogma emas, vosita. Murakkab, uzoq yashaydigan domenda (boy biznes qoidalari) — bebaho. Oddiy CRUD yoki prototipda — ortiqcha yuk. Uni "hammasi yoki hech narsa" deb qo‘llama: hatto to‘liq qatlamsiz ham, asosiy qoidani (bog‘liqlik ichkariga, biznes DB’ni bilmaydi) saqlash ko‘p foyda beradi.
Qachon va kursning birlashishi
Bu — kursning yakuniy birlashishi. Clean Architecture butun o‘rganganingni tashkil qiladigan idish.
1. Mutanosib qo‘lla: murakkab domen → to‘liq qatlamlar; oddiy ilova → yengil (lekin bog‘liqlik qoidasini saqla).
2. Domenni sof tut: biznes qoidalari framework/DB’ga hech qachon bog‘lanmasin — bu eng muhim intizom.
3. Port & Adapter bilan infratuzilmani almashtiriladigan qil (DI orqali).
4. Har qatlamni alohida testla: domen — sof unit test; use case — mock port; adapter — integratsiya test.
Bu kursda o‘rgangan hamma narsa Clean Architecture ichida yaxshiroq yashaydi: Mikroservis (1) — har servis o‘z toza arxitekturasi bilan; Repository port’lari — sharding/replikatsiya (6,7) adapter’lar ortida yashirin; CQRS/Event Sourcing (9,10) — use case va domenda; Saga (13) — application qatlamda; Gateway, LB, Cache, Resilience (5,8,4,14) — infratuzilma adapter’lari. Domen sof qoladi, murakkablik chetda. Aynan shu tufayli tizim o‘sib, o‘zgarib, lekin buzilmasdan yashaydi.
Eslab qolish + kurs yakuni
- Clean Architecture = kodni biznes markazda, framework/DB tashqarida tashkil qilish. Yagona qoida: bog‘liqliklar ichkariga (biznesga) qaraydi.
- Qatlamlar: Domain (sof qoidalar) → Use Cases (jarayon) → Adapters (tarjima) → Infrastructure (DB, web — detal). Ichki qatlam tashqarini bilmaydi.
- Mexanizm — Ports & Adapters: use case interfeysga (port) bog‘lanadi; infratuzilma uni amalga oshiradi (adapter). NestJS DI ulaydi.
- Yuragi — DIP: abstraksiyaga bog‘lan, konkretga emas; interfeysni biznes belgilaydi → DB detalga aylanadi.
- Foyda: testlanadigan, almashtiriladigan, aniq. Narxi: boilerplate, bilvositalik. Mutanosib qo‘lla — CRUD uchun ortiqcha, murakkab domenda bebaho.
🎓 Tabriklaymiz — kurs tugadi! 15 ta mavzu (Microservices’dan Clean Architecture’gacha), har biri Core + Deep/Senior qatlam bilan — tizim dizaynining to‘liq yo‘li. Endi sizda mikroservis, ma’lumot masshtabi, izchillik, kuzatuvchanlik, chidamlilik va toza kod bo‘yicha junior’dan senior gacha mustahkam poydevor bor.
Bu mavzuning Deep/Senior qatlami (SOLID chuqur, DDD taktik naqshlar — aggregate/bounded context/domain events, anemic vs rich model, mapping strategiyalari, screaming architecture, use case chegaralari, qatlamlar bo‘yicha test strategiyasi, qachon qoidalarni buzish) kerak bo‘lsa — ayting. Aks holda — omad, va qurgan tizimlaringiz uzoq va buzilmasdan yashasin! 🚀