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