Какие классы используются в чистой архитектуре
Что проверяют
Понимаете ли вы, что чистая архитектура это правило направления зависимостей, а не набор обязательных классов. Следом обычно спрашивают, в какой слой положить маппер и нужен ли use case, который просто вызывает репозиторий.
Как отвечать
Разложите классы по слоям:
- domain: модели предметной области (
User,Order) как обычные Kotlin-классы, use case (GetUserProfileUseCase) и интерфейсы репозиториев (UserRepository). Слой не знает про Android, Retrofit и Room, поэтому его удобно держать в отдельном Kotlin-модуле и тестировать обычным JUnit; - use case: один сценарий на класс, часто с
operator fun invoke, чтобы вызывать его как функцию. Возвращает результатsuspend-функции илиFlow; - data:
UserRepositoryImpl, источники данных (UserRemoteDataSourceповерх Retrofit,UserLocalDataSourceповерх Room), DTO и@Entity-классы, мапперы из них в доменные модели. Репозиторий решает, откуда брать данные: сеть, кеш или база; - presentation:
ViewModelиз Jetpack вызывает use case и отдаёт экрану состояние черезStateFlow<UiState>, экран на Compose или фрагментах. UI-модели тоже здесь; - DI: Hilt или Koin связывают интерфейс репозитория с реализацией, например через
@Bindsв Hilt-модуле.
Главное правило: зависимости направлены внутрь, к domain. Data реализует интерфейсы из domain, presentation вызывает use case, а domain не импортирует ничего из внешних слоёв. В официальном руководстве Android по архитектуре доменный слой назван необязательным, и это стоит упомянуть: use case оправдан, когда логика сложная или переиспользуется.
Где спотыкаются
Используют один класс сразу как ответ Retrofit, сущность Room и модель для экрана. Любое изменение API тогда расходится по всему приложению.
Тащат в domain Context, LiveData или аннотации Room, после чего слой уже не тестируется без Android.
Заводят use case на каждый вызов репозитория без логики. Интервьюер оценит, если вы признаете, что такой класс лишний и его можно пропустить.