MVVM для курильщика: почему ваша ViewModel — это помойка на 2000 строк и как это исправить

В статье разбирается «MVVM-курильщика»: когда ViewModel разрастается до «помойки» на тысячи строк и тянет на себя логику, навигацию и даже форматирование. Главный вывод — MVVM работает лучше, когда ViewModel управляет явным состоянием и потоком событий, а не собирает всё подряд.

  • Утверждается, что проблемы MVVM чаще начинаются с неверного понимания ответственности: ViewModel воспринимается как «место, куда кладу всё, что не влезло во View».
  • В качестве причин называются: нарушение инкапсуляции (вплоть до UI-зависимостей во ViewModel), отсутствие чёткого State и противоречивые @Published-переменные, а также логика навигации внутри ViewModel.
  • Вместо двустороннего связывания как «по умолчанию» описывается подход Unidirectional Data Flow (однонаправленный поток данных): View отправляет Action, ViewModel обновляет State, View рендерит State.
  • Предлагается мыслить ViewModel как «машину состояний» и хранить единый State (например enum) со сценариями вроде idle/loading/loaded/error.
  • Побочные эффекты (сеть, аналитика, навигация) предлагается отделять через абстракции/протоколы; навигацию — через Coordinator, а тесты строить без создания UIKit/SwiftUI-объектов.

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

На что обратить внимание: В тексте подчеркивается, что архитектура описывает управление сложностью и состоянием, а не раскладку файлов. Вопросы сводятся к тому, где проходит граница ответственности ViewModel: что считается данными и состоянием, а что — представлением, навигацией и побочными эффектами. Следующий шаг, который подразумевается, — разнести эти роли по отдельным абстракциям и проверить, что сценарии состояния можно перечислить и тестировать.

Коротко

  • Порог «больше 500 строк» в тексте используется как практический сигнал: ViewModel стала массовой, и форматирование/сервисы/трансформации логичнее отделять.
  • Как пример «утечки слоёв» упоминается передача UI-объектов во ViewModel: вместо UIImage и NSAttributedString предлагаются более простые данные, например String.
  • Отдельно критикуется «общая ViewModel на несколько экранов» через Singleton: это ведёт к трудноотлавливаемым сбоям, когда состояние меняется не там, где ожидается.
  • Про Combine сказано, что мощь операторов полезна, но цепочки с 5–6+ операторами становятся сложными для отладки и обычно требуют дробления или выноса логики.
  • Аналитика (вроде Analytics.log(...)) в тексте описана как побочный эффект: её предлагают выносить в декораторы/обсерверы, а инъекцию сервиса допускать в малых проектах.

FAQ

Зачем эта статья про «MVVM-курильщика» важна, если MVVM знаком по учебникам: что в ней объясняется про причины распада «чистого» подхода в бою?

Автор объясняет, почему «чистый» MVVM из учебников рассыпается в реальном коде и как смешение ответственности делает ViewModel свалкой. Далее предлагаются принципы, которые повышают предсказуемость состояния и упрощают тестирование.

Какие три типовые причины провала MVVM перечисляет автор и как каждая из них приводит к росту ViewModel и появлению противоречивых состояний на экране?

Нарушение инкапсуляции, отсутствие чёткого State и навигационная логика внутри ViewModel. В статье это связывается с противоречивыми состояниями (например, одновременно «loading» и ошибка) и ростом связности.

Как в статье предлагается описывать состояние экрана и что делает View, когда ViewModel становится «машиной состояний», а не мешком разрозненных свойств?

Состояние собирается в единый State (например enum) с вариантами idle/loading/loaded/error. View подписывается на State и перерисовывается, по сути «рендеря» его через switch.

Что говорится про выбор между Combine, замыканиями и @Published, и какой признак автор приводит как сигнал, что реактивная цепочка стала слишком сложной?

Выбор зависит от стека и задачи: @Published проще, Combine даёт операторы, замыкания минимальны по зависимостям. Признаком чрезмерной сложности названы цепочки Combine длиннее 5–6 операторов.

Читайте также

  1. Что дал переход на zsh мне, как разработчику?
  2. Ролевой контроль в приложении: варианты реализации
  3. Я устал настраивать ПК и написал для Windows своё приложение на Flutter
  4. Манипулирование данными или как не дать графикам себя обмануть
  5. Анализ целевой аудитории. Сегменты и потребности
Ключевые инсайты из новости (по версии ChatGPT)
  • Антипаттерн «Massive ViewModel» и практический порог роста: Если ViewModel разрастается до сотен строк, это обычно означает смешение ответственности: в неё начинают попадать форматирование, трансформации и побочные эффекты. В статье предложен простой сигнал: при объёме порядка 500+ строк стоит разносить обязанности по отдельным компонентам (форматтеры, сервисы, use case), чтобы снизить связность и упростить поддержку.
    [Архитектура и качество кода]
Для получения полного доступа оформите подписку PubMag PRO.
Зарегистрированные пользователи видят только два тезиса.
Зарегистрироваться
Инсайты автоматически генерируются с помощью искусственного интеллекта на основе текста статьи.
← Назад в лентуЧитать оригинал →
✈️ Подписывайтесь на мой Telegram-канал — там еще больше интересного про AdTech, MarTech, AI и многое другое!