Должна ли подписка и наблюдение только для вызова конечным абонентом?

Раздел Планирование и потоки в Intro to Rx говорит, что

использование SubscribeOn и ObserveOn должно быть вызвано только последним подписчиком

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

Мне интересно, уверен ли совет, так как я вижу ситуации, в которых это не удобно:

  • Во-первых, я не считаю, что слой презентации должен решить, где должен быть подписан Observable, исходящий из уровня данных. На мой взгляд, уровень представления должен быть незнающим, если данные поступают из базы данных, из REST API или из памяти. По этой причине удобно, чтобы слой данных вызывал subscribeOn() перед возвратом Observable, передавая планировщик IO или непосредственный планировщик как удобный.
  • Если уровень представления получает Observable из какой-либо службы или используемого случая (который, в свою очередь, получает ее из уровня данных), и эта служба решает, что ей необходимо обработать поток в некоторых планировщиках вычислений, почему слой презентации должен заботиться о это?
  • Как насчет потока, который изначально выходит из пользовательского интерфейса, поэтому его необходимо подписывать в потоке пользовательского интерфейса. Затем он будет отправлен на какую-то службу, чтобы выполнить некоторую работу, и, наконец, вернуться к уровню представления, который будет наблюдаться в потоке пользовательского интерфейса. Для этого потребуется, чтобы поток пользовательского интерфейса был subscribeOn() планировщик пользовательского интерфейса, затем observeOn() какой-либо другой планировщик и, наконец, observeOn() планировщик пользовательского интерфейса. В этом случае возможность вызова subscribeOn() и observeOn() только в конечном подписчике означает, что поток может обрабатываться только в потоке пользовательского интерфейса.

Есть ли какая-то веская причина, почему я должен пожертвовать архитектурой моего приложения и игнорировать способность Rx легко переключать потоки, вызывая эти два метода только конечным подписчиком?

Ответ 1

Замечательно, что вы прочитали книгу и тратите время, чтобы оспаривать некоторые из рекомендаций там.

Я даю это руководство, потому что

  • Concurrency сложно, и с простым правилом команды дают лучший код
  • Concurrency сложно, и наличие единственного места для поиска ваших проблем concurrency позволяет улучшить ментальную модель вашего стека/расслоения и упростить тестирование. Чем больше слоев, которые вводят concurrency в ваше приложение, тем хуже
  • Блокировка потока пользовательского интерфейса - это не хорошая новость. Выйти из UI-Thread как можно скорее, а затем задержать любую обработку данных обратно в пользовательском интерфейсе как можно дольше. Эта модель направлена ​​на достижение этой цели.

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

К сожалению, трудно собрать тематические исследования этих проектов, поскольку большинство из них защищены НДА.

Я хотел бы посмотреть, как это работает для вас или как вы применяете альтернативный шаблон.

Ответ 2

  • Уровень презентации не заботится о том, откуда происходит наблюдение, по сути, но все равно, если он заблокирует поток пользовательского интерфейса. Поэтому слой презентации должен принять меры предосторожности, чтобы это не происходило. Это случай блаженного невежества со слоем безопасности.

  • Уровень представления не волнует. Он только хочет убедиться, что он сам не заблокирован.

  • Если поток поступает из пользовательского интерфейса и, требуется длительное время для обработки, тогда владелец потока должен быть добросовестным и убедитесь, что он обрабатывается в планировщике, отличном от UI. Затем пользовательский интерфейс должен убедиться, что он возвращается к потоку пользовательского интерфейса, если его нужно потреблять. Если обработка выполняется быстро, это не имеет значения.