From traditional to reactive

Brent Simmons has a series of posts about Reactive vs “Traditional” which sound a lot like the arguments we’re having internally as a team lately. I’ve gotten into RxSwift in the past months and believe it’s a great solution to a number of problems, but it is indeed a big dependency and has a steep learning curve.

I find RxSwift declarative style much easier to read and follow than the imperative counterparts, but it took a while to get there. I remember struggling for months learning to think in terms of streams, and I was really motivated to learn it.

But I thought I’d take some time to take the example in Comparing Reactive and Traditional, as I don’t think it’s a fair comparison (and not in the way you might expect). You can download all the steps in a playground: Traditional to Reactive.playground.

My first “refactor” was just to clean up the code enough to compiled without errors, so I can put it on a playground.

Then I addressed what I found most confusing about the traditional implementation, which is all that throttling logic scattered around the view controller. There’s no need to go reactive there, we just need to contain all that logic and state in one place: Throttle. This is a generic class that takes a timeout and a callback, and you can send new values or cancel. It will call callback after timeout seconds since the last input unless a new input happens. Note that this class is generic and doesn’t need to know anything about the values. It is also easily testable.

This leaves us with a simpler view controller, but we still have some logic in there that’s not really specific and could be extracted: keeping only the last request and canceling the previous one. I’ve called this SwitchToLatest, and it couldn’t be simpler: it just has a switchTo method that keeps a reference to the task, and calls cancel on it whenever there’s a new one. It uses a new Cancelable protocol since we don’t really care about what the task is, we just need to know that we can cancel it. Also really easy to test.

And this is how the final ViewController looks:

Here’s where I think the fair comparison starts. The traditional version has all the behaviors we want in units with a single responsibility, and the view controller takes these building blocks to do what it needs.

What RxSwift brings to the table is the ability to compose these units and a common pattern for cancellation. What you can’t do here is take Throttle and pipe its output into SwitchToLatest. But in this case, that’s fine.

The live search example is typically a nice example of reactive code as it showcases all of it’s features: streams of values, composition of operators, side effects on subscription, and disposables/cancellation. But as we’ve seen, it doesn’t work as a way for reactive code to prove its value, as the traditional counterpart is simple enough.

Compare this to the thing I was trying to write in RxSwift.

  • We have some data that needs to be loaded from the API. That data might be used by a few different view controllers.
  • When a request fails because of network conditions, it should be automatically retried a few times before we give up.
  • We want to poll for new data every minute, counting since the last successful refresh.
  • If a request is taking more than a few seconds, the UI should display a message indicating that “this is taking longer than expected”.
  • If the request fails because an “unrecoverable” error or we give up on retrying, the UI should display an error and we shouldn’t try to poll for data until the user manually refreshes again.
  • The UI should show a message when it detects it’s offline, and stop any polling attempts. When we detect we’re online we should resume polling. (I later learned that Apple doesn’t recommend using Reachability to prevent network requests unless they’ve already failed).
  • If a second VC wants the same data, there should not be a second request going out. Not just caching, but reusing in-progress requests.

When written in RxSwift it was already a complex logic to follow, and I even had to write a couple of custom operators (pausable and retryIf). There’s no silver bullet, and that’s also true for RxSwift, but I believe it can help. I can’t imagine reasoning about all the possible states in a more traditional design.

I also would argue (although someone might disagree) that any time you use NSNotificationCenter, NSFetchedResultsController, or KVO, you are already doing some sort of reactive programming, just not in a declarative way.

Apple on reusing

There was an Apple Event today for the press where they announced new iPads and iPhones.

An interesting thing about the event is that they spent around ten minutes (out of sixty) talking about the environment, how they use renewable energy, and how they work on reusing and recycling their products. They mentioned that the vast majority of iPhones that come back in, get reused in some way.

Everything was awesome and Apple looked like it did a fantastic job in the green category. For a second I almost forgot about planned obsolescence, or how their business is based on people buying new stuff all the time.

Fast forward a bit, and here’s Phil Schiller on stage talking about why they chose the size for the new iPad to target existing PC users, and he says this:

There are over 600 million PCs in use today that are over 5 years old. This is really sad.

Phil Schiller on Stage

I recently replaced a 4 year old MacBook Pro only because I needed all the performance I could get for development work, but it was perfectly functional for less intensive tasks. My previous 5 year old iMac was sold to a friend who still uses it frequently. We also just sold a 6 year old MacBook Air that also worked fine. I even keep a 12 year old iBook that would work fine if it weren’t for the broken AC adapter. My mother uses my 6 year old iPhone 4. I fail to see how any of this is sad other than it means less money for Apple.

Learn me a Haskell

Lately I’ve become interested in functional programming, and Haskell always felt like the thing I should learn, so this week I finally started reading  Learn You a Haskell. So far I’ve been through the first six chapters and they do a great job at indroducing many concepts.

