Pull to refresh

Comments 9

А как реализована работа с сайд эффектами?

reSwift - middlewares, есть thunk

TCA - редьюсер может возвращать эффект

Мы одинаково подходим к работе как с сайд эффектами в виде рендеринга UI так и к асинхронным сайд эффектам. Например в виде запросов к серверу или локальной базе данных. То есть, если нам нужно сделать запрос к серверу, то мы создаем состояние для этого запроса, создаем компонент для этого запроса, который следит за своим состоянием и как только видит что ему необходимо выполнить запрос, то переходит к его исполнению. Впервые такой подход мы встретили у Алексея Демедецкого и попробовали у себя. На данный момент такой подход решает все наши задачи. По опыту можем выделить такие плюсы и минусы:

Плюсы:
- Единый подход ко всем сайд эффектам. Какой бы не был сайт эффект разработчик всегда будет создавать компонент, который этот сайд эффект реализует.
- Максимальная гибкость. Мы полностью управляем временем жизни сайд эффекта и можем в нужный момент подключить его к стору и отключить. Так же такой подход позволяет синхронизировать между собой работу отдельных сайд эффектов через стейт.
- В случае TCA если не нужен сайд эффект, то в редюсере необходимо вернуть .none. Это может усложнять чтение кода. В используемом нами подходе редюсеру не нужно ничего возвращать.

Минусы:
-В простых случаях получается избыточно. Реализовать Thunk для простого сценария получается быстрее.
-В TCA на уровне редюсера можно понять какой сайд эффект исполнится следующим. В случае сайд эффектов как отдельных компонентов необходимо смотреть кто подписывается на изменения данного стейта.

В будущих статьях планируем детальнее раскрыть тему работы с сайд эффектами.

Спасибо за развернутый ответ, было бы здорово увидеть пример в репе с простым асинк запросом

Подскажите, а почему State единый и такой массивный? Чем это обусловлено? Кажется, что если просто поделить один божественный State на кучу мелких, но подписывающихся друг на друга, большая часть ваших проблем, если не все, уйдут. Тот же профиль вы выделяете в отдельную сущность, за которой потом следит тот, кому нужен профиль, без слежения за всем "богом". Кажется, что в Redux не должно быть ограничения на то, что состояние обязано быть одним. Но даже если и так, можно же завести под каждый UI-компонент свой фасад, который будет под собой объединять по нужной Вам логике отдельные независимые стейты. Кажется, что корень проблем модуляризации у Вас -- это попытка затянуть God-объект, связывающий в большой клубок все ваще приложение, в модульную архитектуру. Кажется, что так не выйдет. Модуляризация подразумевает в том числе разнесение модели и стейта на независимые куски.

Одна из главных причин держать весь State в одном месте — это единый источник правды. Если говорить про Redux, то у него в документации в соответствующем пункте прописано про глобальный State и один Store. Конечно, если есть какая-то часть приложения, которая никак не зависит от всего приложения, то ее без проблем можно вынести в отдельный Store(в Redux это тоже упоминается).

Проблемы начинаются когда части приложения очень активно общаются:
-Если UI компоненту нужно отправить экшены сразу в два стора, то у нас не будет возможности синхронно обновить их стейты. В такой ситуации могут возникнуть недопустимые состояния приложения и их будет сложно отловить.
-Если сторам нужно использовать стейты друг друга, то их придется либо копировать либо работать с ними асинхронно. Это может привести к рассинхрону между сторами, который будет очень тяжело обнаружить.

Единый State лишен таких проблем. За одну итерацию редюсера мы можем синхронно обновить любую часть приложения, написать на это тест и гарантировать отсутсвие рассинхронов. Да это влечет за собой ряд доработок, но они в результате позволяют разделить части приложения на отдельные модули и свести к минимуму взаимодействие между ними. Про наш подход к модуляризации конкретно доменного слоя можно почитать здесь.

Кажется, что единый Стейт все же не решает проблемы многопоточности, ну вот никак. Даже с единым стейтом вы все равно не застрахованы, что ваше приложение не окажется в конкретный момент времени в непредусмотренном состоянии. Даже с единым стейтом, система в любой момент времени может перекинуть вас на другой поток. Даже во время вашего перехода из одного стейта в другой, пока этот самый Стейт еще не обновился полностью. И вы получите тот же самый рассинхрон, которого Вы так опасаетесь. Проблему мог бы решить единственный поток, в котором и происходят все смены состояний и их чтения, но мы прекрасно знаем, что в iOS работать в одном единственном потоке практически невозможно. А значит, единый Стейт для Вас - это лишь попытка себя обмануть. Кажется, что единственный возможный выход из данной проблемы - это правильная работа в многопоточной среде с атомарными записями и чтениями состояния. И тут уже не важно, единый у вас Стейт или распределенный, но обеспечивающий атомарность записи и чтения. Тем более, что Вы тоже согласны, что Стейт в Redux не обязан быть единым. Кажется, что единый Стейт обеспечивал бы те плюсы, что Вам нужны, в каком-то другом программерском мире, но не в иосном. Возможно, я ошибаюсь.

Тут еще такие мысли. Кажется, что при переходе не реактивное слежение за сигналами, читать явно значения переменных не стоит. Т.е. не стоит смешивать активное и реактивное программирование. Если уж у вас везде реакции на изменения, то убрав явное чтение значений в каждый конкретный момент, Вы исключаете саму возможность прочитать неверное состояние. А сигналы рано или поздно дойдут до всех подписчиков в актуальном состоянии.

Да, суть как раз в единственном потоке на котором обрабатывается обновления состояния. Мы под это выделяем отдельную последовательную очередь, в TCA например по умолчанию редюсеры работают на мейне. На перфоманс это критически не влияет.

В любом случае у каждого подхода есть плюсы и минусы. В нашем случае единый стейт показал себя достаточно хорошо, а его минусы не настолько критичны. Но, конечно, важно учитывать особенности проекта при выборе архитектуры.

ну, если вы понимаете это, то вам не составит труда и разделять стейты и разносить их по зонам ответственности. Тогда и не придется столько сопутствующих проблем решать. Но хозяин -- барин, как говорится.

Sign up to leave a comment.