DEV Community

Cover image for Observables, Reactive Programming, and Regret
Ben Lesh for RxJS

Posted on

Observables, Reactive Programming, and Regret

As of this writing, I've been working on the RxJS project for almost 6 years, I think. When I started out, I really had no idea what I was getting into (And I wouldn't have been able to ship those first versions without Paul Taylor and others, for sure). I can remember looking at the number of weekly downloads on npm, and being able to figure out how exactly how many of them were mine. Fast forward to today, RxJS and observables have become extremely popular... Loved by many, hated by a few, and my fear is, misunderstood by most.

Observables vs Reactive Programming vs RxJS

A big problem I see nowadays is how observables have now been intimately linked, for better or worse, to RxJS. Looking back, I sort of wish we had published the Observable primitive as a separate package, and the operators in another package.

When this effort started, I was naively optimistic that Observable would land in the ECMAScript standard, and RxJS would just "become a collection of helper functions" as I think I put it. But years passed, and the TC39 proposal stalled. And the way the world came to know Observable was through RxJS.

Observables are not RxJS. Observables do not require "operators". They are a primitive. The "dual" of the Iterable. A simple push-based type. Nothing more.

Reactive programming isn't necessarily observables. Reactive programming is a paradigm or a practice. It can be done with functions, Promises, etc. In essence, if you can compartmentalize your code into functions that will "react" to incoming events without knowing anything about the source, congrats, you're "reactive".

RxJS is a library of functions built around observables, not the other way around. Observables can, and do, exist in the wild without RxJS. They show up in other libraries, often times in slightly different shapes, but the overall concept is the same. Facebook's Relay has an internal Observable implementation that is eerily similar to RxJS's implementation. In fact, I've lost count of the number of times I've seen an abstraction that amounts to an interface that accepts a callback to handle multiple values, an error, or a completion, and returns or otherwise uses some sort of cancellation semantic.

Regrets

1. The huge API

RxJS 5 inherited its HUGE API surface area from RxJS 4 and under. RxJS 4 and under, in turn, inherited it's API from RxNET, many, many years ago. So much of the API that some might deem "unnecessary" exists because "it always has been, and always must be". RxJS 5 might have been our only chance in the history of the library to truly ween that down. Which we did a bit, but probably not enough. The large API surface leads to confusion and loathing in the community. All of which is understandable, IMO.

2. RxJS out-shined Observable

Observables never had a chance to shine on their own. The real win, IMO, to RxJS is the Observable type itself. Not the operators. Those are just fluff that allow you to do some cool things. Having a lazy type with guarantees like Observable is actually a bigger deal.

With Observable you're guaranteed:

  1. Once it's complete, errored, or unsubscribed, you will get no more messages
  2. Registered teardown WILL occur. If you complete, error, or unsubscribe, you are guaranteed to clean up resources.
  3. A unified API that can represent a wide variety of things: Events, multiple values, single values, user interactions, streaming data, synchronous values, asynchronous values, etc. etc.

There are other great advantages to its design. But IMO, those are the biggest.

RxJS and all of its operators are inseparable in some people's heads from observables. And that's a real shame. Observable is a simple thing. A very simple type. RxJS is complicated with it's huge API and odd names.

3. We never really outlined where RxJS would best serve people

Disclaimer: These are MY opinions on RxJS/Observable use, and not really the RxJS core team's. Feel free to use RxJS or whatever library in whatever way you see fit. If it works, you can maintain it, and you can test it, IMO it's good code. The end.

To put it simply, once people get into RxJS, it's an exciting technology. It suddenly gets used for everything. It's fair to say this mentality exists in tech for a lot of libraries and frameworks. But I think with RxJS it becomes insidious to the detriment of the RxJS community.

Examples:

  • You have a button that, when clicked, fetches the latest data and displays it. Do you need full-on RxJS? No, probably not. "But what about cancellation???" .. You wanted an observable. Not operators. You can use RxJS here for the Observable implementation, but I would caution against jumping into concatMap et al. Especially if your team isn't used to RxJS. But that doesn't mean you shouldn't use Observable. In fact, you probably should.

  • You have streaming data over a web socket, and you need to split it into a couple of different streams and update two parts of your UI. Yes! This is what RxJS is for. You're a filter operator away from a solid use case.

  • You have complex async coordination and/or race conditions, even with APIs that return promises? Honestly, you might want to use RxJS here as well, because of guarantees provided by Observable, and useful operators like concatMap that can guarantee ordering, etc, and have complete interop with async/await and Promise.

4. We never taught people how to write readable code with RxJS

We handed people powerful tools and let them go at it. No guidance or experienced wisdom provided with how to effectively use the library so that you didn't drive your coworkers crazy. This is sort of like getting a power tool set with no manuals. How do you maintain it? How do you resolve issues? Where do you store the tools? etc.

The result of this is people write code they don't understand when they revisit it. Most amazingly, some engineers, who are usually a rational bunch, then declare RxJS to be "unreadable", as in, no matter what they did, they could never make the code readable. Seems defeatist to me. Like anything else, good practices and strategies around reading and organizing rxjs code can be learned and taught. But I know that I personally haven't done enough to spread this know-how.

Consequences