Pattern matching got me hooked. I had read the Patterns chapter in the swift book, and a couple blog posts on the subject, but they always felt like little more than “switch with ranges”. After reading the pattern matching chapter in Learn You a Haskell, suddenly Patterns appeared much more useful, even in Swift.

And then I read some of the concepts around higher order functions, how all functions are curried, how trivial partial application is, and how concise and clear everything reads once you get past the syntax choices. My mind was blown time after time.

xwouu8g

One of those days…

I wake up early, ready to start the week with a fresh mind and debug that issue that drove me crazy on Friday. I pick up from were I left in Xcode, and hit run.

It slowly builds and installs the app on my iPad, then promptly shows the launch screen, then more launch screen. I try again, change some things, reconnect the iPad. One hour later I manage to run the app.

I set a few breakpoints in the debugger to figure out what’s going on. When I hit one, I inspect the call trace and Xcode crashes. Relaunch, debug, inspect, crash again. Repeat 3-4 times.

I yell at the screen, and decide to take a deep breath and walk for a bit to relax. I come back, five minutes later, to a dead mouse that doesn’t seem to work. I change the batteries, I try all the batteries in the house. I clean the contacts. It seems dead.

I try some of those tricks where you shut down your computer, press ctrl-option-shift-power and then start. Nothing. Also, my MacBook Pro won’t even start if the Thunderbolt Ethernet Adapter is plugged in.

I disconnect that, restart, and reconnect. I’m greeted by a couple dialogs asking for permissions, and an app wants to install an update. Nope, not now.

I give up on the Magic Mouse, and go back to the G500 which still works, although it sometimes double-clicks when you click.

I started working 4 hours ago, and so far I got nothing done, for reasons beyond my control.

Some days, I really hate technology.

Using all the buttons of a Logitech G500 on a Mac

For a while, I’ve been meaning to replace my current Apple Magic Mouse with something a bit more ergonomic. It seems like a few coworkers are quite happy with the MX Master, but it’s a bit pricey and, as it turns out, I already have a mouse that’s more ergonomic. A few years ago I got a G500 for gaming, but it also makes for a nice regular mouse.

My main problem switching to a more traditional mouse is that I’m really used to the gesture on the magic mouse to go back/forward, so I needed to replicate that.

Using Logitech’s Gaming Software, you can map the forward and back buttons, but they really just send ⌘-[ and ⌘-], which works for Safari, but not for other apps like Xcode.

Screen Shot 2015-11-23 at 16.25.45.png

Searching about it, I discovered BetterTouchTool, a nice free app that let’s you customize gestures, buttons, and keyboard shortcuts. It looks way more powerful than what I’m currently using it for, but it gets the job done.

My first problem was that it didn’t recognize the back/forward buttons on the thumb area. From what I’ve read, the mouse doesn’t send mouse events for those but keystrokes for whatever reason. It now makes sense that I got the new keyboard assistant when I first plugged it in.

Screen Shot 2015-11-23 at 16.24.21.png
The G500 detected as a keyboard

I next tried to map the scroll left/right to back forward, which felt a lot like the magic mouse, until I had to actually do horizontal scroll and I was stuck.

My final solution works, although it’s definitely hacky: map the back/forward buttons to a keystroke that I won’t normally use (in this case F13, ⇧-F13), and then map those to the gesture in BetterTouchTool

Screen Shot 2015-11-23 at 15.37.13.pngScreen Shot 2015-11-23 at 15.37.57.png

After an hour of usage, I wasn’t missing my Magic Mouse at all, but my hands started to get tired. Then I remembered to remove all the weights :facepalm:

IMG_1177.jpg
These are great for FPS, not so much for extended usage

Decluttering: mobile edition

Since I got a new watch a few months ago, I find myself looking at my phone less by accident. By that I mean those times when you just wanted to check the time and saw a notification, ended up checking email or Facebook anyway, and spent 10 minutes looking at the phone doing nothing useful.

But still there’s a number of times when that happens, mostly because of notifications. Having more Facebook friends than the years has days means that pretty much every day is somebody’s birthday. And so when I pick the phone in the morning the first thing I see is a Facebook notification about it, which gave me an excuse to open Facebook. I noticed that, for a while, the first thing I did in the morning was checking Facebook, and it didn’t feel right at all.

There’s also those times when you are slightly bored and go to your phone out of habit. I would check Facebook again, or maybe play a game, or catch up on blogs on Feedly.

I felt I was spending way too much time and attention on things of little value, so I stopped. This is my home screen today:

Screen Shot 2015-08-17 at 15.52.28

What you won’t find in there (or the other screen): Facebook, Twitter, games, Feedly, Flipboard, Zite.

I kept Pocket since at least that has content that I already selected myself. Other than that, if I’m checking my phone to kill some time, I have books.

I’ve had this going for almost a month and while I’ve barely had any notifications making me check my phone, I still have the habit of checking Facebook way too often, even from Safari.