Clean Architecture — asoslari, Entities, Use Cases va Gateways qatlamlari

Muallif: IT Sectr Nashr etilgan: 2026-02-17 O'qish vaqti: 10 daq

Clean Architecture — 2012-yilda Robert Martin (Uncle Bob) tomonidan taklif qilingan, ilovani mustaqil qatlamlarga ajratuvchi ko'p qatlamli arxitektura: Domain (Entities, Use Cases), Data (Repositories, DataSources) va Presentation (ViewModels, Views). Asosiy prinsip — Dependency Rule: bog'liqliklar ichkariga yo'naltirilgan, tashqi qatlamlar ichki qatlamlarga bog'liq, aksincha emas. Clean Architecture yuqori murakkablikdagi biznes mantiqiga ega loyihalar uchun mobil ishlab chiqishda qo'llaniladi. Batafsil — The Clean Architecture kitobida.

Asosiy fikrlar

  • Clean Architecture — uch qatlam: Domain (biznes mantiq), Data (ma'lumotlar), Presentation (UI) Dependency Rule bilan
  • Dependency Rule — bog'liqliklar ichkariga yo'naltirilgan, Domain Data va Presentation haqida bilmaydi
  • Use Cases (Interactors) — biznes mantiq ssenariylari, har bir Use Case — bitta metodli bitta sinf
  • Repository Interface — Domainda ma'lumot abstraksiyasi, Data qatlamida amalga oshirish
  • Sinovdan o'tkazish — Domain va Use Cases Android SDK va iOS UIKit siz unit testlar bilan tekshiriladi

Clean Architecture — ko'p qatlamli arxitektura asoslari

Clean Architecture — 2012-yilda Robert Martin (Uncle Bob) tomonidan shakllantirilgan arxitektura namunasi. Asosiy g'oya — ilonani qat'iy bog'liqlik qoidasi bilan qatlamlarga bo'lish: qatlam ichidagi kod tashqaridagi kod haqida bilmaydi. Tashqi qatlamlar (UI, freymvorklar, ma'lumotlar bazasi) — amalga oshirish tafsilotlari. Ichki qatlamlar (biznes mantiq, korxona qoidalari) — ilonaning mohiyati.

Clean Architecture qatlamlari mobil ishlab chiqishda: 1) Domain — Entities (biznes obyektlari) va Use Cases (foydalanish ssenariylari); 2) Data — RepositoryImpl (repozitoriylarni amalga oshirish), DataSources (tarmoq, ma'lumotlar bazasi, keshlash); 3) Presentation — ViewModels, Views (Compose/SwiftUI). Domain — bog'liqliklari bo'lmagan eng ichki qatlam. Data Domain ga bog'liq (repozitori interfeyslarini amalga oshiradi). Presentation Domain ga bog'liq (Use Cases ni chaqiradi, natijaga obuna bo'ladi).

QatlamMazmuniBog'liqliklar
DomainEntities, Use Cases, Repository InterfacesYo'q (toza Kotlin/Swift)
DataRepositoryImpl, DataSources (API, DB, Cache)Domain, Retrofit, Room, Ktor
PresentationViewModels, Views, ComposablesDomain, Jetpack, SwiftUI

Dependency Rule — Clean Architecture ning yagona qat'iy qoidasi. Manba kodi faqat o'z ichidagi qatlamga yoki pastdagi qatlamga (markazga yaqinroq) murojaat qilishi mumkin. Presentation Domain ni import qiladi. Domain Data yoki Presentation ni import qilmaydi. Bunga bog'liqliklarni inversiyalash (Dependency Inversion Principle) orqali erishiladi: Domain Repository interfeysini belgilaydi, Data uni amalga oshiradi. Presentation aniq repozitoriyga emas, UseCase abstraksiyasiga bog'liq.

Domain Layer: Entities, Use Cases va Repository Interfaces

