Архитектура, с которой мы работаем изо дня в день, оставляет желать лучшего. Иначе как объяснить тот хаос и стресс, который каждый из нас испытывает, приходя на новое место работы? В большинстве случаев самым сложным слоем является UI, и эта сложность зачастую обусловлена не разнообразием элементов интерфейса, а неправильным подходом к архитектуре этого слоя. Отсюда можно сделать вывод, что нельзя дробить приложение в привычной форме: на UI, domain и data. Необходимо добавить еще один дочерний слой — ui/viewModel, и на этом слое, одном из самых важных, я хочу акцентировать ваше внимание.
Меня зовут Илья и мы начинаем!

Вопрос остается открытым: почему UI слой является таким сложным? Ведь его задача — просто получить и передать запрашиваемые данные. Возможно, это зависит от специфики приложения, но, увы, в вашем случае это не так. ViewModel — вот истинный источник наших ночных кошмаров, но, как ни странно, на эту проблему мало кто обращает внимание. И Google, который рекомендует использовать одно поле как public, а другое как private, что плохо не только с точки зрения поддержки кода, но и с точки зрения здравого смысла. А если открыть публичные репозитории на GitHub, посвященные Android-приложениям, то разобраться без крепкого напитка бывает сложно — почти все пишут код, который сложно поддерживать, а иногда он просто ужасен. Но, как ни странно, за это нам платят, и, по крайней мере, из эгоистических соображений мы должны упростить себе работу.
Здесь приходит на помощь мое решение — Apex (Aligned Protocol and Execution). Этот подход является производным от архитектуры UDF (Unidirectional Data Flow). Его ключевой особенностью является комьюнити: каждый может предложить свою идею, и, если она действительно стоящая, ей будет дан шанс на развитие.

Что такое Apex?
На диаграмме представлена архитектура взаимодействия между пользовательским интерфейсом (UI) и ViewModel, которая помогает структурировать обработку данных и управление состоянием в приложении. Главным компонентом в этой системе является State — объект, содержащий данные и текущее состояние UI, которые динамически меняются в зависимости от действий пользователя и внутренней логики приложения. State позволяет контролировать, какие данные и в каком виде отображаются на экране, обеспечивая синхронизацию с пользовательским интерфейсом. UI слой отслеживает изменения State и обновляет компоненты интерфейса, чтобы отображаемая информация всегда была актуальной и согласованной с данными.
При взаимодействии пользователя с интерфейсом, например, при нажатии кнопки, UI слой отправляет команду EX (Execute Command), которую перехватывает компонент Executor. Этот компонент играет ключевую роль в архитектуре, так как он отвечает за выполнение логики, обновление State и обработку команд. Executor работает в UI-потоке, поэтому его задачи ограничиваются легкими операциями, такими как обновление данных или переключение состояния элементов. Это позволяет поддерживать высокую отзывчивость интерфейса, избегая блокировок и задержек.
В дополнение к изменению состояния, Executor может инициировать два типа дополнительных процессов: Effect и Event.
Effect — это механизм для выполнения сложных или долгосрочных операций, которые выходят за рамки простых изменений состояния и требуют работы в фоновом потоке. Эти операции могут включать запросы к серверу, выполнение сложных расчетов, построение графиков или работу с базой данных. Задача Executor — делегировать выполнение Effect вспомогательным компонентам, чтобы они могли работать параллельно и не блокировать основной UI-поток. После завершения Effect может отправить одну или несколько команд EX обратно в Executor, который обновит State с учетом результатов завершенной операции. Это позволяет организовать асинхронное взаимодействие, при котором длительные операции не мешают основной работе приложения и не влияют на его производительность.
Event — это сообщения, отправляемые для UI слоя, предназначенные для инициирования определенных действий в интерфейсе, таких как показ уведомлений, открытие диалогов или отображение всплывающих окон. Event используется для передачи немедленных указаний от Executor, требующих визуального отклика интерфейса. В отличие от State, который отслеживается на постоянной основе, Event является одноразовым сигналом, который не сохраняется. Например, по завершении операции Executor может отправить Event, чтобы UI отобразил сообщение об успешном выполнении задачи или показал ошибку, если что-то пошло не так.
Эта архитектура позволяет отделить логику обработки данных и событий от пользовательского интерфейса, делая код более структурированным, модульным и удобным для тестирования. Каждый элемент выполняет строго определенную роль: State хранит данные и состояние, Executor выполняет простую логику и отвечает за обновление State, Effect позволяет делегировать длительные процессы, а Event — управлять реакцией UI на события
Довольно теории, идем к практике!
