
В мире Android-разработки существуют различные архитектурные паттерны.
Многие из вас хорошо знакомы с MVVM, и возможно сталкивались с MVP. В последнее время всё чаще звучит аббревиатура MVI (Model-View-Intent). Однако наряду с MVI существует похожий на неё подход – KoTEA (Kotlin The Elm Architecture).
Оба этих паттерна следуют принципам UDF (Unidirectional Data Flow).
Суть UDF архитектуры заключается в том, что данные в приложении движутся строго в одном направлении от единого источника истины к визуальным компонентам. Каждая фича (например, экран) имеет единственное неизменяемое состояние (State). Изменить его напрямую нельзя — только создать новое на основе предыдущего. Это соответствует принципу конечных автоматов и делает переходы между состояниями прозрачными и контролируемыми.
В классическом понимании MVI можно выделить следующие сущности:
View– интерфейс пользователя. Подписан на состояние фичи через паттерн "Наблюдатель".Model– слой данных, с которым взаимодействуетStore.Store– центральный узел, который хранит состояние фичи, управляет им и обрабатывает поступающие события.Intent– событие, которое отправляется изViewвStore.Executor– сущность внутриStore, которой делегируется выполнение бизнес-логики, побочных эффектов и работа сModel. По окончанию своей работыExecutorпередаёт результат о проделанной работе вReducer.Reducer– чистая функция, которая формирует новое состояние после проделанной работы.

Например, представим мессенджер, в котором пользователь нажимает кнопку "Отправить сообщение". View отправляет Intent для отправки сообщения в Store, Store отдаёт его обработчику Executor, он в свою очередь пытается выполнить отправку сообщения по сети, и в случае успеха передаёт Reducer, что сообщение успешно доставлено. Reducer меняет соответствующим образом состояние, о чем узнаёт View, и обновляется, чтобы пользователь узнал о результате выполненной операции.
Теперь перейдём к паттерну KoTEA:
View– интерфейс пользователя. Подписан на состояние фичи через паттерн "Наблюдатель".Model– слой данных, с которым взаимодействуетStore.Store– центральный узел, который хранит состояние фичи, управляет им и обрабатывает поступающие события.Event– событие, которое требует, чтобы его обработали. Похож наIntentизMVI, но в отличие от негоEventможет быть как изView, так и изнутриStore.Update– чистая функция внутриStore, которая обрабатывает поступающие событияEventи решает два вопроса:Каким будет новое состояние
State?Какие команды
Commandнужно выполнить?
Сам
Updateникакую бизнес-логику не выполняет, а передаёт командыCommand Flow Handler.Command Flow Handler- выполняет команды, поступившие изUpdate. Он занимается выполнением бизнес-логики и изменяетModel. По выполнению работы отправляет событияEventвUpdate.

Возьмём тот же пример с мессенджером. Пользователь нажимает кнопку "Отправить сообщение". View отправляет событие в Store, он передаёт его в Update. Update передаёт команду на отправку сообщения в Command Flow Handler, где происходит попытка отправить сообщение по сети. В результате чего Command Flow Handler отдаёт событие с результатом в Update и тот обновляет состояние фичи.
То есть разница в MVI и KoTEA заключается в том, как Store распределяет обязанности между своими сущностями. В MVI реакцией на Intent является то, что Executor выполняет работу и просит Reducer обновить состояние, а в KoTEA Update разбирает события и делегирует работу Command Flow Handler.

Также необходимо упомянуть, что в этих паттернах есть механизм для отправки во View событий, требующих разовой обработки, например, если нужно выполнить навигацию, либо показать сообщение об ошибке. Чтобы это сделать мы могли бы создавать определённые переменные-флаги внутри состояния State, но нам предлагается более удобный способ через отправку событий по потоку Flow. В MVI для этого предоставляется сущность Label, в KoTEA – News.
Что же выбрать?
Выбор между MVI и KoTEA — это скорее вопрос вкуса и предпочтений команды.
Обе архитектуры превосходно справляются со сложностью современных Android-приложений, обеспечивая предсказуемость и тестируемость.
MVI может показаться более привычным для разработчиков, переходящих с MVVM. Разделение на Intent и State интуитивно понятно. Reducer — это простой и очевидный способ обновления UI.
KoTEA предлагает более «функциональный» подход. Update является единственным местом, где принимаются решения, что делает логику работы фичи предельно прозрачной. Это упрощает тестирование сложных сценариев.