<?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: Dean Radcliffe</title>
    <description>The latest articles on DEV Community by Dean Radcliffe (@deanius).</description>
    <link>https://dev.to/deanius</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F132121%2F37b3aa4a-accf-497b-a737-df3ab7414036.jpeg</url>
      <title>DEV Community: Dean Radcliffe</title>
      <link>https://dev.to/deanius</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/deanius"/>
    <language>en</language>
    <item>
      <title>Vibe Coding an Audio Engineer Who Never Sleeps</title>
      <dc:creator>Dean Radcliffe</dc:creator>
      <pubDate>Wed, 25 Feb 2026 19:09:12 +0000</pubDate>
      <link>https://dev.to/deanius/vibe-coding-an-audio-engineer-who-never-sleeps-4o61</link>
      <guid>https://dev.to/deanius/vibe-coding-an-audio-engineer-who-never-sleeps-4o61</guid>
      <description>&lt;p&gt;I've been coding since I was 11, but playing guitar and writing and singing and recording songs for about a decade now. And somewhere in my musical journey, I realized something:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The red “Record” button changes you.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It tightens your shoulders.&lt;br&gt;
It turns exploration into performance.&lt;br&gt;
It makes you think instead of &lt;em&gt;play&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;So you leave it to not recording by default - then when inspiration strikes, and you think "Record that!” — oops it’s gone already. So I built myself an audio engineer  agent to always be listening. I did it solely by chatting with OpenClaw via Telegram, on a Raspberry pi 5. He was up and running in under 30 minutes - using code techniques I didn't even know at the beginning! And if you were curious - I named him "Rick" - because he's always rolling... &lt;/p&gt;

&lt;h2&gt;
  
  
  The Idea: A Ring Buffer As The Engineer
&lt;/h2&gt;

&lt;p&gt;The idea is simply this: An always-on ring buffer.&lt;/p&gt;

&lt;p&gt;A rolling 10–15 minutes of audio. Continuously recording. Continuously overwriting itself.&lt;/p&gt;

&lt;p&gt;Like an engineer in the room who’s always listening, but never judging.&lt;/p&gt;

&lt;p&gt;If something magical happens?&lt;/p&gt;

&lt;p&gt;You tell it "Rick send me the last 5 minutes you recorded"&lt;br&gt;
And you get the file in under a minute as a telegram message.&lt;/p&gt;

&lt;p&gt;No prep.&lt;br&gt;
No red light.&lt;br&gt;
No performance mode.&lt;/p&gt;

&lt;p&gt;Just: &lt;em&gt;Oh yeah - that's what I was going for.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  How I Built it (OpenClaw Vibe Coding)
&lt;/h2&gt;

&lt;p&gt;This is where it gets wild.&lt;/p&gt;

&lt;p&gt;I didn’t open a whiteboard.&lt;br&gt;
I didn’t spec it.&lt;br&gt;
I didn’t design a formal architecture.&lt;/p&gt;

&lt;p&gt;I opened OpenClaw and vibe-coded it by chatting with it and testing it out.&lt;/p&gt;

&lt;p&gt;“Give me a low-latency circular audio buffer.”&lt;br&gt;
“Now add a command to flush the last N minutes to disk and send that file via Telegram”&lt;/p&gt;

&lt;p&gt;Each prompt fit in a text message. Each step took minutes. No doc-diving through audio libraries for two hours. Just momentum.&lt;/p&gt;

&lt;p&gt;By 10 pm I had:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Live mic input&lt;/li&gt;
&lt;li&gt;A rolling buffer&lt;/li&gt;
&lt;li&gt;A save-last-5-minutes command&lt;/li&gt;
&lt;li&gt;Zero disk clutter&lt;/li&gt;
&lt;li&gt;Zero pressure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By 11 I was adding clip detection, file renaming, and purging as features. And of course I stayed up past that!&lt;/p&gt;

&lt;h2&gt;
  
  
  This Is the Era of the Single-Person Toolmaker
&lt;/h2&gt;

&lt;p&gt;This would have been a weekend project a few years ago.&lt;/p&gt;

&lt;p&gt;Or something I’d half-start and abandon.&lt;/p&gt;

&lt;p&gt;Instead?&lt;/p&gt;

&lt;p&gt;One evening.&lt;br&gt;
Some prompts.&lt;br&gt;
Tight feedback loops.&lt;br&gt;
Working software.&lt;/p&gt;

&lt;p&gt;And here’s what’s exciting:&lt;/p&gt;

&lt;p&gt;I didn’t build a whole product.&lt;/p&gt;

&lt;p&gt;I built a tiny tool I've dreamed about for years - that permanently upgrades how I create.&lt;/p&gt;

&lt;h2&gt;
  
  
  No Deployment. No Users. Just Me.
&lt;/h2&gt;

&lt;p&gt;This never needs to ship.&lt;/p&gt;

&lt;p&gt;It doesn’t need auth.&lt;br&gt;
It doesn’t need analytics.&lt;br&gt;
It doesn’t need a landing page.&lt;/p&gt;

&lt;p&gt;It exists entirely in my studio.&lt;br&gt;
If I want to share it with someone - I can send them the prompts I used and they can build it for themselves!&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bigger Shift
&lt;/h2&gt;

&lt;p&gt;As a software engineering manager, I spend a lot of time thinking about leverage. This was personal leverage.&lt;/p&gt;

&lt;p&gt;The same force that’s reshaping design systems, agent-first dev, and code generation pipelines - can also  reshape your personal and creative life.&lt;/p&gt;

&lt;p&gt;Tonight, I sent 2 tracks to 2 friends just by talking to Rick.&lt;/p&gt;

&lt;p&gt;I didn’t hit record once, or write any code by hand.&lt;/p&gt;

&lt;p&gt;I just became a vibe coding believer.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>openclaw</category>
      <category>vibecode</category>
      <category>music</category>
    </item>
    <item>
      <title>This is how I'm going to Vibe Code from now on - Schema-First.</title>
      <dc:creator>Dean Radcliffe</dc:creator>
      <pubDate>Mon, 19 May 2025 14:35:40 +0000</pubDate>
      <link>https://dev.to/deanius/this-is-how-im-going-to-vibe-code-from-now-on-schema-first-p5g</link>
      <guid>https://dev.to/deanius/this-is-how-im-going-to-vibe-code-from-now-on-schema-first-p5g</guid>
      <description>&lt;h1&gt;
  
  
  Schema-First: The Unsung Hero of Vibe Coding
&lt;/h1&gt;

&lt;p&gt;Last Friday's AI workshop revealed an approach that genuinely caught my attention. After building systems for decades, I've seen countless methodologies come and go, but my colleague's presentation of a vibe-coded medical appointment scheduling system demonstrated something rare: perfect synchronization between frontend and backend components despite rapid development cycles.&lt;/p&gt;

&lt;p&gt;What stood out wasn't the polished UI or time it took to occur—it was how locked-in every part of the application was. When he revealed the how it was simply: "Schema-first, with zero exceptions."&lt;/p&gt;

&lt;p&gt;What struck me most was how this approach enhanced rather than restricted their "vibe coding" style. While they maintained the intuitive, developer-experience-focused approach that makes coding enjoyable, the schema provided guardrails that prevented chaos. Of course this has always been the case - to build a house you put up a foundation first - but in our hope to nail it all together with one prompt, one shot, we've forgotten how to do layer upon layer upon solid foundations.&lt;/p&gt;

&lt;p&gt;I left that workshop with a renewed appreciation for architectural fundamentals. In our rush to embrace developer experience and intuition-driven approaches, we sometimes forget that structure enables creativity rather than hindering it. The lesson wasn't that vibe coding is wrong—it's that vibe coding becomes exponentially more powerful when built on a foundation of well-defined schemas and interfaces.&lt;/p&gt;

&lt;p&gt;As I tried this approach on subsequent projects, the results confirm what I witnessed that Friday: architecture still matters, perhaps more than ever. The sweet spot isn't choosing between rigid structure and creative freedom—it's recognizing how the right structure creates the perfect playground for innovation.&lt;/p&gt;

</description>
      <category>vibecoding</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Building the 7GUIs with GitHub Copilot</title>
      <dc:creator>Dean Radcliffe</dc:creator>
      <pubDate>Wed, 13 Dec 2023 04:46:38 +0000</pubDate>
      <link>https://dev.to/deanius/building-the-7guis-with-github-copilot-3cgo</link>
      <guid>https://dev.to/deanius/building-the-7guis-with-github-copilot-3cgo</guid>
      <description>&lt;p&gt;Unless you've been hiding under a rock, you know that 2023 has been quite a year for AI and programming. And Github Copilot is perhaps the biggest way programmers are using AI to supplement their work. But can AI replace the work of programming? &lt;/p&gt;

&lt;p&gt;I think we should put Github Copilot - end of 2023 version - up to some tasks relevant to the modern UI/UX developer. Someone like yourself who might be using React to code front-ends to web applications, and wondering - can AI do my job? Will it take my job? I have a plan to answer that question - at least in 2023 terms.&lt;/p&gt;

&lt;p&gt;There are a set of UI programming benchmarks named the 7 GUIs &lt;a href="https://eugenkiss.github.io/7guis/" rel="noopener noreferrer"&gt;(link)&lt;/a&gt;. 7 apps whose specifications range from the simple — a counter — to the complex — a spreadsheet. 7 quests designed to test the mettle of any developer— or AI. If we ask Github Copilot to build each of these 7 GUIs of increasing complexity — how far will it get? Can it do it all for us, from the UI to the logic, or is it useful more for one part of the app than another?&lt;/p&gt;

&lt;p&gt;In order to make these solutions understandable to the widest audience of developers, I'll specify that these must be built in React, with hooks, not classes. I'll avoid requiring TypeScript types, but evaulate whether the code was written with correct types, if any. I'll include the prompts that I use.&lt;/p&gt;

&lt;p&gt;A few disclaimers, for context: I am an English-speaking senior developer with over 20 years experience. I have built all the 7 GUIs in React before. But, I have been working with automated code generators like GitHub Copilot for only about a month. And I want to try, at least at first, getting it all done with standard English prompts that presume nothing about the target solution. I will not try my Spanish out in this series of posts, but I may in a future series, recognizing the global impact of AI across the diverse developer community. And finally I care about maintainability of software. I'll have a robot build my car, but I want the human mechanic to be able to get at the parts to replace them. And I want a certain aesthetic beauty when I look under the hood :)&lt;/p&gt;

&lt;p&gt;Lastly, as part of the evaluation, I come with reference solutions to which I will compare the AI solutions. These reference solutions use my libraries &lt;code&gt;@rxfx/bus&lt;/code&gt; and &lt;code&gt;@rxfx/service&lt;/code&gt; &lt;a href="https://github.com/deanrad/rxfx" rel="noopener noreferrer"&gt;on Github here&lt;/a&gt;. So this might become a commercial for those libraries, if the translation of natural language prompts to code goes smoother with RxFx than with Copilot. &lt;/p&gt;

&lt;p&gt;With that said, I think we're ready to begin! ❤️ or comment on this post if you are willing to partake in this experiment with me, or have any ideas for how I could tailor it to what you are interested in learning.&lt;/p&gt;

&lt;p&gt;See you in the ring, AI!&lt;/p&gt;

&lt;p&gt;— Dean Radcliffe&lt;/p&gt;

&lt;p&gt;The 7 GUIs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://eugenkiss.github.io/7guis/tasks#counter" rel="noopener noreferrer"&gt;Counter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://eugenkiss.github.io/7guis/tasks#temp" rel="noopener noreferrer"&gt;Temperature Converter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://eugenkiss.github.io/7guis/tasks#flight" rel="noopener noreferrer"&gt;Flight Booker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://eugenkiss.github.io/7guis/tasks#timer" rel="noopener noreferrer"&gt;Timer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://eugenkiss.github.io/7guis/tasks#crud" rel="noopener noreferrer"&gt;CRUD&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://eugenkiss.github.io/7guis/tasks#circle" rel="noopener noreferrer"&gt;Circle Drawer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://eugenkiss.github.io/7guis/tasks#cells" rel="noopener noreferrer"&gt;Cells&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>githubcopilot</category>
      <category>ai</category>
      <category>react</category>
    </item>
    <item>
      <title>Making Async, Animated Toasts with an RxFx Service</title>
      <dc:creator>Dean Radcliffe</dc:creator>
      <pubDate>Wed, 15 Nov 2023 21:20:27 +0000</pubDate>
      <link>https://dev.to/deanius/reactive-objects-and-effects-with-an-rxfx-service-1b64</link>
      <guid>https://dev.to/deanius/reactive-objects-and-effects-with-an-rxfx-service-1b64</guid>
      <description>&lt;h2&gt;
  
  
  A use case: A list of notifications
&lt;/h2&gt;

&lt;p&gt;One time, I needed to code up a list of Notifications, commonly known as "toasts". These pop up for a user's attention, populated by an API or some event, and can be dismissed by the user. They may look like this:&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.amazonaws.com%2Fuploads%2Farticles%2Fuzr0v2b8esf5fnm325z5.gif" 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.amazonaws.com%2Fuploads%2Farticles%2Fuzr0v2b8esf5fnm325z5.gif" alt="notification list with fade" width="276" height="264"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I wanted to build this in pure JS, but use it in React. At first I had an OOP model of it in mind- like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Notifications&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I wondered - could I use an object like this, in React, in such a way that whenever an item is added, the UI always displays the current &lt;code&gt;items&lt;/code&gt;? It seemed this object model wasn't enough to support a fully reactive list. I didn't want to build this out of React state - I wanted my items in pure JS, so any file that wanted a real-time view of them could simply import and use them. I did not want to worry about Context, or ReactTransitionGroup, or any other view-layer-specific issues, just code in pure JS!&lt;/p&gt;

