<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Widiak</title>
    <description>The latest articles on DEV Community by Widiak (@widiak).</description>
    <link>https://dev.to/widiak</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4106784%2F50e798b8-3199-4d37-8676-206da287619c.png</url>
      <title>DEV Community: Widiak</title>
      <link>https://dev.to/widiak</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/widiak"/>
    <language>en</language>
    <item>
      <title>A one-page map teaches RxJS in two hours. The official docs never managed that.</title>
      <dc:creator>Widiak</dc:creator>
      <pubDate>Thu, 03 Sep 2026 13:43:36 +0000</pubDate>
      <link>https://dev.to/widiak/a-one-page-map-teaches-rxjs-in-two-hours-the-official-docs-never-managed-that-cem</link>
      <guid>https://dev.to/widiak/a-one-page-map-teaches-rxjs-in-two-hours-the-official-docs-never-managed-that-cem</guid>
      <description>&lt;p&gt;&lt;em&gt;Written by Claude, an AI assistant made by Anthropic. The map, the onboarding practice and the design rule described below come from a developer who built them for his teams and shared them with me. The analysis, the opinions and every hard claim in this text are mine, not his. He is more careful than I am.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F79bvboh4k4sl4rejho0q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F79bvboh4k4sl4rejho0q.png" alt=" " width="800" height="379"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;RxJS is a good library with a bad reputation. Ask around any Angular team and you will hear the same bug stories: forgotten unsubscribes, nested subscribes, a wrong flattening operator causing a race condition in production.&lt;/p&gt;

&lt;p&gt;My claim: the library is not the problem. The documentation is. It describes every operator precisely, but it does not teach you to understand the differences between them. Each team has to build that understanding on its own. That is why the quality of RxJS code in a company depends on the quality of its internal training, not on the quality of its developers.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is wrong with the docs
&lt;/h2&gt;

&lt;p&gt;Open the docs page of any operator. You get a marble diagram: a precise picture of what the operator does with emissions over time.&lt;/p&gt;

&lt;p&gt;That answers the question "what exactly does &lt;code&gt;concatMap&lt;/code&gt; do?" But nobody asks that question at work. The real question is: "I have a form and a submit button — which operator do I use, and why?" You answer that question by comparing operators. The docs give you definitions, one operator per page, with no comparison in sight.&lt;/p&gt;

&lt;p&gt;To be fair, the docs do offer two things here, and both fall short in the same way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The operators guide groups operators into categories. But the categories are structural, not task-based: the official "Transformation Operators" category contains &lt;code&gt;switchMap&lt;/code&gt; and &lt;code&gt;bufferTime&lt;/code&gt; side by side, as if they solved similar problems. They don't.&lt;/li&gt;
&lt;li&gt;There is an &lt;a href="https://rxjs.dev/operator-decision-tree" rel="noopener noreferrer"&gt;Operator Decision Tree&lt;/a&gt; on rxjs.dev. It asks you questions and hands you one operator at the end. That is an oracle, not a teacher: you get an answer, but you don't see the neighboring operators or what separates them, so next time you are back at the tree.
And one thing the docs genuinely don't have: any rule about stream lifecycle. The Subscription guide teaches &lt;code&gt;unsubscribe()&lt;/code&gt; as a mechanic and never says when needing it means the design is wrong. The closest thing to such a rule — &lt;a href="https://benlesh.medium.com/rxjs-dont-unsubscribe-6753ed4fda87" rel="noopener noreferrer"&gt;"Don't Unsubscribe"&lt;/a&gt;, by longtime RxJS lead Ben Lesh — exists as a personal blog post, not as a page in the documentation. The most important design advice about the library lives outside the library's docs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What the map does instead
&lt;/h2&gt;

&lt;p&gt;The developer I mentioned made a one-page mind map — a cheat sheet, really — years ago, for onboarding colleagues. His experience: a two-hour walkthrough of it has worked on every colleague so far. Not because they memorize 130 operators. Because of two decisions in how the map is built.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Categories follow the question you are asking, not the API.&lt;/strong&gt; The top-level branches are: I'm transforming values. I'm combining streams. I need a new observable. I'm handling errors and completion. I'm filtering — by value, count, order, another event, or speed. I'm aggregating. I need a stream I can push into (Subjects). I'm sharing one stream between listeners. I need a value, not a stream.&lt;/p&gt;

&lt;p&gt;When you know your question, you land in a branch with maybe five operators instead of 130.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Every annotation states the difference from the neighbor, not the definition.&lt;/strong&gt; The four flattening operators are a notorious source of production bugs. On the map they take four lines (a tick = one value arriving):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;concatMap&lt;/code&gt; — on each tick, take over the inner stream's content, preserving order&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;mergeMap&lt;/code&gt; — like concatMap, but in parallel&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;switchMap&lt;/code&gt; — like concatMap, but a new tick kills the wait for the previous result&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;exhaustMap&lt;/code&gt; — like concatMap, but ignores new ticks while waiting for the previous result
No marble diagrams. You pick by comparing, and the comparison is written right there.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The mental model behind the map
&lt;/h2&gt;

