Как паттерн use case помогает абстрагировать бизнес-логику между моделью и сервисом
Что проверяют
Понимаете ли вы, где в iOS-приложении должна жить бизнес-логика и зачем выделять её в отдельный слой, а не держать во ViewModel или в сервисе. Следом обычно спрашивают: «А если use case просто вызывает репозиторий, зачем он нужен?»
Как отвечать
Use case, он же Interactor в терминах Clean Architecture, это один объект на один бизнес-сценарий: PlaceOrderUseCase, RefreshTokenUseCase. Он стоит между слоем представления и слоем данных:
- сверху его вызывает ViewModel или Presenter, передаёт входные данные и получает доменную модель или ошибку;
- снизу он работает через протоколы вроде
OrderRepositoryиPaymentServiceи ничего не знает проURLSession, Core Data, SwiftData или формат JSON; - внутри живут правила: проверка корзины, лимиты, порядок вызовов, сборка результата из нескольких источников.
Отсюда и абстракция между моделью и сервисом: сервис умеет сходить в сеть или в базу, модель описывает данные, а решение, что и в каком порядке делать, принадлежит use case. Поменяли API или перенесли кэш из Core Data в SwiftData, а use case и его тесты остались прежними.
На Swift это обычно структура или final class с зависимостями через инициализатор и одним методом func execute(_ input: Input) async throws -> Output, иногда через callAsFunction. Живёт в доменном модуле, часто в отдельном Swift Package без импорта UIKit и SwiftUI, и тогда границу слоя проверяет компилятор. Тесты пишутся на XCTest или Swift Testing с заглушками репозиториев, без запуска интерфейса.
Бонус: один сценарий переиспользуется из экрана, виджета и App Intents.
Где спотыкаются
Заводят use case на каждый вызов репозитория, даже когда в нём нет ни одного правила. Честный ответ на уточнение: такой прокси оправдан только ради единообразия в большой команде, иначе это лишний слой.
Собирают OrderUseCase с двадцатью методами. Это тот же сервис под другим именем, и принцип «один сценарий, одна причина меняться» теряется.
Протаскивают в домен детали чужих слоёв: DTO из сети, NSManagedObject, готовые строки для подписей или импорт SwiftUI. Тогда use case уже не протестировать и не переиспользовать отдельно.