&lt;p&gt;I also wondered how to implement them with fade-in/fade-out, since it's definitely smoother and less confusing with a transition. &lt;/p&gt;

&lt;p&gt;I first tried to write an API like this, wrapping a hook around our object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;notifications&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Notifications&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;notifications&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Svelte&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Notifications&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;notifications&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;items&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;addNew&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;notifications&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;RxFx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ol&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;addNew&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; 
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;li&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/li&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;))&lt;/span&gt;&lt;span class="sr"&gt; &lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ol&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I tried several times to implement this &lt;code&gt;useObject&lt;/code&gt; hook, including polling &lt;code&gt;items&lt;/code&gt;, but I was never happy with it. Particularly since it didn't address animation, and looked bad without it.&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.amazonaws.com%2Fuploads%2Farticles%2Fkeukhdtagvydwkrzo4us.gif" 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.amazonaws.com%2Fuploads%2Farticles%2Fkeukhdtagvydwkrzo4us.gif" alt="notification list with no fade" width="280" height="278"&gt;&lt;/a&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.amazonaws.com%2Fuploads%2Farticles%2Fuzr0v2b8esf5fnm325z5.gif" 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.amazonaws.com%2Fuploads%2Farticles%2Fuzr0v2b8esf5fnm325z5.gif" alt="notification list with fade" width="276" height="264"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then I found an object called a Service, from the &lt;code&gt;@rxfx/service&lt;/code&gt; package. With a Service, I could have what I wanted, even queued animations! I only had to change the API from the &lt;code&gt;useObject&lt;/code&gt; hook by a little bit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;notifications&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;createAsyncListService&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;notifications&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;push&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Svelte&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Notifications&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;notifications&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;addNew&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;notifications&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;push&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;RxFx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ol&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;addNew&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; 
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;li&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/li&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;))&lt;/span&gt;&lt;span class="sr"&gt; &lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ol&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of directly calling methods, I send objects with the method name into the service via its &lt;code&gt;request()&lt;/code&gt; method. I invoke &lt;code&gt;useService&lt;/code&gt; with a service you'll see defined shortly. Then I extract the state from the return value of &lt;code&gt;useService&lt;/code&gt;, and pluck of its &lt;code&gt;items&lt;/code&gt; field.&lt;/p&gt;

&lt;p&gt;To ensure it was reactive, I wrote the &lt;code&gt;addNew&lt;/code&gt; click handler to add an object on the fly. And did it update reactively? It did! Now, I had the reactive, async, animating list of my dreams!&lt;/p&gt;

&lt;p&gt;And so I thought I'd share how you can build this functionality in just a few lines of code with an RxFx service, ending up with framework free code you can use in any view layer from ReactNative to Angular to Svelte.&lt;/p&gt;

&lt;h3&gt;
  
  
  Defining the Service
&lt;/h3&gt;

&lt;p&gt;The first thing to understand about an async list vs. an immediate synchronous list, is that items can be in a state of entering or leaving, as well as fully present. So the state model can not simply be a list of &lt;code&gt;items&lt;/code&gt; as in the OOP model.&lt;/p&gt;

&lt;p&gt;There are at least two ways a service could represent this state.&lt;/p&gt;

&lt;p&gt;Option 1 is that the state could contain a value ranging from 0 to 100, updated on every animation frame, representing how fully in the list the item was. So, for an appearing item in the list:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;RxFx&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="na"&gt;percentComplete&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;95&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;percentComplete&lt;/code&gt; could be used to update DOM properties like &lt;code&gt;opacity&lt;/code&gt;, or &lt;code&gt;height&lt;/code&gt;. But this approach fails to make use of CSS' power to perform animations with just a class name. And it's also not clear whether the item is coming or going.&lt;/p&gt;

&lt;p&gt;Option 2 might be to model our state with &lt;code&gt;items&lt;/code&gt;, but also with &lt;code&gt;entering&lt;/code&gt; and &lt;code&gt;leaving&lt;/code&gt;. Imagine we already had &lt;code&gt;'Svelte'&lt;/code&gt; in the list, and pushed &lt;code&gt;'RxFx'&lt;/code&gt;. The state would resemble this, until 'RxFx' is done animating in.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Svelte&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;RxFx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="nx"&gt;entering&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;RxFx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="nx"&gt;leaving&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the state model RxFx' &lt;code&gt;createAsyncListService&lt;/code&gt; supplies. Here's all we have to do to use it. We define the service like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createAsyncListService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@rxfx/service&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PER_ITEM_DELAY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;notifications&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createAsyncListService&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;list/notifications&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;PER_ITEM_DELAY&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The (optional) arguments are a name for logging, which we'll see more of later. And a delay in milliseconds for each animation. &lt;/p&gt;

&lt;p&gt;Notice this service definition can and should live outside of any view component, it's just pure JavaScript! Let's see how to make our view layer react to it now.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using the Service
&lt;/h3&gt;

&lt;p&gt;Thanks to a utility from the &lt;code&gt;@rxfx/react&lt;/code&gt; library called &lt;code&gt;useService&lt;/code&gt;, the state of the service can be easily brought into the React view. This gives us arrays &lt;code&gt;items&lt;/code&gt;, and &lt;code&gt;entering&lt;/code&gt;, and we only need to check if an item is in &lt;code&gt;entering&lt;/code&gt;, to assign a CSS class to it to fade it in. The component using the service looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;List&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;entering&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;notifications&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;addNew&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;notifications&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;push&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;RxFx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ol&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;addNew&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; 
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isEntering&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;entering&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;isEntering&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;item-entering&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;li&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/li&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ol&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You are easily able to test that calling &lt;code&gt;addNew&lt;/code&gt; adds an item to the service state, and React picks up on it right away. If you wanted to see every change of the service state, you could also send it to the console on every change with this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;notifications&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And if you wanted to see every lifecycle event of the service - you can use the fact that it's a listener on an RxFx event bus, and simply log all event bus events to the console:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defaultBus&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@rxfx/service&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nx"&gt;defaultBus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;spy&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes debugging a breeze. Now, to finish things up, we just need some CSS to enable the fade, and voila, we're animating!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@keyframes&lt;/span&gt; &lt;span class="n"&gt;fadeIn&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="err"&gt;100&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.item-entering&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;animation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;fadeIn&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--per-item-delay&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A finishing touch is to send the same &lt;code&gt;DELAY&lt;/code&gt; we used in JavaScript into CSS, so the CSS animation and the service' delay are the same:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nb"&gt;document&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#root&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--per-item-delay&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PER_ITEM_DELAY&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;s&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(Thanks to David Khourshid of Stately AI for introducing me to CSS variables)&lt;/p&gt;

&lt;p&gt;Now, see the &lt;a href="https://codesandbox.io/p/sandbox/rxfx-asynclist-hdtsv5" rel="noopener noreferrer"&gt;CodeSandbox&lt;/a&gt; for the working version.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use &lt;code&gt;@rxfx/service&lt;/code&gt; for all the things!
&lt;/h3&gt;

&lt;p&gt;It turns out, this &lt;code&gt;@rxfx/service&lt;/code&gt; container is useful for any async effect, from animation to AJAX. And it has a standard API: &lt;code&gt;.request()&lt;/code&gt;, &lt;code&gt;.state.value&lt;/code&gt;, and &lt;code&gt;.cancelCurrent()&lt;/code&gt;, so you learn it once, and use it for many use cases. Even better, this code is directly usable in Svelte, or Angular or Vue, since it is pure JS/TS code with no view-layer dependencies!&lt;/p&gt;

&lt;p&gt;It's built on RxJS, and in other articles I'll show you how other async situations can be handled easily by wrapping an effect in an &lt;code&gt;@rxfx/service&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Happy Notifying!&lt;/p&gt;

&lt;p&gt;Please star &lt;a href="https://github.com/deanrad/rxfx/tree/main/service" rel="noopener noreferrer"&gt;@rxfx/service on GitHub&lt;/a&gt;!&lt;/p&gt;

&lt;h3&gt;
  
  
  Appendix: Integrating with Redux
&lt;/h3&gt;

&lt;p&gt;Many times, the need for animation comes up after a basic non-animated solution is in place. This was the case for these notifications. The items were in a Redux store, a &lt;code&gt;dispatch&lt;/code&gt; was used to put an item into the store, and a &lt;code&gt;useSelector&lt;/code&gt; hook brought the items to the page. After we add the RxFx service to handle transitions - will we need to keep Redux?&lt;/p&gt;

&lt;p&gt;In this app, in this particular case, we want to keep Redux informed of our list of notifications. We'll have the benefit of the Redux ecosystem, like Redux-Persist, to save and load the store to localStorage. &lt;/p&gt;

&lt;p&gt;So, we'll use the service for its animation ability, and Redux for persistence of state.&lt;/p&gt;

&lt;h4&gt;
  
  
  Inside a custom hook, make the service an intermediary
&lt;/h4&gt;

&lt;p&gt;Initially the Notifications component looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Notifications&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;addNew&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dismiss&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useNotifications&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="cm"&gt;/* render items */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A custom hook &lt;code&gt;useNotifications&lt;/code&gt; defined the API to notifications - you can retrieve &lt;code&gt;items&lt;/code&gt;, or &lt;code&gt;addNew&lt;/code&gt; or &lt;code&gt;dismiss&lt;/code&gt;, and these were implemented by a selector, and sending dispatches.&lt;/p&gt;

&lt;p&gt;We can keep this API - but internally we want to make the service an intermediary.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Instead of dispatching, we'll make &lt;code&gt;request()&lt;/code&gt; calls to the service&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;items&lt;/code&gt; of our service are used to populate Redux&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;items&lt;/code&gt; can still come from Redux&lt;/li&gt;
&lt;li&gt;We can get a class name for an item, based on the state of the service.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We'll add a &lt;code&gt;getClassName(item)&lt;/code&gt; to the hook's return value, then get to work inside:&lt;/p&gt;

&lt;h4&gt;
  
  
  Changing the custom hook
&lt;/h4&gt;

&lt;p&gt;Inside the hook, &lt;code&gt;push&lt;/code&gt; and &lt;code&gt;remove&lt;/code&gt; performed dispatches, and &lt;code&gt;items&lt;/code&gt; populated by a selector.&lt;/p&gt;

&lt;p&gt;Instead, now we'll change the dispatching functions to make &lt;code&gt;request()&lt;/code&gt; of our service. This ensures our service is in charge of all changes to &lt;code&gt;items&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Next, we need to sync these items to Redux as they change. We'll use the power of RxJS to ensure that we have an Observable of only changes of &lt;code&gt;items&lt;/code&gt;. This enables us to keep Redux free of any information like what is entering and leaving, and focus only on what should persist across sessions.&lt;/p&gt;

&lt;p&gt;The finished useNotifications hook looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;distinctUntilChanged&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rxjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./store&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;notifications&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./services/notifications&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// Sync to Redux&lt;/span&gt;
&lt;span class="nx"&gt;notifications&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nf"&gt;distinctUntilChanged&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;setItems&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nf"&gt;useNotifications&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;entering&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;leaving&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;notifications&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getClassName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cm"&gt;/*  based on whether entering/leaving */&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Make changes first to our service&lt;/span&gt;
  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;addNew&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;notifications&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;push&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;dismiss&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;notifications&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;remove&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;addNew&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dismiss&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getClassName&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that, we now have the service as our source of truth for the state of the UI, and Redux is a persistence layer, with all the benefits of its DevTools and persistence layer. &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.amazonaws.com%2Fuploads%2Farticles%2F6cndeczahkti7n4en73q.gif" 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.amazonaws.com%2Fuploads%2Farticles%2F6cndeczahkti7n4en73q.gif" alt="notification list with Redux" width="760" height="494"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, that's how we integrate. We let Redux do persistence, and let dynamic effects and animations live in a service, which is not persisted. A service will help you keep state fields like &lt;code&gt;loading&lt;/code&gt; out of your stores. That's right - you don't need to track &lt;code&gt;loading&lt;/code&gt; if you have a service! If you want to know whether the animation is running, you can pluck off the &lt;code&gt;isActive&lt;/code&gt; field from the &lt;code&gt;useService&lt;/code&gt; return value.&lt;/p&gt;

</description>
      <category>rxfx</category>
      <category>rxjs</category>
      <category>redux</category>
      <category>async</category>
    </item>
    <item>
      <title>How to use 𝗥𝘅𝑓𝑥 for a realistic user-typing simulation.</title>
      <dc:creator>Dean Radcliffe</dc:creator>
      <pubDate>Mon, 20 Mar 2023 18:14:06 +0000</pubDate>
      <link>https://dev.to/deanius/how-to-use-a-poisson-process-for-realistic-user-simulation-4aif</link>
      <guid>https://dev.to/deanius/how-to-use-a-poisson-process-for-realistic-user-simulation-4aif</guid>
      <description>&lt;p&gt;Here we will use a couple of components from the 𝗥𝘅𝑓𝑥 toolkit to write some text into a textarea, much as a user would fill out a form.&lt;/p&gt;

&lt;p&gt;If we use a library like &lt;code&gt;@testing-library/user-event&lt;/code&gt;, we can automate typing into a field with a configurable delay between characters. However, real users don't type this way, they type in spurts, like this:&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.amazonaws.com%2Fuploads%2Farticles%2F93n2mv1kv2yzf0sdox5f.gif" 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.amazonaws.com%2Fuploads%2Farticles%2F93n2mv1kv2yzf0sdox5f.gif" alt="Realistic typing" width="133" height="31"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Filling out a form in a randomized way  will stress-test your form more realistically - some of the time (about 1/6 of the time) your user's consecutive key presses will be half the average duration. Particularly if you are using React controlled inputs, this can reveal stutter in the system that you would not have known about. Also, I find that lorem ipsum text is more pleasurable to see typed with randomized timing than at a uniform rate! But importantly, we don't want total randomness - we want it to hover &lt;em&gt;around&lt;/em&gt; a certain given amount. &lt;/p&gt;

