Можно ли вызывать репозиторий из ViewModel напрямую при совпадении модели с бизнес и презентационными требованиями
Что проверяют
Понимаете ли вы, что слой use case в Android не обязателен и появляется по конкретной причине, а не по шаблону. Следом обычно спрашивают, в какой момент вы бы всё-таки завели UseCase и что делать, если модель данных перестанет совпадать с тем, что нужно экрану.
Как отвечать
Короткий ответ: да, можно. В официальном руководстве Google по архитектуре доменный слой помечен как необязательный, и ViewModel, которая получает репозиторий через конструктор, считается нормальной схемой. Каркас ответа:
- зависимость через DI:
@HiltViewModelи@Inject constructor(private val repo: UserRepository), в тестах подставляется фейковая реализация интерфейса; - когда нужен UseCase: одна и та же логика нужна нескольким ViewModel, данные собираются из двух репозиториев или правило настолько сложное, что его стоит тестировать отдельно;
- асинхронность: репозиторий отдаёт
suspend-функции илиFlow, ViewModel запускает их вviewModelScopeи превращает вStateFlowчерезstateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), initial); - граница моделей: даже при совпадении полей экрану лучше отдавать
UiState, а не сущность Room или DTO сети. Сегодня поля совпадают, завтра бэкенд переименует одно из них, и правка расползётся по всем экранам.
Сильная формулировка: «Пока модель совпадает, вызываю репозиторий напрямую. UseCase добавлю, когда появится повторное использование или составная логика, это правка на один класс».
Где спотыкаются
Отвечают «никогда, только через UseCase». В итоге в проекте десятки классов, которые просто вызывают метод репозитория и ничего не добавляют, а интервьюер слышит заученную схему вместо понимания.
Отдают в UI сущность с аннотацией @Entity или DTO с nullable-полями под формат API. Экран начинает зависеть от формата хранения, и замена источника данных ломает вёрстку.
Зовут репозиторий синхронно, как в старых примерах: блокирующий вызов прямо в методе ViewModel на главном потоке или запуск через GlobalScope, который переживает экран и течёт.