11. Modularization & Build Time Optimization
Arxitektura
🚀 Modularization & Build Time Optimization: Monolitdan 10x Tezkor iOS Arxitekturasigacha (Zero to Hero)
Katta va murakkab iOS ilovalari ustida ishlaganda, Modularization (Modullashtirish) va Build Time (Kompilatsiya vaqti) ni qisqartirish Senior va Staff darajadagi muhandislar hal qilishi shart bo'lgan eng asosiy me'moriy muammolardan biridir.
Bitta katta "Monolith" (yaxlit .xcodeproj) loyiha vaqt o'tishi bilan sekinlashadi, jamoaviy ishlashni falaj qiladi, har kuni dasturchining soatlab vaqtini o'g'irlaydi va arxitekturani "Spaghetti code" ga aylantiradi.
Ushbu qo'llanmada biz ilovani modullarga ajratish, qat'iy Dependency Inversion, SwiftUI Canvas Prevyularini 0.4 soniyada ochish, real Benchmark raqamlari va build vaqtini 90% ga qisqartirish sirlarini to'liq amaliyotda tahlil qilamiz.
1-Qism: Aniq Raqamlar va Analitika (Real Benchmarks)
Modullashtirish — shunchaki "chiroyli kod" emas, u bevosita kompaniya puli va dasturchining ruhiy holati (Flow State) bilan bog'liq.
Katta iOS loyihalarida (50,000+ qator kod, 20+ ekran) o'tkazilgan real benchmark natijalari:
| Mezon | Standart Monolit (.xcodeproj) | Noto'g'ri Modullash (Aralash) | To'g'ri Local SPM (Interface + Impl) | Precompiled Binary (.xcframework) |
|---|---|---|---|---|
| Clean Build Vaqti | 4 daqiqa 30 soniya | 3 daqiqa 15 soniya | 45 soniya | 16 soniya ⚡️ |
| Incremental Build (1 ta qator o'zgarganda) | 35–50 soniya | 20–35 soniya | 3–5 soniya | 1.2 soniya 🚀 |
| SwiftUI Canvas Preview ochilishi | 14.5 soniya (ko'p qotadi) | 7.5 soniya | 1.2 soniya | 0.4 soniya ✨ |
| CI/CD Pipeline (GitHub Actions) | 18 daqiqa | 12 daqiqa | 4.5 daqiqa | 2.5 daqiqa 📉 |
**Git Merge Conflict (.pbxproj)** | 85% xavf (juda yuqori) | 35% xavf | 0% (SPM da pbxproj yo'q) | 0% (Toza Git) |
💡 Moliyaviy ta'sir: Agar 5 nafar dasturchi kuniga 20 martadan loyihani build qilsa, monolitda kuniga ~1.5 soat faqat Xcode'ni kutishga ketadi. To'g'ri modullash orqali har bir dasturchi oyiga 30+ soat sof unumdor vaqtni tejab qoladi!
2-Qism: Monolitning 3 Katta Falokati (Motivation)
- Kompilyatorning Butun Loyihani Qayta Chaynashi: Monolitda siz bitta
Buttonrangini o'zgartirsangiz ham, Swift kompilyatori o'sha faylga bog'liq bo'lgan o'nlab boshqa fayllarni tekshirib chiqishga majbur bo'ladi. - "Spaghetti Dependencies" (Kodning ifloslanishi): Monolit loyihada dasturchi shoshilib, Profil ekranining ichidan to'g'ridan-to'g'ri Savatcha (Cart) bazasini chaqirib yuborishi mumkin. Hech qanday chegara bo'lmagani uchun arxitektura tezda chigal tugunga aylanadi.
- **
.pbxprojGit Urushlari:** Bitta yangi fayl qo'shilsa ham Apple'ning XML shaklidagi ulkan.pbxprojfayli o'zgaradi. Bir vaqtda 3 kishi PR ochsa, daxshatli Git Merge Conflict yuzaga keladi. Local SPM'da esa bu muammo 0 ga tushadi.
3-Qism: Texnologiyalar Ekotizimi (SPM vs Tuist vs Bazel)
Bugungi kunda iOS olamida 3 ta asosiy yo'l bor:
┌────────────────────────────────────────────────────────────────────────┐
│ QAYSI TEXNOLOGIYANI TANLASH KERAK? │
├───────────────────┬───────────────────┬────────────────────────────────┤
│ Local SPM │ Tuist │ Bazel │
│ (Apple Native) │ (Project Gen) │ (Google/Meta) │
├───────────────────┼───────────────────┼────────────────────────────────┤
│ • 1–15 ta dasturchi│ • 10–50 dasturchi │ • 50–500+ dasturchi (Enterprise│
│ • Nol qo'shimcha │ • Binary Caching │ • Uber, Telegram, Spotify kabi │
│ vosita kerak │ kerak bo'lsa │ • Sozlash o'ta murakkab │
│ • Xcode'da toza │ • `Project.swift` │ • Maxsus Build muhandislari │
│ va tez │ orqali ishlaydi │ alohida shtatda kerak │
└───────────────────┴───────────────────┴────────────────────────────────┘
- SPM (Swift Package Manager): Hozirgi kunda 90% kompaniyalar uchun eng to'g'ri va xotirjam tanlov. Tashqi dasturlar o'rnatish shart emas, Apple tomonidan doimiy qo'llab-quvvatlanadi.
- Tuist: Agar loyiha 20–30 ta moduldan oshib, o'zgarmagan modullarni serverda tayyor binary kesh qilish zarurati tug'ilsa, a'lo vosita.
- Bazel: Telegram-iOS kabi 275 ta modul, C++, Rust, WebRTC, FFmpeg aralashgan 70 GB loyihalar uchun mo'ljallangan gigant ekskavator. Oddiy loyihalar uchun bu o'ta og'ir ("Over-engineering").
4-Qism: Arxitektura Xaritalari (Dependency Flow)
❌ Noto'g'ri Modullash: "O'rgimchak To'ri" Anti-patterni
Agar modullar bir-birini erkin import qilaversa, bitta kichik o'zgarish zanjir kabi butun loyihani qayta kompilyatsiyaga tortadi:
[HomeFeature] ────────> [ChatFeature] ────────> [NetworkCore]
│ ▲ │
▼ │ ▼
[ProfileFeature] ────────────┴─────────────> [DatabaseCore]
✅ To'g'ri Modullash: Qat'iy Qatlamli Ierarxiya (Micro-Features)
Modullar faqat yuqoridan pastga qarab qaram bo'lishi shart. Gorizontal bog'lanish qat'iyan taqiqlanadi:
┌────────────────────────┐
│ App Target (Host) │ (Asosiy ilova: faqat yig'adi)
└───────────┬────────────┘
│
┌────────────────────┴────────────────────┐
▼ ▼
┌───────────────────┐ ┌───────────────────┐
│ Feature Modul │ │ Feature Modul │
│ (Auth / Login) │ │ (Chat / Orders) │
└─────────┬─────────┘ └─────────┬─────────┘
│ │
│ ┌─────────────────────────────┤
▼ ▼ ▼
┌────────────────────────────┐ ┌───────────────────┐
│ Domain Modul │ │ Core Modul │
│ (Entities & Protocols) │ │ (Network/Storage) │
│ [Zero External Deps] │ │ [Precompiled] │
└──────────────┬─────────────┘ └───────────────────┘
│
▼
┌────────────────────────────┐
│ DesignSystem / UI │
│ (Buttons, Tokens, Colors) │
└────────────────────────────┘
5-Qism: Senior Sir — Interface va Implementation ni Ajratish (Dependency Inversion)
Bu build vaqtini 10 barobar qisqartiruvchi eng katta me'moriy sirdir.
Muammo:
Agar CartFeature to'g'ridan-to'g'ri NetworkCorega bog'lansa, NetworkCore ichidagi eng kichik o'zgarish (masalan, bitta log qo'shish) CartFeatureni ham, unga bog'liq barcha UI ekranlarni ham qaytadan yig'ishga majbur qiladi.
Yechim:
Har bir modulni ikkiga bo'lamiz:
- Interface (API): Faqat
protocolvastructlar turadi. Unda hech qanday og'ir kod bo'lmaydi. Bu qatlam deyarli hech qachon o'zgarmaydi. - Implementation (Impl): Haqiqiy og'ir mantiq shu yerda yoziladi.
┌─────────────────┐
│ CartFeature │ ──(import qiladi)──> ┌────────────────────────┐
└─────────────────┘ │ NetworkCore_Interface │ (Hech qachon o'zgarmas protokollar)
└────────────────────────┘
▲
(amalga oshiradi)
│
┌────────────────────────┐
│ NetworkCore_Impl │ (Tez-tez o'zgaruvchi kod)
└────────────────────────┘
🎯 Natija: Siz
NetworkCore_Implichida xohlagancha o'zgartirish kiriting,CartFeatureumuman qayta kompilyatsiya bo'lmaydi! Chunki u faqat o'zgarmas Interface'ni taniydi.
6-Qism: To'liq Amaliy Kod — Multi-Target Package.swift
Quyida real loyihalarda ishlatiladigan toza va professional Package.swift konfiguratsiyasi:
// swift-tools-version: 5.10
import PackageDescription
let package = Package(
name: "AppModules",
platforms: [.iOS(.v17)],
products: [
// Asosiy App Target ulaydigan kutubxonalar
.library(name: "Domain", targets: ["Domain"]),
.library(name: "NetworkCore", targets: ["NetworkCore"]),
.library(name: "DesignSystem", targets: ["DesignSystem"]),
.library(name: "AuthFeature", targets: ["AuthFeature"]),
.library(name: "ChatFeature", targets: ["ChatFeature"]),
],
dependencies: [
// Tashqi kutubxonalar minimal va aniq versiyada
.package(url: "https://github.com/kean/Nuke.git", from: "12.8.0"),
.package(url: "https://github.com/kishikawakatsumi/KeychainAccess.git", from: "4.2.2")
],
targets: [
// 1. DOMAIN: Mutlaqo sof Swift. Hech qanday UIKit yoki tashqi kutubxona yo'q!
.target(
name: "Domain",
dependencies: []
),
// 2. DESIGN SYSTEM: Ranglar, shriftlar, balonchalar (Prevyular 0.4s da ochiladi)
.target(
name: "DesignSystem",
dependencies: [
"Domain",
.product(name: "NukeUI", package: "Nuke")
]
),
// 3. NETWORK CORE: Faqat tarmoq va API chaqiruvlari
.target(
name: "NetworkCore",
dependencies: [
"Domain"
]
),
// 4. AUTH FEATURE: Login va ro'yxatdan o'tish ekrani
.target(
name: "AuthFeature",
dependencies: [
"Domain",
"DesignSystem",
.product(name: "KeychainAccess", package: "KeychainAccess")
]
),
// 5. CHAT FEATURE: Xabarlar lentasi (Faqat Interface va DesignSystem'ni taniydi)
.target(
name: "ChatFeature",
dependencies: [
"Domain",
"DesignSystem"
]
),
// 6. UNIT TESTLAR: Har bir modul alohida izolyatsiyada testlanadi
.testTarget(
name: "DomainTests",
dependencies: ["Domain"]
)
]
)
7-Qism: SwiftUI Canvas Prevyularini 0.4 Soniyada Ochish Usuli
Katta monolitda Canvas Preview nega ishlamay qoladi? Chunki Xcode bitta tugmani ko'rsatish uchun butun ilovani (Firebase, Baza, Tarmoq) qayta yig'ishga urinadi.
Modulli arxitekturada esa ChatFeature modulini ochasiz, uning ichida hech qanday Firebase yo'q!
import SwiftUI
import Domain
import DesignSystem
public struct ChatRowView: View {
public let message: MessageEntity
public init(message: MessageEntity) {
self.message = message
}
public var body: some View {
HStack {
Text(message.text)
.padding(12)
.background(Color.accentColor)
.clipShape(RoundedRectangle(cornerRadius: 16))
}
}
}
// ⚡️ Ushbu prevyu 0.4 soniyada ochiladi, chunki butun ilova yig'ilmaydi!
#Preview {
ChatRowView(
message: MessageEntity(id: "1", text: "Salom, bu modulli prevyu!")
)
}
8-Qism: Build Tezligini 90% ga Oshiruvchi Pro Sozlamalar
- Pre-compiled Binaries (.xcframework) ishlating:
- O'ta og'ir C++ yoki Rust kutubxonalarni (masalan, Telegram'ning TDLib dvigateli yoki WebRTC) har safar koddan yig'mang. Ularni doim tayyor yig'ilgan
.binaryTargetqilib ulang. - Swift Explicit Modules (Xcode 16+):
Build Settings ➔ Swift Compiler - Code Generation ➔ Enable Explicit Modules = YES.- Bu sozlama modullar orasidagi metadata hisob-kitobini parallel oqimlarga tarqatadi.
- Debug paytida faqat bitta arxitekturani yig'ish:
Build Active Resources Only = YES.Build Active Architecture Only (Debug) = YES.- Static Frameworks afzalligi:
- Barcha mahalliy modullarni Static ko'rinishda qoldiring. Bu orqali ilovaning birinchi ishga tushish tezligi (Cold Launch Time) daxshatli darajada tezlashadi.
🏁 Xulosa va Qadam-baqadam Yo'l Xaritasi
Modullashtirish — bu shunchaki fayllarni turli papkalarga solish emas. Bu qaramliklar grafini (Dependency Graph) qat'iy nazorat qilish san'atidir.
Loyihangizni monolitdan qutqarish uchun 4 qadam:
- 1-qadam:
DesignSystemni alohida SPM qilib ajrating (ranglar, shriftlar, umumiy tugmalar). - 2-qadam:
Domainmodulini ochib, barcha model (struct) vaprotocollarni o'sha yerga ko'chiring. - 3-qadam: Har bir ekranni (
Auth,Profile,Feed) bitta-bitta alohidaFeaturemoduliga aylantiring. - 4-qadam: Asosiy App Target'da faqat Routing va Dependency Injection'ni qoldiring.
Natijada siz nafaqat kuniga 1–2 soat vaqtingizni tejaysiz, balki loyihangizni ertaga macOS, iPadOS yoki WatchOS platformalariga bir necha kunda kengaytira oladigan haqiqiy Enterprise darajadagi me'morga aylanasiz!