Domain — ilonaning eng barqaror qatlami. Entities — freymvorklardan mustaqil biznes obyektlari: User, Product, Order. Use Cases — bitta invoke metodi (yoki Kotlin da operator fun invoke) bo'lgan, bitta ssenariyni amalga oshiruvchi sinflar: GetUserUseCase, PlaceOrderUseCase, CalculateTotalUseCase. Repository Interfaces — Domain da belgilangan, Data da amalga oshiriladigan ma'lumotga kirish abstraksiyalari. Domain Android SDK, iOS UIKit, Retrofit, Room ni o'z ichiga olmaydi — faqat toza Kotlin yoki Swift.

swift
// Entity — biznes obyekti (Domain)
struct User: Equatable {
    let id: Int
    let name: String
    let email: String
}

// Repository Interface — ma'lumot abstraksiyasi (Domain)
protocol UserRepository {
    func getUser(id: Int) async throws -> User
    func getUsers() async throws -> [User]
}

// Use Case — bitta ssenariy (Domain)
final class GetUserUseCase {
    private let repository: UserRepository

    init(repository: UserRepository) {
        self.repository = repository
    }

    func execute(id: Int) async throws -> User {
        return try await repository.getUser(id: id)
    }
}

Use Case — «bitta metodli sinf» — dogma emas, amaliy tavsiya. Use Case murakkablashganda (validatsiya + loglash + repozitoriy chaqiruvi), uning metodlari ma'noga ko'ra guruhlanadi: UserUseCase.getUser, UserUseCase.searchUsers, UserUseCase.deleteUser. Muhimi — Use Case ma'lumotlarning qayerdan kelishini (tarmoq, ma'lumotlar bazasi, keshlash) va kim ko'rsatishini (Compose, SwiftUI) bilmasligi kerak. IT Sectr da biz har bir biznes qoidasi, tekshirish yoki ikki manbadan ma'lumot birlashtirish operatsiyasi uchun Use Case ajratamiz.

Domain ning tozaligi qatlamlar chegarasida DTO xaritalash orqali erishiladi. Data qatlami JSON modellarini (DTO) oladi, ularni Domain Entity ga xaritalaydi. Presentation Domain Entity ni oladi, ViewModel ga (DisplayItem) xaritalaydi. Domain Entity hech qachon Retrofit, Room, Codable annotatsiyalarini o'z ichiga olmaydi — bu ma'lumotlar bazasi Room dan Realm ga yoki Retrofit Ktor bilan almashtirilganda qatlamni o'zgartirish shart emasligini kafolatlaydi.

Data Layer: Repository Implementation va DataSources

