Проектирование архитектуры мобильного приложения
Неправильно выбранная архитектура — это не «технический долг» в абстрактном смысле. Это конкретная ситуация через 6 месяцев: добавить пуш-уведомления нельзя без переписывания трёх экранов, потому что бизнес-логика живёт прямо в ViewController, а навигация завязана на AppDelegate. Проектирование архитектуры до начала разработки — это инвестиция, которая окупается при первом значимом изменении требований.
Выбор паттерна: не MVVM «по умолчанию»
MVVM стал стандартом де-факто и для iOS (SwiftUI + Combine), и для Android (Jetpack Compose + ViewModel), и для Flutter (BLoC / Riverpod). Но «поставить MVVM» без понимания масштаба проекта — значит переусложнить маленькое приложение или недостаточно структурировать большое.
Что реально влияет на выбор архитектуры:
- Команда и её опыт. Если команда не работала с VIPER — не ставить VIPER. Освоение паттерна в продакшене стоит дороже его преимуществ.
- Масштаб и модульность. 5 экранов — достаточно простого MVVM без Clean Architecture. 50 экранов с командой 8 человек — Clean Architecture обязательна, иначе конфликты в общих файлах и отсутствие изоляции.
- Требования к тестируемости. VIPER и Clean Architecture дают лучшую тестируемость через инверсию зависимостей, но требуют дисциплины от всей команды.
- Платформа. iOS, Android и Flutter имеют разные паттерны: VIPER органичен для iOS/UIKit, MVP исторически популярен на Android с MVP-библиотеками, BLoC стал стандартом для Flutter.
Что входит в проектирование архитектуры
Это не схема в Miro с прямоугольниками «Model — View — ViewModel». Полноценное архитектурное проектирование включает:
Слоевая модель (layering). Определяем границы между слоями: Presentation / Domain / Data. Документируем правила: domain-слой не знает о Flutter/UIKit, data-слой не знает о конкретном UI-фреймворке. Dependency Rule — зависимости только внутрь, никогда наружу.
Модульная структура (modularization). Для крупных проектов: разбивка на feature-модули (auth, profile, payments, feed). На iOS — Swift Package Manager или cocoapods submodules. На Android — Gradle multi-module. На Flutter — Dart packages внутри монорепо. Модульность даёт параллельную разработку команды и управляемое время сборки.
Dependency Injection стратегия. Выбор DI-контейнера: iOS — Resolver / Swinject / ручной чистый DI, Android — Hilt (Dagger2 с кодогенерацией), Flutter — GetIt + injectable. Проектируем граф зависимостей, определяем времена жизни объектов (singleton / scoped / transient).
Навигация. iOS: UINavigationController / Coordinator pattern / SwiftUI NavigationStack. Android: Jetpack Navigation Component с NavGraph. Flutter: go_router с deep linking. Координаторный паттерн важен при сложной навигации с conditions (авторизован / не авторизован / onboarding не пройден).
State management стратегия. Не просто «используем Riverpod» — а как именно: где живёт глобальный стейт (пользователь, тема, locale), где локальный (состояние конкретного экрана), как обрабатываются ошибки (AsyncValue.error), как разделяются side effects.
Сетевой слой. Retrofit (Android) / Moya (iOS) / Dio (Flutter). Interceptors для авторизации (token refresh), логирования, retry-логики. Обработка ошибок: маппинг HTTP-кодов в доменные ошибки, не пробрасывать DioException в presentation-слой.
Офлайн-стратегия. Нужна ли офлайн-поддержка вообще? Если да: Room (Android) / Core Data / SwiftData (iOS) / drift или Hive (Flutter). Repository pattern как абстракция над remote + local data sources: сначала читаем из кэша, фоново обновляем из сети.
Документация архитектуры
Результат работы — не только работающий scaffold. Документируем в виде:
- ADR (Architecture Decision Records) — почему выбрали именно этот паттерн, какие альтернативы рассматривали
- Диаграммы компонентов и зависимостей (C4 model: Context → Container → Component)
- Coding conventions и примеры для каждого слоя
- Шаблонная структура feature-модуля, которой следует вся команда
Практический кейс
На проекте Flutter-приложения для логистики (30+ экранов, реалтайм трекинг, офлайн-работа водителя) первоначальная архитектура была «BLoC везде без чёткого разделения слоёв». Через 4 месяца: BLoC напрямую вызывал Dio, тесты не писались (невозможно изолировать), добавление новой фичи требовало правок в 5–7 несвязанных файлах.
Рефакторинг на Clean Architecture с GetIt + injectable, go_router, drift для офлайн — занял 3 недели, но следующие 6 месяцев команда добавляла фичи в 2 раза быстрее.
Сравнение подходов
| Критерий | MVC/MVP | MVVM | Clean Architecture |
|---|---|---|---|
| Порог входа | Низкий | Средний | Высокий |
| Тестируемость | Низкая | Средняя | Высокая |
| Масштаб команды | 1–2 чел. | 2–5 чел. | 5+ чел. |
| Время на проектирование | 0.5 дня | 1 день | 3–5 дней |
| Окупаемость | С первого месяца | С 3-го месяца | С 6-го месяца |
Процесс и сроки
- Аудит требований — функциональные и нефункциональные требования, NFR по производительности и офлайн
- Анализ платформы и стека — iOS / Android / Flutter / cross-platform, существующий код если есть
- Проектирование — выбор паттернов, документирование решений, ADR
- Реализация scaffold — базовая структура проекта с примерами для каждого слоя
- Код-ревью и онбординг — объяснение командой принципов, code review первых фич
Проектирование архитектуры: 3–5 дней. Для legacy-рефакторинга с существующим кодом — больше. Стоимость рассчитывается после анализа требований к масштабированию и состава команды.







