Teaching ReactiveX (and a lot of other things) Like Skiing

Teaching ReactiveX (and a lot of other things) Like Skiing

Eric Smith

January 28, 2020

I've been intrigued by ReactiveX, in all of its programming-language variations, for a few years now. I'd see code like this:


const bricks$ = generate(1, x => x < 8, x => x + 1)
		.pipe(
				mergeMap(r => 
						generate(r % 2 === 0 ? 1 : 0, x => x < gameSize, x => x + 2)
						.pipe(
								map(c => createGameObject(r, c))
						)
				),
				toArray()
		)

Source: Breakout Game

...and I could tell "something" was really cool here. I bought a couple books on it and watched a few videos, and each time I came away with the same impression: This is cool, but how do I use it? I'd usually try to build a project or test case and could never get things working right.

For a time I assumed that perhaps the problem was me—I didn't have the brain for this, or maybe I wasn't using it for the right use cases. But after spending some time this year learning and finally understanding Rx, I'm convinced the problem isn't me. It's the way we teach it.

Kathy Sierra

Last year I read the book Badass: Making Users Awesome in a few quick sessions while my son did his nightly required reading. In the book, Sierra makes two key analogies, one of which is about skiing. I love skiing, but don't get to do it much (Chicago—plenty of snow but very, very flat), and so it really resonated with me. There are several things we do when people are learning to ski to make sure they are able to progress.

First of all, we start them on a bunny hill. Even though every skier wants to try a foot of fresh powder or to bounce off moguls (basically, to do all the cool stuff), we start everybody on a safe, easy slope until they are ready to advance to steeper hills.

Second, we give them simple instructions. Most beginners don't get poles and have only a few things to do—bend their knees and make a "pizza." Sure, it's not the parallel skiing, and the student might need to "unlearn" some habits, but it gets them moving down the hill.

Third, we make sure to continually tell the student that it's okay, everybody falls, you'll get better. Heck, that's most of what the instructor does. "Bend your knees!" Fall, Boom! "It's okay, let's try again!" That reassurance is vital to prevent the beginner from being discouraged. They need to know the instructor fell down too.

And fourth, and perhaps most importantly, the entire time they are skiing! I call myself a "midwest intermediate"—which means I can ski black diamonds in Wisconsin and have to be careful on blues in Colorado. Could I get better and learn more? Sure. Does it matter? Nope! I am skiing and having fun.

Back To Rx

So what does that have to do with teaching ReactiveX, or really anything else in a technical field? Well let's take an example from the front page of the ReactiveX project:

ReactiveX Debounce Marble Diagram

I don't meant to pick on the ReactiveX maintainers, who do a great job, but debounce is an advanced operator that many users can go a long time without using, and marble diagrams are confusing to the uninitiated. Going back to our skiing analogy, this is teaching the physics of a carved turn down a steep hill to a newbie who can't snowplow. It's confusing, intimidating, and provides no benefit to a beginner because it doesn't focus on why you might want to start using this library. At best you'll get a funny idea that this Rx thing is cool, but you just don't get it. For ReactiveX—and really any topic—we need to start teaching at a level that is safe, simple, reassuring, and finally, useful.

ReactiveX For Beginners

I recently gave a well-received workshop at CodeMash called "Reactive Extensions without Marbles," where we focused on the basic use cases of ReactiveX. I based this on what I used the most in my own work: the simple case of making an HTTP request and using the result. Instead of referring to Reactive Extensions as a "combination of the Observer and Iterator Patterns for asynchronous processing," I simply called them "fancy Promises." Is this description completely accurate? Probably not, but it's close enough to get work accomplished.

Instead of looking at debounce or other more complicated operators, we worked up to an exercise with the following solution:

export const mapStatus = (invalidUrl: string): Observable<number> => {
		return fromFetch(invalidUrl).pipe(
				map(response => response.status)
		);
}

This simple exercise shows how to make a web request, and how to map the raw response to the status, because that's all you care about. It's simple, but also useful. To return again to our analogy, it's skiing, and if you never use any of the features of Reactive Extensions you'll still see benefits from the library.

Speaking of skiing, I also provided the "bunny hill" of a series of progressively more difficult exercises found here. You're welcome to give it a try, and submit issues if you find any problems.

Teaching Beginners

What I've learned is most useful when teaching beginners is to fight the urge to explain every single detail, as you'll overwhelm them with information and they won't be able to pick out what they need to get started. "But what about the fundamentals?! If they don't understand the details of the tool, they'll never use it to its fullest potential!" you may scream, if you talk back to blog posts. This is how we end up with 2000 monad tutorials that nobody understands.

The funny thing about the fundamentals is that they are often only understandable after you've tried out the tool for a while. You use the tool (be it Reactive Extensions, Monads, or other) for a time sub-optimally but still effectively, and then one day the fundamentals start to click so you can move on to more advanced use cases. This is the learning process, and you can't shortcut it by explaining all the inner workings of what you're trying to teach. The learner doesn't want to convert their entire architecture to ReactiveX streams, yet, they just want to know how to make a web request and convert its response to a domain object.

When it comes to teaching beginners, it's vital you keep the experience gradual. Remember to:

  • Provide a safe area to start (bunny hill)
  • Give SIMPLE instructions, ignore the complex (snowplow)
  • Reassure the student that this is okay and they are not stupid (everybody falls)
  • Finally, make sure they are getting something at every step (they are skiing)

Beginners can't understand the advanced concepts by definition, and they'll never get to those advanced concepts if you try to skip the beginner lessons. If you accept that beginners must be sub-optimal before they become optimal, you and your students will be a lot happier and more successful.

Eric Smith

Principal Crafter

Eric Smith is a fan of the Chicago Bears, Chicago Cubs, and Bruce Springsteen; and he’s the recent author of Game Development with Rust and WebAssembly, published by Packt. Eric is a consummate polyglot, with more than a decade of experience leading development teams and delivering software for global enterprise systems. He has also delivered native Android and iOS apps at every stage of their lifecycle.