Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best practice using RX - return an Observable or accept an Observer?

Using Reactive Extensions, I can think of a number of ways to model an operation that has side effects / IO - say subscribe to messages from a chat room. I could either accept parameters (say the chat room), and an Observer, returning a Disposable, i.e.

Disposable SubscribeTo(string chatRoom, Observer<ChatMessage> observer)

or return an Observable given the parameters, i.e.

Observable<ChatMessage> GetObservableFor(string chatRoom)

When returning an Observable, I additionally have the choice between making it "hot" or "cold", i.e. performing the actual subscription either when my method is called or when the observable is subscribed to. In addition, I could make the observable multiplexed or not, i.e. share the same underlying subscription when there are more than one subscribers to the Observable, or initiate a new request each time it is subscribed to.

Is there a best practice approach to this using RX for operations that subscribe to an external source of events with parameters?

like image 441
SoftMemes Avatar asked Aug 19 '13 13:08

SoftMemes


1 Answers

I agree with the other two answers. I would like to further add some clarifications:

  1. If your observable sequence is Hot, it is almost certainly shared. So it sounds like you may have some confusion there as you talk about Hot and Shared as different things.
  2. I think it is fine for a subscription to have side-effects. In Functional Programming, most discussions about avoiding side-effects are with regards to the operators in the pipeline, not the construction of the pipeline. i.e. don't create side effects in your Where/Select/Take etc... operators. To do so creates a jarring experience and leads to unpredictable outcomes. This prevents safe composition, which is a corner stone of FP.
  3. Is is totally fine to pass parameters to a method that returns an observable sequence! Your sample is a great example of when to do so. Other examples include subscribing to a channel, endpoint, session, timer etc...
  4. Avoid the usage of custom implementations of IObservable<T>. It is just a no-no. I have been using Rx for well over 3 years now and there is just no need for it. Even using the Subject implementations is a rare occurrence. As Brad said, look to Observable.Create for creating sequences.*

To summarize, I suggest that you end up with an interface that looks like this:

IObservable<ChatMessage> MessagesFor(string chatRoom)

RE your question of sharing observable sequences, is very much something you need to decide based on your own requirements and architecture. Sometimes you may find that the underlying transport layers will do this for you, so there is no need to you to code it. Other times you may find that sharing a subscription means that the second+ subscribers may miss out on messages that only occur on subscription (e.g. State-Of-World). You could over come this by using a ReplaySubject as your MultiCaster. This raises other issues; are you prepared to take a possibly unbounded cost of storing ChatMessages?

*Disclosure: The link is to my own website

like image 130
Lee Campbell Avatar answered Sep 29 '22 01:09

Lee Campbell