Начать проект

Обсудим проект?

Нажимая на кнопку, вы даете согласие на обработку персональных данных и соглашаетесь с политикой конфиденциальности.

Отправлено!

Спасибо за заявку, мы свяжемся с вами в ближайшее время!

Архитектура мобильного приложения: подходы и паттерны

Архитектура мобильного приложения: слои и паттерны

Если коротко: архитектура приложения — это то, как внутри разделена ответственность между частями кода: где живёт интерфейс, где бизнес-логика, где работа с данными. Пользователь её не видит, но именно она определяет, сможете ли вы быстро добавлять функции, легко чинить ошибки и менять команду без переписывания всего заново, — или приложение через год превратится в клубок, который страшно трогать. Поэтому архитектура — это не вопрос вкуса разработчика, а вопрос денег: цены изменений, поддержки и скорости развития.

Code Pilots с 2014 года проектирует и разрабатывает мобильные приложения, в том числе нагруженные продукты вроде VK Fest и платформы GigAnt, и по умолчанию работает на Flutter. Архитектуру мы выбираем под продукт, а не «по моде»: маленькому приложению сложная архитектура только мешает, большому без неё не выжить. Этот материал — про то, что такое архитектура приложения и почему это про деньги, как устроены слои, чем отличаются паттерны MVC, MVP, MVVM и MVI, что такое Clean Architecture и управление состоянием, и как выбрать подход под свой проект. Выбор технологии (Flutter или нативка) и платформенные детали разобраны в статьях про iOS и Android; здесь — про устройство кода внутри.

Зачем бизнесу архитектура, если её не видно

Соблазн понятный: пользователю всё равно, как устроен код, — лишь бы приложение работало. На старте плохая архитектура и правда не видна: первые экраны выходят даже быстрее, потому что никто не тратит время на «правильное» разделение. Расплата приходит позже, и она денежная.

Когда логики становится больше, а ответственность размазана — интерфейс, бизнес-правила и работа с данными свалены в одном месте (то, что разработчики называют «god object», бог-объект на всё), — происходит вот что. Каждое изменение задевает всё подряд: поправили одно, сломалось три. Новый разработчик неделями разбирается, что где лежит, вместо того чтобы писать функции. Покрыть код тестами невозможно, потому что логику не отделить от интерфейса, — и каждый релиз становится лотереей. В какой-то момент команда говорит фразу, которая стоит дороже всего: «это проще переписать с нуля».

Хорошая архитектура покупает ровно обратное: предсказуемую цену изменений (добавить функцию стоит примерно одинаково и на первом месяце, и на втором году), тестируемость (логика отделена и проверяема), быстрый онбординг (новый человек видит, где что лежит) и возможность менять команду без катастрофы. Это и есть актив, за который платят, — не «красивый код ради красоты», а защита от того, чтобы продукт не сгнил под собственным весом.

Самая дорогая фраза в разработке — «это проще переписать с нуля».

Слои приложения: presentation, domain, data

В основе почти любой вменяемой архитектуры лежит простая идея — разделение ответственности по слоям. Каждый слой занимается своим и не лезет в чужое:

  • Presentation (представление) — всё, что связано с интерфейсом: экраны, их состояние, реакция на действия пользователя. Этот слой знает, как показать, но не знает, откуда берутся данные и по каким правилам считаются.
  • Domain (домен, бизнес-логика) — сердце приложения: правила и сценарии, ради которых оно существует. «Можно ли оформить заказ», «как считается скидка», «что происходит при оплате». Этот слой не зависит ни от интерфейса, ни от того, откуда пришли данные.
  • Data (данные) — работа с источниками: сеть, локальная база, кэш. Слой знает, откуда брать и куда сохранять, но не знает, как это покажут пользователю.

Смысл разделения в том, что слои можно менять независимо: переделали дизайн экрана — бизнес-логика не тронута; сменили API на бэкенде — интерфейс не заметил. Большинство архитектурных подходов — это разные способы провести эти границы аккуратно и не дать слоям перепутаться.

Слои мобильного приложения: presentation, domain и data

Архитектура под продукт, а не по моде

Маленькому приложению сложные слои только мешают, большому без них не выжить. Code Pilots подбирает подход под размер и горизонт продукта — и честно говорит, где не стоит переусложнять.

Обсудить проект

Паттерны представления: MVC, MVP, MVVM, MVI

Внутри слоя представления есть несколько устоявшихся паттернов — способов развести интерфейс и логику его поведения. Они развивались, решая проблемы предыдущих.

