By Casey Liss
RxSwift Primer: Part 2

In order to learn about RxSwift, I wanted to come up with a completely contrived demo application that is written entirely in vanilla UIKit. We can then, step by step, convert that application to use RxSwift. The first couple of steps will be a bit hamfisted, but this will allow new concepts to be introduced slowly.

In part 1 of this series, we saw a visual representation of what this app does:

Demo app animation

This app is written using a storyboard (generally I prefer XIBs, but that’s a discussion for another day), and has a single UIViewController. The entirety of that view controller is below:

import UIKit

class ViewController: UIViewController {

    // MARK: Outlets
    @IBOutlet weak var label: UILabel!
    // MARK: ivars
    private var count = 0
    @IBAction private func onButtonTap(sender: UIControl) {
        self.count += 1
        self.label.text = "You have tapped that button \(count) times."

As you can see, there’s not much to it. There is a UILabel to show how many times a button has been tapped. That button isn’t stored in the class, because it’s wired up to an IBAction. There’s no need to store it.

Unfortunately, we have to manually keep track of how many times the button has been tapped. This data is stored in count.

The @IBAction func onButtonTap(sender:) is the aforementioned IBAction, which is wired up in Interface Builder, and is called by UIKit when the button is tapped.

Naturally, this is all super easy code, and there’s not much to it.

You can see all of this code on GitHub. Note that this is one commit in that repository; if you want to cheat and read ahead, you can look at the commits that follow. Once this series is over, you can walk forward and backward through time by checking out each individual commit.

Converting to Rx

The first step to converting this to use Rx is to think of what the inputs and outputs are. What causes things to happen? What causes us to do a computation, or change what we present to the user?

In such a simple app, it’s quickly obvious that the UIButton being tapped is what kicks off a computation, and a change in state. As the button is tapped, we will need to continue to change the value of count.

Marble Diagrams

How would this transition of state look? Let’s model it over time:


equates to

---[ 1 ]---[ 2 ]---[ 3 ]--->

The above is a crude representation of a marble diagram. A marble diagram is a way of representing signals in the Rx world. The bar represents time. Above, quite obviously, we start on the left and work toward the right. Each tap on the upper diagram yields a different value on the bottom diagram.

Marble diagrams are great ways to show how operators work in Rx. A great example is map: the input is at the top, the output is at the bottom, and the map operation is in the middle:

Map marble diagram

In the example, the map is simply multiplying the input by 10, so 1 becomes 10, 2 becomes 20, and 3 becomes 30.

Aside: You’ll notice in some marble diagrams the arrows aren’t arrows at all, but actually lines. They’ll end with either | or X. A pipe represents a stream that has completed. These streams have declared that they will never signal again. An X represents an error. Streams that error do not continue to signal events after the error.

Coming back to our streams:


equates to

---[ 1 ]---[ 2 ]---[ 3 ]--->

Clearly, the place we start is with the UIButton being tapped. In order to get access to that button programmatically, we’ll need to add it to our view controller. I’ve done so, and called it button:

@IBOutlet weak var button: UIButton!


RxSwift is a foundation; it works for any sort of Swift and is not specific to user interfaces, network calls, nor anything else. RxCocoa is, in short, UIKit wrapped in Rx. For work done on user interfaces, you’ll need to:

import RxSwift
import RxCocoa

Most UIKit controls will have reactive extensions, and in general, they’ll be exposed to developers in the rx property.

So, to get to the stream that represents taps of the button in our view controller, we need to use button.rx.tap.


button.rx.tap is a variable that returns a ControlEvent. A ControlEvent is a special kind of something else: an Observable.

Every time that I’ve said “stream”, what I’m really saying is “Observable”.

Observables are the way streams are represented in Rx. You can perform many operations on observables; that’s what the entire RxMarbles site is for.

Most things that you work with in Rx are related to, or can be converted to, an Observable. In fact, most higher-order types like ControlEvent can be converted to Observables by using .asObservable().

At the end of the day, just remember that an Observable is simply a representation of a stream of events over time.


Generally speaking, the last operation you’ll perform on an Observable—on a stream—is to take action based on that stream signaling. In our case, how do we take action every time the button is tapped?

We will subscribe to that Observable. This allows us to provide a closure where we run whatever code we need. So, our code now looks like this:

    .subscribe(onNext: { _ in

So what do we do inside this closure, when the Observable signals?

Wiring Up

For this first step, we’ll simply use the existing method we wrote for the procedural version of the app: @IBAction func onButtonTap(sender:). This is not the right way to do things in the Rx world, but let’s take things slowly, one step at a time. Thus, our new chain looks like this:

    .subscribe(onNext: { _ in
        self.onButtonTap(sender: self.button)

Since we don’t need onButtonTap(sender:) to be an @IBAction anymore, we can get rid of the sender parameter. That cleans things up nicely:

    .subscribe(onNext: { _ in


In principle, we can build and run right now, and things should work. However, if we do, we’ll see a build warning:

Result of call is unused.

Uh, what‽

In RxSwift, it’s important to clean up after yourself, and terminate Observables, especially network requests. Without getting too deep into the weeds, there is basically only one rule: when you see the above warning, add that object to a DisposeBag.

In our case, we’ll add a DisposeBag to our ViewController. This is because the lifetime of this subscription is tied to the lifetime of our view controller:

private let disposeBag = DisposeBag()

And then we’ll use it in our subscribe() call:

    .subscribe(onNext: { _ in

Don’t let this put you off. There’s really nothing to managing resources, and having a way to reliably dispose of all active Observables comes in very handy from time to time. After a year of doing RxSwift, I’ve never had to think about disposal, outside of dropping things in a dispose bag.

Generally speaking, each class/struct that is doing subscribe()ing gets one shared DisposeBag, and all subscriptions get added to it. That’s it.


With the code we have above, it will run, and it will work. However, what if we want to debug what’s happening within an Observable chain? Naturally, we can place a breakpoint within a closure–such as the one we’re providng to subscribe(). Sometimes, though, you want to see flow, even in places where we don’t have a closure to interrupt.

Luckily, RxSwift provides an easy way to handle this: debug(). Let’s change our chain to include a call to debug():

    .debug("button tap")
    .subscribe(onNext: { [unowned self] _ in

And now let’s run the app, and click 3 times. Here’s the console output:

2016-12-15 19:02:31.396: button tap -> subscribed
2016-12-15 19:02:34.045: button tap -> Event next(())
2016-12-15 19:02:34.584: button tap -> Event next(())
2016-12-15 19:02:35.161: button tap -> Event next(())

The call to debug() will tell us when the Observable is subscribed to, as well as each time it has an event. As discussed above, Observables can signal:

  • Next (with a value)
  • Error (with an error; represented by a X in a marble diagram)
  • Completed (represented by a | in a marble diagram)

All of these will be shown by debug().

Though it’s a bit hard to tell above, debug() also shows us what value was signaled. In our case, the button tap is not just a ControlEvent, but in actuality a ControlEvent<Void>. That’s because a button’s tap doesn’t have any other data to it; all we know is, a tap happened. This is in contrast, say, to the value of a UISegmentedControl, where its value stream is a ControlEvent<Int>. The Int is the index of the selected segment. What good would it be to signal that the selected segment changed without the new selection?

Coming back to our button tap, the ControlEvent<Void>, which is a special kind of Observable, doesn’t really carry a value at all; its value is Void. In Swift, we can represent Void as (). That’s why you’re seeing Event next(()); this could alternatively be written as Event next(Void).

By contrast, if we were signaling with the current count—perhaps after a map—the above would read:

2016-12-15 19:02:31.396: button tap -> subscribed
2016-12-15 19:02:34.045: button tap -> Event next(1)
2016-12-15 19:02:34.584: button tap -> Event next(2)
2016-12-15 19:02:35.161: button tap -> Event next(3)

At first, debug() may seem like it’s just cluttering up your console. However, as we’ll learn in future posts, it’s extremely powerful, and can give you important insight into how your data is flowing through your streams.

Next Steps

Now we’ve dipped our toe into wiring up a procedural interface with Rx. So far, we haven’t really reaped any benefits. We’re simply calling into our old code differently. Having started here, we’re now one step closer to having a proper, Rx implementation.

In the next post, we’ll start to explore a more Rx-y way of going about implementing our view controller. This will include the real coup de grâce: getting rid of var count.

RxSwift Primer: Part 1

When I got to my current job, my team was just starting to look into Reactive Programming as the basis for our clean-room rewrite of our main app. I had never really heard of this before, and I was immediately intrigued.

I set out to learn more about reactive programming, and never found one great guide to answer my questions. Over the next several posts, I’ll attempt to provide exactly that.

Today, we’ll begin with the basic questions. What is Reactive Programming? What does it bring to the table? Why should I care?

What is Rx?

I’d summarize reactive programming (Rx) as:

Modeling a system using a series of composable streams of data, and eliminating stored state wherever possible.

That may not be the most pure academic definition, but that’s how I think of it.

The key to Rx is to think of everything as a series of inputs and outputs; to think of as much as possible as being asynchronous. We can model most systems—most especially user interfaces and network requests—as chains of composable streams.

What Does Rx Bring?

  • Stateless programming
    Naturally every application has some state, but Rx tries very hard to eliminate state. Rather than storing state, Rx attempts wherever possible to simply react to a change from the outside world. These changes may be network callbacks or user actions such as tapping a button.

  • Fewer bugs
    By eliminating state, we’re eliminating avenues for bugs to crop up. Bugs are often caused by the stored state of the world not agreeing with the actual state of the world. Say, for example, a cloud-based app where the local copy of user data is not in sync with the server’s. Naturally, Rx can’t eliminate all of this, but it can get rid of much of it.

    Even something as simple as keeping a data model in sync with a UI control can sometimes be buggy. With Rx, there’s often nothing to store, and thus, nothing to keep in sync, which in turn means fewer bugs.

  • Better local reasoning
    Rx brings a bunch of tools to the table; some are the ones we already know. Some are totally new. Once you get to know the tools, it’s easy to reason about what is being done to a stream. For example:

      .map { selectedIndex in
          return "You've selected #\(selectedIndex)."
      .subscribe { message in

    In the above, we’re taking a button, and upon it being tapped, start to do work. The first thing we do is read the current value of a UISegmentedControl. Once we have that value, we generate a message which we’re printing to the console.

    We’re composing two streams: the button tap and the segmented control’s value, and then mapping the result into a string. Finally, we use that string to do work.

    All of that is easily reasoned from just looking at the properties and methods called above: tap, withLatestFrom(), value, map, and subscribe. It’s all right there.

  • Improved flexibility and speed
    Since everything in your world is (or should be) exposed as a stream, it’s easy to extend what you’ve already written to add new features, or to react to new requirements. So many otherwise-challenging business requirements become quite simple when it’s just a matter of combining streams.

    Just the other day at work, we had a situation where our product owner wanted us to only enable a button when some search filters were selected. Since the filter values are just exposed as streams, it was as simple as a
    withLatestFrom(filters).map {} to make the button enable/disable as a reaction to the state of the filters. It took no time.

  • Cross-language Equivalency
    Most modern languages have a native implementation of Rx. In the case of my job, we’re using RxSwift for iOS and RxJava for Android. If your “native tongue” isn’t Swift, that’s okay. These same ideas and methods should be available in your platform of choice. Check out the ReactiveX site for details.

    The advantage for us is, if the Android team solves a tough problem, it’s likely that the iOS team can crib their solution, platform differences aside. That’s very powerful, as it leads to us all speaking a common language, even though our actual languages are very different.

Why Should I Care?

Having worked in RxSwift since February, I’ve come to really love it. It’s taken me a long time to un-learn all the ways I’ve traditionally thought about writing code. I’m still struggling, from time to time, to truly understand the right—reactive—way to approach a problem.

For all the reasons enumerated above, I can’t imagine writing code the traditional way anymore. It feels so heavy, and bloated, and just… old.

Rx is a completely different way of thinking, and I’ve yet to meet someone that took to it well. It took me a couple months to really get to the point where I could understand it well, and write it with a modicum of efficacy. Almost a year on, I absolutely love it.

Over the next several posts, I’ll be taking the world’s most boring and simple demo application and converting it from traditional, procedural code to use Rx. I’ll be going over the changes one very small step at a time.

The demo application is a single UIView that has a UIButton and a UILabel. As you tap the button, it tells you how many times you’ve done so in the label.

It’s boring and stupid, but by design: in moving from traditional code to the new hotness, I don’t want any other irrelevant stuff clouding the discussion.

Here’s a visual demo of the app:

Demo app animation

In part two, we’ll start by quickly examining the code, written using vanilla UIKit, and then taking the first step of the conversion to Rx.


Remember, way back when, a month ago, when I said this:

Top Gear The boys are back, and I’m so excited to see what comes next.

I, um, well, hm.

As I write this, The Grand Tour posted episode 4 just a few days ago. My summary of these episodes is, roughly:

1: 😂
2: 😱
3: 🙂
4: 😕

I was tentatively excited—thrilled even—after the first episode. Boy was I in for a shock in episode two:

Episode three was closer to the Top Gear I used to love, but still not quite there.

Episode four was, at best, watchable. Which led me to this very uncomfortable feeling:

I had my attention called to a spot-on article in The Guardian reviewing the season so far. It summarized, so well, some of my thoughts so far:

Worse, with the pool of cash Amazon provides, it’s cranked up these irksome indulgences to the point where bolts are popping out. The kernel of what made Top Gear a phenomenon – three men bickering, driving around and being rubbish – is almost entirely absent.

The author, Luke Holland, seems to have come to the same conclusion as I have:

One of the most acute mistakes Clarkson’s iteration of Top Gear increasingly made was its blurring of the line between presenter and actor. May, Hammond and Clarkson are good presenters; they were never good actors. And it was the show requiring them to act that resulted in its most tiresome segments.

And in a fitting summary:

It’s frustrating, because this is such an easy show to get right. Three men, talking about cars, mocking one another, and going on adventures. That’s it. Stop scripting everything, and stop throwing money at pointless explosions. It’s tiresome.

I take some issue with saying it’s “easy” to get right. I think the formula is easy, and has few ingredients. The three hosts, a general outline of a plot, and then stand back and get out of the way. The execution, however, is far more challenging.

Today, Erin said to me:

I used to look forward to the banter between the three of them. Now I dread it.

Nailed it.

By no means am I giving up on The Grand Tour. As many are quick to well, actually point out—as though I’m not acutely aware of it already—the first two seasons of Top Gear were, well, quite rough. Here’s hoping we’ll look at this season of The Grand Tour in the same way: ambitious, but rubbish.


Today I joined Shelly Brisbin, Dan Moren, and Jason Snell on this week’s Clockwise. Four topics, four hosts, a ton of fun, in thirty minutes.

This week, we discussed Amazon Go, tech trends we just can’t seem to get behind, home-tech paranoia, and giving back.

Always a blast, I hope that Clockwise is as fun to listen to as it is to record.

The Holy Trinity

1 year, 8 months, 17 days.

The time between the last normally scheduled Top Gear of the Clarkson era, and the premiere of The Grand Tour.

Now in the past, that time—that absence—seems so short. In the middle of it, it seemed endless.

I recognize how absurd it is to talk this way about a television show. Nonetheless, this is the TV show. The one I would schedule my life around. My favorite, bar none.

I eulogized Top Gear. I spent 75 minutes discussing it. Hell, I eulogized a fan site for the show. We threw parties to celebrate it. My license plate on my car is an homage to it.

The work of these men has meant a lot to me, for many years.

This past Friday, the first episode of The Grand Tour was released on Amazon Prime Video.

The same three hosts, but a new name, a new format, a new corporate overlord.

I’ve been looking forward to this for six months now. I was so amped to see this new creation that perfection was not possible.

Damn if they didn’t come close.

📣 📣 📣
Beyond here, there be spoilers.
If you haven't watched the episode, you should.
📣 📣 📣

Look. At. This. Opening.

So. Much. Happiness.

Look at how damn happy they are. Look at how happy Clarkson is.

No, seriously. Look at Clarkson again:


And May:


And Hammond:


They’re back.

The opening sequence nearly brought me to tears. Truly. It’s absurd, but it’s true.

The Grand Tour opens with Clarkson making a walk of shame out of the BBC headquarters in dreary London. The musical accompanyment begins as simply a piano, forlorn, lovely, understated. We follow Clarkson to Heathrow, boarding a flight to Los Angeles. He picks up his rental car, a blue bespoke Mustang, in a parking garage. Leaving LAX, on a bright and sun-shiny day, the vocals in the background accompaniment start:

I can see clearly now; the rain is gone. I can see all the obstacles in my way…

On the road is when we see the scene above. Clarkson is met by his co-hosts, in matching red, white, and blue Mustangs. Mustangs that, like the wild animals they’re named after, are running free.

Driving in the desert, at speed, amongst a flotilla of cars of all shapes and sizes, our three heroes arrive at what appears to be a music festival—Burning Van—in the middle of nowhere. Suddenly, the question begins to make sense.

As the once-mellow opening song reaches a crescendo, our hosts emerge from their cars amongst a horde of screaming fans. It is somewhat self-indulgent, only getting worse as eight screaming jets do a low-altitude fly by over the crowd. And yet, it’s so… them. I can’t help myself smiling even larger.

The first real words of the show aren’t uttered until our boys arrive on stage, and begin to introduce each other. The hosts introduce each other one by one, mostly “taking the mickey” out of each other in the process.

The opener was perfect.

I have some problems with the first episode. Aside from the opener being a bit over the top, I felt like the segments in the tent needed work. The hosts, to my eye, looked visibly nervous. Some of the jokes, such as the Air Force and celebrity guests, fell very flat, and went on far too long.

By and large, though, I thought this first episode of The Grand Tour was great. It focused largely on cars, which is something Top Gear got dinged for forgetting to do toward the end of its run.

The title of the episode (we’re doing episode titles now, apparently) is reference to the boys finally getting to test “the holy trinity” together. We have seen the 918, P1, and The Ferrari pit against each other. Finally. Having the BMW M2 as the introduction to the “Eboladrome” didn’t hurt this BMW owner’s feelings either.

Top Gear The boys are back, and I’m so excited to see what comes next.

Holiday Gifts 2016

We’re in November, which means it’s time to start stressing thinking about holiday gifts.

As with last year, here’s some things I like that are at various price points. You may find someone in your life that may enjoy one or more of these.

As a gift to me, links here are affiliate links where possible. Some of the below I did not pay for, but can say with an honest heart I absolutely would, had I not gotten the item for free.

Under $10

Apple has discounted USB-C peripherals until the end of the year. Though you may not know anyone getting a shiny new MacBook Pro, it’s likely someone you know will eventually be getting one. For those, they may like a USB-C → USB Adapter.

Or, perhaps, you may wish to pick up a Lightning to Headphone Jack Adapter. Surely you can’t have too many of these lying around.

Under $20

Most of us need a little extra juice for our phones or tablets at some time or another. I recently picked up an Aukey battery pack that has a neat trick up its sleeve: you charge the battery via a standard Lightning port. That means the same cord that you can use to go from the battery → iPhone can also be used to go from a USB charger → the Aukey battery pack. Super convenient.

Also in this price range is one of my favorite fast casual board games. Forbidden Island is a super fun game for 2-4 players that can be played in around half an hour. It’s cooperative, so all the players either fail or they win, but they do so together. It’s easy to learn, super fun, and as challenging as you want it to be.

Under $30

I’ve nearly ruined my wife’s computer (twice) by spilling water on it while recording a podcast. A dear friend took it upon himself to get me a Mighty Mug to use to hold water while I record. I’m deeply indebted to him, as he’s surely saved many pieces of electronics from my clumsiness.

Since that gift, Mighty Mug has expanded their line, and my actual recommendation is for their Double Old Fashioned cups. These are the perfect size for a vodka on the rocks, as I like, or the liquid from a wrung out bar rag, if that’s your thing. These cups are very hard to tip over, which is doubly useful once you’ve drained them once or twice.

Under $40

Another board game, Ticket to Ride is a second favorite of mine. It is reasonably easy to explain, reasonably fast, and very fun. Unlike Forbidden Island it is competitive, but unlike more traditional games like Monopoly, it’s not easy to actively mess with your opponents. Thus, Ticket to Ride is competitive without being aggressive.

Under $50

My friends at Studio Neat have been working on a product for what feels like forever now. They sent me a very early test model a long time ago, and I love this thing. It’s finally for sale now.

The Canopy is a fancy carrying case for the Magic Keyboard (more on that below). I like taking my iMac’s Keyboard with me when I travel for more than a day or two with only my iPad Mini. It allows me to quickly fire off emails, write blog posts, or otherwise get things done. The Canopy is the perfect carrying case for the Magic Keyboard. It’s simple, pretty, and light.

NOTE: Holiday shipping for the Canopy isn’t guaranteed.

Under $75

Speaking of Studio Neat, their Material Dock is really lovely. It’s a charging stand for your iPhone and, if you have one, your Apple Watch as well. I was given a iPhone & Watch Material Dock for testing, and I immediately fell in love. The Material Dock is made of solid walnut, and some really lovely cork backing for your devices.

Note that the Material Dock requires but does not include Apple cables, so you may wish to include one of those those as well.

Under $100

As previously mentioned, I love the Apple Magic Keyboard. This keyboard is my favorite keyboard that I’ve ever used. The key travel and responsiveness are exactly what I want, and I genuinely smile at least once a day because of this keyboard.

Since it’s Bluetooth, it works with not only Macs, but also iOS devices, and presumably PCs as well. Like the Aukey battery, it charges via Lightning, which you only need to do once every couple months.

Under $200

I was recently given a set of Aftershokz Trekz Titanium bone conduction headphones. While not terribly great for music—they’re quite tinny—they are perfect for podcasts. The Trekz are also sweat/dust resistant, and fit snugly on the head, so they’re great for working out, or just being mobile doing chores. Plus, they’re Bluetooth, so there’s no wires to worry about.

Because they work via bone conduction, that leaves your ears open to be able to hear the noises around you. I love using these headphones when I’m on a walk with Declan, or like this very moment, when he’s sleeping, and I need to be able to hear the baby monitor. Very neat stuff.

Two Years

Today, you turn two.

Sometime in the last six or so months, I feel like you’ve changed. You’re no longer our baby. You’re our child. I look at you and see a small boy, rather than an infant.

I’m wholly unprepared for this.

A photo posted by Casey Liss (@caseyliss) on

You’re talking now. Sometimes I can understand. Sometimes I need your mother to translate. Sometimes we’re both completely flummoxed. To be able to really communicate with you—to have even a tiny inkling of what’s going on in your head—changes everything.

It’s fascinating to see the world through your eyes. To see you react to things you’ve never seen. To try things you’ve never tried. To learn to cope with feelings you don’t quite understand.

Sometimes you’re frustrating. I’m told I can be, as well, from time to time.

Days like today, and most days, really, you remind me how lucky we are to have you in our lives. How lucky we are that, somehow, by some miracle, you arrived in our family.

I look back on the journey we took before you arrived, and I remember it like it was yesterday. I remember asking when our infant became a baby; how our baby could already be one. Were you born yesterday, or was it two years ago?

The days can be long. The years are always short.

I’m already looking forward to the next one. And every one I’m lucky enough to share with you after.

Happy birthday, Declan! I love you.



This week I joined Katie Floyd and David Sparks on their long-running and excellent show, Mac Power Users. I was a previous guest a couple years ago, just before Declan was born. Now, two years later, it was a blast to come back and talk with Katie and David again.

On this episode, we discussed my transition to iOS development, some parenting tools, my Mac and iOS workflows, and how I use my Synology NAS.

Mac Power Users is a juggernaut in the Apple podcasting community. It’s an honor to be asked to participate, and always a blast to record with David and Katie.


My buddy Greg Koenig just wrote an interesting post that refutes what many people are taking as fact: Apple is producing a ceramic iPhone.

This all stemmed from a controverial post on Quora which stated, right up front:

Apple will create an iPhone primarily from ZrO2 - Zirconian Ceramics

Greg manufactures things for a living; I use his Luma Loop camera strap every time I pick up my big camera. He tends to know what he’s talking about, and uses much of the same equipment that Jony Ive does. Greg writes:

Apple is a hardware company and machined aluminum is their primary platform. At peak production, Apple is manufacturing roughly 1 million iPhones per day.

For Apple to bring a whole new long-cycle-time process online for the next iPhone, […] they would need warehouses with thousands of machines already in situ, with thousands more in production.

Greg’s post is a fascinating read, which spells out several reasons why it’s highly unlikely Apple will be releasing a ceramic iPhone anytime soon.


A couple of weeks ago I joined my buddy Jelly (of GIFWrapped fame) on his podcast about mobile app development, Mobile Couch. Since Jelly’s normal co-host—and other friend of mine—Ben was on assignment, I got to fill in.

On this episode, Jelly and I discussed both migrations from Objective-C to Swift, as well as my new forays into functional reactive programming using RxSwift.

It’s really hard to verbally describe the magic that is Rx, but I had a lot of fun recording this episode. Come for the nerd talk; stay for Jelly’s delightful accent.