Какую архитектуру выбрать для разработки картографического приложения с нуля?

«Какую архитектуру выбрать для разработки картографического приложения с нуля?» — вопрос из категории Архитектура, который задают на 10% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Для картографического приложения рекомендуется MVVM + Clean Architecture (слоистая архитектура).

Почему такая комбинация?

  1. MVVM идеально подходит для UI, интенсивно работающего с данными (карты, маркеры, анимации). ViewModel управляет состоянием карты и преобразует сырые геоданные для отображения.
  2. Clean Architecture разделяет ответственность на слои, что критично для работы с внешними SDK (MapKit, Google Maps) и сложной доменной логикой (построение маршрутов, геокодирование).

Предлагаемая структура слоев:

// 1. Domain Layer (Бизнес-логика, независима от iOS/SDK)
protocol RouteCalculator {
    func calculateRoute(from: Location, to: Location) async throws -> Route
}

struct Location {
    let latitude: Double
    let longitude: Double
}

// 2. Data Layer (Реализация доменных протоколов, работа с SDK и сетью)
import MapKit
class MapKitRouteService: RouteCalculator {
    func calculateRoute(from: Location, to: Location) async throws -> Route {
        // Использование MapKit/MKDirections
        let request = MKDirections.Request()
        // ... настройка запроса
        let directions = MKDirections(request: request)
        let response = try await directions.calculate()
        // Преобразование ответа MapKit в доменную модель Route
        return Route(from: response)
    }
}

// 3. Presentation Layer (MVVM)
class MapViewModel: ObservableObject {
    @Published var annotations: [Annotation] = []
    @Published var selectedRoute: Route?
    private let routeCalculator: RouteCalculator

    init(routeCalculator: RouteCalculator) {
        self.routeCalculator = routeCalculator
    }

    func findRoute(from: Location, to: Location) async {
        do {
            let route = try await routeCalculator.calculateRoute(from: from, to: to)
            await MainActor.run { self.selectedRoute = route }
        } catch {
            // Обработка ошибки
        }
    }
}

// View (SwiftUI пример)
struct MapView: View {
    @StateObject var viewModel: MapViewModel
    var body: some View {
        Map {
            // Отрисовка маркеров из viewModel.annotations
            // Отрисовка полилинии из viewModel.selectedRoute
        }
        .task { await viewModel.findRoute(...) }
    }
}

Ключевые преимущества:

  • Смена картографического SDK: Чтобы заменить MapKit на Google Maps, нужно изменить только Data Layer (реализацию RouteCalculator), Domain и Presentation слои остаются нетронутыми.
  • Тестируемость: Доменную логику (RouteCalculator) и логику представления (MapViewModel) можно тестировать юнит-тестами с моками, без запуска симулятора.
  • Масштабируемость: Новые функции (поиск POI, оффлайн-карты) добавляются как новые доменные протоколы и сервисы.

Дополнительный компонент: Координатор (Router) для управления навигацией между экранами карты, поиска и детальной информации.