Паттерн Идея Когда уместен
MVC (Model-View-Controller) Классика: модель, представление, контроллер Быстрый старт, простые экраны; плохо масштабируется
MVP (Model-View-Presenter) Логику выносят в Presenter, View — пассивна Когда нужна тестируемость, но без реактивности
MVVM (Model-View-ViewModel) ViewModel хранит состояние, интерфейс обновляется автоматически Баланс скорости и поддержки — дефолт для большинства приложений
MVI (Model-View-Intent) Однонаправленный поток данных, неизменяемое состояние Сложные UI-состояния, где важна предсказуемость

На практике MVVM — рабочий выбор по умолчанию для большинства продуктов: ViewModel держит состояние экрана, а интерфейс сам перерисовывается при его изменении, без ручной возни. MVI идёт дальше: данные текут в одном направлении, а состояние экрана неизменяемо и пересоздаётся целиком — это даёт предсказуемость там, где UI-состояний много и цена ошибки высока (платежи, сложные формы, многошаговые сценарии). MVC и MVP сегодня берут реже: MVC — для совсем простого, MVP — там, где нужна тестируемость без реактивного подхода. Выбор паттерна — не религия, а соответствие сложности экрана: простому хватит MVVM, сложному с кучей состояний выгоднее MVI.

Clean Architecture: это правила, а не ещё один паттерн

Clean Architecture часто ставят в один ряд с MVVM и MVI — и зря, это про другое. MVC, MVP, MVVM, MVI отвечают за слой представления; Clean Architecture (её сформулировал Роберт Мартин, известный как «Uncle Bob») — это набор правил о том, как устроено всё приложение целиком и как слои зависят друг от друга.

Главное правило — правило зависимостей: зависимости направлены внутрь, к бизнес-логике. Доменный слой (правила бизнеса) не знает ничего о внешнем мире — ни про интерфейс, ни про конкретную базу или API. Это presentation и data зависят от домена, а не наоборот. Практический выигрыш: бизнес-логику можно тестировать в полной изоляции, а внешние детали (заменить REST на GraphQL, поменять локальную базу, переписать UI) меняются, не задевая ядро. Clean Architecture отлично сочетается с паттернами представления: внутри presentation работает MVVM или MVI, а Clean задаёт границы между presentation, domain и data на уровне всего приложения.

Цена за это — больше слоёв, интерфейсов и кода на старте. Поэтому Clean Architecture оправдана на средних и крупных продуктах с долгой жизнью, а для крошечного MVP она избыточна — это тот случай, когда «правильно по учебнику» означает «дорого и медленно без пользы».

Зависимости направлены внутрь: бизнес-логика не знает ничего ни про интерфейс, ни про базу.

Управление состоянием: где живёт правда о данных

Современная мобильная разработка крутится вокруг одного вопроса — управления состоянием (state management): где хранится актуальное состояние экрана и как интерфейс узнаёт, что его пора обновить. Когда пользователь нажал «добавить в корзину», счётчик в шапке должен обновиться, экран корзины — тоже, и всё это должно остаться согласованным. Чем сложнее приложение, тем важнее, чтобы у данных был единый предсказуемый источник правды, а не десяток мест, где состояние живёт по-своему и расходится.

Инструменты зависят от технологии. Во Flutter, на котором мы работаем по умолчанию, состоянием управляют через Provider, Riverpod или BLoC — последний реализует MVI-подход с однонаправленным потоком и предсказуемым состоянием, и его берут на крупных приложениях именно за надёжность. В нативной разработке свои инструменты: на Android — ViewModel и Jetpack Compose с Kotlin Flow, на iOS — SwiftUI и Combine. Подход к состоянию выбирают под сложность: простому экрану хватит лёгкого решения, нагруженному приложению с множеством взаимосвязанных состояний нужен строгий однонаправленный поток. Ошибка в управлении состоянием — частый источник плавающих багов, которые сложно поймать, поэтому на нагруженных продуктах это проектируют осознанно, а не «как получится».

Спроектируем состояние без плавающих багов

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

Получить консультацию

Как выбрать архитектуру под проект

Универсального ответа «всегда так» нет — архитектуру подбирают под размер и горизонт продукта. Перебор так же вреден, как недобор: Clean Architecture для приложения на три экрана — это сожжённый бюджет, а god object в продукте на пятьдесят экранов — гарантированная переделка.

Размер проекта Разумный выбор
MVP, небольшое приложение MVVM с чистым разделением слоёв, без лишних абстракций — быстро выйти и проверить гипотезу
Средний продукт MVVM + Clean Architecture (data/domain/presentation) — запас для роста
Крупный продукт MVI + Clean Architecture + модульность (каждая фича — отдельный модуль) — независимость команд и предсказуемость

Логика простая: чем дольше живёт продукт и чем больше команда, тем сильнее окупаются строгие границы и тем дороже их отсутствие. Маленькому и короткоживущему важнее скорость — лишние слои только замедлят. Поэтому правильная архитектура — не самая сложная, а соответствующая задаче; и хороший подрядчик предложит ту, что подходит вашему продукту, а не самую модную.

