В какой слой архитектуры положить сервисы
Что проверяют
Умеете ли вы раскладывать код по слоям и замечать двусмысленность в вопросе. Слово «сервис» в Android означает две разные вещи, и сильный ответ начинается с уточнения. Следом обычно просят показать, как такой сервис подменить в тестах.
Как отвечать
Разведите два смысла.
Если речь о сетевом интерфейсе вроде Retrofit ApiService или о DAO из Room, это data layer. В руководстве Google по архитектуре приложений слоёв три:
- UI layer:
Activity,Fragment, экраны на Compose иViewModel. Про Retrofit и базу не знает; - domain layer: необязательный слой с use case, бизнес-логика без зависимостей от Android SDK;
- data layer: репозитории и источники данных.
ApiServiceживёт здесь внутри удалённого источника, наружу виден только репозиторий, а DTO превращаются в доменные модели на его границе.
В Clean Architecture добавляется инверсия: интерфейс репозитория объявлен в domain, реализация лежит в data. В руководстве Google domain просто зависит от data, встречаются оба варианта. Связывает всё Hilt или Koin, а в тестах вместо реализации подставляется фейк.
Если речь о компоненте android.app.Service, это точка входа приложения наравне с Activity, то есть внешний, фреймворковый слой. Сервис должен быть тонким: принять команду, показать уведомление, делегировать работу репозиториям или use case. Для отложенной фоновой работы, которая должна пережить перезапуск, чаще подходит WorkManager, а для foreground service с Android 14 обязателен foregroundServiceType в манифесте.
Где спотыкаются
Отвечают, не уточнив смысл. Рассказ про Retrofit в ответ на вопрос про Service, который играет музыку в фоне, звучит как незнание платформы.
Вызывают ApiService прямо из ViewModel. Работает, но кеширование, офлайн и маппинг ошибок расползаются по экранам, а подменить источник в тестах становится сложно.
Кладут бизнес-логику внутрь Service или тянут в domain классы Android SDK и аннотации Retrofit. Тогда слой перестаёт тестироваться обычными JVM-тестами, ради которых его и выделяли.