For the most part, I think the response to RxJS has been overwhelmingly positive. The community has organized a conference. I've seen a lot of discussion about it across many communities (beyond just Angular). And usage has been steadily growing.

But on the back swing, there is a trail of destruction to the reputation of RxJS and Observable that has been wrought by misunderstandings about Observable and RxJS, and misuse of the library in general, IMO. There have been well-known tech personalities who have called out "wishing RxJS didn't exist". And my fear is that sort of thinking, if it spreads, will spell doom for the Observable type itself. That would be the biggest shame to this, honestly.

The Observable itself is huge win. It's a primitive that, like I said above, shows up in many forms in many places, and I think it deserves a spot in the language as much as Iterable and Promise. People having a distaste for RxJS's API and/or abuse and misuse is completely understandable, IMO.

There are parts of RxJS I don't like, and here I am unable to pivot the library quickly because it's so popular we'd simply break too many people. But the parts I like the most, the Observable itself, and the guarantees it provides, are in jeopardy of being thrown out with the bath water by some folks. And that's tragic, IMO.

The road forward

For my part, I plan on trying to continue to champion promoting understanding of the when/where/why of RxJS and Observable. And I want to do better to disambiguate Observable from RxJS. I also want to work very hard to simplify the RxJS API: Tighten the API, remove what does not need to be there, improve documentation and readability, add more guidance for folks on how to make their code more maintainable, etc.

Don't get me wrong, I have other regrets with regards to RxJS as it stands, but I'm confident we can remedy all of those things over time. My deepest concern is that there are a huge numbers of people that still don't understand the Observable primitive and its benefits, because they associate it with RxJS and are standoffish about getting involved there because of the learning curve.

Oldest comments (34)

Collapse
 
swyx profile image
swyx

we all have regrets but not enough of us are brave enough to publicly admit them and listen to our detractors. this is one of the best personal reflections I have ever read. the rxjs community is so lucky to have you as it's leader!

Collapse
 
okeeffed profile image
Dennis O'Keeffe

Takes a lot of humility and level headedness to write something of this caliber! I’ve been a fan of the project since hearing the talk on how you implemented it at Netflix years ago, but I will also be the first to admit it is a project that I misunderstood at first. Don’t let those Tweets get to you! Twitter is no place for constructive criticism.

Collapse
 
kayis profile image
K

Thanks for that article!

I found observables intriguing, and Cycle.js got me to look into libs like most and xstream.

I wish JS had observables instead of promises. But in the end, I guess promises were easier to grasp 🙃

Collapse
 
ekrresa profile image
Ochuko Ekrresa

Thanks for the clarification about Observables and RxJS, Ben. As someone who is interested in learning RxJS for quite some time, this has been a huge help.

Collapse
 
manu_sooodhi profile image
Manu Sodhi

Really good read. I've used rxjs and Observables before, but brushing up on Observables tonight. This post has me intrigued about Observables!
Maybe adding a quick example (in the post) of Observables usage could help folks better understand how it's used vs what they'd normally do.

Collapse
 
dmitryefimenko profile image
Dmitry A. Efimenko

Really a great read! I've been a user of RxJS for a long time now and consider myself pretty comfortable with it. However, even though that's the case, it really is helpful to hear again how important it is to mentally separate the Observable primitive type from the operators.

Collapse
 
ken107 profile image
Sarsaparilla • Edited

Precisely how I feel as a user. I've said RxJS is a baby in a tub of dirty bathwater. I just don't know where the baby ends and the bathwater begins. Well, thanks for clearing that up.

Collapse
 
paytonrules profile image
Eric Smith • Edited

3 is the inspiration for a talk and workshop I give on ReactiveX. I had a similar experience when I first found RxJS - I knew something was super cool there, but I couldn't stick a use case on it.

For what it's worth I think this is true of the entire ReactiveX ecosystem. The ReactiveX homepage starts with a marble diagram of debounce. i just completed a nine month Kotlin project that used RxKotlin extensively and we used debounce...once...I think, yet were very effective using Rx tech all over the place. I think it's easy to fall into the trap, after a while, of saying "here's the cool features!" instead of saying what those features are good for.

This is a really nice article, and RxJS is great.

Collapse
 
matyasfodor profile image
Mátyás Fodor

I think this is gonna be a really good direction for RxJS. It's such a powerful library and I was really looking forward to use it when migrated an angularjs app to Angular8. With no internal knowledge of RxJS in the team, at some point we got stuck, so I think more documentation and a smaller API will definitely help. And reactivex.io/learnrx/ is probably still the best functional tutorial out there (not sure who maintains it)

Collapse
 
piotrpalek profile image
Peter • Edited

We handed people powerful tools and let them go at it

I'm quiet new to RxJS, but I feel this is my biggest issue with it.
I especially think pushing RxJS into Angular was a big mistake, as it ends up everywhere and it seems to me that people don't really try to understand it, and blindly apply some operators until it works.

Now that isn't really RxJSs' fault, but it would help if the library would provide a little less foodguns, and a bit more guidance / best practices.

Collapse
 
hansschenker profile image
Hans Schenker

Rxjs has become known to the wider Web community thank's to Angular.
I aggree Angular is a bad example for using Rxjs, it is too intermingled with Angular Lifecycle methods to grasp it.