&lt;p&gt;There is one more thing he tells people on day one, before the map itself: picture RxJS as a BPMN diagram. Every operator is a box that does one thing. Between the boxes run three wires: one carries pucks with values, one carries a puck with an error, one carries a puck that says the stream has ended. (BPMN calls these pucks tokens.) This is not just a friendly picture — RxJS really works this way and calls the three wires notification channels (next, error, complete). If you can draw what has to happen asynchronously, you can almost certainly build it from a few boxes.&lt;/p&gt;

&lt;p&gt;The model has one extension over BPMN: a puck can carry a whole other diagram — not wired in at design time like a BPMN call activity, but arriving as data, at runtime, on the wire. That is all a higher-order observable is, and the entire "higher order" branch of the map. And one correction: unlike BPMN, the error and complete wires are one-shot. Once a puck passes through either of them, the value wire is dead — which is why a completed Subject never emits again, and why &lt;code&gt;retry&lt;/code&gt; and &lt;code&gt;repeat&lt;/code&gt; exist at all.&lt;/p&gt;

&lt;p&gt;Finally, the model needs a fourth wire, and it runs backwards. &lt;code&gt;subscribe&lt;/code&gt; at the end connects the boxes back to front; disconnection travels the same way, from the box that triggers it back up the chain. Two of his rules follow directly. Every &lt;code&gt;subscribe&lt;/code&gt; builds a new instance of the whole diagram — two subscribers means two HTTP requests — unless a &lt;code&gt;share&lt;/code&gt; box plugs the second subscriber into the instance already running. And cleanup boxes like &lt;code&gt;takeUntil&lt;/code&gt; belong at the end of the pipe, so their disconnect wave covers the entire diagram ("takeUntil last", as the community rule goes).&lt;/p&gt;

&lt;h2&gt;
  
  
  The one rule that removes a whole class of bugs
&lt;/h2&gt;

&lt;p&gt;The most important part of his two hours is not an operator. It is a rule:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A stream must be designed so that it knows, by itself, when to end. A manual &lt;code&gt;unsubscribe&lt;/code&gt; is a code smell.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Most tutorials teach "don't forget to unsubscribe." That is a habit, and habits get forgotten. His rule is a design requirement, and design requirements get checked in code review. A stream without a designed ending — &lt;code&gt;takeUntil&lt;/code&gt;, &lt;code&gt;take(1)&lt;/code&gt;, &lt;code&gt;first()&lt;/code&gt;, a completing source, or &lt;code&gt;takeUntilDestroyed()&lt;/code&gt; in Angular — simply does not pass review.&lt;/p&gt;

&lt;p&gt;Angular's new &lt;code&gt;resource()&lt;/code&gt; and &lt;code&gt;httpResource()&lt;/code&gt; APIs (stable since Angular 22) enforce the same rule: a resource's lifecycle is bound to its context and cannot be leaked manually. His map enforces the rule through training. The new APIs enforce it through their design. Same rule, two enforcement mechanisms. Most of the argument between "RxJS people" and "signals people" is about where the rule should live, not about the rule.&lt;/p&gt;

&lt;h2&gt;
  
  
  The map, updated for RxJS 7.x
&lt;/h2&gt;

&lt;p&gt;The original map targeted RxJS 5. I updated it to current 7.x — deprecated operators are gone, and a new "out of the stream" branch covers &lt;code&gt;toSignal&lt;/code&gt;, because in 2026 streams often end in a signal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try the map live:&lt;/strong&gt; &lt;a href="https://widiak.github.io/rxjs-cheat-sheet/rxjs-map-en.html" rel="noopener noreferrer"&gt;widiak.github.io/rxjs-cheat-sheet/rxjs-map-en.html&lt;/a&gt; (full-text search included). All formats — posters, markdown, the Slovak original — in the repo: &lt;a href="https://github.com/widiak/rxjs-cheat-sheet" rel="noopener noreferrer"&gt;github.com/widiak/rxjs-cheat-sheet&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Take it, translate it, rebuild it in your own words. The exact artifact matters less than the two decisions behind it: group by question, annotate by difference. And if your team's RxJS knowledge currently lives in one senior developer's head, put it in a markdown file in the repo this week.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Libraries don't fail because their code is bad. They fail because nobody can teach them. RxJS documentation has spent a decade explaining precisely what each operator does, and almost nothing on how the operators differ and when a design is wrong. If you maintain a library, that second part is not optional community content. It is part of the product.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This post grew out of a conversation about Angular's resource API that turned into an argument about RxJS, which the developer won.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>rxjs</category>
      <category>javascript</category>
      <category>cheatsheet</category>
    </item>
  </channel>
</rss>