&lt;p&gt;So let's bring together a few 𝗥𝘅𝑓𝑥 tools together in order to pull this off, we will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use a bus, typed for character events.&lt;/li&gt;
&lt;li&gt;Trigger character events from a source text.&lt;/li&gt;
&lt;li&gt;Create a listener that returns a time-deferred typing from a character event&lt;/li&gt;
&lt;li&gt;Allow the bus to execute and sequence those time-deferred typings&lt;/li&gt;
&lt;li&gt;Randomize the time amounts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the final step, the code will change only by one line in order to switch to random from not random! Let's dive right in!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codesandbox.io/s/rxfx-example-poisson-process-typing-hncrl0" rel="noopener noreferrer"&gt;See the CodeSandbox&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First, we can type the &lt;code&gt;defaultBus&lt;/code&gt; from &lt;code&gt;@rxfx/bus&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defaultBus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Bus&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@rxfx/bus&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;defaultBus&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Bus&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next we'll use a good old-fashioned &lt;code&gt;for&lt;/code&gt; loop to trigger an event for each character:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;srcText&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;bus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;srcText&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;charAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Building the listener will be tricky - first we know we can't have overlapping character typings - we want them serially. So we will create our listener with &lt;code&gt;bus.listenQueueing&lt;/code&gt;. What will we return? We could have written any delayed Promise function and that would work, but the 𝗥𝘅𝑓𝑥 utility &lt;code&gt;after&lt;/code&gt; is designed just for that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@rxfx/after&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;typer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;bus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listenQueueing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;char&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;after&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AVERAGE_DELAY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;char&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is our entire async behavior!  Those &lt;code&gt;after&lt;/code&gt; values just queue up - they're lazy Observables. But let's not forget that final touch - the randomization.&lt;/p&gt;

&lt;p&gt;In case you are thinking this will be very hard, never fear, 𝗥𝘅𝑓𝑥' &lt;code&gt;@rxfx/perception&lt;/code&gt; exports a function that randomizes numbers given it, but in a way that the average is preserved. We just drop it in a place that used to have a constant, and we're good.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gi"&gt;+ import { randomizePreservingAverage } from "@rxfx/perception";
&lt;/span&gt;&lt;span class="err"&gt;

