Проектирование архитектуры Android, чтобы потом не переписывать всё
Большинство переписываний Android-приложений происходит не потому, что исходный код был плохо написан построчно — а потому, что несколько ранних структурных решений сделали изменения дорогими.
Решение, которое важнее всего: отделить логику от интерфейса
Бизнес-логика, живущая прямо внутри Activity, Fragment или Composable, — самая частая единственная причина, по которой приложениям в итоге требуется дорогое переписывание — она становится непроверяемой в изоляции и невозможной для изменения без риска для интерфейса, и наоборот.
Вам не нужно внедрять полностью реализованный архитектурный паттерн с первого дня, но хранение логики в отдельных классах (ViewModel, репозиторий, простые классы use-case) с самого начала — пусть даже нестрого — оставляет открытой дверь для формализации этого в MVVM или похожий паттерн позже, без переписывания.
Минимальная, защитимая начальная структура
ui/ — Activity, Fragment, Composable — только отображение
viewmodel/ — хранение состояния, предоставляет то, что нужно интерфейсу
repository/ — доступ к данным (сеть, база данных), скрывает источник от остального приложения
data/ — модели, сущности базы данных, типы ответов APIЭто не жёсткий фреймворк — это минимальная планка: код интерфейса не общается напрямую с базой данных или сетевым API, он проходит через слой, который может меняться независимо.
Решения, которые действительно трудно отменить позже
- Выбор базы данных и дизайн схемы — миграция моделей данных после появления реальных пользовательских данных значительно сложнее, чем продуманное проектирование заранее. См. наше сравнение Room, SharedPreferences и DataStore для реальных компромиссов.
- Учтена ли поддержка офлайн-режима с самого начала — встраивание offline-first поведения в приложение, построенное в расчёте на постоянное соединение, — существенная переработка, а не постепенное добавление. См. наш гайд по offline-first.
- Структура навигации — глубоко вложенная, специальная настройка навигации становится дорогой для реструктуризации, как только множество экранов начинают зависеть от её текущей формы.
Решения, которые дёшево менять позже (не переусложняйте их)
- Конкретный выбор UI-компонентов, системы стилизации, мелкая замена библиотек вроде загрузки изображений — обычно они достаточно изолированы, чтобы менять их, не трогая остальное приложение.
- Точные соглашения об именовании папок — полезны для консистентности, но не несут архитектурной нагрузки.
Практический вывод
Тратьте ранние усилия по проектированию на решения, которые дорого отменить (разделение логики и интерфейса, дизайн слоя данных, офлайн-стратегия), и сознательно не переинвестируйте в те, что дёшево изменить позже. Перепутать этот баланс — доводить до совершенства соглашения о стилях, пока бизнес-логика живёт прямо в Activity, — распространённая и предотвратимая ловушка.
Начинаете новый Android-проект и хотите второе мнение об архитектуре, прежде чем написать много кода? Свяжитесь со мной — это дешёвый разговор на раннем этапе и дорогая ошибка, если исправлять поздно.
Частые вопросы
Нужен ли MVVM для маленького приложения?
Не обязательно с первого дня, но разделение интерфейса и бизнес-логики с самого начала (пусть даже нестрого) значительно упрощает переход к более полному паттерну вроде MVVM позже, вместо того чтобы встраивать разделение в уже плотно связанный код.
Какая единственная самая дорогая архитектурная ошибка?
Размещение бизнес-логики прямо внутри Activity/Fragment (или Composable) без слоя разделения — это паттерн, который надёжнее всего вынуждает к переписыванию, как только приложение вырастает за небольшой размер, потому что логику и интерфейс становится невозможно менять независимо.
Имеет ли Jetpack Compose отношение к этому решению?
Да — Compose делает интерфейс и управление состоянием более явными, что на самом деле усиливает аргумент за разделение бизнес-логики и интерфейса с самого начала, поскольку модель рекомпозиции Compose наказывает плотно связанную логику заметнее, чем это делала старая система View.