Выбор архитектуры под размер продукта: MVP, средний и крупный

Частые ошибки в архитектуре приложения

  • Отсутствие архитектуры и god object. Всё свалено в одном месте — интерфейс, логика, данные. Работает на старте, превращается в нередактируемый клубок через год.
  • Бизнес-логика в интерфейсе. Когда правила «как считается скидка» живут прямо в экране, их нельзя ни переиспользовать, ни протестировать, а любой редизайн рискует их сломать.
  • Карго-культ паттернов. Взять модный паттерн, потому что «так у всех», не понимая, какую проблему он решает, — и получить сложность без пользы.
  • Оверинжиниринг. Clean Architecture, модульность и пять слоёв абстракции для крошечного приложения — это медленно и дорого без отдачи. Сложность должна быть оправдана размером.
  • Игнорировать управление состоянием. Состояние, размазанное по экранам без единого источника правды, рождает плавающие баги, которые потом неделями ловят.

Правильная архитектура — не самая сложная, а соответствующая задаче.

С чего начать

  • Трезво оценить размер и горизонт продукта (короткий MVP или система надолго)
  • Развести ответственность по слоям с самого начала — интерфейс отдельно, бизнес-логика отдельно, данные отдельно
  • Выбрать паттерн представления под сложность экранов (MVVM по умолчанию, MVI там, где состояний много) и решить про управление состоянием
  • Добавлять строгие границы Clean Architecture и модульность по мере роста, а не на старте
  • Не тащить бизнес-логику в интерфейс и не строить пять слоёв ради трёх экранов

Архитектуру выбирают под продукт, а не наоборот. Самое дорогое в приложении — не написать его, а поддерживать и развивать год за годом; и именно архитектура определяет, будет это дёшево или превратится в «проще переписать». Code Pilots проектирует архитектуру под задачу — от простого MVVM для MVP до Clean Architecture с модульностью для нагруженных продуктов на Flutter, силами senior-команды. Расскажите о задаче — подскажем, какая архитектура подойдёт именно вашему приложению и где не стоит переусложнять.

Главное в архитектуре: разделяй ответственность, соответствуй задаче, не переусложняй на старте

Обсудим ваш проект?

Оценим задачу, предложим архитектуру под ваш продукт и пришлём КП с кликабельным прототипом за 2–3 дня.

Обсудить проект

Частые вопросы (FAQ)

Это то, как внутри разделена ответственность между частями кода: где интерфейс, где бизнес-логика, где работа с данными. Пользователь её не видит, но именно она определяет, легко ли добавлять функции, чинить ошибки и менять команду. Плохая архитектура незаметна на старте и дорого обходится потом, когда приложение превращается в клубок, который страшно трогать.

MVVM и MVI — паттерны слоя представления: они разводят интерфейс и логику его поведения. MVVM хранит состояние во ViewModel и автоматически обновляет интерфейс; MVI добавляет однонаправленный поток данных и неизменяемое состояние для предсказуемости в сложных сценариях. Clean Architecture — не паттерн представления, а правила для всего приложения: как слои (data/domain/presentation) зависят друг от друга. Они не альтернативы, а сочетаются: MVVM или MVI внутри, Clean — снаружи.

По размеру и горизонту. Для MVP и небольшого приложения — MVVM с чистым разделением слоёв, без лишних абстракций. Для среднего продукта — MVVM плюс Clean Architecture с разделением на data/domain/presentation. Для крупного — MVI плюс Clean плюс модульность, где каждая фича — отдельный модуль. Главное — не переусложнять: сложность архитектуры должна быть оправдана размером продукта.

Управление состоянием (state management) — это то, как приложение хранит актуальное состояние экранов и синхронно их обновляет: нажал «в корзину» — счётчик и экран корзины обновились согласованно. Чем сложнее приложение, тем важнее единый предсказуемый источник правды о данных, иначе состояние расходится и появляются плавающие баги. Во Flutter для этого используют Provider, Riverpod или BLoC, в нативной разработке — свои инструменты.

Да, и для небольших продуктов это разумно — начать с MVVM и чистого разделения слоёв, без избыточных абстракций. Главное — сразу развести интерфейс, логику и данные: тогда добавить строгие границы Clean Architecture и модульность по мере роста несложно. А вот если на старте всё свалить в одно место, переход к нормальной архитектуре потом превращается в переписывание — поэтому базовое разделение слоёв закладывают с первого дня.

Обсудим проект?

Заполните форму или напишите нам
на airmail@code-pilots.ru
Нажимая на кнопку, вы даете согласие на обработку персональных данных и соглашаетесь с политикой конфиденциальности.

Спасибо!

Спасибо за сообщение, мы свяжемся
с вами в ближайшее время!
success