Архитектура Clean, SwiftUI + Combine

Проект Clean Architecture SwiftUI — пример реализации "Чистой архитектуры" (Clean Architecture) в приложении на SwiftUI. Этот подход структурирует код так, чтобы он был легко расширяемым, поддерживаемым и тестируемым. В статье мы рассмотрим основные компоненты этой архитектуры, паттерны, которые используются, и как это всё помогает разработчикам создавать качественные приложения.

Введение в Clean Architecture

Clean Architecture — это концепция, предложенная Робертом Мартином (более известным как Uncle Bob). Она направлена на разделение кода на несколько слоёв, каждый из которых отвечает за свою конкретную задачу. Основная цель — отделить бизнес-логику от пользовательского интерфейса и других инфраструктурных компонентов, что делает код более независимым и легким для тестирования.

Основные слои Clean Architecture включают:

  1. Entities (Сущности) — объекты, представляющие бизнес-логику. Они независимы от остальных частей приложения.
  2. Use Cases (Прецеденты) — определяют действия, которые могут быть выполнены с данными, хранящимися в Entities.
  3. Interface Adapters (Адаптеры интерфейса) — содержат логику преобразования данных между слоями.
  4. Frameworks and Drivers (Фреймворки и драйверы) — слой, взаимодействующий с внешними системами, такими как базы данных или сети.

Эта архитектура гарантирует, что изменения в одном слое не повлияют на другие, что делает код более устойчивым к изменениям.

Как это работает в SwiftUI

В проекте Clean Architecture SwiftUI, автор демонстрирует, как можно адаптировать традиционные принципы чистой архитектуры для работы с фреймворком SwiftUI. Поскольку SwiftUI предлагает декларативный подход к построению интерфейсов, важно сохранить структуру кода гибкой и разделённой на независимые слои.

Основные паттерны в проекте

Проект Clean Architecture SwiftUI использует несколько ключевых паттернов:

  1. Dependency Injection (Внедрение зависимостей) — позволяет легко заменять компоненты и упрощает тестирование.
  2. Repository Pattern (Паттерн репозитория) — используется для абстракции доступа к данным.
  3. MVVM (Model-View-ViewModel) — разделение логики представления (View) и логики обработки данных (ViewModel).

Эти паттерны помогают поддерживать код в чистом состоянии и позволяют разработчикам легко адаптировать его к изменениям требований.

Пример использования

Рассмотрим, как организован код в проекте.

Сущности

struct User: Identifiable {
    let id: UUID
    let name: String
}

Это простой пример сущности, которая представляет пользователя. Сущности должны быть максимально независимыми и не зависеть от конкретной реализации в UI или других системах.

Прецеденты (Use Cases)

class GetUserUseCase {
    private let repository: UserRepository

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

    func execute() -> User? {
        return repository.getUser()
    }
}

Прецедент отвечает за выполнение бизнес-логики и взаимодействие с репозиторием для получения данных.

Репозитории

protocol UserRepository {
    func getUser() -> User?
}

class DefaultUserRepository: UserRepository {
    func getUser() -> User? {
        // Логика получения данных
    }
}

Репозитории используются для абстрагирования логики получения данных. Это может быть обращение к сети, базе данных или кэшированным данным.

Адаптеры интерфейса

class UserViewModel: ObservableObject {
    @Published var user: User?
    private let getUserUseCase: GetUserUseCase

    init(getUserUseCase: GetUserUseCase) {
        self.getUserUseCase = getUserUseCase
    }

    func loadUser() {
        self.user = getUserUseCase.execute()
    }
}

ViewModel действует как связующее звено между пользовательским интерфейсом и бизнес-логикой, представляя данные в удобном для отображения виде.

Пользовательский интерфейс

struct ContentView: View {
    @StateObject var viewModel = UserViewModel(getUserUseCase: GetUserUseCase(repository: DefaultUserRepository()))

    var body: some View {
        Text(viewModel.user?.name ?? "No User")
            .onAppear {
                viewModel.loadUser()
            }
    }
}

SwiftUI позволяет легко связать ViewModel с интерфейсом и автоматически обновлять UI при изменении данных.

Преимущества Clean Architecture в SwiftUI

Использование Clean Architecture в SwiftUI позволяет добиться следующих преимуществ:

  1. Разделение ответственности. Каждый компонент отвечает за свою задачу, что упрощает поддержку и развитие приложения.
  2. Модульность. Легко добавлять новые функции и менять существующие без риска сломать весь код.
  3. Тестируемость. Бизнес-логика и UI разделены, что упрощает написание юнит-тестов.

Заключение

Проект Clean Architecture SwiftUI — это прекрасный пример того, как можно адаптировать традиционные архитектурные подходы к современным фреймворкам. Использование чистой архитектуры позволяет создать легко поддерживаемое и масштабируемое приложение, которое будет отвечать требованиям пользователей и легко адаптироваться к изменениям в бизнес-логике. Такой подход особенно актуален для долгосрочных проектов, где важна гибкость и устойчивость к изменениям. Подробнее с этим проектом ознакомимся в следующих статьях и видео материалах.