Data Layer — Domain da belgilangan interfeyslarni amalga oshirish. RepositoryImpl (UserRepository ni amalga oshiruvchi sinflar) va DataSources (RemoteDataSource — API, LocalDataSource — ma'lumotlar bazasi, CacheDataSource — SharedPreferences/NSUserDefaults) ni o'z ichiga oladi. Data qatlami Domain ga (repozitori interfeyslari va Entities ni import qiladi) va freymvorklarga (Retrofit, Room, Ktor, CoreData) bog'liq. RepositoryImpl Domain dan ma'lumot manbasini yashiradi — Use Case ma'lumotlarning tarmoqdan yoki keshlashdan kelganini bilmaydi.

kotlin
// DTO — tarmoq uchun model (Data)
data class UserDto(
    @SerializedName("id") val id: Int,
    @SerializedName("first_name") val firstName: String,
    @SerializedName("last_name") val lastName: String,
    @SerializedName("email") val email: String
)

// RepositoryImpl — amalga oshirish (Data)
class UserRepositoryImpl(
    private val remoteDataSource: UserRemoteDataSource,
    private val localDataSource: UserLocalDataSource
) : UserRepository {

    override suspend fun getUser(id: Int): User {
        // Keshlashdan olishga harakat qilamiz
        localDataSource.getUser(id)?.let { return it.toDomain() }
        // Agar yo'q bo'lsa — tarmoqdan yuklaymiz
        val dto = remoteDataSource.fetchUser(id)
        val user = dto.toDomain()
        localDataSource.saveUser(user)
        return user
    }

    override suspend fun getUsers(): List<User> {
        return remoteDataSource.fetchAllUsers().map { it.toDomain() }
    }
}

// Mapper — DTO ↔ Domain konvertatsiyasi
fun UserDto.toDomain() = User(
    id = id,
    name = "$firstName $lastName",
    email = email
)

Keshlash strategiyasi Data Layer da: RepositoryImpl avval mahalliy saqlashni tekshiradi, ma'lumot bo'lmasa — tarmoqdan yuklaydi va mahalliy saqlaydi. Tarmoq mavjud bo'lmasa — isStale belgisi bilan eskirgan ma'lumotlarni qaytaradi. Domain dagi Use Case strategiya haqida bilmaydi — User ni Repository.getUser(id) orqali oladi. Strategiyani o'zgartirish (masalan, har 15 daqiqada keshlashni bekor qilish) Domain va Presentation ga ta'sir qilmaydi.

Android da modullik — Kotlin Multiplatform Domain ni Android SDK dan bog'liqliklarsiz alohida KMP moduliga chiqarishga imkon beradi. Data — Domain ga bog'liq alohida modul. Presentation — Domain ga bog'liq Android moduli. Gradle bog'liqliklari: domain (pure Kotlin), data (domain + Retrofit + Room), app (domain + presentation + Hilt). Bunday modullik katta loyihalar uchun majburiy — CI Domain ni alohida quradi, Domain ning unit testlari Android emulyatorini talab qilmaydi.

Presentation Layer: ViewModels va Views

Presentation Layer — Clean Architecture ning eng tashqi qatlami. ViewModels (Android) / ObservableObject (iOS) va Views (Compose/SwiftUI) ni o'z ichiga oladi. ViewModel Use Case ni chaqiradi, natijani oladi va UI holatiga (State) aylantiradi. View State ga obuna bo'ladi va ko'rsatadi. Presentation Domain ga bog'liq — Use Cases va Entities ni import qiladi. Presentation Data Layer ni import qilmaydi — ma'lumotlar Use Case orqali keladi, u ichida Repository dan foydalanadi.

Clean Architecture dagi ViewModel biznes mantiqni o'z ichiga olmaydi — Use Case ni chaqiradi. Agar Use Case User qaytarsa, ViewModel uni UserDisplayItem ga (name, emailFormatted, avatarUrl) — sof prezentatsiya modeliga aylantiradi. Use Case DisplayItem haqida bilmaydi — Entity qaytaradi. Bu bo'linish Use Case ni UI siz va ViewModel ni UseCase siz (mock orqali) sinovdan o'tkazishga imkon beradi. IT Sectr da biz qat'iy rioya qilamiz: Use Case — biznes mantiq, ViewModel — faqat prezentatsiya, View — faqat ko'rsatish.

kotlin
// Use Case (Domain) — toza biznes mantiq
class GetUserUseCase(
    private val repository: UserRepository
) {
    suspend operator fun invoke(id: Int): User {
        return repository.getUser(id)
    }
}

// ViewModel (Presentation) — faqat prezentatsiya
class UserViewModel(
    private val getUserUseCase: GetUserUseCase
) : ViewModel() {

    private val _state = MutableStateFlow<UserScreenState>(UserScreenState.Loading)
    val state: StateFlow<UserScreenState> = _state.asStateFlow()

    fun loadUser(id: Int) {
        viewModelScope.launch {
            _state.value = UserScreenState.Loading
            val user = getUserUseCase(id)
            val displayItem = UserDisplayItem(
                name = user.name,
                email = user.email,
                initials = user.name.split(" ").joinToString("") { it.first().toString() }
            )
            _state.value = UserScreenState.Success(displayItem)
        }
    }
}

data class UserDisplayItem(
    val name: String,
    val email: String,
    val initials: String
)

sealed interface UserScreenState {
    data object Loading : UserScreenState
    data class Success(val displayItem: UserDisplayItem) : UserScreenState
    data class Error(val message: String) : UserScreenState
}

Navigation Presentation qatlamida — tashqi halqaning bir qismi. Clean Architecture navigatsiya mexanizmini belgilamaydi — bu NavController (Compose), NavigationStack (SwiftUI), Coordinator (UIKit) yoki Router (VIPER) bo'lishi mumkin. Muhimi: navigatsiya qarorini Presentation qabul qiladi, ammo navigatsiya Use Case ga kirmasligi kerak. Use Case natija qaytaradi, ViewModel qaysi ekranga o'tishni hal qiladi. Clean Architecture da navigatsiya Domain o'zgartirilmasdan almashtirilishi mumkin bo'lgan tafsilotdir.

Clean Architecture iOS va Android da: kod misollari

Android da Clean Architecture Gradle modullari orqali amalga oshiriladi: domain (pure Kotlin), data (domain + Retrofit + Room), presentation (domain + Compose). Papka tuzilishi: domain/user/User.kt, GetUserUseCase.kt, UserRepository.kt; data/remote/UserRemoteDataSource.kt, local/UserDao.kt, repository/UserRepositoryImpl.kt; presentation/ui/user/UserViewModel.kt, UserScreen.kt. DI (Hilt) qatlamlarni bog'laydi: UserRepositoryImpl domain modulidagi UserRepository interfeysiga bog'lanadi.

iOS da Clean Architecture alohida modullarsiz SPM yoki Xcode guruhlaridan foydalanadi (Xcode cheklovlari tufayli). Domain — UIKit yoki SwiftUI ni import qilmaydigan fayllar papkasi. Data — APIClient, CoreDataStack, RepositoryImpl bo'lgan papka. Presentation — ViewModels va SwiftUI Views bo'lgan papka. DI konstruktor yoki App dagi assembly orqali. Asosiy chaqiruv — UI yangilanishlari uchun MainActor tekshiruvi bilan UseCase.execute() orqali async/await.

swift
// Data Layer: Remote DataSource (iOS)
final class UserRemoteDataSource {
    private let apiClient: APIClient

    func fetchUser(id: Int) async throws -> UserDTO {
        return try await apiClient.get("/users/\(id)")
    }
}

// Repository Implementation (Data)
final class UserRepositoryImpl: UserRepository {
    private let remote: UserRemoteDataSource
    private let local: UserLocalDataSource

    func getUser(id: Int) async throws -> User {
        if let cached = try await local.getUser(id) {
            return cached
        }
        let dto = try await remote.fetchUser(id)
        let user = dto.toDomain()
        try await local.saveUser(user)
        return user
    }
}

// Presentation: ViewModel + SwiftUI View
@MainActor
final class UserViewModel: ObservableObject {
    @Published private(set) var state: UserScreenState = .loading
    private let getUserUseCase: GetUserUseCase

    func loadUser(id: Int) {
        Task {
            state = .loading
            if let user = try? await getUserUseCase.execute(id: id) {
                state = .success(user)
            } else {
                state = .error("Failed to load")
            }
        }
    }
}

IT Sectr loyihalarida Clean Architecture — 30 kundan boshlab loyihalar uchun standartimiz. 2022 yildan beri Android/iOS uchun Kotlin Multiplatform bilan uch qatlamli arxitekturadan foydalanamiz. Domain — umumiy KMP moduli, Data — platforma modullari (Android da Retrofit, iOS da URLSession), Presentation — mahalliy UI. Bu iOS va Android o'rtasida biznes mantiqining 60–80% umumiy kodini beradi, ikkita alohida amalga oshirish bilan solishtirganda ishlab chiqish vaqtini 30–40% qisqartiradi.

Tez-tez beriladigan savollar

Clean Architecture da nechta qatlam bo'lishi kerak?

Minimal uchta: Domain, Data, Presentation. Katta loyihalar uchun Framework (Android SDK/iOS UIKit bog'liqliklari) va Device (GPS, kamera, sensorlar) qo'shiladi. Qatlamlar soni — qat'iy qoida emas, qulaylik masalasi. Muhimi — Dependency Rule ga rioya qilish: bog'liqliklar ichkariga, Domain ga yo'naltirilgan. Uchdan boshlab, loyiha o'sib borgan sayin qatlamlar qo'shish mumkin.

Clean Architecture kod miqdorini oshiradimi?

Ha — MVVM bilan solishtirganda 30–50% ga, repozitori interfeyslari, Use Cases va maperlarni ajratish hisobiga. Oddiy CRUD ilovasi uchun bu ortiqcha. Clean Architecture test qilish va qatlamlarni izolyatsiya qilish ishlab chiqish tezligidan muhimroq bo'lgan murakkab biznes mantiqli loyihalar uchun asoslanadi. MVP yoki prototip uchun MVVM dan foydalaning — Clean Architecture ishga tushirishni sekinlashtiradi.

Clean Architecture ni MVI bilan birlashtirish mumkinmi?

Ha, bu keng tarqalgan amaliyot. Use Cases Domain da qoladi, Presentation esa MVI siklidan (Intent → Reducer → State) foydalanadi. Data Layer — bir xil, Domain — bir xil. Presentation dagi MVI bashorat qilinadigan ekran holatini beradi, Clean Architecture — biznes mantiqni izolyatsiya qilishni. Bu kombinatsiya o'nlab dasturchilari bo'lgan katta loyihalarda qo'llaniladi.

Har bir ma'lumot so'rovi uchun Use Cases kerakmi?

Use Case operatsiya biznes qoidasini o'z ichiga olganida kerak: validatsiya, ikki manbadan ma'lumot birlashtirish, hisoblash, loglash, kirish huquqlarini tekshirish. Qo'shimcha mantiqsiz oddiy getUser(id) so'rovi Repository ni to'g'ridan-to'g'ri ViewModel dan chaqirishi mumkin. Ammo arxitektura bir xilligi uchun ko'p jamoalar Repository ning har bir ommaviy metodi uchun Use Case yaratadi — bu 5–10% kod qo'shadi, lekin o'qishni osonlashtiradi.

Clean Architecture ni qanday test qilish kerak?

Domain: mock Repository bilan Use Cases ning unit testlari — Android SDK siz toza Kotlin/Swift. Data: mock/fake DataSource bilan RepositoryImpl ning integratsiya testlari. Presentation: mock UseCase bilan ViewModel testlari. Dependency Rule tufayli har bir qatlam izolyatsiya qilingan holda test qilinadi. IT Sectr da Domain qamrovi 95% ga, Data — 70–80% ga, Presentation — 60–70% ga etadi.

Xulosa

  • Clean Architecture — uch qatlam (Domain, Data, Presentation) ichkariga Dependency Rule bilan
  • Dependency Rule — Domain Data va Presentation haqida bilmaydi, interfeyslar orqali izolyatsiya
  • Domain — Entities, Use Cases, Repository Interfaces — freymvorksiz toza Kotlin/Swift
  • Data — RepositoryImpl, DataSources (tarmoq, ma'lumotlar bazasi, keshlash) — Domain interfeyslarini amalga oshirish
  • Presentation — ViewModels, Views — faqat ko'rsatish, biznes mantiq Use Cases da
  • Test qilish — Domain 90–95% unit testlar bilan qoplanadi
  • KMP — Kotlin Multiplatform bilan Clean Architecture iOS + Android uchun 60–80% umumiy kod beradi

Biz kalit topshirig'i bilan mobil ilovani ishlab chiqamiz

IT Sectr 2017-yildan beri startaplar va korxonalar uchun iOS va Android ilovalarini yaratadi. Biz sizga maslahat beramiz va eng yaxshi yechimni taklif qilamiz.

Loyihani muhokama qilish

Shuningdek o'qing