&lt;/span&gt;&lt;span class="p"&gt;const typer = bus.listenQueueing(
&lt;/span&gt;  () =&amp;gt; true, 
  (char) =&amp;gt; {
&lt;span class="gd"&gt;-    return after(AVERAGE_DELAY, () =&amp;gt; {
&lt;/span&gt;&lt;span class="gi"&gt;+    return after(randomizePreservingAverage(AVERAGE_DELAY), () =&amp;gt; {
&lt;/span&gt;      console.write(char);
    });
  }
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, all that's left to do is trigger each character to the bus, and the queued effects will produce randomly timed typing!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;This message will reveal randomly&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;char&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;bus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;char&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There we go! A pseudo-human typist - something that will look good for chatbot responses, AI, Chat GPT - whatever!&lt;/p&gt;

&lt;p&gt;Check out &lt;a href="https://codesandbox.io/s/rxfx-example-poisson-process-typing-hncrl0" rel="noopener noreferrer"&gt;the CodeSandbox&lt;/a&gt; and then see how you can use, and enjoy using this!&lt;/p&gt;

&lt;p&gt;—𝗥𝘅𝑓𝑥&lt;/p&gt;

&lt;p&gt;PS How does &lt;code&gt;randomizePreserveAverage&lt;/code&gt; work? One answer I could tell you is that it scales a number by the absolute value of a randomly chosen logarithm between 0 and 1. But a more intuitive way to say it is that it makes 1/3 of numbers larger, while 2/3 get smaller — given that a single doubling event requires two halving events to preserve the average.&lt;/p&gt;

</description>
      <category>rxfx</category>
      <category>rxjs</category>
      <category>statistics</category>
    </item>
    <item>
      <title>Excellent Effect Management in React with 𝗥𝘅𝑓𝑥 and RxJS</title>
      <dc:creator>Dean Radcliffe</dc:creator>
      <pubDate>Fri, 17 Mar 2023 19:45:28 +0000</pubDate>
      <link>https://dev.to/deanius/excellent-effect-management-in-react-with-and-rxjs-35cn</link>
      <guid>https://dev.to/deanius/excellent-effect-management-in-react-with-and-rxjs-35cn</guid>
      <description>&lt;p&gt;In &lt;a href="https://dev.to/deanius/how-an-interview-convinced-me-to-use-an-event-bus-for-rxjs-in-react-396l"&gt;Part 1&lt;/a&gt;, I'd shared an interview that opened my mind to how, and why, to use 𝗥𝘅𝑓𝑥 in React. &lt;/p&gt;

&lt;p&gt;In this final installment part we take the UX of the Cat Fetcher to the extreme by adding these features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Preload images as a chained part of the &lt;code&gt;gifService&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Cancel an image preload when canceled.&lt;/li&gt;
&lt;li&gt;Send out Analytics events, without coupling to existing code.&lt;/li&gt;
&lt;li&gt;Apply a timeout to the Ajax load and overall load. &lt;/li&gt;
&lt;li&gt;Pad the loading spinner to a minimum duration.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We'll even build a cancelable image preloader along the way. So let's dive right in!&lt;/p&gt;




&lt;h2&gt;
  
  
  Chained Loading Of the Image Bytes
&lt;/h2&gt;

&lt;p&gt;There was an issue with our service. &lt;code&gt;isActive&lt;/code&gt; would become &lt;code&gt;false&lt;/code&gt; at the time where we knew the URL of the cat image-  but didn't yet have its bytes:&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.amazonaws.com%2Fuploads%2Farticles%2F782aeot3lnlgyfqmclvl.jpg" 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.amazonaws.com%2Fuploads%2Farticles%2F782aeot3lnlgyfqmclvl.jpg" alt="loading indicator analysis" width="800" height="365"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This led to the loading indicator turning off, and the UI looks like it's doing nothing - until the image bytes arrive. And that image could take a while to load, if over a slow pipe!&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.amazonaws.com%2Fuploads%2Farticles%2Flw6z50d8c9ygg4odjqux.gif" 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.amazonaws.com%2Fuploads%2Farticles%2Flw6z50d8c9ygg4odjqux.gif" alt="template with loading state, with delay" width="380" height="395"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Image Preloading
&lt;/h2&gt;

&lt;p&gt;This old trick always worked to preload an image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;preloadImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a Promise-returning function that resolves (with the img &lt;code&gt;url&lt;/code&gt;) only once the image has loaded. Perfect! But how would we chain/compose that with the Observable? Simple - one line, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  return
     ajax.getJSON("https://api.thecatapi.com/v1/images/search", {...})
     .pipe(
        map((data) =&amp;gt; data[0].url),
&lt;span class="gi"&gt;+        mergeMap(preloadImage)
&lt;/span&gt;     );
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Perfect! We've used the fact that a function which returns &lt;code&gt;Promise&amp;lt;string&amp;gt;&lt;/code&gt; can be composed onto an Observable with &lt;code&gt;mergeMap&lt;/code&gt; - because a &lt;code&gt;Promise&amp;lt;string&amp;gt;&lt;/code&gt; is a subset of an &lt;code&gt;ObservableInput&amp;lt;string&amp;gt;&lt;/code&gt;. That's all we needed.&lt;/p&gt;

&lt;p&gt;But for comparison purposes, and to get ready for cancelation, let's return an Observable instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;preloadImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Observable&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;notify&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;notify&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;notify&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So we change our Promise-returning function into an Observable-returning one - sending out a single &lt;code&gt;next&lt;/code&gt; notification (like a Promise's singular resolution) - followed by a single &lt;code&gt;complete&lt;/code&gt; notification. Now we're ready for cancelation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cancelation
&lt;/h2&gt;

&lt;p&gt;This chaining, or 'composition', is convenient, but not yet optimal. If a cancelation occurs while the image bytes are loading  - the loading of the image itself is not canceled. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://camo.githubusercontent.com/848f567ba25b79138ef70b1d7c7139645544ee3fc617d7adc13ffc4ddd0db617/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f7777772e6465616e6975732e636f6d2f6361742d726571756573742d32782d756e6d6f756e742d776974682d6c65616b732e676966" class="article-body-image-wrapper"&gt;&lt;img src="https://camo.githubusercontent.com/848f567ba25b79138ef70b1d7c7139645544ee3fc617d7adc13ffc4ddd0db617/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f7777772e6465616e6975732e636f6d2f6361742d726571756573742d32782d756e6d6f756e742d776974682d6c65616b732e676966" alt="not canceled" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The strength of the Observable is you can bundle cleanup/cancelation logic right at the definition of the Effect. For this cancelation,  we should cancel the Image loading by switching the &lt;code&gt;src&lt;/code&gt; property to an image that doesn't need downloading. The DOM would then cancel itself..&lt;/p&gt;

&lt;p&gt;So we simply return a cancelation function from the Observable constructor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;function preloadImage(url) {
&lt;/span&gt;  return new Observable((notify) =&amp;gt; {
    const img = new Image();
    img.onload = () =&amp;gt; {
      notify.next(url);
      notify.complete();
    };
    img.src = url;
&lt;span class="gi"&gt;+
+   return () =&amp;gt; img.src = "data:image/gif;base64,R0lGOD...Ow==";
&lt;/span&gt;  };
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, even when cancelation occurs during image bytes downloading, the Observable teardown can stop it mid-request! Cool and performant!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://camo.githubusercontent.com/9ba133a6ba0b9fd0577fdadb87e43d0dc7e25ebf11fe8f63ef3bb7088f69478a/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f7777772e6465616e6975732e636f6d2f6361742d696d6167652d726571756573742d756e6d6f756e742d63616e63656c2d73746174657265636c61696d2e676966" class="article-body-image-wrapper"&gt;&lt;img src="https://camo.githubusercontent.com/9ba133a6ba0b9fd0577fdadb87e43d0dc7e25ebf11fe8f63ef3bb7088f69478a/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f7777772e6465616e6975732e636f6d2f6361742d696d6167652d726571756573742d756e6d6f756e742d63616e63656c2d73746174657265636c61696d2e676966" alt="Cancelable Image Download" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Other Subscribers - Analytics
&lt;/h2&gt;

&lt;p&gt;Now, a new Feature Request arrives that requires we log clicks to an Analytics Service whenever the Fetch Cat button is pressed, so marketing can assess how engaging the app is.&lt;/p&gt;

&lt;p&gt;You might be wondering now whether the UI &lt;code&gt;onClick&lt;/code&gt; handler, or the &lt;code&gt;gifService&lt;/code&gt; Observable ought to change. 𝗥𝘅𝑓𝑥 says - change neither, they're done already! &lt;/p&gt;

&lt;p&gt;Handle it by observing the service's requests, with a cancelable item called a Subscription:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;analyticsSub&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;gifService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt; &lt;span class="nf"&gt;logAnalytics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fetch cat clicked&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="c1"&gt;// to turn off&lt;/span&gt;
&lt;span class="c1"&gt;// analyticsSub.unsubscribe();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For light-weight fire-and-forget functions you don't need to chain or concurrency-control, this mechanism will decouple sections of your codebase, and allow you to keep the code intact (and tests!) of existing components.&lt;/p&gt;

&lt;h2&gt;
  
  
  Timeouts
&lt;/h2&gt;

&lt;p&gt;Users don't want to wait forever without feedback, and even a spinner gets old. In &lt;a href="https://dev.to/deanius/the-thresholds-of-perception-in-ux-435g"&gt;this post&lt;/a&gt;, I set out some thresholds that are handy to reference in timing constants - they are published in the &lt;code&gt;@rxfx/perception&lt;/code&gt; library. Whatever values we choose, we need to pass them into code somewhere, and there are a few places this may happen.&lt;/p&gt;

&lt;p&gt;For the AJAX to get the URL of the next cat image, we can specify a timeout directly in its options:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;function fetchRandomGIF() {
&lt;/span&gt;  return ajax({
    url: "https://api.thecatapi.com/v1/images/search",
&lt;span class="gi"&gt;+    timeout: TIMEOUTS.URL
&lt;/span&gt;  }).pipe(
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;gifService&lt;/code&gt; will trigger a &lt;code&gt;gif/error&lt;/code&gt; to the bus if it fails to get the url within that timeout. &lt;/p&gt;

&lt;p&gt;But we must ask if overall our &lt;code&gt;gif/request&lt;/code&gt; handler might exceed the user's patience. For that, we can wrap the handler in a &lt;code&gt;timeoutHandler&lt;/code&gt; modifier from &lt;code&gt;@rxfx/service&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;export const gifService = createQueueingService(
&lt;/span&gt;  "gif", // namespace for actions requested,started,next,complete,error,etc
  bus, // bus to read consequences and requests from
&lt;span class="gd"&gt;-  fetchRandomGIF,
&lt;/span&gt;&lt;span class="gi"&gt;+  timeoutHandler({ duration: TIMEOUTS.OVERALL }, fetchRandomGIF),
&lt;/span&gt;  (ACTIONS) =&amp;gt; gifReducer(ACTIONS)
);
&lt;span class="err"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Doing it this way, our &lt;code&gt;currentError&lt;/code&gt; property of the service will display information about the timeout, just like any other error!&lt;/p&gt;

&lt;h2&gt;
  
  
  Concurrency Control
&lt;/h2&gt;

&lt;p&gt;We just handled what happens when the connection is too slow - and we ensured that users get feedback rather than wait forever. But can it ever trouble users if their connection is too fast? Imagine - a user performs 3 quick clicks to queue up 3 kitty downloads - and they could be displayed, and gone before they have a chance to be admired if they download too fast. Here we can pad the download with just another RxJS operator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;function fetchRandomGIF() {
&lt;/span&gt;  return ajax({
    url: "https://api.thecatapi.com/v1/images/search",
    timeout: TIMEOUTS.URL
  }).pipe(
    mergeMap(preloadImage),
&lt;span class="gi"&gt;+   padToTime(TIMEOUTS.KITTY_MINIMUM)
&lt;/span&gt;  )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While we may decide this amount of padding isn't necessary in every app, for these cute kitties it's probably worth it 😀 🐈 The lesson, of course, is that any RxJS or 𝗥𝘅𝑓𝑥 operator can be used to modify timing with usually no change to surrounding code - whether it's for timeout or time padding. This lets our UX be more intentional in its experience, and less vulnerable to random network conditions.&lt;/p&gt;




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

&lt;p&gt;If there's one thing this code example showed, it's that there's never anything as simple as 'async data fetching'. Timing, timeouts, cancelation, and chained and related effects are requirements that swiftly come on the heels of making a simple &lt;code&gt;fetch&lt;/code&gt;. Excellence in UX depends upon handling these 'edge cases' in the very core of your product.&lt;/p&gt;

&lt;p&gt;𝗥𝘅𝑓𝑥 has the features you need so that the app can scale in functionality without ballooning in complexity.&lt;/p&gt;

</description>
      <category>rxjs</category>
      <category>rxfx</category>
      <category>javascript</category>
      <category>react</category>
    </item>
    <item>
      <title>The Radcliffe Concurrency Model</title>
      <dc:creator>Dean Radcliffe</dc:creator>
      <pubDate>Sun, 13 Nov 2022 08:38:08 +0000</pubDate>
      <link>https://dev.to/deanius/the-radcliffe-concurrency-model-3ll8</link>
      <guid>https://dev.to/deanius/the-radcliffe-concurrency-model-3ll8</guid>
      <description>&lt;p&gt;TL;DR The Radcliffe Concurrency Model is a way of understanding how a computer resource, or person responds to an interruption, which will help us understand multitasking in programming, and in life.&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.amazonaws.com%2Fuploads%2Farticles%2Ftb29grcc1worb147ylz7.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.amazonaws.com%2Fuploads%2Farticles%2Ftb29grcc1worb147ylz7.png" alt="The Radcliffe Model of Concurrency" width="800" height="736"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Interruptions are a fact of life. Nobody has the luxury of being able to single-task on each thing they start until its sweet completion. No— life is more like this: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Kid: "Dad, I want a grilled cheese, please."&lt;/li&gt;
&lt;li&gt;Dad: &lt;em&gt;starts making a grilled cheese sandwich...&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Kid: "Dad, can I have chicken nuggets?"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When we ask what we would do as the dad, we are considering which one of our &lt;strong&gt;Concurrency Strategies&lt;/strong&gt; should we use? We'll list these out shortly. But first - notice that although everyone makes these strategy choices - &lt;em&gt;nobody can quickly list what all the choices are!&lt;/em&gt; It's like we haven't studied this problem space well enough to pin down the options.&lt;/p&gt;

&lt;p&gt;So we'll list the options-but first we'll see how much we need them, and how widely they apply, for developers and humans alike :)&lt;/p&gt;

&lt;h2&gt;
  
  
  A Lack of Shared Vocabulary Weighs Us Down
&lt;/h2&gt;

&lt;p&gt;If you do something alot, it pays to have concise words to describe it. Some languages have many words for rain or snow or love. Resource schedulers like us need better conceptual tools as well.&lt;/p&gt;

&lt;p&gt;What I find today is that async programs —and the humans that make them— do &lt;strong&gt;not&lt;/strong&gt; currently reflect the awareness of these modes. They seem to be a mix of defaulting into a strategy like &lt;strong&gt;Immediate&lt;/strong&gt; , or using only what's &lt;em&gt;easiest&lt;/em&gt; in the features of our programming tools. But now, to be able to make clear, tiny-sized changes that fix timing behavior &lt;em&gt;declaratively&lt;/em&gt; is a game changer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interruptions Affect Computers, UX and People
&lt;/h2&gt;

&lt;p&gt;Computers too must decide what to do when they are busy and get a new request. A chain of coffeehouses has a Dropbox into which each coffehouse uploads its daily transactions as a CSV file. The server is now processing a file of 500 transactions, and a new, different file from the same coffeehouse gets dropped there. What should the server do?&lt;/p&gt;

&lt;p&gt;In User Interface / UX these strategies must be chosen and used everywhere! A user begins one download while already downloading another. Or a Ring notification sound is triggered but another just started. Or a like button is clicked twice, or two like buttons in close succession. Or a remote control is slow to respond and you press the button again. &lt;em&gt;What should the app do?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Front-end development, back-end development, and every person you know depends upon selecting good Concurrency Strategies. Then, why don't we know what they are? Is there a listable set? There is, and the Radcliffe Model of Concurrency makes them available for our understanding, so that we can choose the correct one for each UX, or life situation.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Also a JavaScript library &lt;a href="https://github.com/deanrad/rxfx" rel="noopener noreferrer"&gt;𝗥𝘅𝑓𝑥&lt;/a&gt; makes them available to program with directly)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Knowing Our Options is Empowering
&lt;/h2&gt;

&lt;p&gt;Before they were called The Radcliffe Model, the Concurrency Strategies, &lt;em&gt;aka modes&lt;/em&gt;, were cheekily called: &lt;em&gt;The 5 Kinds of Busy.&lt;/em&gt; For the situation of the Dad making dinner, then given another request, the dad could:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Start satisfying the 2nd request right away.&lt;/li&gt;
&lt;li&gt;Make it after the 1st request, to use the same pan.&lt;/li&gt;
&lt;li&gt;Stop the 1st request, make the 2nd instead.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The other two modes sound funny when applied to humans, but are still relevant sometimes!&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ignore the 2nd request—basically the &lt;em&gt;"Not Now"&lt;/em&gt; response.&lt;/li&gt;
&lt;li&gt;Turn off the stove and just quit. "I cant keep changing what I make for you— come back when you know what you want!" (This has &lt;em&gt;never&lt;/em&gt; happened in the Radcliffe household! 😂)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So, it was out of necessity, that the Radcliffe Model was born!&lt;/p&gt;

&lt;h2&gt;
  
  
  The Radcliffe Model of Concurrency
&lt;/h2&gt;

&lt;p&gt;The modes in the Radcliffe Model, in English are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Immediate&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Queueing&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Replacing&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Blocking&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Toggling&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&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.amazonaws.com%2Fuploads%2Farticles%2Ftb29grcc1worb147ylz7.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.amazonaws.com%2Fuploads%2Farticles%2Ftb29grcc1worb147ylz7.png" alt="The Radcliffe Model of Concurrency" width="800" height="736"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I recognize these might not be the names you'd call these - you may have used &lt;code&gt;serial&lt;/code&gt; and &lt;code&gt;parallel&lt;/code&gt;, for either of the top 2 modes. Fine! But the value is not in what they are called, but the fact &lt;em&gt;that they are known as an entire set.&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;Sometimes, trying to fulfill every request of you, as &lt;strong&gt;Immediate&lt;/strong&gt; and &lt;strong&gt;Queueing&lt;/strong&gt; modes do - stretches resources too thin. The &lt;strong&gt;Blocking&lt;/strong&gt; mode may smartly reduce concurrency by favoring a prior request, just as an elevator that is already requested does nothing on subsequent calls to the same floor. The &lt;strong&gt;Replacing&lt;/strong&gt; mode is seen in how one video playing replaces another when we browse a social site, or how your session timeout keeps starting over after activity. And &lt;strong&gt;Toggling&lt;/strong&gt; is what a one-button power switch does - more on &lt;strong&gt;Toggling&lt;/strong&gt; later.&lt;/p&gt;

&lt;p&gt;The reason to learn this model is that getting a computer program, UX, or human behavior to be correct is often done simply by &lt;em&gt;choosing the best mode from the list!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I'll save an elaboration and derivation of each mode for another article. The graphic arranges them spatially to show how they relate, and at the end of the article are some trading-card-style images you can even print as a reference! (And play Oblique Strategies with them if you like) &lt;/p&gt;

&lt;h2&gt;
  
  
  Yes, Toggling is a Real Thing!
&lt;/h2&gt;

&lt;p&gt;Some of you inquire why &lt;strong&gt;Toggling&lt;/strong&gt; is in this list, since it's actually a failure to do anything concurrent. That's true. Yet still - sometimes it is the called-for response to an interruption.&lt;/p&gt;

&lt;p&gt;Sometimes the presence of a 2nd request - like a second nightly file put into the Dropbox on the same night - indicates an exception or error condition.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Toggle&lt;/strong&gt; and kin are analyzed more in the next post&lt;/p&gt;

&lt;h2&gt;
  
  
  Go Forth and Be Concurrent!
&lt;/h2&gt;

&lt;p&gt;You can use this model to further your or your colleagues' understandings of multitasking strategies. Or if you program asynchronous systems like User Interfaces, you can use &lt;a href="https://github.com/deanrad/rxfx/tree/main/bus" rel="noopener noreferrer"&gt;𝗥𝘅𝑓𝑥&lt;/a&gt;, to have the easiest, framework-free async programming experience you could have.&lt;/p&gt;

&lt;p&gt;To share it, just consult the &lt;a href="https://creativecommons.org/licenses/by-sa/4.0/" rel="noopener noreferrer"&gt;Attribution-Share-alike license&lt;/a&gt;, which generally says it is free to share,provided you attribute the author and maintain the same terms.&lt;/p&gt;

&lt;p&gt;Folks with translation skills - would you propose your languages' names for the modes in the comments?&lt;/p&gt;

&lt;p&gt;Thanks, I'd love to hear how you've found this model to apply to you!&lt;/p&gt;

&lt;p&gt;Dean Radcliffe (&lt;a href="https://twitter.com/DeanDevDad" rel="noopener noreferrer"&gt;@DeanDevDad&lt;/a&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.amazonaws.com%2Fuploads%2Farticles%2Fjussnxconmdjyvvnt9w1.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.amazonaws.com%2Fuploads%2Farticles%2Fjussnxconmdjyvvnt9w1.png" alt="RxFx Strategy Cards" width="800" height="761"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>rxjs</category>
      <category>rxfx</category>
      <category>concurrency</category>
      <category>javascript</category>
    </item>
    <item>
      <title>RxJS - I Have A Bone To Pick With You</title>
      <dc:creator>Dean Radcliffe</dc:creator>
      <pubDate>Mon, 31 Oct 2022 14:28:23 +0000</pubDate>
      <link>https://dev.to/deanius/rxjs-i-have-a-bone-to-pick-with-you-31nb</link>
      <guid>https://dev.to/deanius/rxjs-i-have-a-bone-to-pick-with-you-31nb</guid>
      <description>&lt;p&gt;RxJS, there are some things I really love about you, but I think I'm falling for someone new - &lt;a href="https://github.com/deanrad/rxfx/tree/main/bus" rel="noopener noreferrer"&gt;𝗥𝘅𝑓𝑥&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your popularity— You have more downloads a month than React and Angular combined.&lt;/p&gt;

&lt;p&gt;Your maturity— You're a ripe 13 years old. Forever in technology time, and 3 years older than Promises, even.&lt;/p&gt;

&lt;p&gt;Your utility— For eliminating race conditions, all forms of timing control, and resource management— you have no equal.&lt;/p&gt;

&lt;p&gt;But RxJS— with all this time you've been around, how come everybody doesn't know that you're the best already? How did you let React become the biggest framework, with useEffect and its quirks, and not even have them build upon you - the best choice available at the time? Now there are all these React developers out there who don't know the joy and power of working with you, RxJS. &lt;/p&gt;

&lt;p&gt;But I know you're thinking what React did can't be your fault right? I mean - your documentation is perfect right? No friction to onboarding at-all, right... &lt;/p&gt;

&lt;p&gt;So to help you out, I'm going to tell you about your DevRel issues (DevRel) and how to fix them. To start, you gotta do something about your...&lt;/p&gt;

&lt;h2&gt;
  
  
  Confusing Concurrency Docs
&lt;/h2&gt;

&lt;p&gt;Your documentation for your &lt;code&gt;*Map&lt;/code&gt; operators is tragically hard to read. In the v6 docs you say &lt;code&gt;exhaustMap&lt;/code&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Projects each source value to an Observable which is merged in the output Observable only if the previous projected Observable has completed. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, a previously running &lt;del&gt;Observable&lt;/del&gt; Subscription &lt;strong&gt;blocks&lt;/strong&gt; others from starting, you mean.&lt;/p&gt;

&lt;p&gt;You could have called it something resembling &lt;strong&gt;Blocking&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Your concurrency operators (&lt;code&gt;mergeMap&lt;/code&gt;, &lt;code&gt;concatMap&lt;/code&gt;, &lt;code&gt;switchMap&lt;/code&gt;, and &lt;code&gt;exhaustMap&lt;/code&gt;) focus on the notifications themselves, instead of the concurrency strategy that produces them.&lt;/p&gt;

&lt;p&gt;This mapping operator could be illustrated by a picture:&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.amazonaws.com%2Fuploads%2Farticles%2F5afpdkog8gnlir4f6w5r.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.amazonaws.com%2Fuploads%2Farticles%2F5afpdkog8gnlir4f6w5r.png" alt="Blocking Concurrency Mode" width="674" height="996"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Or the family of all of them illustrated as cards with common names and use cases.&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.amazonaws.com%2Fuploads%2Farticles%2Fduc3byn5cbqvbt0u9kg8.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.amazonaws.com%2Fuploads%2Farticles%2Fduc3byn5cbqvbt0u9kg8.png" alt="RxFx cards" width="800" height="761"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That will straighten out your comprehensability issue around these operators.&lt;/p&gt;

&lt;h2&gt;
  
  
  Observable vs Subscription Confusion
&lt;/h2&gt;

&lt;p&gt;Developers who understand Promises often fail to realize that an Observable is doing nothing without a Subscription. This is what makes an Observable not something you can &lt;code&gt;await&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But RxJS, you sometimes fail to differentiate sufficiently between an Observable and a Subscription in the docs! When the &lt;code&gt;exhaustMap&lt;/code&gt; docs said: &lt;em&gt;"only if the previous projected Observable has completed"&lt;/em&gt; - that should have said &lt;em&gt;"the previously running Subscription has completed"&lt;/em&gt;. Observables are templates for work. Only subscriptions can deliver values.&lt;/p&gt;

&lt;p&gt;I don't think calling an Observable multicast helps either. An Observable, being like a command, can be executed several times - we dont say that the command is multicasting to its executions. &lt;/p&gt;

&lt;p&gt;I don't like calling an Observable a 'stream' of notifications either - it may not have any! I prefer to say that an Observable is a template for creating a process - containing a start function and a cleanup function.&lt;/p&gt;

&lt;p&gt;So - terminology is confusing. But it's also unclear where to split up a big chain of Observables.&lt;/p&gt;

&lt;h2&gt;
  
  
  App Partitioning / Where to Call Subscribe
&lt;/h2&gt;

&lt;p&gt;Some schools of RxJS believe in constructing a giant chain of Observables, with some higher-order ones in the middle, and calling &lt;code&gt;.subscribe()&lt;/code&gt; once at the end of it only. The &lt;a href="https://www.learnrxjs.io/learn-rxjs/recipes/swipe-to-refresh" rel="noopener noreferrer"&gt;Swipe-To-Refresh example from LearnRxJS.io&lt;/a&gt; does this.&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%2Fdrive.google.com%2Fuc%3Fexport%3Dview%26id%3D1BLA2TcAhjwtodkcnsJ8e91ckrvurqkEv" 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%2Fdrive.google.com%2Fuc%3Fexport%3Dview%26id%3D1BLA2TcAhjwtodkcnsJ8e91ckrvurqkEv" alt="swipe to refresh demo" width="1920" height="1080"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check out its code on &lt;a href="https://stackblitz.com/edit/rxjs-refresh?devtoolsheight=40&amp;amp;file=index.ts" rel="noopener noreferrer"&gt;StackBlitz&lt;/a&gt;. I don't know what you thought separation of concerns was supposed to be - but I don't think that is it. &lt;/p&gt;

&lt;p&gt;What &lt;em&gt;are&lt;/em&gt; good practices, when combining Observables, especially higher-order ones? If operators are the individual words of your code paragraphs, what does a sentence-level structure look like? If we had that it might help us solve...&lt;/p&gt;

&lt;h2&gt;
  
  
  Operator Soup
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://www.learnrxjs.io/learn-rxjs/recipes/swipe-to-refresh" rel="noopener noreferrer"&gt;Swipe-To-Refresh example from LearnRxJS.io&lt;/a&gt; starts out with 19 imported operators and functions with raw RxJS. With 𝗥𝘅𝑓𝑥 you implement &lt;em&gt;the same functionality&lt;/em&gt; with 6. That's 66% less you have to fit into your mind at once, 13 fewer operators to understand.&lt;/p&gt;

&lt;p&gt;Some of this comes from demo sites wanting to show all operators in use. But it's not uncommon to find a ton of operators in real RxJS production code. While each one is purposeful, their many combinations can be confusing.&lt;/p&gt;

&lt;p&gt;If we could use fewer operators, we would have less code, and not suffer from as many...&lt;/p&gt;

&lt;h2&gt;
  
  
  Errors
&lt;/h2&gt;

&lt;p&gt;This is already a well covered topic, RxJS. But you already know it's a source of pain and confusion. Recent changes have helped producers interfere with each other less, but the risk of &lt;code&gt;UnhandledRejectionError&lt;/code&gt; bringing down a process is still large. &lt;/p&gt;

&lt;p&gt;Why can't we specify 'containers' that can individually terminate on error, without risk to the overall process?&lt;/p&gt;

&lt;p&gt;You see, we need some help, RxjS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution - 𝗥𝘅𝑓𝑥
&lt;/h2&gt;

&lt;p&gt;When a community and library are mature enough, some "contrib" library emerges that the community puts its best value-add goodies in. That is what 𝗥𝘅𝑓𝑥 aims to be. &lt;/p&gt;

&lt;p&gt;𝗥𝘅𝑓𝑥 is RxJS "The Good Parts". With infinite expansion possibilities via 'raw' RxJS.&lt;/p&gt;

&lt;p&gt;Problems like Confusing Docs, Observable vs Subscription Confusion, App partitioning, and Operator Soup, and even Errors are reduced when 𝗥𝘅𝑓𝑥 is your interface to RxJS. &lt;/p&gt;

&lt;p&gt;Think of 𝗥𝘅𝑓𝑥 as sugar around an RxJS &lt;code&gt;Subject&lt;/code&gt; that acts as an event bus. Each subscriber we call a "listener", and it is a concurrency-controlled, independent Subscription that is error-isolated from all others.&lt;/p&gt;

&lt;p&gt;Basically, this means you can get more done with less skipping the several years you need to be fluent in RxJS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Case Study— RxJS &lt;a href="https://stackblitz.com/edit/rxjs-refresh?devtoolsheight=40&amp;amp;file=index.ts" rel="noopener noreferrer"&gt;Swipe-To-Refresh Demo&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://stackblitz.com/edit/rxjs-refresh?devtoolsheight=40&amp;amp;file=index.ts" rel="noopener noreferrer"&gt;Swipe-To-Refresh Demo&lt;/a&gt; starts out with 19 imported operators and functions with raw RxJS. In 𝗥𝘅𝑓𝑥 - it needs only 6.&lt;/p&gt;

&lt;p&gt;I'll dissect and rebuild it in my &lt;a href="https://dev.to/deanius/-a-productivity-layer-around-rxjs-2igi"&gt;next post&lt;/a&gt; :)&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/deanrad/rxfx/tree/main/bus" rel="noopener noreferrer"&gt;𝗥𝘅𝑓𝑥 Bus Readme&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/deanrad/rxfx-example-swipe-to-refresh-blitz/pulls" rel="noopener noreferrer"&gt;Swipe-To-Refresh commit-by-commit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://codesandbox.io/search?query=rxfx&amp;amp;page=1&amp;amp;configure%5BhitsPerPage%5D=12&amp;amp;refinementList%5Bnpm_dependencies.dependency%5D%5B0%5D=%40rxfx%2Fbus&amp;amp;refinementList%5Bnpm_dependencies.dependency%5D%5B1%5D=%40rxfx%2Fservice" rel="noopener noreferrer"&gt;𝗥𝘅𝑓𝑥 Examples&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://replit.com/@deanius/Hello-World-rxfxbus#index.js" rel="noopener noreferrer"&gt;𝗥𝘅𝑓𝑥 Minimal Repl on Repl.it&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




</description>
      <category>rxjs</category>
      <category>rxfx</category>
      <category>angluar</category>
      <category>observables</category>
    </item>
    <item>
      <title>𝗥𝘅𝑓𝑥 - A productivity layer around RxJS.</title>
      <dc:creator>Dean Radcliffe</dc:creator>
      <pubDate>Mon, 17 Oct 2022 19:43:09 +0000</pubDate>
      <link>https://dev.to/deanius/-a-productivity-layer-around-rxjs-2igi</link>
      <guid>https://dev.to/deanius/-a-productivity-layer-around-rxjs-2igi</guid>
      <description>&lt;p&gt;RxJS and Observables solve 2 problems that every front-end dev has: Tuning async code for performance and eliminating race conditions for optimal UX.&lt;/p&gt;

&lt;p&gt;In this post, we'll deep-dive into building an example with the two main abstractions for async in 𝗥𝘅𝑓𝑥: the bus listener, and the service.&lt;/p&gt;

&lt;h1&gt;
  
  
  Example: Swipe To Refresh
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;Obective:&lt;/em&gt; Build a "Swipe To Refresh" UX widget with an 𝗥𝘅𝑓𝑥 event bus from &lt;a href="https://github.com/deanrad/rxfx/tree/main/bus" rel="noopener noreferrer"&gt;&lt;code&gt;@rxfx/bus&lt;/code&gt;&lt;/a&gt;, and a service on that bus from &lt;a href="https://github.com/deanrad/rxfx/tree/main/service" rel="noopener noreferrer"&gt;&lt;code&gt;@rxfx/service&lt;/code&gt;&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;(A complete version is here &lt;a href="https://stackblitz.com/edit/rxjs-refresh-jg6uy6?devtoolsheight=40&amp;amp;file=README.md,index.ts" rel="noopener noreferrer"&gt;on StackBlitz&lt;/a&gt;, and built incrementally &lt;a href="https://github.com/deanrad/rxfx-example-swipe-to-refresh-blitz/pull/15/files" rel="noopener noreferrer"&gt;on GitHub&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  What We'll Build
&lt;/h1&gt;

&lt;p&gt;A drag-and-drop UI widget that can trigger a refresh.&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.amazonaws.com%2Fuploads%2Farticles%2F0kit667qqtznlfu28x8b.gif" 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.amazonaws.com%2Fuploads%2Farticles%2F0kit667qqtznlfu28x8b.gif" width="256" height="156"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The requirements are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The dot is draggable&lt;/li&gt;
&lt;li&gt;The dot triggers a refresh when it overlaps the darker dot.&lt;/li&gt;
&lt;li&gt;The dot's position resets upon refresh or release.&lt;/li&gt;
&lt;li&gt;The time displays 1 second after a refresh&lt;/li&gt;
&lt;li&gt;During time refresh, no other refreshes can begin, and the dot is not draggable.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Overview
&lt;/h1&gt;

&lt;p&gt;This widget will be made from two async 'containers' which we'll develop separately:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The time 'endpoint' (simulated)&lt;/li&gt;
&lt;li&gt;The draggable refresh dot&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then to cap it all off, we'll trigger the Time Listener when the Pointer Service is ready, no problem!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;One decision criteria for whether to use a listener on an &lt;code&gt;@rxfx/bus&lt;/code&gt; or an &lt;code&gt;@rxfx/service&lt;/code&gt; is whether we need to know when the service is 'active'. Changing the dot's appearance while dragging is such a use case. To start with, we'll make the mouse-dragger a full service, and the time 'endpoint' a simple listener, and go from there!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Setup / Organization
&lt;/h2&gt;

&lt;p&gt;We're starting with a styled HTML document, and a module of DOM mutating functions. We'll place these in &lt;code&gt;services/DOM&lt;/code&gt;. Our time lookup will go in &lt;code&gt;services/time&lt;/code&gt;, and our pointer service in &lt;code&gt;services/pointer&lt;/code&gt;. A bus will connect all of these, allowing for centralized logging, error handling, etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install The Bus
&lt;/h2&gt;

&lt;p&gt;The bus is like a &lt;code&gt;Subject&lt;/code&gt;, on which &lt;code&gt;next&lt;/code&gt; is renamed to &lt;code&gt;trigger&lt;/code&gt;, and &lt;code&gt;listenBlocking(cond, handler)&lt;/code&gt; is a shortcut for &lt;code&gt;subject.asObservable().pipe(filter(cond), exhaustMap(handler))&lt;/code&gt;. It comes pre-wired in a single import.&lt;/p&gt;

&lt;p&gt;Understanding that, let's declare a bus that accepts strings, and listen for those to implement the refresh side&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const bus = new Bus&amp;lt;string&amp;gt;();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  The Time Listener
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://github.com/deanrad/rxfx-example-swipe-to-refresh-blitz/pull/16" rel="noopener noreferrer"&gt;PR containing Just Time Listener Code&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A delayed value with &lt;code&gt;@rxfx/after&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The original Swipe-To-Refresh demo on &lt;a href="https://www.learnrxjs.io/learn-rxjs/recipes/swipe-to-refresh" rel="noopener noreferrer"&gt;LearnRxjs.io&lt;/a&gt; demo uses no fewer than 4 functions to create a delayed time endpoint: &lt;code&gt;of&lt;/code&gt;, &lt;code&gt;delay&lt;/code&gt;, &lt;code&gt;pipe&lt;/code&gt; and &lt;code&gt;tap&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;We can declare a fake value using &lt;code&gt;after&lt;/code&gt; from &lt;code&gt;@rxfx/after&lt;/code&gt; with only one. Depending on whether we want the time computed at the beginning or the end, we can call &lt;code&gt;after&lt;/code&gt; with either a value or a function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fakeDateNow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;after&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="c1"&gt;// &lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fakeDateAtEnd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;after&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="c1"&gt;// &lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fakeEndpoint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;fakeDateAtEnd&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  On request, call the time 'endpoint'
&lt;/h2&gt;

&lt;p&gt;Now, we'll create a bus listener to respond with the fake data. Suppose the initiation of the time lookup is to begin when an item equal to &lt;code&gt;time/request&lt;/code&gt; goes on the bus.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;bus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s2"&gt;`time/request`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;fakeEndpoint&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We intentionally return the deferred value of the date from the handler. This would work whether the return value was a Promise or an RxJS Observable. Since &lt;code&gt;after&lt;/code&gt; is an Observable, thus lazy, we return it to the bus so that it can call &lt;code&gt;.subscribe()&lt;/code&gt; on it. But we don't want to subscribe to a new delayed date if one is pending already, so let's solve that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't refresh while already refreshing
&lt;/h2&gt;

&lt;p&gt;Using the console, we see that calling &lt;code&gt;bus.trigger(TIME_REQUEST)&lt;/code&gt; twice results in double loading messages. &lt;/p&gt;

&lt;p&gt;To adjust this In raw RxJS we would &lt;code&gt;pipe&lt;/code&gt; something through an &lt;code&gt;exhaustMap&lt;/code&gt;, but we can skip those imports.&lt;/p&gt;

&lt;p&gt;In contrast to &lt;code&gt;bus#listen&lt;/code&gt;, &lt;code&gt;bus#listenBlocking&lt;/code&gt; takes the same arguments, but runs the effect with &lt;code&gt;exhaustMap&lt;/code&gt; semantics. We just do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;- bus.listen(
&lt;/span&gt;&lt;span class="gi"&gt;+ bus.listenBlocking(
&lt;/span&gt;  event =&amp;gt; event === `time/request`, 
  () =&amp;gt; fakeEndpoint()
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even if our UI will disable things, this makes the intention clear to those reading it. Now lets see these results in the DOM!&lt;/p&gt;

&lt;h2&gt;
  
  
  On reponse, update the DOM
&lt;/h2&gt;

&lt;p&gt;We have a couple of wrapper functions around our DOM mutation functions, called &lt;code&gt;handleRequestBegin&lt;/code&gt; and &lt;code&gt;handleRequestDone&lt;/code&gt;, which will update the DOM with the text &lt;code&gt;...loading...&lt;/code&gt;, or the new date, respectively. &lt;/p&gt;

&lt;p&gt;To recap, the arguments to &lt;code&gt;listen*&lt;/code&gt; are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;cause&lt;/strong&gt; - the condition that will cause the effect&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;effect&lt;/strong&gt; - the side-effecting function to call&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and to this we'll now add:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;reactions&lt;/strong&gt; - callbacks that will react to life-cycle events of the Effect.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This &lt;code&gt;observer&lt;/code&gt; will be &lt;code&gt;tap&lt;/code&gt;-ped in without us needing to import &lt;code&gt;tap&lt;/code&gt;, &lt;code&gt;finalize&lt;/code&gt;, or others.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleRequestBegin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;loading...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;loading...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;bus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;TIME_REQUEST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;fakeResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;handleRequestBegin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;handleRequestDone&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Time Listener Complete!
&lt;/h2&gt;

&lt;p&gt;This completes our time listener! Whenever anyone calls &lt;code&gt;trigger(TIME_REQUEST)&lt;/code&gt;, the time will go in the DOM with &lt;strong&gt;Blocking&lt;/strong&gt; behavior. We've cut out a lot of operators at this point, but we can do more.&lt;/p&gt;

&lt;p&gt;Let's build the Swipe-To-Refresh pointer functionality out of the higher-level 𝗥𝘅𝑓𝑥 building block - the &lt;code&gt;@rxfx/service&lt;/code&gt;, akin to &lt;code&gt;createAsyncThunk&lt;/code&gt; or NgRx, and continue to drop operators.&lt;/p&gt;

&lt;h1&gt;
  
  
  Pointer Service
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://github.com/deanrad/rxfx-example-swipe-to-refresh-blitz/pull/18" rel="noopener noreferrer"&gt;PR containing Just Pointer Service Code&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We expect our Pointer Service to implement dragging our UI element under the pointer, then trigger the time listener. To create the service we need to know what kinds of "requests" it can get - in this case the string "up" or "down". We want its responses to be a stream of &lt;code&gt;number&lt;/code&gt;s - the &lt;code&gt;clientY&lt;/code&gt; field of each &lt;code&gt;pointer/move&lt;/code&gt; it sees. And its errors are the normal type &lt;code&gt;Error&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pointerService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createService&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;up&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;down&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pointer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;bus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;mouseMoveYs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mouseMoveYs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The arguments are the namespace, for logging purposes, the bus on which it will put responses, and the effect. The effect will return an Observable of responses, and these will go onto our bus as they occur.&lt;/p&gt;

&lt;h2&gt;
  
  
  DOM listeners talk to the Pointer service
&lt;/h2&gt;

&lt;p&gt;Now we can add DOM listeners that will pass the service the string 'up' or 'down'.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sendDown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;pointerService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;down&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sendUp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;pointerService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;up&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;connectDOMEventsToPointerService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;POINTER_EVENTS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DOWN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sendDown&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;POINTER_EVENTS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;UP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sendUp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll write a &lt;code&gt;disconnectDOMEventsFromPointerService&lt;/code&gt; function as well, not shown here. First - let's specify this service's effect and its responses.&lt;/p&gt;

&lt;h2&gt;
  
  
  On down, moves become responses (until up)
&lt;/h2&gt;

&lt;p&gt;First, let's ensure we're &lt;code&gt;spy&lt;/code&gt;ing on all bus events so we can see what's going on even before we hook it up to the UI.&lt;/p&gt;

&lt;p&gt;Now, import &lt;code&gt;fromEvent&lt;/code&gt; and &lt;code&gt;map&lt;/code&gt; from RxJS..&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mouseMoveYs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;fromEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pointer/move&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MouseEvent&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Try pressing the mouse down, and notice how as you move the pointer, the console will stream with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pointer/next&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pointer/next&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we add in cancelation with &lt;code&gt;takeUntil&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mouseMoveYs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;fromEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pointer/move&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MouseEvent&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientY&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;takeUntil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fromEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pointer/up&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're using operators, but only for their intended purposes. Now, when it comes to updating the DOM, our &lt;code&gt;service&lt;/code&gt; gives us choices and modularity that raw RxJS doesn't.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dot follows pointer / is dragged
&lt;/h2&gt;

&lt;p&gt;We established that &lt;code&gt;pointerService&lt;/code&gt; has responses that are of type &lt;code&gt;number&lt;/code&gt;, right? And we have a &lt;code&gt;setRefreshPos&lt;/code&gt; function that changes the DOM position of the refresh dot. So all we need is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;pointerService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;responses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setRefreshPos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While the pointerService effect returned raw numbers, the &lt;code&gt;@rxfx/service&lt;/code&gt; bundled them into the Flux Standard Actions. We retrieve the raw &lt;code&gt;number&lt;/code&gt; from their &lt;code&gt;payload&lt;/code&gt; - and yes, TypeScript would have helped you see that :)&lt;/p&gt;

&lt;p&gt;What's nice about adding dragging this way is that it doesn't &lt;code&gt;tap&lt;/code&gt; into one giant chain. The Dot position is a subscriber - a &lt;em&gt;follower&lt;/em&gt; of those pointer/moves. This helps us keep things separated, like ...&lt;/p&gt;

&lt;h2&gt;
  
  
  On cancel (or complete), reset the dot's DOM position
&lt;/h2&gt;

&lt;p&gt;We'd like, once we've stopped dragging, for the refresh dot to return to its initial position. As you saw in the console, once the &lt;code&gt;pointer/up&lt;/code&gt; event occurred, a &lt;code&gt;pointer/complete&lt;/code&gt; event was also seen.&lt;/p&gt;

&lt;p&gt;We can hook off of this &lt;code&gt;pointer/complete&lt;/code&gt; event to call &lt;code&gt;resetRefresh&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;bus&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pointerService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;resetRefresh&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are filtering the bus down to all &lt;code&gt;pointer/complete&lt;/code&gt; events, and each one causes a &lt;code&gt;resetRefresh&lt;/code&gt;. We query the bus since these events are not part of the stream of &lt;code&gt;pointerService.responses&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now let's hook up our final part, the refresh!&lt;/p&gt;

&lt;h2&gt;
  
  
  On move, if far enough, cancel drag and trigger the time refresh
&lt;/h2&gt;

&lt;p&gt;We can listen to our service's responses as a stream, and if we exceed the Y threshold to trigger the refresh, we can reset the refresh button by canceling it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;pointerService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;responses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;isPastThreshold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;pointerService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cancelCurrent&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;bus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;TIME_REQUEST&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our pointer will return to the starting point, because the &lt;code&gt;pointer/complete&lt;/code&gt; event will fire upon &lt;code&gt;cancelCurrent()&lt;/code&gt;. And we'll no longer be draggging the dot until the next &lt;code&gt;pointer/down&lt;/code&gt;. Lastly, we've triggered our time listener with that event of &lt;code&gt;TIME_REQUEST&lt;/code&gt;, so everything is working!&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus: during drag, change appearances.
&lt;/h2&gt;

&lt;p&gt;I wouldn't want to miss describing one of the great features of &lt;code&gt;@rxfx/service&lt;/code&gt; - the &lt;code&gt;isActive&lt;/code&gt; Observable that lets you react to one of its effects being active. Just watch how we can make it easier on the eye!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;pointerService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isActive&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;isActive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;isActive&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;add&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;remove&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;refresh&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;isDragging&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  While refreshing, the dot is not draggable
&lt;/h2&gt;

&lt;p&gt;We built our Pointer Service and Time Listener to not know about each other—initially. Now that we want to do something while the Time Listener is active, we could re-write it as a service and subscribe to its &lt;code&gt;isActive&lt;/code&gt; property as we could for the Pointer Service.&lt;/p&gt;

&lt;p&gt;But since we already have functions in the Time Listener's Observer we can use those to stop sending events to the Pointer Service.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleRequestBegin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;loading...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;disconnectDOMEventsFromPointerService&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nf"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;loading...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, as our &lt;em&gt;coup-de-grâce&lt;/em&gt;, we have implemented a form of blocking mode by hand to complete our widget! &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/deanrad/rxfx-example-swipe-to-refresh-blitz/pull/18/files" rel="noopener noreferrer"&gt;PR of Pointer Service&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/deanrad/rxfx-example-swipe-to-refresh-blitz/pull/15/files" rel="noopener noreferrer"&gt;PR of entire demo&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;p&gt;We used fewer individual RxJS operators to build the 𝗥𝘅𝑓𝑥 way than with raw RxJS. The service and listener concepts let us apply operators without creating a giant chain. Features are added separately, with little interference to each other.&lt;/p&gt;

&lt;p&gt;With 𝗥𝘅𝑓𝑥 your app is mostly a list of tuples of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[cause1, effect1, reactions1[]]
[cause2, effect2, reactions2[]]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your app grows in a maintainable and performant fashion — at least, it has for me. You can also use it to create Observables of state from triggered events, and a lot of other fun things. Pub-Sub is a great paradigm for rapid and modular app building.&lt;/p&gt;

&lt;p&gt;Enjoy building and listening!&lt;/p&gt;

&lt;p&gt;𝗥𝘅𝑓𝑥 Creator, Dean Radcliffe&lt;/p&gt;

</description>
      <category>rxjs</category>
      <category>rxfx</category>
      <category>eventbus</category>
      <category>pubsub</category>
    </item>
    <item>
      <title>Ordering Event Bus Events with RxJS and concatMap</title>
      <dc:creator>Dean Radcliffe</dc:creator>
      <pubDate>Tue, 20 Sep 2022 04:34:20 +0000</pubDate>
      <link>https://dev.to/deanius/ordering-event-bus-events-with-rxjs-and-concatmap-mik</link>
      <guid>https://dev.to/deanius/ordering-event-bus-events-with-rxjs-and-concatmap-mik</guid>
      <description>&lt;p&gt;An Event Bus can help our app by providing a single source of truth for the relative timing of events. If &lt;code&gt;trigger('B')&lt;/code&gt;  follows &lt;code&gt;trigger('A')&lt;/code&gt; , then we we expect listeners will receive events in &lt;code&gt;A, B&lt;/code&gt; order. Any other order would certainly lead to bugs.&lt;/p&gt;

&lt;p&gt;Strangely enough, with a simple implementation of an Event Bus in RxJS (a Subject, and some Observers that &lt;code&gt;tap&lt;/code&gt; in a function), one can accidentally introduce a bug in which listeners don't hear events in the same order! Both the buses Luis Aviles made  &lt;a href="https://www.thisdot.co/blog/how-to-implement-an-event-bus-in-typescript" rel="noopener noreferrer"&gt;here&lt;/a&gt; and the one I built in &lt;a href="https://dev.to/deanius/a-typesafe-event-bus-with-rxjs-5972"&gt;this post&lt;/a&gt; suffer from this bug. In this post we will use &lt;code&gt;concatMap&lt;/code&gt; to fix that, learning the "Return The Work" principle of Observables.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your Thoughts?
&lt;/h2&gt;

&lt;p&gt;The library that implements this bus fully today is called &lt;code&gt;omnibus-rxjs&lt;/code&gt;. I'm thinking of putting it up as &lt;code&gt;@rxfx/bus&lt;/code&gt;, and extracting out a family of libraries under that namespace. Which name do you like? Leave a comment below.&lt;/p&gt;




&lt;h2&gt;
  
  
  Trigger and Listen
&lt;/h2&gt;

&lt;p&gt;In &lt;a href="https://dev.to/deanius/a-typesafe-event-bus-with-rxjs-5972"&gt;part 1&lt;/a&gt; we constructed an Event Bus that let us:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Call  &lt;code&gt;bus.trigger&lt;/code&gt;  to trigger an event to the bus&lt;/li&gt;
&lt;li&gt; Use &lt;code&gt;bus.listen&lt;/code&gt; to register a function to be run on matching events.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;On this bus, what happens if a handler function run by &lt;code&gt;bus.listen&lt;/code&gt; contains a call to &lt;code&gt;bus.trigger&lt;/code&gt;? Could this confuse the event ordering?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;bus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello-dave&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;bus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello-HAL&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the surface there's nothing suspicious here. And to review our bus code at this point, it's nothing more than this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Bus&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kr"&gt;private&lt;/span&gt; &lt;span class="na"&gt;events&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Subject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;events&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Subject&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;matcher&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Predicate&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Subscription&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;events&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;asObservable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;matcher&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, assuming 3 events are triggered, how could 2 listeners disagree on what order the events arrived?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Listener 1 heard: ["hello-world", "hello-Dave", "hello-HAL"]&lt;/span&gt;
&lt;span class="c1"&gt;// Listener 2 heard: ["hello-world", "hello-HAL", "hello-Dave"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Stack is The Culprit
&lt;/h2&gt;

&lt;p&gt;JavaScript is a stack-based language, where each synchronous function call begins and ends inside its parents'. How is this relevant? Allow me to illustrate..&lt;/p&gt;

&lt;p&gt;Suppose there are 3 listeners on a bus carrying strings. First we create a logger called L1. Then our 'Dave listener' which will re-trigger. Then another logger called L2 will be attached. If we fire an event that re-triggers, like &lt;code&gt;"hello-dave"&lt;/code&gt;, this shows the sequence of calls to the listeners that results in the problem:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt; &lt;span class="nf"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello-Dave&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;L1&lt;/span&gt; &lt;span class="nx"&gt;listener&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;Dave&lt;/span&gt; &lt;span class="nx"&gt;listener&lt;/span&gt;
     &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nf"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello-HAL&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;L1&lt;/span&gt; &lt;span class="nx"&gt;listener&lt;/span&gt;
        &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;L2&lt;/span&gt; &lt;span class="nx"&gt;listener&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;L2&lt;/span&gt; &lt;span class="nx"&gt;listener&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At runtime, the &lt;code&gt;trigger('hello-HAL')&lt;/code&gt; from inside the "Dave" listener started firing each matching listener sequentially. But L2 hadn't yet processed &lt;code&gt;hello-Dave&lt;/code&gt;, so L2 sees &lt;code&gt;hello-HAL&lt;/code&gt; even before &lt;code&gt;hello-Dave&lt;/code&gt;. This is what we want to prevent. Our answer will be to not begin the re-triggering immediately, but to "Return the Work"&lt;/p&gt;

&lt;h2&gt;
  
  
  Observables - Units of Work
&lt;/h2&gt;

&lt;p&gt;Of all the definitions of Observables out there, the one I like is that an Observable represents the potential for some work to be done, or resource to be used. Like the command-line string &lt;code&gt;ls -l&lt;/code&gt; encodes the &lt;em&gt;potential&lt;/em&gt; of a memory-occupying, data-emitting process. So wherever you did work immediately before, you can now do it in an Observable. Like React VDOM is for DOM elements, Observables are to effects.&lt;/p&gt;

&lt;p&gt;Now, if we have a stream of these work Observables, we can strictly serialize them with the RxJS operator &lt;code&gt;concatMap&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Fix
&lt;/h2&gt;

&lt;p&gt;If you suspected some kind of queueing was the solution you're right. But if you didn't know about&lt;code&gt;concatMap&lt;/code&gt;, you may have imagined building some data structure to hold the queue. But the &lt;code&gt;concatMap&lt;/code&gt; operator actually does this internally already. Let's give our bus an RxJS  &lt;code&gt;Subject&lt;/code&gt;  for the triggerings we want to serialize.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;class Bus&amp;lt;T&amp;gt; {
&lt;/span&gt;  private events: Subject&amp;lt;T&amp;gt;;
&lt;span class="gi"&gt;+  private triggerings: Subject&amp;lt;Observable&amp;lt;void&amp;gt;&amp;gt;;
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;  constructor() {
    this.events = new Subject();
&lt;span class="gi"&gt;+    this.triggerings = new Subject();
+    this.triggerings.pipe(
+      concatMap((t) =&amp;gt; t)
+    ).subscribe();
&lt;/span&gt;  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the constructor is run, the &lt;code&gt;triggerings&lt;/code&gt;Subject begins listening for work items—Observables—which it passes to &lt;code&gt;concatMap&lt;/code&gt; to execute only serially. Now, we change the implementation of &lt;code&gt;trigger&lt;/code&gt; to push one of these work items to that Subject:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  trigger(item: T) {
&lt;span class="gd"&gt;-    this.events.next(item);  
&lt;/span&gt;&lt;span class="gi"&gt;+    this.triggerings.next(
+      new Observable((notify) =&amp;gt; {
+        this.events.next(item);
+        notify.complete();
+      })
+    );
&lt;/span&gt;  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Observable's work is to run each listener for the item completely and synchronously with &lt;code&gt;events.next(item)&lt;/code&gt;, and only then call &lt;code&gt;notify.complete()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And voila! &lt;code&gt;concatMap&lt;/code&gt; can serialize the calls now! We no longer violate causality, and our logs show each listener agrees on the same event ordering.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Listener 1 heard: ["hello-world", "hello-Dave", "hello-HAL"]
// Listener 2 heard: ["hello-world", "hello-Dave", "hello-HAL"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we can see this is because triggerings—the execution of those Observables—always finishes notifying listeners for one event before processing the next one.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt; &lt;span class="nf"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello-dave&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;L1&lt;/span&gt; &lt;span class="nx"&gt;listener&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;Dave&lt;/span&gt; &lt;span class="nf"&gt;listener &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;queues&lt;/span&gt; &lt;span class="nx"&gt;hello&lt;/span&gt; &lt;span class="nx"&gt;HAL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;L2&lt;/span&gt; &lt;span class="nx"&gt;listener&lt;/span&gt;
 &lt;span class="nf"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello-HAL&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;L1&lt;/span&gt; &lt;span class="nx"&gt;listener&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;L2&lt;/span&gt; &lt;span class="nx"&gt;listener&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Decoupling For The Win
&lt;/h2&gt;

&lt;p&gt;Where we're going with this bus is to make it usable for a Pub-Sub implementation. This bug we just fixed was a kind of coupling, where "Dave listener" was interfering with L2's event order. This is normal when making sync calls in a stack-based language, but we can bring order back to it again with RxJS.&lt;/p&gt;

&lt;p&gt;Now that we've decoupled this runtime behavior of listeners from each other, it's time to look at another important way listeners should be decoupled: errors. And that will be the topic of the next post.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://codesandbox.io/s/minibus-2-sequence-error-1f1enf?file=/src/index.ts" rel="noopener noreferrer"&gt;CodeSandbox with error&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://codesandbox.io/s/minibus-3-sequence-fixed-w2jv53?file=/src/bus.ts" rel="noopener noreferrer"&gt;CodeSandbox, fixed with &lt;code&gt;concatMap&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>rxjs</category>
      <category>async</category>
      <category>operators</category>
      <category>eventbus</category>
    </item>
    <item>
      <title>How an Interview Convinced Me to Use 𝗥𝘅𝑓𝑥 and RxJS for Effect Management in React</title>
      <dc:creator>Dean Radcliffe</dc:creator>
      <pubDate>Fri, 20 May 2022 15:02:58 +0000</pubDate>
      <link>https://dev.to/deanius/how-an-interview-convinced-me-to-use-an-event-bus-for-rxjs-in-react-396l</link>
      <guid>https://dev.to/deanius/how-an-interview-convinced-me-to-use-an-event-bus-for-rxjs-in-react-396l</guid>
      <description>&lt;p&gt;Edit: Here is &lt;a href="https://dev.to/deanius/excellent-effect-management-in-react-with-and-rxjs-35cn"&gt;part 2&lt;/a&gt; of this series.&lt;/p&gt;

&lt;p&gt;Note: Some images refer to the library's old name "Omnibus-RxJS" and have not been updated to 𝗥𝘅𝑓𝑥.&lt;/p&gt;

&lt;h2&gt;
  
  
  An Interview Like No Other
&lt;/h2&gt;

&lt;p&gt;It was a front-end React UI developer interview which began like any other. But unlike others, by the end of it I'd learned enough to change my whole approach to data-fetching, or maybe to async programming in general.&lt;/p&gt;

&lt;p&gt;I was the interviewer for a 60 minutes live-coding interview. The goal was to build a simple React GUI that could fetch a random GIF. We assumed any candidate who reached this round could do async data-fetching in React. But we wanted to learn how a candidate thought about front-end problems in general. We were looking for some insight that we didn't already have. And in this candidate— call them &lt;strong&gt;Chris&lt;/strong&gt; - we found it :)&lt;/p&gt;

&lt;p&gt;I handed Chris the paper with the requirements for their live-coding interview.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Acquainted
&lt;/h2&gt;

&lt;p&gt;The requirements contained an image of what was to be built in the interview.&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.amazonaws.com%2Fuploads%2Farticles%2Ftatc2yiuphjbyc513q7m.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.amazonaws.com%2Fuploads%2Farticles%2Ftatc2yiuphjbyc513q7m.png" alt="empty template" width="764" height="954"&gt;&lt;/a&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.amazonaws.com%2Fuploads%2Farticles%2Fsalx6ipiy55e10564x8g.jpg" 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.amazonaws.com%2Fuploads%2Farticles%2Fsalx6ipiy55e10564x8g.jpg" alt="Implement a React UI that loads a random GIF upon the click of a button Respond to and display any errors that occur Implement a cancel button" width="800" height="221"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Chris asked a few questions:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Does it have to be cats, or will any GIF do?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;"Ha!" I said. "You can choose any GIF you want, but we've provided a function to get cats."&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchRandomGif&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://api.thecatapi.com/v1/images/search&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;x-api-key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;blah-blah&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;"Can I use any libraries?"&lt;/em&gt; was Chris's next question. I replied: "Do you think one is needed for this app?"&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Well, we need a cancel button... And I find Observables make for cleaner, less error-prone code around cancelation."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This took me by surprise. I only knew of one cancelation tool, AbortControllers, and Chris pinpointed my frustrations with them - that they're easy to forget, don't compose well, and obscure the logic of the happy path.&lt;/p&gt;

&lt;p&gt;I said, "yes you can use a library, but you must be able to explain what it is doing, and justify its contribution to the bundle size."&lt;/p&gt;

&lt;p&gt;Chris chimed up with, &lt;em&gt;"Sounds good— shall we get to work then?"&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  𝗥𝘅𝑓𝑥—An Odd Choice of Library
&lt;/h2&gt;

&lt;p&gt;Chris started by creating a new file, naming it &lt;code&gt;gifService.ts&lt;/code&gt;. I gently inquired why they made a separate file instead of coding into the provided React component.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"React is the view layer, this is- well, a service layer. Easier to test with no React dependencies. Can I proceed?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;"Go for it," I said. Chris wrote the following as though from memory, and in TypeScript, but I'll post just the JS here.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@rxfx/service&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;fetchRandomGif&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./prebuilt-for-candidate&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gifService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gif&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;fetchRandomGif&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;gifService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;spy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// log all lifecycle events on its default bus&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I said - Ok, now what is this library doing?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Have you used Redux Saga, createAsyncThunk, or other async middleware? 𝗥𝘅𝑓𝑥 is a drop-in replacement, at less than half the bundle size. The bus receives events, which the service will put onto the bus as the effect starts, provides data, etc."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I knew Redux Saga. I said "The &lt;code&gt;fetchRandomGif&lt;/code&gt; function - it's not written as a generator function or a saga, it just returns a Promise. Is that going to be compatible with your bus?"&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Yep, no problem. It can do Promises, Observables, iterables. It's just RxJS underneath.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you've ever been frustrated using React Context or prop-drilling to share data across an app, a &lt;code&gt;service&lt;/code&gt; or &lt;code&gt;bus&lt;/code&gt; is a framework-free way to do the same. It was Signals before Signals! It's so useful, I don't know why it's not built into every app!"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I did have prop-drilling and React Context issues, and I saw how events being visible to any part of the app by default would result in less code. That satisfied me of their choice, and I asked Chris to continue.&lt;/p&gt;

&lt;h2&gt;
  
  
  The State Model and Reducer
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;"Great— now let's start on our state model. It looks like there's only one field we need in state - the URL of the current image - is that right?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I said "Are you forgetting the loading and error states?"&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"One nice thing about an 𝗥𝘅𝑓𝑥 service is your state model doesn't need to include loading and error. You get into trouble when you mix transient fields like &lt;code&gt;loading&lt;/code&gt; and &lt;code&gt;error&lt;/code&gt; into state fields that you may want to persist for longer - like across sessions. Separate things that change at different rates, right?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I had just dealt with a bug where a &lt;code&gt;loading&lt;/code&gt; state loaded from local storage with a value of &lt;code&gt;true&lt;/code&gt; - the spinner spun but nothing was happening. It occurred to me it was not really DRY to have a state field that isn't a direct reflection of whether a process is actually running, so I was ready to see it in action.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"We still need to see loading and error in the UI, but let's go ahead with a loading-free reducer."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The reducer looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;initialState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gifReducer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;initialState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gif/next&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nl"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I noticed the strings in the &lt;code&gt;case&lt;/code&gt; statements, and I said "These look like Redux Toolkit conventions, but with different names - where do they come from?"&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Fair question. A service has a standard set of actions, based on Observable life-cycle events. The &lt;code&gt;next&lt;/code&gt; event delivers data, &lt;code&gt;error&lt;/code&gt; an error, and &lt;code&gt;started&lt;/code&gt; indicates a search began. There are typesafe versions of these too, do you want me to use them?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I said, "Let's skip that for now and get our data in the UI."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Cool. Then let's add the reducer to our service."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Chris changed the line to create the service ever-so-slightly, by adding the reducer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;- createService('gif', () =&amp;gt; fetchRandomGif);
&lt;/span&gt;&lt;span class="gi"&gt;+ createService('gif', () =&amp;gt; fetchRandomGif, () =&amp;gt; gifReducer);
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;"And now let's bring state into our UI"&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  UI Updates
&lt;/h2&gt;

&lt;p&gt;Chris typed the following in a flurry of keystrokes..&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;gifService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./services/gifService&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@rxfx/react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;CatFetcher&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;gifService&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Animal GIF&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I said "Let me get caught up. Through the &lt;code&gt;useService&lt;/code&gt; hook, we have a reference to the state produced by the reducer. And we have a function with which to request the effect, which changes the state?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Yeah, precisely!"&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.amazonaws.com%2Fuploads%2Farticles%2F44hf8nkaea7y8j90wigs.gif" 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.amazonaws.com%2Fuploads%2Farticles%2F44hf8nkaea7y8j90wigs.gif" alt="template with cat" width="260" height="290"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It worked great— on the happy path. Now what about errors, I asked.&lt;/p&gt;

&lt;h2&gt;
  
  
  Errors
&lt;/h2&gt;

&lt;p&gt;Chris hacked a thrown error into the fetch endpoint. Then captured a &lt;code&gt;currentError&lt;/code&gt; field from the hook. Then used it in React to show the message.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;-  const { state, request } = useService(gifService);
&lt;/span&gt;&lt;span class="gi"&gt;+  const { state, request, currentError } = useService(gifService);
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;currentError&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I tested that when an error was shown in the GIF fetcher, the error display &lt;em&gt;just worked&lt;/em&gt;. And it was cleared automatically on the next click. I guess that's why the field is named "currentError"—once a new one begins there &lt;em&gt;is no current error&lt;/em&gt;. A nice convenience.&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.amazonaws.com%2Fuploads%2Farticles%2Fv9cgiil6jnkujdrdpe6x.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.amazonaws.com%2Fuploads%2Farticles%2Fv9cgiil6jnkujdrdpe6x.png" alt="template with error" width="306" height="337"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After it had shown an error, it resumed future fetches just fine. I said to Chris "You pulled that off nicely. But since you left &lt;code&gt;loading&lt;/code&gt; out of your state, how will we display that?"&lt;/p&gt;

&lt;h2&gt;
  
  
  Loading State
&lt;/h2&gt;

&lt;p&gt;While the GIF is loading, let's change the text "Fetch Cat" to "Fetching.."&lt;/p&gt;

&lt;p&gt;Chris captured the &lt;code&gt;isActive&lt;/code&gt; field from the &lt;code&gt;useService&lt;/code&gt; hook return value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;-  const { ... currentError } = useService(gifService);
&lt;/span&gt;&lt;span class="gi"&gt;+  const { ... currentError, isActive } = useService(gifService);
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;gifService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Fetching.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Fetch Cat&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Fetch Cat */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;HourglassSpinner&lt;/span&gt; &lt;span class="na"&gt;show&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That &lt;code&gt;isActive&lt;/code&gt; variable - the hook just knows that a fetch is active?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Sure does. The service knows when it's doing work. It keeps a count of &lt;code&gt;gif/started&lt;/code&gt; and &lt;code&gt;gif/complete&lt;/code&gt; events and emits &lt;code&gt;true&lt;/code&gt; when the count is &lt;code&gt;&amp;gt; 0&lt;/code&gt; and &lt;code&gt;false&lt;/code&gt; otherwise."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I pretty much decided Chris had passed the interview, but to throw a challenge I asked about cancelation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cancelation and The Finished Product
&lt;/h2&gt;

&lt;p&gt;I'd shipped many apps without cancelation before, especially before Abort Controllers. But I knew that to do top-notch UX, one had to be able to cancel effects to free up resources.&lt;/p&gt;

&lt;p&gt;I asked how we could cancel a load while in progress. Chris added a Cancel button to the form, and I stepped out of the room for a second.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;onClick=&lt;/span&gt;&lt;span class="s"&gt;{()&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; gifService.cancelCurrent()}&amp;gt;Cancel&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When I returned, I opened up DevTools, and clicked Fetch Cat. I clicked Cancel, and BOOM, a canceled XHR on &lt;code&gt;/search&lt;/code&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.amazonaws.com%2Fuploads%2Farticles%2Fqzi7fbh5zkxcbybd406f.jpg" 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.amazonaws.com%2Fuploads%2Farticles%2Fqzi7fbh5zkxcbybd406f.jpg" alt="cat loading fixed" width="800" height="93"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Chris showed the new fetchRandomGif function - which looked like the Promise-based version.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ajax&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rxjs/ajax&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchRandomGif&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;ajax&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getJSON&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://api.thecatapi.com/v1/images/search&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Seeing this, I asked, "So the service can just cancel this AJAX, even without an AbortController?"&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Cancelation is automatic- as long as the endpoint returns an Observable. It's crazy - every Observable since 2012 is cancelable, and yet today we have just Promises. It's nice that in 𝗥𝘅𝑓𝑥 you can return a &lt;code&gt;Promise&lt;/code&gt; for an MVP, and switch to an Observable when you implement cancelation in phase 2 - with no change to surrounding code."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This was great. That ease of change was not my experience with Promises, where switching to a Promise requires all kinds of functions to be labeled &lt;code&gt;async&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I made a mental note: Suggest the whole team learn about Observables and this API around them. Promises being run-to-complete by default started to look like a very bad idea, especially when it was easy as this to swap a non-cancelable AJAX with a cancelable one.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Mysterious Departure
&lt;/h2&gt;

&lt;p&gt;Chris had exceeded expectations on the first 3 mandatory points of the challenge. I wanted to hire, so I moved on to Chris's questions. We talked pleasantly, then when we were standing up to say goodbye, curiosity got the best of me, and I asked one more technical question:&lt;/p&gt;

&lt;p&gt;"Just curious- but how would you handle a click while a GIF was already loading? Something like XState?"&lt;/p&gt;

&lt;p&gt;Chris lifted their backpack to their shoulder and smiled.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Oh, the 𝗥𝘅𝑓𝑥 service has that covered too. Just change the call to &lt;code&gt;createService&lt;/code&gt; to &lt;code&gt;createQueueingService&lt;/code&gt; and you're covered. I'll send you a CodeSandbox of it later today so you can try it out."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And with that, Chris was gone. And my learning into RxJS and 𝗥𝘅𝑓𝑥 had just begun.&lt;/p&gt;




&lt;h2&gt;
  
  
  Author's Note
&lt;/h2&gt;

&lt;p&gt;Here's the &lt;a href="https://codesandbox.io/s/rxfx-service-example-data-fetcher-nweq0h" rel="noopener noreferrer"&gt;CodeSandbox&lt;/a&gt; of the Cat Fetcher.&lt;/p&gt;

&lt;p&gt;As you may have guessed, this was a fictitious story, written by me, Dean, the author of the &lt;a href="https://github.com/deanrad/rxfx" rel="noopener noreferrer"&gt;𝗥𝘅𝑓𝑥 packages&lt;/a&gt;. 𝗥𝘅𝑓𝑥 was not designed to handle interview problems, but real world ones! And it has been deployed to production in various forms for 4 years, solving problems like dynamic forms, 60FPS animation, Web Sockets and many more. I hope you will give it a look, and let me know what you think!&lt;/p&gt;

&lt;p&gt;And soon there will be Part 2 where we address timeouts, maintaining the loading state until the bytes of the image have arrived, and other subtleties of data fetching and effects in general.&lt;/p&gt;

&lt;p&gt;-- Dean&lt;/p&gt;

&lt;p&gt;Update: Here is &lt;a href="https://dev.to/deanius/excellent-effect-management-in-react-with-and-rxjs-35cn"&gt;part 2!&lt;/a&gt;&lt;/p&gt;

</description>
      <category>rxjs</category>
      <category>rxfx</category>
      <category>javascript</category>
      <category>react</category>
    </item>
    <item>
      <title>Kata, Bunkai and Testing</title>
      <dc:creator>Dean Radcliffe</dc:creator>
      <pubDate>Sun, 06 Mar 2022 19:06:26 +0000</pubDate>
      <link>https://dev.to/deanius/kata-bunkai-and-testing-261h</link>
      <guid>https://dev.to/deanius/kata-bunkai-and-testing-261h</guid>
      <description>&lt;h2&gt;
  
  
  Kata
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Kata (martial arts): A detailed, choreographed sequence of movements, blocks, strikes and footwork, executed without a partner. Kata are used as a mnemonic device for a series of techniques, flowed together.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Bunkai
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Bunkai (分解) in Japanese, literally meaning "analysis" or "disassembly" is used in Japanese martial arts to describe the process of extracting fighting techniques from the movements of a &lt;strong&gt;kata&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Kata in the Karate Kid (and Cobra Kai)
&lt;/h2&gt;

&lt;p&gt;In the 1989 film Karate Kid, Mr. Miyagi has Daniel-san practice cleaning the dojo as part of his training. You may recall the "wax-on, wax-off" lesson. This introduced Daniel to a technique, or fragment of a kata. For the longest time Daniel didn't know if he was doing it right. Then Mr. Miyagi throws a punch at him - and his body reacts with the technique he rehearsed. "Wax on" - and he deflects the punch automatically! This illustrates the power of intentional practice - which by analogy we will extend to writing production code as its own kind of fight.&lt;/p&gt;

&lt;h2&gt;
  
  
  Kata in Karate
&lt;/h2&gt;

&lt;p&gt;A karate class usually has a group kata practice toward its end. The time before is spent focusing on individual techniques, often practiced with partners. This helps establish the building blocks of the kata.&lt;/p&gt;

&lt;p&gt;A belt promotion depends, among other things, on satisfactory demonstration of that belt's entire kata. This ensures that all the techniques associated with that belt level are demonstrated by the student. Thus the number of demonstrable katas is one measure of a student's skill level. The first 10 levels up to 1st degree black have widely varying kata, ensuring each level adds to the student's skill.&lt;/p&gt;

&lt;h2&gt;
  
  
  "Code" Kata
&lt;/h2&gt;

&lt;p&gt;Code Kata is the rehearsal of specific coding problems, and I've definitely seen workshops built on it. Sites like Project Euler and Code Warrior provide simple problems where you can focus on honing individual skills. I suggest at least trying them. Many coders think it's pointless to solve 'simple' problems, and thus miss the opportunity to develop the "wax on wax off" kind of mastery that comes only from repetition.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing as Bunkai
&lt;/h2&gt;

&lt;p&gt;The analogy of kata to production code is pretty interesting. Both are composed of smaller building blocks. Both are complex and take time to get right. Kata, like production code, are what get people promotions and recognition. But bunkai, like testing, is the counterpoint is needed to develop them.&lt;/p&gt;

&lt;p&gt;How bunkai develops kata is like this: To practice a kata's block/punch combination, your partner will throw an attack. When you respond to the attack, you practice the kata's technique &lt;em&gt;in the context of its intended application&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;In this way, the bunkai is the &lt;strong&gt;&lt;em&gt;reason&lt;/em&gt;&lt;/strong&gt; for the kata.&lt;/em&gt; Exactly as test-first development 'throws the first punch' and puts pressure on the code to respond correctly!&lt;/p&gt;

&lt;p&gt;Kata that are not practiced against opponents' bunkai seldom have the snap or polish they could have. Could the same be true about code that is not robustly tested?&lt;/p&gt;

&lt;h2&gt;
  
  
  Tests Shape Code as Testing Shapes Developers.
&lt;/h2&gt;

&lt;p&gt;What if I said, "I think 50/50 is a good theoretical split of time focused on tests/prod code". Would that be an uncomfortable thought to you? If so-why? It could be that you haven't figured out how to turn its benefits to your favor. Perhaps doing an 'analysis' aka bunkai will help.&lt;/p&gt;

&lt;p&gt;If you believe testing is less than 50% important, consider a thought experiment: Imagine a machine, or an AI, that could spit out source code, which you could quickly test whether that source code satisfied the test suite or not. You might not know or care what the code looks like, you just know it does &lt;em&gt;what you specified in the test suite!&lt;/em&gt; Programmers may become replaceable, but those who write the specifications (aka tests) can't be replaced! Investing in those skills just seems smart to me.&lt;/p&gt;




&lt;p&gt;In summary, testing is an "analysis" or "disassembly" of production-ready code, as bunkai is for kata in karate. When there are complementary evolutionary pressures, it results in growth on both sides. Anyway its secretly fun! If you've never written a failing test first, then made it pass, you are missing out on one of the great satisfactions of programming. To have pairing sessions where someone 'tests' and another codes - aka "ping-pong" style 🏓 - is simply delightful.&lt;/p&gt;

&lt;p&gt;Let testing do for your software practice what bunkai does for kata in karate. Enjoy crane-kicking your way to success!&lt;/p&gt;




&lt;p&gt;&lt;em&gt;A Personal note: My adult karate path began in 2010 when my friend Hope gave me a gift certificate for a membership at her karate dojo. Though I saw her achieve 1st black belt, mental health and depression issues claimed her before her time. This one is for mental health awareness—and Hope.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>testing</category>
      <category>tdd</category>
      <category>kata</category>
      <category>karate</category>
    </item>
  </channel>
</rss>
