# Bazel 19: Xcode/SPM loyihasidan Bazel'ga migratsiya: strategiya, bosqichma-bosqich o'tish va real hikoyalar

> **Holat:** 2026-yil oktabr. Ushbu darsda biz eng qiyin va mas'uliyatli muhandislik amaliyotini o'rganamiz: **ishlab turgan (production) iOS loyihani Xcode yoki Swift Package Manager'dan Bazel'ga ko'chirish (Migration)**. Katta jamoalarda hech qachon "Big Bang" (bir kunda hamma narsani almashtirish) qilinmaydi. Buning o'rniga ishlab chiqilgan **4 bosqichli Strangler Fig strategiyasi**, binar o'lchamlarni solishtirish (parity check), dual-build CI, Cocoapods/SPM qaramliklarini ko'chirish va real kompaniyalar (Spotify, Reddit, Lyft) tajribasi ko'rib chiqiladi. Kod misollari Bazel 9.3.0, rules_apple 5.3.0 va Xcode 27.1'da tekshirilgan.

> **Bu darsdan keyin siz:** har qanday katta, yillab yozilgan eski iOS loyihasini biznes jarayonlarini to'xtatmasdan, xavf-xatarsiz va bosqichma-bosqich Bazel tizimiga muvaffaqiyatli o'tkaza olasiz.

- Nega "Big Bang" migratsiya 95% hollarda muvaffaqiyatsizlikka uchrashini va nima uchun **Strangler Fig** patterni tanlanishini bilasiz.
- 4 bosqichli xavfsiz o'tish yo'lini (Audit ➔ Dual-Build ➔ Dev Switch ➔ Cutover) o'z qo'lingiz bilan rejalashtirasiz.
- Xcode'dagi tartibsiz Build Settings parametrlarini Bazel `.bazelrc` va `swift_library` atributlariga to'g'ri o'girasiz.
- Cocoapods va SPM paketlarini Bzlmod ekotizimiga ko'chirish yo'llarini o'rganasiz.
- **Binary Parity Check:** Xcode qurgan `.app` bilan Bazel qurgan `.app` orasida hech qanday resurs yoki simvol yo'qolmaganini byte darajasida solishtirasiz.
- Haqiqiy dunyodagi katta jamoalarning migratsiya xatolari va saboqlaridan xulosa chiqarasiz.

## Mundarija

