反应式编程的界限在哪里 [英] Where to draw the line with reactive programming

查看:24
本文介绍了反应式编程的界限在哪里的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经在我的项目中使用 RxJava 大约一年了.随着时间的推移,我变得非常喜欢它 - 现在我可能想太多了......

I have been using RxJava in my project for about a year now. With time, I grew to love it very much - now I'm thinking maybe too much...

我现在编写的大多数方法都包含某种形式的 Rx,这很棒!(直到它不是).我现在注意到有些方法需要大量的工作来组合不同的可观察生成方法.我有一种感觉,虽然我现在明白我写的东西,但下一个程序员将​​很难理解我的代码.

Most methods I write now have some form of Rx in it, which is great! (until it's not). I now notice that some methods require a lot of work to combine the different observable producing methods. I get the feeling that although I understand what I write now, the next programmer will have a really hard time understanding my code.

在我说到底之前,让我直接从我在 Kotlin 中的代码给出一个例子(不要太深入):

Before I get to the bottom line let me give an example straight from my code in Kotlin (Don't dive too deep into it):

private fun <T : Entity> getCachedEntities(
      getManyFunc: () -> Observable<Timestamped<List<T>>>,
      getFromNetwork: () -> Observable<ListResult<T>>,
      getFunc: (String) -> Observable<Timestamped<T>>,
      insertFunc: (T) -> Unit,
      updateFunc: (T) -> Unit,
      deleteFunc: (String) -> Unit)
      = concat(
      getManyFunc().filter { isNew(it.timestampMillis) }
          .map { ListResult(it.value, "") },
      getFromNetwork().doOnNext {
        syncWithStorage(it.entities, getFunc, insertFunc, updateFunc, deleteFunc)
      }).first()
      .onErrorResumeNext { e ->  // If a network error occurred, return the cached data and the error
        concat(getManyFunc().map { ListResult(it.value, "") }, error(e))
      }

简单地说,它的作用是:

Briefly what this does is:

  • 从存储中检索一些带时间戳的数据
    • 如果数据不是新的,从网络获取数据
      • 再次与存储同步网络数据(以更新)

      我的实际问题来了:反应式编程提供了一些非常强大的概念.但正如我们所知能力越大责任越大.

      And here comes my actual question: Reactive programming offers some really powerful concepts. But as we know with great power comes great responsibility.

      我们在哪里划线?用很棒的反应式 oneliner 填充我们的整个程序是否可以,还是我们应该只为真正平凡的操作保存它?

      Where do we draw the line? Is it OK to fill our entire programs with awesome reactive oneliners or should we save it only for really mundane operations?

      显然这是非常主观的,但我希望有更多经验的人可以分享他的知识和陷阱.让我说得更好

      Obviously this is very subjective, but I hope someone with more experience can share his knowledge and pitfalls. Let me phrase it better

      我如何设计我的代码,使其既具有反应性又易于阅读?

      How do I design my code to be reactive yet easy to read?

      推荐答案

      当你拿起 Rx 时,它会变得非常闪亮 锤子,一切都开始像生锈的钉子,等着你来敲门.

      When you pick up Rx, it becomes this awesome shiny hammer and everything starts looking like a rusty nail just waiting for you to bang in.

      就我个人而言,我认为最大的线索在于它的名字,reactive 框架.给定一项需求,您需要考虑反应式解决方案是否真正有意义.

      Personally, I think the biggest clue is in the name, reactive framework. Given a requirement, you need to reflect upon whether a reactive solution truly makes sense.

      在任何 Rx 命题中,您都希望引入一个或多个事件流并针对事件执行一些操作.

      In any Rx proposition, you are looking to introduce one or more event streams and carry out some action in response to an event.

      我认为有两个关键问题要问:

      I think there are two key questions to ask:

      • 您能控制事件流吗?
      • 您必须在多大程度上以事件流的速度完成响应?

      如果您没有控制事件流,并且您必须响应事件流,那么 Rx 是一个不错的选择.

      If you do not have control of the event stream and you must respond at the rate of the event stream then Rx is a good candidate.

      在任何其他情况下,这可能都是一个糟糕的选择.

      In any other circumstance, it is probably a poor choice.

      我见过很多例子,人们为了证明 Rx 的合理性而越过箍创造缺乏控制的错觉——这对我来说似乎很疯狂.为什么要放弃您拥有的控制权?

      I have seen many examples where people have jumped through hoops to create the illusion of a lack of control in order to justify Rx - which seems crazy to me. Why give up the control that you have?

      一些例子:

      1. 您必须从固定的文件列表中提取数据并将其存储在数据库中.您决定将每个文件名推送到一个主题中,并创建一个反应式管道来打开每个文件并投射数据,然后以某种方式处理数据,最后将其写入数据库.

      1. You have to extract data from a fixed list of files and store it in a database. You decide to push each file name into a subject and create a reactive pipeline that opens each file and projects the data, then processes the data in some way and finally writes it to the database.

      这未通过控制测试和速率测试.迭代文件并拉入它们并尽可能快地处理它们会容易得多.短语决定推动"是这里的赠品.

      This fails the control test and the rate test. It would be far easier to iterate over the files and pull them in and process them as fast as you can. The phrase "decide to push" is the giveaway here.

      您需要显示证券交易所的股票价格.

      You need to display stock prices from a stock exchange.

      显然这是 Rx 的不错选择.如果你跟不上一般的价格速度,你就完蛋了.可能您将价格混为一谈(也许每秒只提供一次更新) - 但这仍然符合要求.你不能做的一件事就是要求证券交易所放慢速度.

      Clearly this is a good choice for Rx. If you can't keep up with the rate of prices in general, you are screwed. It might be the case that you conflate prices (perhaps to provide an update only once every second) - but this still qualifies as keeping up. The one thing you can't do is ask the stock exchange to slow down.

      这些(现实世界)示例几乎处于光谱的两端,没有太多灰色区域.但是有很多灰色地带,控制不明确.

      These (real world) examples pretty much fall at opposite ends of the spectrum and don't have much grey area. But there is a lot of grey area out there where control isn't clear.

      有时您在客户端/服务器系统中戴着客户端帽子,很容易陷入牺牲控制或将控制放在错误位置的陷阱 - 这可以通过正确的设计轻松解决.考虑一下:

      Sometimes you are wearing the client hat in a client/server system and it can be easy to fall into the trap of sacrificing control, or putting control in the wrong place - which can easily be fixed with correct design. Consider this:

      1. 客户端应用程序显示来自服务器的新闻更新.

      1. A client application displays news updates from a server.

      • 新闻更新会随时提交到服务器并大量创建.
      • 应该按照客户端设置的时间间隔刷新客户端.
      • 可以随时更改刷新间隔,并且用户始终可以请求立即刷新.
      • 客户端仅显示用用户指定的特定关键字标记的更新.
      • 新闻更新有时很长,客户端不应存储新闻更新的全部内容,而应显示标题和摘要.
      • 应用户要求,可以显示文章的全部内容.

      在这里,新闻更新的频率不受客户端控制.但所需的刷新率和感兴趣的标签是.

      Here, the frequency of news updates is not in control of the client. But the desired refresh rate and the tags of interest are.

      对于客户端接收所有到达的新闻更新并对其进行过滤,客户端是行不通的.但是有很多选择:

      For the client to receive all the news updates as they arrive and filter them client side isn't going to work. But there are plenty of options:

      • 考虑到客户端刷新率,服务器是否应该发送更新数据流?如果客户端离线怎么办?
      • 如果有数千个客户怎么办?如果客户想要立即刷新怎么办?

      有很多有效的方法可以解决这个问题,包括或多或少的反应性元素.但是任何好的解决方案都应该考虑到客户端对标签和所需刷新率的控制,以及缺乏对新闻更新频率的控制(由客户端或服务器).您可能希望服务器通过更新它推送到客户端的事件来响应客户端兴趣的变化 - 只要客户端正在侦听(通过心跳检测),它就会推送这些事件.当用户想要一篇完整的文章时,客户端会拉下文章.

      There are lots of valid ways to tackle this problem that include more or less reactive elements. But any good solution should take account of the client's control of tags and desired refresh rate, and the lack of control of news update frequency (by client or server). You might want the server to react to changes in client interest by updating the events that it pushes to the client - which it pushes only as long as the client is listening (detected via a heartbeat). When the user wants a full article, then the client would pull the article down.

      在 Rx 社区中有很多关于背压的争论.这是客户端应该在过载时通知服务器并且服务器通过以某种方式减少事件流来响应的想法.我认为这是一种误导性的方法,可能会导致设计混乱.

      There is much debate in the Rx community about back-pressure. This is the idea that the client should inform the server when it is overloaded and the server respond by somehow reducing the event stream. I think this is a misguided approach that can lead to confusing designs.

      在我看来,一旦客户需要提供此反馈,它就未能通过响应率测试.在这一点上,您不是处于 反应式 状态,而是处于 异步可枚举 状态.即客户应该说我准备好了";当它准备好更多时,然后以非阻塞方式等待服务器响应.

      To my mind, as soon as a client needs to give this feedback, it has failed the response rate test. At this point, you are not in a reactive situation, you are in an async enumerable situation. i.e. The client should be saying "I am ready" when it is ready for more and then waiting in a non-blocking fashion for server to respond.

      如果第一个场景被修改为到达放置文件夹、长度和处理复杂性不同的文件,这将是合适的.客户端应该对下一个文件进行非阻塞调用,处理它,然后重复.(根据需要添加并行性)- 并且不响应文件到达的事件流.

      This would be appropriate if the first scenario were modified to be files arriving in a drop-folder, of varying lengths and complexity to process. The client should make a non-blocking call for the next file, process it, and repeat. (Add parallelism as required) - and not be responding to a stream of file-arrived events.

      我特意避免了其他有效的问题,例如代码的可维护性、Rx 本身的性能等.主要是因为它们在别处得到了解决,更重要的是因为我认为这里的想法比这些问题更具分裂性.

      I've deliberately avoided other valid concerns such as maintainability of code, performance of Rx itself etc. Most because they are addressed elsewhere and more importantly because I think the ideas here are more divisive than those concerns.

      因此,如果您在您的场景中反思控制响应率的元素,您可能会保持正确的轨道.

      So if you reflect on the elements of control and response rate in your scenario you and will probably stay on the right track.

      响应率问题可能很微妙 - 程度 方面很重要.到达率可能会波动,并且响应率会有一定程度的波动 - 显然,如果您最终没有办法赶上"然后在某些时候客户端会爆炸.

      The response rate issue can be subtle - and the degree aspect is important. Arrival rate can fluctuate, and there is going to be some acceptable degree of fluctuation in response rate - clearly, if you don't ultimately have a way to "catch up" then at some point the client will blow up.

      这篇关于反应式编程的界限在哪里的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