🙅‍♂️ Stop trying to learn RxJS
Tags: javascript, rxjs, node, deno
Published: 2020-06-09 19:57:51

If you have any interest in [RxJS](https://github.com/ReactiveX/rxjs), this article is for you. If you have no idea what RxJS is, I advise you not to worry about it and check out [rubico](https://github.com/a-synchronous/rubico): a new asynchronous functional programming library authored by yours truly.

At the highest level, the relationship between rubico and RxJS is characterized by [convergent evolution](https://en.wikipedia.org/wiki/Convergent_evolution), that is

> the independent evolution of similar features in species of different periods or epochs in time

Emphasis on **different periods in time**. One period without async iterables, and one period in the future when they're a thing.

For the longest time, I had at best a hazy idea of RxJS. In fact, My first encounter with [the reactive paradigm](https://en.wikipedia.org/wiki/Reactive_programming) was through talks of RxSwift with a pal of mine from an old job. It wasn't until after I had heard numerous comparisons of RxJS to rubico that I really hunkered down and dove in.

This set me off to learn RxJS, and I'll be honest, I was disappointed. At no point in either of the [release](https://github.com/ReactiveX/rxjs/tree/6.x) [branches](https://github.com/ReactiveX/rxjs) or the [main site](https://rxjs-dev.firebaseapp.com/guide/overview) do they talk about _why_ RxJS. It always just starts with _what_. It's like reading a research paper that starts with "hey guys, here's our research! it's important because we say so!". There needs to be a reason why the research is being done, otherwise no one will care. Just take a look at any TC39 proposal, it always [starts](https://www.npmjs.com/package/rxjs-for-await) [with](https://github.com/tc39/proposal-promise-any#motivation) [why](https://www.npmjs.com/package/rxjs-for-await). For RxJS, on the other hand, the current first time experience on the site is

 1. Introduction - "RxJS is..." <- this is what
 2. Example 1 - RxJS is powerful because you can use pure functions and pure functions are less error prone
 3. Example 2 - RxJS has operators for flow control
 4. Example 3 - RxJS has operators to transform values in RxJS observables
 5. Observables - "Observables are..."

They never answered my first question: why is this here in the first place? On [rubico](https://github.rubico.land) it's

 1. Motivation - Why is this here? Because When I was still writing in the imperative style, I got tired of looking at my own code. I created this library for myself, so I can write in a style I love.
 2. Principles - What is the highest level of what I want from this library? Simple code; don't care about async; and simple, composable, and performant transformations (on all collections)
 3. rubico follows these principles to grant you freedom
 4. Introduction - [take the tour](https://tour.rubico.land/), [read the docs](https://github.rubico.land#documentation)
 5. Examples...

Why should always precede what. Otherwise, your product will run in circles. I experienced this first hand at my previous company.

![battle of chattanooga](https://www.history.com/.image/t_share/MTcxNTQ5OTYwMzUxODUyMTk0/battle-of-chattanooga-gettyimages-513682009.jpg)

[From the creator of RxJS](https://mobile.twitter.com/BenLesh/status/1260332868234022914)

> RxJS isn't easy to learn. But the alternative lessons you'll learn if you try to roll your own streaming paradigm for your app with a lot of streaming data will be much, much more painful and costly.

I mean I can't predict the future, but I agree. I trust that the creator of RxJS speaks from experience. There will probably be a lot of pain rolling my own streaming paradigm, which is why I'm not going to roll my own streaming paradigm. In fact, I'm not going to invent another paradigm at all; I'm just going to borrow the existing [functional paradigm](https://opensource.com/article/17/6/functional-javascript) and polish it for JavaScript.

> ...and at the end of the day, anything you create will just be another flavor of Observable without the safety guarantees.

Does the async iterable count as another flavor of the Observable? It seems the spec is leaving RxJS behind when async iterables are already here to stay, while Observables are a [stage 1 proposal](https://tc39.es/proposal-observable/). Observables are **not** async iterables, but they compete for the same streaming data model. Async Iterables were created partly because of the [pains of NodeJS streams](https://github.com/nodejs/node/issues/89), which are analogs to RxJS Observables. Part of these pains are [backpressure problems](https://github.com/tc39/proposal-observable/issues/205), from RxJS creator:

> Since observables are all push-based, there are memory and back pressure concerns unless you use a lossy strategy to adapt the incoming values into the asyncIterator. I have a proposal to add this as a feature to RxJS, but it's not without it's drawbacks.

^ that turned into [this library](https://www.npmjs.com/package/rxjs-for-await).

You can see excitement for async iterable streams in [this issue in the streams spec](https://github.com/whatwg/streams/issues/778). Read it for the good vibes. Here's a nice summary from domenic

> It's starting to feel a bit magic though....

Really, I'm just against spaghetti code. You'll get [spaghetti](https://www.npmjs.com/package/rxjs-for-await) if you model streams as a push datatype like Observable. You'll get worry free code if you model streams as async iterables. Finally, you'll get magical code if you feed an async iterable to rubico's `transform`. Check out this functional style async iterable webserver with rubico and deno
```javascript
const s = serve({ port: 8001 });
console.log("http://localhost:8001/");
transform(map(req => {
  req.respond({ body: "Hello World\n" });
}), null)(s);
```

Here's my abridged list of features and roadblocks comparing RxJS and rubico. I encourage you to voice any additions or subtractions in the comments.

|Features of RxJS|Features of rubico|
|:----------------|:----------------|
|special asynchronous stream datatype, the [Observable](https://rxjs-dev.firebaseapp.com/guide/observable) - wraps built-in types for reactive operations down the line|no special data types: rubico works out of the box for built-in types; this includes async iterables|
|familiar design pattern: the Observer pattern - plugs into Observables|no design pattern lock-in: rubico composes your functions together. You choose the design pattern|
|[interop with Promises](https://medium.com/@benlesh/rxjs-observable-interop-with-promises-and-async-await-bebb05306875)|fully managed Promises: rubico stops you from having to manually resolve Promises, for example having to call<br>`Promise.all` on an array of Promises|
|functional programming style via Operators + `Observable.prototype.pipe`|functional programming style by design|

|Roadblocks for RxJS|More Features of rubico|
|:--------------------|:--------------------|
|async iterables undermine the need for rxjs's core datatype: the Observable.|async iterables make rubico great; the async iterable is a core rubico (and JavaScript) datatype|
|[multitude of concepts](https://www.learnrxjs.io/learn-rxjs/concepts)|simple foundational concept: just pipe functions together|
|[large API surface](https://rxjs-dev.firebaseapp.com/api)|[small, cohesive API surface](https://github.com/a-synchronous/rubico/#documentation)|
|[RxJS is hard to learn](https://www.learnrxjs.io/)|**rubico is easy to learn**|

I'm telling you to stop learning and using RxJS because rubico is that much better at doing what RxJS is trying to do. Don't get me wrong, rubico _is_ easy to learn, but it takes time and hard work to master. I urge you to put your time to better use: [take the tour](https://tour.rubico.land).