С точки зрения теории в интернетах гуляет очень много материала. Но есть источники, которые заслуживают отдельного упоминания, и которые мы рекомендуем прежде всего.
Первое, это серия статей от Five:
Android Architecture: Part 1 - every new beginning is hard
Android Architecture: Part 2 - the clean architecture
Android Architecture: Part 3 - Applying clean architecture on Android
Android Architecture: Part 4 - Applying Clean Architecture on Android, Hands on (source code included)
Android Architecture: Part 5 - How to Test Clean Architecture
Очень грамотное теоретическое описание трансформации классической Clean Architecture от дядюшки Боба в Clean Architecture для Android.
Единственное, вторая статья как-то немного запутала с этими input/output портами для UseCase и решением проблемы флоу данных через наследование и композицию. Немного оторвано от практики, как нам показалось. Лучше сразу к третьей части приступить, если вы также не совсем поняли.
Еще есть моменты, над которыми можно похоливарить.
Второе, это видео 2016 года и 2017 года о Чистой архитектуре от Евгения Мацюка и Александра Блинова.
Однако, с течением времени некоторые вещи, упомянутые в видео, уточняются и переосмысливаются. И в этом нужно сказать спасибо всем участникам архитектурного чатика. Поэтому мы настоятельно советуем пересмотреть доклады и прочитать дополнения.
Итак дополнения:
-
Проектировать фичу лучше начинать сверху вниз, а не наоборот, так как вы прежде всего отталкиваетесь от того, что видит конечный пользователь.
-
Общая структура. Итоговый вид структуры пакетов соответствует классическим канонам Чистой архитектуры
Структура пакетов:
project
├─ di
│ ├─ app
│ ├─ payments
│ └─ operation
├─ presentation
│ ├─ view
│ │ ├─ payments
│ │ │ ├─ PaymentsView
│ │ │ └─ PaymentsFragment
│ │ └─ operations
│ │ ├─ OperationsView
│ │ ├─ OperationsFragment
│ │ └─ models
│ │ └─ OperationUIModel
│ └─ presenter
│ ├─ payments
│ │ └─ PaymantsPresenter
│ └─ operations
│ └─ OperationsPresenter
├─ domain (он же business)
│ ├─ payments
│ │ ├─ PaymentsInteractor
│ │ ├─ PaymentsInteractorImpl
│ │ ├─ CurrencyHandler (вспомогательный класс для PaymentsInteractor)
| | ├─ PaymentsRepository
| | └─ models
| | └─PaymentsModel
│ └─ operations
│ ├─ OperationsInteractor
│ ├─ rubs
│ │ ├─ OperationsInteractorRubs
│ │ └─ RubsManager (вспомогательный класс для OperationsInteractorRubs)
│ ├─ currency
│ │ ├─ OperationsInteractorCurr
│ │ └─ CurrencyManager (вспомогательный класс для OperationsInteractorCurr)
│ ├─ OperationsRepository
│ └─ models
│ ├─ OperationsRubModel
│ └─ OperationCurrModel
├─ data
│ ├─ repositories
│ │ ├─ payments
│ │ │ └─ PaymentsRepositoryImpl
│ │ └─ operations
│ │ ├─ OperationsRepositoryImpl
│ │ └─ models
│ │ ├─ OperationsRubNetworkModel
│ │ └─ OperationCurrNetworkModel
│ ├─ network
│ └─ db
-
Есть несколько вариантов трактования понятия "Репозиторий". Подробно можно почитать, например, здесь. В Андроид-мире "Репозиторий" - это абстракция для получения данных, то есть она скрывает, с какого именно источника получены те или иные данные.
Кроме того Репозиторий может внутри себя реализовывать логику кэширования данных и соответственно выдачи либо закэшированных данных, либо данных с сети. -
Дядюшка Боб говорит, что Interactor- это объект, реализующий Use Case. Более того, предлагается создавать их с помощью паттерна Команда. У нас же сложилась тенденция объединять различные пользовательские сценарии, связанные с одним функционалом, в отдельные классы - Use case feature facade. Вдобавок многие использует в своих проектах RxJava, и мы получаем довольно лаконичный способ описания основного функционала. Были некоторые споры о том, должны ли такие классы называться в стиле "FeatureInteractor", или "FeatureInteractors" (во множественном числе), но больше прижился первый способ наименования.
-
Domain ничего не знает о других слоях. По классике к domain относятся Интеракторы и интерфейсы Репозиториев. Поэтому Интерактор не может являться маппером моделей. Мапперами моделей будут выступать Репозитории (из моделей data в модели domain и наоборот) и Презентеры (из моделей domain в модели View и наоборот).
Когда мы проектируем фичу и разрабатываем ее по слоям, то в отношении моделей нужно исходить все-таки из принципа минимализма. Если вы знаете, что для вашей фичи вам достаточно будет просто сходить в сеть и полученный результат отобразить на экране и ничего более, и такое поведение вряд ли когда-нибудь изменится, то на все слои вашей фичи лучше держать одну модель.
Чаще бывает, когда полученный результат с сервера нам нужно немного подкорректировать, и уже можно отображать на экране. Тогда на фичу будет две модели (data и domain).
Ну и бывает, что по сути на каждый слой необходима своя модель (presentation, domain, data). -
Activity, Service, BroadcastReceivers относятся ко внешнему кругу Чистой архитектуры, так как они являются частью платформы. Роли же у них могут быть разные: они могут быть и точками входа в приложение, и являться частью view, и работать в качестве источника данных. Соответственно, так как они относятся ко внешнему кругу, вы при необходимости можете внедрить туда и Интерактор, и Репозиторий, и другие классы из внутренних кругов.
-
В видео 2016 года для Интерфейса Вьюшки много методов (setName, setAccountNumber, setCardNumber, setNearestDepartments). На самом деле все эти методы можно заменить на один типа setData, и в аргументы передавать какую-то специальную модельку.
-
Взаимодействие между вьюшкой и презентером и решение вопроса с ЖЦ лучше делегировать какой-то специальной библиотеке. Например, Moxy. Тогда вы избавитесь от большой части довольно нудной работы - обработка ЖЦ.
Кроме того про распространенные заблуждения с отсылом в первоисточники хорошо описано в статье Василия.
Вот кратко и вся теория, которую мы рекомендуем изучить в первую очередь. Остальные материалы на базе приобретенных вами знаний станут более понятными и логичными. У вас составится определенная картина, определенная база, от которой уже можно отталкиваться.