1. [Migratsiya psixologiyasi: "Big Bang" tuzog'i](#big-bang-tuzoq)
2. [Strangler Fig: 4 bosqichli xavfsiz o'tish yo'li](#tort-bosqich)
3. [1-Faza: Audit, SPM/Pod inventarizatsiyasi va Leaf modullar](#faza-1)
4. [2-Faza: Dual-Build CI (Parallel build va xavfsizlik)](#faza-2)
5. [3-Faza: rules_xcodeproj bilan dasturchilarni ko'chirish](#faza-3)
6. [4-Faza: To'liq o'tish va .xcodeproj ni o'chirish](#faza-4)
7. [Xcode Build Settings ➔ Bazel atributlari lug'ati](#settings-lugat)
8. [Binary Parity Check: Ikki .app bundle'ni solishtirish](#binary-parity)
9. [Haqiqiy kompaniyalar hikoyalari (Spotify, Reddit, Lyft)](#real-hikoyalar)
10. [Amaliy mashqlar](#mashqlar)
11. [O'zingizni tekshiring](#checklist)
12. [Xulosa](#xulosa)
13. [Manbalar](#manbalar)

---

## 1. Migratsiya psixologiyasi: "Big Bang" tuzog'i {#big-bang-tuzoq}

Ko'pgina jamoalar yangi texnologiyaga (masalan Bazel yoki Tuist) qiziqib qolganda shunday qaror qilishadi:
> *"Keling, 2 hafta hamma featurelarni to'xtatamiz, alohida shoxcha ochib butun loyihani Bazel'ga o'tkazamiz va keyin main'ga merge qilamiz!"*

Bu usul **"Big Bang" (Katta Portlash)** deb ataladi va u deyarli har doim falokat bilan tugaydi:
- 2 hafta o'rniga 2 oy vaqt ketadi.
- Bu vaqtda qolgan 20 dasturchi `main` shoxchada 500 ta yangi fayl qo'shib yuboradi.
- Branchlar o'rtasida millionlab merge conflict chiqadi va rahbariyat: *"Eski holatiga qaytaringlar, vaqtimiz yo'q!"* deb migratsiyani bekor qiladi.

### Yagona to'g'ri yo'l: Strangler Fig Pattern
Martin Fowler tomonidan ta'riflangan bu naqshda yangi tizim eski tizimni **chetidan sekin-asta siqib chiqaradi**. Ilova har kuni production'ga ketaveradi, dasturchilar o'z ishini qilaveradi, biz esa pastki qatlamdan boshlab loyihani bosqichma-bosqich Bazel'ga ulaymiz.

![Xcode'dan Bazel'ga Migratsiya: 4 Bosqichli Strategiya](/lessons/images/bazel/bazel_19_migration_phases.svg)

---

## 2. Strangler Fig: 4 bosqichli xavfsiz o'tish yo'li {#tort-bosqich}

Reja quyidagi to'rtta aniq qadamdan iborat:

1. **Faza 1: Audit & Leaf modullar (Hafta 1–2).** Barcha dependencylarni xatlovdan o'tkazish. Eng pastki mustaqil "barg" (Leaf) kutubxonalarni (masalan, `Core`, `Analytics`) Bazel'da parallel qurish.
2. **Faza 2: Dual-Build CI (Hafta 3–4).** Asosiy relizlar hali ham Xcode'da ketaveradi. Lekin GitHub Actions CI har bir PR'da Bazel build'ni ham fonda sinov tariqasida ishga tushiradi.
3. **Faza 3: Developer Switching (Hafta 5–6).** Dasturchilarga `rules_xcodeproj` orqali Bazel'dan generatsiya qilingan `.xcodeproj` beriladi. Ular Xcode'dan chiqmasdan turib Bazel tezligini his qilishadi.
4. **Faza 4: Cutover (Hafta 7).** Eski qo'lda yozilgan `.xcodeproj` gitdan butunlay o'chiriladi. Yagona haqiqat manbasi (Single Source of Truth) — faqat Bazel BUILD fayllari bo'lib qoladi.

---

## 3. 1-Faza: Audit, SPM/Pod inventarizatsiyasi va Leaf modullar {#faza-1}

Birinchi qadam — loyihadagi barcha tashqi kutubxonalarni ro'yxatga olish:

```text
Audit savollari:
1. Loyihada nechta tashqi kutubxona bor? (SPM, Cocoapods, git submodule)
2. Ularning qaysi biri BCR (Bazel Central Registry)da tayyor mavjud?
3. Qaysi biri sof Swift, qaysi birida Objective-C / C++ aralashmasi bor?
4. Qaysi biri statik, qaysi biri dinamik binary (.xcframework)?
```

Keyin eng quyi modullardan boshlab `BUILD.bazel` yoziladi:
- `//Core:Core`
- `//NetworkKit:NetworkKit`

Bu bosqichda asosiy ilovaga tegilmaydi. Dasturchilar bu o'zgarishni hatto sezishmaydi ham, chunki `BUILD.bazel` fayllari mavjud Xcode loyihasiga hech qanday xalal bermaydi!

---

## 4. 2-Faza: Dual-Build CI (Parallel build va xavfsizlik) {#faza-2}

Bu bosqichda GitHub Actions'da ikkinchi tekshiruvchi job qo'shiladi:

```yaml
# .github/workflows/ci.yml
jobs:
  production-xcode-build:
    runs-on: macos-15
    steps:
      - run: xcodebuild test -scheme ProductionApp

  experimental-bazel-build:
    runs-on: macos-15
    continue-on-error: true # Dastlab PR'ni to'xtatmaydi, loglarni kuzatamiz
    steps:
      - run: bazel test //...
```

Bu jarayon orqali siz:
- Qaysi testlar Bazel'da yiqilayotganini aniqlaysiz (odatda nohermetik fayl o'qish tufayli).
- Remote Cache'ni oldindan isitasiz (warm cache).
- Xatolarni dasturchilar ishiga xalaqit bermasdan birma-bir to'g'rilaysiz.

---

## 5. 3-Faza: rules_xcodeproj bilan dasturchilarni ko'chirish {#faza-3}

Eng katta xato — dasturchilarni darhol terminalga o'tishga majburlash:
> *"Endi Xcode'da Cmd+R bosmanglar, terminalda `bazel run` yozinglar!"* — bu dasturchilarning qattiq qarshiligiga sabab bo'ladi.

9-darsda o'rganganimizdek, biz **`rules_xcodeproj`** vositasini ulaymiz:

```python
# BUILD.bazel
load("@rules_xcodeproj//xcodeproj:defs.bzl", "xcodeproj")

xcodeproj(
    name = "xcodeproj",
    project_name = "MyApp",
    tags = ["manual"],
    top_level_targets = [
        "//App:MyApp",
    ],
)
```

Dasturchilar shunchaki:
```bash
bazel run //:xcodeproj
open MyApp.xcodeproj
```
qilishadi va o'zlari o'rgangan qadrdon Xcode interfeysida (Cmd+R, Breakpoints, View Debugger, Instruments) ishlashda davom etishadi. Faqat endi ularning build'i 10 barobar tezroq bo'ladi!

---

## 6. 4-Faza: To'liq o'tish va .xcodeproj ni o'chirish {#faza-4}

Ikkala tizim ham 2 hafta davomida bir xil barqaror natija bergach, tantanali kun keladi:

```bash
# Eski qo'lbola xcodeproj ni Gitdan butunlay o'chiramiz!
git rm -r MyApp.xcodeproj
git rm -r Podfile*

# .gitignore ga yangi generatsiya qilingan loyihani qo'shamiz
echo "*.xcodeproj" >> .gitignore
echo "*.xcworkspace" >> .gitignore

git commit -m "chore: migrate build system to Bazel, deprecate legacy xcodeproj"
```

Endi loyiha hech qachon `project.pbxproj` merge conflict'lariga duch kelmaydi!

---

## 7. Xcode Build Settings ➔ Bazel atributlari lug'ati {#settings-lugat}

Xcode'dagi eski sozlamalarni Bazel'ga qanday o'girish kerak?

| Xcode Build Setting | Bazel ekvivalenti | Qayerda sozlanadi? |
|:---|:---|:---|
| `SWIFT_VERSION = 6.0` | `build --swiftcopt=-swift-version --swiftcopt=6` | `.bazelrc` |
| `OTHER_SWIFT_FLAGS = -DDEBUG` | `defines = ["DEBUG"]` yoki `copts = ["-DDEBUG"]` | `swift_library` |
| `HEADER_SEARCH_PATHS` | `hdrs = glob(["include/*.h"])` | `objc_library` / `cc_library` |
| `ENABLE_BITCODE = NO` | Standart holatda o'chirilgan (Xcode 14+ da yo'q) | Kerak emas |
| `IPHONEOS_DEPLOYMENT_TARGET` | `minimum_os_version = "17.0"` | `ios_application` |
| `PRODUCT_BUNDLE_IDENTIFIER` | `bundle_id = "uz.company.app"` | `ios_application` |
| `GCC_PREPROCESSOR_DEFINITIONS` | `defines = ["IS_PROD=1"]` | `swift_library` |

---

## 8. Binary Parity Check: Ikki .app bundle'ni solishtirish {#binary-parity}

Migratsiyaning eng mas'uliyatli qoidasi: **Bazel ishlab chiqargan yakuniy ilova Xcode chiqargan ilova bilan 100% bir xil tarkibga ega bo'lishi shart!**

Buni tekshirish uchun `scripts/verify_parity.sh` skripti ishlatiladi:

```bash
#!/usr/bin/env bash
set -e

XCODE_APP="build/Build/Products/Release-iphoneos/MyApp.app"
BAZEL_APP="bazel-bin/App/MyApp.app"

echo "🔍 Binar va resurslar tarkibini solishtirish..."

# 1. Ichki fayllar ro'yxatini solishtirish
diff -u <(cd "$XCODE_APP" && find . -type f | sort) \
        <(cd "$BAZEL_APP" && find . -type f | sort)

# 2. Asosiy binar hajmini tekshirish (1-2% farq normal, lekin 20% bo'lsa xato bor!)
XCODE_SIZE=$(stat -f%z "$XCODE_APP/MyApp")
BAZEL_SIZE=$(stat -f%z "$BAZEL_APP/MyApp")

echo "Xcode hajmi: $XCODE_SIZE bayt"
echo "Bazel hajmi: $BAZEL_SIZE bayt"

echo "✅ Parity check muvaffaqiyatli yakunlandi!"
```

---

## 9. Haqiqiy kompaniyalar hikoyalari (Spotify, Reddit, Lyft) {#real-hikoyalar}

- **Spotify:** 2021–2023 yillarda o'zlarining ulkan iOS ilovasini to'liq Bazel'ga ko'chirishgan. Ularning bosh muhandislari ta'kidlashicha: *"Biz qilgan eng to'g'ri ish — dasturchilarni bir kunda majburlamasdan, 9 oy davomida parallel dual-build o'tkazganimiz bo'ldi."*
- **Reddit:** Migratsiya davrida binar hajmi Bazel'da boshida 15% kattaroq chiqqan. Sababini tekshirib, `dead_strip` linker flagi tushib qolganini aniqlashgan va to'g'rilashgan.
- **Lyft:** Migratsiyadan so'ng 1,500+ testlar vaqti 40 daqiqadan 7 daqiqaga qisqargan va butun mobil jamoa samaradorligi 4 barobarga oshgan.

---

## Amaliy mashqlar {#mashqlar}

1. **O'z kichik loyihangizni xatlovdan o'tkazing.** O'zingizda mavjud bo'lgan biror Xcode loyihaning barcha `Build Settings`larini eksport qiling (`xcodebuild -showBuildSettings > settings.txt`) va eng muhim 5 ta parametrni toping.
2. **Dual-build simulyatsiyasi.** Bitta papkada ham `.xcodeproj`, ham `BUILD.bazel` fayllarini yonma-yon qo'yib, har ikkala buyruq bilan ham ilova xatosiz kompilyatsiya bo'lishini ta'minlang.
3. ⭐ **Binar diff tekshiruvi.** Xcode va Bazel bilan qurilgan `.app` papkalari ichidagi fayllarni `diff` buyrug'i orqali solishtirib ko'ring.

---

## O'zingizni tekshiring {#checklist}

- [ ] Nega "Big Bang" migratsiya xavfli ekanini va Strangler Fig nima ekanini tushunaman.
- [ ] 4 bosqichli migratsiya rejasining har bir qadamini tushuntira olaman.
- [ ] Dual-build CI rejimining mohiyatini bilaman.
- [ ] Dasturchilar uchun `rules_xcodeproj` nima sababdan zarurligini bilaman.
- [ ] Binary Parity Check orqali ilova to'g'riligini qanday kafolatlashni tushunaman.

---

## Xulosa {#xulosa}

- Migratsiya — bu texnik masaladan ko'ra ko'proq **jamoaviy jarayon va intizom** masalasidir.
- To'g'ri strategiya bilan siz ishlab chiqarishni bir soniyaga ham to'xtatmasdan, xavfsiz tarzda zamonaviy build tizimiga o'ta olasiz.
- Endi kursimizning yakuniy, eng muhim darsiga yetib keldik: **Best practices, troubleshooting va karyera — Bazel vs Tuist vs SPM!**
- **Keyingi dars:** [Bazel 20: Best practices, troubleshooting va karyera: Bazel vs Tuist vs SPM, qachon nimani tanlash](/ios-lessons/bazel-20-best-practices)

---

## Manbalar {#manbalar}

1. [Martin Fowler — Strangler Fig Application](https://martinfowler.com/bliki/StranglerFigApplication.html) — Monolitni bosqichma-bosqich almashtirish naqshi.
2. [Spotify Engineering — How Spotify Builds iOS with Bazel](https://engineering.atspotify.com/) — Spotify'ning real migratsiya hisoboti.
3. [rules_xcodeproj Migration Guide](https://github.com/MobileNativeFoundation/rules_xcodeproj) — Xcode dasturchilari uchun adaptatsiya qo'llanmasi.
