Вопрос проверяет умение анализировать сложные UI-сценарии и превращать их в поддерживаемую архитектуру.
Декомпозиция начинается с понимания ответственности экрана и пользовательских сценариев. Экран разбивается на независимые логические блоки и состояния. Бизнес-логика выносится из view controller. Навигация и побочные эффекты отделяются от отображения. Цель — сделать каждый элемент экрана простым и изолированным.
Декомпозиция сложного экрана — это не про «разбить файл», а про разделить ответственность и сценарии, чтобы код можно было читать, менять и тестировать.
Перед тем как писать или рефакторить код, важно ответить на вопросы:
Какие пользовательские сценарии есть у экрана?
Какие состояния экран может иметь?
Что является бизнес-логикой, а что — отображением?
Пример сценариев:
первый вход;
загрузка данных;
ошибка;
пустое состояние;
пользовательское действие (поиск, фильтр, отправка формы).
Практически любой сложный экран можно описать через ограниченный набор состояний.
Типовой подход:
enum ScreenState {
case loading
case content(ContentModel)
case empty
case error(String)
}
Что это дает:
Убирает хаотичные флаги (isLoading, hasError, shouldReload).
Делает UI детерминированным.
Упрощает тестирование логики.
После состояний экран делится на независимые части.
Примеры логических блоков:
Header (заголовок, фильтры, поиск).
Content (список, форма, карточки).
Footer (кнопки, итоги).
Overlays (loader, error, empty state).
Практика:
каждый блок — отдельный UIView или компонент;
блок не знает о данных других блоков;
блок получает только то, что ему нужно для отображения.
Сложный экран почти всегда содержит:
преобразование данных;
валидацию;
условия отображения;
реакции на события.
Эта логика не должна жить в контроллере.
Обычно выносят:
В ViewModel / Presenter — если используется MVVM/VIPER.
В отдельные use case / service — если логика общая.
В отдельные модели состояния.
Контроллеру остается:
подписка на состояние;
рендер UI;
проксирование пользовательских действий.
Навигация — отдельная ответственность.
Антипаттерн:
контроллер сам создает следующий экран;
передает зависимости;
решает, как именно переходить.
Хорошая практика:
Навигация вынесена в координатор / роутер.
Контроллер сообщает что произошло, а не куда идти.
При декомпозиции важно:
чтобы асинхронность была централизована;
чтобы экран не знал деталей сети;
чтобы отмена была управляемой.
Часто это означает:
асинхронность в ViewModel;
state как единственный источник правды для UI.
Декомпозиция сложного экрана — это последовательный процесс: сценарии → состояния → UI-блоки → бизнес-логика → навигация. Чем раньше экран разбит на независимые части с четкими границами, тем проще его развивать и поддерживать.