MVVM для курильщика: почему ваша ViewModel — это помойка на 2000 строк и как это исправить
- Утверждается, что проблемы 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 операторов.
Читайте также
- Антипаттерн «Massive ViewModel» и практический порог роста: Если ViewModel разрастается до сотен строк, это обычно означает смешение ответственности: в неё начинают попадать форматирование, трансформации и побочные эффекты. В статье предложен простой сигнал: при объёме порядка 500+ строк стоит разносить обязанности по отдельным компонентам (форматтеры, сервисы, use case), чтобы снизить связность и упростить поддержку.
[Архитектура и качество кода]
Зарегистрированные пользователи видят только два тезиса.
Зарегистрироваться

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