DevOps, Deployment va Dasturiy Arxitektura — Texnik Intervyu
Full-stack dasturchi uchun chuqur savol-javob to'plami. Ushbu hujjat DevOps amaliyoti (Docker, Kubernetes, CI/CD, Nginx, Linux, cloud, monitoring, secrets, HTTPS, git) va dasturiy arxitektura (SOLID, design patterns, monolith vs microservices, layered/hexagonal, message queue, caching, 12-factor) bo'yicha real intervyularda uchraydigan savollarni qamrab oladi.
Kirish
DevOps va arxitektura savollari — bu junior darajasidan senior darajasigacha nomzodni ajratib turadigan asosiy mezon. Kod yozishni ko'pchilik biladi, ammo kodni ishlab chiqarishga (production) qanday yetkazish, uni kengaytirish (scale), kuzatish (observability) va barqaror arxitektura qurish — bu alohida mahorat.
Har bir savol quyidagi tuzilishga ega:
- Daraja belgisi: Junior, Middle, Senior
- Ta'rif — atamaning aniq ma'nosi
- Mexanizm — ichki ishlash prinsipi (chuqur)
- Kod/config misol — amaliy ko'rsatma
- Keng tarqalgan xato — nomzodlar tez-tez qiladigan xatolar
- Follow-up — intervyu davomida beriladigan qo'shimcha savol
Atamalar (Docker, container, pod, SOLID) ingliz tilida saqlanadi, chunki ular kasbiy standart hisoblanadi.
1-BO'LIM: Docker va konteynerlashtirish
S1: [] Image va container o'rtasidagi farq nima? (Junior)
Ta'rif: Docker image — bu dasturni ishga tushirish uchun kerak bo'lgan hamma narsani (kod, runtime, kutubxonalar, muhit o'zgaruvchilari) o'z ichiga olgan o'zgarmas (immutable) shablon. Container — bu image'ning ishga tushirilgan, jonli namunasi (instance).
Mexanizm (chuqur): Image — bu faqat o'qish uchun (read-only) qatlamlar (layers) to'plami. Container ishga tushganda, Docker image ustiga yozish mumkin bo'lgan (writable) yupqa qatlam qo'shadi — buni copy-on-write deb ataladi. Ya'ni bir xil image'dan yuzlab container yaratsangiz ham, ular faqat o'zgargan fayllar uchun joy egallaydi, umumiy qatlamlar disk'da bir marta saqlanadi. Bu class va object munosabatiga o'xshaydi: image — bu class, container — bu object.
# Image yaratish
docker build -t myapp:1.0 .
# Image'dan container ishga tushirish (bitta image, uchta container)
docker run -d --name web1 myapp:1.0
docker run -d --name web2 myapp:1.0
docker run -d --name web3 myapp:1.0
# Mavjud image'larni ko'rish
docker images
# Ishlayotgan container'larni ko'rish
docker psKeng tarqalgan xato: Container ichida muhim ma'lumot saqlash. Container o'chirilganda writable qatlam ham yo'qoladi. Doimiy ma'lumot uchun volume ishlatish kerak. Yana bir xato: har bir kod o'zgarishida yangi image build qilish o'rniga, ishlayotgan container ichida fayllarni tahrirlash — bu o'zgarishlar yo'qoladi.
Follow-up: Bir container'ni o'chirsangiz, undan yaratilgan image ham o'chadimi? (Javob: yo'q, image mustaqil qoladi.)
S2: [] Docker image qatlamlari (layers) qanday ishlaydi va nima uchun tartib muhim? (Middle)
Ta'rif: Har bir Dockerfile ko'rsatmasi (instruction) yangi qatlam (layer) yaratadi. Qatlamlar bir-birining ustiga qo'yiladi va layer cache orqali qayta build tezlashtiriladi.
Mexanizm (chuqur): Docker har bir qatlamni uning tarkibiga qarab hash qiladi. Qayta build qilganingizda, agar qatlam va undan yuqoridagi barcha qatlamlar o'zgarmagan bo'lsa, Docker cache'dan foydalanadi. Ammo bitta qatlam o'zgarsa, undan keyingi barcha qatlamlar qaytadan quriladi (cache bekor bo'ladi). Shu sababli kam o'zgaradigan narsalarni (dependencies) yuqoriga, tez-tez o'zgaradigan narsalarni (source code) pastga joylashtirish kerak.
FROM node:20-alpine
WORKDIR /app
# 1-qadam: faqat package fayllarini ko'chirish (kam o'zgaradi)
COPY package.json package-lock.json ./
# 2-qadam: dependencies o'rnatish — bu qatlam cache'da qoladi
RUN npm ci
# 3-qadam: kodni ko'chirish (tez-tez o'zgaradi)
COPY . .
CMD ["node", "server.js"]Agar COPY . . ni RUN npm ci dan oldin qo'ysangiz, har bir kod o'zgarishida npm ci qaytadan ishlaydi — bu build vaqtini bir necha barobar oshiradi.
Keng tarqalgan xato: COPY . . ni yuqoriga qo'yish va keyin RUN npm install yozish. Natijada har bir kichik kod o'zgarishida barcha dependencies qaytadan o'rnatiladi. Yana: har bir RUN uchun alohida qator yozish o'rniga && bilan birlashtirmaslik — bu ortiqcha qatlamlar hosil qiladi.
Follow-up: .dockerignore fayli nima uchun kerak? (Javob: node_modules, .git kabi papkalarni build kontekstiga kiritmaslik uchun — bu build'ni tezlashtiradi va image hajmini kamaytiradi.)
S3: [] Multi-stage build nima va qanday foyda beradi? (Middle)
Ta'rif: Multi-stage build — bitta Dockerfile ichida bir necha FROM bosqichidan foydalanish. Bu build uchun kerakli vositalarni (compiler, dev dependencies) yakuniy image'ga kiritmaslik imkonini beradi.
Mexanizm (chuqur): Birinchi bosqich (builder stage) to'liq muhitda kodni kompilatsiya qiladi yoki build qiladi. Ikkinchi bosqich esa faqat yakuniy natijani (masalan, compiled binary yoki dist papkasi) birinchi bosqichdan COPY --from orqali oladi. Natijada yakuniy image faqat ishga tushirish uchun zarur narsalarni saqlaydi — hajmi keskin kichrayadi (ba'zan 1GB dan 50MB gacha).
# 1-bosqich: build muhiti (og'ir)
FROM node:20 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# 2-bosqich: production muhiti (yengil)
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]Bu yerda node:20 (1GB) faqat build uchun ishlatiladi, yakuniy image esa 40MB) asosida quriladi va faqat statik fayllarni saqlaydi.nginx:alpine (
Keng tarqalgan xato: Dev dependencies va build vositalarini production image'da qoldirish. Bu image hajmini oshiradi va xavfsizlik yuzasini (attack surface) kengaytiradi. Yana: --from=builder da noto'g'ri yo'l ko'rsatish.
Follow-up: Nima uchun kichik image xavfsizlik nuqtayi nazaridan yaxshiroq? (Javob: kamroq paket = kamroq zaiflik (vulnerability), kamroq attack surface.)
S4: [] Docker volume va bind mount o'rtasidagi farq nima? (Middle)
Ta'rif: Volume — Docker tomonidan boshqariladigan doimiy saqlash mexanizmi. Bind mount — host mashinaning aniq papkasini container ichiga ulash.
Mexanizm (chuqur): Volume Docker tomonidan /var/lib/docker/volumes/ da saqlanadi va container hayotiy siklidan mustaqil. Volume'ni Docker to'liq boshqaradi: yaratish, backup, ko'chirish. Bind mount esa hostdagi aniq yo'lni to'g'ridan-to'g'ri container'ga bog'laydi — development'da kod o'zgarishlarini real vaqtda ko'rish uchun qulay, ammo host tuzilishiga bog'liq bo'lgani uchun production'da tavsiya etilmaydi.
# Volume yaratish va ishlatish (production uchun)
docker volume create db_data
docker run -d -v db_data:/var/lib/postgresql/data postgres:16
# Bind mount (development uchun — kod real vaqtda yangilanadi)
docker run -d -v $(pwd)/src:/app/src myapp:dev# docker-compose.yml da
services:
db:
image: postgres:16
volumes:
- db_data:/var/lib/postgresql/data # named volume
volumes:
db_data:Keng tarqalgan xato: Ma'lumotlar bazasini volume'siz ishga tushirish. Container qayta yaratilganda barcha ma'lumot yo'qoladi. Yana: bind mount'ni production'da ishlatib, host bilan kutilmagan bog'liqlik yaratish.
Follow-up: tmpfs mount qachon kerak bo'ladi? (Javob: faqat xotirada (RAM) saqlanadigan, disk'ga yozilmasligi kerak bo'lgan maxfiy vaqtinchalik ma'lumot uchun.)
S5: [] Docker network turlari qanday va bridge network qanday ishlaydi? (Middle)
Ta'rif: Docker network — container'lar o'rtasida va tashqi dunyo bilan aloqani ta'minlaydigan mexanizm. Asosiy turlari: bridge, host, none, overlay.
Mexanizm (chuqur): Default bridge network container'larga ichki IP beradi va ular NAT orqali tashqariga chiqadi. User-defined bridge yaratsangiz, container'lar bir-birini nom orqali (DNS) topa oladi — bu microservices uchun muhim. Host network container'ni to'g'ridan-to'g'ri host tarmog'iga ulaydi (izolyatsiya yo'q, ammo tez). Overlay — bir necha host'dagi container'larni bir tarmoqqa bog'laydi (Docker Swarm/Kubernetes).
# User-defined bridge yaratish
docker network create app_net
# Container'larni shu tarmoqqa ulash
docker run -d --name db --network app_net postgres:16
docker run -d --name api --network app_net myapi:1.0
# Endi "api" container "db" nomi orqali ulanadi:
# postgresql://db:5432/mydb (IP kerak emas!)# docker-compose avtomatik ravishda umumiy network yaratadi
services:
api:
build: .
depends_on:
- db
db:
image: postgres:16
# "api" ichida "db" host nomi avtomatik ishlaydi Keng tarqalgan xato: Default bridge'da container'larni IP orqali bog'lashga urinish (IP har safar o'zgarishi mumkin). To'g'ri yechim — user-defined network va DNS nomlari. Yana: localhost orqali boshqa container'ga ulanishga urinish — container ichida localhost o'sha container'ning o'zini bildiradi.
Follow-up: Ikki container bir-biriga ulana olmayapti — qanday debug qilasiz? (Javob: bir tarmoqda ekanini tekshirish docker network inspect, nom to'g'riligini, portni tekshirish, docker exec orqali ping/curl.)
S6: [] Docker Compose nima uchun kerak? (Junior)
Ta'rif: Docker Compose — bir necha container'dan iborat ilovani bitta YAML fayl orqali e'lon qilib (declarative), bitta buyruq bilan boshqarish vositasi.
Mexanizm (chuqur): docker-compose.yml da har bir service (container), ularning tarmog'i, volume'lari va o'zaro bog'liqligi (depends_on) tavsiflanadi. docker compose up buyrug'i barcha service'larni to'g'ri tartibda ishga tushiradi, umumiy network yaratadi va ularni bir-biriga bog'laydi. Bu, ayniqsa, local development va integration test uchun qulay.
version: "3.9"
services:
api:
build: .
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgresql://db:5432/mydb
depends_on:
db:
condition: service_healthy
db:
image: postgres:16
environment:
- POSTGRES_PASSWORD=secret
volumes:
- db_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
retries: 5
volumes:
db_data: Keng tarqalgan xato: depends_on faqat container ishga tushish tartibini kafolatlaydi, lekin service tayyor ekanini kafolatlamaydi. Ma'lumotlar bazasi to'liq yuklanmasdan API ulanmoqchi bo'lib xato beradi. Yechim — healthcheck va condition: service_healthy.
Follow-up: Production'da Docker Compose ishlatish mumkinmi? (Javob: kichik loyihalar uchun mumkin, ammo katta miqyos, avto-scaling va self-healing uchun Kubernetes yaxshiroq.)
2-BO'LIM: Kubernetes
S7: [] Kubernetes'da Pod nima va nima uchun container'ni to'g'ridan-to'g'ri ishlatmaymiz? (Middle)
Ta'rif: Pod — Kubernetes'dagi eng kichik joylashtirish (deployment) birligi. Pod bir yoki bir necha container'ni o'z ichiga oladi, ular umumiy tarmoq (IP) va saqlashni bo'lishadi.
Mexanizm (chuqur): Kubernetes container bilan bevosita ishlamaydi — u Pod bilan ishlaydi. Bitta Pod ichidagi container'lar localhost orqali bir-biriga ulanadi va umumiy volume'larni bo'lishadi. Odatda bitta Pod'da bitta asosiy container bo'ladi, ammo sidecar pattern da yordamchi container'lar qo'shiladi (masalan, log yig'uvchi yoki proxy). Pod o'zi vaqtinchalik (ephemeral) — o'chsa, yangi IP bilan qayta yaratiladi.
apiVersion: v1
kind: Pod
metadata:
name: web-pod
labels:
app: web
spec:
containers:
- name: app
image: myapp:1.0
ports:
- containerPort: 3000
- name: log-agent # sidecar container
image: fluentbit:latestKeng tarqalgan xato: Pod'ni to'g'ridan-to'g'ri yaratish. Pod o'chsa qayta tiklanmaydi. Deployment orqali yaratish kerak — u Pod'ni avtomatik boshqaradi va self-healing ta'minlaydi.
Follow-up: Bitta Pod'ga nechta container qo'yish kerak? (Javob: odatda bitta asosiy; qo'shimchalar faqat asosiy bilan qattiq bog'liq yordamchi jarayonlar bo'lishi kerak.)
S8: [] Deployment, ReplicaSet va Pod munosabati qanday? (Middle)
Ta'rif: Deployment — Pod'larning desired state (kerakli holat) ini boshqaradigan yuqori darajali obyekt. U ReplicaSet yaratadi, ReplicaSet esa kerakli sonda Pod larni ushlab turadi.
Mexanizm (chuqur): Siz Deployment'da "3 ta replica kerak" deb e'lon qilasiz. Kubernetes controller doimiy ravishda desired state (3 Pod) ni actual state (hozir ishlayotgan Pod'lar) bilan solishtiradi. Agar bitta Pod o'lsa, ReplicaSet darhol yangisini yaratadi (self-healing). Yangi versiyaga o'tganingizda, Deployment rolling update qiladi: eski Pod'larni asta-sekin yangilariga almashtiradi, xizmat to'xtamaydi.
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-deploy
spec:
replicas: 3
selector:
matchLabels:
app: web
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
app: web
spec:
containers:
- name: app
image: myapp:2.0
readinessProbe:
httpGet:
path: /health
port: 3000# Yangi versiyaga rolling update
kubectl set image deployment/web-deploy app=myapp:2.1
# Muammo bo'lsa oldingi versiyaga qaytish
kubectl rollout undo deployment/web-deploy Keng tarqalgan xato: readinessProbe qo'ymaslik. Kubernetes Pod tayyor deb hisoblaydi va trafik yuboradi, ammo ilova hali yuklanmagan bo'ladi — foydalanuvchilar xato oladi.
Follow-up: livenessProbe va readinessProbe farqi nima? (Javob: liveness — Pod "tirik"mi (o'lsa qayta ishga tushiriladi); readiness — Pod trafik qabul qilishga tayyormi (tayyor bo'lmasa Service undan trafikni uzadi).)
S9: [] Service nima uchun kerak va uning turlari qanday? (Middle)
Ta'rif: Service — o'zgaruvchan (ephemeral) Pod'lar to'plamiga barqaror tarmoq manzili (stable endpoint) beradigan abstraksiya.
Mexanizm (chuqur): Pod'lar o'lib-tirilib turadi, IP'lari o'zgaradi. Service esa doimiy virtual IP (ClusterIP) va DNS nomi beradi. U label selector orqali qaysi Pod'larga tegishli ekanini aniqlaydi va trafikni ular o'rtasida taqsimlaydi (load balancing). Turlari: ClusterIP (faqat klaster ichida), NodePort (har bir node portida ochadi), LoadBalancer (cloud provayder LB'sini yaratadi), ExternalName (tashqi DNS'ga havola).
apiVersion: v1
kind: Service
metadata:
name: web-service
spec:
type: ClusterIP
selector:
app: web # shu label'li Pod'larni tanlaydi
ports:
- port: 80 # Service porti
targetPort: 3000 # Pod portiEndi boshqa Pod'lar http://web-service orqali ulanadi — Pod IP'lari o'zgarsa ham, Service barqaror qoladi.
Keng tarqalgan xato: Service selector label'i Pod label'iga mos kelmasligi. Bunda Service hech qaysi Pod'ni topmaydi va "no endpoints" xatosi chiqadi. kubectl get endpoints bilan tekshirish kerak.
Follow-up: Ingress Service'dan qanday farq qiladi? (Javob: Ingress HTTP/HTTPS darajasida ishlaydi, path va host asosida yo'naltiradi, bitta IP orqali ko'p service'ga marshrutlash va SSL tugatish (termination) beradi.)
S10: [] Horizontal Pod Autoscaler (HPA) qanday ishlaydi? (Senior)
Ta'rif: HPA — yuklama (CPU, xotira yoki maxsus metrikalar) asosida Pod replikalari sonini avtomatik ko'paytirib-kamaytiradigan mexanizm.
Mexanizm (chuqur): HPA controller har 15 soniyada (default) Metrics Server'dan metrikalarni oladi va formula bo'yicha kerakli replica sonini hisoblaydi: desiredReplicas = ceil(currentReplicas × (currentMetric / targetMetric)). Masalan, 3 Pod 90% CPU'da ishlayapti, target 50% bo'lsa: ceil(3 × 90/50) = ceil(5.4) = 6 Pod kerak. Tez-tez ko'tarilib-tushishning oldini olish uchun stabilization window va scale-down delay mavjud.
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: web-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: web-deploy
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50 Keng tarqalgan xato: Pod'larda resources.requests belgilamaslik. HPA foizni requests ga nisbatan hisoblaydi; agar requests bo'lmasa, HPA ishlamaydi. Yana: Metrics Server o'rnatilmagan holatda HPA ishlaydi deb kutish.
Follow-up: HPA, VPA va Cluster Autoscaler farqi nima? (Javob: HPA — Pod sonini, VPA — Pod resurslarini (CPU/RAM), Cluster Autoscaler — node (mashina) sonini o'zgartiradi.)
3-BO'LIM: CI/CD
S11: [] CI va CD o'rtasidagi farq nima? (Junior)
Ta'rif: CI (Continuous Integration) — kod o'zgarishlarini tez-tez umumiy branch'ga birlashtirish va har birini avtomatik test qilish. CD (Continuous Delivery/Deployment) — testdan o'tgan kodni avtomatik tarzda tayyorlash yoki to'g'ridan-to'g'ri production'ga yetkazish.
Mexanizm (chuqur): CI'da har bir push yoki pull request da pipeline ishga tushadi: kod build qilinadi, testlar (unit, integration) o'tkaziladi, linter tekshiradi. Bu xatolarni erta bosqichda topadi. Continuous Delivery — kod har doim deploy'ga tayyor holatda, ammo production'ga chiqarish qo'lda tasdiqlanadi. Continuous Deployment — insonning aralashuvisiz, testdan o'tsa avtomatik production'ga chiqadi.
# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- run: npm run lint
- run: npm testKeng tarqalgan xato: CI/CD ni faqat "avtomatik deploy" deb tushunish. Aslida asosiy qiymat — tez fikr-mulohaza (feedback) va sifat nazorati. Testlarsiz CD — bu xatolarni tezroq production'ga yetkazish demakdir.
Follow-up: Continuous Delivery va Continuous Deployment farqini bir jumlada tushuntiring. (Javob: Delivery'da production'ga chiqarish uchun qo'lda tugma bosiladi; Deployment'da bu ham avtomatik.)
S12: [] GitHub Actions pipeline'ida job, step va workflow qanday tuziladi? (Middle)
Ta'rif: Workflow — butun avtomatlashtirilgan jarayon. U bir necha job'dan iborat, har bir job bir necha step'dan tashkil topadi. Job'lar parallel yoki ketma-ket (needs) ishlashi mumkin.
Mexanizm (chuqur): Har bir job alohida runner (virtual mashina) da ishlaydi va standart holatda parallel bajariladi. needs orqali bog'liqlikni belgilaysiz — masalan, deploy job faqat test job muvaffaqiyatli tugagach ishga tushadi. secrets orqali maxfiy ma'lumotlar (token, parol) xavfsiz uzatiladi. Cache (actions/cache) dependencies'ni saqlab, keyingi ishlashni tezlashtiradi.
name: CI/CD
on:
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm test
deploy:
needs: test # test o'tmasa deploy ishlamaydi
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Docker image build va push
run: |
docker build -t registry.example.com/myapp:${{ github.sha }} .
echo "${{ secrets.REGISTRY_TOKEN }}" | docker login -u ci --password-stdin registry.example.com
docker push registry.example.com/myapp:${{ github.sha }} Keng tarqalgan xato: Maxfiy ma'lumotlarni to'g'ridan-to'g'ri YAML'ga yozish yoki echo bilan log'ga chiqarish. GitHub secrets'ni ishlatish shart. Yana: har bir job alohida mashinada ishlashini unutib, bir job'da yaratilgan faylni boshqa job'da ishlatishga urinish (bu uchun artifacts kerak).
Follow-up: Pipeline'ni qanday tezlashtirasiz? (Javob: dependency caching, kerakli job'larni parallel qilish, matrix build, o'zgargan qismlargina test qilish (affected).)
S13: [] Blue-green va canary deployment strategiyalarini solishtiring. (Senior)
Ta'rif: Blue-green — ikkita bir xil muhit (blue = joriy, green = yangi); trafik bir zumda green'ga o'tkaziladi. Canary — yangi versiya avval trafikning kichik qismiga (masalan, 5%) beriladi, muammo bo'lmasa asta-sekin oshiriladi.
Mexanizm (chuqur): Blue-green'da green muhitga yangi versiya deploy qilinadi va to'liq test qilinadi. Load balancer'ni green'ga o'tkazish bir soniyada bo'ladi — muammo chiqsa, darhol blue'ga qaytariladi (instant rollback). Kamchilik — ikki barobar resurs kerak. Canary'da xavf minimallashtiriladi: agar yangi versiyada xato bo'lsa, faqat 5% foydalanuvchi ta'sirlanadi. Metrikalar (error rate, latency) kuzatiladi va avtomatik yoki qo'lda oshiriladi.
# Canary — Kubernetes'da ikki Deployment va trafik nisbati
# stable: 9 replica, canary: 1 replica ~10% trafik canary'ga
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-stable
spec:
replicas: 9
template:
spec:
containers:
- name: app
image: myapp:2.0
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-canary
spec:
replicas: 1
template:
spec:
containers:
- name: app
image: myapp:2.1 # yangi versiya# Blue-green: Service selector'ni almashtirish
kubectl patch service web -p '{"spec":{"selector":{"version":"green"}}}'Keng tarqalgan xato: Ma'lumotlar bazasi sxemasi (schema) o'zgarishlarini e'tibordan chetda qoldirish. Ikkala versiya bir vaqtda ishlaganda (canary yoki blue-green o'tish payti), DB sxemasi ikkala versiyaga ham mos bo'lishi kerak (backward-compatible migration).
Follow-up: Rolling update qachon blue-green'dan afzal? (Javob: resurs cheklangan bo'lsa va bir zumli rollback shart bo'lmasa; rolling update qo'shimcha muhit talab qilmaydi.)
4-BO'LIM: Nginx va Linux
S14: [] Nginx reverse proxy sifatida qanday ishlaydi? (Middle)
Ta'rif: Reverse proxy — mijoz (client) so'rovlarini qabul qilib, ularni orqadagi (backend) serverlarga uzatadigan va javobni mijozga qaytaradigan server. Mijoz orqadagi serverni ko'rmaydi.
Mexanizm (chuqur): Nginx listen porti orqali so'rovni qabul qiladi, location bloklariga ko'ra qaysi backendga yuborishni hal qiladi (proxy_pass). U SSL tugatish (termination), header'larni o'zgartirish, statik fayllarni to'g'ridan-to'g'ri berish, gzip siqish va caching kabi vazifalarni bajaradi. Backend serverlar to'g'ridan-to'g'ri internetga ochilmaydi — bu xavfsizlik va moslashuvchanlikni oshiradi.
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# Statik fayllar to'g'ridan-to'g'ri
location /static/ {
root /var/www;
expires 30d;
}
# Qolgan so'rovlar backendga
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
} Keng tarqalgan xato: X-Forwarded-For va X-Forwarded-Proto header'larini uzatmaslik. Bunda backend mijozning haqiqiy IP'sini va HTTPS ishlatilganini bilmaydi — logging va redirect logikasi buziladi.
Follow-up: WebSocket'ni proxy qilish uchun qo'shimcha nima kerak? (Javob: proxy_set_header Upgrade $http_upgrade; va proxy_set_header Connection "upgrade"; hamda HTTP/1.1.)
S15: [] Nginx load balancing qanday algoritmlar bilan ishlaydi? (Middle)
Ta'rif: Load balancing — kelayotgan trafikni bir necha backend server o'rtasida taqsimlash. Nginx upstream bloki orqali buni amalga oshiradi.
Mexanizm (chuqur): Nginx bir necha algoritm taklif qiladi: round-robin (default — navbat bilan har biriga), least_conn (eng kam faol ulanishga ega serverga), ip_hash (bir IP doim bir serverga — session uchun), weighted (quvvatga qarab og'irlik). max_fails va fail_timeout orqali nosoz serverni vaqtincha chetlatadi (passive health check).
upstream backend {
least_conn; # eng kam ulanishli serverga
server 10.0.0.1:3000 weight=3; # kuchliroq server — 3x trafik
server 10.0.0.2:3000;
server 10.0.0.3:3000 max_fails=3 fail_timeout=30s;
server 10.0.0.4:3000 backup; # faqat boshqalari o'lsa ishlaydi
}
server {
listen 80;
location / {
proxy_pass http://backend;
}
} Keng tarqalgan xato: Session'ni server xotirasida saqlab, round-robin ishlatish. Foydalanuvchi keyingi so'rovda boshqa serverga tushadi va session yo'qoladi. Yechim — session'ni tashqi joyga (Redis) ko'chirish yoki ip_hash (kamroq afzal).
Follow-up: Passive va active health check farqi nima? (Javob: passive — haqiqiy so'rovlar orqali xatoni sezish; active — muntazam maxsus so'rov yuborib tekshirish (Nginx Plus yoki alohida modul).)
S16: [] Linux'da fayl ruxsatlari (permissions) qanday o'qiladi? (Junior)
Ta'rif: Linux'da har bir fayl uchun uch guruh (owner, group, others) uchun uch ruxsat (read=4, write=2, execute=1) belgilanadi.
Mexanizm (chuqur): ls -l da -rwxr-xr-- ko'rinishida ko'rinadi: birinchi belgi tur (- fayl, d papka, l symlink), keyin uch-uchtadan ruxsatlar. Raqamli ko'rinishda har guruh yig'indi bilan ifodalanadi: rwx = 4+2+1 = 7, r-x = 4+0+1 = 5, r-- = 4. Ya'ni 754. Papka uchun execute — unga kirish (cd) huquqini bildiradi.
# Ruxsatlarni ko'rish
ls -l script.sh
# -rwxr-xr-- owner: rwx(7), group: r-x(5), others: r--(4) 754
# O'zgartirish (raqamli)
chmod 755 script.sh # owner to'liq, boshqalar o'qish+execute
# O'zgartirish (belgi bilan)
chmod u+x script.sh # owner'ga execute qo'shish
chmod o-w file.txt # others'dan write olib tashlash
# Egasini o'zgartirish
chown user:group file.txt Keng tarqalgan xato: Muammoni yechish uchun chmod 777 qilish. Bu hamma uchun to'liq ruxsat — jiddiy xavfsizlik teshigi. To'g'ri yechim — aniq kerakli ruxsatni berish (masalan, web fayllar uchun 644, skriptlar uchun 755).
Follow-up: SUID bit nima qiladi? (Javob: fayl egasining huquqi bilan ishga tushiradi, foydalanuvchi kim bo'lishidan qat'i nazar — masalan passwd buyrug'i.)
S17: [] Linux'da process va systemd service qanday boshqariladi? (Middle)
Ta'rif: Process — ishlayotgan dastur namunasi (PID bilan). systemd — Linux'da xizmatlarni (service) boshqaradigan init tizimi (PID 1).
Mexanizm (chuqur): systemd .service fayllari orqali xizmatlarni boshqaradi: avtomatik ishga tushirish (boot'da), qulash holatida qayta ishga tushirish (Restart=always), bog'liqliklar (After=), log yig'ish (journald). Har bir process signal orqali boshqariladi: SIGTERM (nazokat bilan to'xtatish), SIGKILL (majburiy o'ldirish). systemd xizmatning holatini kuzatib, u qulasa avtomatik tiklaydi.
# /etc/systemd/system/myapp.service
[Unit]
Description=My Node App
After=network.target
[Service]
Type=simple
User=appuser
WorkingDirectory=/opt/myapp
ExecStart=/usr/bin/node server.js
Restart=always
RestartSec=5
Environment=NODE_ENV=production
[Install]
WantedBy=multi-user.targetsudo systemctl daemon-reload
sudo systemctl enable --now myapp # yoqish + darhol ishga tushirish
sudo systemctl status myapp
journalctl -u myapp -f # loglarni real vaqtda kuzatish Keng tarqalgan xato: Ilovani nohup node server.js & bilan ishga tushirish. Server qayta ishga tushsa yoki ilova qulasa, u tiklanmaydi. systemd (yoki PM2, yoki container orchestrator) ishlatish kerak.
Follow-up: SIGTERM va SIGKILL farqi nima? (Javob: SIGTERM'ni ilova ushlab, resurslarni tozalab (graceful shutdown) chiqishi mumkin; SIGKILL'ni ushlab bo'lmaydi — darhol o'ldiriladi.)
5-BO'LIM: Cloud, monitoring, secrets
S18: [] VM, container va serverless o'rtasidagi farqni tushuntiring. (Middle)
Ta'rif: VM (Virtual Machine) — to'liq virtual kompyuter, o'z operatsion tizimi bilan. Container — OS yadrosini (kernel) bo'lishadigan yengil izolyatsiya. Serverless — kodni faqat kerak bo'lganda ishga tushiradigan, server boshqaruvi provayder zimmasida bo'lgan model.
Mexanizm (chuqur): VM'da hypervisor har bir mashinaga to'liq OS ajratadi — kuchli izolyatsiya, ammo og'ir (GB'larda, sekundlarda-daqiqalarda ishga tushadi). Container host OS yadrosini bo'lishadi, faqat ilova va uning bog'liqliklarini o'raydi — yengil (MB'larda, soniyalarda). Serverless (FaaS, masalan AWS Lambda) da siz faqat funksiya yozasiz; provayder uni so'rov kelganda ishga tushiradi va tugagach o'chiradi — scale-to-zero, faqat ishlagan vaqt uchun to'lov. Kamchilik — cold start (birinchi so'rov sekin).
// Serverless funksiya (AWS Lambda)
export const handler = async (event) => {
const name = event.queryStringParameters?.name || "World";
return {
statusCode: 200,
body: JSON.stringify({ message: `Hello, ${name}` }),
};
};Keng tarqalgan xato: Serverless'ni har doim arzon deb hisoblash. Doimiy yuqori trafik va uzoq ishlaydigan jarayonlar uchun serverless container/VM'dan qimmatroq va sekinroq bo'lishi mumkin. Serverless — o'zgaruvchan, notekis yuklama uchun ideal.
Follow-up: Cold start muammosini qanday kamaytirasiz? (Javob: provisioned concurrency, funksiya hajmini kichraytirish, engil runtime tanlash, ulanishlarni funksiyadan tashqarida saqlash.)
S19: [] Structured logging nima va nima uchun muhim? (Middle)
Ta'rif: Structured logging — loglarni erkin matn emas, mashina o'qiy oladigan tuzilgan format (odatda JSON) da yozish.
Mexanizm (chuqur): An'anaviy matn log (console.log("User 5 logged in")) inson uchun tushunarli, ammo qidirish va tahlil qilish qiyin. Structured log har bir voqeani maydonlar (fields) bilan yozadi: level, timestamp, message, userId, traceId. Bu loglarni markazlashtirilgan tizimda (ELK, Loki, Datadog) filtrlash, agregatsiya va ogohlantirish (alerting) uchun qulay qiladi. traceId orqali bitta so'rovni butun microservices bo'ylab kuzatib borish mumkin.
import pino from "pino";
const logger = pino();
// Structured log — JSON chiqadi
logger.info(
{ userId: 5, action: "login", ip: "10.0.0.1", traceId: "abc-123" },
"user logged in"
);
// {"level":30,"time":...,"userId":5,"action":"login","traceId":"abc-123","msg":"user logged in"} Keng tarqalgan xato: Loglarga maxfiy ma'lumot (parol, token, kredit karta) yozish. Bu jiddiy xavfsizlik va compliance buzilishi. Yana: log darajalarini (debug/info/warn/error) noto'g'ri ishlatish — hamma narsani info qilib, muhim signallarni ko'mib tashlash.
Follow-up: Observability'ning uch ustuni nima? (Javob: logs, metrics, traces — birgalikda tizim holatini to'liq ko'rsatadi.)
S20: [] Prometheus va Grafana qanday birga ishlaydi? (Middle)
Ta'rif: Prometheus — metrikalarni yig'ib, vaqt qatori (time-series) ma'lumotlar bazasida saqlaydigan monitoring tizimi. Grafana — bu metrikalarni vizual dashboard'larda ko'rsatadigan vosita.
Mexanizm (chuqur): Prometheus pull modeli bilan ishlaydi: u belgilangan interval'da ilovalarning /metrics endpoint'iga so'rov yuborib (scrape), metrikalarni yig'adi. Metrikalar to'rt turda bo'ladi: Counter (faqat o'sadi — masalan, so'rovlar soni), Gauge (ko'tarilib-tushadi — masalan, xotira), Histogram va Summary (taqsimot — masalan, latency). PromQL tili bilan so'rovlar yoziladi. Grafana Prometheus'ni ma'lumot manbasi sifatida ishlatib, grafiklar chizadi va Alertmanager orqali ogohlantirish yuboradi.
// Node.js'da metrika ochish (prom-client)
import client from "prom-client";
const httpRequests = new client.Counter({
name: "http_requests_total",
help: "Umumiy HTTP so'rovlar soni",
labelNames: ["method", "status"],
});
app.use((req, res, next) => {
res.on("finish", () => {
httpRequests.inc({ method: req.method, status: res.statusCode });
});
next();
});
app.get("/metrics", async (req, res) => {
res.set("Content-Type", client.register.contentType);
res.end(await client.register.metrics());
});# PromQL: oxirgi 5 daqiqadagi xatolik darajasi
rate(http_requests_total{status=~"5.."}[5m])Keng tarqalgan xato: Label'larda yuqori kardinallikdagi qiymatlar (userId, requestId) ishlatish. Har bir noyob qiymat yangi time-series yaratadi — Prometheus xotirasi portlaydi.
Follow-up: RED va USE metodlari nima? (Javob: RED — Rate, Errors, Duration (servislar uchun); USE — Utilization, Saturation, Errors (resurslar uchun).)
S21: [] Secrets management'ni to'g'ri qanday tashkil qilasiz? (Senior)
Ta'rif: Secrets management — parollar, API kalitlari, sertifikatlar kabi maxfiy ma'lumotlarni xavfsiz saqlash, uzatish va aylantirishni (rotation) tashkil qilish.
Mexanizm (chuqur): Maxfiy ma'lumotlar hech qachon kodga yoki git'ga tushmasligi kerak. To'g'ri yechim — maxsus vositalar: HashiCorp Vault, AWS Secrets Manager, Kubernetes Secrets (base64, encryption at rest bilan). Bu tizimlar markazlashtirilgan saqlash, kirish nazorati (access control), audit log va avtomatik rotation beradi. Ilova ishga tushganda secret'ni runtime'da oladi. Muhit o'zgaruvchilari (environment variables) — oddiy usul, ammo ular process ro'yxatida va crash dump'da ko'rinishi mumkin.
# Kubernetes Secret
apiVersion: v1
kind: Secret
metadata:
name: db-credentials
type: Opaque
stringData:
password: "super-secret-value"
---
# Pod'da ishlatish
apiVersion: v1
kind: Pod
metadata:
name: app
spec:
containers:
- name: app
image: myapp:1.0
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-credentials
key: password# Vault'dan secret olish
vault kv get -field=password secret/myapp/db Keng tarqalgan xato: .env faylini yoki secret'ni git'ga commit qilish. Agar bir marta commit qilingan bo'lsa, git tarixidan ham o'chirish va secret'ni darhol aylantirish (rotate) kerak — chunki u allaqachon oshkor bo'lgan.
Follow-up: Kubernetes Secrets base64 kodlangan — bu shifrlash (encryption)mi? (Javob: yo'q, base64 shunchaki kodlash, hamma osongina ochadi. Haqiqiy himoya uchun encryption at rest va RBAC yoqilishi kerak.)
S22: [] HTTPS/SSL/TLS qanday ishlaydi va sertifikat nima uchun kerak? (Middle)
Ta'rif: TLS (Transport Layer Security) — mijoz va server o'rtasidagi aloqani shifrlaydigan protokol. SSL sertifikati — serverning haqiqiyligini tasdiqlaydigan, ishonchli markaz (CA) tomonidan imzolangan hujjat.
Mexanizm (chuqur): TLS handshake jarayonida: mijoz serverga ulanadi, server o'z sertifikatini (public key bilan) yuboradi, mijoz uni ishonchli CA imzosiga qarab tekshiradi. Keyin asimmetrik shifrlash (public/private key) yordamida umumiy sessiya kaliti (symmetric) kelishib olinadi — chunki simmetrik shifrlash tezroq. Shundan so'ng barcha ma'lumot shu sessiya kaliti bilan shifrlanadi. Bu maxfiylik (encryption), yaxlitlik (integrity) va autentifikatsiyani (server haqiqiyligi) ta'minlaydi.
# Let's Encrypt orqali bepul sertifikat (Certbot)
sudo certbot --nginx -d example.com -d www.example.com
# Avtomatik yangilash (sertifikat 90 kunda tugaydi)
sudo certbot renew --dry-run
# Sertifikatni tekshirish
openssl s_client -connect example.com:443 -servername example.comKeng tarqalgan xato: Sertifikatni avtomatik yangilashni (auto-renewal) sozlamaslik. Let's Encrypt sertifikatlari 90 kunda tugaydi — qo'lda yangilashni unutsangiz, sayt ishlamay qoladi. Yana: HTTP'dan HTTPS'ga redirect qo'ymaslik.
Follow-up: TLS termination nima va uni qayerda qilish yaxshi? (Javob: shifrlangan aloqani ochish jarayoni; odatda load balancer yoki reverse proxy (Nginx) da qilinadi, backend'ni yuklamadan xalos qiladi.)
S23: [] Git branching strategiyalari qanday va qay birini tanlaysiz? (Middle)
Ta'rif: Git branching strategy — jamoada branch'larni tashkil qilish va birlashtirish (merge) qoidalari. Asosiylari: Git Flow, GitHub Flow, Trunk-Based Development.
Mexanizm (chuqur): Git Flow — main, develop, feature/*, release/*, hotfix/* branch'lari; murakkab, kam-kam relizli loyihalar uchun. GitHub Flow — soddaroq: main doim deploy'ga tayyor, har bir ish feature branch'da, PR orqali birlashtiriladi. Trunk-Based — hamma main (trunk) ga tez-tez, kichik commit'lar bilan qo'shadi; feature flag bilan tugallanmagan funksiyalar yashiriladi; CI/CD va tez-tez deploy uchun ideal.
# GitHub Flow misoli
git checkout -b feature/user-auth
# ... ishlash, commit qilish ...
git push origin feature/user-auth
# GitHub'da Pull Request ochish review CI o'tadi merge
# Trunk-Based — feature flag bilan
if (featureFlags.newCheckout) {
renderNewCheckout(); // hali tayyor bo'lmagan funksiya yashirin
} else {
renderOldCheckout();
} Keng tarqalgan xato: Feature branch'ni juda uzoq ushlab, main'dan uzoqlashib ketish. Natijada merge paytida katta konfliktlar (merge hell) yuzaga keladi. Yechim — kichik, tez-tez merge qilinadigan branch'lar va main'ni muntazam olib turish.
Follow-up: Merge va rebase farqi nima va qachon qaysi birini ishlatasiz? (Javob: merge tarixni saqlaydi, merge commit yaratadi; rebase tarixni chiziqli (linear) qiladi. Umumiy branch'da rebase qilmang — u tarixni qayta yozadi.)
6-BO'LIM: SOLID tamoyillari
S24: [] Single Responsibility Principle (SRP) nima? (Middle)
Ta'rif: SRP — har bir class faqat bitta sababga ko'ra o'zgarishi kerak, ya'ni faqat bitta mas'uliyatga (responsibility) ega bo'lishi lozim.
Mexanizm (chuqur): Agar class bir necha vazifani bajarsa (masalan, ma'lumotni saqlash, formatlash va yuborish), bittasidagi o'zgarish boshqalariga ta'sir qilish xavfini oshiradi. SRP class'larni mas'uliyat chegaralari bo'yicha ajratadi — bu kodni tushunish, test qilish va o'zgartirishni osonlashtiradi. "Bitta sabab" — ko'pincha bitta aktor (foydalanuvchi turi yoki tashqi tizim) manfaati.
// Yomon: bitta class uch mas'uliyat
class User {
saveToDb() { /* DB logikasi */ }
sendEmail() { /* email logikasi */ }
generateReport() { /* hisobot logikasi */ }
}
// Yaxshi: har class bitta mas'uliyat
class UserRepository {
save(user) { /* faqat DB */ }
}
class EmailService {
send(user) { /* faqat email */ }
}
class ReportGenerator {
generate(user) { /* faqat hisobot */ }
}Keng tarqalgan xato: SRP'ni "har bir class'da bitta method bo'lishi kerak" deb tushunish. Bu noto'g'ri — mezon method soni emas, o'zgarish sababi. Bir mas'uliyatga oid bir necha method bir class'da bo'lishi normal.
Follow-up: God object nima va u qaysi tamoyilni buzadi? (Javob: hamma narsani qiladigan ulkan class; SRP'ni buzadi, kohesiyani (cohesion) pasaytiradi.)
S25: [] Open/Closed Principle (OCP) nima? (Middle)
Ta'rif: OCP — dastur birliklari (class, module) kengaytirish uchun ochiq, o'zgartirish uchun yopiq bo'lishi kerak. Ya'ni yangi funksiya qo'shishda mavjud kodni o'zgartirmasdan, uni kengaytirish orqali erishish lozim.
Mexanizm (chuqur): Buni abstraksiya (interface, abstract class) va polimorfizm orqali amalga oshiriladi. Yangi holat qo'shilganda, mavjud if/else yoki switch ni o'zgartirish o'rniga, yangi class yaratasiz. Bu regressiya (mavjud ishlayotgan kodni buzish) xavfini kamaytiradi.
// Yomon: yangi shakl qo'shishda funksiyani o'zgartirish kerak
function area(shape) {
if (shape.type === "circle") return Math.PI * shape.r ** 2;
if (shape.type === "square") return shape.side ** 2;
// yangi shakl bu yerni o'zgartirish kerak
}
// Yaxshi: har shakl o'z hisobini biladi
class Circle {
constructor(r) { this.r = r; }
area() { return Math.PI * this.r ** 2; }
}
class Square {
constructor(side) { this.side = side; }
area() { return this.side ** 2; }
}
// Yangi shakl yangi class, mavjud kod o'zgarmaydi
class Triangle {
constructor(b, h) { this.b = b; this.h = h; }
area() { return 0.5 * this.b * this.h; }
}Keng tarqalgan xato: Har bir joyga abstraksiya kiritib, kodni ortiqcha murakkablashtirish (over-engineering). OCP kerak bo'ladigan joyda — o'zgarish ehtimoli yuqori bo'lgan nuqtalarda qo'llanishi kerak, hamma joyda emas.
Follow-up: OCP'ni buzmasdan yangi to'lov usuli qanday qo'shasiz? (Javob: PaymentMethod interface'ini yaratib, har bir usulni alohida class sifatida implement qilish.)
S26: [] Liskov Substitution Principle (LSP) nima? (Senior)
Ta'rif: LSP — subclass (avlod) o'zining superclass (ota) o'rniga hech qanday xatti-harakat buzilmasdan qo'yilishi (substitute) mumkin bo'lishi kerak.
Mexanizm (chuqur): Agar B class A class'dan meros olsa, dasturning har qanday joyida A ishlatilgan bo'lsa, uni B bilan almashtirsak, dastur to'g'ri ishlashda davom etishi kerak. Buzilishga klassik misol — "kvadrat to'rtburchakning avlodi" muammosi: matematik jihatdan to'g'ri, ammo Rectangle'da alohida width va height o'rnatish mumkin, Square'da esa ular bog'liq — bu superclass shartnomasini (contract) buzadi.
// LSP buzilishi
class Rectangle {
setWidth(w) { this.w = w; }
setHeight(h) { this.h = h; }
area() { return this.w * this.h; }
}
class Square extends Rectangle {
setWidth(w) { this.w = w; this.h = w; } // kutilmagan yon ta'sir
setHeight(h) { this.w = h; this.h = h; }
}
// Bu funksiya Rectangle bilan ishlaydi, Square bilan buziladi:
function test(rect) {
rect.setWidth(5);
rect.setHeight(4);
console.assert(rect.area() === 20); // Square'da 16 chiqadi — buzildi!
}
// Yaxshi: umumiy abstraksiya, meros o'rniga
class Shape {
area() { throw new Error("not implemented"); }
}
class Rectangle2 extends Shape {
constructor(w, h) { super(); this.w = w; this.h = h; }
area() { return this.w * this.h; }
}
class Square2 extends Shape {
constructor(side) { super(); this.side = side; }
area() { return this.side ** 2; }
} Keng tarqalgan xato: Subclass'da method'ni override qilib, undan throw new Error("not supported") qilish (masalan, ReadOnlyList.add()). Bu superclass shartnomasini buzadi — bu LSP buzilishining aniq belgisi.
Follow-up: LSP buzilishini kod ko'rmasdan qanday sezasiz? (Javob: subclass method'ida throw not supported, preconditionni kuchaytirish yoki postconditionni zaiflashtirish, tur tekshiruvi (instanceof) mavjudligi — bular belgi.)
S27: [] Interface Segregation Principle (ISP) nima? (Middle)
Ta'rif: ISP — mijoz (client) o'ziga kerak bo'lmagan method'larga bog'liq bo'lishga majbur qilinmasligi kerak. Ya'ni katta, umumiy interface'lar o'rniga kichik, maxsuslashtirilgan interface'lar afzal.
Mexanizm (chuqur): Agar interface juda katta bo'lsa, uni implement qiladigan class'lar keraksiz method'larni ham (ko'pincha bo'sh yoki throw bilan) yozishga majbur bo'ladi. Bu keraksiz bog'liqlik yaratadi — interface'dagi o'zgarish uni ishlatmaydigan class'larga ham ta'sir qiladi. ISP interface'larni rol (role) bo'yicha bo'lishni tavsiya qiladi.
// Yomon: bitta katta interface
class Worker {
work() {}
eat() {}
sleep() {}
}
// Robot ishlaydi, lekin ovqatlanmaydi — eat()ni implement qilishga majbur
class Robot extends Worker {
work() { /* ... */ }
eat() { throw new Error("robot ovqatlanmaydi"); } // ISP buzildi
sleep() { throw new Error("robot uxlamaydi"); }
}
// Yaxshi: kichik, maxsus interface'lar (JS'da mixin/composition)
const Workable = { work() {} };
const Feedable = { eat() {} };
class Human {
work() {}
eat() {}
}
class Robot2 {
work() {} // faqat kerakli qobiliyat
}Keng tarqalgan xato: "Fat interface" — bir joyga hamma method'ni to'plash "qulay" deb o'ylash. Aslida bu implementatsiyalarni keraksiz method'lar bilan ifloslantiradi va bog'liqlikni oshiradi.
Follow-up: ISP va SRP qanday bog'liq? (Javob: ISP — interface darajasidagi SRP; ikkalasi ham "bitta narsaga fokus" g'oyasiga asoslanadi.)
S28: [] Dependency Inversion Principle (DIP) nima? (Senior)
Ta'rif: DIP — yuqori darajali modullar quyi darajali modullarga emas, ikkalasi ham abstraksiyalarga bog'liq bo'lishi kerak. Abstraksiyalar detallarga emas, detallar abstraksiyalarga bog'liq bo'lishi lozim.
Mexanizm (chuqur): An'anaviy kodda yuqori darajali biznes logika to'g'ridan-to'g'ri quyi darajali detallarga (aniq DB, aniq API) bog'lanadi. DIP bu bog'liqlikni "ag'daradi" (invert): biznes logika interface e'lon qiladi, quyi darajali detal esa uni implement qiladi. Bu Dependency Injection orqali amalga oshiriladi. Natijada biznes logikani DB'ni almashtirmasdan test qilish yoki DB'ni o'zgartirish mumkin.
// Yomon: yuqori daraja to'g'ridan-to'g'ri quyi darajaga bog'liq
class MySQLDatabase {
save(data) { /* MySQL logikasi */ }
}
class UserService {
constructor() {
this.db = new MySQLDatabase(); // qattiq bog'liqlik (hard dependency)
}
}
// Yaxshi: ikkalasi ham abstraksiyaga bog'liq
class UserService2 {
constructor(database) { // interface qabul qiladi
this.db = database;
}
createUser(user) { this.db.save(user); }
}
// Har qanday implementatsiyani "in'ektsiya" qilish mumkin
const service = new UserService2(new MySQLDatabase());
// Test'da:
const testService = new UserService2({ save: () => {} }); // mock Keng tarqalgan xato: DIP'ni "har doim yangi obyektni new bilan yaratish o'rniga uzatish" deb tushunib, uni Dependency Injection bilan aralashtirish. DI — DIP'ga erishish usuli, DIP esa — tamoyil (abstraksiyaga bog'lanish).
Follow-up: DIP microservices va test qilishga qanday yordam beradi? (Javob: haqiqiy bog'liqliklarni (DB, tashqi API) mock/stub bilan almashtirishga imkon beradi — izolyatsiyalangan test va moslashuvchan arxitektura.)
7-BO'LIM: Design Patterns
S29: [] Singleton pattern nima va uning xavflari qanday? (Middle)
Ta'rif: Singleton — class'dan butun dastur davomida faqat bitta namuna (instance) yaratilishini kafolatlaydigan va unga global kirish beradigan yaratuvchi (creational) pattern.
Mexanizm (chuqur): Konstruktor tashqaridan chaqirilishi bloklanadi, yagona namuna ichki statik maydonda saqlanadi. Birinchi murojaatda yaratiladi (lazy) yoki oldindan (eager). DB ulanishlar pool'i, konfiguratsiya, logger uchun mos. Ammo Singleton — yashirin global holat (global state) hisoblanadi, bu test qilishni qiyinlashtiradi va yashirin bog'liqliklar yaratadi.
// JS'da Singleton (module pattern — eng oddiy usul)
class Database {
constructor() {
if (Database.instance) return Database.instance;
this.connection = this.connect();
Database.instance = this;
}
connect() { return "connected"; }
}
const db1 = new Database();
const db2 = new Database();
console.log(db1 === db2); // true — bir xil namunaKeng tarqalgan xato: Singleton'ni haddan tashqari ishlatib, global holat yaratish. Bu modullarni bir-biriga yashirin bog'laydi (tight coupling), parallel test'larni buzadi. Ko'p hollarda Dependency Injection yaxshiroq alternativa. Yana: ko'p oqimli (multi-threaded) muhitda thread-safe qilmaslik.
Follow-up: Singleton'ni qanday qilib test qilish mumkin holatga keltirasiz? (Javob: uni interface orqali in'ektsiya qilish, yoki reset method qo'shish, yoki umuman DI konteynerga ishonib topshirish.)
S30: [] Factory pattern nima uchun kerak? (Middle)
Ta'rif: Factory — obyekt yaratish logikasini alohida joyda inkapsulatsiya qiladigan, mijoz aniq class nomini bilmasdan obyekt oladigan yaratuvchi pattern.
Mexanizm (chuqur): Mijoz new ConcreteClass() chaqirish o'rniga, factory'dan obyekt so'raydi. Factory qaysi konkret class yaratishni (ko'pincha kirish parametriga qarab) o'zi hal qiladi. Bu obyekt yaratishni ishlatishdan ajratadi — yangi tur qo'shishda mijoz kodini o'zgartirish shart emas (OCP'ga hamohang).
// Factory pattern
class EmailNotification {
send(msg) { console.log(`Email: ${msg}`); }
}
class SmsNotification {
send(msg) { console.log(`SMS: ${msg}`); }
}
class PushNotification {
send(msg) { console.log(`Push: ${msg}`); }
}
class NotificationFactory {
static create(type) {
switch (type) {
case "email": return new EmailNotification();
case "sms": return new SmsNotification();
case "push": return new PushNotification();
default: throw new Error(`Noma'lum tur: ${type}`);
}
}
}
// Mijoz aniq class'ni bilmaydi
const notifier = NotificationFactory.create("sms");
notifier.send("Salom!");Keng tarqalgan xato: Factory va Abstract Factory'ni chalkashtirish. Factory — bitta obyekt yaratadi; Abstract Factory — bir-biriga bog'liq obyektlar oilasini (family) yaratadi. Yana: juda oddiy holatlarda ham factory qo'shib, keraksiz murakkablik yaratish.
Follow-up: Factory Method va Simple Factory farqi nima? (Javob: Simple Factory — bitta method/class hamma turlarni yaratadi; Factory Method — yaratishni subclass'larga topshiradi (polimorfizm orqali).)
S31: [] Observer pattern qanday ishlaydi? (Middle)
Ta'rif: Observer — bir obyekt (subject) holati o'zgarganda, unga obuna bo'lgan barcha obyektlar (observers) avtomatik xabardor qilinadigan xatti-harakat (behavioral) pattern.
Mexanizm (chuqur): Subject observer'lar ro'yxatini saqlaydi va o'zgarish sodir bo'lganda hammasini notify() orqali xabardor qiladi. Observer'lar subscribe/unsubscribe qila oladi. Bu bir-biriga bo'sh bog'langan (loosely coupled) tizim yaratadi — subject observer'lar kimligini bilmaydi, faqat interface'ni biladi. Event tizimlari, reaktiv dasturlash (RxJS), UI framework'lar shu prinsipga asoslanadi.
class Subject {
constructor() { this.observers = []; }
subscribe(observer) { this.observers.push(observer); }
unsubscribe(observer) {
this.observers = this.observers.filter((o) => o !== observer);
}
notify(data) {
this.observers.forEach((o) => o.update(data));
}
}
class Logger {
update(data) { console.log(`Log: ${data}`); }
}
class Analytics {
update(data) { console.log(`Analytics: ${data}`); }
}
const store = new Subject();
store.subscribe(new Logger());
store.subscribe(new Analytics());
store.notify("buyurtma yaratildi"); // ikkala observer xabardor bo'ladi Keng tarqalgan xato: Observer'larni unsubscribe qilmaslik — bu xotira sizishiga (memory leak) olib keladi, chunki subject ularga havolani ushlab turadi. UI komponentlarda, komponent yo'q qilinganda obunani bekor qilish shart.
Follow-up: Observer va Pub/Sub farqi nima? (Javob: Observer'da subject observer'larni bevosita biladi; Pub/Sub'da o'rtada broker/event bus bo'lib, publisher va subscriber bir-birini bilmaydi.)
S32: [] Strategy pattern nima va qachon ishlatiladi? (Middle)
Ta'rif: Strategy — algoritmlar oilasini alohida class'larga ajratib, ularni ish vaqtida (runtime) almashtirish imkonini beradigan xatti-harakat pattern.
Mexanizm (chuqur): Har bir algoritm umumiy interface'ni implement qiladi. Kontekst (context) aniq algoritmni bilmaydi — u faqat interface bilan ishlaydi va kerakli strategiyani tashqaridan oladi. Bu ko'p if/else/switch ni yo'q qiladi va yangi algoritm qo'shishni osonlashtiradi (OCP). Masalan, turli to'lov usullari, saralash algoritmlari, chegirma hisoblash.
// Har xil chegirma strategiyalari
class NoDiscount {
apply(price) { return price; }
}
class PercentDiscount {
constructor(percent) { this.percent = percent; }
apply(price) { return price * (1 - this.percent / 100); }
}
class FixedDiscount {
constructor(amount) { this.amount = amount; }
apply(price) { return Math.max(0, price - this.amount); }
}
class Cart {
constructor(strategy) { this.strategy = strategy; }
setStrategy(strategy) { this.strategy = strategy; }
total(price) { return this.strategy.apply(price); }
}
const cart = new Cart(new PercentDiscount(20));
console.log(cart.total(100)); // 80
cart.setStrategy(new FixedDiscount(15));
console.log(cart.total(100)); // 85Keng tarqalgan xato: Strategy'ni State pattern bilan chalkashtirish. Strategy — algoritmni tashqaridan tanlaymiz; State — obyekt o'z holatiga qarab o'zini boshqacha tutadi va holatlar o'zaro o'tishni boshqaradi.
Follow-up: Strategy pattern OCP'ga qanday xizmat qiladi? (Javob: yangi algoritm — yangi strategy class, mavjud kontekst kodi o'zgarmaydi.)
S33: [] Repository pattern nima va nima uchun foydali? (Senior)
Ta'rif: Repository — ma'lumotlarga kirish logikasini (data access) biznes logikadan ajratib, ma'lumotlar bazasi ustida to'plam (collection) kabi abstraksiya beradigan pattern.
Mexanizm (chuqur): Repository biznes logikaga find, save, delete kabi domenga oid method'lar beradi va ichkarida aniq DB texnologiyasini (SQL, ORM, NoSQL) yashiradi. Biznes logika SELECT * FROM ... yozmaydi — u faqat userRepository.findById(5) chaqiradi. Bu ma'lumot manbasini almashtirishni (masalan, PostgreSQL'dan MongoDB'ga) yoki test'da mock ishlatishni osonlashtiradi va DIP'ga hamohang.
// Repository interface (kontrakt)
class UserRepository {
findById(id) { throw new Error("not implemented"); }
save(user) { throw new Error("not implemented"); }
}
// PostgreSQL implementatsiyasi
class PostgresUserRepository extends UserRepository {
constructor(db) { super(); this.db = db; }
async findById(id) {
const rows = await this.db.query("SELECT * FROM users WHERE id = $1", [id]);
return rows[0];
}
async save(user) {
await this.db.query("INSERT INTO users(name) VALUES($1)", [user.name]);
}
}
// Biznes logika DB detallarini bilmaydi
class UserService {
constructor(userRepository) { this.repo = userRepository; }
async getProfile(id) { return this.repo.findById(id); }
}Keng tarqalgan xato: ORM (masalan, Prisma, TypeORM) ustiga yana bir keraksiz Repository qatlami qo'shib, hech qanday qo'shimcha qiymat bermaslik. Repository — DB detallarini yashirish uchun; agar ORM allaqachon yetarli abstraksiya bersa, ortiqcha qatlam faqat murakkablik qo'shadi.
Follow-up: Repository va Data Mapper (Active Record) farqi nima? (Javob: Active Record'da obyekt o'zini saqlaydi (user.save()); Repository ma'lumotni obyektdan ajratib, alohida boshqaradi — biznes obyekt "sof" qoladi.)
S34: [] Dependency Injection (DI) nima va qanday turlari bor? (Middle)
Ta'rif: Dependency Injection — obyekt o'z bog'liqliklarini (dependencies) o'zi yaratish o'rniga, ularni tashqaridan qabul qiladigan texnika.
Mexanizm (chuqur): Bog'liqlik obyektni new bilan ichkarida yaratish o'rniga, uni konstruktor, setter yoki method orqali "in'ektsiya" qilinadi. Turlari: constructor injection (eng keng tarqalgan — bog'liqlik konstruktorga uzatiladi), setter injection, method injection. Ko'pincha DI container (IoC container) bog'liqliklarni avtomatik yechadi va hayotiy siklini boshqaradi. DI — DIP'ga erishishning amaliy usuli; u testlash va moslashuvchanlikni oshiradi.
// Constructor injection
class Mailer {
send(to, msg) { /* ... */ }
}
class Logger {
log(msg) { /* ... */ }
}
class OrderService {
// Bog'liqliklar tashqaridan keladi
constructor(mailer, logger) {
this.mailer = mailer;
this.logger = logger;
}
placeOrder(order) {
this.logger.log("buyurtma yaratildi");
this.mailer.send(order.email, "Rahmat!");
}
}
// Ulanish nuqtasi (composition root)
const service = new OrderService(new Mailer(), new Logger());
// Test'da mock in'ektsiya qilinadi
const fakeMailer = { send: () => {} };
const fakeLogger = { log: () => {} };
const testService = new OrderService(fakeMailer, fakeLogger);Keng tarqalgan xato: DI'ni faqat framework (Spring, NestJS) xususiyati deb o'ylash. Aslida DI — oddiy dizayn texnikasi; hech qanday framework'siz, shunchaki konstruktorga uzatish orqali ham qo'llansa bo'ladi. Yana: Service Locator anti-pattern'ini DI deb adashtirish.
Follow-up: DI container qanday afzallik beradi? (Javob: bog'liqliklar grafini avtomatik yechadi, hayotiy sikl (singleton/transient) ni boshqaradi, katta ilovada qo'lda ulashdan xalos qiladi.)
8-BO'LIM: Arxitektura uslublari
S35: [] Monolith va microservices trade-off'larini tushuntiring. (Senior)
Ta'rif: Monolith — butun ilova bitta joylashtiriladigan (deployable) birlik. Microservices — ilova mustaqil joylashtiriladigan, o'z ma'lumot bazasiga ega kichik servislarga bo'lingan.
Mexanizm (chuqur): Monolith'da hamma modul bitta jarayonda ishlaydi, ular funksiya chaqiruvi orqali bog'lanadi — oddiy, tez, tranzaksiya oson. Ammo o'sgani sayin deploy og'irlashadi, bitta modul boshqalarni bloklashi mumkin, jamoalar bir-biriga to'sqinlik qiladi. Microservices'da har servis mustaqil deploy va scale qilinadi, turli texnologiya ishlatishi mumkin, jamoalar mustaqil ishlaydi. Ammo tarmoq orqali aloqa (latency, xatolik), taqsimlangan tranzaksiya, monitoring va operatsion murakkablik keskin oshadi.
# Monolith: bitta deploy
services:
app:
build: . # butun ilova
ports: ["3000:3000"]
# Microservices: har biri mustaqil
services:
users-service:
build: ./users
orders-service:
build: ./orders
payments-service:
build: ./payments
gateway:
build: ./gateway # API Gateway hammani birlashtiradiKeng tarqalgan xato: Kichik loyihada yoki tajribasiz jamoada darrov microservices'ni tanlash ("hype-driven"). Bu keraksiz murakkablik keltiradi. Ko'pincha to'g'ri yo'l — modular monolith dan boshlab, keyin haqiqiy ehtiyoj paydo bo'lganda ajratish.
Follow-up: Microservices'ga o'tishning belgisi nima? (Javob: jamoalar bir-biriga to'sqinlik qilishi, modullarning turli scaling talabi, mustaqil deploy zarurati, katta hajm.)
S36: [] Layered (N-tier) va Hexagonal arxitekturani solishtiring. (Middle)
Ta'rif: Layered — kodni gorizontal qatlamlarga (presentation business data) ajratish. Hexagonal (Ports & Adapters) — biznes logikani markazga qo'yib, tashqi dunyoga port va adapter orqali ulanish.
Mexanizm (chuqur): Layered'da har qatlam faqat pastdagisiga bog'lanadi; oddiy, ammo biznes logika ko'pincha DB detallariga bog'lanib qoladi. Hexagonal'da yadro (domain) hech qanday tashqi texnologiyani bilmaydi — u port (interface) e'lon qiladi, tashqi detallar (DB, UI, API) esa adapter orqali shu portlarga ulanadi. Bog'liqlik yo'nalishi doim yadroga qaratilgan (dependency rule). Bu biznes logikani infratuzilmadan to'liq ajratadi va test qilishni osonlashtiradi.
// Hexagonal: domain port e'lon qiladi (yadro)
class UserRepositoryPort {
save(user) { throw new Error("not implemented"); }
}
// Domain servis faqat port'ni biladi
class RegisterUser {
constructor(repo) { this.repo = repo; }
execute(data) {
const user = { id: crypto.randomUUID(), ...data };
this.repo.save(user); // qaysi DB ekanini bilmaydi
return user;
}
}
// Adapter — port'ni aniq texnologiya bilan implement qiladi
class MongoUserAdapter extends UserRepositoryPort {
save(user) { /* Mongo logikasi */ }
}Keng tarqalgan xato: "Toza arxitektura"ni har bir kichik CRUD ilovaga majburan qo'llash. Ko'p qatlam va abstraksiya oddiy loyihada faqat ortiqcha kod (boilerplate) keltiradi. Arxitektura murakkabligi loyiha murakkabligiga mos bo'lishi kerak.
Follow-up: MVC hexagonal'ning qayeriga to'g'ri keladi? (Javob: MVC — asosan presentation qatlami/adapter darajasidagi pattern; hexagonal esa butun ilova strukturasi haqida — ular bir-birini istisno qilmaydi.)
S37: [] Event-driven arxitektura va message queue qanday ishlaydi? (Senior)
Ta'rif: Event-driven — komponentlar bir-biriga to'g'ridan-to'g'ri murojaat qilmasdan, voqealar (events) orqali aloqa qiladigan arxitektura. Message queue — xabarlarni ishonchli yetkazadigan oraliq bufer (broker).
Mexanizm (chuqur): Producer voqeani queue/broker'ga (RabbitMQ, Kafka) yuboradi, consumer uni o'z tezligida qayta ishlaydi. Bu asinxron va bo'sh bog'langan (loosely coupled) — producer consumer kimligini yoki tayyorligini bilmasligi kerak emas. Foydalari: yuk ko'tarilganda queue bufer bo'ladi (back-pressure), consumer qulasa xabar yo'qolmaydi (durability), yangi consumer qo'shish oson. Yetkazish kafolatlari: at-most-once, at-least-once, exactly-once. Idempotency muhim — bir xabar ikki marta yetsa ham natija bir xil bo'lishi kerak.
// Producer — voqeani queue'ga yuboradi
await channel.assertQueue("order_created", { durable: true });
channel.sendToQueue(
"order_created",
Buffer.from(JSON.stringify({ orderId: 42, amount: 100 })),
{ persistent: true }
);
// Consumer — o'z tezligida qayta ishlaydi
channel.consume("order_created", async (msg) => {
const order = JSON.parse(msg.content.toString());
await sendConfirmationEmail(order); // sekin ish — asinxron
channel.ack(msg); // muvaffaqiyatli — tasdiqlash
}); Keng tarqalgan xato: Consumer'ni idempotent qilmaslik. At-least-once yetkazishda xabar takrorlanishi mumkin — masalan, to'lov ikki marta amalga oshishi mumkin. Har xabarga noyob ID berib, qayta ishlanganini tekshirish kerak. Yana: ack ni noto'g'ri joyda chaqirib, ish tugamasdan xabarni tasdiqlash (xato bo'lsa yo'qoladi).
Follow-up: Kafka va RabbitMQ farqi nima? (Javob: RabbitMQ — an'anaviy message broker (queue, routing); Kafka — taqsimlangan log/stream, xabarlarni saqlaydi va qayta o'qishga imkon beradi, yuqori throughput.)
S38: [] Caching qanday ishlaydi va qaysi strategiyalar mavjud? (Middle)
Ta'rif: Caching — tez-tez kerak bo'ladigan ma'lumotni tezroq joyda (xotira) saqlab, sekin manbaga (DB, API) murojaatni kamaytirish.
Mexanizm (chuqur): Cache asosiy manbadan tezroq (RAM, Redis) bo'lgani uchun javob vaqtini keskin kamaytiradi va DB yukini pasaytiradi. Asosiy strategiyalar: cache-aside (ilova avval cache'ni tekshiradi, bo'lmasa DB'dan olib cache'ga yozadi), write-through (yozishda cache va DB birga yangilanadi), write-behind (avval cache, keyin asinxron DB). Eng qiyin qism — invalidation (eskirgan ma'lumotni yangilash) va TTL (yashash muddati). Cache miss, cache stampede, stale data — asosiy muammolar.
// Cache-aside pattern (Redis bilan)
async function getUser(id) {
const cacheKey = `user:${id}`;
// 1. Avval cache'ni tekshirish
const cached = await redis.get(cacheKey);
if (cached) return JSON.parse(cached); // cache hit
// 2. Cache'da yo'q — DB'dan olish (cache miss)
const user = await db.query("SELECT * FROM users WHERE id = $1", [id]);
// 3. Cache'ga yozish (TTL bilan)
await redis.set(cacheKey, JSON.stringify(user), "EX", 300); // 5 daqiqa
return user;
}
// Ma'lumot o'zgarganda cache'ni bekor qilish
async function updateUser(id, data) {
await db.query("UPDATE users SET ... WHERE id = $1", [id]);
await redis.del(`user:${id}`); // invalidation
}Keng tarqalgan xato: Cache invalidation'ni unutish — ma'lumot o'zgargach ham eski (stale) qiymat berilaveradi. "Kompyuter fanidagi ikki qiyin narsadan biri — cache invalidation." Yana: TTL'siz cheksiz cache'lash — xotira to'lib ketadi.
Follow-up: Cache stampede (thundering herd) nima va qanday oldini olasiz? (Javob: cache bir vaqtda tugab, ko'p so'rov birdan DB'ga urilishi; yechim — lock/mutex, jitter bilan TTL, yoki oldindan yangilash (refresh-ahead).)
S39: [] 12-Factor App metodologiyasi nima? (Middle)
Ta'rif: 12-Factor App — bulutga mos (cloud-native), kengaytiriladigan va barqaror SaaS ilovalarni qurish uchun o'n ikkita tamoyildan iborat metodologiya.
Mexanizm (chuqur): Asosiy tamoyillar: Codebase (bitta kod, ko'p deploy), Dependencies (aniq e'lon qilingan), Config (muhitda, kodda emas), Backing services (DB, cache — almashtiriladigan resurs), Build/release/run (aniq ajratilgan bosqichlar), Processes (stateless — holat tashqarida saqlanadi), Port binding, Concurrency (process orqali gorizontal scaling), Disposability (tez ishga tushish/to'xtash), Dev/prod parity (muhitlar o'xshash), Logs (event oqimi sifatida), Admin processes. Bu tamoyillar ilovani container va cloud muhitiga tabiiy moslashtiradi.
// Yomon: config kodda qattiq yozilgan
const db = connect("postgres://admin:pass123@prod-db:5432/app");
// Yaxshi: config muhit o'zgaruvchisidan (Factor III)
const db = connect(process.env.DATABASE_URL);
// Stateless process (Factor VI): session xotirada emas, Redis'da
app.use(session({
store: new RedisStore({ client: redisClient }), // holat tashqarida
secret: process.env.SESSION_SECRET,
}));Keng tarqalgan xato: Session yoki fayllarni process xotirasi/local diskda saqlash (stateful). Bunda ilovani gorizontal scale qilib bo'lmaydi — foydalanuvchi boshqa instance'ga tushsa holatini yo'qotadi. Holat tashqi service'da (Redis, S3, DB) bo'lishi kerak.
Follow-up: Nima uchun config kodda emas, muhitda bo'lishi kerak? (Javob: bir xil build'ni turli muhitlarda (dev/staging/prod) o'zgarishsiz ishlatish, maxfiy ma'lumotni koddan ajratish uchun.)
S40: [] Coupling va cohesion nima va yaxshi dizayn qanday bo'lishi kerak? (Senior)
Ta'rif: Coupling — modullar orasidagi bog'liqlik darajasi. Cohesion — bitta modul ichidagi elementlarning bir maqsadga qanchalik yaqinligi. Yaxshi dizayn — past coupling, yuqori cohesion.
Mexanizm (chuqur): Yuqori coupling'da bir modulni o'zgartirish boshqalarni buzadi — tizim mo'rt (fragile) va tushunish qiyin bo'ladi. Past coupling'da modullar bir-biridan mustaqil, interface orqali aloqa qiladi. Yuqori cohesion'da modul ichidagi hamma narsa bitta aniq vazifaga xizmat qiladi (SRP bilan bog'liq); bu modulni tushunish, qayta ishlatish va test qilishni osonlashtiradi. Bu ikki tushuncha yaxshi arxitekturaning o'lchov mezoni hisoblanadi.
// Yuqori coupling: OrderService PaymentService ichki detaliga bog'liq
class OrderService {
process(order) {
const payment = new StripePayment();
payment.stripeApiKey = "sk_..."; // ichki detalga kirish
payment.chargeViaStripe(order.total); // aniq implementatsiyaga bog'liq
}
}
// Past coupling: interface orqali, detallar yashirin
class OrderService2 {
constructor(paymentGateway) { // abstraksiyaga bog'liq
this.payment = paymentGateway;
}
process(order) {
this.payment.charge(order.total); // faqat interface
}
}
// Yuqori cohesion: class faqat buyurtma bilan bog'liq ishlarni qiladi
class Order {
addItem(item) { /* ... */ }
removeItem(item) { /* ... */ }
calculateTotal() { /* ... */ }
// email yuborish, DB saqlash — bu yerda EMAS
}Keng tarqalgan xato: Kodni ko'plab kichik fayllarga bo'lishni past coupling deb o'ylash. Aslida fayllar ko'p bo'lsa ham, ular bir-biriga qattiq bog'langan bo'lishi mumkin. Coupling — bu bog'liqlik tabiati, fayl soni emas.
Follow-up: DRY prinsipini haddan tashqari qo'llash coupling'ga qanday zarar yetkazadi? (Javob: har bir o'xshash kodni majburan birlashtirish (noto'g'ri abstraksiya) bir-biriga aloqasi yo'q modullarni bog'lab qo'yadi; ba'zan biroz takrorlash noto'g'ri abstraksiyadan yaxshiroq.)
Eng ko'p so'raladigan 10 savol
Quyidagi savollar amaliy intervyularda eng tez-tez uchraydi. Ularga puxta tayyorgarlik ko'ring:
Docker image va container o'rtasidagi farq nima? (S1) — Deyarli har bir DevOps suhbatining boshlanishi. Immutable shablon va uning jonli namunasi.
Multi-stage build nima uchun kerak? (S3) — Image hajmini kamaytirish va xavfsizlik haqidagi tushunchani ko'rsatadi.
Kubernetes'da Deployment, ReplicaSet va Pod munosabati qanday? (S8) — Self-healing va rolling update tushunchasini tekshiradi.
CI va CD farqi nima? (S11) — Har qanday darajadagi nomzoddan so'raladi.
SOLID tamoyillarini kod bilan tushuntiring, ayniqsa SRP va DIP. (S24, S28) — Arxitektura savollarining o'zagi.
Dependency Injection nima va nima uchun foydali? (S34) — Testlash va toza dizayn bilan bevosita bog'liq.
Monolith va microservices trade-off'lari qanday? (S35) — Senior darajaning asosiy savoli; "microservices har doim yaxshi" tuzoq'iga tushmang.
Caching strategiyalari va cache invalidation muammosi. (S38) — Performance va real muammolarni tushunishni ko'rsatadi.
HTTPS/TLS qanday ishlaydi va sertifikat nima uchun kerak? (S22) — Xavfsizlik asoslari.
Nginx reverse proxy va load balancing qanday ishlaydi? (S14, S15) — Deployment amaliyotining amaliy qismi.
Maslahat: Intervyuga tayyorlanayotganda faqat ta'riflarni yodlamang — har bir tushunchani nima uchun kerakligini, qanday muammoni yechishini va qachon ishlatmaslik kerakligini tushuning. Senior darajadagi nomzodni ajratib turadigan narsa — trade-off'larni ko'ra bilish va "hamma joyda bir xil yechim" tuzog'iga tushmaslik. Amaliy tajriba — har bir tushunchani o'z qo'lingiz bilan sinab ko'rish — nazariy bilimdan ko'ra qimmatliroq.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!